blob: ccb75c974d81d9494654dc97d72fe52c2424c729 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/**
* A directive for managing all active Guacamole sessions.
*/
angular.module('settings').directive('guacSettingsSessions', [function guacSettingsSessions() {
return {
// Element only
restrict: 'E',
replace: true,
scope: {
},
templateUrl: 'app/settings/templates/settingsSessions.html',
controller: ['$scope', '$injector', function settingsSessionsController($scope, $injector) {
// Required types
var ActiveConnectionWrapper = $injector.get('ActiveConnectionWrapper');
var ConnectionGroup = $injector.get('ConnectionGroup');
var SortOrder = $injector.get('SortOrder');
// Required services
var $filter = $injector.get('$filter');
var $translate = $injector.get('$translate');
var $q = $injector.get('$q');
var activeConnectionService = $injector.get('activeConnectionService');
var authenticationService = $injector.get('authenticationService');
var connectionGroupService = $injector.get('connectionGroupService');
var dataSourceService = $injector.get('dataSourceService');
var guacNotification = $injector.get('guacNotification');
var requestService = $injector.get('requestService');
/**
* The identifiers of all data sources accessible by the current
* user.
*
* @type String[]
*/
var dataSources = authenticationService.getAvailableDataSources();
/**
* The ActiveConnectionWrappers of all active sessions accessible
* by the current user, or null if the active sessions have not yet
* been loaded.
*
* @type ActiveConnectionWrapper[]
*/
$scope.wrappers = null;
/**
* SortOrder instance which maintains the sort order of the visible
* connection wrappers.
*
* @type SortOrder
*/
$scope.wrapperOrder = new SortOrder([
'activeConnection.username',
'startDate',
'activeConnection.remoteHost',
'name'
]);
/**
* Array of all wrapper properties that are filterable.
*
* @type String[]
*/
$scope.filteredWrapperProperties = [
'activeConnection.username',
'startDate',
'activeConnection.remoteHost',
'name'
];
/**
* All active connections, if known, grouped by corresponding data
* source identifier, or null if active connections have not yet
* been loaded.
*
* @type Object.<String, Object.<String, ActiveConnection>>
*/
var allActiveConnections = null;
/**
* Map of all visible connections by data source identifier and
* object identifier, or null if visible connections have not yet
* been loaded.
*
* @type Object.<String, Object.<String, Connection>>
*/
var allConnections = null;
/**
* The date format for use for session-related dates.
*
* @type String
*/
var sessionDateFormat = null;
/**
* Map of all currently-selected active connection wrappers by
* data source and identifier.
*
* @type Object.<String, Object.<String, ActiveConnectionWrapper>>
*/
var allSelectedWrappers = {};
/**
* Adds the given connection to the internal set of visible
* connections.
*
* @param {String} dataSource
* The identifier of the data source associated with the given
* connection.
*
* @param {Connection} connection
* The connection to add to the internal set of visible
* connections.
*/
var addConnection = function addConnection(dataSource, connection) {
// Add given connection to set of visible connections
allConnections[dataSource][connection.identifier] = connection;
};
/**
* Adds all descendant connections of the given connection group to
* the internal set of connections.
*
* @param {String} dataSource
* The identifier of the data source associated with the given
* connection group.
*
* @param {ConnectionGroup} connectionGroup
* The connection group whose descendant connections should be
* added to the internal set of connections.
*/
var addDescendantConnections = function addDescendantConnections(dataSource, connectionGroup) {
// Add all child connections
angular.forEach(connectionGroup.childConnections, function addConnectionForDataSource(connection) {
addConnection(dataSource, connection);
});
// Add all child connection groups
angular.forEach(connectionGroup.childConnectionGroups, function addConnectionGroupForDataSource(connectionGroup) {
addDescendantConnections(dataSource, connectionGroup);
});
};
/**
* Wraps all loaded active connections, storing the resulting array
* within the scope. If required data has not yet finished loading,
* this function has no effect.
*/
var wrapAllActiveConnections = function wrapAllActiveConnections() {
// Abort if not all required data is available
if (!allActiveConnections || !allConnections || !sessionDateFormat)
return;
// Wrap all active connections for sake of display
$scope.wrappers = [];
angular.forEach(allActiveConnections, function wrapActiveConnections(activeConnections, dataSource) {
angular.forEach(activeConnections, function wrapActiveConnection(activeConnection, identifier) {
// Retrieve corresponding connection
var connection = allConnections[dataSource][activeConnection.connectionIdentifier];
// Add wrapper
if (activeConnection.username !== null) {
$scope.wrappers.push(new ActiveConnectionWrapper({
dataSource : dataSource,
name : connection.name,
startDate : $filter('date')(activeConnection.startDate, sessionDateFormat),
activeConnection : activeConnection
}));
}
});
});
};
// Retrieve all connections
dataSourceService.apply(
connectionGroupService.getConnectionGroupTree,
dataSources,
ConnectionGroup.ROOT_IDENTIFIER
)
.then(function connectionGroupsReceived(rootGroups) {
allConnections = {};
// 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
wrapAllActiveConnections();
}, requestService.WARN);
// Query active sessions
dataSourceService.apply(
activeConnectionService.getActiveConnections,
dataSources
)
.then(function sessionsRetrieved(retrievedActiveConnections) {
// Store received map of active connections
allActiveConnections = retrievedActiveConnections;
// Attempt to produce wrapped list of active connections
wrapAllActiveConnections();
}, requestService.WARN);
// Get session date format
$translate('SETTINGS_SESSIONS.FORMAT_STARTDATE').then(function sessionDateFormatReceived(retrievedSessionDateFormat) {
// Store received date format
sessionDateFormat = retrievedSessionDateFormat;
// Attempt to produce wrapped list of active connections
wrapAllActiveConnections();
}, angular.noop);
/**
* Returns whether critical data has completed being loaded.
*
* @returns {Boolean}
* true if enough data has been loaded for the user interface
* to be useful, false otherwise.
*/
$scope.isLoaded = function isLoaded() {
return $scope.wrappers !== null;
};
/**
* An action to be provided along with the object sent to
* showStatus which closes the currently-shown status dialog.
*/
var CANCEL_ACTION = {
name : "SETTINGS_SESSIONS.ACTION_CANCEL",
// Handle action
callback : function cancelCallback() {
guacNotification.showStatus(false);
}
};
/**
* An action to be provided along with the object sent to
* showStatus which immediately deletes the currently selected
* sessions.
*/
var DELETE_ACTION = {
name : "SETTINGS_SESSIONS.ACTION_DELETE",
className : "danger",
// Handle action
callback : function deleteCallback() {
deleteAllSessionsImmediately();
guacNotification.showStatus(false);
}
};
/**
* Immediately deletes the selected sessions, without prompting the
* user for confirmation.
*/
var deleteAllSessionsImmediately = function deleteAllSessionsImmediately() {
var deletionRequests = [];
// 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
$scope.wrappers = $scope.wrappers.filter(function activeConnectionStillExists(wrapper) {
return !(wrapper.activeConnection.identifier in (allSelectedWrappers[wrapper.dataSource] || {}));
});
// Clear selection
allSelectedWrappers = {};
}, guacNotification.SHOW_REQUEST_ERROR);
};
/**
* Delete all selected sessions, prompting the user first to
* confirm that deletion is desired.
*/
$scope.deleteSessions = function deleteSessions() {
// Confirm deletion request
guacNotification.showStatus({
'title' : 'SETTINGS_SESSIONS.DIALOG_HEADER_CONFIRM_DELETE',
'text' : {
'key' : 'SETTINGS_SESSIONS.TEXT_CONFIRM_DELETE'
},
'actions' : [ DELETE_ACTION, CANCEL_ACTION]
});
};
/**
* Returns whether the selected sessions can be deleted.
*
* @returns {Boolean}
* true if selected sessions can be deleted, false otherwise.
*/
$scope.canDeleteSessions = function canDeleteSessions() {
// We can delete sessions if at least one is selected
for (var dataSource in allSelectedWrappers) {
for (var identifier in allSelectedWrappers[dataSource])
return true;
}
return false;
};
/**
* Called whenever an active connection wrapper changes selected
* status.
*
* @param {ActiveConnectionWrapper} wrapper
* The wrapper whose selected status has changed.
*/
$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
if (wrapper.checked)
selectedWrappers[wrapper.activeConnection.identifier] = wrapper;
// Otherwise, remove wrapper from map
else
delete selectedWrappers[wrapper.activeConnection.identifier];
};
}]
};
}]);