GUAC-586: Restore management of active sessions.

This commit is contained in:
Michael Jumper
2015-09-02 17:16:16 -07:00
parent ddd144fc47
commit a7ea7ba6c9
2 changed files with 127 additions and 69 deletions

View File

@@ -44,10 +44,21 @@ angular.module('settings').directive('guacSettingsSessions', [function guacSetti
// Required services // Required services
var $filter = $injector.get('$filter'); var $filter = $injector.get('$filter');
var $translate = $injector.get('$translate'); var $translate = $injector.get('$translate');
var $q = $injector.get('$q');
var activeConnectionService = $injector.get('activeConnectionService'); var activeConnectionService = $injector.get('activeConnectionService');
var authenticationService = $injector.get('authenticationService');
var connectionGroupService = $injector.get('connectionGroupService'); var connectionGroupService = $injector.get('connectionGroupService');
var dataSourceService = $injector.get('dataSourceService');
var guacNotification = $injector.get('guacNotification'); var guacNotification = $injector.get('guacNotification');
/**
* The identifiers of all data sources accessible by the current
* user.
*
* @type String[]
*/
var dataSources = authenticationService.getAvailableDataSources();
/** /**
* The ActiveConnectionWrappers of all active sessions accessible * The ActiveConnectionWrappers of all active sessions accessible
* by the current user, or null if the active sessions have not yet * by the current user, or null if the active sessions have not yet
@@ -83,20 +94,22 @@ angular.module('settings').directive('guacSettingsSessions', [function guacSetti
]; ];
/** /**
* All active connections, if known, or null if active connections * All active connections, if known, grouped by corresponding data
* have not yet been loaded. * source identifier, or null if active connections have not yet
* been loaded.
* *
* @type ActiveConnection * @type Object.<String, Object.<String, ActiveConnection>>
*/ */
var activeConnections = null; var allActiveConnections = null;
/** /**
* Map of all visible connections by object identifier, or null if * Map of all visible connections by data source identifier and
* visible connections have not yet been loaded. * object identifier, or null if visible connections have not yet
* been loaded.
* *
* @type Object.<String, Connection> * @type Object.<String, Object.<String, Connection>>
*/ */
var connections = null; var allConnections = null;
/** /**
* The date format for use for session-related dates. * The date format for use for session-related dates.
@@ -107,24 +120,28 @@ angular.module('settings').directive('guacSettingsSessions', [function guacSetti
/** /**
* Map of all currently-selected active connection wrappers by * Map of all currently-selected active connection wrappers by
* identifier. * data source and identifier.
* *
* @type Object.<String, ActiveConnectionWrapper> * @type Object.<String, Object.<String, ActiveConnectionWrapper>>
*/ */
var selectedWrappers = {}; var allSelectedWrappers = {};
/** /**
* Adds the given connection to the internal set of visible * Adds the given connection to the internal set of visible
* connections. * connections.
* *
* @param {String} dataSource
* The identifier of the data source associated with the given
* connection.
*
* @param {Connection} connection * @param {Connection} connection
* The connection to add to the internal set of visible * The connection to add to the internal set of visible
* connections. * connections.
*/ */
var addConnection = function addConnection(connection) { var addConnection = function addConnection(dataSource, connection) {
// Add given connection to set of visible connections // Add given connection to set of visible connections
connections[connection.identifier] = connection; allConnections[dataSource][connection.identifier] = connection;
}; };
@@ -132,19 +149,25 @@ angular.module('settings').directive('guacSettingsSessions', [function guacSetti
* Adds all descendant connections of the given connection group to * Adds all descendant connections of the given connection group to
* the internal set of connections. * the internal set of connections.
* *
* @param {String} dataSource
* The identifier of the data source associated with the given
* connection group.
*
* @param {ConnectionGroup} connectionGroup * @param {ConnectionGroup} connectionGroup
* The connection group whose descendant connections should be * The connection group whose descendant connections should be
* added to the internal set of connections. * added to the internal set of connections.
*/ */
var addDescendantConnections = function addDescendantConnections(connectionGroup) { var addDescendantConnections = function addDescendantConnections(dataSource, connectionGroup) {
// Add all child connections // Add all child connections
if (connectionGroup.childConnections) angular.forEach(connectionGroup.childConnections, function addConnectionForDataSource(connection) {
connectionGroup.childConnections.forEach(addConnection); addConnection(dataSource, connection);
});
// Add all child connection groups // Add all child connection groups
if (connectionGroup.childConnectionGroups) angular.forEach(connectionGroup.childConnectionGroups, function addConnectionGroupForDataSource(connectionGroup) {
connectionGroup.childConnectionGroups.forEach(addDescendantConnections); addDescendantConnections(dataSource, connectionGroup);
});
}; };
@@ -153,50 +176,66 @@ angular.module('settings').directive('guacSettingsSessions', [function guacSetti
* within the scope. If required data has not yet finished loading, * within the scope. If required data has not yet finished loading,
* this function has no effect. * this function has no effect.
*/ */
var wrapActiveConnections = function wrapActiveConnections() { var wrapAllActiveConnections = function wrapAllActiveConnections() {
// Abort if not all required data is available // Abort if not all required data is available
if (!activeConnections || !connections || !sessionDateFormat) if (!allActiveConnections || !allConnections || !sessionDateFormat)
return; return;
// Wrap all active connections for sake of display // Wrap all active connections for sake of display
$scope.wrappers = []; $scope.wrappers = [];
for (var identifier in activeConnections) { angular.forEach(allActiveConnections, function wrapActiveConnections(activeConnections, dataSource) {
angular.forEach(activeConnections, function wrapActiveConnection(activeConnection, identifier) {
var activeConnection = activeConnections[identifier]; // Retrieve corresponding connection
var connection = connections[activeConnection.connectionIdentifier]; var connection = allConnections[dataSource][activeConnection.connectionIdentifier];
$scope.wrappers.push(new ActiveConnectionWrapper( // Add wrapper
connection.name, $scope.wrappers.push(new ActiveConnectionWrapper({
$filter('date')(activeConnection.startDate, sessionDateFormat), dataSource : dataSource,
activeConnection name : connection.name,
)); startDate : $filter('date')(activeConnection.startDate, sessionDateFormat),
activeConnection : activeConnection
}));
} });
});
}; };
// Retrieve all connections // Retrieve all connections
connectionGroupService.getConnectionGroupTree(ConnectionGroup.ROOT_IDENTIFIER) dataSourceService.apply(
.success(function connectionGroupReceived(retrievedRootGroup) { connectionGroupService.getConnectionGroupTree,
dataSources,
ConnectionGroup.ROOT_IDENTIFIER
)
.then(function connectionGroupsReceived(rootGroups) {
// Load connections from retrieved group tree allConnections = {};
connections = {};
addDescendantConnections(retrievedRootGroup); // Load connections from each received root group
angular.forEach(rootGroups, function connectionGroupReceived(rootGroup, dataSource) {
allConnections[dataSource] = {};
addDescendantConnections(dataSource, rootGroup);
});
// Attempt to produce wrapped list of active connections // Attempt to produce wrapped list of active connections
wrapActiveConnections(); wrapAllActiveConnections();
}); });
// Query active sessions // Query active sessions
activeConnectionService.getActiveConnections().success(function sessionsRetrieved(retrievedActiveConnections) { dataSourceService.apply(
activeConnectionService.getActiveConnections,
dataSources
)
.then(function sessionsRetrieved(retrievedActiveConnections) {
// Store received list // Store received map of active connections
activeConnections = retrievedActiveConnections; allActiveConnections = retrievedActiveConnections;
// Attempt to produce wrapped list of active connections // Attempt to produce wrapped list of active connections
wrapActiveConnections(); wrapAllActiveConnections();
}); });
@@ -207,7 +246,7 @@ angular.module('settings').directive('guacSettingsSessions', [function guacSetti
sessionDateFormat = retrievedSessionDateFormat; sessionDateFormat = retrievedSessionDateFormat;
// Attempt to produce wrapped list of active connections // Attempt to produce wrapped list of active connections
wrapActiveConnections(); wrapAllActiveConnections();
}); });
@@ -219,10 +258,7 @@ angular.module('settings').directive('guacSettingsSessions', [function guacSetti
* to be useful, false otherwise. * to be useful, false otherwise.
*/ */
$scope.isLoaded = function isLoaded() { $scope.isLoaded = function isLoaded() {
return $scope.wrappers !== null;
return $scope.wrappers !== null
&& $scope.sessionDateFormat !== null;
}; };
/** /**
@@ -259,7 +295,7 @@ angular.module('settings').directive('guacSettingsSessions', [function guacSetti
className : "danger", className : "danger",
// Handle action // Handle action
callback : function deleteCallback() { callback : function deleteCallback() {
deleteSessionsImmediately(); deleteAllSessionsImmediately();
guacNotification.showStatus(false); guacNotification.showStatus(false);
} }
}; };
@@ -268,24 +304,36 @@ angular.module('settings').directive('guacSettingsSessions', [function guacSetti
* Immediately deletes the selected sessions, without prompting the * Immediately deletes the selected sessions, without prompting the
* user for confirmation. * user for confirmation.
*/ */
var deleteSessionsImmediately = function deleteSessionsImmediately() { var deleteAllSessionsImmediately = function deleteAllSessionsImmediately() {
// Perform deletion var deletionRequests = [];
activeConnectionService.deleteActiveConnections(Object.keys(selectedWrappers))
.success(function activeConnectionsDeleted() { // Perform deletion for each relevant data source
angular.forEach(allSelectedWrappers, function deleteSessionsImmediately(selectedWrappers, dataSource) {
// Delete sessions, if any are selected
var identifiers = Object.keys(selectedWrappers);
if (identifiers.length)
deletionRequests.push(activeConnectionService.deleteActiveConnections(dataSource, identifiers));
});
// Update interface
$q.all(deletionRequests)
.then(function activeConnectionsDeleted() {
// Remove deleted connections from wrapper array // Remove deleted connections from wrapper array
$scope.wrappers = $scope.wrappers.filter(function activeConnectionStillExists(wrapper) { $scope.wrappers = $scope.wrappers.filter(function activeConnectionStillExists(wrapper) {
return !(wrapper.activeConnection.identifier in selectedWrappers); return !(wrapper.activeConnection.identifier in (allSelectedWrappers[wrapper.dataSource] || {}));
}); });
// Clear selection // Clear selection
selectedWrappers = {}; allSelectedWrappers = {};
}) },
// Notify of any errors // Notify of any errors
.error(function activeConnectionDeletionFailed(error) { function activeConnectionDeletionFailed(error) {
guacNotification.showStatus({ guacNotification.showStatus({
'className' : 'error', 'className' : 'error',
'title' : 'SETTINGS_SESSIONS.DIALOG_HEADER_ERROR', 'title' : 'SETTINGS_SESSIONS.DIALOG_HEADER_ERROR',
@@ -318,8 +366,10 @@ angular.module('settings').directive('guacSettingsSessions', [function guacSetti
$scope.canDeleteSessions = function canDeleteSessions() { $scope.canDeleteSessions = function canDeleteSessions() {
// We can delete sessions if at least one is selected // We can delete sessions if at least one is selected
for (var identifier in selectedWrappers) for (var dataSource in allSelectedWrappers) {
return true; for (var identifier in allSelectedWrappers[dataSource])
return true;
}
return false; return false;
@@ -334,6 +384,11 @@ angular.module('settings').directive('guacSettingsSessions', [function guacSetti
*/ */
$scope.wrapperSelectionChange = function wrapperSelectionChange(wrapper) { $scope.wrapperSelectionChange = function wrapperSelectionChange(wrapper) {
// Get selection map for associated data source, creating if necessary
var selectedWrappers = allSelectedWrappers[wrapper.dataSource];
if (!selectedWrappers)
selectedWrappers = allSelectedWrappers[wrapper.dataSource] = {};
// Add wrapper to map if selected // Add wrapper to map if selected
if (wrapper.checked) if (wrapper.checked)
selectedWrappers[wrapper.activeConnection.identifier] = wrapper; selectedWrappers[wrapper.activeConnection.identifier] = wrapper;

View File

@@ -31,44 +31,47 @@ angular.module('settings').factory('ActiveConnectionWrapper', [
* properties, such as a checked option. * properties, such as a checked option.
* *
* @constructor * @constructor
* @param {String} name * @param {ActiveConnectionWrapper|Object} template
* The display name of the active connection. * The object whose properties should be copied within the new
* * ActiveConnectionWrapper.
* @param {String} startDate
* The date and time this session began, pre-formatted for display.
*
* @param {ActiveConnection} activeConnection
* The ActiveConnection to wrap.
*/ */
var ActiveConnectionWrapper = function ActiveConnectionWrapper(name, startDate, activeConnection) { var ActiveConnectionWrapper = function ActiveConnectionWrapper(template) {
/**
* The identifier of the data source associate dwith the
* ActiveConnection wrapped by this ActiveConnectionWrapper.
*
* @type String
*/
this.dataSource = template.dataSource;
/** /**
* The display name of this connection. * The display name of this connection.
* *
* @type String * @type String
*/ */
this.name = name; this.name = template.name;
/** /**
* The date and time this session began, pre-formatted for display. * The date and time this session began, pre-formatted for display.
* *
* @type String * @type String
*/ */
this.startDate = startDate; this.startDate = template.startDate;
/** /**
* The wrapped ActiveConnection. * The wrapped ActiveConnection.
* *
* @type ActiveConnection * @type ActiveConnection
*/ */
this.activeConnection = activeConnection; this.activeConnection = template.activeConnection;
/** /**
* A flag indicating that the active connection has been selected. * A flag indicating that the active connection has been selected.
* *
* @type Boolean * @type Boolean
*/ */
this.checked = false; this.checked = template.checked || false;
}; };