Skip to content

Commit d36a155

Browse files
committed
Add manage-status changes
1 parent 1484f07 commit d36a155

File tree

21 files changed

+5745
-109
lines changed

21 files changed

+5745
-109
lines changed

client/src/api/index.js

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,22 @@ import { clearAllState } from '../store/actions';
55
const isDev = process.env.NODE_ENV === 'development';
66
const apiUrl = isDev ? process.env.BACKEND_DEV_HOST : process.env.BACKEND_PROD_HOST;
77

8+
const clearState = async () => {
9+
store.dispatch(clearAllState());
10+
await persistor.purge();
11+
localStorage.clear();
12+
};
13+
814
const instance = axios.create({
915
baseURL: apiUrl,
1016
withCredentials: true,
1117
});
1218

1319
instance.interceptors.response.use(
1420
response => response,
15-
err => {
21+
async err => {
1622
if (err?.response?.status === 401) {
17-
store.dispatch(clearAllState());
23+
await clearState();
1824
}
1925
throw err;
2026
}
@@ -35,8 +41,7 @@ export const api = Object.freeze({
3541
},
3642
logout: async () => {
3743
await instance.get('/auth/jwt/logout');
38-
await persistor.purge();
39-
localStorage.clear();
44+
await clearState();
4045
},
4146
loginStatus: async () => {
4247
const response = await instance.get('/auth/jwt/login-status');
@@ -51,8 +56,7 @@ export const api = Object.freeze({
5156
},
5257
logout: async () => {
5358
await instance.get('/auth/passport/logout');
54-
await persistor.purge();
55-
localStorage.clear();
59+
await clearState();
5660
},
5761
callbackExecute: async code => {
5862
const response = await instance.get(`/auth/passport/callback?code=${code}`);
@@ -80,7 +84,7 @@ export const api = Object.freeze({
8084
const response = await instance.put(`/workflows/${workflow.id}/instances/${workflow.instanceId}/cancel`);
8185
return response;
8286
} catch (error) {
83-
console.log(error);
87+
return error.response;
8488
}
8589
},
8690
publishWorkflow: async workflowId => {
@@ -96,6 +100,7 @@ export const api = Object.freeze({
96100
return published;
97101
} catch (error) {
98102
console.log(error);
103+
return error.response;
99104
}
100105
}
101106

client/src/components/Popups/WorkflowDefinitionCreation/WorkflowDefinitionCreation.jsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,25 @@ const WorkflowDefinitionCreation = ({ message }) => {
3535
return;
3636
}
3737

38+
if (workflow?.status === 400 && workflow?.data?.errorMessage.includes('limit (5)')) {
39+
dispatch(
40+
showErrorTextInPopup(
41+
'Publish workflow was unsuccessful',
42+
"You've used all your 5 available workflows on the account. Delete active workflows to make space.",
43+
null
44+
)
45+
);
46+
dispatch(closeLoadingCircleInPopup());
47+
return;
48+
}
49+
3850
dispatch(
3951
showErrorTextInPopup(
4052
'Publish workflow was unsuccessful',
4153
'The Docusign server returned an error during the workflow publishing. Try again later.',
4254
null
4355
)
4456
);
45-
4657
dispatch(closeLoadingCircleInPopup());
4758
};
4859

client/src/components/Popups/WorkflowTriggerResult/WorkflowTriggerResult.module.css

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,7 @@
3939

4040
.popupContainer a:hover {
4141
color: var(--white-main);
42-
background-color: var(--primary-dark);
43-
box-shadow: 0px 5px 14px rgba(0, 0, 0, 0.5);
42+
background-color: var(--secondary-main);
4443
}
4544

4645
.popupContainer div {

client/src/components/TriggerForm/TriggerForm.jsx

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,14 @@ const TriggerForm = ({ workflowId }) => {
4242
setWorkflowInstanceUrl(triggeredWorkflow.workflowInstanceUrl);
4343

4444
// Update workflowDefinitions. "...workflow" creates new workflow-object to avoid mutation in redux
45-
const updatedWorkflowDefinitions = workflows.map(workflow => {
46-
if (workflow.id === workflowId) {
47-
return {
48-
...workflow,
49-
instanceId: triggeredWorkflow.instanceId,
50-
isTriggered: true,
51-
};
52-
}
53-
54-
return { ...workflow };
45+
const updatedWorkflowDefinitions = workflows.map(w => {
46+
if (w.id !== workflowId) return { ...w };
47+
48+
return {
49+
...w,
50+
instanceId: triggeredWorkflow.instanceId,
51+
isTriggered: true,
52+
};
5553
});
5654

5755
dispatch(updateWorkflowDefinitions(updatedWorkflowDefinitions));
@@ -97,8 +95,9 @@ const TriggerForm = ({ workflowId }) => {
9795
</div>
9896

9997
<div className={styles.divider} />
100-
<button type="submit" disabled={isDataSending}>
101-
{textContent.buttons.continue}
98+
<button className="btn btn-primary" type="submit" disabled={isDataSending}>
99+
<span className="sr-only">{textContent.buttons.continue}</span>
100+
{isDataSending ? <span className="spinner-border spinner-border-sm" /> : null}
102101
</button>
103102
</form>
104103
{isPopupOpened && (

client/src/components/TriggerForm/TriggerForm.module.css

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ label {
5555
}
5656

5757
.triggerForm label:after {
58-
content: " *";
58+
content: ' *';
5959
color: var(--secondary-main);
6060
}
6161

@@ -84,7 +84,11 @@ label {
8484
}
8585

8686
.triggerForm button:disabled {
87+
display: flex;
88+
justify-content: space-around;
89+
padding: 0;
90+
align-items: center;
8791
background-color: var(--grey-main);
88-
color: var(--black-extraextralight);
92+
color: var(--black-extralight);
8993
cursor: not-allowed;
9094
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import styles from './StatusLoader.module.css';
2+
3+
const StatusLoader = () => {
4+
return (
5+
<div className={styles.loader}>
6+
<div></div>
7+
<div></div>
8+
<div></div>
9+
<div></div>
10+
<div></div>
11+
</div>
12+
);
13+
};
14+
15+
export default StatusLoader;
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
.loader {
2+
--size: 4px;
3+
4+
display: flex;
5+
justify-content: center;
6+
align-items: center;
7+
gap: calc(var(--size));
8+
height: calc(var(--size) * 5);
9+
width: 80px;
10+
}
11+
12+
.loader div {
13+
width: var(--size);
14+
height: var(--size);
15+
border-radius: var(--size);
16+
background-color: #ffd700;
17+
animation: wave 2s infinite ease-in-out;
18+
}
19+
20+
@keyframes wave {
21+
25% {
22+
height: calc(var(--size) * 5);
23+
background-color: #fc00ff;
24+
}
25+
26+
50% {
27+
height: var(--size);
28+
background-color: #9c73f8;
29+
}
30+
}
31+
32+
.loader :nth-child(2) {
33+
animation-delay: 0.2s;
34+
}
35+
36+
.loader :nth-child(3) {
37+
animation-delay: 0.4s;
38+
}
39+
40+
.loader :nth-child(4) {
41+
animation-delay: 0.6s;
42+
}
43+
44+
.loader :nth-child(5) {
45+
animation-delay: 0.8s;
46+
}

client/src/components/WorkflowList/WorkflowList.jsx

Lines changed: 46 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,56 +2,77 @@ import { useState } from 'react';
22
import { Link, useNavigate } from 'react-router-dom';
33
import { useDispatch, useSelector } from 'react-redux';
44
import styles from './WorkflowList.module.css';
5-
import WorkflowStatusPill from '../WorkflowStatusPill/WorkflowStatusPill.jsx';
5+
import WorkflowStatusPill from './WorkflowStatusPill/WorkflowStatusPill.jsx';
66
import Loader from '../Loader/Loader.jsx';
77
import dropdownSvg from '../../assets/img/dropdown.svg';
8-
import { ROUTE, WorkflowItemsInteractionType } from '../../constants.js';
8+
import { ROUTE, WorkflowItemsInteractionType, WorkflowStatus } from '../../constants.js';
99
import textContent from '../../assets/text.json';
1010
import { api } from '../../api';
1111
import { cancelTriggeredWorkflow, updateWorkflowDefinitions } from '../../store/actions';
12+
import StatusLoader from './StatusLoader/StatusLoader.jsx';
1213

1314
const WorkflowList = ({ items, interactionType, isLoading }) => {
1415
const dispatch = useDispatch();
1516
const navigate = useNavigate();
1617
const workflows = useSelector(state => state.workflows.workflows);
17-
const [isOptionsOpen, setOptionsOpen] = useState(false);
18-
const [dropdownIdx, setDropdownIdx] = useState(null);
18+
const [loadingWorkflow, setLoadingWorkflow] = useState({ id: '', isLoading: false });
19+
const [dropdownOptions, setDropdownOptions] = useState({ id: '', isOpen: false });
1920

2021
const handleFocusDropdown = idx => {
2122
setTimeout(() => {
22-
setDropdownIdx(idx);
23-
setOptionsOpen(true);
23+
setDropdownOptions({ id: idx, isOpen: true });
2424
}, 120);
2525
};
2626

2727
const handleBlurDropdown = () => {
2828
setTimeout(() => {
29-
setDropdownIdx(null);
30-
setOptionsOpen(false);
29+
setDropdownOptions({ id: '', isOpen: false });
3130
}, 100);
3231
};
3332

3433
const handleUpdateWorkflowStatus = async workflow => {
34+
setLoadingWorkflow({ id: workflow.id, isLoading: true });
3535
const { data: workflowInstance } = await api.workflows.getWorkflowInstance(workflow);
36-
if (workflowInstance.instanceState === workflow.instanceState) return;
3736

38-
const updatedWorkflows = workflows.map(workflowDefinition => {
39-
if (workflowDefinition.id === workflow.id) {
40-
return { ...workflowDefinition, instanceState: workflowInstance.instanceState };
41-
}
42-
return { ...workflowDefinition };
43-
});
37+
if (workflowInstance.instanceState !== workflow.instanceState) {
38+
const updatedWorkflows = workflows.map(w => {
39+
if (w.id !== workflow.id) return { ...w };
40+
return { ...w, instanceState: workflowInstance.instanceState };
41+
});
42+
dispatch(updateWorkflowDefinitions(updatedWorkflows));
43+
}
4444

45-
dispatch(updateWorkflowDefinitions(updatedWorkflows));
46-
setOptionsOpen(false);
45+
setLoadingWorkflow({ id: '', isLoading: false });
46+
setDropdownOptions({ id: '', isOpen: false });
4747
};
4848

4949
const handleCancelWorkflow = async workflow => {
50+
setLoadingWorkflow({ id: workflow.id, isLoading: true });
5051
const { status } = await api.workflows.cancelWorkflowInstance(workflow);
51-
if (status !== 200) return;
52+
if (status !== 200) {
53+
setLoadingWorkflow({ id: '', isLoading: false });
54+
return;
55+
}
56+
57+
const updatedWorkflows = await Promise.all(
58+
workflows.map(async w => {
59+
if (w.id !== workflow.id) return { ...w };
60+
61+
const { data } = await api.workflows.getWorkflowInstances(workflow.id);
62+
const relevantInstanceState = data.length > 0 ? data[data.length - 1].instanceState : WorkflowStatus.NotRun;
63+
return {
64+
...workflow,
65+
instanceState: relevantInstanceState,
66+
};
67+
})
68+
);
5269

70+
// // Update workflow statuses
71+
dispatch(updateWorkflowDefinitions(updatedWorkflows));
5372
dispatch(cancelTriggeredWorkflow(workflow.id));
54-
setOptionsOpen(false);
73+
74+
setLoadingWorkflow({ id: '', isLoading: false });
75+
setDropdownOptions({ id: '', isOpen: false });
5576
};
5677

5778
const listStyles = {
@@ -109,7 +130,11 @@ const WorkflowList = ({ items, interactionType, isLoading }) => {
109130
{items.map((item, idx) => (
110131
<div key={`${item.name}${idx}`} className="list-group-item list-group-item-action">
111132
<div style={{ display: 'flex', flexDirection: 'row', gap: '16px' }}>
112-
<WorkflowStatusPill status={item.instanceState} />
133+
{loadingWorkflow.isLoading && loadingWorkflow.id === item.id ? (
134+
<StatusLoader />
135+
) : (
136+
<WorkflowStatusPill status={item.instanceState} />
137+
)}
113138
<h4>{WorkflowItemsInteractionType.TRIGGER ? item.name : item.instanceName}</h4>
114139
</div>
115140
<p>{item.type}</p>
@@ -139,7 +164,7 @@ const WorkflowList = ({ items, interactionType, isLoading }) => {
139164
</button>
140165
<div
141166
className={`dropdown-menu dropdown-menu-right ${styles.dropdownMenu}`}
142-
style={isOptionsOpen && dropdownIdx === idx ? { display: 'block' } : {}}
167+
style={dropdownOptions.isOpen && dropdownOptions.id === idx ? { display: 'block' } : {}}
143168
>
144169
<a
145170
className={`dropdown-item ${styles.dropdownItem}`}

client/src/components/WorkflowList/WorkflowList.module.css

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,6 @@
132132
}
133133

134134
.dropdownItem {
135-
cursor: pointer;
136135
height: 100%;
137136
width: 100%;
138137
max-height: 32px;
@@ -141,6 +140,11 @@
141140
background-color: var(--white-main);
142141
}
143142

143+
.dropdownItem:hover {
144+
cursor: pointer;
145+
background-color: var(--blue-light);
146+
}
147+
144148
.dropdownItem:active {
145149
background-color: var(--primary-main);
146150
}

client/src/components/WorkflowStatusPill/WorkflowStatusPill.jsx renamed to client/src/components/WorkflowList/WorkflowStatusPill/WorkflowStatusPill.jsx

File renamed without changes.

0 commit comments

Comments
 (0)