Show workflow badge

Add Workflow tags

Hookup workflow details link

Add parent workflow and job explanation fields

Add workflow key icon to WF maker and WF results

Hookup wf prompting

Add wf key dropdown and hide wf info badge
This commit is contained in:
Marliana Lara
2018-10-06 19:41:12 -04:00
parent f6cc351f7f
commit e20d8c8e81
12 changed files with 317 additions and 130 deletions

View File

@@ -102,6 +102,7 @@ function TemplatesStrings (BaseString) {
ALWAYS: t.s('Always'),
PROJECT_SYNC: t.s('Project Sync'),
INVENTORY_SYNC: t.s('Inventory Sync'),
WORKFLOW: t.s('Workflow'),
WARNING: t.s('Warning'),
TOTAL_TEMPLATES: t.s('TOTAL TEMPLATES'),
ADD_A_TEMPLATE: t.s('ADD A TEMPLATE'),

View File

@@ -493,21 +493,6 @@ table, tbody {
}
}
.List-infoCell--badge {
height: 15px;
color: @default-interface-txt;
background-color: @default-list-header-bg;
border-radius: 5px;
font-size: 10px;
padding-left: 10px;
padding-right: 10px;
margin-left: 10px;
text-transform: uppercase;
font-weight: 100;
margin-top: 2.25px;
outline: none;
}
.List-actionsInner {
display: flex;
}

View File

@@ -1,3 +1,4 @@
<div class="List-infoCell">
<span class="List-infoCell--badge" aw-pop-over="<dl><dt>{{ 'INVENTORY' | translate }}</dt><dd>{{(job_template.summary_fields.inventory.name | sanitize) || ('NONE SELECTED' | translate)}}</dd></dl><dl><dt>{{ 'PROJECT' | translate }}</dt><dd>{{job_template.summary_fields.project.name | sanitize}}</dd></dl><dl><dt>{{ 'PLAYBOOK' | translate }}</dt><dd>{{job_template.playbook| sanitize}}</dd></dl><dl><dt>{{ 'CREDENTIAL' | translate }}</dt> <dd>{{(job_template.summary_fields.credential.name | sanitize) || ('NONE SELECTED' | translate)}}</dd></dl>" data-popover-title="{{job_template.name| sanitize}}" translate>INFO</span>
<div class="List-infoCell" ng-if="job_template.type === 'job_template'">
<span class="Key-icon Key-icon--circle Key-icon--default" aw-pop-over="<dl><dt>{{ 'INVENTORY' | translate }}</dt><dd>{{(job_template.summary_fields.inventory.name | sanitize) || ('NONE SELECTED' | translate)}}</dd></dl><dl><dt>{{ 'PROJECT' | translate }}</dt><dd>{{job_template.summary_fields.project.name | sanitize}}</dd></dl><dl><dt>{{ 'PLAYBOOK' | translate }}</dt><dd>{{job_template.playbook| sanitize}}</dd></dl><dl><dt>{{ 'CREDENTIAL' | translate }}</dt> <dd>{{(job_template.summary_fields.credential.name | sanitize) || ('NONE SELECTED' | translate)}}</dd></dl>"
data-popover-title="{{job_template.name| sanitize}}">?</span>
</div>

View File

@@ -696,6 +696,13 @@ angular.module('GeneratorHelpers', [systemStatus.name])
if (options.mode !== 'lookup' && field.badgeIcon && field.badgePlacement && field.badgePlacement !== 'left') {
html += Badge(field);
}
// Field Tag
if (field.tag) {
html += `<span class="at-RowItem-tag" ng-show="${field.showTag}">
${field.tag}
</span>`;
}
}
}

View File

@@ -409,9 +409,6 @@ angular.module('templates', [surveyMaker.name, jobTemplates.name, labels.name, p
workflowMaker = {
name: 'templates.editWorkflowJobTemplate.workflowMaker',
url: '/workflow-maker',
// ncyBreadcrumb: {
// label: 'WORKFLOW MAKER'
// },
data: {
formChildState: true
},
@@ -468,14 +465,14 @@ angular.module('templates', [surveyMaker.name, jobTemplates.name, labels.name, p
$scope[`${list.iterator}_dataset`] = Dataset.data;
$scope[list.name] = $scope[`${list.iterator}_dataset`].results;
$scope.$watch('job_templates', function(){
$scope.$watch('templates', function(){
if($scope.selectedTemplate){
$scope.job_templates.forEach(function(row, i) {
$scope.templates.forEach(function(row, i) {
if(row.id === $scope.selectedTemplate.id) {
$scope.job_templates[i].checked = 1;
$scope.templates[i].checked = 1;
}
else {
$scope.job_templates[i].checked = 0;
$scope.templates[i].checked = 0;
}
});
}
@@ -484,9 +481,9 @@ angular.module('templates', [surveyMaker.name, jobTemplates.name, labels.name, p
$scope.toggle_row = function(selectedRow) {
if ($scope.workflowJobTemplateObj.summary_fields.user_capabilities.edit) {
$scope.job_templates.forEach(function(row, i) {
$scope.templates.forEach(function(row, i) {
if (row.id === selectedRow.id) {
$scope.job_templates[i].checked = 1;
$scope.templates[i].checked = 1;
$scope.selection[list.iterator] = {
id: row.id,
name: row.name
@@ -499,27 +496,27 @@ angular.module('templates', [surveyMaker.name, jobTemplates.name, labels.name, p
};
$scope.$watch('selectedTemplate', () => {
$scope.job_templates.forEach(function(row, i) {
if(_.hasIn($scope, 'selectedTemplate.id') && row.id === $scope.selectedTemplate.id) {
$scope.job_templates[i].checked = 1;
$scope.templates.forEach(function(row, i) {
if(_.has($scope, 'selectedTemplate.id') && row.id === $scope.selectedTemplate.id) {
$scope.templates[i].checked = 1;
}
else {
$scope.job_templates[i].checked = 0;
$scope.templates[i].checked = 0;
}
});
});
$scope.$watch('activeTab', () => {
if(!$scope.activeTab || $scope.activeTab !== "jobs") {
$scope.job_templates.forEach(function(row, i) {
$scope.job_templates[i].checked = 0;
$scope.templates.forEach(function(row, i) {
$scope.templates[i].checked = 0;
});
}
});
$scope.$on('clearWorkflowLists', function() {
$scope.job_templates.forEach(function(row, i) {
$scope.job_templates[i].checked = 0;
$scope.templates.forEach(function(row, i) {
$scope.templates[i].checked = 0;
});
});
}
@@ -699,8 +696,8 @@ angular.module('templates', [surveyMaker.name, jobTemplates.name, labels.name, p
return qs.search(path, $stateParams[`${list.iterator}_search`]);
}
],
WorkflowMakerJobTemplateList: ['TemplateList',
(TemplateList) => {
WorkflowMakerJobTemplateList: ['TemplateList', 'i18n',
(TemplateList, i18n) => {
let list = _.cloneDeep(TemplateList);
delete list.actions;
delete list.fields.type;
@@ -709,15 +706,18 @@ angular.module('templates', [surveyMaker.name, jobTemplates.name, labels.name, p
delete list.fields.labels;
delete list.fieldActions;
list.fields.name.columnClass = "col-md-8";
list.fields.name.tag = i18n._('WORKFLOW');
list.fields.name.showTag = "{{template.type === 'workflow_job_template'}}";
list.disableRow = "{{ !workflowJobTemplateObj.summary_fields.user_capabilities.edit }}";
list.disableRowValue = '!workflowJobTemplateObj.summary_fields.user_capabilities.edit';
list.iterator = 'job_template';
list.name = 'job_templates';
list.iterator = 'template';
list.name = 'templates';
list.basePath = 'unified_job_templates';
list.fields.info = {
ngInclude: "'/static/partials/job-template-details.html'",
type: 'template',
columnClass: 'col-md-3',
infoHeaderClass: 'col-md-3',
label: '',
nosort: true
};

View File

@@ -385,8 +385,13 @@ export default ['$state', 'moment', '$timeout', '$window', '$filter', 'Rest', 'G
.attr("r", 10)
.attr("class", "WorkflowChart-nodeTypeCircle")
.style("display", function (d) {
return d.unifiedJobTemplate && (d.unifiedJobTemplate.type === "project" || d.unifiedJobTemplate.unified_job_type === "project_update" || d.unifiedJobTemplate.type === "inventory_source" || d.unifiedJobTemplate.unified_job_type === "inventory_update") ? null : "none";
});
return d.unifiedJobTemplate && (d.unifiedJobTemplate.type === "project" ||
d.unifiedJobTemplate.unified_job_type === "project_update" ||
d.unifiedJobTemplate.type === "inventory_source" ||
d.unifiedJobTemplate.unified_job_type === "inventory_update" ||
d.unifiedJobTemplate.type === "workflow_job_template" ||
d.unifiedJobTemplate.unified_job_type === "workflow_job") ? null : "none";
});
thisNode.append("text")
.attr("y", nodeH)
@@ -394,10 +399,42 @@ export default ['$state', 'moment', '$timeout', '$window', '$filter', 'Rest', 'G
.attr("text-anchor", "middle")
.attr("class", "WorkflowChart-nodeTypeLetter")
.text(function (d) {
return (d.unifiedJobTemplate && (d.unifiedJobTemplate.type === "project" || d.unifiedJobTemplate.unified_job_type === "project_update")) ? "P" : (d.unifiedJobTemplate && (d.unifiedJobTemplate.type === "inventory_source" || d.unifiedJobTemplate.unified_job_type === "inventory_update") ? "I" : "");
let nodeTypeLetter = "";
if (d.unifiedJobTemplate && d.unifiedJobTemplate.type) {
switch (d.unifiedJobTemplate.type) {
case "project":
nodeTypeLetter = "P";
break;
case "inventory_source":
nodeTypeLetter = "I";
break;
case "workflow_job_template":
nodeTypeLetter = "W";
break;
}
} else if (d.unifiedJobTemplate && d.unifiedJobTemplate.unified_job_type) {
switch (d.unifiedJobTemplate.unified_job_type) {
case "project_update":
nodeTypeLetter = "P";
break;
case "inventory_update":
nodeTypeLetter = "I";
break;
case "workflow_job":
nodeTypeLetter = "W";
break;
}
}
return nodeTypeLetter;
})
.style("display", function (d) {
return d.unifiedJobTemplate && (d.unifiedJobTemplate.type === "project" || d.unifiedJobTemplate.unified_job_type === "project_update" || d.unifiedJobTemplate.type === "inventory_source" || d.unifiedJobTemplate.unified_job_type === "inventory_update") ? null : "none";
return d.unifiedJobTemplate &&
(d.unifiedJobTemplate.type === "project" ||
d.unifiedJobTemplate.unified_job_type === "project_update" ||
d.unifiedJobTemplate.type === "inventory_source" ||
d.unifiedJobTemplate.unified_job_type === "inventory_update" ||
d.unifiedJobTemplate.type === "workflow_job_template" ||
d.unifiedJobTemplate.unified_job_type === "workflow_job") ? null : "none";
});
thisNode.append("rect")
@@ -828,15 +865,52 @@ export default ['$state', 'moment', '$timeout', '$window', '$filter', 'Rest', 'G
t.selectAll(".WorkflowChart-nodeTypeCircle")
.style("display", function (d) {
return d.unifiedJobTemplate && (d.unifiedJobTemplate.type === "project" || d.unifiedJobTemplate.unified_job_type === "project_update" || d.unifiedJobTemplate.type === "inventory_source" || d.unifiedJobTemplate.unified_job_type === "inventory_update") ? null : "none";
return d.unifiedJobTemplate && (d.unifiedJobTemplate.type === "project" ||
d.unifiedJobTemplate.unified_job_type === "project_update" ||
d.unifiedJobTemplate.type === "inventory_source" ||
d.unifiedJobTemplate.unified_job_type === "inventory_update" ||
d.unifiedJobTemplate.type === "workflow_job_template" ||
d.unifiedJobTemplate.unified_job_type === "workflow_job") ? null : "none";
});
t.selectAll(".WorkflowChart-nodeTypeLetter")
.text(function (d) {
return (d.unifiedJobTemplate && (d.unifiedJobTemplate.type === "project" || d.unifiedJobTemplate.unified_job_type === "project_update")) ? "P" : (d.unifiedJobTemplate && (d.unifiedJobTemplate.type === "inventory_source" || d.unifiedJobTemplate.unified_job_type === "inventory_update") ? "I" : "");
let nodeTypeLetter = "";
if (d.unifiedJobTemplate && d.unifiedJobTemplate.type) {
switch (d.unifiedJobTemplate.type) {
case "project":
nodeTypeLetter = "P";
break;
case "inventory_source":
nodeTypeLetter = "I";
break;
case "workflow_job_template":
nodeTypeLetter = "W";
break;
}
} else if (d.unifiedJobTemplate && d.unifiedJobTemplate.unified_job_type) {
switch (d.unifiedJobTemplate.unified_job_type) {
case "project_update":
nodeTypeLetter = "P";
break;
case "inventory_update":
nodeTypeLetter = "I";
break;
case "workflow_job":
nodeTypeLetter = "W";
break;
}
}
return nodeTypeLetter;
})
.style("display", function (d) {
return d.unifiedJobTemplate && (d.unifiedJobTemplate.type === "project" || d.unifiedJobTemplate.unified_job_type === "project_update" || d.unifiedJobTemplate.type === "inventory_source" || d.unifiedJobTemplate.unified_job_type === "inventory_update") ? null : "none";
return d.unifiedJobTemplate &&
(d.unifiedJobTemplate.type === "project" ||
d.unifiedJobTemplate.unified_job_type === "project_update" ||
d.unifiedJobTemplate.type === "inventory_source" ||
d.unifiedJobTemplate.unified_job_type === "inventory_update" ||
d.unifiedJobTemplate.type === "workflow_job_template" ||
d.unifiedJobTemplate.unified_job_type === "workflow_job") ? null : "none";
});
t.selectAll(".WorkflowChart-nodeStatus")
@@ -1011,6 +1085,10 @@ export default ['$state', 'moment', '$timeout', '$window', '$filter', 'Rest', 'G
id: d.job.id,
type: 'project'
});
} else if (job_type === 'workflow_job') {
$state.go('workflowResults', {
id: d.job.id,
});
}
};

View File

@@ -202,23 +202,17 @@
line-height: 20px;
}
.WorkflowLegend-details {
align-items: center;
display: flex;
height: 40px;
line-height: 40px;
padding-left: 20px;
margin-top:10px;
border: 1px solid @d7grey;
border-top-left-radius: 5px;
border-top-right-radius: 5px;
}
.WorkflowLegend-legendItem {
display: flex;
}
.WorkflowLegend-legendItem:not(:last-child) {
padding-right: 20px;
}
.WorkflowLegend-details--left {
display: flex;
display: block;
flex: 1 0 auto;
}
.WorkflowLegend-details--right {
@@ -304,6 +298,7 @@
height: 3px;
width: 20px;
margin: 9px 5px 9px 0px;
outline: none;
}
.Key-heading {
font-weight: 700;

View File

@@ -5,10 +5,10 @@
*************************************************/
export default ['$scope', 'WorkflowService', 'TemplatesService',
'ProcessErrors', 'CreateSelect2', '$q', 'JobTemplateModel',
'ProcessErrors', 'CreateSelect2', '$q', 'JobTemplateModel', 'WorkflowJobTemplateModel',
'Empty', 'PromptService', 'Rest', 'TemplatesStrings', '$timeout',
function ($scope, WorkflowService, TemplatesService,
ProcessErrors, CreateSelect2, $q, JobTemplate,
ProcessErrors, CreateSelect2, $q, JobTemplate, WorkflowJobTemplate,
Empty, PromptService, Rest, TemplatesStrings, $timeout) {
let promptWatcher, surveyQuestionWatcher, credentialsWatcher;
@@ -110,7 +110,7 @@ export default ['$scope', 'WorkflowService', 'TemplatesService',
// Check to see if the user has provided any prompt values that are different
// from the defaults in the job template
if (params.node.unifiedJobTemplate.type === "job_template" && params.node.promptData) {
if ((params.node.unifiedJobTemplate.type === "job_template" || params.node.unifiedJobTemplate.type === "workflow_job_template") && params.node.promptData) {
sendableNodeData = PromptService.bundlePromptDataForSaving({
promptData: params.node.promptData,
dataToSave: sendableNodeData
@@ -188,7 +188,11 @@ export default ['$scope', 'WorkflowService', 'TemplatesService',
params.node.isNew = false;
continueRecursing(data.data.id);
}, function ({ data, config, status }) {
}, function ({
data,
config,
status
}) {
ProcessErrors($scope, data, status, null, {
hdr: $scope.strings.get('error.HEADER'),
msg: $scope.strings.get('error.CALL', {
@@ -339,7 +343,7 @@ export default ['$scope', 'WorkflowService', 'TemplatesService',
let missingPromptValue = false;
if ($scope.missingSurveyValue) {
missingPromptValue = true;
} else if (!$scope.promptData.prompts.inventory.value || !$scope.promptData.prompts.inventory.value.id) {
} else if ($scope.selectedTemplate.type === 'job_template' && (!$scope.promptData.prompts.inventory.value || !$scope.promptData.prompts.inventory.value.id)) {
missingPromptValue = true;
}
$scope.promptModalMissingReqFields = missingPromptValue;
@@ -481,7 +485,8 @@ export default ['$scope', 'WorkflowService', 'TemplatesService',
$scope.placeholderNode.unifiedJobTemplate = $scope.selectedTemplate;
$scope.placeholderNode.edgeType = $scope.edgeType.value;
if ($scope.placeholderNode.unifiedJobTemplate.type === 'job_template') {
if ($scope.placeholderNode.unifiedJobTemplate.type === 'job_template' ||
$scope.placeholderNode.unifiedJobTemplate.type === 'workflow_job_template') {
$scope.placeholderNode.promptData = _.cloneDeep($scope.promptData);
}
$scope.placeholderNode.canEdit = true;
@@ -498,8 +503,7 @@ export default ['$scope', 'WorkflowService', 'TemplatesService',
if ($scope.selectedTemplate && $scope.edgeType && $scope.edgeType.value) {
$scope.nodeBeingEdited.unifiedJobTemplate = $scope.selectedTemplate;
$scope.nodeBeingEdited.edgeType = $scope.edgeType.value;
if ($scope.nodeBeingEdited.unifiedJobTemplate.type === 'job_template') {
if ($scope.nodeBeingEdited.unifiedJobTemplate.type === 'job_template' || $scope.nodeBeingEdited.unifiedJobTemplate.type === 'workflow_job_template') {
$scope.nodeBeingEdited.promptData = _.cloneDeep($scope.promptData);
}
@@ -591,9 +595,8 @@ export default ['$scope', 'WorkflowService', 'TemplatesService',
$scope.nodeBeingEdited.isActiveEdit = true;
let finishConfiguringEdit = function () {
let jobTemplate = new JobTemplate();
let templateType = $scope.nodeBeingEdited.unifiedJobTemplate.type;
let jobTemplate = templateType === "workflow_job_template" ? new WorkflowJobTemplate() : new JobTemplate();
if (!_.isEmpty($scope.nodeBeingEdited.promptData)) {
$scope.promptData = _.cloneDeep($scope.nodeBeingEdited.promptData);
const launchConf = $scope.promptData.launchConf;
@@ -615,15 +618,17 @@ export default ['$scope', 'WorkflowService', 'TemplatesService',
} else {
$scope.showPromptButton = true;
if (launchConf.ask_inventory_on_launch && !_.has(launchConf, 'defaults.inventory') && !_.has($scope, 'nodeBeingEdited.originalNodeObj.summary_fields.inventory')) {
if ($scope.nodeBeingEdited.unifiedJobTemplate.type === 'job_template' && launchConf.ask_inventory_on_launch && !_.has(launchConf, 'defaults.inventory') && !_.has($scope, 'nodeBeingEdited.originalNodeObj.summary_fields.inventory')) {
$scope.promptModalMissingReqFields = true;
} else {
$scope.promptModalMissingReqFields = false;
}
}
} else if (
_.get($scope, 'nodeBeingEdited.unifiedJobTemplate.unified_job_type') === 'job_template' ||
_.get($scope, 'nodeBeingEdited.unifiedJobTemplate.type') === 'job_template'
_.get($scope, 'nodeBeingEdited.unifiedJobTemplate.unified_job_type') === 'job' ||
_.get($scope, 'nodeBeingEdited.unifiedJobTemplate.type') === 'job_template' ||
_.get($scope, 'nodeBeingEdited.unifiedJobTemplate.unified_job_type') === 'workflow_job' ||
_.get($scope, 'nodeBeingEdited.unifiedJobTemplate.type') === 'workflow_job_template'
) {
let promises = [jobTemplate.optionsLaunch($scope.nodeBeingEdited.unifiedJobTemplate.id), jobTemplate.getLaunch($scope.nodeBeingEdited.unifiedJobTemplate.id)];
@@ -674,8 +679,12 @@ export default ['$scope', 'WorkflowService', 'TemplatesService',
prompts.credentials.value = workflowNodeCredentials.concat(defaultCredsWithoutOverrides);
if ((!$scope.nodeBeingEdited.unifiedJobTemplate.inventory && !launchConf.ask_inventory_on_launch) || !$scope.nodeBeingEdited.unifiedJobTemplate.project) {
$scope.selectedTemplateInvalid = true;
if ($scope.nodeBeingEdited.unifiedJobTemplate.unified_job_template === 'job') {
if ((!$scope.nodeBeingEdited.unifiedJobTemplate.inventory && !launchConf.ask_inventory_on_launch) || !$scope.nodeBeingEdited.unifiedJobTemplate.project) {
$scope.selectedTemplateInvalid = true;
} else {
$scope.selectedTemplateInvalid = false;
}
} else {
$scope.selectedTemplateInvalid = false;
}
@@ -774,7 +783,9 @@ export default ['$scope', 'WorkflowService', 'TemplatesService',
}
if (_.get($scope, 'nodeBeingEdited.unifiedJobTemplate')) {
if (_.get($scope, 'nodeBeingEdited.unifiedJobTemplate.type') === "job_template") {
if (_.get($scope, 'nodeBeingEdited.unifiedJobTemplate.type') === "job_template" ||
_.get($scope, 'nodeBeingEdited.unifiedJobTemplate.type') === "workflow_job_template") {
$scope.workflowMakerFormConfig.activeTab = "jobs";
}
@@ -783,6 +794,7 @@ export default ['$scope', 'WorkflowService', 'TemplatesService',
if ($scope.selectedTemplate.unified_job_type) {
switch ($scope.selectedTemplate.unified_job_type) {
case "job":
case "workflow_job":
$scope.workflowMakerFormConfig.activeTab = "jobs";
break;
case "project_update":
@@ -795,6 +807,7 @@ export default ['$scope', 'WorkflowService', 'TemplatesService',
} else if ($scope.selectedTemplate.type) {
switch ($scope.selectedTemplate.type) {
case "job_template":
case "workflow_job_template":
$scope.workflowMakerFormConfig.activeTab = "jobs";
break;
case "project":
@@ -843,8 +856,9 @@ export default ['$scope', 'WorkflowService', 'TemplatesService',
// Determine whether or not we need to go out and GET this nodes unified job template
// in order to determine whether or not prompt fields are needed
if (!$scope.nodeBeingEdited.isNew && !$scope.nodeBeingEdited.edited && $scope.nodeBeingEdited.unifiedJobTemplate && $scope.nodeBeingEdited.unifiedJobTemplate.unified_job_type && $scope.nodeBeingEdited.unifiedJobTemplate.unified_job_type === 'job') {
if (!$scope.nodeBeingEdited.isNew && !$scope.nodeBeingEdited.edited &&
(_.get($scope, 'nodeBeingEdited.unifiedJobTemplate.unified_job_type') === 'job' ||
_.get($scope, 'nodeBeingEdited.unifiedJobTemplate.unified_job_type') === 'workflow_job')) {
// This is a node that we got back from the api with an incomplete
// unified job template so we're going to pull down the whole object
@@ -852,15 +866,19 @@ export default ['$scope', 'WorkflowService', 'TemplatesService',
.then(function (data) {
$scope.nodeBeingEdited.unifiedJobTemplate = _.clone(data.data.results[0]);
finishConfiguringEdit();
}, function ({ data, status, config }) {
ProcessErrors($scope, data, status, null, {
hdr: $scope.strings.get('error.HEADER'),
msg: $scope.strings.get('error.CALL', {
path: `${config.url}`,
action: `${config.method}`,
status
})
});
}, function ({
data,
status,
config
}) {
ProcessErrors($scope, data, status, null, {
hdr: $scope.strings.get('error.HEADER'),
msg: $scope.strings.get('error.CALL', {
path: `${config.url}`,
action: `${config.method}`,
status
})
});
});
} else {
finishConfiguringEdit();
@@ -982,24 +1000,24 @@ export default ['$scope', 'WorkflowService', 'TemplatesService',
}
$scope.promptData = null;
if (selectedTemplate.type === "job_template") {
let jobTemplate = new JobTemplate();
if (selectedTemplate.type === "job_template" || selectedTemplate.type === "workflow_job_template") {
let jobTemplate = selectedTemplate.type === "workflow_job_template" ? new WorkflowJobTemplate() : new JobTemplate();
$q.all([jobTemplate.optionsLaunch(selectedTemplate.id), jobTemplate.getLaunch(selectedTemplate.id)])
.then((responses) => {
let launchConf = responses[1].data;
if (selectedTemplate.type === 'job_template') {
if ((!selectedTemplate.inventory && !launchConf.ask_inventory_on_launch) || !selectedTemplate.project) {
$scope.selectedTemplateInvalid = true;
} else {
$scope.selectedTemplateInvalid = false;
}
if ((!selectedTemplate.inventory && !launchConf.ask_inventory_on_launch) || !selectedTemplate.project) {
$scope.selectedTemplateInvalid = true;
} else {
$scope.selectedTemplateInvalid = false;
}
if (launchConf.passwords_needed_to_start && launchConf.passwords_needed_to_start.length > 0) {
$scope.credentialRequiresPassword = true;
} else {
$scope.credentialRequiresPassword = false;
if (launchConf.passwords_needed_to_start && launchConf.passwords_needed_to_start.length > 0) {
$scope.credentialRequiresPassword = true;
} else {
$scope.credentialRequiresPassword = false;
}
}
$scope.selectedTemplate = angular.copy(selectedTemplate);
@@ -1021,8 +1039,12 @@ export default ['$scope', 'WorkflowService', 'TemplatesService',
} else {
$scope.showPromptButton = true;
if (launchConf.ask_inventory_on_launch && !_.has(launchConf, 'defaults.inventory')) {
$scope.promptModalMissingReqFields = true;
if (selectedTemplate.type === 'job_template') {
if (launchConf.ask_inventory_on_launch && !_.has(launchConf, 'defaults.inventory')) {
$scope.promptModalMissingReqFields = true;
} else {
$scope.promptModalMissingReqFields = false;
}
} else {
$scope.promptModalMissingReqFields = false;
}
@@ -1156,7 +1178,11 @@ export default ['$scope', 'WorkflowService', 'TemplatesService',
// This is the last page
buildTreeFromNodes();
}
}, function ({ data, status, config }) {
}, function ({
data,
status,
config
}) {
ProcessErrors($scope, data, status, null, {
hdr: $scope.strings.get('error.HEADER'),
msg: $scope.strings.get('error.CALL', {

View File

@@ -62,6 +62,10 @@
<div class="Key-icon Key-icon--circle Key-icon--default">I</div>
<p class="Key-listItemContent Key-listItemContent--circle">{{strings.get('workflow_maker.INVENTORY_SYNC')}}</p>
</li>
<li class="Key-listItem">
<div class="Key-icon Key-icon--circle Key-icon--default">W</div>
<p class="Key-listItemContent Key-listItemContent--circle">{{strings.get('workflow_maker.WORKFLOW')}}</p>
</li>
<li class="Key-listItem">
<div class="Key-icon Key-icon--circle Key-icon--warning">!</div>
<p class="Key-listItemContent Key-listItemContent--circle">{{strings.get('workflow_maker.WARNING')}}</p>
@@ -95,7 +99,9 @@
</div>
<span ng-show="selectedTemplate &&
((selectedTemplate.type === 'job_template' || selectedTemplate.type === 'workflow_job_template' && workflowMakerFormConfig.activeTab === 'jobs') ||
(selectedTemplate.unified_job_type === 'job' || selectedTemplate.unified_job_type === 'workflow_job' && workflowMakerFormConfig.activeTab === 'jobs') ||
(selectedTemplate.type === 'project' && workflowMakerFormConfig.activeTab === 'project_sync') ||
(selectedTemplate.unified_job_type === 'inventory_update' && workflowMakerFormConfig.activeTab === 'inventory_sync') ||
(selectedTemplate.type === 'inventory_source' && workflowMakerFormConfig.activeTab === 'inventory_sync'))">
<div ng-if="selectedTemplate && selectedTemplateInvalid">
<div class="WorkflowMaker-invalidJobTemplateWarning">

View File

@@ -141,3 +141,13 @@
.WorkflowResults-extraVarsLabel {
font-size:14px!important;
}
.WorkflowResults-seeMoreLess {
color: #337AB7;
margin: 4px 0px;
text-transform: uppercase;
padding: 2px 0px;
cursor: pointer;
border-radius: 5px;
font-size: 11px;
}

View File

@@ -1,9 +1,9 @@
export default ['workflowData', 'workflowResultsService', 'workflowDataOptions',
'jobLabels', 'workflowNodes', '$scope', 'ParseTypeChange',
'ParseVariableString', 'WorkflowService', 'count', '$state', 'i18n',
'moment', function(workflowData, workflowResultsService,
'moment', '$filter', function(workflowData, workflowResultsService,
workflowDataOptions, jobLabels, workflowNodes, $scope, ParseTypeChange,
ParseVariableString, WorkflowService, count, $state, i18n, moment) {
ParseVariableString, WorkflowService, count, $state, i18n, moment, $filter) {
var runTimeElapsedTimer = null;
var getLinks = function() {
@@ -50,13 +50,17 @@ export default ['workflowData', 'workflowResultsService', 'workflowDataOptions',
STARTED: i18n._('Started'),
FINISHED: i18n._('Finished'),
LABELS: i18n._('Labels'),
STATUS: i18n._('Status'),
SLICE_TEMPLATE: i18n._('Slice Job Template'),
STATUS: i18n._('Status')
JOB_EXPLANATION: i18n._('Explanation'),
SOURCE_WORKFLOW_JOB: i18n._('Parent Workflow')
},
details: {
HEADER: i18n._('DETAILS'),
NOT_FINISHED: i18n._('Not Finished'),
NOT_STARTED: i18n._('Not Started'),
SHOW_LESS: i18n._('Show Less'),
SHOW_MORE: i18n._('Show More'),
},
results: {
TOTAL_JOBS: i18n._('Total Jobs'),
@@ -68,6 +72,7 @@ export default ['workflowData', 'workflowResultsService', 'workflowDataOptions',
ALWAYS: i18n._('Always'),
PROJECT_SYNC: i18n._('Project Sync'),
INVENTORY_SYNC: i18n._('Inventory Sync'),
WORKFLOW: i18n._('Workflow'),
KEY: i18n._('KEY'),
}
};
@@ -100,6 +105,9 @@ export default ['workflowData', 'workflowResultsService', 'workflowDataOptions',
$scope.labels = jobLabels;
$scope.count = count.val;
$scope.showManualControls = false;
$scope.showKey = false;
$scope.toggleKey = () => $scope.showKey = !$scope.showKey;
$scope.keyClassList = `{ 'Key-menuIcon--active': showKey }`;
// Start elapsed time updater for job known to be running
if ($scope.workflow.started !== null && $scope.workflow.status === 'running') {
@@ -116,6 +124,27 @@ export default ['workflowData', 'workflowResultsService', 'workflowDataOptions',
$scope.slice_job_template_link = `/#/templates/job_template/${$scope.workflow.summary_fields.job_template.id}`;
}
if (_.get(workflowData, 'summary_fields.source_workflow_job.id')) {
$scope.source_workflow_job_link = `/#/workflows/${workflowData.summary_fields.source_workflow_job.id}`;
}
if (workflowData.job_explanation) {
const limit = 150;
const more = workflowData.job_explanation;
const less = $filter('limitTo')(more, limit);
const showMore = false;
const hasMoreToShow = more.length > limit;
const job_explanation = {
more: more,
less: less,
showMore: showMore,
hasMoreToShow: hasMoreToShow
};
$scope.job_explanation = job_explanation;
}
// turn related api browser routes into front end routes
getLinks();

View File

@@ -75,6 +75,33 @@
</div>
</div>
<!-- EXPLANATION DETAIL -->
<div class="WorkflowResults-resultRow" ng-show="workflow.job_explanation">
<label class="WorkflowResults-resultRowLabel">
{{ strings.labels.JOB_EXPLANATION }}
</label>
<div class="WorkflowResults-resultRowText"
ng-show="!job_explanation.showMore">
{{ job_explanation.less }}
<span ng-show="job_explanation.hasMoreToShow">...</span>
<span ng-show="job_explanation.hasMoreToShow"
class="WorkflowResults-seeMoreLess"
ng-click="job_explanation.showMore = true">
{{ strings.details.SHOW_MORE }}
</span>
</div>
<div class="WorkflowResults-resultRowText"
ng-show="job_explanation.showMore">
{{ job_explanation.more }}
<span class="WorkflowResults-seeMoreLess"
ng-click="job_explanation.showMore = false">
{{ strings.details.SHOW_LESS }}
</span>
</div>
</div>
<!-- START TIME DETAIL -->
<div class="WorkflowResults-resultRow"
ng-show="workflow.started">
@@ -144,18 +171,31 @@
</div>
</div>
<!-- SLIIIIIICE -->
<!-- SLIIIIIICE -->
<div class="WorkflowResults-resultRow"
ng-show="workflow.summary_fields.job_template.name">
<label
class="WorkflowResults-resultRowLabel">
{{ strings.labels.SLICE_TEMPLATE }}
</label>
<div class="WorkflowResults-resultRowText">
<a href="{{ slice_job_template_link }}"
aw-tool-tip="{{ strings.tooltips.EDIT_SLICE_TEMPLATE }}"
data-placement="top">
{{ workflow.summary_fields.job_template.name }}
</a>
</div>
</div>
<!-- PARENT WORKFLOW DETAIL -->
<div class="WorkflowResults-resultRow"
ng-show="workflow.summary_fields.job_template.name">
<label
class="WorkflowResults-resultRowLabel">
{{ strings.labels.SLICE_TEMPLATE }}
ng-if="workflow.summary_fields.source_workflow_job">
<label class="WorkflowResults-resultRowLabel">
{{ strings.labels.SOURCE_WORKFLOW_JOB }}
</label>
<div class="WorkflowResults-resultRowText">
<a href="{{ slice_job_template_link }}"
aw-tool-tip="{{ strings.tooltips.EDIT_SLICE_TEMPLATE }}"
data-placement="top">
{{ workflow.summary_fields.job_template.name }}
<a href="{{ source_workflow_job_link }}">
{{ workflow.summary_fields.source_workflow_job.name }}
</a>
</div>
</div>
@@ -268,27 +308,36 @@
<workflow-status-bar></workflow-status-bar>
<div class="WorkflowLegend-details">
<div class="WorkflowLegend-details--left">
<div class="WorkflowLegend-legendItem">{{ strings.legend.KEY }}:</div>
<div class="WorkflowLegend-legendItem">
<div class="WorkflowLegend-onSuccessLegend"></div>
<div>{{ strings.legend.ON_SUCCESS }}</div>
</div>
<div class="WorkflowLegend-legendItem">
<div class="WorkflowLegend-onFailLegend"></div>
<div>{{ strings.legend.ON_FAIL }}</div>
</div>
<div class="WorkflowLegend-legendItem">
<div class="WorkflowLegend-alwaysLegend"></div>
<div>{{ strings.legend.ALWAYS }}</div>
</div>
<div class="WorkflowLegend-legendItem">
<div class="WorkflowLegend-letterCircle">P</div>
<div>{{ strings.legend.PROJECT_SYNC }}</div>
</div>
<div class="WorkflowLegend-legendItem">
<div class="WorkflowLegend-letterCircle">I</div>
<div>{{ strings.legend.INVENTORY_SYNC }}</div>
</div>
<i ng-class="{{ keyClassList }}" class="fa fa-key Key-menuIcon" ng-click="toggleKey()"></i>
<ul ng-show="showKey" class="Key-list noselect">
<li class="Key-listItem">
<p class="Key-heading">{{strings.legend.KEY}}</p>
</li>
<li class="Key-listItem">
<div class="Key-icon Key-icon--success"></div>
<p class="Key-listItemContent">{{strings.legend.ON_SUCCESS}}</p>
</li>
<li class="Key-listItem">
<div class="Key-icon Key-icon--fail"></div>
<p class="Key-listItemContent">{{strings.legend.ON_FAILURE}}</p>
</li>
<li class="Key-listItem">
<div class="Key-icon Key-icon--always"></div>
<p class="Key-listItemContent">{{strings.legend.ALWAYS}}</p>
</li>
<li class="Key-listItem">
<div class="Key-icon Key-icon--circle Key-icon--default">P</div>
<p class="Key-listItemContent Key-listItemContent--circle">{{strings.legend.PROJECT_SYNC}}</p>
</li>
<li class="Key-listItem">
<div class="Key-icon Key-icon--circle Key-icon--default">I</div>
<p class="Key-listItemContent Key-listItemContent--circle">{{strings.legend.INVENTORY_SYNC}}</p>
</li>
<li class="Key-listItem">
<div class="Key-icon Key-icon--circle Key-icon--default">W</div>
<p class="Key-listItemContent Key-listItemContent--circle">{{strings.legend.WORKFLOW}}</p>
</li>
</ul>
</div>
<div class="WorkflowLegend-details--right">
<i ng-class="{'WorkflowMaker-manualControlsIcon--active': showManualControls}" class="fa fa-cog WorkflowMaker-manualControlsIcon" aria-hidden="true" alt="Controls" ng-click="toggleManualControls()"></i>