mirror of
				https://github.com/gyurix1968/guacamole-client.git
				synced 2025-10-31 09:03:21 +00:00 
			
		
		
		
	Merge 1.0.0 changes back to master.
This commit is contained in:
		| @@ -30,9 +30,10 @@ angular.module('groupList').directive('guacGroupListFilter', [function guacGroup | ||||
|  | ||||
|             /** | ||||
|              * The property to which a subset of the provided map of connection | ||||
|              * groups will be assigned. | ||||
|              * groups will be assigned. The type of each item within the | ||||
|              * original map is preserved within the filtered map. | ||||
|              * | ||||
|              * @type Array | ||||
|              * @type Object.<String, ConnectionGroup|GroupListItem> | ||||
|              */ | ||||
|             filteredConnectionGroups : '=', | ||||
|  | ||||
| @@ -155,6 +156,94 @@ angular.module('groupList').directive('guacGroupListFilter', [function guacGroup | ||||
|  | ||||
|             }; | ||||
|  | ||||
|             /** | ||||
|              * Flattens the connection group hierarchy of the given | ||||
|              * GroupListItem such that all descendants are copied as immediate | ||||
|              * children. The hierarchy of nested items is otherwise completely | ||||
|              * preserved. A connection or connection group nested two or more | ||||
|              * levels deep within the hierarchy will thus appear within the | ||||
|              * returned item in two places: in its original location AND as an | ||||
|              * immediate child. | ||||
|              * | ||||
|              * @param {GroupListItem} item | ||||
|              *     The GroupListItem whose descendents should be copied as | ||||
|              *     first-level children. | ||||
|              * | ||||
|              * @returns {GroupListItem} | ||||
|              *     A new GroupListItem completely identical to the provided | ||||
|              *     item, except that absolutely all descendents have been | ||||
|              *     copied into the first level of children. | ||||
|              */ | ||||
|             var flattenGroupListItem = function flattenGroupListItem(item) { | ||||
|  | ||||
|                 // Replace item with shallow copy | ||||
|                 item = new GroupListItem(item); | ||||
|  | ||||
|                 // Ensure children are defined and independent copies | ||||
|                 item.children = angular.copy(item.children) || []; | ||||
|  | ||||
|                 // Flatten all children to the top-level group | ||||
|                 angular.forEach(item.children, function flattenChild(child) { | ||||
|                     if (child.type === GroupListItem.Type.CONNECTION_GROUP) { | ||||
|  | ||||
|                         var flattenedChild = flattenConnectionGroup(child); | ||||
|  | ||||
|                         // Merge all children | ||||
|                         Array.prototype.push.apply( | ||||
|                             item.children, | ||||
|                             flattenedChild.children | ||||
|                         ); | ||||
|  | ||||
|                     } | ||||
|                 }); | ||||
|  | ||||
|                 return item; | ||||
|  | ||||
|             }; | ||||
|  | ||||
|             /** | ||||
|              * Replaces the set of children within the given GroupListItem such | ||||
|              * that only children which match the filter predicate for the | ||||
|              * current search string are present. | ||||
|              * | ||||
|              * @param {GroupListItem} item | ||||
|              *     The GroupListItem whose children should be filtered. | ||||
|              */ | ||||
|             var filterGroupListItem = function filterGroupListItem(item) { | ||||
|                 item.children = item.children.filter(function applyFilterPattern(child) { | ||||
|  | ||||
|                     // Filter connections and connection groups by | ||||
|                     // given pattern | ||||
|                     switch (child.type) { | ||||
|  | ||||
|                         case GroupListItem.Type.CONNECTION: | ||||
|                             return connectionFilterPattern.predicate(child.wrappedItem); | ||||
|  | ||||
|                         case GroupListItem.Type.CONNECTION_GROUP: | ||||
|                             return connectionGroupFilterPattern.predicate(child.wrappedItem); | ||||
|  | ||||
|                     } | ||||
|  | ||||
|                     // Include all other children | ||||
|                     return true; | ||||
|  | ||||
|                 }); | ||||
|             }; | ||||
|  | ||||
|             /** | ||||
|              * Replaces the set of child connections and connection groups | ||||
|              * within the given connection group such that only children which | ||||
|              * match the filter predicate for the current search string are | ||||
|              * present. | ||||
|              * | ||||
|              * @param {ConnectionGroup} connectionGroup | ||||
|              *     The connection group whose children should be filtered. | ||||
|              */ | ||||
|             var filterConnectionGroup = function filterConnectionGroup(connectionGroup) { | ||||
|                 connectionGroup.childConnections = connectionGroup.childConnections.filter(connectionFilterPattern.predicate); | ||||
|                 connectionGroup.childConnectionGroups = connectionGroup.childConnectionGroups.filter(connectionGroupFilterPattern.predicate); | ||||
|             }; | ||||
|  | ||||
|             /** | ||||
|              * Applies the current filter predicate, filtering all provided | ||||
|              * connection groups and storing the result in | ||||
| @@ -177,16 +266,17 @@ angular.module('groupList').directive('guacGroupListFilter', [function guacGroup | ||||
|                 if (connectionGroups) { | ||||
|                     angular.forEach(connectionGroups, function updateFilteredConnectionGroup(connectionGroup, dataSource) { | ||||
|  | ||||
|                         // Unwrap GroupListItem | ||||
|                         if (connectionGroup instanceof GroupListItem) | ||||
|                             connectionGroup = connectionGroup.wrappedItem; | ||||
|                         var filteredGroup; | ||||
|  | ||||
|                         // Flatten hierarchy of connection group | ||||
|                         var filteredGroup = flattenConnectionGroup(connectionGroup); | ||||
|  | ||||
|                         // Filter all direct children | ||||
|                         filteredGroup.childConnections = filteredGroup.childConnections.filter(connectionFilterPattern.predicate); | ||||
|                         filteredGroup.childConnectionGroups = filteredGroup.childConnectionGroups.filter(connectionGroupFilterPattern.predicate); | ||||
|                         // Flatten and filter depending on type | ||||
|                         if (connectionGroup instanceof GroupListItem) { | ||||
|                             filteredGroup = flattenGroupListItem(connectionGroup); | ||||
|                             filterGroupListItem(filteredGroup); | ||||
|                         } | ||||
|                         else { | ||||
|                             filteredGroup = flattenConnectionGroup(connectionGroup); | ||||
|                             filterConnectionGroup(filteredGroup); | ||||
|                         } | ||||
|  | ||||
|                         // Store now-filtered root | ||||
|                         $scope.filteredConnectionGroups[dataSource] = filteredGroup; | ||||
|   | ||||
| @@ -74,6 +74,10 @@ h2 { | ||||
|  | ||||
| } | ||||
|  | ||||
| .header.tabbed { | ||||
|     margin-bottom: 0; | ||||
| } | ||||
|  | ||||
| .header ~ * .header, | ||||
| .header ~ .header { | ||||
|     margin-top: 1em; | ||||
|   | ||||
| @@ -84,6 +84,67 @@ angular.module('manage').directive('connectionPermissionEditor', ['$injector', | ||||
|  | ||||
|     directive.controller = ['$scope', function connectionPermissionEditorController($scope) { | ||||
|  | ||||
|         /** | ||||
|          * A map of data source identifiers to all root connection groups | ||||
|          * within those data sources, regardless of the permissions granted for | ||||
|          * the items within those groups. As only one data source is applicable | ||||
|          * to any particular permission set being edited/created, this will only | ||||
|          * contain a single key. If the data necessary to produce this map has | ||||
|          * not yet been loaded, this will be null. | ||||
|          * | ||||
|          * @type Object.<String, GroupListItem> | ||||
|          */ | ||||
|         var allRootGroups = null; | ||||
|  | ||||
|         /** | ||||
|          * A map of data source identifiers to the root connection groups within | ||||
|          * those data sources, excluding all items which are not explicitly | ||||
|          * readable according to $scope.permissionFlags. As only one data | ||||
|          * source is applicable to any particular permission set being | ||||
|          * edited/created, this will only contain a single key. If the data | ||||
|          * necessary to produce this map has not yet been loaded, this will be | ||||
|          * null. | ||||
|          * | ||||
|          * @type Object.<String, GroupListItem> | ||||
|          */ | ||||
|         var readableRootGroups = null; | ||||
|  | ||||
|         /** | ||||
|          * The name of the tab within the connection permission editor which | ||||
|          * displays currently selected (readable) connections only. | ||||
|          * | ||||
|          * @constant | ||||
|          * @type String | ||||
|          */ | ||||
|         var CURRENT_CONNECTIONS = 'CURRENT_CONNECTIONS'; | ||||
|  | ||||
|         /** | ||||
|          * The name of the tab within the connection permission editor which | ||||
|          * displays all connections, regardless of whether they are readable. | ||||
|          * | ||||
|          * @constant | ||||
|          * @type String | ||||
|          */ | ||||
|         var ALL_CONNECTIONS = 'ALL_CONNECTIONS'; | ||||
|  | ||||
|         /** | ||||
|          * The names of all tabs which should be available within the | ||||
|          * connection permission editor, in display order. | ||||
|          * | ||||
|          * @type String[] | ||||
|          */ | ||||
|         $scope.tabs = [ | ||||
|             CURRENT_CONNECTIONS, | ||||
|             ALL_CONNECTIONS | ||||
|         ]; | ||||
|  | ||||
|         /** | ||||
|          * The name of the currently selected tab. | ||||
|          * | ||||
|          * @type String | ||||
|          */ | ||||
|         $scope.currentTab = ALL_CONNECTIONS; | ||||
|  | ||||
|         /** | ||||
|          * Array of all connection properties that are filterable. | ||||
|          * | ||||
| @@ -104,31 +165,53 @@ angular.module('manage').directive('connectionPermissionEditor', ['$injector', | ||||
|         ]; | ||||
|  | ||||
|         /** | ||||
|          * A map of data source identifiers to the root connection groups within | ||||
|          * thost data sources. As only one data source is applicable to any | ||||
|          * particular permission set being edited/created, this will only | ||||
|          * contain a single key. | ||||
|          * Returns the root groups which should be displayed within the | ||||
|          * connection permission editor. | ||||
|          * | ||||
|          * @type Object.<String, GroupListItem> | ||||
|          * @returns {Object.<String, GroupListItem>} | ||||
|          *     The root groups which should be displayed within the connection | ||||
|          *     permission editor as a map of data source identifiers to the | ||||
|          *     root connection groups within those data sources. | ||||
|          */ | ||||
|         $scope.rootGroups = null; | ||||
|         $scope.getRootGroups = function getRootGroups() { | ||||
|             return $scope.currentTab === CURRENT_CONNECTIONS ? readableRootGroups : allRootGroups; | ||||
|         }; | ||||
|  | ||||
|         // Retrieve all connections for which we have ADMINISTER permission | ||||
|         dataSourceService.apply( | ||||
|             connectionGroupService.getConnectionGroupTree, | ||||
|             [$scope.dataSource], | ||||
|             ConnectionGroup.ROOT_IDENTIFIER, | ||||
|             [PermissionSet.ObjectPermissionType.ADMINISTER] | ||||
|         ) | ||||
|         .then(function connectionGroupReceived(rootGroups) { | ||||
|         /** | ||||
|          * Returns whether the given PermissionFlagSet declares explicit READ | ||||
|          * permission for the connection, connection group, or sharing profile | ||||
|          * represented by the given GroupListItem. | ||||
|          * | ||||
|          * @param {GroupListItem} item | ||||
|          *     The GroupListItem which should be checked against the | ||||
|          *     PermissionFlagSet. | ||||
|          * | ||||
|          * @param {PemissionFlagSet} flags | ||||
|          *     The set of permissions which should be used to determine whether | ||||
|          *     explicit READ permission is granted for the given item. | ||||
|          * | ||||
|          * @returns {Boolean} | ||||
|          *     true if explicit READ permission is granted for the given item | ||||
|          *     according to the given permission set, false otherwise. | ||||
|          */ | ||||
|         var isReadable = function isReadable(item, flags) { | ||||
|  | ||||
|             // Convert all received ConnectionGroup objects into GroupListItems | ||||
|             $scope.rootGroups = {}; | ||||
|             angular.forEach(rootGroups, function addGroupListItem(rootGroup, dataSource) { | ||||
|                 $scope.rootGroups[dataSource] = GroupListItem.fromConnectionGroup(dataSource, rootGroup); | ||||
|             }); | ||||
|             switch (item.type) { | ||||
|  | ||||
|         }, requestService.WARN); | ||||
|                 case GroupListItem.Type.CONNECTION: | ||||
|                     return flags.connectionPermissions.READ[item.identifier]; | ||||
|  | ||||
|                 case GroupListItem.Type.CONNECTION_GROUP: | ||||
|                     return flags.connectionGroupPermissions.READ[item.identifier]; | ||||
|  | ||||
|                 case GroupListItem.Type.SHARING_PROFILE: | ||||
|                     return flags.sharingProfilePermissions.READ[item.identifier]; | ||||
|  | ||||
|             } | ||||
|  | ||||
|             return false; | ||||
|  | ||||
|         }; | ||||
|  | ||||
|         /** | ||||
|          * Expands all items within the tree descending from the given | ||||
| @@ -144,6 +227,9 @@ angular.module('manage').directive('connectionPermissionEditor', ['$injector', | ||||
|          * @param {PemissionFlagSet} flags | ||||
|          *     The set of permissions which should be used to determine whether | ||||
|          *     the given item and its descendants are expanded. | ||||
|          * | ||||
|          * @returns {Boolean} | ||||
|          *     true if the given item has been expanded, false otherwise. | ||||
|          */ | ||||
|         var expandReadable = function expandReadable(item, flags) { | ||||
|  | ||||
| @@ -152,29 +238,10 @@ angular.module('manage').directive('connectionPermissionEditor', ['$injector', | ||||
|             if (item.expandable && item.children) { | ||||
|                 angular.forEach(item.children, function expandReadableChild(child) { | ||||
|  | ||||
|                     // Determine whether the permission set contains 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 permission set contains READ | ||||
|                     // permission on the child | ||||
|                     item.expanded |= expandReadable(child, flags) || readable; | ||||
|                     item.expanded |= expandReadable(child, flags) || isReadable(child, flags); | ||||
|  | ||||
|                 }); | ||||
|             } | ||||
| @@ -183,22 +250,105 @@ angular.module('manage').directive('connectionPermissionEditor', ['$injector', | ||||
|  | ||||
|         }; | ||||
|  | ||||
|         // Update default expanded state whenever connection groups and | ||||
|         // associated permissions change | ||||
|         $scope.$watchGroup(['rootGroups', 'permissionFlags'], function updateDefaultExpandedStates() { | ||||
|         /** | ||||
|          * Creates a deep copy of all items within the tree descending from the | ||||
|          * given GroupListItem which have at least one descendant for which | ||||
|          * explicit READ permission is granted. Items which lack explicit READ | ||||
|          * permission and which have no descendants having explicit READ | ||||
|          * permission are omitted from the copy. | ||||
|          * | ||||
|          * @param {GroupListItem} item | ||||
|          *     The GroupListItem which should be conditionally copied | ||||
|          *     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 or any of its descendants are copied. | ||||
|          * | ||||
|          * @returns {GroupListItem} | ||||
|          *     A new GroupListItem containing a deep copy of the given item, | ||||
|          *     omitting any items which lack explicit READ permission and whose | ||||
|          *     descendants also lack explicit READ permission, or null if even | ||||
|          *     the given item would not be copied. | ||||
|          */ | ||||
|         var copyReadable = function copyReadable(item, flags) { | ||||
|  | ||||
|             if (!$scope.rootGroups || !$scope.permissionFlags) | ||||
|                 return; | ||||
|             // Produce initial shallow copy of given item | ||||
|             item = new GroupListItem(item); | ||||
|  | ||||
|             angular.forEach($scope.rootGroups, function updateExpandedStates(rootGroup) { | ||||
|             // Replace children array with an array containing only readable | ||||
|             // children (or children with at least one readable descendant), | ||||
|             // flagging the current item for copying if any such children exist | ||||
|             if (item.children) { | ||||
|  | ||||
|                 // Automatically expand all objects with any descendants for | ||||
|                 // which the permission set contains READ permission | ||||
|                 expandReadable(rootGroup, $scope.permissionFlags); | ||||
|                 var children = []; | ||||
|                 angular.forEach(item.children, function copyReadableChildren(child) { | ||||
|  | ||||
|                     // Reduce child tree to only explicitly readable items and | ||||
|                     // their parents | ||||
|                     child = copyReadable(child, flags); | ||||
|  | ||||
|                     // Include child only if they are explicitly readable, they | ||||
|                     // have explicitly readable descendants, or their parent is | ||||
|                     // readable (and thus all children are relevant) | ||||
|                     if ((child.children && child.children.length) | ||||
|                             || isReadable(item, flags) | ||||
|                             || isReadable(child, flags)) | ||||
|                         children.push(child); | ||||
|  | ||||
|                 }); | ||||
|  | ||||
|                 item.children = children; | ||||
|  | ||||
|             } | ||||
|  | ||||
|             return item; | ||||
|  | ||||
|         }; | ||||
|  | ||||
|         // Retrieve all connections for which we have ADMINISTER permission | ||||
|         dataSourceService.apply( | ||||
|             connectionGroupService.getConnectionGroupTree, | ||||
|             [$scope.dataSource], | ||||
|             ConnectionGroup.ROOT_IDENTIFIER, | ||||
|             [PermissionSet.ObjectPermissionType.ADMINISTER] | ||||
|         ) | ||||
|         .then(function connectionGroupReceived(rootGroups) { | ||||
|  | ||||
|             // Update default expanded state and the all / readable-only views | ||||
|             // when associated permissions change | ||||
|             $scope.$watchGroup(['permissionFlags'], function updateDefaultExpandedStates() { | ||||
|  | ||||
|                 if (!$scope.permissionFlags) | ||||
|                     return; | ||||
|  | ||||
|                 allRootGroups = {}; | ||||
|                 readableRootGroups = {}; | ||||
|  | ||||
|                 angular.forEach(rootGroups, function addGroupListItem(rootGroup, dataSource) { | ||||
|  | ||||
|                     // Convert all received ConnectionGroup objects into GroupListItems | ||||
|                     var item = GroupListItem.fromConnectionGroup(dataSource, rootGroup); | ||||
|                     allRootGroups[dataSource] = item; | ||||
|  | ||||
|                     // Automatically expand all objects with any descendants for | ||||
|                     // which the permission set contains READ permission | ||||
|                     expandReadable(item, $scope.permissionFlags); | ||||
|  | ||||
|                     // Create a duplicate view which contains only readable | ||||
|                     // items | ||||
|                     readableRootGroups[dataSource] = copyReadable(item, $scope.permissionFlags); | ||||
|  | ||||
|                 }); | ||||
|  | ||||
|                 // Display only readable connections by default if at least one | ||||
|                 // readable connection exists | ||||
|                 $scope.currentTab = !!readableRootGroups[$scope.dataSource].children.length ? CURRENT_CONNECTIONS : ALL_CONNECTIONS; | ||||
|  | ||||
|             }); | ||||
|  | ||||
|         }); | ||||
|         }, requestService.WARN); | ||||
|  | ||||
|         /** | ||||
|          * Updates the permissionsAdded and permissionsRemoved permission sets | ||||
|   | ||||
| @@ -17,10 +17,6 @@ | ||||
|  * under the License. | ||||
|  */ | ||||
|  | ||||
| .manage-user .username.header { | ||||
|     margin-bottom: 0; | ||||
| } | ||||
|  | ||||
| .manage-user .page-tabs .page-list li.read-only a[href], | ||||
| .manage-user .page-tabs .page-list li.unlinked  a[href], | ||||
| .manage-user .page-tabs .page-list li.linked    a[href] { | ||||
|   | ||||
| @@ -1,12 +1,13 @@ | ||||
| <div class="connection-permissions"> | ||||
|     <div class="header"> | ||||
|     <div class="header tabbed"> | ||||
|         <h2>{{'MANAGE_USER.SECTION_HEADER_CONNECTIONS' | translate}}</h2> | ||||
|         <guac-group-list-filter connection-groups="rootGroups" | ||||
|         <guac-group-list-filter connection-groups="getRootGroups()" | ||||
|             filtered-connection-groups="filteredRootGroups" | ||||
|             placeholder="'MANAGE_USER.FIELD_PLACEHOLDER_FILTER' | translate" | ||||
|             connection-properties="filteredConnectionProperties" | ||||
|             connection-group-properties="filteredConnectionGroupProperties"></guac-group-list-filter> | ||||
|     </div> | ||||
|     <guac-section-tabs namespace="MANAGE_USER" current="currentTab" tabs="tabs"></guac-section-tabs> | ||||
|     <div class="section"> | ||||
|         <guac-group-list | ||||
|             context="groupListContext" | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
| <div class="manage-user view" ng-class="{loading: !isLoaded()}"> | ||||
|  | ||||
|     <!-- User header and data source tabs --> | ||||
|     <div class="username header"> | ||||
|     <div class="header tabbed"> | ||||
|         <h2>{{'MANAGE_USER.SECTION_HEADER_EDIT_USER' | translate}}</h2> | ||||
|         <guac-user-menu></guac-user-menu> | ||||
|     </div> | ||||
|   | ||||
| @@ -0,0 +1,143 @@ | ||||
| /* | ||||
|  * 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. | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * Directive which displays a set of tabs dividing a section of a page into | ||||
|  * logical subsections or views. The currently selected tab is communicated | ||||
|  * through assignment to the variable bound to the <code>current</code> | ||||
|  * attribute. No navigation occurs as a result of selecting a tab. | ||||
|  */ | ||||
| angular.module('navigation').directive('guacSectionTabs', ['$injector', | ||||
|     function guacSectionTabs($injector) { | ||||
|  | ||||
|     // Required services | ||||
|     var translationStringService = $injector.get('translationStringService'); | ||||
|  | ||||
|     var directive = { | ||||
|  | ||||
|         restrict    : 'E', | ||||
|         replace     : true, | ||||
|         templateUrl : 'app/navigation/templates/guacSectionTabs.html', | ||||
|  | ||||
|         scope : { | ||||
|  | ||||
|             /** | ||||
|              * The translation namespace to use when producing translation | ||||
|              * strings for each tab. Tab translation strings will be of the | ||||
|              * form: | ||||
|              * | ||||
|              * <code>NAMESPACE.SECTION_HEADER_NAME<code> | ||||
|              * | ||||
|              * where <code>NAMESPACE</code> is the namespace provided to this | ||||
|              * attribute and <code>NAME</code> is one of the names within the | ||||
|              * array provided to the <code>tabs</code> attribute and | ||||
|              * transformed via translationStringService.canonicalize(). | ||||
|              */ | ||||
|             namespace : '@', | ||||
|  | ||||
|             /** | ||||
|              * The name of the currently selected tab. This name MUST be one of | ||||
|              * the names present in the array given via the <code>tabs</code> | ||||
|              * attribute. This directive will not automatically choose an | ||||
|              * initially selected tab, and a default value should be manually | ||||
|              * assigned to <code>current</code> to ensure a tab is initially | ||||
|              * selected. | ||||
|              * | ||||
|              * @type String | ||||
|              */ | ||||
|             current : '=', | ||||
|  | ||||
|             /** | ||||
|              * The unique names of all tabs which should be made available, in | ||||
|              * display order. These names will be assigned to the variable | ||||
|              * bound to the <code>current</code> attribute when the current | ||||
|              * tab changes. | ||||
|              * | ||||
|              * @type String[] | ||||
|              */ | ||||
|             tabs : '=' | ||||
|  | ||||
|         } | ||||
|  | ||||
|     }; | ||||
|  | ||||
|     directive.controller = ['$scope', function dataSourceTabsController($scope) { | ||||
|  | ||||
|         /** | ||||
|          * Produces the translation string for the section header representing | ||||
|          * the tab having the given name. The translation string will be of the | ||||
|          * form: | ||||
|          * | ||||
|          * <code>NAMESPACE.SECTION_HEADER_NAME<code> | ||||
|          * | ||||
|          * where <code>NAMESPACE</code> is the namespace provided to the | ||||
|          * directive and <code>NAME</code> is the given name transformed | ||||
|          * via translationStringService.canonicalize(). | ||||
|          * | ||||
|          * @param {String} name | ||||
|          *     The name of the tab. | ||||
|          * | ||||
|          * @returns {String} | ||||
|          *     The translation string which produces the translated header | ||||
|          *     of the tab having the given name. | ||||
|          */ | ||||
|         $scope.getSectionHeader = function getSectionHeader(name) { | ||||
|  | ||||
|             // If no name, then no header | ||||
|             if (!name) | ||||
|                 return ''; | ||||
|  | ||||
|             return translationStringService.canonicalize($scope.namespace || 'MISSING_NAMESPACE') | ||||
|                     + '.SECTION_HEADER_' + translationStringService.canonicalize(name); | ||||
|  | ||||
|         }; | ||||
|  | ||||
|         /** | ||||
|          * Selects the tab having the given name. The name of the currently | ||||
|          * selected tab will be communicated outside the directive through | ||||
|          * $scope.current. | ||||
|          * | ||||
|          * @param {String} name | ||||
|          *     The name of the tab to select. | ||||
|          */ | ||||
|         $scope.selectTab = function selectTab(name) { | ||||
|             $scope.current = name; | ||||
|         }; | ||||
|  | ||||
|         /** | ||||
|          * Returns whether the tab having the given name is currently | ||||
|          * selected. A tab is currently selected if its name is stored within | ||||
|          * $scope.current, as assigned externally or by selectTab(). | ||||
|          * | ||||
|          * @param {String} name | ||||
|          *     The name of the tab to test. | ||||
|          * | ||||
|          * @returns {Boolean} | ||||
|          *     true if the tab having the given name is currently selected, | ||||
|          *     false otherwise. | ||||
|          */ | ||||
|         $scope.isSelected = function isSelected(name) { | ||||
|             return $scope.current === name; | ||||
|         }; | ||||
|  | ||||
|     }]; | ||||
|  | ||||
|     return directive; | ||||
|  | ||||
| }]); | ||||
| @@ -17,23 +17,27 @@ | ||||
|  * under the License. | ||||
|  */ | ||||
| 
 | ||||
| .page-tabs .page-list ul { | ||||
| .page-tabs .page-list ul, | ||||
| .section-tabs ul { | ||||
|     margin: 0; | ||||
|     padding: 0; | ||||
|     background: rgba(0, 0, 0, 0.0125); | ||||
|     border-bottom: 1px solid rgba(0, 0, 0, 0.05); | ||||
| } | ||||
| 
 | ||||
| .page-tabs .page-list ul + ul { | ||||
| .page-tabs .page-list ul + ul, | ||||
| .section-tabs ul + ul { | ||||
|     font-size: 0.75em; | ||||
| } | ||||
| 
 | ||||
| .page-tabs .page-list li { | ||||
| .page-tabs .page-list li, | ||||
| .section-tabs li { | ||||
|     display: inline-block; | ||||
|     list-style: none; | ||||
| } | ||||
| 
 | ||||
| .page-tabs .page-list li a[href] { | ||||
| .page-tabs .page-list li a[href], | ||||
| .section-tabs li a { | ||||
|     display: block; | ||||
|     color: black; | ||||
|     text-decoration: none; | ||||
| @@ -44,12 +48,16 @@ | ||||
|     color: black; | ||||
| } | ||||
| 
 | ||||
| .page-tabs .page-list li a[href]:hover { | ||||
| .page-tabs .page-list li a[href]:hover, | ||||
| .section-tabs li a:hover { | ||||
|     background-color: #CDA; | ||||
|     cursor: pointer; | ||||
| } | ||||
| 
 | ||||
| .page-tabs .page-list li a[href].current, | ||||
| .page-tabs .page-list li a[href].current:hover { | ||||
| .page-tabs .page-list li a[href].current:hover, | ||||
| .section-tabs li a.current, | ||||
| .section-tabs li a.current:hover { | ||||
|     background: rgba(0,0,0,0.3); | ||||
|     cursor: default; | ||||
| } | ||||
| @@ -0,0 +1,10 @@ | ||||
| <div class="section-tabs" ng-show="tabs.length"> | ||||
|     <ul> | ||||
|         <li ng-repeat="name in tabs"> | ||||
|             <a ng-click="selectTab(name)" | ||||
|                ng-class="{ current : isSelected(name) }"> | ||||
|                 {{ getSectionHeader(name) | translate }} | ||||
|             </a> | ||||
|         </li> | ||||
|     </ul> | ||||
| </div> | ||||
| @@ -17,10 +17,6 @@ | ||||
|  * under the License. | ||||
|  */ | ||||
|  | ||||
| .settings .header { | ||||
|     margin-bottom: 0; | ||||
| } | ||||
|  | ||||
| .settings table.properties th { | ||||
|     text-align: left; | ||||
|     font-weight: normal; | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
|  | ||||
| <div class="view"> | ||||
|  | ||||
|     <div class="header"> | ||||
|     <div class="header tabbed"> | ||||
|         <h2>{{'SETTINGS.SECTION_HEADER_SETTINGS' | translate}}</h2> | ||||
|         <guac-user-menu></guac-user-menu> | ||||
|     </div> | ||||
|   | ||||
| @@ -303,9 +303,11 @@ | ||||
|  | ||||
|         "INFO_READ_ONLY" : "Sorry, but this user account cannot be edited.", | ||||
|  | ||||
|         "SECTION_HEADER_CONNECTIONS" : "Connections", | ||||
|         "SECTION_HEADER_EDIT_USER"   : "Edit User", | ||||
|         "SECTION_HEADER_PERMISSIONS" : "Permissions", | ||||
|         "SECTION_HEADER_ALL_CONNECTIONS"     : "All Connections", | ||||
|         "SECTION_HEADER_CONNECTIONS"         : "Connections", | ||||
|         "SECTION_HEADER_CURRENT_CONNECTIONS" : "Current Connections", | ||||
|         "SECTION_HEADER_EDIT_USER"           : "Edit User", | ||||
|         "SECTION_HEADER_PERMISSIONS"         : "Permissions", | ||||
|  | ||||
|         "TEXT_CONFIRM_DELETE" : "Users cannot be restored after they have been deleted. Are you sure you want to delete this user?" | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user