diff --git a/awx/ui/client/features/jobs/index.js b/awx/ui/client/features/jobs/index.js
index 7212944ddc..c26f2b9d8f 100644
--- a/awx/ui/client/features/jobs/index.js
+++ b/awx/ui/client/features/jobs/index.js
@@ -1,5 +1,5 @@
import JobsStrings from './jobs.strings';
-import jobsRoute from './jobs.route';
+import jobsRoute from './routes/jobs.route';
const MODULE_NAME = 'at.features.jobs';
diff --git a/awx/ui/client/features/jobs/jobsList.view.html b/awx/ui/client/features/jobs/jobsList.view.html
index 85f54bbfdc..6031a956ab 100644
--- a/awx/ui/client/features/jobs/jobsList.view.html
+++ b/awx/ui/client/features/jobs/jobsList.view.html
@@ -63,7 +63,7 @@
-
{
+ const models = [
+ new UnifiedJob(['options']),
+ ];
+ return Promise.all(models);
+ },
+ ],
+ Dataset: [
+ '$stateParams',
+ 'Wait',
+ 'GetBasePath',
+ 'QuerySet',
+ ($stateParams, Wait, GetBasePath, qs) => {
+ const groupId = $stateParams.instance_group_id;
+
+ const searchParam = $stateParams.job_search;
+
+ const searchPath = `api/v2/instance_groups/${groupId}/jobs`;
+
+ Wait('start');
+ return qs.search(searchPath, searchParam)
+ .finally(() => Wait('stop'));
+ }
+ ]
+ }
+};
diff --git a/awx/ui/client/features/jobs/routes/instanceJobs.route.js b/awx/ui/client/features/jobs/routes/instanceJobs.route.js
new file mode 100644
index 0000000000..76fed1f1b0
--- /dev/null
+++ b/awx/ui/client/features/jobs/routes/instanceJobs.route.js
@@ -0,0 +1,64 @@
+import listContainerController from '~src/instance-groups/jobs/jobsListContainer.controller';
+import { N_ } from '../../../src/i18n';
+import jobsListController from '../jobsList.controller';
+
+const jobsListTemplate = require('~features/jobs/jobsList.view.html');
+const listContainerTemplate = require('~src/instance-groups/jobs/jobsListContainer.partial.html');
+
+export default {
+ name: 'instanceGroups.instanceJobs',
+ url: '/:instance_group_id/instances/:instance_id/jobs',
+ ncyBreadcrumb: {
+ parent: 'instanceGroups.instances',
+ label: N_('JOBS')
+ },
+ views: {
+ 'jobsContainer@instances': {
+ templateUrl: listContainerTemplate,
+ controller: listContainerController,
+ controllerAs: 'vm'
+ },
+ 'jobsList@instances': {
+ templateUrl: jobsListTemplate,
+ controller: jobsListController,
+ controllerAs: 'vm'
+ },
+ },
+ params: {
+ job_search: {
+ value: {
+ page_size: '10',
+ order_by: '-finished'
+ },
+ dynamic: true
+ },
+ },
+ resolve: {
+ resolvedModels: [
+ 'UnifiedJobModel',
+ (UnifiedJob) => {
+ const models = [
+ new UnifiedJob(['options']),
+ ];
+ return Promise.all(models);
+ },
+ ],
+ Dataset: [
+ '$stateParams',
+ 'Wait',
+ 'GetBasePath',
+ 'QuerySet',
+ ($stateParams, Wait, GetBasePath, qs) => {
+ const instanceId = $stateParams.instance_id;
+
+ const searchParam = $stateParams.job_search;
+
+ const searchPath = `api/v2/instances/${instanceId}/jobs`;
+
+ Wait('start');
+ return qs.search(searchPath, searchParam)
+ .finally(() => Wait('stop'));
+ }
+ ]
+ }
+};
diff --git a/awx/ui/client/features/jobs/routes/inventoryCompletedJobs.route.js b/awx/ui/client/features/jobs/routes/inventoryCompletedJobs.route.js
new file mode 100644
index 0000000000..333359c6f6
--- /dev/null
+++ b/awx/ui/client/features/jobs/routes/inventoryCompletedJobs.route.js
@@ -0,0 +1,63 @@
+import { N_ } from '../../../src/i18n';
+import jobsListController from '../jobsList.controller';
+
+const jobsListTemplate = require('~features/jobs/jobsList.view.html');
+
+export default {
+ url: '/completed_jobs',
+ params: {
+ job_search: {
+ value: {
+ page_size: '20',
+ or__job__inventory: '',
+ or__adhoccommand__inventory: '',
+ or__inventoryupdate__inventory_source__inventory: '',
+ order_by: '-id'
+ },
+ dynamic: true,
+ squash: ''
+ }
+ },
+ ncyBreadcrumb: {
+ label: N_('JOBS')
+ },
+ views: {
+ related: {
+ templateUrl: jobsListTemplate,
+ controller: jobsListController,
+ controllerAs: 'vm'
+ }
+ },
+ resolve: {
+ resolvedModels: [
+ 'UnifiedJobModel',
+ (UnifiedJob) => {
+ const models = [
+ new UnifiedJob(['options']),
+ ];
+ return Promise.all(models);
+ },
+ ],
+ Dataset: [
+ '$stateParams',
+ 'Wait',
+ 'GetBasePath',
+ 'QuerySet',
+ ($stateParams, Wait, GetBasePath, qs) => {
+ const inventoryId = $stateParams.inventory_id ?
+ $stateParams.inventory_id : $stateParams.smartinventory_id;
+
+ const searchParam = _.assign($stateParams.job_search, {
+ or__job__inventory: inventoryId,
+ or__adhoccommand__inventory: inventoryId,
+ or__inventoryupdate__inventory_source__inventory: inventoryId });
+
+ const searchPath = GetBasePath('unified_jobs');
+
+ Wait('start');
+ return qs.search(searchPath, searchParam)
+ .finally(() => Wait('stop'));
+ }
+ ]
+ }
+};
diff --git a/awx/ui/client/features/jobs/jobs.route.js b/awx/ui/client/features/jobs/routes/jobs.route.js
similarity index 94%
rename from awx/ui/client/features/jobs/jobs.route.js
rename to awx/ui/client/features/jobs/routes/jobs.route.js
index 4aed40d11d..c3ee0b4fef 100644
--- a/awx/ui/client/features/jobs/jobs.route.js
+++ b/awx/ui/client/features/jobs/routes/jobs.route.js
@@ -1,5 +1,5 @@
-import { N_ } from '../../src/i18n';
-import jobsListController from './jobsList.controller';
+import { N_ } from '../../../src/i18n';
+import jobsListController from '../jobsList.controller';
const indexTemplate = require('~features/jobs/index.view.html');
const jobsListTemplate = require('~features/jobs/jobsList.view.html');
diff --git a/awx/ui/client/features/jobs/routes/portalModeAllJobs.route.js b/awx/ui/client/features/jobs/routes/portalModeAllJobs.route.js
new file mode 100644
index 0000000000..9595da3547
--- /dev/null
+++ b/awx/ui/client/features/jobs/routes/portalModeAllJobs.route.js
@@ -0,0 +1,50 @@
+import jobsListController from '../jobsList.controller';
+
+const jobsListTemplate = require('~features/jobs/jobsList.view.html');
+
+export default {
+ name: 'portalMode.allJobs',
+ url: '/alljobs?{job_search:queryset}',
+ params: {
+ job_search: {
+ value: {
+ page_size: '20',
+ order_by: '-finished'
+ },
+ dynamic: true
+ }
+ },
+ views: {
+ 'jobs@portalMode': {
+ templateUrl: jobsListTemplate,
+ controller: jobsListController,
+ controllerAs: 'vm'
+ }
+ },
+ resolve: {
+ resolvedModels: [
+ 'UnifiedJobModel',
+ (UnifiedJob) => {
+ const models = [
+ new UnifiedJob(['options']),
+ ];
+ return Promise.all(models);
+ },
+ ],
+ Dataset: [
+ '$stateParams',
+ 'Wait',
+ 'GetBasePath',
+ 'QuerySet',
+ ($stateParams, Wait, GetBasePath, qs) => {
+ const searchParam = $stateParams.job_search;
+
+ const searchPath = GetBasePath('unified_jobs');
+
+ Wait('start');
+ return qs.search(searchPath, searchParam)
+ .finally(() => Wait('stop'));
+ }
+ ]
+ }
+};
diff --git a/awx/ui/client/features/jobs/routes/portalModeMyJobs.route.js b/awx/ui/client/features/jobs/routes/portalModeMyJobs.route.js
new file mode 100644
index 0000000000..07506a553f
--- /dev/null
+++ b/awx/ui/client/features/jobs/routes/portalModeMyJobs.route.js
@@ -0,0 +1,53 @@
+import jobsListController from '../jobsList.controller';
+
+const jobsListTemplate = require('~features/jobs/jobsList.view.html');
+
+export default {
+ name: 'portalMode.myJobs',
+ url: '/myjobs?{job_search:queryset}',
+ params: {
+ job_search: {
+ value: {
+ page_size: '20',
+ order_by: '-finished',
+ created_by: null
+ },
+ dynamic: true
+ }
+ },
+ views: {
+ 'jobs@portalMode': {
+ templateUrl: jobsListTemplate,
+ controller: jobsListController,
+ controllerAs: 'vm'
+ }
+ },
+ resolve: {
+ resolvedModels: [
+ 'UnifiedJobModel',
+ (UnifiedJob) => {
+ const models = [
+ new UnifiedJob(['options']),
+ ];
+ return Promise.all(models);
+ },
+ ],
+ Dataset: [
+ '$stateParams',
+ 'Wait',
+ 'GetBasePath',
+ 'QuerySet',
+ '$rootScope',
+ ($stateParams, Wait, GetBasePath, qs, $rootScope) => {
+ const searchParam = _.assign($stateParams.job_search, {
+ created_by: $rootScope.current_user.id });
+
+ const searchPath = GetBasePath('unified_jobs');
+
+ Wait('start');
+ return qs.search(searchPath, searchParam)
+ .finally(() => Wait('stop'));
+ }
+ ]
+ }
+};
diff --git a/awx/ui/client/features/jobs/routes/templateCompletedJobs.route.js b/awx/ui/client/features/jobs/routes/templateCompletedJobs.route.js
new file mode 100644
index 0000000000..3fc69a5ffe
--- /dev/null
+++ b/awx/ui/client/features/jobs/routes/templateCompletedJobs.route.js
@@ -0,0 +1,60 @@
+import { N_ } from '../../../src/i18n';
+import jobsListController from '../jobsList.controller';
+
+const jobsListTemplate = require('~features/jobs/jobsList.view.html');
+
+export default {
+ url: '/completed_jobs',
+ name: 'templates.editJobTemplate.completed_jobs',
+ params: {
+ job_search: {
+ value: {
+ page_size: '20',
+ job__job_template: '',
+ order_by: '-id'
+ },
+ dynamic: true,
+ squash: ''
+ }
+ },
+ ncyBreadcrumb: {
+ label: N_('COMPLETED JOBS')
+ },
+ views: {
+ related: {
+ templateUrl: jobsListTemplate,
+ controller: jobsListController,
+ controllerAs: 'vm'
+ }
+ },
+ resolve: {
+ resolvedModels: [
+ 'UnifiedJobModel',
+ (UnifiedJob) => {
+ const models = [
+ new UnifiedJob(['options']),
+ ];
+ return Promise.all(models);
+ },
+ ],
+ Dataset: [
+ '$stateParams',
+ 'Wait',
+ 'GetBasePath',
+ 'QuerySet',
+ ($stateParams, Wait, GetBasePath, qs) => {
+ const templateId = $stateParams.job_template_id ?
+ $stateParams.job_template_id : $stateParams.job_template_id;
+
+ const searchParam = _.assign($stateParams
+ .job_search, { job__job_template: templateId });
+
+ const searchPath = GetBasePath('unified_jobs');
+
+ Wait('start');
+ return qs.search(searchPath, searchParam)
+ .finally(() => Wait('stop'));
+ }
+ ]
+ }
+};
diff --git a/awx/ui/client/src/app.js b/awx/ui/client/src/app.js
index ab93141b7d..5e67b3a381 100644
--- a/awx/ui/client/src/app.js
+++ b/awx/ui/client/src/app.js
@@ -33,7 +33,6 @@ import login from './login/main';
import activityStream from './activity-stream/main';
import standardOut from './standard-out/main';
import Templates from './templates/main';
-import jobs from './jobs/main';
import teams from './teams/main';
import users from './users/main';
import projects from './projects/main';
@@ -92,7 +91,6 @@ angular
standardOut.name,
Templates.name,
portalMode.name,
- jobs.name,
teams.name,
users.name,
projects.name,
diff --git a/awx/ui/client/src/instance-groups/instance-groups.partial.html b/awx/ui/client/src/instance-groups/instance-groups.partial.html
index 217efd98d0..680f8b1ded 100644
--- a/awx/ui/client/src/instance-groups/instance-groups.partial.html
+++ b/awx/ui/client/src/instance-groups/instance-groups.partial.html
@@ -7,7 +7,7 @@
-
+
diff --git a/awx/ui/client/src/instance-groups/instances/instance-jobs/instance-jobs.controller.js b/awx/ui/client/src/instance-groups/instances/instance-jobs/instance-jobs.controller.js
deleted file mode 100644
index bdabf14436..0000000000
--- a/awx/ui/client/src/instance-groups/instances/instance-jobs/instance-jobs.controller.js
+++ /dev/null
@@ -1,89 +0,0 @@
-
-function InstanceJobsController ($scope, $filter, $state, model, strings, jobStrings, Instance) {
- const vm = this || {};
- let { instance } = model;
- const instance_id = instance.get('id');
-
- init();
-
- function init(){
- vm.strings = strings;
- vm.jobStrings = jobStrings;
- vm.queryset = { page_size: '10', order_by: '-finished'};
- vm.jobs = instance.get('related.jobs.results');
- vm.dataset = instance.get('related.jobs');
- vm.count = instance.get('related.jobs.count');
- vm.panelTitle = `${jobStrings.get('list.PANEL_TITLE')} | ${instance.get('hostname')}`;
-
- vm.tab = {
- details: {_hide: true},
- instances: {_hide: true},
- jobs: {_hide: true}
- };
- }
-
- vm.getTime = function(time) {
- let val = "";
- if (time) {
- val += $filter('longDate')(time);
- }
- if (val === "") {
- val = undefined;
- }
- return val;
- };
-
- $scope.isSuccessful = function (status) {
- return (status === "successful");
- };
-
- $scope.viewjobResults = function(job) {
- var goTojobResults = function(state) {
- $state.go(state, { id: job.id }, { reload: true });
- };
- switch (job.type) {
- case 'job':
- goTojobResults('jobResult');
- break;
- case 'ad_hoc_command':
- goTojobResults('adHocJobStdout');
- break;
- case 'system_job':
- goTojobResults('managementJobStdout');
- break;
- case 'project_update':
- goTojobResults('scmUpdateStdout');
- break;
- case 'inventory_update':
- goTojobResults('inventorySyncStdout');
- break;
- case 'workflow_job':
- goTojobResults('workflowResults');
- break;
- }
- };
-
- $scope.$on('ws-jobs', () => {
- new Instance(['get', 'options'], [instance_id, instance_id])
- .then((data) => {
- return data.extend('get', 'jobs', {params: {page_size: "10", order_by: "-finished"}});
- })
- .then((data) => {
- instance = data;
- init();
- });
- });
-
-}
-
-InstanceJobsController.$inject = [
- '$scope',
- '$filter',
- '$state',
- 'resolvedModels',
- 'InstanceGroupsStrings',
- 'JobStrings',
- 'InstanceModel'
-];
-
-export default InstanceJobsController;
diff --git a/awx/ui/client/src/instance-groups/jobs/jobs-list.partial.html b/awx/ui/client/src/instance-groups/jobs/jobs-list.partial.html
deleted file mode 100644
index 8fdea7b2da..0000000000
--- a/awx/ui/client/src/instance-groups/jobs/jobs-list.partial.html
+++ /dev/null
@@ -1,86 +0,0 @@
-
-
- {{ vm.panelTitle }}
-
-
- {{:: vm.strings.get('tab.DETAILS') }}
- {{:: vm.strings.get('tab.INSTANCES') }}
- {{:: vm.strings.get('tab.JOBS') }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/awx/ui/client/src/instance-groups/jobs/jobs.controller.js b/awx/ui/client/src/instance-groups/jobs/jobs.controller.js
deleted file mode 100644
index 0b54a962b8..0000000000
--- a/awx/ui/client/src/instance-groups/jobs/jobs.controller.js
+++ /dev/null
@@ -1,100 +0,0 @@
-
-function InstanceGroupJobsController ($scope, $filter, $state, model, strings, jobStrings, InstanceGroup) {
- const vm = this || {};
- let { instanceGroup } = model;
- const instance_group_id = instanceGroup.get('id');
-
- init();
-
- function init(){
- vm.strings = strings;
- vm.jobStrings = jobStrings;
- vm.queryset = { page_size: '10', order_by: '-finished', instance_group_id: instance_group_id };
- vm.jobs = instanceGroup.get('related.jobs.results');
- vm.dataset = instanceGroup.get('related.jobs');
- vm.count = instanceGroup.get('related.jobs.count');
- vm.panelTitle = instanceGroup.get('name');
-
- vm.tab = {
- details: {
- _go: 'instanceGroups.edit',
- _params: { instance_group_id },
- _label: strings.get('tab.DETAILS')
- },
- instances: {
- _go: 'instanceGroups.instances',
- _params: { instance_group_id },
- _label: strings.get('tab.INSTANCES')
- },
- jobs: {
- _active: true,
- _label: strings.get('tab.JOBS')
- }
- };
- }
-
- vm.getTime = function(time) {
- let val = "";
- if (time) {
- val += $filter('longDate')(time);
- }
- if (val === "") {
- val = undefined;
- }
- return val;
- };
-
- $scope.isSuccessful = function (status) {
- return (status === "successful");
- };
-
- vm.viewjobResults = function(job) {
- var goTojobResults = function(state) {
- $state.go(state, { id: job.id }, { reload: true });
- };
- switch (job.type) {
- case 'job':
- goTojobResults('jobResult');
- break;
- case 'ad_hoc_command':
- goTojobResults('adHocJobStdout');
- break;
- case 'system_job':
- goTojobResults('managementJobStdout');
- break;
- case 'project_update':
- goTojobResults('scmUpdateStdout');
- break;
- case 'inventory_update':
- goTojobResults('inventorySyncStdout');
- break;
- case 'workflow_job':
- goTojobResults('workflowResults');
- break;
- }
- };
-
- $scope.$on('ws-jobs', () => {
- new InstanceGroup(['get', 'options'], [instance_group_id, instance_group_id])
- .then((instance_group) => {
- return instance_group.extend('get', 'jobs', {params: {page_size: "10", order_by: "-finished"}});
- })
- .then((instance_group) => {
- instanceGroup = instance_group;
- init();
- });
- });
-
-}
-
-InstanceGroupJobsController.$inject = [
- '$scope',
- '$filter',
- '$state',
- 'resolvedModels',
- 'InstanceGroupsStrings',
- 'JobStrings',
- 'InstanceGroupModel'
-];
-
-export default InstanceGroupJobsController;
\ No newline at end of file
diff --git a/awx/ui/client/src/instance-groups/jobs/jobs.list.js b/awx/ui/client/src/instance-groups/jobs/jobs.list.js
deleted file mode 100644
index 59e14ba19b..0000000000
--- a/awx/ui/client/src/instance-groups/jobs/jobs.list.js
+++ /dev/null
@@ -1,76 +0,0 @@
-export default ['i18n', function (i18n) {
- return {
- name: 'jobs',
- iterator: 'job',
- basePath: 'api/v2/instance_groups/{{$stateParams.instance_group_id}}/jobs/',
- index: false,
- hover: false,
- well: true,
- emptyListText: i18n._('No jobs have yet run.'),
- listTitle: false,
-
- fields: {
- status: {
- label: '',
- columnClass: 'col-lg-1 col-md-1 col-sm-2 col-xs-2 List-staticColumn--smallStatus',
- dataTipWatch: 'job.status_tip',
- awToolTip: "{{ job.status_tip }}",
- awTipPlacement: "right",
- dataTitle: "{{ job.status_popover_title }}",
- icon: 'icon-job-{{ job.status }}',
- iconOnly: true,
- ngClick: "viewjobResults(job)",
- nosort: true
- },
- id: {
- label: i18n._('ID'),
- ngClick: "viewjobResults(job)",
- columnClass: 'col-lg-1 col-md-1 col-sm-2 col-xs-2 List-staticColumnAdjacent',
- awToolTip: "{{ job.status_tip }}",
- dataPlacement: 'top',
- noLink: true
- },
- name: {
- label: i18n._('Name'),
- columnClass: 'col-lg-2 col-md-3 col-sm-4 col-xs-6',
- ngClick: "viewjobResults(job)",
- badgePlacement: 'right',
- badgeCustom: true,
- nosort: true,
- badgeIcon: `
-
- W
-
- `
- },
- type: {
- label: i18n._('Type'),
- ngBind: 'job.type_label',
- columnClass: "col-lg-2 hidden-md hidden-sm hidden-xs",
- nosort: true
- },
- finished: {
- label: i18n._('Finished'),
- noLink: true,
- filter: "longDate",
- columnClass: "col-lg-2 col-md-3 col-sm-3 hidden-xs",
- key: true,
- desc: true,
- nosort: true
- },
- labels: {
- label: i18n._('Labels'),
- type: 'labels',
- nosort: true,
- showDelete: false,
- columnClass: 'List-tableCell col-lg-4 col-md-4 hidden-sm hidden-xs',
- sourceModel: 'labels',
- sourceField: 'name'
- },
- }
- };
-}];
diff --git a/awx/ui/client/src/instance-groups/jobs/jobs.strings.js b/awx/ui/client/src/instance-groups/jobs/jobs.strings.js
deleted file mode 100644
index 8ecffd5a0a..0000000000
--- a/awx/ui/client/src/instance-groups/jobs/jobs.strings.js
+++ /dev/null
@@ -1,30 +0,0 @@
-function JobStrings (BaseString) {
- BaseString.call(this, 'jobs');
-
- const { t } = this;
- const ns = this.jobs;
-
- ns.state = {
- LIST_BREADCRUMB_LABEL: t.s('JOBS')
- };
-
- ns.list = {
- PANEL_TITLE: t.s('JOBS'),
- ADD_BUTTON_LABEL: t.s('ADD'),
- ADD_DD_JT_LABEL: t.s('Job Template'),
- ADD_DD_WF_LABEL: t.s('Workflow Template'),
- ROW_ITEM_LABEL_ACTIVITY: t.s('Activity'),
- ROW_ITEM_LABEL_INVENTORY: t.s('Inventory'),
- ROW_ITEM_LABEL_PROJECT: t.s('Project'),
- ROW_ITEM_LABEL_TEMPLATE: t.s('Template'),
- ROW_ITEM_LABEL_CREDENTIALS: t.s('Credentials'),
- ROW_ITEM_LABEL_MODIFIED: t.s('Last Modified'),
- ROW_ITEM_LABEL_RAN: t.s('Last Ran'),
- ROW_ITEM_LABEL_STARTED: t.s('Started'),
- ROW_ITEM_LABEL_FINISHED: t.s('Finished')
- };
-}
-
-JobStrings.$inject = ['BaseStringService'];
-
-export default JobStrings;
diff --git a/awx/ui/client/src/instance-groups/jobs/jobsListContainer.controller.js b/awx/ui/client/src/instance-groups/jobs/jobsListContainer.controller.js
new file mode 100644
index 0000000000..6ccb6775ff
--- /dev/null
+++ b/awx/ui/client/src/instance-groups/jobs/jobsListContainer.controller.js
@@ -0,0 +1,36 @@
+
+function InstanceGroupJobsContainerController (strings, $state) {
+ const vm = this || {};
+
+ init();
+ function init() {
+ const instanceGroupId = $state.params.instance_group_id;
+
+ vm.panelTitle = 'Jobs'
+
+ vm.tab = {
+ details: {
+ _go: 'instanceGroups.edit',
+ _params: { instanceGroupId },
+ _label: strings.get('tab.DETAILS')
+ },
+ instances: {
+ _go: 'instanceGroups.instances',
+ _params: { instanceGroupId },
+ _label: strings.get('tab.INSTANCES')
+ },
+ jobs: {
+ _active: true,
+ _label: strings.get('tab.JOBS')
+ }
+ };
+ }
+
+}
+
+InstanceGroupJobsContainerController.$inject = [
+ 'InstanceGroupsStrings',
+ '$state'
+];
+
+export default InstanceGroupJobsContainerController;
diff --git a/awx/ui/client/src/instance-groups/jobs/jobsListContainer.partial.html b/awx/ui/client/src/instance-groups/jobs/jobsListContainer.partial.html
new file mode 100644
index 0000000000..9eab62c32f
--- /dev/null
+++ b/awx/ui/client/src/instance-groups/jobs/jobsListContainer.partial.html
@@ -0,0 +1,11 @@
+
+
+ {{ vm.panelTitle }}
+
+
+ {{:: vm.strings.get('tab.DETAILS') }}
+ {{:: vm.strings.get('tab.INSTANCES') }}
+ {{:: vm.strings.get('tab.JOBS') }}
+
+
+
diff --git a/awx/ui/client/src/instance-groups/main.js b/awx/ui/client/src/instance-groups/main.js
index f241df97cb..2314aee41a 100644
--- a/awx/ui/client/src/instance-groups/main.js
+++ b/awx/ui/client/src/instance-groups/main.js
@@ -15,10 +15,6 @@ import InstanceGroupsListController from './list/instance-groups-list.controller
import InstancesTemplate from './instances/instances-list.partial.html';
import InstanceListController from './instances/instances.controller';
-import JobsTemplate from './jobs/jobs-list.partial.html';
-import InstanceGroupJobsListController from './jobs/jobs.controller';
-import InstanceJobsListController from './instances/instance-jobs/instance-jobs.controller';
-
import InstanceModalTemplate from './instances/instance-modal.partial.html';
import InstanceModalController from './instances/instance-modal.controller.js';
@@ -26,7 +22,9 @@ import list from './instance-groups.list';
import service from './instance-groups.service';
import InstanceGroupsStrings from './instance-groups.strings';
-import JobStrings from './jobs/jobs.strings';
+
+import instanceGroupJobsRoute from '~features/jobs/routes/instanceGroupJobs.route.js';
+import instanceJobsRoute from '~features/jobs/routes/instanceJobs.route.js';
const MODULE_NAME = 'instanceGroups';
@@ -255,73 +253,8 @@ function InstanceGroupsRun ($stateExtender, strings, ComponentsStrings) {
resolvedModels: InstanceGroupsResolve
});
- $stateExtender.addState({
- name: 'instanceGroups.instanceJobs',
- url: '/:instance_group_id/instances/:instance_id/jobs',
- ncyBreadcrumb: {
- parent: 'instanceGroups.instances',
- label: ComponentsStrings.get('layout.JOBS')
- },
- views: {
- 'instanceJobs@instanceGroups': {
- templateUrl: JobsTemplate,
- controller: 'InstanceJobsListController',
- controllerAs: 'vm'
- },
- },
- params: {
- job_search: {
- value: {
- page_size: '10',
- order_by: '-finished'
- },
- dynamic: true
- },
- },
- data: {
- socket: {
- "groups": {
- "jobs": ["status_changed"],
- }
- }
- },
- resolvedModels: InstanceGroupsResolve
- });
-
- $stateExtender.addState({
- name: 'instanceGroups.jobs',
- url: '/:instance_group_id/jobs',
- ncyBreadcrumb: {
- parent: 'instanceGroups.edit',
- label: ComponentsStrings.get('layout.JOBS')
- },
- params: {
- job_search: {
- value: {
- page_size: '10',
- order_by: '-finished'
- },
- dynamic: true
- }
- },
- data: {
- socket: {
- "groups": {
- "jobs": ["status_changed"],
- }
- }
- },
- views: {
- 'jobs@instanceGroups': {
- templateUrl: JobsTemplate,
- controller: 'InstanceGroupJobsListController',
- controllerAs: 'vm'
- },
- },
- resolve: {
- resolvedModels: InstanceGroupsResolve
- }
- });
+ $stateExtender.addState(instanceJobsRoute);
+ $stateExtender.addState(instanceGroupJobsRoute);
}
InstanceGroupsRun.$inject = [
@@ -334,16 +267,13 @@ angular.module(MODULE_NAME, [])
.service('InstanceGroupsService', service)
.factory('InstanceGroupList', list)
.controller('InstanceGroupsListController', InstanceGroupsListController)
- .controller('InstanceGroupJobsListController', InstanceGroupJobsListController)
.controller('InstanceListController', InstanceListController)
- .controller('InstanceJobsListController', InstanceJobsListController)
.directive('instanceListPolicy', InstanceListPolicy)
.directive('instanceGroupsMultiselect', instanceGroupsMultiselect)
.directive('instanceGroupsModal', instanceGroupsModal)
.directive('capacityAdjuster', CapacityAdjuster)
.directive('capacityBar', CapacityBar)
.service('InstanceGroupsStrings', InstanceGroupsStrings)
- .service('JobStrings', JobStrings)
.run(InstanceGroupsRun);
export default MODULE_NAME;
diff --git a/awx/ui/client/src/inventories-hosts/inventories/main.js b/awx/ui/client/src/inventories-hosts/inventories/main.js
index cf10245ffe..66ff152d23 100644
--- a/awx/ui/client/src/inventories-hosts/inventories/main.js
+++ b/awx/ui/client/src/inventories-hosts/inventories/main.js
@@ -8,12 +8,11 @@ import adhoc from './adhoc/main';
import group from './related/groups/main';
import sources from './related/sources/main';
import relatedHost from './related/hosts/main';
-import inventoryCompletedJobs from './related/completed-jobs/main';
import inventoryList from './list/main';
import InventoryList from './inventory.list';
import adHocRoute from './adhoc/adhoc.route';
import insights from './insights/main';
-import completedJobsRoute from './related/completed-jobs/completed-jobs.route';
+import completedJobsRoute from '~features/jobs/routes/inventoryCompletedJobs.route.js';
import inventorySourceEditRoute from './related/sources/edit/sources-edit.route';
import inventorySourceEditNotificationsRoute from './related/sources/edit/sources-notifications.route';
import inventorySourceAddRoute from './related/sources/add/sources-add.route';
@@ -53,7 +52,6 @@ angular.module('inventory', [
group.name,
sources.name,
relatedHost.name,
- inventoryCompletedJobs.name,
inventoryList.name,
insights.name,
SmartInventory.name,
diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.list.js b/awx/ui/client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.list.js
deleted file mode 100644
index 5ab048c55e..0000000000
--- a/awx/ui/client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.list.js
+++ /dev/null
@@ -1,86 +0,0 @@
-/*************************************************
- * Copyright (c) 2015 Ansible, Inc.
- *
- * All Rights Reserved
- *************************************************/
-
-
-export default ['i18n', function(i18n) {
- return {
- // These tooltip fields are consumed to build disabled related tabs tooltips in the form > add view
- awToolTip: i18n._('Please save and run a job to view.'),
- dataPlacement: 'top',
- name: 'completed_jobs',
- basePath: 'unified_jobs',
- iterator: 'completed_job',
- search: {
- "or__job__inventory": ''
- },
- editTitle: i18n._('COMPLETED JOBS'),
- index: false,
- hover: true,
- well: true,
- emptyListText: i18n._('No completed jobs'),
-
- fields: {
- status: {
- label: '',
- columnClass: 'List-staticColumn--smallStatus',
- awToolTip: "{{ completed_job.status_tip }}",
- awTipPlacement: "right",
- dataTitle: "{{ completed_job.status_popover_title }}",
- icon: 'icon-job-{{ completed_job.status }}',
- iconOnly: true,
- uiSref: '{{completed_job.linkToDetails}}',
- nosort: true
- },
- id: {
- label: i18n._('ID'),
- uiSref: '{{completed_job.linkToDetails}}',
- columnClass: 'col-lg-1 col-md-1 col-sm-2 col-xs-2 List-staticColumnAdjacent',
- awToolTip: "{{ completed_job.status_tip }}",
- dataPlacement: 'top'
- },
- name: {
- label: i18n._('Name'),
- columnClass: 'col-lg-4 col-md-4 col-sm-4 col-xs-6',
- uiSref: '{{completed_job.linkToDetails}}',
- awToolTip: "{{ completed_job.name | sanitize }}",
- dataPlacement: 'top'
- },
- type: {
- label: i18n._('Type'),
- ngBind: 'completed_job.type_label',
- link: false,
- columnClass: "col-lg-2 col-md-2 hidden-sm hidden-xs",
- },
- finished: {
- label: i18n._('Finished'),
- noLink: true,
- filter: "longDate",
- columnClass: "col-lg-3 col-md-3 col-sm-3 hidden-xs",
- key: true,
- desc: true
- }
- },
-
- actions: { },
-
- fieldActions: {
-
- columnClass: 'col-lg-2 col-md-2 col-sm-3 col-xs-4',
-
- submit: {
- ngShow: "!completed_job.type == 'system_job' || completed_job.summary_fields.user_capabilities.start",
- // uses the at-relaunch directive
- relaunch: true
- },
- "delete": {
- mode: 'all',
- ngClick: 'deleteJob(completed_job.id)',
- awToolTip: i18n._('Delete the job'),
- dataPlacement: 'top',
- ngShow: 'completed_job.summary_fields.user_capabilities.delete'
- }
- }
- };}];
diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.route.js b/awx/ui/client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.route.js
deleted file mode 100644
index 9c150aa5b2..0000000000
--- a/awx/ui/client/src/inventories-hosts/inventories/related/completed-jobs/completed-jobs.route.js
+++ /dev/null
@@ -1,60 +0,0 @@
-import { N_ } from '../../../../i18n';
-
-export default {
- url: "/completed_jobs",
- params: {
- completed_job_search: {
- value: {
- page_size: '20',
- or__job__inventory:"",
- or__adhoccommand__inventory:"",
- or__inventoryupdate__inventory_source__inventory:"",
- order_by: "-id"
- },
- dynamic: true,
- squash:""
- }
- },
- ncyBreadcrumb: {
- label: N_("COMPLETED JOBS")
- },
- views: {
- 'related': {
- templateProvider: function(FormDefinition, GenerateForm) {
- let html = GenerateForm.buildCollection({
- mode: 'edit',
- related: 'completed_jobs',
- form: typeof(FormDefinition) === 'function' ?
- FormDefinition() : FormDefinition
- });
- return html;
- },
- controller: 'JobsList'
- }
- },
- resolve: {
- ListDefinition: ['InventoryCompletedJobsList', (InventoryCompletedJobsList) => {
- return InventoryCompletedJobsList;
- }],
- Dataset: ['InventoryCompletedJobsList', '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 inventory_id = $stateParams.inventory_id ? $stateParams.inventory_id : $stateParams.smartinventory_id;
-
- $stateParams[`${list.iterator}_search`].or__job__inventory = inventory_id;
- $stateParams[`${list.iterator}_search`].or__adhoccommand__inventory = inventory_id;
- $stateParams[`${list.iterator}_search`].or__inventoryupdate__inventory_source__inventory = inventory_id;
-
- return qs.search(path, $stateParams[`${list.iterator}_search`]);
- }
- ]
- }
-};
diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/completed-jobs/main.js b/awx/ui/client/src/inventories-hosts/inventories/related/completed-jobs/main.js
deleted file mode 100644
index 7326b4c18b..0000000000
--- a/awx/ui/client/src/inventories-hosts/inventories/related/completed-jobs/main.js
+++ /dev/null
@@ -1,11 +0,0 @@
-/*************************************************
- * Copyright (c) 2017 Ansible, Inc.
- *
- * All Rights Reserved
- *************************************************/
-
-import list from './completed-jobs.list';
-
-export default
- angular.module('inventoryCompletedJobs', [])
- .factory('InventoryCompletedJobsList', list);
diff --git a/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js b/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js
index 08fc29dd60..46df8595b0 100644
--- a/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js
+++ b/awx/ui/client/src/inventories-hosts/inventories/smart-inventory/smart-inventory.form.js
@@ -4,25 +4,7 @@
* All Rights Reserved
*************************************************/
-export default ['i18n', 'InventoryCompletedJobsList', function(i18n, InventoryCompletedJobsList) {
-
- var completed_jobs_object = {
- name: 'completed_jobs',
- index: false,
- basePath: "unified_jobs",
- title: i18n._('Completed Jobs'),
- iterator: 'completed_job',
- generateList: true,
- skipGenerator: true,
- search: {
- "or__job__inventory": ''
- },
- ngClick: "$state.go('inventories.editSmartInventory.completed_jobs')"
- };
-
- let clone = _.clone(InventoryCompletedJobsList);
- completed_jobs_object = angular.extend(clone, completed_jobs_object);
-
+export default ['i18n', function(i18n) {
return {
addTitle: i18n._('NEW SMART INVENTORY'),
@@ -169,7 +151,11 @@ export default ['i18n', 'InventoryCompletedJobsList', function(i18n, InventoryCo
ngClick: "$state.go('inventories.editSmartInventory.hosts');",
skipGenerator: true
},
- completed_jobs: completed_jobs_object
+ completed_jobs: {
+ title: i18n._('Completed Jobs'),
+ skipGenerator: true,
+ ngClick: "$state.go('inventories.editSmartInventory.completed_jobs')"
+ }
}
};
diff --git a/awx/ui/client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js b/awx/ui/client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js
index d07b53ec8e..ab8d562088 100644
--- a/awx/ui/client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js
+++ b/awx/ui/client/src/inventories-hosts/inventories/standard-inventory/inventory.form.js
@@ -10,25 +10,8 @@
* @description This form is for adding/editing an inventory
*/
-export default ['i18n', 'InventoryCompletedJobsList',
-function(i18n, InventoryCompletedJobsList) {
-
- var completed_jobs_object = {
- name: 'completed_jobs',
- index: false,
- basePath: "unified_jobs",
- include: "InventoryCompletedJobsList",
- title: i18n._('Completed Jobs'),
- iterator: 'completed_job',
- generateList: true,
- skipGenerator: true,
- search: {
- "or__job__inventory": ''
- }
- };
- let clone = _.clone(InventoryCompletedJobsList);
- completed_jobs_object = angular.extend(clone, completed_jobs_object);
-
+export default ['i18n',
+function(i18n) {
return {
addTitle: i18n._('NEW INVENTORY'),
@@ -185,7 +168,10 @@ function(i18n, InventoryCompletedJobsList) {
iterator: 'inventory_source',
skipGenerator: true
},
- completed_jobs: completed_jobs_object
+ completed_jobs: {
+ title: i18n._('Completed Jobs'),
+ skipGenerator: true
+ }
},
relatedButtons: {
remediate_inventory: {
diff --git a/awx/ui/client/src/jobs/all-jobs.list.js b/awx/ui/client/src/jobs/all-jobs.list.js
deleted file mode 100644
index 08cb3b99f7..0000000000
--- a/awx/ui/client/src/jobs/all-jobs.list.js
+++ /dev/null
@@ -1,115 +0,0 @@
-/*************************************************
- * Copyright (c) 2015 Ansible, Inc.
- *
- * All Rights Reserved
- *************************************************/
-
-
-export default ['i18n', function(i18n) {
- return {
-
- name: 'jobs',
- basePath: 'unified_jobs',
- iterator: 'job',
- editTitle: i18n._('ALL JOBS'),
- index: false,
- hover: true,
- well: false,
- emptyListText: i18n._('No jobs have yet run.'),
- title: false,
-
- fields: {
- status: {
- label: '',
- columnClass: 'col-lg-1 col-md-1 col-sm-2 col-xs-2 List-staticColumn--smallStatus',
- dataTipWatch: 'job.status_tip',
- awToolTip: "{{ job.status_tip }}",
- awTipPlacement: "right",
- dataTitle: "{{ job.status_popover_title }}",
- icon: 'icon-job-{{ job.status }}',
- iconOnly: true,
- uiSref: '{{job.linkToDetails}}',
- nosort: true
- },
- id: {
- label: 'ID',
- columnClass: 'col-lg-1 col-md-1 col-sm-2 col-xs-2 List-staticColumnAdjacent',
- awToolTip: "{{ job.status_tip }}",
- dataPlacement: 'top',
- noLink: true
- },
- name: {
- label: i18n._('Name'),
- columnClass: 'col-lg-2 col-md-3 col-sm-4 col-xs-6',
- uiSref: '{{job.linkToDetails}}',
- badgePlacement: 'right',
- badgeCustom: true,
- badgeIcon: `
-
- W
-
- `
- },
- type: {
- label: i18n._('Type'),
- ngBind: 'job.type_label',
- link: false,
- columnClass: "col-lg-2 hidden-md hidden-sm hidden-xs",
- columnShow: "showJobType",
- },
- finished: {
- label: i18n._('Finished'),
- noLink: true,
- filter: "longDate",
- columnClass: "col-lg-2 col-md-3 col-sm-3 hidden-xs",
- key: true,
- desc: true
- },
- labels: {
- label: i18n._('Labels'),
- type: 'labels',
- nosort: true,
- showDelete: false,
- columnClass: 'List-tableCell col-lg-4 col-md-4 hidden-sm hidden-xs',
- sourceModel: 'labels',
- sourceField: 'name'
- },
- },
-
- actions: { },
-
- fieldActions: {
-
- columnClass: 'col-lg-2 col-md-2 col-sm-3 col-xs-4',
- "view": {
- mode: "all",
- ngClick: "viewjobResults(job)",
- awToolTip: i18n._("View the job"),
- dataPlacement: "top"
- },
- submit: {
- ngShow: "!(job.type == 'system_job') && job.summary_fields.user_capabilities.start",
- // uses the at-relaunch directive
- relaunch: true,
- },
- cancel: {
- mode: 'all',
- ngClick: 'deleteJob(job.id)',
- awToolTip: i18n._('Cancel the job'),
- dataPlacement: 'top',
- ngShow: "(job.status === 'running'|| job.status === 'waiting' || job.status === 'pending') && job.summary_fields.user_capabilities.start"
- },
- "delete": {
- mode: 'all',
- ngClick: 'deleteJob(job.id)',
- awToolTip: i18n._('Delete the job'),
- dataPlacement: 'top',
- ngShow: "(job.status !== 'running' && job.status !== 'waiting' && job.status !== 'pending') && job.summary_fields.user_capabilities.delete"
- }
- }
- };
-}];
diff --git a/awx/ui/client/src/jobs/factories/delete-job.factory.js b/awx/ui/client/src/jobs/factories/delete-job.factory.js
deleted file mode 100644
index 3900fc0da1..0000000000
--- a/awx/ui/client/src/jobs/factories/delete-job.factory.js
+++ /dev/null
@@ -1,145 +0,0 @@
- export default
- function DeleteJob($state, Find, Rest, Wait, ProcessErrors, Prompt, Alert,
- $filter, i18n) {
- return function(params) {
- var scope = params.scope,
- id = params.id,
- job = params.job,
- callback = params.callback,
- action, jobs, url, action_label, hdr;
-
- if (!job) {
- 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.status === 'pending' || job.status === 'running' || job.status === 'waiting') {
- url = job.related.cancel;
- action_label = 'cancel';
- hdr = i18n._('Cancel');
- } else {
- url = job.url;
- action_label = 'delete';
- hdr = i18n._('Delete');
- }
-
- action = function () {
- Wait('start');
- Rest.setUrl(url);
- if (action_label === 'cancel') {
- Rest.post()
- .then(() => {
- $('#prompt-modal').modal('hide');
- if (callback) {
- scope.$emit(callback, action_label);
- }
- else {
- $state.reload();
- Wait('stop');
- }
- })
- .catch(({obj, status}) => {
- Wait('stop');
- $('#prompt-modal').modal('hide');
- if (status === 403) {
- Alert('Error', obj.detail);
- }
- // Ignore the error. The job most likely already finished.
- // ProcessErrors(scope, data, status, null, { hdr: 'Error!', msg: 'Call to ' + url +
- // ' failed. POST returned status: ' + status });
- });
- } else {
- Rest.destroy()
- .then(() => {
- $('#prompt-modal').modal('hide');
- if (callback) {
- scope.$emit(callback, action_label);
- }
- else {
- let reloadListStateParams = null;
-
- if(scope.jobs.length === 1 && $state.params.job_search && !_.isEmpty($state.params.job_search.page) && $state.params.job_search.page !== '1') {
- reloadListStateParams = _.cloneDeep($state.params);
- reloadListStateParams.job_search.page = (parseInt(reloadListStateParams.job_search.page)-1).toString();
- }
-
- $state.go('.', reloadListStateParams, {reload: true});
- Wait('stop');
- }
- })
- .catch(({obj, status}) => {
- Wait('stop');
- $('#prompt-modal').modal('hide');
- if (status === 403) {
- Alert('Error', obj.detail);
- }
- // Ignore the error. The job most likely already finished.
- //ProcessErrors(scope, data, status, null, { hdr: 'Error!', msg: 'Call to ' + url +
- // ' failed. DELETE returned status: ' + status });
- });
- }
- };
-
- if (scope.removeCancelNotAllowed) {
- scope.removeCancelNotAllowed();
- }
- scope.removeCancelNotAllowed = scope.$on('CancelNotAllowed', function() {
- Wait('stop');
- Alert('Job Completed', 'The request to cancel the job could not be submitted. The job already completed.', 'alert-info');
- });
-
- if (scope.removeCancelJob) {
- scope.removeCancelJob();
- }
- scope.removeCancelJob = scope.$on('CancelJob', function() {
- var cancelBody = "" + i18n._("Are you sure you want to submit the request to cancel this job?") + "
";
- var deleteBody = "" + i18n._("Are you sure you want to delete this job?") + "
";
- Prompt({
- hdr: hdr,
- resourceName: `#${job.id} ` + $filter('sanitize')(job.name),
- body: (action_label === 'cancel' || job.status === 'new') ? cancelBody : deleteBody,
- action: action,
- actionText: (action_label === 'cancel' || job.status === 'new') ? i18n._("OK") : i18n._("DELETE")
- });
- });
-
- if (action_label === 'cancel') {
- Rest.setUrl(url);
- Rest.get()
- .then(({data}) => {
- if (data.can_cancel) {
- scope.$emit('CancelJob');
- }
- else {
- scope.$emit('CancelNotAllowed');
- }
- })
- .catch(({data, status}) => {
- ProcessErrors(scope, data, status, null, { hdr: 'Error!', msg: 'Call to ' + url +
- ' failed. GET returned: ' + status });
- });
- }
- else {
- scope.$emit('CancelJob');
- }
- };
- }
-
-DeleteJob.$inject =
- [ '$state', 'Find', 'Rest', 'Wait',
- 'ProcessErrors', 'Prompt', 'Alert', '$filter', 'i18n'
- ];
diff --git a/awx/ui/client/src/jobs/jobs-list.controller.js b/awx/ui/client/src/jobs/jobs-list.controller.js
deleted file mode 100644
index 9707c87d87..0000000000
--- a/awx/ui/client/src/jobs/jobs-list.controller.js
+++ /dev/null
@@ -1,143 +0,0 @@
-/*************************************************
- * Copyright (c) 2015 Ansible, Inc.
- *
- * All Rights Reserved
- *************************************************/
-
-/**
- * @ngdoc function
- * @name controllers.function:Jobs
- * @description This controller's for the jobs page
- */
-
- export default ['$state', '$rootScope', '$scope', '$stateParams', 'Find', 'DeleteJob',
- 'GetBasePath', 'Dataset', 'QuerySet', 'ListDefinition', '$interpolate',
- function($state, $rootScope, $scope, $stateParams, Find, DeleteJob,
- GetBasePath, Dataset, qs, ListDefinition, $interpolate) {
-
- var list = ListDefinition;
-
- init();
-
- function init() {
- // search init
- $scope.list = list;
- $scope[`${list.iterator}_dataset`] = Dataset.data;
- $scope[list.name] = $scope[`${list.iterator}_dataset`].results;
-
- $scope.showJobType = true;
- }
-
- $scope.$on(`${list.iterator}_options`, function(event, data){
- $scope.options = data.data.actions.GET;
- optionsRequestDataProcessing();
- });
-
- $scope.$watchCollection(`${$scope.list.name}`, function() {
- optionsRequestDataProcessing();
- }
- );
-
- // iterate over the list and add fields like type label, after the
- // OPTIONS request returns, or the list is sorted/paginated/searched
- function optionsRequestDataProcessing(){
-
- if($scope[list.name] && $scope[list.name].length > 0) {
- $scope[list.name].forEach(function(item, item_idx) {
- var itm = $scope[list.name][item_idx];
-
- switch (item.type) {
- case 'job':
- item.linkToDetails = `jobResult({id: ${item.id}})`;
- break;
- case 'ad_hoc_command':
- item.linkToDetails = `adHocJobStdout({id: ${item.id}})`;
- break;
- case 'system_job':
- item.linkToDetails = `managementJobStdout({id: ${item.id}})`;
- break;
- case 'project_update':
- item.linkToDetails = `scmUpdateStdout({id: ${item.id}})`;
- break;
- case 'inventory_update':
- item.linkToDetails = `inventorySyncStdout({id: ${item.id}})`;
- break;
- case 'workflow_job':
- item.linkToDetails = `workflowResults({id: ${item.id}})`;
- break;
- }
-
- 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.forEach(function(choice) {
- if (choice[0] === item.type) {
- itm.type_label = choice[1];
- }
- });
- }
- buildTooltips(itm);
- });
- }
- }
- function buildTooltips(job) {
- job.status_tip = 'Job ' + job.status + ". Click for details.";
- }
-
- $scope.deleteJob = function(id) {
- DeleteJob({ scope: $scope, id: id });
- };
-
- $scope.viewjobResults = function(job) {
-
- var goTojobResults = function(state) {
- $state.go(state, { id: job.id }, { reload: true });
- };
- switch (job.type) {
- case 'job':
- goTojobResults('jobResult');
- break;
- case 'ad_hoc_command':
- goTojobResults('adHocJobStdout');
- break;
- case 'system_job':
- goTojobResults('managementJobStdout');
- break;
- case 'project_update':
- goTojobResults('scmUpdateStdout');
- break;
- case 'inventory_update':
- goTojobResults('inventorySyncStdout');
- break;
- case 'workflow_job':
- goTojobResults('workflowResults');
- break;
- }
-
- };
-
- $scope.$on('ws-jobs', function(){
- 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;
- $scope[list.name] = $scope[`${list.iterator}_dataset`].results;
- });
- });
-
- $scope.$on('ws-schedules', function(){
- $state.reload();
- });
-}];
diff --git a/awx/ui/client/src/jobs/jobs.partial.html b/awx/ui/client/src/jobs/jobs.partial.html
deleted file mode 100644
index 46f7b09761..0000000000
--- a/awx/ui/client/src/jobs/jobs.partial.html
+++ /dev/null
@@ -1,23 +0,0 @@
-
diff --git a/awx/ui/client/src/jobs/main.js b/awx/ui/client/src/jobs/main.js
deleted file mode 100644
index 2bb8f0a7a5..0000000000
--- a/awx/ui/client/src/jobs/main.js
+++ /dev/null
@@ -1,15 +0,0 @@
-/*************************************************
- * Copyright (c) 2017 Ansible, Inc.
- *
- * All Rights Reserved
- *************************************************/
-
-import jobsList from './jobs-list.controller';
-import DeleteJob from './factories/delete-job.factory';
-import AllJobsList from './all-jobs.list';
-
-export default
- angular.module('JobsModule', [])
- .controller('JobsList', jobsList)
- .factory('DeleteJob', DeleteJob)
- .factory('AllJobsList', AllJobsList);
diff --git a/awx/ui/client/src/management-jobs/main.js b/awx/ui/client/src/management-jobs/main.js
index 12d25fbc6b..7b850261b9 100644
--- a/awx/ui/client/src/management-jobs/main.js
+++ b/awx/ui/client/src/management-jobs/main.js
@@ -6,7 +6,6 @@
import managementJobsCard from './card/main';
import managementJobsScheduler from './scheduler/main';
-import list from './management-jobs.list';
import managementJobsNotifications from './notifications/main';
export default
@@ -15,4 +14,3 @@ export default
managementJobsScheduler.name,
managementJobsNotifications.name
])
- .factory('managementJobsListObject', list);
diff --git a/awx/ui/client/src/management-jobs/management-jobs.list.js b/awx/ui/client/src/management-jobs/management-jobs.list.js
deleted file mode 100644
index 7ad1af547a..0000000000
--- a/awx/ui/client/src/management-jobs/management-jobs.list.js
+++ /dev/null
@@ -1,43 +0,0 @@
-/*************************************************
- * Copyright (c) 2015 Ansible, Inc.
- *
- * All Rights Reserved
- *************************************************/
-
-export default function(){
- return {
- name: 'configure_jobs',
- iterator: 'configure_job',
- index: false,
- hover: true,
- listTitle: 'MANAGEMENT JOBS',
-
- fields: {
- name: {
- label: 'Name',
- columnClass: 'col-sm-4 col-xs-4',
- awToolTip: '{{configure_job.description | sanitize}}',
- dataPlacement: 'top'
- }
- },
- actions: {
-
- },
- fieldActions: {
- submit: {
- label: 'Launch',
- mode: 'all',
- ngClick: 'submitJob(configure_job.id, configure_job.name)',
- awToolTip: 'Start a job using this template',
- dataPlacement: 'top'
- },
- schedule: {
- label: 'Schedule',
- mode: 'all',
- ngClick: 'configureSchedule()',
- awToolTip: 'Schedule job template runs',
- dataPlacement: 'top',
- }
- }
- };
-}
diff --git a/awx/ui/client/src/portal-mode/jobs/portal-mode-all-jobs.route.js b/awx/ui/client/src/portal-mode/jobs/portal-mode-all-jobs.route.js
deleted file mode 100644
index 582f806b89..0000000000
--- a/awx/ui/client/src/portal-mode/jobs/portal-mode-all-jobs.route.js
+++ /dev/null
@@ -1,49 +0,0 @@
-import { PortalModeJobsController } from '../portal-mode-jobs.controller';
-
-// Using multiple named views requires a parent layout
-// https://github.com/angular-ui/ui-router/wiki/Multiple-Named-Views
-export default {
- name: 'portalMode.allJobs',
- url: '/alljobs?{job_search:queryset}',
- ncyBreadcrumb: {
- skip: true
- },
- params: {
- job_search: {
- value: {
- page_size: '20',
- order_by: '-finished'
- },
- dynamic: true
- }
- },
- data: {
- socket: {
- "groups": {
- "jobs": ["status_changed"]
- }
- }
- },
- views: {
- 'jobs@portalMode': {
- templateProvider: function(PortalJobsList, generateList) {
- let html = generateList.build({
- list: PortalJobsList,
- mode: 'edit'
- });
- return html;
- },
- controller: PortalModeJobsController
- }
- },
- resolve: {
- jobsDataset: ['PortalJobsList', 'QuerySet', '$rootScope', '$stateParams', 'GetBasePath',
- function(list, qs, $rootScope, $stateParams, GetBasePath) {
- let path = GetBasePath(list.basePath) || GetBasePath(list.name);
- return $rootScope.loginConfig.promise.then(() => {
- return qs.search(path, $stateParams[`${list.iterator}_search`]);
- });
- }
- ]
- }
-};
diff --git a/awx/ui/client/src/portal-mode/jobs/portal-mode-my-jobs.route.js b/awx/ui/client/src/portal-mode/jobs/portal-mode-my-jobs.route.js
deleted file mode 100644
index 9d5c0382f3..0000000000
--- a/awx/ui/client/src/portal-mode/jobs/portal-mode-my-jobs.route.js
+++ /dev/null
@@ -1,51 +0,0 @@
-import { PortalModeJobsController } from '../portal-mode-jobs.controller';
-
-// Using multiple named views requires a parent layout
-// https://github.com/angular-ui/ui-router/wiki/Multiple-Named-Views
-export default {
- name: 'portalMode.myJobs',
- url: '/myjobs?{job_search:queryset}',
- ncyBreadcrumb: {
- skip: true
- },
- params: {
- job_search: {
- value: {
- page_size: '20',
- order_by: '-finished',
- created_by: null
- },
- dynamic: true
- }
- },
- data: {
- socket: {
- "groups": {
- "jobs": ["status_changed"]
- }
- }
- },
- views: {
- 'jobs@portalMode': {
- templateProvider: function(PortalJobsList, generateList) {
- let html = generateList.build({
- list: PortalJobsList,
- mode: 'edit'
- });
- return html;
- },
- controller: PortalModeJobsController
- }
- },
- resolve: {
- jobsDataset: ['PortalJobsList', 'QuerySet', '$rootScope', '$stateParams', 'GetBasePath',
- function(list, qs, $rootScope, $stateParams, GetBasePath) {
- let path = GetBasePath(list.basePath) || GetBasePath(list.name);
- return $rootScope.loginConfig.promise.then(() => {
- $stateParams[`${list.iterator}_search`].created_by = $rootScope.current_user.id;
- return qs.search(path, $stateParams[`${list.iterator}_search`]);
- });
- }
- ]
- }
-};
diff --git a/awx/ui/client/src/portal-mode/main.js b/awx/ui/client/src/portal-mode/main.js
index a88d3f86b9..e4e1dc2a2c 100644
--- a/awx/ui/client/src/portal-mode/main.js
+++ b/awx/ui/client/src/portal-mode/main.js
@@ -5,17 +5,15 @@
*************************************************/
import route from './portal-mode.route';
-import myJobsRoute from './jobs/portal-mode-my-jobs.route';
-import allJobsRoute from './jobs/portal-mode-all-jobs.route';
-import PortalJobsList from './portal-jobs.list';
+import myJobsRoute from '~features/jobs/routes/portalModeMyJobs.route.js';
+import allJobsRoute from '~features/jobs/routes/portalModeAllJobs.route.js';
import PortalJobTemplateList from './portal-job-templates.list';
export default
angular.module('portalMode', [])
- .factory('PortalJobsList', PortalJobsList)
.factory('PortalJobTemplateList', PortalJobTemplateList)
.run(['$stateExtender', function($stateExtender){
- $stateExtender.addState(route);
- $stateExtender.addState(myJobsRoute);
- $stateExtender.addState(allJobsRoute);
+ $stateExtender.addState(route);
+ $stateExtender.addState(myJobsRoute);
+ $stateExtender.addState(allJobsRoute);
}]);
diff --git a/awx/ui/client/src/portal-mode/portal-jobs.list.js b/awx/ui/client/src/portal-mode/portal-jobs.list.js
deleted file mode 100644
index 24f9b2afe3..0000000000
--- a/awx/ui/client/src/portal-mode/portal-jobs.list.js
+++ /dev/null
@@ -1,50 +0,0 @@
-/*************************************************
- * Copyright (c) 2015 Ansible, Inc.
- *
- * All Rights Reserved
- *************************************************/
-
-
-export default ['i18n', function(i18n) {
- return {
-
- name: 'jobs',
- iterator: 'job',
- editTitle: i18n._('JOBS'),
- index: false,
- hover: true,
- well: true,
- listTitle: i18n._('JOBS'),
- emptyListText: i18n._('There are no jobs to display at this time'),
- searchBarFullWidth: true,
-
- fields: {
- status: {
- label: '',
- columnClass: 'List-staticColumn--smallStatus',
- dataTitle: "{{ job.status_popover_title }}",
- icon: 'icon-job-{{ job.status }}',
- iconOnly: true,
- nosort: true,
- awTipPlacement: "top",
- awToolTip: "{{ job.status_tip }}",
- dataTipWatch: 'job.status_tip',
- ngClick:"viewjobResults(job)",
- },
- name: {
- label: i18n._('Name'),
- columnClass: 'col-lg-4 col-md-4 col-sm-4 col-xs-6 List-staticColumnAdjacent',
- linkTo: '/#/jobs/{{job.id}}',
- },
- finished: {
- label: i18n._('Finished'),
- noLink: true,
- filter: "longDate",
- key: true,
- desc: true,
- columnClass: "col-lg-4 col-md-4 col-sm-3"
- }
- },
-
- actions: { }
- };}];
diff --git a/awx/ui/client/src/portal-mode/portal-mode-jobs.controller.js b/awx/ui/client/src/portal-mode/portal-mode-jobs.controller.js
deleted file mode 100644
index b297e126eb..0000000000
--- a/awx/ui/client/src/portal-mode/portal-mode-jobs.controller.js
+++ /dev/null
@@ -1,105 +0,0 @@
-/*************************************************
- * Copyright (c) 2016 Ansible, Inc.
- *
- * All Rights Reserved
- *************************************************/
-
-export function PortalModeJobsController($scope, $state, qs, GetBasePath, PortalJobsList, Dataset) {
-
- var list = PortalJobsList;
-
- $scope.$on('ws-jobs', function() {
- let path = GetBasePath(list.basePath) || GetBasePath(list.name);
- qs.search(path, $state.params[`${list.iterator}_search`])
- .then(function(searchResponse) {
- $scope[`${list.iterator}_dataset`] = searchResponse.data;
- $scope[list.name] = $scope[`${list.iterator}_dataset`].results;
- });
- });
-
- init();
-
- function init(data) {
- let d = (!data) ? Dataset : data;
- // search init
- $scope.list = list;
- $scope[`${list.iterator}_dataset`] = d.data;
- $scope[list.name] = $scope[`${list.iterator}_dataset`].results;
-
- $scope.iterator = list.iterator;
- }
-
- $scope.refresh = function() {
- $state.go('.', null, {reload: true});
- };
-
- $scope.$on(`${list.iterator}_options`, function(event, data){
- $scope.options = data.data.actions.GET;
- optionsRequestDataProcessing();
- });
-
- $scope.$watchCollection(`${$scope.list.name}`, function() {
- optionsRequestDataProcessing();
- }
- );
-
- // iterate over the list and add fields like type label, after the
- // OPTIONS request returns, or the list is sorted/paginated/searched
- function optionsRequestDataProcessing(){
-
- 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.forEach(function(choice) {
- if (choice[0] === item.type) {
- itm.type_label = choice[1];
- }
- });
- }
- buildTooltips(itm);
- });
- }
- }
- function buildTooltips(job) {
- job.status_tip = `Job ${job.status}. Click for details.`;
- }
-
- $scope.viewjobResults = function(job) {
-
- var goTojobResults = function(state) {
- $state.go(state, { id: job.id }, { reload: true });
- };
- switch (job.type) {
- case 'job':
- goTojobResults('jobResult');
- break;
- case 'ad_hoc_command':
- goTojobResults('adHocJobStdout');
- break;
- case 'system_job':
- goTojobResults('managementJobStdout');
- break;
- case 'project_update':
- goTojobResults('scmUpdateStdout');
- break;
- case 'inventory_update':
- goTojobResults('inventorySyncStdout');
- break;
- case 'workflow_job':
- goTojobResults('workflowResults');
- break;
- }
-
- };
-}
-
-PortalModeJobsController.$inject = ['$scope', '$state', 'QuerySet', 'GetBasePath', 'PortalJobsList', 'jobsDataset'];
diff --git a/awx/ui/client/src/portal-mode/portal-mode-jobs.partial.html b/awx/ui/client/src/portal-mode/portal-mode-jobs.partial.html
deleted file mode 100644
index 8543683d7c..0000000000
--- a/awx/ui/client/src/portal-mode/portal-mode-jobs.partial.html
+++ /dev/null
@@ -1,26 +0,0 @@
-
diff --git a/awx/ui/client/src/templates/completed-jobs.list.js b/awx/ui/client/src/templates/completed-jobs.list.js
deleted file mode 100644
index 54ba53a48e..0000000000
--- a/awx/ui/client/src/templates/completed-jobs.list.js
+++ /dev/null
@@ -1,87 +0,0 @@
-/*************************************************
- * Copyright (c) 2015 Ansible, Inc.
- *
- * All Rights Reserved
- *************************************************/
-
-
-export default ['i18n', function(i18n) {
- return {
- // These tooltip fields are consumed to build disabled related tabs tooltips in the form > add view
- awToolTip: i18n._('Please save and run a job to view.'),
- dataPlacement: 'top',
- name: 'completed_jobs',
- basePath: 'api/v2/job_templates/{{$stateParams.job_template_id}}/jobs',
- search: {
- or__status__in: "successful,failed,error,canceled",
- order_by: "-id"
- },
- iterator: 'completed_job',
- editTitle: i18n._('COMPLETED JOBS'),
- index: false,
- hover: true,
- well: false,
- emptyListText: i18n._('No completed jobs'),
-
- fields: {
- status: {
- label: '',
- columnClass: 'List-staticColumn--smallStatus',
- awToolTip: "{{ completed_job.status_tip }}",
- awTipPlacement: "right",
- dataTitle: "{{ completed_job.status_popover_title }}",
- icon: 'icon-job-{{ completed_job.status }}',
- iconOnly: true,
- uiSref: '{{completed_job.linkToDetails}}',
- nosort: true
- },
- id: {
- label: 'ID',
- uiSref: '{{completed_job.linkToDetails}}',
- columnClass: 'col-lg-1 col-md-1 col-sm-2 col-xs-2 List-staticColumnAdjacent',
- awToolTip: "{{ completed_job.status_tip }}",
- dataPlacement: 'top'
- },
- name: {
- label: i18n._('Name'),
- columnClass: 'col-lg-4 col-md-4 col-sm-4 col-xs-6',
- uiSref: '{{completed_job.linkToDetails}}',
- awToolTip: "{{ completed_job.name | sanitize }}",
- dataPlacement: 'top'
- },
- type: {
- label: i18n._('Type'),
- ngBind: 'completed_job.type_label',
- link: false,
- columnClass: "col-lg-2 col-md-2 hidden-sm hidden-xs",
- },
- finished: {
- label: i18n._('Finished'),
- noLink: true,
- filter: "longDate",
- columnClass: "col-lg-3 col-md-3 col-sm-3 hidden-xs",
- key: true,
- desc: true
- }
- },
-
- actions: { },
-
- fieldActions: {
-
- columnClass: 'col-lg-2 col-md-2 col-sm-3 col-xs-4',
-
- submit: {
- ngShow: "!completed_job.type == 'system_job' || completed_job.summary_fields.user_capabilities.start",
- // uses the at-relaunch directive
- relaunch: true
- },
- "delete": {
- mode: 'all',
- ngClick: 'deleteJob(completed_job.id)',
- awToolTip: i18n._('Delete the job'),
- dataPlacement: 'top',
- ngShow: 'completed_job.summary_fields.user_capabilities.delete'
- }
- }
- };}];
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 422d722c3a..fc24852e2d 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
@@ -11,8 +11,8 @@
*/
-export default ['NotificationsList', 'CompletedJobsList', 'i18n',
-function(NotificationsList, CompletedJobsList, i18n) {
+export default ['NotificationsList', 'i18n',
+function(NotificationsList, i18n) {
return function() {
var JobTemplateFormObject = {
@@ -433,7 +433,9 @@ function(NotificationsList, CompletedJobsList, i18n) {
include: "NotificationsList"
},
"completed_jobs": {
- include: "CompletedJobsList"
+ title: i18n._('Completed Jobs'),
+ skipGenerator: true,
+ ngClick: "$state.go('templates.editJobTemplate.completed_jobs')"
}
},
@@ -473,11 +475,6 @@ function(NotificationsList, CompletedJobsList, i18n) {
JobTemplateFormObject.related[itm].ngClick = "$state.go('templates.editJobTemplate.notifications')";
JobTemplateFormObject.related[itm].generateList = true; // tell form generator to call list generator and inject a list
}
- if (JobTemplateFormObject.related[itm].include === "CompletedJobsList") {
- JobTemplateFormObject.related[itm] = CompletedJobsList;
- JobTemplateFormObject.related[itm].ngClick = "$state.go('templates.editJobTemplate.completed_jobs')";
- JobTemplateFormObject.related[itm].generateList = true;
- }
}
return JobTemplateFormObject;
diff --git a/awx/ui/client/src/templates/main.js b/awx/ui/client/src/templates/main.js
index c2f2d0e9a6..f9280252a0 100644
--- a/awx/ui/client/src/templates/main.js
+++ b/awx/ui/client/src/templates/main.js
@@ -16,11 +16,11 @@ import workflowMaker from './workflows/workflow-maker/main';
import workflowControls from './workflows/workflow-controls/main';
import workflowService from './workflows/workflow.service';
import WorkflowForm from './workflows.form';
-import CompletedJobsList from './completed-jobs.list';
import InventorySourcesList from './inventory-sources.list';
import TemplateList from './templates.list';
import TemplatesStrings from './templates.strings';
import listRoute from '~features/templates/list.route.js';
+import templateCompletedJobsRoute from '~features/jobs/routes/templateCompletedJobs.route.js';
export default
angular.module('templates', [surveyMaker.name, jobTemplates.name, labels.name, prompt.name, workflowAdd.name, workflowEdit.name,
@@ -29,7 +29,6 @@ angular.module('templates', [surveyMaker.name, jobTemplates.name, labels.name, p
.service('TemplatesService', templatesService)
.service('WorkflowService', workflowService)
.factory('WorkflowForm', WorkflowForm)
- .factory('CompletedJobsList', CompletedJobsList)
// TODO: currently being kept arround for rbac selection, templates within projects and orgs, etc.
.factory('TemplateList', TemplateList)
.value('InventorySourcesList', InventorySourcesList)
@@ -151,10 +150,7 @@ angular.module('templates', [surveyMaker.name, jobTemplates.name, labels.name, p
modes: ['edit'],
form: 'JobTemplateForm',
controllers: {
- edit: 'JobTemplateEdit',
- related: {
- completed_jobs: 'JobsList'
- }
+ edit: 'JobTemplateEdit'
},
data: {
activityStream: true,
@@ -742,6 +738,7 @@ angular.module('templates', [surveyMaker.name, jobTemplates.name, labels.name, p
return result.concat(definition.states);
}, [
stateExtender.buildDefinition(listRoute),
+ stateExtender.buildDefinition(templateCompletedJobsRoute),
stateExtender.buildDefinition(workflowMaker)
])
};