diff --git a/awx/ui/client/features/jobs/index.js b/awx/ui/client/features/jobs/index.js index c26f2b9d8f..8bb692f0c8 100644 --- a/awx/ui/client/features/jobs/index.js +++ b/awx/ui/client/features/jobs/index.js @@ -1,5 +1,6 @@ import JobsStrings from './jobs.strings'; import jobsRoute from './routes/jobs.route'; +import { jobsSchedulesRoute, jobsSchedulesEditRoute } from '../../src/scheduler/schedules.route'; const MODULE_NAME = 'at.features.jobs'; @@ -8,6 +9,8 @@ angular .service('JobsStrings', JobsStrings) .run(['$stateExtender', ($stateExtender) => { $stateExtender.addState(jobsRoute); + $stateExtender.addState(jobsSchedulesRoute); + $stateExtender.addState(jobsSchedulesEditRoute); }]); export default MODULE_NAME; diff --git a/awx/ui/client/features/jobs/index.view.html b/awx/ui/client/features/jobs/index.view.html index 054e26c2ba..2328e24261 100644 --- a/awx/ui/client/features/jobs/index.view.html +++ b/awx/ui/client/features/jobs/index.view.html @@ -1,13 +1,14 @@ +
-
+
JOBS
-
+
SCHEDULES diff --git a/awx/ui/client/features/templates/index.view.html b/awx/ui/client/features/templates/index.view.html index 5f6ae703f6..346ab0c0f1 100644 --- a/awx/ui/client/features/templates/index.view.html +++ b/awx/ui/client/features/templates/index.view.html @@ -1,3 +1,4 @@ +
diff --git a/awx/ui/client/features/templates/templatesList.controller.js b/awx/ui/client/features/templates/templatesList.controller.js index 569bdc4b3a..5ad7388fd4 100644 --- a/awx/ui/client/features/templates/templatesList.controller.js +++ b/awx/ui/client/features/templates/templatesList.controller.js @@ -98,9 +98,9 @@ function ListTemplatesController( } if (isJobTemplate(template)) { - $state.go('jobTemplateSchedules', { id: template.id }); + $state.go('templates.editJobTemplate.schedules', { job_template_id: template.id }); } else if (isWorkflowTemplate(template)) { - $state.go('workflowJobTemplateSchedules', { id: template.id }); + $state.go('templates.editWorkflowJobTemplate.schedules', { workflow_job_template_id: template.id }); } else { Alert(strings.get('error.UNKNOWN'), strings.get('alert.UNKNOWN_SCHEDULE')); } diff --git a/awx/ui/client/src/inventories-hosts/inventories/inventories.partial.html b/awx/ui/client/src/inventories-hosts/inventories/inventories.partial.html index 73bb0becd1..282fa47ad2 100644 --- a/awx/ui/client/src/inventories-hosts/inventories/inventories.partial.html +++ b/awx/ui/client/src/inventories-hosts/inventories/inventories.partial.html @@ -1,6 +1,7 @@
+
diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js b/awx/ui/client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js index 104ff2574a..eb3c083cd4 100644 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js +++ b/awx/ui/client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js @@ -33,6 +33,7 @@ export default ['$state', '$stateParams', '$scope', 'ParseVariableString', {verbosity: inventorySourceData.verbosity}); $scope.inventory_source_obj = inventorySourceData; + $scope.breadcrumb.inventory_source_name = inventorySourceData.name; if (inventorySourceData.credential) { $scope.credential_name = inventorySourceData.summary_fields.credential.name; } diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.route.js b/awx/ui/client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.route.js index 2402b9fb08..dbc2337357 100644 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.route.js +++ b/awx/ui/client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.route.js @@ -1,11 +1,9 @@ -import { N_ } from '../../../../../i18n'; - export default { name: "inventories.edit.inventory_sources.edit", url: "/edit/:inventory_source_id", ncyBreadcrumb: { parent: "inventories.edit.inventory_sources", - label: N_("INVENTORY SOURCES") + label: '{{breadcrumb.inventory_source_name}}' }, views: { 'groupForm@inventories': { diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/schedule/sources-schedule-add.route.js b/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/schedule/sources-schedule-add.route.js index cb7ac3efb7..0b38774378 100644 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/schedule/sources-schedule-add.route.js +++ b/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/schedule/sources-schedule-add.route.js @@ -5,10 +5,11 @@ export default { name: 'inventories.edit.inventory_sources.edit.schedules.add', url: '/add', ncyBreadcrumb: { + parent: 'inventories.edit.inventory_sources.edit.schedules', label: N_("CREATE SCHEDULE") }, views: { - 'form': { + 'scheduler@inventories': { controller: 'schedulerAddController', templateUrl: templateUrl("scheduler/schedulerForm") } diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/schedule/sources-schedule-edit.route.js b/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/schedule/sources-schedule-edit.route.js index 0fc89af835..2c956fd6cd 100644 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/schedule/sources-schedule-edit.route.js +++ b/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/schedule/sources-schedule-edit.route.js @@ -1,15 +1,18 @@ import {templateUrl} from '../../../../../../shared/template-url/template-url.factory'; +import editScheduleResolve from '../../../../../../scheduler/editSchedule.resolve'; export default { name: 'inventories.edit.inventory_sources.edit.schedules.edit', url: '/:schedule_id', ncyBreadcrumb: { - label: "{{schedule_obj.name}}" + parent: 'inventories.edit.inventory_sources.edit.schedules', + label: "{{breadcrumb.schedule_name}}" }, views: { - 'form': { + 'scheduler@inventories': { templateUrl: templateUrl("scheduler/schedulerForm"), controller: 'schedulerEditController', } - } + }, + resolve: editScheduleResolve() }; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/schedule/sources-schedule.route.js b/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/schedule/sources-schedule.route.js index 962263e673..aebe56b624 100644 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/schedule/sources-schedule.route.js +++ b/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/schedule/sources-schedule.route.js @@ -1,21 +1,35 @@ import { N_ } from '../../../../../../i18n'; export default { + searchPrefix: 'schedule', name: 'inventories.edit.inventory_sources.edit.schedules', url: '/schedules', - searchPrefix: 'schedule', ncyBreadcrumb: { + parent: 'inventories.edit.inventory_sources.edit', label: N_('SCHEDULES') }, + views: { + 'related': { + templateProvider: function(SchedulesList, generateList){ + SchedulesList.title = false; + let html = generateList.build({ + list: SchedulesList, + mode: 'edit' + }); + return html; + }, + controller: 'schedulerListController' + } + }, resolve: { - Dataset: ['ScheduleList', 'QuerySet', '$stateParams', 'GetBasePath', 'inventorySourceData', - function(list, qs, $stateParams, GetBasePath, inventorySourceData) { - let path = `${inventorySourceData.related.schedules}`; + Dataset: ['ScheduleList', 'QuerySet', '$stateParams', 'GetBasePath', 'inventorySource', + function(list, qs, $stateParams, GetBasePath, inventorySource) { + let path = `${inventorySource.get().related.schedules}`; return qs.search(path, $stateParams[`${list.iterator}_search`]); } ], - ParentObject: ['inventorySourceData', function(inventorySourceData) { - return inventorySourceData; + ParentObject: ['inventorySource', function(inventorySource) { + return inventorySource.get(); }], UnifiedJobsOptions: ['Rest', 'GetBasePath', '$stateParams', '$q', function(Rest, GetBasePath, $stateParams, $q) { @@ -29,32 +43,12 @@ export default { }); return val.promise; }], - ScheduleList: ['SchedulesList', 'inventorySourceData', - (SchedulesList, inventorySourceData) => { + ScheduleList: ['SchedulesList', 'inventorySource', + (SchedulesList, inventorySource) => { let list = _.cloneDeep(SchedulesList); - list.basePath = `${inventorySourceData.related.schedules}`; + list.basePath = `${inventorySource.get().related.schedules}`; return list; } ] - }, - views: { - // clear form template when views render in this substate - 'form': { - templateProvider: () => '' - }, - // target the un-named ui-view @ root level - '@': { - templateProvider: function(ScheduleList, generateList, ParentObject, $filter) { - // include name of parent resource in listTitle - ScheduleList.listTitle = `${$filter('sanitize')(ParentObject.name)}
` + N_('SCHEDULES'); - let html = generateList.build({ - list: ScheduleList, - mode: 'edit' - }); - html = generateList.wrapPanel(html); - return "
" + generateList.insertFormView() + html + "
"; - }, - controller: 'schedulerListController' - } } }; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js b/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js index 25d88d695e..6b2d43ee55 100644 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js +++ b/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js @@ -222,7 +222,7 @@ $scope.scheduleSource = function(id) { // Add this inv source's id to the array of inv source id's so that it gets // added to the breadcrumb trail - $state.go('inventories.edit.inventory_sources.edit.schedules', {inventory_source_id: id}, {reload: true}); + $state.go('inventories.edit.inventory_sources.edit.schedules',{inventory_source_id: id}); }; $scope.syncAllSources = function() { diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/sources.form.js b/awx/ui/client/src/inventories-hosts/inventories/related/sources/sources.form.js index d7d6e31c2b..89299827b9 100644 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/sources.form.js +++ b/awx/ui/client/src/inventories-hosts/inventories/related/sources/sources.form.js @@ -411,8 +411,14 @@ return { }, related: { - notifications: notifications_object + notifications: notifications_object, + schedules: { + title: i18n._('Schedules'), + skipGenerator: true, + ngClick: "$state.go('inventories.edit.inventory_sources.edit.schedules')" + } } + }; }]; diff --git a/awx/ui/client/src/organizations/linkout/controllers/organizations-job-templates.controller.js b/awx/ui/client/src/organizations/linkout/controllers/organizations-job-templates.controller.js index 2d5e0eab40..67003502ce 100644 --- a/awx/ui/client/src/organizations/linkout/controllers/organizations-job-templates.controller.js +++ b/awx/ui/client/src/organizations/linkout/controllers/organizations-job-templates.controller.js @@ -74,27 +74,7 @@ export default ['$scope', '$rootScope', }; $scope.scheduleJob = function(id) { - $state.go('jobTemplateSchedules', { id: id }); + $state.go('templates.editJobTemplate.schedules', { id: id }); }; - - // $scope.copyTemplate = function(id) { - // Wait('start'); - // TemplateCopyService.get(id) - // .then((data) => { - // TemplateCopyService.set(data.results) - // .then((results) => { - // Wait('stop'); - // if(results.type && results.type === 'job_template') { - // $state.go('templates.editJobTemplate', {job_template_id: results.id}, {reload: true}); - // } - // }); - // }) - // .catch(({data, status}) => { - // ProcessErrors($rootScope, data, status, null, {hdr: 'Error!', - // msg: 'Call failed. Return status: '+ status}); - // }); - // - // }; - } ]; diff --git a/awx/ui/client/src/organizations/linkout/controllers/organizations-projects.controller.js b/awx/ui/client/src/organizations/linkout/controllers/organizations-projects.controller.js index 51e753c8a4..48a59a967d 100644 --- a/awx/ui/client/src/organizations/linkout/controllers/organizations-projects.controller.js +++ b/awx/ui/client/src/organizations/linkout/controllers/organizations-projects.controller.js @@ -301,7 +301,7 @@ export default ['$scope', '$rootScope', '$log', '$stateParams', 'Rest', 'Alert', $scope.editSchedules = function(id) { var project = Find({ list: $scope.projects, key: 'id', val: id }); if (!(project.scm_type === "Manual" || Empty(project.scm_type)) && !(project.status === 'updating' || project.status === 'running' || project.status === 'pending')) { - $state.go('projectSchedules', { id: id }); + $state.go('projects.edit.schedules', { project_id: id }); } }; diff --git a/awx/ui/client/src/projects/edit/projects-edit.controller.js b/awx/ui/client/src/projects/edit/projects-edit.controller.js index 2aa9434c15..8f28ac1b79 100644 --- a/awx/ui/client/src/projects/edit/projects-edit.controller.js +++ b/awx/ui/client/src/projects/edit/projects-edit.controller.js @@ -156,6 +156,7 @@ export default ['$scope', '$rootScope', '$stateParams', 'ProjectsForm', 'Rest', $scope.project_obj = data; $scope.name = data.name; + $scope.breadcrumb.project_name = data.name; $scope.$emit('projectLoaded'); Wait('stop'); }) diff --git a/awx/ui/client/src/projects/list/projects-list.controller.js b/awx/ui/client/src/projects/list/projects-list.controller.js index bea12bdf0d..c4aa5db6c8 100644 --- a/awx/ui/client/src/projects/list/projects-list.controller.js +++ b/awx/ui/client/src/projects/list/projects-list.controller.js @@ -332,7 +332,7 @@ export default ['$scope', '$rootScope', '$log', 'Rest', 'Alert', $scope.editSchedules = function(id) { var project = Find({ list: $scope.projects, key: 'id', val: id }); if (!(project.scm_type === "Manual" || Empty(project.scm_type)) && !(project.status === 'updating' || project.status === 'running' || project.status === 'pending')) { - $state.go('projectSchedules', { id: id }); + $state.go('projects.edit.schedules', { project_id: id }); } }; } diff --git a/awx/ui/client/src/projects/main.js b/awx/ui/client/src/projects/main.js index 8f186e5458..144fb99b91 100644 --- a/awx/ui/client/src/projects/main.js +++ b/awx/ui/client/src/projects/main.js @@ -13,6 +13,11 @@ 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 { + projectsSchedulesListRoute, + projectsSchedulesAddRoute, + projectsSchedulesEditRoute +} from '../scheduler/schedules.route'; import ProjectsTemplatesRoute from '~features/templates/routes/projectsTemplatesList.route'; import ProjectsStrings from './projects.strings'; @@ -66,6 +71,7 @@ angular.module('Projects', []) let projectTree = stateDefinitions.generateTree({ parent: 'projects', // top-most node in the generated tree (will replace this state definition) modes: ['add', 'edit'], + generateSchedulerView: true, list: 'ProjectList', form: 'ProjectsForm', controllers: { @@ -85,6 +91,9 @@ angular.module('Projects', []) ncyBreadcrumb: { label: N_('PROJECTS') }, + breadcrumbs: { + edit: '{{breadcrumb.project_name}}' + }, resolve: { add: projectResolve, edit: projectResolve @@ -99,6 +108,9 @@ angular.module('Projects', []) return result.concat(definition.states); }, [ stateExtender.buildDefinition(ProjectsTemplatesRoute), + stateExtender.buildDefinition(projectsSchedulesListRoute), + stateExtender.buildDefinition(projectsSchedulesAddRoute), + stateExtender.buildDefinition(projectsSchedulesEditRoute) ]) }; }); diff --git a/awx/ui/client/src/projects/projects.form.js b/awx/ui/client/src/projects/projects.form.js index 6b0454a1bc..bd82dabbc2 100644 --- a/awx/ui/client/src/projects/projects.form.js +++ b/awx/ui/client/src/projects/projects.form.js @@ -285,6 +285,11 @@ export default ['i18n', 'NotificationsList', 'TemplateList', templates: { include: "TemplateList", }, + schedules: { + title: i18n._('Schedules'), + skipGenerator: true, + ngClick: "$state.go('projects.edit.schedules')" + } } }; diff --git a/awx/ui/client/src/scheduler/editSchedule.resolve.js b/awx/ui/client/src/scheduler/editSchedule.resolve.js index 9d6e777896..f65dc17b9c 100644 --- a/awx/ui/client/src/scheduler/editSchedule.resolve.js +++ b/awx/ui/client/src/scheduler/editSchedule.resolve.js @@ -3,7 +3,6 @@ function editScheduleResolve () { scheduleResolve: ['Rest', '$stateParams', 'GetBasePath', 'ProcessErrors', (Rest, $stateParams, GetBasePath, ProcessErrors) => { var path = `${GetBasePath('schedules')}${parseInt($stateParams.schedule_id)}/`; - // const path = GetBasePath('schedules') + parseInt($stateParams.schedule_id) + '/'); Rest.setUrl(path); return Rest.get() .then(function(data) { diff --git a/awx/ui/client/src/scheduler/main.js b/awx/ui/client/src/scheduler/main.js index b20b77b349..038053e83a 100644 --- a/awx/ui/client/src/scheduler/main.js +++ b/awx/ui/client/src/scheduler/main.js @@ -7,16 +7,13 @@ import listController from './schedulerList.controller'; import addController from './schedulerAdd.controller'; import editController from './schedulerEdit.controller'; -import {templateUrl} from '../shared/template-url/template-url.factory'; import schedulerDatePicker from './schedulerDatePicker.directive'; -import { N_ } from '../i18n'; import DeleteSchedule from './factories/delete-schedule.factory'; import RRuleToAPI from './factories/r-rule-to-api.factory'; import SchedulePost from './factories/schedule-post.factory'; import ToggleSchedule from './factories/toggle-schedule.factory'; import SchedulesList from './schedules.list'; import ScheduledJobsList from './scheduled-jobs.list'; -import editScheduleResolve from './editSchedule.resolve'; export default angular.module('scheduler', []) @@ -29,341 +26,4 @@ export default .factory('ToggleSchedule', ToggleSchedule) .factory('SchedulesList', SchedulesList) .factory('ScheduledJobsList', ScheduledJobsList) - .directive('schedulerDatePicker', schedulerDatePicker) - .run(['$stateExtender', function($stateExtender) { - // Inventory sync schedule states registered in: awx/ui/client/src/inventories/manage/groups/main.js - // Scheduled jobs states registered in awx/uiclient/src/job-detail/main.js - - // job templates - $stateExtender.addState({ - searchPrefix: 'schedule', - name: 'jobTemplateSchedules', - route: '/templates/job_template/:id/schedules', - data: { - activityStream: true, - activityStreamTarget: 'job_template', - activityStreamId: 'id' - }, - // ncyBreadcrumb: { - // parent: 'templates.editJobTemplate({job_template_id: parentObject.id})', - // label: N_('SCHEDULES') - // }, - resolve: { - Dataset: ['ScheduleList', 'QuerySet', '$stateParams', 'GetBasePath', - function(list, qs, $stateParams, GetBasePath) { - let path = `${GetBasePath('job_templates')}${$stateParams.id}/schedules`; - return qs.search(path, $stateParams[`${list.iterator}_search`]); - } - ], - ParentObject: ['$stateParams', 'Rest', 'GetBasePath', function($stateParams, Rest, GetBasePath){ - let path = `${GetBasePath('job_templates')}${$stateParams.id}`; - Rest.setUrl(path); - return Rest.get(path).then(response => response.data); - }], - UnifiedJobsOptions: ['Rest', 'GetBasePath', '$stateParams', '$q', - function(Rest, GetBasePath, $stateParams, $q) { - Rest.setUrl(GetBasePath('unified_jobs')); - var val = $q.defer(); - Rest.options() - .then(function(data) { - val.resolve(data.data); - }, function(data) { - val.reject(data); - }); - return val.promise; - }], - ScheduleList: ['SchedulesList', 'GetBasePath', '$stateParams', - (SchedulesList, GetBasePath, $stateParams) => { - let list = _.cloneDeep(SchedulesList); - list.basePath = GetBasePath('job_templates') + $stateParams.id + '/schedules/'; - return list; - } - ] - }, - views: { - '@': { - templateProvider: function(ScheduleList, generateList, ParentObject, $filter){ - // include name of parent resource in listTitle - ScheduleList.listTitle = `${$filter('sanitize')(ParentObject.name)}
` + N_('SCHEDULES'); - let html = generateList.build({ - list: ScheduleList, - mode: 'edit' - }); - html = generateList.wrapPanel(html); - return generateList.insertFormView() + html; - }, - controller: 'schedulerListController' - } - } - }); - $stateExtender.addState({ - name: 'jobTemplateSchedules.add', - route: '/add', - views: { - 'form': { - controller: 'schedulerAddController', - templateUrl: templateUrl("scheduler/schedulerForm"), - } - }, - ncyBreadcrumb: { - parent: 'jobTemplateSchedules', - label: N_('CREATE SCHEDULE') - } - }); - $stateExtender.addState({ - name: 'jobTemplateSchedules.edit', - route: '/:schedule_id', - views: { - 'form': { - controller: 'schedulerEditController', - templateUrl: templateUrl("scheduler/schedulerForm"), - } - }, - ncyBreadcrumb: { - parent: 'jobTemplateSchedules', - label: '{{schedule_obj.name}}' - }, - resolve: editScheduleResolve() - }); - - // workflows - $stateExtender.addState({ - searchPrefix: 'schedule', - name: 'workflowJobTemplateSchedules', - route: '/templates/workflow_job_template/:id/schedules', - data: { - activityStream: true, - activityStreamTarget: 'job_template', - activityStreamId: 'id' - }, - ncyBreadcrumb: { - parent: 'templates.editWorkflowJobTemplate({workflow_job_template_id: parentObject.id})', - label: N_('SCHEDULES') - }, - resolve: { - Dataset: ['ScheduleList', 'QuerySet', '$stateParams', 'GetBasePath', - function(list, qs, $stateParams, GetBasePath) { - let path = `${GetBasePath('workflow_job_templates')}${$stateParams.id}/schedules`; - return qs.search(path, $stateParams[`${list.iterator}_search`]); - } - ], - ParentObject: ['$stateParams', 'Rest', 'GetBasePath', function($stateParams, Rest, GetBasePath){ - let path = `${GetBasePath('workflow_job_templates')}${$stateParams.id}`; - Rest.setUrl(path); - return Rest.get(path).then(response => response.data); - }], - UnifiedJobsOptions: ['Rest', 'GetBasePath', '$stateParams', '$q', - function(Rest, GetBasePath, $stateParams, $q) { - Rest.setUrl(GetBasePath('unified_jobs')); - var val = $q.defer(); - Rest.options() - .then(function(data) { - val.resolve(data.data); - }, function(data) { - val.reject(data); - }); - return val.promise; - }], - ScheduleList: ['SchedulesList', 'GetBasePath', '$stateParams', - (SchedulesList, GetBasePath, $stateParams) => { - let list = _.cloneDeep(SchedulesList); - list.basePath = GetBasePath('workflow_job_templates') + $stateParams.id + '/schedules/'; - return list; - } - ] - }, - views: { - '@': { - templateProvider: function(ScheduleList, generateList, ParentObject, $filter){ - // include name of parent resource in listTitle - ScheduleList.listTitle = `${$filter('sanitize')(ParentObject.name)}
` + N_('SCHEDULES'); - let html = generateList.build({ - list: ScheduleList, - mode: 'edit' - }); - html = generateList.wrapPanel(html); - return generateList.insertFormView() + html; - }, - controller: 'schedulerListController' - } - } - }); - $stateExtender.addState({ - name: 'workflowJobTemplateSchedules.add', - route: '/add', - views: { - 'form': { - controller: 'schedulerAddController', - templateUrl: templateUrl("scheduler/schedulerForm"), - } - }, - ncyBreadcrumb: { - parent: 'workflowJobTemplateSchedules', - label: N_('CREATE SCHEDULE') - } - }); - $stateExtender.addState({ - name: 'workflowJobTemplateSchedules.edit', - route: '/:schedule_id', - views: { - 'form': { - controller: 'schedulerEditController', - templateUrl: templateUrl("scheduler/schedulerForm"), - } - }, - ncyBreadcrumb: { - parent: 'workflowJobTemplateSchedules', - label: '{{schedule_obj.name}}' - }, - resolve: editScheduleResolve() - }); - // projects - $stateExtender.addState({ - searchPrefix: 'schedule', - name: 'projectSchedules', - route: '/projects/:id/schedules', - data: { - activityStream: true, - activityStreamTarget: 'project', - activityStreamId: 'id' - }, - ncyBreadcrumb: { - parent: 'projects.edit({project_id: parentObject.id})', - label: N_('SCHEDULES') - }, - resolve: { - Dataset: ['ScheduleList', 'QuerySet', '$stateParams', 'GetBasePath', - function(list, qs, $stateParams, GetBasePath) { - let path = `${GetBasePath('projects')}${$stateParams.id}/schedules`; - return qs.search(path, $stateParams[`${list.iterator}_search`]); - } - ], - ParentObject: ['$stateParams', 'Rest', 'GetBasePath', function($stateParams, Rest, GetBasePath){ - let path = `${GetBasePath('projects')}${$stateParams.id}`; - Rest.setUrl(path); - return Rest.get(path).then(response => response.data); - }], - UnifiedJobsOptions: ['Rest', 'GetBasePath', '$stateParams', '$q', - function(Rest, GetBasePath, $stateParams, $q) { - Rest.setUrl(GetBasePath('unified_jobs')); - var val = $q.defer(); - Rest.options() - .then(function(data) { - val.resolve(data.data); - }, function(data) { - val.reject(data); - }); - return val.promise; - }], - ScheduleList: ['SchedulesList', 'GetBasePath', '$stateParams', - (SchedulesList, GetBasePath, $stateParams) => { - let list = _.cloneDeep(SchedulesList); - list.basePath = GetBasePath('projects') + $stateParams.id + '/schedules/'; - return list; - } - ] - }, - views: { - '@': { - templateProvider: function(ScheduleList, generateList, ParentObject, $filter){ - // include name of parent resource in listTitle - ScheduleList.listTitle = `${$filter('sanitize')(ParentObject.name)}
` + N_('SCHEDULES'); - let html = generateList.build({ - list: ScheduleList, - mode: 'edit' - }); - html = generateList.wrapPanel(html); - return generateList.insertFormView() + html; - }, - controller: 'schedulerListController' - } - } - }); - - $stateExtender.addState({ - name: 'projectSchedules.add', - route: '/add', - ncyBreadcrumb: { - label: N_('CREATE SCHEDULE') - }, - views: { - 'form': { - controller: 'schedulerAddController', - templateUrl: templateUrl("scheduler/schedulerForm"), - } - } - }); - $stateExtender.addState({ - name: 'projectSchedules.edit', - route: '/:schedule_id', - ncyBreadcrumb: { - label: '{{schedule_obj.name}}' - }, - views: { - 'form': { - controller: 'schedulerEditController', - templateUrl: templateUrl("scheduler/schedulerForm"), - } - }, - resolve: editScheduleResolve() - }); - // upcoming scheduled jobs - $stateExtender.addState({ - searchPrefix: 'schedule', - name: 'jobs.schedules', - route: '/schedules', - params: { - schedule_search: { - value: { - next_run__isnull: 'false', - order_by: 'unified_job_template__polymorphic_ctype__model' - }, - dynamic: true - } - }, - data: { - activityStream: false, - }, - ncyBreadcrumb: { - parent: 'jobs', - label: N_('SCHEDULED') - }, - resolve: { - ScheduleList: ['ScheduledJobsList', function(list){ - return list; - }], - Dataset: ['ScheduleList', 'QuerySet', '$stateParams', 'GetBasePath', - function(list, qs, $stateParams, GetBasePath) { - let path = GetBasePath('schedules'); - return qs.search(path, $stateParams[`${list.iterator}_search`]); - } - ], - ParentObject: ['GetBasePath', (GetBasePath) =>{return {endpoint:GetBasePath('schedules')}; }], - UnifiedJobsOptions: ['Rest', 'GetBasePath', '$stateParams', '$q', - function(Rest, GetBasePath, $stateParams, $q) { - Rest.setUrl(GetBasePath('unified_jobs')); - var val = $q.defer(); - Rest.options() - .then(function(data) { - val.resolve(data.data); - }, function(data) { - val.reject(data); - }); - return val.promise; - }] - }, - views: { - 'schedulesList@jobs': { - templateProvider: function(ScheduleList, generateList){ - let html = generateList.build({ - list: ScheduleList, - mode: 'edit', - title: false - }); - return html; - }, - controller: 'schedulerListController' - } - } - }); - }]); + .directive('schedulerDatePicker', schedulerDatePicker); diff --git a/awx/ui/client/src/scheduler/schedulerAdd.controller.js b/awx/ui/client/src/scheduler/schedulerAdd.controller.js index d312083bd2..5c87f3c484 100644 --- a/awx/ui/client/src/scheduler/schedulerAdd.controller.js +++ b/awx/ui/client/src/scheduler/schedulerAdd.controller.js @@ -8,12 +8,12 @@ export default ['$filter', '$state', '$stateParams', '$http', 'Wait', '$scope', '$rootScope', 'CreateSelect2', 'ParseTypeChange', 'GetBasePath', 'Rest', 'ParentObject', 'JobTemplateModel', '$q', 'Empty', 'SchedulePost', 'ProcessErrors', 'SchedulerInit', '$location', 'PromptService', 'RRuleToAPI', 'moment', - 'WorkflowJobTemplateModel', 'TemplatesStrings', + 'WorkflowJobTemplateModel', 'TemplatesStrings', 'rbacUiControlService', function($filter, $state, $stateParams, $http, Wait, $scope, $rootScope, CreateSelect2, ParseTypeChange, GetBasePath, Rest, ParentObject, JobTemplate, $q, Empty, SchedulePost, ProcessErrors, SchedulerInit, $location, PromptService, RRuleToAPI, moment, - WorkflowJobTemplate, TemplatesStrings + WorkflowJobTemplate, TemplatesStrings, rbacUiControlService ) { var base = $scope.base || $location.path().replace(/^\//, '').split('/')[0], @@ -21,7 +21,15 @@ export default ['$filter', '$state', '$stateParams', '$http', 'Wait', job_type; var schedule_url = ParentObject.related.schedules || `${ParentObject.related.inventory_source}schedules`; - + if (ParentObject){ + $scope.parentObject = ParentObject; + let scheduleEndpoint = ParentObject.endpoint|| ParentObject.related.schedules || `${ParentObject.related.inventory_source}schedules`; + $scope.canAdd = false; + rbacUiControlService.canAdd(scheduleEndpoint) + .then(function(params) { + $scope.canAdd = params.canAdd; + }); + } let processSchedulerEndDt = function(){ // set the schedulerEndDt to be equal to schedulerStartDt + 1 day @ midnight var dt = new Date($scope.schedulerUTCTime); @@ -90,7 +98,7 @@ export default ['$filter', '$state', '$stateParams', '$http', 'Wait', $scope.hideForm = true; // extra_data field is not manifested in the UI when scheduling a Management Job - if ($state.current.name === 'jobTemplateSchedules.add'){ + if ($state.current.name === 'templates.editJobTemplate.schedules.add'){ $scope.parseType = 'yaml'; let jobTemplate = new JobTemplate(); @@ -206,7 +214,7 @@ export default ['$filter', '$state', '$stateParams', '$http', 'Wait', } } }); - } else if ($state.current.name === 'workflowJobTemplateSchedules.add'){ + } else if ($state.current.name === 'templates.editWorkflowJobTemplate.schedules.add'){ let workflowJobTemplate = new WorkflowJobTemplate(); $q.all([workflowJobTemplate.optionsLaunch(ParentObject.id), workflowJobTemplate.getLaunch(ParentObject.id)]) @@ -276,8 +284,8 @@ export default ['$filter', '$state', '$stateParams', '$http', 'Wait', }); } - if ($state.current.name === 'workflowJobTemplateSchedules.add' || - $state.current.name === 'projectSchedules.add' || + if ($state.current.name === 'templates.editWorkflowJobTemplate.schedules.add' || + $state.current.name === 'projects.edit.schedules.add' || $state.current.name === 'inventories.edit.inventory_sources.edit.schedules.add' ){ $scope.noVars = true; diff --git a/awx/ui/client/src/scheduler/schedulerEdit.controller.js b/awx/ui/client/src/scheduler/schedulerEdit.controller.js index e247a22322..b50f6dbb52 100644 --- a/awx/ui/client/src/scheduler/schedulerEdit.controller.js +++ b/awx/ui/client/src/scheduler/schedulerEdit.controller.js @@ -132,7 +132,7 @@ function($filter, $state, $stateParams, Wait, $scope, moment, // sets the UNTIL portion of the schedule form after the angular-scheduler // sets it, but this function reads the 'until' key/value pair directly - // from the schedule GET response. + // from the schedule GET response. function setUntil (scheduler) { let { until } = scheduleResolve; if(until !== ''){ @@ -223,13 +223,16 @@ function($filter, $state, $stateParams, Wait, $scope, moment, $scope.showRRuleDetail = false; scheduler.setRRule(schedule.rrule); scheduler.setName(schedule.name); + $rootScope.breadcrumb.schedule_name = $scope.schedulerName; + $rootScope.breadcrumb[`${$scope.parentObject.type}_name`] = $scope.parentObject.name; + $scope.noVars = true; scheduler.scope.timeZones = timezonesResolve; scheduler.scope.schedulerTimeZone = scheduleResolve.timezone; if ($scope.cleanupJob){ $scope.schedulerPurgeDays = Number(schedule.extra_data.days); } - if ($state.current.name === 'jobTemplateSchedules.edit'){ + if ($state.current.name === 'templates.editJobTemplate.schedules.edit' || $scope.parentObject.type === 'job_template'){ let jobTemplate = new JobTemplate(); @@ -295,7 +298,19 @@ function($filter, $state, $stateParams, Wait, $scope, moment, prompts.credentials.value = defaultCredsWithoutOverrides.concat(scheduleCredentials); - if (!launchConf.ask_variables_on_launch) { + if (launchConf.ask_variables_on_launch) { + // the extra vars codemirror is ONLY shown if the + // schedule is for a JT and the JT has + // ask_variables_on_launch = true. + $scope.extraVars = ParentObject.extra_vars === '' ? '---' : ParentObject.extra_vars; + $scope.noVars = false; + ParseTypeChange({ + scope: $scope, + variable: 'extraVars', + parse_variable: 'parseType', + field_id: 'SchedulerForm-extraVars' + }); + } else { $scope.noVars = true; } @@ -378,7 +393,7 @@ function($filter, $state, $stateParams, Wait, $scope, moment, } } }); - } else if ($state.current.name === 'workflowJobTemplateSchedules.edit') { + } else if ($state.current.name === 'templates.editWorkflowJobTemplate.schedules.edit' || $scope.parentObject.type === 'workflow_job_template') { let workflowJobTemplate = new WorkflowJobTemplate(); $q.all([workflowJobTemplate.optionsLaunch(ParentObject.id), workflowJobTemplate.getLaunch(ParentObject.id)]) @@ -447,26 +462,10 @@ function($filter, $state, $stateParams, Wait, $scope, moment, } } }); - } - // extra_data field is not manifested in the UI when scheduling a Management Job - if ($state.current.name !== 'managementJobsList.schedule.add' && $state.current.name !== 'managementJobsList.schedule.edit'){ - if ($state.current.name === 'projectSchedules.edit' || - $state.current.name === 'inventories.edit.inventory_sources.edit.schedules.edit' || - $state.current.name === 'workflowJobTemplateSchedules.add' - ){ - $scope.noVars = true; - } else { - ParseTypeChange({ - scope: $scope, - variable: 'extraVars', - parse_variable: 'parseType', - field_id: 'SchedulerForm-extraVars', - readOnly: !$scope.schedule_obj.summary_fields.user_capabilities.edit - }); - } } } + init(); callSelect2(); diff --git a/awx/ui/client/src/scheduler/schedulerList.controller.js b/awx/ui/client/src/scheduler/schedulerList.controller.js index 3ae664216a..e09566a797 100644 --- a/awx/ui/client/src/scheduler/schedulerList.controller.js +++ b/awx/ui/client/src/scheduler/schedulerList.controller.js @@ -137,14 +137,14 @@ export default [ if($state.current.name.endsWith('.edit')) { $state.go('^.add'); } - else if(!$state.current.name.endsWith('.add')) { + if(!$state.current.name.endsWith('.add')) { $state.go('.add'); } }; $scope.editSchedule = function(schedule) { if ($state.is('jobs.schedules')){ - routeToScheduleForm(schedule, 'edit'); + $state.go('jobs.schedules.edit', {schedule_id: schedule.id}); } else { if($state.current.name.endsWith('.add')) { @@ -157,75 +157,6 @@ export default [ $state.go('.edit', { schedule_id: schedule.id }); } } - - function buildStateMap(schedule){ - - let deferred = $q.defer(); - - switch(schedule.summary_fields.unified_job_template.unified_job_type){ - case 'job': - deferred.resolve({ - name: 'jobTemplateSchedules.edit', - params: { - id: schedule.unified_job_template, - schedule_id: schedule.id - } - }); - break; - - case 'workflow_job': - deferred.resolve({ - name: 'workflowJobTemplateSchedules.edit', - params: { - id: schedule.unified_job_template, - schedule_id: schedule.id - } - }); - break; - - case 'inventory_update': - Rest.setUrl(schedule.related.unified_job_template); - Rest.get().then( (res) => { - deferred.resolve({ - name: 'inventories.edit.inventory_sources.edit.schedules.edit', - params: { - inventory_source_id: res.data.id, - inventory_id: res.data.inventory, - schedule_id: schedule.id, - } - }); - }); - break; - - case 'project_update': - deferred.resolve({ - name: 'projectSchedules.edit', - params: { - id: schedule.unified_job_template, - schedule_id: schedule.id - } - }); - break; - - case 'system_job': - deferred.resolve({ - name: 'managementJobsList.schedule.edit', - params: { - id: schedule.unified_job_template, - schedule_id: schedule.id - } - }); - break; - } - - return deferred.promise; - } - - function routeToScheduleForm(schedule){ - buildStateMap(schedule).then((state) =>{ - $state.go(state.name, state.params); - }); - } }; $scope.toggleSchedule = function(event, id) { diff --git a/awx/ui/client/src/scheduler/schedules.route.js b/awx/ui/client/src/scheduler/schedules.route.js new file mode 100644 index 0000000000..965b42f97d --- /dev/null +++ b/awx/ui/client/src/scheduler/schedules.route.js @@ -0,0 +1,369 @@ +import { N_ } from '../i18n'; +import {templateUrl} from '../shared/template-url/template-url.factory'; +import editScheduleResolve from './editSchedule.resolve'; + +const jobTemplatesSchedulesListRoute = { + searchPrefix: 'schedule', + name: 'templates.editJobTemplate.schedules', + route: '/schedules', + data: { + activityStream: true, + activityStreamTarget: 'job_template', + activityStreamId: 'id' + }, + ncyBreadcrumb: { + label: N_('SCHEDULES') + }, + resolve: { + Dataset: ['ScheduleList', 'QuerySet', '$stateParams', 'GetBasePath', + function(list, qs, $stateParams, GetBasePath) { + let path = `${GetBasePath('job_templates')}${$stateParams.job_template_id}/schedules`; + return qs.search(path, $stateParams[`${list.iterator}_search`]); + } + ], + ParentObject: ['$stateParams', 'Rest', 'GetBasePath', function($stateParams, Rest, GetBasePath){ + let path = `${GetBasePath('job_templates')}${$stateParams.job_template_id}`; + Rest.setUrl(path); + return Rest.get(path).then(response => response.data); + }], + UnifiedJobsOptions: ['Rest', 'GetBasePath', '$q', + function(Rest, GetBasePath, $q) { + Rest.setUrl(GetBasePath('unified_jobs')); + var val = $q.defer(); + Rest.options() + .then(function(data) { + val.resolve(data.data); + }, function(data) { + val.reject(data); + }); + return val.promise; + }], + ScheduleList: ['SchedulesList', 'GetBasePath', '$stateParams', + (SchedulesList, GetBasePath, $stateParams) => { + let list = _.cloneDeep(SchedulesList); + list.basePath = GetBasePath('job_templates') + $stateParams.job_template_id + '/schedules/'; + return list; + } + ] + }, + views: { + related: { + templateProvider: function(ScheduleList, generateList){ + ScheduleList.title = false; + let html = generateList.build({ + list: ScheduleList, + mode: 'edit' + }); + return html; + }, + controller: 'schedulerListController' + } + } +}; + +const jobTemplatesSchedulesAddRoute = { + name: 'templates.editJobTemplate.schedules.add', + route: '/add', + views: { + 'scheduler@templates': { + controller: 'schedulerAddController', + templateUrl: templateUrl("scheduler/schedulerForm"), + } + }, + ncyBreadcrumb: { + label: N_('CREATE SCHEDULE') + } +}; + +const jobTemplatesSchedulesEditRoute = { + name: 'templates.editJobTemplate.schedules.edit', + route: '/:schedule_id', + views: { + 'scheduler@templates': { + controller: 'schedulerEditController', + templateUrl: templateUrl("scheduler/schedulerForm"), + } + }, + ncyBreadcrumb: { + label: "{{breadcrumb.schedule_name}}" + }, + resolve: editScheduleResolve() +}; + +// workflows +const workflowSchedulesRoute = { + searchPrefix: 'schedule', + name: 'templates.editWorkflowJobTemplate.schedules', + route: '/schedules', + data: { + activityStream: true, + activityStreamTarget: 'job_template', + activityStreamId: 'id' + }, + ncyBreadcrumb: { + label: N_('SCHEDULES') + }, + resolve: { + Dataset: ['ScheduleList', 'QuerySet', '$stateParams', 'GetBasePath', + function(list, qs, $stateParams, GetBasePath) { + let path = `${GetBasePath('workflow_job_templates')}${$stateParams.workflow_job_template_id}/schedules`; + return qs.search(path, $stateParams[`${list.iterator}_search`]); + } + ], + ParentObject: ['$stateParams', 'Rest', 'GetBasePath', function($stateParams, Rest, GetBasePath){ + let path = `${GetBasePath('workflow_job_templates')}${$stateParams.workflow_job_template_id}`; + Rest.setUrl(path); + return Rest.get(path).then(response => response.data); + }], + UnifiedJobsOptions: ['Rest', 'GetBasePath', '$stateParams', '$q', + function(Rest, GetBasePath, $stateParams, $q) { + Rest.setUrl(GetBasePath('unified_jobs')); + var val = $q.defer(); + Rest.options() + .then(function(data) { + val.resolve(data.data); + }, function(data) { + val.reject(data); + }); + return val.promise; + }], + ScheduleList: ['SchedulesList', 'GetBasePath', '$stateParams', + (SchedulesList, GetBasePath, $stateParams) => { + let list = _.cloneDeep(SchedulesList); + list.basePath = GetBasePath('workflow_job_templates') + $stateParams.workflow_job_template_id + '/schedules/'; + return list; + } + ] + }, + views: { + related: { + templateProvider: function(ScheduleList, generateList){ + ScheduleList.title = false; + let html = generateList.build({ + list: ScheduleList, + mode: 'edit' + }); + return html; + }, + controller: 'schedulerListController' + } + } +}; + +const workflowSchedulesAddRoute = { + name: 'templates.editWorkflowJobTemplate.schedules.add', + route: '/add', + views: { + 'scheduler@templates': { + controller: 'schedulerAddController', + templateUrl: templateUrl("scheduler/schedulerForm"), + } + }, + ncyBreadcrumb: { + label: N_('CREATE SCHEDULE') + } +}; + +const workflowSchedulesEditRoute = { + name: 'templates.editWorkflowJobTemplate.schedules.edit', + route: '/:schedule_id', + views: { + 'scheduler@templates': { + controller: 'schedulerEditController', + templateUrl: templateUrl("scheduler/schedulerForm"), + } + }, + ncyBreadcrumb: { + label: '{{breadcrumb.schedule_name}}' + }, + resolve: editScheduleResolve() +}; + +const projectsSchedulesListRoute = { + searchPrefix: 'schedule', + name: 'projects.edit.schedules', + route: '/schedules', + data: { + activityStream: true, + activityStreamTarget: 'project', + activityStreamId: 'id' + }, + ncyBreadcrumb: { + label: N_('SCHEDULES') + }, + resolve: { + Dataset: ['ScheduleList', 'QuerySet', '$stateParams', 'GetBasePath', + function(list, qs, $stateParams, GetBasePath) { + let path = `${GetBasePath('projects')}${$stateParams.project_id}/schedules`; + return qs.search(path, $stateParams[`${list.iterator}_search`]); + } + ], + ParentObject: ['$stateParams', 'Rest', 'GetBasePath', function($stateParams, Rest, GetBasePath){ + let path = `${GetBasePath('projects')}${$stateParams.project_id}`; + Rest.setUrl(path); + return Rest.get(path).then(response => response.data); + }], + UnifiedJobsOptions: ['Rest', 'GetBasePath', '$stateParams', '$q', + function(Rest, GetBasePath, $stateParams, $q) { + Rest.setUrl(GetBasePath('unified_jobs')); + var val = $q.defer(); + Rest.options() + .then(function(data) { + val.resolve(data.data); + }, function(data) { + val.reject(data); + }); + return val.promise; + }], + ScheduleList: ['SchedulesList', 'GetBasePath', '$stateParams', + (SchedulesList, GetBasePath, $stateParams) => { + let list = _.cloneDeep(SchedulesList); + list.basePath = GetBasePath('projects') + $stateParams.project_id + '/schedules/'; + return list; + } + ] + }, + views: { + related: { + templateProvider: function(ScheduleList, generateList){ + ScheduleList.title = false; + let html = generateList.build({ + list: ScheduleList, + mode: 'edit' + }); + return html; + }, + controller: 'schedulerListController' + } + } +}; + +const projectsSchedulesAddRoute = { + name: 'projects.edit.schedules.add', + route: '/add', + ncyBreadcrumb: { + label: N_('CREATE SCHEDULE') + }, + views: { + 'scheduler@projects': { + controller: 'schedulerAddController', + templateUrl: templateUrl("scheduler/schedulerForm"), + } + } +}; + +const projectsSchedulesEditRoute = { + name: 'projects.edit.schedules.edit', + route: '/:schedule_id', + ncyBreadcrumb: { + label: "{{breadcrumb.schedule_name}}" + }, + views: { + 'scheduler@projects': { + controller: 'schedulerEditController', + templateUrl: templateUrl("scheduler/schedulerForm"), + } + }, + resolve: editScheduleResolve() +}; + +const jobsSchedulesRoute = { + searchPrefix: 'schedule', + name: 'jobs.schedules', + route: '/schedules', + params: { + schedule_search: { + value: { + next_run__isnull: 'false', + order_by: 'unified_job_template__polymorphic_ctype__model' + }, + dynamic: true + } + }, + data: { + activityStream: false, + }, + ncyBreadcrumb: { + parent: 'jobs', + label: N_('SCHEDULES') + }, + resolve: { + ScheduleList: ['ScheduledJobsList', function(list){ + return list; + }], + Dataset: ['ScheduleList', 'QuerySet', '$stateParams', 'GetBasePath', + function(list, qs, $stateParams, GetBasePath) { + let path = GetBasePath('schedules'); + return qs.search(path, $stateParams[`${list.iterator}_search`]); + } + ], + ParentObject: ['GetBasePath', (GetBasePath) =>{return {endpoint:GetBasePath('schedules')}; }], + UnifiedJobsOptions: ['Rest', 'GetBasePath', '$stateParams', '$q', + function(Rest, GetBasePath, $stateParams, $q) { + Rest.setUrl(GetBasePath('unified_jobs')); + var val = $q.defer(); + Rest.options() + .then(function(data) { + val.resolve(data.data); + }, function(data) { + val.reject(data); + }); + return val.promise; + }] + }, + views: { + 'schedulesList@jobs': { + templateProvider: function(ScheduleList, generateList){ + let html = generateList.build({ + list: ScheduleList, + mode: 'edit', + title: false + }); + return html; + }, + controller: 'schedulerListController' + } + } +}; + +// the /#/jobs/schedules/:schedule_id state needs to know about the type of +// resource is being scheduled. +const parentResolve = { + ParentObject: ['$stateParams', 'Rest', 'GetBasePath', 'scheduleResolve', + function($stateParams, Rest, GetBasePath, scheduleResolve){ + let path = scheduleResolve.related.unified_job_template; + Rest.setUrl(path); + return Rest.get(path).then(response => response.data); + } + ] +}; + +const jobsSchedulesEditRoute = { + name: 'jobs.schedules.edit', + route: '/:schedule_id', + ncyBreadcrumb: { + parent: 'jobs.schedules', + label: "{{breadcrumb.schedule_name}}" + }, + views: { + 'scheduler@jobs': { + controller: 'schedulerEditController', + templateUrl: templateUrl("scheduler/schedulerForm"), + } + }, + resolve: _.merge(editScheduleResolve(), parentResolve) +}; + +export { + jobTemplatesSchedulesListRoute, + jobTemplatesSchedulesAddRoute, + jobTemplatesSchedulesEditRoute, + workflowSchedulesRoute, + workflowSchedulesAddRoute, + workflowSchedulesEditRoute, + projectsSchedulesListRoute, + projectsSchedulesAddRoute, + projectsSchedulesEditRoute, + jobsSchedulesRoute, + jobsSchedulesEditRoute +}; diff --git a/awx/ui/client/src/shared/list-generator/list-generator.factory.js b/awx/ui/client/src/shared/list-generator/list-generator.factory.js index 4e1189095e..a1f7088769 100644 --- a/awx/ui/client/src/shared/list-generator/list-generator.factory.js +++ b/awx/ui/client/src/shared/list-generator/list-generator.factory.js @@ -594,6 +594,10 @@ export default ['$compile', 'Attr', 'Icon', insertFormView: function(){ return `
`; + }, + + insertSchedulerView: function(){ + return `
`; } }; } diff --git a/awx/ui/client/src/shared/stateDefinitions.factory.js b/awx/ui/client/src/shared/stateDefinitions.factory.js index 63182fa98f..99dc4f6f99 100644 --- a/awx/ui/client/src/shared/stateDefinitions.factory.js +++ b/awx/ui/client/src/shared/stateDefinitions.factory.js @@ -86,7 +86,11 @@ function($injector, $stateExtender, $log, i18n) { }); html = generateList.wrapPanel(html); // generateList.formView() inserts a ui-view="form" inside the list view's hierarchy - return generateList.insertFormView() + html; + html = generateList.insertFormView() + html; + if(params.generateSchedulerView){ + html = generateList.insertSchedulerView() + html; + } + return html; }; } } diff --git a/awx/ui/client/src/templates/job_templates/edit-job-template/job-template-edit.controller.js b/awx/ui/client/src/templates/job_templates/edit-job-template/job-template-edit.controller.js index a5a6a23946..85bc0882a2 100644 --- a/awx/ui/client/src/templates/job_templates/edit-job-template/job-template-edit.controller.js +++ b/awx/ui/client/src/templates/job_templates/edit-job-template/job-template-edit.controller.js @@ -278,6 +278,7 @@ export default $scope.removeLoadJobs = $scope.$on('LoadJobs', function() { $scope.job_template_obj = jobTemplateData; $scope.name = jobTemplateData.name; + $scope.breadcrumb.job_template_name = jobTemplateData.name; var fld, i; for (fld in form.fields) { if (fld !== 'extra_vars' && fld !== 'survey' && fld !== 'forks' && jobTemplateData[fld] !== null && jobTemplateData[fld] !== undefined) { diff --git a/awx/ui/client/src/templates/job_templates/job-template.form.js b/awx/ui/client/src/templates/job_templates/job-template.form.js index a3f83954f1..bfc1073c7f 100644 --- a/awx/ui/client/src/templates/job_templates/job-template.form.js +++ b/awx/ui/client/src/templates/job_templates/job-template.form.js @@ -438,6 +438,11 @@ function(NotificationsList, i18n) { title: i18n._('Completed Jobs'), skipGenerator: true, ngClick: "$state.go('templates.editJobTemplate.completed_jobs')" + }, + "schedules": { + title: i18n._('Schedules'), + skipGenerator: true, + ngClick: "$state.go('templates.editJobTemplate.schedules')" } }, diff --git a/awx/ui/client/src/templates/main.js b/awx/ui/client/src/templates/main.js index ac0c5036a0..4bb8a15b49 100644 --- a/awx/ui/client/src/templates/main.js +++ b/awx/ui/client/src/templates/main.js @@ -21,6 +21,14 @@ import TemplateList from './templates.list'; import listRoute from '~features/templates/routes/templatesList.route.js'; import templateCompletedJobsRoute from '~features/jobs/routes/templateCompletedJobs.route.js'; import workflowJobTemplateCompletedJobsRoute from '~features/jobs/routes/workflowJobTemplateCompletedJobs.route.js'; +import { + jobTemplatesSchedulesListRoute, + jobTemplatesSchedulesAddRoute, + jobTemplatesSchedulesEditRoute, + workflowSchedulesRoute, + workflowSchedulesAddRoute, + workflowSchedulesEditRoute +} from '../scheduler/schedules.route'; export default angular.module('templates', [surveyMaker.name, jobTemplates.name, labels.name, prompt.name, workflowAdd.name, workflowEdit.name, @@ -156,6 +164,9 @@ angular.module('templates', [surveyMaker.name, jobTemplates.name, labels.name, p activityStreamTarget: 'job_template', activityStreamId: 'job_template_id' }, + breadcrumbs: { + edit: '{{breadcrumb.job_template_name}}' + }, resolve: { edit: { jobTemplateData: ['$stateParams', 'TemplatesService', 'ProcessErrors', @@ -338,6 +349,9 @@ angular.module('templates', [surveyMaker.name, jobTemplates.name, labels.name, p activityStreamTarget: 'workflow_job_template', activityStreamId: 'workflow_job_template_id' }, + breadcrumbs: { + edit: '{{breadcrumb.workflow_job_template_name}}' + }, resolve: { edit: { availableLabels: ['Rest', '$stateParams', 'GetBasePath', 'ProcessErrors', 'TemplatesService', @@ -748,7 +762,13 @@ angular.module('templates', [surveyMaker.name, jobTemplates.name, labels.name, p stateExtender.buildDefinition(listRoute), stateExtender.buildDefinition(templateCompletedJobsRoute), stateExtender.buildDefinition(workflowJobTemplateCompletedJobsRoute), - stateExtender.buildDefinition(workflowMaker) + stateExtender.buildDefinition(workflowMaker), + stateExtender.buildDefinition(jobTemplatesSchedulesListRoute), + stateExtender.buildDefinition(jobTemplatesSchedulesAddRoute), + stateExtender.buildDefinition(jobTemplatesSchedulesEditRoute), + stateExtender.buildDefinition(workflowSchedulesRoute), + stateExtender.buildDefinition(workflowSchedulesAddRoute), + stateExtender.buildDefinition(workflowSchedulesEditRoute) ]) }; }); diff --git a/awx/ui/client/src/templates/workflows.form.js b/awx/ui/client/src/templates/workflows.form.js index 5812ed7435..42face36b2 100644 --- a/awx/ui/client/src/templates/workflows.form.js +++ b/awx/ui/client/src/templates/workflows.form.js @@ -181,6 +181,11 @@ export default ['NotificationsList', 'i18n', function(NotificationsList, i18n) { title: i18n._('Completed Jobs'), skipGenerator: true, ngClick: "$state.go('templates.editWorkflowJobTemplate.completed_jobs')" + }, + "schedules": { + title: i18n._('Schedules'), + skipGenerator: true, + ngClick: "$state.go('templates.editWorkflowJobTemplate.schedules')" } }, diff --git a/awx/ui/client/src/templates/workflows/edit-workflow/workflow-edit.controller.js b/awx/ui/client/src/templates/workflows/edit-workflow/workflow-edit.controller.js index 4d1bc567a7..0ef57520d9 100644 --- a/awx/ui/client/src/templates/workflows/edit-workflow/workflow-edit.controller.js +++ b/awx/ui/client/src/templates/workflows/edit-workflow/workflow-edit.controller.js @@ -264,6 +264,7 @@ export default [ $scope.workflow_job_template_obj = workflowJobTemplateData; $scope.name = workflowJobTemplateData.name; $scope.can_edit = workflowJobTemplateData.summary_fields.user_capabilities.edit; + $scope.breadcrumb.workflow_job_template_name = $scope.name; let fld, i; for (fld in form.fields) { if (fld !== 'variables' && fld !== 'survey' && workflowJobTemplateData[fld] !== null && workflowJobTemplateData[fld] !== undefined) {