@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
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { defineLogicFunction } from 'twenty-sdk/define';
|
|
2
2
|
|
|
3
3
|
import { handOutFormStep } from 'src/server/process-tasks';
|
|
4
|
+
import { logDocflow } from 'src/shared/log.util';
|
|
4
5
|
import { HAND_OUT_FORM_STEP_LOGIC_FUNCTION_UNIVERSAL_IDENTIFIER } from 'src/universal-identifiers';
|
|
5
6
|
|
|
6
7
|
const handler = async (payload: {
|
|
@@ -18,7 +19,11 @@ const handler = async (payload: {
|
|
|
18
19
|
return { status: 'INVALID_PAYLOAD' };
|
|
19
20
|
}
|
|
20
21
|
|
|
21
|
-
|
|
22
|
+
const status = await handOutFormStep({ workflowRunId, stepId, waitKey: threadId });
|
|
23
|
+
|
|
24
|
+
logDocflow('hand out', { workflowRunId, stepId, status });
|
|
25
|
+
|
|
26
|
+
return { status };
|
|
22
27
|
};
|
|
23
28
|
|
|
24
29
|
export default defineLogicFunction({
|
|
@@ -1691,12 +1691,16 @@ var readUserMessage = (value) => {
|
|
|
1691
1691
|
}
|
|
1692
1692
|
return void 0;
|
|
1693
1693
|
};
|
|
1694
|
+
var isMissingGraphqlField = (error) => error instanceof CoreGraphqlError && /Cannot query field|Unknown type/i.test(error.message);
|
|
1694
1695
|
var callCoreGraphql = async ({
|
|
1695
1696
|
query,
|
|
1696
|
-
variables
|
|
1697
|
+
variables,
|
|
1698
|
+
runAs = "person"
|
|
1697
1699
|
}) => {
|
|
1698
1700
|
const apiUrl = process.env.TWENTY_API_URL;
|
|
1699
|
-
const
|
|
1701
|
+
const personToken = process.env.TWENTY_APP_ACCESS_TOKEN;
|
|
1702
|
+
const applicationToken = process.env.TWENTY_APP_APPLICATION_ACCESS_TOKEN;
|
|
1703
|
+
const token = runAs === "person" ? personToken ?? applicationToken : applicationToken ?? personToken;
|
|
1700
1704
|
if (apiUrl === void 0 || token === void 0) {
|
|
1701
1705
|
throw new CoreGraphqlError(
|
|
1702
1706
|
"TWENTY_API_URL or TWENTY_APP_ACCESS_TOKEN is not set",
|
|
@@ -1724,6 +1728,27 @@ var callCoreGraphql = async ({
|
|
|
1724
1728
|
var RUN_WORKFLOW_VERSION_MUTATION = `mutation RunWorkflowVersion($input: RunWorkflowVersionInput!) {
|
|
1725
1729
|
runWorkflowVersion(input: $input) { workflowRunId }
|
|
1726
1730
|
}`;
|
|
1731
|
+
var CORE_WORKFLOWS_QUERY = `query CoreWorkflows($first: Int!, $after: String) {
|
|
1732
|
+
coreWorkflows(first: $first, after: $after) {
|
|
1733
|
+
pageInfo { hasNextPage endCursor }
|
|
1734
|
+
edges { node { id name updatedAt workspaceWorkflowId lastPublishedCoreWorkflowVersionId statuses } }
|
|
1735
|
+
}
|
|
1736
|
+
}`;
|
|
1737
|
+
var CORE_WORKFLOWS_WITH_CURRENT_VERSIONS_QUERY = `query CoreWorkflowsWithCurrentVersions($input: CoreWorkflowsWithCurrentVersionsInput!) {
|
|
1738
|
+
coreWorkflowsWithCurrentVersions(input: $input) {
|
|
1739
|
+
workflow { id }
|
|
1740
|
+
currentVersion { id status createdAt trigger steps workspaceWorkflowVersionId }
|
|
1741
|
+
versions { id status createdAt workspaceWorkflowVersionId }
|
|
1742
|
+
}
|
|
1743
|
+
}`;
|
|
1744
|
+
var CORE_WORKFLOW_VERSION_BY_ID_QUERY = `query CoreWorkflowVersionById($coreWorkflowVersionId: UUID!) {
|
|
1745
|
+
coreWorkflowVersionById(coreWorkflowVersionId: $coreWorkflowVersionId) {
|
|
1746
|
+
id status createdAt trigger steps workspaceWorkflowVersionId
|
|
1747
|
+
}
|
|
1748
|
+
}`;
|
|
1749
|
+
var RUN_CORE_WORKFLOW_VERSION_MUTATION = `mutation RunCoreWorkflowVersion($input: RunCoreWorkflowVersionInput!) {
|
|
1750
|
+
runCoreWorkflowVersion(input: $input) { workflowRunId }
|
|
1751
|
+
}`;
|
|
1727
1752
|
|
|
1728
1753
|
// src/shared/api/object-summaries.ts
|
|
1729
1754
|
import { MetadataApiClient } from "twenty-client-sdk/metadata";
|
|
@@ -1774,6 +1799,14 @@ var readDataValue = (response) => {
|
|
|
1774
1799
|
}
|
|
1775
1800
|
return Object.values(data)[0];
|
|
1776
1801
|
};
|
|
1802
|
+
var readRestList = (response) => {
|
|
1803
|
+
const value = readDataValue(response);
|
|
1804
|
+
return {
|
|
1805
|
+
records: Array.isArray(value) ? value : [],
|
|
1806
|
+
pageInfo: response?.pageInfo ?? {},
|
|
1807
|
+
totalCount: response?.totalCount
|
|
1808
|
+
};
|
|
1809
|
+
};
|
|
1777
1810
|
var readRestRecord = (response) => {
|
|
1778
1811
|
const value = readDataValue(response);
|
|
1779
1812
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
@@ -1785,6 +1818,7 @@ var DOCFLOW_LAUNCH_PARAMETERS_KEY = "smbDocflowParameters";
|
|
|
1785
1818
|
var LAUNCH_PARAMETERS_STEP_INPUT = `{{trigger.${DOCFLOW_LAUNCH_PARAMETERS_KEY}}}`;
|
|
1786
1819
|
var LAUNCH_TRIGGER_NAME = "\u0417\u0430\u043F\u0443\u0441\u043A \u0441 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u0430\u043C\u0438";
|
|
1787
1820
|
var LAUNCH_RECORD_KEY = "record";
|
|
1821
|
+
var DOCFLOW_LAUNCHED_BY_KEY = "smbDocflowLaunchedBy";
|
|
1788
1822
|
var LAUNCH_RECORDS_LIMIT = 50;
|
|
1789
1823
|
var FORM_FIELD_REQUIRED_SETTING = "smbIsRequired";
|
|
1790
1824
|
var FORM_FIELD_ROLE_SETTING = "smbRole";
|
|
@@ -1823,7 +1857,17 @@ var parseFormFields = (value) => Array.isArray(value) ? value.filter(
|
|
|
1823
1857
|
) : [];
|
|
1824
1858
|
|
|
1825
1859
|
// src/shared/workflow/launch-step.util.ts
|
|
1860
|
+
var isPlainRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1826
1861
|
var isLaunchTrigger = (trigger) => trigger?.type === "WEBHOOK" && trigger.name === LAUNCH_TRIGGER_NAME;
|
|
1862
|
+
var parseExpectedBodyFields = (trigger) => {
|
|
1863
|
+
const expectedBody = trigger?.type === "WEBHOOK" ? trigger.settings?.expectedBody : void 0;
|
|
1864
|
+
if (!isPlainRecord(expectedBody)) {
|
|
1865
|
+
return [];
|
|
1866
|
+
}
|
|
1867
|
+
return Object.entries(expectedBody).flatMap(
|
|
1868
|
+
([name, sample]) => name === LAUNCH_RECORD_KEY || name.startsWith("smbDocflow") || isPlainRecord(sample) || Array.isArray(sample) ? [] : [{ id: `body-${name}`, name, label: name, type: typeof sample === "number" ? "NUMBER" : "TEXT" }]
|
|
1869
|
+
);
|
|
1870
|
+
};
|
|
1827
1871
|
var parseLaunchFields = (value) => getFillableFormFields(parseFormFields(value));
|
|
1828
1872
|
var parseLaunchObject = (value) => typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
1829
1873
|
var buildLaunchParameters = ({
|
|
@@ -119313,6 +119357,8 @@ var VI2 = /* @__PURE__ */ (function(e3) {
|
|
|
119313
119357
|
return e3.OK = "OK", e3.SUCCESS = "SUCCESS", e3.INFO = "INFO", e3.WARNING = "WARNING", e3.ERROR = "ERROR", e3.NEUTRAL = "NEUTRAL", e3.UNKNOWN = "UNKNOWN", e3;
|
|
119314
119358
|
})({});
|
|
119315
119359
|
Object.values(VI2).filter((e3) => e3 !== VI2.OK && e3 !== VI2.UNKNOWN), W2.TEXT, W2.ARRAY, W2.BOOLEAN, W2.DATE, W2.DATE_TIME, W2.NUMBER, W2.NUMERIC, W2.RAW_JSON, W2.RICH_TEXT, W2.SELECT, W2.MULTI_SELECT, kF2.SEND_EMAIL, kF2.DRAFT_EMAIL, kF2.CREATE_CALENDAR_EVENT;
|
|
119360
|
+
var HI2 = "TWENTY_API_URL";
|
|
119361
|
+
var UI2 = "TWENTY_APP_APPLICATION_ACCESS_TOKEN";
|
|
119316
119362
|
hp2.map((e3) => mp2[e3]);
|
|
119317
119363
|
var WI2 = {
|
|
119318
119364
|
universalIdentifier: Wl2(),
|
|
@@ -119445,6 +119491,27 @@ fd2({
|
|
|
119445
119491
|
message: e4.message
|
|
119446
119492
|
});
|
|
119447
119493
|
});
|
|
119494
|
+
var XI2 = () => process.env.TWENTY_APP_APPLICATION_ACCESS_TOKEN ?? process.env.TWENTY_APP_ACCESS_TOKEN;
|
|
119495
|
+
var ZI = async ({ query: e3, variables: t4, caller: n4 }) => {
|
|
119496
|
+
let r4 = process.env[HI2], i5 = XI2();
|
|
119497
|
+
if (!r4 || !i5) throw Error(`${n4}() requires the app runtime env vars ${HI2} and ${UI2}.`);
|
|
119498
|
+
let a5 = await fetch(`${r4}/metadata`, {
|
|
119499
|
+
method: "POST",
|
|
119500
|
+
headers: {
|
|
119501
|
+
"Content-Type": "application/json",
|
|
119502
|
+
Authorization: `Bearer ${i5}`
|
|
119503
|
+
},
|
|
119504
|
+
body: JSON.stringify({
|
|
119505
|
+
query: e3,
|
|
119506
|
+
variables: t4
|
|
119507
|
+
})
|
|
119508
|
+
});
|
|
119509
|
+
if (!a5.ok) throw Error(`${n4}() failed: HTTP ${a5.status} ${a5.statusText}`);
|
|
119510
|
+
let o5 = await a5.json();
|
|
119511
|
+
if (o5.errors && o5.errors.length > 0) throw Error(`${n4}() failed: ${o5.errors.map((e4) => e4.message).join(", ")}`);
|
|
119512
|
+
if (!o5.data) throw Error(`${n4}() failed: response contained no data.`);
|
|
119513
|
+
return o5.data;
|
|
119514
|
+
};
|
|
119448
119515
|
var aL = "\n id\n handle\n displayName\n visibility\n connectedAccountId\n isSyncEnabled\n";
|
|
119449
119516
|
var oL = `
|
|
119450
119517
|
mutation CreateAppMessageChannel($input: CreateAppMessageChannelInput!) {
|
|
@@ -119474,6 +119541,45 @@ var fL = `
|
|
|
119474
119541
|
}
|
|
119475
119542
|
}
|
|
119476
119543
|
`;
|
|
119544
|
+
var TL = "\n query GetAppKeyValue($key: String!, $scope: AppKeyValueScope) {\n appKeyValue(key: $key, scope: $scope) {\n key\n value\n scope\n }\n }\n";
|
|
119545
|
+
var EL = "\n mutation SetAppKeyValue($input: SetAppKeyValueInput!) {\n setAppKeyValue(input: $input) {\n key\n value\n scope\n }\n }\n";
|
|
119546
|
+
var DL = "\n mutation DeleteAppKeyValue($key: String!, $scope: AppKeyValueScope) {\n deleteAppKeyValue(key: $key, scope: $scope)\n }\n";
|
|
119547
|
+
var OL = "WORKSPACE";
|
|
119548
|
+
var kL = {
|
|
119549
|
+
async get(e3, t4) {
|
|
119550
|
+
let { appKeyValue: n4 } = await ZI({
|
|
119551
|
+
query: TL,
|
|
119552
|
+
variables: {
|
|
119553
|
+
key: e3,
|
|
119554
|
+
scope: t4?.scope ?? OL
|
|
119555
|
+
},
|
|
119556
|
+
caller: "kv.get"
|
|
119557
|
+
});
|
|
119558
|
+
return n4?.value ?? null;
|
|
119559
|
+
},
|
|
119560
|
+
async set(e3, t4, n4) {
|
|
119561
|
+
await ZI({
|
|
119562
|
+
query: EL,
|
|
119563
|
+
variables: { input: {
|
|
119564
|
+
key: e3,
|
|
119565
|
+
value: t4,
|
|
119566
|
+
scope: n4?.scope ?? OL
|
|
119567
|
+
} },
|
|
119568
|
+
caller: "kv.set"
|
|
119569
|
+
});
|
|
119570
|
+
},
|
|
119571
|
+
async delete(e3, t4) {
|
|
119572
|
+
let { deleteAppKeyValue: n4 } = await ZI({
|
|
119573
|
+
query: DL,
|
|
119574
|
+
variables: {
|
|
119575
|
+
key: e3,
|
|
119576
|
+
scope: t4?.scope ?? OL
|
|
119577
|
+
},
|
|
119578
|
+
caller: "kv.delete"
|
|
119579
|
+
});
|
|
119580
|
+
return n4;
|
|
119581
|
+
}
|
|
119582
|
+
};
|
|
119477
119583
|
var AL = class {
|
|
119478
119584
|
constructor(e3, t4) {
|
|
119479
119585
|
this.__twentyHttpResponse = true, this.body = e3, this.status = t4?.status, this.headers = t4?.headers;
|
|
@@ -119509,33 +119615,158 @@ var withRouteErrors = (name, handler2) => async (...args) => {
|
|
|
119509
119615
|
}
|
|
119510
119616
|
};
|
|
119511
119617
|
|
|
119618
|
+
// src/shared/api/rest-filter.util.ts
|
|
119619
|
+
var UNSAFE_FILTER_CHARACTERS = /[()[\]'",]/g;
|
|
119620
|
+
var sanitizeFilterText = (text) => text.replace(UNSAFE_FILTER_CHARACTERS, " ").trim();
|
|
119621
|
+
var quote = (value) => `'${sanitizeFilterText(value)}'`;
|
|
119622
|
+
var restEq = (field, value) => `${field}[eq]:${quote(value)}`;
|
|
119623
|
+
|
|
119512
119624
|
// src/server/records.ts
|
|
119513
119625
|
var clients = {
|
|
119514
119626
|
person: new u2(),
|
|
119515
119627
|
application: new u2({ runAs: "application" })
|
|
119516
119628
|
};
|
|
119517
119629
|
var restClient = (runAs) => clients[runAs];
|
|
119518
|
-
|
|
119519
|
-
|
|
119520
|
-
|
|
119521
|
-
var
|
|
119522
|
-
|
|
119630
|
+
|
|
119631
|
+
// src/server/process-catalog.ts
|
|
119632
|
+
var MEMBERSHIP_KEY = "docflow-processes";
|
|
119633
|
+
var PAGE_SIZE = 200;
|
|
119634
|
+
var VERSIONS_BATCH_SIZE = 50;
|
|
119635
|
+
var readStringList = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
119636
|
+
var readMembership = async () => {
|
|
119637
|
+
const stored = await kL.get(MEMBERSHIP_KEY);
|
|
119638
|
+
return { included: readStringList(stored?.included), excluded: readStringList(stored?.excluded) };
|
|
119639
|
+
};
|
|
119640
|
+
var readLegacyWorkflows = async (runAs) => {
|
|
119641
|
+
try {
|
|
119642
|
+
const { records } = readRestList(
|
|
119643
|
+
await restClient(runAs).get("/rest/workflows", {
|
|
119644
|
+
query: { filter: restEq("smbSection", DOCFLOW_SECTION), limit: PAGE_SIZE }
|
|
119645
|
+
})
|
|
119646
|
+
);
|
|
119647
|
+
return new Map(records.map((record) => [record.id, record]));
|
|
119648
|
+
} catch {
|
|
119649
|
+
return /* @__PURE__ */ new Map();
|
|
119650
|
+
}
|
|
119651
|
+
};
|
|
119652
|
+
var listCoreWorkflows = async (runAs) => {
|
|
119653
|
+
const nodes = [];
|
|
119654
|
+
let after;
|
|
119655
|
+
do {
|
|
119656
|
+
const { coreWorkflows } = await callCoreGraphql({ query: CORE_WORKFLOWS_QUERY, variables: { first: PAGE_SIZE, after }, runAs });
|
|
119657
|
+
nodes.push(...coreWorkflows.edges.map(({ node }) => node));
|
|
119658
|
+
after = coreWorkflows.pageInfo.hasNextPage ? coreWorkflows.pageInfo.endCursor ?? void 0 : void 0;
|
|
119659
|
+
} while (after !== void 0);
|
|
119660
|
+
return nodes;
|
|
119661
|
+
};
|
|
119662
|
+
var isDocflowNode = (node, membership, legacy) => !membership.excluded.includes(node.id) && (membership.included.includes(node.id) || typeof node.workspaceWorkflowId === "string" && legacy.has(node.workspaceWorkflowId));
|
|
119663
|
+
var byNewest = (first, second) => new Date(second.createdAt ?? 0).getTime() - new Date(first.createdAt ?? 0).getTime();
|
|
119664
|
+
var getVersion = async (id3, runAs) => (await callCoreGraphql({
|
|
119665
|
+
query: CORE_WORKFLOW_VERSION_BY_ID_QUERY,
|
|
119666
|
+
variables: { coreWorkflowVersionId: id3 },
|
|
119667
|
+
runAs
|
|
119668
|
+
})).coreWorkflowVersionById ?? void 0;
|
|
119669
|
+
var readVersions = async (workflowIds, runAs) => {
|
|
119670
|
+
const result = /* @__PURE__ */ new Map();
|
|
119671
|
+
for (let start = 0; start < workflowIds.length; start += VERSIONS_BATCH_SIZE) {
|
|
119672
|
+
const { coreWorkflowsWithCurrentVersions } = await callCoreGraphql({
|
|
119673
|
+
query: CORE_WORKFLOWS_WITH_CURRENT_VERSIONS_QUERY,
|
|
119674
|
+
variables: { input: { coreWorkflowIds: workflowIds.slice(start, start + VERSIONS_BATCH_SIZE) } },
|
|
119675
|
+
runAs
|
|
119676
|
+
});
|
|
119677
|
+
for (const { workflow, currentVersion, versions } of coreWorkflowsWithCurrentVersions) {
|
|
119678
|
+
const sorted = [...versions].sort(byNewest);
|
|
119679
|
+
const current = currentVersion ?? void 0;
|
|
119680
|
+
const activeId = sorted.find(({ status }) => status === "ACTIVE")?.id;
|
|
119681
|
+
const draft = current?.status === "DRAFT" ? current : void 0;
|
|
119682
|
+
const active = activeId === void 0 ? void 0 : current?.id === activeId ? current : await getVersion(activeId, runAs);
|
|
119683
|
+
const deactivatedId = sorted.find(({ status }) => status === "DEACTIVATED")?.id;
|
|
119684
|
+
const deactivated = deactivatedId === void 0 || active !== void 0 || draft !== void 0 ? void 0 : current?.id === deactivatedId ? current : await getVersion(deactivatedId, runAs);
|
|
119685
|
+
result.set(workflow.id, { active, draft, deactivated });
|
|
119686
|
+
}
|
|
119687
|
+
}
|
|
119688
|
+
return result;
|
|
119689
|
+
};
|
|
119690
|
+
var toProcess = (node, versions, legacy) => {
|
|
119691
|
+
const savedFields = parseLaunchFields(legacy?.smbLaunchFields);
|
|
119692
|
+
const active = versions?.active;
|
|
119693
|
+
return {
|
|
119694
|
+
workflowId: node.id,
|
|
119695
|
+
workspaceWorkflowId: node.workspaceWorkflowId ?? null,
|
|
119696
|
+
name: node.name?.trim() || "\u0411\u0435\u0437 \u043D\u0430\u0437\u0432\u0430\u043D\u0438\u044F",
|
|
119697
|
+
updatedAt: node.updatedAt ?? null,
|
|
119698
|
+
...versions,
|
|
119699
|
+
// Fields saved by docflow, or for a webhook set up in the Twenty editor
|
|
119700
|
+
// the values its body expects
|
|
119701
|
+
launchFields: savedFields.length > 0 ? savedFields : parseExpectedBodyFields(active?.trigger),
|
|
119702
|
+
launchObject: isLaunchTrigger(active?.trigger) ? parseLaunchObject(legacy?.smbLaunchObject) : void 0
|
|
119703
|
+
};
|
|
119704
|
+
};
|
|
119705
|
+
var listDocflowProcesses = async (runAs = "person") => {
|
|
119706
|
+
const [nodes, membership, legacy] = await Promise.all([
|
|
119707
|
+
listCoreWorkflows(runAs),
|
|
119708
|
+
readMembership(),
|
|
119709
|
+
readLegacyWorkflows(runAs)
|
|
119710
|
+
]);
|
|
119711
|
+
const docflowNodes = nodes.filter((node) => isDocflowNode(node, membership, legacy));
|
|
119712
|
+
const versions = await readVersions(
|
|
119713
|
+
docflowNodes.map(({ id: id3 }) => id3),
|
|
119714
|
+
runAs
|
|
119715
|
+
);
|
|
119716
|
+
return docflowNodes.map(
|
|
119717
|
+
(node) => toProcess(node, versions.get(node.id), node.workspaceWorkflowId ? legacy.get(node.workspaceWorkflowId) : void 0)
|
|
119718
|
+
);
|
|
119719
|
+
};
|
|
119720
|
+
var findDocflowProcess = async (workflowId, runAs = "person") => (await listDocflowProcesses(runAs)).find(
|
|
119721
|
+
(process2) => process2.workflowId === workflowId || process2.workspaceWorkflowId === workflowId
|
|
119523
119722
|
);
|
|
119524
119723
|
|
|
119525
119724
|
// src/shared/workflow/workflow-run.util.ts
|
|
119526
119725
|
var DAY_IN_MS = 24 * 60 * 60 * 1e3;
|
|
119527
119726
|
|
|
119528
119727
|
// src/server/workflow-engine.ts
|
|
119529
|
-
var
|
|
119530
|
-
|
|
119728
|
+
var runManualProcess = async ({
|
|
119729
|
+
workspaceWorkflowVersionId,
|
|
119730
|
+
coreWorkflowVersionId,
|
|
119531
119731
|
workflowRunId,
|
|
119532
119732
|
payload
|
|
119533
119733
|
}) => {
|
|
119734
|
+
if (typeof workspaceWorkflowVersionId === "string") {
|
|
119735
|
+
try {
|
|
119736
|
+
const data2 = await callCoreGraphql({
|
|
119737
|
+
query: RUN_WORKFLOW_VERSION_MUTATION,
|
|
119738
|
+
variables: { input: { workflowVersionId: workspaceWorkflowVersionId, workflowRunId, payload } }
|
|
119739
|
+
});
|
|
119740
|
+
return data2.runWorkflowVersion.workflowRunId;
|
|
119741
|
+
} catch (error) {
|
|
119742
|
+
if (!isMissingGraphqlField(error)) {
|
|
119743
|
+
throw error;
|
|
119744
|
+
}
|
|
119745
|
+
}
|
|
119746
|
+
}
|
|
119534
119747
|
const data = await callCoreGraphql({
|
|
119535
|
-
query:
|
|
119536
|
-
variables: { input: {
|
|
119748
|
+
query: RUN_CORE_WORKFLOW_VERSION_MUTATION,
|
|
119749
|
+
variables: { input: { coreWorkflowVersionId, workflowRunId, payload } }
|
|
119750
|
+
});
|
|
119751
|
+
return data.runCoreWorkflowVersion.workflowRunId;
|
|
119752
|
+
};
|
|
119753
|
+
var runWebhookProcess = async ({
|
|
119754
|
+
workspaceId,
|
|
119755
|
+
workflowId,
|
|
119756
|
+
payload
|
|
119757
|
+
}) => {
|
|
119758
|
+
const apiUrl = (process.env.TWENTY_API_URL ?? "").replace(/\/$/, "");
|
|
119759
|
+
const response = await fetch(`${apiUrl}/webhooks/workflows/${workspaceId}/${workflowId}`, {
|
|
119760
|
+
method: "POST",
|
|
119761
|
+
headers: { "content-type": "application/json" },
|
|
119762
|
+
body: JSON.stringify(payload)
|
|
119537
119763
|
});
|
|
119538
|
-
|
|
119764
|
+
const body = await response.json().catch(() => ({}));
|
|
119765
|
+
if (!response.ok || typeof body.workflowRunId !== "string") {
|
|
119766
|
+
const reason = Array.isArray(body.messages) ? body.messages.join("; ") : body.message;
|
|
119767
|
+
throw new Error(`\u041F\u0440\u043E\u0446\u0435\u0441\u0441 \u043D\u0435 \u0437\u0430\u043F\u0443\u0441\u0442\u0438\u043B\u0441\u044F: ${typeof reason === "string" ? reason : `HTTP ${response.status}`}`);
|
|
119768
|
+
}
|
|
119769
|
+
return body.workflowRunId;
|
|
119539
119770
|
};
|
|
119540
119771
|
|
|
119541
119772
|
// src/universal-identifiers.ts
|
|
@@ -119548,21 +119779,21 @@ var handler = async (event, context) => {
|
|
|
119548
119779
|
return jsonResponse(401, { message: "\u0417\u0430\u043F\u0443\u0441\u043A\u0430\u0442\u044C \u043F\u0440\u043E\u0446\u0435\u0441\u0441\u044B \u043C\u043E\u0436\u0435\u0442 \u0442\u043E\u043B\u044C\u043A\u043E \u0441\u043E\u0442\u0440\u0443\u0434\u043D\u0438\u043A" });
|
|
119549
119780
|
}
|
|
119550
119781
|
const body = readJsonBody(event.body);
|
|
119551
|
-
const
|
|
119782
|
+
const workflowId = body.workflowId;
|
|
119552
119783
|
const values = readJsonBody(body.values);
|
|
119553
119784
|
const recordIds = readRecordIds(body.recordIds);
|
|
119554
|
-
if (typeof
|
|
119785
|
+
if (typeof workflowId !== "string" || workflowId.length === 0) {
|
|
119555
119786
|
return jsonResponse(400, { message: "\u041D\u0435 \u0443\u043A\u0430\u0437\u0430\u043D \u043F\u0440\u043E\u0446\u0435\u0441\u0441" });
|
|
119556
119787
|
}
|
|
119557
|
-
const
|
|
119558
|
-
|
|
119559
|
-
|
|
119788
|
+
const docflowProcess = await findDocflowProcess(workflowId, "person");
|
|
119789
|
+
const version = docflowProcess?.active;
|
|
119790
|
+
if (docflowProcess === void 0) {
|
|
119791
|
+
return jsonResponse(404, { message: "\u041F\u0440\u043E\u0446\u0435\u0441\u0441 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u043E\u043E\u0431\u043E\u0440\u043E\u0442\u0430 \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D" });
|
|
119560
119792
|
}
|
|
119561
|
-
|
|
119562
|
-
|
|
119563
|
-
return jsonResponse(403, { message: "\u041F\u0440\u043E\u0446\u0435\u0441\u0441 \u043D\u0435 \u043E\u0442\u043D\u043E\u0441\u0438\u0442\u0441\u044F \u043A \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u043E\u043E\u0431\u043E\u0440\u043E\u0442\u0443" });
|
|
119793
|
+
if (version === void 0) {
|
|
119794
|
+
return jsonResponse(404, { message: "\u041F\u0440\u043E\u0446\u0435\u0441\u0441 \u043D\u0435 \u043E\u043F\u0443\u0431\u043B\u0438\u043A\u043E\u0432\u0430\u043D" });
|
|
119564
119795
|
}
|
|
119565
|
-
const fields =
|
|
119796
|
+
const fields = docflowProcess.launchFields;
|
|
119566
119797
|
const parameters = buildLaunchParameters({ fields, values });
|
|
119567
119798
|
const missingFields = findMissingRequiredFields({ fields, values: parameters });
|
|
119568
119799
|
if (missingFields.length > 0) {
|
|
@@ -119571,8 +119802,8 @@ var handler = async (event, context) => {
|
|
|
119571
119802
|
missingFieldNames: missingFields.map(({ name }) => name)
|
|
119572
119803
|
});
|
|
119573
119804
|
}
|
|
119574
|
-
const launchObjectName =
|
|
119575
|
-
const isLaunchedOnRecords = launchObjectName !== void 0
|
|
119805
|
+
const launchObjectName = docflowProcess.launchObject;
|
|
119806
|
+
const isLaunchedOnRecords = launchObjectName !== void 0;
|
|
119576
119807
|
let records = [void 0];
|
|
119577
119808
|
if (isLaunchedOnRecords) {
|
|
119578
119809
|
if (recordIds.length === 0) {
|
|
@@ -119603,23 +119834,28 @@ var handler = async (event, context) => {
|
|
|
119603
119834
|
}
|
|
119604
119835
|
const workflowRunIds = [];
|
|
119605
119836
|
for (const record of records) {
|
|
119606
|
-
const
|
|
119837
|
+
const payload = {
|
|
119838
|
+
...fields.length > 0 || record !== void 0 ? buildLaunchPayload(parameters, record) : {},
|
|
119839
|
+
[DOCFLOW_LAUNCHED_BY_KEY]: context.workspaceMemberId
|
|
119840
|
+
};
|
|
119607
119841
|
try {
|
|
119608
|
-
|
|
119609
|
-
|
|
119610
|
-
|
|
119611
|
-
|
|
119612
|
-
|
|
119842
|
+
workflowRunIds.push(
|
|
119843
|
+
version.trigger?.type === "WEBHOOK" ? await runWebhookProcess({ workspaceId: context.workspaceId, workflowId: docflowProcess.workflowId, payload }) : await runManualProcess({
|
|
119844
|
+
workspaceWorkflowVersionId: version.workspaceWorkflowVersionId,
|
|
119845
|
+
coreWorkflowVersionId: version.id,
|
|
119846
|
+
workflowRunId: crypto.randomUUID(),
|
|
119847
|
+
payload
|
|
119848
|
+
})
|
|
119849
|
+
);
|
|
119613
119850
|
} catch (error) {
|
|
119614
|
-
logDocflowError("launch: run failed", error, {
|
|
119851
|
+
logDocflowError("launch: run failed", error, { workflowId: docflowProcess.workflowId, recordId: record?.id });
|
|
119615
119852
|
return jsonResponse(403, {
|
|
119616
|
-
message: error instanceof CoreGraphqlError && error.userMessage !== void 0 ? error.userMessage : "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0437\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u044C \u043F\u0440\u043E\u0446\u0435\u0441\u0441",
|
|
119853
|
+
message: error instanceof CoreGraphqlError && error.userMessage !== void 0 ? /only start its own/i.test(`${error.message} ${error.userMessage}`) ? "\u0412 \u044D\u0442\u043E\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 Twenty \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u0437\u0430\u043F\u0443\u0441\u043A\u0430\u0435\u0442 \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u0440\u043E\u0446\u0435\u0441\u0441\u044B \u0441 \u0442\u0440\u0438\u0433\u0433\u0435\u0440\u043E\u043C \xABWebhook\xBB. \u041F\u0440\u043E\u0446\u0435\u0441\u0441 \u0441 \u0440\u0443\u0447\u043D\u044B\u043C \u0437\u0430\u043F\u0443\u0441\u043A\u043E\u043C \u0437\u0430\u043F\u0443\u0441\u043A\u0430\u0435\u0442\u0441\u044F \u0438\u0437 \u0441\u0430\u043C\u043E\u0439 Twenty, \u0438\u043B\u0438 \u043F\u043E\u043C\u0435\u043D\u044F\u0439\u0442\u0435 \u0435\u043C\u0443 \u0442\u0440\u0438\u0433\u0433\u0435\u0440 \u0432 \u0440\u0435\u0434\u0430\u043A\u0442\u043E\u0440\u0435." : error.userMessage : error instanceof Error ? error.message : "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0437\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u044C \u043F\u0440\u043E\u0446\u0435\u0441\u0441",
|
|
119617
119854
|
workflowRunIds
|
|
119618
119855
|
});
|
|
119619
119856
|
}
|
|
119620
|
-
workflowRunIds.push(workflowRunId);
|
|
119621
119857
|
}
|
|
119622
|
-
logDocflow("launch: started", {
|
|
119858
|
+
logDocflow("launch: started", { workflowId: docflowProcess.workflowId, workflowRunIds, parameters, recordIds });
|
|
119623
119859
|
return { workflowRunId: workflowRunIds[0], workflowRunIds };
|
|
119624
119860
|
};
|
|
119625
119861
|
var launch_process_logic_function_default = defineLogicFunction({
|
|
@@ -7,18 +7,16 @@ import {
|
|
|
7
7
|
import { CoreGraphqlError } from 'src/shared/api/core-graphql.util';
|
|
8
8
|
import { getObjectSummaries } from 'src/shared/api/object-summaries';
|
|
9
9
|
import { readRestRecord } from 'src/shared/api/rest-response.util';
|
|
10
|
-
import {
|
|
10
|
+
import { DOCFLOW_LAUNCHED_BY_KEY, LAUNCH_RECORDS_LIMIT } from 'src/shared/docflow.constants';
|
|
11
11
|
import { findMissingRequiredFields } from 'src/shared/form/form-fields.util';
|
|
12
12
|
import {
|
|
13
13
|
buildLaunchParameters,
|
|
14
14
|
buildLaunchPayload,
|
|
15
|
-
isLaunchTrigger,
|
|
16
|
-
parseLaunchFields,
|
|
17
|
-
parseLaunchObject,
|
|
18
15
|
} from 'src/shared/workflow/launch-step.util';
|
|
19
16
|
import { readJsonBody, jsonResponse, withRouteErrors } from 'src/server/http-response';
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
17
|
+
import { findDocflowProcess } from 'src/server/process-catalog';
|
|
18
|
+
import { restClient } from 'src/server/records';
|
|
19
|
+
import { runManualProcess, runWebhookProcess } from 'src/server/workflow-engine';
|
|
22
20
|
import { logDocflow, logDocflowError } from 'src/shared/log.util';
|
|
23
21
|
import { LAUNCH_PROCESS_LOGIC_FUNCTION_UNIVERSAL_IDENTIFIER } from 'src/universal-identifiers';
|
|
24
22
|
|
|
@@ -31,7 +29,9 @@ const readRecordIds = (value: unknown): string[] =>
|
|
|
31
29
|
// so they stay in the run as its trigger output ({{trigger.<field>}}). A
|
|
32
30
|
// process launched on records runs once per record, the record read as the
|
|
33
31
|
// person and put into its run as {{trigger.record}}, like the standard manual
|
|
34
|
-
// launch on a selection does.
|
|
32
|
+
// launch on a selection does. A webhook process starts through its webhook
|
|
33
|
+
// (Twenty 2.45 and 2.50 alike); the webhook knows no person, so the one who
|
|
34
|
+
// launched rides in the payload too.
|
|
35
35
|
const handler = async (
|
|
36
36
|
event: RoutePayload,
|
|
37
37
|
context: LogicFunctionExecutionContext,
|
|
@@ -41,30 +41,28 @@ const handler = async (
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
const body = readJsonBody(event.body);
|
|
44
|
-
const
|
|
44
|
+
const workflowId = body.workflowId;
|
|
45
45
|
const values = readJsonBody(body.values);
|
|
46
46
|
const recordIds = readRecordIds(body.recordIds);
|
|
47
47
|
|
|
48
|
-
if (typeof
|
|
48
|
+
if (typeof workflowId !== 'string' || workflowId.length === 0) {
|
|
49
49
|
return jsonResponse(400, { message: 'Не указан процесс' });
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
// Read as the person: without the "Workflows" permission the engine does
|
|
53
|
+
// not show processes, and then they cannot be launched either
|
|
54
|
+
const docflowProcess = await findDocflowProcess(workflowId, 'person');
|
|
55
|
+
const version = docflowProcess?.active;
|
|
53
56
|
|
|
54
|
-
if (
|
|
55
|
-
return jsonResponse(404, { message: 'Процесс не найден
|
|
57
|
+
if (docflowProcess === undefined) {
|
|
58
|
+
return jsonResponse(404, { message: 'Процесс документооборота не найден' });
|
|
56
59
|
}
|
|
57
60
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
? await getWorkflow('person', version.workflowId)
|
|
61
|
-
: undefined;
|
|
62
|
-
|
|
63
|
-
if (workflow?.smbSection !== DOCFLOW_SECTION) {
|
|
64
|
-
return jsonResponse(403, { message: 'Процесс не относится к документообороту' });
|
|
61
|
+
if (version === undefined) {
|
|
62
|
+
return jsonResponse(404, { message: 'Процесс не опубликован' });
|
|
65
63
|
}
|
|
66
64
|
|
|
67
|
-
const fields =
|
|
65
|
+
const fields = docflowProcess.launchFields;
|
|
68
66
|
const parameters = buildLaunchParameters({ fields, values });
|
|
69
67
|
const missingFields = findMissingRequiredFields({ fields, values: parameters });
|
|
70
68
|
|
|
@@ -75,10 +73,8 @@ const handler = async (
|
|
|
75
73
|
});
|
|
76
74
|
}
|
|
77
75
|
|
|
78
|
-
const launchObjectName =
|
|
79
|
-
|
|
80
|
-
// already hold the object of a draft not published yet.
|
|
81
|
-
const isLaunchedOnRecords = launchObjectName !== undefined && isLaunchTrigger(version.trigger);
|
|
76
|
+
const launchObjectName = docflowProcess.launchObject;
|
|
77
|
+
const isLaunchedOnRecords = launchObjectName !== undefined;
|
|
82
78
|
let records: (Record<string, unknown> | undefined)[] = [undefined];
|
|
83
79
|
|
|
84
80
|
if (isLaunchedOnRecords) {
|
|
@@ -119,31 +115,40 @@ const handler = async (
|
|
|
119
115
|
const workflowRunIds: string[] = [];
|
|
120
116
|
|
|
121
117
|
for (const record of records) {
|
|
122
|
-
const
|
|
118
|
+
const payload = {
|
|
119
|
+
...(fields.length > 0 || record !== undefined ? buildLaunchPayload(parameters, record) : {}),
|
|
120
|
+
[DOCFLOW_LAUNCHED_BY_KEY]: context.workspaceMemberId,
|
|
121
|
+
};
|
|
123
122
|
|
|
124
123
|
try {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
124
|
+
workflowRunIds.push(
|
|
125
|
+
version.trigger?.type === 'WEBHOOK'
|
|
126
|
+
? await runWebhookProcess({ workspaceId: context.workspaceId, workflowId: docflowProcess.workflowId, payload })
|
|
127
|
+
: await runManualProcess({
|
|
128
|
+
workspaceWorkflowVersionId: version.workspaceWorkflowVersionId,
|
|
129
|
+
coreWorkflowVersionId: version.id,
|
|
130
|
+
workflowRunId: crypto.randomUUID(),
|
|
131
|
+
payload,
|
|
132
|
+
}),
|
|
133
|
+
);
|
|
131
134
|
} catch (error) {
|
|
132
|
-
logDocflowError('launch: run failed', error, {
|
|
135
|
+
logDocflowError('launch: run failed', error, { workflowId: docflowProcess.workflowId, recordId: record?.id });
|
|
133
136
|
|
|
134
137
|
return jsonResponse(403, {
|
|
135
138
|
message:
|
|
136
139
|
error instanceof CoreGraphqlError && error.userMessage !== undefined
|
|
137
|
-
? error.userMessage
|
|
138
|
-
|
|
140
|
+
? /only start its own/i.test(`${error.message} ${error.userMessage}`)
|
|
141
|
+
? 'В этой версии Twenty приложение запускает только процессы с триггером «Webhook». Процесс с ручным запуском запускается из самой Twenty, или поменяйте ему триггер в редакторе.'
|
|
142
|
+
: error.userMessage
|
|
143
|
+
: error instanceof Error
|
|
144
|
+
? error.message
|
|
145
|
+
: 'Не удалось запустить процесс',
|
|
139
146
|
workflowRunIds,
|
|
140
147
|
});
|
|
141
148
|
}
|
|
142
|
-
|
|
143
|
-
workflowRunIds.push(workflowRunId);
|
|
144
149
|
}
|
|
145
150
|
|
|
146
|
-
logDocflow('launch: started', {
|
|
151
|
+
logDocflow('launch: started', { workflowId: docflowProcess.workflowId, workflowRunIds, parameters, recordIds });
|
|
147
152
|
|
|
148
153
|
return { workflowRunId: workflowRunIds[0], workflowRunIds };
|
|
149
154
|
};
|