@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
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { defineLogicFunction } from 'twenty-sdk/define';
|
|
2
|
+
import {
|
|
3
|
+
type LogicFunctionExecutionContext,
|
|
4
|
+
type RoutePayload,
|
|
5
|
+
} from 'twenty-sdk/logic-function';
|
|
6
|
+
|
|
7
|
+
import { CoreGraphqlError } from 'src/shared/api/core-graphql.util';
|
|
8
|
+
import { jsonResponse, readJsonBody, withRouteErrors } from 'src/server/http-response';
|
|
9
|
+
import {
|
|
10
|
+
listDocflowProcesses,
|
|
11
|
+
listOtherProcesses,
|
|
12
|
+
setDocflowMembership,
|
|
13
|
+
} from 'src/server/process-catalog';
|
|
14
|
+
import { logDocflow } from 'src/shared/log.util';
|
|
15
|
+
import { PROCESS_CATALOG_LOGIC_FUNCTION_UNIVERSAL_IDENTIFIER } from 'src/universal-identifiers';
|
|
16
|
+
|
|
17
|
+
const readIds = (value: unknown): string[] =>
|
|
18
|
+
Array.isArray(value)
|
|
19
|
+
? [...new Set(value.filter((id): id is string => typeof id === 'string' && id.length > 0))]
|
|
20
|
+
: [];
|
|
21
|
+
|
|
22
|
+
// The processes pages read docflow processes here, not from the process
|
|
23
|
+
// records: Twenty 2.50 keeps processes only in its engine. Read as the
|
|
24
|
+
// person, so the "Workflows" permission decides who sees them.
|
|
25
|
+
// { action: 'list' } docflow processes with their versions
|
|
26
|
+
// { action: 'others' } the workspace's other processes
|
|
27
|
+
// { action: 'add' | 'remove', workflowIds }
|
|
28
|
+
const handler = async (event: RoutePayload, context: LogicFunctionExecutionContext) => {
|
|
29
|
+
if (context.workspaceMemberId === null) {
|
|
30
|
+
return jsonResponse(401, { message: 'Процессы доступны только сотруднику' });
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const body = readJsonBody(event.body);
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
switch (body.action) {
|
|
37
|
+
case 'list':
|
|
38
|
+
return { processes: await listDocflowProcesses('person') };
|
|
39
|
+
case 'others':
|
|
40
|
+
return { processes: await listOtherProcesses() };
|
|
41
|
+
case 'add':
|
|
42
|
+
case 'remove': {
|
|
43
|
+
const workflowIds = readIds(body.workflowIds);
|
|
44
|
+
// Only processes the person can see: the ids are checked against them
|
|
45
|
+
const known = new Set([
|
|
46
|
+
...(await listDocflowProcesses('person')).map(({ workflowId }) => workflowId),
|
|
47
|
+
...(await listOtherProcesses()).map(({ workflowId }) => workflowId),
|
|
48
|
+
]);
|
|
49
|
+
const accepted = workflowIds.filter((id) => known.has(id));
|
|
50
|
+
|
|
51
|
+
if (accepted.length === 0) {
|
|
52
|
+
return jsonResponse(404, { message: 'Процесс не найден' });
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
await setDocflowMembership(accepted, body.action === 'add');
|
|
56
|
+
logDocflow(`catalog: ${body.action}`, { workflowIds: accepted });
|
|
57
|
+
|
|
58
|
+
return { workflowIds: accepted };
|
|
59
|
+
}
|
|
60
|
+
default:
|
|
61
|
+
return jsonResponse(400, { message: 'Неизвестное действие' });
|
|
62
|
+
}
|
|
63
|
+
} catch (error) {
|
|
64
|
+
// The engine refuses a person without the "Workflows" permission
|
|
65
|
+
if (error instanceof CoreGraphqlError && error.userMessage !== undefined) {
|
|
66
|
+
return jsonResponse(403, { message: error.userMessage });
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
throw error;
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export default defineLogicFunction({
|
|
74
|
+
universalIdentifier: PROCESS_CATALOG_LOGIC_FUNCTION_UNIVERSAL_IDENTIFIER,
|
|
75
|
+
name: 'docflow-process-catalog',
|
|
76
|
+
description: 'Процессы документооборота: список и отметка процессов Twenty',
|
|
77
|
+
timeoutSeconds: 30,
|
|
78
|
+
handler: withRouteErrors('process-catalog', handler),
|
|
79
|
+
httpRouteTriggerSettings: {
|
|
80
|
+
path: '/docflow/processes/catalog',
|
|
81
|
+
httpMethod: 'POST',
|
|
82
|
+
isAuthRequired: true,
|
|
83
|
+
},
|
|
84
|
+
});
|
|
@@ -1693,10 +1693,13 @@ var readUserMessage = (value) => {
|
|
|
1693
1693
|
};
|
|
1694
1694
|
var callCoreGraphql = async ({
|
|
1695
1695
|
query,
|
|
1696
|
-
variables
|
|
1696
|
+
variables,
|
|
1697
|
+
runAs = "person"
|
|
1697
1698
|
}) => {
|
|
1698
1699
|
const apiUrl = process.env.TWENTY_API_URL;
|
|
1699
|
-
const
|
|
1700
|
+
const personToken = process.env.TWENTY_APP_ACCESS_TOKEN;
|
|
1701
|
+
const applicationToken = process.env.TWENTY_APP_APPLICATION_ACCESS_TOKEN;
|
|
1702
|
+
const token = runAs === "person" ? personToken ?? applicationToken : applicationToken ?? personToken;
|
|
1700
1703
|
if (apiUrl === void 0 || token === void 0) {
|
|
1701
1704
|
throw new CoreGraphqlError(
|
|
1702
1705
|
"TWENTY_API_URL or TWENTY_APP_ACCESS_TOKEN is not set",
|
|
@@ -1721,6 +1724,24 @@ var callCoreGraphql = async ({
|
|
|
1721
1724
|
}
|
|
1722
1725
|
return body.data;
|
|
1723
1726
|
};
|
|
1727
|
+
var CORE_WORKFLOWS_QUERY = `query CoreWorkflows($first: Int!, $after: String) {
|
|
1728
|
+
coreWorkflows(first: $first, after: $after) {
|
|
1729
|
+
pageInfo { hasNextPage endCursor }
|
|
1730
|
+
edges { node { id name updatedAt workspaceWorkflowId lastPublishedCoreWorkflowVersionId statuses } }
|
|
1731
|
+
}
|
|
1732
|
+
}`;
|
|
1733
|
+
var CORE_WORKFLOWS_WITH_CURRENT_VERSIONS_QUERY = `query CoreWorkflowsWithCurrentVersions($input: CoreWorkflowsWithCurrentVersionsInput!) {
|
|
1734
|
+
coreWorkflowsWithCurrentVersions(input: $input) {
|
|
1735
|
+
workflow { id }
|
|
1736
|
+
currentVersion { id status createdAt trigger steps workspaceWorkflowVersionId }
|
|
1737
|
+
versions { id status createdAt workspaceWorkflowVersionId }
|
|
1738
|
+
}
|
|
1739
|
+
}`;
|
|
1740
|
+
var CORE_WORKFLOW_VERSION_BY_ID_QUERY = `query CoreWorkflowVersionById($coreWorkflowVersionId: UUID!) {
|
|
1741
|
+
coreWorkflowVersionById(coreWorkflowVersionId: $coreWorkflowVersionId) {
|
|
1742
|
+
id status createdAt trigger steps workspaceWorkflowVersionId
|
|
1743
|
+
}
|
|
1744
|
+
}`;
|
|
1724
1745
|
var ACTIVATE_WORKFLOW_VERSION_MUTATION = `mutation ActivateWorkflowVersion($workflowVersionId: UUID!) {
|
|
1725
1746
|
activateWorkflowVersion(workflowVersionId: $workflowVersionId)
|
|
1726
1747
|
}`;
|
|
@@ -1728,11 +1749,6 @@ var DEACTIVATE_WORKFLOW_VERSION_MUTATION = `mutation DeactivateWorkflowVersion($
|
|
|
1728
1749
|
deactivateWorkflowVersion(workflowVersionId: $workflowVersionId)
|
|
1729
1750
|
}`;
|
|
1730
1751
|
|
|
1731
|
-
// src/shared/docflow.constants.ts
|
|
1732
|
-
var DOCFLOW_SECTION = "DOCFLOW";
|
|
1733
|
-
var DOCFLOW_LAUNCH_PARAMETERS_KEY = "smbDocflowParameters";
|
|
1734
|
-
var LAUNCH_PARAMETERS_STEP_INPUT = `{{trigger.${DOCFLOW_LAUNCH_PARAMETERS_KEY}}}`;
|
|
1735
|
-
|
|
1736
1752
|
// node_modules/twenty-sdk/dist/logic-function/isDefined-Dtu5EYqP-CMNeFg4z.mjs
|
|
1737
1753
|
var import_guards = __toESM(require_build(), 1);
|
|
1738
1754
|
var n = (n4) => !(0, import_guards.isUndefined)(n4) && !(0, import_guards.isNull)(n4);
|
|
@@ -119205,6 +119221,8 @@ var VI2 = /* @__PURE__ */ (function(e3) {
|
|
|
119205
119221
|
return e3.OK = "OK", e3.SUCCESS = "SUCCESS", e3.INFO = "INFO", e3.WARNING = "WARNING", e3.ERROR = "ERROR", e3.NEUTRAL = "NEUTRAL", e3.UNKNOWN = "UNKNOWN", e3;
|
|
119206
119222
|
})({});
|
|
119207
119223
|
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;
|
|
119224
|
+
var HI2 = "TWENTY_API_URL";
|
|
119225
|
+
var UI2 = "TWENTY_APP_APPLICATION_ACCESS_TOKEN";
|
|
119208
119226
|
hp2.map((e3) => mp2[e3]);
|
|
119209
119227
|
var WI2 = {
|
|
119210
119228
|
universalIdentifier: Wl2(),
|
|
@@ -119337,6 +119355,27 @@ fd2({
|
|
|
119337
119355
|
message: e4.message
|
|
119338
119356
|
});
|
|
119339
119357
|
});
|
|
119358
|
+
var XI2 = () => process.env.TWENTY_APP_APPLICATION_ACCESS_TOKEN ?? process.env.TWENTY_APP_ACCESS_TOKEN;
|
|
119359
|
+
var ZI = async ({ query: e3, variables: t4, caller: n4 }) => {
|
|
119360
|
+
let r4 = process.env[HI2], i5 = XI2();
|
|
119361
|
+
if (!r4 || !i5) throw Error(`${n4}() requires the app runtime env vars ${HI2} and ${UI2}.`);
|
|
119362
|
+
let a5 = await fetch(`${r4}/metadata`, {
|
|
119363
|
+
method: "POST",
|
|
119364
|
+
headers: {
|
|
119365
|
+
"Content-Type": "application/json",
|
|
119366
|
+
Authorization: `Bearer ${i5}`
|
|
119367
|
+
},
|
|
119368
|
+
body: JSON.stringify({
|
|
119369
|
+
query: e3,
|
|
119370
|
+
variables: t4
|
|
119371
|
+
})
|
|
119372
|
+
});
|
|
119373
|
+
if (!a5.ok) throw Error(`${n4}() failed: HTTP ${a5.status} ${a5.statusText}`);
|
|
119374
|
+
let o5 = await a5.json();
|
|
119375
|
+
if (o5.errors && o5.errors.length > 0) throw Error(`${n4}() failed: ${o5.errors.map((e4) => e4.message).join(", ")}`);
|
|
119376
|
+
if (!o5.data) throw Error(`${n4}() failed: response contained no data.`);
|
|
119377
|
+
return o5.data;
|
|
119378
|
+
};
|
|
119340
119379
|
var aL = "\n id\n handle\n displayName\n visibility\n connectedAccountId\n isSyncEnabled\n";
|
|
119341
119380
|
var oL = `
|
|
119342
119381
|
mutation CreateAppMessageChannel($input: CreateAppMessageChannelInput!) {
|
|
@@ -119366,6 +119405,45 @@ var fL = `
|
|
|
119366
119405
|
}
|
|
119367
119406
|
}
|
|
119368
119407
|
`;
|
|
119408
|
+
var TL = "\n query GetAppKeyValue($key: String!, $scope: AppKeyValueScope) {\n appKeyValue(key: $key, scope: $scope) {\n key\n value\n scope\n }\n }\n";
|
|
119409
|
+
var EL = "\n mutation SetAppKeyValue($input: SetAppKeyValueInput!) {\n setAppKeyValue(input: $input) {\n key\n value\n scope\n }\n }\n";
|
|
119410
|
+
var DL = "\n mutation DeleteAppKeyValue($key: String!, $scope: AppKeyValueScope) {\n deleteAppKeyValue(key: $key, scope: $scope)\n }\n";
|
|
119411
|
+
var OL = "WORKSPACE";
|
|
119412
|
+
var kL = {
|
|
119413
|
+
async get(e3, t4) {
|
|
119414
|
+
let { appKeyValue: n4 } = await ZI({
|
|
119415
|
+
query: TL,
|
|
119416
|
+
variables: {
|
|
119417
|
+
key: e3,
|
|
119418
|
+
scope: t4?.scope ?? OL
|
|
119419
|
+
},
|
|
119420
|
+
caller: "kv.get"
|
|
119421
|
+
});
|
|
119422
|
+
return n4?.value ?? null;
|
|
119423
|
+
},
|
|
119424
|
+
async set(e3, t4, n4) {
|
|
119425
|
+
await ZI({
|
|
119426
|
+
query: EL,
|
|
119427
|
+
variables: { input: {
|
|
119428
|
+
key: e3,
|
|
119429
|
+
value: t4,
|
|
119430
|
+
scope: n4?.scope ?? OL
|
|
119431
|
+
} },
|
|
119432
|
+
caller: "kv.set"
|
|
119433
|
+
});
|
|
119434
|
+
},
|
|
119435
|
+
async delete(e3, t4) {
|
|
119436
|
+
let { deleteAppKeyValue: n4 } = await ZI({
|
|
119437
|
+
query: DL,
|
|
119438
|
+
variables: {
|
|
119439
|
+
key: e3,
|
|
119440
|
+
scope: t4?.scope ?? OL
|
|
119441
|
+
},
|
|
119442
|
+
caller: "kv.delete"
|
|
119443
|
+
});
|
|
119444
|
+
return n4;
|
|
119445
|
+
}
|
|
119446
|
+
};
|
|
119369
119447
|
var AL = class {
|
|
119370
119448
|
constructor(e3, t4) {
|
|
119371
119449
|
this.__twentyHttpResponse = true, this.body = e3, this.status = t4?.status, this.headers = t4?.headers;
|
|
@@ -119423,10 +119501,39 @@ var readRestList = (response) => {
|
|
|
119423
119501
|
totalCount: response?.totalCount
|
|
119424
119502
|
};
|
|
119425
119503
|
};
|
|
119426
|
-
|
|
119427
|
-
|
|
119428
|
-
|
|
119504
|
+
|
|
119505
|
+
// src/shared/docflow.constants.ts
|
|
119506
|
+
var DOCFLOW_SECTION = "DOCFLOW";
|
|
119507
|
+
var DOCFLOW_LAUNCH_PARAMETERS_KEY = "smbDocflowParameters";
|
|
119508
|
+
var LAUNCH_PARAMETERS_STEP_INPUT = `{{trigger.${DOCFLOW_LAUNCH_PARAMETERS_KEY}}}`;
|
|
119509
|
+
var LAUNCH_TRIGGER_NAME = "\u0417\u0430\u043F\u0443\u0441\u043A \u0441 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u0430\u043C\u0438";
|
|
119510
|
+
var LAUNCH_RECORD_KEY = "record";
|
|
119511
|
+
var FORM_FIELD_ROLE_SETTING = "smbRole";
|
|
119512
|
+
|
|
119513
|
+
// src/shared/form/form-fields.util.ts
|
|
119514
|
+
var getFormFieldRole = (field) => {
|
|
119515
|
+
const role = field.settings?.[FORM_FIELD_ROLE_SETTING];
|
|
119516
|
+
return role === "ASSIGNEE" || role === "DUE_AT" ? role : void 0;
|
|
119517
|
+
};
|
|
119518
|
+
var getFillableFormFields = (fields) => fields.filter((field) => getFormFieldRole(field) === void 0);
|
|
119519
|
+
var parseFormFields = (value) => Array.isArray(value) ? value.filter(
|
|
119520
|
+
(field) => typeof field === "object" && field !== null && typeof field.name === "string" && typeof field.label === "string" && typeof field.type === "string"
|
|
119521
|
+
) : [];
|
|
119522
|
+
|
|
119523
|
+
// src/shared/workflow/launch-step.util.ts
|
|
119524
|
+
var isPlainRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
119525
|
+
var isLaunchTrigger = (trigger) => trigger?.type === "WEBHOOK" && trigger.name === LAUNCH_TRIGGER_NAME;
|
|
119526
|
+
var parseExpectedBodyFields = (trigger) => {
|
|
119527
|
+
const expectedBody = trigger?.type === "WEBHOOK" ? trigger.settings?.expectedBody : void 0;
|
|
119528
|
+
if (!isPlainRecord(expectedBody)) {
|
|
119529
|
+
return [];
|
|
119530
|
+
}
|
|
119531
|
+
return Object.entries(expectedBody).flatMap(
|
|
119532
|
+
([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" }]
|
|
119533
|
+
);
|
|
119429
119534
|
};
|
|
119535
|
+
var parseLaunchFields = (value) => getFillableFormFields(parseFormFields(value));
|
|
119536
|
+
var parseLaunchObject = (value) => typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
119430
119537
|
|
|
119431
119538
|
// src/server/records.ts
|
|
119432
119539
|
var clients = {
|
|
@@ -119434,9 +119541,6 @@ var clients = {
|
|
|
119434
119541
|
application: new u2({ runAs: "application" })
|
|
119435
119542
|
};
|
|
119436
119543
|
var restClient = (runAs) => clients[runAs];
|
|
119437
|
-
var getWorkflow = async (runAs, workflowId) => readRestRecord(
|
|
119438
|
-
await restClient(runAs).get(`/rest/workflows/${workflowId}`)
|
|
119439
|
-
);
|
|
119440
119544
|
var listWorkflowVersions = async (runAs, workflowId) => readRestList(
|
|
119441
119545
|
await restClient(runAs).get("/rest/workflowVersions", {
|
|
119442
119546
|
query: {
|
|
@@ -119447,6 +119551,99 @@ var listWorkflowVersions = async (runAs, workflowId) => readRestList(
|
|
|
119447
119551
|
})
|
|
119448
119552
|
).records;
|
|
119449
119553
|
|
|
119554
|
+
// src/server/process-catalog.ts
|
|
119555
|
+
var MEMBERSHIP_KEY = "docflow-processes";
|
|
119556
|
+
var PAGE_SIZE = 200;
|
|
119557
|
+
var VERSIONS_BATCH_SIZE = 50;
|
|
119558
|
+
var readStringList = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
119559
|
+
var readMembership = async () => {
|
|
119560
|
+
const stored = await kL.get(MEMBERSHIP_KEY);
|
|
119561
|
+
return { included: readStringList(stored?.included), excluded: readStringList(stored?.excluded) };
|
|
119562
|
+
};
|
|
119563
|
+
var readLegacyWorkflows = async (runAs) => {
|
|
119564
|
+
try {
|
|
119565
|
+
const { records } = readRestList(
|
|
119566
|
+
await restClient(runAs).get("/rest/workflows", {
|
|
119567
|
+
query: { filter: restEq("smbSection", DOCFLOW_SECTION), limit: PAGE_SIZE }
|
|
119568
|
+
})
|
|
119569
|
+
);
|
|
119570
|
+
return new Map(records.map((record) => [record.id, record]));
|
|
119571
|
+
} catch {
|
|
119572
|
+
return /* @__PURE__ */ new Map();
|
|
119573
|
+
}
|
|
119574
|
+
};
|
|
119575
|
+
var listCoreWorkflows = async (runAs) => {
|
|
119576
|
+
const nodes = [];
|
|
119577
|
+
let after;
|
|
119578
|
+
do {
|
|
119579
|
+
const { coreWorkflows } = await callCoreGraphql({ query: CORE_WORKFLOWS_QUERY, variables: { first: PAGE_SIZE, after }, runAs });
|
|
119580
|
+
nodes.push(...coreWorkflows.edges.map(({ node }) => node));
|
|
119581
|
+
after = coreWorkflows.pageInfo.hasNextPage ? coreWorkflows.pageInfo.endCursor ?? void 0 : void 0;
|
|
119582
|
+
} while (after !== void 0);
|
|
119583
|
+
return nodes;
|
|
119584
|
+
};
|
|
119585
|
+
var isDocflowNode = (node, membership, legacy) => !membership.excluded.includes(node.id) && (membership.included.includes(node.id) || typeof node.workspaceWorkflowId === "string" && legacy.has(node.workspaceWorkflowId));
|
|
119586
|
+
var byNewest = (first, second) => new Date(second.createdAt ?? 0).getTime() - new Date(first.createdAt ?? 0).getTime();
|
|
119587
|
+
var getVersion = async (id3, runAs) => (await callCoreGraphql({
|
|
119588
|
+
query: CORE_WORKFLOW_VERSION_BY_ID_QUERY,
|
|
119589
|
+
variables: { coreWorkflowVersionId: id3 },
|
|
119590
|
+
runAs
|
|
119591
|
+
})).coreWorkflowVersionById ?? void 0;
|
|
119592
|
+
var readVersions = async (workflowIds, runAs) => {
|
|
119593
|
+
const result = /* @__PURE__ */ new Map();
|
|
119594
|
+
for (let start = 0; start < workflowIds.length; start += VERSIONS_BATCH_SIZE) {
|
|
119595
|
+
const { coreWorkflowsWithCurrentVersions } = await callCoreGraphql({
|
|
119596
|
+
query: CORE_WORKFLOWS_WITH_CURRENT_VERSIONS_QUERY,
|
|
119597
|
+
variables: { input: { coreWorkflowIds: workflowIds.slice(start, start + VERSIONS_BATCH_SIZE) } },
|
|
119598
|
+
runAs
|
|
119599
|
+
});
|
|
119600
|
+
for (const { workflow, currentVersion, versions } of coreWorkflowsWithCurrentVersions) {
|
|
119601
|
+
const sorted = [...versions].sort(byNewest);
|
|
119602
|
+
const current = currentVersion ?? void 0;
|
|
119603
|
+
const activeId = sorted.find(({ status }) => status === "ACTIVE")?.id;
|
|
119604
|
+
const draft = current?.status === "DRAFT" ? current : void 0;
|
|
119605
|
+
const active = activeId === void 0 ? void 0 : current?.id === activeId ? current : await getVersion(activeId, runAs);
|
|
119606
|
+
const deactivatedId = sorted.find(({ status }) => status === "DEACTIVATED")?.id;
|
|
119607
|
+
const deactivated = deactivatedId === void 0 || active !== void 0 || draft !== void 0 ? void 0 : current?.id === deactivatedId ? current : await getVersion(deactivatedId, runAs);
|
|
119608
|
+
result.set(workflow.id, { active, draft, deactivated });
|
|
119609
|
+
}
|
|
119610
|
+
}
|
|
119611
|
+
return result;
|
|
119612
|
+
};
|
|
119613
|
+
var toProcess = (node, versions, legacy) => {
|
|
119614
|
+
const savedFields = parseLaunchFields(legacy?.smbLaunchFields);
|
|
119615
|
+
const active = versions?.active;
|
|
119616
|
+
return {
|
|
119617
|
+
workflowId: node.id,
|
|
119618
|
+
workspaceWorkflowId: node.workspaceWorkflowId ?? null,
|
|
119619
|
+
name: node.name?.trim() || "\u0411\u0435\u0437 \u043D\u0430\u0437\u0432\u0430\u043D\u0438\u044F",
|
|
119620
|
+
updatedAt: node.updatedAt ?? null,
|
|
119621
|
+
...versions,
|
|
119622
|
+
// Fields saved by docflow, or for a webhook set up in the Twenty editor
|
|
119623
|
+
// the values its body expects
|
|
119624
|
+
launchFields: savedFields.length > 0 ? savedFields : parseExpectedBodyFields(active?.trigger),
|
|
119625
|
+
launchObject: isLaunchTrigger(active?.trigger) ? parseLaunchObject(legacy?.smbLaunchObject) : void 0
|
|
119626
|
+
};
|
|
119627
|
+
};
|
|
119628
|
+
var listDocflowProcesses = async (runAs = "person") => {
|
|
119629
|
+
const [nodes, membership, legacy] = await Promise.all([
|
|
119630
|
+
listCoreWorkflows(runAs),
|
|
119631
|
+
readMembership(),
|
|
119632
|
+
readLegacyWorkflows(runAs)
|
|
119633
|
+
]);
|
|
119634
|
+
const docflowNodes = nodes.filter((node) => isDocflowNode(node, membership, legacy));
|
|
119635
|
+
const versions = await readVersions(
|
|
119636
|
+
docflowNodes.map(({ id: id3 }) => id3),
|
|
119637
|
+
runAs
|
|
119638
|
+
);
|
|
119639
|
+
return docflowNodes.map(
|
|
119640
|
+
(node) => toProcess(node, versions.get(node.id), node.workspaceWorkflowId ? legacy.get(node.workspaceWorkflowId) : void 0)
|
|
119641
|
+
);
|
|
119642
|
+
};
|
|
119643
|
+
var findDocflowProcess = async (workflowId, runAs = "person") => (await listDocflowProcesses(runAs)).find(
|
|
119644
|
+
(process2) => process2.workflowId === workflowId || process2.workspaceWorkflowId === workflowId
|
|
119645
|
+
);
|
|
119646
|
+
|
|
119450
119647
|
// src/shared/workflow/publish-error.util.ts
|
|
119451
119648
|
var INVALID_STEP_PATTERN = /Step "([^"]+)" configuration is invalid/g;
|
|
119452
119649
|
var describeUnfinishedSteps = (message) => {
|
|
@@ -119472,11 +119669,16 @@ var handler = async (event, context) => {
|
|
|
119472
119669
|
if (typeof workflowId !== "string" || workflowId.length === 0) {
|
|
119473
119670
|
return jsonResponse(400, { message: "\u041D\u0435 \u0443\u043A\u0430\u0437\u0430\u043D \u043F\u0440\u043E\u0446\u0435\u0441\u0441" });
|
|
119474
119671
|
}
|
|
119475
|
-
const
|
|
119476
|
-
if (
|
|
119672
|
+
const docflowProcess = await findDocflowProcess(workflowId, "person");
|
|
119673
|
+
if (docflowProcess === void 0) {
|
|
119477
119674
|
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" });
|
|
119478
119675
|
}
|
|
119479
|
-
|
|
119676
|
+
if (docflowProcess.workspaceWorkflowId === null) {
|
|
119677
|
+
return jsonResponse(409, {
|
|
119678
|
+
message: "\u0412 \u044D\u0442\u043E\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 Twenty \u043F\u0440\u043E\u0446\u0435\u0441\u0441 \u043F\u0443\u0431\u043B\u0438\u043A\u0443\u0435\u0442\u0441\u044F \u0432 \u0435\u0433\u043E \u0440\u0435\u0434\u0430\u043A\u0442\u043E\u0440\u0435: \xAB\u041E\u0442\u043A\u0440\u044B\u0442\u044C \u0440\u0435\u0434\u0430\u043A\u0442\u043E\u0440\xBB \u2192 \xAB\u0410\u043A\u0442\u0438\u0432\u0438\u0440\u043E\u0432\u0430\u0442\u044C\xBB"
|
|
119679
|
+
});
|
|
119680
|
+
}
|
|
119681
|
+
const versions = await listWorkflowVersions("person", docflowProcess.workspaceWorkflowId);
|
|
119480
119682
|
const isActive = versions.some(({ status }) => status === "ACTIVE");
|
|
119481
119683
|
const version = isPublish ? versions.find(({ status }) => status === "DRAFT") ?? (isActive ? void 0 : versions.find(({ status }) => status === "DEACTIVATED")) : versions.find(({ status }) => status === "ACTIVE");
|
|
119482
119684
|
if (version === void 0) {
|
|
@@ -10,9 +10,9 @@ import {
|
|
|
10
10
|
CoreGraphqlError,
|
|
11
11
|
DEACTIVATE_WORKFLOW_VERSION_MUTATION,
|
|
12
12
|
} from 'src/shared/api/core-graphql.util';
|
|
13
|
-
import { DOCFLOW_SECTION } from 'src/shared/docflow.constants';
|
|
14
13
|
import { jsonResponse, readJsonBody, withRouteErrors } from 'src/server/http-response';
|
|
15
|
-
import {
|
|
14
|
+
import { findDocflowProcess } from 'src/server/process-catalog';
|
|
15
|
+
import { listWorkflowVersions } from 'src/server/records';
|
|
16
16
|
import { logDocflow, logDocflowError } from 'src/shared/log.util';
|
|
17
17
|
import { describeUnfinishedSteps } from 'src/shared/workflow/publish-error.util';
|
|
18
18
|
import { PUBLISH_PROCESS_LOGIC_FUNCTION_UNIVERSAL_IDENTIFIER } from 'src/universal-identifiers';
|
|
@@ -34,15 +34,23 @@ const handler = async (event: RoutePayload, context: LogicFunctionExecutionConte
|
|
|
34
34
|
return jsonResponse(400, { message: 'Не указан процесс' });
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
const
|
|
37
|
+
const docflowProcess = await findDocflowProcess(workflowId, 'person');
|
|
38
38
|
|
|
39
|
-
if (
|
|
39
|
+
if (docflowProcess === undefined) {
|
|
40
40
|
return jsonResponse(404, { message: 'Процесс документооборота не найден' });
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
// Twenty 2.50 publishes processes only in its own editor: it keeps no
|
|
44
|
+
// process records an app could publish by
|
|
45
|
+
if (docflowProcess.workspaceWorkflowId === null) {
|
|
46
|
+
return jsonResponse(409, {
|
|
47
|
+
message: 'В этой версии Twenty процесс публикуется в его редакторе: «Открыть редактор» → «Активировать»',
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
43
51
|
// Newest first. A process taken off without a draft since is published
|
|
44
52
|
// again from the version that was taken off.
|
|
45
|
-
const versions = await listWorkflowVersions('person',
|
|
53
|
+
const versions = await listWorkflowVersions('person', docflowProcess.workspaceWorkflowId);
|
|
46
54
|
const isActive = versions.some(({ status }) => status === 'ACTIVE');
|
|
47
55
|
const version = isPublish
|
|
48
56
|
? (versions.find(({ status }) => status === 'DRAFT') ??
|
|
@@ -1693,10 +1693,13 @@ var readUserMessage = (value) => {
|
|
|
1693
1693
|
};
|
|
1694
1694
|
var callCoreGraphql = async ({
|
|
1695
1695
|
query,
|
|
1696
|
-
variables
|
|
1696
|
+
variables,
|
|
1697
|
+
runAs = "person"
|
|
1697
1698
|
}) => {
|
|
1698
1699
|
const apiUrl = process.env.TWENTY_API_URL;
|
|
1699
|
-
const
|
|
1700
|
+
const personToken = process.env.TWENTY_APP_ACCESS_TOKEN;
|
|
1701
|
+
const applicationToken = process.env.TWENTY_APP_APPLICATION_ACCESS_TOKEN;
|
|
1702
|
+
const token = runAs === "person" ? personToken ?? applicationToken : applicationToken ?? personToken;
|
|
1700
1703
|
if (apiUrl === void 0 || token === void 0) {
|
|
1701
1704
|
throw new CoreGraphqlError(
|
|
1702
1705
|
"TWENTY_API_URL or TWENTY_APP_ACCESS_TOKEN is not set",
|
|
@@ -119387,10 +119387,13 @@ var readUserMessage = (value) => {
|
|
|
119387
119387
|
};
|
|
119388
119388
|
var callCoreGraphql = async ({
|
|
119389
119389
|
query,
|
|
119390
|
-
variables
|
|
119390
|
+
variables,
|
|
119391
|
+
runAs = "person"
|
|
119391
119392
|
}) => {
|
|
119392
119393
|
const apiUrl = process.env.TWENTY_API_URL;
|
|
119393
|
-
const
|
|
119394
|
+
const personToken = process.env.TWENTY_APP_ACCESS_TOKEN;
|
|
119395
|
+
const applicationToken = process.env.TWENTY_APP_APPLICATION_ACCESS_TOKEN;
|
|
119396
|
+
const token = runAs === "person" ? personToken ?? applicationToken : applicationToken ?? personToken;
|
|
119394
119397
|
if (apiUrl === void 0 || token === void 0) {
|
|
119395
119398
|
throw new CoreGraphqlError(
|
|
119396
119399
|
"TWENTY_API_URL or TWENTY_APP_ACCESS_TOKEN is not set",
|