@arbidocs/blocks 0.4.73 → 0.4.74

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 (58) hide show
  1. package/dist/agents/index.cjs +253 -253
  2. package/dist/agents/index.js +3 -3
  3. package/dist/agents/workflows/WorkflowRunner.d.ts +20 -4
  4. package/dist/agents/workflows/WorkflowStepBar.d.ts +23 -0
  5. package/dist/agents/workflows/run.d.ts +1 -0
  6. package/dist/agents/workflows/types.d.ts +2 -0
  7. package/dist/chat/index.cjs +124 -124
  8. package/dist/chat/index.js +3 -3
  9. package/dist/{chunk-IUR565UW.cjs → chunk-5LP54CWR.cjs} +32 -32
  10. package/dist/chunk-5LP54CWR.cjs.map +1 -0
  11. package/dist/{chunk-3SFFTSOI.cjs → chunk-7CVF3DK2.cjs} +5 -5
  12. package/dist/{chunk-3SFFTSOI.cjs.map → chunk-7CVF3DK2.cjs.map} +1 -1
  13. package/dist/{chunk-V3L5DONY.cjs → chunk-B4SRYJLM.cjs} +31 -2
  14. package/dist/chunk-B4SRYJLM.cjs.map +1 -0
  15. package/dist/{chunk-WOYUXVVQ.cjs → chunk-HITAN7JF.cjs} +4 -4
  16. package/dist/{chunk-WOYUXVVQ.cjs.map → chunk-HITAN7JF.cjs.map} +1 -1
  17. package/dist/{chunk-3VQYJBOI.js → chunk-HOXKR26S.js} +31 -4
  18. package/dist/chunk-HOXKR26S.js.map +1 -0
  19. package/dist/{chunk-KJ3QEKOJ.cjs → chunk-IPGKTUF7.cjs} +7 -33
  20. package/dist/chunk-IPGKTUF7.cjs.map +1 -0
  21. package/dist/{chunk-QDNXEB3T.js → chunk-KOSGX3UK.js} +5 -5
  22. package/dist/chunk-KOSGX3UK.js.map +1 -0
  23. package/dist/{chunk-ORA2XE7U.js → chunk-MK6NJQGF.js} +3 -3
  24. package/dist/{chunk-ORA2XE7U.js.map → chunk-MK6NJQGF.js.map} +1 -1
  25. package/dist/{chunk-GTNUQBXI.cjs → chunk-P2RBE3FD.cjs} +254 -102
  26. package/dist/chunk-P2RBE3FD.cjs.map +1 -0
  27. package/dist/{chunk-G5DP27DU.js → chunk-UIWLDSTF.js} +3 -29
  28. package/dist/chunk-UIWLDSTF.js.map +1 -0
  29. package/dist/{chunk-VRPRAU3J.js → chunk-WJEKRSPH.js} +3 -3
  30. package/dist/{chunk-VRPRAU3J.js.map → chunk-WJEKRSPH.js.map} +1 -1
  31. package/dist/{chunk-2P3T23C7.js → chunk-YWYVIQ7T.js} +256 -104
  32. package/dist/chunk-YWYVIQ7T.js.map +1 -0
  33. package/dist/connect/index.cjs +95 -36
  34. package/dist/connect/index.cjs.map +1 -1
  35. package/dist/connect/index.js +80 -21
  36. package/dist/connect/index.js.map +1 -1
  37. package/dist/connection/ConnectedWorkflowRunner.d.ts +5 -1
  38. package/dist/connection/useWorkflowThread.d.ts +4 -0
  39. package/dist/index.cjs +382 -382
  40. package/dist/index.js +6 -6
  41. package/dist/studio/index.cjs +4 -4
  42. package/dist/studio/index.js +3 -3
  43. package/dist/workflow-canvas/StepInspector.d.ts +11 -0
  44. package/dist/workflow-canvas/WorkflowCanvas.d.ts +6 -2
  45. package/dist/workflow-canvas/index.cjs +200 -90
  46. package/dist/workflow-canvas/index.cjs.map +1 -1
  47. package/dist/workflow-canvas/index.js +168 -58
  48. package/dist/workflow-canvas/index.js.map +1 -1
  49. package/dist/workflow-canvas/viewport.d.ts +47 -0
  50. package/package.json +4 -4
  51. package/dist/chunk-2P3T23C7.js.map +0 -1
  52. package/dist/chunk-3VQYJBOI.js.map +0 -1
  53. package/dist/chunk-G5DP27DU.js.map +0 -1
  54. package/dist/chunk-GTNUQBXI.cjs.map +0 -1
  55. package/dist/chunk-IUR565UW.cjs.map +0 -1
  56. package/dist/chunk-KJ3QEKOJ.cjs.map +0 -1
  57. package/dist/chunk-QDNXEB3T.js.map +0 -1
  58. package/dist/chunk-V3L5DONY.cjs.map +0 -1
@@ -1,9 +1,9 @@
1
1
  "use client";
2
2
  import { useConnection } from '../chunk-OYMWV45N.js';
3
- import { describeRRule, RecurrenceBuilder, AgentSelect, useWorkflowPreview, workflowWhen, isoToLocalInput, localInputToIso } from '../chunk-QDNXEB3T.js';
3
+ import { describeRRule, RecurrenceBuilder, AgentSelect, useWorkflowPreview, workflowWhen, isoToLocalInput, localInputToIso } from '../chunk-KOSGX3UK.js';
4
4
  import '../chunk-CKB64Z4R.js';
5
5
  import '../chunk-P6GHJSLR.js';
6
- import { workflowSteps, dependsOn, stepLevels, stepDependencies, validateWorkflowGraph, WorkflowRunner, fromPlanSteps, layoutFromPlanSteps, skillToWorkflow, orderSteps, toPlanSteps } from '../chunk-2P3T23C7.js';
6
+ import { workflowSteps, dependsOn, stepLevels, stepDependencies, runFields, validateWorkflowGraph, WorkflowRunner, fromPlanSteps, layoutFromPlanSteps, skillToWorkflow, orderSteps, toPlanSteps } from '../chunk-YWYVIQ7T.js';
7
7
  import '../chunk-4WWM3GQ5.js';
8
8
  import '../chunk-RFXJYIDV.js';
9
9
  import '../chunk-DPLRHEJZ.js';
@@ -13,7 +13,7 @@ import '../chunk-YU2KUMGE.js';
13
13
  import '../chunk-DDF5GPIJ.js';
14
14
  import '../chunk-XD2M6LIG.js';
15
15
  import '../chunk-S7PSMMRG.js';
16
- import '../chunk-3VQYJBOI.js';
16
+ import '../chunk-HOXKR26S.js';
17
17
  import '../chunk-AA3PT6KR.js';
18
18
  import '../chunk-SLSBJRWW.js';
19
19
  import '../chunk-NPLYHR2E.js';
@@ -25,9 +25,9 @@ import '../chunk-VUNV25KB.js';
25
25
  import { useMemo, useState, useEffect, useCallback, useRef } from 'react';
26
26
  import { useWorkflows, useSkills, useAgents, useConversations, useCreateWorkflow, useUpdateWorkflow, useRunWorkflow } from '@arbidocs/react';
27
27
  import { Input, Textarea, Checkbox, Button, cn, Label, Popover, PopoverTrigger, PopoverContent } from '@arbidocs/react/ui';
28
- import { X, Trash2, Plus, ClipboardCheck, Bot, Upload, FileInput, PencilRuler, Eye, LayoutGrid, Settings2, Play, Loader2, Save, Zap, GitBranch, Check, AlertTriangle, MinusCircle } from 'lucide-react';
28
+ import { X, Trash2, Plus, Maximize, ClipboardCheck, Bot, Upload, FileInput, PencilRuler, Eye, LayoutGrid, Settings2, Play, Loader2, Save, Zap, GitBranch, Check, AlertTriangle, MinusCircle } from 'lucide-react';
29
29
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
30
- import { MarkerType, applyNodeChanges, ReactFlow, Background, BackgroundVariant, Controls, MiniMap, Handle, Position } from '@xyflow/react';
30
+ import { MarkerType, applyNodeChanges, ReactFlow, Background, BackgroundVariant, Controls, ControlButton, MiniMap, Handle, Position } from '@xyflow/react';
31
31
 
32
32
  // src/workflow-canvas/edit.ts
33
33
  function newSteppedWorkflow(id, title) {
@@ -71,7 +71,7 @@ function blankStep(kind, id, title) {
71
71
  case "upload":
72
72
  return { id, kind, title };
73
73
  case "agent":
74
- return { id, kind, title, run: { kind: "prompt", promptTemplate: "" } };
74
+ return { id, kind, title };
75
75
  case "review":
76
76
  return { id, kind, title, instructions: "" };
77
77
  }
@@ -176,10 +176,13 @@ var DEFAULT_STEP_INSPECTOR_LABELS = {
176
176
  fieldType: "Type",
177
177
  required: "Required",
178
178
  runs: "Runs",
179
+ chooseRun: "Choose a skill or write an instruction\u2026",
179
180
  ownPrompt: "Its own instruction",
180
181
  prompt: "Instruction",
181
182
  promptHint: "Use {{field}} for an input and {{steps.<id>}} for an earlier step\u2019s answer.",
182
183
  inputFor: "Input",
184
+ inputHint: "Type a value, or use a field: {fields}",
185
+ inputHintNoFields: "Type a value, or add a form field to fill it from.",
183
186
  thread: "Where it runs",
184
187
  threadMain: "In the run\u2019s thread (sees the conversation so far)",
185
188
  threadBranch: "On a branch (delivers only its result to the thread)",
@@ -327,7 +330,17 @@ function StepInspector({
327
330
  }
328
331
  ) })
329
332
  ] }),
330
- step.kind === "agent" && /* @__PURE__ */ jsx(AgentSettings, { step, workflows, patch, l, testId }),
333
+ step.kind === "agent" && /* @__PURE__ */ jsx(
334
+ AgentSettings,
335
+ {
336
+ step,
337
+ workflows,
338
+ fields: runFields(workflow).map((f) => f.name),
339
+ patch,
340
+ l,
341
+ testId
342
+ }
343
+ ),
331
344
  step.kind === "review" && /* @__PURE__ */ jsx(Field, { label: l.instructions, hint: l.instructionsHint, children: /* @__PURE__ */ jsx(
332
345
  Textarea,
333
346
  {
@@ -440,42 +453,77 @@ function FormFields({
440
453
  )
441
454
  ] }) });
442
455
  }
456
+ var OWN_PROMPT = "__prompt";
457
+ function prefillSkillInputs(target, fields, current = {}) {
458
+ const out = {};
459
+ for (const f of target?.inputs ?? []) {
460
+ const typed = current[f.name];
461
+ if (typed) out[f.name] = typed;
462
+ else if (fields.includes(f.name)) out[f.name] = `{{${f.name}}}`;
463
+ }
464
+ return out;
465
+ }
443
466
  function AgentSettings({
444
467
  step,
445
468
  workflows,
469
+ fields,
446
470
  patch,
447
471
  l,
448
472
  testId
449
473
  }) {
450
474
  const target = step.workflow ? workflows.find((w) => w.id === step.workflow) : void 0;
475
+ const value = step.workflow ?? (step.run ? OWN_PROMPT : "");
476
+ const codes = fields.map((f) => `{{${f}}}`).join(", ");
451
477
  return /* @__PURE__ */ jsxs(Fragment, { children: [
452
478
  /* @__PURE__ */ jsx(Field, { label: l.runs, children: /* @__PURE__ */ jsxs(
453
479
  "select",
454
480
  {
455
481
  className: selectClass,
456
- value: step.workflow ?? "",
457
- onChange: (e) => e.target.value ? patch({ workflow: e.target.value, run: void 0, with: step.with ?? {} }) : patch({
458
- workflow: void 0,
459
- with: void 0,
460
- run: { kind: "prompt", promptTemplate: "" }
461
- }),
482
+ value,
483
+ onChange: (e) => {
484
+ const id = e.target.value;
485
+ if (id === OWN_PROMPT)
486
+ patch({
487
+ workflow: void 0,
488
+ with: void 0,
489
+ run: { kind: "prompt", promptTemplate: "" }
490
+ });
491
+ else if (id)
492
+ patch({
493
+ workflow: id,
494
+ run: void 0,
495
+ with: prefillSkillInputs(
496
+ workflows.find((w) => w.id === id),
497
+ fields,
498
+ step.with
499
+ )
500
+ });
501
+ },
462
502
  "data-testid": `${testId}-runs`,
463
503
  children: [
464
- /* @__PURE__ */ jsx("option", { value: "", children: l.ownPrompt }),
504
+ !value && /* @__PURE__ */ jsx("option", { value: "", disabled: true, children: l.chooseRun }),
505
+ /* @__PURE__ */ jsx("option", { value: OWN_PROMPT, children: l.ownPrompt }),
465
506
  workflows.map((w) => /* @__PURE__ */ jsx("option", { value: w.id, children: w.title }, w.id)),
466
507
  step.workflow && !target && /* @__PURE__ */ jsx("option", { value: step.workflow, children: step.workflow })
467
508
  ]
468
509
  }
469
510
  ) }),
470
- step.workflow ? (target?.inputs ?? []).map((f) => /* @__PURE__ */ jsx(Field, { label: `${l.inputFor}: ${f.label}`, children: /* @__PURE__ */ jsx(
471
- Input,
511
+ step.workflow ? (target?.inputs ?? []).map((f) => /* @__PURE__ */ jsx(
512
+ Field,
472
513
  {
473
- value: step.with?.[f.name] ?? "",
474
- placeholder: `{{${f.name}}}`,
475
- onChange: (e) => patch({ with: { ...step.with, [f.name]: e.target.value } }),
476
- "data-testid": `${testId}-with-${f.name}`
477
- }
478
- ) }, f.name)) : step.run?.kind === "prompt" ? /* @__PURE__ */ jsx(Field, { label: l.prompt, hint: l.promptHint, children: /* @__PURE__ */ jsx(
514
+ label: `${l.inputFor}: ${f.label}`,
515
+ hint: step.with?.[f.name] ? void 0 : codes ? l.inputHint.replace("{fields}", codes) : l.inputHintNoFields,
516
+ children: /* @__PURE__ */ jsx(
517
+ Input,
518
+ {
519
+ value: step.with?.[f.name] ?? "",
520
+ onChange: (e) => patch({ with: { ...step.with, [f.name]: e.target.value } }),
521
+ "data-testid": `${testId}-with-${f.name}`
522
+ }
523
+ )
524
+ },
525
+ f.name
526
+ )) : step.run?.kind === "prompt" ? /* @__PURE__ */ jsx(Field, { label: l.prompt, hint: l.promptHint, children: /* @__PURE__ */ jsx(
479
527
  Textarea,
480
528
  {
481
529
  value: step.run.promptTemplate,
@@ -656,6 +704,45 @@ function TriggerInspector({
656
704
  ] })
657
705
  ] });
658
706
  }
707
+
708
+ // src/workflow-canvas/viewport.ts
709
+ var READABLE_ZOOM = 0.7;
710
+ var DEFAULT_W = 256;
711
+ var DEFAULT_H = 80;
712
+ var MARGIN = 48;
713
+ var sizeOf = (n) => ({
714
+ w: n.measured?.width ?? DEFAULT_W,
715
+ h: n.measured?.height ?? DEFAULT_H
716
+ });
717
+ function readableViewport(nodes, fittedZoom, frame, {
718
+ anchor,
719
+ centre = false,
720
+ reserveRight = 0
721
+ } = {}) {
722
+ if (fittedZoom >= READABLE_ZOOM || !frame.height || nodes.length === 0) return null;
723
+ const z = READABLE_ZOOM;
724
+ const at = nodes.find((n) => n.id === anchor) ?? nodes.reduce((a, b) => b.position.x < a.position.x ? b : a);
725
+ const { w, h } = sizeOf(at);
726
+ const y = frame.height / 2 - (at.position.y + h / 2) * z;
727
+ if (centre && at.id === anchor) {
728
+ const visible = Math.max(0, frame.width - reserveRight);
729
+ return { x: visible / 2 - (at.position.x + w / 2) * z, y, zoom: z };
730
+ }
731
+ return { x: MARGIN - at.position.x * z, y, zoom: z };
732
+ }
733
+ function revealCenter(node, view, frame, reserveRight = 0) {
734
+ const { w, h } = sizeOf(node);
735
+ const { x, y, zoom } = view;
736
+ const left = node.position.x * zoom + x;
737
+ const top = node.position.y * zoom + y;
738
+ const right = frame.width - reserveRight;
739
+ if (left >= 16 && top >= 16 && left + w * zoom <= right - 16 && top + h * zoom <= frame.height - 16)
740
+ return null;
741
+ return {
742
+ x: node.position.x + w / 2 + reserveRight / 2 / zoom,
743
+ y: node.position.y + h / 2
744
+ };
745
+ }
659
746
  var DEFAULT_WORKFLOW_CANVAS_LABELS = {
660
747
  form: "Form",
661
748
  upload: "Upload",
@@ -670,12 +757,13 @@ var DEFAULT_WORKFLOW_CANVAS_LABELS = {
670
757
  },
671
758
  addNext: "Add the next step",
672
759
  runs: "Runs \u201C{name}\u201D",
673
- instruction: "No instruction yet",
760
+ chooseRun: "Choose a skill or write an instruction",
674
761
  fields: "{count} fields",
675
762
  noFields: "No fields yet",
676
763
  approvedBy: "A person approves",
677
764
  emptyTitle: "Start your workflow",
678
- emptyHint: "Add the first step: what should happen when it starts?"
765
+ emptyHint: "Add the first step: what should happen when it starts?",
766
+ fitView: "Fit view"
679
767
  };
680
768
  var TRIGGER_NODE = "__trigger";
681
769
  var STEP_KIND_ICONS = {
@@ -800,7 +888,6 @@ function TriggerNode({ data }) {
800
888
  );
801
889
  }
802
890
  var NODE_TYPES = { step: StepNode, trigger: TriggerNode };
803
- var READABLE_ZOOM = 0.7;
804
891
  var firstWords = (text, n = 14) => {
805
892
  const words = text.trim().split(/\s+/);
806
893
  return words.length > n ? `${words.slice(0, n).join(" ")}\u2026` : text.trim();
@@ -811,7 +898,8 @@ function summaryOf(step, l, workflowTitle) {
811
898
  case "agent":
812
899
  if (step.workflow)
813
900
  return l.runs.replace("{name}", workflowTitle?.(step.workflow) ?? step.workflow);
814
- return step.run?.kind === "prompt" && step.run.promptTemplate.trim() ? firstWords(step.run.promptTemplate) : l.instruction;
901
+ if (step.run?.kind === "operation") return void 0;
902
+ return step.run?.kind === "prompt" && step.run.promptTemplate.trim() ? firstWords(step.run.promptTemplate) : l.chooseRun;
815
903
  case "form":
816
904
  return step.inputs.length ? step.inputs.length === 1 ? step.inputs[0].label : l.fields.replace("{count}", String(step.inputs.length)) : l.noFields;
817
905
  case "upload":
@@ -825,6 +913,7 @@ function WorkflowCanvas({
825
913
  onChange,
826
914
  selected = null,
827
915
  onSelect,
916
+ focus,
828
917
  onAddAfter,
829
918
  phases,
830
919
  workflowTitle,
@@ -916,46 +1005,57 @@ function WorkflowCanvas({
916
1005
  );
917
1006
  const frame = useRef(null);
918
1007
  const flowRef = useRef(null);
919
- const onInit = useCallback(
920
- async (flow) => {
921
- flowRef.current = flow;
1008
+ const hasTrigger = !!trigger;
1009
+ const selectedRef = useRef(selected);
1010
+ selectedRef.current = selected;
1011
+ const fit = useCallback(
1012
+ async (flow, anchorOnSelection) => {
922
1013
  await flow.fitView({
923
1014
  padding: { top: "48px", bottom: "48px", left: "48px", right: `${reserveRight + 48}px` },
924
1015
  maxZoom: 1
925
1016
  });
926
- const height = frame.current?.clientHeight;
927
- const shown = flow.getNodes();
928
- if (flow.getZoom() >= READABLE_ZOOM || !height || !shown.length) return;
929
- const left = Math.min(...shown.map((n) => n.position.x));
930
- const ys = shown.map((n) => n.position.y + (n.measured?.height ?? 0) / 2);
931
- const middle = (Math.min(...ys) + Math.max(...ys)) / 2;
932
- flow.setViewport({
933
- x: 48 - left * READABLE_ZOOM,
934
- y: height / 2 - middle * READABLE_ZOOM,
935
- zoom: READABLE_ZOOM
936
- });
1017
+ const box = frame.current;
1018
+ const picked = anchorOnSelection ? selectedRef.current : null;
1019
+ const view = readableViewport(
1020
+ flow.getNodes(),
1021
+ flow.getZoom(),
1022
+ { width: box?.clientWidth ?? 0, height: box?.clientHeight ?? 0 },
1023
+ {
1024
+ anchor: picked ?? (hasTrigger ? TRIGGER_NODE : null),
1025
+ centre: !!picked,
1026
+ reserveRight
1027
+ }
1028
+ );
1029
+ if (view) await flow.setViewport(view);
1030
+ },
1031
+ [reserveRight, hasTrigger]
1032
+ );
1033
+ const onInit = useCallback(
1034
+ async (flow) => {
1035
+ flowRef.current = flow;
1036
+ await fit(flow, false);
937
1037
  },
938
- [reserveRight]
1038
+ [fit]
939
1039
  );
1040
+ const target = focus ?? selected;
1041
+ const revealed = useRef(null);
940
1042
  useEffect(() => {
941
1043
  const flow = flowRef.current;
942
1044
  const box = frame.current;
943
- const node = selected ? flow?.getNode(selected) : void 0;
944
- if (!flow || !box || !node) return;
945
- const { x, y, zoom } = flow.getViewport();
946
- const w = (node.measured?.width ?? 256) * zoom;
947
- const h = (node.measured?.height ?? 80) * zoom;
948
- const left = node.position.x * zoom + x;
949
- const top = node.position.y * zoom + y;
950
- const right = box.clientWidth - reserveRight;
951
- if (left >= 16 && top >= 16 && left + w <= right - 16 && top + h <= box.clientHeight - 16)
952
- return;
953
- void flow.setCenter(
954
- node.position.x + (node.measured?.width ?? 256) / 2 + reserveRight / 2 / zoom,
955
- node.position.y + (node.measured?.height ?? 80) / 2,
956
- { zoom, duration: 250 }
1045
+ const node = target ? flow?.getNode(target) : void 0;
1046
+ const key = `${target}:${reserveRight}`;
1047
+ if (!target) revealed.current = null;
1048
+ if (!flow || !box || !node || revealed.current === key) return;
1049
+ revealed.current = key;
1050
+ const view = flow.getViewport();
1051
+ const centre = revealCenter(
1052
+ node,
1053
+ view,
1054
+ { width: box.clientWidth, height: box.clientHeight },
1055
+ reserveRight
957
1056
  );
958
- }, [selected, nodes, reserveRight]);
1057
+ if (centre) void flow.setCenter(centre.x, centre.y, { zoom: view.zoom, duration: 250 });
1058
+ }, [target, nodes, reserveRight]);
959
1059
  const onDelete = useCallback(
960
1060
  ({ nodes: gone, edges: cut }) => {
961
1061
  if (!onChange) return;
@@ -997,12 +1097,21 @@ function WorkflowCanvas({
997
1097
  elementsSelectable: true,
998
1098
  deleteKeyCode: editable ? ["Backspace", "Delete"] : null,
999
1099
  onInit,
1000
- fitViewOptions: { padding: 0.2, maxZoom: 1 },
1001
1100
  minZoom: 0.3,
1002
1101
  proOptions: { hideAttribution: true },
1003
1102
  children: [
1004
1103
  /* @__PURE__ */ jsx(Background, { variant: BackgroundVariant.Dots, gap: 18, size: 1.5 }),
1005
- /* @__PURE__ */ jsx(Controls, { showInteractive: false, position: "bottom-left" }),
1104
+ /* @__PURE__ */ jsx(Controls, { showInteractive: false, showFitView: false, position: "bottom-left", children: /* @__PURE__ */ jsx(
1105
+ ControlButton,
1106
+ {
1107
+ className: "react-flow__controls-fitview",
1108
+ onClick: () => flowRef.current && void fit(flowRef.current, true),
1109
+ title: l.fitView,
1110
+ "aria-label": l.fitView,
1111
+ "data-testid": `${testId}-fit`,
1112
+ children: /* @__PURE__ */ jsx(Maximize, {})
1113
+ }
1114
+ ) }),
1006
1115
  steps.length > 3 && /* @__PURE__ */ jsx(
1007
1116
  MiniMap,
1008
1117
  {
@@ -1224,6 +1333,7 @@ function WorkflowBuilder({
1224
1333
  onChange: setWorkflow,
1225
1334
  selected,
1226
1335
  onSelect: setSelected,
1336
+ focus: selected ?? (panelOpen ? TRIGGER_NODE : null),
1227
1337
  onAddAfter: addAfter,
1228
1338
  trigger: { title: l.start, summary },
1229
1339
  workflowTitle: (id) => titles.get(id),