@haiiro/docuflow 0.0.16 → 0.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -2
- package/manifest.json +34 -19
- package/package.json +1 -1
- package/public/app/docflow-app.js +5 -5
- package/src/front-components/docflow-documents.front-component.mjs +1 -1
- package/src/front-components/docflow-processes.front-component.mjs +35 -35
- package/src/front-components/docflow-processes.front-component.tsx +187 -85
- package/src/front-components/docflow-tasks.front-component.mjs +24 -24
- package/src/front-components/launch-process.front-component.mjs +19 -19
- package/src/front-components/launch-process.front-component.tsx +36 -60
- package/src/front-components/process-steps.front-component.mjs +17 -17
- package/src/front-components/task-form.front-component.mjs +10 -10
- package/src/logic-functions/bitrix-app.logic-function.mjs +1 -1
- package/src/logic-functions/complete-task.logic-function.mjs +39 -8
- package/src/logic-functions/docflow-app.logic-function.mjs +1 -1
- package/src/logic-functions/hand-out-form-step.logic-function.mjs +71284 -11217
- package/src/logic-functions/hand-out-form-step.logic-function.ts +6 -1
- package/src/logic-functions/launch-process.logic-function.mjs +269 -33
- package/src/logic-functions/launch-process.logic-function.ts +42 -37
- package/src/logic-functions/on-task-updated.logic-function.mjs +39 -8
- package/src/logic-functions/on-workflow-run-updated.logic-function.mjs +48 -9
- package/src/logic-functions/on-workflow-run-updated.logic-function.ts +18 -3
- package/src/logic-functions/process-catalog.logic-function.mjs +119726 -0
- package/src/logic-functions/process-catalog.logic-function.ts +84 -0
- package/src/logic-functions/publish-process.logic-function.mjs +218 -16
- package/src/logic-functions/publish-process.logic-function.ts +13 -5
- package/src/logic-functions/save-launch-fields.logic-function.mjs +5 -2
- package/src/logic-functions/save-step-settings.logic-function.mjs +5 -2
|
@@ -59485,12 +59485,16 @@ var readUserMessage = (value) => {
|
|
|
59485
59485
|
}
|
|
59486
59486
|
return void 0;
|
|
59487
59487
|
};
|
|
59488
|
+
var isMissingGraphqlField = (error) => error instanceof CoreGraphqlError && /Cannot query field|Unknown type/i.test(error.message);
|
|
59488
59489
|
var callCoreGraphql = async ({
|
|
59489
59490
|
query,
|
|
59490
|
-
variables
|
|
59491
|
+
variables,
|
|
59492
|
+
runAs = "person"
|
|
59491
59493
|
}) => {
|
|
59492
59494
|
const apiUrl = process.env.TWENTY_API_URL;
|
|
59493
|
-
const
|
|
59495
|
+
const personToken = process.env.TWENTY_APP_ACCESS_TOKEN;
|
|
59496
|
+
const applicationToken = process.env.TWENTY_APP_APPLICATION_ACCESS_TOKEN;
|
|
59497
|
+
const token = runAs === "person" ? personToken ?? applicationToken : applicationToken ?? personToken;
|
|
59494
59498
|
if (apiUrl === void 0 || token === void 0) {
|
|
59495
59499
|
throw new CoreGraphqlError(
|
|
59496
59500
|
"TWENTY_API_URL or TWENTY_APP_ACCESS_TOKEN is not set",
|
|
@@ -59515,6 +59519,9 @@ var callCoreGraphql = async ({
|
|
|
59515
59519
|
}
|
|
59516
59520
|
return body.data;
|
|
59517
59521
|
};
|
|
59522
|
+
var SUBMIT_FORM_STEP_MUTATION = `mutation SubmitFormStep($input: SubmitFormStepInput!) {
|
|
59523
|
+
submitFormStep(input: $input)
|
|
59524
|
+
}`;
|
|
59518
59525
|
var ANSWER_TOOL_CALL_MUTATION = `mutation AnswerToolCall($input: AnswerToolCallInput!) {
|
|
59519
59526
|
answerToolCall(input: $input) { streamId }
|
|
59520
59527
|
}`;
|
|
@@ -59574,17 +59581,24 @@ var getFormStepAssignment = ({
|
|
|
59574
59581
|
now
|
|
59575
59582
|
)
|
|
59576
59583
|
});
|
|
59584
|
+
var getStepWaitKey = ({
|
|
59585
|
+
workflowRunId,
|
|
59586
|
+
stepId,
|
|
59587
|
+
stepInfo
|
|
59588
|
+
}) => typeof stepInfo?.threadId === "string" && stepInfo.threadId.length > 0 ? stepInfo.threadId : `${workflowRunId}.${stepId}`;
|
|
59589
|
+
var isStepWaitingForAnswer = (stepInfo) => stepInfo?.status === "PENDING" && (stepInfo.error === void 0 || stepInfo.error === null) && (typeof stepInfo.threadId === "string" && stepInfo.threadId.length > 0 || stepInfo.wait?.type === "CALLBACK");
|
|
59577
59590
|
|
|
59578
59591
|
// src/server/workflow-engine.ts
|
|
59579
59592
|
var answerFormStep = async ({
|
|
59580
59593
|
state,
|
|
59594
|
+
workflowRunId,
|
|
59581
59595
|
stepId,
|
|
59582
|
-
|
|
59596
|
+
waitKey,
|
|
59583
59597
|
values
|
|
59584
59598
|
}) => {
|
|
59585
59599
|
const step = state?.flow?.steps?.find((candidate) => candidate.id === stepId);
|
|
59586
59600
|
const stepInfo = state?.stepInfos?.[stepId];
|
|
59587
|
-
if (step === void 0 || !isFormStep(step) || stepInfo
|
|
59601
|
+
if (step === void 0 || !isFormStep(step) || !isStepWaitingForAnswer(stepInfo) || getStepWaitKey({ workflowRunId, stepId, stepInfo }) !== waitKey) {
|
|
59588
59602
|
return { status: "NOT_WAITING" };
|
|
59589
59603
|
}
|
|
59590
59604
|
const fields = resolveFormStepFields(
|
|
@@ -59608,10 +59622,26 @@ var answerFormStep = async ({
|
|
|
59608
59622
|
),
|
|
59609
59623
|
values
|
|
59610
59624
|
});
|
|
59611
|
-
|
|
59612
|
-
|
|
59613
|
-
|
|
59625
|
+
const threadId = stepInfo?.threadId;
|
|
59626
|
+
const submitFormStep = () => callCoreGraphql({
|
|
59627
|
+
query: SUBMIT_FORM_STEP_MUTATION,
|
|
59628
|
+
variables: { input: { stepId, workflowRunId, response } }
|
|
59614
59629
|
});
|
|
59630
|
+
if (typeof threadId === "string" && threadId.length > 0) {
|
|
59631
|
+
try {
|
|
59632
|
+
await callCoreGraphql({
|
|
59633
|
+
query: ANSWER_TOOL_CALL_MUTATION,
|
|
59634
|
+
variables: { input: { threadId, toolCallId: stepId, response } }
|
|
59635
|
+
});
|
|
59636
|
+
} catch (error) {
|
|
59637
|
+
if (!isMissingGraphqlField(error)) {
|
|
59638
|
+
throw error;
|
|
59639
|
+
}
|
|
59640
|
+
await submitFormStep();
|
|
59641
|
+
}
|
|
59642
|
+
} else {
|
|
59643
|
+
await submitFormStep();
|
|
59644
|
+
}
|
|
59615
59645
|
return { status: "ANSWERED" };
|
|
59616
59646
|
};
|
|
59617
59647
|
|
|
@@ -59625,8 +59655,9 @@ var answerStepOfTask = async (task, values) => {
|
|
|
59625
59655
|
try {
|
|
59626
59656
|
const result = await answerFormStep({
|
|
59627
59657
|
state: run?.state,
|
|
59658
|
+
workflowRunId: task.smbWorkflowRunId,
|
|
59628
59659
|
stepId: task.smbWorkflowStepId,
|
|
59629
|
-
|
|
59660
|
+
waitKey: task.smbWorkflowThreadId,
|
|
59630
59661
|
values
|
|
59631
59662
|
});
|
|
59632
59663
|
return result.status === "MISSING_REQUIRED" ? { status: "MISSING_REQUIRED", labels: result.labels } : void 0;
|
|
@@ -119321,13 +119321,18 @@ var xL = async (e3) => {
|
|
|
119321
119321
|
var getDocflowEngine = (value = process.env.DOCFLOW_ENGINE) => value === "FORK" ? "FORK" : "APP";
|
|
119322
119322
|
var isAppEngine = (value) => getDocflowEngine(value) === "APP";
|
|
119323
119323
|
|
|
119324
|
+
// src/shared/log.util.ts
|
|
119325
|
+
var PREFIX = "[docflow]";
|
|
119326
|
+
var logDocflow = (event, details) => console.info(PREFIX, event, details ?? "");
|
|
119327
|
+
|
|
119324
119328
|
// src/shared/docflow.constants.ts
|
|
119325
119329
|
var DOCFLOW_LAUNCH_PARAMETERS_KEY = "smbDocflowParameters";
|
|
119326
119330
|
var LAUNCH_PARAMETERS_STEP_INPUT = `{{trigger.${DOCFLOW_LAUNCH_PARAMETERS_KEY}}}`;
|
|
119327
|
-
var
|
|
119331
|
+
var DOCFLOW_LAUNCHED_BY_KEY = "smbDocflowLaunchedBy";
|
|
119328
119332
|
var TASK_DONE_STATUS = "DONE";
|
|
119329
119333
|
var FORM_FIELD_ROLE_SETTING = "smbRole";
|
|
119330
119334
|
var FORM_FIELD_DUE_IN_DAYS_SETTING = "smbDueInDays";
|
|
119335
|
+
var TRIGGER_STEP_ID = "trigger";
|
|
119331
119336
|
|
|
119332
119337
|
// src/shared/form/form-fields.util.ts
|
|
119333
119338
|
var getFormFieldRole = (field) => {
|
|
@@ -119340,8 +119345,7 @@ var parseFormFields = (value) => Array.isArray(value) ? value.filter(
|
|
|
119340
119345
|
) : [];
|
|
119341
119346
|
|
|
119342
119347
|
// src/shared/workflow/launch-step.util.ts
|
|
119343
|
-
var
|
|
119344
|
-
var isLaunchableTrigger = (trigger) => trigger?.type === "MANUAL" || isLaunchTrigger(trigger);
|
|
119348
|
+
var isLaunchableTrigger = (trigger) => trigger?.type === "MANUAL" || trigger?.type === "WEBHOOK";
|
|
119345
119349
|
|
|
119346
119350
|
// src/shared/workflow/workflow-run.util.ts
|
|
119347
119351
|
var DAY_IN_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -119398,7 +119402,26 @@ var getFormStepAssignment = ({
|
|
|
119398
119402
|
now
|
|
119399
119403
|
)
|
|
119400
119404
|
});
|
|
119405
|
+
var getStepWaitKey = ({
|
|
119406
|
+
workflowRunId,
|
|
119407
|
+
stepId,
|
|
119408
|
+
stepInfo
|
|
119409
|
+
}) => typeof stepInfo?.threadId === "string" && stepInfo.threadId.length > 0 ? stepInfo.threadId : `${workflowRunId}.${stepId}`;
|
|
119410
|
+
var isStepWaitingForAnswer = (stepInfo) => stepInfo?.status === "PENDING" && (stepInfo.error === void 0 || stepInfo.error === null) && (typeof stepInfo.threadId === "string" && stepInfo.threadId.length > 0 || stepInfo.wait?.type === "CALLBACK");
|
|
119411
|
+
var getRunStarterWorkspaceMemberId = ({
|
|
119412
|
+
createdByWorkspaceMemberId,
|
|
119413
|
+
state
|
|
119414
|
+
}) => {
|
|
119415
|
+
if (typeof createdByWorkspaceMemberId === "string" && createdByWorkspaceMemberId.length > 0) {
|
|
119416
|
+
return createdByWorkspaceMemberId;
|
|
119417
|
+
}
|
|
119418
|
+
const triggerResult = state?.stepInfos?.[TRIGGER_STEP_ID]?.result;
|
|
119419
|
+
return readWorkspaceMemberId(
|
|
119420
|
+
isPlainRecord(triggerResult) ? triggerResult[DOCFLOW_LAUNCHED_BY_KEY] : void 0
|
|
119421
|
+
);
|
|
119422
|
+
};
|
|
119401
119423
|
var getFormStepTaskRequests = ({
|
|
119424
|
+
workflowRunId,
|
|
119402
119425
|
state,
|
|
119403
119426
|
runStarterWorkspaceMemberId,
|
|
119404
119427
|
now
|
|
@@ -119406,9 +119429,13 @@ var getFormStepTaskRequests = ({
|
|
|
119406
119429
|
const steps = state?.flow?.steps ?? [];
|
|
119407
119430
|
const stepInfos = state?.stepInfos ?? {};
|
|
119408
119431
|
const isStartedByHand = isLaunchableTrigger(state?.flow?.trigger);
|
|
119432
|
+
const runStarterId = getRunStarterWorkspaceMemberId({
|
|
119433
|
+
createdByWorkspaceMemberId: runStarterWorkspaceMemberId,
|
|
119434
|
+
state
|
|
119435
|
+
});
|
|
119409
119436
|
return steps.flatMap((step) => {
|
|
119410
119437
|
const stepInfo = stepInfos[step.id];
|
|
119411
|
-
if (!isFormStep(step) || stepInfo
|
|
119438
|
+
if (!isFormStep(step) || !isStepWaitingForAnswer(stepInfo)) {
|
|
119412
119439
|
return [];
|
|
119413
119440
|
}
|
|
119414
119441
|
const fields = resolveFormStepFields(getFormStepFields(step), stepInfos);
|
|
@@ -119416,7 +119443,7 @@ var getFormStepTaskRequests = ({
|
|
|
119416
119443
|
fields,
|
|
119417
119444
|
now
|
|
119418
119445
|
});
|
|
119419
|
-
const fallbackAssigneeId = isStartedByHand ?
|
|
119446
|
+
const fallbackAssigneeId = isStartedByHand ? runStarterId : void 0;
|
|
119420
119447
|
const taskAssigneeId = assigneeWorkspaceMemberId ?? fallbackAssigneeId;
|
|
119421
119448
|
if (taskAssigneeId === void 0) {
|
|
119422
119449
|
return [];
|
|
@@ -119424,7 +119451,7 @@ var getFormStepTaskRequests = ({
|
|
|
119424
119451
|
return [
|
|
119425
119452
|
{
|
|
119426
119453
|
stepId: step.id,
|
|
119427
|
-
|
|
119454
|
+
waitKey: getStepWaitKey({ workflowRunId, stepId: step.id, stepInfo }),
|
|
119428
119455
|
title: step.name,
|
|
119429
119456
|
assigneeWorkspaceMemberId: taskAssigneeId,
|
|
119430
119457
|
dueAt,
|
|
@@ -119497,7 +119524,7 @@ var closeTasksOfAnsweredSteps = async (run) => {
|
|
|
119497
119524
|
let closedCount = 0;
|
|
119498
119525
|
for (const task of tasks) {
|
|
119499
119526
|
const stepInfo = typeof task.smbWorkflowStepId === "string" ? run.state?.stepInfos?.[task.smbWorkflowStepId] : void 0;
|
|
119500
|
-
if (stepInfo?.status !== "SUCCESS" ||
|
|
119527
|
+
if (typeof task.smbWorkflowStepId !== "string" || stepInfo?.status !== "SUCCESS" || getStepWaitKey({ workflowRunId: run.id, stepId: task.smbWorkflowStepId, stepInfo }) !== task.smbWorkflowThreadId) {
|
|
119501
119528
|
continue;
|
|
119502
119529
|
}
|
|
119503
119530
|
const answer = typeof stepInfo.result === "object" && stepInfo.result !== null ? stepInfo.result : {};
|
|
@@ -119524,9 +119551,11 @@ var handler = async (event) => {
|
|
|
119524
119551
|
}
|
|
119525
119552
|
const run = { ...event.properties.after, id: event.recordId };
|
|
119526
119553
|
if (run.status !== "RUNNING" || run.state === void 0 || run.state === null) {
|
|
119554
|
+
logDocflow("run updated: skipped", { workflowRunId: run.id, status: run.status, hasState: run.state != null });
|
|
119527
119555
|
return { skipped: "NOT_RUNNING" };
|
|
119528
119556
|
}
|
|
119529
119557
|
const requests = getFormStepTaskRequests({
|
|
119558
|
+
workflowRunId: run.id,
|
|
119530
119559
|
state: run.state,
|
|
119531
119560
|
runStarterWorkspaceMemberId: run.createdBy?.workspaceMemberId,
|
|
119532
119561
|
now: /* @__PURE__ */ new Date()
|
|
@@ -119538,14 +119567,24 @@ var handler = async (event) => {
|
|
|
119538
119567
|
payload: {
|
|
119539
119568
|
workflowRunId: run.id,
|
|
119540
119569
|
stepId: request.stepId,
|
|
119541
|
-
threadId:
|
|
119570
|
+
// The wait key travels as threadId: jobs queued by 0.0.16 and
|
|
119571
|
+
// earlier carry that name
|
|
119572
|
+
threadId: request.waitKey
|
|
119542
119573
|
},
|
|
119543
|
-
jobId: `hand-out-${request.
|
|
119574
|
+
jobId: `hand-out-${request.waitKey}`
|
|
119544
119575
|
})),
|
|
119545
119576
|
retryLimit: 2
|
|
119546
119577
|
});
|
|
119547
119578
|
}
|
|
119548
119579
|
const closedTaskCount = await closeTasksOfAnsweredSteps(run);
|
|
119580
|
+
logDocflow("run updated", {
|
|
119581
|
+
workflowRunId: run.id,
|
|
119582
|
+
queued: requests.map(({ stepId, waitKey }) => ({ stepId, waitKey })),
|
|
119583
|
+
closedTaskCount,
|
|
119584
|
+
stepStatuses: Object.fromEntries(
|
|
119585
|
+
Object.entries(run.state.stepInfos ?? {}).map(([stepId, info]) => [stepId, info?.status])
|
|
119586
|
+
)
|
|
119587
|
+
});
|
|
119549
119588
|
return { queuedTaskCount: requests.length, closedTaskCount };
|
|
119550
119589
|
};
|
|
119551
119590
|
var on_workflow_run_updated_logic_function_default = defineLogicFunction({
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
} from 'twenty-sdk/logic-function';
|
|
7
7
|
|
|
8
8
|
import { isAppEngine } from 'src/shared/engine';
|
|
9
|
+
import { logDocflow } from 'src/shared/log.util';
|
|
9
10
|
import { getFormStepTaskRequests } from 'src/shared/workflow/workflow-run.util';
|
|
10
11
|
import { closeTasksOfAnsweredSteps } from 'src/server/process-tasks';
|
|
11
12
|
import { type WorkflowRunRecord } from 'src/server/records';
|
|
@@ -16,7 +17,7 @@ import {
|
|
|
16
17
|
|
|
17
18
|
// Process tasks follow the run: a FORM step the run waits on becomes a CRM
|
|
18
19
|
// task, and a step answered elsewhere closes its task. Handing out is queued
|
|
19
|
-
// under the step's
|
|
20
|
+
// under the step's wait key, so repeated run updates create one task.
|
|
20
21
|
const handler = async (
|
|
21
22
|
event: DatabaseEventPayload<ObjectRecordUpdateEvent<WorkflowRunRecord>>,
|
|
22
23
|
) => {
|
|
@@ -27,10 +28,13 @@ const handler = async (
|
|
|
27
28
|
const run = { ...event.properties.after, id: event.recordId };
|
|
28
29
|
|
|
29
30
|
if (run.status !== 'RUNNING' || run.state === undefined || run.state === null) {
|
|
31
|
+
logDocflow('run updated: skipped', { workflowRunId: run.id, status: run.status, hasState: run.state != null });
|
|
32
|
+
|
|
30
33
|
return { skipped: 'NOT_RUNNING' };
|
|
31
34
|
}
|
|
32
35
|
|
|
33
36
|
const requests = getFormStepTaskRequests({
|
|
37
|
+
workflowRunId: run.id,
|
|
34
38
|
state: run.state,
|
|
35
39
|
runStarterWorkspaceMemberId: run.createdBy?.workspaceMemberId,
|
|
36
40
|
now: new Date(),
|
|
@@ -44,9 +48,11 @@ const handler = async (
|
|
|
44
48
|
payload: {
|
|
45
49
|
workflowRunId: run.id,
|
|
46
50
|
stepId: request.stepId,
|
|
47
|
-
threadId:
|
|
51
|
+
// The wait key travels as threadId: jobs queued by 0.0.16 and
|
|
52
|
+
// earlier carry that name
|
|
53
|
+
threadId: request.waitKey,
|
|
48
54
|
},
|
|
49
|
-
jobId: `hand-out-${request.
|
|
55
|
+
jobId: `hand-out-${request.waitKey}`,
|
|
50
56
|
})),
|
|
51
57
|
retryLimit: 2,
|
|
52
58
|
});
|
|
@@ -54,6 +60,15 @@ const handler = async (
|
|
|
54
60
|
|
|
55
61
|
const closedTaskCount = await closeTasksOfAnsweredSteps(run);
|
|
56
62
|
|
|
63
|
+
logDocflow('run updated', {
|
|
64
|
+
workflowRunId: run.id,
|
|
65
|
+
queued: requests.map(({ stepId, waitKey }) => ({ stepId, waitKey })),
|
|
66
|
+
closedTaskCount,
|
|
67
|
+
stepStatuses: Object.fromEntries(
|
|
68
|
+
Object.entries(run.state.stepInfos ?? {}).map(([stepId, info]) => [stepId, info?.status]),
|
|
69
|
+
),
|
|
70
|
+
});
|
|
71
|
+
|
|
57
72
|
return { queuedTaskCount: requests.length, closedTaskCount };
|
|
58
73
|
};
|
|
59
74
|
|