Files
awx/awx/ui/client/features/output/details.directive.js
2018-04-13 13:50:52 -04:00

624 lines
15 KiB
JavaScript

const templateUrl = require('~features/output/details.partial.html');
let $http;
let $filter;
let $scope;
let $state;
let error;
let parse;
let prompt;
let resource;
let strings;
let status;
let wait;
let vm;
function mapChoices (choices) {
if (!choices) return {};
return Object.assign(...choices.map(([k, v]) => ({ [k]: v })));
}
function getStatusDetails (jobStatus) {
const unmapped = jobStatus || resource.model.get('status');
if (!unmapped) {
return null;
}
const choices = mapChoices(resource.model.options('actions.GET.status.choices'));
const label = 'Status';
const icon = `fa icon-job-${unmapped}`;
const value = choices[unmapped];
return { label, icon, value };
}
function getStartDetails (started) {
const unfiltered = started || resource.model.get('started');
const label = 'Started';
let value;
if (unfiltered) {
value = $filter('longDate')(unfiltered);
} else {
value = 'Not Started';
}
return { label, value };
}
function getFinishDetails (finished) {
const unfiltered = finished || resource.model.get('finished');
const label = 'Finished';
let value;
if (unfiltered) {
value = $filter('longDate')(unfiltered);
} else {
value = 'Not Finished';
}
return { label, value };
}
function getModuleArgDetails () {
const value = resource.model.get('module_args');
const label = 'Module Args';
if (!value) {
return null;
}
return { label, value };
}
function getJobTypeDetails () {
const unmapped = resource.model.get('job_type');
if (!unmapped) {
return null;
}
const choices = mapChoices(resource.model.options('actions.GET.job_type.choices'));
const label = 'Job Type';
const value = choices[unmapped];
return { label, value };
}
function getVerbosityDetails () {
const verbosity = resource.model.get('verbosity');
if (!verbosity) {
return null;
}
const choices = mapChoices(resource.model.options('actions.GET.verbosity.choices'));
const label = 'Verbosity';
const value = choices[verbosity];
return { label, value };
}
function getSourceWorkflowJobDetails () {
const sourceWorkflowJob = resource.model.get('summary_fields.source_workflow_job');
if (!sourceWorkflowJob) {
return null;
}
const link = `/#/workflows/${sourceWorkflowJob.id}`;
const tooltip = strings.get('resourceTooltips.SOURCE_WORKFLOW_JOB');
return { link, tooltip };
}
function getJobTemplateDetails () {
const jobTemplate = resource.model.get('summary_fields.job_template');
if (!jobTemplate) {
return null;
}
const label = 'Job Template';
const link = `/#/templates/job_template/${jobTemplate.id}`;
const value = $filter('sanitize')(jobTemplate.name);
const tooltip = strings.get('resourceTooltips.JOB_TEMPLATE');
return { label, link, value, tooltip };
}
function getLaunchedByDetails () {
const createdBy = resource.model.get('summary_fields.created_by');
const jobTemplate = resource.model.get('summary_fields.job_template');
const relatedSchedule = resource.model.get('related.schedule');
const schedule = resource.model.get('summary_fields.schedule');
if (!createdBy && !schedule) {
return null;
}
const label = 'Launched By';
let link;
let tooltip;
let value;
if (createdBy) {
tooltip = strings.get('resourceTooltips.USER');
link = `/#/users/${createdBy.id}`;
value = $filter('sanitize')(createdBy.username);
} else if (relatedSchedule && jobTemplate) {
tooltip = strings.get('resourceTooltips.SCHEDULE');
link = `/#/templates/job_template/${jobTemplate.id}/schedules/${schedule.id}`;
value = $filter('sanitize')(schedule.name);
} else {
tooltip = null;
link = null;
value = $filter('sanitize')(schedule.name);
}
return { label, link, tooltip, value };
}
function getInventoryDetails () {
const inventory = resource.model.get('summary_fields.inventory');
if (!inventory) {
return null;
}
const label = 'Inventory';
const tooltip = strings.get('resourceTooltips.INVENTORY');
const value = $filter('sanitize')(inventory.name);
let link;
if (inventory.kind === 'smart') {
link = `/#/inventories/smart/${inventory.id}`;
} else {
link = `/#/inventories/inventory/${inventory.id}`;
}
return { label, link, tooltip, value };
}
function getProjectDetails () {
const project = resource.model.get('summary_fields.project');
if (!project) {
return null;
}
const label = 'Project';
const link = `/#/projects/${project.id}`;
const value = $filter('sanitize')(project.name);
const tooltip = strings.get('resourceTooltips.PROJECT');
return { label, link, value, tooltip };
}
function getProjectStatusDetails (projectStatus) {
const project = resource.model.get('summary_fields.project');
const jobStatus = projectStatus || resource.model.get('summary_fields.project_update.status');
if (!project) {
return null;
}
return jobStatus;
}
function getProjectUpdateDetails (updateId) {
const project = resource.model.get('summary_fields.project');
const jobId = updateId || resource.model.get('summary_fields.project_update.id');
if (!project) {
return null;
}
const link = `/#/jobz/project/${jobId}`;
const tooltip = strings.get('resourceTooltips.PROJECT_UPDATE');
return { link, tooltip };
}
function getSCMRevisionDetails () {
const label = 'Revision';
const value = resource.model.get('scm_revision');
if (!value) {
return null;
}
return { label, value };
}
function getPlaybookDetails () {
const label = 'Playbook';
const value = resource.model.get('playbook');
if (!value) {
return null;
}
return { label, value };
}
function getJobExplanationDetails () {
const explanation = resource.model.get('job_explanation');
if (!explanation) {
return null;
}
const limit = 150;
const label = 'Explanation';
let more = explanation;
if (explanation.split(':')[0] === 'Previous Task Failed') {
const taskStringIndex = explanation.split(':')[0].length + 1;
const task = JSON.parse(explanation.substring(taskStringIndex));
more = `${task.job_type} failed for ${task.job_name} with ID ${task.job_id}`;
}
const less = $filter('limitTo')(more, limit);
const showMore = false;
const hasMoreToShow = more.length > limit;
return { label, less, more, showMore, hasMoreToShow };
}
function getResultTracebackDetails () {
const traceback = resource.model.get('result_traceback');
if (!traceback) {
return null;
}
const limit = 150;
const label = 'Results Traceback';
const more = traceback;
const less = $filter('limitTo')(more, limit);
const showMore = false;
const hasMoreToShow = more.length > limit;
return { label, less, more, showMore, hasMoreToShow };
}
function getCredentialDetails () {
const credential = resource.model.get('summary_fields.credential');
if (!credential) {
return null;
}
let label = 'Credential';
if (resource.type === 'playbook') {
label = 'Machine Credential';
}
if (resource.type === 'inventory') {
label = 'Source Credential';
}
const link = `/#/credentials/${credential.id}`;
const tooltip = strings.get('resourceTooltips.CREDENTIAL');
const value = $filter('sanitize')(credential.name);
return { label, link, tooltip, value };
}
function getForkDetails () {
const label = 'Forks';
const value = resource.model.get('forks');
if (!value) {
return null;
}
return { label, value };
}
function getLimitDetails () {
const label = 'Limit';
const value = resource.model.get('limit');
if (!value) {
return null;
}
return { label, value };
}
function getInstanceGroupDetails () {
const instanceGroup = resource.model.get('summary_fields.instance_group');
if (!instanceGroup) {
return null;
}
const label = 'Instance Group';
const value = $filter('sanitize')(instanceGroup.name);
let isolated = null;
if (instanceGroup.controller_id) {
isolated = 'Isolated';
}
return { label, value, isolated };
}
function getJobTagDetails () {
const label = 'Job Tags';
const value = resource.model.get('job_tags');
if (!value) {
return null;
}
return { label, value };
}
function getSkipTagDetails () {
const label = 'Skip Tags';
const value = resource.model.get('skip_tags');
if (!value) {
return null;
}
return { label, value };
}
function getExtraVarsDetails () {
const extraVars = resource.model.get('extra_vars');
if (!extraVars) {
return null;
}
const label = 'Extra Variables';
const tooltip = 'Read-only view of extra variables added to the job template.';
const value = parse(extraVars);
return { label, tooltip, value };
}
function getLabelDetails () {
const jobLabels = _.get(resource.model.get('related.labels'), 'results', []);
if (jobLabels.length < 1) {
return null;
}
const label = 'Labels';
const more = false;
const value = jobLabels.map(({ name }) => name).map($filter('sanitize'));
return { label, more, value };
}
function createErrorHandler (path, action) {
return res => {
const hdr = strings.get('error.HEADER');
const msg = strings.get('error.CALL', { path, action, status: res.status });
error($scope, res.data, res.status, null, { hdr, msg });
};
}
const ELEMENT_LABELS = '#job-results-labels';
const ELEMENT_PROMPT_MODAL = '#prompt-modal';
const LABELS_SLIDE_DISTANCE = 200;
function toggleLabels () {
if (!this.labels.more) {
$(ELEMENT_LABELS).slideUp(LABELS_SLIDE_DISTANCE);
this.labels.more = true;
} else {
$(ELEMENT_LABELS).slideDown(LABELS_SLIDE_DISTANCE);
this.labels.more = false;
}
}
function cancelJob () {
const actionText = strings.get('warnings.CANCEL_ACTION');
const hdr = strings.get('warnings.CANCEL_HEADER');
const warning = strings.get('warnings.CANCEL_BODY');
const id = resource.model.get('id');
const name = $filter('sanitize')(resource.model.get('name'));
const body = `<div class="Prompt-bodyQuery">${warning}</div>`;
const resourceName = `#${id} ${name}`;
const method = 'POST';
const url = `${resource.model.path}${id}/cancel/`;
const errorHandler = createErrorHandler('cancel job', method);
const action = () => {
wait('start');
$http({ method, url })
.catch(errorHandler)
.finally(() => {
$(ELEMENT_PROMPT_MODAL).modal('hide');
wait('stop');
});
};
prompt({ hdr, resourceName, body, actionText, action });
}
function deleteJob () {
const actionText = strings.get('DELETE');
const hdr = strings.get('warnings.DELETE_HEADER');
const warning = strings.get('warnings.DELETE_BODY');
const id = resource.model.get('id');
const name = $filter('sanitize')(resource.model.get('name'));
const body = `<div class="Prompt-bodyQuery">${warning}</div>`;
const resourceName = `#${id} ${name}`;
const method = 'DELETE';
const url = `${resource.model.path}${id}/`;
const errorHandler = createErrorHandler('delete job', method);
const action = () => {
wait('start');
$http({ method, url })
.then(() => $state.go('jobs'))
.catch(errorHandler)
.finally(() => {
$(ELEMENT_PROMPT_MODAL).modal('hide');
wait('stop');
});
};
prompt({ hdr, resourceName, body, actionText, action });
}
function AtJobDetailsController (
_$http_,
_$filter_,
_$state_,
_error_,
_prompt_,
_strings_,
_status_,
_wait_,
ParseTypeChange,
ParseVariableString,
) {
vm = this || {};
$http = _$http_;
$filter = _$filter_;
$state = _$state_;
error = _error_;
parse = ParseVariableString;
prompt = _prompt_;
strings = _strings_;
status = _status_;
wait = _wait_;
vm.init = _$scope_ => {
$scope = _$scope_;
resource = $scope.resource; // eslint-disable-line prefer-destructuring
vm.status = getStatusDetails();
vm.started = getStartDetails();
vm.finished = getFinishDetails();
vm.moduleArgs = getModuleArgDetails();
vm.jobType = getJobTypeDetails();
vm.jobTemplate = getJobTemplateDetails();
vm.sourceWorkflowJob = getSourceWorkflowJobDetails();
vm.inventory = getInventoryDetails();
vm.project = getProjectDetails();
vm.projectUpdate = getProjectUpdateDetails();
vm.projectStatus = getProjectStatusDetails();
vm.scmRevision = getSCMRevisionDetails();
vm.playbook = getPlaybookDetails();
vm.resultTraceback = getResultTracebackDetails();
vm.launchedBy = getLaunchedByDetails();
vm.jobExplanation = getJobExplanationDetails();
vm.verbosity = getVerbosityDetails();
vm.credential = getCredentialDetails();
vm.forks = getForkDetails();
vm.limit = getLimitDetails();
vm.instanceGroup = getInstanceGroupDetails();
vm.jobTags = getJobTagDetails();
vm.skipTags = getSkipTagDetails();
vm.extraVars = getExtraVarsDetails();
vm.labels = getLabelDetails();
// Relaunch and Delete Components
vm.job = _.get(resource.model, 'model.GET', {});
vm.canDelete = resource.model.get('summary_fields.user_capabilities.delete');
// XX - Codemirror
if (vm.extraVars) {
const cm = {
parseType: 'yaml',
$apply: $scope.$apply,
variables: vm.extraVars.value,
};
ParseTypeChange({
field_id: 'cm-extra-vars',
readOnly: true,
scope: cm,
});
}
vm.cancelJob = cancelJob;
vm.deleteJob = deleteJob;
vm.toggleLabels = toggleLabels;
const observe = (getter, transform, key) => {
$scope.$watch(getter, value => { vm[key] = transform(value); });
};
observe(status.getStarted, getStartDetails, 'started');
observe(status.getJobStatus, getStatusDetails, 'status');
observe(status.getFinished, getFinishDetails, 'finished');
observe(status.getProjectUpdateId, getProjectUpdateDetails, 'projectUpdate');
observe(status.getProjectStatus, getProjectStatusDetails, 'projectStatus');
};
}
AtJobDetailsController.$inject = [
'$http',
'$filter',
'$state',
'ProcessErrors',
'Prompt',
'JobStrings',
'JobStatusService',
'Wait',
'ParseTypeChange',
'ParseVariableString',
];
function atJobDetailsLink (scope, el, attrs, controllers) {
const [atDetailsController] = controllers;
atDetailsController.init(scope);
}
function atJobDetails () {
return {
templateUrl,
restrict: 'E',
require: ['atJobDetails'],
controllerAs: 'vm',
link: atJobDetailsLink,
controller: AtJobDetailsController,
scope: { resource: '=', },
};
}
export default atJobDetails;