Skip to content

Commit 55cd8aa

Browse files
Merge pull request #21 from docusign/added-embedding-of-workflow
Added embedding of maestro workflow
2 parents 30cc6b5 + 225ac84 commit 55cd8aa

File tree

10 files changed

+105
-50
lines changed

10 files changed

+105
-50
lines changed

client/src/assets/text.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,9 @@
7878
},
7979
"popups": {
8080
"workflowTriggered": {
81-
"title": "Workflow triggered",
82-
"description": "To complete the workflow steps, select Continue"
81+
"title": "Incompatible workflow",
82+
"descriptiona": "See and redirect the user back to the workflows page",
83+
"description": "See <a href='https://developers.docusign.com/docs/maestro-api/maestro101/embed-workflow/#embedded-workflow-instance-recommendations-and-restrictions' target='_blank'>Embedded workflow instance recommendations and restrictions</a> and redirect the user back to the workflows page"
8384
}
8485
},
8586
"buttons": {
@@ -99,4 +100,4 @@
99100
"createsandbox": "https://go.docusign.com/o/sandbox/",
100101
"learnmore": "https://developers.docusign.com/docs/maestro-api/"
101102
}
102-
}
103+
}

client/src/components/Popups/WorkflowTriggerResult/WorkflowTriggerResult.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ const WorkflowTriggerResult = ({ workflowInstanceUrl }) => {
2020
<div className={styles.popupContainer}>
2121
<img src={imgSuccess} alt="" />
2222
<h2>{textContent.popups.workflowTriggered.title}</h2>
23-
<p>{textContent.popups.workflowTriggered.description}</p>
23+
<p className={styles.popupMessageContainer} dangerouslySetInnerHTML={{ __html: textContent.popups.workflowTriggered.description }}></p>
2424
<a href={workflowInstanceUrl} target="_blank" rel="noreferrer" onClick={handleFinishTrigger}>
2525
{textContent.buttons.continue}
2626
</a>
27-
</div>
27+
</div >
2828
);
2929
};
3030
const WorkflowTriggerResultPopup = withPopup(WorkflowTriggerResult);

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

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,30 @@
5252
border: 1px solid var(--black-extraextralight);
5353
}
5454

55+
.popupMessageContainer {
56+
width: 100%;
57+
height: 55px;
58+
}
59+
60+
.popupMessageContainer a {
61+
color: #646cff;
62+
text-decoration: inherit;
63+
background-color: white;
64+
text-align: center;
65+
margin: 1rem 0 2rem 0;
66+
width: 80%;
67+
font-size: 16px;
68+
font-weight: 430;
69+
padding: 0;
70+
}
71+
72+
.popupMessageContainer a:hover {
73+
color: #535bf2;
74+
background-color: white;
75+
}
76+
5577
.popupContainer span {
5678
margin: 1rem;
5779
font-family: 'Courier New', Courier, monospace;
5880
font-size: 10px;
59-
}
81+
}

client/src/components/TriggerForm/TriggerForm.jsx

Lines changed: 40 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { useDispatch, useSelector } from 'react-redux';
44
import styles from './TriggerForm.module.css';
55
import WorkflowTriggerResultPopup from '../Popups/WorkflowTriggerResult/WorkflowTriggerResult.jsx';
66
import { triggerForm, buttons } from '../../assets/text.json';
7-
import { ROUTE, TemplateType } from '../../constants.js';
7+
import { ROUTE, TemplateType, WorkflowTriggerResponse } from '../../constants.js';
88
import { api } from '../../api';
99
import { openPopupWindow, closePopupWindow, updateWorkflowDefinitions } from '../../store/actions';
1010

@@ -49,7 +49,13 @@ const TriggerForm = ({ workflowId, templateType }) => {
4949
case "-":
5050
try {
5151
api.workflows.getWorkflowTriggerRequirements(workflowId).then(data => {
52-
setRelevantFormFields(generateDynamicForm(data.data.trigger_input_schema, 'Custom'));
52+
const result = Object.values(data.data.trigger_input_schema)
53+
.filter(entry => entry.field_name !== "startDate")
54+
.map(entry => ({
55+
field_name: entry.field_name,
56+
}));
57+
58+
setRelevantFormFields(generateDynamicForm(result, 'Custom'));
5359
});
5460
} catch (error) {
5561
console.error("Failed to fetch trigger requirements:", error);
@@ -92,44 +98,50 @@ const TriggerForm = ({ workflowId, templateType }) => {
9298

9399
setDataSending(true);
94100

95-
if(!relevantFormFields.length) {
101+
if (!relevantFormFields.length) {
96102
body = {};
97103
}
98104

99105
const { data: triggeredWorkflow } = await api.workflows.triggerWorkflow(workflowId, templateType, body);
100106
setWorkflowInstanceUrl(triggeredWorkflow.instance_url);
101107

102-
// Update workflowDefinitions. "...workflow" creates new workflow-object to avoid mutation in redux
103-
const updatedWorkflowDefinitions = workflows.map(w => {
104-
if (w.id !== workflowId) return { ...w };
105-
106-
return {
107-
...w,
108-
instanceId: triggeredWorkflow.instanceId,
109-
isTriggered: true,
110-
};
111-
});
108+
if (triggeredWorkflow.instance_url !== undefined) {
109+
navigate(`${ROUTE.TRIGGERFORM}/${workflowId}?type=${templateType}&triggerUrl=${encodeURIComponent(triggeredWorkflow.instance_url)}`)
110+
}
112111

113-
dispatch(updateWorkflowDefinitions(updatedWorkflowDefinitions));
114-
setDataSending(false);
115-
dispatch(openPopupWindow());
112+
if (triggeredWorkflow === WorkflowTriggerResponse.TRIGGER_ISSUE) {
113+
// Update workflowDefinitions. "...workflow" creates new workflow-object to avoid mutation in redux
114+
const updatedWorkflowDefinitions = workflows.map(w => {
115+
if (w.id !== workflowId) return { ...w };
116+
117+
return {
118+
...w,
119+
instanceId: triggeredWorkflow.instanceId,
120+
isTriggered: true,
121+
};
122+
});
123+
124+
dispatch(updateWorkflowDefinitions(updatedWorkflowDefinitions));
125+
setDataSending(false);
126+
dispatch(openPopupWindow());
127+
}
116128
};
117129

118130
if (!relevantFormFields.length)
119131
return (
120132
<div className={styles.formContainer}>
121-
<h2>{triggerForm.formTitleWithoutInputs}</h2>
122-
123-
<form className={styles.triggerForm} onSubmit={handleSubmit}>
124-
<button className="btn btn-primary" type="submit" disabled={isDataSending}>
125-
<span className="sr-only">{buttons.triggerWorkflow}</span>
126-
{isDataSending ? <span className="spinner-border spinner-border-sm" /> : null}
127-
</button>
128-
</form>
129-
{isPopupOpened && (
130-
<WorkflowTriggerResultPopup workflowInstanceUrl={workflowInstanceUrl} togglePopup={handleCloseTriggerPopup} />
131-
)}
132-
</div>
133+
<h2>{triggerForm.formTitleWithoutInputs}</h2>
134+
135+
<form className={styles.triggerForm} onSubmit={handleSubmit}>
136+
<button className="btn btn-primary" type="submit" disabled={isDataSending}>
137+
<span className="sr-only">{buttons.triggerWorkflow}</span>
138+
{isDataSending ? <span className="spinner-border spinner-border-sm" /> : null}
139+
</button>
140+
</form>
141+
{isPopupOpened && (
142+
<WorkflowTriggerResultPopup workflowInstanceUrl={workflowInstanceUrl} togglePopup={handleCloseTriggerPopup} />
143+
)}
144+
</div>
133145
);
134146

135147
return (

client/src/constants.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ export const WorkflowItemsInteractionType = {
1313
TRIGGER: 'Trigger',
1414
};
1515

16+
export const WorkflowTriggerResponse = {
17+
TRIGGER_ISSUE: 'Incompatible workflow',
18+
};
19+
1620
export const TemplateType = {
1721
I9: { name: 'Maestro: I-9', type: 'I-9 document' },
1822
OFFER: { name: 'Maestro: Offer Letter', type: 'Offer letter' },

client/src/pages/TriggerWorkflowForm/TriggerWorkflowForm.jsx

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,28 @@ const TriggerWorkflowForm = () => {
1515
const location = useLocation();
1616
const searchParams = new URLSearchParams(location.search);
1717
const type = searchParams.get('type');
18+
const triggerUrl = searchParams.get('triggerUrl');
19+
20+
if (triggerUrl !== null) {
21+
return (
22+
<div className="page-box">
23+
<Header />
24+
<div className={styles.contentContainer}>
25+
<WorkflowDescription
26+
title={textContent.pageTitles.completeWorkflow}
27+
behindTheScenesComponent={<TriggerBehindTheScenes />}
28+
backRoute={ROUTE.TRIGGER}
29+
/>
30+
31+
<div className={styles.formContainer}>
32+
<iframe src={triggerUrl} width="800" height="600">
33+
</iframe>
34+
</div>
35+
</div>
36+
<Footer withContent={false} />
37+
</div>
38+
);
39+
}
1840

1941
return (
2042
<div className="page-box">

server/constants.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,16 @@ const METHOD = {
1414
ACG: 'grand-auth',
1515
};
1616

17+
const ISSUES = {
18+
TRIGGER_ISSUE: 'Incompatible workflow',
19+
};
20+
1721
const MAESTRO_SCOPES = ['signature', 'aow_manage', 'impersonation'];
1822

1923
module.exports = {
2024
scopes: MAESTRO_SCOPES,
2125
BACKEND_ROUTE,
2226
TEMPLATE_TYPE,
2327
METHOD,
28+
ISSUES,
2429
};

server/controllers/workflowsController.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const docusign = require('docusign-esign');
1515
const config = require('../config');
1616
const WorkflowsService = require('../services/workflowsService');
1717
const createPrefixedLogger = require('../utils/logger');
18-
const { getPayloadBySchema } = require('../utils/utils');
18+
const { ISSUES } = require('../constants');
1919

2020
const oAuth = docusign.ApiClient.OAuth;
2121
const restApi = docusign.ApiClient.RestApi;
@@ -76,11 +76,10 @@ class WorkflowsController {
7676

7777
try {
7878
const triggerRequirements = await WorkflowsService.getWorkflowTriggerRequirements(args);
79-
const payload = getPayloadBySchema(body, triggerRequirements.trigger_input_schema);
80-
const result = await WorkflowsService.triggerWorkflowInstance(args, payload, triggerRequirements);
79+
const result = await WorkflowsService.triggerWorkflowInstance(args, body, triggerRequirements);
8180
res.status(200).send(result);
8281
} catch (error) {
83-
this.handleErrorResponse(error, res);
82+
res.status(200).send(ISSUES.TRIGGER_ISSUE);
8483
}
8584
};
8685

server/services/workflowsService.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class WorkflowsService {
2929
static triggerWorkflowInstance = async (args, payload, triggerRequirements) => {
3030
const api = initMaestroApi(args.accountId, args.basePath, args.accessToken);
3131
const triggerPayload = {
32-
instance_name: '',
32+
instance_name: 'test',
3333
trigger_inputs: payload,
3434
};
3535
const triggerResponse = await api.triggerWorkflow(triggerPayload, triggerRequirements.trigger_http_config.url);

server/utils/utils.js

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,4 @@ const extractPortFromUrl = url => {
1515
return null;
1616
};
1717

18-
const getPayloadBySchema = (data, schema) => {
19-
return schema.reduce((acc, field) => {
20-
const fieldName = field.field_name;
21-
if (fieldName in data) {
22-
acc[fieldName] = data[fieldName];
23-
}
24-
return acc;
25-
}, {});
26-
};
27-
28-
module.exports = { getParameterValueFromUrl, extractPortFromUrl, getPayloadBySchema };
18+
module.exports = { getParameterValueFromUrl, extractPortFromUrl };

0 commit comments

Comments
 (0)