@burdenoff/fluidgrids-fe-sdk 2026.1114.6 → 2026.1115.1

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 (64) hide show
  1. package/dist/{AiStudioPage-C2SBRqab.js → AiStudioPage-CtHmZ3Lw.js} +4 -4
  2. package/dist/{DataSinkDashboardPage-Dnp1yRYQ.js → DataSinkDashboardPage-DFtWv2nD.js} +1 -1
  3. package/dist/{ExecutionDetailPage-B-8s_Sqw.js → ExecutionDetailPage-D5iWwMnk.js} +8 -8
  4. package/dist/{ExecutionsListPage-Ky3TAL9U.js → ExecutionsListPage-BYW5WiX7.js} +6 -6
  5. package/dist/FileDownloadUrlDocument-CVOYKcL5.js +92 -0
  6. package/dist/{FluidGridsProvider-C-WGQwuT.js → FluidGridsProvider-CDjkq3Zj.js} +281 -59
  7. package/dist/{HistoryPage-D4rkw4zu.js → HistoryPage-fMZlXsIY.js} +1 -1
  8. package/dist/{InsightsPage-CVzNu4F7.js → InsightsPage-DozSYGVD.js} +1 -1
  9. package/dist/NodeUsageStatusDocument-B-XguSjm.js +531 -0
  10. package/dist/{OpenTemplateAsCodeButton-pepQUqje.js → OpenTemplateAsCodeButton-Cjnagq9H.js} +2 -2
  11. package/dist/{PaidTemplateConfirm-BJCcJh5t.js → PaidTemplateConfirm-Crs0CXXl.js} +1 -1
  12. package/dist/{SettingsPage-BSucNHrq.js → SettingsPage-qSvV7r0y.js} +6 -6
  13. package/dist/{TaskQueuesPage-WMJz9imi.js → TaskQueuesPage-BuWQwT5I.js} +2 -2
  14. package/dist/{TemplateCard-Cx_eZr9q.js → TemplateCard-BsrXJ1Su.js} +21 -5
  15. package/dist/{TemplateConfigurationModal-D2i7ZXOM.js → TemplateConfigurationModal-B_ME8M-1.js} +1 -1
  16. package/dist/{TemplatePreview-DwdGa8bH.js → TemplatePreview-BOIhJSBD.js} +5 -5
  17. package/dist/{TemplatesPage-DF5PK7CB.js → TemplatesPage-dj7NseMt.js} +358 -16
  18. package/dist/{WorkflowBuilder-DkzzbrNn.js → WorkflowBuilder-ByG9twmu.js} +5 -5
  19. package/dist/{WorkflowBuilder-CjsO7i-D.js → WorkflowBuilder-DjpAoBVO.js} +3 -3
  20. package/dist/{WorkflowSearchRedirect-0MLrCjDn.js → WorkflowSearchRedirect-DRidTx1L.js} +1 -1
  21. package/dist/{WorkflowsList-4VADoiz_.js → WorkflowsList-BQ_5hkWi.js} +6 -7
  22. package/dist/{agentTools-DuCukaUX.js → agentTools-Cx5yPBe7.js} +3 -2
  23. package/dist/{api-DKfMt0IX.js → api-CEzqoN5H.js} +1 -1
  24. package/dist/{api-CEnNq15C.js → api-o5UUDbr8.js} +1 -1
  25. package/dist/{canvasNoteTools-DnsO-gHe.js → canvasNoteTools-BxknF5rX.js} +1 -1
  26. package/dist/executions.js +2 -2
  27. package/dist/{flow-builder-CIV6u8y-.js → flow-builder-D8f31DFR.js} +25 -36
  28. package/dist/history.js +1 -1
  29. package/dist/{index-BY0V255h.d.ts → index-BprVea6e.d.ts} +5 -2
  30. package/dist/index.d.ts +1 -1
  31. package/dist/index.js +100 -97
  32. package/dist/{node-detail-view-DkajTGfb.js → node-detail-view-C__INEVF.js} +9 -219
  33. package/dist/{node-editor-tab-body-ChLrBfKp.js → node-editor-tab-body-BintGoSp.js} +2 -2
  34. package/dist/observability.d.ts +1 -1
  35. package/dist/observability.js +2 -2
  36. package/dist/{popover-CCJlf41J.js → popover-2-6xmS1q.js} +3 -3
  37. package/dist/{quick-config-panel-Bq_uF9XF.js → quick-config-panel-Bxi9TwCG.js} +3 -3
  38. package/dist/{schedule-panel-7TtPt1t_.js → schedule-panel-BbRtGDEt.js} +6 -6
  39. package/dist/settings.js +1 -1
  40. package/dist/{shared-C0LCTtyh.js → shared-mbyvDPde.js} +2 -24
  41. package/dist/{sidebar-node-editor-n-7ux5IN.js → sidebar-node-editor-DG-34YEW.js} +3 -3
  42. package/dist/{template-code-B3cMigJS.js → template-code-B7x-XMAm.js} +9 -2
  43. package/dist/templates.js +2 -2
  44. package/dist/typed-calls-BqokR321.js +26 -0
  45. package/dist/{WorkflowEditLeaseStatusDocument-Dp62med3.js → use-workflow-code-editor-CBOkjntt.js} +216 -90
  46. package/dist/{useAgentDefinitions-Daa3fGVg.js → useAgentDefinitions-YUDx_OW2.js} +2 -2
  47. package/dist/useConnections-CmnwGk09.js +439 -0
  48. package/dist/{useDurableParity-gigqyXDq.js → useDurableParity-X_zfFzQv.js} +1 -1
  49. package/dist/{useExecutions-wka2Z5w3.js → useExecutions-BWbMt16D.js} +1 -1
  50. package/dist/{useGlobalStoreClient-BcwWGtm7.js → useGlobalStoreClient-CwBAeiXV.js} +1 -1
  51. package/dist/{useObservability-CjZTYldC.js → useObservability-mXM7lCop.js} +1 -1
  52. package/dist/{useRunHistory-Be-GggNA.js → useRunHistory-DYDriBz1.js} +1 -1
  53. package/dist/{useWorkflowCodeExport-lRmbjY49.js → useWorkflowCodeExport-uKBDVvnA.js} +78 -114
  54. package/dist/{useWorkflows-BrqrVT8h.js → useWorkflows-Dg7q_Tzf.js} +1 -1
  55. package/dist/workflow-builder.js +4 -4
  56. package/dist/workflow-description-CeXdyWX8.js +123 -0
  57. package/dist/workflow-pages.d.ts +1 -1
  58. package/dist/workflow-pages.js +14 -14
  59. package/dist/{workflow-code-transfer-BsLPUrKP.js → workflow-transfer-CktP7o1c.js} +103 -1
  60. package/dist/workflows-list.js +1 -1
  61. package/package.json +1 -1
  62. package/dist/QuotaExhaustedDialog-YjKgRTmu.js +0 -55
  63. package/dist/useConnections-BlB0gbOB.js +0 -931
  64. package/dist/workflow-transfer-CQnQC-ke.js +0 -104
@@ -1,25 +1,30 @@
1
1
  "use client";
2
2
  import { t as __exportAll } from "./rolldown-runtime-hDbaFkMy.js";
3
- import { h as useWorkflowDefinitions, l as useLazyWorkflowDefinition, s as useDuplicateWorkflow } from "./useWorkflows-BrqrVT8h.js";
4
- import { i as useTemplateImportFlow, l as useWorkflowTemplates, r as isPaidTemplate, t as TemplateCard } from "./TemplateCard-Cx_eZr9q.js";
5
- import { nL as WorkflowStatus } from "./graphql-types-dS3Fk9Z5.js";
3
+ import { h as useWorkflowDefinitions, l as useLazyWorkflowDefinition, s as useDuplicateWorkflow } from "./useWorkflows-Dg7q_Tzf.js";
4
+ import { i as useTemplateImportFlow, l as useWorkflowTemplates, r as isPaidTemplate, t as TemplateCard, v as storeContextHeaders } from "./TemplateCard-BsrXJ1Su.js";
5
+ import { OI as WorkflowExportFormat, nL as WorkflowStatus } from "./graphql-types-dS3Fk9Z5.js";
6
6
  import { i as SdkPermissionButton, t as FLUIDGRIDS_PERMISSIONS } from "./constants-65QV61nQ.js";
7
- import { t as QuotaExhaustedDialog } from "./QuotaExhaustedDialog-YjKgRTmu.js";
7
+ import { i as QuotaExhaustedDialog, t as fetchWorkflowCodeExport } from "./useWorkflowCodeExport-uKBDVvnA.js";
8
8
  import { r as useTr } from "./TranslationBridge-Da-TPgQm.js";
9
- import { t as FluidGridsContext, un as useFluidGridsAnalytics } from "./FluidGridsProvider-C-WGQwuT.js";
9
+ import { fn as useFluidGridsAnalytics, t as FluidGridsContext } from "./FluidGridsProvider-CDjkq3Zj.js";
10
10
  import { a as emitTemplateUsed } from "./fluidgridsEvents-Dm5CaHtr.js";
11
11
  import { n as useFluidGridsPageControls } from "./pageControlsBridge-0pX9s-3k.js";
12
12
  import { r as templatesControls } from "./pageControlSpecs-DZJ9K37m.js";
13
13
  import { c as isQuotaExhaustedFailure, t as BILLING_PLANS_PATH } from "./quota-Cdt8yz7N.js";
14
14
  import { t as FluidGridsDocsLink } from "./FluidGridsDocsLink-JxkBpOeb.js";
15
- import { t as useGlobalStoreClient } from "./useGlobalStoreClient-BcwWGtm7.js";
15
+ import { h as usePhaseDFlags } from "./feature-flags-B_b8PJ6Z.js";
16
+ import { t as fetchWorkflowCodeSource } from "./use-workflow-code-editor-CBOkjntt.js";
17
+ import { t as fetchConnectionNames } from "./useConnections-CmnwGk09.js";
18
+ import { m as isLosslessReport } from "./workflow-transfer-CktP7o1c.js";
19
+ import { a as contentTypeOf, n as TemplateCodeError, o as isTier2Definition, r as assertTemplateSources, t as TEMPLATE_SOURCES_MAX_BYTES } from "./template-code-B7x-XMAm.js";
20
+ import { t as useGlobalStoreClient } from "./useGlobalStoreClient-CwBAeiXV.js";
21
+ import { r as getFluidGridsConfig } from "./config-X97zrIvn.js";
16
22
  import { o as throwIfResultError, t as describeOperationError } from "./errors-xPZ-IbQd.js";
17
23
  import { t as NodeTypeIcon } from "./node-type-icon-DEAztACh.js";
18
24
  import { n as formatRunVersion } from "./run-display-UjLAoYqQ.js";
19
25
  import { n as useNavigationV2 } from "./useNavigationV2-C2WeqN7d.js";
20
26
  import { t as TechnicalDetails } from "./TechnicalDetails-r5JXr1jZ.js";
21
- import { t as PaidTemplateConfirm } from "./PaidTemplateConfirm-BJCcJh5t.js";
22
- import { r as getFluidGridsConfig } from "./config-X97zrIvn.js";
27
+ import { t as PaidTemplateConfirm } from "./PaidTemplateConfirm-Crs0CXXl.js";
23
28
  import { t as cn } from "./cn-QqidFIgr.js";
24
29
  import { useCallback, useContext, useEffect, useMemo, useState } from "react";
25
30
  import { useNavigate } from "react-router";
@@ -28,7 +33,7 @@ import { Icon } from "@iconify/react";
28
33
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
29
34
  import { toast } from "sonner";
30
35
  import { gql } from "@apollo/client";
31
- import { Badge, Card, CardHeader, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, Input, Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Skeleton, Textarea } from "@burdenoff/fe-libs/ui";
36
+ import { Badge, Card, CardHeader, Checkbox, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, Input, Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Skeleton, Textarea } from "@burdenoff/fe-libs/ui";
32
37
  import { Button as Button$1 } from "@burdenoff/fe-libs/button";
33
38
  import { v4 } from "uuid";
34
39
 
@@ -270,6 +275,56 @@ const SubmitWorkflowTemplateDocument = {
270
275
  "arguments": [],
271
276
  "directives": []
272
277
  },
278
+ {
279
+ "kind": "Field",
280
+ "name": {
281
+ "kind": "Name",
282
+ "value": "code"
283
+ },
284
+ "arguments": [],
285
+ "directives": [],
286
+ "selectionSet": {
287
+ "kind": "SelectionSet",
288
+ "selections": [
289
+ {
290
+ "kind": "Field",
291
+ "name": {
292
+ "kind": "Name",
293
+ "value": "tier"
294
+ },
295
+ "arguments": [],
296
+ "directives": []
297
+ },
298
+ {
299
+ "kind": "Field",
300
+ "name": {
301
+ "kind": "Name",
302
+ "value": "format"
303
+ },
304
+ "arguments": [],
305
+ "directives": []
306
+ },
307
+ {
308
+ "kind": "Field",
309
+ "name": {
310
+ "kind": "Name",
311
+ "value": "fileCount"
312
+ },
313
+ "arguments": [],
314
+ "directives": []
315
+ },
316
+ {
317
+ "kind": "Field",
318
+ "name": {
319
+ "kind": "Name",
320
+ "value": "bytes"
321
+ },
322
+ "arguments": [],
323
+ "directives": []
324
+ }
325
+ ]
326
+ }
327
+ },
273
328
  {
274
329
  "kind": "Field",
275
330
  "name": {
@@ -708,6 +763,56 @@ const MyWorkflowTemplateSubmissionsDocument = {
708
763
  "arguments": [],
709
764
  "directives": []
710
765
  },
766
+ {
767
+ "kind": "Field",
768
+ "name": {
769
+ "kind": "Name",
770
+ "value": "code"
771
+ },
772
+ "arguments": [],
773
+ "directives": [],
774
+ "selectionSet": {
775
+ "kind": "SelectionSet",
776
+ "selections": [
777
+ {
778
+ "kind": "Field",
779
+ "name": {
780
+ "kind": "Name",
781
+ "value": "tier"
782
+ },
783
+ "arguments": [],
784
+ "directives": []
785
+ },
786
+ {
787
+ "kind": "Field",
788
+ "name": {
789
+ "kind": "Name",
790
+ "value": "format"
791
+ },
792
+ "arguments": [],
793
+ "directives": []
794
+ },
795
+ {
796
+ "kind": "Field",
797
+ "name": {
798
+ "kind": "Name",
799
+ "value": "fileCount"
800
+ },
801
+ "arguments": [],
802
+ "directives": []
803
+ },
804
+ {
805
+ "kind": "Field",
806
+ "name": {
807
+ "kind": "Name",
808
+ "value": "bytes"
809
+ },
810
+ "arguments": [],
811
+ "directives": []
812
+ }
813
+ ]
814
+ }
815
+ },
711
816
  {
712
817
  "kind": "Field",
713
818
  "name": {
@@ -758,11 +863,18 @@ const TEMPLATE_STORE_CATEGORIES = [
758
863
  * which already masks literal secrets. The store removes connection bindings,
759
864
  * pinned run data and any remaining secrets, builds the manifest and puts the
760
865
  * template into review; a store admin approves or rejects it.
866
+ *
867
+ * With `code` the template also carries the workflow as code (G22). The
868
+ * workspace context goes with the request, because the store checks the
869
+ * workspace's code-first flags before it accepts code.
761
870
  */
762
871
  function usePublishToStore() {
763
872
  const [publishing, setPublishing] = useState(false);
764
873
  const [error, setError] = useState(null);
765
874
  const globalClient = useGlobalStoreClient();
875
+ const context = useContext(FluidGridsContext);
876
+ const workspaceId = context?.workspaceId ?? getFluidGridsConfig().workspaceId;
877
+ const organizationId = context?.organizationId;
766
878
  return {
767
879
  publishToStore: useCallback(async (input) => {
768
880
  setPublishing(true);
@@ -785,8 +897,14 @@ function usePublishToStore() {
785
897
  authorName: input.authorName?.trim() || void 0,
786
898
  difficultyLevel: input.difficultyLevel,
787
899
  estimatedTimeMinutes: input.estimatedTimeMinutes,
788
- notes: input.notes?.trim() || void 0
789
- } }
900
+ notes: input.notes?.trim() || void 0,
901
+ code: input.code
902
+ } },
903
+ context: { headers: storeContextHeaders({
904
+ organizationId,
905
+ workspaceId,
906
+ workspaceToken: getFluidGridsConfig().workspaceToken
907
+ }) }
790
908
  })).data?.submitWorkflowTemplate;
791
909
  if (!submission) throw new Error("The store did not return the submitted template");
792
910
  return {
@@ -805,7 +923,11 @@ function usePublishToStore() {
805
923
  } finally {
806
924
  setPublishing(false);
807
925
  }
808
- }, [globalClient]),
926
+ }, [
927
+ globalClient,
928
+ organizationId,
929
+ workspaceId
930
+ ]),
809
931
  publishing,
810
932
  error
811
933
  };
@@ -863,6 +985,176 @@ function useTemplateSubmissions(enabled = true, limit = 50) {
863
985
  };
864
986
  }
865
987
 
988
+ // src/hooks/store/templateCode.ts
989
+ /**
990
+ * *Include code* when a workflow is published as a community template
991
+ * (code-first gap G22, BOFF-14107, spec code-first/07 section 9).
992
+ *
993
+ * Collects the code `submitWorkflowTemplate` takes in `input.code`:
994
+ *
995
+ * - A canvas workflow (tier 1) is lifted to TypeScript by the service
996
+ * (`exportWorkflow`). Connections are written by name (the names of the
997
+ * author's saved connections), never by id, and pinned data is left out, so
998
+ * the code carries nothing the store removes from the definition. Only a
999
+ * lossless lift is published, so installing the code gives back the same
1000
+ * workflow.
1001
+ * - A durable function (tier 2) attaches its project files
1002
+ * (`workflowCodeSource`, vendored files excluded), TypeScript or Python.
1003
+ * TypeScript files may import only project files and
1004
+ * `@fluidgrids/workflows`.
1005
+ *
1006
+ * The store's rules (64 files, 1 MiB, safe and unique paths) are checked here
1007
+ * first, so a refusal is explained before anything is sent. The store checks
1008
+ * them again, and also refuses code that carries a secret.
1009
+ */
1010
+ /** Thrown when a flag *Include code* needs is off (fails closed). */
1011
+ var CodeTemplatesDisabledError = class extends Error {
1012
+ constructor() {
1013
+ super("Publishing a template with its code is not enabled here");
1014
+ this.name = "CodeTemplatesDisabledError";
1015
+ }
1016
+ };
1017
+ function isRecord(value) {
1018
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1019
+ }
1020
+ /** Keys that bind a node to a saved connection (as global-store-svc reads them). */
1021
+ const CONNECTION_KEYS = /* @__PURE__ */ new Set([
1022
+ "connectionId",
1023
+ "credentialId",
1024
+ "credentialsId"
1025
+ ]);
1026
+ const CONNECTION_ID_FIELDS = [
1027
+ "id",
1028
+ "connectionId",
1029
+ "credentialId",
1030
+ "credentialsId"
1031
+ ];
1032
+ /** Deepest nesting walked; a definition the store accepts is never deeper. */
1033
+ const MAX_DEPTH = 64;
1034
+ /**
1035
+ * The saved-connection ids a definition refers to: values of `connectionId`,
1036
+ * `credentialId` and `credentialsId`, and the entries of `connections`
1037
+ * lists (an id, or an object's id field).
1038
+ */
1039
+ function definitionConnectionIds(definition) {
1040
+ const found = /* @__PURE__ */ new Set();
1041
+ const visit = (value, depth) => {
1042
+ if (depth > MAX_DEPTH) return;
1043
+ if (Array.isArray(value)) {
1044
+ for (const item of value) visit(item, depth + 1);
1045
+ return;
1046
+ }
1047
+ if (!isRecord(value)) return;
1048
+ for (const [key, child] of Object.entries(value)) {
1049
+ if (CONNECTION_KEYS.has(key) && typeof child === "string" && child) found.add(child);
1050
+ else if (key === "connections" && Array.isArray(child)) {
1051
+ for (const entry of child) if (typeof entry === "string" && entry) found.add(entry);
1052
+ else if (isRecord(entry)) for (const field of CONNECTION_ID_FIELDS) {
1053
+ const id = entry[field];
1054
+ if (typeof id === "string" && id) found.add(id);
1055
+ }
1056
+ }
1057
+ visit(child, depth + 1);
1058
+ }
1059
+ };
1060
+ visit(definition, 0);
1061
+ return [...found];
1062
+ }
1063
+ /** The language of a tier-2 definition's code block. */
1064
+ function tier2Format(definitionJson) {
1065
+ const code = isRecord(definitionJson) ? definitionJson.code : void 0;
1066
+ return (isRecord(code) ? code.language : void 0) === "python" ? "PYTHON" : "TYPESCRIPT";
1067
+ }
1068
+ async function collectTier2(workflow) {
1069
+ const source = await fetchWorkflowCodeSource(workflow.workflowKey, workflow.version);
1070
+ if (!source || source.files.length === 0) throw new TemplateCodeError({ code: "no-files" });
1071
+ const files = source.files.map((file) => ({
1072
+ path: file.path,
1073
+ contentType: contentTypeOf(file.path),
1074
+ content: file.content
1075
+ }));
1076
+ assertTemplateSources(files, "tier2");
1077
+ return {
1078
+ tier: "TIER2",
1079
+ format: tier2Format(workflow.definitionJson),
1080
+ files
1081
+ };
1082
+ }
1083
+ async function collectTier1(workflow) {
1084
+ const connectionIds = definitionConnectionIds(workflow.definitionJson);
1085
+ const connectionNameMap = await fetchConnectionNames(connectionIds);
1086
+ const exported = await fetchWorkflowCodeExport({
1087
+ workflowKey: workflow.workflowKey,
1088
+ version: workflow.version,
1089
+ format: "TYPESCRIPT",
1090
+ options: {
1091
+ connectionNameMap,
1092
+ connectionNames: true,
1093
+ includeLayout: true,
1094
+ includePinnedData: false
1095
+ }
1096
+ });
1097
+ if (!isLosslessReport(exported.fidelity)) throw new TemplateCodeError({ code: "lossy" });
1098
+ const files = exported.files.map((file) => ({
1099
+ path: file.path,
1100
+ contentType: file.contentType || contentTypeOf(file.path),
1101
+ content: file.content ?? ""
1102
+ }));
1103
+ if (connectionIds.find((id) => !connectionNameMap[id] && files.some((file) => file.content.includes(id))) !== void 0) throw new TemplateCodeError({ code: "unnamed-connection" });
1104
+ assertTemplateSources(files, "tier1");
1105
+ return {
1106
+ tier: "TIER1",
1107
+ format: "TYPESCRIPT",
1108
+ files,
1109
+ sourceIrHash: exported.irHash
1110
+ };
1111
+ }
1112
+ /** Whether *Include code* can be offered for a workflow with these flags. */
1113
+ function canIncludeTemplateCode(definitionJson, flags) {
1114
+ return isTier2Definition(definitionJson) ? flags.codeTemplatesDurable : flags.codeTemplates;
1115
+ }
1116
+ /**
1117
+ * The code to publish with a workflow version. Throws
1118
+ * {@link CodeTemplatesDisabledError} when a needed flag is off and
1119
+ * {@link TemplateCodeError} when the code cannot be published (a lossy lift,
1120
+ * a connection without a name, no files, or a store rule broken).
1121
+ */
1122
+ async function collectTemplateCode(workflow, flags) {
1123
+ if (!canIncludeTemplateCode(workflow.definitionJson, flags)) throw new CodeTemplatesDisabledError();
1124
+ return isTier2Definition(workflow.definitionJson) ? collectTier2(workflow) : collectTier1(workflow);
1125
+ }
1126
+
1127
+ // src/modules/templates/utils/template-code-messages.ts
1128
+ /**
1129
+ * Messages for *Include code* refusals in the publish dialog (G22,
1130
+ * BOFF-14107). Each one tells the author what to change, or that they can
1131
+ * untick *Include code* and publish the definition only.
1132
+ */
1133
+ /**
1134
+ * The message for an error raised while collecting a template's code, or
1135
+ * null when the error is not a code refusal (the caller then shows the
1136
+ * error's own message).
1137
+ */
1138
+ function templateCodeErrorMessage(error, tr) {
1139
+ if (error instanceof CodeTemplatesDisabledError) return tr("fluidgrids.templates.publish.code.disabled", "Publishing a template with its code is not turned on for this workspace. Untick Include code to publish the workflow without it.");
1140
+ if (!(error instanceof TemplateCodeError)) return null;
1141
+ const { problem } = error;
1142
+ switch (problem.code) {
1143
+ case "lossy": return tr("fluidgrids.templates.publish.code.lossy", "This workflow cannot be turned into code without losing something (see the Code view for what). Untick Include code to publish it without code.");
1144
+ case "unnamed-connection": return tr("fluidgrids.templates.publish.code.unnamedConnection", "A node uses a connection that no longer exists, so its code would carry the connection's id. Pick a saved connection for it, save, and try again.");
1145
+ case "no-files": return tr("fluidgrids.templates.publish.code.noFiles", "This version has no code files to include. Save the workflow's code and try again.");
1146
+ case "too-large": return tr("fluidgrids.templates.publish.code.tooLarge", "The code is larger than the store allows ({{limit}} KB).", { limit: Math.round(TEMPLATE_SOURCES_MAX_BYTES / 1024) });
1147
+ case "too-many-files": return tr("fluidgrids.templates.publish.code.tooManyFiles", "The code has more files than the store allows ({{limit}}).", { limit: 64 });
1148
+ case "unsafe-path": return tr("fluidgrids.templates.publish.code.unsafePath", "The file {{path}} has a path the store does not accept.", { path: problem.path });
1149
+ case "duplicate-path": return tr("fluidgrids.templates.publish.code.duplicatePath", "Two files share the path {{path}}.", { path: problem.path });
1150
+ case "foreign-import": return tr("fluidgrids.templates.publish.code.foreignImport", "{{path}} imports {{specifier}}. Template code may import only its own files and @fluidgrids/workflows.", {
1151
+ path: problem.path,
1152
+ specifier: problem.specifier
1153
+ });
1154
+ case "python-tier2": return tr("fluidgrids.templates.publish.code.pythonTier2", "Python code cannot be installed from a template.");
1155
+ }
1156
+ }
1157
+
866
1158
  // src/modules/templates/utils/template-categories.ts
867
1159
  /** English labels for the store's template categories (BOFF-4316). */
868
1160
  const TEMPLATE_CATEGORY_LABELS = {
@@ -915,7 +1207,11 @@ function parseTemplateTags(value) {
915
1207
  * definition. The store removes the author's connection bindings, pinned run
916
1208
  * data and literal secrets before keeping a copy, and a store admin reviews the
917
1209
  * template before it is listed. Passing `resubmit` updates one of the author's
918
- * rejected or withdrawn templates instead of creating a new one.
1210
+ * rejected or withdrawn templates instead of creating one.
1211
+ *
1212
+ * *Include code* (G22, shown when the workspace has code templates on) also
1213
+ * publishes the workflow as code, so people who install the template can
1214
+ * open it as a code project. The store refuses code that carries a secret.
919
1215
  */
920
1216
  const DIFFICULTIES = [
921
1217
  "easy",
@@ -930,6 +1226,10 @@ function PublishTemplateDialog({ open, onOpenChange, workflow, resubmit, onSubmi
930
1226
  const tr = useTr();
931
1227
  const { publishToStore, publishing } = usePublishToStore();
932
1228
  const { getWorkflow } = useLazyWorkflowDefinition();
1229
+ const phaseD = usePhaseDFlags();
1230
+ const [includeCode, setIncludeCode] = useState(false);
1231
+ const [collectingCode, setCollectingCode] = useState(false);
1232
+ const busy = publishing || collectingCode;
933
1233
  const [name, setName] = useState("");
934
1234
  const [description, setDescription] = useState("");
935
1235
  const [longDescription, setLongDescription] = useState("");
@@ -949,6 +1249,7 @@ function PublishTemplateDialog({ open, onOpenChange, workflow, resubmit, onSubmi
949
1249
  setAuthorName(resubmit?.authorName ?? "");
950
1250
  setDifficulty("medium");
951
1251
  setNotes("");
1252
+ setIncludeCode(false);
952
1253
  setError(null);
953
1254
  }, [
954
1255
  open,
@@ -971,8 +1272,21 @@ function PublishTemplateDialog({ open, onOpenChange, workflow, resubmit, onSubmi
971
1272
  setError(tr("fluidgrids.templates.publish.definitionMissing", "Could not read this workflow's definition. Save it and try again."));
972
1273
  return;
973
1274
  }
1275
+ let code;
1276
+ if (includeCode && phaseD.codeTemplates) {
1277
+ setCollectingCode(true);
1278
+ try {
1279
+ code = await collectTemplateCode(current, phaseD);
1280
+ } catch (err) {
1281
+ setError(templateCodeErrorMessage(err, tr) ?? (err instanceof Error ? err.message : tr("fluidgrids.templates.publish.code.failed", "Could not read this workflow's code.")));
1282
+ return;
1283
+ } finally {
1284
+ setCollectingCode(false);
1285
+ }
1286
+ }
974
1287
  const result = await publishToStore({
975
1288
  workflow: current,
1289
+ code,
976
1290
  productId: resubmit?.id,
977
1291
  name,
978
1292
  description,
@@ -1111,6 +1425,26 @@ function PublishTemplateDialog({ open, onOpenChange, workflow, resubmit, onSubmi
1111
1425
  onChange: (e) => setNotes(e.target.value)
1112
1426
  })]
1113
1427
  }),
1428
+ phaseD.codeTemplates && /* @__PURE__ */ jsxs("div", {
1429
+ className: "space-y-1",
1430
+ children: [/* @__PURE__ */ jsxs("div", {
1431
+ className: "flex items-center gap-2",
1432
+ children: [/* @__PURE__ */ jsx(Checkbox, {
1433
+ id: "publish-template-include-code",
1434
+ "data-testid": "publish-template-include-code",
1435
+ checked: includeCode,
1436
+ disabled: busy,
1437
+ onCheckedChange: (on) => setIncludeCode(on === true)
1438
+ }), /* @__PURE__ */ jsx(Label, {
1439
+ htmlFor: "publish-template-include-code",
1440
+ className: "text-sm",
1441
+ children: tr("fluidgrids.templates.publish.includeCodeLabel", "Include code")
1442
+ })]
1443
+ }), /* @__PURE__ */ jsx("p", {
1444
+ className: "text-xs text-text-secondary",
1445
+ children: tr("fluidgrids.templates.publish.includeCodeHint", "People who install the template can open it as a code project. Code that contains a secret is refused.")
1446
+ })]
1447
+ }),
1114
1448
  error && /* @__PURE__ */ jsx("p", {
1115
1449
  role: "alert",
1116
1450
  className: "text-sm text-[var(--color-status-error-text)]",
@@ -1122,13 +1456,13 @@ function PublishTemplateDialog({ open, onOpenChange, workflow, resubmit, onSubmi
1122
1456
  /* @__PURE__ */ jsxs(DialogFooter, { children: [/* @__PURE__ */ jsx(Button$1, {
1123
1457
  variant: "outline",
1124
1458
  onClick: () => onOpenChange(false),
1125
- disabled: publishing,
1459
+ disabled: busy,
1126
1460
  children: tr("fluidgrids.templates.publish.cancel", "Cancel")
1127
1461
  }), /* @__PURE__ */ jsxs(Button$1, {
1128
1462
  onClick: () => void submit(),
1129
- disabled: publishing || !workflow,
1463
+ disabled: busy || !workflow,
1130
1464
  "data-testid": "publish-template-submit",
1131
- children: [publishing ? /* @__PURE__ */ jsx(Icon, {
1465
+ children: [busy ? /* @__PURE__ */ jsx(Icon, {
1132
1466
  icon: "mdi:loading",
1133
1467
  width: 14,
1134
1468
  className: "mr-1.5 animate-spin"
@@ -1295,6 +1629,14 @@ function MySubmissionsPanel({ onResubmit }) {
1295
1629
  " ",
1296
1630
  tr("fluidgrids.templates.submissions.downloads", "{{count}} imports", { count: submission.downloads })
1297
1631
  ] }),
1632
+ submission.code && /* @__PURE__ */ jsxs("span", {
1633
+ "data-testid": "my-submission-code",
1634
+ children: [
1635
+ "·",
1636
+ " ",
1637
+ tr("fluidgrids.templates.submissions.includesCode", "includes code ({{count}} files)", { count: submission.code.fileCount })
1638
+ ]
1639
+ }),
1298
1640
  submission.sourceWorkflowKey && /* @__PURE__ */ jsxs("span", {
1299
1641
  className: "truncate",
1300
1642
  children: [
@@ -1,21 +1,21 @@
1
1
  "use client";
2
2
  import { t as __exportAll } from "./rolldown-runtime-hDbaFkMy.js";
3
- import { d as releaseLeaseKeptForReload, f as useWorkflowReloadStore, t as FlowBuilderPage } from "./flow-builder-CIV6u8y-.js";
3
+ import { d as releaseLeaseKeptForReload, f as useWorkflowReloadStore, t as FlowBuilderPage } from "./flow-builder-D8f31DFR.js";
4
4
  import { n as registerLiveCanvasHandler } from "./liveCanvas-D5ytXDp8.js";
5
5
  import { r as getFluidGridsConfig } from "./config-X97zrIvn.js";
6
6
  import { n as getFluidGridsClient } from "./client-Ctl4jmY3.js";
7
7
  import { o as throwIfResultError } from "./errors-xPZ-IbQd.js";
8
8
  import { t as WorkflowDefinitionDocument } from "./WorkflowDefinitionDocument-DZLbTPUZ.js";
9
9
  import { r as useTr } from "./TranslationBridge-Da-TPgQm.js";
10
- import { $t as workflowFingerprint, Jt as codeBuildIdOf, M as createConfiguredNode, Tt as useSaveStatusStore, U as paramsFromOperation, Ut as rememberRevision, cn as resolveNodeOperation, g as registerWorkflowNodeTypes, h as registerNodeManifests, m as refetchStoreNodes, o as NODE_CONFIGS, u as ensureNodeTypesLoaded, xt as classifyCreateRefusal, yt as blankWorkflowCreateInput } from "./FluidGridsProvider-C-WGQwuT.js";
10
+ import { Ct as classifyCreateRefusal, Dt as useSaveStatusStore, G as paramsFromOperation, Gt as rememberRevision, P as createConfiguredNode, Xt as codeBuildIdOf, _ as registerNodeManifests, d as ensureNodeTypesLoaded, g as refetchStoreNodes, o as NODE_CONFIGS, tn as workflowFingerprint, un as resolveNodeOperation, v as registerWorkflowNodeTypes, xt as blankWorkflowCreateInput } from "./FluidGridsProvider-CDjkq3Zj.js";
11
11
  import { A as useFlowStore } from "./node-operation-selection-DHbtGNrG.js";
12
12
  import { t as canvasFromDefinition } from "./definition-canvas-DL25_6NH.js";
13
- import { l as useLazyWorkflowDefinition, n as useCreateWorkflow } from "./useWorkflows-BrqrVT8h.js";
14
- import { _ as useInstalledNodes, a as buildNodeCheck, o as buildRequiredNodeTypes, s as getWorkflowNodeTypes } from "./TemplateCard-Cx_eZr9q.js";
13
+ import { l as useLazyWorkflowDefinition, n as useCreateWorkflow } from "./useWorkflows-Dg7q_Tzf.js";
14
+ import { _ as useInstalledNodes, a as buildNodeCheck, o as buildRequiredNodeTypes, s as getWorkflowNodeTypes } from "./TemplateCard-BsrXJ1Su.js";
15
15
  import { r as mergeStickyNotes } from "./sticky-notes-23j-wL6Q.js";
16
16
  import { c as withoutGuidedTourIntent, l as decideMissingWorkflow, o as isGuidedTourIntent, s as pickGuidedTour, u as isCreateIntent } from "./firstWorkflow-C_h0KMB2.js";
17
17
  import { t as BILLING_PLANS_PATH } from "./quota-Cdt8yz7N.js";
18
- import { c as CreateWorkflowRefusalDialog } from "./useWorkflowCodeExport-lRmbjY49.js";
18
+ import { o as CreateWorkflowRefusalDialog } from "./workflow-description-CeXdyWX8.js";
19
19
  import { Suspense, lazy, useCallback, useEffect, useMemo, useRef, useState } from "react";
20
20
  import { useLocation, useNavigate, useParams } from "react-router";
21
21
  import { Icon } from "@iconify/react";
@@ -1,12 +1,12 @@
1
1
  "use client";
2
- import { fn as useCanvasEdges, n as FluidGridsProvider } from "./FluidGridsProvider-C-WGQwuT.js";
2
+ import { mn as useCanvasEdges, n as FluidGridsProvider } from "./FluidGridsProvider-CDjkq3Zj.js";
3
3
  import { A as useFlowStore } from "./node-operation-selection-DHbtGNrG.js";
4
4
  import { t as Button } from "./button-DG7y_FVJ.js";
5
5
  import { t as Input } from "./input-ChT6Q-Pr.js";
6
- import { v as Card } from "./TemplateCard-Cx_eZr9q.js";
6
+ import { y as Card } from "./TemplateCard-BsrXJ1Su.js";
7
7
  import { t as cn } from "./cn-QqidFIgr.js";
8
8
  import { r as useTr } from "./TranslationBridge-Da-TPgQm.js";
9
- import { m as FluidGridsMark, p as useNodeSelectedEvent } from "./flow-builder-CIV6u8y-.js";
9
+ import { m as FluidGridsMark, p as useNodeSelectedEvent } from "./flow-builder-D8f31DFR.js";
10
10
  import { useCallback, useEffect, useRef, useState } from "react";
11
11
  import { Background, Controls, Handle, MarkerType, MiniMap, Position, ReactFlow, ReactFlowProvider, useReactFlow } from "@xyflow/react";
12
12
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { t as __exportAll } from "./rolldown-runtime-hDbaFkMy.js";
3
- import { m as useWorkflowDefinition } from "./useWorkflows-BrqrVT8h.js";
3
+ import { m as useWorkflowDefinition } from "./useWorkflows-Dg7q_Tzf.js";
4
4
  import { Navigate, useParams } from "react-router";
5
5
  import { Icon } from "@iconify/react";
6
6
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -1,23 +1,22 @@
1
1
  "use client";
2
2
  import { t as __exportAll } from "./rolldown-runtime-hDbaFkMy.js";
3
- import { c as useImportWorkflow, h as useWorkflowDefinitions, l as useLazyWorkflowDefinition, n as useCreateWorkflow, o as useDeleteWorkflow, s as useDuplicateWorkflow, u as usePreviewN8nImport } from "./useWorkflows-BrqrVT8h.js";
4
- import { St as createThenOpen, t as FluidGridsContext } from "./FluidGridsProvider-C-WGQwuT.js";
5
- import { a as saveWorkflowDescription, c as CreateWorkflowRefusalDialog, o as visibleWorkflowDescription, r as commitWorkflowDescription, s as workflowDescriptionCharactersLeft, t as useExportWorkflowAs } from "./useWorkflowCodeExport-lRmbjY49.js";
3
+ import { c as useImportWorkflow, h as useWorkflowDefinitions, l as useLazyWorkflowDefinition, n as useCreateWorkflow, o as useDeleteWorkflow, s as useDuplicateWorkflow, u as usePreviewN8nImport } from "./useWorkflows-Dg7q_Tzf.js";
4
+ import { t as FluidGridsContext, wt as createThenOpen } from "./FluidGridsProvider-CDjkq3Zj.js";
5
+ import { a as workflowDescriptionCharactersLeft, i as visibleWorkflowDescription, o as CreateWorkflowRefusalDialog, r as saveWorkflowDescription, t as commitWorkflowDescription } from "./workflow-description-CeXdyWX8.js";
6
6
  import { c as isQuotaExhaustedFailure, t as BILLING_PLANS_PATH } from "./quota-Cdt8yz7N.js";
7
7
  import { A as useFlowStore } from "./node-operation-selection-DHbtGNrG.js";
8
8
  import { a as SdkPermissionGate, i as SdkPermissionButton, s as useFluidGridsPermission, t as FLUIDGRIDS_PERMISSIONS } from "./constants-65QV61nQ.js";
9
- import { t as QuotaExhaustedDialog } from "./QuotaExhaustedDialog-YjKgRTmu.js";
9
+ import { i as QuotaExhaustedDialog, n as useExportWorkflowAs } from "./useWorkflowCodeExport-uKBDVvnA.js";
10
10
  import { r as useTr } from "./TranslationBridge-Da-TPgQm.js";
11
11
  import { a as isExecutionMode, i as isAutonomyLevel, n as EXECUTION_MODES, o as useAutonomyLevelCopy, r as EXECUTION_MODE_ICONS, s as useExecutionModeCopy } from "./run-mode-Bu_pgjeM.js";
12
12
  import { OI as WorkflowExportFormat, vI as WorkflowAccessFilter } from "./graphql-types-dS3Fk9Z5.js";
13
- import { a as assertImportByteSize, g as readProjectArchive, h as primaryImportModule, i as MAX_IMPORT_SOURCE_BYTES, l as importAcceptAttribute, n as ImportSourceError, r as MAX_IMPORT_ARCHIVE_BYTES, s as checkTypeScriptImport, t as CODE_EXPORT_FORMATS, u as importFileKind, v as typeScriptImportSource, x as workflowNameFromFile, y as typeScriptModuleFile } from "./workflow-code-transfer-BsLPUrKP.js";
13
+ import { S as typeScriptModuleFile, a as ImportSourceError, c as assertImportByteSize, f as importAcceptAttribute, i as CODE_EXPORT_FORMATS, n as downloadWorkflowExport, o as MAX_IMPORT_ARCHIVE_BYTES, p as importFileKind, r as parseWorkflowImport, s as MAX_IMPORT_SOURCE_BYTES, u as checkTypeScriptImport, v as primaryImportModule, w as workflowNameFromFile, x as typeScriptImportSource, y as readProjectArchive } from "./workflow-transfer-CktP7o1c.js";
14
14
  import { i as canShareWorkflow, r as canEditWorkflow, t as WorkflowShareDialog } from "./WorkflowShareDialog-B9yZMhEi.js";
15
15
  import { i as useOpenRequest, n as ACTION_PARAM_VALUES, r as useActionParam } from "./useActionParam-B0ebTZmg.js";
16
16
  import { d as useFluidGridsFlag, t as FLUIDGRIDS_FLAGS } from "./feature-flags-B_b8PJ6Z.js";
17
- import { n as downloadWorkflowExport, r as parseWorkflowImport } from "./workflow-transfer-CQnQC-ke.js";
18
17
  import { a as useWorkflowProjects, i as useWorkflowProjectActions, n as useWorkflowFolderActions, r as useWorkflowFolders, t as useBulkWorkflowActions } from "./useWorkflowOrganization-r5FWNBs6.js";
19
18
  import { t as describeOperationError } from "./errors-xPZ-IbQd.js";
20
- import { a as useExecutions } from "./useExecutions-wka2Z5w3.js";
19
+ import { a as useExecutions } from "./useExecutions-BWbMt16D.js";
21
20
  import { a as firstWorkflowProgress, i as builderPathFor, r as GUIDED_TOUR_STATE } from "./firstWorkflow-C_h0KMB2.js";
22
21
  import { n as useFluidGridsPageControls } from "./pageControlsBridge-0pX9s-3k.js";
23
22
  import { i as workflowsListControls } from "./pageControlSpecs-DZJ9K37m.js";
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { A as SENSITIVE_PARAM, M as createConfiguredNode, Tt as useSaveStatusStore, U as paramsFromOperation, V as nodeTitle, W as selectedOperationOf, _ as registryNodeData, ct as autosaveAllowedFor, f as isNodeConfigsInitialized, gt as isFlowComplete, o as NODE_CONFIGS, z as fixedParameterState } from "./FluidGridsProvider-C-WGQwuT.js";
2
+ import { Dt as useSaveStatusStore, G as paramsFromOperation, K as selectedOperationOf, M as SENSITIVE_PARAM, P as createConfiguredNode, U as nodeTitle, V as fixedParameterState, o as NODE_CONFIGS, p as isNodeConfigsInitialized, u as ensureNodeTypeReady, ut as autosaveAllowedFor, vt as isFlowComplete, y as registryNodeData } from "./FluidGridsProvider-CDjkq3Zj.js";
3
3
  import { A as useFlowStore, T as resolveOutputHandles, w as resolveInputHandles } from "./node-operation-selection-DHbtGNrG.js";
4
4
  import { o as isNodeTypeHiddenFromPalette } from "./durable-nodes-DXCCQYWD.js";
5
5
  import { t as computeAttachPosition } from "./attach-node-helpers-4d-YMaBH.js";
@@ -162,12 +162,13 @@ function createBuilderAgentTools(options = {}) {
162
162
  operation: z.string().trim().min(1).max(120).optional().describe("The operation to pin. Omit for a single-operation node."),
163
163
  afterNodeId: nodeId.optional().describe("Place the new node after this node and connect it.")
164
164
  }),
165
- execute: ({ nodeType, operation, afterNodeId }) => {
165
+ execute: async ({ nodeType, operation, afterNodeId }) => {
166
166
  requireCatalogue(catalogueReady);
167
167
  if (isHidden(nodeType) || !NODE_CONFIGS.some((config) => config.type === nodeType)) throw new AgentToolError("NOT_FOUND", `No node type "${nodeType.slice(0, 60)}". Use fg_canvas_node_types.`, { retryable: true });
168
168
  const operations = operationNames(nodeType);
169
169
  if (operation && !operations.includes(operation)) throw new AgentToolError("INVALID_INPUT", `No operation "${operation.slice(0, 60)}" on ${nodeType}. Operations: ${operations.slice(0, 12).join(", ")}.`);
170
170
  if (!operation && operations.length > 1) throw new AgentToolError("INVALID_INPUT", `Choose an operation for ${nodeType}: ${operations.slice(0, 12).join(", ")}.`);
171
+ if (!await ensureNodeTypeReady(nodeType)) throw new AgentToolError("FAILED", `Could not load ${nodeType.slice(0, 60)}. Try again.`);
171
172
  const anchor = afterNodeId ? findNode(afterNodeId) : void 0;
172
173
  const current = store().workflow.nodes;
173
174
  const position = computeAttachPosition(anchor) ?? freePosition(current);
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { d as readTyped, f as writeTyped } from "./shared-C0LCTtyh.js";
2
+ import { n as writeTyped, t as readTyped } from "./typed-calls-BqokR321.js";
3
3
 
4
4
  // src/generated/documents/wspace/CreateTaskQueueDocument.ts
5
5
  const CreateTaskQueueDocument = {
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { d as readTyped, f as writeTyped } from "./shared-C0LCTtyh.js";
2
+ import { n as writeTyped, t as readTyped } from "./typed-calls-BqokR321.js";
3
3
 
4
4
  // src/generated/documents/wspace/PauseActivityDocument.ts
5
5
  const PauseActivityDocument = {
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { n as useAgentMarksStore, r as toPlainText } from "./marksStore-a9oIMMot.js";
3
- import { U as paramsFromOperation, V as nodeTitle, W as selectedOperationOf } from "./FluidGridsProvider-C-WGQwuT.js";
3
+ import { G as paramsFromOperation, K as selectedOperationOf, U as nodeTitle } from "./FluidGridsProvider-CDjkq3Zj.js";
4
4
  import { A as useFlowStore } from "./node-operation-selection-DHbtGNrG.js";
5
5
  import { t as notesKeyOf } from "./notesKey-5EaREBGA.js";
6
6
  import { AgentToolError, defineAgentTool } from "@burdenoff/fe-libs/shared/agent-tools";
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { t as ExecutionsListPage } from "./ExecutionsListPage-Ky3TAL9U.js";
3
- import { t as ExecutionDetailPage } from "./ExecutionDetailPage-B-8s_Sqw.js";
2
+ import { t as ExecutionsListPage } from "./ExecutionsListPage-BYW5WiX7.js";
3
+ import { t as ExecutionDetailPage } from "./ExecutionDetailPage-D5iWwMnk.js";
4
4
 
5
5
  export { ExecutionDetailPage, ExecutionsListPage };