@oomol-lab/open-flow 0.1.0-beta.80 → 0.1.0-beta.82

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 (52) hide show
  1. package/README.md +35 -0
  2. package/dist/browser/{FlowCanvas-CrsiDHK8.js → FlowCanvas-Dew2fmoT.js} +55 -274
  3. package/dist/browser/{createResourceDialog-CS3u9ga9.js → createResourceDialog-bdOJa5Zk.js} +2 -1
  4. package/dist/browser/{exportPng-BOPfjeEi.js → exportPng-Cjdb6COo.js} +2 -2
  5. package/dist/browser/{flowChanges-pFjPHU5k.js → flowChanges-URBEd4DI.js} +2719 -78
  6. package/dist/browser/{flowWorkspace-CRlqc403.js → flowWorkspace-BlXx-yAn.js} +445 -2699
  7. package/dist/browser/{markdownContent-CAG_CQfH.js → markdownContent-D8G_oNOe.js} +18 -41
  8. package/dist/browser/{markdownContent-frwDfQQU.js → markdownContent-IS8xXDoc.js} +18 -40
  9. package/dist/browser/preview.css +88 -80
  10. package/dist/browser/preview.js +291 -188
  11. package/dist/browser/ui.css +8 -0
  12. package/dist/browser/{dist-CHwj9BhV.js → videoLink-NAWDmBtf.js} +35 -1
  13. package/dist/browser/workbench-contract.d.ts +6 -0
  14. package/dist/browser/workbench.css +259 -251
  15. package/dist/browser/workbench.d.ts +2 -0
  16. package/dist/browser/workbench.js +311 -143
  17. package/dist/browser/{ContentIcon-CMn0c-kl.js → wrapLayout-DZvW9dBs.js} +4397 -4152
  18. package/dist/command/index.js +43 -41
  19. package/dist/common/authoring.d.ts +1 -1
  20. package/dist/common/control-api-conformance.js +306 -2
  21. package/dist/common/control-api.d.ts +20 -0
  22. package/dist/common/control-api.js +306 -4
  23. package/dist/common/control-requests.d.ts +3 -5
  24. package/dist/common/control-requests.js +24 -10
  25. package/dist/common/flow-authoring.js +19 -3
  26. package/dist/common/flow-encoding.d.ts +1 -0
  27. package/dist/common/flow-encoding.js +167 -1
  28. package/dist/common/flow-semantics.js +44 -7
  29. package/dist/common/flow-workflowBundle.d.ts +27 -0
  30. package/dist/common/flow-workflowFile.d.ts +2 -0
  31. package/dist/common/flow-workflowReferences.d.ts +4 -0
  32. package/dist/common/mcp.d.ts +2 -0
  33. package/dist/common/mcp.js +312 -4
  34. package/dist/render/browser/licenses.md +4047 -0
  35. package/dist/render/browser/runtime.css +14877 -0
  36. package/dist/render/browser/runtime.js +266765 -0
  37. package/dist/render/common/png.d.ts +24 -0
  38. package/dist/render/node/index.d.ts +11 -0
  39. package/dist/render/node/index.js +9491 -0
  40. package/dist/render/node/licenses.md +75 -0
  41. package/package.json +12 -2
  42. package/src/connector/common/actionContract.ts +26 -0
  43. package/src/control/common/api.ts +50 -0
  44. package/src/control/common/flowDecoders.ts +2 -0
  45. package/src/control/common/mcp.ts +4 -4
  46. package/src/control/common/requests.ts +12 -1
  47. package/src/flow/common/edgeChanges.ts +9 -6
  48. package/src/flow/common/encoding.ts +1 -0
  49. package/src/flow/common/semantics.ts +11 -8
  50. package/src/flow/common/workflowBundle.ts +117 -0
  51. package/src/flow/common/workflowFile.ts +4 -0
  52. package/src/flow/common/workflowReferences.ts +20 -0
@@ -1,11 +1,11 @@
1
- import { A as DropdownMenuSeparator, E as DropdownMenuItem, P as DropdownMenuTrigger, S as DropdownMenu, _ as PopoverTrigger, d as Popover, f as PopoverContent, g as PopoverTitle, ut as IconThemeContext, w as DropdownMenuContent } from "./ContentIcon-CMn0c-kl.js";
1
+ import { D as DropdownMenuContent, L as DropdownMenuTrigger, N as DropdownMenuSeparator, S as IconifyProvider, T as DropdownMenu, _ as ContentIcon, d as PopoverTitle, f as PopoverTrigger, ft as IconThemeContext, k as DropdownMenuItem, o as Popover, s as PopoverContent } from "./wrapLayout-DZvW9dBs.js";
2
2
  import { a as derive, i as compute, l as val } from "./dist-bO8nvHFH.js";
3
3
  import { c as useLang, l as useTranslate, o as I18nProvider, u as useVal } from "./dist-BFmpkX4P.js";
4
4
  import { Cr as cn, i as TooltipTrigger, n as TooltipContent, t as Tooltip, xr as Button } from "./tooltip-BDcVTNpu.js";
5
- import { C as upgradeManualTrigger, M as mapConditionSources, N as nodeInputMappings, Rt as dequal, S as resourceNameIssue, _ as applyFlowChanges, a as DialogFooter, d as Field, g as FlowChangeError, h as FieldLabel, i as DialogDescription, in as Input, l as Icon, m as FieldGroup, o as DialogHeader, p as FieldError, r as DialogContent, s as DialogTitle, t as Dialog, u as Spinner, v as isTriggerNode, w as upgradeRevisionContent } from "./dialog-CFlvkliO.js";
6
- import { $ as action, $n as normalizeTriggerOutputs, An as EmptyHeader, At as connectionCatalog, Bn as errorNotice, Bt as setNodePositions, C as updateValue, Cn as followWorkbenchLink, Ct as Latest, Dn as Empty, Dr as record, En as InputGroupInput, Er as invalidResponse, Ft as restoreCanvasPresentation, Gt as setConnectorConnection, Hn as normalizeFlowQuery, Ht as repairNodeNames, It as setCanvasLayout, J as scopedValue, Jt as updateStartInputDefs, K as combineSources, Kn as decodeTriggerCatalog, Kt as setInputSources, Ln as createI18n, Lt as setComment, Mn as EmptyTitle, Mt as commentIds, Nn as Badge, Nt as flowPresentation, On as EmptyContent, Or as ApiError, Pn as EventSourcesPage, Pt as removeComments, Q as resourceValue, Qt as IdTooltip, Rt as setFlowViewport, S as updateTriggerConfig, Sn as useFlowQuery, Sr as workflowCandidate, St as flowResourceReferences, Tn as InputGroupAddon, Tt as diagnosticItems, U as addNodeIntent, Un as randomId, Ut as resetInputValues, Vn as WorkbenchClient, Vt as setVerticalNodeWidth, W as deriveAddNodeOptions, Wn as allConnectorConnectionsQuery, Wt as setCodeActions, Xt as dequal$1, Y as CacheResource, Yt as updateTriggerSchedule, Z as resourceData, Zt as WorkflowExportMenuItem, _ as updateOutputPorts, _t as providerIcon, a as nameCreatedNodes, ar as encodeWorkflowFile, b as updateTaskAdditionalInputs, c as setInputVariable, cr as workflowNameFromFile, ct as createPersistentCache, d as updateCondition, dt as designerGraph, en as FlowSettingsDialog, er as sampleErrorOutputs, et as provider, f as updateHttpParameters, g as updateNodeSettings, h as updateNodeName, i as deleteSelection, ir as connectorActionMetadata, it as getActionsCache, jn as EmptyMedia, jt as canvasPresentationChange, kn as EmptyDescription, kr as controlErrorCode, kt as actionWithConnections, l as setTriggerConnection, lt as createSessionCache, m as updateNodeIcon, nn as TagPicker, nt as validateAction, o as selectWebhookResponse, or as parseWorkflowFile, ot as getConnectionsCache, p as updateNodeDescription, qt as setServiceConnections, r as applyFlowChanges$1, rr as connection, s as setInputValue, sr as workflowFileName, st as getProvidersCache, t as addNode, tn as FlowTagChips, tr as triggerOutputDefinitions, tt as proxyResponse, u as setTriggerEventSource, v as updateResolution, vt as RunStore, w as updateWebhook, wn as InputGroup, wt as deriveInspectorDiagnostics, x as updateTaskPorts, xt as revisionView, y as updateTask, zt as setNodeContentHidden } from "./flowChanges-pFjPHU5k.js";
5
+ import { C as upgradeManualTrigger, Dt as matchesSchema, M as mapConditionSources, N as nodeInputMappings, Rt as dequal, S as resourceNameIssue, _ as applyFlowChanges, a as DialogFooter, d as Field, g as FlowChangeError, h as FieldLabel, i as DialogDescription, in as Input, kt as schemaObject, l as Icon, m as FieldGroup, o as DialogHeader, p as FieldError, r as DialogContent, s as DialogTitle, t as Dialog, u as Spinner, v as isTriggerNode, w as upgradeRevisionContent } from "./dialog-CFlvkliO.js";
6
+ import { $ as resourceValue, $n as allConnectorConnectionsQuery, $t as WorkflowExportDialog, At as actionWithConnections, Bn as EmptyMedia, Br as ApiError, Bt as setNodeContentHidden, C as updateValue, Ct as flowResourceReferences, Et as diagnosticItems, Fn as InputGroupInput, Ft as removeComments, Gt as setCodeActions, Hn as Badge, Ht as setVerticalNodeWidth, In as Empty, It as restoreCanvasPresentation, J as scopedValue, Jt as setServiceConnections, K as combineSources, Kn as createI18n, Kt as setConnectorConnection, Ln as EmptyContent, Lt as setCanvasLayout, Mn as followWorkbenchLink, Mt as canvasPresentationChange, Nn as InputGroup, Nt as commentIds, Pn as InputGroupAddon, Pr as workflowCandidate, Pt as flowPresentation, Q as resourceData, Qn as randomId, Qt as WorkflowBundleSummary, Rn as EmptyDescription, Rr as invalidResponse, Rt as setComment, S as updateTriggerConfig, St as revisionView, Tt as deriveInspectorDiagnostics, U as addNodeIntent, Un as EventSourcesPage, Ut as repairNodeNames, Vn as EmptyTitle, Vr as controlErrorCode, Vt as setNodePositions, W as deriveAddNodeOptions, Wt as resetInputValues, X as CacheResource, Xn as WorkbenchClient, Xt as updateTriggerSchedule, Y as connectorActionPresentation, Yn as errorNotice, Yt as updateStartInputDefs, Zn as normalizeFlowQuery, Zt as dequal$1, _ as updateOutputPorts, _r as workflowBundleFromPreview, a as nameCreatedNodes, an as FlowTagChips, at as getActionsCache, b as updateTaskAdditionalInputs, br as workflowNameFromFile, c as setInputVariable, cr as normalizeTriggerOutputs, ct as getProvidersCache, d as updateCondition, en as WorkflowExportMenuItem, et as action, f as updateHttpParameters, fr as isJsonValue, ft as designerGraph, g as updateNodeSettings, gr as parseWorkflowImportFile, h as updateNodeName, hr as encodeWorkflowBundle, i as deleteSelection, in as FlowSettingsDialog, jn as useFlowQuery, jt as connectionCatalog, l as setTriggerConnection, lr as sampleErrorOutputs, lt as createPersistentCache, m as updateNodeIcon, mr as connectorActionMetadata, nn as IdTooltip, nt as proxyResponse, o as selectWebhookResponse, on as TagPicker, p as updateNodeDescription, pr as connection, qt as setInputSources, r as applyFlowChanges$1, rt as validateAction, s as setInputValue, st as getConnectionsCache, t as addNode, tn as useWorkflowExportAction, tr as decodeTriggerCatalog, tt as provider, u as setTriggerEventSource, ur as triggerOutputDefinitions, ut as createSessionCache, v as updateResolution, vr as encodeWorkflowFile, vt as providerIcon, w as updateWebhook, wt as Latest, x as updateTaskPorts, y as updateTask, yr as workflowFileName, yt as RunStore, zn as EmptyHeader, zr as record, zt as setFlowViewport } from "./flowChanges-URBEd4DI.js";
7
7
  import { a as uiLanguages, i as uiLanguageNames, n as isUiLanguage, r as resolveUiLanguage, t as importedWorkflowName } from "./languages-gYzoQqCi.js";
8
- import { i as objectValue, n as isJsonValue } from "./value-BbFQZZ_V.js";
8
+ import { i as objectValue, n as isJsonValue$1, s as valueType, t as initialValue } from "./value-BbFQZZ_V.js";
9
9
  import { Suspense, forwardRef, lazy, useEffect, useImperativeHandle, useLayoutEffect, useRef, useState } from "react";
10
10
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
11
11
  import * as Cause from "effect/Cause";
@@ -101,6 +101,9 @@ var NavigationStore = class {
101
101
  async importFlow(file, name, key, importer, tagIds) {
102
102
  return await this.#openNewFlow(() => this.#store.importFlow(file, name, key, importer, tagIds));
103
103
  }
104
+ async importFlowBundle(file, name, key, importer, tagIds) {
105
+ return await this.#openNewFlow(() => this.#store.importFlowBundle(file, name, key, importer, tagIds));
106
+ }
104
107
  async createFlow(name, create, tagIds) {
105
108
  return await this.#openNewFlow(() => this.#store.createFlow(name, create, tagIds));
106
109
  }
@@ -517,7 +520,7 @@ function FlowDeletionDialog({ flow, workspace, container, busy, finalFocus, onCl
517
520
  }
518
521
  //#endregion
519
522
  //#region src/workbench/browser/runtime/shell/resourceBrowser.tsx
520
- var CreateResourceDialog = lazy(() => import("./createResourceDialog-CS3u9ga9.js"));
523
+ var CreateResourceDialog = lazy(() => import("./createResourceDialog-bdOJa5Zk.js"));
521
524
  var flowIdTooltipAlignOffset = 44;
522
525
  var renamePopoverAlignOffset = -12;
523
526
  function compactFlowId(flowId) {
@@ -535,6 +538,7 @@ function formatUpdatedAt(updatedAt, locale) {
535
538
  });
536
539
  }
537
540
  function FlowItem({ busy, flow, href, hrefForFlow, onSelect, store, onTagFilter, onChanged, settingsFinalFocus }) {
541
+ const exportAction = useWorkflowExportAction(() => void store.workspace.exportFlow(flow.flowId));
538
542
  const [root, setRoot] = useState(null);
539
543
  const renameAnchor = useRef(null);
540
544
  const actionsButton = useRef(null);
@@ -584,7 +588,11 @@ function FlowItem({ busy, flow, href, hrefForFlow, onSelect, store, onTagFilter,
584
588
  children: [/* @__PURE__ */ jsx("span", {
585
589
  "aria-hidden": "true",
586
590
  className: "resource-flow-icon",
587
- children: /* @__PURE__ */ jsx("i", { className: "i-lucide-light:workflow" })
591
+ children: /* @__PURE__ */ jsx(ContentIcon, {
592
+ src: flow.icon,
593
+ className: "size-3.5",
594
+ fallback: /* @__PURE__ */ jsx("i", { className: "i-lucide-light:workflow" })
595
+ })
588
596
  }), /* @__PURE__ */ jsxs("span", {
589
597
  className: "resource-primary-copy",
590
598
  children: [/* @__PURE__ */ jsxs("span", {
@@ -612,7 +620,13 @@ function FlowItem({ busy, flow, href, hrefForFlow, onSelect, store, onTagFilter,
612
620
  container: root,
613
621
  collisionBoundary: [],
614
622
  positionMethod: "fixed",
615
- children: flow.name
623
+ children: /* @__PURE__ */ jsxs("div", {
624
+ className: "flex min-w-0 flex-col gap-1",
625
+ children: [/* @__PURE__ */ jsx("span", { children: flow.name }), flow.description && /* @__PURE__ */ jsx("span", {
626
+ className: "whitespace-pre-wrap",
627
+ children: flow.description
628
+ })]
629
+ })
616
630
  })] }), flow.status == "active" && /* @__PURE__ */ jsx(Popover, {
617
631
  onOpenChange: (open) => {
618
632
  setMode(open ? "rename" : "idle");
@@ -745,106 +759,109 @@ function FlowItem({ busy, flow, href, hrefForFlow, onSelect, store, onTagFilter,
745
759
  container: root,
746
760
  hrefForFlow,
747
761
  onSelectFlow: onSelect
748
- }), /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsx(TooltipTrigger, {
749
- render: /* @__PURE__ */ jsx(DropdownMenuTrigger, { render: /* @__PURE__ */ jsx(Button, {
750
- ref: actionsButton,
751
- "aria-label": t("resource.actions"),
752
- size: "icon-sm",
753
- variant: "ghost"
754
- }) }),
755
- children: /* @__PURE__ */ jsx("i", {
756
- "aria-hidden": "true",
757
- className: "i-lucide-light:ellipsis"
758
- })
759
- }), /* @__PURE__ */ jsx(TooltipContent, {
760
- container: root,
761
- collisionBoundary: [],
762
- positionMethod: "fixed",
763
- children: t("resource.actions")
764
- })] }), /* @__PURE__ */ jsxs(DropdownMenuContent, {
765
- align: "end",
766
- collisionBoundary: [],
767
- positionMethod: "fixed",
768
- container: root,
769
- className: "w-48",
770
- finalFocus: mode == "idle" ? actionsButton : false,
771
- children: [
772
- /* @__PURE__ */ jsxs(DropdownMenuItem, {
773
- disabled: flow.status != "active",
774
- onClick: () => onSelect(flow),
775
- children: [/* @__PURE__ */ jsx("i", {
776
- "aria-hidden": "true",
777
- className: "i-lucide-light:square-pen size-4 shrink-0"
778
- }), t("resource.edit")]
779
- }),
780
- /* @__PURE__ */ jsxs(DropdownMenuItem, {
781
- disabled: flow.status != "active" || busy != null || pending != null,
782
- onClick: () => {
783
- setName(flow.name);
784
- setMode("rename");
785
- },
786
- children: [/* @__PURE__ */ jsx("i", {
787
- "aria-hidden": "true",
788
- className: "i-lucide-light:text-cursor-input size-4 shrink-0"
789
- }), t("common.rename")]
790
- }),
791
- /* @__PURE__ */ jsxs(DropdownMenuItem, {
792
- disabled: flow.status != "active" || busy != null,
793
- onClick: () => setMode("settings"),
794
- children: [/* @__PURE__ */ jsx("i", {
795
- "aria-hidden": "true",
796
- className: "i-lucide-light:settings size-4 shrink-0"
797
- }), t("flowSettings.title")]
798
- }),
799
- /* @__PURE__ */ jsxs(DropdownMenuItem, {
800
- disabled: flow.status != "active" || busy != null || pending != null || flow.live != null && !changed,
801
- onClick: () => void update("publish"),
802
- children: [/* @__PURE__ */ jsx("i", {
803
- "aria-hidden": "true",
804
- className: "i-lucide-light:upload size-4 shrink-0"
805
- }), t(pending == "publish" ? "workspace.publishing" : flow.live == null ? "resource.publish" : "resource.publishUpdate")]
806
- }),
807
- flow.live != null && /* @__PURE__ */ jsxs(DropdownMenuItem, {
808
- disabled: flow.status != "active" || busy != null || pending != null,
809
- onClick: () => void update(flow.live?.enabled != true),
810
- children: [/* @__PURE__ */ jsx("i", {
811
- "aria-hidden": "true",
812
- className: cn("size-4 shrink-0", flow.live.enabled ? "i-lucide-light:square" : "i-lucide-light:play")
813
- }), t(flow.live.enabled ? "resource.stop" : "resource.start")]
814
- }),
815
- /* @__PURE__ */ jsx(DropdownMenuSeparator, { className: "mx-2 bg-border/50" }),
816
- /* @__PURE__ */ jsx(WorkflowExportMenuItem, {
817
- disabled: flow.status != "active" || busy != null,
818
- onClick: () => void store.workspace.exportFlow(flow.flowId)
819
- }),
820
- /* @__PURE__ */ jsxs(DropdownMenuItem, {
821
- disabled: flow.status != "active",
822
- onClick: () => onSelect(flow, "publications"),
823
- children: [/* @__PURE__ */ jsx("i", {
824
- "aria-hidden": "true",
825
- className: "i-lucide-light:cloud-upload size-4 shrink-0"
826
- }), t("workspace.publications")]
827
- }),
828
- /* @__PURE__ */ jsxs(DropdownMenuItem, {
829
- disabled: flow.status != "active",
830
- onClick: () => onSelect(flow, "runs"),
831
- children: [/* @__PURE__ */ jsx("i", {
832
- "aria-hidden": "true",
833
- className: "i-lucide-light:history size-4 shrink-0"
834
- }), t("workspace.runs")]
835
- }),
836
- /* @__PURE__ */ jsx(DropdownMenuSeparator, { className: "mx-2 bg-border/50" }),
837
- /* @__PURE__ */ jsxs(DropdownMenuItem, {
838
- disabled: flow.status != "active" || busy != null || pending != null,
839
- variant: "destructive",
840
- onClick: () => setMode("delete"),
841
- children: [/* @__PURE__ */ jsx("i", {
842
- "aria-hidden": "true",
843
- className: "i-lucide-light:trash-2 size-4 shrink-0"
844
- }), t("common.delete")]
762
+ }), /* @__PURE__ */ jsxs(DropdownMenu, {
763
+ onOpenChangeComplete: exportAction.onOpenChangeComplete,
764
+ children: [/* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsx(TooltipTrigger, {
765
+ render: /* @__PURE__ */ jsx(DropdownMenuTrigger, { render: /* @__PURE__ */ jsx(Button, {
766
+ ref: actionsButton,
767
+ "aria-label": t("resource.actions"),
768
+ size: "icon-sm",
769
+ variant: "ghost"
770
+ }) }),
771
+ children: /* @__PURE__ */ jsx("i", {
772
+ "aria-hidden": "true",
773
+ className: "i-lucide-light:ellipsis"
845
774
  })
846
- ]
847
- })] })]
775
+ }), /* @__PURE__ */ jsx(TooltipContent, {
776
+ container: root,
777
+ collisionBoundary: [],
778
+ positionMethod: "fixed",
779
+ children: t("resource.actions")
780
+ })] }), /* @__PURE__ */ jsxs(DropdownMenuContent, {
781
+ align: "end",
782
+ collisionBoundary: [],
783
+ positionMethod: "fixed",
784
+ container: root,
785
+ className: "w-48",
786
+ finalFocus: mode == "idle" ? actionsButton : false,
787
+ children: [
788
+ /* @__PURE__ */ jsxs(DropdownMenuItem, {
789
+ disabled: flow.status != "active",
790
+ onClick: () => onSelect(flow),
791
+ children: [/* @__PURE__ */ jsx("i", {
792
+ "aria-hidden": "true",
793
+ className: "i-lucide-light:square-pen size-4 shrink-0"
794
+ }), t("resource.edit")]
795
+ }),
796
+ /* @__PURE__ */ jsxs(DropdownMenuItem, {
797
+ disabled: flow.status != "active" || busy != null || pending != null,
798
+ onClick: () => {
799
+ setName(flow.name);
800
+ setMode("rename");
801
+ },
802
+ children: [/* @__PURE__ */ jsx("i", {
803
+ "aria-hidden": "true",
804
+ className: "i-lucide-light:text-cursor-input size-4 shrink-0"
805
+ }), t("common.rename")]
806
+ }),
807
+ /* @__PURE__ */ jsxs(DropdownMenuItem, {
808
+ disabled: flow.status != "active" || busy != null,
809
+ onClick: () => setMode("settings"),
810
+ children: [/* @__PURE__ */ jsx("i", {
811
+ "aria-hidden": "true",
812
+ className: "i-lucide-light:settings size-4 shrink-0"
813
+ }), t("flowSettings.title")]
814
+ }),
815
+ /* @__PURE__ */ jsxs(DropdownMenuItem, {
816
+ disabled: flow.status != "active" || busy != null || pending != null || flow.live != null && !changed,
817
+ onClick: () => void update("publish"),
818
+ children: [/* @__PURE__ */ jsx("i", {
819
+ "aria-hidden": "true",
820
+ className: "i-lucide-light:upload size-4 shrink-0"
821
+ }), t(pending == "publish" ? "workspace.publishing" : flow.live == null ? "resource.publish" : "resource.publishUpdate")]
822
+ }),
823
+ flow.live != null && /* @__PURE__ */ jsxs(DropdownMenuItem, {
824
+ disabled: flow.status != "active" || busy != null || pending != null,
825
+ onClick: () => void update(flow.live?.enabled != true),
826
+ children: [/* @__PURE__ */ jsx("i", {
827
+ "aria-hidden": "true",
828
+ className: cn("size-4 shrink-0", flow.live.enabled ? "i-lucide-light:square" : "i-lucide-light:play")
829
+ }), t(flow.live.enabled ? "resource.stop" : "resource.start")]
830
+ }),
831
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, { className: "mx-2 bg-border/50" }),
832
+ /* @__PURE__ */ jsx(WorkflowExportMenuItem, {
833
+ disabled: flow.status != "active" || busy != null,
834
+ onClick: exportAction.onClick
835
+ }),
836
+ /* @__PURE__ */ jsxs(DropdownMenuItem, {
837
+ disabled: flow.status != "active",
838
+ onClick: () => onSelect(flow, "publications"),
839
+ children: [/* @__PURE__ */ jsx("i", {
840
+ "aria-hidden": "true",
841
+ className: "i-lucide-light:cloud-upload size-4 shrink-0"
842
+ }), t("workspace.publications")]
843
+ }),
844
+ /* @__PURE__ */ jsxs(DropdownMenuItem, {
845
+ disabled: flow.status != "active",
846
+ onClick: () => onSelect(flow, "runs"),
847
+ children: [/* @__PURE__ */ jsx("i", {
848
+ "aria-hidden": "true",
849
+ className: "i-lucide-light:history size-4 shrink-0"
850
+ }), t("workspace.runs")]
851
+ }),
852
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, { className: "mx-2 bg-border/50" }),
853
+ /* @__PURE__ */ jsxs(DropdownMenuItem, {
854
+ disabled: flow.status != "active" || busy != null || pending != null,
855
+ variant: "destructive",
856
+ onClick: () => setMode("delete"),
857
+ children: [/* @__PURE__ */ jsx("i", {
858
+ "aria-hidden": "true",
859
+ className: "i-lucide-light:trash-2 size-4 shrink-0"
860
+ }), t("common.delete")]
861
+ })
862
+ ]
863
+ })]
864
+ })]
848
865
  }),
849
866
  mode == "settings" && /* @__PURE__ */ jsx(FlowSettingsDialog, {
850
867
  store,
@@ -895,7 +912,7 @@ function FlowSkeleton() {
895
912
  })]
896
913
  });
897
914
  }
898
- var FlowBrowser = forwardRef(function FlowBrowser({ catalogWidth, createFlowDisabled, createFlowField, hrefForFlow, initializing = false, onCreateFlow, onImportFlow, onSelectFlow, store, language }, ref) {
915
+ var FlowBrowser = forwardRef(function FlowBrowser({ catalogWidth, createFlowDisabled, createFlowField, hrefForFlow, initializing = false, onCreateFlow, onImportFlow, onImportFlowBundle, onSelectFlow, store, language }, ref) {
899
916
  const t = useTranslate();
900
917
  const busy = useVal(store.workspace.$.busy);
901
918
  const [filter, setFilter] = useState("");
@@ -943,7 +960,7 @@ var FlowBrowser = forwardRef(function FlowBrowser({ catalogWidth, createFlowDisa
943
960
  if (initializing || store.workspace.$.busy.value != null || creation$.value != null || onImportFlow == null) return "unavailable";
944
961
  let file;
945
962
  try {
946
- file = parseWorkflowFile(input.text);
963
+ file = parseWorkflowImportFile(input.text);
947
964
  } catch {
948
965
  store.workspace.notify({
949
966
  kind: "error",
@@ -951,9 +968,17 @@ var FlowBrowser = forwardRef(function FlowBrowser({ catalogWidth, createFlowDisa
951
968
  });
952
969
  return "invalid-file";
953
970
  }
971
+ if (file.kind == "open-flow-workflow-bundle" && onImportFlowBundle == null) {
972
+ store.workspace.notify({
973
+ kind: "error",
974
+ message: t("workflowTransfer.hostUnsupported")
975
+ });
976
+ return "unavailable";
977
+ }
978
+ const entry = file.kind == "open-flow-workflow-bundle" ? file.workflows.find((item) => item.flowId == file.entryFlowId).file : file;
954
979
  setCreationTags([]);
955
980
  setCreatingTag(false);
956
- setName(file.name ?? (input.fileName == null ? importedWorkflowName(language) : workflowNameFromFile(input.fileName)));
981
+ setName(entry.name ?? (input.fileName == null ? importedWorkflowName(language) : workflowNameFromFile(input.fileName)));
957
982
  creation$.set({
958
983
  kind: "import",
959
984
  file,
@@ -974,11 +999,11 @@ var FlowBrowser = forwardRef(function FlowBrowser({ catalogWidth, createFlowDisa
974
999
  const request = creation$.value;
975
1000
  const nextName = name.trim();
976
1001
  if (request == null || creatingTag || resourceNameIssue(nextName) != null) return;
977
- if (!(request.kind == "create" ? await onCreateFlow(nextName, creationTags) : await onImportFlow?.(request.file, nextName, request.key, creationTags)) || command.current == null || creation$.value !== request) return;
1002
+ if (!(request.kind == "create" ? await onCreateFlow(nextName, creationTags) : request.file.kind == "open-flow-workflow-bundle" ? await onImportFlowBundle?.(request.file, nextName, request.key, creationTags) : await onImportFlow?.(request.file, nextName, request.key, creationTags)) || command.current == null || creation$.value !== request) return;
978
1003
  creation$.set(void 0);
979
1004
  setName("");
980
1005
  }
981
- return /* @__PURE__ */ jsx("main", {
1006
+ return /* @__PURE__ */ jsx(IconifyProvider, { children: /* @__PURE__ */ jsx("main", {
982
1007
  className: "resource-browser",
983
1008
  "data-tooltip-portal": true,
984
1009
  ref: setRoot,
@@ -1203,6 +1228,10 @@ var FlowBrowser = forwardRef(function FlowBrowser({ catalogWidth, createFlowDisa
1203
1228
  })
1204
1229
  ]
1205
1230
  }),
1231
+ /* @__PURE__ */ jsx(WorkflowExportDialog, {
1232
+ workspace: store.workspace,
1233
+ container: root
1234
+ }),
1206
1235
  creation != null && /* @__PURE__ */ jsx(Suspense, {
1207
1236
  fallback: null,
1208
1237
  children: /* @__PURE__ */ jsx(CreateResourceDialog, {
@@ -1215,6 +1244,10 @@ var FlowBrowser = forwardRef(function FlowBrowser({ catalogWidth, createFlowDisa
1215
1244
  value: creationTags,
1216
1245
  onChange: setCreationTags
1217
1246
  })] }),
1247
+ summary: creation.kind == "import" && creation.file.kind == "open-flow-workflow-bundle" ? /* @__PURE__ */ jsx(WorkflowBundleSummary, {
1248
+ bundle: creation.file,
1249
+ entryName: name
1250
+ }) : void 0,
1218
1251
  field: createFlowField,
1219
1252
  id: "flow-name",
1220
1253
  issue: resourceNameIssue(name),
@@ -1236,7 +1269,7 @@ var FlowBrowser = forwardRef(function FlowBrowser({ catalogWidth, createFlowDisa
1236
1269
  })
1237
1270
  ]
1238
1271
  })
1239
- });
1272
+ }) });
1240
1273
  });
1241
1274
  //#endregion
1242
1275
  //#region ../../node_modules/.bun/nanoid@6.0.1/node_modules/nanoid/index.browser.js
@@ -1274,6 +1307,21 @@ var customRandom = (alphabet, defaultSize, getRandom) => {
1274
1307
  };
1275
1308
  var customAlphabet = (alphabet, size = 21) => customRandom(alphabet, size | 0, random);
1276
1309
  //#endregion
1310
+ //#region src/connector/common/actionContract.ts
1311
+ /** These rules also apply to existing Revision snapshots without a catalog lookup. */
1312
+ var connectorActionContracts = { "leina.send_notification": {
1313
+ inputConstraints: [{
1314
+ handle: "leinaId",
1315
+ jsonSchema: {
1316
+ type: "string",
1317
+ pattern: "\\S"
1318
+ },
1319
+ code: "leina.robot-required",
1320
+ message: "Select a Leina robot or bind its identifier to an input source."
1321
+ }],
1322
+ pendingMessageInput: "message"
1323
+ } };
1324
+ //#endregion
1277
1325
  //#region src/flow/common/edgeChanges.ts
1278
1326
  function connect(content, edge) {
1279
1327
  const selected = content.document.graph;
@@ -1284,11 +1332,12 @@ function connect(content, edge) {
1284
1332
  }];
1285
1333
  const source = selected.nodes[edge.source];
1286
1334
  const target = selected.nodes[edge.target];
1287
- if (edge.sourceHandle == "pending" && (source?.kind == "approval" || source?.kind == "wait") && target?.kind == "task" && "executor" in target.task && target.task.executor.kind == "connector" && target.task.executor.action == "leina.send_notification" && (target.inputs.message == null || target.inputs.message.kind == "unset")) changes.push({
1335
+ const messageInput = target?.kind == "task" && "executor" in target.task && target.task.executor.kind == "connector" ? connectorActionContracts[target.task.executor.action]?.pendingMessageInput : void 0;
1336
+ if (edge.sourceHandle == "pending" && (source?.kind == "approval" || source?.kind == "wait") && target?.kind == "task" && messageInput != null && (target.inputs[messageInput] == null || target.inputs[messageInput]?.kind == "unset")) changes.push({
1288
1337
  kind: "graph.node.input.set",
1289
1338
  nodeId: edge.target,
1290
- handle: "message",
1291
- before: target.inputs.message,
1339
+ handle: messageInput,
1340
+ before: target.inputs[messageInput],
1292
1341
  value: {
1293
1342
  kind: "sources",
1294
1343
  sources: [{
@@ -1940,7 +1989,7 @@ async function readRunInputs(scope) {
1940
1989
  return new Map(records.flatMap((raw) => {
1941
1990
  const record = objectValue(raw);
1942
1991
  const values = objectValue(record?.values);
1943
- return record != null && typeof record.key === "string" && typeof record.signature === "string" && typeof record.valid === "boolean" && values != null && isJsonValue(values) ? [[record.key, {
1992
+ return record != null && typeof record.key === "string" && typeof record.signature === "string" && typeof record.valid === "boolean" && values != null && isJsonValue$1(values) ? [[record.key, {
1944
1993
  signature: record.signature,
1945
1994
  valid: record.valid,
1946
1995
  values
@@ -1954,6 +2003,76 @@ async function writeRunInputs(scope, key, inputs) {
1954
2003
  }, `${scopeKey(scope)}\u0000${key}`));
1955
2004
  }
1956
2005
  //#endregion
2006
+ //#region src/workbench/browser/runtime/runs/triggerTestInputs.ts
2007
+ /** Best-effort test data. Unsupported constraints stay unset for the user to fill in. */
2008
+ function sampleValue(schema) {
2009
+ const source = schemaObject(schema);
2010
+ const types = Array.isArray(source?.type) ? source.type : [source?.type];
2011
+ const type = types.find((candidate) => candidate !== "null") ?? types[0];
2012
+ const initial = initialValue(schema, valueType({ type }, null));
2013
+ if (source == null) return isJsonValue(initial) && matchesSchema(initial, schema) ? initial : void 0;
2014
+ if ((Object.hasOwn(source, "default") || Object.hasOwn(source, "const") || Array.isArray(source.enum)) && isJsonValue(initial) && matchesSchema(initial, schema)) return initial;
2015
+ let value = null;
2016
+ switch (type) {
2017
+ case "object": {
2018
+ const properties = schemaObject(source.properties ?? {}) ?? {};
2019
+ const required = Array.isArray(source.required) ? source.required : [];
2020
+ value = Object.fromEntries(Object.entries(properties).flatMap(([key, property]) => {
2021
+ if (!required.includes(key) && !Object.hasOwn(schemaObject(property) ?? {}, "default")) return [];
2022
+ const sample = sampleValue(property);
2023
+ return sample === void 0 ? [] : [[key, sample]];
2024
+ }));
2025
+ break;
2026
+ }
2027
+ case "array": {
2028
+ const item = sampleValue(source.items ?? {});
2029
+ const count = Math.min(20, typeof source.maxItems === "number" ? source.maxItems : 20, Math.max(1, Number(source.minItems) || 0));
2030
+ value = item === void 0 ? [] : Array.from({ length: count }, () => structuredClone(item));
2031
+ break;
2032
+ }
2033
+ case "string":
2034
+ value = ({
2035
+ "date-time": (/* @__PURE__ */ new Date()).toISOString(),
2036
+ "date": (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
2037
+ "time": "12:00:00Z",
2038
+ "email": "test@example.com",
2039
+ "uri": "https://example.com",
2040
+ "uri-reference": "https://example.com",
2041
+ "uuid": "00000000-0000-4000-8000-000000000001"
2042
+ }[String(source.format)] ?? "sample").padEnd(Math.min(256, Number(source.minLength) || 0), "x").slice(0, typeof source.maxLength === "number" ? source.maxLength : void 0);
2043
+ break;
2044
+ case "number":
2045
+ case "integer": {
2046
+ const step = typeof source.multipleOf === "number" && source.multipleOf > 0 ? source.multipleOf : 1;
2047
+ let number = typeof source.minimum === "number" ? source.minimum : 1;
2048
+ if (typeof source.exclusiveMinimum === "number") number = Math.max(number, source.exclusiveMinimum + step);
2049
+ if (typeof source.maximum === "number") number = Math.min(number, source.maximum);
2050
+ if (typeof source.exclusiveMaximum === "number") number = Math.min(number, source.exclusiveMaximum - step);
2051
+ value = Math.ceil((type === "integer" ? Math.ceil(number) : number) / step) * step;
2052
+ break;
2053
+ }
2054
+ default: if (isJsonValue(initial)) value = initial;
2055
+ }
2056
+ if (matchesSchema(value, schema)) return value;
2057
+ return isJsonValue(initial) && matchesSchema(initial, schema) ? initial : void 0;
2058
+ }
2059
+ function defaultTriggerTestOutputs(trigger) {
2060
+ if (trigger.kind === "error") return structuredClone(sampleErrorOutputs);
2061
+ if (trigger.kind === "cron") return { scheduledAt: (/* @__PURE__ */ new Date()).toISOString() };
2062
+ return Object.fromEntries(triggerOutputDefinitions(trigger).flatMap((port) => {
2063
+ if (trigger.kind === "start" && port.nullable) return [];
2064
+ let value = trigger.kind === "webhook" && port.handle === "webhookUrl" ? "https://example.com/webhook" : sampleValue(port.jsonSchema);
2065
+ if (trigger.kind === "webhook" && port.handle === "body") {
2066
+ const body = {
2067
+ ...schemaObject(value ?? {}),
2068
+ ...Object.fromEntries(trigger.bodyFields.flatMap((field) => field.value === void 0 ? [] : [[field.handle, structuredClone(field.value)]]))
2069
+ };
2070
+ value = matchesSchema(body, port.jsonSchema) ? body : void 0;
2071
+ }
2072
+ return value === void 0 ? port.nullable ? [[port.handle, null]] : [] : [[port.handle, value]];
2073
+ }));
2074
+ }
2075
+ //#endregion
1957
2076
  //#region src/workbench/browser/runtime/runs/runRequestStore.ts
1958
2077
  var initialState$5 = { starting: false };
1959
2078
  function inputSpec(draft, triggerId) {
@@ -1963,7 +2082,7 @@ function inputSpec(draft, triggerId) {
1963
2082
  return definitions.length === 0 ? void 0 : {
1964
2083
  definitions,
1965
2084
  allowOmittedNullable: trigger.kind == "start",
1966
- samples: trigger.kind == "error" ? sampleErrorOutputs : void 0
2085
+ trigger
1967
2086
  };
1968
2087
  }
1969
2088
  function inputSignature(spec) {
@@ -1980,14 +2099,13 @@ async function inputEditor(spec, language, values) {
1980
2099
  if (spec == null) return void 0;
1981
2100
  const { FlowRunInputEditorStore } = await import("./flowRunInputEditorStore-ys1-w9GW.js").then((n) => n.t);
1982
2101
  const editor = new FlowRunInputEditorStore(spec.definitions, language, { allowOmittedNullable: spec.allowOmittedNullable });
1983
- const initial = values ?? spec.samples;
1984
- if (initial != null) editor.replaceValues(Object.fromEntries(spec.definitions.flatMap(({ handle }) => Object.hasOwn(initial, handle) ? [[handle, initial[handle]]] : [])));
2102
+ const initial = values ?? defaultTriggerTestOutputs(spec.trigger);
2103
+ editor.replaceValues(Object.fromEntries(spec.definitions.flatMap(({ handle }) => Object.hasOwn(initial, handle) ? [[handle, initial[handle]]] : [])));
1985
2104
  return editor;
1986
2105
  }
1987
2106
  function testOutputs(revision, triggerId) {
1988
2107
  const node = revisionView(revision).graph()?.nodes[triggerId];
1989
- if (node?.kind == "error") return sampleErrorOutputs;
1990
- return node?.kind === "cron" ? { scheduledAt: (/* @__PURE__ */ new Date()).toISOString() } : {};
2108
+ return node != null && isTriggerNode(node) ? defaultTriggerTestOutputs(node) : {};
1991
2109
  }
1992
2110
  var RunRequestStore = class {
1993
2111
  #prepareDraft;
@@ -3113,10 +3231,10 @@ function ports(values) {
3113
3231
  }));
3114
3232
  }
3115
3233
  function option$1(action, t) {
3116
- if (action.actionId == "leina.send_notification") action = {
3234
+ const presentation = connectorActionPresentation(action.actionId, t);
3235
+ if (presentation != null) action = {
3117
3236
  ...action,
3118
- name: t("leina.notification"),
3119
- description: t("leina.description")
3237
+ name: presentation.name
3120
3238
  };
3121
3239
  return {
3122
3240
  connector: action,
@@ -3781,6 +3899,17 @@ var FlowCatalog = class {
3781
3899
  ...tagIds == null ? {} : { tagIds }
3782
3900
  }) : this.#client.getFlow(await (tagIds == null ? importer(file, name, key) : importer(file, name, key, { tagIds }))));
3783
3901
  }
3902
+ importBundle(file, name, key, importer, tagIds) {
3903
+ return this.#create(async () => {
3904
+ const result = importer == null ? await this.#client.importFlowBundle(file, {
3905
+ name,
3906
+ idempotencyKey: key,
3907
+ ...tagIds == null ? {} : { tagIds }
3908
+ }) : await (tagIds == null ? importer(file, name, key) : importer(file, name, key, { tagIds }));
3909
+ if (!this.#disposed) for (const member of result.flows) this.#insert(member);
3910
+ return result.flow;
3911
+ });
3912
+ }
3784
3913
  async #create(create) {
3785
3914
  try {
3786
3915
  const created = await create();
@@ -6019,6 +6148,7 @@ var NodeEdits = class {
6019
6148
  //#endregion
6020
6149
  //#region src/workbench/browser/runtime/stores/workspaceStore.ts
6021
6150
  var WorkspaceStore = class {
6151
+ #exporting;
6022
6152
  #edits;
6023
6153
  #canvasCommandListeners;
6024
6154
  #client;
@@ -6041,6 +6171,8 @@ var WorkspaceStore = class {
6041
6171
  this.flowCreated = flowCreated;
6042
6172
  this.accessChanged = accessChanged;
6043
6173
  this.filterTriggerConnections = filterTriggerConnections;
6174
+ this.exportPreview = val(void 0);
6175
+ this.#exporting = false;
6044
6176
  this.#canvasCommandListeners = /* @__PURE__ */ new Set();
6045
6177
  this.notify = (notice) => {
6046
6178
  if (!this.#disposed) this.#setNotice(notice);
@@ -6072,6 +6204,7 @@ var WorkspaceStore = class {
6072
6204
  dispose() {
6073
6205
  this.catalogs.dispose();
6074
6206
  this.#disposed = true;
6207
+ this.exportPreview.dispose();
6075
6208
  this.#edits.dispose();
6076
6209
  this.#stopCatalogWatch?.();
6077
6210
  this.#stopFlowWatch?.();
@@ -6270,29 +6403,54 @@ var WorkspaceStore = class {
6270
6403
  return this.#edits.selectNodes(nodeIds);
6271
6404
  }
6272
6405
  async exportFlow(flowId) {
6406
+ if (this.#exporting || this.exportPreview.value != null || this.$.busy.value != null) return;
6407
+ this.#exporting = true;
6273
6408
  const current = this.#edits.capture();
6274
6409
  const selected = this.#model.value.flowId == flowId;
6275
- if (selected && (!await this.#edits.flush() || !current())) {
6276
- this.#setNotice({
6277
- kind: "error",
6278
- message: this.#i18n.t("notice.exportSaveFailed")
6279
- });
6280
- return;
6281
- }
6282
- this.#edits.set({ busy: "flow" });
6283
6410
  try {
6284
- const file = await this.#client.exportFlow(flowId);
6411
+ if (selected && (!await this.#edits.flush() || !current())) {
6412
+ this.#setNotice({
6413
+ kind: "error",
6414
+ message: this.#i18n.t("notice.exportSaveFailed")
6415
+ });
6416
+ return;
6417
+ }
6418
+ this.#edits.set({ busy: "flow" });
6419
+ const preview = await this.#client.getFlowExportPreview(flowId);
6285
6420
  if (this.#disposed || selected && !current()) return;
6286
- const url = URL.createObjectURL(new Blob([encodeWorkflowFile(file)], { type: "application/json;charset=utf-8" }));
6421
+ if (preview.workflows.length == 1 && preview.unavailableFlowIds.length == 0 && !flowResourceReferences(preview.workflows[0].file.content).calledFlowIds?.length) this.#downloadWorkflow(preview.workflows[0].file);
6422
+ else this.exportPreview.set(preview);
6423
+ } catch (error) {
6424
+ if (!this.#disposed) this.#setNotice(errorNotice(error, this.#i18n.t));
6425
+ } finally {
6426
+ this.#exporting = false;
6427
+ if (!this.#disposed) this.#edits.set({ busy: void 0 });
6428
+ }
6429
+ }
6430
+ closeExport() {
6431
+ this.exportPreview.set(void 0);
6432
+ }
6433
+ completeExport(includeDependencies) {
6434
+ const preview = this.exportPreview.value;
6435
+ if (preview == null || this.#disposed) return;
6436
+ try {
6437
+ this.#downloadWorkflow(includeDependencies ? workflowBundleFromPreview(preview) : preview.workflows.find((item) => item.flowId == preview.entryFlowId).file);
6438
+ this.closeExport();
6439
+ } catch (error) {
6440
+ this.#setNotice(errorNotice(error, this.#i18n.t));
6441
+ }
6442
+ }
6443
+ #downloadWorkflow(file) {
6444
+ const entry = file.kind == "open-flow-workflow-bundle" ? file.workflows.find((item) => item.flowId == file.entryFlowId).file : file;
6445
+ const text = file.kind == "open-flow-workflow-bundle" ? encodeWorkflowBundle(file) : encodeWorkflowFile(file);
6446
+ const url = URL.createObjectURL(new Blob([text], { type: "application/json;charset=utf-8" }));
6447
+ try {
6287
6448
  const link = document.createElement("a");
6288
6449
  link.href = url;
6289
- link.download = workflowFileName(file.name ?? "workflow");
6450
+ link.download = workflowFileName(entry.name ?? "workflow");
6290
6451
  link.click();
6291
- setTimeout(() => URL.revokeObjectURL(url), 0);
6292
- } catch (error) {
6293
- if (!this.#disposed) this.#setNotice(errorNotice(error, this.#i18n.t));
6294
6452
  } finally {
6295
- this.#edits.set({ busy: void 0 });
6453
+ setTimeout(() => URL.revokeObjectURL(url), 0);
6296
6454
  }
6297
6455
  }
6298
6456
  createFlow(name, create, tagIds, presentation) {
@@ -6301,6 +6459,9 @@ var WorkspaceStore = class {
6301
6459
  importFlow(file, name, key, importer, tagIds) {
6302
6460
  return this.#createFlow(() => this.#flows.import(file, name, key, importer, tagIds));
6303
6461
  }
6462
+ importFlowBundle(file, name, key, importer, tagIds) {
6463
+ return this.#createFlow(() => this.#flows.importBundle(file, name, key, importer, tagIds));
6464
+ }
6304
6465
  async #createFlow(create) {
6305
6466
  if (!await this.saveModuleEditor()) return;
6306
6467
  this.#edits.set({ busy: "flow" });
@@ -6818,7 +6979,7 @@ var WorkbenchStore = class {
6818
6979
  const model = this.$.designer.value;
6819
6980
  const title = this.workspace.$.flow.value?.name ?? this.workspace.$.flowId.value ?? "Workflow";
6820
6981
  try {
6821
- const { downloadFlowPng } = await import("./exportPng-BOPfjeEi.js");
6982
+ const { downloadFlowPng } = await import("./exportPng-Cjdb6COo.js");
6822
6983
  const result = await downloadFlowPng(model, title, language, options);
6823
6984
  if (!this.#disposed) this.#notice.set({
6824
6985
  kind: "success",
@@ -6884,6 +7045,11 @@ var WorkbenchStore = class {
6884
7045
  async importFlow(file, name, key, importer, tagIds) {
6885
7046
  return await this.#openNewFlow(await this.workspace.importFlow(file, name, key, importer, tagIds), "notice.flowImported");
6886
7047
  }
7048
+ async importFlowBundle(file, name, key, importer, tagIds) {
7049
+ const result = await this.workspace.importFlowBundle(file, name, key, importer, tagIds);
7050
+ if (result != null) this.tags.reload();
7051
+ return await this.#openNewFlow(result, "notice.flowImported");
7052
+ }
6887
7053
  async createFlow(name, create, tagIds) {
6888
7054
  return await this.#openNewFlow(await this.workspace.createFlow(name, create, tagIds, setCanvasLayout({}, this.#defaultDirection)));
6889
7055
  }
@@ -7078,7 +7244,7 @@ var WorkbenchStore = class {
7078
7244
  };
7079
7245
  //#endregion
7080
7246
  //#region src/workbench/browser/runtime/openFlowWorkbench.tsx
7081
- var FlowWorkspace = lazy(() => import("./flowWorkspace-CRlqc403.js"));
7247
+ var FlowWorkspace = lazy(() => import("./flowWorkspace-BlXx-yAn.js"));
7082
7248
  function OpenFlowSessionGate({ action, description, error, onSubmit, onTokenChange, pending = false, title, token, tokenLabel }) {
7083
7249
  const hasToken = token != null && tokenLabel != null && onTokenChange != null;
7084
7250
  const tokenValue = token ?? "";
@@ -7184,7 +7350,7 @@ function FlowNameBridge({ store, onChange }) {
7184
7350
  useEffect(() => () => onChange(void 0), [onChange]);
7185
7351
  return null;
7186
7352
  }
7187
- function Workbench({ importRef, catalogWidth, createFlow, importFlow, createFlowDisabled, createFlowField, connectionHref, hrefFor, flowId, initializing, language, navigation, onConfigureConnector, onManageConnectorAccess, onLanguageChange, store, theme }) {
7353
+ function Workbench({ importRef, catalogWidth, createFlow, importFlow, importFlowBundle, createFlowDisabled, createFlowField, connectionHref, hrefFor, flowId, initializing, language, navigation, onConfigureConnector, onManageConnectorAccess, onLanguageChange, store, theme }) {
7188
7354
  return /* @__PURE__ */ jsx("div", {
7189
7355
  className: "app-shell",
7190
7356
  children: flowId == null ? /* @__PURE__ */ jsx(FlowBrowser, {
@@ -7200,6 +7366,7 @@ function Workbench({ importRef, catalogWidth, createFlow, importFlow, createFlow
7200
7366
  language,
7201
7367
  onCreateFlow: (name, tagIds) => navigation.createFlow(name, createFlow, tagIds),
7202
7368
  onImportFlow: (file, name, key, tagIds) => navigation.importFlow(file, name, key, importFlow, tagIds),
7369
+ onImportFlowBundle: importFlow != null && importFlowBundle == null ? void 0 : (file, name, key, tagIds) => navigation.importFlowBundle(file, name, key, importFlowBundle, tagIds),
7203
7370
  onLanguageChange,
7204
7371
  onSelectFlow: (flow, view) => void navigation.selectFlow(flow, view),
7205
7372
  store
@@ -7220,7 +7387,7 @@ function Workbench({ importRef, catalogWidth, createFlow, importFlow, createFlow
7220
7387
  })
7221
7388
  });
7222
7389
  }
7223
- var Session = forwardRef(function Session({ catalogWidth, createFlow, importFlow, createFlowDisabled, createFlowField, connectionHref, host, hrefFor, language, location, onConfigureConnector, onManageConnectorAccess, onLanguageChange, onNavigate, onFlowNameChange, preferences, sessionKey, theme, variables = true }, ref) {
7390
+ var Session = forwardRef(function Session({ catalogWidth, createFlow, importFlow, importFlowBundle, createFlowDisabled, createFlowField, connectionHref, host, hrefFor, language, location, onConfigureConnector, onManageConnectorAccess, onLanguageChange, onNavigate, onFlowNameChange, preferences, sessionKey, theme, variables = true }, ref) {
7224
7391
  const importRef = useRef(null);
7225
7392
  useImperativeHandle(ref, () => ({ openImport: (input) => importRef.current?.openImport(input) ?? "unavailable" }), []);
7226
7393
  const navigate = useRef(onNavigate);
@@ -7290,6 +7457,7 @@ var Session = forwardRef(function Session({ catalogWidth, createFlow, importFlow
7290
7457
  catalogWidth,
7291
7458
  createFlow,
7292
7459
  importFlow,
7460
+ importFlowBundle,
7293
7461
  createFlowDisabled,
7294
7462
  createFlowField,
7295
7463
  connectionHref,