diff --git a/awx/ui/static/js/app.js b/awx/ui/static/js/app.js
index e2e7b87a7e..03a775ce42 100644
--- a/awx/ui/static/js/app.js
+++ b/awx/ui/static/js/app.js
@@ -103,7 +103,7 @@ angular.module('ansible', [
$routeProvider.
when('/jobs', {
templateUrl: urlPrefix + 'partials/jobs.html',
- controller: 'JobsListCtrl'
+ controller: 'JobsList'
}).
when('/jobs/:id', {
diff --git a/awx/ui/static/js/controllers/Jobs.js b/awx/ui/static/js/controllers/Jobs.js
index ecbf8d86e5..452651fd52 100644
--- a/awx/ui/static/js/controllers/Jobs.js
+++ b/awx/ui/static/js/controllers/Jobs.js
@@ -4,426 +4,51 @@
*
* Jobs.js
*
- * Controller functions for the Job model.
+ * Controller functions for the Inventory model.
*
*/
-
+
'use strict';
-function JobsListCtrl($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, JobList, GenerateList, LoadBreadCrumbs, Prompt,
- SearchInit, PaginateInit, ReturnToCaller, ClearScope, ProcessErrors, GetBasePath, LookUpInit, SubmitJob, FormatDate, Refresh,
- JobStatusToolTip, Empty, Wait) {
-
+function JobsList($scope, $compile, ClearScope, Breadcrumbs, LoadScope, JobList) {
+
ClearScope();
- var list = JobList,
- defaultUrl = GetBasePath('jobs'),
- generator = GenerateList,
- opt;
-
- generator.inject(list, { mode: 'edit', scope: $scope });
+ var e, completed_scope, running_scope, queued_scope, schedule_scope,
+ completed_list, running_list, queued_list, schedule_list;
- $rootScope.flashMessage = null;
- $scope.selected = [];
+ // Add breadcrumbs
+ e = angular.element(document.getElementById('breadcrumbs'));
+ e.html(Breadcrumbs({ list: JobList, mode: 'edit' }));
+ $compile(e)($scope);
- if ($scope.removePostRefresh) {
- $scope.removePostRefresh();
- }
- $scope.removePostRefresh = $scope.$on('PostRefresh', function () {
- var i, cDate;
- $("tr.success").each(function () {
- // Make sure no rows have a green background
- var ngc = $(this).attr('ng-class');
- $scope[ngc] = "";
- });
- if ($scope.jobs && $scope.jobs.length) {
- for (i = 0; i < $scope.jobs.length; i++) {
- // Convert created date to local time zone
- cDate = new Date($scope.jobs[i].created);
- $scope.jobs[i].created = FormatDate(cDate);
- // Set tooltip and link
- $scope.jobs[i].statusBadgeToolTip = JobStatusToolTip($scope.jobs[i].status) +
- " Click to view status details.";
- $scope.jobs[i].statusLinkTo = '/#/jobs/' + $scope.jobs[i].id;
- }
- }
+ completed_list = angular.copy(JobList);
+ completed_list.name = "completed_jobs";
+ completed_list.iterator = "completed_jobs";
+ completed_list.editTitle = "Completed";
+ completed_scope = $scope.$new();
+ LoadScope({
+ scope: completed_scope,
+ list: completed_list,
+ id: 'completed_jobs',
+ url: '/api/v1/jobs'
});
- if ($routeParams.job_host_summaries__host) {
- defaultUrl += '?job_host_summaries__host=' + $routeParams.job_host_summaries__host;
- } else if ($routeParams.inventory__int && $routeParams.status) {
- defaultUrl += '?inventory__int=' + $routeParams.inventory__int + '&status=' +
- $routeParams.status;
- }
- SearchInit({
- scope: $scope,
- set: 'jobs',
- list: list,
- url: defaultUrl
- });
- PaginateInit({
- scope: $scope,
- list: list,
- url: defaultUrl
+ running_list = angular.copy(JobList);
+ running_list.name = "running_jobs";
+ running_list.iterator = "running_job";
+ running_list.editTitle = "Running";
+ running_scope = $scope.$new();
+ LoadScope({
+ scope: running_scope,
+ list: running_list,
+ id: 'running_jobs',
+ url: '/api/v1/jobs'
});
- // Called from Inventories page, failed jobs link. Find jobs for selected inventory.
- if ($routeParams.inventory__int) {
- $scope[list.iterator + 'SearchField'] = 'inventory';
- $scope[list.iterator + 'SearchValue'] = $routeParams.inventory__int;
- $scope[list.iterator + 'SearchFieldLabel'] = 'Inventory ID';
- }
- if ($routeParams.id__int) {
- $scope[list.iterator + 'SearchField'] = 'id';
- $scope[list.iterator + 'SearchValue'] = $routeParams.id__int;
- $scope[list.iterator + 'SearchFieldLabel'] = 'Job ID';
- }
- if ($routeParams.status) {
- $scope[list.iterator + 'SearchField'] = 'status';
- $scope[list.iterator + 'SelectShow'] = true;
- $scope[list.iterator + 'SearchSelectOpts'] = list.fields.status.searchOptions;
- $scope[list.iterator + 'SearchFieldLabel'] = list.fields.status.label.replace(/
/g, ' ');
- for (opt in list.fields.status.searchOptions) {
- if (list.fields.status.searchOptions[opt].value === $routeParams.status) {
- $scope[list.iterator + 'SearchSelectValue'] = list.fields.status.searchOptions[opt];
- break;
- }
- }
- }
-
- $scope.search(list.iterator);
-
- LoadBreadCrumbs();
-
- $scope.refresh = function () {
- Wait('start');
- $scope.jobLoading = false;
- Refresh({ scope: $scope, set: 'jobs', iterator: 'job', url: $scope.current_url });
- };
-
- $scope.refreshJob = $scope.refresh;
-
- $scope.editJob = function (id, name) {
- LoadBreadCrumbs({ path: '/jobs/' + id, title: id + ' - ' + name });
- $location.path($location.path() + '/' + id);
- };
-
- $scope.viewEvents = function (id, name) {
- LoadBreadCrumbs({ path: '/jobs/' + id, title: id + ' - ' + name });
- $location.path($location.path() + '/' + id + '/job_events');
- };
-
- $scope.viewSummary = function (id, name) {
- LoadBreadCrumbs({ path: '/jobs/' + id, title: id + ' - ' + name });
- $location.path($location.path() + '/' + id + '/job_host_summaries');
- };
-
- $scope.deleteJob = function (id) {
- Rest.setUrl(defaultUrl + id + '/');
- Rest.get()
- .success(function (data) {
-
- var action, url, action_label, hdr;
-
- if (data.status === 'pending' || data.status === 'running' || data.status === 'waiting') {
- url = data.related.cancel;
- action_label = 'cancel';
- hdr = 'Cancel Job';
- } else {
- url = defaultUrl + id + '/';
- action_label = 'delete';
- hdr = 'Delete Job';
- }
-
- action = function () {
- Rest.setUrl(url);
- if (action_label === 'cancel') {
- Rest.post()
- .success(function () {
- $('#prompt-modal').modal('hide');
- $scope.search(list.iterator);
- })
- .error(function (data, status) {
- $('#prompt-modal').modal('hide');
- ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Call to ' + url +
- ' failed. POST returned status: ' + status });
- });
- } else {
- Rest.destroy()
- .success(function () {
- $('#prompt-modal').modal('hide');
- $scope.search(list.iterator);
- })
- .error(function (data, status) {
- $('#prompt-modal').modal('hide');
- ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Call to ' + url +
- ' failed. DELETE returned status: ' + status });
- });
- }
- };
-
- Prompt({
- hdr: hdr,
- body: 'Are you sure you want to ' + action_label + ' job ' + id + '?',
- action: action
- });
- })
- .error(function (data, status) {
- ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to get job details. GET returned status: ' + status });
- });
- };
-
- $scope.submitJob = function (id, template) {
- SubmitJob({ scope: $scope, id: id, template: template });
- };
}
-JobsListCtrl.$inject = ['$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'JobList',
- 'GenerateList', 'LoadBreadCrumbs', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope',
- 'ProcessErrors', 'GetBasePath', 'LookUpInit', 'SubmitJob', 'FormatDate', 'Refresh', 'JobStatusToolTip',
- 'Empty', 'Wait'
-];
+JobsList.$inject = ['$scope', '$compile', 'ClearScope', 'Breadcrumbs', 'LoadScope', 'JobList'];
-function JobsEdit($scope, $rootScope, $compile, $location, $log, $routeParams, JobForm, JobTemplateForm, GenerateForm, Rest,
- Alert, ProcessErrors, LoadBreadCrumbs, RelatedSearchInit, RelatedPaginateInit, ReturnToCaller, ClearScope, InventoryList,
- CredentialList, ProjectList, LookUpInit, PromptPasswords, GetBasePath, md5Setup, FormatDate, JobStatusToolTip, Wait, Empty,
- ParseVariableString) {
- ClearScope();
-
- var defaultUrl = GetBasePath('jobs'),
- generator = GenerateForm,
- id = $routeParams.id,
- loadingFinishedCount = 0,
- templateForm = {};
-
- generator.inject(JobForm, { mode: 'edit', related: true, scope: $scope });
-
- $scope.job_id = id;
- $scope.parseType = 'yaml';
- $scope.statusSearchSpin = false;
- $scope.disableParseSelection = true;
-
- function getPlaybooks(project, playbook) {
- if (!Empty(project)) {
- var url = GetBasePath('projects') + project + '/playbooks/';
- Rest.setUrl(url);
- Rest.get()
- .success(function (data) {
- var i;
- $scope.playbook_options = [];
- for (i = 0; i < data.length; i++) {
- $scope.playbook_options.push(data[i]);
- }
- for (i = 0; i < $scope.playbook_options.length; i++) {
- if ($scope.playbook_options[i] === playbook) {
- $scope.playbook = $scope.playbook_options[i];
- }
- }
- $scope.$emit('jobTemplateLoadFinished');
- })
- .error(function () {
- $scope.$emit('jobTemplateLoadFinished');
- });
- } else {
- $scope.$emit('jobTemplateLoadFinished');
- }
- }
-
-
- // Retrieve each related set and populate the playbook list
- if ($scope.jobLoadedRemove) {
- $scope.jobLoadedRemove();
- }
- $scope.jobLoadedRemove = $scope.$on('jobLoaded', function (e, related_cloud_credential, project, playbook) {
-
- getPlaybooks(project, playbook);
-
- //$scope[form.name + 'ReadOnly'] = ($scope.status === 'new') ? false : true;
-
- //$('#forks-slider').slider("option", "value", $scope.forks);
- //$('#forks-slider').slider("disable");
- //$('input[type="checkbox"]').attr('disabled', 'disabled');
- //$('input[type="radio"]').attr('disabled', 'disabled');
- //$('#host_config_key-gen-btn').attr('disabled', 'disabled');
- //$('textarea').attr('readonly', 'readonly');
-
- // Get job template and display/hide host callback fields
- /*Rest.setUrl($scope.template_url);
- Rest.get()
- .success(function (data) {
- var dft = (data.host_config_key) ? 'true' : 'false';
- $scope.host_config_key = data.host_config_key;
- md5Setup({
- scope: $scope,
- master: master,
- check_field: 'allow_callbacks',
- default_val: dft
- });
- $scope.callback_url = (data.related) ? data.related.callback : '<< Job template not found >>';
- $scope.$emit('jobTemplateLoadFinished');
- })
- .error(function () {
- Wait('stop');
- $scope.callback_url = '<< Job template not found >>';
- });
- */
- if (related_cloud_credential) {
- //Get the name of the cloud credential
- Rest.setUrl(related_cloud_credential);
- Rest.get()
- .success(function (data) {
- $scope.cloud_credential_name = data.name;
- $scope.$emit('jobTemplateLoadFinished');
- })
- .error(function (data, status) {
- ProcessErrors($scope, data, status, null, { hdr: 'Error!',
- msg: 'Failed to related cloud credential. GET returned status: ' + status });
- });
- } else {
- $scope.$emit('jobTemplateLoadFinished');
- }
-
- });
-
- // Turn off 'Wait' after both cloud credential and playbook list come back
- if ($scope.removeJobTemplateLoadFinished) {
- $scope.removeJobTemplateLoadFinished();
- }
- $scope.removeJobTemplateLoadFinished = $scope.$on('jobTemplateLoadFinished', function () {
- loadingFinishedCount++;
- if (loadingFinishedCount >= 2) {
- // The initial template load finished. Now load related jobs, which
- // will turn off the 'working' spinner.
- Wait('stop');
- }
- });
-
- // Our job type options
- $scope.job_type_options = [{
- value: 'run',
- label: 'Run'
- }, {
- value: 'check',
- label: 'Check'
- }];
- $scope.verbosity_options = [{
- value: 0,
- label: 'Default'
- }, {
- value: 1,
- label: 'Verbose'
- }, {
- value: 3,
- label: 'Debug'
- }];
- $scope.playbook_options = null;
- $scope.playbook = null;
-
- function calcRows(content) {
- var n = content.match(/\n/g),
- rows = (n) ? n.length : 1;
- return (rows > 15) ? 15 : rows;
- }
-
- // Retrieve detail record and prepopulate the form
- Wait('start');
- Rest.setUrl(defaultUrl + ':id/');
- Rest.get({ params: { id: id } })
- .success(function (data) {
-
- var i, fld;
-
- LoadBreadCrumbs();
-
- $scope.status = data.status;
- $scope.created = FormatDate(data.created);
- $scope.result_stdout = data.result_stdout;
- $scope.result_traceback = data.result_traceback;
- $scope.stdout_rows = calcRows($scope.result_stdout);
- $scope.traceback_rows = calcRows($scope.result_traceback);
-
- // Now load the job template form
- templateForm.addTitle = 'Create Job Templates';
- templateForm.editTitle = '{{ name }}';
- templateForm.name = 'job_templates';
- templateForm.twoColumns = true;
- templateForm.fields = angular.copy(JobTemplateForm.fields);
- for (fld in templateForm.fields) {
- templateForm.fields[fld].readonly = true;
- }
-
- $('#ui-accordion-jobs-collapse-0-panel-1').find('div').attr('id','job-template-container');
- generator.inject(templateForm, { mode: 'edit', id: 'job-template-container', scope: $scope, breadCrumbs: false });
-
- for (fld in templateForm.fields) {
- if (fld !== 'variables' && data[fld] !== null && data[fld] !== undefined) {
- if (JobTemplateForm.fields[fld].type === 'select') {
- if ($scope[fld + '_options'] && $scope[fld + '_options'].length > 0) {
- for (i = 0; i < $scope[fld + '_options'].length; i++) {
- if (data[fld] === $scope[fld + '_options'][i].value) {
- $scope[fld] = $scope[fld + '_options'][i];
- }
- }
- } else {
- $scope[fld] = data[fld];
- }
- } else {
- $scope[fld] = data[fld];
- }
- }
- if (fld === 'variables') {
- $scope.variables = ParseVariableString(data.extra_vars);
- }
- if (JobTemplateForm.fields[fld].type === 'lookup' && data.summary_fields[JobTemplateForm.fields[fld].sourceModel]) {
- $scope[JobTemplateForm.fields[fld].sourceModel + '_' + JobTemplateForm.fields[fld].sourceField] =
- data.summary_fields[JobTemplateForm.fields[fld].sourceModel][JobTemplateForm.fields[fld].sourceField];
- }
- }
-
- $scope.id = data.id;
- $scope.name = (data.summary_fields && data.summary_fields.job_template) ? data.summary_fields.job_template.name : '';
- $scope.statusToolTip = JobStatusToolTip(data.status);
- $scope.url = data.url;
- $scope.project = data.project;
-
- $scope.$emit('jobLoaded', data.related.cloud_credential, data.project, data.playbook);
- })
- .error(function (data, status) {
- ProcessErrors($scope, data, status, null, { hdr: 'Error!',
- msg: 'Failed to retrieve job: ' + $routeParams.id + '. GET status: ' + status });
- });
-
- $scope.refresh = function () {
- Wait('start');
- Rest.setUrl(defaultUrl + id + '/');
- Rest.get()
- .success(function (data) {
- $scope.status = data.status;
- $scope.result_stdout = data.result_stdout;
- $scope.result_traceback = data.result_traceback;
- $scope.stdout_rows = calcRows($scope.result_stdout);
- $scope.traceback_rows = calcRows($scope.result_traceback);
- Wait('stop');
- })
- .error(function (data, status) {
- ProcessErrors($scope, data, status, null, { hdr: 'Error!',
- msg: 'Attempt to load job failed. GET returned status: ' + status });
- });
- };
-
- $scope.jobSummary = function () {
- $location.path('/jobs/' + id + '/job_host_summaries');
- };
-
- $scope.jobEvents = function () {
- $location.path('/jobs/' + id + '/job_events');
- };
-}
-
-JobsEdit.$inject = ['$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'JobForm', 'JobTemplateForm',
- 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'RelatedSearchInit', 'RelatedPaginateInit',
- 'ReturnToCaller', 'ClearScope', 'InventoryList', 'CredentialList', 'ProjectList', 'LookUpInit', 'PromptPasswords',
- 'GetBasePath', 'md5Setup', 'FormatDate', 'JobStatusToolTip', 'Wait', 'Empty', 'ParseVariableString'
-];
diff --git a/awx/ui/static/js/controllers/Jobs.js.old b/awx/ui/static/js/controllers/Jobs.js.old
new file mode 100644
index 0000000000..ecbf8d86e5
--- /dev/null
+++ b/awx/ui/static/js/controllers/Jobs.js.old
@@ -0,0 +1,429 @@
+/************************************
+ * Copyright (c) 2014 AnsibleWorks, Inc.
+ *
+ *
+ * Jobs.js
+ *
+ * Controller functions for the Job model.
+ *
+ */
+
+'use strict';
+
+function JobsListCtrl($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, JobList, GenerateList, LoadBreadCrumbs, Prompt,
+ SearchInit, PaginateInit, ReturnToCaller, ClearScope, ProcessErrors, GetBasePath, LookUpInit, SubmitJob, FormatDate, Refresh,
+ JobStatusToolTip, Empty, Wait) {
+
+ ClearScope();
+
+ var list = JobList,
+ defaultUrl = GetBasePath('jobs'),
+ generator = GenerateList,
+ opt;
+
+ generator.inject(list, { mode: 'edit', scope: $scope });
+
+ $rootScope.flashMessage = null;
+ $scope.selected = [];
+
+ if ($scope.removePostRefresh) {
+ $scope.removePostRefresh();
+ }
+ $scope.removePostRefresh = $scope.$on('PostRefresh', function () {
+ var i, cDate;
+ $("tr.success").each(function () {
+ // Make sure no rows have a green background
+ var ngc = $(this).attr('ng-class');
+ $scope[ngc] = "";
+ });
+ if ($scope.jobs && $scope.jobs.length) {
+ for (i = 0; i < $scope.jobs.length; i++) {
+ // Convert created date to local time zone
+ cDate = new Date($scope.jobs[i].created);
+ $scope.jobs[i].created = FormatDate(cDate);
+ // Set tooltip and link
+ $scope.jobs[i].statusBadgeToolTip = JobStatusToolTip($scope.jobs[i].status) +
+ " Click to view status details.";
+ $scope.jobs[i].statusLinkTo = '/#/jobs/' + $scope.jobs[i].id;
+ }
+ }
+ });
+
+ if ($routeParams.job_host_summaries__host) {
+ defaultUrl += '?job_host_summaries__host=' + $routeParams.job_host_summaries__host;
+ } else if ($routeParams.inventory__int && $routeParams.status) {
+ defaultUrl += '?inventory__int=' + $routeParams.inventory__int + '&status=' +
+ $routeParams.status;
+ }
+ SearchInit({
+ scope: $scope,
+ set: 'jobs',
+ list: list,
+ url: defaultUrl
+ });
+ PaginateInit({
+ scope: $scope,
+ list: list,
+ url: defaultUrl
+ });
+
+ // Called from Inventories page, failed jobs link. Find jobs for selected inventory.
+ if ($routeParams.inventory__int) {
+ $scope[list.iterator + 'SearchField'] = 'inventory';
+ $scope[list.iterator + 'SearchValue'] = $routeParams.inventory__int;
+ $scope[list.iterator + 'SearchFieldLabel'] = 'Inventory ID';
+ }
+ if ($routeParams.id__int) {
+ $scope[list.iterator + 'SearchField'] = 'id';
+ $scope[list.iterator + 'SearchValue'] = $routeParams.id__int;
+ $scope[list.iterator + 'SearchFieldLabel'] = 'Job ID';
+ }
+ if ($routeParams.status) {
+ $scope[list.iterator + 'SearchField'] = 'status';
+ $scope[list.iterator + 'SelectShow'] = true;
+ $scope[list.iterator + 'SearchSelectOpts'] = list.fields.status.searchOptions;
+ $scope[list.iterator + 'SearchFieldLabel'] = list.fields.status.label.replace(/
/g, ' ');
+ for (opt in list.fields.status.searchOptions) {
+ if (list.fields.status.searchOptions[opt].value === $routeParams.status) {
+ $scope[list.iterator + 'SearchSelectValue'] = list.fields.status.searchOptions[opt];
+ break;
+ }
+ }
+ }
+
+ $scope.search(list.iterator);
+
+ LoadBreadCrumbs();
+
+ $scope.refresh = function () {
+ Wait('start');
+ $scope.jobLoading = false;
+ Refresh({ scope: $scope, set: 'jobs', iterator: 'job', url: $scope.current_url });
+ };
+
+ $scope.refreshJob = $scope.refresh;
+
+ $scope.editJob = function (id, name) {
+ LoadBreadCrumbs({ path: '/jobs/' + id, title: id + ' - ' + name });
+ $location.path($location.path() + '/' + id);
+ };
+
+ $scope.viewEvents = function (id, name) {
+ LoadBreadCrumbs({ path: '/jobs/' + id, title: id + ' - ' + name });
+ $location.path($location.path() + '/' + id + '/job_events');
+ };
+
+ $scope.viewSummary = function (id, name) {
+ LoadBreadCrumbs({ path: '/jobs/' + id, title: id + ' - ' + name });
+ $location.path($location.path() + '/' + id + '/job_host_summaries');
+ };
+
+ $scope.deleteJob = function (id) {
+ Rest.setUrl(defaultUrl + id + '/');
+ Rest.get()
+ .success(function (data) {
+
+ var action, url, action_label, hdr;
+
+ if (data.status === 'pending' || data.status === 'running' || data.status === 'waiting') {
+ url = data.related.cancel;
+ action_label = 'cancel';
+ hdr = 'Cancel Job';
+ } else {
+ url = defaultUrl + id + '/';
+ action_label = 'delete';
+ hdr = 'Delete Job';
+ }
+
+ action = function () {
+ Rest.setUrl(url);
+ if (action_label === 'cancel') {
+ Rest.post()
+ .success(function () {
+ $('#prompt-modal').modal('hide');
+ $scope.search(list.iterator);
+ })
+ .error(function (data, status) {
+ $('#prompt-modal').modal('hide');
+ ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Call to ' + url +
+ ' failed. POST returned status: ' + status });
+ });
+ } else {
+ Rest.destroy()
+ .success(function () {
+ $('#prompt-modal').modal('hide');
+ $scope.search(list.iterator);
+ })
+ .error(function (data, status) {
+ $('#prompt-modal').modal('hide');
+ ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Call to ' + url +
+ ' failed. DELETE returned status: ' + status });
+ });
+ }
+ };
+
+ Prompt({
+ hdr: hdr,
+ body: 'Are you sure you want to ' + action_label + ' job ' + id + '?',
+ action: action
+ });
+ })
+ .error(function (data, status) {
+ ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to get job details. GET returned status: ' + status });
+ });
+ };
+
+ $scope.submitJob = function (id, template) {
+ SubmitJob({ scope: $scope, id: id, template: template });
+ };
+}
+
+JobsListCtrl.$inject = ['$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'JobList',
+ 'GenerateList', 'LoadBreadCrumbs', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope',
+ 'ProcessErrors', 'GetBasePath', 'LookUpInit', 'SubmitJob', 'FormatDate', 'Refresh', 'JobStatusToolTip',
+ 'Empty', 'Wait'
+];
+
+
+function JobsEdit($scope, $rootScope, $compile, $location, $log, $routeParams, JobForm, JobTemplateForm, GenerateForm, Rest,
+ Alert, ProcessErrors, LoadBreadCrumbs, RelatedSearchInit, RelatedPaginateInit, ReturnToCaller, ClearScope, InventoryList,
+ CredentialList, ProjectList, LookUpInit, PromptPasswords, GetBasePath, md5Setup, FormatDate, JobStatusToolTip, Wait, Empty,
+ ParseVariableString) {
+
+ ClearScope();
+
+ var defaultUrl = GetBasePath('jobs'),
+ generator = GenerateForm,
+ id = $routeParams.id,
+ loadingFinishedCount = 0,
+ templateForm = {};
+
+ generator.inject(JobForm, { mode: 'edit', related: true, scope: $scope });
+
+ $scope.job_id = id;
+ $scope.parseType = 'yaml';
+ $scope.statusSearchSpin = false;
+ $scope.disableParseSelection = true;
+
+ function getPlaybooks(project, playbook) {
+ if (!Empty(project)) {
+ var url = GetBasePath('projects') + project + '/playbooks/';
+ Rest.setUrl(url);
+ Rest.get()
+ .success(function (data) {
+ var i;
+ $scope.playbook_options = [];
+ for (i = 0; i < data.length; i++) {
+ $scope.playbook_options.push(data[i]);
+ }
+ for (i = 0; i < $scope.playbook_options.length; i++) {
+ if ($scope.playbook_options[i] === playbook) {
+ $scope.playbook = $scope.playbook_options[i];
+ }
+ }
+ $scope.$emit('jobTemplateLoadFinished');
+ })
+ .error(function () {
+ $scope.$emit('jobTemplateLoadFinished');
+ });
+ } else {
+ $scope.$emit('jobTemplateLoadFinished');
+ }
+ }
+
+
+ // Retrieve each related set and populate the playbook list
+ if ($scope.jobLoadedRemove) {
+ $scope.jobLoadedRemove();
+ }
+ $scope.jobLoadedRemove = $scope.$on('jobLoaded', function (e, related_cloud_credential, project, playbook) {
+
+ getPlaybooks(project, playbook);
+
+ //$scope[form.name + 'ReadOnly'] = ($scope.status === 'new') ? false : true;
+
+ //$('#forks-slider').slider("option", "value", $scope.forks);
+ //$('#forks-slider').slider("disable");
+ //$('input[type="checkbox"]').attr('disabled', 'disabled');
+ //$('input[type="radio"]').attr('disabled', 'disabled');
+ //$('#host_config_key-gen-btn').attr('disabled', 'disabled');
+ //$('textarea').attr('readonly', 'readonly');
+
+ // Get job template and display/hide host callback fields
+ /*Rest.setUrl($scope.template_url);
+ Rest.get()
+ .success(function (data) {
+ var dft = (data.host_config_key) ? 'true' : 'false';
+ $scope.host_config_key = data.host_config_key;
+ md5Setup({
+ scope: $scope,
+ master: master,
+ check_field: 'allow_callbacks',
+ default_val: dft
+ });
+ $scope.callback_url = (data.related) ? data.related.callback : '<< Job template not found >>';
+ $scope.$emit('jobTemplateLoadFinished');
+ })
+ .error(function () {
+ Wait('stop');
+ $scope.callback_url = '<< Job template not found >>';
+ });
+ */
+ if (related_cloud_credential) {
+ //Get the name of the cloud credential
+ Rest.setUrl(related_cloud_credential);
+ Rest.get()
+ .success(function (data) {
+ $scope.cloud_credential_name = data.name;
+ $scope.$emit('jobTemplateLoadFinished');
+ })
+ .error(function (data, status) {
+ ProcessErrors($scope, data, status, null, { hdr: 'Error!',
+ msg: 'Failed to related cloud credential. GET returned status: ' + status });
+ });
+ } else {
+ $scope.$emit('jobTemplateLoadFinished');
+ }
+
+ });
+
+ // Turn off 'Wait' after both cloud credential and playbook list come back
+ if ($scope.removeJobTemplateLoadFinished) {
+ $scope.removeJobTemplateLoadFinished();
+ }
+ $scope.removeJobTemplateLoadFinished = $scope.$on('jobTemplateLoadFinished', function () {
+ loadingFinishedCount++;
+ if (loadingFinishedCount >= 2) {
+ // The initial template load finished. Now load related jobs, which
+ // will turn off the 'working' spinner.
+ Wait('stop');
+ }
+ });
+
+ // Our job type options
+ $scope.job_type_options = [{
+ value: 'run',
+ label: 'Run'
+ }, {
+ value: 'check',
+ label: 'Check'
+ }];
+ $scope.verbosity_options = [{
+ value: 0,
+ label: 'Default'
+ }, {
+ value: 1,
+ label: 'Verbose'
+ }, {
+ value: 3,
+ label: 'Debug'
+ }];
+ $scope.playbook_options = null;
+ $scope.playbook = null;
+
+ function calcRows(content) {
+ var n = content.match(/\n/g),
+ rows = (n) ? n.length : 1;
+ return (rows > 15) ? 15 : rows;
+ }
+
+ // Retrieve detail record and prepopulate the form
+ Wait('start');
+ Rest.setUrl(defaultUrl + ':id/');
+ Rest.get({ params: { id: id } })
+ .success(function (data) {
+
+ var i, fld;
+
+ LoadBreadCrumbs();
+
+ $scope.status = data.status;
+ $scope.created = FormatDate(data.created);
+ $scope.result_stdout = data.result_stdout;
+ $scope.result_traceback = data.result_traceback;
+ $scope.stdout_rows = calcRows($scope.result_stdout);
+ $scope.traceback_rows = calcRows($scope.result_traceback);
+
+ // Now load the job template form
+ templateForm.addTitle = 'Create Job Templates';
+ templateForm.editTitle = '{{ name }}';
+ templateForm.name = 'job_templates';
+ templateForm.twoColumns = true;
+ templateForm.fields = angular.copy(JobTemplateForm.fields);
+ for (fld in templateForm.fields) {
+ templateForm.fields[fld].readonly = true;
+ }
+
+ $('#ui-accordion-jobs-collapse-0-panel-1').find('div').attr('id','job-template-container');
+ generator.inject(templateForm, { mode: 'edit', id: 'job-template-container', scope: $scope, breadCrumbs: false });
+
+ for (fld in templateForm.fields) {
+ if (fld !== 'variables' && data[fld] !== null && data[fld] !== undefined) {
+ if (JobTemplateForm.fields[fld].type === 'select') {
+ if ($scope[fld + '_options'] && $scope[fld + '_options'].length > 0) {
+ for (i = 0; i < $scope[fld + '_options'].length; i++) {
+ if (data[fld] === $scope[fld + '_options'][i].value) {
+ $scope[fld] = $scope[fld + '_options'][i];
+ }
+ }
+ } else {
+ $scope[fld] = data[fld];
+ }
+ } else {
+ $scope[fld] = data[fld];
+ }
+ }
+ if (fld === 'variables') {
+ $scope.variables = ParseVariableString(data.extra_vars);
+ }
+ if (JobTemplateForm.fields[fld].type === 'lookup' && data.summary_fields[JobTemplateForm.fields[fld].sourceModel]) {
+ $scope[JobTemplateForm.fields[fld].sourceModel + '_' + JobTemplateForm.fields[fld].sourceField] =
+ data.summary_fields[JobTemplateForm.fields[fld].sourceModel][JobTemplateForm.fields[fld].sourceField];
+ }
+ }
+
+ $scope.id = data.id;
+ $scope.name = (data.summary_fields && data.summary_fields.job_template) ? data.summary_fields.job_template.name : '';
+ $scope.statusToolTip = JobStatusToolTip(data.status);
+ $scope.url = data.url;
+ $scope.project = data.project;
+
+ $scope.$emit('jobLoaded', data.related.cloud_credential, data.project, data.playbook);
+ })
+ .error(function (data, status) {
+ ProcessErrors($scope, data, status, null, { hdr: 'Error!',
+ msg: 'Failed to retrieve job: ' + $routeParams.id + '. GET status: ' + status });
+ });
+
+ $scope.refresh = function () {
+ Wait('start');
+ Rest.setUrl(defaultUrl + id + '/');
+ Rest.get()
+ .success(function (data) {
+ $scope.status = data.status;
+ $scope.result_stdout = data.result_stdout;
+ $scope.result_traceback = data.result_traceback;
+ $scope.stdout_rows = calcRows($scope.result_stdout);
+ $scope.traceback_rows = calcRows($scope.result_traceback);
+ Wait('stop');
+ })
+ .error(function (data, status) {
+ ProcessErrors($scope, data, status, null, { hdr: 'Error!',
+ msg: 'Attempt to load job failed. GET returned status: ' + status });
+ });
+ };
+
+ $scope.jobSummary = function () {
+ $location.path('/jobs/' + id + '/job_host_summaries');
+ };
+
+ $scope.jobEvents = function () {
+ $location.path('/jobs/' + id + '/job_events');
+ };
+}
+
+JobsEdit.$inject = ['$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'JobForm', 'JobTemplateForm',
+ 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'RelatedSearchInit', 'RelatedPaginateInit',
+ 'ReturnToCaller', 'ClearScope', 'InventoryList', 'CredentialList', 'ProjectList', 'LookUpInit', 'PromptPasswords',
+ 'GetBasePath', 'md5Setup', 'FormatDate', 'JobStatusToolTip', 'Wait', 'Empty', 'ParseVariableString'
+];
diff --git a/awx/ui/static/js/helpers/Jobs.js b/awx/ui/static/js/helpers/Jobs.js
index 0ac79b2560..9501103586 100644
--- a/awx/ui/static/js/helpers/Jobs.js
+++ b/awx/ui/static/js/helpers/Jobs.js
@@ -158,4 +158,42 @@ angular.module('JobsHelper', ['Utilities', 'FormGenerator', 'JobSummaryDefinitio
};
}
-]);
\ No newline at end of file
+])
+
+/**
+ *
+ * Called from JobsList controller to load each section or list on the page
+ *
+ */
+.factory('LoadScope', ['SearchInit', 'PaginateInit', 'GenerateList', function(SearchInit, PaginateInit, GenerateList) {
+ return function(params) {
+ var scope = params.scope,
+ list = params.list,
+ id = params.id,
+ url = params.url;
+
+ GenerateList.inject(list, {
+ mode: 'edit',
+ id: id,
+ breadCrumbs: false,
+ scope: scope,
+ searchSize: 'col-lg-4 col-md-6 col-sm-12 col-xs-12',
+ showSearch: false
+ });
+
+ url = '/static/sample/data/schedules/inventory/data.json';
+ SearchInit({
+ scope: scope,
+ set: list.name,
+ list: list,
+ url: url
+ });
+
+ PaginateInit({
+ scope: scope,
+ list: list,
+ url: url,
+ pageSize: 10
+ });
+ };
+}]);
\ No newline at end of file
diff --git a/awx/ui/static/js/lists/Jobs.js b/awx/ui/static/js/lists/Jobs.js
index 6d746d4a54..c246501505 100644
--- a/awx/ui/static/js/lists/Jobs.js
+++ b/awx/ui/static/js/lists/Jobs.js
@@ -15,8 +15,10 @@ angular.module('JobsListDefinition', [])
name: 'jobs',
iterator: 'job',
editTitle: 'Jobs',
+ showTitle: true,
index: false,
hover: true,
+ well: false,
"class": 'jobs-table',
fields: {
diff --git a/awx/ui/static/less/ansible-ui.less b/awx/ui/static/less/ansible-ui.less
index b8a55d9ad9..6253163c2c 100644
--- a/awx/ui/static/less/ansible-ui.less
+++ b/awx/ui/static/less/ansible-ui.less
@@ -142,7 +142,6 @@ a:focus {
}
#home_groups_table .actions .cancel { padding-right: 3px; }
-#jobs_table .actions .cancel { padding-right: 10px; }
.success-badge {
color: #ffffff;
@@ -991,13 +990,6 @@ input[type="checkbox"].checkbox-no-label {
content: "\f111";
}
- /*.icon-failures-none,
- .icon-failures-na,
- .icon-failures-true,
- .icon-failures-false {
- font-size: 12px;
- }*/
-
.badge {
padding: 2px 3px 3px 4px;
font-size: 10px;
@@ -1005,6 +997,18 @@ input[type="checkbox"].checkbox-no-label {
line-height: 1;
}
+ .job_list {
+ padding-left: 15px;
+ padding-right: 15px;
+ margin-top: 30px;
+
+ .form-title {
+ padding-left: 8px;
+ }
+ }
+
+
+
/* Inventory job status badge */
.failures-true {
background-color: @red;
diff --git a/awx/ui/static/lib/ansible/list-generator.js b/awx/ui/static/lib/ansible/list-generator.js
index 7378592b39..17efee59ef 100644
--- a/awx/ui/static/lib/ansible/list-generator.js
+++ b/awx/ui/static/lib/ansible/list-generator.js
@@ -166,102 +166,104 @@ angular.module('ListGenerator', ['GeneratorHelpers'])
html += "