@bian-womp/spark-workbench 0.2.21 → 0.2.23
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.
- package/lib/cjs/index.cjs +186 -60
- package/lib/cjs/index.cjs.map +1 -1
- package/lib/cjs/src/misc/DefaultNode.d.ts.map +1 -1
- package/lib/cjs/src/misc/NodeHandles.d.ts.map +1 -1
- package/lib/cjs/src/misc/WorkbenchStudio.d.ts +3 -37
- package/lib/cjs/src/misc/WorkbenchStudio.d.ts.map +1 -1
- package/lib/cjs/src/misc/context/WorkbenchContext.d.ts +34 -1
- package/lib/cjs/src/misc/context/WorkbenchContext.d.ts.map +1 -1
- package/lib/cjs/src/misc/context/WorkbenchContext.provider.d.ts +3 -1
- package/lib/cjs/src/misc/context/WorkbenchContext.provider.d.ts.map +1 -1
- package/lib/cjs/src/misc/mapping.d.ts +1 -0
- package/lib/cjs/src/misc/mapping.d.ts.map +1 -1
- package/lib/cjs/src/runtime/LocalGraphRunner.d.ts.map +1 -1
- package/lib/esm/index.js +186 -60
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/src/misc/DefaultNode.d.ts.map +1 -1
- package/lib/esm/src/misc/NodeHandles.d.ts.map +1 -1
- package/lib/esm/src/misc/WorkbenchStudio.d.ts +3 -37
- package/lib/esm/src/misc/WorkbenchStudio.d.ts.map +1 -1
- package/lib/esm/src/misc/context/WorkbenchContext.d.ts +34 -1
- package/lib/esm/src/misc/context/WorkbenchContext.d.ts.map +1 -1
- package/lib/esm/src/misc/context/WorkbenchContext.provider.d.ts +3 -1
- package/lib/esm/src/misc/context/WorkbenchContext.provider.d.ts.map +1 -1
- package/lib/esm/src/misc/mapping.d.ts +1 -0
- package/lib/esm/src/misc/mapping.d.ts.map +1 -1
- package/lib/esm/src/runtime/LocalGraphRunner.d.ts.map +1 -1
- package/package.json +4 -4
package/lib/cjs/index.cjs
CHANGED
|
@@ -534,13 +534,19 @@ class LocalGraphRunner extends AbstractGraphRunner {
|
|
|
534
534
|
const def = undefined; // UI will supply def/positions on download for local
|
|
535
535
|
const inputs = this.getInputs(this.runtime
|
|
536
536
|
? {
|
|
537
|
-
nodes: Array.from(this.runtime.getNodeIds()).map((id) => ({
|
|
537
|
+
nodes: Array.from(this.runtime.getNodeIds()).map((id) => ({
|
|
538
|
+
nodeId: id,
|
|
539
|
+
typeId: "",
|
|
540
|
+
})),
|
|
538
541
|
edges: [],
|
|
539
542
|
}
|
|
540
543
|
: { nodes: [], edges: [] });
|
|
541
544
|
const outputs = this.getOutputs(this.runtime
|
|
542
545
|
? {
|
|
543
|
-
nodes: Array.from(this.runtime.getNodeIds()).map((id) => ({
|
|
546
|
+
nodes: Array.from(this.runtime.getNodeIds()).map((id) => ({
|
|
547
|
+
nodeId: id,
|
|
548
|
+
typeId: "",
|
|
549
|
+
})),
|
|
544
550
|
edges: [],
|
|
545
551
|
}
|
|
546
552
|
: { nodes: [], edges: [] });
|
|
@@ -1261,18 +1267,44 @@ function layoutNode(args) {
|
|
|
1261
1267
|
}
|
|
1262
1268
|
|
|
1263
1269
|
function toReactFlow(def, positions, registry, opts) {
|
|
1270
|
+
const EDGE_STYLE_MISSING = { stroke: "#f59e0b", strokeWidth: 2 }; // amber-500
|
|
1264
1271
|
const EDGE_STYLE_ERROR = { stroke: "#ef4444", strokeWidth: 2 };
|
|
1265
1272
|
const EDGE_STYLE_RUNNING = { stroke: "#3b82f6" };
|
|
1266
|
-
|
|
1267
|
-
|
|
1273
|
+
// Build a map of valid handles per node up-front
|
|
1274
|
+
const validHandleMap = {};
|
|
1275
|
+
for (const n of def.nodes) {
|
|
1276
|
+
const { inputs, outputs } = computeEffectiveHandles(n, registry);
|
|
1277
|
+
const inputOrder = Object.keys(inputs).filter((k) => !sparkGraph.isInputPrivate(inputs, k));
|
|
1278
|
+
const outputOrder = Object.keys(outputs);
|
|
1279
|
+
validHandleMap[n.nodeId] = {
|
|
1280
|
+
inputs: new Set(inputOrder),
|
|
1281
|
+
outputs: new Set(outputOrder),
|
|
1282
|
+
};
|
|
1283
|
+
}
|
|
1284
|
+
// Track which inputs are connected (for UI) and which handles are missing (for layout)
|
|
1268
1285
|
const connectedInputs = {};
|
|
1286
|
+
const missingInputsByNode = {};
|
|
1287
|
+
const missingOutputsByNode = {};
|
|
1269
1288
|
for (const e of def.edges) {
|
|
1270
|
-
const
|
|
1271
|
-
const
|
|
1272
|
-
if (!connectedInputs[
|
|
1273
|
-
connectedInputs[
|
|
1274
|
-
connectedInputs[
|
|
1275
|
-
|
|
1289
|
+
const tgtId = e.target.nodeId;
|
|
1290
|
+
const tgtHandle = e.target.handle;
|
|
1291
|
+
if (!connectedInputs[tgtId])
|
|
1292
|
+
connectedInputs[tgtId] = new Set();
|
|
1293
|
+
connectedInputs[tgtId].add(tgtHandle);
|
|
1294
|
+
const tgtValid = !!validHandleMap[tgtId]?.inputs.has(tgtHandle);
|
|
1295
|
+
if (!tgtValid) {
|
|
1296
|
+
(missingInputsByNode[tgtId] || (missingInputsByNode[tgtId] = new Set())).add(tgtHandle);
|
|
1297
|
+
}
|
|
1298
|
+
const srcId = e.source.nodeId;
|
|
1299
|
+
const srcHandle = e.source.handle;
|
|
1300
|
+
const srcValid = !!validHandleMap[srcId]?.outputs.has(srcHandle);
|
|
1301
|
+
if (!srcValid) {
|
|
1302
|
+
(missingOutputsByNode[srcId] || (missingOutputsByNode[srcId] = new Set())).add(srcHandle);
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
// This map is still used later for certain checks; align with valid handles
|
|
1306
|
+
const nodeHandleMap = {};
|
|
1307
|
+
Object.assign(nodeHandleMap, validHandleMap);
|
|
1276
1308
|
const nodes = def.nodes.map((n) => {
|
|
1277
1309
|
const { inputs: inputSource, outputs: outputSource } = computeEffectiveHandles(n, registry);
|
|
1278
1310
|
const overrideSize = opts.getDefaultNodeSize?.(n.typeId);
|
|
@@ -1294,11 +1326,61 @@ function toReactFlow(def, positions, registry, opts) {
|
|
|
1294
1326
|
inputs: new Set(inputHandles.map((h) => h.id)),
|
|
1295
1327
|
outputs: new Set(outputHandles.map((h) => h.id)),
|
|
1296
1328
|
};
|
|
1297
|
-
//
|
|
1329
|
+
// Append placeholder entries for any missing handles (below valid ones)
|
|
1330
|
+
const baseLeftCount = geom.inputOrder.length;
|
|
1331
|
+
const baseRightCount = geom.outputOrder.length;
|
|
1332
|
+
const extraInputs = Array.from(missingInputsByNode[n.nodeId] || []);
|
|
1333
|
+
const extraOutputs = Array.from(missingOutputsByNode[n.nodeId] || []);
|
|
1334
|
+
const HEADER = NODE_HEADER_HEIGHT_PX;
|
|
1335
|
+
const ROW = NODE_ROW_HEIGHT_PX;
|
|
1336
|
+
const extraHandleLayoutLeft = extraInputs.map((id, i) => ({
|
|
1337
|
+
id,
|
|
1338
|
+
type: "target",
|
|
1339
|
+
position: react.Position.Left,
|
|
1340
|
+
y: HEADER + (baseLeftCount + i) * ROW + ROW / 2,
|
|
1341
|
+
missing: true,
|
|
1342
|
+
}));
|
|
1343
|
+
const extraHandleLayoutRight = extraOutputs.map((id, i) => ({
|
|
1344
|
+
id,
|
|
1345
|
+
type: "source",
|
|
1346
|
+
position: react.Position.Right,
|
|
1347
|
+
y: HEADER + (baseRightCount + i) * ROW + ROW / 2,
|
|
1348
|
+
missing: true,
|
|
1349
|
+
}));
|
|
1350
|
+
const handleLayout = [
|
|
1351
|
+
...geom.handleLayout,
|
|
1352
|
+
...extraHandleLayoutLeft,
|
|
1353
|
+
...extraHandleLayoutRight,
|
|
1354
|
+
];
|
|
1355
|
+
// Precompute handle bounds (including missing) so edges can render immediately
|
|
1356
|
+
const missingBoundsLeft = extraInputs.map((id, i) => ({
|
|
1357
|
+
id,
|
|
1358
|
+
type: "target",
|
|
1359
|
+
position: react.Position.Left,
|
|
1360
|
+
x: 0,
|
|
1361
|
+
y: HEADER + (baseLeftCount + i) * ROW,
|
|
1362
|
+
width: 1,
|
|
1363
|
+
height: ROW + 2,
|
|
1364
|
+
}));
|
|
1365
|
+
const missingBoundsRight = extraOutputs.map((id, i) => ({
|
|
1366
|
+
id,
|
|
1367
|
+
type: "source",
|
|
1368
|
+
position: react.Position.Right,
|
|
1369
|
+
x: geom.width - 1,
|
|
1370
|
+
y: HEADER + (baseRightCount + i) * ROW,
|
|
1371
|
+
width: 1,
|
|
1372
|
+
height: ROW + 2,
|
|
1373
|
+
}));
|
|
1374
|
+
const handles = [
|
|
1375
|
+
...geom.handles,
|
|
1376
|
+
...missingBoundsLeft,
|
|
1377
|
+
...missingBoundsRight,
|
|
1378
|
+
];
|
|
1379
|
+
// Adjust node height to accommodate missing handle rows
|
|
1380
|
+
const baseRows = Math.max(baseLeftCount, baseRightCount);
|
|
1381
|
+
const newRows = Math.max(baseLeftCount + extraInputs.length, baseRightCount + extraOutputs.length);
|
|
1298
1382
|
const initialWidth = geom.width;
|
|
1299
|
-
const initialHeight = geom.height;
|
|
1300
|
-
// Precompute handle bounds so edges can render immediately without waiting for measurement
|
|
1301
|
-
const handles = geom.handles;
|
|
1383
|
+
const initialHeight = geom.height + Math.max(0, newRows - baseRows) * ROW;
|
|
1302
1384
|
return {
|
|
1303
1385
|
id: n.nodeId,
|
|
1304
1386
|
data: {
|
|
@@ -1310,7 +1392,7 @@ function toReactFlow(def, positions, registry, opts) {
|
|
|
1310
1392
|
h.id,
|
|
1311
1393
|
!!connectedInputs[n.nodeId]?.has(h.id),
|
|
1312
1394
|
])),
|
|
1313
|
-
handleLayout
|
|
1395
|
+
handleLayout,
|
|
1314
1396
|
showValues: opts.showValues,
|
|
1315
1397
|
renderWidth: initialWidth,
|
|
1316
1398
|
renderHeight: initialHeight,
|
|
@@ -1337,24 +1419,21 @@ function toReactFlow(def, positions, registry, opts) {
|
|
|
1337
1419
|
height: initialHeight,
|
|
1338
1420
|
};
|
|
1339
1421
|
});
|
|
1340
|
-
const edges = def.edges
|
|
1341
|
-
.filter((e) => {
|
|
1342
|
-
const src = nodeHandleMap[e.source.nodeId];
|
|
1343
|
-
const dst = nodeHandleMap[e.target.nodeId];
|
|
1344
|
-
if (!src || !dst)
|
|
1345
|
-
return false;
|
|
1346
|
-
return (src.outputs.has(e.source.handle) && dst.inputs.has(e.target.handle));
|
|
1347
|
-
})
|
|
1348
|
-
.map((e) => {
|
|
1422
|
+
const edges = def.edges.map((e) => {
|
|
1349
1423
|
const st = opts.edgeStatus?.[e.id];
|
|
1350
1424
|
const isRunning = !!st?.activeRuns;
|
|
1351
1425
|
const hasError = !!st?.lastError;
|
|
1352
1426
|
const isInvalidEdge = !!opts.edgeValidation?.[e.id];
|
|
1353
|
-
const
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1427
|
+
const sourceMissing = !validHandleMap[e.source.nodeId]?.outputs.has(e.source.handle);
|
|
1428
|
+
const targetMissing = !validHandleMap[e.target.nodeId]?.inputs.has(e.target.handle);
|
|
1429
|
+
const isMissing = sourceMissing || targetMissing;
|
|
1430
|
+
const style = isMissing
|
|
1431
|
+
? EDGE_STYLE_MISSING
|
|
1432
|
+
: hasError || isInvalidEdge
|
|
1433
|
+
? EDGE_STYLE_ERROR
|
|
1434
|
+
: isRunning
|
|
1435
|
+
? EDGE_STYLE_RUNNING
|
|
1436
|
+
: undefined;
|
|
1358
1437
|
return {
|
|
1359
1438
|
id: e.id,
|
|
1360
1439
|
source: e.source.nodeId,
|
|
@@ -1364,7 +1443,7 @@ function toReactFlow(def, positions, registry, opts) {
|
|
|
1364
1443
|
selected: opts.selectedEdgeIds
|
|
1365
1444
|
? opts.selectedEdgeIds.has(e.id)
|
|
1366
1445
|
: undefined,
|
|
1367
|
-
animated: isRunning,
|
|
1446
|
+
animated: isRunning && !isMissing,
|
|
1368
1447
|
style,
|
|
1369
1448
|
label: e.typeId || undefined,
|
|
1370
1449
|
};
|
|
@@ -1420,7 +1499,7 @@ function useWorkbenchContext() {
|
|
|
1420
1499
|
return ctx;
|
|
1421
1500
|
}
|
|
1422
1501
|
|
|
1423
|
-
function WorkbenchProvider({ wb, runner, registry, setRegistry, children, }) {
|
|
1502
|
+
function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, children, }) {
|
|
1424
1503
|
const [nodeStatus, setNodeStatus] = React.useState({});
|
|
1425
1504
|
const [edgeStatus, setEdgeStatus] = React.useState({});
|
|
1426
1505
|
const [events, setEvents] = React.useState([]);
|
|
@@ -1551,8 +1630,14 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, children, }) {
|
|
|
1551
1630
|
if (!node)
|
|
1552
1631
|
continue;
|
|
1553
1632
|
// Prefer showValues sizing similar to node rendering
|
|
1554
|
-
//
|
|
1555
|
-
const
|
|
1633
|
+
// Consider per-type overrides when available via UI
|
|
1634
|
+
const overrideSize = overrides?.getDefaultNodeSize?.(node.typeId) ?? undefined;
|
|
1635
|
+
const size = estimateNodeSize({
|
|
1636
|
+
node,
|
|
1637
|
+
registry,
|
|
1638
|
+
showValues: true,
|
|
1639
|
+
overrides: overrideSize,
|
|
1640
|
+
});
|
|
1556
1641
|
heights[id] = size.height;
|
|
1557
1642
|
if (size.width > maxWidth)
|
|
1558
1643
|
maxWidth = size.width;
|
|
@@ -1567,7 +1652,7 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, children, }) {
|
|
|
1567
1652
|
curX += maxWidth + H_GAP;
|
|
1568
1653
|
}
|
|
1569
1654
|
wb.setPositions(pos);
|
|
1570
|
-
}, [wb]);
|
|
1655
|
+
}, [wb, registry, overrides?.getDefaultNodeSize]);
|
|
1571
1656
|
const updateEdgeType = React.useCallback((edgeId, typeId) => wb.updateEdgeType(edgeId, typeId), [wb]);
|
|
1572
1657
|
const triggerExternal = React.useCallback((nodeId, event) => runner.triggerExternal(nodeId, event), [runner]);
|
|
1573
1658
|
// Subscribe to runner/workbench events
|
|
@@ -2155,6 +2240,17 @@ function Inspector({ debug, autoScroll, hideWorkbench, onAutoScrollChange, onHid
|
|
|
2155
2240
|
}, title: "Delete referenced edge", children: "Delete edge" }))] }, i))) })] }))] })) }), debug && (jsxRuntime.jsx("div", { className: "mt-3 flex-none min-h-0 h-[50%]", children: jsxRuntime.jsx(DebugEvents, { autoScroll: !!autoScroll, hideWorkbench: !!hideWorkbench, onAutoScrollChange: onAutoScrollChange, onHideWorkbenchChange: onHideWorkbenchChange }) }))] }));
|
|
2156
2241
|
}
|
|
2157
2242
|
|
|
2243
|
+
function NodeHandleItem({ kind, id, type, position, y, isConnectable, className, labelClassName, renderLabel, }) {
|
|
2244
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(react.Handle, { id: id, type: type, position: position, isConnectable: isConnectable, className: className, style: y !== undefined ? { top: y } : undefined }), renderLabel && (jsxRuntime.jsx("div", { className: labelClassName + (kind === "input" ? " left-2" : " right-2"), style: {
|
|
2245
|
+
top: (y ?? 0) - 8,
|
|
2246
|
+
...(kind === "input"
|
|
2247
|
+
? { right: "50%" }
|
|
2248
|
+
: { left: "50%", textAlign: "right" }),
|
|
2249
|
+
whiteSpace: "nowrap",
|
|
2250
|
+
overflow: "hidden",
|
|
2251
|
+
textOverflow: "ellipsis",
|
|
2252
|
+
}, children: renderLabel({ kind, id }) }))] }));
|
|
2253
|
+
}
|
|
2158
2254
|
function NodeHandles({ data, isConnectable, inputClassName = "!w-2 !h-2 !bg-gray-600", outputClassName = "!w-2 !h-2 !bg-gray-600", getClassName, renderLabel, labelClassName = "absolute text-[11px] text-gray-700 dark:text-gray-300 pointer-events-none", }) {
|
|
2159
2255
|
const layout = data.handleLayout ?? [];
|
|
2160
2256
|
const byId = React.useMemo(() => {
|
|
@@ -2165,40 +2261,49 @@ function NodeHandles({ data, isConnectable, inputClassName = "!w-2 !h-2 !bg-gray
|
|
|
2165
2261
|
position: h.position,
|
|
2166
2262
|
y: h.y,
|
|
2167
2263
|
type: h.type,
|
|
2264
|
+
missing: h.missing,
|
|
2168
2265
|
});
|
|
2169
2266
|
// Back-compat: also store by id-only if not already set
|
|
2170
2267
|
if (!m.has(h.id))
|
|
2171
|
-
m.set(h.id, {
|
|
2268
|
+
m.set(h.id, {
|
|
2269
|
+
position: h.position,
|
|
2270
|
+
y: h.y,
|
|
2271
|
+
type: h.type,
|
|
2272
|
+
missing: h.missing,
|
|
2273
|
+
});
|
|
2172
2274
|
}
|
|
2173
2275
|
return m;
|
|
2174
2276
|
}, [layout]);
|
|
2277
|
+
const inputIds = React.useMemo(() => new Set((data.inputHandles ?? []).map((h) => h.id)), [data.inputHandles]);
|
|
2278
|
+
const outputIds = React.useMemo(() => new Set((data.outputHandles ?? []).map((h) => h.id)), [data.outputHandles]);
|
|
2279
|
+
const missingInputs = React.useMemo(() => (layout || []).filter((h) => h.type === "target" && (!inputIds.has(h.id) || h.missing)), [layout, inputIds]);
|
|
2280
|
+
const missingOutputs = React.useMemo(() => (layout || []).filter((h) => h.type === "source" && (!outputIds.has(h.id) || h.missing)), [layout, outputIds]);
|
|
2175
2281
|
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [(data.inputHandles ?? []).map((h) => {
|
|
2176
2282
|
const placed = byId.get(`target:${h.id}`) ?? byId.get(h.id);
|
|
2177
2283
|
const position = placed?.position ?? react.Position.Left;
|
|
2178
2284
|
const y = placed?.y;
|
|
2179
2285
|
const cls = getClassName?.({ kind: "input", id: h.id, type: "target" }) ??
|
|
2180
2286
|
inputClassName;
|
|
2181
|
-
return (jsxRuntime.
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2287
|
+
return (jsxRuntime.jsx(NodeHandleItem, { kind: "input", id: h.id, type: "target", position: position, y: y, isConnectable: isConnectable, className: cls, labelClassName: labelClassName, renderLabel: renderLabel }, h.id));
|
|
2288
|
+
}), missingInputs.map((h) => {
|
|
2289
|
+
const key = `missing-input:${h.id}`;
|
|
2290
|
+
const position = h.position ?? react.Position.Left;
|
|
2291
|
+
const y = h.y;
|
|
2292
|
+
const cls = "!w-3 !h-3 !bg-amber-400 !border-amber-500";
|
|
2293
|
+
return (jsxRuntime.jsx(NodeHandleItem, { kind: "input", id: h.id, type: "target", position: position, y: y, isConnectable: false, className: cls, labelClassName: labelClassName, renderLabel: renderLabel }, key));
|
|
2188
2294
|
}), (data.outputHandles ?? []).map((h) => {
|
|
2189
2295
|
const placed = byId.get(`source:${h.id}`) ?? byId.get(h.id);
|
|
2190
2296
|
const position = placed?.position ?? react.Position.Right;
|
|
2191
2297
|
const y = placed?.y;
|
|
2192
2298
|
const cls = getClassName?.({ kind: "output", id: h.id, type: "source" }) ??
|
|
2193
2299
|
outputClassName;
|
|
2194
|
-
return (jsxRuntime.
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
}, children: renderLabel({ kind: "output", id: h.id }) }))] }, h.id));
|
|
2300
|
+
return (jsxRuntime.jsx(NodeHandleItem, { kind: "output", id: h.id, type: "source", position: position, y: y, isConnectable: isConnectable, className: `${cls} wb-nodrag wb-nowheel`, labelClassName: labelClassName, renderLabel: renderLabel }, h.id));
|
|
2301
|
+
}), missingOutputs.map((h) => {
|
|
2302
|
+
const key = `missing-output:${h.id}`;
|
|
2303
|
+
const position = h.position ?? react.Position.Right;
|
|
2304
|
+
const y = h.y;
|
|
2305
|
+
const cls = "!w-3 !h-3 !bg-amber-400 !border-amber-500 !rounded-none wb-nodrag wb-nowheel";
|
|
2306
|
+
return (jsxRuntime.jsx(NodeHandleItem, { kind: "output", id: h.id, type: "source", position: position, y: y, isConnectable: false, className: cls, labelClassName: labelClassName, renderLabel: renderLabel }, key));
|
|
2202
2307
|
})] }));
|
|
2203
2308
|
}
|
|
2204
2309
|
|
|
@@ -2262,6 +2367,18 @@ function DefaultNodeHeader({ id, title, validation, right, showId, onInvalidate,
|
|
|
2262
2367
|
}
|
|
2263
2368
|
function DefaultNodeContent({ data, isConnectable, }) {
|
|
2264
2369
|
const { showValues, inputValues, outputValues, toString } = data;
|
|
2370
|
+
const prettyHandle = React.useCallback((id) => {
|
|
2371
|
+
try {
|
|
2372
|
+
const parts = String(id).split(":");
|
|
2373
|
+
// If there are exactly 3 colons (4 parts), display only the second part
|
|
2374
|
+
if (parts.length === 4)
|
|
2375
|
+
return parts[1] || id;
|
|
2376
|
+
return id;
|
|
2377
|
+
}
|
|
2378
|
+
catch {
|
|
2379
|
+
return id;
|
|
2380
|
+
}
|
|
2381
|
+
}, []);
|
|
2265
2382
|
const inputEntries = data.inputHandles ?? [];
|
|
2266
2383
|
const outputEntries = data.outputHandles ?? [];
|
|
2267
2384
|
const status = data.status ?? { activeRuns: 0 };
|
|
@@ -2279,7 +2396,7 @@ function DefaultNodeContent({ data, isConnectable, }) {
|
|
|
2279
2396
|
const entries = kind === "input" ? inputEntries : outputEntries;
|
|
2280
2397
|
const entry = entries.find((e) => e.id === handleId);
|
|
2281
2398
|
if (!entry)
|
|
2282
|
-
return handleId;
|
|
2399
|
+
return prettyHandle(handleId);
|
|
2283
2400
|
const vIssues = (kind === "input" ? validation.inputs : validation.outputs).filter((v) => v.handle === handleId);
|
|
2284
2401
|
const hasAny = vIssues.length > 0;
|
|
2285
2402
|
const hasErr = vIssues.some((v) => v.level === "error");
|
|
@@ -2297,7 +2414,7 @@ function DefaultNodeContent({ data, isConnectable, }) {
|
|
|
2297
2414
|
const txt = toString(resolved.typeId, resolved.value);
|
|
2298
2415
|
return typeof txt === "string" ? txt : String(txt);
|
|
2299
2416
|
})();
|
|
2300
|
-
return (jsxRuntime.jsxs("span", { className: "flex items-center gap-1 w-full", children: [kind === "output" ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [valueText !== undefined ? (jsxRuntime.jsx("span", { className: "opacity-60 truncate pl-1", style: { flex: 1, minWidth: 0, maxWidth: "100%" }, children: valueText })) : (jsxRuntime.jsx("span", { style: { flex: 1, minWidth: 0, maxWidth: "100%" } })), jsxRuntime.jsx("span", { className: "truncate shrink-0", style: valueText !== undefined ? { maxWidth: "40%" } : {}, children: handleId })] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("span", { className: "truncate shrink-0", style: valueText !== undefined ? { maxWidth: "40%" } : {}, children: handleId }), valueText !== undefined && (jsxRuntime.jsx("span", { className: "opacity-60 truncate pr-1", style: { flex: 1, minWidth: 0, maxWidth: "100%" }, children: valueText }))] })), hasAny && (jsxRuntime.jsx(IssueBadge, { level: hasErr ? "error" : "warning", size: 12, className: "shrink-0", title: title }))] }));
|
|
2417
|
+
return (jsxRuntime.jsxs("span", { className: "flex items-center gap-1 w-full", children: [kind === "output" ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [valueText !== undefined ? (jsxRuntime.jsx("span", { className: "opacity-60 truncate pl-1", style: { flex: 1, minWidth: 0, maxWidth: "100%" }, children: valueText })) : (jsxRuntime.jsx("span", { style: { flex: 1, minWidth: 0, maxWidth: "100%" } })), jsxRuntime.jsx("span", { className: "truncate shrink-0", style: valueText !== undefined ? { maxWidth: "40%" } : {}, children: prettyHandle(handleId) })] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("span", { className: "truncate shrink-0", style: valueText !== undefined ? { maxWidth: "40%" } : {}, children: prettyHandle(handleId) }), valueText !== undefined && (jsxRuntime.jsx("span", { className: "opacity-60 truncate pr-1", style: { flex: 1, minWidth: 0, maxWidth: "100%" }, children: valueText }))] })), hasAny && (jsxRuntime.jsx(IssueBadge, { level: hasErr ? "error" : "warning", size: 12, className: "shrink-0", title: title }))] }));
|
|
2301
2418
|
} })] }));
|
|
2302
2419
|
}
|
|
2303
2420
|
|
|
@@ -2887,6 +3004,7 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
|
|
|
2887
3004
|
return overrides.getExamples(defaultExamples);
|
|
2888
3005
|
return defaultExamples;
|
|
2889
3006
|
}, [overrides, defaultExamples]);
|
|
3007
|
+
const [hydrated, setHydrated] = React.useState(false);
|
|
2890
3008
|
const lastAutoLaunched = React.useRef(undefined);
|
|
2891
3009
|
const autoLayoutRan = React.useRef(false);
|
|
2892
3010
|
const canvasRef = React.useRef(null);
|
|
@@ -2910,7 +3028,6 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
|
|
|
2910
3028
|
runner.setInputs(nodeId, map);
|
|
2911
3029
|
}
|
|
2912
3030
|
}
|
|
2913
|
-
runAutoLayout();
|
|
2914
3031
|
};
|
|
2915
3032
|
onInit({ wb, runner, setInitialGraph });
|
|
2916
3033
|
}, [onInit, wb, runner, runAutoLayout, registry, setRegistry]);
|
|
@@ -3098,7 +3215,7 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
|
|
|
3098
3215
|
createRuntime: () => ({
|
|
3099
3216
|
async onInputsChanged() { },
|
|
3100
3217
|
}),
|
|
3101
|
-
policy: {
|
|
3218
|
+
policy: { asyncConcurrency: "switch" },
|
|
3102
3219
|
};
|
|
3103
3220
|
r.categories.register(category);
|
|
3104
3221
|
}
|
|
@@ -3167,23 +3284,32 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
|
|
|
3167
3284
|
}, [engine, runner, wb, backendKind]);
|
|
3168
3285
|
// When switching to remote backend, auto-hydrate registry from backend
|
|
3169
3286
|
React.useEffect(() => {
|
|
3287
|
+
let hydrate;
|
|
3170
3288
|
if (backendKind === "remote-http" && httpBaseUrl) {
|
|
3171
|
-
hydrateFromBackend("remote-http", httpBaseUrl);
|
|
3289
|
+
hydrate = hydrateFromBackend("remote-http", httpBaseUrl);
|
|
3172
3290
|
}
|
|
3173
3291
|
else if (backendKind === "remote-ws" && wsUrl) {
|
|
3174
|
-
hydrateFromBackend("remote-ws", wsUrl);
|
|
3292
|
+
hydrate = hydrateFromBackend("remote-ws", wsUrl);
|
|
3175
3293
|
}
|
|
3176
|
-
|
|
3294
|
+
if (hydrate) {
|
|
3295
|
+
hydrate.then(() => {
|
|
3296
|
+
setHydrated(true);
|
|
3297
|
+
});
|
|
3298
|
+
}
|
|
3299
|
+
}, [backendKind, httpBaseUrl, wsUrl, hydrateFromBackend, setHydrated]);
|
|
3177
3300
|
React.useEffect(() => {
|
|
3178
3301
|
if (autoLayoutRan.current)
|
|
3179
3302
|
return;
|
|
3303
|
+
if (backendKind !== "local" && !hydrated)
|
|
3304
|
+
return;
|
|
3180
3305
|
const cur = wb.export();
|
|
3181
|
-
const
|
|
3306
|
+
const positions = wb.getPositions();
|
|
3307
|
+
const allMissing = cur.nodes.every((n) => !positions[n.nodeId]);
|
|
3182
3308
|
if (allMissing) {
|
|
3183
3309
|
autoLayoutRan.current = true;
|
|
3184
3310
|
runAutoLayout();
|
|
3185
3311
|
}
|
|
3186
|
-
}, [wb, runAutoLayout]);
|
|
3312
|
+
}, [wb, runAutoLayout, backendKind, hydrated]);
|
|
3187
3313
|
const baseSetInput = React.useCallback((handle, raw) => {
|
|
3188
3314
|
if (!selectedNodeId)
|
|
3189
3315
|
return;
|
|
@@ -3409,7 +3535,7 @@ function WorkbenchStudio({ engine, onEngineChange, example, onExampleChange, bac
|
|
|
3409
3535
|
overrides?.registerUI?.(baseRegisterUI, { wb, wbRunner: runner });
|
|
3410
3536
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
3411
3537
|
}, [wb, runner, overrides]);
|
|
3412
|
-
return (jsxRuntime.jsx(WorkbenchProvider, { wb: wb, runner: runner, registry: registry, setRegistry: setRegistry, children: jsxRuntime.jsx(WorkbenchStudioCanvas, { setRegistry: setRegistry, autoScroll: autoScroll, onAutoScrollChange: onAutoScrollChange, example: example, onExampleChange: onExampleChange, engine: engine, onEngineChange: onEngineChange, backendKind: backendKind, onBackendKindChange: (v) => {
|
|
3538
|
+
return (jsxRuntime.jsx(WorkbenchProvider, { wb: wb, runner: runner, registry: registry, setRegistry: setRegistry, overrides: overrides, children: jsxRuntime.jsx(WorkbenchStudioCanvas, { setRegistry: setRegistry, autoScroll: autoScroll, onAutoScrollChange: onAutoScrollChange, example: example, onExampleChange: onExampleChange, engine: engine, onEngineChange: onEngineChange, backendKind: backendKind, onBackendKindChange: (v) => {
|
|
3413
3539
|
if (runner.isRunning())
|
|
3414
3540
|
runner.dispose();
|
|
3415
3541
|
onBackendKindChange(v);
|