Approval drawer cleanup and workflow node form UX cleanup

This commit is contained in:
mabashian 2019-07-15 15:39:06 -04:00 committed by Ryan Petrello
parent 1d814beca1
commit e0cdc4ff80
No known key found for this signature in database
GPG Key ID: F2AA5F2122351777
8 changed files with 166 additions and 145 deletions

View File

@ -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;
}
}
}
}

View File

@ -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'];

View File

@ -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>

View File

@ -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')
};
}

View File

@ -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;

View File

@ -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>

View File

@ -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;

View File

@ -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()"/>