@tangle-network/sandbox-ui 0.51.0 → 0.53.0

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.
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-GTJ5PSK5.js";
4
4
  import {
5
5
  buildWorkflowGraph
6
- } from "./chunk-46VFHJPQ.js";
6
+ } from "./chunk-DEN4GUA7.js";
7
7
  import {
8
8
  providerLabel
9
9
  } from "./chunk-7JLB7UZ3.js";
@@ -15,7 +15,9 @@ import {
15
15
  Controls,
16
16
  Handle,
17
17
  Position,
18
- ReactFlow
18
+ ReactFlow,
19
+ useEdgesState,
20
+ useNodesState
19
21
  } from "@xyflow/react";
20
22
  import "@xyflow/react/dist/style.css";
21
23
  import {
@@ -27,7 +29,9 @@ import {
27
29
 
28
30
  // src/workflows/flow-graph.ts
29
31
  function buildFlowGraph(yaml, nodeState) {
30
- const graph = buildWorkflowGraph(yaml);
32
+ const graph = buildWorkflowGraph(yaml, {
33
+ reserveRunState: nodeState !== void 0
34
+ });
31
35
  return {
32
36
  error: graph.error,
33
37
  nodes: graph.nodes.map(
@@ -47,6 +51,22 @@ function buildFlowGraph(yaml, nodeState) {
47
51
  }))
48
52
  };
49
53
  }
54
+ function sameRunState(a, b) {
55
+ if (a === b) return true;
56
+ if (!a || !b) return false;
57
+ const aKeys = Object.keys(a);
58
+ const bKeys = Object.keys(b);
59
+ if (aKeys.length !== bKeys.length) return false;
60
+ return aKeys.every((k) => a[k] === b[k]);
61
+ }
62
+ function mergeRunState(prev, baseDataById, nodeState) {
63
+ return prev.map((n) => {
64
+ const base = baseDataById.get(n.id) ?? n.data;
65
+ const s = nodeState?.[n.id];
66
+ const nextData = s ? { ...base, state: s } : base;
67
+ return sameRunState(n.data.state, nextData.state) ? n : { ...n, data: nextData };
68
+ });
69
+ }
50
70
 
51
71
  // src/workflows/format.ts
52
72
  function fmtDuration(ms) {
@@ -240,22 +260,33 @@ function WorkflowGraph({
240
260
  onNodeClick
241
261
  }) {
242
262
  const colorMode = useColorMode();
243
- const { nodes, edges, error } = useMemo(
244
- () => buildFlowGraph(yaml, nodeState),
245
- [yaml, nodeState]
263
+ const hasRunOverlay = nodeState !== void 0;
264
+ const structural = useMemo(
265
+ () => buildFlowGraph(yaml, hasRunOverlay ? {} : void 0),
266
+ [yaml, hasRunOverlay]
246
267
  );
268
+ const [nodes, setNodes, onNodesChange] = useNodesState(structural.nodes);
269
+ const [edges, setEdges, onEdgesChange] = useEdgesState(structural.edges);
270
+ useEffect(() => {
271
+ setNodes(structural.nodes);
272
+ setEdges(structural.edges);
273
+ }, [structural, setNodes, setEdges]);
274
+ useEffect(() => {
275
+ const baseById = new Map(structural.nodes.map((n) => [n.id, n.data]));
276
+ setNodes((prev) => mergeRunState(prev, baseById, nodeState));
277
+ }, [nodeState, structural, setNodes]);
247
278
  const handleNodeClick = useCallback(
248
279
  (_event, node) => {
249
280
  onNodeClick?.(node.id, node.data);
250
281
  },
251
282
  [onNodeClick]
252
283
  );
253
- if (error || nodes.length === 0) {
284
+ if (structural.error || structural.nodes.length === 0) {
254
285
  return /* @__PURE__ */ jsx(
255
286
  "div",
256
287
  {
257
288
  className: `flex items-center justify-center rounded-lg border border-border border-dashed p-4 text-center text-text-muted text-xs ${className ?? ""}`,
258
- children: error ?? "Nothing to show"
289
+ children: structural.error ?? "Nothing to show"
259
290
  }
260
291
  );
261
292
  }
@@ -265,6 +296,8 @@ function WorkflowGraph({
265
296
  {
266
297
  nodes,
267
298
  edges,
299
+ onNodesChange,
300
+ onEdgesChange,
268
301
  nodeTypes: NODE_TYPES,
269
302
  colorMode,
270
303
  onNodeClick: onNodeClick ? handleNodeClick : void 0,
@@ -273,6 +306,8 @@ function WorkflowGraph({
273
306
  proOptions: { hideAttribution: true },
274
307
  nodesDraggable: !isPreview,
275
308
  nodesConnectable: false,
309
+ deleteKeyCode: null,
310
+ edgesReconnectable: false,
276
311
  elementsSelectable: !isPreview,
277
312
  edgesFocusable: false,
278
313
  zoomOnScroll: false,
@@ -4,10 +4,22 @@ import {
4
4
 
5
5
  // src/workflows/model.ts
6
6
  import { parse as parseYaml } from "yaml";
7
- var ROW_GAP = 112;
8
7
  var BRANCH_X = 300;
9
- var BRANCH_ROW_GAP = 84;
10
- var BRANCH_STACK_PADDING = 40;
8
+ var NODE_GAP = 44;
9
+ var BRANCH_GAP = 24;
10
+ var CARD_CHROME = 20;
11
+ var TITLE_ROW = 22;
12
+ var TEXT_ROW = 20;
13
+ var META_ROW = 44;
14
+ var PREVIEW_ROW = 34;
15
+ function estimateNodeHeight(data, withRunState) {
16
+ let h = CARD_CHROME + TITLE_ROW;
17
+ if (data.subtitle) h += TEXT_ROW;
18
+ if (withRunState || data.model) h += META_ROW;
19
+ if (withRunState) h += PREVIEW_ROW;
20
+ if (data.provider) h += TEXT_ROW;
21
+ return h;
22
+ }
11
23
  function asRecord(v) {
12
24
  return v && typeof v === "object" && !Array.isArray(v) ? v : {};
13
25
  }
@@ -165,7 +177,8 @@ function describeTrigger(on) {
165
177
  tone: "trigger"
166
178
  };
167
179
  }
168
- function buildWorkflowGraph(yaml) {
180
+ function buildWorkflowGraph(yaml, options) {
181
+ const reserveRunState = options?.reserveRunState ?? false;
169
182
  if (!yaml || yaml.trim() === "") {
170
183
  return { nodes: [], edges: [], error: "No definition" };
171
184
  }
@@ -193,13 +206,10 @@ function buildWorkflowGraph(yaml) {
193
206
  });
194
207
  };
195
208
  if (def.on) {
196
- nodes.push({
197
- id: "trigger",
198
- position: { x: 0, y },
199
- data: describeTrigger(def.on)
200
- });
209
+ const data = describeTrigger(def.on);
210
+ nodes.push({ id: "trigger", position: { x: 0, y }, data });
201
211
  prevId = "trigger";
202
- y += ROW_GAP;
212
+ y += estimateNodeHeight(data, false) + NODE_GAP;
203
213
  }
204
214
  actions.forEach((action, i) => {
205
215
  const id = `a${i}`;
@@ -207,6 +217,7 @@ function buildWorkflowGraph(yaml) {
207
217
  nodes.push({ id, position: { x: 0, y }, data });
208
218
  if (prevId) addEdge(prevId, id, false);
209
219
  prevId = id;
220
+ const spineHeight = estimateNodeHeight(data, reserveRunState);
210
221
  const rec = asRecord(action);
211
222
  const children = "parallel" in rec ? Array.isArray(asRecord(rec.parallel).branches) ? asRecord(rec.parallel).branches : [] : "foreach" in rec ? (
212
223
  // A foreach with no `do` template has no child to render.
@@ -214,22 +225,23 @@ function buildWorkflowGraph(yaml) {
214
225
  ) : [];
215
226
  if (children.length > 0) {
216
227
  let by = y;
228
+ let branchStackHeight = 0;
217
229
  children.forEach((child, j) => {
218
230
  const cid = `${id}-b${j}`;
231
+ const childData = describeAction(child);
219
232
  nodes.push({
220
233
  id: cid,
221
234
  position: { x: BRANCH_X, y: by },
222
- data: describeAction(child)
235
+ data: childData
223
236
  });
224
237
  addEdge(id, cid, true);
225
- by += BRANCH_ROW_GAP;
238
+ const childHeight = estimateNodeHeight(childData, reserveRunState);
239
+ by += childHeight + BRANCH_GAP;
240
+ branchStackHeight += childHeight + BRANCH_GAP;
226
241
  });
227
- y += Math.max(
228
- ROW_GAP,
229
- children.length * BRANCH_ROW_GAP + BRANCH_STACK_PADDING
230
- );
242
+ y += Math.max(spineHeight, branchStackHeight) + NODE_GAP;
231
243
  } else {
232
- y += ROW_GAP;
244
+ y += spineHeight + NODE_GAP;
233
245
  }
234
246
  });
235
247
  return { nodes, edges, error: null };