From e3d0309089944ebe06ee16f832ff51763fd0c38d Mon Sep 17 00:00:00 2001 From: John Mitchell Date: Wed, 27 Apr 2016 11:27:45 -0400 Subject: [PATCH 1/3] fixed related lists for users and teams edit --- awx/ui/client/src/controllers/Teams.js | 17 +- awx/ui/client/src/controllers/Users.js | 34 +++- awx/ui/client/src/forms/Teams.js | 175 ++++-------------- awx/ui/client/src/forms/Users.js | 103 ++++------- .../src/search/getSearchHtml.service.js | 1 + awx/ui/client/src/shared/form-generator.js | 48 +++-- awx/ui/client/src/shared/generator-helpers.js | 6 +- 7 files changed, 154 insertions(+), 230 deletions(-) diff --git a/awx/ui/client/src/controllers/Teams.js b/awx/ui/client/src/controllers/Teams.js index 280f40c4c1..e2be443712 100644 --- a/awx/ui/client/src/controllers/Teams.js +++ b/awx/ui/client/src/controllers/Teams.js @@ -199,7 +199,8 @@ export function TeamsEdit($scope, $rootScope, $location, generator = GenerateForm, form = TeamForm, id = $stateParams.team_id, - relatedSets = {}; + relatedSets = {}, + set; $scope.team_id = id; @@ -263,6 +264,12 @@ export function TeamsEdit($scope, $rootScope, $location, relatedSets: relatedSets }); + for (set in relatedSets) { + $scope.search(relatedSets[set].iterator); + } + + $scope.team_obj = data; + LookUpInit({ url: GetBasePath('organizations'), scope: $scope, @@ -298,6 +305,14 @@ export function TeamsEdit($scope, $rootScope, $location, init(); + $scope.convertApiUrl = function(str) { + if (str) { + return str.replace("api/v1", "#"); + } else { + return null; + } + }; + /* Related Set implementation TDB */ } diff --git a/awx/ui/client/src/controllers/Users.js b/awx/ui/client/src/controllers/Users.js index f0679cebf1..f6ac43d219 100644 --- a/awx/ui/client/src/controllers/Users.js +++ b/awx/ui/client/src/controllers/Users.js @@ -231,7 +231,8 @@ export function UsersEdit($scope, $rootScope, $location, form = UserForm, master = {}, id = $stateParams.user_id, - relatedSets = {}; + relatedSets = {}, + set; generator.inject(form, { mode: 'edit', related: true, scope: $scope }); generator.reset(); @@ -248,17 +249,25 @@ export function UsersEdit($scope, $rootScope, $location, return; }; + $scope.convertApiUrl = function(str) { + if (str) { + return str.replace("api/v1", "#"); + } else { + return null; + } + }; + var setScopeRelated = function(data, related){ _(related) - .pick(function(value, key){ - return data.related.hasOwnProperty(key) === true; - }) - .forEach(function(value, key){ - relatedSets[key] = { - url: data.related[key], - iterator: value.iterator - }; - }) + .pick(function(value, key){ + return data.related.hasOwnProperty(key) === true; + }) + .forEach(function(value, key){ + relatedSets[key] = { + url: data.related[key], + iterator: value.iterator + }; + }) .value(); }; // prepares a data payload for a PUT request to the API @@ -295,6 +304,11 @@ export function UsersEdit($scope, $rootScope, $location, scope: $scope, relatedSets: relatedSets }); + + for (set in relatedSets) { + $scope.search(relatedSets[set].iterator); + } + Wait('stop'); }) .error(function (data, status) { diff --git a/awx/ui/client/src/forms/Teams.js b/awx/ui/client/src/forms/Teams.js index 471cda62c4..9c9d3b6812 100644 --- a/awx/ui/client/src/forms/Teams.js +++ b/awx/ui/client/src/forms/Teams.js @@ -59,11 +59,10 @@ export default }, related: { - /* - permissions: { + access_list: { basePath: 'teams/:id/access_list/', type: 'collection', - title: 'Permissions', + title: 'Users', iterator: 'permission', index: false, open: false, @@ -76,148 +75,50 @@ export default actionClass: 'btn List-buttonSubmit', buttonContent: '+ ADD' } - } - }, - */ - - - credentials: { - type: 'collection', - title: 'Credentials', - iterator: 'credential', - open: false, - index: false, - - actions: { - add: { - ngClick: "add('credentials')", - label: 'Add', - add: 'Add a new credential', - actionClass: 'btn List-buttonSubmit', - buttonContent: '+ ADD' - } - }, - - fields: { - name: { - key: true, - label: 'Name' - }, - description: { - label: 'Description' - } - }, - - fieldActions: { - edit: { - label: 'Edit', - ngClick: "edit('credentials', credential.id, credential.name)", - icon: 'icon-edit', - awToolTip: 'Modify the credential', - 'class': 'btn btn-default' - }, - "delete": { - label: 'Delete', - ngClick: "delete('credentials', credential.id, credential.name, 'credential')", - icon: 'icon-trash', - "class": 'btn-danger', - awToolTip: 'Remove the credential' - } - } - }, - - projects: { - type: 'collection', - title: 'Projects', - iterator: 'project', - open: false, - index: false, - - actions: { - add: { - ngClick: "add('projects')", - label: 'Add', - actionClass: 'btn List-buttonSubmit', - buttonContent: '+ ADD' - } - }, - - fields: { - name: { - key: true, - label: 'Name' - }, - description: { - label: 'Description' - } - }, - - fieldActions: { - edit: { - label: 'Edit', - ngClick: "edit('projects', project.id, project.name)", - icon: 'icon-edit', - awToolTip: 'Modify the project', - 'class': 'btn btn-default' - }, - "delete": { - label: 'Delete', - ngClick: "delete('projects', project.id, project.name, 'project')", - icon: 'icon-trash', - "class": 'btn-danger', - awToolTip: 'Remove the project' - } - } - }, - - users: { - type: 'collection', - title: 'Users', - iterator: 'user', - open: false, - index: false, - - actions: { - add: { - ngClick: "add('users')", - label: 'Add', - awToolTip: 'Add a user', - actionClass: 'btn List-buttonSubmit', - buttonContent: '+ ADD' - } }, fields: { username: { key: true, - label: 'Username' + label: 'User', + linkBase: 'users', + class: 'col-lg-3 col-md-3 col-sm-3 col-xs-4' }, - first_name: { - label: 'First Name' - }, - last_name: { - label: 'Last Name' - } - }, - - fieldActions: { - edit: { - label: 'Edit', - ngClick: "edit('users', user.id, user.username)", - icon: 'icon-edit', - awToolTip: 'Edit user', - 'class': 'btn btn-default' - }, - "delete": { - label: 'Delete', - ngClick: "delete('users', user.id, user.username, 'user')", - icon: 'icon-terash', - "class": 'btn-danger', - awToolTip: 'Remove user' + role: { + label: 'Role', + type: 'role', + noSort: true, + class: 'col-lg-9 col-md-9 col-sm-9 col-xs-8' } } + }, + roles: { + type: 'collection', + title: 'Permissions', + iterator: 'role', + open: false, + index: false, + actions: {}, + + fields: { + name: { + label: 'Name', + ngBind: 'role.summary_fields.resource_name', + linkTo: '{{convertApiUrl(role.related[role.summary_fields.resource_type])}}', + noSort: true + }, + type: { + label: 'Type', + ngBind: 'role.summary_fields.resource_type_display_name', + noSort: true + }, + role: { + label: 'Role', + ngBind: 'role.name', + noSort: true + } + }, + hideOnSuperuser: true } - } - }); //InventoryForm diff --git a/awx/ui/client/src/forms/Users.js b/awx/ui/client/src/forms/Users.js index d1c2c2613f..d115ae3011 100644 --- a/awx/ui/client/src/forms/Users.js +++ b/awx/ui/client/src/forms/Users.js @@ -115,71 +115,6 @@ export default }, related: { - /* - permissions: { - basePath: 'teams/:id/access_list/', - type: 'collection', - title: 'Permissions', - iterator: 'permission', - index: false, - open: false, - searchType: 'select', - actions: { - add: { - ngClick: "addPermission", - label: 'Add', - awToolTip: 'Add a permission', - actionClass: 'btn List-buttonSubmit', - buttonContent: '+ ADD' - } - } - }, - */ - - credentials: { - type: 'collection', - title: 'Credentials', - iterator: 'credential', - open: false, - index: false, - - actions: { - add: { - ngClick: "add('credentials')", - label: 'Add', - awToolTip: 'Add a credential for this user', - actionClass: 'btn List-buttonSubmit', - buttonContent: '+ ADD' - } - }, - - fields: { - name: { - key: true, - label: 'Name' - }, - description: { - label: 'Description' - } - }, - - fieldActions: { - edit: { - label: 'Edit', - ngClick: "edit('credentials', credential.id, credential.name)", - icon: 'icon-edit', - awToolTip: 'Edit the credential', - 'class': 'btn btn-default' - }, - "delete": { - label: 'Delete', - ngClick: "delete('credentials', credential.id, credential.name, 'credential')", - icon: 'icon-trash', - "class": 'btn-danger', - awToolTip: 'Delete the credential' - } - } - }, organizations: { type: 'collection', title: 'Organizations', @@ -197,9 +132,9 @@ export default description: { label: 'Description' } - } + }, + hideOnSuperuser: true }, - teams: { type: 'collection', title: 'Teams', @@ -217,8 +152,38 @@ export default description: { label: 'Description' } - } + }, + hideOnSuperuser: true + }, + roles: { + hideSearchAndActions: true, + type: 'collection', + title: 'Permissions', + iterator: 'permission', + open: false, + index: false, + actions: {}, + + fields: { + name: { + label: 'Name', + ngBind: 'permission.summary_fields.resource_name', + linkTo: '{{convertApiUrl(permission.related[permission.summary_fields.resource_type])}}', + noSort: true + }, + type: { + label: 'Type', + ngBind: 'permission.summary_fields.resource_type_display_name', + noSort: true + }, + role: { + label: 'Role', + ngBind: 'permission.name', + noSort: true + } + }, + hideOnSuperuser: true } } - }); //UserForm + }); diff --git a/awx/ui/client/src/search/getSearchHtml.service.js b/awx/ui/client/src/search/getSearchHtml.service.js index b7da64f702..f64e5a12bf 100644 --- a/awx/ui/client/src/search/getSearchHtml.service.js +++ b/awx/ui/client/src/search/getSearchHtml.service.js @@ -16,6 +16,7 @@ export default ['GetBasePath', function(GetBasePath) { delete f[i].ngClass; delete f[i].ngClick; delete f[i].icon; + delete f[i].linkTo; return {[i]: f[i]}; }).reduce(function (acc, i) { var key = Object.keys(i); diff --git a/awx/ui/client/src/shared/form-generator.js b/awx/ui/client/src/shared/form-generator.js index d5d44b0be2..ade9b3d79e 100644 --- a/awx/ui/client/src/shared/form-generator.js +++ b/awx/ui/client/src/shared/form-generator.js @@ -1462,7 +1462,7 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat html += (options.mode === 'edit') ? this.form.editTitle : this.form.addTitle; if(this.form.name === "user"){ html+= "Admin"; + "ng-if=is_superuser>System Administrator"; } html += "\n"; html += "
"; @@ -1781,14 +1781,16 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat }); html += ` -
+
0 - )\"> + ${collection.iterator}_total_rows > 0)\" + ng-hide=\"is_superuser && ${collection.hideOnSuperuser}\" + > ${tagSearch}
@@ -1800,18 +1802,39 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat `; // Message for when a search returns no results. This should only get shown after a search is executed with no results. - html += "
\n"; - html += "
No records matched your search.
\n"; - html += "
\n"; + var hideOnSuperuser = (hideOnSuperuser === true) ? true : false; + html += ` +
+
+ No records matched your search. +
+
+ `; // Show the "no items" box when loading is done and the user isn't actively searching and there are no results html += "
PLEASE ADD ITEMS TO THIS LIST
"; + html += ` +
+ System Administrators have access to all ${collection.iterator}s +
+ `; + // Start the list - html += "
0)\">\n"; - html += "\n"; - html += "\n"; - html += "\n"; + html += ` +
0)) && + !(is_superuser && ${collection.hideOnSuperuser})\"> +
+ + + `; html += (collection.index === undefined || collection.index !== false) ? "\n" : ""; for (fld in collection.fields) { html += "
#\n"; + html += ` +
+ `; html += "
"; html += "
"; html += "
    \n"; From deee1bafc7c2a6bed20aaff8f1c232327c34e283 Mon Sep 17 00:00:00 2001 From: John Mitchell Date: Wed, 27 Apr 2016 11:31:35 -0400 Subject: [PATCH 2/3] fixed jshint errors --- .../hosts/dashboard-hosts-edit.controller.js | 16 ++++++------- .../hosts/dashboard-hosts-list.controller.js | 24 +++++++++---------- .../dashboard/hosts/dashboard-hosts.form.js | 4 ++-- .../dashboard/hosts/dashboard-hosts.list.js | 4 ++-- .../dashboard/hosts/dashboard-hosts.route.js | 6 ++--- awx/ui/client/src/search/tagSearch.service.js | 4 ++-- 6 files changed, 29 insertions(+), 29 deletions(-) diff --git a/awx/ui/client/src/dashboard/hosts/dashboard-hosts-edit.controller.js b/awx/ui/client/src/dashboard/hosts/dashboard-hosts-edit.controller.js index 8393088f4a..c70d7d39ad 100644 --- a/awx/ui/client/src/dashboard/hosts/dashboard-hosts-edit.controller.js +++ b/awx/ui/client/src/dashboard/hosts/dashboard-hosts-edit.controller.js @@ -27,10 +27,10 @@ description: $scope.description, enabled: $scope.host.enabled }; - DashboardHostService.putHost(host).then(function(res){ + DashboardHostService.putHost(host).then(function(){ $state.go('^', null, {reload: true}); }); - + }; var init = function(){ $scope.host = host; @@ -38,13 +38,13 @@ generator.inject(form, {mode: 'edit', related: false, scope: $scope}); $scope.extraVars = $scope.host.variables === '' ? '---' : $scope.host.variables; $scope.name = host.name; - $scope.description = host.description; - ParseTypeChange({ - scope: $scope, - field_id: 'host_variables', - variable: 'extraVars', + $scope.description = host.description; + ParseTypeChange({ + scope: $scope, + field_id: 'host_variables', + variable: 'extraVars', }); }; init(); - }]; \ No newline at end of file + }]; diff --git a/awx/ui/client/src/dashboard/hosts/dashboard-hosts-list.controller.js b/awx/ui/client/src/dashboard/hosts/dashboard-hosts-list.controller.js index 066ab5f9aa..43970c30b4 100644 --- a/awx/ui/client/src/dashboard/hosts/dashboard-hosts-list.controller.js +++ b/awx/ui/client/src/dashboard/hosts/dashboard-hosts-list.controller.js @@ -5,9 +5,17 @@ *************************************************/ export default - ['$scope', '$state', '$stateParams', 'PageRangeSetup', 'GetBasePath', 'DashboardHostsList', - 'generateList', 'PaginateInit', 'SetStatus', 'DashboardHostService', 'hosts', + ['$scope', '$state', '$stateParams', 'PageRangeSetup', 'GetBasePath', 'DashboardHostsList', + 'generateList', 'PaginateInit', 'SetStatus', 'DashboardHostService', 'hosts', function($scope, $state, $stateParams, PageRangeSetup, GetBasePath, DashboardHostsList, GenerateList, PaginateInit, SetStatus, DashboardHostService, hosts){ + var setJobStatus = function(){ + _.forEach($scope.hosts, function(value){ + SetStatus({ + scope: $scope, + host: value + }); + }); + }; var generator = GenerateList, list = DashboardHostsList, defaultUrl = GetBasePath('hosts'); @@ -23,21 +31,13 @@ export default }); }; $scope.$on('PostRefresh', function(){ - $scope.hosts = _.map($scope.hosts, function(value, key){ + $scope.hosts = _.map($scope.hosts, function(value){ value.inventory_name = value.summary_fields.inventory.name; value.inventory_id = value.summary_fields.inventory.id; return value; }); setJobStatus(); }); - var setJobStatus = function(){ - _.forEach($scope.hosts, function(value, key){ - SetStatus({ - scope: $scope, - host: value - }); - }); - }; var init = function(){ $scope.list = list; $scope.host_active_search = false; @@ -61,4 +61,4 @@ export default $scope.hostLoading = false; }; init(); - }]; \ No newline at end of file + }]; diff --git a/awx/ui/client/src/dashboard/hosts/dashboard-hosts.form.js b/awx/ui/client/src/dashboard/hosts/dashboard-hosts.form.js index 654e76a13e..2ae47e1046 100644 --- a/awx/ui/client/src/dashboard/hosts/dashboard-hosts.form.js +++ b/awx/ui/client/src/dashboard/hosts/dashboard-hosts.form.js @@ -61,7 +61,7 @@ export default function(){ "YAML:
    \n" + "
    ---
    somevar: somevalue
    password: magic
    \n" + '

    View JSON examples at www.json.org

    ' + - '

    View YAML examples at docs.ansible.com

    ', + '

    View YAML examples at docs.ansible.com

    ', } }, buttons: { @@ -74,4 +74,4 @@ export default function(){ } } }; -}; \ No newline at end of file +} diff --git a/awx/ui/client/src/dashboard/hosts/dashboard-hosts.list.js b/awx/ui/client/src/dashboard/hosts/dashboard-hosts.list.js index 4731155cbb..9ad52a7899 100644 --- a/awx/ui/client/src/dashboard/hosts/dashboard-hosts.list.js +++ b/awx/ui/client/src/dashboard/hosts/dashboard-hosts.list.js @@ -89,5 +89,5 @@ export default function(){ actions: { } - } -}; + }; +} diff --git a/awx/ui/client/src/dashboard/hosts/dashboard-hosts.route.js b/awx/ui/client/src/dashboard/hosts/dashboard-hosts.route.js index 84f31ad981..4b8b95b0a6 100644 --- a/awx/ui/client/src/dashboard/hosts/dashboard-hosts.route.js +++ b/awx/ui/client/src/dashboard/hosts/dashboard-hosts.route.js @@ -29,13 +29,13 @@ var dashboardHostsList = { var defaultUrl = GetBasePath('hosts') + '?page_size=10'; Rest.setUrl(defaultUrl); return Rest.get().then(function(res){ - var results = _.map(res.data.results, function(value, key){ + var results = _.map(res.data.results, function(value){ value.inventory_name = value.summary_fields.inventory.name; value.inventory_id = value.summary_fields.inventory.id; return value; }); res.data.results = results; - return res.data + return res.data; }); }] } @@ -61,4 +61,4 @@ var dashboardHostsEdit = { } }; -export {dashboardHostsList, dashboardHostsEdit}; \ No newline at end of file +export {dashboardHostsList, dashboardHostsEdit}; diff --git a/awx/ui/client/src/search/tagSearch.service.js b/awx/ui/client/src/search/tagSearch.service.js index eb004a2e39..fc8111e8ed 100644 --- a/awx/ui/client/src/search/tagSearch.service.js +++ b/awx/ui/client/src/search/tagSearch.service.js @@ -35,7 +35,7 @@ export default ['Rest', '$q', 'GetBasePath', 'Wait', 'ProcessErrors', '$log', fu obj.value = value; obj.label = label; obj.type = type; - obj.basePath = field['basePath'] || null; + obj.basePath = field.basePath || null; // return the built option if (type === 'select') { @@ -81,7 +81,7 @@ export default ['Rest', '$q', 'GetBasePath', 'Wait', 'ProcessErrors', '$log', fu Rest.setUrl(needsRequest[0].basePath ? GetBasePath(needsRequest[0].basePath) : basePath); Rest.options() .success(function (data) { - try { + try { var options = data.actions.GET; needsRequest = needsRequest .map(function (option) { From 85aee6af8c5b286e642ef30dfec54f420095c2f2 Mon Sep 17 00:00:00 2001 From: John Mitchell Date: Wed, 27 Apr 2016 15:35:37 -0400 Subject: [PATCH 3/3] added deletion to permissions lists --- awx/ui/client/src/app.js | 60 ++++++++++++++++++++++++++++++++ awx/ui/client/src/forms/Teams.js | 11 +++++- awx/ui/client/src/forms/Users.js | 10 ++++-- 3 files changed, 78 insertions(+), 3 deletions(-) diff --git a/awx/ui/client/src/app.js b/awx/ui/client/src/app.js index a79460b0ea..b3a2802df3 100644 --- a/awx/ui/client/src/app.js +++ b/awx/ui/client/src/app.js @@ -716,6 +716,66 @@ var tower = angular.module('Tower', [ }); }; + $rootScope.deletePermissionFromUser = function (userId, userName, roleName, roleType, url) { + var action = function () { + $('#prompt-modal').modal('hide'); + Wait('start'); + Rest.setUrl(url); + Rest.post({"disassociate": true, "id": userId}) + .success(function () { + Wait('stop'); + $rootScope.$broadcast("refreshList", "permission"); + }) + .error(function (data, status) { + ProcessErrors($rootScope, data, status, null, { hdr: 'Error!', + msg: 'Could not disassociate user from role. Call to ' + url + ' failed. DELETE returned status: ' + status }); + }); + }; + + Prompt({ + hdr: `Remove role`, + body: ` +
    + Confirm the removal of the ${roleType} + ${roleName} + role associated with ${userName}. +
    + `, + action: action, + actionText: 'REMOVE' + }); + }; + + $rootScope.deletePermissionFromTeam = function (teamId, teamName, roleName, roleType, url) { + var action = function () { + $('#prompt-modal').modal('hide'); + Wait('start'); + Rest.setUrl(url); + Rest.post({"disassociate": true, "id": teamId}) + .success(function () { + Wait('stop'); + $rootScope.$broadcast("refreshList", "role"); + }) + .error(function (data, status) { + ProcessErrors($rootScope, data, status, null, { hdr: 'Error!', + msg: 'Could not disassociate team from role. Call to ' + url + ' failed. DELETE returned status: ' + status }); + }); + }; + + Prompt({ + hdr: `Remove role`, + body: ` +
    + Confirm the removal of the ${roleType} + ${roleName} + role associated with the ${teamName} team. +
    + `, + action: action, + actionText: 'REMOVE' + }); + }; + function activateTab() { // Make the correct tab active var base = $location.path().replace(/^\//, '').split('/')[0]; diff --git a/awx/ui/client/src/forms/Teams.js b/awx/ui/client/src/forms/Teams.js index 9c9d3b6812..4d56a75f7e 100644 --- a/awx/ui/client/src/forms/Teams.js +++ b/awx/ui/client/src/forms/Teams.js @@ -118,7 +118,16 @@ export default noSort: true } }, + fieldActions: { + "delete": { + label: 'Remove', + ngClick: 'deletePermissionFromTeam(team_id, team_obj.name, role.name, role.summary_fields.resource_name, role.related.teams)', + class: "List-actionButton--delete", + iconClass: 'fa fa-times', + awToolTip: 'Dissasociate permission from team' + } + }, hideOnSuperuser: true } - } + }, }); //InventoryForm diff --git a/awx/ui/client/src/forms/Users.js b/awx/ui/client/src/forms/Users.js index d115ae3011..954a61225b 100644 --- a/awx/ui/client/src/forms/Users.js +++ b/awx/ui/client/src/forms/Users.js @@ -162,8 +162,6 @@ export default iterator: 'permission', open: false, index: false, - actions: {}, - fields: { name: { label: 'Name', @@ -180,6 +178,14 @@ export default label: 'Role', ngBind: 'permission.name', noSort: true + }, + }, + fieldActions: { + "delete": { + label: 'Remove', + ngClick: 'deletePermissionFromUser(user_id, username, permission.name, permission.summary_fields.resource_name, permission.related.users)', + iconClass: 'fa fa-times', + awToolTip: 'Dissasociate permission from user' } }, hideOnSuperuser: true