GUACAMOLE-338: Merge expand connections/groups by default if any of their descendants are selected.

This commit is contained in:
Nick Couchman
2017-07-14 15:07:11 -04:00
4 changed files with 95 additions and 9 deletions

View File

@@ -32,7 +32,7 @@ angular.module('groupList').directive('guacGroupList', [function guacGroupList()
* The connection groups to display as a map of data source * The connection groups to display as a map of data source
* identifier to corresponding root group. * identifier to corresponding root group.
* *
* @type Object.<String, ConnectionGroup> * @type Object.<String, ConnectionGroup|GroupListItem>
*/ */
connectionGroups : '=', connectionGroups : '=',
@@ -167,15 +167,23 @@ angular.module('groupList').directive('guacGroupList', [function guacGroupList()
// Add each provided connection group // Add each provided connection group
angular.forEach(connectionGroups, function addConnectionGroup(connectionGroup, dataSource) { angular.forEach(connectionGroups, function addConnectionGroup(connectionGroup, dataSource) {
var rootItem;
// Prepare data source for active connection counting // Prepare data source for active connection counting
dataSources.push(dataSource); dataSources.push(dataSource);
connectionCount[dataSource] = {}; connectionCount[dataSource] = {};
// If the provided connection group is already a
// GroupListItem, no need to create a new item
if (connectionGroup instanceof GroupListItem)
rootItem = connectionGroup;
// Create root item for current connection group // Create root item for current connection group
var rootItem = GroupListItem.fromConnectionGroup(dataSource, connectionGroup, else
$scope.isVisible(GroupListItem.Type.CONNECTION), rootItem = GroupListItem.fromConnectionGroup(dataSource, connectionGroup,
$scope.isVisible(GroupListItem.Type.SHARING_PROFILE), $scope.isVisible(GroupListItem.Type.CONNECTION),
countActiveConnections); $scope.isVisible(GroupListItem.Type.SHARING_PROFILE),
countActiveConnections);
// If root group is to be shown, add it as a root item // If root group is to be shown, add it as a root item
if ($scope.showRootGroup) if ($scope.showRootGroup)

View File

@@ -49,7 +49,7 @@ angular.module('groupList').directive('guacGroupListFilter', [function guacGroup
* identifier to corresponding root group. A subset of this map * identifier to corresponding root group. A subset of this map
* will be exposed as filteredConnectionGroups. * will be exposed as filteredConnectionGroups.
* *
* @type Object.<String, ConnectionGroup> * @type Object.<String, ConnectionGroup|GroupListItem>
*/ */
connectionGroups : '&', connectionGroups : '&',
@@ -81,6 +81,7 @@ angular.module('groupList').directive('guacGroupListFilter', [function guacGroup
// Required types // Required types
var ConnectionGroup = $injector.get('ConnectionGroup'); var ConnectionGroup = $injector.get('ConnectionGroup');
var FilterPattern = $injector.get('FilterPattern'); var FilterPattern = $injector.get('FilterPattern');
var GroupListItem = $injector.get('GroupListItem');
/** /**
* The pattern object to use when filtering connections. * The pattern object to use when filtering connections.
@@ -176,6 +177,10 @@ angular.module('groupList').directive('guacGroupListFilter', [function guacGroup
if (connectionGroups) { if (connectionGroups) {
angular.forEach(connectionGroups, function updateFilteredConnectionGroup(connectionGroup, dataSource) { angular.forEach(connectionGroups, function updateFilteredConnectionGroup(connectionGroup, dataSource) {
// Unwrap GroupListItem
if (connectionGroup instanceof GroupListItem)
connectionGroup = connectionGroup.wrappedItem;
// Flatten hierarchy of connection group // Flatten hierarchy of connection group
var filteredGroup = flattenConnectionGroup(connectionGroup); var filteredGroup = flattenConnectionGroup(connectionGroup);

View File

@@ -187,7 +187,7 @@ angular.module('groupList').factory('GroupListItem', ['ConnectionGroup', functio
dataSource : dataSource, dataSource : dataSource,
// Type information // Type information
expandable : includeSharingProfiles, expandable : includeSharingProfiles !== false,
type : GroupListItem.Type.CONNECTION, type : GroupListItem.Type.CONNECTION,
// Already-converted children // Already-converted children

View File

@@ -25,6 +25,7 @@ angular.module('manage').controller('manageUserController', ['$scope', '$injecto
// Required types // Required types
var ConnectionGroup = $injector.get('ConnectionGroup'); var ConnectionGroup = $injector.get('ConnectionGroup');
var GroupListItem = $injector.get('GroupListItem');
var PageDefinition = $injector.get('PageDefinition'); var PageDefinition = $injector.get('PageDefinition');
var PermissionFlagSet = $injector.get('PermissionFlagSet'); var PermissionFlagSet = $injector.get('PermissionFlagSet');
var PermissionSet = $injector.get('PermissionSet'); var PermissionSet = $injector.get('PermissionSet');
@@ -133,7 +134,7 @@ angular.module('manage').controller('manageUserController', ['$scope', '$injecto
* thost data sources. As only one data source is applicable to any one * thost data sources. As only one data source is applicable to any one
* user being edited/created, this will only contain a single key. * user being edited/created, this will only contain a single key.
* *
* @type Object.<String, ConnectionGroup> * @type Object.<String, GroupListItem>
*/ */
$scope.rootGroups = null; $scope.rootGroups = null;
@@ -607,6 +608,59 @@ angular.module('manage').controller('manageUserController', ['$scope', '$injecto
} }
/**
* Expands all items within the tree descending from the given
* GroupListItem which have at least one descendant for which explicit READ
* permission is granted. The expanded state of all other items is left
* untouched.
*
* @param {GroupListItem} item
* The GroupListItem which should be conditionally expanded depending
* on whether READ permission is granted for any of its descendants.
*
* @param {PemissionFlagSet} flags
* The set of permissions which should be used to determine whether the
* given item and its descendants are expanded.
*/
var expandReadable = function expandReadable(item, flags) {
// If the current item is expandable and has defined children,
// determine whether it should be expanded
if (item.expandable && item.children) {
angular.forEach(item.children, function expandReadableChild(child) {
// Determine whether the user has READ permission for the
// current child object
var readable = false;
switch (child.type) {
case GroupListItem.Type.CONNECTION:
readable = flags.connectionPermissions.READ[child.identifier];
break;
case GroupListItem.Type.CONNECTION_GROUP:
readable = flags.connectionGroupPermissions.READ[child.identifier];
break;
case GroupListItem.Type.SHARING_PROFILE:
readable = flags.sharingProfilePermissions.READ[child.identifier];
break;
}
// The parent should be expanded by default if the child is
// expanded by default OR the user has READ permission on the
// child
item.expanded |= expandReadable(child, flags) || readable;
});
}
return item.expanded;
};
// Retrieve all connections for which we have ADMINISTER permission // Retrieve all connections for which we have ADMINISTER permission
dataSourceService.apply( dataSourceService.apply(
connectionGroupService.getConnectionGroupTree, connectionGroupService.getConnectionGroupTree,
@@ -615,7 +669,13 @@ angular.module('manage').controller('manageUserController', ['$scope', '$injecto
[PermissionSet.ObjectPermissionType.ADMINISTER] [PermissionSet.ObjectPermissionType.ADMINISTER]
) )
.then(function connectionGroupReceived(rootGroups) { .then(function connectionGroupReceived(rootGroups) {
$scope.rootGroups = rootGroups;
// Convert all received ConnectionGroup objects into GroupListItems
$scope.rootGroups = {};
angular.forEach(rootGroups, function addGroupListItem(rootGroup, dataSource) {
$scope.rootGroups[dataSource] = GroupListItem.fromConnectionGroup(dataSource, rootGroup);
});
}); });
// Query the user's permissions for the current user // Query the user's permissions for the current user
@@ -628,6 +688,19 @@ angular.module('manage').controller('manageUserController', ['$scope', '$injecto
$scope.permissions = permissions; $scope.permissions = permissions;
}); });
// Update default expanded state whenever connection groups and associated
// permissions change
$scope.$watchGroup(['rootGroups', 'permissionFlags'], function updateDefaultExpandedStates() {
angular.forEach($scope.rootGroups, function updateExpandedStates(rootGroup) {
// Automatically expand all objects with any descendants for which
// the user has READ permission
if ($scope.permissionFlags)
expandReadable(rootGroup, $scope.permissionFlags);
});
});
/** /**
* Available system permission types, as translation string / internal * Available system permission types, as translation string / internal
* value pairs. * value pairs.