@oomol-lab/open-flow 0.1.0-beta.70 → 0.1.0-beta.72

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 (37) hide show
  1. package/dist/browser/{FlowCanvas-CqtUDPGj.js → FlowCanvas-Dtf8_cQp.js} +31 -31
  2. package/dist/browser/{createResourceDialog-BAHYW9yu.js → createResourceDialog-BWJkjiOO.js} +2 -2
  3. package/dist/browser/{dialog-DcGOzUP2.js → dialog-CUy_fwx9.js} +4586 -4586
  4. package/dist/browser/{exportSvg-Dv5Qgrq7.js → exportSvg-BOoy7-Db.js} +1 -1
  5. package/dist/browser/flow-authoring.js +9467 -9467
  6. package/dist/browser/flow-change.d.ts +2 -14
  7. package/dist/browser/flow-change.js +23 -21
  8. package/dist/browser/{flowChanges-CYyehKer.js → flowChanges-CgSnSqqP.js} +5731 -5627
  9. package/dist/browser/{flowWorkspace-qYUZPJHR.js → flowWorkspace-Bf7H-r0t.js} +4 -4
  10. package/dist/browser/preview.js +5241 -5135
  11. package/dist/browser/workbench.js +1576 -1461
  12. package/dist/browser/{workbenchSelect-D8_vP2p5.js → workbenchSelect-C3e4J93X.js} +1 -1
  13. package/dist/command/index.js +22 -22
  14. package/dist/common/connector-proxy.d.ts +4 -1
  15. package/dist/common/control-api-conformance.js +23 -21
  16. package/dist/common/control-api.js +3454 -3452
  17. package/dist/common/control-requests.js +2032 -2032
  18. package/dist/common/decision.js +29 -6403
  19. package/dist/common/event-source-definition.d.ts +45 -0
  20. package/dist/common/event-source.d.ts +200 -1
  21. package/dist/common/event-source.js +22 -1
  22. package/dist/common/flow-schema.d.ts +2 -1
  23. package/dist/common/flow-schemaKeywords.d.ts +15 -0
  24. package/dist/common/flow-semantics.js +9797 -9795
  25. package/dist/common/integration-trigger.js +53 -6517
  26. package/dist/common/mcp.js +3389 -3389
  27. package/dist/common/openapi.js +29 -6493
  28. package/dist/common/poll-trigger.js +29 -6517
  29. package/dist/common/provider-triggers.js +6 -65
  30. package/dist/common/scheduler-checkpoint.d.ts +42 -0
  31. package/dist/common/scheduler-dependencies.d.ts +80 -0
  32. package/dist/common/scheduler-node-execution.d.ts +75 -0
  33. package/dist/common/scheduler.d.ts +5 -58
  34. package/dist/common/scheduler.js +575 -471
  35. package/dist/common/webhook-trigger.js +5 -6449
  36. package/dist/common/workflow.js +31 -916
  37. package/package.json +1 -1
@@ -2,8 +2,8 @@ import { C as DropdownMenuContent, N as DropdownMenuTrigger, T as DropdownMenuIt
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 { br as cn, i as TooltipTrigger, n as TooltipContent, t as Tooltip, vr as Button } from "./tooltip-wZJRB9oP.js";
5
- import { A as upgradeManualTrigger, It as Input, R as mapConditionSources, S as applyFlowChanges, a as DialogFooter, d as Field, gt as dequal$1, h as FieldLabel, i as DialogDescription, j as upgradeRevisionContent, k as resourceNameIssue, l as Icon, m as FieldGroup, o as DialogHeader, p as FieldError, r as DialogContent, s as DialogTitle, t as Dialog, u as Spinner, w as isTriggerNode, x as FlowChangeError, z as nodeInputMappings } from "./dialog-DcGOzUP2.js";
6
- import { $ as designerGraph, $t as errorNotice, An as workflowCandidate, At as setInputSources, Bt as Empty, C as updateWebhook, Ct as setFlowViewport, Dt as resetInputValues, Et as repairNodeNames, Fn as jsonValue, Ft as IdTooltip, G as combineSources, Gt as EmptyTitle, H as addNodeIntent, Ht as EmptyDescription, In as record, It as followWorkbenchLink, J as CacheResource, Kt as Badge, Ln as string, Lt as InputGroup, Mt as updateStartInputDefs, Nt as updateTriggerSchedule, Ot as setCodeActions, Pn as invalidResponse, Pt as WorkflowExportMenuItem, Q as connectorActionPorts, Rn as ApiError, Rt as InputGroupAddon, S as updateValue, St as setComment, Tt as setNodePositions, U as deriveAddNodeOptions, Ut as EmptyHeader, Vt as EmptyContent, Wt as EmptyMedia, X as resourceData, Xt as createI18n, Z as resourceValue, _ as updateResolution, _n as parseWorkflowFile, _t as canvasPresentationChange, a as nameCreatedNodes, b as updateTaskPorts, bt as removeComments, c as setInputVariable, ct as flowResourceReferences, d as updateCondition, dn as sampleErrorOutputs, dt as diagnosticItems, en as WorkbenchClient, f as updateNodeDescription, fn as triggerOutputDefinitions, g as updateOutputPorts, gn as encodeWorkflowFile, gt as connectionCatalog, h as updateNodeSettings, hn as connectorActionMetadata, ht as actionWithConnections, i as deleteSelection, in as decodeTriggerCatalog, it as RunStore, jt as setServiceConnections, kt as setConnectorConnection, l as setTriggerConnection, lt as Latest, m as updateNodeName, mn as connection, nn as allConnectorConnectionsQuery, o as selectWebhookResponse, p as updateNodeIcon, q as scopedValue, qt as EventSourcesPage, r as applyFlowChanges$1, rt as providerIcon, s as setInputValue, st as revisionView, t as addNode, tn as randomId, u as setTriggerEventSource, un as normalizeTriggerOutputs, ut as deriveInspectorDiagnostics, v as updateTask, vn as workflowFileName, vt as commentIds, wt as setNodeContentHidden, x as updateTriggerConfig, xt as restoreCanvasPresentation, y as updateTaskAdditionalInputs, yn as workflowNameFromFile, yt as flowPresentation, zn as controlErrorCode, zt as InputGroupInput } from "./flowChanges-CYyehKer.js";
5
+ import { C as resourceNameIssue, It as Input, M as mapConditionSources, N as nodeInputMappings, T as upgradeRevisionContent, _ as applyFlowChanges, a as DialogFooter, d as Field, g as FlowChangeError, gt as dequal$1, h as FieldLabel, i as DialogDescription, 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 upgradeManualTrigger } from "./dialog-CUy_fwx9.js";
6
+ import { $ as designerGraph, $t as errorNotice, At as setInputSources, Bt as Empty, C as updateWebhook, Ct as setFlowViewport, Dt as resetInputValues, Et as repairNodeNames, Fn as jsonValue, Ft as IdTooltip, G as combineSources, Gt as EmptyTitle, H as addNodeIntent, Ht as EmptyDescription, In as record, It as followWorkbenchLink, J as CacheResource, Kt as Badge, Ln as string, Lt as InputGroup, Mt as updateStartInputDefs, Nt as updateTriggerSchedule, Ot as setCodeActions, Pn as invalidResponse, Pt as WorkflowExportMenuItem, Q as connectorActionPorts, Rn as ApiError, Rt as InputGroupAddon, S as updateValue, St as setComment, Tt as setNodePositions, U as deriveAddNodeOptions, Ut as EmptyHeader, Vt as EmptyContent, Wt as EmptyMedia, X as resourceData, Xt as createI18n, Z as resourceValue, _ as updateResolution, _n as parseWorkflowFile, _t as canvasPresentationChange, a as nameCreatedNodes, b as updateTaskPorts, bt as removeComments, c as setInputVariable, ct as flowResourceReferences, d as updateCondition, dn as sampleErrorOutputs, dt as diagnosticItems, en as WorkbenchClient, f as updateNodeDescription, fn as triggerOutputDefinitions, g as updateOutputPorts, gn as encodeWorkflowFile, gt as connectionCatalog, h as updateNodeSettings, hn as connectorActionMetadata, ht as actionWithConnections, i as deleteSelection, in as decodeTriggerCatalog, it as RunStore, jn as workflowCandidate, jt as setServiceConnections, kt as setConnectorConnection, l as setTriggerConnection, lt as Latest, m as updateNodeName, mn as connection, nn as allConnectorConnectionsQuery, o as selectWebhookResponse, p as updateNodeIcon, q as scopedValue, qt as EventSourcesPage, r as applyFlowChanges$1, rt as providerIcon, s as setInputValue, st as revisionView, t as addNode, tn as randomId, u as setTriggerEventSource, un as normalizeTriggerOutputs, ut as deriveInspectorDiagnostics, v as updateTask, vn as workflowFileName, vt as commentIds, wt as setNodeContentHidden, x as updateTriggerConfig, xt as restoreCanvasPresentation, y as updateTaskAdditionalInputs, yn as workflowNameFromFile, yt as flowPresentation, zn as controlErrorCode, zt as InputGroupInput } from "./flowChanges-CgSnSqqP.js";
7
7
  import { a as uiLanguages, i as uiLanguageNames, n as isUiLanguage, r as resolveUiLanguage, t as importedWorkflowName } from "./languages-gYzoQqCi.js";
8
8
  import { Suspense, forwardRef, lazy, useEffect, useImperativeHandle, useLayoutEffect, useRef, useState } from "react";
9
9
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
@@ -516,7 +516,7 @@ function FlowDeletionDialog({ flow, workspace, container, busy, finalFocus, onCl
516
516
  }
517
517
  //#endregion
518
518
  //#region src/workbench/browser/runtime/shell/resourceBrowser.tsx
519
- var CreateResourceDialog = lazy(() => import("./createResourceDialog-BAHYW9yu.js"));
519
+ var CreateResourceDialog = lazy(() => import("./createResourceDialog-BWJkjiOO.js"));
520
520
  var flowIdTooltipAlignOffset = 44;
521
521
  var renamePopoverAlignOffset = -12;
522
522
  function compactFlowId(flowId) {
@@ -4351,6 +4351,244 @@ var TriggerStore = class {
4351
4351
  }
4352
4352
  };
4353
4353
  //#endregion
4354
+ //#region src/workbench/browser/runtime/editor/nodeClipboard.ts
4355
+ function copyNodes(revision, nodeIds) {
4356
+ const nodes = revision.graph()?.nodes ?? {};
4357
+ const copied = Object.fromEntries(nodeIds.flatMap((nodeId) => nodes[nodeId] == null ? [] : [[nodeId, nodes[nodeId]]]));
4358
+ return {
4359
+ edges: (revision.graph()?.edges ?? []).filter((edge) => copied[edge.source] != null && copied[edge.target] != null),
4360
+ bindings: Object.fromEntries(Object.values(copied).flatMap((node) => {
4361
+ if (!("inputs" in node) && node.kind != "outputs") return [];
4362
+ return Object.values(nodeInputMappings(node)).flatMap((mapping) => mapping.kind == "sources" ? mapping.sources.flatMap((source) => {
4363
+ if (source.kind != "binding") return [];
4364
+ const binding = revision.binding(source.bindingId);
4365
+ return binding?.kind == "variable" ? [[source.bindingId, binding]] : [];
4366
+ }) : []);
4367
+ })),
4368
+ modules: Object.fromEntries(Object.values(copied).flatMap((node) => {
4369
+ if (node.kind != "task" || !("moduleId" in node.task)) return [];
4370
+ const module = revision.revision.content.modules[node.task.moduleId];
4371
+ return module == null ? [] : [[node.task.moduleId, module]];
4372
+ })),
4373
+ nodes: copied
4374
+ };
4375
+ }
4376
+ function pasteNodes(revision, clipboard, identity) {
4377
+ const hasOutputs = Object.values(revision.graph().nodes).some((node) => node.kind == "outputs");
4378
+ const hasErrorTrigger = Object.values(revision.graph()?.nodes ?? {}).some((node) => node.kind === "error");
4379
+ const hasStartTrigger = Object.values(revision.graph()?.nodes ?? {}).some((node) => node.kind === "manual" || node.kind === "start");
4380
+ const entries = Object.entries(clipboard.nodes).filter(([, node]) => (node.kind !== "manual" && node.kind !== "start" || !hasStartTrigger) && (node.kind !== "outputs" || !hasOutputs) && (node.kind !== "error" || !hasErrorTrigger) && (node.kind != "task" || !("moduleId" in node.task) || clipboard.modules[node.task.moduleId] != null));
4381
+ const sourceIds = entries.map(([sourceId]) => sourceId);
4382
+ const ids = new Map(sourceIds.map((sourceId) => [sourceId, identity()]));
4383
+ const operations = [];
4384
+ const bindingIds = /* @__PURE__ */ new Map();
4385
+ for (const [, node] of entries) {
4386
+ if (!("inputs" in node) && node.kind != "outputs") continue;
4387
+ const inputs = Object.values(nodeInputMappings(node));
4388
+ for (const mapping of inputs) {
4389
+ if (mapping.kind != "sources") continue;
4390
+ for (const source of mapping.sources) {
4391
+ if (source.kind != "binding" || clipboard.bindings[source.bindingId]?.kind != "variable" || bindingIds.has(source.bindingId)) continue;
4392
+ bindingIds.set(source.bindingId, identity());
4393
+ }
4394
+ }
4395
+ }
4396
+ for (const [sourceId, bindingId] of bindingIds) {
4397
+ const binding = clipboard.bindings[sourceId];
4398
+ if (binding != null) operations.push({
4399
+ binding,
4400
+ bindingId,
4401
+ kind: "binding.create"
4402
+ });
4403
+ }
4404
+ for (const [sourceId, node] of entries) {
4405
+ const nodeId = ids.get(sourceId);
4406
+ if (!("inputs" in node) && node.kind != "outputs") {
4407
+ const response = node.kind === "webhook" ? node.options?.responseBody : void 0;
4408
+ const copy = node.kind === "webhook" && response?.kind === "webhook-response" && response.nodeId != null ? {
4409
+ ...node,
4410
+ options: {
4411
+ ...node.options,
4412
+ responseBody: {
4413
+ ...response,
4414
+ nodeId: ids.get(response.nodeId) ?? response.nodeId
4415
+ }
4416
+ }
4417
+ } : node;
4418
+ operations.push({
4419
+ kind: "graph.node.create",
4420
+ node: copy,
4421
+ nodeId
4422
+ });
4423
+ continue;
4424
+ }
4425
+ const remapInputs = (sourceInputs) => {
4426
+ const inputs = {};
4427
+ for (const [handle, mapping] of Object.entries(sourceInputs)) {
4428
+ if (mapping.kind != "sources") {
4429
+ inputs[handle] = mapping;
4430
+ continue;
4431
+ }
4432
+ const sources = [];
4433
+ for (const source of mapping.sources) {
4434
+ if (source.kind == "binding") {
4435
+ const copiedBindingId = bindingIds.get(source.bindingId);
4436
+ if (copiedBindingId != null) sources.push({
4437
+ ...source,
4438
+ bindingId: copiedBindingId
4439
+ });
4440
+ continue;
4441
+ }
4442
+ if (source.kind != "node") {
4443
+ sources.push(source);
4444
+ continue;
4445
+ }
4446
+ const copiedNodeId = ids.get(source.nodeId);
4447
+ if (copiedNodeId != null) sources.push({
4448
+ ...source,
4449
+ nodeId: copiedNodeId
4450
+ });
4451
+ }
4452
+ if (sources.length > 0) inputs[handle] = {
4453
+ kind: "sources",
4454
+ sources
4455
+ };
4456
+ }
4457
+ return inputs;
4458
+ };
4459
+ const inputs = remapInputs(nodeInputMappings(node));
4460
+ let copy = node.kind == "outputs" ? {
4461
+ ...node,
4462
+ outputMappings: inputs
4463
+ } : {
4464
+ ...node,
4465
+ inputs
4466
+ };
4467
+ if (node.kind == "condition") copy = mapConditionSources(node, (source) => source.kind == "node" ? {
4468
+ ...source,
4469
+ nodeId: ids.get(source.nodeId) ?? source.nodeId
4470
+ } : source.kind == "binding" ? {
4471
+ ...source,
4472
+ bindingId: bindingIds.get(source.bindingId) ?? source.bindingId
4473
+ } : source);
4474
+ if (node.kind == "task" && "moduleId" in node.task) {
4475
+ const moduleId = nodeId;
4476
+ const module = clipboard.modules[node.task.moduleId];
4477
+ operations.push({
4478
+ kind: "module.create",
4479
+ module: {
4480
+ ...module,
4481
+ name: `${module.name} copy`
4482
+ },
4483
+ moduleId
4484
+ });
4485
+ copy = {
4486
+ ...node,
4487
+ inputs,
4488
+ ...node.name == null ? {} : { name: node.name },
4489
+ task: {
4490
+ ...node.task,
4491
+ moduleId,
4492
+ name: `${node.task.name} copy`
4493
+ }
4494
+ };
4495
+ }
4496
+ operations.push({
4497
+ kind: "graph.node.create",
4498
+ node: copy,
4499
+ nodeId
4500
+ });
4501
+ }
4502
+ for (const edge of clipboard.edges) {
4503
+ const source = ids.get(edge.source);
4504
+ const destination = ids.get(edge.target);
4505
+ if (source != null && destination != null) operations.push({
4506
+ kind: "graph.edge.connect",
4507
+ edge: {
4508
+ ...edge,
4509
+ source,
4510
+ target: destination
4511
+ }
4512
+ });
4513
+ }
4514
+ return {
4515
+ changes: nameCreatedNodes(revision, operations),
4516
+ nodeIds: [...ids.values()],
4517
+ sourceIds
4518
+ };
4519
+ }
4520
+ //#endregion
4521
+ //#region src/workbench/browser/runtime/editor/canvasClipboard.ts
4522
+ var CanvasClipboard = class {
4523
+ #value;
4524
+ constructor(identity, t) {
4525
+ this.identity = identity;
4526
+ this.t = t;
4527
+ }
4528
+ copy(revision, graph, nodeIds) {
4529
+ const selected = new Set(nodeIds);
4530
+ this.#value = {
4531
+ hiddenNodeIds: graph.nodes.flatMap((node) => node.contentHidden && selected.has(node.id) ? [node.id] : []),
4532
+ comments: graph.nodes.flatMap((node) => node.kind == "comment" && selected.has(node.id) ? [{
4533
+ content: node.content,
4534
+ position: node.position,
4535
+ sourceId: node.id,
4536
+ title: node.title
4537
+ }] : []),
4538
+ nodes: copyNodes(revision, nodeIds)
4539
+ };
4540
+ }
4541
+ paste(revision, graph, sourcePositions, offset = {
4542
+ x: 40,
4543
+ y: 40
4544
+ }) {
4545
+ if (this.#value == null) return;
4546
+ const hiddenNodeIds = new Set(this.#value.hiddenNodeIds);
4547
+ const pasted = pasteNodes(revision, this.#value.nodes, this.identity);
4548
+ const comments = this.#value.comments.map((comment) => ({
4549
+ ...comment,
4550
+ nodeId: this.identity()
4551
+ }));
4552
+ if (pasted.nodeIds.length == 0 && comments.length == 0) return;
4553
+ const designerNodes = new Map(graph.nodes.map((node) => [node.id, node]));
4554
+ const added = /* @__PURE__ */ new Set([...pasted.nodeIds, ...comments.map((comment) => comment.nodeId)]);
4555
+ const occupied = new Set([...designerNodes].filter(([nodeId]) => !added.has(nodeId)).map(([, node]) => `${node.position.x}\0${node.position.y}`));
4556
+ const sources = [...pasted.sourceIds.map((sourceId) => sourcePositions?.[sourceId] ?? designerNodes.get(sourceId)?.position ?? {
4557
+ x: 80,
4558
+ y: 80
4559
+ }), ...comments.map((comment) => comment.position)];
4560
+ let step = 1;
4561
+ if (offset.x != 0 || offset.y != 0) while (sources.some((source) => occupied.has(`${source.x + offset.x * step}\0${source.y + offset.y * step}`))) step += 1;
4562
+ const positions = Object.fromEntries(pasted.sourceIds.map((sourceId, index) => {
4563
+ const source = sourcePositions?.[sourceId] ?? designerNodes.get(sourceId)?.position;
4564
+ return [pasted.nodeIds[index], {
4565
+ x: (source?.x ?? 80) + offset.x * step,
4566
+ y: (source?.y ?? 80) + offset.y * step
4567
+ }];
4568
+ }));
4569
+ return {
4570
+ changes: pasted.changes,
4571
+ nodeIds: [...pasted.nodeIds, ...comments.map((comment) => comment.nodeId)],
4572
+ update: (value) => {
4573
+ let next = setNodePositions(value, positions);
4574
+ for (const [index, sourceId] of pasted.sourceIds.entries()) if (hiddenNodeIds.has(sourceId)) next = setNodeContentHidden(next, pasted.nodeIds[index], true);
4575
+ for (const comment of comments) {
4576
+ if (hiddenNodeIds.has(comment.sourceId)) next = setNodeContentHidden(next, comment.nodeId, true);
4577
+ next = setComment(next, comment.nodeId, {
4578
+ content: comment.content,
4579
+ position: {
4580
+ x: comment.position.x + offset.x * step,
4581
+ y: comment.position.y + offset.y * step
4582
+ },
4583
+ title: this.t("addNode.commentCopy", { title: comment.title })
4584
+ });
4585
+ }
4586
+ return next;
4587
+ }
4588
+ };
4589
+ }
4590
+ };
4591
+ //#endregion
4354
4592
  //#region src/flow/common/inverseChanges.ts
4355
4593
  /** Invert authoring operations and cascading deletions while retaining model upgrades. */
4356
4594
  function inverseFlowChanges(content, operations) {
@@ -4600,244 +4838,6 @@ function inverseFlowChanges(content, operations) {
4600
4838
  return groups.toReversed().flat();
4601
4839
  }
4602
4840
  //#endregion
4603
- //#region src/workbench/browser/runtime/editor/nodeClipboard.ts
4604
- function copyNodes(revision, nodeIds) {
4605
- const nodes = revision.graph()?.nodes ?? {};
4606
- const copied = Object.fromEntries(nodeIds.flatMap((nodeId) => nodes[nodeId] == null ? [] : [[nodeId, nodes[nodeId]]]));
4607
- return {
4608
- edges: (revision.graph()?.edges ?? []).filter((edge) => copied[edge.source] != null && copied[edge.target] != null),
4609
- bindings: Object.fromEntries(Object.values(copied).flatMap((node) => {
4610
- if (!("inputs" in node) && node.kind != "outputs") return [];
4611
- return Object.values(nodeInputMappings(node)).flatMap((mapping) => mapping.kind == "sources" ? mapping.sources.flatMap((source) => {
4612
- if (source.kind != "binding") return [];
4613
- const binding = revision.binding(source.bindingId);
4614
- return binding?.kind == "variable" ? [[source.bindingId, binding]] : [];
4615
- }) : []);
4616
- })),
4617
- modules: Object.fromEntries(Object.values(copied).flatMap((node) => {
4618
- if (node.kind != "task" || !("moduleId" in node.task)) return [];
4619
- const module = revision.revision.content.modules[node.task.moduleId];
4620
- return module == null ? [] : [[node.task.moduleId, module]];
4621
- })),
4622
- nodes: copied
4623
- };
4624
- }
4625
- function pasteNodes(revision, clipboard, identity) {
4626
- const hasOutputs = Object.values(revision.graph().nodes).some((node) => node.kind == "outputs");
4627
- const hasErrorTrigger = Object.values(revision.graph()?.nodes ?? {}).some((node) => node.kind === "error");
4628
- const hasStartTrigger = Object.values(revision.graph()?.nodes ?? {}).some((node) => node.kind === "manual" || node.kind === "start");
4629
- const entries = Object.entries(clipboard.nodes).filter(([, node]) => (node.kind !== "manual" && node.kind !== "start" || !hasStartTrigger) && (node.kind !== "outputs" || !hasOutputs) && (node.kind !== "error" || !hasErrorTrigger) && (node.kind != "task" || !("moduleId" in node.task) || clipboard.modules[node.task.moduleId] != null));
4630
- const sourceIds = entries.map(([sourceId]) => sourceId);
4631
- const ids = new Map(sourceIds.map((sourceId) => [sourceId, identity()]));
4632
- const operations = [];
4633
- const bindingIds = /* @__PURE__ */ new Map();
4634
- for (const [, node] of entries) {
4635
- if (!("inputs" in node) && node.kind != "outputs") continue;
4636
- const inputs = Object.values(nodeInputMappings(node));
4637
- for (const mapping of inputs) {
4638
- if (mapping.kind != "sources") continue;
4639
- for (const source of mapping.sources) {
4640
- if (source.kind != "binding" || clipboard.bindings[source.bindingId]?.kind != "variable" || bindingIds.has(source.bindingId)) continue;
4641
- bindingIds.set(source.bindingId, identity());
4642
- }
4643
- }
4644
- }
4645
- for (const [sourceId, bindingId] of bindingIds) {
4646
- const binding = clipboard.bindings[sourceId];
4647
- if (binding != null) operations.push({
4648
- binding,
4649
- bindingId,
4650
- kind: "binding.create"
4651
- });
4652
- }
4653
- for (const [sourceId, node] of entries) {
4654
- const nodeId = ids.get(sourceId);
4655
- if (!("inputs" in node) && node.kind != "outputs") {
4656
- const response = node.kind === "webhook" ? node.options?.responseBody : void 0;
4657
- const copy = node.kind === "webhook" && response?.kind === "webhook-response" && response.nodeId != null ? {
4658
- ...node,
4659
- options: {
4660
- ...node.options,
4661
- responseBody: {
4662
- ...response,
4663
- nodeId: ids.get(response.nodeId) ?? response.nodeId
4664
- }
4665
- }
4666
- } : node;
4667
- operations.push({
4668
- kind: "graph.node.create",
4669
- node: copy,
4670
- nodeId
4671
- });
4672
- continue;
4673
- }
4674
- const remapInputs = (sourceInputs) => {
4675
- const inputs = {};
4676
- for (const [handle, mapping] of Object.entries(sourceInputs)) {
4677
- if (mapping.kind != "sources") {
4678
- inputs[handle] = mapping;
4679
- continue;
4680
- }
4681
- const sources = [];
4682
- for (const source of mapping.sources) {
4683
- if (source.kind == "binding") {
4684
- const copiedBindingId = bindingIds.get(source.bindingId);
4685
- if (copiedBindingId != null) sources.push({
4686
- ...source,
4687
- bindingId: copiedBindingId
4688
- });
4689
- continue;
4690
- }
4691
- if (source.kind != "node") {
4692
- sources.push(source);
4693
- continue;
4694
- }
4695
- const copiedNodeId = ids.get(source.nodeId);
4696
- if (copiedNodeId != null) sources.push({
4697
- ...source,
4698
- nodeId: copiedNodeId
4699
- });
4700
- }
4701
- if (sources.length > 0) inputs[handle] = {
4702
- kind: "sources",
4703
- sources
4704
- };
4705
- }
4706
- return inputs;
4707
- };
4708
- const inputs = remapInputs(nodeInputMappings(node));
4709
- let copy = node.kind == "outputs" ? {
4710
- ...node,
4711
- outputMappings: inputs
4712
- } : {
4713
- ...node,
4714
- inputs
4715
- };
4716
- if (node.kind == "condition") copy = mapConditionSources(node, (source) => source.kind == "node" ? {
4717
- ...source,
4718
- nodeId: ids.get(source.nodeId) ?? source.nodeId
4719
- } : source.kind == "binding" ? {
4720
- ...source,
4721
- bindingId: bindingIds.get(source.bindingId) ?? source.bindingId
4722
- } : source);
4723
- if (node.kind == "task" && "moduleId" in node.task) {
4724
- const moduleId = nodeId;
4725
- const module = clipboard.modules[node.task.moduleId];
4726
- operations.push({
4727
- kind: "module.create",
4728
- module: {
4729
- ...module,
4730
- name: `${module.name} copy`
4731
- },
4732
- moduleId
4733
- });
4734
- copy = {
4735
- ...node,
4736
- inputs,
4737
- ...node.name == null ? {} : { name: node.name },
4738
- task: {
4739
- ...node.task,
4740
- moduleId,
4741
- name: `${node.task.name} copy`
4742
- }
4743
- };
4744
- }
4745
- operations.push({
4746
- kind: "graph.node.create",
4747
- node: copy,
4748
- nodeId
4749
- });
4750
- }
4751
- for (const edge of clipboard.edges) {
4752
- const source = ids.get(edge.source);
4753
- const destination = ids.get(edge.target);
4754
- if (source != null && destination != null) operations.push({
4755
- kind: "graph.edge.connect",
4756
- edge: {
4757
- ...edge,
4758
- source,
4759
- target: destination
4760
- }
4761
- });
4762
- }
4763
- return {
4764
- changes: nameCreatedNodes(revision, operations),
4765
- nodeIds: [...ids.values()],
4766
- sourceIds
4767
- };
4768
- }
4769
- //#endregion
4770
- //#region src/workbench/browser/runtime/editor/canvasClipboard.ts
4771
- var CanvasClipboard = class {
4772
- #value;
4773
- constructor(identity, t) {
4774
- this.identity = identity;
4775
- this.t = t;
4776
- }
4777
- copy(revision, graph, nodeIds) {
4778
- const selected = new Set(nodeIds);
4779
- this.#value = {
4780
- hiddenNodeIds: graph.nodes.flatMap((node) => node.contentHidden && selected.has(node.id) ? [node.id] : []),
4781
- comments: graph.nodes.flatMap((node) => node.kind == "comment" && selected.has(node.id) ? [{
4782
- content: node.content,
4783
- position: node.position,
4784
- sourceId: node.id,
4785
- title: node.title
4786
- }] : []),
4787
- nodes: copyNodes(revision, nodeIds)
4788
- };
4789
- }
4790
- paste(revision, graph, sourcePositions, offset = {
4791
- x: 40,
4792
- y: 40
4793
- }) {
4794
- if (this.#value == null) return;
4795
- const hiddenNodeIds = new Set(this.#value.hiddenNodeIds);
4796
- const pasted = pasteNodes(revision, this.#value.nodes, this.identity);
4797
- const comments = this.#value.comments.map((comment) => ({
4798
- ...comment,
4799
- nodeId: this.identity()
4800
- }));
4801
- if (pasted.nodeIds.length == 0 && comments.length == 0) return;
4802
- const designerNodes = new Map(graph.nodes.map((node) => [node.id, node]));
4803
- const added = /* @__PURE__ */ new Set([...pasted.nodeIds, ...comments.map((comment) => comment.nodeId)]);
4804
- const occupied = new Set([...designerNodes].filter(([nodeId]) => !added.has(nodeId)).map(([, node]) => `${node.position.x}\0${node.position.y}`));
4805
- const sources = [...pasted.sourceIds.map((sourceId) => sourcePositions?.[sourceId] ?? designerNodes.get(sourceId)?.position ?? {
4806
- x: 80,
4807
- y: 80
4808
- }), ...comments.map((comment) => comment.position)];
4809
- let step = 1;
4810
- if (offset.x != 0 || offset.y != 0) while (sources.some((source) => occupied.has(`${source.x + offset.x * step}\0${source.y + offset.y * step}`))) step += 1;
4811
- const positions = Object.fromEntries(pasted.sourceIds.map((sourceId, index) => {
4812
- const source = sourcePositions?.[sourceId] ?? designerNodes.get(sourceId)?.position;
4813
- return [pasted.nodeIds[index], {
4814
- x: (source?.x ?? 80) + offset.x * step,
4815
- y: (source?.y ?? 80) + offset.y * step
4816
- }];
4817
- }));
4818
- return {
4819
- changes: pasted.changes,
4820
- nodeIds: [...pasted.nodeIds, ...comments.map((comment) => comment.nodeId)],
4821
- update: (value) => {
4822
- let next = setNodePositions(value, positions);
4823
- for (const [index, sourceId] of pasted.sourceIds.entries()) if (hiddenNodeIds.has(sourceId)) next = setNodeContentHidden(next, pasted.nodeIds[index], true);
4824
- for (const comment of comments) {
4825
- if (hiddenNodeIds.has(comment.sourceId)) next = setNodeContentHidden(next, comment.nodeId, true);
4826
- next = setComment(next, comment.nodeId, {
4827
- content: comment.content,
4828
- position: {
4829
- x: comment.position.x + offset.x * step,
4830
- y: comment.position.y + offset.y * step
4831
- },
4832
- title: this.t("addNode.commentCopy", { title: comment.title })
4833
- });
4834
- }
4835
- return next;
4836
- }
4837
- };
4838
- }
4839
- };
4840
- //#endregion
4841
4841
  //#region src/workbench/browser/runtime/stores/canvasHistory.ts
4842
4842
  var CanvasHistory = class {
4843
4843
  constructor() {
@@ -4851,35 +4851,82 @@ var CanvasHistory = class {
4851
4851
  });
4852
4852
  this.#undo = [];
4853
4853
  this.#redo = [];
4854
- this.generation = 0;
4855
- this.pending = 0;
4856
- this.applying = false;
4857
- this.failed = false;
4854
+ this.#generation = 0;
4855
+ this.#pending = 0;
4856
+ this.#applying = false;
4857
+ this.#failed = false;
4858
+ this.#disposed = false;
4858
4859
  }
4859
4860
  #undo;
4860
4861
  #redo;
4862
+ #generation;
4863
+ #pending;
4864
+ #applying;
4865
+ #failed;
4866
+ #disposed;
4867
+ get generation() {
4868
+ return this.#generation;
4869
+ }
4870
+ get applying() {
4871
+ return this.#applying;
4872
+ }
4873
+ get failed() {
4874
+ return this.#failed;
4875
+ }
4876
+ beginChange() {
4877
+ this.#pending++;
4878
+ this.#publish();
4879
+ }
4880
+ endChange() {
4881
+ this.#pending--;
4882
+ this.#publish();
4883
+ }
4884
+ beginRestore() {
4885
+ this.#applying = true;
4886
+ this.#publish();
4887
+ }
4888
+ endRestore() {
4889
+ this.#applying = false;
4890
+ this.#publish();
4891
+ }
4892
+ beginRecovery() {
4893
+ this.#failed = true;
4894
+ this.clear();
4895
+ }
4896
+ endRecovery() {
4897
+ this.#failed = false;
4898
+ this.#publish();
4899
+ }
4900
+ reset() {
4901
+ this.#failed = false;
4902
+ this.clear();
4903
+ }
4904
+ dispose() {
4905
+ this.#disposed = true;
4906
+ this.state$.dispose();
4907
+ }
4861
4908
  clear() {
4862
4909
  const hadHistory = this.#undo.length + this.#redo.length > 0;
4863
- this.generation++;
4910
+ this.#generation++;
4864
4911
  this.#undo.length = 0;
4865
4912
  this.#redo.length = 0;
4866
- this.publish();
4913
+ this.#publish();
4867
4914
  return hadHistory;
4868
4915
  }
4869
4916
  discardRedo() {
4870
4917
  if (this.#redo.length == 0) return;
4871
4918
  this.#redo.length = 0;
4872
- this.publish();
4919
+ this.#publish();
4873
4920
  }
4874
4921
  completeNodeCreation(nodeId, changes) {
4875
4922
  const index = this.#undo.findIndex((entry) => entry.forward.some((operation) => operation.kind == "graph.node.create" && operation.nodeId == nodeId));
4876
- if (index < 0 || this.applying || this.failed) return false;
4923
+ if (index < 0 || this.#applying || this.#failed) return false;
4877
4924
  const entry = this.#undo[index];
4878
4925
  this.#undo[index] = {
4879
4926
  ...entry,
4880
4927
  forward: [...entry.forward, ...changes]
4881
4928
  };
4882
- this.publish();
4929
+ this.#publish();
4883
4930
  return true;
4884
4931
  }
4885
4932
  rebaseModuleCreation(moduleId, module) {
@@ -4903,7 +4950,7 @@ var CanvasHistory = class {
4903
4950
  };
4904
4951
  }
4905
4952
  while (this.#undo.length > 0 && this.#bytes(this.#undo) > 10485760) this.#undo.shift();
4906
- this.publish();
4953
+ this.#publish();
4907
4954
  }
4908
4955
  record(entry) {
4909
4956
  this.#redo.length = 0;
@@ -4913,7 +4960,7 @@ var CanvasHistory = class {
4913
4960
  return false;
4914
4961
  }
4915
4962
  while (this.#undo.length > 30 || this.#bytes(this.#undo) > 10485760) this.#undo.shift();
4916
- this.publish();
4963
+ this.#publish();
4917
4964
  return true;
4918
4965
  }
4919
4966
  complete(redo) {
@@ -4921,15 +4968,16 @@ var CanvasHistory = class {
4921
4968
  const destination = redo ? this.#undo : this.#redo;
4922
4969
  const entry = source.pop();
4923
4970
  if (entry != null) destination.push(entry);
4924
- this.publish();
4971
+ this.#publish();
4925
4972
  }
4926
- publish() {
4927
- const available = this.pending == 0 && !this.applying && !this.failed;
4973
+ #publish() {
4974
+ if (this.#disposed) return;
4975
+ const available = this.#pending == 0 && !this.#applying && !this.#failed;
4928
4976
  this.state$.set({
4929
4977
  canUndo: available && this.#undo.length > 0,
4930
4978
  canRedo: available && this.#redo.length > 0,
4931
- applying: this.applying,
4932
- failed: this.failed,
4979
+ applying: this.#applying,
4980
+ failed: this.#failed,
4933
4981
  undo: this.#undo.at(-1),
4934
4982
  redo: this.#redo.at(-1)
4935
4983
  });
@@ -5118,270 +5166,6 @@ var DraftChanges = class {
5118
5166
  }
5119
5167
  };
5120
5168
  //#endregion
5121
- //#region src/workbench/browser/runtime/stores/flowCatalog.ts
5122
- var pageLimit = 50;
5123
- var initialState$1 = {
5124
- failed: false,
5125
- loaded: false,
5126
- loading: true,
5127
- loadingMore: false,
5128
- loadMoreFailed: false,
5129
- refreshing: false,
5130
- flows: []
5131
- };
5132
- var FlowCatalog = class {
5133
- #client;
5134
- #i18n;
5135
- #session = new Latest();
5136
- #setNotice;
5137
- #state = val(initialState$1);
5138
- #lifetime = new AbortController();
5139
- #pending = /* @__PURE__ */ new Set();
5140
- #disposed = false;
5141
- constructor(client, setNotice, i18n) {
5142
- this.#client = client;
5143
- this.#i18n = i18n;
5144
- this.#setNotice = setNotice;
5145
- this.$ = {
5146
- failed: derive(this.#state, (state) => state.failed),
5147
- loading: derive(this.#state, (state) => state.loading),
5148
- loadingMore: derive(this.#state, (state) => state.loadingMore),
5149
- loadMoreFailed: derive(this.#state, (state) => state.loadMoreFailed),
5150
- refreshing: derive(this.#state, (state) => state.refreshing),
5151
- nextCursor: derive(this.#state, (state) => state.nextCursor),
5152
- flows: derive(this.#state, (state) => state.flows),
5153
- total: derive(this.#state, (state) => state.total)
5154
- };
5155
- }
5156
- get loaded() {
5157
- return this.#state.value.loaded;
5158
- }
5159
- dispose() {
5160
- this.#disposed = true;
5161
- this.#lifetime.abort();
5162
- this.#session.invalidate();
5163
- for (const value of Object.values(this.$)) value.dispose();
5164
- this.#state.dispose();
5165
- }
5166
- flow(flowId) {
5167
- return this.#state.value.flows.find((flow) => flow.flowId == flowId);
5168
- }
5169
- async reload() {
5170
- const current = this.#session.begin();
5171
- const loaded = this.#state.value.loaded;
5172
- if (loaded) this.#set({
5173
- failed: false,
5174
- loadingMore: false,
5175
- loadMoreFailed: false,
5176
- refreshing: true
5177
- });
5178
- else this.#set({
5179
- failed: false,
5180
- loading: true,
5181
- loadingMore: false,
5182
- loadMoreFailed: false,
5183
- refreshing: false,
5184
- nextCursor: void 0,
5185
- flows: [],
5186
- total: void 0
5187
- });
5188
- try {
5189
- const page = await this.#client.listFlows({
5190
- includeTotal: true,
5191
- limit: pageLimit
5192
- });
5193
- if (!current()) return;
5194
- this.#set({
5195
- loaded: true,
5196
- loading: false,
5197
- refreshing: false,
5198
- nextCursor: page.nextCursor,
5199
- flows: page.flows,
5200
- total: page.total
5201
- });
5202
- } catch (error) {
5203
- if (!current()) return;
5204
- this.#set({
5205
- failed: !loaded,
5206
- loading: false,
5207
- refreshing: false
5208
- });
5209
- this.#setNotice(errorNotice(error, this.#i18n.t));
5210
- }
5211
- }
5212
- async loadMore() {
5213
- const { loadingMore, nextCursor, refreshing } = this.#state.value;
5214
- if (loadingMore || refreshing || nextCursor == null) return;
5215
- const current = this.#session.capture();
5216
- this.#set({
5217
- loadingMore: true,
5218
- loadMoreFailed: false
5219
- });
5220
- try {
5221
- const page = await this.#client.listFlows({
5222
- cursor: nextCursor,
5223
- limit: pageLimit
5224
- });
5225
- if (!current()) return;
5226
- const flows = new Map(this.#state.value.flows.map((flow) => [flow.flowId, flow]));
5227
- for (const flow of page.flows) flows.set(flow.flowId, flow);
5228
- this.#set({
5229
- loadingMore: false,
5230
- nextCursor: page.nextCursor,
5231
- flows: [...flows.values()]
5232
- });
5233
- } catch (error) {
5234
- if (!current()) return;
5235
- this.#set({
5236
- loadingMore: false,
5237
- loadMoreFailed: true
5238
- });
5239
- this.#setNotice(errorNotice(error, this.#i18n.t));
5240
- }
5241
- }
5242
- async setEnabled(flow, enabled) {
5243
- if (flow.live == null || this.#pending.has(flow.flowId)) return;
5244
- this.#pending.add(flow.flowId);
5245
- try {
5246
- const changed = await this.#client.setFlowEnabled(flow.flowId, flow.live.publicationId, enabled);
5247
- if (!this.#disposed) this.include(changed);
5248
- } catch (error) {
5249
- if (!this.#disposed) {
5250
- this.#setNotice(errorNotice(error, this.#i18n.t));
5251
- await this.reload();
5252
- }
5253
- } finally {
5254
- this.#pending.delete(flow.flowId);
5255
- }
5256
- }
5257
- async publish(flow) {
5258
- if (this.#pending.has(flow.flowId)) return;
5259
- this.#pending.add(flow.flowId);
5260
- try {
5261
- const initial = await this.#client.publishFlow(flow.flowId, flow.draftRevisionId, flow.live?.publicationId ?? null);
5262
- if (this.#disposed) return;
5263
- const operation = await Effect.runPromise(Effect.gen({ self: this }, function* () {
5264
- let current = initial;
5265
- while (current.status == "pending") {
5266
- yield* Effect.sleep(1e3);
5267
- current = yield* Effect.tryPromise((signal) => this.#client.getPublishOperation(flow.flowId, current.operationId, signal));
5268
- }
5269
- return current;
5270
- }), { signal: this.#lifetime.signal });
5271
- if (this.#disposed) return;
5272
- if (operation.status == "failed") this.#setNotice({
5273
- kind: "error",
5274
- message: operation.issue.message
5275
- });
5276
- else this.#setNotice({
5277
- kind: "success",
5278
- message: this.#i18n.t("notice.published", { name: flow.name })
5279
- });
5280
- this.include(await this.#client.getFlow(flow.flowId));
5281
- } catch (error) {
5282
- if (!this.#disposed) this.#setNotice(errorNotice(error, this.#i18n.t));
5283
- } finally {
5284
- this.#pending.delete(flow.flowId);
5285
- }
5286
- }
5287
- create(name, create) {
5288
- return this.#create(async () => create == null ? this.#client.createFlow(name) : this.#client.getFlow(await create(name)));
5289
- }
5290
- import(file, name, key, importer) {
5291
- return this.#create(async () => importer == null ? this.#client.importFlow(file, {
5292
- name,
5293
- idempotencyKey: key
5294
- }) : this.#client.getFlow(await importer(file, name, key)));
5295
- }
5296
- async #create(create) {
5297
- try {
5298
- const created = await create();
5299
- if (this.#disposed) return;
5300
- this.#insert(created);
5301
- return created;
5302
- } catch (error) {
5303
- if (!this.#disposed) this.#setNotice(errorNotice(error, this.#i18n.t));
5304
- }
5305
- }
5306
- async delete(flowId) {
5307
- const flow = this.flow(flowId);
5308
- if (flow == null || flow.status == "retiring") return false;
5309
- try {
5310
- await this.#client.deleteFlow(flowId);
5311
- if (this.#disposed) return false;
5312
- this.#remove(flowId);
5313
- this.#setNotice({
5314
- kind: "success",
5315
- message: this.#i18n.t("notice.flowDeleteAccepted", { name: flow.name })
5316
- });
5317
- return true;
5318
- } catch (error) {
5319
- if (!this.#disposed) this.#setNotice(errorNotice(error, this.#i18n.t));
5320
- return false;
5321
- }
5322
- }
5323
- async rename(flowId, name) {
5324
- const flow = this.flow(flowId);
5325
- const nextName = name.trim();
5326
- if (flow == null || nextName.length == 0) return false;
5327
- if (flow.name == nextName) return true;
5328
- try {
5329
- const changed = await this.#client.renameFlow(flowId, nextName);
5330
- if (this.#disposed) return false;
5331
- this.include(changed);
5332
- this.#setNotice({
5333
- kind: "success",
5334
- message: this.#i18n.t("notice.flowRenamed", { name: nextName })
5335
- });
5336
- return true;
5337
- } catch (error) {
5338
- if (!this.#disposed) this.#setNotice(errorNotice(error, this.#i18n.t));
5339
- return false;
5340
- }
5341
- }
5342
- include(flow) {
5343
- const index = this.#state.value.flows.findIndex((candidate) => candidate.flowId == flow.flowId);
5344
- if (index < 0) {
5345
- this.#set({ flows: [...this.#state.value.flows, flow] });
5346
- return;
5347
- }
5348
- const referenceCount = this.#state.value.flows[index].referenceCount;
5349
- this.#set({ flows: this.#state.value.flows.with(index, {
5350
- ...flow,
5351
- ...referenceCount == null ? {} : { referenceCount }
5352
- }) });
5353
- }
5354
- #insert(flow) {
5355
- if (this.#state.value.flows.some((candidate) => candidate.flowId == flow.flowId)) return;
5356
- this.#set({
5357
- flows: [...this.#state.value.flows, flow],
5358
- total: this.#state.value.total == null ? void 0 : this.#state.value.total + 1
5359
- });
5360
- }
5361
- #remove(flowId) {
5362
- this.#set({
5363
- flows: this.#state.value.flows.filter((flow) => flow.flowId != flowId),
5364
- total: this.#state.value.total == null ? void 0 : this.#state.value.total - 1
5365
- });
5366
- }
5367
- advanceHead(flowId, revisionId, content) {
5368
- this.#set({ flows: this.#state.value.flows.map((flow) => flow.flowId == flowId ? {
5369
- ...flow,
5370
- draftRevisionId: revisionId,
5371
- resourceReferences: {
5372
- ...flow.resourceReferences,
5373
- draft: flowResourceReferences(content)
5374
- }
5375
- } : flow) });
5376
- }
5377
- #set(patch) {
5378
- if (!this.#disposed) this.#state.set({
5379
- ...this.#state.value,
5380
- ...patch
5381
- });
5382
- }
5383
- };
5384
- //#endregion
5385
5169
  //#region src/workbench/browser/runtime/stores/moduleEditorSession.ts
5386
5170
  var ModuleEditorSession = class {
5387
5171
  #moduleDrafts = /* @__PURE__ */ new Map();
@@ -5517,183 +5301,6 @@ var ModuleEditorSession = class {
5517
5301
  }
5518
5302
  };
5519
5303
  //#endregion
5520
- //#region src/workbench/browser/runtime/stores/nodeEdits.ts
5521
- var NodeEdits = class {
5522
- constructor(revision, save, identity) {
5523
- this.revision = revision;
5524
- this.save = save;
5525
- this.identity = identity;
5526
- }
5527
- async saveErrorSources(nodeId, value) {
5528
- const node = this.revision.value?.graph()?.nodes[nodeId];
5529
- if (node?.kind != "error" || dequal$1(node.sourceFlowIds ?? [], value)) return false;
5530
- return await this.save([{
5531
- kind: "graph.trigger.sources.set",
5532
- nodeId,
5533
- before: node.sourceFlowIds,
5534
- value: value.length == 0 ? void 0 : value
5535
- }]);
5536
- }
5537
- async saveNodeSettings(nodeId, settings) {
5538
- const revision = this.revision.value;
5539
- if (revision == null) return false;
5540
- const changes = updateNodeSettings(revision, nodeId, settings);
5541
- return changes != null && await this.save(changes);
5542
- }
5543
- async saveNodeDescription(nodeId, description) {
5544
- const revision = this.revision.value;
5545
- if (revision == null) return false;
5546
- const changes = updateNodeDescription(revision, nodeId, description);
5547
- return changes != null && await this.save(changes);
5548
- }
5549
- async saveNodeIcon(nodeId, icon) {
5550
- const revision = this.revision.value;
5551
- if (revision == null) return false;
5552
- const changes = updateNodeIcon(revision, nodeId, icon);
5553
- return changes != null && await this.save(changes);
5554
- }
5555
- async saveNodeTitle(nodeId, title) {
5556
- const revision = this.revision.value;
5557
- if (revision == null) return false;
5558
- const changes = updateNodeName(revision, nodeId, title);
5559
- return changes != null && await this.save(changes);
5560
- }
5561
- async setInputValue(nodeId, handle, value, deletion) {
5562
- const revision = this.revision.value;
5563
- if (revision == null) return false;
5564
- const changes = setInputValue(revision, nodeId, handle, value);
5565
- return changes != null && await this.save(changes, deletion);
5566
- }
5567
- async resetInputs(nodeId, handles) {
5568
- const revision = this.revision.value;
5569
- if (revision == null) return false;
5570
- return await this.save(resetInputValues(revision.revision.content, nodeId, handles));
5571
- }
5572
- async saveOutputsDefs(nodeId, definitions, deletion, values) {
5573
- const revision = this.revision.value;
5574
- if (revision == null || revision.graph().nodes[nodeId]?.kind != "outputs") return false;
5575
- return await this.save(updateOutputPorts(revision, nodeId, definitions, values), deletion);
5576
- }
5577
- async saveStartInputDefs(nodeId, inputDefs, deletion) {
5578
- const revision = this.revision.value;
5579
- if (revision == null || revision.graph().nodes[nodeId]?.kind != "start") return false;
5580
- const changes = updateStartInputDefs(revision.revision.content, nodeId, inputDefs);
5581
- return await this.save(changes, deletion);
5582
- }
5583
- async resetTriggerConfig(triggerId, names) {
5584
- const revision = this.revision.value;
5585
- if (revision == null) return false;
5586
- const trigger = revision.graph()?.nodes[triggerId];
5587
- if (trigger?.kind !== "poll" && trigger?.kind !== "integration") return false;
5588
- const changes = (names == null ? Object.entries(trigger.config) : names.flatMap((name) => Object.hasOwn(trigger.config, name) ? [[name, trigger.config[name]]] : [])).map(([name, before]) => ({
5589
- kind: "graph.trigger.config.set",
5590
- nodeId: triggerId,
5591
- name,
5592
- before,
5593
- value: void 0
5594
- }));
5595
- return await this.save(changes);
5596
- }
5597
- async setInputSource(nodeId, handle, source) {
5598
- const revision = this.revision.value;
5599
- if (revision == null) return false;
5600
- return await this.save(setInputSources(revision.revision.content, nodeId, handle, [{
5601
- kind: "node",
5602
- ...source
5603
- }]));
5604
- }
5605
- async setInputVariable(nodeId, handle, name) {
5606
- const revision = this.revision.value;
5607
- if (revision == null) return false;
5608
- const changes = name == null ? setInputValue(revision, nodeId, handle, void 0) : setInputVariable(revision, nodeId, handle, name, this.identity());
5609
- return changes != null && await this.save(changes);
5610
- }
5611
- async saveCondition(nodeId, settings, deletion) {
5612
- const revision = this.revision.value;
5613
- if (revision == null) return false;
5614
- const changes = updateCondition(revision, nodeId, settings);
5615
- return changes != null && await this.save(changes, deletion);
5616
- }
5617
- async saveValue(nodeId, values, deletion) {
5618
- const revision = this.revision.value;
5619
- if (revision == null) return false;
5620
- const changes = updateValue(revision, nodeId, values);
5621
- return changes != null && await this.save(changes, deletion);
5622
- }
5623
- async saveResolution(nodeId, settings, deletion, values) {
5624
- const revision = this.revision.value;
5625
- if (revision == null) return false;
5626
- const changes = updateResolution(revision, nodeId, settings, values);
5627
- return changes != null && await this.save(changes, deletion);
5628
- }
5629
- async saveTaskSettings(nodeId, settings, deletion) {
5630
- const revision = this.revision.value;
5631
- if (revision == null) return false;
5632
- const changes = updateTask(revision, nodeId, settings);
5633
- return changes != null && await this.save(changes, deletion);
5634
- }
5635
- async saveTaskPorts(nodeId, ports, deletion, values) {
5636
- const revision = this.revision.value;
5637
- if (revision == null) return false;
5638
- const changes = updateTaskPorts(revision, nodeId, ports, values);
5639
- return changes != null && await this.save(changes, deletion);
5640
- }
5641
- async saveTaskAdditionalInputs(nodeId, inputs, deletion, values) {
5642
- const revision = this.revision.value;
5643
- if (revision == null) return false;
5644
- const changes = updateTaskAdditionalInputs(revision, nodeId, inputs, values);
5645
- return changes != null && await this.save(changes, deletion);
5646
- }
5647
- async setConnectorConnection(nodeId, connectionId) {
5648
- const revision = this.revision.value;
5649
- if (revision == null) return false;
5650
- const changes = setConnectorConnection(revision.revision.content, nodeId, connectionId);
5651
- return changes != null && await this.save(changes);
5652
- }
5653
- async setServiceConnections(providerId, connectionId, previousConnectionId) {
5654
- const revision = this.revision.value;
5655
- if (revision == null) return false;
5656
- const changes = setServiceConnections(revision.revision.content, providerId, connectionId, previousConnectionId);
5657
- return changes.length == 0 || await this.save(changes);
5658
- }
5659
- async setCodeActions(nodeId, capabilities) {
5660
- const revision = this.revision.value;
5661
- if (revision == null) return false;
5662
- const changes = setCodeActions(revision.revision.content, nodeId, capabilities);
5663
- return changes == null || await this.save(changes);
5664
- }
5665
- async setTriggerEventSource(triggerId, source) {
5666
- const revision = this.revision.value;
5667
- if (revision == null) return false;
5668
- const changes = setTriggerEventSource(revision, triggerId, source);
5669
- return changes != null && await this.save(changes);
5670
- }
5671
- async saveTriggerConfig(triggerId, name, value) {
5672
- const revision = this.revision.value;
5673
- if (revision == null) return false;
5674
- const changes = updateTriggerConfig(revision, triggerId, name, value);
5675
- return changes != null && await this.save(changes);
5676
- }
5677
- async saveTriggerSchedule(triggerId, schedule) {
5678
- const revision = this.revision.value;
5679
- if (revision == null) return false;
5680
- const changes = updateTriggerSchedule(revision.revision.content, triggerId, schedule);
5681
- return changes != null && await this.save(changes);
5682
- }
5683
- async saveWebhook(triggerId, settings, deletion) {
5684
- const revision = this.revision.value;
5685
- if (revision == null) return false;
5686
- const changes = updateWebhook(revision, triggerId, settings);
5687
- return changes != null && await this.save(changes, deletion);
5688
- }
5689
- async setTriggerConnection(triggerId, connectionId) {
5690
- const revision = this.revision.value;
5691
- if (revision == null) return false;
5692
- const changes = setTriggerConnection(revision, triggerId, connectionId);
5693
- return changes != null && await this.save(changes);
5694
- }
5695
- };
5696
- //#endregion
5697
5304
  //#region src/workbench/browser/runtime/stores/presentationChanges.ts
5698
5305
  var PresentationChanges = class {
5699
5306
  #client;
@@ -5796,7 +5403,7 @@ var PresentationChanges = class {
5796
5403
  };
5797
5404
  //#endregion
5798
5405
  //#region src/workbench/browser/runtime/stores/workspaceModel.ts
5799
- var initialState = {
5406
+ var initialState$1 = {
5800
5407
  checkLoading: false,
5801
5408
  selectedNodeIds: [],
5802
5409
  workspaceLoadFailed: false,
@@ -5826,7 +5433,7 @@ function selectedModuleEditor(revision, nodeIds) {
5826
5433
  };
5827
5434
  }
5828
5435
  var WorkspaceModel = class {
5829
- #state = val(initialState);
5436
+ #state = val(initialState$1);
5830
5437
  #catalogValues;
5831
5438
  constructor(i18n, flows) {
5832
5439
  const busy = derive(this.#state, (state) => state.busy);
@@ -5911,7 +5518,7 @@ var WorkspaceModel = class {
5911
5518
  }
5912
5519
  };
5913
5520
  //#endregion
5914
- //#region src/workbench/browser/runtime/stores/workspaceStore.ts
5521
+ //#region src/workbench/browser/runtime/stores/editSession.ts
5915
5522
  var deletionMessageKeys = {
5916
5523
  field: "history.deleted.field",
5917
5524
  group: "history.deleted.group",
@@ -5923,75 +5530,45 @@ var deletionMessageKeys = {
5923
5530
  conditionGroup: "history.deleted.conditionGroup",
5924
5531
  webhookBody: "history.deleted.webhookBody"
5925
5532
  };
5926
- var WorkspaceStore = class {
5927
- #canvasCommandListeners;
5533
+ var EditSession = class {
5928
5534
  #client;
5929
5535
  #draftChanges;
5930
5536
  #draftSession;
5931
5537
  #i18n;
5932
- #identity;
5933
5538
  #presentationChanges;
5934
5539
  #flows;
5935
- #runChanged;
5936
5540
  #setNotice;
5937
5541
  #model;
5938
5542
  #modules;
5939
5543
  #history;
5940
5544
  #historyRecovery;
5941
- #clipboard;
5942
- #diagnosticFocusId;
5943
5545
  #draftInvalidation;
5944
5546
  #draftUpdateNotice;
5945
5547
  #disposed;
5946
- #started;
5947
5548
  #draftSyncQueued;
5948
- #nodeFocusId;
5949
- #pendingRepair;
5950
- #stopCatalogWatch;
5951
- #stopFlowWatch;
5952
- constructor(client, setNotice, identity = createAuthoringId, i18n = createI18n(), runChanged = () => {}, catalogs = new CatalogStores(client), flowCreated = () => {}, accessChanged = () => {}, filterTriggerConnections) {
5953
- this.catalogs = catalogs;
5954
- this.flowCreated = flowCreated;
5955
- this.accessChanged = accessChanged;
5956
- this.filterTriggerConnections = filterTriggerConnections;
5957
- this.#canvasCommandListeners = /* @__PURE__ */ new Set();
5549
+ constructor(client, model, flows, setNotice, i18n) {
5958
5550
  this.#draftSession = new Latest();
5959
- this.notify = (notice) => {
5960
- if (!this.#disposed) this.#setNotice(notice);
5961
- };
5962
5551
  this.#history = new CanvasHistory();
5963
5552
  this.history$ = this.#history.state$;
5964
- this.#diagnosticFocusId = 0;
5965
5553
  this.#draftInvalidation = 0;
5966
5554
  this.#draftUpdateNotice = false;
5967
5555
  this.#disposed = false;
5968
- this.#started = false;
5969
5556
  this.#draftSyncQueued = false;
5970
- this.#nodeFocusId = 0;
5971
- this.subscribeCanvasCommands = (execute) => {
5972
- this.#canvasCommandListeners.add(execute);
5973
- return () => {
5974
- this.#canvasCommandListeners.delete(execute);
5975
- };
5976
- };
5977
5557
  this.#client = client;
5558
+ this.#model = model;
5559
+ this.#flows = flows;
5978
5560
  this.#setNotice = setNotice;
5979
- this.#identity = identity;
5980
- this.#clipboard = new CanvasClipboard(identity, i18n.t);
5981
5561
  this.#i18n = i18n;
5982
- this.#runChanged = runChanged;
5983
- this.#flows = new FlowCatalog(client, setNotice, i18n);
5984
- this.#model = new WorkspaceModel(i18n, this.#flows);
5985
5562
  this.#modules = new ModuleEditorSession(this.#model, this.#draftSession, (changes) => this.#saveModuleSource(changes), setNotice, i18n);
5986
5563
  this.#draftChanges = new DraftChanges(client, setNotice, i18n, {
5987
5564
  apply: (draft) => this.#applyDraft(draft, "local"),
5988
5565
  beforeChange: (manageBusy) => {
5989
- if (manageBusy) this.#set({ busy: "designer" });
5566
+ if (manageBusy) this.set({ busy: "designer" });
5990
5567
  },
5991
- check: () => void this.#checkDraft(),
5568
+ check: () => void this.checkDraft(),
5992
5569
  current: (context) => this.#isDraftChangeCurrent(context),
5993
5570
  finishChanges: () => {
5994
- if (!this.#disposed && this.#model.value.busy == "designer") this.#set({ busy: void 0 });
5571
+ if (!this.#disposed && this.#model.value.busy == "designer") this.set({ busy: void 0 });
5995
5572
  },
5996
5573
  headChanged: (flowId, revisionId, content) => this.#flows.advanceHead(flowId, revisionId, content),
5997
5574
  recover: (context) => {
@@ -5999,446 +5576,368 @@ var WorkspaceStore = class {
5999
5576
  return this.#syncDraftHead(context, true);
6000
5577
  }
6001
5578
  });
6002
- this.#presentationChanges = new PresentationChanges(client, setNotice, (presentation) => this.#set({ presentation }), i18n);
6003
- this.$ = this.#model.$;
6004
- this.nodes = new NodeEdits(this.$.revision, async (changes, deletion) => await this.#canvasChange("edit", 1, changes, void 0, void 0, deletion) && this.#model.value.draft != null, identity);
5579
+ this.#presentationChanges = new PresentationChanges(client, setNotice, (presentation) => this.set({ presentation }), i18n);
6005
5580
  }
6006
- dispose() {
6007
- this.catalogs.dispose();
6008
- this.#disposed = true;
6009
- this.#modules.dispose();
6010
- this.#draftSession.invalidate();
6011
- this.#presentationChanges.dispose();
6012
- this.#stopCatalogWatch?.();
6013
- this.#stopFlowWatch?.();
6014
- this.#canvasCommandListeners.clear();
6015
- this.history$.dispose();
6016
- this.#model.dispose();
6017
- this.#flows.dispose();
5581
+ selectNodes(nodeIds) {
5582
+ if (nodeIds.length == this.#model.value.selectedNodeIds.length && nodeIds.every((nodeId, index) => nodeId == this.#model.value.selectedNodeIds[index])) return true;
5583
+ this.#modules.flush();
5584
+ this.set({
5585
+ diagnosticFocus: void 0,
5586
+ moduleEditor: selectedModuleEditor(this.#model.value.draft == null ? void 0 : revisionView(this.#model.value.draft), nodeIds),
5587
+ nodeFocus: void 0,
5588
+ selectedNodeIds: nodeIds
5589
+ });
5590
+ return true;
6018
5591
  }
6019
- async start(flowId) {
6020
- this.#started = false;
6021
- await this.selectFlow(flowId);
6022
- this.#started = !this.#disposed;
5592
+ updateModuleSource(source) {
5593
+ const editor = this.#model.value.moduleEditor;
5594
+ if (this.#history.applying || this.#history.failed || editor == null || editor.source == source) return;
5595
+ this.#history.discardRedo();
5596
+ this.#modules.updateModuleSource(source);
6023
5597
  }
6024
- async #loadFlowCatalog() {
6025
- if (this.#flows.loaded && this.#stopCatalogWatch != null) return;
6026
- let initialLoad;
6027
- if (this.#stopCatalogWatch == null) {
6028
- const subscription = this.#client.watchFlowCatalog((event) => {
6029
- if (this.#disposed) return;
6030
- this.reloadFlows();
6031
- if (event?.kind == "flow.created" && this.#started && this.#model.value.flowId == null && this.#model.value.busy == null) this.flowCreated(event.flowId);
6032
- });
6033
- this.#stopCatalogWatch = subscription.stop;
6034
- subscription.ready.then(async () => {
6035
- if (initialLoad == null || this.#disposed) return;
6036
- await initialLoad;
6037
- if (!this.#disposed) await this.reloadFlows();
6038
- });
6039
- await Promise.resolve();
6040
- }
6041
- if (this.#disposed) return;
6042
- initialLoad = this.reloadFlows();
6043
- await initialLoad;
6044
- }
6045
- async reloadFlows() {
6046
- await this.#flows.reload();
5598
+ discardModuleChanges() {
5599
+ this.#modules.discardModuleChanges();
6047
5600
  }
6048
- async setFlowEnabled(flow, enabled) {
6049
- await this.#flows.setEnabled(flow, enabled);
5601
+ get hasUnsavedCode() {
5602
+ return this.#modules.hasUnsavedCode;
6050
5603
  }
6051
- async publishFlow(flow) {
6052
- await this.#flows.publish(flow);
5604
+ async saveDraft() {
5605
+ const current = this.#draftSession.capture();
5606
+ if ((await Promise.all([this.#draftChanges.flush(), this.saveModuleEditor()])).some((success) => !success) || !current()) return false;
5607
+ return await this.#draftChanges.flush() && current() && !this.#disposed && !this.#history.failed;
6053
5608
  }
6054
- async loadMoreFlows() {
6055
- await this.#flows.loadMore();
5609
+ saveModuleEditor() {
5610
+ return this.#modules.saveModuleEditor();
6056
5611
  }
6057
- async selectFlow(flowId) {
6058
- if (this.#history.applying) return false;
6059
- if (!await this.saveModuleEditor() || this.#disposed) return false;
6060
- this.#history.clear();
6061
- this.#pendingRepair = void 0;
6062
- this.#history.failed = false;
6063
- this.#history.publish();
6064
- const current = this.#draftSession.begin();
6065
- this.#draftChanges.reset();
6066
- this.#presentationChanges.reset();
6067
- this.#draftInvalidation = 0;
6068
- this.#draftUpdateNotice = false;
6069
- this.#draftSyncQueued = false;
6070
- this.#stopFlowWatch?.();
6071
- this.#stopFlowWatch = void 0;
6072
- this.#set({
6073
- checkLoading: false,
6074
- diagnosticFocus: void 0,
6075
- diagnostics: void 0,
6076
- draft: void 0,
6077
- live: void 0,
6078
- moduleEditor: void 0,
6079
- nodeFocus: void 0,
6080
- presentation: void 0,
6081
- flowId,
6082
- selectedNodeIds: [],
6083
- workspaceLoadFailed: false,
6084
- workspaceLoadProblem: void 0,
6085
- workspaceLoading: flowId != null,
6086
- workspaceRepairing: false
6087
- });
6088
- if (flowId == null) {
6089
- await this.#loadFlowCatalog();
6090
- return true;
6091
- }
6092
- try {
6093
- let invalidated = false;
6094
- let pendingRevision;
6095
- const changed = (revisionId) => {
6096
- if (!current()) return;
6097
- if (this.#draftChanges.committed == null) {
6098
- invalidated = true;
6099
- pendingRevision = revisionId;
6100
- } else if (revisionId != this.#draftChanges.committed.revisionId) this.#refreshDraft(revisionId);
6101
- };
6102
- const subscription = this.#client.watchFlow(flowId, changed, (event) => {
6103
- if (current()) this.#runChanged(event);
6104
- }, (accessRevision) => {
6105
- if (current()) {
6106
- this.accessChanged(flowId, accessRevision);
6107
- this.#refreshLive(flowId, current);
6108
- }
6109
- }, (command) => {
6110
- if (current() && !this.#model.value.workspaceLoading) for (const execute of this.#canvasCommandListeners) execute(command);
6111
- });
6112
- this.#stopFlowWatch = subscription.stop;
6113
- let reading = false;
6114
- subscription.ready.then(() => {
6115
- if (reading) changed();
6116
- }, (error) => {
6117
- if (!current()) return;
6118
- subscription.stop();
6119
- this.#stopFlowWatch = void 0;
6120
- this.#setNotice(errorNotice(error, this.#i18n.t));
6121
- });
6122
- await Promise.resolve();
6123
- if (!current()) return false;
6124
- reading = true;
6125
- let editor = await this.#client.getEditor(flowId);
6126
- for (let attempt = 0; current() && Object.values(revisionView(editor.draft).graph().nodes).some((node) => node.kind == "manual"); attempt += 1) {
6127
- if (attempt >= 3) throw new ApiError(409, controlErrorCode.flowRevisionConflict, "The Draft changed while upgrading its Start node.");
6128
- try {
6129
- await this.#client.upgradeDraft(flowId, editor.draft.revisionId, { idempotencyKey: this.#identity() });
6130
- } catch (error) {
6131
- if (!(error instanceof ApiError) || error.code !== controlErrorCode.flowRevisionConflict || attempt >= 2) throw error;
5612
+ #notifyDeletion(deletion, entry) {
5613
+ this.#setNotice({
5614
+ kind: "success",
5615
+ message: "name" in deletion ? this.#i18n.t(deletionMessageKeys[deletion.target], { name: deletion.name }) : this.#i18n.t(deletionMessageKeys[deletion.target]),
5616
+ undo: {
5617
+ label: this.#i18n.t("history.undo"),
5618
+ run: async () => {
5619
+ if (this.history$.value.undo !== entry) return;
5620
+ await this.undo();
6132
5621
  }
6133
- if (!current()) return false;
6134
- editor = await this.#client.getEditor(flowId);
6135
5622
  }
6136
- const { flow, draft, live, presentation } = editor;
6137
- if (!current()) return false;
6138
- this.#draftChanges.reset(draft);
6139
- this.#presentationChanges.reset(presentation);
6140
- this.#flows.include(flow);
6141
- this.#set({
6142
- draft,
6143
- live,
6144
- presentation,
6145
- workspaceLoadFailed: false,
6146
- workspaceLoadProblem: void 0
6147
- });
6148
- await this.#repairDraftNodeNames(current);
6149
- if (!current()) return false;
6150
- this.#set({ workspaceLoading: false });
6151
- if (invalidated && pendingRevision != draft.revisionId) this.#refreshDraft(pendingRevision);
6152
- } catch (error) {
6153
- if (!current()) return false;
6154
- this.#stopFlowWatch?.();
6155
- this.#stopFlowWatch = void 0;
6156
- const kind = error instanceof ApiError && error.code == controlErrorCode.flowUpgradeRequired ? "upgrade" : error instanceof ApiError && (error.code == controlErrorCode.flowRepairRequired || error.code == controlErrorCode.flowInvalid) ? "repair" : "failed";
6157
- this.#set({
6158
- workspaceLoadFailed: true,
6159
- workspaceLoadProblem: {
6160
- kind,
6161
- ...kind == "failed" ? { message: errorNotice(error, this.#i18n.t).message } : {}
6162
- },
6163
- workspaceLoading: false
6164
- });
6165
- return false;
6166
- }
6167
- return true;
5623
+ });
6168
5624
  }
6169
- async repairWorkspace() {
5625
+ async #changeDraft(changes, manageBusy = true, historyMode = "clear") {
5626
+ if (this.#disposed || (this.#history.applying || this.#history.failed) && historyMode != "canvas") return;
6170
5627
  const flowId = this.#model.value.flowId;
6171
- if (flowId == null || this.#model.value.workspaceRepairing) return;
5628
+ const draft = this.#model.value.draft;
5629
+ if (flowId == null || draft == null) return;
5630
+ if (changes.length == 0 || dequal$1(applyFlowChanges$1(draft, changes).content, draft.content)) return draft;
5631
+ const cleared = historyMode == "clear" && this.#history.clear();
6172
5632
  const current = this.#draftSession.capture();
6173
- this.#set({
6174
- workspaceRepairing: true,
6175
- workspaceLoadProblem: this.#model.value.workspaceLoadProblem
6176
- });
5633
+ this.#history.beginChange();
6177
5634
  try {
6178
- let repair = this.#pendingRepair;
6179
- if (repair == null) {
6180
- const flow = this.#flows.flow(flowId) ?? await this.#client.getFlow(flowId);
6181
- if (!current()) return;
6182
- repair = this.#pendingRepair = {
6183
- changeId: this.#identity(),
6184
- expectedRevisionId: flow.draftRevisionId
6185
- };
6186
- }
6187
- await this.#client.repairDraft(flowId, repair.expectedRevisionId, repair.changeId);
6188
- if (!current()) return;
6189
- this.#pendingRepair = void 0;
6190
- await this.selectFlow(flowId);
6191
- } catch (error) {
6192
- if (this.#disposed || !current()) return;
6193
- if (error instanceof ApiError && error.code == controlErrorCode.flowRevisionConflict) {
6194
- this.#pendingRepair = void 0;
6195
- await this.selectFlow(flowId);
6196
- return;
6197
- }
6198
- this.#set({
6199
- workspaceLoadProblem: {
6200
- kind: this.#model.value.workspaceLoadProblem?.kind == "upgrade" ? "upgrade" : "repair",
6201
- message: errorNotice(error, this.#i18n.t).message
6202
- },
6203
- workspaceRepairing: false
5635
+ const saved = this.#draftChanges.change({
5636
+ current,
5637
+ flowId
5638
+ }, draft, changes, manageBusy);
5639
+ if (cleared) this.#setNotice({
5640
+ kind: "success",
5641
+ message: this.#i18n.t("history.cleared")
6204
5642
  });
5643
+ const result = await saved;
5644
+ if (result == null && current()) this.retryHistorySync();
5645
+ return result;
5646
+ } finally {
5647
+ this.#history.endChange();
6205
5648
  }
6206
5649
  }
6207
- async #refreshLive(flowId, current) {
6208
- try {
6209
- const live = await this.#client.getLive(flowId);
6210
- if (current() && this.#model.value.flowId == flowId) this.#set({ live });
6211
- } catch (error) {
6212
- if (current() && this.#model.value.flowId == flowId) this.#setNotice(errorNotice(error, this.#i18n.t));
5650
+ async #saveModuleSource(changes) {
5651
+ const saved = await this.#changeDraft(changes, false, "code");
5652
+ if (saved != null) for (const operation of changes) {
5653
+ if (operation.kind != "module.source.replace") continue;
5654
+ const module = saved.content.modules[operation.moduleId];
5655
+ if (module != null) this.#history.rebaseModuleCreation(operation.moduleId, module);
6213
5656
  }
5657
+ return saved;
6214
5658
  }
6215
- selectNodes(nodeIds) {
6216
- if (nodeIds.length == this.#model.value.selectedNodeIds.length && nodeIds.every((nodeId, index) => nodeId == this.#model.value.selectedNodeIds[index])) return true;
6217
- this.#modules.flush();
6218
- this.#set({
6219
- diagnosticFocus: void 0,
6220
- moduleEditor: selectedModuleEditor(this.#model.value.draft == null ? void 0 : revisionView(this.#model.value.draft), nodeIds),
6221
- nodeFocus: void 0,
6222
- selectedNodeIds: nodeIds
5659
+ async repairDraftNodeNames(current) {
5660
+ for (let attempt = 0; attempt < 2 && current(); attempt += 1) {
5661
+ const draft = this.#model.value.draft;
5662
+ if (draft == null) return;
5663
+ const repairs = repairNodeNames(draft.content, { start: this.#i18n.t("addNode.start") });
5664
+ if (repairs.length == 0) {
5665
+ this.checkDraft();
5666
+ return;
5667
+ }
5668
+ if (await this.#changeDraft(repairs, false) != null || !current()) return;
5669
+ if (this.#model.value.draft?.revisionId == draft.revisionId) break;
5670
+ }
5671
+ if (current()) this.checkDraft();
5672
+ }
5673
+ #applyDraft(draft, origin) {
5674
+ const previousDraft = this.#model.value.draft;
5675
+ const { revision, selectedNodeIds } = this.#reconcileRevision(draft);
5676
+ const editor = this.#model.value.moduleEditor;
5677
+ const keepEditor = editor != null && (origin == "external" || previousDraft != null) && moduleEditorStatus(previousDraft, editor) != "saved";
5678
+ let moduleEditor;
5679
+ if (keepEditor) moduleEditor = origin == "external" ? {
5680
+ ...editor,
5681
+ phase: "failed"
5682
+ } : editor;
5683
+ else moduleEditor = selectedModuleEditor(revision, selectedNodeIds);
5684
+ this.set({
5685
+ draft,
5686
+ moduleEditor,
5687
+ selectedNodeIds
6223
5688
  });
6224
- return true;
5689
+ return keepEditor;
6225
5690
  }
6226
- async exportFlow(flowId) {
5691
+ async changePresentation(update, historyOwned = false) {
5692
+ if (this.#disposed || (this.#history.applying || this.#history.failed) && !historyOwned) return false;
5693
+ const flowId = this.#model.value.flowId;
5694
+ const presentation = this.#model.value.presentation;
5695
+ if (flowId == null || presentation == null) return false;
5696
+ if (dequal$1(update(presentation.value), presentation.value)) return true;
5697
+ if (!historyOwned) this.#clearHistoryForEdit();
6227
5698
  const current = this.#draftSession.capture();
6228
- const selected = this.#model.value.flowId == flowId;
6229
- if (selected && (!await this.saveDraft() || !await this.#presentationChanges.flush() || !current())) {
6230
- this.#setNotice({
6231
- kind: "error",
6232
- message: this.#i18n.t("notice.exportSaveFailed")
6233
- });
6234
- return;
6235
- }
6236
- this.#set({ busy: "flow" });
5699
+ this.#history.beginChange();
6237
5700
  try {
6238
- const file = await this.#client.exportFlow(flowId);
6239
- if (this.#disposed || selected && !current()) return;
6240
- const url = URL.createObjectURL(new Blob([encodeWorkflowFile(file)], { type: "application/json;charset=utf-8" }));
6241
- const link = document.createElement("a");
6242
- link.href = url;
6243
- link.download = workflowFileName(file.name ?? "workflow");
6244
- link.click();
6245
- setTimeout(() => URL.revokeObjectURL(url), 0);
6246
- } catch (error) {
6247
- if (!this.#disposed) this.#setNotice(errorNotice(error, this.#i18n.t));
5701
+ const result = await this.#presentationChanges.change(flowId, presentation, current, update);
5702
+ if (!result && current()) this.retryHistorySync();
5703
+ return result;
6248
5704
  } finally {
6249
- this.#set({ busy: void 0 });
5705
+ this.#history.endChange();
6250
5706
  }
6251
5707
  }
6252
- createFlow(name, create) {
6253
- return this.#createFlow(() => this.#flows.create(name, create));
6254
- }
6255
- importFlow(file, name, key, importer) {
6256
- return this.#createFlow(() => this.#flows.import(file, name, key, importer));
5708
+ #clearHistoryForEdit() {
5709
+ if (this.#history.clear()) this.#setNotice({
5710
+ kind: "success",
5711
+ message: this.#i18n.t("history.cleared")
5712
+ });
6257
5713
  }
6258
- async #createFlow(create) {
6259
- if (!await this.saveModuleEditor()) return;
6260
- this.#set({ busy: "flow" });
5714
+ async canvasChange(action, count, changes, update, selection = this.#model.value.selectedNodeIds, deletion) {
5715
+ if (this.#disposed || this.#history.applying || this.#history.failed) return false;
5716
+ const { draft, presentation, selectedNodeIds } = this.#model.value;
5717
+ if (draft == null || presentation == null) return false;
5718
+ const next = update?.(presentation.value) ?? presentation.value;
5719
+ const presentationChange = canvasPresentationChange(presentation.value, next);
5720
+ if (dequal$1(applyFlowChanges$1(draft, changes).content, draft.content) && presentationChange.nodeIds.length == 0) return true;
5721
+ const generation = this.#history.generation;
5722
+ const inverse = inverseFlowChanges(draft.content, changes);
5723
+ this.#history.beginChange();
5724
+ const entry = {
5725
+ action,
5726
+ count,
5727
+ forward: changes,
5728
+ inverse,
5729
+ presentation: presentationChange,
5730
+ beforeSelection: selectedNodeIds,
5731
+ afterSelection: selection
5732
+ };
5733
+ const retained = this.#history.record(entry);
6261
5734
  try {
6262
- return await create();
5735
+ const change = changes.length == 0 ? Promise.resolve(draft) : this.#changeDraft(changes, true, "canvas");
5736
+ const layout = update == null ? Promise.resolve(true) : this.changePresentation(update, true);
5737
+ this.selectNodes(selection);
5738
+ if (!retained) this.#setNotice({
5739
+ kind: "success",
5740
+ message: this.#i18n.t("history.tooLarge")
5741
+ });
5742
+ const [saved, positioned] = await Promise.all([change, layout]);
5743
+ const complete = saved != null && positioned && (!retained || generation == this.#history.generation);
5744
+ if (complete && retained && deletion != null && this.history$.value.undo === entry) this.#notifyDeletion(deletion, entry);
5745
+ return complete;
5746
+ } catch (error) {
5747
+ this.#setNotice(errorNotice(error, this.#i18n.t));
5748
+ this.retryHistorySync();
5749
+ return false;
6263
5750
  } finally {
6264
- this.#set({ busy: void 0 });
5751
+ this.#history.endChange();
6265
5752
  }
6266
5753
  }
6267
- getFlowReferences(flowId, options = {}) {
6268
- return this.#client.getFlowReferences(flowId, {
6269
- ...options,
6270
- direction: "incoming",
6271
- limit: 50
6272
- });
5754
+ async undo() {
5755
+ await this.#restoreHistory(false);
6273
5756
  }
6274
- getErrorListeners(flowId, signal) {
6275
- return this.#client.getErrorListeners(flowId, signal);
5757
+ async redo() {
5758
+ await this.#restoreHistory(true);
6276
5759
  }
6277
- async deleteFlow(flowId) {
6278
- if (!await this.saveModuleEditor()) return false;
6279
- this.#set({ busy: "flow" });
5760
+ async #restoreHistory(redo) {
5761
+ if (this.hasUnsavedCode && !await this.saveModuleEditor()) return;
5762
+ const state = this.history$.value;
5763
+ if (!(redo ? state.canRedo : state.canUndo)) return;
5764
+ const entry = redo ? state.redo : state.undo;
5765
+ if (entry == null) return;
5766
+ const generation = this.#history.generation;
5767
+ this.#history.beginRestore();
6280
5768
  try {
6281
- return await this.#flows.delete(flowId);
5769
+ const [draft, presentation] = await Promise.all([this.#changeDraft(redo ? entry.forward : entry.inverse, true, "canvas"), this.changePresentation((value) => restoreCanvasPresentation(value, entry.presentation, redo), true)]);
5770
+ if (draft != null && presentation && generation == this.#history.generation) {
5771
+ this.selectNodes(redo ? entry.afterSelection : entry.beforeSelection);
5772
+ this.#history.complete(redo);
5773
+ }
5774
+ } catch (error) {
5775
+ this.#setNotice(errorNotice(error, this.#i18n.t));
5776
+ this.retryHistorySync();
6282
5777
  } finally {
6283
- this.#set({ busy: void 0 });
5778
+ this.#history.endRestore();
6284
5779
  }
6285
5780
  }
6286
- async renameFlow(flowId, name) {
6287
- this.#set({ busy: "flow" });
5781
+ async retryHistorySync() {
5782
+ if (this.#disposed || this.#historyRecovery != null) return this.#historyRecovery;
5783
+ const flowId = this.#model.value.flowId;
5784
+ if (flowId == null) return;
5785
+ const current = this.#draftSession.capture();
5786
+ this.#history.beginRecovery();
5787
+ const recovery = async () => {
5788
+ await Promise.allSettled([this.#draftChanges.settled(), this.#presentationChanges.settled()]);
5789
+ if (!current() || this.#disposed) return;
5790
+ try {
5791
+ const { draft, presentation } = await this.#client.getEditor(flowId);
5792
+ if (!current() || this.#disposed) return;
5793
+ this.#draftChanges.reset(draft);
5794
+ this.#presentationChanges.reset(presentation);
5795
+ this.#applyDraft(draft, "external");
5796
+ this.set({ presentation });
5797
+ this.#flows.advanceHead(flowId, draft.revisionId, draft.content);
5798
+ this.#history.endRecovery();
5799
+ this.#setNotice({
5800
+ kind: "error",
5801
+ message: this.#i18n.t("history.resynced")
5802
+ });
5803
+ this.checkDraft();
5804
+ } catch {
5805
+ if (current() && !this.#disposed) this.#setNotice({
5806
+ kind: "error",
5807
+ message: this.#i18n.t("history.syncFailed")
5808
+ });
5809
+ }
5810
+ };
5811
+ this.#historyRecovery = recovery().finally(() => {
5812
+ this.#historyRecovery = void 0;
5813
+ });
5814
+ return this.#historyRecovery;
5815
+ }
5816
+ async checkDraft() {
5817
+ if (this.#disposed) return;
5818
+ const flowId = this.#model.value.flowId;
5819
+ const draft = this.#model.value.draft;
5820
+ if (flowId == null || draft == null) {
5821
+ if (this.#model.value.draft == null) this.set({
5822
+ checkLoading: false,
5823
+ diagnostics: void 0
5824
+ });
5825
+ return;
5826
+ }
5827
+ this.set({
5828
+ checkLoading: true,
5829
+ diagnosticFocus: void 0
5830
+ });
6288
5831
  try {
6289
- return await this.#flows.rename(flowId, name);
5832
+ const diagnostics = await this.#client.checkFlow(flowId, draft.revisionId);
5833
+ if (!this.#disposed && flowId == this.#model.value.flowId && draft.revisionId == this.#model.value.draft?.revisionId) {
5834
+ const live = this.#model.value.live;
5835
+ this.set({
5836
+ diagnostics,
5837
+ live: live == null ? void 0 : {
5838
+ ...live,
5839
+ hasUnpublishedChanges: live.publication == null || live.publication.closureDigest != diagnostics.closureDigest
5840
+ }
5841
+ });
5842
+ }
5843
+ } catch (error) {
5844
+ if (!this.#disposed && flowId == this.#model.value.flowId && draft.revisionId == this.#model.value.draft?.revisionId) this.#setNotice(errorNotice(error, this.#i18n.t));
6290
5845
  } finally {
6291
- this.#set({ busy: void 0 });
5846
+ if (!this.#disposed && flowId == this.#model.value.flowId && draft.revisionId == this.#model.value.draft?.revisionId) this.set({ checkLoading: false });
6292
5847
  }
6293
5848
  }
6294
- async addNode(option, position, connection, relatedChanges) {
6295
- if (!await this.saveModuleEditor()) return;
6296
- const draft = this.#model.value.draft;
6297
- if (draft == null) return;
6298
- const nodeId = this.#identity();
6299
- if (option.kind == "comment") return await this.#addComment(nodeId, position);
6300
- const revision = revisionView(draft);
6301
- const intent = addNodeIntent(option, revision, this.#i18n.t);
6302
- if (intent == null) return;
6303
- const edge = connection?.(nodeId);
6304
- const created = addNode(revision, nodeId, intent);
6305
- const nodeChanges = created == null ? void 0 : [...created, ...relatedChanges?.(nodeId, revision) ?? []];
6306
- if (nodeChanges == null) return;
6307
- const changes = edge == null ? nodeChanges : [...nodeChanges, ...connect(applyFlowChanges$1(draft, nodeChanges).content, {
6308
- source: edge.source,
6309
- target: edge.target,
6310
- ...edge.sourceHandle.startsWith("$branch:") ? { sourceHandle: edge.sourceHandle.slice(8) } : {}
6311
- })];
6312
- if (!await this.#canvasChange("add", 1, changes, (value) => setNodePositions(value, { [nodeId]: position }), [nodeId])) return;
5849
+ async refreshDraft(revisionId) {
6313
5850
  if (this.#disposed) return;
6314
- this.#set({ nodeFocus: {
6315
- nodeId,
6316
- requestId: ++this.#nodeFocusId
6317
- } });
6318
- if (intent.kind == "provider-trigger" && intent.connectionId == null) this.#configureAddedTrigger(draft.flowId, nodeId, intent.definition);
6319
- return nodeId;
6320
- }
6321
- async addWebhookResponseNode(triggerId) {
6322
- const option = this.$.addNodeOptions.value.find((item) => item.kind === "webhook-response");
6323
- const position = this.#designer().nodes.find((node) => node.id === triggerId)?.position;
6324
- if (option == null || position == null) return;
6325
- return this.addNode(option, {
6326
- x: position.x + 320,
6327
- y: position.y
6328
- }, void 0, (nodeId, revision) => selectWebhookResponse(revision, triggerId, nodeId) ?? []);
5851
+ const flowId = this.#model.value.flowId;
5852
+ if (flowId == null) return;
5853
+ this.#draftInvalidation += 1;
5854
+ if (revisionId != null) this.#draftUpdateNotice = true;
5855
+ if (this.#draftSyncQueued) return;
5856
+ this.#draftSyncQueued = true;
5857
+ const context = {
5858
+ current: this.#draftSession.capture(),
5859
+ flowId
5860
+ };
5861
+ await this.#draftChanges.enqueue(async () => {
5862
+ let generation;
5863
+ do {
5864
+ generation = this.#draftInvalidation;
5865
+ const notifyUpdate = this.#draftUpdateNotice;
5866
+ this.#draftUpdateNotice = false;
5867
+ await this.#syncDraftHead(context, false, notifyUpdate);
5868
+ } while (this.#isDraftChangeCurrent(context) && generation != this.#draftInvalidation);
5869
+ });
5870
+ if (this.#isDraftChangeCurrent(context)) this.#draftSyncQueued = false;
6329
5871
  }
6330
- async #configureAddedTrigger(flowId, nodeId, definition) {
6331
- const current = this.#draftSession.capture();
6332
- const original = this.$.revision.value?.graph().nodes[nodeId];
6333
- const unchanged = () => current() && !this.#disposed && this.$.revision.value?.graph().nodes[nodeId] === original;
5872
+ async #syncDraftHead(context, reportError, notifyUpdate = false) {
6334
5873
  try {
6335
- const connections = await resourceValue(this.catalogs.connections.get(definition.provider, flowId));
6336
- if (!unchanged()) return;
6337
- const allowed = this.filterTriggerConnections == null ? connections : await this.filterTriggerConnections(flowId, definition, connections);
6338
- if (!unchanged()) return;
6339
- const connection = connectionCatalog(allowed).preferred;
6340
- if (connection == null) return;
6341
- const revision = this.$.revision.value;
6342
- if (revision == null) return;
6343
- const changes = setTriggerConnection(revision, nodeId, connection.connectionId);
6344
- if (changes != null && this.#history.completeNodeCreation(nodeId, changes)) await this.#changeDraft(changes, false, "canvas");
5874
+ const base = this.#draftChanges.committed;
5875
+ if (base == null) return false;
5876
+ const synced = await this.#client.syncDraft(context.flowId);
5877
+ if (!this.#isDraftChangeCurrent(context)) return false;
5878
+ const committed = synced.draft;
5879
+ if (committed.revisionId == base.revisionId) return true;
5880
+ if (this.#history.clear()) this.#setNotice({
5881
+ kind: "success",
5882
+ message: this.#i18n.t("history.external")
5883
+ });
5884
+ const draft = this.#draftChanges.replaceCommitted(committed);
5885
+ const preserveModuleEditor = this.#applyDraft(draft, "external");
5886
+ this.#flows.advanceHead(context.flowId, committed.revisionId, committed.content);
5887
+ if (notifyUpdate) this.#setNotice({
5888
+ kind: preserveModuleEditor ? "error" : "success",
5889
+ message: this.#i18n.t(preserveModuleEditor ? "notice.moduleUpdated" : "notice.draftUpdated")
5890
+ });
5891
+ this.checkDraft();
5892
+ return true;
6345
5893
  } catch (error) {
6346
- if (unchanged()) this.#setNotice(errorNotice(error, this.#i18n.t));
5894
+ if (reportError && this.#isDraftChangeCurrent(context)) this.#setNotice(errorNotice(error, this.#i18n.t));
5895
+ return false;
6347
5896
  }
6348
5897
  }
6349
- async connect(edge) {
6350
- const revision = this.$.revision.value;
6351
- if (revision == null) return;
6352
- const changes = connect(revision.revision.content, {
6353
- source: edge.source,
6354
- target: edge.target,
6355
- ...edge.sourceHandle.startsWith("$branch:") ? { sourceHandle: edge.sourceHandle.slice(8) } : {}
6356
- });
6357
- if (changes.length > 0) await this.#canvasChange("connect", 1, changes);
5898
+ #reconcileRevision(draft) {
5899
+ const revision = revisionView(draft);
5900
+ return {
5901
+ revision,
5902
+ selectedNodeIds: this.#model.value.selectedNodeIds.filter((nodeId) => revision.selection(nodeId) != null)
5903
+ };
6358
5904
  }
6359
- async disconnect(edge) {
6360
- const revision = this.$.revision.value;
6361
- if (revision == null) return;
6362
- const changes = disconnect(revision.revision.content, {
6363
- source: edge.source,
6364
- target: edge.target,
6365
- ...edge.sourceHandle.startsWith("$branch:") ? { sourceHandle: edge.sourceHandle.slice(8) } : {}
5905
+ #isDraftChangeCurrent(context) {
5906
+ return !this.#disposed && context.flowId == this.#model.value.flowId && context.current();
5907
+ }
5908
+ set(patch) {
5909
+ if (this.#disposed) return;
5910
+ const editor = Object.hasOwn(patch, "moduleEditor") ? patch.moduleEditor : this.#model.value.moduleEditor;
5911
+ this.#model.set({
5912
+ ...patch,
5913
+ ...this.#modules.state(editor)
6366
5914
  });
6367
- if (changes.length > 0) await this.#canvasChange("disconnect", 1, changes);
6368
5915
  }
6369
- async deleteSelectedNodes() {
6370
- if (!await this.saveModuleEditor()) return;
6371
- const revision = this.$.revision.value;
6372
- if (revision == null || this.#model.value.selectedNodeIds.length == 0) return;
6373
- const selectedNodeIds = [...this.#model.value.selectedNodeIds];
6374
- const comments = commentIds(this.#model.value.presentation?.value ?? {});
6375
- const commentNodes = new Set(this.#model.value.selectedNodeIds.filter((nodeId) => comments.has(nodeId)));
6376
- const changes = deleteSelection(revision, this.#model.value.selectedNodeIds);
6377
- await this.#canvasChange("delete", this.#model.value.selectedNodeIds.length, changes, (value) => {
6378
- let next = commentNodes.size == 0 ? value : removeComments(value, commentNodes);
6379
- for (const nodeId of selectedNodeIds) next = setNodeContentHidden(next, nodeId, false);
6380
- return next;
6381
- }, []);
6382
- }
6383
- copySelectedNodes() {
6384
- const revision = this.$.revision.value;
6385
- if (revision == null || this.#model.value.selectedNodeIds.length == 0) return;
6386
- this.#clipboard.copy(revision, this.#designer(), this.#model.value.selectedNodeIds);
6387
- }
6388
- async pasteNodes(sourcePositions, offset) {
6389
- if (!await this.saveModuleEditor()) return;
6390
- const revision = this.$.revision.value;
6391
- if (revision == null) return;
6392
- const pasted = this.#clipboard.paste(revision, this.#designer(), sourcePositions, offset);
6393
- if (pasted != null) await this.#canvasChange("paste", pasted.nodeIds.length, pasted.changes, pasted.update, pasted.nodeIds);
6394
- }
6395
- async duplicateSelectedNodes(positions, offset) {
6396
- this.copySelectedNodes();
6397
- await this.pasteNodes(positions, offset);
6398
- }
6399
- async saveNodeContentHidden(nodeId, hidden) {
6400
- const node = this.#designer().nodes.find((candidate) => candidate.id == nodeId);
6401
- if (node == null || node.kind == "condition") return;
6402
- await this.#canvasChange("edit", 1, [], (value) => setNodeContentHidden(value, nodeId, hidden));
6403
- }
6404
- async saveComment(nodeId, comment) {
6405
- if (this.#model.value.draft == null) return;
6406
- const position = this.#designer().nodes.find((node) => node.id == nodeId)?.position;
6407
- if (position == null) return;
6408
- await this.#canvasChange("edit", 1, [], (value) => setComment(value, nodeId, {
6409
- ...comment,
6410
- position
6411
- }));
5916
+ get applying() {
5917
+ return this.#history.applying;
6412
5918
  }
6413
- async listWorkflowTargets(signal) {
6414
- const flowId = this.$.revision.value?.revision.flowId;
6415
- if (flowId == null) return [];
6416
- const candidates = [];
6417
- let cursor;
6418
- do {
6419
- const page = await this.#client.listFlows({
6420
- cursor,
6421
- limit: 100,
6422
- signal
6423
- });
6424
- candidates.push(...page.flows.filter((flow) => flow.flowId != flowId).map((flow) => workflowCandidate(flow)));
6425
- cursor = page.nextCursor;
6426
- } while (cursor != null);
6427
- return candidates;
5919
+ get committed() {
5920
+ return this.#draftChanges.committed;
6428
5921
  }
6429
- loadWorkflowContract(flowId, signal) {
6430
- return this.#client.getWorkflowContract(flowId, signal);
5922
+ begin() {
5923
+ this.#history.reset();
5924
+ const current = this.#draftSession.begin();
5925
+ this.#draftChanges.reset();
5926
+ this.#presentationChanges.reset();
5927
+ this.#draftInvalidation = 0;
5928
+ this.#draftUpdateNotice = false;
5929
+ this.#draftSyncQueued = false;
5930
+ return current;
6431
5931
  }
6432
- loadOpenApiDocument(url, signal) {
6433
- return this.#client.loadOpenApiDocument(url, signal);
5932
+ capture() {
5933
+ return this.#draftSession.capture();
6434
5934
  }
6435
- get eventSourceClient() {
6436
- return this.#client;
5935
+ reset(draft, presentation) {
5936
+ this.#draftChanges.reset(draft);
5937
+ this.#presentationChanges.reset(presentation);
6437
5938
  }
6438
- async loadEventSources(signal) {
6439
- const flowId = this.#model.value.flowId;
6440
- if (flowId == null) throw new Error("No Flow selected");
6441
- return await this.#client.listEventSources(flowId, signal);
5939
+ async finishNodeCreation(nodeId, changes) {
5940
+ if (this.#history.completeNodeCreation(nodeId, changes)) await this.#changeDraft(changes, false, "canvas");
6442
5941
  }
6443
5942
  async loadTriggerConfigOptions(triggerId, field, signal) {
6444
5943
  const flowId = this.#model.value.flowId;
@@ -6448,392 +5947,1008 @@ var WorkspaceStore = class {
6448
5947
  if (this.#disposed || !current() || flowId == null) throw new DOMException("Draft changed", "AbortError");
6449
5948
  return await this.#client.listTriggerConfigOptions(flowId, triggerId, field, signal);
6450
5949
  }
6451
- updateModuleSource(source) {
6452
- const editor = this.#model.value.moduleEditor;
6453
- if (this.#history.applying || this.#history.failed || editor == null || editor.source == source) return;
6454
- this.#history.discardRedo();
6455
- this.#modules.updateModuleSource(source);
6456
- }
6457
- discardModuleChanges() {
6458
- this.#modules.discardModuleChanges();
6459
- }
6460
- get hasUnsavedCode() {
6461
- return this.#modules.hasUnsavedCode;
6462
- }
6463
- async saveDraft() {
5950
+ async flush() {
6464
5951
  const current = this.#draftSession.capture();
6465
- if ((await Promise.all([this.#draftChanges.flush(), this.saveModuleEditor()])).some((success) => !success) || !current()) return false;
6466
- return await this.#draftChanges.flush() && current() && !this.#disposed && !this.#history.failed;
6467
- }
6468
- saveModuleEditor() {
6469
- return this.#modules.saveModuleEditor();
6470
- }
6471
- async moveNodes(positions) {
6472
- if (this.#model.value.draft == null) return;
6473
- await this.#canvasChange("move", Object.keys(positions).length, [], (value) => setNodePositions(value, positions));
6474
- }
6475
- async moveViewport(viewport) {
6476
- if (this.#model.value.draft == null) return;
6477
- await this.#changePresentation((value) => setFlowViewport(value, viewport), true);
6478
- }
6479
- async check() {
6480
- await this.#checkDraft();
5952
+ return await this.saveDraft() && await this.#presentationChanges.flush() && current();
6481
5953
  }
6482
- async refreshFlows() {
6483
- await this.reloadFlows();
5954
+ dispose() {
5955
+ this.#disposed = true;
5956
+ this.#modules.dispose();
5957
+ this.#draftSession.invalidate();
5958
+ this.#presentationChanges.dispose();
5959
+ this.#history.dispose();
6484
5960
  }
6485
- updateLive(live) {
6486
- if (live.flowId == this.#model.value.flowId) this.#set({ live });
5961
+ };
5962
+ //#endregion
5963
+ //#region src/workbench/browser/runtime/stores/flowCatalog.ts
5964
+ var pageLimit = 50;
5965
+ var initialState = {
5966
+ failed: false,
5967
+ loaded: false,
5968
+ loading: true,
5969
+ loadingMore: false,
5970
+ loadMoreFailed: false,
5971
+ refreshing: false,
5972
+ flows: []
5973
+ };
5974
+ var FlowCatalog = class {
5975
+ #client;
5976
+ #i18n;
5977
+ #session = new Latest();
5978
+ #setNotice;
5979
+ #state = val(initialState);
5980
+ #lifetime = new AbortController();
5981
+ #pending = /* @__PURE__ */ new Set();
5982
+ #disposed = false;
5983
+ constructor(client, setNotice, i18n) {
5984
+ this.#client = client;
5985
+ this.#i18n = i18n;
5986
+ this.#setNotice = setNotice;
5987
+ this.$ = {
5988
+ failed: derive(this.#state, (state) => state.failed),
5989
+ loading: derive(this.#state, (state) => state.loading),
5990
+ loadingMore: derive(this.#state, (state) => state.loadingMore),
5991
+ loadMoreFailed: derive(this.#state, (state) => state.loadMoreFailed),
5992
+ refreshing: derive(this.#state, (state) => state.refreshing),
5993
+ nextCursor: derive(this.#state, (state) => state.nextCursor),
5994
+ flows: derive(this.#state, (state) => state.flows),
5995
+ total: derive(this.#state, (state) => state.total)
5996
+ };
6487
5997
  }
6488
- locateNode(nodeId, { preserveSelection = false } = {}) {
6489
- const revision = this.$.revision.value;
6490
- if (revision == null) return false;
6491
- if (revision.node(nodeId) == null && !commentIds(this.#model.value.presentation?.value ?? {}).has(nodeId)) return false;
6492
- if (!preserveSelection && !this.selectNodes([nodeId])) return false;
6493
- this.#set({ nodeFocus: {
6494
- nodeId,
6495
- requestId: ++this.#nodeFocusId
6496
- } });
6497
- return true;
5998
+ get loaded() {
5999
+ return this.#state.value.loaded;
6498
6000
  }
6499
- locateDiagnostic(item) {
6500
- if (item.location == null || !this.selectNodes([item.location.nodeId])) return false;
6501
- this.#set({ diagnosticFocus: {
6502
- ...item.location,
6503
- diagnostic: item.diagnostic,
6504
- requestId: ++this.#diagnosticFocusId
6505
- } });
6506
- return true;
6001
+ dispose() {
6002
+ this.#disposed = true;
6003
+ this.#lifetime.abort();
6004
+ this.#session.invalidate();
6005
+ for (const value of Object.values(this.$)) value.dispose();
6006
+ this.#state.dispose();
6507
6007
  }
6508
- async #addComment(nodeId, position) {
6509
- const number = Math.max(0, ...this.#designer().nodes.flatMap((node) => {
6510
- if (node.kind != "comment") return [];
6511
- const match = /#(\d+)$/.exec(node.title);
6512
- return match == null ? [] : [Number(match[1])];
6513
- }));
6514
- if (!await this.#canvasChange("add", 1, [], (value) => setComment(value, nodeId, {
6515
- content: "",
6516
- position,
6517
- title: this.#i18n.t("addNode.commentName", { number: number + 1 })
6518
- }), [nodeId]) || this.#disposed) return;
6519
- return nodeId;
6008
+ flow(flowId) {
6009
+ return this.#state.value.flows.find((flow) => flow.flowId == flowId);
6520
6010
  }
6521
- #notifyDeletion(deletion, entry) {
6522
- this.#setNotice({
6523
- kind: "success",
6524
- message: "name" in deletion ? this.#i18n.t(deletionMessageKeys[deletion.target], { name: deletion.name }) : this.#i18n.t(deletionMessageKeys[deletion.target]),
6525
- undo: {
6526
- label: this.#i18n.t("history.undo"),
6527
- run: async () => {
6528
- if (this.history$.value.undo !== entry) return;
6529
- await this.undo();
6530
- }
6531
- }
6011
+ async reload() {
6012
+ const current = this.#session.begin();
6013
+ const loaded = this.#state.value.loaded;
6014
+ if (loaded) this.#set({
6015
+ failed: false,
6016
+ loadingMore: false,
6017
+ loadMoreFailed: false,
6018
+ refreshing: true
6019
+ });
6020
+ else this.#set({
6021
+ failed: false,
6022
+ loading: true,
6023
+ loadingMore: false,
6024
+ loadMoreFailed: false,
6025
+ refreshing: false,
6026
+ nextCursor: void 0,
6027
+ flows: [],
6028
+ total: void 0
6532
6029
  });
6533
- }
6534
- async #changeDraft(changes, manageBusy = true, historyMode = "clear") {
6535
- if (this.#disposed || (this.#history.applying || this.#history.failed) && historyMode != "canvas") return;
6536
- const flowId = this.#model.value.flowId;
6537
- const draft = this.#model.value.draft;
6538
- if (flowId == null || draft == null) return;
6539
- if (changes.length == 0 || dequal$1(applyFlowChanges$1(draft, changes).content, draft.content)) return draft;
6540
- const cleared = historyMode == "clear" && this.#history.clear();
6541
- const current = this.#draftSession.capture();
6542
- this.#history.pending++;
6543
- this.#history.publish();
6544
6030
  try {
6545
- const saved = this.#draftChanges.change({
6546
- current,
6547
- flowId
6548
- }, draft, changes, manageBusy);
6549
- if (cleared) this.#setNotice({
6550
- kind: "success",
6551
- message: this.#i18n.t("history.cleared")
6031
+ const page = await this.#client.listFlows({
6032
+ includeTotal: true,
6033
+ limit: pageLimit
6552
6034
  });
6553
- const result = await saved;
6554
- if (result == null && current()) this.retryHistorySync();
6555
- return result;
6556
- } finally {
6557
- this.#history.pending--;
6558
- if (!this.#disposed) this.#history.publish();
6559
- }
6560
- }
6561
- async #saveModuleSource(changes) {
6562
- const saved = await this.#changeDraft(changes, false, "code");
6563
- if (saved != null) for (const operation of changes) {
6564
- if (operation.kind != "module.source.replace") continue;
6565
- const module = saved.content.modules[operation.moduleId];
6566
- if (module != null) this.#history.rebaseModuleCreation(operation.moduleId, module);
6035
+ if (!current()) return;
6036
+ this.#set({
6037
+ loaded: true,
6038
+ loading: false,
6039
+ refreshing: false,
6040
+ nextCursor: page.nextCursor,
6041
+ flows: page.flows,
6042
+ total: page.total
6043
+ });
6044
+ } catch (error) {
6045
+ if (!current()) return;
6046
+ this.#set({
6047
+ failed: !loaded,
6048
+ loading: false,
6049
+ refreshing: false
6050
+ });
6051
+ this.#setNotice(errorNotice(error, this.#i18n.t));
6567
6052
  }
6568
- return saved;
6569
6053
  }
6570
- async #repairDraftNodeNames(current) {
6571
- for (let attempt = 0; attempt < 2 && current(); attempt += 1) {
6572
- const draft = this.#model.value.draft;
6573
- if (draft == null) return;
6574
- const repairs = repairNodeNames(draft.content, { start: this.#i18n.t("addNode.start") });
6575
- if (repairs.length == 0) {
6576
- this.#checkDraft();
6577
- return;
6578
- }
6579
- if (await this.#changeDraft(repairs, false) != null || !current()) return;
6580
- if (this.#model.value.draft?.revisionId == draft.revisionId) break;
6581
- }
6582
- if (current()) this.#checkDraft();
6583
- }
6584
- #applyDraft(draft, origin) {
6585
- const previousDraft = this.#model.value.draft;
6586
- const { revision, selectedNodeIds } = this.#reconcileRevision(draft);
6587
- const editor = this.#model.value.moduleEditor;
6588
- const keepEditor = editor != null && (origin == "external" || previousDraft != null) && moduleEditorStatus(previousDraft, editor) != "saved";
6589
- let moduleEditor;
6590
- if (keepEditor) moduleEditor = origin == "external" ? {
6591
- ...editor,
6592
- phase: "failed"
6593
- } : editor;
6594
- else moduleEditor = selectedModuleEditor(revision, selectedNodeIds);
6054
+ async loadMore() {
6055
+ const { loadingMore, nextCursor, refreshing } = this.#state.value;
6056
+ if (loadingMore || refreshing || nextCursor == null) return;
6057
+ const current = this.#session.capture();
6595
6058
  this.#set({
6596
- draft,
6597
- moduleEditor,
6598
- selectedNodeIds
6059
+ loadingMore: true,
6060
+ loadMoreFailed: false
6599
6061
  });
6600
- return keepEditor;
6062
+ try {
6063
+ const page = await this.#client.listFlows({
6064
+ cursor: nextCursor,
6065
+ limit: pageLimit
6066
+ });
6067
+ if (!current()) return;
6068
+ const flows = new Map(this.#state.value.flows.map((flow) => [flow.flowId, flow]));
6069
+ for (const flow of page.flows) flows.set(flow.flowId, flow);
6070
+ this.#set({
6071
+ loadingMore: false,
6072
+ nextCursor: page.nextCursor,
6073
+ flows: [...flows.values()]
6074
+ });
6075
+ } catch (error) {
6076
+ if (!current()) return;
6077
+ this.#set({
6078
+ loadingMore: false,
6079
+ loadMoreFailed: true
6080
+ });
6081
+ this.#setNotice(errorNotice(error, this.#i18n.t));
6082
+ }
6601
6083
  }
6602
- async #changePresentation(update, historyOwned = false) {
6603
- if (this.#disposed || (this.#history.applying || this.#history.failed) && !historyOwned) return false;
6604
- const flowId = this.#model.value.flowId;
6605
- const presentation = this.#model.value.presentation;
6606
- if (flowId == null || presentation == null) return false;
6607
- if (dequal$1(update(presentation.value), presentation.value)) return true;
6608
- if (!historyOwned) this.#clearHistoryForEdit();
6609
- const current = this.#draftSession.capture();
6610
- this.#history.pending++;
6611
- this.#history.publish();
6084
+ async setEnabled(flow, enabled) {
6085
+ if (flow.live == null || this.#pending.has(flow.flowId)) return;
6086
+ this.#pending.add(flow.flowId);
6612
6087
  try {
6613
- const result = await this.#presentationChanges.change(flowId, presentation, current, update);
6614
- if (!result && current()) this.retryHistorySync();
6615
- return result;
6088
+ const changed = await this.#client.setFlowEnabled(flow.flowId, flow.live.publicationId, enabled);
6089
+ if (!this.#disposed) this.include(changed);
6090
+ } catch (error) {
6091
+ if (!this.#disposed) {
6092
+ this.#setNotice(errorNotice(error, this.#i18n.t));
6093
+ await this.reload();
6094
+ }
6616
6095
  } finally {
6617
- this.#history.pending--;
6618
- if (!this.#disposed) this.#history.publish();
6096
+ this.#pending.delete(flow.flowId);
6619
6097
  }
6620
6098
  }
6621
- #clearHistoryForEdit() {
6622
- if (this.#history.clear()) this.#setNotice({
6623
- kind: "success",
6624
- message: this.#i18n.t("history.cleared")
6625
- });
6626
- }
6627
- async #canvasChange(action, count, changes, update, selection = this.#model.value.selectedNodeIds, deletion) {
6628
- if (this.#disposed || this.#history.applying || this.#history.failed) return false;
6629
- const { draft, presentation, selectedNodeIds } = this.#model.value;
6630
- if (draft == null || presentation == null) return false;
6631
- const next = update?.(presentation.value) ?? presentation.value;
6632
- const presentationChange = canvasPresentationChange(presentation.value, next);
6633
- if (dequal$1(applyFlowChanges$1(draft, changes).content, draft.content) && presentationChange.nodeIds.length == 0) return true;
6634
- const generation = this.#history.generation;
6635
- const inverse = inverseFlowChanges(draft.content, changes);
6636
- this.#history.pending++;
6637
- const entry = {
6638
- action,
6639
- count,
6640
- forward: changes,
6641
- inverse,
6642
- presentation: presentationChange,
6643
- beforeSelection: selectedNodeIds,
6644
- afterSelection: selection
6645
- };
6646
- const retained = this.#history.record(entry);
6099
+ async publish(flow) {
6100
+ if (this.#pending.has(flow.flowId)) return;
6101
+ this.#pending.add(flow.flowId);
6647
6102
  try {
6648
- const change = changes.length == 0 ? Promise.resolve(draft) : this.#changeDraft(changes, true, "canvas");
6649
- const layout = update == null ? Promise.resolve(true) : this.#changePresentation(update, true);
6650
- this.selectNodes(selection);
6651
- if (!retained) this.#setNotice({
6103
+ const initial = await this.#client.publishFlow(flow.flowId, flow.draftRevisionId, flow.live?.publicationId ?? null);
6104
+ if (this.#disposed) return;
6105
+ const operation = await Effect.runPromise(Effect.gen({ self: this }, function* () {
6106
+ let current = initial;
6107
+ while (current.status == "pending") {
6108
+ yield* Effect.sleep(1e3);
6109
+ current = yield* Effect.tryPromise((signal) => this.#client.getPublishOperation(flow.flowId, current.operationId, signal));
6110
+ }
6111
+ return current;
6112
+ }), { signal: this.#lifetime.signal });
6113
+ if (this.#disposed) return;
6114
+ if (operation.status == "failed") this.#setNotice({
6115
+ kind: "error",
6116
+ message: operation.issue.message
6117
+ });
6118
+ else this.#setNotice({
6652
6119
  kind: "success",
6653
- message: this.#i18n.t("history.tooLarge")
6120
+ message: this.#i18n.t("notice.published", { name: flow.name })
6654
6121
  });
6655
- const [saved, positioned] = await Promise.all([change, layout]);
6656
- const complete = saved != null && positioned && (!retained || generation == this.#history.generation);
6657
- if (complete && retained && deletion != null && this.history$.value.undo === entry) this.#notifyDeletion(deletion, entry);
6658
- return complete;
6122
+ this.include(await this.#client.getFlow(flow.flowId));
6659
6123
  } catch (error) {
6660
- this.#setNotice(errorNotice(error, this.#i18n.t));
6661
- this.retryHistorySync();
6662
- return false;
6124
+ if (!this.#disposed) this.#setNotice(errorNotice(error, this.#i18n.t));
6663
6125
  } finally {
6664
- this.#history.pending--;
6665
- if (!this.#disposed) this.#history.publish();
6126
+ this.#pending.delete(flow.flowId);
6666
6127
  }
6667
6128
  }
6668
- async undo() {
6669
- await this.#restoreHistory(false);
6129
+ create(name, create) {
6130
+ return this.#create(async () => create == null ? this.#client.createFlow(name) : this.#client.getFlow(await create(name)));
6670
6131
  }
6671
- async redo() {
6672
- await this.#restoreHistory(true);
6132
+ import(file, name, key, importer) {
6133
+ return this.#create(async () => importer == null ? this.#client.importFlow(file, {
6134
+ name,
6135
+ idempotencyKey: key
6136
+ }) : this.#client.getFlow(await importer(file, name, key)));
6673
6137
  }
6674
- async #restoreHistory(redo) {
6675
- if (this.hasUnsavedCode && !await this.saveModuleEditor()) return;
6676
- const state = this.history$.value;
6677
- if (!(redo ? state.canRedo : state.canUndo)) return;
6678
- const entry = redo ? state.redo : state.undo;
6679
- if (entry == null) return;
6680
- const generation = this.#history.generation;
6681
- this.#history.applying = true;
6682
- this.#history.publish();
6138
+ async #create(create) {
6683
6139
  try {
6684
- const [draft, presentation] = await Promise.all([this.#changeDraft(redo ? entry.forward : entry.inverse, true, "canvas"), this.#changePresentation((value) => restoreCanvasPresentation(value, entry.presentation, redo), true)]);
6685
- if (draft != null && presentation && generation == this.#history.generation) {
6686
- this.selectNodes(redo ? entry.afterSelection : entry.beforeSelection);
6687
- this.#history.complete(redo);
6688
- }
6140
+ const created = await create();
6141
+ if (this.#disposed) return;
6142
+ this.#insert(created);
6143
+ return created;
6689
6144
  } catch (error) {
6690
- this.#setNotice(errorNotice(error, this.#i18n.t));
6691
- this.retryHistorySync();
6692
- } finally {
6693
- this.#history.applying = false;
6694
- if (!this.#disposed) this.#history.publish();
6145
+ if (!this.#disposed) this.#setNotice(errorNotice(error, this.#i18n.t));
6695
6146
  }
6696
6147
  }
6697
- async retryHistorySync() {
6698
- if (this.#disposed || this.#historyRecovery != null) return this.#historyRecovery;
6699
- const flowId = this.#model.value.flowId;
6700
- if (flowId == null) return;
6701
- const current = this.#draftSession.capture();
6702
- this.#history.failed = true;
6703
- this.#history.clear();
6704
- const recovery = async () => {
6705
- await Promise.allSettled([this.#draftChanges.settled(), this.#presentationChanges.settled()]);
6706
- if (!current() || this.#disposed) return;
6707
- try {
6708
- const { draft, presentation } = await this.#client.getEditor(flowId);
6709
- if (!current() || this.#disposed) return;
6710
- this.#draftChanges.reset(draft);
6711
- this.#presentationChanges.reset(presentation);
6712
- this.#applyDraft(draft, "external");
6713
- this.#set({ presentation });
6714
- this.#flows.advanceHead(flowId, draft.revisionId, draft.content);
6715
- this.#history.failed = false;
6716
- this.#setNotice({
6717
- kind: "error",
6718
- message: this.#i18n.t("history.resynced")
6719
- });
6720
- this.#checkDraft();
6721
- } catch {
6722
- if (current() && !this.#disposed) this.#setNotice({
6723
- kind: "error",
6724
- message: this.#i18n.t("history.syncFailed")
6725
- });
6726
- }
6727
- };
6728
- this.#historyRecovery = recovery().finally(() => {
6729
- this.#historyRecovery = void 0;
6730
- if (!this.#disposed) this.#history.publish();
6731
- });
6732
- return this.#historyRecovery;
6148
+ async delete(flowId) {
6149
+ const flow = this.flow(flowId);
6150
+ if (flow == null || flow.status == "retiring") return false;
6151
+ try {
6152
+ await this.#client.deleteFlow(flowId);
6153
+ if (this.#disposed) return false;
6154
+ this.#remove(flowId);
6155
+ this.#setNotice({
6156
+ kind: "success",
6157
+ message: this.#i18n.t("notice.flowDeleteAccepted", { name: flow.name })
6158
+ });
6159
+ return true;
6160
+ } catch (error) {
6161
+ if (!this.#disposed) this.#setNotice(errorNotice(error, this.#i18n.t));
6162
+ return false;
6163
+ }
6733
6164
  }
6734
- async #checkDraft() {
6735
- if (this.#disposed) return;
6736
- const flowId = this.#model.value.flowId;
6737
- const draft = this.#model.value.draft;
6738
- if (flowId == null || draft == null) {
6739
- if (this.#model.value.draft == null) this.#set({
6740
- checkLoading: false,
6741
- diagnostics: void 0
6165
+ async rename(flowId, name) {
6166
+ const flow = this.flow(flowId);
6167
+ const nextName = name.trim();
6168
+ if (flow == null || nextName.length == 0) return false;
6169
+ if (flow.name == nextName) return true;
6170
+ try {
6171
+ const changed = await this.#client.renameFlow(flowId, nextName);
6172
+ if (this.#disposed) return false;
6173
+ this.include(changed);
6174
+ this.#setNotice({
6175
+ kind: "success",
6176
+ message: this.#i18n.t("notice.flowRenamed", { name: nextName })
6742
6177
  });
6178
+ return true;
6179
+ } catch (error) {
6180
+ if (!this.#disposed) this.#setNotice(errorNotice(error, this.#i18n.t));
6181
+ return false;
6182
+ }
6183
+ }
6184
+ include(flow) {
6185
+ const index = this.#state.value.flows.findIndex((candidate) => candidate.flowId == flow.flowId);
6186
+ if (index < 0) {
6187
+ this.#set({ flows: [...this.#state.value.flows, flow] });
6743
6188
  return;
6744
6189
  }
6190
+ const referenceCount = this.#state.value.flows[index].referenceCount;
6191
+ this.#set({ flows: this.#state.value.flows.with(index, {
6192
+ ...flow,
6193
+ ...referenceCount == null ? {} : { referenceCount }
6194
+ }) });
6195
+ }
6196
+ #insert(flow) {
6197
+ if (this.#state.value.flows.some((candidate) => candidate.flowId == flow.flowId)) return;
6745
6198
  this.#set({
6746
- checkLoading: true,
6747
- diagnosticFocus: void 0
6199
+ flows: [...this.#state.value.flows, flow],
6200
+ total: this.#state.value.total == null ? void 0 : this.#state.value.total + 1
6748
6201
  });
6749
- try {
6750
- const diagnostics = await this.#client.checkFlow(flowId, draft.revisionId);
6751
- if (!this.#disposed && flowId == this.#model.value.flowId && draft.revisionId == this.#model.value.draft?.revisionId) {
6752
- const live = this.#model.value.live;
6753
- this.#set({
6754
- diagnostics,
6755
- live: live == null ? void 0 : {
6756
- ...live,
6757
- hasUnpublishedChanges: live.publication == null || live.publication.closureDigest != diagnostics.closureDigest
6758
- }
6759
- });
6760
- }
6761
- } catch (error) {
6762
- if (!this.#disposed && flowId == this.#model.value.flowId && draft.revisionId == this.#model.value.draft?.revisionId) this.#setNotice(errorNotice(error, this.#i18n.t));
6763
- } finally {
6764
- if (!this.#disposed && flowId == this.#model.value.flowId && draft.revisionId == this.#model.value.draft?.revisionId) this.#set({ checkLoading: false });
6765
- }
6766
6202
  }
6767
- async #refreshDraft(revisionId) {
6203
+ #remove(flowId) {
6204
+ this.#set({
6205
+ flows: this.#state.value.flows.filter((flow) => flow.flowId != flowId),
6206
+ total: this.#state.value.total == null ? void 0 : this.#state.value.total - 1
6207
+ });
6208
+ }
6209
+ advanceHead(flowId, revisionId, content) {
6210
+ this.#set({ flows: this.#state.value.flows.map((flow) => flow.flowId == flowId ? {
6211
+ ...flow,
6212
+ draftRevisionId: revisionId,
6213
+ resourceReferences: {
6214
+ ...flow.resourceReferences,
6215
+ draft: flowResourceReferences(content)
6216
+ }
6217
+ } : flow) });
6218
+ }
6219
+ #set(patch) {
6220
+ if (!this.#disposed) this.#state.set({
6221
+ ...this.#state.value,
6222
+ ...patch
6223
+ });
6224
+ }
6225
+ };
6226
+ //#endregion
6227
+ //#region src/workbench/browser/runtime/stores/nodeEdits.ts
6228
+ var NodeEdits = class {
6229
+ constructor(revision, save, identity) {
6230
+ this.revision = revision;
6231
+ this.save = save;
6232
+ this.identity = identity;
6233
+ }
6234
+ async saveErrorSources(nodeId, value) {
6235
+ const node = this.revision.value?.graph()?.nodes[nodeId];
6236
+ if (node?.kind != "error" || dequal$1(node.sourceFlowIds ?? [], value)) return false;
6237
+ return await this.save([{
6238
+ kind: "graph.trigger.sources.set",
6239
+ nodeId,
6240
+ before: node.sourceFlowIds,
6241
+ value: value.length == 0 ? void 0 : value
6242
+ }]);
6243
+ }
6244
+ async saveNodeSettings(nodeId, settings) {
6245
+ const revision = this.revision.value;
6246
+ if (revision == null) return false;
6247
+ const changes = updateNodeSettings(revision, nodeId, settings);
6248
+ return changes != null && await this.save(changes);
6249
+ }
6250
+ async saveNodeDescription(nodeId, description) {
6251
+ const revision = this.revision.value;
6252
+ if (revision == null) return false;
6253
+ const changes = updateNodeDescription(revision, nodeId, description);
6254
+ return changes != null && await this.save(changes);
6255
+ }
6256
+ async saveNodeIcon(nodeId, icon) {
6257
+ const revision = this.revision.value;
6258
+ if (revision == null) return false;
6259
+ const changes = updateNodeIcon(revision, nodeId, icon);
6260
+ return changes != null && await this.save(changes);
6261
+ }
6262
+ async saveNodeTitle(nodeId, title) {
6263
+ const revision = this.revision.value;
6264
+ if (revision == null) return false;
6265
+ const changes = updateNodeName(revision, nodeId, title);
6266
+ return changes != null && await this.save(changes);
6267
+ }
6268
+ async setInputValue(nodeId, handle, value, deletion) {
6269
+ const revision = this.revision.value;
6270
+ if (revision == null) return false;
6271
+ const changes = setInputValue(revision, nodeId, handle, value);
6272
+ return changes != null && await this.save(changes, deletion);
6273
+ }
6274
+ async resetInputs(nodeId, handles) {
6275
+ const revision = this.revision.value;
6276
+ if (revision == null) return false;
6277
+ return await this.save(resetInputValues(revision.revision.content, nodeId, handles));
6278
+ }
6279
+ async saveOutputsDefs(nodeId, definitions, deletion, values) {
6280
+ const revision = this.revision.value;
6281
+ if (revision == null || revision.graph().nodes[nodeId]?.kind != "outputs") return false;
6282
+ return await this.save(updateOutputPorts(revision, nodeId, definitions, values), deletion);
6283
+ }
6284
+ async saveStartInputDefs(nodeId, inputDefs, deletion) {
6285
+ const revision = this.revision.value;
6286
+ if (revision == null || revision.graph().nodes[nodeId]?.kind != "start") return false;
6287
+ const changes = updateStartInputDefs(revision.revision.content, nodeId, inputDefs);
6288
+ return await this.save(changes, deletion);
6289
+ }
6290
+ async resetTriggerConfig(triggerId, names) {
6291
+ const revision = this.revision.value;
6292
+ if (revision == null) return false;
6293
+ const trigger = revision.graph()?.nodes[triggerId];
6294
+ if (trigger?.kind !== "poll" && trigger?.kind !== "integration") return false;
6295
+ const changes = (names == null ? Object.entries(trigger.config) : names.flatMap((name) => Object.hasOwn(trigger.config, name) ? [[name, trigger.config[name]]] : [])).map(([name, before]) => ({
6296
+ kind: "graph.trigger.config.set",
6297
+ nodeId: triggerId,
6298
+ name,
6299
+ before,
6300
+ value: void 0
6301
+ }));
6302
+ return await this.save(changes);
6303
+ }
6304
+ async setInputSource(nodeId, handle, source) {
6305
+ const revision = this.revision.value;
6306
+ if (revision == null) return false;
6307
+ return await this.save(setInputSources(revision.revision.content, nodeId, handle, [{
6308
+ kind: "node",
6309
+ ...source
6310
+ }]));
6311
+ }
6312
+ async setInputVariable(nodeId, handle, name) {
6313
+ const revision = this.revision.value;
6314
+ if (revision == null) return false;
6315
+ const changes = name == null ? setInputValue(revision, nodeId, handle, void 0) : setInputVariable(revision, nodeId, handle, name, this.identity());
6316
+ return changes != null && await this.save(changes);
6317
+ }
6318
+ async saveCondition(nodeId, settings, deletion) {
6319
+ const revision = this.revision.value;
6320
+ if (revision == null) return false;
6321
+ const changes = updateCondition(revision, nodeId, settings);
6322
+ return changes != null && await this.save(changes, deletion);
6323
+ }
6324
+ async saveValue(nodeId, values, deletion) {
6325
+ const revision = this.revision.value;
6326
+ if (revision == null) return false;
6327
+ const changes = updateValue(revision, nodeId, values);
6328
+ return changes != null && await this.save(changes, deletion);
6329
+ }
6330
+ async saveResolution(nodeId, settings, deletion, values) {
6331
+ const revision = this.revision.value;
6332
+ if (revision == null) return false;
6333
+ const changes = updateResolution(revision, nodeId, settings, values);
6334
+ return changes != null && await this.save(changes, deletion);
6335
+ }
6336
+ async saveTaskSettings(nodeId, settings, deletion) {
6337
+ const revision = this.revision.value;
6338
+ if (revision == null) return false;
6339
+ const changes = updateTask(revision, nodeId, settings);
6340
+ return changes != null && await this.save(changes, deletion);
6341
+ }
6342
+ async saveTaskPorts(nodeId, ports, deletion, values) {
6343
+ const revision = this.revision.value;
6344
+ if (revision == null) return false;
6345
+ const changes = updateTaskPorts(revision, nodeId, ports, values);
6346
+ return changes != null && await this.save(changes, deletion);
6347
+ }
6348
+ async saveTaskAdditionalInputs(nodeId, inputs, deletion, values) {
6349
+ const revision = this.revision.value;
6350
+ if (revision == null) return false;
6351
+ const changes = updateTaskAdditionalInputs(revision, nodeId, inputs, values);
6352
+ return changes != null && await this.save(changes, deletion);
6353
+ }
6354
+ async setConnectorConnection(nodeId, connectionId) {
6355
+ const revision = this.revision.value;
6356
+ if (revision == null) return false;
6357
+ const changes = setConnectorConnection(revision.revision.content, nodeId, connectionId);
6358
+ return changes != null && await this.save(changes);
6359
+ }
6360
+ async setServiceConnections(providerId, connectionId, previousConnectionId) {
6361
+ const revision = this.revision.value;
6362
+ if (revision == null) return false;
6363
+ const changes = setServiceConnections(revision.revision.content, providerId, connectionId, previousConnectionId);
6364
+ return changes.length == 0 || await this.save(changes);
6365
+ }
6366
+ async setCodeActions(nodeId, capabilities) {
6367
+ const revision = this.revision.value;
6368
+ if (revision == null) return false;
6369
+ const changes = setCodeActions(revision.revision.content, nodeId, capabilities);
6370
+ return changes == null || await this.save(changes);
6371
+ }
6372
+ async setTriggerEventSource(triggerId, source) {
6373
+ const revision = this.revision.value;
6374
+ if (revision == null) return false;
6375
+ const changes = setTriggerEventSource(revision, triggerId, source);
6376
+ return changes != null && await this.save(changes);
6377
+ }
6378
+ async saveTriggerConfig(triggerId, name, value) {
6379
+ const revision = this.revision.value;
6380
+ if (revision == null) return false;
6381
+ const changes = updateTriggerConfig(revision, triggerId, name, value);
6382
+ return changes != null && await this.save(changes);
6383
+ }
6384
+ async saveTriggerSchedule(triggerId, schedule) {
6385
+ const revision = this.revision.value;
6386
+ if (revision == null) return false;
6387
+ const changes = updateTriggerSchedule(revision.revision.content, triggerId, schedule);
6388
+ return changes != null && await this.save(changes);
6389
+ }
6390
+ async saveWebhook(triggerId, settings, deletion) {
6391
+ const revision = this.revision.value;
6392
+ if (revision == null) return false;
6393
+ const changes = updateWebhook(revision, triggerId, settings);
6394
+ return changes != null && await this.save(changes, deletion);
6395
+ }
6396
+ async setTriggerConnection(triggerId, connectionId) {
6397
+ const revision = this.revision.value;
6398
+ if (revision == null) return false;
6399
+ const changes = setTriggerConnection(revision, triggerId, connectionId);
6400
+ return changes != null && await this.save(changes);
6401
+ }
6402
+ };
6403
+ //#endregion
6404
+ //#region src/workbench/browser/runtime/stores/workspaceStore.ts
6405
+ var WorkspaceStore = class {
6406
+ #edits;
6407
+ #canvasCommandListeners;
6408
+ #client;
6409
+ #i18n;
6410
+ #identity;
6411
+ #flows;
6412
+ #runChanged;
6413
+ #setNotice;
6414
+ #model;
6415
+ #clipboard;
6416
+ #diagnosticFocusId;
6417
+ #disposed;
6418
+ #started;
6419
+ #nodeFocusId;
6420
+ #pendingRepair;
6421
+ #stopCatalogWatch;
6422
+ #stopFlowWatch;
6423
+ constructor(client, setNotice, identity = createAuthoringId, i18n = createI18n(), runChanged = () => {}, catalogs = new CatalogStores(client), flowCreated = () => {}, accessChanged = () => {}, filterTriggerConnections) {
6424
+ this.catalogs = catalogs;
6425
+ this.flowCreated = flowCreated;
6426
+ this.accessChanged = accessChanged;
6427
+ this.filterTriggerConnections = filterTriggerConnections;
6428
+ this.#canvasCommandListeners = /* @__PURE__ */ new Set();
6429
+ this.notify = (notice) => {
6430
+ if (!this.#disposed) this.#setNotice(notice);
6431
+ };
6432
+ this.#diagnosticFocusId = 0;
6433
+ this.#disposed = false;
6434
+ this.#started = false;
6435
+ this.#nodeFocusId = 0;
6436
+ this.subscribeCanvasCommands = (execute) => {
6437
+ this.#canvasCommandListeners.add(execute);
6438
+ return () => {
6439
+ this.#canvasCommandListeners.delete(execute);
6440
+ };
6441
+ };
6442
+ this.#client = client;
6443
+ this.#setNotice = setNotice;
6444
+ this.#identity = identity;
6445
+ this.#clipboard = new CanvasClipboard(identity, i18n.t);
6446
+ this.#i18n = i18n;
6447
+ this.#runChanged = runChanged;
6448
+ this.#flows = new FlowCatalog(client, setNotice, i18n);
6449
+ this.#model = new WorkspaceModel(i18n, this.#flows);
6450
+ this.#edits = new EditSession(client, this.#model, this.#flows, setNotice, i18n);
6451
+ this.history$ = this.#edits.history$;
6452
+ this.$ = this.#model.$;
6453
+ this.nodes = new NodeEdits(this.$.revision, async (changes, deletion) => await this.#edits.canvasChange("edit", 1, changes, void 0, void 0, deletion) && this.#model.value.draft != null, identity);
6454
+ }
6455
+ dispose() {
6456
+ this.catalogs.dispose();
6457
+ this.#disposed = true;
6458
+ this.#edits.dispose();
6459
+ this.#stopCatalogWatch?.();
6460
+ this.#stopFlowWatch?.();
6461
+ this.#canvasCommandListeners.clear();
6462
+ this.#model.dispose();
6463
+ this.#flows.dispose();
6464
+ }
6465
+ async start(flowId) {
6466
+ this.#started = false;
6467
+ await this.selectFlow(flowId);
6468
+ this.#started = !this.#disposed;
6469
+ }
6470
+ async #loadFlowCatalog() {
6471
+ if (this.#flows.loaded && this.#stopCatalogWatch != null) return;
6472
+ let initialLoad;
6473
+ if (this.#stopCatalogWatch == null) {
6474
+ const subscription = this.#client.watchFlowCatalog((event) => {
6475
+ if (this.#disposed) return;
6476
+ this.reloadFlows();
6477
+ if (event?.kind == "flow.created" && this.#started && this.#model.value.flowId == null && this.#model.value.busy == null) this.flowCreated(event.flowId);
6478
+ });
6479
+ this.#stopCatalogWatch = subscription.stop;
6480
+ subscription.ready.then(async () => {
6481
+ if (initialLoad == null || this.#disposed) return;
6482
+ await initialLoad;
6483
+ if (!this.#disposed) await this.reloadFlows();
6484
+ });
6485
+ await Promise.resolve();
6486
+ }
6768
6487
  if (this.#disposed) return;
6488
+ initialLoad = this.reloadFlows();
6489
+ await initialLoad;
6490
+ }
6491
+ async reloadFlows() {
6492
+ await this.#flows.reload();
6493
+ }
6494
+ async setFlowEnabled(flow, enabled) {
6495
+ await this.#flows.setEnabled(flow, enabled);
6496
+ }
6497
+ async publishFlow(flow) {
6498
+ await this.#flows.publish(flow);
6499
+ }
6500
+ async loadMoreFlows() {
6501
+ await this.#flows.loadMore();
6502
+ }
6503
+ async selectFlow(flowId) {
6504
+ if (this.#edits.applying) return false;
6505
+ if (!await this.saveModuleEditor() || this.#disposed) return false;
6506
+ this.#pendingRepair = void 0;
6507
+ const current = this.#edits.begin();
6508
+ this.#stopFlowWatch?.();
6509
+ this.#stopFlowWatch = void 0;
6510
+ this.#edits.set({
6511
+ checkLoading: false,
6512
+ diagnosticFocus: void 0,
6513
+ diagnostics: void 0,
6514
+ draft: void 0,
6515
+ live: void 0,
6516
+ moduleEditor: void 0,
6517
+ nodeFocus: void 0,
6518
+ presentation: void 0,
6519
+ flowId,
6520
+ selectedNodeIds: [],
6521
+ workspaceLoadFailed: false,
6522
+ workspaceLoadProblem: void 0,
6523
+ workspaceLoading: flowId != null,
6524
+ workspaceRepairing: false
6525
+ });
6526
+ if (flowId == null) {
6527
+ await this.#loadFlowCatalog();
6528
+ return true;
6529
+ }
6530
+ try {
6531
+ let invalidated = false;
6532
+ let pendingRevision;
6533
+ const changed = (revisionId) => {
6534
+ if (!current()) return;
6535
+ if (this.#edits.committed == null) {
6536
+ invalidated = true;
6537
+ pendingRevision = revisionId;
6538
+ } else if (revisionId != this.#edits.committed.revisionId) this.#edits.refreshDraft(revisionId);
6539
+ };
6540
+ const subscription = this.#client.watchFlow(flowId, changed, (event) => {
6541
+ if (current()) this.#runChanged(event);
6542
+ }, (accessRevision) => {
6543
+ if (current()) {
6544
+ this.accessChanged(flowId, accessRevision);
6545
+ this.#refreshLive(flowId, current);
6546
+ }
6547
+ }, (command) => {
6548
+ if (current() && !this.#model.value.workspaceLoading) for (const execute of this.#canvasCommandListeners) execute(command);
6549
+ });
6550
+ this.#stopFlowWatch = subscription.stop;
6551
+ let reading = false;
6552
+ subscription.ready.then(() => {
6553
+ if (reading) changed();
6554
+ }, (error) => {
6555
+ if (!current()) return;
6556
+ subscription.stop();
6557
+ this.#stopFlowWatch = void 0;
6558
+ this.#setNotice(errorNotice(error, this.#i18n.t));
6559
+ });
6560
+ await Promise.resolve();
6561
+ if (!current()) return false;
6562
+ reading = true;
6563
+ let editor = await this.#client.getEditor(flowId);
6564
+ for (let attempt = 0; current() && Object.values(revisionView(editor.draft).graph().nodes).some((node) => node.kind == "manual"); attempt += 1) {
6565
+ if (attempt >= 3) throw new ApiError(409, controlErrorCode.flowRevisionConflict, "The Draft changed while upgrading its Start node.");
6566
+ try {
6567
+ await this.#client.upgradeDraft(flowId, editor.draft.revisionId, { idempotencyKey: this.#identity() });
6568
+ } catch (error) {
6569
+ if (!(error instanceof ApiError) || error.code !== controlErrorCode.flowRevisionConflict || attempt >= 2) throw error;
6570
+ }
6571
+ if (!current()) return false;
6572
+ editor = await this.#client.getEditor(flowId);
6573
+ }
6574
+ const { flow, draft, live, presentation } = editor;
6575
+ if (!current()) return false;
6576
+ this.#edits.reset(draft, presentation);
6577
+ this.#flows.include(flow);
6578
+ this.#edits.set({
6579
+ draft,
6580
+ live,
6581
+ presentation,
6582
+ workspaceLoadFailed: false,
6583
+ workspaceLoadProblem: void 0
6584
+ });
6585
+ await this.#edits.repairDraftNodeNames(current);
6586
+ if (!current()) return false;
6587
+ this.#edits.set({ workspaceLoading: false });
6588
+ if (invalidated && pendingRevision != draft.revisionId) this.#edits.refreshDraft(pendingRevision);
6589
+ } catch (error) {
6590
+ if (!current()) return false;
6591
+ this.#stopFlowWatch?.();
6592
+ this.#stopFlowWatch = void 0;
6593
+ const kind = error instanceof ApiError && error.code == controlErrorCode.flowUpgradeRequired ? "upgrade" : error instanceof ApiError && (error.code == controlErrorCode.flowRepairRequired || error.code == controlErrorCode.flowInvalid) ? "repair" : "failed";
6594
+ this.#edits.set({
6595
+ workspaceLoadFailed: true,
6596
+ workspaceLoadProblem: {
6597
+ kind,
6598
+ ...kind == "failed" ? { message: errorNotice(error, this.#i18n.t).message } : {}
6599
+ },
6600
+ workspaceLoading: false
6601
+ });
6602
+ return false;
6603
+ }
6604
+ return true;
6605
+ }
6606
+ async repairWorkspace() {
6769
6607
  const flowId = this.#model.value.flowId;
6770
- if (flowId == null) return;
6771
- this.#draftInvalidation += 1;
6772
- if (revisionId != null) this.#draftUpdateNotice = true;
6773
- if (this.#draftSyncQueued) return;
6774
- this.#draftSyncQueued = true;
6775
- const context = {
6776
- current: this.#draftSession.capture(),
6777
- flowId
6778
- };
6779
- await this.#draftChanges.enqueue(async () => {
6780
- let generation;
6781
- do {
6782
- generation = this.#draftInvalidation;
6783
- const notifyUpdate = this.#draftUpdateNotice;
6784
- this.#draftUpdateNotice = false;
6785
- await this.#syncDraftHead(context, false, notifyUpdate);
6786
- } while (this.#isDraftChangeCurrent(context) && generation != this.#draftInvalidation);
6608
+ if (flowId == null || this.#model.value.workspaceRepairing) return;
6609
+ const current = this.#edits.capture();
6610
+ this.#edits.set({
6611
+ workspaceRepairing: true,
6612
+ workspaceLoadProblem: this.#model.value.workspaceLoadProblem
6613
+ });
6614
+ try {
6615
+ let repair = this.#pendingRepair;
6616
+ if (repair == null) {
6617
+ const flow = this.#flows.flow(flowId) ?? await this.#client.getFlow(flowId);
6618
+ if (!current()) return;
6619
+ repair = this.#pendingRepair = {
6620
+ changeId: this.#identity(),
6621
+ expectedRevisionId: flow.draftRevisionId
6622
+ };
6623
+ }
6624
+ await this.#client.repairDraft(flowId, repair.expectedRevisionId, repair.changeId);
6625
+ if (!current()) return;
6626
+ this.#pendingRepair = void 0;
6627
+ await this.selectFlow(flowId);
6628
+ } catch (error) {
6629
+ if (this.#disposed || !current()) return;
6630
+ if (error instanceof ApiError && error.code == controlErrorCode.flowRevisionConflict) {
6631
+ this.#pendingRepair = void 0;
6632
+ await this.selectFlow(flowId);
6633
+ return;
6634
+ }
6635
+ this.#edits.set({
6636
+ workspaceLoadProblem: {
6637
+ kind: this.#model.value.workspaceLoadProblem?.kind == "upgrade" ? "upgrade" : "repair",
6638
+ message: errorNotice(error, this.#i18n.t).message
6639
+ },
6640
+ workspaceRepairing: false
6641
+ });
6642
+ }
6643
+ }
6644
+ async #refreshLive(flowId, current) {
6645
+ try {
6646
+ const live = await this.#client.getLive(flowId);
6647
+ if (current() && this.#model.value.flowId == flowId) this.#edits.set({ live });
6648
+ } catch (error) {
6649
+ if (current() && this.#model.value.flowId == flowId) this.#setNotice(errorNotice(error, this.#i18n.t));
6650
+ }
6651
+ }
6652
+ selectNodes(nodeIds) {
6653
+ return this.#edits.selectNodes(nodeIds);
6654
+ }
6655
+ async exportFlow(flowId) {
6656
+ const current = this.#edits.capture();
6657
+ const selected = this.#model.value.flowId == flowId;
6658
+ if (selected && (!await this.#edits.flush() || !current())) {
6659
+ this.#setNotice({
6660
+ kind: "error",
6661
+ message: this.#i18n.t("notice.exportSaveFailed")
6662
+ });
6663
+ return;
6664
+ }
6665
+ this.#edits.set({ busy: "flow" });
6666
+ try {
6667
+ const file = await this.#client.exportFlow(flowId);
6668
+ if (this.#disposed || selected && !current()) return;
6669
+ const url = URL.createObjectURL(new Blob([encodeWorkflowFile(file)], { type: "application/json;charset=utf-8" }));
6670
+ const link = document.createElement("a");
6671
+ link.href = url;
6672
+ link.download = workflowFileName(file.name ?? "workflow");
6673
+ link.click();
6674
+ setTimeout(() => URL.revokeObjectURL(url), 0);
6675
+ } catch (error) {
6676
+ if (!this.#disposed) this.#setNotice(errorNotice(error, this.#i18n.t));
6677
+ } finally {
6678
+ this.#edits.set({ busy: void 0 });
6679
+ }
6680
+ }
6681
+ createFlow(name, create) {
6682
+ return this.#createFlow(() => this.#flows.create(name, create));
6683
+ }
6684
+ importFlow(file, name, key, importer) {
6685
+ return this.#createFlow(() => this.#flows.import(file, name, key, importer));
6686
+ }
6687
+ async #createFlow(create) {
6688
+ if (!await this.saveModuleEditor()) return;
6689
+ this.#edits.set({ busy: "flow" });
6690
+ try {
6691
+ return await create();
6692
+ } finally {
6693
+ this.#edits.set({ busy: void 0 });
6694
+ }
6695
+ }
6696
+ getFlowReferences(flowId, options = {}) {
6697
+ return this.#client.getFlowReferences(flowId, {
6698
+ ...options,
6699
+ direction: "incoming",
6700
+ limit: 50
6787
6701
  });
6788
- if (this.#isDraftChangeCurrent(context)) this.#draftSyncQueued = false;
6789
6702
  }
6790
- async #syncDraftHead(context, reportError, notifyUpdate = false) {
6703
+ getErrorListeners(flowId, signal) {
6704
+ return this.#client.getErrorListeners(flowId, signal);
6705
+ }
6706
+ async deleteFlow(flowId) {
6707
+ if (!await this.saveModuleEditor()) return false;
6708
+ this.#edits.set({ busy: "flow" });
6791
6709
  try {
6792
- const base = this.#draftChanges.committed;
6793
- if (base == null) return false;
6794
- const synced = await this.#client.syncDraft(context.flowId);
6795
- if (!this.#isDraftChangeCurrent(context)) return false;
6796
- const committed = synced.draft;
6797
- if (committed.revisionId == base.revisionId) return true;
6798
- if (this.#history.clear()) this.#setNotice({
6799
- kind: "success",
6800
- message: this.#i18n.t("history.external")
6801
- });
6802
- const draft = this.#draftChanges.replaceCommitted(committed);
6803
- const preserveModuleEditor = this.#applyDraft(draft, "external");
6804
- this.#flows.advanceHead(context.flowId, committed.revisionId, committed.content);
6805
- if (notifyUpdate) this.#setNotice({
6806
- kind: preserveModuleEditor ? "error" : "success",
6807
- message: this.#i18n.t(preserveModuleEditor ? "notice.moduleUpdated" : "notice.draftUpdated")
6808
- });
6809
- this.#checkDraft();
6810
- return true;
6811
- } catch (error) {
6812
- if (reportError && this.#isDraftChangeCurrent(context)) this.#setNotice(errorNotice(error, this.#i18n.t));
6813
- return false;
6710
+ return await this.#flows.delete(flowId);
6711
+ } finally {
6712
+ this.#edits.set({ busy: void 0 });
6814
6713
  }
6815
6714
  }
6816
- #designer() {
6817
- const state = this.#model.value;
6818
- return designerGraph(state.draft, state.presentation?.value, state.diagnostics?.diagnostics, {}, {}, this.#i18n.t);
6715
+ async renameFlow(flowId, name) {
6716
+ this.#edits.set({ busy: "flow" });
6717
+ try {
6718
+ return await this.#flows.rename(flowId, name);
6719
+ } finally {
6720
+ this.#edits.set({ busy: void 0 });
6721
+ }
6819
6722
  }
6820
- #reconcileRevision(draft) {
6723
+ async addNode(option, position, connection, relatedChanges) {
6724
+ if (!await this.saveModuleEditor()) return;
6725
+ const draft = this.#model.value.draft;
6726
+ if (draft == null) return;
6727
+ const nodeId = this.#identity();
6728
+ if (option.kind == "comment") return await this.#addComment(nodeId, position);
6821
6729
  const revision = revisionView(draft);
6822
- return {
6823
- revision,
6824
- selectedNodeIds: this.#model.value.selectedNodeIds.filter((nodeId) => revision.selection(nodeId) != null)
6825
- };
6730
+ const intent = addNodeIntent(option, revision, this.#i18n.t);
6731
+ if (intent == null) return;
6732
+ const edge = connection?.(nodeId);
6733
+ const created = addNode(revision, nodeId, intent);
6734
+ const nodeChanges = created == null ? void 0 : [...created, ...relatedChanges?.(nodeId, revision) ?? []];
6735
+ if (nodeChanges == null) return;
6736
+ const changes = edge == null ? nodeChanges : [...nodeChanges, ...connect(applyFlowChanges$1(draft, nodeChanges).content, {
6737
+ source: edge.source,
6738
+ target: edge.target,
6739
+ ...edge.sourceHandle.startsWith("$branch:") ? { sourceHandle: edge.sourceHandle.slice(8) } : {}
6740
+ })];
6741
+ if (!await this.#edits.canvasChange("add", 1, changes, (value) => setNodePositions(value, { [nodeId]: position }), [nodeId])) return;
6742
+ if (this.#disposed) return;
6743
+ this.#edits.set({ nodeFocus: {
6744
+ nodeId,
6745
+ requestId: ++this.#nodeFocusId
6746
+ } });
6747
+ if (intent.kind == "provider-trigger" && intent.connectionId == null) this.#configureAddedTrigger(draft.flowId, nodeId, intent.definition);
6748
+ return nodeId;
6826
6749
  }
6827
- #isDraftChangeCurrent(context) {
6828
- return !this.#disposed && context.flowId == this.#model.value.flowId && context.current();
6750
+ async addWebhookResponseNode(triggerId) {
6751
+ const option = this.$.addNodeOptions.value.find((item) => item.kind === "webhook-response");
6752
+ const position = this.#designer().nodes.find((node) => node.id === triggerId)?.position;
6753
+ if (option == null || position == null) return;
6754
+ return this.addNode(option, {
6755
+ x: position.x + 320,
6756
+ y: position.y
6757
+ }, void 0, (nodeId, revision) => selectWebhookResponse(revision, triggerId, nodeId) ?? []);
6829
6758
  }
6830
- #set(patch) {
6831
- if (this.#disposed) return;
6832
- const editor = Object.hasOwn(patch, "moduleEditor") ? patch.moduleEditor : this.#model.value.moduleEditor;
6833
- this.#model.set({
6834
- ...patch,
6835
- ...this.#modules.state(editor)
6759
+ async #configureAddedTrigger(flowId, nodeId, definition) {
6760
+ const current = this.#edits.capture();
6761
+ const original = this.$.revision.value?.graph().nodes[nodeId];
6762
+ const unchanged = () => current() && !this.#disposed && this.$.revision.value?.graph().nodes[nodeId] === original;
6763
+ try {
6764
+ const connections = await resourceValue(this.catalogs.connections.get(definition.provider, flowId));
6765
+ if (!unchanged()) return;
6766
+ const allowed = this.filterTriggerConnections == null ? connections : await this.filterTriggerConnections(flowId, definition, connections);
6767
+ if (!unchanged()) return;
6768
+ const connection = connectionCatalog(allowed).preferred;
6769
+ if (connection == null) return;
6770
+ const revision = this.$.revision.value;
6771
+ if (revision == null) return;
6772
+ const changes = setTriggerConnection(revision, nodeId, connection.connectionId);
6773
+ if (changes != null) await this.#edits.finishNodeCreation(nodeId, changes);
6774
+ } catch (error) {
6775
+ if (unchanged()) this.#setNotice(errorNotice(error, this.#i18n.t));
6776
+ }
6777
+ }
6778
+ async connect(edge) {
6779
+ const revision = this.$.revision.value;
6780
+ if (revision == null) return;
6781
+ const changes = connect(revision.revision.content, {
6782
+ source: edge.source,
6783
+ target: edge.target,
6784
+ ...edge.sourceHandle.startsWith("$branch:") ? { sourceHandle: edge.sourceHandle.slice(8) } : {}
6785
+ });
6786
+ if (changes.length > 0) await this.#edits.canvasChange("connect", 1, changes);
6787
+ }
6788
+ async disconnect(edge) {
6789
+ const revision = this.$.revision.value;
6790
+ if (revision == null) return;
6791
+ const changes = disconnect(revision.revision.content, {
6792
+ source: edge.source,
6793
+ target: edge.target,
6794
+ ...edge.sourceHandle.startsWith("$branch:") ? { sourceHandle: edge.sourceHandle.slice(8) } : {}
6836
6795
  });
6796
+ if (changes.length > 0) await this.#edits.canvasChange("disconnect", 1, changes);
6797
+ }
6798
+ async deleteSelectedNodes() {
6799
+ if (!await this.saveModuleEditor()) return;
6800
+ const revision = this.$.revision.value;
6801
+ if (revision == null || this.#model.value.selectedNodeIds.length == 0) return;
6802
+ const selectedNodeIds = [...this.#model.value.selectedNodeIds];
6803
+ const comments = commentIds(this.#model.value.presentation?.value ?? {});
6804
+ const commentNodes = new Set(this.#model.value.selectedNodeIds.filter((nodeId) => comments.has(nodeId)));
6805
+ const changes = deleteSelection(revision, this.#model.value.selectedNodeIds);
6806
+ await this.#edits.canvasChange("delete", this.#model.value.selectedNodeIds.length, changes, (value) => {
6807
+ let next = commentNodes.size == 0 ? value : removeComments(value, commentNodes);
6808
+ for (const nodeId of selectedNodeIds) next = setNodeContentHidden(next, nodeId, false);
6809
+ return next;
6810
+ }, []);
6811
+ }
6812
+ copySelectedNodes() {
6813
+ const revision = this.$.revision.value;
6814
+ if (revision == null || this.#model.value.selectedNodeIds.length == 0) return;
6815
+ this.#clipboard.copy(revision, this.#designer(), this.#model.value.selectedNodeIds);
6816
+ }
6817
+ async pasteNodes(sourcePositions, offset) {
6818
+ if (!await this.saveModuleEditor()) return;
6819
+ const revision = this.$.revision.value;
6820
+ if (revision == null) return;
6821
+ const pasted = this.#clipboard.paste(revision, this.#designer(), sourcePositions, offset);
6822
+ if (pasted != null) await this.#edits.canvasChange("paste", pasted.nodeIds.length, pasted.changes, pasted.update, pasted.nodeIds);
6823
+ }
6824
+ async duplicateSelectedNodes(positions, offset) {
6825
+ this.copySelectedNodes();
6826
+ await this.pasteNodes(positions, offset);
6827
+ }
6828
+ async saveNodeContentHidden(nodeId, hidden) {
6829
+ const node = this.#designer().nodes.find((candidate) => candidate.id == nodeId);
6830
+ if (node == null || node.kind == "condition") return;
6831
+ await this.#edits.canvasChange("edit", 1, [], (value) => setNodeContentHidden(value, nodeId, hidden));
6832
+ }
6833
+ async saveComment(nodeId, comment) {
6834
+ if (this.#model.value.draft == null) return;
6835
+ const position = this.#designer().nodes.find((node) => node.id == nodeId)?.position;
6836
+ if (position == null) return;
6837
+ await this.#edits.canvasChange("edit", 1, [], (value) => setComment(value, nodeId, {
6838
+ ...comment,
6839
+ position
6840
+ }));
6841
+ }
6842
+ async listWorkflowTargets(signal) {
6843
+ const flowId = this.$.revision.value?.revision.flowId;
6844
+ if (flowId == null) return [];
6845
+ const candidates = [];
6846
+ let cursor;
6847
+ do {
6848
+ const page = await this.#client.listFlows({
6849
+ cursor,
6850
+ limit: 100,
6851
+ signal
6852
+ });
6853
+ candidates.push(...page.flows.filter((flow) => flow.flowId != flowId).map((flow) => workflowCandidate(flow)));
6854
+ cursor = page.nextCursor;
6855
+ } while (cursor != null);
6856
+ return candidates;
6857
+ }
6858
+ loadWorkflowContract(flowId, signal) {
6859
+ return this.#client.getWorkflowContract(flowId, signal);
6860
+ }
6861
+ loadOpenApiDocument(url, signal) {
6862
+ return this.#client.loadOpenApiDocument(url, signal);
6863
+ }
6864
+ get eventSourceClient() {
6865
+ return this.#client;
6866
+ }
6867
+ async loadEventSources(signal) {
6868
+ const flowId = this.#model.value.flowId;
6869
+ if (flowId == null) throw new Error("No Flow selected");
6870
+ return await this.#client.listEventSources(flowId, signal);
6871
+ }
6872
+ loadTriggerConfigOptions(triggerId, field, signal) {
6873
+ return this.#edits.loadTriggerConfigOptions(triggerId, field, signal);
6874
+ }
6875
+ updateModuleSource(source) {
6876
+ this.#edits.updateModuleSource(source);
6877
+ }
6878
+ discardModuleChanges() {
6879
+ this.#edits.discardModuleChanges();
6880
+ }
6881
+ get hasUnsavedCode() {
6882
+ return this.#edits.hasUnsavedCode;
6883
+ }
6884
+ async saveDraft() {
6885
+ return this.#edits.saveDraft();
6886
+ }
6887
+ saveModuleEditor() {
6888
+ return this.#edits.saveModuleEditor();
6889
+ }
6890
+ async moveNodes(positions) {
6891
+ if (this.#model.value.draft == null) return;
6892
+ await this.#edits.canvasChange("move", Object.keys(positions).length, [], (value) => setNodePositions(value, positions));
6893
+ }
6894
+ async moveViewport(viewport) {
6895
+ if (this.#model.value.draft == null) return;
6896
+ await this.#edits.changePresentation((value) => setFlowViewport(value, viewport), true);
6897
+ }
6898
+ async check() {
6899
+ await this.#edits.checkDraft();
6900
+ }
6901
+ async refreshFlows() {
6902
+ await this.reloadFlows();
6903
+ }
6904
+ updateLive(live) {
6905
+ if (live.flowId == this.#model.value.flowId) this.#edits.set({ live });
6906
+ }
6907
+ locateNode(nodeId, { preserveSelection = false } = {}) {
6908
+ const revision = this.$.revision.value;
6909
+ if (revision == null) return false;
6910
+ if (revision.node(nodeId) == null && !commentIds(this.#model.value.presentation?.value ?? {}).has(nodeId)) return false;
6911
+ if (!preserveSelection && !this.selectNodes([nodeId])) return false;
6912
+ this.#edits.set({ nodeFocus: {
6913
+ nodeId,
6914
+ requestId: ++this.#nodeFocusId
6915
+ } });
6916
+ return true;
6917
+ }
6918
+ locateDiagnostic(item) {
6919
+ if (item.location == null || !this.selectNodes([item.location.nodeId])) return false;
6920
+ this.#edits.set({ diagnosticFocus: {
6921
+ ...item.location,
6922
+ diagnostic: item.diagnostic,
6923
+ requestId: ++this.#diagnosticFocusId
6924
+ } });
6925
+ return true;
6926
+ }
6927
+ async #addComment(nodeId, position) {
6928
+ const number = Math.max(0, ...this.#designer().nodes.flatMap((node) => {
6929
+ if (node.kind != "comment") return [];
6930
+ const match = /#(\d+)$/.exec(node.title);
6931
+ return match == null ? [] : [Number(match[1])];
6932
+ }));
6933
+ if (!await this.#edits.canvasChange("add", 1, [], (value) => setComment(value, nodeId, {
6934
+ content: "",
6935
+ position,
6936
+ title: this.#i18n.t("addNode.commentName", { number: number + 1 })
6937
+ }), [nodeId]) || this.#disposed) return;
6938
+ return nodeId;
6939
+ }
6940
+ async undo() {
6941
+ await this.#edits.undo();
6942
+ }
6943
+ async redo() {
6944
+ await this.#edits.redo();
6945
+ }
6946
+ async retryHistorySync() {
6947
+ return this.#edits.retryHistorySync();
6948
+ }
6949
+ #designer() {
6950
+ const state = this.#model.value;
6951
+ return designerGraph(state.draft, state.presentation?.value, state.diagnostics?.diagnostics, {}, {}, this.#i18n.t);
6837
6952
  }
6838
6953
  };
6839
6954
  //#endregion
@@ -7051,7 +7166,7 @@ var WorkbenchStore = class {
7051
7166
  const model = this.$.designer.value;
7052
7167
  const title = this.workspace.$.flow.value?.name ?? this.workspace.$.flowId.value ?? "Workflow";
7053
7168
  try {
7054
- const { downloadFlowSvg } = await import("./exportSvg-Dv5Qgrq7.js");
7169
+ const { downloadFlowSvg } = await import("./exportSvg-BOoy7-Db.js");
7055
7170
  await downloadFlowSvg(model, title, language, options);
7056
7171
  if (!this.#disposed) this.#notice.set({
7057
7172
  kind: "success",
@@ -7305,7 +7420,7 @@ var WorkbenchStore = class {
7305
7420
  };
7306
7421
  //#endregion
7307
7422
  //#region src/workbench/browser/runtime/openFlowWorkbench.tsx
7308
- var FlowWorkspace = lazy(() => import("./flowWorkspace-qYUZPJHR.js"));
7423
+ var FlowWorkspace = lazy(() => import("./flowWorkspace-Bf7H-r0t.js"));
7309
7424
  function OpenFlowSessionGate({ action, description, error, onSubmit, onTokenChange, pending = false, title, token, tokenLabel }) {
7310
7425
  const hasToken = token != null && tokenLabel != null && onTokenChange != null;
7311
7426
  const tokenValue = token ?? "";