@haiiro/docuflow 0.0.12 → 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 (26) hide show
  1. package/README.md +38 -8
  2. package/manifest.json +99 -13
  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 +3 -3
  7. package/src/front-components/docflow-processes.front-component.mjs +19 -19
  8. package/src/front-components/docflow-processes.front-component.tsx +18 -2
  9. package/src/front-components/docflow-tasks.front-component.mjs +3 -3
  10. package/src/front-components/launch-process.front-component.mjs +75 -0
  11. package/src/front-components/launch-process.front-component.tsx +270 -0
  12. package/src/front-components/process-steps.front-component.mjs +24 -24
  13. package/src/front-components/process-steps.front-component.tsx +54 -9
  14. package/src/front-components/task-form.front-component.mjs +21 -21
  15. package/src/logic-functions/bitrix-app.logic-function.mjs +160 -87
  16. package/src/logic-functions/bitrix-app.logic-function.ts +22 -59
  17. package/src/logic-functions/bitrix-install.logic-function.mjs +0 -11
  18. package/src/logic-functions/bitrix-install.logic-function.ts +0 -3
  19. package/src/logic-functions/docflow-app-session.logic-function.mjs +60043 -0
  20. package/src/logic-functions/docflow-app-session.logic-function.ts +54 -0
  21. package/src/logic-functions/docflow-app.logic-function.mjs +60122 -0
  22. package/src/logic-functions/docflow-app.logic-function.ts +37 -0
  23. package/src/logic-functions/launch-process.logic-function.mjs +113 -29
  24. package/src/logic-functions/launch-process.logic-function.ts +83 -22
  25. package/src/logic-functions/save-launch-fields.logic-function.mjs +176 -9
  26. package/src/logic-functions/save-launch-fields.logic-function.ts +24 -6
@@ -1673,42 +1673,6 @@ var __anyHandler = {
1673
1673
  var __anyStub = new Proxy(() => void 0, __anyHandler);
1674
1674
  var defineLogicFunction = __defineFactoryStub;
1675
1675
 
1676
- // src/shared/api/rest-filter.util.ts
1677
- var UNSAFE_FILTER_CHARACTERS = /[()[\]'",]/g;
1678
- var sanitizeFilterText = (text) => text.replace(UNSAFE_FILTER_CHARACTERS, " ").trim();
1679
- var quote = (value) => `'${sanitizeFilterText(value)}'`;
1680
- var restEq = (field, value) => `${field}[eq]:${quote(value)}`;
1681
- var restNeq = (field, value) => `${field}[neq]:${quote(value)}`;
1682
- var restIsNull = (field) => `${field}[is]:NULL`;
1683
- var restAnd = (...conditions) => {
1684
- const present = conditions.filter(
1685
- (condition) => condition !== void 0
1686
- );
1687
- return present.length === 0 ? void 0 : `and(${present.join(",")})`;
1688
- };
1689
- var restOr = (...conditions) => `or(${conditions.join(",")})`;
1690
-
1691
- // src/shared/api/rest-response.util.ts
1692
- var readDataValue = (response) => {
1693
- const data = response?.data;
1694
- if (typeof data !== "object" || data === null) {
1695
- return void 0;
1696
- }
1697
- return Object.values(data)[0];
1698
- };
1699
- var readRestList = (response) => {
1700
- const value = readDataValue(response);
1701
- return {
1702
- records: Array.isArray(value) ? value : [],
1703
- pageInfo: response?.pageInfo ?? {},
1704
- totalCount: response?.totalCount
1705
- };
1706
- };
1707
- var readRestRecord = (response) => {
1708
- const value = readDataValue(response);
1709
- return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
1710
- };
1711
-
1712
1676
  // src/shared/bitrix/bitrix.util.ts
1713
1677
  var BITRIX_OAUTH_TOKEN_URL = "https://oauth.bitrix.info/oauth/token/";
1714
1678
  var BITRIX_PORTAL_KV_KEY = "bitrix:portal";
@@ -1844,15 +1808,42 @@ var callBitrix = async ({
1844
1808
  return body.result;
1845
1809
  };
1846
1810
 
1847
- // src/shared/docflow.constants.ts
1848
- var DOCFLOW_SECTION = "DOCFLOW";
1849
- var DOCFLOW_LAUNCH_PARAMETERS_KEY = "smbDocflowParameters";
1850
- var LAUNCH_PARAMETERS_STEP_INPUT = `{{trigger.${DOCFLOW_LAUNCH_PARAMETERS_KEY}}}`;
1851
- var TASK_DONE_STATUS = "DONE";
1811
+ // src/shared/app/docflow-app.util.ts
1812
+ var DOCFLOW_APP_SECTIONS = ["tasks", "processes", "documents"];
1813
+ var readDocflowAppSection = (value) => DOCFLOW_APP_SECTIONS.find((section) => section === value) ?? "tasks";
1814
+ var SESSION_RENEW_BEFORE_MS = 10 * 60 * 1e3;
1815
+ var SESSION_EXPIRY_MARGIN_MS = 60 * 1e3;
1852
1816
 
1853
1817
  // src/server/bitrix-member.ts
1854
1818
  import { randomBytes } from "node:crypto";
1855
1819
 
1820
+ // src/shared/api/rest-filter.util.ts
1821
+ var UNSAFE_FILTER_CHARACTERS = /[()[\]'",]/g;
1822
+ var sanitizeFilterText = (text) => text.replace(UNSAFE_FILTER_CHARACTERS, " ").trim();
1823
+ var quote = (value) => `'${sanitizeFilterText(value)}'`;
1824
+ var restEq = (field, value) => `${field}[eq]:${quote(value)}`;
1825
+
1826
+ // src/shared/api/rest-response.util.ts
1827
+ var readDataValue = (response) => {
1828
+ const data = response?.data;
1829
+ if (typeof data !== "object" || data === null) {
1830
+ return void 0;
1831
+ }
1832
+ return Object.values(data)[0];
1833
+ };
1834
+ var readRestList = (response) => {
1835
+ const value = readDataValue(response);
1836
+ return {
1837
+ records: Array.isArray(value) ? value : [],
1838
+ pageInfo: response?.pageInfo ?? {},
1839
+ totalCount: response?.totalCount
1840
+ };
1841
+ };
1842
+ var readRestRecord = (response) => {
1843
+ const value = readDataValue(response);
1844
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
1845
+ };
1846
+
1856
1847
  // src/shared/bitrix/bitrix-user.util.ts
1857
1848
  var readText = (value) => typeof value === "string" ? value.trim() : "";
1858
1849
  var readBitrixUserEmail = (user) => {
@@ -61229,6 +61220,10 @@ var u2 = class {
61229
61220
  }
61230
61221
  };
61231
61222
 
61223
+ // src/shared/docflow.constants.ts
61224
+ var DOCFLOW_LAUNCH_PARAMETERS_KEY = "smbDocflowParameters";
61225
+ var LAUNCH_PARAMETERS_STEP_INPUT = `{{trigger.${DOCFLOW_LAUNCH_PARAMETERS_KEY}}}`;
61226
+
61232
61227
  // src/server/records.ts
61233
61228
  var clients = {
61234
61229
  person: new u2(),
@@ -119722,7 +119717,6 @@ var renderBitrixPage = ({
119722
119717
  title,
119723
119718
  message,
119724
119719
  crmUrl,
119725
- tasks,
119726
119720
  isInstall
119727
119721
  }) => `<!doctype html>
119728
119722
  <html lang="ru">
@@ -119736,23 +119730,129 @@ var renderBitrixPage = ({
119736
119730
  h1 { font-size: 20px; margin: 0 0 8px; }
119737
119731
  p { color: #666; margin: 0 0 16px; }
119738
119732
  a.button { display: inline-block; padding: 8px 16px; border-radius: 8px; background: #1961ed; color: #fff; text-decoration: none; }
119739
- ul { list-style: none; padding: 0; margin: 16px 0 0; }
119740
- li { padding: 8px 0; border-top: 1px solid #eee; display: flex; justify-content: space-between; gap: 16px; }
119741
- li a { color: #1961ed; text-decoration: none; }
119742
- .due { color: #999; white-space: nowrap; }
119743
119733
  </style>
119744
119734
  </head>
119745
119735
  <body>
119746
119736
  <h1>${escapeHtml(title)}</h1>
119747
119737
  <p>${escapeHtml(message)}</p>
119748
119738
  ${crmUrl !== void 0 ? `<a class="button" href="${escapeHtml(crmUrl)}" target="_blank" rel="noopener">\u041E\u0442\u043A\u0440\u044B\u0442\u044C \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u043E\u043E\u0431\u043E\u0440\u043E\u0442</a>` : ""}
119749
- ${tasks.length > 0 ? `<ul>${tasks.map(
119750
- (task) => `<li>${task.url !== void 0 ? `<a href="${escapeHtml(task.url)}" target="_blank" rel="noopener">${escapeHtml(task.title)}</a>` : escapeHtml(task.title)}<span class="due">${escapeHtml(task.dueAt ?? "")}</span></li>`
119751
- ).join("")}</ul>` : ""}
119752
119739
  ${isInstall ? "<script>if (window.BX24) { BX24.init(function () { BX24.installFinish(); }); }</script>" : ""}
119753
119740
  </body>
119754
119741
  </html>`;
119755
119742
 
119743
+ // src/server/crm-url.ts
119744
+ var getCrmUrl = () => {
119745
+ const value = process.env.CRM_PUBLIC_URL?.trim();
119746
+ return value !== void 0 && /^https?:\/\//.test(value) ? value.replace(/\/$/, "") : void 0;
119747
+ };
119748
+
119749
+ // package.json
119750
+ var package_default = {
119751
+ name: "@haiiro/docuflow",
119752
+ version: "0.0.13",
119753
+ description: "NorDiv \u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u043E\u043E\u0431\u043E\u0440\u043E\u0442: \u0437\u0430\u0434\u0430\u043D\u0438\u044F \u0441 \u043F\u043E\u043B\u044F\u043C\u0438, \u043F\u0440\u043E\u0446\u0435\u0441\u0441\u044B \u0441 \u0437\u0430\u043F\u0443\u0441\u043A\u043E\u043C \u043F\u043E \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u0430\u043C, \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u044B \u0441\u043E \u0432\u0441\u0435\u0445 \u0437\u0430\u043F\u0438\u0441\u0435\u0439, \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u0411\u0438\u0442\u0440\u0438\u043A\u044124",
119754
+ license: "AGPL-3.0-only",
119755
+ publishConfig: {
119756
+ access: "public",
119757
+ registry: "https://registry.npmjs.org/"
119758
+ },
119759
+ bin: {
119760
+ "nordiv-docuflow": "bin/install.mjs"
119761
+ },
119762
+ files: [
119763
+ "bin/**/*",
119764
+ "manifest.json",
119765
+ "front-component-shared-dependencies.mjs",
119766
+ "yarn.lock",
119767
+ "src/**/*",
119768
+ "public/**/*",
119769
+ "README.md",
119770
+ "tsconfig.json",
119771
+ "tsconfig.spec.json",
119772
+ "vitest.unit.config.ts",
119773
+ ".oxlintrc.json",
119774
+ ".nvmrc",
119775
+ ".yarnrc.yml",
119776
+ "!**/*.map",
119777
+ "!**/__tests__/**"
119778
+ ],
119779
+ engines: {
119780
+ node: "^24.5.0",
119781
+ npm: "please-use-yarn",
119782
+ yarn: ">=4.0.2"
119783
+ },
119784
+ keywords: [
119785
+ "twenty-app"
119786
+ ],
119787
+ packageManager: "yarn@4.13.0",
119788
+ scripts: {
119789
+ twenty: "twenty",
119790
+ app: "twenty",
119791
+ build: "yarn build:app && twenty dev:build",
119792
+ lint: "oxlint -c .oxlintrc.json .",
119793
+ "lint:fix": "oxlint --fix -c .oxlintrc.json .",
119794
+ typecheck: "tsc --noEmit -p tsconfig.spec.json",
119795
+ test: "vitest run --config vitest.unit.config.ts",
119796
+ "build:app": "vite build --config vite.app.config.ts"
119797
+ },
119798
+ devDependencies: {
119799
+ "@types/node": "^24.7.2",
119800
+ "@types/react": "^19.0.0",
119801
+ "@types/react-dom": "^19.0.0",
119802
+ oxlint: "^0.16.0",
119803
+ react: "^19.0.0",
119804
+ "react-dom": "^19.0.0",
119805
+ "twenty-client-sdk": "2.45.0",
119806
+ "twenty-sdk": "2.45.0",
119807
+ "twenty-ui": "2.45.0",
119808
+ typescript: "^5.9.3",
119809
+ vite: "^8.0.0",
119810
+ "vite-tsconfig-paths": "^4.2.1",
119811
+ vitest: "^4.0.0"
119812
+ },
119813
+ frontComponentSharedDependencies: [
119814
+ "react",
119815
+ "react-dom/client",
119816
+ "twenty-ui/primitives/input",
119817
+ "twenty-ui/primitives/data-display",
119818
+ "twenty-ui/theme",
119819
+ "twenty-ui/icon"
119820
+ ]
119821
+ };
119822
+
119823
+ // src/server/docflow-app-page.ts
119824
+ var BX24_SDK_URL2 = "https://api.bitrix24.com/api/v1/";
119825
+ var buildAssetUrl = (workspaceId, file) => `/public-assets/${workspaceId}/${process.env.APPLICATION_ID ?? ""}/public/app/${file}?v=${encodeURIComponent(package_default.version)}`;
119826
+ var serializeConfig = (config) => JSON.stringify(config).replace(/</g, "\\u003c");
119827
+ var renderDocflowAppPage = ({
119828
+ workspaceId,
119829
+ config
119830
+ }) => new AL(
119831
+ `<!doctype html>
119832
+ <html lang="ru" class="dark">
119833
+ <head>
119834
+ <meta charset="utf-8">
119835
+ <meta name="viewport" content="width=device-width, initial-scale=1">
119836
+ <title>\u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u043E\u043E\u0431\u043E\u0440\u043E\u0442</title>
119837
+ <link rel="stylesheet" href="${escapeHtml(buildAssetUrl(workspaceId, "docflow-app.css"))}">
119838
+ <style>html, body, #root { height: 100%; margin: 0; } body { font-family: Inter, -apple-system, "Segoe UI", Roboto, sans-serif; }</style>
119839
+ ${config.mode === "bitrix" ? `<script src="${BX24_SDK_URL2}"></script>` : ""}
119840
+ <script id="docflow-app-config" type="application/json">${serializeConfig(config)}</script>
119841
+ </head>
119842
+ <body>
119843
+ <div id="root"></div>
119844
+ <script src="${escapeHtml(buildAssetUrl(workspaceId, "docflow-app.js"))}"></script>
119845
+ </body>
119846
+ </html>`,
119847
+ {
119848
+ status: 200,
119849
+ headers: {
119850
+ "content-type": "text/html; charset=utf-8",
119851
+ "cache-control": "no-store"
119852
+ }
119853
+ }
119854
+ );
119855
+
119756
119856
  // src/server/http-response.ts
119757
119857
  var htmlResponse = (status, html) => new AL(html, {
119758
119858
  status,
@@ -119763,29 +119863,7 @@ var htmlResponse = (status, html) => new AL(html, {
119763
119863
  var BITRIX_APP_LOGIC_FUNCTION_UNIVERSAL_IDENTIFIER = "00fa5cea-d57b-4215-980a-c4bed9232a4f";
119764
119864
 
119765
119865
  // src/logic-functions/bitrix-app.logic-function.ts
119766
- var TASKS_SHOWN_IN_PORTAL = 20;
119767
- var getCrmUrl = () => {
119768
- const value = process.env.CRM_PUBLIC_URL?.trim();
119769
- return value !== void 0 && /^https?:\/\//.test(value) ? value.replace(/\/$/, "") : void 0;
119770
- };
119771
- var listOpenTasksForMember = async (memberId, crmUrl) => readRestList(
119772
- await restClient("application").get("/rest/tasks", {
119773
- query: {
119774
- filter: restAnd(
119775
- restEq("smbSection", DOCFLOW_SECTION),
119776
- restEq("assigneeId", memberId),
119777
- restOr(restNeq("status", TASK_DONE_STATUS), restIsNull("status"))
119778
- ),
119779
- order_by: "dueAt[AscNullsLast]",
119780
- limit: TASKS_SHOWN_IN_PORTAL
119781
- }
119782
- })
119783
- ).records.map((task) => ({
119784
- title: task.title?.trim() || "\u0411\u0435\u0437 \u043D\u0430\u0437\u0432\u0430\u043D\u0438\u044F",
119785
- url: crmUrl !== void 0 ? `${crmUrl}/object/task/${task.id}` : void 0,
119786
- dueAt: typeof task.dueAt === "string" ? new Date(task.dueAt).toLocaleDateString("ru-RU") : void 0
119787
- }));
119788
- var handler = async (event) => {
119866
+ var handler = async (event, context) => {
119789
119867
  const crmUrl = getCrmUrl();
119790
119868
  if (!isBitrixConfigured()) {
119791
119869
  return htmlResponse(
@@ -119794,7 +119872,6 @@ var handler = async (event) => {
119794
119872
  title: "\u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u043E\u043E\u0431\u043E\u0440\u043E\u0442",
119795
119873
  message: "\u0412 \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0430\u0445 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u044F \u0432 CRM \u043D\u0435 \u0443\u043A\u0430\u0437\u0430\u043D\u044B BITRIX_CLIENT_ID \u0438 BITRIX_CLIENT_SECRET.",
119796
119874
  crmUrl,
119797
- tasks: [],
119798
119875
  isInstall: false
119799
119876
  })
119800
119877
  );
@@ -119820,22 +119897,20 @@ var handler = async (event) => {
119820
119897
  title: "\u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u043E\u043E\u0431\u043E\u0440\u043E\u0442",
119821
119898
  message: "\u0412 \u043F\u0440\u043E\u0444\u0438\u043B\u0435 \u0411\u0438\u0442\u0440\u0438\u043A\u044124 \u043D\u0435\u0442 \u043F\u043E\u0447\u0442\u044B \u2014 \u0431\u0435\u0437 \u043D\u0435\u0451 \u043D\u0435\u043B\u044C\u0437\u044F \u043D\u0430\u0439\u0442\u0438 \u0438\u043B\u0438 \u0441\u043E\u0437\u0434\u0430\u0442\u044C \u0441\u043E\u0442\u0440\u0443\u0434\u043D\u0438\u043A\u0430 \u0432 CRM.",
119822
119899
  crmUrl,
119823
- tasks: [],
119824
119900
  isInstall: false
119825
119901
  })
119826
119902
  );
119827
119903
  }
119828
- const tasks = await listOpenTasksForMember(member.id, crmUrl);
119829
- return htmlResponse(
119830
- 200,
119831
- renderBitrixPage({
119832
- title: "\u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u043E\u043E\u0431\u043E\u0440\u043E\u0442",
119833
- message: tasks.length === 0 ? "\u041E\u0442\u043A\u0440\u044B\u0442\u044B\u0445 \u0437\u0430\u0434\u0430\u043D\u0438\u0439 \u043D\u0435\u0442." : "\u0412\u0430\u0448\u0438 \u043E\u0442\u043A\u0440\u044B\u0442\u044B\u0435 \u0437\u0430\u0434\u0430\u043D\u0438\u044F:",
119834
- crmUrl,
119835
- tasks,
119836
- isInstall: false
119837
- })
119838
- );
119904
+ return renderDocflowAppPage({
119905
+ workspaceId: context.workspaceId,
119906
+ config: {
119907
+ mode: "bitrix",
119908
+ crmUrl: crmUrl ?? "",
119909
+ section: readDocflowAppSection(event.queryStringParameters.section),
119910
+ expectedWorkspaceMemberId: member.id,
119911
+ portalDomain: portal.portalDomain
119912
+ }
119913
+ });
119839
119914
  } catch (error) {
119840
119915
  if (error instanceof BitrixError) {
119841
119916
  return htmlResponse(
@@ -119844,7 +119919,6 @@ var handler = async (event) => {
119844
119919
  title: "\u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u043E\u043E\u0431\u043E\u0440\u043E\u0442",
119845
119920
  message: `\u0417\u0430\u043F\u0440\u043E\u0441 \u043F\u043E\u0440\u0442\u0430\u043B\u0430 \u043D\u0435 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0451\u043D: ${error.message}`,
119846
119921
  crmUrl,
119847
- tasks: [],
119848
119922
  isInstall: false
119849
119923
  })
119850
119924
  );
@@ -119855,7 +119929,6 @@ var handler = async (event) => {
119855
119929
  title: "\u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u043E\u043E\u0431\u043E\u0440\u043E\u0442",
119856
119930
  message: error instanceof Error ? error.message : "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043E\u0442\u043A\u0440\u044B\u0442\u044C \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u043E\u043E\u0431\u043E\u0440\u043E\u0442 \u0434\u043B\u044F \u0432\u0430\u0448\u0435\u0433\u043E \u043F\u0440\u043E\u0444\u0438\u043B\u044F \u0411\u0438\u0442\u0440\u0438\u043A\u044124.",
119857
119931
  crmUrl,
119858
- tasks: [],
119859
119932
  isInstall: false
119860
119933
  })
119861
119934
  );
@@ -1,57 +1,26 @@
1
1
  import { defineLogicFunction } from 'twenty-sdk/define';
2
- import { type RoutePayload } from 'twenty-sdk/logic-function';
2
+ import {
3
+ type LogicFunctionExecutionContext,
4
+ type RoutePayload,
5
+ } from 'twenty-sdk/logic-function';
3
6
 
4
- import { restAnd, restEq, restIsNull, restNeq, restOr } from 'src/shared/api/rest-filter.util';
5
- import { readRestList } from 'src/shared/api/rest-response.util';
6
7
  import { BitrixError, callBitrix, isBitrixConfigured } from 'src/shared/bitrix/bitrix-client';
7
8
  import { type BitrixUserProfile } from 'src/shared/bitrix/bitrix-user.util';
8
9
  import { parseBitrixRequest } from 'src/shared/bitrix/bitrix.util';
9
- import { DOCFLOW_SECTION, TASK_DONE_STATUS } from 'src/shared/docflow.constants';
10
+ import { readDocflowAppSection } from 'src/shared/app/docflow-app.util';
10
11
  import { findOrCreateWorkspaceMemberFromBitrix } from 'src/server/bitrix-member';
11
12
  import { proveAndLinkBitrixPortal } from 'src/server/bitrix-portal';
12
- import { renderBitrixPage, type BitrixPageTask } from 'src/server/bitrix-page';
13
+ import { renderBitrixPage } from 'src/server/bitrix-page';
14
+ import { getCrmUrl } from 'src/server/crm-url';
15
+ import { renderDocflowAppPage } from 'src/server/docflow-app-page';
13
16
  import { htmlResponse } from 'src/server/http-response';
14
- import { restClient } from 'src/server/records';
15
17
  import { BITRIX_APP_LOGIC_FUNCTION_UNIVERSAL_IDENTIFIER } from 'src/universal-identifiers';
16
18
 
17
- const TASKS_SHOWN_IN_PORTAL = 20;
18
-
19
- const getCrmUrl = (): string | undefined => {
20
- const value = process.env.CRM_PUBLIC_URL?.trim();
21
-
22
- return value !== undefined && /^https?:\/\//.test(value)
23
- ? value.replace(/\/$/, '')
24
- : undefined;
25
- };
26
-
27
- const listOpenTasksForMember = async (
28
- memberId: string,
29
- crmUrl: string | undefined,
30
- ): Promise<BitrixPageTask[]> =>
31
- readRestList<{ id: string; title?: string | null; dueAt?: string | null }>(
32
- await restClient('application').get('/rest/tasks', {
33
- query: {
34
- filter: restAnd(
35
- restEq('smbSection', DOCFLOW_SECTION),
36
- restEq('assigneeId', memberId),
37
- restOr(restNeq('status', TASK_DONE_STATUS), restIsNull('status')),
38
- ),
39
- order_by: 'dueAt[AscNullsLast]',
40
- limit: TASKS_SHOWN_IN_PORTAL,
41
- },
42
- }),
43
- ).records.map((task) => ({
44
- title: task.title?.trim() || 'Без названия',
45
- url: crmUrl !== undefined ? `${crmUrl}/object/task/${task.id}` : undefined,
46
- dueAt:
47
- typeof task.dueAt === 'string'
48
- ? new Date(task.dueAt).toLocaleDateString('ru-RU')
49
- : undefined,
50
- }));
51
-
52
19
  // "Путь вашего обработчика" of the local Bitrix24 application: the page a
53
- // person sees when they open the app in the portal.
54
- const handler = async (event: RoutePayload) => {
20
+ // person sees when they open the app in the portal. After the portal and the
21
+ // person are checked it is the standalone docflow page; it signs in to the
22
+ // CRM itself (the portal frame gets no CRM cookie).
23
+ const handler = async (event: RoutePayload, context: LogicFunctionExecutionContext) => {
55
24
  const crmUrl = getCrmUrl();
56
25
 
57
26
  if (!isBitrixConfigured()) {
@@ -61,7 +30,6 @@ const handler = async (event: RoutePayload) => {
61
30
  title: 'Документооборот',
62
31
  message: 'В настройках приложения в CRM не указаны BITRIX_CLIENT_ID и BITRIX_CLIENT_SECRET.',
63
32
  crmUrl,
64
- tasks: [],
65
33
  isInstall: false,
66
34
  }),
67
35
  );
@@ -90,24 +58,21 @@ const handler = async (event: RoutePayload) => {
90
58
  title: 'Документооборот',
91
59
  message: 'В профиле Битрикс24 нет почты — без неё нельзя найти или создать сотрудника в CRM.',
92
60
  crmUrl,
93
- tasks: [],
94
61
  isInstall: false,
95
62
  }),
96
63
  );
97
64
  }
98
65
 
99
- const tasks = await listOpenTasksForMember(member.id, crmUrl);
100
-
101
- return htmlResponse(
102
- 200,
103
- renderBitrixPage({
104
- title: 'Документооборот',
105
- message: tasks.length === 0 ? 'Открытых заданий нет.' : 'Ваши открытые задания:',
106
- crmUrl,
107
- tasks,
108
- isInstall: false,
109
- }),
110
- );
66
+ return renderDocflowAppPage({
67
+ workspaceId: context.workspaceId,
68
+ config: {
69
+ mode: 'bitrix',
70
+ crmUrl: crmUrl ?? '',
71
+ section: readDocflowAppSection(event.queryStringParameters.section),
72
+ expectedWorkspaceMemberId: member.id,
73
+ portalDomain: portal.portalDomain,
74
+ },
75
+ });
111
76
  } catch (error) {
112
77
  if (error instanceof BitrixError) {
113
78
  return htmlResponse(
@@ -116,7 +81,6 @@ const handler = async (event: RoutePayload) => {
116
81
  title: 'Документооборот',
117
82
  message: `Запрос портала не подтверждён: ${error.message}`,
118
83
  crmUrl,
119
- tasks: [],
120
84
  isInstall: false,
121
85
  }),
122
86
  );
@@ -131,7 +95,6 @@ const handler = async (event: RoutePayload) => {
131
95
  ? error.message
132
96
  : 'Не удалось открыть документооборот для вашего профиля Битрикс24.',
133
97
  crmUrl,
134
- tasks: [],
135
98
  isInstall: false,
136
99
  }),
137
100
  );
@@ -119538,7 +119538,6 @@ var renderBitrixPage = ({
119538
119538
  title,
119539
119539
  message,
119540
119540
  crmUrl,
119541
- tasks,
119542
119541
  isInstall
119543
119542
  }) => `<!doctype html>
119544
119543
  <html lang="ru">
@@ -119552,19 +119551,12 @@ var renderBitrixPage = ({
119552
119551
  h1 { font-size: 20px; margin: 0 0 8px; }
119553
119552
  p { color: #666; margin: 0 0 16px; }
119554
119553
  a.button { display: inline-block; padding: 8px 16px; border-radius: 8px; background: #1961ed; color: #fff; text-decoration: none; }
119555
- ul { list-style: none; padding: 0; margin: 16px 0 0; }
119556
- li { padding: 8px 0; border-top: 1px solid #eee; display: flex; justify-content: space-between; gap: 16px; }
119557
- li a { color: #1961ed; text-decoration: none; }
119558
- .due { color: #999; white-space: nowrap; }
119559
119554
  </style>
119560
119555
  </head>
119561
119556
  <body>
119562
119557
  <h1>${escapeHtml(title)}</h1>
119563
119558
  <p>${escapeHtml(message)}</p>
119564
119559
  ${crmUrl !== void 0 ? `<a class="button" href="${escapeHtml(crmUrl)}" target="_blank" rel="noopener">\u041E\u0442\u043A\u0440\u044B\u0442\u044C \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u043E\u043E\u0431\u043E\u0440\u043E\u0442</a>` : ""}
119565
- ${tasks.length > 0 ? `<ul>${tasks.map(
119566
- (task) => `<li>${task.url !== void 0 ? `<a href="${escapeHtml(task.url)}" target="_blank" rel="noopener">${escapeHtml(task.title)}</a>` : escapeHtml(task.title)}<span class="due">${escapeHtml(task.dueAt ?? "")}</span></li>`
119567
- ).join("")}</ul>` : ""}
119568
119560
  ${isInstall ? "<script>if (window.BX24) { BX24.init(function () { BX24.installFinish(); }); }</script>" : ""}
119569
119561
  </body>
119570
119562
  </html>`;
@@ -119586,7 +119578,6 @@ var handler = async (event) => {
119586
119578
  renderBitrixPage({
119587
119579
  title: "\u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u043E\u043E\u0431\u043E\u0440\u043E\u0442",
119588
119580
  message: "\u0412 \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0430\u0445 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u044F \u0432 CRM \u043D\u0435 \u0443\u043A\u0430\u0437\u0430\u043D\u044B BITRIX_CLIENT_ID \u0438 BITRIX_CLIENT_SECRET.",
119589
- tasks: [],
119590
119581
  isInstall: false
119591
119582
  })
119592
119583
  );
@@ -119613,7 +119604,6 @@ var handler = async (event) => {
119613
119604
  renderBitrixPage({
119614
119605
  title: "\u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u043E\u043E\u0431\u043E\u0440\u043E\u0442 \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0451\u043D",
119615
119606
  message: `\u041F\u043E\u0440\u0442\u0430\u043B ${portal.portalDomain} \u0441\u0432\u044F\u0437\u0430\u043D \u0441 CRM.`,
119616
- tasks: [],
119617
119607
  isInstall: true
119618
119608
  })
119619
119609
  );
@@ -119623,7 +119613,6 @@ var handler = async (event) => {
119623
119613
  renderBitrixPage({
119624
119614
  title: "\u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u043E\u043E\u0431\u043E\u0440\u043E\u0442",
119625
119615
  message: error instanceof BitrixError ? `\u041F\u043E\u0440\u0442\u0430\u043B \u043D\u0435 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0451\u043D: ${error.message}` : "\u041F\u043E\u0440\u0442\u0430\u043B \u043D\u0435 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0451\u043D.",
119626
- tasks: [],
119627
119616
  isInstall: false
119628
119617
  })
119629
119618
  );
@@ -17,7 +17,6 @@ const handler = async (event: RoutePayload) => {
17
17
  renderBitrixPage({
18
18
  title: 'Документооборот',
19
19
  message: 'В настройках приложения в CRM не указаны BITRIX_CLIENT_ID и BITRIX_CLIENT_SECRET.',
20
- tasks: [],
21
20
  isInstall: false,
22
21
  }),
23
22
  );
@@ -47,7 +46,6 @@ const handler = async (event: RoutePayload) => {
47
46
  renderBitrixPage({
48
47
  title: 'Документооборот подключён',
49
48
  message: `Портал ${portal.portalDomain} связан с CRM.`,
50
- tasks: [],
51
49
  isInstall: true,
52
50
  }),
53
51
  );
@@ -60,7 +58,6 @@ const handler = async (event: RoutePayload) => {
60
58
  error instanceof BitrixError
61
59
  ? `Портал не подтверждён: ${error.message}`
62
60
  : 'Портал не подтверждён.',
63
- tasks: [],
64
61
  isInstall: false,
65
62
  }),
66
63
  );