mirror of
https://github.com/ansible/awx.git
synced 2026-01-12 18:40:01 -03:30
Prompt bug cleanup. Filter workflow_approval jobs out of jobs list. Add initial support for timeout.
This commit is contained in:
parent
3357c96774
commit
013792f0f8
@ -15,6 +15,7 @@ export default {
|
||||
job_search: {
|
||||
value: {
|
||||
not__launch_type: 'sync',
|
||||
not__type: 'workflow_approval',
|
||||
order_by: '-finished'
|
||||
},
|
||||
dynamic: true,
|
||||
|
||||
@ -148,7 +148,8 @@ function TemplatesStrings (BaseString) {
|
||||
EXIT: t.s('EXIT'),
|
||||
CANCEL: t.s('CANCEL'),
|
||||
SAVE_AND_EXIT: t.s('SAVE & EXIT'),
|
||||
APPROVAL: t.s('Approval')
|
||||
APPROVAL: t.s('Approval'),
|
||||
TIMEOUT_POPOVER: t.s('The amount of time (in seconds) to wait before this approval step is automatically denied. Defaults to 0 for no timeout.')
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -15,8 +15,6 @@
|
||||
height: 100%;
|
||||
width: 540px;
|
||||
background-color: @default-bg;
|
||||
animation-name: slidein;
|
||||
animation-duration: 250ms;
|
||||
padding: 20px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
@ -63,14 +61,4 @@
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slidein {
|
||||
from {
|
||||
width: 0px;
|
||||
}
|
||||
|
||||
to {
|
||||
width: 540px;
|
||||
}
|
||||
}
|
||||
@ -28,7 +28,6 @@
|
||||
<div class="at-Row-items">
|
||||
<div class="at-Row-container">
|
||||
<div class="at-Row-container">
|
||||
<!-- TODO: translate header tag -->
|
||||
<at-row-item
|
||||
header-value="{{ approval.summary_fields.source_workflow_job.name }}"
|
||||
header-state="workflowResults({id: {{approval.summary_fields.source_workflow_job.id}}})"
|
||||
@ -40,10 +39,12 @@
|
||||
<at-row-item
|
||||
value-bind-html="{{ approval.created | longDate }}">
|
||||
</at-row-item>
|
||||
<!-- todo: clean this up if it becomes a real thing-->
|
||||
<at-row-item
|
||||
style="color: red;"
|
||||
value-bind-html="Expires: Never">
|
||||
</at-row-item>
|
||||
<!-- todo: hook this up when timeout is active-->
|
||||
<!-- <at-row-item
|
||||
style="color: red;"
|
||||
value-bind-html="Expires {{ approval.created | longDate }}">
|
||||
|
||||
@ -92,8 +92,8 @@
|
||||
margin-left: 10px;
|
||||
padding: 5px;
|
||||
border-radius: 3px;
|
||||
background-color: red;
|
||||
color: white;
|
||||
background-color: @at-red-bright;
|
||||
color: @at-white;
|
||||
height: 15px;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
@ -165,12 +165,12 @@ angular
|
||||
'CheckLicense', '$location', 'Authorization', 'LoadBasePaths', 'Timer',
|
||||
'LoadConfig', 'Store', 'pendoService', 'Rest',
|
||||
'$state', 'GetBasePath', 'ConfigService',
|
||||
'SocketService', 'AppStrings', '$transitions',
|
||||
'SocketService', 'AppStrings', '$transitions', 'i18n',
|
||||
function($q, $cookies, $rootScope, $log, $stateParams,
|
||||
CheckLicense, $location, Authorization, LoadBasePaths, Timer,
|
||||
LoadConfig, Store, pendoService, Rest,
|
||||
$state, GetBasePath, ConfigService,
|
||||
SocketService, AppStrings, $transitions) {
|
||||
SocketService, AppStrings, $transitions, i18n) {
|
||||
|
||||
$rootScope.$state = $state;
|
||||
$rootScope.$state.matches = function(stateName) {
|
||||
@ -393,8 +393,11 @@ angular
|
||||
.then(({data}) => {
|
||||
$rootScope.pendingApprovalCount = data.count;
|
||||
})
|
||||
.catch(() => {
|
||||
// TODO: handle this
|
||||
.catch(({data, status}) => {
|
||||
ProcessErrors($scope, data, status, null, {
|
||||
hdr: i18n._('Error!'),
|
||||
msg: i18n._('Failed to get workflow jobs pending approval. GET returned status: ') + status
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,11 +42,11 @@
|
||||
export default ['$log', '$cookies', '$rootScope',
|
||||
'$location', 'Authorization', 'Alert', 'Wait', 'Timer',
|
||||
'Empty', '$scope', 'pendoService', 'ConfigService',
|
||||
'CheckLicense', 'SocketService', 'Rest', 'GetBasePath',
|
||||
'CheckLicense', 'SocketService', 'Rest', 'GetBasePath', 'i18n',
|
||||
function ($log, $cookies, $rootScope,
|
||||
$location, Authorization, Alert, Wait, Timer,
|
||||
Empty, scope, pendoService, ConfigService,
|
||||
CheckLicense, SocketService, Rest, GetBasePath) {
|
||||
CheckLicense, SocketService, Rest, GetBasePath, i18n) {
|
||||
var lastPath, lastUser, sessionExpired, loginAgain, preAuthUrl;
|
||||
|
||||
loginAgain = function() {
|
||||
@ -145,8 +145,11 @@ export default ['$log', '$cookies', '$rootScope',
|
||||
.then(({data}) => {
|
||||
$rootScope.pendingApprovalCount = data.count;
|
||||
})
|
||||
.catch(() => {
|
||||
// TODO: handle this
|
||||
.catch(({data, status}) => {
|
||||
ProcessErrors($scope, data, status, null, {
|
||||
hdr: i18n._('Error!'),
|
||||
msg: i18n._('Failed to get workflow jobs pending approval. GET returned status: ') + status
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -218,6 +218,7 @@ export default [ 'ProcessErrors', 'CredentialTypeModel', 'TemplatesStrings', '$f
|
||||
if(vm.steps[step].tab) {
|
||||
if(vm.steps[step].tab.order === currentTab.order) {
|
||||
vm.steps[step].tab._active = false;
|
||||
vm.steps[step].tab._disabled = true;
|
||||
} else if(vm.steps[step].tab.order === currentTab.order + 1) {
|
||||
activeTab = currentTab;
|
||||
vm.steps[step].tab._active = true;
|
||||
|
||||
@ -45,7 +45,7 @@
|
||||
<div class="Prompt-footer">
|
||||
<button id="prompt_cancel" class="Prompt-defaultButton" ng-click="vm.cancel()" ng-show="!vm.readOnlyPrompts">{{:: vm.strings.get('CANCEL') }}</button>
|
||||
<button id="prompt_close" class="Prompt-defaultButton" ng-click="vm.cancel()" ng-show="vm.readOnlyPrompts">{{:: vm.strings.get('CLOSE') }}</button>
|
||||
<button id="prompt_inventory_next" class="Prompt-actionButton" ng-show="vm.steps.inventory.tab._active" ng-click="vm.next(vm.steps.inventory.tab)" ng-disabled="vm.promptData.templateType === 'workflow_job_template' && !vm.promptDataClone.prompts.inventory.value.id && vm.promptDataClone.launchConf.defaults.inventory.id && !vm.readOnlyPrompts">{{:: vm.strings.get('NEXT') }}</button>
|
||||
<button id="prompt_inventory_next" class="Prompt-actionButton" ng-show="vm.steps.inventory.tab._active" ng-click="vm.next(vm.steps.inventory.tab)" ng-disabled="((vm.promptData.templateType === 'job_template' && !vm.promptDataClone.prompts.inventory.value.id) || (vm.promptData.templateType === 'workflow_job_template' && !vm.promptDataClone.prompts.inventory.value.id && vm.promptDataClone.launchConf.defaults.inventory.id)) && !vm.readOnlyPrompts">{{:: vm.strings.get('NEXT') }}</button>
|
||||
<button id="prompt_credential_next" class="Prompt-actionButton"
|
||||
ng-show="vm.steps.credential.tab._active"
|
||||
ng-click="vm.next(vm.steps.credential.tab)"
|
||||
|
||||
@ -290,15 +290,6 @@ export default ['Rest', 'GetBasePath', '$q', 'NextPage', function(Rest, GetBaseP
|
||||
|
||||
Rest.setUrl(url);
|
||||
return Rest.post(params.data);
|
||||
},
|
||||
createApprovalTemplate: ({url, data}) => {
|
||||
data = data || {};
|
||||
Rest.setUrl(url);
|
||||
return Rest.post(data);
|
||||
},
|
||||
patchApprovalTemplate: ({id, data}) => {
|
||||
Rest.setUrl(`/api/v2/workflow_approval_templates/${id}`);
|
||||
return Rest.patch(data);
|
||||
}
|
||||
};
|
||||
}];
|
||||
|
||||
@ -5,11 +5,11 @@
|
||||
*************************************************/
|
||||
|
||||
export default ['$scope', 'TemplatesService',
|
||||
'ProcessErrors', '$q',
|
||||
'ProcessErrors', '$q', 'Rest',
|
||||
'PromptService', 'TemplatesStrings', 'WorkflowChartService',
|
||||
'Wait', '$state',
|
||||
function ($scope, TemplatesService,
|
||||
ProcessErrors, $q,
|
||||
ProcessErrors, $q, Rest,
|
||||
PromptService, TemplatesStrings, WorkflowChartService,
|
||||
Wait, $state
|
||||
) {
|
||||
@ -145,7 +145,6 @@ export default ['$scope', 'TemplatesService',
|
||||
let editPromises = [];
|
||||
let credentialRequests = [];
|
||||
|
||||
// TODO: clean up data generation of approval template requests
|
||||
Object.keys(nodeRef).map((workflowMakerNodeId) => {
|
||||
const node = nodeRef[workflowMakerNodeId];
|
||||
if (node.isNew) {
|
||||
@ -153,16 +152,15 @@ export default ['$scope', 'TemplatesService',
|
||||
addPromises.push(TemplatesService.addWorkflowNode({
|
||||
url: $scope.workflowJobTemplateObj.related.workflow_nodes,
|
||||
data: {}
|
||||
}).then(({data}) => {
|
||||
approvalTemplatePromises.push(TemplatesService.createApprovalTemplate({
|
||||
url: data.related.create_approval_template,
|
||||
data: {
|
||||
name: node.unifiedJobTemplate.name,
|
||||
description: node.unifiedJobTemplate.description
|
||||
}
|
||||
}).then(({data: newNodeData}) => {
|
||||
Rest.setUrl(newNodeData.related.create_approval_template);
|
||||
approvalTemplatePromises.push(Rest.post({
|
||||
name: node.unifiedJobTemplate.name,
|
||||
description: node.unifiedJobTemplate.description,
|
||||
timeout: node.unifiedJobTemplate.timeout
|
||||
}).then(() => {
|
||||
node.originalNodeObject = data;
|
||||
nodeIdToChartNodeIdMapping[data.id] = parseInt(workflowMakerNodeId);
|
||||
node.originalNodeObject = newNodeData;
|
||||
nodeIdToChartNodeIdMapping[newNodeData.id] = parseInt(workflowMakerNodeId);
|
||||
}).catch(({ data, status }) => {
|
||||
Wait('stop');
|
||||
ProcessErrors($scope, data, status, null, {
|
||||
@ -179,9 +177,9 @@ export default ['$scope', 'TemplatesService',
|
||||
addPromises.push(TemplatesService.addWorkflowNode({
|
||||
url: $scope.workflowJobTemplateObj.related.workflow_nodes,
|
||||
data: buildSendableNodeData(node)
|
||||
}).then(({data}) => {
|
||||
node.originalNodeObject = data;
|
||||
nodeIdToChartNodeIdMapping[data.id] = parseInt(workflowMakerNodeId);
|
||||
}).then(({data: newNodeData}) => {
|
||||
node.originalNodeObject = newNodeData;
|
||||
nodeIdToChartNodeIdMapping[newNodeData.id] = parseInt(workflowMakerNodeId);
|
||||
if (_.get(node, 'promptData.launchConf.ask_credential_on_launch')) {
|
||||
// This finds the credentials that were selected in the prompt but don't occur
|
||||
// in the template defaults
|
||||
@ -194,7 +192,7 @@ export default ['$scope', 'TemplatesService',
|
||||
|
||||
credentialIdsToPost.forEach((credentialToPost) => {
|
||||
credentialRequests.push({
|
||||
id: data.id,
|
||||
id: newNodeData.id,
|
||||
data: {
|
||||
id: credentialToPost.id
|
||||
}
|
||||
@ -211,12 +209,11 @@ export default ['$scope', 'TemplatesService',
|
||||
} else if (node.isEdited) {
|
||||
if (node.unifiedJobTemplate && node.unifiedJobTemplate.unified_job_type === "workflow_approval") {
|
||||
if (node.originalNodeObject.summary_fields.unified_job_template.unified_job_type === "workflow_approval") {
|
||||
approvalTemplatePromises.push(TemplatesService.patchApprovalTemplate({
|
||||
id: node.originalNodeObject.summary_fields.unified_job_template.id,
|
||||
data: {
|
||||
name: node.unifiedJobTemplate.name,
|
||||
description: node.unifiedJobTemplate.description
|
||||
}
|
||||
Rest.setUrl(node.originalNodeObject.related.unified_job_template);
|
||||
approvalTemplatePromises.push(Rest.patch({
|
||||
name: node.unifiedJobTemplate.name,
|
||||
description: node.unifiedJobTemplate.description,
|
||||
timeout: node.unifiedJobTemplate.timeout
|
||||
}).catch(({ data, status }) => {
|
||||
Wait('stop');
|
||||
ProcessErrors($scope, data, status, null, {
|
||||
@ -224,12 +221,11 @@ export default ['$scope', 'TemplatesService',
|
||||
});
|
||||
}));
|
||||
} else {
|
||||
approvalTemplatePromises.push(TemplatesService.createApprovalTemplate({
|
||||
url: node.originalNodeObject.related.create_approval_template,
|
||||
data: {
|
||||
name: node.unifiedJobTemplate.name,
|
||||
description: node.unifiedJobTemplate.description
|
||||
}
|
||||
Rest.setUrl(newNodeData.related.create_approval_template);
|
||||
approvalTemplatePromises.push(Rest.post({
|
||||
name: node.unifiedJobTemplate.name,
|
||||
description: node.unifiedJobTemplate.description,
|
||||
timeout: node.unifiedJobTemplate.timeout
|
||||
}).catch(({ data, status }) => {
|
||||
Wait('stop');
|
||||
ProcessErrors($scope, data, status, null, {
|
||||
@ -301,7 +297,6 @@ export default ['$scope', 'TemplatesService',
|
||||
$q.all(approvalTemplatePromises)
|
||||
.then(() => {
|
||||
let disassociatePromises = [];
|
||||
let associatePromises = [];
|
||||
let linkMap = {};
|
||||
|
||||
// Build a link map for easy access
|
||||
@ -376,59 +371,60 @@ export default ['$scope', 'TemplatesService',
|
||||
}
|
||||
});
|
||||
|
||||
Object.keys(linkMap).map((sourceNodeId) => {
|
||||
Object.keys(linkMap[sourceNodeId]).map((targetNodeId) => {
|
||||
const sourceChartNodeId = nodeIdToChartNodeIdMapping[sourceNodeId];
|
||||
const targetChartNodeId = nodeIdToChartNodeIdMapping[targetNodeId];
|
||||
switch(linkMap[sourceNodeId][targetNodeId]) {
|
||||
case "success":
|
||||
if (
|
||||
!nodeRef[sourceChartNodeId].originalNodeObject.success_nodes ||
|
||||
!nodeRef[sourceChartNodeId].originalNodeObject.success_nodes.includes(nodeRef[targetChartNodeId].originalNodeObject.id)
|
||||
) {
|
||||
associatePromises.push(
|
||||
TemplatesService.associateWorkflowNode({
|
||||
parentId: parseInt(sourceNodeId),
|
||||
nodeId: parseInt(targetNodeId),
|
||||
edge: "success"
|
||||
})
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "failure":
|
||||
if (
|
||||
!nodeRef[sourceChartNodeId].originalNodeObject.failure_nodes ||
|
||||
!nodeRef[sourceChartNodeId].originalNodeObject.failure_nodes.includes(nodeRef[targetChartNodeId].originalNodeObject.id)
|
||||
) {
|
||||
associatePromises.push(
|
||||
TemplatesService.associateWorkflowNode({
|
||||
parentId: parseInt(sourceNodeId),
|
||||
nodeId: parseInt(targetNodeId),
|
||||
edge: "failure"
|
||||
})
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "always":
|
||||
if (
|
||||
!nodeRef[sourceChartNodeId].originalNodeObject.always_nodes ||
|
||||
!nodeRef[sourceChartNodeId].originalNodeObject.always_nodes.includes(nodeRef[targetChartNodeId].originalNodeObject.id)
|
||||
) {
|
||||
associatePromises.push(
|
||||
TemplatesService.associateWorkflowNode({
|
||||
parentId: parseInt(sourceNodeId),
|
||||
nodeId: parseInt(targetNodeId),
|
||||
edge: "always"
|
||||
})
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$q.all(disassociatePromises)
|
||||
.then(() => {
|
||||
let associatePromises = [];
|
||||
Object.keys(linkMap).map((sourceNodeId) => {
|
||||
Object.keys(linkMap[sourceNodeId]).map((targetNodeId) => {
|
||||
const sourceChartNodeId = nodeIdToChartNodeIdMapping[sourceNodeId];
|
||||
const targetChartNodeId = nodeIdToChartNodeIdMapping[targetNodeId];
|
||||
switch(linkMap[sourceNodeId][targetNodeId]) {
|
||||
case "success":
|
||||
if (
|
||||
!nodeRef[sourceChartNodeId].originalNodeObject.success_nodes ||
|
||||
!nodeRef[sourceChartNodeId].originalNodeObject.success_nodes.includes(nodeRef[targetChartNodeId].originalNodeObject.id)
|
||||
) {
|
||||
associatePromises.push(
|
||||
TemplatesService.associateWorkflowNode({
|
||||
parentId: parseInt(sourceNodeId),
|
||||
nodeId: parseInt(targetNodeId),
|
||||
edge: "success"
|
||||
})
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "failure":
|
||||
if (
|
||||
!nodeRef[sourceChartNodeId].originalNodeObject.failure_nodes ||
|
||||
!nodeRef[sourceChartNodeId].originalNodeObject.failure_nodes.includes(nodeRef[targetChartNodeId].originalNodeObject.id)
|
||||
) {
|
||||
associatePromises.push(
|
||||
TemplatesService.associateWorkflowNode({
|
||||
parentId: parseInt(sourceNodeId),
|
||||
nodeId: parseInt(targetNodeId),
|
||||
edge: "failure"
|
||||
})
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "always":
|
||||
if (
|
||||
!nodeRef[sourceChartNodeId].originalNodeObject.always_nodes ||
|
||||
!nodeRef[sourceChartNodeId].originalNodeObject.always_nodes.includes(nodeRef[targetChartNodeId].originalNodeObject.id)
|
||||
) {
|
||||
associatePromises.push(
|
||||
TemplatesService.associateWorkflowNode({
|
||||
parentId: parseInt(sourceNodeId),
|
||||
nodeId: parseInt(targetNodeId),
|
||||
edge: "always"
|
||||
})
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
let credentialPromises = credentialRequests.map((request) => {
|
||||
return TemplatesService.postWorkflowNodeCredential({
|
||||
id: request.id,
|
||||
@ -589,6 +585,7 @@ export default ['$scope', 'TemplatesService',
|
||||
unifiedJobTemplate: {
|
||||
name: selectedTemplate.name,
|
||||
description: selectedTemplate.description,
|
||||
timeout: selectedTemplate.timeout,
|
||||
unified_job_type: "workflow_approval"
|
||||
},
|
||||
isNew: true
|
||||
@ -631,6 +628,7 @@ export default ['$scope', 'TemplatesService',
|
||||
nodeRef[$scope.nodeConfig.nodeId].unifiedJobTemplate = {
|
||||
name: selectedTemplate.name,
|
||||
description: selectedTemplate.description,
|
||||
timeout: selectedTemplate.timeout,
|
||||
unified_job_type: "workflow_approval"
|
||||
};
|
||||
nodeRef[$scope.nodeConfig.nodeId].isEdited = true;
|
||||
@ -643,7 +641,8 @@ export default ['$scope', 'TemplatesService',
|
||||
node.unifiedJobTemplate = {
|
||||
unified_job_type: 'workflow_approval',
|
||||
name: selectedTemplate.name,
|
||||
description: selectedTemplate.description
|
||||
description: selectedTemplate.description,
|
||||
timeout: selectedTemplate.timeout,
|
||||
};
|
||||
} else {
|
||||
node.unifiedJobTemplate = selectedTemplate;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user