mirror of
https://github.com/ansible/awx.git
synced 2024-11-02 09:51:09 +03:00
Starting rewrite of Jobs tab.
This commit is contained in:
parent
0c4bd4bfa8
commit
9614103964
@ -103,7 +103,7 @@ angular.module('ansible', [
|
||||
$routeProvider.
|
||||
when('/jobs', {
|
||||
templateUrl: urlPrefix + 'partials/jobs.html',
|
||||
controller: 'JobsListCtrl'
|
||||
controller: 'JobsList'
|
||||
}).
|
||||
|
||||
when('/jobs/:id', {
|
||||
|
@ -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(/<br>/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'
|
||||
];
|
||||
|
429
awx/ui/static/js/controllers/Jobs.js.old
Normal file
429
awx/ui/static/js/controllers/Jobs.js.old
Normal file
@ -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(/<br>/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'
|
||||
];
|
@ -158,4 +158,42 @@ angular.module('JobsHelper', ['Utilities', 'FormGenerator', 'JobSummaryDefinitio
|
||||
};
|
||||
|
||||
}
|
||||
]);
|
||||
])
|
||||
|
||||
/**
|
||||
*
|
||||
* 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
|
||||
});
|
||||
};
|
||||
}]);
|
@ -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: {
|
||||
|
@ -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;
|
||||
|
@ -166,102 +166,104 @@ angular.module('ListGenerator', ['GeneratorHelpers'])
|
||||
|
||||
html += "<div class=\"row\">\n";
|
||||
|
||||
if (list.name !== 'groups') {
|
||||
if (options.searchSize) {
|
||||
html += SearchWidget({
|
||||
iterator: list.iterator,
|
||||
template: list,
|
||||
mini: true,
|
||||
size: options.searchSize,
|
||||
searchWidgets: list.searchWidgets
|
||||
});
|
||||
} else if (options.mode === 'summary') {
|
||||
html += SearchWidget({
|
||||
iterator: list.iterator,
|
||||
template: list,
|
||||
mini: true,
|
||||
size: 'col-lg-6'
|
||||
});
|
||||
} else if (options.mode === 'lookup' || options.id !== undefined) {
|
||||
html += SearchWidget({
|
||||
iterator: list.iterator,
|
||||
template: list,
|
||||
mini: true,
|
||||
size: 'col-lg-8'
|
||||
});
|
||||
} else {
|
||||
html += SearchWidget({
|
||||
iterator: list.iterator,
|
||||
template: list,
|
||||
mini: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (options.mode !== 'lookup') {
|
||||
//actions
|
||||
base = $location.path().replace(/^\//, '').split('/')[0];
|
||||
html += "<div class=\"";
|
||||
if (list.name === 'groups') {
|
||||
html += "col-lg-12";
|
||||
} else if (options.searchSize) {
|
||||
// User supplied searchSize, calc the remaining
|
||||
size = parseInt(options.searchSize.replace(/([A-Z]|[a-z]|\-)/g, ''));
|
||||
size = (list.searchWidgets) ? list.searchWidgets * size : size;
|
||||
html += 'col-lg-' + (12 - size);
|
||||
} else if (options.mode === 'summary') {
|
||||
html += 'col-lg-6';
|
||||
} else if (options.id !== undefined) {
|
||||
html += "col-lg-4";
|
||||
} else {
|
||||
html += "col-lg-8 col-md-6";
|
||||
}
|
||||
html += "\">\n";
|
||||
|
||||
html += "<div class=\"list-actions\">\n";
|
||||
|
||||
// Add toolbar buttons or 'actions'
|
||||
for (action in list.actions) {
|
||||
if (list.actions[action].mode === 'all' || list.actions[action].mode === options.mode) {
|
||||
if ((list.actions[action].basePaths === undefined) ||
|
||||
(list.actions[action].basePaths && list.actions[action].basePaths.indexOf(base) > -1)) {
|
||||
html += this.button({
|
||||
btn: list.actions[action],
|
||||
action: action,
|
||||
toolbar: true
|
||||
});
|
||||
}
|
||||
if (options.showSearch === undefined || options.showSearch === true) {
|
||||
if (list.name !== 'groups') {
|
||||
if (options.searchSize) {
|
||||
html += SearchWidget({
|
||||
iterator: list.iterator,
|
||||
template: list,
|
||||
mini: true,
|
||||
size: options.searchSize,
|
||||
searchWidgets: list.searchWidgets
|
||||
});
|
||||
} else if (options.mode === 'summary') {
|
||||
html += SearchWidget({
|
||||
iterator: list.iterator,
|
||||
template: list,
|
||||
mini: true,
|
||||
size: 'col-lg-6'
|
||||
});
|
||||
} else if (options.mode === 'lookup' || options.id !== undefined) {
|
||||
html += SearchWidget({
|
||||
iterator: list.iterator,
|
||||
template: list,
|
||||
mini: true,
|
||||
size: 'col-lg-8'
|
||||
});
|
||||
} else {
|
||||
html += SearchWidget({
|
||||
iterator: list.iterator,
|
||||
template: list,
|
||||
mini: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//select instructions
|
||||
if (options.mode === 'select' && list.selectInstructions) {
|
||||
btn = {
|
||||
awPopOver: list.selectInstructions,
|
||||
dataPlacement: 'left',
|
||||
dataContainer: 'body',
|
||||
'class': 'btn-xs btn-help',
|
||||
awToolTip: 'Click for help',
|
||||
dataTitle: 'Help',
|
||||
iconSize: 'fa-lg'
|
||||
};
|
||||
//html += this.button(btn, 'select');
|
||||
html += this.button({
|
||||
btn: btn,
|
||||
action: 'help',
|
||||
toolbar: true
|
||||
});
|
||||
if (options.mode !== 'lookup') {
|
||||
//actions
|
||||
base = $location.path().replace(/^\//, '').split('/')[0];
|
||||
html += "<div class=\"";
|
||||
if (list.name === 'groups') {
|
||||
html += "col-lg-12";
|
||||
} else if (options.searchSize) {
|
||||
// User supplied searchSize, calc the remaining
|
||||
size = parseInt(options.searchSize.replace(/([A-Z]|[a-z]|\-)/g, ''));
|
||||
size = (list.searchWidgets) ? list.searchWidgets * size : size;
|
||||
html += 'col-lg-' + (12 - size);
|
||||
} else if (options.mode === 'summary') {
|
||||
html += 'col-lg-6';
|
||||
} else if (options.id !== undefined) {
|
||||
html += "col-lg-4";
|
||||
} else {
|
||||
html += "col-lg-8 col-md-6";
|
||||
}
|
||||
html += "\">\n";
|
||||
|
||||
html += "<div class=\"list-actions\">\n";
|
||||
|
||||
// Add toolbar buttons or 'actions'
|
||||
for (action in list.actions) {
|
||||
if (list.actions[action].mode === 'all' || list.actions[action].mode === options.mode) {
|
||||
if ((list.actions[action].basePaths === undefined) ||
|
||||
(list.actions[action].basePaths && list.actions[action].basePaths.indexOf(base) > -1)) {
|
||||
html += this.button({
|
||||
btn: list.actions[action],
|
||||
action: action,
|
||||
toolbar: true
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//select instructions
|
||||
if (options.mode === 'select' && list.selectInstructions) {
|
||||
btn = {
|
||||
awPopOver: list.selectInstructions,
|
||||
dataPlacement: 'left',
|
||||
dataContainer: 'body',
|
||||
'class': 'btn-xs btn-help',
|
||||
awToolTip: 'Click for help',
|
||||
dataTitle: 'Help',
|
||||
iconSize: 'fa-lg'
|
||||
};
|
||||
//html += this.button(btn, 'select');
|
||||
html += this.button({
|
||||
btn: btn,
|
||||
action: 'help',
|
||||
toolbar: true
|
||||
});
|
||||
}
|
||||
|
||||
html += "</div><!-- list-acitons -->\n";
|
||||
html += "</div><!-- list-actions-column -->\n";
|
||||
} else {
|
||||
//lookup
|
||||
html += "<div class=\"col-lg-7\"></div>\n";
|
||||
}
|
||||
|
||||
html += "</div><!-- list-acitons -->\n";
|
||||
html += "</div><!-- list-actions-column -->\n";
|
||||
} else {
|
||||
//lookup
|
||||
html += "<div class=\"col-lg-7\"></div>\n";
|
||||
html += "</div><!-- row -->\n";
|
||||
}
|
||||
|
||||
html += "</div><!-- row -->\n";
|
||||
|
||||
// Add a title and optionally a close button (used on Inventory->Groups)
|
||||
if (options.mode !== 'lookup' && list.showTitle) {
|
||||
html += "<div class=\"form-title\">";
|
||||
|
@ -1,3 +1,17 @@
|
||||
<div class="tab-pane" id="jobs">
|
||||
<div ng-cloak id="htmlTemplate"></div>
|
||||
<div ng-cloak id="htmlTemplate">
|
||||
<div class="row">
|
||||
<div class="col-lg-12" id="breadcrumbs"></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="well">
|
||||
<div class="job_list" id="completed_jobs"></div>
|
||||
<div class="job_list" id="running_jobs"></div>
|
||||
<div class="job_list" id="queued_jobs"></div>
|
||||
<div class="job_list" id="scheduled_jobs"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
231
awx/ui/static/sample/data/jobs/completed/data.json
Normal file
231
awx/ui/static/sample/data/jobs/completed/data.json
Normal file
@ -0,0 +1,231 @@
|
||||
{
|
||||
"count": 2,
|
||||
"next": null,
|
||||
"previous": null,
|
||||
"results": [
|
||||
{
|
||||
"id": 1,
|
||||
"url": "/api/v1/jobs/1/",
|
||||
"related": {
|
||||
"job_host_summaries": "/api/v1/jobs/1/job_host_summaries/",
|
||||
"activity_stream": "/api/v1/jobs/1/activity_stream/",
|
||||
"job_events": "/api/v1/jobs/1/job_events/",
|
||||
"job_template": "/api/v1/job_templates/3/",
|
||||
"inventory": "/api/v1/inventories/4/",
|
||||
"project": "/api/v1/projects/1/",
|
||||
"credential": "/api/v1/credentials/8/",
|
||||
"start": "/api/v1/jobs/1/start/",
|
||||
"cancel": "/api/v1/jobs/1/cancel/"
|
||||
},
|
||||
"summary_fields": {
|
||||
"credential": {
|
||||
"name": "ssh",
|
||||
"description": "machine creds",
|
||||
"kind": "ssh",
|
||||
"cloud": false
|
||||
},
|
||||
"job_template": {
|
||||
"name": "Hello World",
|
||||
"description": ""
|
||||
},
|
||||
"project": {
|
||||
"name": "Examples",
|
||||
"description": "Ansible example project",
|
||||
"status": "successful"
|
||||
},
|
||||
"inventory": {
|
||||
"name": "Rackspace",
|
||||
"description": "",
|
||||
"has_active_failures": true,
|
||||
"total_hosts": 20,
|
||||
"hosts_with_active_failures": 20,
|
||||
"total_groups": 3,
|
||||
"groups_with_active_failures": 3,
|
||||
"has_inventory_sources": true,
|
||||
"total_inventory_sources": 1,
|
||||
"inventory_sources_with_failures": 1
|
||||
}
|
||||
},
|
||||
"created": "2014-03-06T16:51:04.557Z",
|
||||
"modified": "2014-03-06T16:51:14.272Z",
|
||||
"job_template": 3,
|
||||
"job_type": "playbook_run",
|
||||
"inventory": 4,
|
||||
"project": 1,
|
||||
"playbook": "lamp_simple/site.yml",
|
||||
"credential": 8,
|
||||
"cloud_credential": null,
|
||||
"forks": 0,
|
||||
"limit": "",
|
||||
"verbosity": 0,
|
||||
"extra_vars": "{\n\t\"variable1\": \"some value\",\n\t\"variable2\": \"another value\"\n}",
|
||||
"job_tags": "",
|
||||
"launch_type": "manual",
|
||||
"status": "failed",
|
||||
"failed": true,
|
||||
"result_traceback": "",
|
||||
"passwords_needed_to_start": [],
|
||||
"job_args": "[\"ssh-agent\", \"sh\", \"-c\", \"ssh-add /tmp/tmp5N437j && ansible-playbook -i /vagrant/ansible-commander/awx/plugins/inventory/awxrest.py -u vagrant -e '{\\\"variable1\\\": \\\"some value\\\", \\\"variable2\\\": \\\"another value\\\"}' lamp_simple/site.yml\"]",
|
||||
"job_cwd": "/vagrant/ansible-commander/awx/projects/_1__examples",
|
||||
"job_env": {
|
||||
"CELERY_LOG_REDIRECT_LEVEL": "WARNING",
|
||||
"ANSIBLE_PARAMIKO_RECORD_HOST_KEYS": "False",
|
||||
"DJANGO_LIVE_TEST_SERVER_ADDRESS": "localhost:9013-9199",
|
||||
"LESSOPEN": "|/usr/bin/lesspipe.sh %s",
|
||||
"_MP_FORK_LOGFILE_": "",
|
||||
"SSH_CLIENT": "10.0.2.2 61378 22",
|
||||
"CVS_RSH": "ssh",
|
||||
"LOGNAME": "vagrant",
|
||||
"USER": "vagrant",
|
||||
"HOME": "/home/vagrant",
|
||||
"PATH": "/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/vagrant/bin",
|
||||
"REST_API_TOKEN": "**********************************",
|
||||
"CALLBACK_CONSUMER_PORT": "tcp://127.0.0.1:5557",
|
||||
"ANSIBLE_CALLBACK_PLUGINS": "/vagrant/ansible-commander/awx/plugins/callback",
|
||||
"LANG": "en_US.UTF-8",
|
||||
"HISTCONTROL": "ignoredups",
|
||||
"TERM": "xterm",
|
||||
"SHELL": "/bin/bash",
|
||||
"TZ": "America/New_York",
|
||||
"_MP_FORK_LOGFORMAT_": "[%(asctime)s: %(levelname)s/%(processName)s] %(message)s",
|
||||
"SHLVL": "1",
|
||||
"G_BROKEN_FILENAMES": "1",
|
||||
"HISTSIZE": "1000",
|
||||
"CELERY_LOG_FILE": "",
|
||||
"DJANGO_PROJECT_DIR": "/vagrant/ansible-commander",
|
||||
"ANSIBLE_HOST_KEY_CHECKING": "False",
|
||||
"JOB_ID": "1",
|
||||
"PYTHONPATH": "/vagrant/ansible-commander/awx/lib/site-packages:",
|
||||
"CELERY_LOADER": "djcelery.loaders.DjangoLoader",
|
||||
"_MP_FORK_LOGLEVEL_": "10",
|
||||
"ANSIBLE_NOCOLOR": "1",
|
||||
"JOB_CALLBACK_DEBUG": "1",
|
||||
"REST_API_URL": "http://127.0.0.1:8013",
|
||||
"_": "/usr/bin/nohup",
|
||||
"SSH_CONNECTION": "10.0.2.2 61378 10.0.2.15 22",
|
||||
"INVENTORY_HOSTVARS": "True",
|
||||
"SSH_TTY": "/dev/pts/0",
|
||||
"CELERY_LOG_LEVEL": "10",
|
||||
"HOSTNAME": "vagrant-centos64.vagrantup.com",
|
||||
"INVENTORY_ID": "4",
|
||||
"PWD": "/home/vagrant",
|
||||
"CELERY_LOG_REDIRECT": "1",
|
||||
"DJANGO_SETTINGS_MODULE": "awx.settings.development",
|
||||
"MAIL": "/var/spool/mail/vagrant",
|
||||
"LS_COLORS": "rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:*.tbz=01;31:*.tbz2=01;31:*.bz=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36:"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"url": "/api/v1/jobs/2/",
|
||||
"related": {
|
||||
"job_host_summaries": "/api/v1/jobs/2/job_host_summaries/",
|
||||
"activity_stream": "/api/v1/jobs/2/activity_stream/",
|
||||
"job_events": "/api/v1/jobs/2/job_events/",
|
||||
"job_template": "/api/v1/job_templates/3/",
|
||||
"inventory": "/api/v1/inventories/4/",
|
||||
"project": "/api/v1/projects/1/",
|
||||
"credential": "/api/v1/credentials/8/",
|
||||
"start": "/api/v1/jobs/2/start/",
|
||||
"cancel": "/api/v1/jobs/2/cancel/"
|
||||
},
|
||||
"summary_fields": {
|
||||
"credential": {
|
||||
"name": "ssh",
|
||||
"description": "machine creds",
|
||||
"kind": "ssh",
|
||||
"cloud": false
|
||||
},
|
||||
"job_template": {
|
||||
"name": "Hello World",
|
||||
"description": ""
|
||||
},
|
||||
"project": {
|
||||
"name": "Examples",
|
||||
"description": "Ansible example project",
|
||||
"status": "successful"
|
||||
},
|
||||
"inventory": {
|
||||
"name": "Rackspace",
|
||||
"description": "",
|
||||
"has_active_failures": true,
|
||||
"total_hosts": 20,
|
||||
"hosts_with_active_failures": 20,
|
||||
"total_groups": 3,
|
||||
"groups_with_active_failures": 3,
|
||||
"has_inventory_sources": true,
|
||||
"total_inventory_sources": 1,
|
||||
"inventory_sources_with_failures": 1
|
||||
}
|
||||
},
|
||||
"created": "2014-03-07T23:28:06.999Z",
|
||||
"modified": "2014-03-07T23:28:16.424Z",
|
||||
"job_template": 3,
|
||||
"job_type": "playbook_run",
|
||||
"inventory": 4,
|
||||
"project": 1,
|
||||
"playbook": "lamp_simple/site.yml",
|
||||
"credential": 8,
|
||||
"cloud_credential": null,
|
||||
"forks": 0,
|
||||
"limit": "",
|
||||
"verbosity": 0,
|
||||
"extra_vars": "{\n\t\"variable1\": \"some value\",\n\t\"variable2\": \"another value\"\n}",
|
||||
"job_tags": "",
|
||||
"launch_type": "manual",
|
||||
"status": "failed",
|
||||
"failed": true,
|
||||
"result_traceback": "",
|
||||
"passwords_needed_to_start": [],
|
||||
"job_args": "[\"ssh-agent\", \"sh\", \"-c\", \"ssh-add /tmp/tmpoeaDyc && ansible-playbook -i /vagrant/ansible-commander/awx/plugins/inventory/awxrest.py -u vagrant -e '{\\\"variable1\\\": \\\"some value\\\", \\\"variable2\\\": \\\"another value\\\"}' lamp_simple/site.yml\"]",
|
||||
"job_cwd": "/vagrant/ansible-commander/awx/projects/_1__examples",
|
||||
"job_env": {
|
||||
"CELERY_LOG_REDIRECT_LEVEL": "WARNING",
|
||||
"ANSIBLE_PARAMIKO_RECORD_HOST_KEYS": "False",
|
||||
"DJANGO_LIVE_TEST_SERVER_ADDRESS": "localhost:9013-9199",
|
||||
"LESSOPEN": "|/usr/bin/lesspipe.sh %s",
|
||||
"_MP_FORK_LOGFILE_": "",
|
||||
"SSH_CLIENT": "10.0.2.2 61378 22",
|
||||
"CVS_RSH": "ssh",
|
||||
"LOGNAME": "vagrant",
|
||||
"USER": "vagrant",
|
||||
"HOME": "/home/vagrant",
|
||||
"PATH": "/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/vagrant/bin",
|
||||
"REST_API_TOKEN": "**********************************",
|
||||
"CALLBACK_CONSUMER_PORT": "tcp://127.0.0.1:5557",
|
||||
"ANSIBLE_CALLBACK_PLUGINS": "/vagrant/ansible-commander/awx/plugins/callback",
|
||||
"LANG": "en_US.UTF-8",
|
||||
"HISTCONTROL": "ignoredups",
|
||||
"TERM": "xterm",
|
||||
"SHELL": "/bin/bash",
|
||||
"TZ": "America/New_York",
|
||||
"_MP_FORK_LOGFORMAT_": "[%(asctime)s: %(levelname)s/%(processName)s] %(message)s",
|
||||
"SHLVL": "1",
|
||||
"G_BROKEN_FILENAMES": "1",
|
||||
"HISTSIZE": "1000",
|
||||
"CELERY_LOG_FILE": "",
|
||||
"DJANGO_PROJECT_DIR": "/vagrant/ansible-commander",
|
||||
"ANSIBLE_HOST_KEY_CHECKING": "False",
|
||||
"JOB_ID": "2",
|
||||
"PYTHONPATH": "/vagrant/ansible-commander/awx/lib/site-packages:",
|
||||
"CELERY_LOADER": "djcelery.loaders.DjangoLoader",
|
||||
"_MP_FORK_LOGLEVEL_": "10",
|
||||
"ANSIBLE_NOCOLOR": "1",
|
||||
"JOB_CALLBACK_DEBUG": "1",
|
||||
"REST_API_URL": "http://127.0.0.1:8013",
|
||||
"_": "/usr/bin/nohup",
|
||||
"SSH_CONNECTION": "10.0.2.2 61378 10.0.2.15 22",
|
||||
"INVENTORY_HOSTVARS": "True",
|
||||
"SSH_TTY": "/dev/pts/0",
|
||||
"CELERY_LOG_LEVEL": "10",
|
||||
"HOSTNAME": "vagrant-centos64.vagrantup.com",
|
||||
"INVENTORY_ID": "4",
|
||||
"PWD": "/home/vagrant",
|
||||
"CELERY_LOG_REDIRECT": "1",
|
||||
"DJANGO_SETTINGS_MODULE": "awx.settings.development",
|
||||
"MAIL": "/var/spool/mail/vagrant",
|
||||
"LS_COLORS": "rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:*.tbz=01;31:*.tbz2=01;31:*.bz=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36:"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue
Block a user