From c9a5163ab0284fe6bf9f55ae6e54c7c78c8cbcb3 Mon Sep 17 00:00:00 2001 From: Michael Abashian Date: Wed, 1 Feb 2017 13:07:03 -0500 Subject: [PATCH 1/4] Fixed permissions multi-select issues --- .../rbac-resource.controller.js | 4 +- .../rbac-user-team.controller.js | 2 +- .../rbac-multiselect/permissionsUsers.list.js | 6 -- awx/ui/client/src/lists/Users.js | 6 -- .../linkout/addUsers/addUsers.controller.js | 61 +++++++++++++++--- .../linkout/addUsers/addUsers.directive.js | 6 +- .../linkout/addUsers/addUsers.partial.html | 3 +- .../organizations-admins.controller.js | 9 +-- .../organizations-users.controller.js | 12 ++-- .../linkout/organizations-linkout.route.js | 62 ------------------- .../select-list-item.directive.js | 2 +- 11 files changed, 69 insertions(+), 104 deletions(-) diff --git a/awx/ui/client/src/access/add-rbac-resource/rbac-resource.controller.js b/awx/ui/client/src/access/add-rbac-resource/rbac-resource.controller.js index e40589a3f6..6e41696faa 100644 --- a/awx/ui/client/src/access/add-rbac-resource/rbac-resource.controller.js +++ b/awx/ui/client/src/access/add-rbac-resource/rbac-resource.controller.js @@ -62,13 +62,13 @@ export default ['$rootScope', '$scope', 'GetBasePath', 'Rest', '$q', 'Wait', 'Pr user.username; } - if (item.isSelected) { + if (value.isSelected) { if (item.type === 'user') { item.name = buildName(item); } scope.allSelected.push(item); } else { - scope.allSelected = _.remove(scope.allSelected, { id: item.id }); + _.remove(scope.allSelected, { id: item.id }); } }); diff --git a/awx/ui/client/src/access/add-rbac-user-team/rbac-user-team.controller.js b/awx/ui/client/src/access/add-rbac-user-team/rbac-user-team.controller.js index edbd5eaf6f..a97bd0218c 100644 --- a/awx/ui/client/src/access/add-rbac-user-team/rbac-user-team.controller.js +++ b/awx/ui/client/src/access/add-rbac-user-team/rbac-user-team.controller.js @@ -127,7 +127,7 @@ function(rootScope, scope, $state, i18n, CreateSelect2, GetBasePath, Rest, $q, W let resourceType = scope.currentTab(), item = value.value; - if (item.isSelected) { + if (value.isSelected) { scope.selected[resourceType][item.id] = item; scope.selected[resourceType][item.id].roles = []; aggregateKey(item, resourceType); diff --git a/awx/ui/client/src/access/rbac-multiselect/permissionsUsers.list.js b/awx/ui/client/src/access/rbac-multiselect/permissionsUsers.list.js index 9769df3506..39b083f06c 100644 --- a/awx/ui/client/src/access/rbac-multiselect/permissionsUsers.list.js +++ b/awx/ui/client/src/access/rbac-multiselect/permissionsUsers.list.js @@ -9,12 +9,6 @@ return { name: 'users', iterator: 'user', - defaultSearchParams: function(term){ - return {or__username__icontains: term, - or__first_name__icontains: term, - or__last_name__icontains: term - }; - }, title: false, listTitleBadge: false, multiSelect: true, diff --git a/awx/ui/client/src/lists/Users.js b/awx/ui/client/src/lists/Users.js index bfff119616..fb84286bfb 100644 --- a/awx/ui/client/src/lists/Users.js +++ b/awx/ui/client/src/lists/Users.js @@ -15,12 +15,6 @@ export default search: { order_by: 'username' }, - defaultSearchParams: function(term){ - return {or__username__icontains: term, - or__first_name__icontains: term, - or__last_name__icontains: term - }; - }, iterator: 'user', selectTitle: i18n._('Add Users'), editTitle: i18n._('Users'), diff --git a/awx/ui/client/src/organizations/linkout/addUsers/addUsers.controller.js b/awx/ui/client/src/organizations/linkout/addUsers/addUsers.controller.js index e576ac5fd2..0a59ddbaef 100644 --- a/awx/ui/client/src/organizations/linkout/addUsers/addUsers.controller.js +++ b/awx/ui/client/src/organizations/linkout/addUsers/addUsers.controller.js @@ -11,10 +11,10 @@ * Controller for handling permissions adding */ -export default ['$scope', '$rootScope', 'ProcessErrors', 'GetBasePath', -'SelectionInit', 'templateUrl', '$state', 'Rest', '$q', 'Wait', '$window', -function($scope, $rootScope, ProcessErrors, GetBasePath, - SelectionInit, templateUrl, $state, Rest, $q, Wait, $window) { +export default ['$scope', '$rootScope', 'ProcessErrors', 'GetBasePath', 'generateList', +'SelectionInit', 'templateUrl', '$state', 'Rest', '$q', 'Wait', '$window', 'QuerySet', 'UserList', +function($scope, $rootScope, ProcessErrors, GetBasePath, generateList, + SelectionInit, templateUrl, $state, Rest, $q, Wait, $window, qs, UserList) { $scope.$on("linkLists", function() { if ($state.current.name.split(".")[1] === "users") { @@ -26,16 +26,59 @@ function($scope, $rootScope, ProcessErrors, GetBasePath, init(); function init(){ - // search init - $scope.list = $scope.$parent.add_user_list; - $scope.add_user_dataset = $scope.$parent.add_user_dataset; - $scope.add_users = $scope.$parent.add_user_dataset.results; + $scope.add_user_default_params = { + order_by: 'username', + page_size: 5 + }; + + $scope.add_user_queryset = { + order_by: 'username', + page_size: 5 + }; + + let list = _.cloneDeep(UserList); + list.basePath = 'users'; + list.iterator = 'add_user'; + list.name = 'add_users'; + list.multiSelect = true; + list.fields.username.ngClick = 'linkoutUser(add_user.id)'; + delete list.actions; + delete list.fieldActions; + + // Fire off the initial search + qs.search(GetBasePath('users'), $scope.add_user_default_params) + .then(function(res) { + $scope.add_user_dataset = res.data; + $scope.add_users = $scope.add_user_dataset.results; + + let html = generateList.build({ + list: list, + mode: 'edit', + title: false + }); + + $scope.list = list; + + $scope.compileList(html); + + $scope.$watchCollection('add_users', function () { + if($scope.selectedItems) { + // Loop across the users and see if any of them should be "checked" + $scope.add_users.forEach(function(row, i) { + if (_.includes($scope.selectedItems, row.id)) { + $scope.add_users[i].isSelected = true; + } + }); + } + }); + + }); $scope.selectedItems = []; $scope.$on('selectedOrDeselected', function(e, value) { let item = value.value; - if (item.isSelected) { + if (value.isSelected) { $scope.selectedItems.push(item.id); } else { diff --git a/awx/ui/client/src/organizations/linkout/addUsers/addUsers.directive.js b/awx/ui/client/src/organizations/linkout/addUsers/addUsers.directive.js index f146149b13..65c721be17 100644 --- a/awx/ui/client/src/organizations/linkout/addUsers/addUsers.directive.js +++ b/awx/ui/client/src/organizations/linkout/addUsers/addUsers.directive.js @@ -7,7 +7,7 @@ /* jshint unused: vars */ import addUsers from './addUsers.controller'; export default - ['Wait', 'templateUrl', '$state', '$view', function(Wait, templateUrl, $state, $view) { + ['Wait', 'templateUrl', '$state', '$view', '$compile', function(Wait, templateUrl, $state, $view, $compile) { return { restrict: 'E', scope: { @@ -48,6 +48,10 @@ export default scope.closeModal(); }); + scope.compileList = function(html) { + $('#add-users-list').append($compile(html)(scope)); + }; + Wait('stop'); window.scrollTo(0,0); diff --git a/awx/ui/client/src/organizations/linkout/addUsers/addUsers.partial.html b/awx/ui/client/src/organizations/linkout/addUsers/addUsers.partial.html index a8a6cbbb81..b7e24e3940 100644 --- a/awx/ui/client/src/organizations/linkout/addUsers/addUsers.partial.html +++ b/awx/ui/client/src/organizations/linkout/addUsers/addUsers.partial.html @@ -15,8 +15,7 @@ -
-
+
-
+
-
+
From 80313779b28909b314c5a0daa1640ef243ef0115 Mon Sep 17 00:00:00 2001 From: Michael Abashian Date: Mon, 6 Feb 2017 16:53:14 -0500 Subject: [PATCH 4/4] Fixed bug where deleting search tags was not removing the equivalent state param for lists in modals. Also did some cleanup on pagination directive. --- .../shared/paginate/paginate.controller.js | 36 ++++++++----- .../src/shared/paginate/paginate.partial.html | 20 +++---- .../smart-search/smart-search.controller.js | 54 ++++++++++++------- 3 files changed, 70 insertions(+), 40 deletions(-) diff --git a/awx/ui/client/src/shared/paginate/paginate.controller.js b/awx/ui/client/src/shared/paginate/paginate.controller.js index a4f45b7d5a..e4dbcbd22c 100644 --- a/awx/ui/client/src/shared/paginate/paginate.controller.js +++ b/awx/ui/client/src/shared/paginate/paginate.controller.js @@ -16,9 +16,21 @@ export default ['$scope', '$stateParams', '$state', '$filter', 'GetBasePath', 'Q $scope.pageSize = pageSize; function init() { - $scope.pageRange = calcPageRange($scope.current(), $scope.last()); - $scope.dataRange = calcDataRange(); + + let updatePaginationVariables = function() { + $scope.current = calcCurrent(); + $scope.last = calcLast(); + $scope.pageRange = calcPageRange($scope.current, $scope.last); + $scope.dataRange = calcDataRange(); + }; + + updatePaginationVariables(); + + $scope.$watch('collection', function(){ + updatePaginationVariables(); + }); } + $scope.dataCount = function() { return $filter('number')($scope.dataset.count); }; @@ -52,22 +64,22 @@ export default ['$scope', '$stateParams', '$state', '$filter', 'GetBasePath', 'Q $scope.dataset = res.data; $scope.collection = res.data.results; }); - $scope.pageRange = calcPageRange($scope.current(), $scope.last()); + $scope.pageRange = calcPageRange($scope.current, $scope.last); $scope.dataRange = calcDataRange(); }; - $scope.current = function() { + function calcLast() { + return Math.ceil($scope.dataset.count / pageSize); + } + + function calcCurrent() { if($scope.querySet) { return parseInt($scope.querySet.page || '1'); } else { return parseInt($stateParams[`${$scope.iterator}_search`].page || '1'); } - }; - - $scope.last = function() { - return Math.ceil($scope.dataset.count / pageSize); - }; + } function calcPageRange(current, last) { let result = []; @@ -84,12 +96,12 @@ export default ['$scope', '$stateParams', '$state', '$filter', 'GetBasePath', 'Q } function calcDataRange() { - if ($scope.current() === 1 && $scope.dataset.count < parseInt(pageSize)) { + if ($scope.current === 1 && $scope.dataset.count < parseInt(pageSize)) { return `1 - ${$scope.dataset.count}`; - } else if ($scope.current() === 1) { + } else if ($scope.current === 1) { return `1 - ${pageSize}`; } else { - let floor = (($scope.current() - 1) * parseInt(pageSize)) + 1; + let floor = (($scope.current - 1) * parseInt(pageSize)) + 1; let ceil = floor + parseInt(pageSize) < $scope.dataset.count ? floor + parseInt(pageSize) : $scope.dataset.count; return `${floor} - ${ceil}`; } diff --git a/awx/ui/client/src/shared/paginate/paginate.partial.html b/awx/ui/client/src/shared/paginate/paginate.partial.html index b00cc97fa1..8001e72da4 100644 --- a/awx/ui/client/src/shared/paginate/paginate.partial.html +++ b/awx/ui/client/src/shared/paginate/paginate.partial.html @@ -2,37 +2,37 @@
Page - {{current()}} of - {{last()}} + {{current}} of + {{last}}
diff --git a/awx/ui/client/src/shared/smart-search/smart-search.controller.js b/awx/ui/client/src/shared/smart-search/smart-search.controller.js index 22a91ec61a..6c10c1d752 100644 --- a/awx/ui/client/src/shared/smart-search/smart-search.controller.js +++ b/awx/ui/client/src/shared/smart-search/smart-search.controller.js @@ -148,9 +148,25 @@ export default ['$stateParams', '$scope', '$state', 'QuerySet', 'GetBasePath', ' // remove tag, merge new queryset, $state.go $scope.remove = function(index) { - let tagToRemove = $scope.searchTags.splice(index, 1)[0]; - let termParts = SmartSearchService.splitTermIntoParts(tagToRemove); - let removed; + let tagToRemove = $scope.searchTags.splice(index, 1)[0], + termParts = SmartSearchService.splitTermIntoParts(tagToRemove), + removed; + + let removeFromQuerySet = function(set) { + _.each(removed, (value, key) => { + if (Array.isArray(set[key])){ + _.remove(set[key], (item) => item === value); + // If the array is now empty, remove that key + if(set[key].length === 0) { + delete set[key]; + } + } + else { + delete set[key]; + } + }); + }; + if (termParts.length === 1) { removed = setDefaults(tagToRemove); } @@ -169,21 +185,16 @@ export default ['$stateParams', '$scope', '$state', 'QuerySet', 'GetBasePath', ' } removed = qs.encodeParam(encodeParams); } - _.each(removed, (value, key) => { - if (Array.isArray(queryset[key])){ - _.remove(queryset[key], (item) => item === value); - // If the array is now empty, remove that key - if(queryset[key].length === 0) { - delete queryset[key]; - } - } - else { - delete queryset[key]; - } - }); + removeFromQuerySet(queryset); if(!$scope.querySet) { $state.go('.', { - [$scope.iterator + '_search']: queryset }, {notify: false}); + [$scope.iterator + '_search']: queryset }, {notify: false}).then(function(){ + // ISSUE: for some reason deleting a tag from a list in a modal does not + // remove the param from $stateParams. Here we'll manually check to make sure + // that that happened and remove it if it didn't. + + removeFromQuerySet($stateParams[`${$scope.iterator}_search`]); + }); } qs.search(path, queryset).then((res) => { if($scope.querySet) { @@ -243,7 +254,6 @@ export default ['$stateParams', '$scope', '$state', 'QuerySet', 'GetBasePath', ' } }); - params.page = '1'; queryset = _.merge(queryset, params, (objectValue, sourceValue, key, object) => { if (object[key] && object[key] !== sourceValue){ if(_.isArray(object[key])) { @@ -262,12 +272,20 @@ export default ['$stateParams', '$scope', '$state', 'QuerySet', 'GetBasePath', ' return undefined; } }); + + // Go back to the first page after a new search + delete queryset.page; + // https://ui-router.github.io/docs/latest/interfaces/params.paramdeclaration.html#dynamic // This transition will not reload controllers/resolves/views // but will register new $stateParams[$scope.iterator + '_search'] terms if(!$scope.querySet) { $state.go('.', { - [$scope.iterator + '_search']: queryset }, {notify: false}); + [$scope.iterator + '_search']: queryset }, {notify: false}).then(function(){ + // ISSUE: same as above in $scope.remove. For some reason deleting the page + // from the queryset works for all lists except lists in modals. + delete $stateParams[$scope.iterator + '_search'].page; + }); } qs.search(path, queryset).then((res) => { if($scope.querySet) {