From 625c0ad578ff9672b08ea9a3fe349eec6e101dd5 Mon Sep 17 00:00:00 2001 From: Jared Tabor Date: Mon, 23 Oct 2017 15:33:17 -0700 Subject: [PATCH 1/3] Adding Project Based Navigation of Job Templates This adds a Job Templates tab onto the Project form that gives the user the ability to see all the job templates using a project. Clicking the add button on this list will take the user to the job template form with the project field auto-filled with the project. --- awx/ui/client/src/projects/main.js | 37 +++++++++---- .../src/projects/projects-templates.route.js | 55 +++++++++++++++++++ awx/ui/client/src/projects/projects.form.js | 11 +++- .../src/shared/socket/socket.service.js | 1 - awx/ui/client/src/templates/main.js | 24 ++++++-- 5 files changed, 111 insertions(+), 17 deletions(-) create mode 100644 awx/ui/client/src/projects/projects-templates.route.js diff --git a/awx/ui/client/src/projects/main.js b/awx/ui/client/src/projects/main.js index 37461d3d0a..e5534b4a79 100644 --- a/awx/ui/client/src/projects/main.js +++ b/awx/ui/client/src/projects/main.js @@ -13,6 +13,7 @@ import { N_ } from '../i18n'; import GetProjectPath from './factories/get-project-path.factory'; import GetProjectIcon from './factories/get-project-icon.factory'; import GetProjectToolTip from './factories/get-project-tool-tip.factory'; +import ProjectsTemplatesRoute from './projects-templates.route'; export default angular.module('Projects', []) @@ -24,9 +25,10 @@ angular.module('Projects', []) .factory('GetProjectToolTip', GetProjectToolTip) .factory('ProjectList', ProjectList) .factory('ProjectsForm', ProjectsForm) - .config(['$stateProvider', 'stateDefinitionsProvider', - function($stateProvider, stateDefinitionsProvider) { + .config(['$stateProvider', 'stateDefinitionsProvider', '$stateExtenderProvider', + function($stateProvider, stateDefinitionsProvider,$stateExtenderProvider) { let stateDefinitions = stateDefinitionsProvider.$get(); + let stateExtender = $stateExtenderProvider.$get(); var projectResolve = { CredentialTypes: ['Rest', '$stateParams', 'GetBasePath', 'ProcessErrors', (Rest, $stateParams, GetBasePath, ProcessErrors) => { @@ -45,12 +47,9 @@ angular.module('Projects', []) } ] }; - // lazily generate a tree of substates which will replace this node in ui-router's stateRegistry - // see: stateDefinition.factory for usage documentation - $stateProvider.state({ - name: 'projects.**', - url: '/projects', - lazyLoad: () => stateDefinitions.generateTree({ + + function generateStateTree() { + let projectTree = stateDefinitions.generateTree({ parent: 'projects', // top-most node in the generated tree (will replace this state definition) modes: ['add', 'edit'], list: 'ProjectList', @@ -76,7 +75,25 @@ angular.module('Projects', []) add: projectResolve, edit: projectResolve } - }) - }); + }); + + return Promise.all([ + projectTree + ]).then((generated) => { + return { + states: _.reduce(generated, (result, definition) => { + return result.concat(definition.states); + }, [ + stateExtender.buildDefinition(ProjectsTemplatesRoute), + ]) + }; + }); + } + let stateTree = { + name: 'projects.**', + url: '/projects', + lazyLoad: () => generateStateTree() + }; + $stateProvider.state(stateTree); } ]); diff --git a/awx/ui/client/src/projects/projects-templates.route.js b/awx/ui/client/src/projects/projects-templates.route.js new file mode 100644 index 0000000000..45c3caa2ea --- /dev/null +++ b/awx/ui/client/src/projects/projects-templates.route.js @@ -0,0 +1,55 @@ +import { N_ } from '../i18n'; + +export default { + url: "/templates", + name: 'projects.edit.templates', + params: { + template_search: { + value: { + page_size: '20', + project: '', + order_by: "-id" + } + } + }, + ncyBreadcrumb: { + label: N_("JOB TEMPLATES") + }, + views: { + 'related': { + templateProvider: function(FormDefinition, GenerateForm) { + let html = GenerateForm.buildCollection({ + mode: 'edit', + related: 'templates', + form: typeof(FormDefinition) === 'function' ? + FormDefinition() : FormDefinition + }); + return html; + }, + controller: 'TemplatesListController' + } + }, + resolve: { + ListDefinition: ['TemplateList', '$transition$', (TemplateList, $transition$) => { + let id = $transition$.params().project_id; + TemplateList.actions.add.ngClick = `$state.go('templates.addJobTemplate', {project_id: ${id}})`; + return TemplateList; + }], + Dataset: ['ListDefinition', 'QuerySet', '$stateParams', 'GetBasePath', '$interpolate', '$rootScope', + (list, qs, $stateParams, GetBasePath, $interpolate, $rootScope) => { + // allow related list definitions to use interpolated $rootScope / $stateParams in basePath field + let path, interpolator; + if (GetBasePath(list.basePath)) { + path = GetBasePath(list.basePath); + } else { + interpolator = $interpolate(list.basePath); + path = interpolator({ $rootScope: $rootScope, $stateParams: $stateParams }); + } + let project_id = $stateParams.project_id; + $stateParams[`${list.iterator}_search`].project = project_id; + path = GetBasePath('job_templates'); + return qs.search(path, $stateParams[`${list.iterator}_search`]); + } + ] + } +}; diff --git a/awx/ui/client/src/projects/projects.form.js b/awx/ui/client/src/projects/projects.form.js index 3223dbf104..c56df778ca 100644 --- a/awx/ui/client/src/projects/projects.form.js +++ b/awx/ui/client/src/projects/projects.form.js @@ -10,7 +10,8 @@ * @description This form is for adding/editing projects */ -export default ['i18n', 'NotificationsList', function(i18n, NotificationsList) { +export default ['i18n', 'NotificationsList', 'TemplateList', + function(i18n, NotificationsList, TemplateList) { return function() { var projectsFormObj = { addTitle: i18n._('NEW PROJECT'), @@ -220,6 +221,9 @@ export default ['i18n', 'NotificationsList', function(i18n, NotificationsList) { }, related: { + templates: { + include: "TemplateList", + }, permissions: { name: 'permissions', awToolTip: i18n._('Please save before assigning permissions.'), @@ -275,6 +279,11 @@ export default ['i18n', 'NotificationsList', function(i18n, NotificationsList) { var itm; for (itm in projectsFormObj.related) { + if (projectsFormObj.related[itm].include === "TemplateList") { + projectsFormObj.related[itm] = _.clone(TemplateList); + projectsFormObj.related[itm].title = i18n._('Job Templates'); + projectsFormObj.related[itm].skipGenerator = true; + } if (projectsFormObj.related[itm].include === "NotificationsList") { projectsFormObj.related[itm] = NotificationsList; projectsFormObj.related[itm].generateList = true; // tell form generator to call list generator and inject a list diff --git a/awx/ui/client/src/shared/socket/socket.service.js b/awx/ui/client/src/shared/socket/socket.service.js index 3b7a60e9ab..8157fc4477 100644 --- a/awx/ui/client/src/shared/socket/socket.service.js +++ b/awx/ui/client/src/shared/socket/socket.service.js @@ -34,7 +34,6 @@ export default self.socket.onopen = function () { $log.debug("Websocket connection opened. Socket readyState: " + self.socket.readyState); socketPromise.resolve(); - console.log('promise resolved, and readyState: '+ self.readyState); self.checkStatus(); if(needsResubscribing){ self.subscribe(self.getLast()); diff --git a/awx/ui/client/src/templates/main.js b/awx/ui/client/src/templates/main.js index 78f7922d45..2712437a23 100644 --- a/awx/ui/client/src/templates/main.js +++ b/awx/ui/client/src/templates/main.js @@ -44,7 +44,7 @@ angular.module('templates', [surveyMaker.name, templatesList.name, jobTemplates. addJobTemplate = stateDefinitions.generateTree({ name: 'templates.addJobTemplate', - url: '/add_job_template?inventory_id&credential_id', + url: '/add_job_template?inventory_id&credential_id&project_id', modes: ['add'], form: 'JobTemplateForm', controllers: { @@ -69,10 +69,10 @@ angular.module('templates', [surveyMaker.name, templatesList.name, jobTemplates. }); } }], - Project: ['$stateParams', 'Rest', 'GetBasePath', 'ProcessErrors', - function($stateParams, Rest, GetBasePath, ProcessErrors){ - if($stateParams.credential_id){ - let path = `${GetBasePath('projects')}?credential__id=${Number($stateParams.credential_id)}`; + Project: ['Rest', 'GetBasePath', 'ProcessErrors', '$transition$', + function(Rest, GetBasePath, ProcessErrors, $transition$){ + if($transition$.params().credential_id){ + let path = `${GetBasePath('projects')}?credential__id=${Number($transition$.params().credential_id)}`; Rest.setUrl(path); return Rest.get(). then(function(data){ @@ -85,6 +85,20 @@ angular.module('templates', [surveyMaker.name, templatesList.name, jobTemplates. }); }); } + else if($transition$.params().project_id){ + let path = `${GetBasePath('projects')}${$transition$.params().project_id}`; + Rest.setUrl(path); + return Rest.get(). + then(function(data){ + return data.data; + }).catch(function(response) { + ProcessErrors(null, response.data, response.status, null, { + hdr: 'Error!', + msg: 'Failed to get project info. GET returned status: ' + + response.status + }); + }); + } }], availableLabels: ['ProcessErrors', 'TemplatesService', function(ProcessErrors, TemplatesService) { From 5e349590fdc41a30777028c23e8b8ab3e583feae Mon Sep 17 00:00:00 2001 From: Jared Tabor Date: Wed, 25 Oct 2017 09:47:43 -0700 Subject: [PATCH 2/3] making JOB TEMPLATES tab the last tab on the projects form --- awx/ui/client/src/projects/projects.form.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/awx/ui/client/src/projects/projects.form.js b/awx/ui/client/src/projects/projects.form.js index c56df778ca..a9d6762860 100644 --- a/awx/ui/client/src/projects/projects.form.js +++ b/awx/ui/client/src/projects/projects.form.js @@ -221,9 +221,6 @@ export default ['i18n', 'NotificationsList', 'TemplateList', }, related: { - templates: { - include: "TemplateList", - }, permissions: { name: 'permissions', awToolTip: i18n._('Please save before assigning permissions.'), @@ -271,7 +268,10 @@ export default ['i18n', 'NotificationsList', 'TemplateList', }, notifications: { include: "NotificationsList", - } + }, + templates: { + include: "TemplateList", + }, } }; From 4fbfddaa93f427bf869ed7c6285c819cd9ac226c Mon Sep 17 00:00:00 2001 From: Jared Tabor Date: Thu, 26 Oct 2017 16:50:12 -0700 Subject: [PATCH 3/3] changes from PR feedback: removing ghost action icon and fixing a bug where the list of job templates was improperly updated when a job was running and live events were received. --- .../src/projects/projects-templates.route.js | 1 + awx/ui/client/src/shared/form-generator.js | 44 ++++++++++--------- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/awx/ui/client/src/projects/projects-templates.route.js b/awx/ui/client/src/projects/projects-templates.route.js index 45c3caa2ea..0015c9661e 100644 --- a/awx/ui/client/src/projects/projects-templates.route.js +++ b/awx/ui/client/src/projects/projects-templates.route.js @@ -33,6 +33,7 @@ export default { ListDefinition: ['TemplateList', '$transition$', (TemplateList, $transition$) => { let id = $transition$.params().project_id; TemplateList.actions.add.ngClick = `$state.go('templates.addJobTemplate', {project_id: ${id}})`; + TemplateList.basePath = 'job_templates'; return TemplateList; }], Dataset: ['ListDefinition', 'QuerySet', '$stateParams', 'GetBasePath', '$interpolate', '$rootScope', diff --git a/awx/ui/client/src/shared/form-generator.js b/awx/ui/client/src/shared/form-generator.js index d90cac087a..6444370b3b 100644 --- a/awx/ui/client/src/shared/form-generator.js +++ b/awx/ui/client/src/shared/form-generator.js @@ -1950,29 +1950,31 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat if (collection.fieldActions) { html += "
"; for (act in collection.fieldActions) { - fAction = collection.fieldActions[act]; - html += ""; } - // html += SelectIcon({ action: act }); - //html += (fAction.label) ? " " + fAction.label + "": ""; - html += ""; } html += "
"; html += "\n";