@pipelex/mthds-ui 0.5.2 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -17,9 +17,22 @@ var __spreadValues = (a, b) => {
17
17
  return a;
18
18
  };
19
19
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
+ var __objRest = (source, exclude) => {
21
+ var target = {};
22
+ for (var prop in source)
23
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
24
+ target[prop] = source[prop];
25
+ if (source != null && __getOwnPropSymbols)
26
+ for (var prop of __getOwnPropSymbols(source)) {
27
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
28
+ target[prop] = source[prop];
29
+ }
30
+ return target;
31
+ };
20
32
 
21
33
  export {
22
34
  __spreadValues,
23
- __spreadProps
35
+ __spreadProps,
36
+ __objRest
24
37
  };
25
- //# sourceMappingURL=chunk-DDAAVRWG.js.map
38
+ //# sourceMappingURL=chunk-2NMEKWO5.js.map
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=chunk-IZ4FH2WM.js.map
@@ -1,7 +1,8 @@
1
1
  import {
2
+ __objRest,
2
3
  __spreadProps,
3
4
  __spreadValues
4
- } from "./chunk-DDAAVRWG.js";
5
+ } from "./chunk-2NMEKWO5.js";
5
6
 
6
7
  // src/graph/types.ts
7
8
  var NODE_TYPE_PIPE_CARD = "pipeCard";
@@ -30,6 +31,14 @@ var EDGE_TYPE = {
30
31
  STRAIGHT: "straight",
31
32
  SMOOTH_STEP: "smoothstep"
32
33
  };
34
+ var FOLD_MODE = {
35
+ /** Every pipe controller folded into a single pipe card. */
36
+ FOLDED: "folded",
37
+ /** Every pipe controller expanded as a group wrapper. */
38
+ EXPANDED: "expanded",
39
+ /** Renderer decides — reserved for future heuristics; currently behaves like EXPANDED. */
40
+ AUTO: "auto"
41
+ };
33
42
  var CONTROLLER_PADDING_X = 40;
34
43
  var CONTROLLER_PADDING_TOP = 48;
35
44
  var CONTROLLER_PADDING_BOTTOM = 20;
@@ -204,7 +213,7 @@ function resolveConceptRef(spec, codeOrRef) {
204
213
  return void 0;
205
214
  }
206
215
 
207
- // src/graph/graphBuilders.ts
216
+ // src/graph/pipeCardPayload.ts
208
217
  function defaultDescription(pipeType, pipeCode) {
209
218
  const code = pipeCode || "this step";
210
219
  const verb = {
@@ -215,13 +224,54 @@ function defaultDescription(pipeType, pipeCode) {
215
224
  PipeSearch: "Search the web for",
216
225
  PipeFunc: "Process data in"
217
226
  };
218
- return `${verb[pipeType || ""] || "Execute"} ${code.replace(/_/g, " ")}`;
227
+ return `${verb[pipeType] || "Execute"} ${code.replace(/_/g, " ")}`;
228
+ }
229
+ function buildPipeCardPayload(node, graphspec, analysis) {
230
+ var _a, _b, _c, _d, _e, _f, _g;
231
+ const pipeType = node.pipe_type;
232
+ const pipeCode = node.pipe_code || node.id;
233
+ const isController = analysis.controllerNodeIds.has(node.id);
234
+ const inputs = ((_b = (_a = node.io) == null ? void 0 : _a.inputs) != null ? _b : []).map((i) => {
235
+ var _a2, _b2;
236
+ return {
237
+ name: (_a2 = i.name) != null ? _a2 : "",
238
+ concept: (_b2 = i.concept) != null ? _b2 : ""
239
+ };
240
+ });
241
+ const outputs = ((_d = (_c = node.io) == null ? void 0 : _c.outputs) != null ? _d : []).map((o) => {
242
+ var _a2, _b2;
243
+ return {
244
+ name: (_a2 = o.name) != null ? _a2 : "",
245
+ concept: (_b2 = o.concept) != null ? _b2 : ""
246
+ };
247
+ });
248
+ const registryDescription = node.pipe_code ? (_f = (_e = graphspec.pipe_registry) == null ? void 0 : _e[node.pipe_code]) == null ? void 0 : _f.description : void 0;
249
+ let description;
250
+ if (node.description) {
251
+ description = node.description;
252
+ } else if (registryDescription) {
253
+ description = registryDescription;
254
+ } else if (isController) {
255
+ description = void 0;
256
+ } else {
257
+ description = defaultDescription(pipeType, node.pipe_code);
258
+ }
259
+ return {
260
+ pipeCode,
261
+ pipeType,
262
+ description,
263
+ status: (_g = node.status) != null ? _g : "scheduled",
264
+ inputs,
265
+ outputs
266
+ };
219
267
  }
268
+
269
+ // src/graph/graphBuilders.ts
220
270
  var STUFF_CHAR_WIDTH_PX = 7;
221
271
  var STUFF_LABEL_PADDING = 48;
222
272
  var MIN_STUFF_WIDTH = 140;
223
273
  function buildDataflowGraph(graphspec, analysis, edgeType) {
224
- var _a, _b, _c, _d, _e;
274
+ var _a;
225
275
  const nodes = [];
226
276
  const edges = [];
227
277
  const participatingPipes = /* @__PURE__ */ new Set();
@@ -237,21 +287,7 @@ function buildDataflowGraph(graphspec, analysis, edgeType) {
237
287
  if (!participatingPipes.has(node.id)) continue;
238
288
  const isFailed = node.status === "failed";
239
289
  const label = node.pipe_code || node.id.split(":").pop() || node.id;
240
- const inputs = ((_b = (_a = node.io) == null ? void 0 : _a.inputs) != null ? _b : []).map((i) => {
241
- var _a2, _b2;
242
- return {
243
- name: (_a2 = i.name) != null ? _a2 : "",
244
- concept: (_b2 = i.concept) != null ? _b2 : ""
245
- };
246
- });
247
- const outputs = ((_d = (_c = node.io) == null ? void 0 : _c.outputs) != null ? _d : []).map((o) => {
248
- var _a2, _b2;
249
- return {
250
- name: (_a2 = o.name) != null ? _a2 : "",
251
- concept: (_b2 = o.concept) != null ? _b2 : ""
252
- };
253
- });
254
- const operatorType = node.pipe_type || "PipeFunc";
290
+ const pipeCardData = buildPipeCardPayload(node, graphspec, analysis);
255
291
  nodes.push({
256
292
  id: node.id,
257
293
  type: NODE_TYPE_PIPE_CARD,
@@ -261,16 +297,9 @@ function buildDataflowGraph(graphspec, analysis, edgeType) {
261
297
  isPipe: true,
262
298
  isStuff: false,
263
299
  labelText: label,
264
- pipeCode: node.pipe_code || label,
300
+ pipeCode: pipeCardData.pipeCode,
265
301
  pipeType: node.pipe_type,
266
- pipeCardData: {
267
- pipeCode: node.pipe_code || label,
268
- pipeType: operatorType,
269
- description: node.description || defaultDescription(node.pipe_type, node.pipe_code),
270
- status: node.status || "scheduled",
271
- inputs,
272
- outputs
273
- }
302
+ pipeCardData
274
303
  },
275
304
  position: { x: 0, y: 0 }
276
305
  });
@@ -282,7 +311,7 @@ function buildDataflowGraph(graphspec, analysis, edgeType) {
282
311
  const textWidth = Math.max(label.length, concept.length) * STUFF_CHAR_WIDTH_PX + STUFF_LABEL_PADDING;
283
312
  const stuffWidth = Math.max(MIN_STUFF_WIDTH, textWidth);
284
313
  const isInput = !analysis.stuffProducers[digest];
285
- const isOutput = !isInput && !((_e = analysis.stuffConsumers[digest]) == null ? void 0 : _e.length);
314
+ const isOutput = !isInput && !((_a = analysis.stuffConsumers[digest]) == null ? void 0 : _a.length);
286
315
  const stuffRole = isInput ? "input" : isOutput ? "output" : void 0;
287
316
  const borderColor = isInput ? "var(--color-stuff-input-border, #50FA7B)" : isOutput ? "var(--color-stuff-output-border, #a78bfa)" : "var(--color-stuff-border)";
288
317
  nodes.push({
@@ -428,6 +457,216 @@ function buildGraph(graphspec, edgeType) {
428
457
  return { graphData: { nodes: [], edges: [] }, analysis: null };
429
458
  }
430
459
 
460
+ // src/graph/graphFolds.ts
461
+ function findCousinControllers(controllerId, graphspec, controllerNodeIds) {
462
+ const result = /* @__PURE__ */ new Set([controllerId]);
463
+ const clicked = graphspec.nodes.find((n) => n.id === controllerId);
464
+ const pipeCode = clicked == null ? void 0 : clicked.pipe_code;
465
+ if (!pipeCode) return result;
466
+ for (const node of graphspec.nodes) {
467
+ if (node.pipe_code !== pipeCode) continue;
468
+ if (!controllerNodeIds.has(node.id)) continue;
469
+ result.add(node.id);
470
+ }
471
+ return result;
472
+ }
473
+ function buildContainmentChain(nodeId, childToCtrl) {
474
+ const chain = [];
475
+ let current = childToCtrl[nodeId];
476
+ const seen = /* @__PURE__ */ new Set();
477
+ while (current && !seen.has(current)) {
478
+ chain.push(current);
479
+ seen.add(current);
480
+ current = childToCtrl[current];
481
+ }
482
+ return chain;
483
+ }
484
+ function outermostFoldedAncestor(nodeId, childToCtrl, foldedSet) {
485
+ const chain = buildContainmentChain(nodeId, childToCtrl);
486
+ let outermost = null;
487
+ for (const ancestorId of chain) {
488
+ if (foldedSet.has(ancestorId)) outermost = ancestorId;
489
+ }
490
+ return outermost;
491
+ }
492
+ function effectiveId(nodeId, childToCtrl, foldedSet) {
493
+ var _a;
494
+ return (_a = outermostFoldedAncestor(nodeId, childToCtrl, foldedSet)) != null ? _a : nodeId;
495
+ }
496
+ function findSpecNode(graphspec, id) {
497
+ return graphspec.nodes.find((n) => n.id === id);
498
+ }
499
+ function applyFolds(graphData, analysis, graphspec, foldedSet, onToggleFold) {
500
+ var _a, _b;
501
+ if (foldedSet.size === 0) {
502
+ return { nodes: graphData.nodes, edges: graphData.edges, analysis };
503
+ }
504
+ const childToCtrl = buildChildToControllerMap(graphspec, analysis);
505
+ const outputDeclarers = /* @__PURE__ */ new Map();
506
+ for (const controllerId of foldedSet) {
507
+ const ctrlNode = findSpecNode(graphspec, controllerId);
508
+ const outputs = (_a = ctrlNode == null ? void 0 : ctrlNode.io) == null ? void 0 : _a.outputs;
509
+ if (!outputs) continue;
510
+ for (const output of outputs) {
511
+ if (!output.digest) continue;
512
+ let set = outputDeclarers.get(output.digest);
513
+ if (!set) {
514
+ set = /* @__PURE__ */ new Set();
515
+ outputDeclarers.set(output.digest, set);
516
+ }
517
+ set.add(controllerId);
518
+ }
519
+ }
520
+ if (outputDeclarers.size > 0) {
521
+ for (const node of graphData.nodes) {
522
+ if (!isStuffNodeId(node.id)) continue;
523
+ const declarers = outputDeclarers.get(stuffDigestFromId(node.id));
524
+ if (!declarers) continue;
525
+ let current = childToCtrl[node.id];
526
+ let outermostDeclarer = null;
527
+ const seen = /* @__PURE__ */ new Set();
528
+ while (current && !seen.has(current)) {
529
+ seen.add(current);
530
+ if (declarers.has(current)) outermostDeclarer = current;
531
+ current = childToCtrl[current];
532
+ }
533
+ if (!outermostDeclarer) continue;
534
+ const newParent = childToCtrl[outermostDeclarer];
535
+ if (newParent) {
536
+ childToCtrl[node.id] = newParent;
537
+ } else {
538
+ delete childToCtrl[node.id];
539
+ }
540
+ }
541
+ }
542
+ const visibleNodes = [];
543
+ for (const node of graphData.nodes) {
544
+ if (outermostFoldedAncestor(node.id, childToCtrl, foldedSet)) continue;
545
+ visibleNodes.push(node);
546
+ }
547
+ for (const folded of foldedSet) {
548
+ if (outermostFoldedAncestor(folded, childToCtrl, foldedSet)) continue;
549
+ const specNode = findSpecNode(graphspec, folded);
550
+ if (!specNode) continue;
551
+ const payload = buildPipeCardPayload(specNode, graphspec, analysis);
552
+ if (onToggleFold) {
553
+ payload.onExpand = (options) => onToggleFold(folded, options);
554
+ }
555
+ const cardNode = {
556
+ id: folded,
557
+ type: NODE_TYPE_PIPE_CARD,
558
+ data: {
559
+ labelDescriptor: {
560
+ kind: "pipe",
561
+ label: payload.pipeCode,
562
+ isFailed: payload.status === "failed"
563
+ },
564
+ nodeData: specNode,
565
+ isPipe: false,
566
+ isStuff: false,
567
+ isController: true,
568
+ labelText: payload.pipeCode,
569
+ pipeCode: payload.pipeCode,
570
+ pipeType: specNode.pipe_type,
571
+ pipeCardData: payload
572
+ },
573
+ position: { x: 0, y: 0 }
574
+ };
575
+ visibleNodes.push(cardNode);
576
+ }
577
+ const updatedControllerIds = /* @__PURE__ */ new Set();
578
+ for (const ctrlId of analysis.controllerNodeIds) {
579
+ if (foldedSet.has(ctrlId)) continue;
580
+ if (outermostFoldedAncestor(ctrlId, childToCtrl, foldedSet)) continue;
581
+ updatedControllerIds.add(ctrlId);
582
+ }
583
+ const updatedContainmentTree = {};
584
+ for (const ctrlId of updatedControllerIds) {
585
+ const originalChildren = (_b = analysis.containmentTree[ctrlId]) != null ? _b : [];
586
+ const survivors = [];
587
+ for (const childId of originalChildren) {
588
+ const outer = outermostFoldedAncestor(childId, childToCtrl, foldedSet);
589
+ if (outer && outer !== childId) continue;
590
+ survivors.push(childId);
591
+ }
592
+ updatedContainmentTree[ctrlId] = survivors;
593
+ }
594
+ const updatedChildNodeIds = /* @__PURE__ */ new Set();
595
+ for (const children of Object.values(updatedContainmentTree)) {
596
+ for (const child of children) updatedChildNodeIds.add(child);
597
+ }
598
+ const updatedStuffProducers = {};
599
+ for (const [digest, producerId] of Object.entries(analysis.stuffProducers)) {
600
+ updatedStuffProducers[digest] = effectiveId(producerId, childToCtrl, foldedSet);
601
+ }
602
+ const updatedStuffConsumers = {};
603
+ for (const [digest, consumers] of Object.entries(analysis.stuffConsumers)) {
604
+ const seen = /* @__PURE__ */ new Set();
605
+ for (const consumerId of consumers) {
606
+ seen.add(effectiveId(consumerId, childToCtrl, foldedSet));
607
+ }
608
+ updatedStuffConsumers[digest] = [...seen];
609
+ }
610
+ const updatedAnalysis = {
611
+ stuffRegistry: analysis.stuffRegistry,
612
+ stuffProducers: updatedStuffProducers,
613
+ stuffConsumers: updatedStuffConsumers,
614
+ controllerNodeIds: updatedControllerIds,
615
+ childNodeIds: updatedChildNodeIds,
616
+ containmentTree: updatedContainmentTree
617
+ };
618
+ const dedupMap = /* @__PURE__ */ new Map();
619
+ for (const edge of graphData.edges) {
620
+ const newSrc = effectiveId(edge.source, childToCtrl, foldedSet);
621
+ const newDst = effectiveId(edge.target, childToCtrl, foldedSet);
622
+ if (newSrc === newDst) continue;
623
+ const bucket = edge._batchEdge ? "batch" : "data";
624
+ const key = `${newSrc}->${newDst}|${bucket}`;
625
+ if (dedupMap.has(key)) continue;
626
+ const cloned = __spreadProps(__spreadValues({}, edge), {
627
+ source: newSrc,
628
+ target: newDst,
629
+ id: edge.id
630
+ });
631
+ if (edge._batchEdge && (newSrc !== edge.source || newDst !== edge.target)) {
632
+ cloned.label = "[N]";
633
+ }
634
+ delete cloned._crossGroup;
635
+ dedupMap.set(key, cloned);
636
+ }
637
+ const foldedChildToCtrl = buildChildToControllerMap(
638
+ __spreadProps(__spreadValues({}, graphspec), {
639
+ // Mask out the contains edges for folded outermost controllers — they no
640
+ // longer logically contain anything after folding.
641
+ edges: graphspec.edges.filter((e) => {
642
+ if (e.kind !== "contains") return true;
643
+ return updatedControllerIds.has(e.source);
644
+ })
645
+ }),
646
+ updatedAnalysis
647
+ );
648
+ const rewrittenEdges = [];
649
+ for (const edge of dedupMap.values()) {
650
+ const srcCtrl = foldedChildToCtrl[edge.source] || null;
651
+ const tgtCtrl = foldedChildToCtrl[edge.target] || null;
652
+ if (srcCtrl && tgtCtrl && srcCtrl !== tgtCtrl) {
653
+ edge._crossGroup = true;
654
+ edge.style = __spreadProps(__spreadValues({}, edge.style), {
655
+ strokeWidth: 1.5,
656
+ opacity: 0.65
657
+ });
658
+ } else if (edge.style && (edge.style.opacity === 0.65 || edge.style.strokeWidth === 1.5)) {
659
+ const _c = edge.style, { opacity: _opacity, strokeWidth: _strokeWidth } = _c, rest = __objRest(_c, ["opacity", "strokeWidth"]);
660
+ edge.style = __spreadProps(__spreadValues({}, rest), { strokeWidth: 2 });
661
+ if (!edge.markerEnd) {
662
+ edge.markerEnd = { type: ARROW_CLOSED_MARKER, color: "var(--color-edge)" };
663
+ }
664
+ }
665
+ rewrittenEdges.push(edge);
666
+ }
667
+ return { nodes: visibleNodes, edges: rewrittenEdges, analysis: updatedAnalysis };
668
+ }
669
+
431
670
  // src/graph/elkGraphBuilder.ts
432
671
  function elkDirection(direction) {
433
672
  switch (direction) {
@@ -968,7 +1207,7 @@ function buildControllerNodes(graphspec, analysis, layoutedNodes, controllerPosi
968
1207
  }
969
1208
  return controllerNodes;
970
1209
  }
971
- function applyControllers(layoutedNodes, layoutedEdges, graphspec, analysis, showControllers, expandedControllers, onToggleCollapse, controllerPositions) {
1210
+ function applyControllers(layoutedNodes, layoutedEdges, graphspec, analysis, showControllers, expandedControllers, onToggleCollapse, controllerPositions, onToggleFold) {
972
1211
  var _a;
973
1212
  if (!showControllers || !analysis || !graphspec) {
974
1213
  return { nodes: layoutedNodes, edges: layoutedEdges };
@@ -978,13 +1217,13 @@ function applyControllers(layoutedNodes, layoutedEdges, graphspec, analysis, sho
978
1217
  const controllerTypeMap = {};
979
1218
  for (const node of graphspec.nodes) {
980
1219
  if (analysis.controllerNodeIds.has(node.id)) {
981
- controllerTypeMap[node.id] = node.pipe_type || "";
1220
+ controllerTypeMap[node.id] = node.pipe_type;
982
1221
  }
983
1222
  }
984
1223
  for (const ctrlId of analysis.controllerNodeIds) {
985
1224
  const directChildren = analysis.containmentTree[ctrlId] || [];
986
1225
  childCounts[ctrlId] = directChildren.length;
987
- const pipeType = controllerTypeMap[ctrlId] || "";
1226
+ const pipeType = controllerTypeMap[ctrlId];
988
1227
  const isCollapsible = pipeType === "PipeParallel" || pipeType === "PipeBatch";
989
1228
  if (isCollapsible && directChildren.length > MAX_VISIBLE_CONTROLLER_CHILDREN && !(expandedControllers == null ? void 0 : expandedControllers.has(ctrlId))) {
990
1229
  collapsedSet.add(ctrlId);
@@ -1050,6 +1289,10 @@ function applyControllers(layoutedNodes, layoutedEdges, graphspec, analysis, sho
1050
1289
  const id = cn.id;
1051
1290
  cn.data.onToggleCollapse = () => onToggleCollapse(id);
1052
1291
  }
1292
+ if (onToggleFold) {
1293
+ const id = cn.id;
1294
+ cn.data.onToggleFold = (options) => onToggleFold(id, options);
1295
+ }
1053
1296
  }
1054
1297
  const allNodes = [...controllerNodes, ...filteredNodes];
1055
1298
  const nodeMap = {};
@@ -1078,6 +1321,7 @@ function applyControllers(layoutedNodes, layoutedEdges, graphspec, analysis, sho
1078
1321
  var DEFAULT_GRAPH_CONFIG = {
1079
1322
  direction: "LR",
1080
1323
  showControllers: false,
1324
+ foldMode: FOLD_MODE.EXPANDED,
1081
1325
  nodesep: 50,
1082
1326
  ranksep: 100,
1083
1327
  edgeType: EDGE_TYPE.DEFAULT,
@@ -1127,6 +1371,7 @@ export {
1127
1371
  stuffDigestFromId,
1128
1372
  GRAPH_DIRECTION,
1129
1373
  EDGE_TYPE,
1374
+ FOLD_MODE,
1130
1375
  CONTROLLER_PADDING_X,
1131
1376
  CONTROLLER_PADDING_TOP,
1132
1377
  CONTROLLER_PADDING_BOTTOM,
@@ -1138,8 +1383,13 @@ export {
1138
1383
  getPipeBlueprint,
1139
1384
  getConceptInfo,
1140
1385
  resolveConceptRef,
1386
+ buildPipeCardPayload,
1141
1387
  buildDataflowGraph,
1142
1388
  buildGraph,
1389
+ findCousinControllers,
1390
+ buildContainmentChain,
1391
+ outermostFoldedAncestor,
1392
+ applyFolds,
1143
1393
  inputPortId,
1144
1394
  outputPortId,
1145
1395
  estimateNodeDimensions,
@@ -1152,4 +1402,4 @@ export {
1152
1402
  DEFAULT_GRAPH_CONFIG,
1153
1403
  getPaletteColors
1154
1404
  };
1155
- //# sourceMappingURL=chunk-OMJ6DRXM.js.map
1405
+ //# sourceMappingURL=chunk-NISDJYQJ.js.map