Merge pull request #5170 from mabashian/5153-permission-scope

Related lists custom scope
This commit is contained in:
Michael Abashian 2017-02-06 10:27:04 -05:00 committed by GitHub
commit 3913ddb331
9 changed files with 248 additions and 159 deletions

View File

@ -7,10 +7,12 @@
import roleList from './rbac-role-column/roleList.directive';
import addRbacResource from './add-rbac-resource/main';
import addRbacUserTeam from './add-rbac-user-team/main';
import permissionsList from './permissions-list.controller';
export default
angular.module('RbacModule', [
addRbacResource.name,
addRbacUserTeam.name
])
.controller('PermissionsList', permissionsList)
.directive('roleList', roleList);

View File

@ -0,0 +1,82 @@
/*************************************************
* Copyright (c) 2016 Ansible, Inc.
*
* All Rights Reserved
*************************************************/
export default ['$scope', 'ListDefinition', 'Dataset', 'Wait', 'Rest', 'ProcessErrors', 'Prompt', '$state',
function($scope, list, Dataset, Wait, Rest, ProcessErrors, Prompt, $state) {
init();
function init() {
$scope.list = list;
$scope[`${list.iterator}_dataset`] = Dataset.data;
$scope[`${list.iterator}s`] = $scope[`${list.iterator}_dataset`].results;
}
$scope.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');
$state.go('.', null, {reload: true});
})
.error(function(data, status) {
ProcessErrors($scope, 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: `
<div class="Prompt-bodyQuery">
Confirm the removal of the ${roleType}
<span class="Prompt-emphasis"> ${roleName} </span>
role associated with ${userName}.
</div>
`,
action: action,
actionText: 'REMOVE'
});
};
$scope.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');
$state.go('.', null, {reload: true});
})
.error(function(data, status) {
ProcessErrors($scope, 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: `
<div class="Prompt-bodyQuery">
Confirm the removal of the ${roleType}
<span class="Prompt-emphasis"> ${roleName} </span>
role associated with the ${teamName} team.
</div>
`,
action: action,
actionText: 'REMOVE'
});
};
}
];

View File

@ -44,7 +44,6 @@ import './filters';
import { Home } from './controllers/Home';
import { SocketsController } from './controllers/Sockets';
import { CredentialsAdd, CredentialsEdit, CredentialsList } from './controllers/Credentials';
import { JobsListController } from './controllers/Jobs';
import portalMode from './portal-mode/main';
import systemTracking from './system-tracking/main';
import inventories from './inventories/main';
@ -70,6 +69,7 @@ import activityStream from './activity-stream/main';
import standardOut from './standard-out/main';
import Templates from './templates/main';
import credentials from './credentials/main';
import jobs from './jobs/main';
import { ProjectsList, ProjectsAdd, ProjectsEdit } from './controllers/Projects';
import { UsersList, UsersAdd, UsersEdit } from './controllers/Users';
import { TeamsList, TeamsAdd, TeamsEdit } from './controllers/Teams';
@ -134,6 +134,7 @@ var tower = angular.module('Tower', [
portalMode.name,
config.name,
credentials.name,
jobs.name,
//'templates',
'Utilities',
'OrganizationFormDefinition',
@ -422,53 +423,6 @@ var tower = angular.module('Tower', [
}
});
$stateExtender.addState({
searchPrefix: 'job',
name: 'jobs',
url: '/jobs',
ncyBreadcrumb: {
label: N_("JOBS")
},
params: {
job_search: {
value: {
not__launch_type: 'sync',
order_by: '-finished'
},
squash: ''
}
},
data: {
socket: {
"groups": {
"jobs": ["status_changed"],
"schedules": ["changed"]
}
}
},
resolve: {
Dataset: ['AllJobsList', 'QuerySet', '$stateParams', 'GetBasePath', (list, qs, $stateParams, GetBasePath) => {
let path = GetBasePath(list.basePath) || GetBasePath(list.name);
return qs.search(path, $stateParams[`${list.iterator}_search`]);
}]
},
views: {
'@': {
templateUrl: urlPrefix + 'partials/jobs.html',
},
'list@jobs': {
templateProvider: function(AllJobsList, generateList) {
let html = generateList.build({
list: AllJobsList,
mode: 'edit'
});
return html;
},
controller: JobsListController
}
}
});
$stateExtender.addState({
name: 'userCredentials',
url: '/users/:user_id/credentials',
@ -500,70 +454,6 @@ 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: `
<div class="Prompt-bodyQuery">
Confirm the removal of the ${roleType}
<span class="Prompt-emphasis"> ${roleName} </span>
role associated with ${userName}.
</div>
`,
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: `
<div class="Prompt-bodyQuery">
Confirm the removal of the ${roleType}
<span class="Prompt-emphasis"> ${roleName} </span>
role associated with the ${teamName} team.
</div>
`,
action: action,
actionText: 'REMOVE'
});
};
function activateTab() {
// Make the correct tab active
var base = $location.path().replace(/^\//, '').split('/')[0];

View File

@ -10,14 +10,16 @@
* @description This controller's for the jobs page
*/
export function JobsListController($state, $rootScope, $log, $scope, $compile, $stateParams,
ClearScope, Find, DeleteJob, RelaunchJob, AllJobsList, ScheduledJobsList, GetBasePath, Dataset, qs) {
export default ['$state', '$rootScope', '$log', '$scope', '$compile', '$stateParams',
'ClearScope', 'Find', 'DeleteJob', 'RelaunchJob', 'AllJobsList', 'ScheduledJobsList',
'GetBasePath', 'Dataset', 'QuerySet', 'ListDefinition', '$interpolate',
function($state, $rootScope, $log, $scope, $compile, $stateParams,
ClearScope, Find, DeleteJob, RelaunchJob, AllJobsList, ScheduledJobsList,
GetBasePath, Dataset, qs, ListDefinition, $interpolate) {
ClearScope();
var list = AllJobsList;
var list = ListDefinition;
init();
@ -44,27 +46,29 @@ export function JobsListController($state, $rootScope, $log, $scope, $compile, $
// OPTIONS request returns, or the list is sorted/paginated/searched
function optionsRequestDataProcessing(){
$scope[list.name].forEach(function(item, item_idx) {
var itm = $scope[list.name][item_idx];
if($scope[list.name] && $scope[list.name].length > 0) {
$scope[list.name].forEach(function(item, item_idx) {
var itm = $scope[list.name][item_idx];
if(item.summary_fields && item.summary_fields.source_workflow_job &&
item.summary_fields.source_workflow_job.id){
item.workflow_result_link = `/#/workflows/${item.summary_fields.source_workflow_job.id}`;
}
// Set the item type label
if (list.fields.type && $scope.options &&
$scope.options.hasOwnProperty('type')) {
$scope.options.type.choices.every(function(choice) {
if (choice[0] === item.type) {
itm.type_label = choice[1];
return false;
}
return true;
});
if(item.summary_fields && item.summary_fields.source_workflow_job &&
item.summary_fields.source_workflow_job.id){
item.workflow_result_link = `/#/workflows/${item.summary_fields.source_workflow_job.id}`;
}
buildTooltips(itm);
});
// Set the item type label
if (list.fields.type && $scope.options &&
$scope.options.hasOwnProperty('type')) {
$scope.options.type.choices.every(function(choice) {
if (choice[0] === item.type) {
itm.type_label = choice[1];
return false;
}
return true;
});
}
buildTooltips(itm);
});
}
}
function buildTooltips(job) {
job.status_tip = 'Job ' + job.status + ". Click for details.";
@ -75,14 +79,31 @@ export function JobsListController($state, $rootScope, $log, $scope, $compile, $
};
$scope.relaunchJob = function(event, id) {
var job, typeId;
let job, typeId, jobs;
try {
$(event.target).tooltip('hide');
} catch (e) {
//ignore
}
job = Find({ list: $scope.jobs, key: 'id', val: id });
if ($scope.completed_jobs) {
jobs = $scope.completed_jobs;
}
else if ($scope.running_jobs) {
jobs = $scope.running_jobs;
}
else if ($scope.queued_jobs) {
jobs = $scope.queued_jobs;
}
else if ($scope.all_jobs) {
jobs = $scope.all_jobs;
}
else if ($scope.jobs) {
jobs = $scope.jobs;
}
job = Find({list: jobs, key: 'id', val: id });
if (job.type === 'inventory_update') {
typeId = job.inventory_source;
} else if (job.type === 'project_update') {
@ -122,7 +143,14 @@ export function JobsListController($state, $rootScope, $log, $scope, $compile, $
};
$scope.$on('ws-jobs', function(){
let path = GetBasePath(list.basePath) || GetBasePath(list.name);
let path;
if (GetBasePath(list.basePath) || GetBasePath(list.name)) {
path = GetBasePath(list.basePath) || GetBasePath(list.name);
} else {
// completed jobs base path involves $stateParams
let interpolator = $interpolate(list.basePath);
path = interpolator({ $rootScope: $rootScope, $stateParams: $stateParams });
}
qs.search(path, $state.params[`${list.iterator}_search`])
.then(function(searchResponse) {
$scope[`${list.iterator}_dataset`] = searchResponse.data;
@ -133,8 +161,4 @@ export function JobsListController($state, $rootScope, $log, $scope, $compile, $
$scope.$on('ws-schedules', function(){
$state.reload();
});
}
JobsListController.$inject = ['$state', '$rootScope', '$log', '$scope', '$compile', '$stateParams',
'ClearScope', 'Find', 'DeleteJob', 'RelaunchJob', 'AllJobsList', 'ScheduledJobsList', 'GetBasePath', 'Dataset','QuerySet'
];
}];

View File

@ -0,0 +1,58 @@
/*************************************************
* Copyright (c) 2016 Ansible, Inc.
*
* All Rights Reserved
*************************************************/
import { N_ } from '../i18n';
import {templateUrl} from '../shared/template-url/template-url.factory';
export default {
searchPrefix: 'job',
name: 'jobs',
url: '/jobs',
ncyBreadcrumb: {
label: N_("JOBS")
},
params: {
job_search: {
value: {
not__launch_type: 'sync',
order_by: '-finished'
},
squash: ''
}
},
data: {
socket: {
"groups": {
"jobs": ["status_changed"],
"schedules": ["changed"]
}
}
},
resolve: {
Dataset: ['AllJobsList', 'QuerySet', '$stateParams', 'GetBasePath', (list, qs, $stateParams, GetBasePath) => {
let path = GetBasePath(list.basePath) || GetBasePath(list.name);
return qs.search(path, $stateParams[`${list.iterator}_search`]);
}],
ListDefinition: ['AllJobsList', (list) => {
return list;
}]
},
views: {
'@': {
templateUrl: templateUrl('jobs/jobs')
},
'list@jobs': {
templateProvider: function(AllJobsList, generateList) {
let html = generateList.build({
list: AllJobsList,
mode: 'edit'
});
return html;
},
controller: 'JobsList'
}
}
};

View File

@ -0,0 +1,15 @@
/*************************************************
* Copyright (c) 2017 Ansible, Inc.
*
* All Rights Reserved
*************************************************/
import jobsList from './jobs-list.controller';
import jobsRoute from './jobs.route';
export default
angular.module('JobsModule', [])
.run(['$stateExtender', function($stateExtender) {
$stateExtender.addState(jobsRoute);
}])
.controller('JobsList', jobsList);

View File

@ -230,7 +230,7 @@ export default ['$injector', '$stateExtender', '$log', 'i18n', function($injecto
break;
}
states.push(formNode);
states = states.concat(this.generateLookupNodes(form, formNode)).concat(this.generateFormListDefinitions(form, formNode));
states = states.concat(this.generateLookupNodes(form, formNode)).concat(this.generateFormListDefinitions(form, formNode, params));
return states;
},
/**
@ -241,7 +241,7 @@ export default ['$injector', '$stateExtender', '$log', 'i18n', function($injecto
* @params {object} formStateDefinition - the parent form node
* @returns {array} Array of state definitions [{...}, {...}, ...]
*/
generateFormListDefinitions: function(form, formStateDefinition) {
generateFormListDefinitions: function(form, formStateDefinition, params) {
function buildRbacUserTeamDirective(){
let states = [];
@ -559,14 +559,17 @@ export default ['$injector', '$stateExtender', '$log', 'i18n', function($injecto
function buildListDefinition(field) {
let state,
list = field.include ? $injector.get(field.include) : field;
state = $stateExtender.buildDefinition({
list = field.include ? $injector.get(field.include) : field,
// Added this line specifically for Completed Jobs but should be OK
// for all the rest of the related tabs
breadcrumbLabel = field.iterator.replace('_', ' '),
stateConfig = {
searchPrefix: `${list.iterator}`,
name: `${formStateDefinition.name}.${list.iterator}s`,
url: `/${list.iterator}s`,
ncyBreadcrumb: {
parent: `${formStateDefinition.name}`,
label: `${field.iterator}s`
label: `${breadcrumbLabel}s`
},
params: {
[list.iterator + '_search']: {
@ -583,14 +586,7 @@ export default ['$injector', '$stateExtender', '$log', 'i18n', function($injecto
FormDefinition() : FormDefinition
});
return html;
},
controller: ['$scope', 'ListDefinition', 'Dataset',
function($scope, list, Dataset) {
$scope.list = list;
$scope[`${list.iterator}_dataset`] = Dataset.data;
$scope[`${list.iterator}s`] = $scope[`${list.iterator}_dataset`].results;
}
]
}
}
},
resolve: {
@ -611,7 +607,26 @@ export default ['$injector', '$stateExtender', '$log', 'i18n', function($injecto
}
]
}
});
};
if(params.controllers && params.controllers.related && params.controllers.related[field.name]) {
stateConfig.views.related.controller = params.controllers.related[field.name];
}
else if(field.name === 'permissions') {
stateConfig.views.related.controller = 'PermissionsList';
}
else {
// Generic controller
stateConfig.views.related.controller = ['$scope', 'ListDefinition', 'Dataset',
function($scope, list, Dataset) {
$scope.list = list;
$scope[`${list.iterator}_dataset`] = Dataset.data;
$scope[`${list.iterator}s`] = $scope[`${list.iterator}_dataset`].results;
}
];
}
state = $stateExtender.buildDefinition(stateConfig);
// appy any default search parameters in form definition
if (field.search) {
state.params[`${field.iterator}_search`].value = _.merge(state.params[`${field.iterator}_search`].value, field.search);

View File

@ -52,7 +52,10 @@ angular.module('templates', [surveyMaker.name, templatesList.name, jobTemplatesA
modes: ['edit'],
form: 'JobTemplateForm',
controllers: {
edit: 'JobTemplateEdit'
edit: 'JobTemplateEdit',
related: {
completed_jobs: 'JobsList'
}
},
data: {
activityStream: true,