mirror of
https://github.com/ansible/awx.git
synced 2026-01-19 13:41:28 -03:30
Approval drawer cleanup and workflow node form UX cleanup
This commit is contained in:
parent
1d814beca1
commit
e0cdc4ff80
@ -1,16 +1,25 @@
|
||||
.at-ApprovalsDrawer {
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
width: 540px;
|
||||
background-color: white;
|
||||
z-index: 1000000;
|
||||
animation-duration: 0.5s;
|
||||
// TODO: fix animation?
|
||||
// animation-name: slidein;
|
||||
padding: 20px;
|
||||
box-shadow: -3px 0px 8px -2px #aaaaaa;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
// z-index of the nav header is 1040
|
||||
z-index: 1041;
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
|
||||
&-drawer {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
width: 540px;
|
||||
background-color: @default-bg;
|
||||
animation-name: slidein;
|
||||
animation-duration: 250ms;
|
||||
padding: 20px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
&-header {
|
||||
display: flex;
|
||||
@ -20,12 +29,23 @@
|
||||
|
||||
&-title {
|
||||
flex: 1 0 auto;
|
||||
color: #606060;
|
||||
color: @default-interface-txt;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
width: calc(82%);
|
||||
}
|
||||
|
||||
&-actionRow {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
width: 100%;
|
||||
margin-top: 10px;
|
||||
|
||||
button {
|
||||
margin-left: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
&-exit {
|
||||
justify-content: flex-end;
|
||||
display: flex;
|
||||
@ -33,7 +53,7 @@
|
||||
button {
|
||||
height: 20px;
|
||||
font-size: 20px;
|
||||
color: #D7D7D7;
|
||||
color: @d7grey;
|
||||
line-height: 1;
|
||||
opacity: 1;
|
||||
}
|
||||
@ -41,7 +61,7 @@
|
||||
button:hover{
|
||||
color: @default-icon;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -8,52 +8,36 @@ function AtApprovalsDrawerController (strings, Rest, GetBasePath, $rootScope) {
|
||||
value: 'created'
|
||||
};
|
||||
|
||||
vm.strings = strings;
|
||||
vm.toolbarSortValue = toolbarSortDefault;
|
||||
vm.queryset = {
|
||||
page: 1,
|
||||
page_size: 5,
|
||||
order_by: 'created',
|
||||
status: 'pending'
|
||||
};
|
||||
vm.emptyListReason = vm.strings.get('approvals.NONE');
|
||||
|
||||
// This will probably need to be expanded
|
||||
vm.toolbarSortOptions = [
|
||||
toolbarSortDefault,
|
||||
{ label: `${strings.get('sort.CREATED_DESCENDING')}`, value: '-created' }
|
||||
{ label: `${vm.strings.get('sort.CREATED_DESCENDING')}`, value: '-created' }
|
||||
];
|
||||
|
||||
vm.queryset = {
|
||||
page_size: 5
|
||||
};
|
||||
|
||||
vm.emptyListReason = strings.get('approvals.NONE');
|
||||
|
||||
const loadTheList = () => {
|
||||
Rest.setUrl(`${GetBasePath('workflow_approval')}?page_size=5&order_by=created&status=pending`);
|
||||
Rest.get()
|
||||
const queryParams = Object.keys(vm.queryset).map(key => `${key}=${vm.queryset[key]}`).join('&');
|
||||
Rest.setUrl(`${GetBasePath('workflow_approval')}?${queryParams}`);
|
||||
return Rest.get()
|
||||
.then(({ data }) => {
|
||||
vm.dataset = data;
|
||||
vm.approvals = data.results;
|
||||
vm.count = data.count;
|
||||
$rootScope.pendingApprovalCount = data.count;
|
||||
vm.listLoaded = true;
|
||||
});
|
||||
};
|
||||
|
||||
loadTheList();
|
||||
|
||||
vm.onToolbarSort = (sort) => {
|
||||
vm.toolbarSortValue = sort;
|
||||
|
||||
// TODO: this...
|
||||
// const queryParams = Object.assign(
|
||||
// {},
|
||||
// $state.params.user_search,
|
||||
// paginateQuerySet,
|
||||
// { order_by: sort.value }
|
||||
// );
|
||||
|
||||
// // Update URL with params
|
||||
// $state.go('.', {
|
||||
// user_search: queryParams
|
||||
// }, { notify: false, location: 'replace' });
|
||||
|
||||
// rather than ^^ we want to just re-load the data based on new params
|
||||
};
|
||||
loadTheList()
|
||||
.then(() => { vm.listLoaded = true; });
|
||||
|
||||
vm.approve = (approval) => {
|
||||
Rest.setUrl(`${GetBasePath('workflow_approval')}${approval.id}/approve`);
|
||||
@ -66,6 +50,13 @@ function AtApprovalsDrawerController (strings, Rest, GetBasePath, $rootScope) {
|
||||
Rest.post()
|
||||
.then(() => loadTheList());
|
||||
};
|
||||
|
||||
vm.onToolbarSort = (sort) => {
|
||||
vm.toolbarSortValue = sort;
|
||||
vm.queryset.page = 1;
|
||||
vm.queryset.order_by = sort.value;
|
||||
loadTheList();
|
||||
};
|
||||
}
|
||||
|
||||
AtApprovalsDrawerController.$inject = ['ComponentsStrings', 'Rest', 'GetBasePath', '$rootScope'];
|
||||
|
||||
@ -1,79 +1,79 @@
|
||||
<div style="width: 100%;height: 100%;position: fixed;top: 0;right: 0;opacity: 0.5;background-color: black;z-index: 10000;"></div>
|
||||
<div class="at-ApprovalsDrawer" ng-if="vm.listLoaded">
|
||||
<div class="at-ApprovalsDrawer-header">
|
||||
<div class="at-ApprovalsDrawer-title">
|
||||
<span>
|
||||
NOTIFICATIONS
|
||||
</span>
|
||||
<span class="at-Panel-headingTitleBadge">
|
||||
{{vm.count}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="at-ApprovalsDrawer-exit">
|
||||
<button class="close" ng-click="closeApprovals()">
|
||||
<i class="fa fa-times-circle"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<at-list-toolbar
|
||||
ng-if="vm.approvals.length > 0"
|
||||
sort-only="true"
|
||||
sort-value="vm.toolbarSortValue"
|
||||
sort-options="vm.toolbarSortOptions"
|
||||
on-sort="vm.onToolbarSort">
|
||||
</at-list-toolbar>
|
||||
<at-list results="vm.approvals" id="approvals_list" empty-list-reason="{{ vm.emptyListReason }}">
|
||||
<at-row ng-repeat="approval in vm.approvals"
|
||||
id="approval-row-{{ approval.id }}">
|
||||
<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}}})"
|
||||
header-tag="Workflow Template">
|
||||
</at-row-item>
|
||||
</div>
|
||||
</div>
|
||||
<div class="at-Row-container--wrapped">
|
||||
<at-row-item
|
||||
value-bind-html="{{ approval.created | longDate }}">
|
||||
</at-row-item>
|
||||
<at-row-item
|
||||
style="color: red;"
|
||||
value-bind-html="Expires: Never">
|
||||
</at-row-item>
|
||||
<!-- <at-row-item
|
||||
style="color: red;"
|
||||
value-bind-html="Expires {{ approval.created | longDate }}">
|
||||
</at-row-item> -->
|
||||
</div>
|
||||
<div class="at-Row-container--wrapped">
|
||||
<div style="display: flex; justify-content: flex-end; width: 100%; margin-top: 10px;">
|
||||
<div>Continue workflow job?</div>
|
||||
<button class="btn at-Button--success"
|
||||
style="margin-left: 15px;"
|
||||
ng-click="vm.approve(approval)"
|
||||
type="button">
|
||||
APPROVE
|
||||
</button>
|
||||
<button class="btn at-Button--error"
|
||||
style="margin-left: 15px;"
|
||||
ng-click="vm.deny(approval)"
|
||||
type="button">
|
||||
DENY
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="at-ApprovalsDrawer">
|
||||
<div class="at-ApprovalsDrawer-drawer" ng-if="vm.listLoaded">
|
||||
<div class="at-ApprovalsDrawer-header">
|
||||
<div class="at-ApprovalsDrawer-title">
|
||||
<span>
|
||||
{{:: vm.strings.get('approvals.NOTIFICATIONS') }}
|
||||
</span>
|
||||
<span class="at-Panel-headingTitleBadge">
|
||||
{{vm.count}}
|
||||
</span>
|
||||
</div>
|
||||
</at-row>
|
||||
</at-list>
|
||||
<paginate
|
||||
collection="vm.approvals"
|
||||
dataset="vm.dataset"
|
||||
iterator="template"
|
||||
base-path="unified_job_templates"
|
||||
query-set="vm.queryset">
|
||||
</paginate>
|
||||
<div class="at-ApprovalsDrawer-exit">
|
||||
<button class="close" ng-click="closeApprovals()">
|
||||
<i class="fa fa-times-circle"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<at-list-toolbar
|
||||
ng-if="vm.approvals.length > 0"
|
||||
sort-only="true"
|
||||
sort-value="vm.toolbarSortValue"
|
||||
sort-options="vm.toolbarSortOptions"
|
||||
on-sort="vm.onToolbarSort">
|
||||
</at-list-toolbar>
|
||||
<at-list results="vm.approvals" id="approvals_list" empty-list-reason="{{ vm.emptyListReason }}">
|
||||
<at-row ng-repeat="approval in vm.approvals"
|
||||
id="approval-row-{{ approval.id }}">
|
||||
<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}}})"
|
||||
header-tag="{{:: vm.strings.get('approvals.WORKFLOW_TEMPLATE') }}">
|
||||
</at-row-item>
|
||||
</div>
|
||||
</div>
|
||||
<div class="at-Row-container--wrapped">
|
||||
<at-row-item
|
||||
value-bind-html="{{ approval.created | longDate }}">
|
||||
</at-row-item>
|
||||
<at-row-item
|
||||
style="color: red;"
|
||||
value-bind-html="Expires: Never">
|
||||
</at-row-item>
|
||||
<!-- <at-row-item
|
||||
style="color: red;"
|
||||
value-bind-html="Expires {{ approval.created | longDate }}">
|
||||
</at-row-item> -->
|
||||
</div>
|
||||
<div class="at-Row-container--wrapped">
|
||||
<div class="at-ApprovalsDrawer-actionRow">
|
||||
<div>{{:: vm.strings.get('approvals.CONTINUE') }}</div>
|
||||
<button class="btn at-Button--success"
|
||||
ng-click="vm.approve(approval)"
|
||||
type="button">
|
||||
{{:: vm.strings.get('approvals.APPROVE') }}
|
||||
</button>
|
||||
<button class="btn at-Button--error"
|
||||
ng-click="vm.deny(approval)"
|
||||
type="button">
|
||||
{{:: vm.strings.get('approvals.DENY') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</at-row>
|
||||
</at-list>
|
||||
<paginate
|
||||
collection="vm.approvals"
|
||||
dataset="vm.dataset"
|
||||
iterator="template"
|
||||
base-path="unified_job_templates"
|
||||
query-set="vm.queryset"
|
||||
hide-view-per-page="true">
|
||||
</paginate>
|
||||
</div>
|
||||
</div>
|
||||
@ -121,7 +121,12 @@ function ComponentsStrings (BaseString) {
|
||||
};
|
||||
|
||||
ns.approvals = {
|
||||
NONE: t.s('There are no jobs awaiting approval')
|
||||
NONE: t.s('There are no jobs awaiting approval'),
|
||||
APPROVE: t.s('APPROVE'),
|
||||
DENY: t.s('DENY'),
|
||||
CONTINUE: t.s('Continue workflow job?'),
|
||||
NOTIFICATIONS: t.s('NOTIFICATIONS'),
|
||||
WORKFLOW_TEMPLATE: t.s('Workflow Template')
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
export default ['$scope', '$stateParams', '$state', '$filter', 'GetBasePath', 'QuerySet', '$interpolate',
|
||||
function($scope, $stateParams, $state, $filter, GetBasePath, qs, $interpolate) {
|
||||
export default ['$scope', '$stateParams', '$state', 'GetBasePath', 'QuerySet', '$interpolate',
|
||||
function($scope, $stateParams, $state, GetBasePath, qs, $interpolate) {
|
||||
|
||||
let pageSize = $scope.querySet ? $scope.querySet.page_size || 20 : $stateParams[`${$scope.iterator}_search`].page_size || 20,
|
||||
queryset, path;
|
||||
|
||||
@ -281,4 +281,4 @@
|
||||
<button type="button" class="btn btn-sm Form-saveButton" id="workflow_maker_select_node_btn" ng-show="!readOnly" ng-click="select({selectedTemplate, promptData, edgeType, pauseNode})" ng-disabled="!(selectedTemplate || pauseNode.isPauseNode) || promptModalMissingReqFields || credentialRequiresPassword || selectedTemplateInvalid || (pauseNode.isPauseNode && !pauseNode.name)"> {{:: strings.get('workflow_maker.SELECT') }}</button>
|
||||
</div>
|
||||
<prompt prompt-data="promptData" action-text="{{:: strings.get('prompt.CONFIRM')}}" prevent-creds-with-passwords="preventCredsWithPasswords" read-only-prompts="readOnly"></prompt>
|
||||
</div>
|
||||
</div>
|
||||
@ -226,7 +226,7 @@ export default ['$scope', 'TemplatesService',
|
||||
}).then(({data: approvalTemplateData}) => {
|
||||
// Make sure that this isn't overwriting everything on the node...
|
||||
editPromises.push(TemplatesService.editWorkflowNode({
|
||||
url: $scope.workflowJobTemplateObj.related.workflow_nodes,
|
||||
id: node.originalNodeObject.id,
|
||||
data: {
|
||||
unified_job_template: approvalTemplateData.id
|
||||
}
|
||||
@ -583,26 +583,31 @@ export default ['$scope', 'TemplatesService',
|
||||
$scope.formState.showNodeForm = true;
|
||||
};
|
||||
|
||||
$scope.confirmNodeForm = (selectedTemplate, promptData, edgeType, pauseNode) => {
|
||||
$scope.confirmNodeForm = (nodeFormData) => {
|
||||
const { edgeType, selectedTemplate, promptData } = nodeFormData;
|
||||
const isPauseNode = selectedTemplate.type === "workflow_approval"
|
||||
|| selectedTemplate.unified_job_type === "workflow_approval";
|
||||
// edgeType, selectedTemplate, promptData
|
||||
// can determine pause node by looking at the type (?) or maybe unified_job_type
|
||||
$scope.workflowChangesUnsaved = true;
|
||||
const nodeId = $scope.nodeConfig.nodeId;
|
||||
if ($scope.nodeConfig.mode === "add") {
|
||||
if (edgeType && edgeType.value) {
|
||||
if (selectedTemplate) {
|
||||
if (edgeType && edgeType.value && selectedTemplate) {
|
||||
if (isPauseNode) {
|
||||
nodeRef[$scope.nodeConfig.nodeId] = {
|
||||
unifiedJobTemplate: {
|
||||
name: selectedTemplate.name,
|
||||
description: selectedTemplate.description,
|
||||
unified_job_type: "workflow_approval"
|
||||
},
|
||||
isNew: true
|
||||
};
|
||||
} else {
|
||||
nodeRef[$scope.nodeConfig.nodeId] = {
|
||||
fullUnifiedJobTemplateObject: selectedTemplate,
|
||||
promptData,
|
||||
isNew: true
|
||||
};
|
||||
} else if (pauseNode && pauseNode.isPauseNode) {
|
||||
nodeRef[$scope.nodeConfig.nodeId] = {
|
||||
unifiedJobTemplate: {
|
||||
name: pauseNode.name,
|
||||
description: pauseNode.description,
|
||||
unified_job_type: "workflow_approval"
|
||||
},
|
||||
isNew: true
|
||||
};
|
||||
}
|
||||
$scope.graphState.nodeBeingAdded = null;
|
||||
|
||||
@ -629,12 +634,12 @@ export default ['$scope', 'TemplatesService',
|
||||
link.source.unifiedJobTemplate = selectedTemplate;
|
||||
}
|
||||
});
|
||||
} else if (pauseNode && pauseNode.isPauseNode) {
|
||||
} else if (isPauseNode) {
|
||||
// If it's a _new_ pause node then we'll want to create the new ujt
|
||||
// If it's an existing pause node then we'll want to update the ujt
|
||||
nodeRef[$scope.nodeConfig.nodeId].unifiedJobTemplate = {
|
||||
name: pauseNode.name,
|
||||
description: pauseNode.description,
|
||||
name: selectedTemplate.name,
|
||||
description: selectedTemplate.description,
|
||||
unified_job_type: "workflow_approval"
|
||||
};
|
||||
nodeRef[$scope.nodeConfig.nodeId].isEdited = true;
|
||||
@ -643,11 +648,11 @@ export default ['$scope', 'TemplatesService',
|
||||
|
||||
$scope.graphState.arrayOfNodesForChart.map( (node) => {
|
||||
if (node.id === nodeId) {
|
||||
if (pauseNode && pauseNode.isPauseNode) {
|
||||
if (isPauseNode) {
|
||||
node.unifiedJobTemplate = {
|
||||
unified_job_type: 'workflow_approval',
|
||||
name: pauseNode.name,
|
||||
description: pauseNode.description
|
||||
name: selectedTemplate.name,
|
||||
description: selectedTemplate.description
|
||||
};
|
||||
} else {
|
||||
node.unifiedJobTemplate = selectedTemplate;
|
||||
|
||||
@ -128,7 +128,7 @@
|
||||
</div>
|
||||
<div class="WorkflowMaker-contentRight">
|
||||
<span ng-if="formState.showNodeForm">
|
||||
<workflow-node-form node-config="nodeConfig" workflow-job-template-obj="workflowJobTemplateObj" select="confirmNodeForm(selectedTemplate, promptData, edgeType, pauseNode)" cancel="cancelNodeForm()" read-only="!workflowJobTemplateObj.summary_fields.user_capabilities.edit"/>
|
||||
<workflow-node-form node-config="nodeConfig" workflow-job-template-obj="workflowJobTemplateObj" select="confirmNodeForm(nodeFormData)" cancel="cancelNodeForm()" read-only="!workflowJobTemplateObj.summary_fields.user_capabilities.edit"/>
|
||||
</span>
|
||||
<span ng-if="formState.showLinkForm">
|
||||
<workflow-link-form link-config="linkConfig" read-only="!workflowJobTemplateObj.summary_fields.user_capabilities.edit" select="confirmLinkForm(edgeType)" cancel="cancelLinkForm()" unlink="unlink()"/>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user