@haiiro/docuflow 0.0.11 → 0.0.13

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.
Files changed (33) hide show
  1. package/README.md +45 -9
  2. package/manifest.json +117 -16
  3. package/package.json +6 -3
  4. package/public/app/docflow-app.css +2 -0
  5. package/public/app/docflow-app.js +94 -0
  6. package/src/front-components/docflow-documents.front-component.mjs +42 -42
  7. package/src/front-components/docflow-documents.front-component.tsx +336 -128
  8. package/src/front-components/docflow-processes.front-component.mjs +35 -35
  9. package/src/front-components/docflow-processes.front-component.tsx +527 -131
  10. package/src/front-components/docflow-tasks.front-component.mjs +46 -41
  11. package/src/front-components/docflow-tasks.front-component.tsx +489 -132
  12. package/src/front-components/launch-process.front-component.mjs +75 -0
  13. package/src/front-components/launch-process.front-component.tsx +270 -0
  14. package/src/front-components/process-steps.front-component.mjs +25 -25
  15. package/src/front-components/process-steps.front-component.tsx +55 -10
  16. package/src/front-components/task-form.front-component.mjs +46 -41
  17. package/src/logic-functions/bitrix-app.logic-function.mjs +424 -198
  18. package/src/logic-functions/bitrix-app.logic-function.ts +54 -82
  19. package/src/logic-functions/bitrix-install.logic-function.mjs +0 -11
  20. package/src/logic-functions/bitrix-install.logic-function.ts +0 -3
  21. package/src/logic-functions/capture-file.logic-function.mjs +2 -1
  22. package/src/logic-functions/docflow-app-session.logic-function.mjs +60043 -0
  23. package/src/logic-functions/docflow-app-session.logic-function.ts +54 -0
  24. package/src/logic-functions/docflow-app.logic-function.mjs +60122 -0
  25. package/src/logic-functions/docflow-app.logic-function.ts +37 -0
  26. package/src/logic-functions/hand-out-form-step.logic-function.mjs +2 -1
  27. package/src/logic-functions/launch-process.logic-function.mjs +113 -29
  28. package/src/logic-functions/launch-process.logic-function.ts +83 -22
  29. package/src/logic-functions/on-workflow-run-updated.logic-function.mjs +2 -1
  30. package/src/logic-functions/publish-process.logic-function.mjs +119519 -0
  31. package/src/logic-functions/publish-process.logic-function.ts +91 -0
  32. package/src/logic-functions/save-launch-fields.logic-function.mjs +178 -10
  33. package/src/logic-functions/save-launch-fields.logic-function.ts +24 -6
@@ -0,0 +1,91 @@
1
+ import { defineLogicFunction } from 'twenty-sdk/define';
2
+ import {
3
+ type LogicFunctionExecutionContext,
4
+ type RoutePayload,
5
+ } from 'twenty-sdk/logic-function';
6
+
7
+ import {
8
+ ACTIVATE_WORKFLOW_VERSION_MUTATION,
9
+ callCoreGraphql,
10
+ CoreGraphqlError,
11
+ DEACTIVATE_WORKFLOW_VERSION_MUTATION,
12
+ } from 'src/shared/api/core-graphql.util';
13
+ import { DOCFLOW_SECTION } from 'src/shared/docflow.constants';
14
+ import { jsonResponse, readJsonBody } from 'src/server/http-response';
15
+ import { getWorkflow, listWorkflowVersions } from 'src/server/records';
16
+ import { logDocflow, logDocflowError } from 'src/shared/log.util';
17
+ import { PUBLISH_PROCESS_LOGIC_FUNCTION_UNIVERSAL_IDENTIFIER } from 'src/universal-identifiers';
18
+
19
+ // "Опубликовать" and "Снять с публикации" from the processes page, as the
20
+ // editor's "Активировать" and "Деактивировать": the draft becomes the version
21
+ // people launch, or the published version stops. Done as the person, so the
22
+ // "Workflows" permission decides.
23
+ const handler = async (event: RoutePayload, context: LogicFunctionExecutionContext) => {
24
+ if (context.workspaceMemberId === null) {
25
+ return jsonResponse(401, { message: 'Публиковать процессы может только сотрудник' });
26
+ }
27
+
28
+ const body = readJsonBody(event.body);
29
+ const workflowId = body.workflowId;
30
+ const isPublish = body.publish === true;
31
+
32
+ if (typeof workflowId !== 'string' || workflowId.length === 0) {
33
+ return jsonResponse(400, { message: 'Не указан процесс' });
34
+ }
35
+
36
+ const workflow = await getWorkflow('person', workflowId);
37
+
38
+ if (workflow?.smbSection !== DOCFLOW_SECTION) {
39
+ return jsonResponse(404, { message: 'Процесс документооборота не найден' });
40
+ }
41
+
42
+ // Newest first. A process taken off without a draft since is published
43
+ // again from the version that was taken off.
44
+ const versions = await listWorkflowVersions('person', workflowId);
45
+ const isActive = versions.some(({ status }) => status === 'ACTIVE');
46
+ const version = isPublish
47
+ ? (versions.find(({ status }) => status === 'DRAFT') ??
48
+ (isActive ? undefined : versions.find(({ status }) => status === 'DEACTIVATED')))
49
+ : versions.find(({ status }) => status === 'ACTIVE');
50
+
51
+ if (version === undefined) {
52
+ return jsonResponse(409, {
53
+ message: isPublish ? 'Нечего публиковать: изменений после публикации нет' : 'Процесс не опубликован',
54
+ });
55
+ }
56
+
57
+ try {
58
+ await callCoreGraphql({
59
+ query: isPublish ? ACTIVATE_WORKFLOW_VERSION_MUTATION : DEACTIVATE_WORKFLOW_VERSION_MUTATION,
60
+ variables: { workflowVersionId: version.id },
61
+ });
62
+ } catch (error) {
63
+ logDocflowError('publish: engine refused', error, { workflowId, isPublish });
64
+
65
+ return jsonResponse(422, {
66
+ message:
67
+ error instanceof CoreGraphqlError && error.userMessage !== undefined
68
+ ? error.userMessage
69
+ : isPublish
70
+ ? 'Процесс не опубликован: проверьте его шаги в редакторе'
71
+ : 'Не удалось снять процесс с публикации',
72
+ });
73
+ }
74
+
75
+ logDocflow('publish: done', { workflowId, workflowVersionId: version.id, isPublish });
76
+
77
+ return { status: isPublish ? 'PUBLISHED' : 'UNPUBLISHED' };
78
+ };
79
+
80
+ export default defineLogicFunction({
81
+ universalIdentifier: PUBLISH_PROCESS_LOGIC_FUNCTION_UNIVERSAL_IDENTIFIER,
82
+ name: 'docflow-publish-process',
83
+ description: 'Публикует процесс документооборота или снимает его с публикации',
84
+ timeoutSeconds: 30,
85
+ handler,
86
+ httpRouteTriggerSettings: {
87
+ path: '/docflow/processes/publish',
88
+ httpMethod: 'POST',
89
+ isAuthRequired: true,
90
+ },
91
+ });
@@ -1734,6 +1734,66 @@ var CREATE_DRAFT_FROM_WORKFLOW_VERSION_MUTATION = `mutation CreateDraftFromWorkf
1734
1734
  createDraftFromWorkflowVersion(input: $input) { id }
1735
1735
  }`;
1736
1736
 
1737
+ // src/shared/api/object-summaries.ts
1738
+ import { MetadataApiClient } from "twenty-client-sdk/metadata";
1739
+ var OBJECTS_PAGE_SIZE = 100;
1740
+ var listLaunchObjects = async () => {
1741
+ const client = new MetadataApiClient();
1742
+ const launchObjects = [];
1743
+ let after;
1744
+ do {
1745
+ const { objects } = await client.query({
1746
+ objects: {
1747
+ __args: {
1748
+ paging: { first: OBJECTS_PAGE_SIZE, ...after !== void 0 ? { after } : {} },
1749
+ filter: { isActive: { is: true }, isSystem: { is: false } }
1750
+ },
1751
+ pageInfo: { hasNextPage: true, endCursor: true },
1752
+ edges: {
1753
+ node: {
1754
+ id: true,
1755
+ nameSingular: true,
1756
+ namePlural: true,
1757
+ labelSingular: true,
1758
+ icon: true,
1759
+ fieldsList: {
1760
+ id: true,
1761
+ name: true,
1762
+ label: true,
1763
+ type: true,
1764
+ icon: true,
1765
+ isActive: true,
1766
+ isSystem: true,
1767
+ relation: { type: true }
1768
+ }
1769
+ }
1770
+ }
1771
+ }
1772
+ });
1773
+ for (const { node } of objects.edges) {
1774
+ launchObjects.push({
1775
+ id: node.id,
1776
+ nameSingular: node.nameSingular,
1777
+ namePlural: node.namePlural,
1778
+ labelSingular: node.labelSingular,
1779
+ icon: node.icon,
1780
+ fields: (node.fieldsList ?? []).map((field) => ({
1781
+ id: field.id,
1782
+ name: field.name,
1783
+ label: field.label,
1784
+ type: String(field.type),
1785
+ icon: field.icon,
1786
+ isActive: field.isActive,
1787
+ isSystem: field.isSystem,
1788
+ relationType: field.relation?.type ?? null
1789
+ }))
1790
+ });
1791
+ }
1792
+ after = objects.pageInfo.hasNextPage === true ? objects.pageInfo.endCursor ?? void 0 : void 0;
1793
+ } while (after !== void 0);
1794
+ return launchObjects;
1795
+ };
1796
+
1737
1797
  // src/shared/api/rest-response.util.ts
1738
1798
  var readDataValue = (response) => {
1739
1799
  const data = response?.data;
@@ -1746,7 +1806,8 @@ var readRestList = (response) => {
1746
1806
  const value = readDataValue(response);
1747
1807
  return {
1748
1808
  records: Array.isArray(value) ? value : [],
1749
- pageInfo: response?.pageInfo ?? {}
1809
+ pageInfo: response?.pageInfo ?? {},
1810
+ totalCount: response?.totalCount
1750
1811
  };
1751
1812
  };
1752
1813
  var readRestRecord = (response) => {
@@ -1758,6 +1819,7 @@ var readRestRecord = (response) => {
1758
1819
  var DOCFLOW_LAUNCH_PARAMETERS_KEY = "smbDocflowParameters";
1759
1820
  var LAUNCH_PARAMETERS_STEP_INPUT = `{{trigger.${DOCFLOW_LAUNCH_PARAMETERS_KEY}}}`;
1760
1821
  var LAUNCH_TRIGGER_NAME = "\u0417\u0430\u043F\u0443\u0441\u043A \u0441 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u0430\u043C\u0438";
1822
+ var LAUNCH_RECORD_KEY = "record";
1761
1823
  var FORM_FIELD_ROLE_SETTING = "smbRole";
1762
1824
  var TRIGGER_STEP_ID = "trigger";
1763
1825
 
@@ -1800,6 +1862,8 @@ var isLaunchParametersStep = (step) => {
1800
1862
  var isLaunchTrigger = (trigger) => trigger?.type === "WEBHOOK" && trigger.name === LAUNCH_TRIGGER_NAME;
1801
1863
  var findLaunchParametersStep = (steps) => (steps ?? []).find(isLaunchParametersStep);
1802
1864
  var parseLaunchFields = (value) => getFillableFormFields(parseFormFields(value));
1865
+ var parseLaunchObject = (value) => typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
1866
+ var getLaunchFieldsError = (fields) => fields.some(({ name }) => name === LAUNCH_RECORD_KEY) ? `\u0418\u043C\u044F \u043F\u043E\u043B\u044F \xAB${LAUNCH_RECORD_KEY}\xBB \u0437\u0430\u043D\u044F\u0442\u043E: \u0442\u0430\u043A \u043F\u0440\u043E\u0446\u0435\u0441\u0441 \u043F\u043E\u043B\u0443\u0447\u0430\u0435\u0442 \u0437\u0430\u043F\u0438\u0441\u044C, \u043D\u0430 \u043A\u043E\u0442\u043E\u0440\u043E\u0439 \u0435\u0433\u043E \u0437\u0430\u043F\u0443\u0441\u0442\u0438\u043B\u0438` : void 0;
1803
1867
 
1804
1868
  // src/shared/form/form-field-builder.util.ts
1805
1869
  var OUTPUT_LEAF_TYPES = {
@@ -1830,6 +1894,96 @@ var buildFieldsExpectedBody = (fields) => Object.fromEntries(
1830
1894
  ])
1831
1895
  );
1832
1896
 
1897
+ // src/shared/workflow/launch-record.util.ts
1898
+ var COMPOSITE_PARTS = {
1899
+ ACTOR: [["source", "SELECT"], ["workspaceMemberId", "UUID"], ["name", "TEXT"], ["context", "RAW_JSON"]],
1900
+ ADDRESS: [
1901
+ ["addressStreet1", "TEXT"],
1902
+ ["addressStreet2", "TEXT"],
1903
+ ["addressCity", "TEXT"],
1904
+ ["addressPostcode", "TEXT"],
1905
+ ["addressState", "TEXT"],
1906
+ ["addressCountry", "TEXT"],
1907
+ ["addressLat", "NUMERIC"],
1908
+ ["addressLng", "NUMERIC"]
1909
+ ],
1910
+ CURRENCY: [["amountMicros", "NUMERIC"], ["currencyCode", "TEXT"]],
1911
+ EMAILS: [["primaryEmail", "TEXT"], ["additionalEmails", "RAW_JSON"]],
1912
+ FULL_NAME: [["firstName", "TEXT"], ["lastName", "TEXT"]],
1913
+ LINKS: [["primaryLinkLabel", "TEXT"], ["primaryLinkUrl", "TEXT"], ["secondaryLinks", "RAW_JSON"]],
1914
+ PHONES: [
1915
+ ["primaryPhoneNumber", "TEXT"],
1916
+ ["primaryPhoneCountryCode", "TEXT"],
1917
+ ["primaryPhoneCallingCode", "TEXT"],
1918
+ ["additionalPhones", "RAW_JSON"]
1919
+ ],
1920
+ RICH_TEXT: [["blocknote", "TEXT"], ["markdown", "TEXT"]]
1921
+ };
1922
+ var EXCLUDED_SYSTEM_FIELDS = ["searchVector", "position"];
1923
+ var toTitleCase = (camelCase) => camelCase.replace(/([A-Z])/g, " $1").replace(/^./, (first) => first.toUpperCase());
1924
+ var buildFieldSchema = (field) => {
1925
+ const icon = field.icon ?? void 0;
1926
+ if (field.type === "RELATION") {
1927
+ return [
1928
+ [
1929
+ `${field.name}Id`,
1930
+ {
1931
+ isLeaf: true,
1932
+ icon,
1933
+ type: "UUID",
1934
+ label: toTitleCase(`${field.name}Id`),
1935
+ value: null,
1936
+ fieldMetadataId: field.id,
1937
+ isCompositeSubField: false
1938
+ }
1939
+ ]
1940
+ ];
1941
+ }
1942
+ const parts = COMPOSITE_PARTS[field.type];
1943
+ if (parts !== void 0) {
1944
+ return [
1945
+ [
1946
+ field.name,
1947
+ {
1948
+ isLeaf: false,
1949
+ icon,
1950
+ type: field.type,
1951
+ label: field.label,
1952
+ fieldMetadataId: field.id,
1953
+ value: Object.fromEntries(
1954
+ parts.map(([name, type]) => [
1955
+ name,
1956
+ { isLeaf: true, type, label: toTitleCase(name), value: null, fieldMetadataId: field.id, isCompositeSubField: true }
1957
+ ])
1958
+ )
1959
+ }
1960
+ ]
1961
+ ];
1962
+ }
1963
+ return [
1964
+ [
1965
+ field.name,
1966
+ { isLeaf: true, icon, type: field.type, label: field.label, value: null, fieldMetadataId: field.id, isCompositeSubField: false }
1967
+ ]
1968
+ ];
1969
+ };
1970
+ var isRecordVariable = (field) => field.isActive !== false && !(field.isSystem === true && EXCLUDED_SYSTEM_FIELDS.includes(field.name)) && field.type !== "MORPH_RELATION" && (field.type !== "RELATION" || field.relationType === "MANY_TO_ONE");
1971
+ var buildLaunchRecordOutputSchema = (object) => ({
1972
+ isLeaf: false,
1973
+ icon: object.icon ?? void 0,
1974
+ label: object.labelSingular,
1975
+ value: {
1976
+ object: {
1977
+ icon: object.icon ?? void 0,
1978
+ label: object.labelSingular,
1979
+ objectMetadataId: object.id,
1980
+ fieldIdName: "id"
1981
+ },
1982
+ fields: Object.fromEntries(object.fields.filter(isRecordVariable).flatMap(buildFieldSchema)),
1983
+ _outputSchemaType: "RECORD"
1984
+ }
1985
+ });
1986
+
1833
1987
  // node_modules/twenty-client-sdk/dist/chunk-Dqa2HsxW.mjs
1834
1988
  var e = Object.create;
1835
1989
  var t = Object.defineProperty;
@@ -61229,7 +61383,7 @@ var MANUAL_TRIGGER = {
61229
61383
  },
61230
61384
  nextStepIds: []
61231
61385
  };
61232
- var buildLaunchTrigger = (base, fields) => ({
61386
+ var buildLaunchTrigger = (base, fields, launchObject) => ({
61233
61387
  name: LAUNCH_TRIGGER_NAME,
61234
61388
  type: "WEBHOOK",
61235
61389
  position: base.position ?? { x: 0, y: 0 },
@@ -61237,12 +61391,19 @@ var buildLaunchTrigger = (base, fields) => ({
61237
61391
  settings: {
61238
61392
  httpMethod: "POST",
61239
61393
  authentication: "API_KEY",
61240
- expectedBody: buildFieldsExpectedBody(fields),
61241
- outputSchema: buildFieldsOutputSchema(fields)
61394
+ expectedBody: {
61395
+ ...buildFieldsExpectedBody(fields),
61396
+ ...launchObject !== void 0 ? { [LAUNCH_RECORD_KEY]: { id: "" } } : {}
61397
+ },
61398
+ outputSchema: {
61399
+ ...buildFieldsOutputSchema(fields),
61400
+ ...launchObject !== void 0 ? { [LAUNCH_RECORD_KEY]: buildLaunchRecordOutputSchema(launchObject) } : {}
61401
+ }
61242
61402
  }
61243
61403
  });
61244
61404
  var buildManualTrigger = (base) => ({
61245
61405
  ...MANUAL_TRIGGER,
61406
+ ...base.type === "MANUAL" ? { name: base.name ?? MANUAL_TRIGGER.name, settings: base.settings } : {},
61246
61407
  position: base.position ?? MANUAL_TRIGGER.position,
61247
61408
  nextStepIds: base.nextStepIds ?? []
61248
61409
  });
@@ -61297,7 +61458,8 @@ var removeLegacyLaunchStep = async (draft) => {
61297
61458
  };
61298
61459
  var syncLaunchTrigger = async ({
61299
61460
  workflowId,
61300
- fields
61461
+ fields,
61462
+ launchObject
61301
61463
  }) => {
61302
61464
  const draft = await findOrCreateDraft(workflowId);
61303
61465
  if (draft === void 0) {
@@ -61314,7 +61476,7 @@ var syncLaunchTrigger = async ({
61314
61476
  variables: {
61315
61477
  input: {
61316
61478
  workflowVersionId: draft.id,
61317
- trigger: fields.length > 0 ? buildLaunchTrigger(trigger, fields) : buildManualTrigger(trigger)
61479
+ trigger: fields.length > 0 || launchObject !== void 0 ? buildLaunchTrigger(trigger, fields, launchObject) : buildManualTrigger(trigger)
61318
61480
  }
61319
61481
  }
61320
61482
  });
@@ -119621,23 +119783,29 @@ var handler = async (event) => {
119621
119783
  const body = readJsonBody(event.body);
119622
119784
  const workflowId = body.workflowId;
119623
119785
  const fields = parseLaunchFields(body.fields);
119786
+ const launchObjectName = parseLaunchObject(body.launchObject);
119624
119787
  if (typeof workflowId !== "string" || workflowId.length === 0 || !Array.isArray(body.fields)) {
119625
119788
  return jsonResponse(400, { message: "\u041D\u0435 \u0443\u043A\u0430\u0437\u0430\u043D \u043F\u0440\u043E\u0446\u0435\u0441\u0441 \u0438\u043B\u0438 \u043F\u043E\u043B\u044F" });
119626
119789
  }
119627
- const fieldsError = getFormFieldsError(fields);
119790
+ const fieldsError = getFormFieldsError(fields) ?? (launchObjectName !== void 0 ? getLaunchFieldsError(fields) : void 0);
119628
119791
  if (fieldsError !== void 0) {
119629
119792
  return jsonResponse(422, { message: fieldsError });
119630
119793
  }
119794
+ const launchObject = launchObjectName !== void 0 ? (await listLaunchObjects()).find(({ nameSingular }) => nameSingular === launchObjectName) : void 0;
119795
+ if (launchObjectName !== void 0 && launchObject === void 0) {
119796
+ return jsonResponse(422, { message: `\u041E\u0431\u044A\u0435\u043A\u0442 \xAB${launchObjectName}\xBB \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D` });
119797
+ }
119631
119798
  const workflow = readRestRecord(
119632
119799
  await restClient("person").patch(`/rest/workflows/${workflowId}`, {
119633
- smbLaunchFields: fields.length > 0 ? fields : null
119800
+ smbLaunchFields: fields.length > 0 ? fields : null,
119801
+ smbLaunchObject: launchObject?.nameSingular ?? null
119634
119802
  })
119635
119803
  );
119636
119804
  if (workflow === void 0) {
119637
119805
  return jsonResponse(404, { message: "\u041F\u0440\u043E\u0446\u0435\u0441\u0441 \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D" });
119638
119806
  }
119639
119807
  try {
119640
- const result = await syncLaunchTrigger({ workflowId, fields });
119808
+ const result = await syncLaunchTrigger({ workflowId, fields, launchObject });
119641
119809
  logDocflow("launch fields: draft synced", { workflowId, result });
119642
119810
  if (result?.status === "NOT_MANUAL") {
119643
119811
  return jsonResponse(409, {
@@ -119655,7 +119823,7 @@ var handler = async (event) => {
119655
119823
  var save_launch_fields_logic_function_default = defineLogicFunction({
119656
119824
  universalIdentifier: SAVE_LAUNCH_FIELDS_LOGIC_FUNCTION_UNIVERSAL_IDENTIFIER,
119657
119825
  name: "docflow-save-launch-fields",
119658
- description: "\u0421\u043E\u0445\u0440\u0430\u043D\u044F\u0435\u0442 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B \u0437\u0430\u043F\u0443\u0441\u043A\u0430 \u0438 \u0434\u0435\u043B\u0430\u0435\u0442 \u043F\u0435\u0440\u0432\u044B\u043C \u0431\u043B\u043E\u043A\u043E\u043C \u043F\u0440\u043E\u0446\u0435\u0441\u0441\u0430 \xAB\u0417\u0430\u043F\u0443\u0441\u043A \u0441 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u0430\u043C\u0438\xBB",
119826
+ description: "\u0421\u043E\u0445\u0440\u0430\u043D\u044F\u0435\u0442 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B \u0438 \u043E\u0431\u044A\u0435\u043A\u0442 \u0437\u0430\u043F\u0443\u0441\u043A\u0430 \u0438 \u0434\u0435\u043B\u0430\u0435\u0442 \u043F\u0435\u0440\u0432\u044B\u043C \u0431\u043B\u043E\u043A\u043E\u043C \u043F\u0440\u043E\u0446\u0435\u0441\u0441\u0430 \xAB\u0417\u0430\u043F\u0443\u0441\u043A \u0441 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u0430\u043C\u0438\xBB",
119659
119827
  timeoutSeconds: 30,
119660
119828
  handler,
119661
119829
  httpRouteTriggerSettings: {
@@ -2,37 +2,55 @@ import { defineLogicFunction } from 'twenty-sdk/define';
2
2
  import { type RoutePayload } from 'twenty-sdk/logic-function';
3
3
 
4
4
  import { CoreGraphqlError } from 'src/shared/api/core-graphql.util';
5
+ import { listLaunchObjects } from 'src/shared/api/object-summaries';
5
6
  import { readRestRecord } from 'src/shared/api/rest-response.util';
6
7
  import { getFormFieldsError } from 'src/shared/form/form-fields.util';
7
- import { parseLaunchFields } from 'src/shared/workflow/launch-step.util';
8
+ import {
9
+ getLaunchFieldsError,
10
+ parseLaunchFields,
11
+ parseLaunchObject,
12
+ } from 'src/shared/workflow/launch-step.util';
8
13
  import { syncLaunchTrigger } from 'src/server/launch-step';
9
14
  import { jsonResponse, readJsonBody } from 'src/server/http-response';
10
15
  import { restClient } from 'src/server/records';
11
16
  import { logDocflow, logDocflowError } from 'src/shared/log.util';
12
17
  import { SAVE_LAUNCH_FIELDS_LOGIC_FUNCTION_UNIVERSAL_IDENTIFIER } from 'src/universal-identifiers';
13
18
 
14
- // Saves the parameters of a process and puts them into its draft as the
15
- // "Запуск с параметрами" trigger, whose fields later steps read as variables.
19
+ // Saves the parameters of a process and the object it is launched on, and
20
+ // puts them into its draft as the "Запуск с параметрами" trigger, whose
21
+ // fields and record later steps read as variables.
16
22
  const handler = async (event: RoutePayload) => {
17
23
  const body = readJsonBody(event.body);
18
24
  const workflowId = body.workflowId;
19
25
  const fields = parseLaunchFields(body.fields);
26
+ const launchObjectName = parseLaunchObject(body.launchObject);
20
27
 
21
28
  if (typeof workflowId !== 'string' || workflowId.length === 0 || !Array.isArray(body.fields)) {
22
29
  return jsonResponse(400, { message: 'Не указан процесс или поля' });
23
30
  }
24
31
 
25
- const fieldsError = getFormFieldsError(fields);
32
+ const fieldsError =
33
+ getFormFieldsError(fields) ?? (launchObjectName !== undefined ? getLaunchFieldsError(fields) : undefined);
26
34
 
27
35
  if (fieldsError !== undefined) {
28
36
  return jsonResponse(422, { message: fieldsError });
29
37
  }
30
38
 
39
+ const launchObject =
40
+ launchObjectName !== undefined
41
+ ? (await listLaunchObjects()).find(({ nameSingular }) => nameSingular === launchObjectName)
42
+ : undefined;
43
+
44
+ if (launchObjectName !== undefined && launchObject === undefined) {
45
+ return jsonResponse(422, { message: `Объект «${launchObjectName}» не найден` });
46
+ }
47
+
31
48
  // Written as the person: who may not change the process gets the refusal
32
49
  // of the API, not a half-saved draft.
33
50
  const workflow = readRestRecord<{ id: string }>(
34
51
  await restClient('person').patch(`/rest/workflows/${workflowId}`, {
35
52
  smbLaunchFields: fields.length > 0 ? fields : null,
53
+ smbLaunchObject: launchObject?.nameSingular ?? null,
36
54
  }),
37
55
  );
38
56
 
@@ -41,7 +59,7 @@ const handler = async (event: RoutePayload) => {
41
59
  }
42
60
 
43
61
  try {
44
- const result = await syncLaunchTrigger({ workflowId, fields });
62
+ const result = await syncLaunchTrigger({ workflowId, fields, launchObject });
45
63
 
46
64
  logDocflow('launch fields: draft synced', { workflowId, result });
47
65
 
@@ -67,7 +85,7 @@ const handler = async (event: RoutePayload) => {
67
85
  export default defineLogicFunction({
68
86
  universalIdentifier: SAVE_LAUNCH_FIELDS_LOGIC_FUNCTION_UNIVERSAL_IDENTIFIER,
69
87
  name: 'docflow-save-launch-fields',
70
- description: 'Сохраняет параметры запуска и делает первым блоком процесса «Запуск с параметрами»',
88
+ description: 'Сохраняет параметры и объект запуска и делает первым блоком процесса «Запуск с параметрами»',
71
89
  timeoutSeconds: 30,
72
90
  handler,
73
91
  httpRouteTriggerSettings: {