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) {