diff --git a/awx/ui/client/features/templates/templates.strings.js b/awx/ui/client/features/templates/templates.strings.js index baaae1f783..ab77d0d7b1 100644 --- a/awx/ui/client/features/templates/templates.strings.js +++ b/awx/ui/client/features/templates/templates.strings.js @@ -128,7 +128,9 @@ function TemplatesStrings (BaseString) { EDIT_LINK: t.s('EDIT LINK'), VIEW_LINK: t.s('VIEW LINK'), NEW_LINK: t.s('Please click on an available node to form a new link.'), - UNLINK: t.s('UNLINK') + UNLINK: t.s('UNLINK'), + READ_ONLY_PROMPT_VALUES: t.s('The following promptable values were provided when this node was created:'), + READ_ONLY_NO_PROMPT_VALUES: t.s('No promptable values were provided when this node was created.') }; } diff --git a/awx/ui/client/src/templates/workflows/workflow-chart/workflow-chart.directive.js b/awx/ui/client/src/templates/workflows/workflow-chart/workflow-chart.directive.js index d4b6ca208e..6d6520a1fa 100644 --- a/awx/ui/client/src/templates/workflows/workflow-chart/workflow-chart.directive.js +++ b/awx/ui/client/src/templates/workflows/workflow-chart/workflow-chart.directive.js @@ -114,7 +114,11 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge // There's something off with the math on the root node... if (d.source.id === 1) { - sourceY = sourceY + 10; + if (scope.mode === "details") { + sourceY = sourceY + 17; + } else { + sourceY = sourceY + 10; + } } let points = [{ @@ -1279,7 +1283,7 @@ export default ['$state','moment', '$timeout', '$window', '$filter', 'Rest', 'Ge function node_click() { this.on("click", function(d) { - if(d.id !== scope.graphState.nodeBeingAdded && !scope.readOnly){ + if(d.id !== scope.graphState.nodeBeingAdded){ if(scope.graphState.isLinkMode && !d.isInvalidLinkTarget && scope.graphState.addLinkSource !== d.id) { $('.WorkflowChart-potentialLink').remove(); scope.selectNodeForLinking({ diff --git a/awx/ui/client/src/templates/workflows/workflow-chart/workflow-chart.service.js b/awx/ui/client/src/templates/workflows/workflow-chart/workflow-chart.service.js index 4c51ecc1d1..2973dc1e70 100644 --- a/awx/ui/client/src/templates/workflows/workflow-chart/workflow-chart.service.js +++ b/awx/ui/client/src/templates/workflows/workflow-chart/workflow-chart.service.js @@ -1,42 +1,5 @@ export default [function(){ return { - generateDepthMap: (arrayOfLinks) => { - let depthMap = {}; - let nodesWithChildren = {}; - - let walkBranch = (nodeId, depth) => { - depthMap[nodeId] = depthMap[nodeId] ? (depth > depthMap[nodeId] ? depth : depthMap[nodeId]) : depth; - if (nodesWithChildren[nodeId]) { - _.forEach(nodesWithChildren[nodeId].children, (childNodeId) => { - walkBranch(childNodeId, depth+1); - }); - } - }; - - let rootNodeIds = []; - arrayOfLinks.forEach(link => { - // link.source.index of 0 is our artificial start node - if (link.source.index !== 0) { - if (!nodesWithChildren[link.source.id]) { - nodesWithChildren[link.source.id] = { - children: [] - }; - } - - nodesWithChildren[link.source.id].children.push(link.target.id); - } else { - // Store the fact that might be a root node - rootNodeIds.push(link.target.id); - } - }); - - _.forEach(rootNodeIds, function(rootNodeId) { - walkBranch(rootNodeId, 1); - depthMap[rootNodeId] = 1; - }); - - return depthMap; - }, generateArraysOfNodesAndLinks: function(allNodes) { let nonRootNodeIds = []; let allNodeIds = []; @@ -77,7 +40,7 @@ export default [function(){ nodeObj.job = node.summary_fields.job; } if(node.summary_fields.unified_job_template) { - nodeObj.unifiedJobTemplate = node.summary_fields.unified_job_template; + nodeRef[nodeIdCounter].unifiedJobTemplate = nodeObj.unifiedJobTemplate = node.summary_fields.unified_job_template; } arrayOfNodesForChart.push(nodeObj); diff --git a/awx/ui/client/src/templates/workflows/workflow-maker/forms/workflow-node-form.controller.js b/awx/ui/client/src/templates/workflows/workflow-maker/forms/workflow-node-form.controller.js index 2f876da2e0..0faf9af2be 100644 --- a/awx/ui/client/src/templates/workflows/workflow-maker/forms/workflow-node-form.controller.js +++ b/awx/ui/client/src/templates/workflows/workflow-maker/forms/workflow-node-form.controller.js @@ -7,11 +7,11 @@ export default ['$scope', 'TemplatesService', 'JobTemplateModel', 'PromptService', 'Rest', '$q', 'TemplatesStrings', 'CreateSelect2', 'Empty', 'generateList', 'QuerySet', 'GetBasePath', 'TemplateList', 'ProjectList', 'InventorySourcesList', 'ProcessErrors', - 'i18n', + 'i18n', 'ParseTypeChange', function($scope, TemplatesService, JobTemplate, PromptService, Rest, $q, TemplatesStrings, CreateSelect2, Empty, generateList, qs, GetBasePath, TemplateList, ProjectList, InventorySourcesList, ProcessErrors, - i18n + i18n, ParseTypeChange ) { let promptWatcher, credentialsWatcher, surveyQuestionWatcher, listPromises = []; @@ -139,229 +139,254 @@ export default ['$scope', 'TemplatesService', 'JobTemplateModel', 'PromptService const finishConfiguringEdit = () => { - let jobTemplate = new JobTemplate(); + if (!$scope.readOnly) { + let jobTemplate = new JobTemplate(); - if (_.get($scope, 'nodeConfig.node.promptData') && !_.isEmpty($scope.nodeConfig.node.promptData)) { - $scope.promptData = _.cloneDeep($scope.nodeConfig.node.promptData); - const launchConf = $scope.promptData.launchConf; + if (_.get($scope, 'nodeConfig.node.promptData') && !_.isEmpty($scope.nodeConfig.node.promptData)) { + $scope.promptData = _.cloneDeep($scope.nodeConfig.node.promptData); + const launchConf = $scope.promptData.launchConf; - if (!launchConf.survey_enabled && - !launchConf.ask_inventory_on_launch && - !launchConf.ask_credential_on_launch && - !launchConf.ask_verbosity_on_launch && - !launchConf.ask_job_type_on_launch && - !launchConf.ask_limit_on_launch && - !launchConf.ask_tags_on_launch && - !launchConf.ask_skip_tags_on_launch && - !launchConf.ask_diff_mode_on_launch && - !launchConf.credential_needed_to_start && - !launchConf.ask_variables_on_launch && - launchConf.variables_needed_to_start.length === 0) { - $scope.showPromptButton = false; - $scope.promptModalMissingReqFields = false; - } else { - $scope.showPromptButton = true; - - if (launchConf.ask_inventory_on_launch && !_.has(launchConf, 'defaults.inventory') && !_.has($scope, 'nodeConfig.node.originalNodeObject.summary_fields.inventory')) { - $scope.promptModalMissingReqFields = true; + if (!launchConf.survey_enabled && + !launchConf.ask_inventory_on_launch && + !launchConf.ask_credential_on_launch && + !launchConf.ask_verbosity_on_launch && + !launchConf.ask_job_type_on_launch && + !launchConf.ask_limit_on_launch && + !launchConf.ask_tags_on_launch && + !launchConf.ask_skip_tags_on_launch && + !launchConf.ask_diff_mode_on_launch && + !launchConf.credential_needed_to_start && + !launchConf.ask_variables_on_launch && + launchConf.variables_needed_to_start.length === 0) { + $scope.showPromptButton = false; + $scope.promptModalMissingReqFields = false; } else { - $scope.promptModalMissingReqFields = false; - } - } - $scope.nodeFormDataLoaded = true; - } else if ( - _.get($scope, 'nodeConfig.node.fullUnifiedJobTemplateObject.unified_job_type') === 'job_template' || - _.get($scope, 'nodeConfig.node.fullUnifiedJobTemplateObject.type') === 'job_template' - ) { - let promises = [jobTemplate.optionsLaunch($scope.nodeConfig.node.fullUnifiedJobTemplateObject.id), jobTemplate.getLaunch($scope.nodeConfig.node.fullUnifiedJobTemplateObject.id)]; + $scope.showPromptButton = true; - if (_.has($scope, 'nodeConfig.node.originalNodeObject.related.credentials')) { - Rest.setUrl($scope.nodeConfig.node.originalNodeObject.related.credentials); - promises.push(Rest.get()); - } - - $q.all(promises) - .then((responses) => { - let launchOptions = responses[0].data, - launchConf = responses[1].data, - workflowNodeCredentials = responses[2] ? responses[2].data.results : []; - - let prompts = PromptService.processPromptValues({ - launchConf: responses[1].data, - launchOptions: responses[0].data, - currentValues: $scope.nodeConfig.node.originalNodeObject - }); - - let defaultCredsWithoutOverrides = []; - - prompts.credentials.previousOverrides = _.cloneDeep(workflowNodeCredentials); - - const credentialHasScheduleOverride = (templateDefaultCred) => { - let credentialHasOverride = false; - workflowNodeCredentials.forEach((scheduleCred) => { - if (templateDefaultCred.credential_type === scheduleCred.credential_type) { - if ( - (!templateDefaultCred.vault_id && !scheduleCred.inputs.vault_id) || - (templateDefaultCred.vault_id && scheduleCred.inputs.vault_id && templateDefaultCred.vault_id === scheduleCred.inputs.vault_id) - ) { - credentialHasOverride = true; - } - } - }); - - return credentialHasOverride; - }; - - if (_.has(launchConf, 'defaults.credentials')) { - launchConf.defaults.credentials.forEach((defaultCred) => { - if (!credentialHasScheduleOverride(defaultCred)) { - defaultCredsWithoutOverrides.push(defaultCred); - } - }); - } - - prompts.credentials.value = workflowNodeCredentials.concat(defaultCredsWithoutOverrides); - - if ((!$scope.nodeConfig.node.fullUnifiedJobTemplateObject.inventory && !launchConf.ask_inventory_on_launch) || !$scope.nodeConfig.node.fullUnifiedJobTemplateObject.project) { - $scope.selectedTemplateInvalid = true; + if (launchConf.ask_inventory_on_launch && !_.has(launchConf, 'defaults.inventory') && !_.has($scope, 'nodeConfig.node.originalNodeObject.summary_fields.inventory')) { + $scope.promptModalMissingReqFields = true; } else { - $scope.selectedTemplateInvalid = false; + $scope.promptModalMissingReqFields = false; } + } + $scope.nodeFormDataLoaded = true; + } else if ( + _.get($scope, 'nodeConfig.node.fullUnifiedJobTemplateObject.unified_job_type') === 'job_template' || + _.get($scope, 'nodeConfig.node.fullUnifiedJobTemplateObject.type') === 'job_template' + ) { + let promises = [jobTemplate.optionsLaunch($scope.nodeConfig.node.fullUnifiedJobTemplateObject.id), jobTemplate.getLaunch($scope.nodeConfig.node.fullUnifiedJobTemplateObject.id)]; - let credentialRequiresPassword = false; + if (_.has($scope, 'nodeConfig.node.originalNodeObject.related.credentials')) { + Rest.setUrl($scope.nodeConfig.node.originalNodeObject.related.credentials); + promises.push(Rest.get()); + } - prompts.credentials.value.forEach((credential) => { - if(credential.inputs) { - if ((credential.inputs.password && credential.inputs.password === "ASK") || - (credential.inputs.become_password && credential.inputs.become_password === "ASK") || - (credential.inputs.ssh_key_unlock && credential.inputs.ssh_key_unlock === "ASK") || - (credential.inputs.vault_password && credential.inputs.vault_password === "ASK") - ) { + $q.all(promises) + .then((responses) => { + let launchOptions = responses[0].data, + launchConf = responses[1].data, + workflowNodeCredentials = responses[2] ? responses[2].data.results : []; + + let prompts = PromptService.processPromptValues({ + launchConf: responses[1].data, + launchOptions: responses[0].data, + currentValues: $scope.nodeConfig.node.originalNodeObject + }); + + let defaultCredsWithoutOverrides = []; + + prompts.credentials.previousOverrides = _.cloneDeep(workflowNodeCredentials); + + const credentialHasScheduleOverride = (templateDefaultCred) => { + let credentialHasOverride = false; + workflowNodeCredentials.forEach((scheduleCred) => { + if (templateDefaultCred.credential_type === scheduleCred.credential_type) { + if ( + (!templateDefaultCred.vault_id && !scheduleCred.inputs.vault_id) || + (templateDefaultCred.vault_id && scheduleCred.inputs.vault_id && templateDefaultCred.vault_id === scheduleCred.inputs.vault_id) + ) { + credentialHasOverride = true; + } + } + }); + + return credentialHasOverride; + }; + + if (_.has(launchConf, 'defaults.credentials')) { + launchConf.defaults.credentials.forEach((defaultCred) => { + if (!credentialHasScheduleOverride(defaultCred)) { + defaultCredsWithoutOverrides.push(defaultCred); + } + }); + } + + prompts.credentials.value = workflowNodeCredentials.concat(defaultCredsWithoutOverrides); + + if ((!$scope.nodeConfig.node.fullUnifiedJobTemplateObject.inventory && !launchConf.ask_inventory_on_launch) || !$scope.nodeConfig.node.fullUnifiedJobTemplateObject.project) { + $scope.selectedTemplateInvalid = true; + } else { + $scope.selectedTemplateInvalid = false; + } + + let credentialRequiresPassword = false; + + prompts.credentials.value.forEach((credential) => { + if(credential.inputs) { + if ((credential.inputs.password && credential.inputs.password === "ASK") || + (credential.inputs.become_password && credential.inputs.become_password === "ASK") || + (credential.inputs.ssh_key_unlock && credential.inputs.ssh_key_unlock === "ASK") || + (credential.inputs.vault_password && credential.inputs.vault_password === "ASK") + ) { + credentialRequiresPassword = true; + } + } else if (credential.passwords_needed && credential.passwords_needed.length > 0) { credentialRequiresPassword = true; } - } else if (credential.passwords_needed && credential.passwords_needed.length > 0) { - credentialRequiresPassword = true; - } - }); + }); - $scope.credentialRequiresPassword = credentialRequiresPassword; + $scope.credentialRequiresPassword = credentialRequiresPassword; - if (!launchConf.survey_enabled && - !launchConf.ask_inventory_on_launch && - !launchConf.ask_credential_on_launch && - !launchConf.ask_verbosity_on_launch && - !launchConf.ask_job_type_on_launch && - !launchConf.ask_limit_on_launch && - !launchConf.ask_tags_on_launch && - !launchConf.ask_skip_tags_on_launch && - !launchConf.ask_diff_mode_on_launch && - !launchConf.credential_needed_to_start && - !launchConf.ask_variables_on_launch && - launchConf.variables_needed_to_start.length === 0) { - $scope.showPromptButton = false; - $scope.promptModalMissingReqFields = false; - $scope.nodeFormDataLoaded = true; - } else { - $scope.showPromptButton = true; - - if (launchConf.ask_inventory_on_launch && !_.has(launchConf, 'defaults.inventory') && !_.has($scope, 'nodeConfig.node.originalNodeObject.summary_fields.inventory')) { - $scope.promptModalMissingReqFields = true; + if (!launchConf.survey_enabled && + !launchConf.ask_inventory_on_launch && + !launchConf.ask_credential_on_launch && + !launchConf.ask_verbosity_on_launch && + !launchConf.ask_job_type_on_launch && + !launchConf.ask_limit_on_launch && + !launchConf.ask_tags_on_launch && + !launchConf.ask_skip_tags_on_launch && + !launchConf.ask_diff_mode_on_launch && + !launchConf.credential_needed_to_start && + !launchConf.ask_variables_on_launch && + launchConf.variables_needed_to_start.length === 0) { + $scope.showPromptButton = false; + $scope.promptModalMissingReqFields = false; + $scope.nodeFormDataLoaded = true; } else { - $scope.promptModalMissingReqFields = false; - } + $scope.showPromptButton = true; - if (responses[1].data.survey_enabled) { - // go out and get the survey questions - jobTemplate.getSurveyQuestions($scope.nodeConfig.node.fullUnifiedJobTemplateObject.id) - .then((surveyQuestionRes) => { + if (launchConf.ask_inventory_on_launch && !_.has(launchConf, 'defaults.inventory') && !_.has($scope, 'nodeConfig.node.originalNodeObject.summary_fields.inventory')) { + $scope.promptModalMissingReqFields = true; + } else { + $scope.promptModalMissingReqFields = false; + } - let processed = PromptService.processSurveyQuestions({ - surveyQuestions: surveyQuestionRes.data.spec, - extra_data: _.cloneDeep($scope.nodeConfig.node.originalNodeObject.extra_data) - }); + if (responses[1].data.survey_enabled) { + // go out and get the survey questions + jobTemplate.getSurveyQuestions($scope.nodeConfig.node.fullUnifiedJobTemplateObject.id) + .then((surveyQuestionRes) => { - $scope.missingSurveyValue = processed.missingSurveyValue; - - $scope.extraVars = (processed.extra_data === '' || _.isEmpty(processed.extra_data)) ? '---' : '---\n' + jsyaml.safeDump(processed.extra_data); - - $scope.nodeConfig.node.promptData = $scope.promptData = { - launchConf: launchConf, - launchOptions: launchOptions, - prompts: prompts, - surveyQuestions: surveyQuestionRes.data.spec, - template: $scope.nodeConfig.node.fullUnifiedJobTemplateObject.id - }; - - surveyQuestionWatcher = $scope.$watch('promptData.surveyQuestions', () => { - let missingSurveyValue = false; - _.each($scope.promptData.surveyQuestions, (question) => { - if (question.required && (Empty(question.model) || question.model === [])) { - missingSurveyValue = true; - } + let processed = PromptService.processSurveyQuestions({ + surveyQuestions: surveyQuestionRes.data.spec, + extra_data: _.cloneDeep($scope.nodeConfig.node.originalNodeObject.extra_data) }); - $scope.missingSurveyValue = missingSurveyValue; - }, true); - checkCredentialsForRequiredPasswords(); + $scope.missingSurveyValue = processed.missingSurveyValue; - watchForPromptChanges(); + $scope.extraVars = (processed.extra_data === '' || _.isEmpty(processed.extra_data)) ? '---' : '---\n' + jsyaml.safeDump(processed.extra_data); - $scope.nodeFormDataLoaded = true; - }); - } else { - $scope.nodeConfig.node.promptData = $scope.promptData = { - launchConf: launchConf, - launchOptions: launchOptions, - prompts: prompts, - template: $scope.nodeConfig.node.fullUnifiedJobTemplateObject.id - }; + $scope.nodeConfig.node.promptData = $scope.promptData = { + launchConf: launchConf, + launchOptions: launchOptions, + prompts: prompts, + surveyQuestions: surveyQuestionRes.data.spec, + template: $scope.nodeConfig.node.fullUnifiedJobTemplateObject.id + }; - checkCredentialsForRequiredPasswords(); + surveyQuestionWatcher = $scope.$watch('promptData.surveyQuestions', () => { + let missingSurveyValue = false; + _.each($scope.promptData.surveyQuestions, (question) => { + if (question.required && (Empty(question.model) || question.model === [])) { + missingSurveyValue = true; + } + }); + $scope.missingSurveyValue = missingSurveyValue; + }, true); - watchForPromptChanges(); + checkCredentialsForRequiredPasswords(); - $scope.nodeFormDataLoaded = true; + watchForPromptChanges(); + + $scope.nodeFormDataLoaded = true; + }); + } else { + $scope.nodeConfig.node.promptData = $scope.promptData = { + launchConf: launchConf, + launchOptions: launchOptions, + prompts: prompts, + template: $scope.nodeConfig.node.fullUnifiedJobTemplateObject.id + }; + + checkCredentialsForRequiredPasswords(); + + watchForPromptChanges(); + + $scope.nodeFormDataLoaded = true; + } } - } - }); - } else { - $scope.nodeFormDataLoaded = true; - } + }); + } else { + $scope.nodeFormDataLoaded = true; + } - if (_.get($scope, 'nodeConfig.node.fullUnifiedJobTemplateObject')) { - if (_.get($scope, 'nodeConfig.node.fullUnifiedJobTemplateObject.type') === "job_template") { + if (_.get($scope, 'nodeConfig.node.fullUnifiedJobTemplateObject')) { + if (_.get($scope, 'nodeConfig.node.fullUnifiedJobTemplateObject.type') === "job_template") { + $scope.activeTab = "jobs"; + } + + $scope.selectedTemplate = $scope.nodeConfig.node.fullUnifiedJobTemplateObject; + + if ($scope.selectedTemplate.unified_job_type) { + switch ($scope.selectedTemplate.unified_job_type) { + case "job": + $scope.activeTab = "jobs"; + break; + case "project_update": + $scope.activeTab = "project_syncs"; + break; + case "inventory_update": + $scope.activeTab = "inventory_syncs"; + break; + } + } else if ($scope.selectedTemplate.type) { + switch ($scope.selectedTemplate.type) { + case "job_template": + $scope.activeTab = "jobs"; + break; + case "project": + $scope.activeTab = "project_syncs"; + break; + case "inventory_source": + $scope.activeTab = "inventory_syncs"; + break; + } + } + } else { $scope.activeTab = "jobs"; } - - $scope.selectedTemplate = $scope.nodeConfig.node.fullUnifiedJobTemplateObject; - - if ($scope.selectedTemplate.unified_job_type) { - switch ($scope.selectedTemplate.unified_job_type) { - case "job": - $scope.activeTab = "jobs"; - break; - case "project_update": - $scope.activeTab = "project_syncs"; - break; - case "inventory_update": - $scope.activeTab = "inventory_syncs"; - break; - } - } else if ($scope.selectedTemplate.type) { - switch ($scope.selectedTemplate.type) { - case "job_template": - $scope.activeTab = "jobs"; - break; - case "project": - $scope.activeTab = "project_syncs"; - break; - case "inventory_source": - $scope.activeTab = "inventory_syncs"; - break; - } - } } else { - $scope.activeTab = "jobs"; + $scope.jobTags = $scope.nodeConfig.node.originalNodeObject.job_tags ? $scope.nodeConfig.node.originalNodeObject.job_tags.split(',').map((tag) => (tag)) : []; + $scope.skipTags = $scope.nodeConfig.node.originalNodeObject.skip_tags ? $scope.nodeConfig.node.originalNodeObject.skip_tags.split(',').map((tag) => (tag)) : []; + $scope.showJobTags = true; + $scope.showSkipTags = true; + + if (!$.isEmptyObject($scope.nodeConfig.node.originalNodeObject.extra_data)) { + $scope.extraVars = '---\n' + jsyaml.safeDump($scope.nodeConfig.node.originalNodeObject.extra_data); + $scope.showExtraVars = true; + $scope.parseType = 'yaml'; + + ParseTypeChange({ + scope: $scope, + variable: 'extraVars', + field_id: 'workflow_node_form_extra_vars', + readOnly: true + }); + } else { + $scope.extraVars = null; + $scope.showExtraVars = false; + } + + $scope.nodeFormDataLoaded = true; } }; diff --git a/awx/ui/client/src/templates/workflows/workflow-maker/forms/workflow-node-form.partial.html b/awx/ui/client/src/templates/workflows/workflow-maker/forms/workflow-node-form.partial.html index 0732e14819..b8866b47b1 100644 --- a/awx/ui/client/src/templates/workflows/workflow-maker/forms/workflow-node-form.partial.html +++ b/awx/ui/client/src/templates/workflows/workflow-maker/forms/workflow-node-form.partial.html @@ -1,11 +1,11 @@