diff --git a/awx/ui/client/features/jobs/routes/jobs.route.js b/awx/ui/client/features/jobs/routes/jobs.route.js
index 73deb2d492..427d7d165d 100644
--- a/awx/ui/client/features/jobs/routes/jobs.route.js
+++ b/awx/ui/client/features/jobs/routes/jobs.route.js
@@ -15,7 +15,6 @@ export default {
job_search: {
value: {
not__launch_type: 'sync',
- not__type: 'workflow_approval',
order_by: '-finished'
},
dynamic: true,
diff --git a/awx/ui/client/features/templates/templates.strings.js b/awx/ui/client/features/templates/templates.strings.js
index b0aa4620ba..38ab92750e 100644
--- a/awx/ui/client/features/templates/templates.strings.js
+++ b/awx/ui/client/features/templates/templates.strings.js
@@ -149,7 +149,8 @@ function TemplatesStrings (BaseString) {
CANCEL: t.s('CANCEL'),
SAVE_AND_EXIT: t.s('SAVE & EXIT'),
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.')
+ TIMEOUT_POPOVER: t.s('The amount of time to wait before this approval step is automatically denied. Defaults to 0 for no timeout.'),
+ TIMED_OUT: t.s('APPROVAL TIMED OUT')
};
}
diff --git a/awx/ui/client/lib/components/approvalsDrawer/_index.less b/awx/ui/client/lib/components/approvalsDrawer/_index.less
index 79771c1d0c..8687fee546 100644
--- a/awx/ui/client/lib/components/approvalsDrawer/_index.less
+++ b/awx/ui/client/lib/components/approvalsDrawer/_index.less
@@ -38,6 +38,7 @@
justify-content: flex-end;
width: 100%;
margin-top: 10px;
+ line-height: 30px;
button {
margin-left: 15px;
diff --git a/awx/ui/client/lib/components/approvalsDrawer/approvalsDrawer.partial.html b/awx/ui/client/lib/components/approvalsDrawer/approvalsDrawer.partial.html
index 7ef3b29443..c57ddca622 100644
--- a/awx/ui/client/lib/components/approvalsDrawer/approvalsDrawer.partial.html
+++ b/awx/ui/client/lib/components/approvalsDrawer/approvalsDrawer.partial.html
@@ -30,8 +30,7 @@
+ header-state="workflowResults({pid: {{approval.summary_fields.source_workflow_job.id}}})">
diff --git a/awx/ui/client/lib/components/layout/_index.less b/awx/ui/client/lib/components/layout/_index.less
index 8c63ec603b..4457e69640 100644
--- a/awx/ui/client/lib/components/layout/_index.less
+++ b/awx/ui/client/lib/components/layout/_index.less
@@ -82,21 +82,29 @@
}
}
- .at-Layout-topNavApprovals {
+ .at-Layout-Approvals {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
+ }
- div {
- margin-left: 10px;
- padding: 5px;
- border-radius: 3px;
- background-color: @at-red-bright;
- color: @at-white;
- height: 15px;
- font-size: 10px;
- }
+ .at-Layout-ApprovalsBadge {
+ margin-left: 10px;
+ padding: 5px;
+ border-radius: 3px;
+ background-color: @at-gray-646972;
+ color: @at-white;
+ height: 16px;
+ font-size: 11px;
+ font-weight: bold;
+ cursor: default;
+ display: flex;
+ align-items: center;
+ }
+
+ .at-Layout-ApprovalsBadgeActive {
+ background-color: @at-red-bright;
}
}
diff --git a/awx/ui/client/lib/components/layout/layout.partial.html b/awx/ui/client/lib/components/layout/layout.partial.html
index d092ce2d95..d48c607abc 100644
--- a/awx/ui/client/lib/components/layout/layout.partial.html
+++ b/awx/ui/client/lib/components/layout/layout.partial.html
@@ -15,9 +15,9 @@
-
+
-
{{vm.approvalsCount}}
+
{{vm.approvalsCount}}
diff --git a/awx/ui/client/src/templates/workflows/workflow-chart/workflow-chart.block.less b/awx/ui/client/src/templates/workflows/workflow-chart/workflow-chart.block.less
index a9c1550d60..8519f28f95 100644
--- a/awx/ui/client/src/templates/workflows/workflow-chart/workflow-chart.block.less
+++ b/awx/ui/client/src/templates/workflows/workflow-chart/workflow-chart.block.less
@@ -148,6 +148,7 @@
color: @default-interface-txt;
text-align: center;
}
+
.WorkflowChart-activeNode {
fill: @default-link;
}
@@ -169,6 +170,13 @@
text-align: center;
}
+.WorkflowChart-timedOutText {
+ width: 180px;
+ height: 14px;
+ color: @default-err;
+ text-align: center;
+}
+
.WorkflowChart-tooltip {
pointer-events: none;
text-align: center;
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 e4c64231d5..ae1da75a35 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
@@ -832,6 +832,9 @@ export default ['moment', '$timeout', '$window', '$filter', 'TemplatesStrings',
baseSvg.selectAll(".WorkflowChart-deletedText")
.style("display", (d) => { return d.unifiedJobTemplate || d.id === scope.graphState.nodeBeingAdded ? "none" : null; });
+ baseSvg.selectAll(".WorkflowChart-timedOutText")
+ .style("display", (d) => { return d.job && d.job.timed_out ? null : "none"; });
+
baseSvg.selectAll(".WorkflowChart-activeNode")
.style("display", (d) => { return d.id === scope.graphState.nodeBeingEdited ? null : "none"; });
@@ -940,6 +943,15 @@ export default ['moment', '$timeout', '$window', '$filter', 'TemplatesStrings',
.html(`${TemplatesStrings.get('workflow_maker.DELETED')}`)
.style("display", (d) => { return d.unifiedJobTemplate || d.id === scope.graphState.nodeBeingAdded ? "none" : null; });
+ thisNode.append("foreignObject")
+ .attr("x", 0)
+ .attr("y", 22)
+ .attr("dy", ".35em")
+ .attr("text-anchor", "middle")
+ .attr("class", "WorkflowChart-defaultText WorkflowChart-timedOutText")
+ .html(`${TemplatesStrings.get('workflow_maker.TIMED_OUT')}`)
+ .style("display", (d) => { return d.job && d.job.timed_out ? null : "none"; });
+
thisNode.append("circle")
.attr("cy", nodeH)
.attr("r", 10)
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 4bd9590869..ad77581a6a 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
@@ -489,7 +489,8 @@ export default ['$scope', 'TemplatesService', 'JobTemplateModel', 'PromptService
$scope.approvalNodeState = {
name: null,
description: null,
- timeout: 0
+ timeoutMinutes: 0,
+ timeoutSeconds: 0
};
$scope.nodeFormDataLoaded = false;
$scope.wf_maker_template_queryset = {
@@ -552,10 +553,14 @@ export default ['$scope', 'TemplatesService', 'JobTemplateModel', 'PromptService
$scope.activeTab = "approval";
select2ifyDropdowns();
+ const timeoutMinutes = Math.floor($scope.nodeConfig.node.unifiedJobTemplate.timeout / 60);
+ const timeoutSeconds = $scope.nodeConfig.node.unifiedJobTemplate.timeout - timeoutMinutes * 60;
+
$scope.approvalNodeState = {
name: $scope.nodeConfig.node.unifiedJobTemplate.name,
description: $scope.nodeConfig.node.unifiedJobTemplate.description,
- timeout: $scope.nodeConfig.node.unifiedJobTemplate.timeout
+ timeoutMinutes,
+ timeoutSeconds
};
$scope.nodeFormDataLoaded = true;
@@ -616,10 +621,12 @@ export default ['$scope', 'TemplatesService', 'JobTemplateModel', 'PromptService
};
if ($scope.activeTab === "approval") {
+ const timeout = $scope.approvalNodeState.timeoutMinutes * 60 + $scope.approvalNodeState.timeoutSeconds;
+
nodeFormData.selectedTemplate = {
name: $scope.approvalNodeState.name,
description: $scope.approvalNodeState.description,
- timeout: $scope.approvalNodeState.timeout,
+ timeout,
unified_job_type: "workflow_approval"
};
} else if($scope.activeTab === "templates") {
@@ -649,7 +656,7 @@ export default ['$scope', 'TemplatesService', 'JobTemplateModel', 'PromptService
} else if($scope.activeTab === "inventory_syncs") {
return !$scope.inventoryNodeState.selectedTemplate;
} else if ($scope.activeTab === "approval") {
- return !($scope.approvalNodeState.name && $scope.approvalNodeState.name !== "") || $scope.workflow_approval.pauseTimeout.$error.min;
+ return !($scope.approvalNodeState.name && $scope.approvalNodeState.name !== "") || $scope.workflow_approval.pauseTimeoutMinutes.$error.min || $scope.workflow_approval.pauseTimeoutSeconds.$error.min;
}
};
@@ -660,7 +667,8 @@ export default ['$scope', 'TemplatesService', 'JobTemplateModel', 'PromptService
$scope.approvalNodeState = {
name: null,
description: null,
- timeout: 0
+ timeoutMinutes: 0,
+ timeoutSeconds: 0
};
$scope.editNodeHelpMessage = getEditNodeHelpMessage(selectedTemplate, $scope.workflowJobTemplateObj);
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 88626d9fdc..d2d8cbeb7d 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
@@ -133,15 +133,22 @@
diff --git a/awx/ui/client/src/templates/workflows/workflow-maker/workflow-maker.block.less b/awx/ui/client/src/templates/workflows/workflow-maker/workflow-maker.block.less
index f163c845e3..bb17089dc9 100644
--- a/awx/ui/client/src/templates/workflows/workflow-maker/workflow-maker.block.less
+++ b/awx/ui/client/src/templates/workflows/workflow-maker/workflow-maker.block.less
@@ -323,11 +323,18 @@
margin-bottom: 20px;
}
-.WorkflowMaker-pauseCheckbox {
- input {
- margin-right: 5px;
+.WorkflowMaker-timeoutInput {
+ .ui-spinner {
+ width: 100px;
}
- margin-bottom: 20px;
+}
+
+.WorkflowMaker-timeoutSeconds {
+ margin-left: 10px;
+}
+
+.WorkflowMaker-timeoutLabel {
+ margin-left: 3px;
}
.Key-list {