diff --git a/awx/ui/static/js/controllers/Jobs.js b/awx/ui/static/js/controllers/Jobs.js index c31b1b635a..259ec8e0a0 100644 --- a/awx/ui/static/js/controllers/Jobs.js +++ b/awx/ui/static/js/controllers/Jobs.js @@ -8,79 +8,81 @@ * */ +/* global jsyaml:false */ + '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 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('htmlTemplate'); - var list = JobList; - var defaultUrl = GetBasePath('jobs'); - var view = GenerateList; - var base = $location.path().replace(/^\//,'').split('/')[0]; - var scope = view.inject(list, { mode: 'edit' }); + + var list = JobList, + defaultUrl = GetBasePath('jobs'), + view = GenerateList, + scope = view.inject(list, { mode: 'edit' }), + opt; + $rootScope.flashMessage = null; scope.selected = []; if (scope.removePostRefresh) { - scope.removePostRefresh(); + scope.removePostRefresh(); } scope.removePostRefresh = scope.$on('PostRefresh', function() { - $("tr.success").each(function(index) { + 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) { - var cDate; - for (var 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 (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']; + 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']; + 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.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.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 (var 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; - } - } + 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); @@ -88,88 +90,89 @@ function JobsListCtrl ($scope, $rootScope, $location, $log, $routeParams, Rest, LoadBreadCrumbs(); scope.refresh = function() { - Wait('start'); - scope['jobLoading'] = false; - Refresh({ scope: scope, set: 'jobs', iterator: 'job', url: scope['current_url'] }); - } + 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); - } + 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'); - } + 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'); - } + LoadBreadCrumbs({ path: '/jobs/' + id, title: id + ' - ' + name }); + $location.path($location.path() + '/' + id + '/job_host_summaries'); + }; - scope.deleteJob = function(id, name) { - Rest.setUrl(defaultUrl + id + '/'); - Rest.get() - .success( function(data, status, headers, config) { - var url, action_label, restcall, 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'; - } + 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'; + } - var action = function() { - Rest.setUrl(url); - if (action_label == 'cancel') { - Rest.post() - .success( function(data, status, headers, config) { - $('#prompt-modal').modal('hide'); - scope.search(list.iterator); - }) - .error( function(data, status, headers, config) { - $('#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(data, status, headers, config) { - $('#prompt-modal').modal('hide'); - scope.search(list.iterator); - }) - .error( function(data, status, headers, config) { - $('#prompt-modal').modal('hide'); - ProcessErrors(scope, data, status, null, - { hdr: 'Error!', msg: 'Call to ' + url + ' failed. DELETE returned status: ' + status }); - }); - } - }; + 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, headers, config) { - ProcessErrors(scope, data, status, null, - { hdr: 'Error!', msg: 'Failed to get job details. GET 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', @@ -179,294 +182,282 @@ JobsListCtrl.$inject = [ '$scope', '$rootScope', '$location', '$log', '$routePar ]; -function JobsEdit ($scope, $rootScope, $compile, $location, $log, $routeParams, JobForm, - GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, RelatedSearchInit, - RelatedPaginateInit, ReturnToCaller, ClearScope, InventoryList, CredentialList, - ProjectList, LookUpInit, PromptPasswords, GetBasePath, md5Setup, FormatDate, - JobStatusToolTip, Wait) -{ - ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior +function JobsEdit ($scope, $rootScope, $compile, $location, $log, $routeParams, JobForm, GenerateForm, Rest, Alert, ProcessErrors, + LoadBreadCrumbs, RelatedSearchInit,RelatedPaginateInit, ReturnToCaller, ClearScope, InventoryList, CredentialList, + ProjectList, LookUpInit, PromptPasswords, GetBasePath, md5Setup, FormatDate, JobStatusToolTip, Wait) { + + ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior //scope. - var defaultUrl= GetBasePath('jobs'); - var generator = GenerateForm; - var form = JobForm; + var defaultUrl= GetBasePath('jobs'), + generator = GenerateForm, + form = JobForm, + scope = generator.inject(form, {mode: 'edit', related: true}), + master = {}, + id = $routeParams.id, + relatedSets = {}, + loadingFinishedCount = 0; + + generator.reset(); - var scope = generator.inject(form, {mode: 'edit', related: true}); - generator.reset(); - var base = $location.path().replace(/^\//,'').split('/')[0]; - var master = {}; - var id = $routeParams.id; - var relatedSets = {}; - var loadingFinishedCount = 0; - - scope.job_id = id; - scope.parseType = 'yaml'; - scope.statusSearchSpin = false; + scope.job_id = id; + scope.parseType = 'yaml'; + scope.statusSearchSpin = false; - function getPlaybooks(project) { - if (project !== null && project !== '' && project !== undefined) { - var url = GetBasePath('projects') + project + '/playbooks/'; - Rest.setUrl(url); - Rest.get() - .success( function(data, status, headers, config) { - scope.playbook_options = []; - for (var i=0; i < data.length; i++) { - scope.playbook_options.push(data[i]); - } - scope.$emit('jobTemplateLoadFinished'); - }) - .error( function(data, status, headers, config) { - scope.$emit('jobTemplateLoadFinished'); - }); - } - else { - scope.$emit('jobTemplateLoadFinished'); - } - } + function getPlaybooks(project) { + if (project !== null && project !== '' && project !== undefined) { + var url = GetBasePath('projects') + project + '/playbooks/'; + Rest.setUrl(url); + Rest.get() + .success( function(data) { + scope.playbook_options = []; + for (var i=0; i < data.length; i++) { + scope.playbook_options.push(data[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) { + // Retrieve each related set and populate the playbook list + if (scope.jobLoadedRemove) { + scope.jobLoadedRemove(); + } + scope.jobLoadedRemove = scope.$on('jobLoaded', function(e, related_cloud_credential) { - getPlaybooks(scope.project); + getPlaybooks(scope.project); - scope[form.name + 'ReadOnly'] = (scope.status == 'new') ? false : true; + 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'); + $('#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, status, headers, config) { - 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['callback']; - scope.$emit('jobTemplateLoadFinished'); - }) - .error( function(data, status, headers, config) { - scope['callback_url'] = '<< Job template not found >>'; - }); + // 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.callback; + 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, status, headers, config) { - scope['cloud_credential_name'] = data.name; - scope.$emit('jobTemplateLoadFinished'); - }) - .error( function(data, status, headers, config) { - ProcessErrors(scope, data, status, null, - { hdr: 'Error!', msg: 'Failed to related cloud credential. GET returned status: ' + status }); - }); - } - else { - scope.$emit('jobTemplateLoadFinished'); - } - }); + 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 >= 3) { - // The initial template load finished. Now load related jobs, which - // will turn off the 'working' spinner. - Wait('stop'); - } - }); + // 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 >= 3) { + // 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; + // 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); - var rows = (n) ? n.length : 1; - return (rows > 15) ? 15 : rows; - } + 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, status, headers, config) { + // Retrieve detail record and prepopulate the form + Wait('start'); + Rest.setUrl(defaultUrl + ':id/'); + Rest.get({ params: {id: id} }) + .success( function(data) { + //LoadBreadCrumbs({ path: '/jobs/' + id, title: data.id + ' - ' + data.summary_fields.job_template.name }); + var i, cDate, fld, json_obj, related, set; + LoadBreadCrumbs(); + for (fld in form.fields) { + if (fld !== 'variables' && data[fld] !== null && data[fld] !== undefined) { + if (form.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]; + } + master[fld] = scope[fld]; + } + + scope.id = data.id; + scope.name = data.summary_fields.job_template.name; + + if (fld === 'variables') { + // Parse extra_vars, converting to YAML. + if ($.isEmptyObject(data.extra_vars) || data.extra_vars === "{}" || data.extra_vars === "null" || + data.extra_vars === "" || data.extra_vars === null) { + scope.variables = "---"; + } + else { + json_obj = JSON.parse(data.extra_vars); + scope.variables = jsyaml.safeDump(json_obj); + } + master.variables = scope.variables; + } + if (form.fields[fld].type === 'lookup' && data.summary_fields[form.fields[fld].sourceModel]) { + scope[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] = + data.summary_fields[form.fields[fld].sourceModel][form.fields[fld].sourceField]; + master[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] = + scope[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField]; + } - //LoadBreadCrumbs({ path: '/jobs/' + id, title: data.id + ' - ' + data.summary_fields.job_template.name }); - LoadBreadCrumbs(); - - for (var fld in form.fields) { - if (fld != 'variables' && data[fld] !== null && data[fld] !== undefined) { - if (form.fields[fld].type == 'select') { - if (scope[fld + '_options'] && scope[fld + '_options'].length > 0) { - for (var i=0; i < scope[fld + '_options'].length; i++) { - if (data[fld] == scope[fld + '_options'][i].value) { - scope[fld] = scope[fld + '_options'][i]; - } - } + for (fld in form.statusFields) { + if (data[fld] !== null && data[fld] !== undefined) { + if (fld === 'created') { + // Convert created date to local time zone + cDate = new Date(data.created); + scope.created = FormatDate(cDate); } else { - scope[fld] = data[fld]; + scope[fld] = data[fld]; } - } - else { - scope[fld] = data[fld]; - } - master[fld] = scope[fld]; - } - - scope.id = data.id; - scope.name = data.summary_fields.job_template.name; + } + } - if (fld == 'variables') { - // Parse extra_vars, converting to YAML. - if ($.isEmptyObject(data.extra_vars) || data.extra_vars == "\{\}" || data.extra_vars == "null" - || data.extra_vars == "" || data.extra_vars == null) { - scope.variables = "---"; - } - else { - var json_obj = JSON.parse(data.extra_vars); - scope.variables = jsyaml.safeDump(json_obj); - } - master.variables = scope.variables; - } - if (form.fields[fld].type == 'lookup' && data.summary_fields[form.fields[fld].sourceModel]) { - scope[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] = - data.summary_fields[form.fields[fld].sourceModel][form.fields[fld].sourceField]; - master[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] = - scope[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField]; - } - } - - for (var fld in form.statusFields) { - if (data[fld] !== null && data[fld] !== undefined) { - if (fld == 'created') { - // Convert created date to local time zone - var cDate = new Date(data.created); - scope.created = FormatDate(cDate); - } - else { - scope[fld] = data[fld]; - } - } - } - - scope.statusToolTip = JobStatusToolTip(data.status); + scope.statusToolTip = JobStatusToolTip(data.status); - $('form[name="jobs_form"] input[type="text"], form[name="jobs_form"] jobs_form textarea').attr('readonly','readonly'); - $('form[name="jobs_form"] select').prop('disabled', 'disabled'); - $('form[name="jobs_form"] .lookup-btn').prop('disabled', 'disabled'); - $('form[name="jobs_form"] .buttons, form[name="jobs_form"] hr').hide(); + $('form[name="jobs_form"] input[type="text"], form[name="jobs_form"] jobs_form textarea').attr('readonly','readonly'); + $('form[name="jobs_form"] select').prop('disabled', 'disabled'); + $('form[name="jobs_form"] .lookup-btn').prop('disabled', 'disabled'); + $('form[name="jobs_form"] .buttons, form[name="jobs_form"] hr').hide(); - scope.url = data.url; - var related = data.related; - for (var set in form.related) { - if (related[set]) { - relatedSets[set] = { url: related[set], iterator: form.related[set].iterator }; - } - } - - // Calc row size of stdout and traceback textarea fields - //var n = scope['result_stdout'].match(/\n/g); - //var rows = (n) ? n.length : 1; - //rows = (rows > 15) ? 15 : rows; - //rows; + scope.url = data.url; + related = data.related; + for (set in form.related) { + if (related[set]) { + relatedSets[set] = { url: related[set], iterator: form.related[set].iterator }; + } + } - scope['stdout_rows'] = calcRows(scope['result_stdout']); + scope.stdout_rows = calcRows(scope.result_stdout); + + scope.traceback_rows = calcRows(scope.result_traceback); - //n = scope['result_traceback'].match(/\n/g); - //var rows = (n) ? n.length : 1; - //rows = (rows > 15) ? 15 : rows; + LookUpInit({ + scope: scope, + form: form, + current_item: data.inventory, + list: InventoryList, + field: 'inventory' + }); - scope['traceback_rows'] = calcRows(scope['result_traceback']); + LookUpInit({ + scope: scope, + form: form, + current_item: data.credential, + list: CredentialList, + field: 'credential' + }); - LookUpInit({ - scope: scope, - form: form, - current_item: data.inventory, - list: InventoryList, - field: 'inventory' - }); + LookUpInit({ + scope: scope, + form: form, + current_item: data.project, + list: ProjectList, + field: 'project' + }); - LookUpInit({ - scope: scope, - form: form, - current_item: data.credential, - list: CredentialList, - field: 'credential' - }); + // Initialize related search functions. Doing it here to make sure relatedSets object is populated. + RelatedSearchInit({ scope: scope, form: form, relatedSets: relatedSets }); + RelatedPaginateInit({ scope: scope, relatedSets: relatedSets }); + scope.template_url = data.related.job_template; + scope.$emit('jobLoaded', data.related.cloud_credential); + }) + .error( function(data, status) { + ProcessErrors(scope, data, status, form, + { hdr: 'Error!', msg: 'Failed to retrieve job: ' + $routeParams.id + '. GET status: ' + status }); + }); - LookUpInit({ - scope: scope, - form: form, - current_item: data.project, - list: ProjectList, - field: 'project' - }); + 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) { + Wait('stop'); + ProcessErrors(scope, data, status, null, + { hdr: 'Error!', msg: 'Attempt to load job failed. GET returned status: ' + status }); + }); + }; - // Initialize related search functions. Doing it here to make sure relatedSets object is populated. - RelatedSearchInit({ scope: scope, form: form, relatedSets: relatedSets }); - RelatedPaginateInit({ scope: scope, relatedSets: relatedSets }); - scope.template_url = data.related.job_template; - scope.$emit('jobLoaded', data.related.cloud_credential); - }) - .error( function(data, status, headers, config) { - ProcessErrors(scope, data, status, form, - { hdr: 'Error!', msg: 'Failed to retrieve job: ' + $routeParams.id + '. GET status: ' + status }); - }); + scope.jobSummary = function() { + $location.path('/jobs/' + id + '/job_host_summaries'); + }; - scope.refresh = function() { - Wait('start'); - Rest.setUrl(defaultUrl + id + '/'); - Rest.get() - .success( function(data, status, headers, config) { - 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, headers, config) { - Wait('stop'); - 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'); - } + scope.jobEvents = function() { + $location.path('/jobs/' + id + '/job_events'); + }; } -JobsEdit.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'JobForm', - 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'RelatedSearchInit', +JobsEdit.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'JobForm', + 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'RelatedSearchInit', 'RelatedPaginateInit', 'ReturnToCaller', 'ClearScope', 'InventoryList', 'CredentialList', 'ProjectList', 'LookUpInit', 'PromptPasswords', 'GetBasePath', 'md5Setup', 'FormatDate', 'JobStatusToolTip', 'Wait' diff --git a/awx/ui/static/js/lists/JobEvents.js b/awx/ui/static/js/lists/JobEvents.js index 47e65504e0..422fb993cd 100644 --- a/awx/ui/static/js/lists/JobEvents.js +++ b/awx/ui/static/js/lists/JobEvents.js @@ -68,7 +68,7 @@ angular.module('JobEventsListDefinition', []) event_display: { label: 'Event', hasChildren: true, - ngClick: 'toggleChildren({{ jobevent.id }}, \'{{ jobevent.related.children }}\')', + ngClick: 'toggleChildren(jobevent.id, jobevent.related.children)', nosort: true, searchable: false, ngClass: '{{ jobevent.class }}', @@ -101,7 +101,7 @@ angular.module('JobEventsListDefinition', []) view: { label: 'View', - ngClick: 'viewJobEvent({{ jobevent.id }})', + ngClick: 'viewJobEvent(jobevent.id)', awToolTip: 'View event details', dataPlacement: 'top' } diff --git a/awx/ui/static/js/lists/JobHosts.js b/awx/ui/static/js/lists/JobHosts.js index 78092ca858..5fc23f5ab7 100644 --- a/awx/ui/static/js/lists/JobHosts.js +++ b/awx/ui/static/js/lists/JobHosts.js @@ -7,8 +7,7 @@ * */ angular.module('JobHostDefinition', []) - .value( - 'JobHostList', { + .value('JobHostList', { name: 'jobhosts', iterator: 'jobhost', @@ -23,50 +22,50 @@ angular.module('JobHostDefinition', []) label: 'Status', icon: 'icon-zoom-in', ngShow: "job_id !== null" - }, + }, events: { href: "/#/jobs/{{ job_id }}/job_events", label: 'Events', icon: 'icon-list-ul' - }, + }, hosts: { href: "/#/jobs/{{ job_id }}/job_host_summaries", label: 'Host Summary', active: true, icon: 'icon-laptop' - } - }, + } + }, fields: { job: { label: 'Job ID', - ngClick: "showJob(\{\{ jobhost.job \}\})", + ngClick: "showJob(jobhost.job)", columnShow: 'host_id !== null', key: true, desc: true - }, + }, host: { label: 'Host', key: true, sourceModel: 'host', sourceField: 'name', ngBind: 'jobhost.host_name', - ngHref: "\{\{ jobhost.hostLinkTo \}\}" - }, + ngHref: "jobhost.hostLinkTo" + }, status: { label: 'Status', - badgeNgHref: "\{\{ jobhost.statusLinkTo \}\}", - badgeIcon: 'fa icon-job-\{\{ jobhost.status \}\}', + badgeNgHref: "{{ jobhost.statusLinkTo }}", + badgeIcon: 'fa icon-job-{{ jobhost.status }}', badgePlacement: 'left', - badgeToolTip: "\{\{ jobhost.statusBadgeToolTip \}\}", + badgeToolTip: "{{ jobhost.statusBadgeToolTip }}", badgeTipPlacement: 'top', - ngHref: "\{\{ jobhost.statusLinkTo \}\}", - awToolTip: "\{\{ jobhost.statusBadgeToolTip \}\}", + ngHref: "{{ jobhost.statusLinkTo }}", + awToolTip: "{{ jobhost.statusBadgeToolTip }}", dataPlacement: 'top', searchField: 'failed', searchType: 'boolean', searchOptions: [{ name: "success", value: 0 }, { name: "error", value: 1 }] - }, + }, failed: { label: 'Job failed?', searchSingleValue: true, @@ -74,32 +73,32 @@ angular.module('JobHostDefinition', []) searchValue: 'true', searchOnly: true, nosort: true - }, + }, ok: { label: 'Success', searchable: false - }, + }, changed: { label: 'Changed', searchable: false - }, + }, failures: { label: 'Failure', searchable: true, searchLabel: 'Contains failed events?', searchType: 'gtzero' - }, + }, dark: { label: 'Unreachable', searchable: true, searchType: 'gtzero', searchLabel: 'Contains unreachable hosts?' - }, + }, skipped: { label: 'Skipped', searchable: false - } - }, + } + }, actions: { help: { @@ -116,17 +115,16 @@ angular.module('JobHostDefinition', []) awToolTip: 'Click for help', dataTitle: 'Job Host Summary', id: 'jobhost-help-button' - }, + }, refresh: { mode: 'all', 'class': 'btn-xs', awToolTip: "Refresh the page", ngClick: "refresh()", ngShow: "host_id == null" //don't show when viewing from inventory->hosts - } - }, - - fieldActions: { } + }, - }); + fieldActions: {} + + }); diff --git a/awx/ui/static/js/lists/Jobs.js b/awx/ui/static/js/lists/Jobs.js index 29a40309d0..2cdec7b5af 100644 --- a/awx/ui/static/js/lists/Jobs.js +++ b/awx/ui/static/js/lists/Jobs.js @@ -7,8 +7,7 @@ * */ angular.module('JobsListDefinition', []) - .value( - 'JobList', { + .value( 'JobList', { name: 'jobs', iterator: 'job', @@ -22,26 +21,26 @@ angular.module('JobsListDefinition', []) label: 'Job ID', key: true, desc: true, - searchType: 'int' - }, + searchType: 'int' + }, inventory: { label: 'Inventory ID', searchType: 'int', searchOnly: true - }, + }, created: { label: 'Create On', link: false, searchable: false - }, + }, job_template: { label: 'Job Template', ngBind: 'job.summary_fields.job_template.name', - //ngHref: "\{\{ '/#/job_templates/?name=' + job.summary_fields.job_template.name \}\}", - ngHref:"\{\{ '/#/job_templates/' + job.job_template \}\}", + //ngHref: "{{ '/#/job_templates/?name=' + job.summary_fields.job_template.name }}", + ngHref:"{{ '/#/job_templates/' + job.job_template }}", sourceModel: 'job_template', sourceField: 'name' - }, + }, failed: { label: 'Job failed?', searchSingleValue: true, @@ -49,76 +48,77 @@ angular.module('JobsListDefinition', []) searchValue: 'true', searchOnly: true, nosort: true - }, + }, status: { label: 'Status', - "class": 'job-\{\{ job.status \}\}', + "class": 'job-{{ job.status }}', searchType: 'select', - linkTo: "\{\{ job.statusLinkTo \}\}", + linkTo: "{{ job.statusLinkTo }}", searchOptions: [ { name: "new", value: "new" }, { name: "waiting", value: "waiting" }, { name: "pending", value: "pending" }, - { name: "running", value: "running" }, + { name: "running", value: "running" }, { name: "successful", value: "successful" }, { name: "error", value: "error" }, { name: "failed", value: "failed" }, - { name: "canceled", value: "canceled" } ], - badgeIcon: 'fa icon-job-\{\{ job.status \}\}', + { name: "canceled", value: "canceled" } + ], + badgeIcon: 'fa icon-job-{{ job.status }}', badgePlacement: 'left', - badgeToolTip: "\{\{ job.statusBadgeToolTip \}\}", + badgeToolTip: "{{ job.statusBadgeToolTip }}", badgeTipPlacement: 'top', - badgeNgHref: "\{\{ job.statusLinkTo \}\}", - awToolTip: "\{\{ job.statusBadgeToolTip \}\}", + badgeNgHref: "{{ job.statusLinkTo }}", + awToolTip: "{{ job.statusBadgeToolTip }}", dataPlacement: 'top' - } - }, + } + }, actions: { refresh: { mode: 'all', awToolTip: "Refresh the page", ngClick: "refresh()" - } - }, + } + }, fieldActions: { submit: { label: 'Relaunch', icon: 'icon-rocket', - mode: 'all', - ngClick: "submitJob(\{\{ job.id \}\}, '\{\{ job.summary_fields.job_template.name \}\}' )", + mode: 'all', + ngClick: 'submitJob(job.id, job.summary_fields.job_template.name)', awToolTip: 'Start the job', dataPlacement: 'top' - }, + }, cancel: { label: 'Stop', mode: 'all', - ngClick: 'deleteJob(\{\{ job.id \}\})', + ngClick: 'deleteJob(job.id)', awToolTip: 'Cancel a running or pending job', ngShow: "job.status == 'pending' || job.status == 'running' || job.status == 'waiting'", dataPlacement: 'top' - }, + }, "delete": { label: 'Delete', mode: 'all', - ngClick: 'deleteJob(\{\{ job.id \}\})', + ngClick: 'deleteJob(job.id)', awToolTip: 'Delete the job', ngShow: "job.status != 'pending' && job.status != 'running' && job.status != 'waiting'", dataPlacement: 'top' - }, - dropdown: { + }, + dropdown: { type: 'DropDown', label: 'View', icon: 'fa-search-plus', 'class': 'btn-default btn-xs', options: [ - { ngClick: "editJob(\{\{ job.id \}\}, '\{\{ job.summary_fields.job_template.name \}\}')", label: 'Status' }, - { ngClick: "viewEvents(\{{ job.id \}\}, '\{\{ job.summary_fields.job_template.name \}\}')", label: 'Events', + { ngClick: 'editJob(job.id, job.summary_fields.job_template.name)', label: 'Status' }, + { ngClick: 'viewEvents(job.id, job.summary_fields.job_template.name)', label: 'Events', ngHide: "job.status == 'new'" }, - { ngClick: "viewSummary(\{{ job.id \}\}, '\{\{ job.summary_fields.job_template.name \}\}')", label: 'Host Summary', + { ngClick: 'viewSummary(job.id, job.summary_fields.job_template.name)', label: 'Host Summary', ngHide: "job.status == 'new'" } - ] - } + ] } - }); + } + }); diff --git a/awx/ui/static/lib/ansible/api-loader.js b/awx/ui/static/lib/ansible/api-loader.js index 668f5535da..bf999cd5c5 100644 --- a/awx/ui/static/lib/ansible/api-loader.js +++ b/awx/ui/static/lib/ansible/api-loader.js @@ -9,51 +9,49 @@ 'use strict'; -angular.module('ApiLoader', ['ngCookies']) - .factory('LoadBasePaths', ['$http', '$rootScope', '$cookieStore', 'ProcessErrors', - function($http, $rootScope, $cookieStore, ProcessErrors) { - return function() { - $http.get('/api/') - .success( function(data, status, headers, config) { - var base = data.current_version; - $http.get(base) - .success( function(data, status, headers, config) { - data['base'] = base; - $rootScope['defaultUrls'] = data; - $cookieStore.remove('api'); - $cookieStore.put('api',data); //Preserve in cookie to prevent against - //loss during browser refresh - }) - .error ( function(data, status, headers, config) { - $rootScope['defaultUrls'] = { status: 'error' }; - ProcessErrors(null, data, status, null, - { hdr: 'Error', msg: 'Failed to read ' + base + '. GET status: ' + status }); - }); - }) - .error( function(data, status, headers, config) { - $rootScope['defaultUrls'] = { status: 'error' }; - ProcessErrors(null, data, status, null, - { hdr: 'Error', msg: 'Failed to read /api. GET status: ' + status }); - }); - } - }]) +angular.module('ApiLoader', ['Utilities']) + + .factory('LoadBasePaths', ['$http', '$rootScope', 'Store', 'ProcessErrors', + function($http, $rootScope, Store, ProcessErrors) { + return function() { + $http.get('/api/') + .success( function(data) { + var base = data.current_version; + $http.get(base) + .success( function(data) { + data.base = base; + $rootScope.defaultUrls = data; + Store('api', data); + }) + .error ( function(data, status) { + $rootScope.defaultUrls = { status: 'error' }; + ProcessErrors(null, data, status, null, + { hdr: 'Error', msg: 'Failed to read ' + base + '. GET status: ' + status }); + }); + }) + .error( function(data, status) { + $rootScope.defaultUrls = { status: 'error' }; + ProcessErrors(null, data, status, null, + { hdr: 'Error', msg: 'Failed to read /api. GET status: ' + status }); + }); + }; + }]) + + .factory('GetBasePath', ['$rootScope', 'Store', 'LoadBasePaths', 'Empty', + function($rootScope, Store, LoadBasePaths, Empty) { + return function(set) { + // use /api/v1/ results to construct API URLs. + if (Empty($rootScope.defaultUrls)) { + // browser refresh must have occurred. load from local storage + if (Store('api')) { + $rootScope.defaultUrls = Store('api'); + return $rootScope.defaultUrls[set]; + } + return ''; //we should never get here + } + return $rootScope.defaultUrls[set]; + }; + }]); - .factory('GetBasePath', ['$rootScope', '$cookieStore', 'LoadBasePaths', - function($rootScope, $cookieStore, LoadBasePaths) { - return function(set) { - // use /api/v1/ results to construct API URLs. - var answer; - if ($rootScope['defaultUrls'] == null || $rootScope['defaultUrls'] == undefined) { - // browser refresh must have occurred. use what's in session cookie and refresh - answer = $cookieStore.get('api')[set]; - LoadBasePaths(); - } - else { - answer = $rootScope['defaultUrls'][set]; - } - return answer; - } - }]); - \ No newline at end of file diff --git a/awx/ui/static/lib/ansible/filters.js b/awx/ui/static/lib/ansible/filters.js index 7e4ff4845d..7c393a469a 100644 --- a/awx/ui/static/lib/ansible/filters.js +++ b/awx/ui/static/lib/ansible/filters.js @@ -12,14 +12,15 @@ angular.module('AWFilters', []) // capitalize -capitalize the first letter of each word // .filter('capitalize', [ function() { - return function(input) { - if (input) { - var values = input.replace(/\_/g,' ').split(" "); - var result = ""; - for (var i = 0; i < values.length; i++){ - result += values[i].charAt(0).toUpperCase() + values[i].substr(1) + ' '; + return function(input) { + var values, result, i; + if (input) { + values = input.replace(/\_/g,' ').split(" "); + result = ""; + for (i = 0; i < values.length; i++){ + result += values[i].charAt(0).toUpperCase() + values[i].substr(1) + ' '; + } + return result.trim(); } - return result.trim(); - } - } - }]); \ No newline at end of file + }; + }]); \ No newline at end of file