@bian-womp/spark-workbench 0.2.8 → 0.2.10
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 +231 -29
- package/lib/cjs/index.cjs.map +1 -1
- package/lib/cjs/src/core/AbstractWorkbench.d.ts +2 -2
- package/lib/cjs/src/core/AbstractWorkbench.d.ts.map +1 -1
- package/lib/cjs/src/core/InMemoryWorkbench.d.ts +2 -2
- package/lib/cjs/src/core/InMemoryWorkbench.d.ts.map +1 -1
- package/lib/cjs/src/core/contracts.d.ts +2 -2
- package/lib/cjs/src/core/contracts.d.ts.map +1 -1
- package/lib/cjs/src/misc/DefaultNode.d.ts +18 -1
- package/lib/cjs/src/misc/DefaultNode.d.ts.map +1 -1
- package/lib/cjs/src/misc/NodeContextMenu.d.ts.map +1 -1
- package/lib/cjs/src/misc/WorkbenchCanvas.d.ts.map +1 -1
- package/lib/cjs/src/misc/WorkbenchStudio.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/IGraphRunner.d.ts +1 -0
- package/lib/cjs/src/runtime/IGraphRunner.d.ts.map +1 -1
- package/lib/cjs/src/runtime/RemoteGraphRunner.d.ts +1 -0
- package/lib/cjs/src/runtime/RemoteGraphRunner.d.ts.map +1 -1
- package/lib/esm/index.js +231 -30
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/src/core/AbstractWorkbench.d.ts +2 -2
- package/lib/esm/src/core/AbstractWorkbench.d.ts.map +1 -1
- package/lib/esm/src/core/InMemoryWorkbench.d.ts +2 -2
- package/lib/esm/src/core/InMemoryWorkbench.d.ts.map +1 -1
- package/lib/esm/src/core/contracts.d.ts +2 -2
- package/lib/esm/src/core/contracts.d.ts.map +1 -1
- package/lib/esm/src/misc/DefaultNode.d.ts +18 -1
- package/lib/esm/src/misc/DefaultNode.d.ts.map +1 -1
- package/lib/esm/src/misc/NodeContextMenu.d.ts.map +1 -1
- package/lib/esm/src/misc/WorkbenchCanvas.d.ts.map +1 -1
- package/lib/esm/src/misc/WorkbenchStudio.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/IGraphRunner.d.ts +1 -0
- package/lib/esm/src/runtime/IGraphRunner.d.ts.map +1 -1
- package/lib/esm/src/runtime/RemoteGraphRunner.d.ts +1 -0
- package/lib/esm/src/runtime/RemoteGraphRunner.d.ts.map +1 -1
- package/package.json +4 -4
package/lib/cjs/index.cjs
CHANGED
|
@@ -169,6 +169,7 @@ class InMemoryWorkbench extends AbstractWorkbench {
|
|
|
169
169
|
change: { type: "addNode", nodeId: id },
|
|
170
170
|
});
|
|
171
171
|
this.refreshValidation();
|
|
172
|
+
return id;
|
|
172
173
|
}
|
|
173
174
|
removeNode(nodeId) {
|
|
174
175
|
this.def.nodes = this.def.nodes.filter((n) => n.nodeId !== nodeId);
|
|
@@ -193,6 +194,7 @@ class InMemoryWorkbench extends AbstractWorkbench {
|
|
|
193
194
|
change: { type: "connect", edgeId: id },
|
|
194
195
|
});
|
|
195
196
|
this.refreshValidation();
|
|
197
|
+
return id;
|
|
196
198
|
}
|
|
197
199
|
disconnect(edgeId) {
|
|
198
200
|
this.def.edges = this.def.edges.filter((e) => e.id !== edgeId);
|
|
@@ -548,6 +550,7 @@ class RemoteGraphRunner extends AbstractGraphRunner {
|
|
|
548
550
|
displayName: d.displayName,
|
|
549
551
|
options: d.options,
|
|
550
552
|
opts: d.opts,
|
|
553
|
+
bakeTarget: d.bakeTarget,
|
|
551
554
|
});
|
|
552
555
|
}
|
|
553
556
|
else if (d.kind === "register-type") {
|
|
@@ -556,6 +559,7 @@ class RemoteGraphRunner extends AbstractGraphRunner {
|
|
|
556
559
|
id: d.id,
|
|
557
560
|
displayName: d.displayName,
|
|
558
561
|
validate: (_v) => true,
|
|
562
|
+
bakeTarget: d.bakeTarget,
|
|
559
563
|
});
|
|
560
564
|
}
|
|
561
565
|
}
|
|
@@ -678,6 +682,15 @@ class RemoteGraphRunner extends AbstractGraphRunner {
|
|
|
678
682
|
catch { }
|
|
679
683
|
});
|
|
680
684
|
}
|
|
685
|
+
async coerce(from, to, value) {
|
|
686
|
+
const runner = await this.ensureRemoteRunner();
|
|
687
|
+
try {
|
|
688
|
+
return await runner.coerce(from, to, value);
|
|
689
|
+
}
|
|
690
|
+
catch {
|
|
691
|
+
return value;
|
|
692
|
+
}
|
|
693
|
+
}
|
|
681
694
|
getOutputs(def) {
|
|
682
695
|
const out = {};
|
|
683
696
|
const cache = this.valueCache;
|
|
@@ -1108,6 +1121,15 @@ function toReactFlow(def, positions, registry, opts) {
|
|
|
1108
1121
|
const EDGE_STYLE_ERROR = { stroke: "#ef4444", strokeWidth: 2 };
|
|
1109
1122
|
const EDGE_STYLE_RUNNING = { stroke: "#3b82f6" };
|
|
1110
1123
|
const nodeHandleMap = {};
|
|
1124
|
+
// Precompute which inputs are connected per node
|
|
1125
|
+
const connectedInputs = {};
|
|
1126
|
+
for (const e of def.edges) {
|
|
1127
|
+
const nid = e.target.nodeId;
|
|
1128
|
+
const hid = e.target.handle;
|
|
1129
|
+
if (!connectedInputs[nid])
|
|
1130
|
+
connectedInputs[nid] = new Set();
|
|
1131
|
+
connectedInputs[nid].add(hid);
|
|
1132
|
+
}
|
|
1111
1133
|
const nodes = def.nodes.map((n) => {
|
|
1112
1134
|
const desc = registry.nodes.get(n.typeId);
|
|
1113
1135
|
const inputHandles = Object.entries(desc?.inputs ?? {})
|
|
@@ -1156,6 +1178,10 @@ function toReactFlow(def, positions, registry, opts) {
|
|
|
1156
1178
|
params: n.params,
|
|
1157
1179
|
inputHandles,
|
|
1158
1180
|
outputHandles,
|
|
1181
|
+
inputConnected: Object.fromEntries(inputHandles.map((h) => [
|
|
1182
|
+
h.id,
|
|
1183
|
+
!!connectedInputs[n.nodeId]?.has(h.id),
|
|
1184
|
+
])),
|
|
1159
1185
|
handleLayout: [
|
|
1160
1186
|
...inputHandles.map((h, i) => ({
|
|
1161
1187
|
id: h.id,
|
|
@@ -2029,17 +2055,37 @@ const DefaultNode = React.memo(function DefaultNode({ id, data, selected, isConn
|
|
|
2029
2055
|
position: "relative",
|
|
2030
2056
|
minWidth: typeof data.renderWidth === "number" ? data.renderWidth : undefined,
|
|
2031
2057
|
minHeight: typeof data.renderHeight === "number" ? data.renderHeight : undefined,
|
|
2032
|
-
}, children: [jsxRuntime.
|
|
2033
|
-
maxHeight: NODE_HEADER_HEIGHT_PX,
|
|
2034
|
-
minHeight: NODE_HEADER_HEIGHT_PX,
|
|
2035
|
-
}, children: [jsxRuntime.jsx("strong", { className: "flex-1 h-full text-sm", style: { lineHeight: `${NODE_HEADER_HEIGHT_PX}px` }, children: typeId }), jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [validation.issues && validation.issues.length > 0 && (jsxRuntime.jsx(IssueBadge, { level: validation.issues.some((i) => i.level === "error")
|
|
2036
|
-
? "error"
|
|
2037
|
-
: "warning", size: 12, className: "w-3 h-3", title: validation.issues
|
|
2038
|
-
.map((v) => `${v.code}: ${v.message}`)
|
|
2039
|
-
.join("; ") })), jsxRuntime.jsxs("span", { className: "text-[10px] opacity-70", children: ["(", id, ")"] })] })] }), jsxRuntime.jsx(DefaultNodeContent, { data: data, isConnectable: isConnectable })] }));
|
|
2058
|
+
}, children: [jsxRuntime.jsx(DefaultNodeHeader, { id: id, title: typeId, status: status, validation: validation }), jsxRuntime.jsx(DefaultNodeContent, { id: id, data: data, isConnectable: isConnectable })] }));
|
|
2040
2059
|
});
|
|
2041
2060
|
DefaultNode.displayName = "DefaultNode";
|
|
2042
|
-
function
|
|
2061
|
+
function DefaultNodeHeader({ id, title, status, validation, right, onInvalidate, }) {
|
|
2062
|
+
const ctx = useWorkbenchContext();
|
|
2063
|
+
const handleInvalidate = React.useCallback(() => {
|
|
2064
|
+
try {
|
|
2065
|
+
if (onInvalidate)
|
|
2066
|
+
return onInvalidate();
|
|
2067
|
+
const kind = ctx.engineKind?.();
|
|
2068
|
+
if (kind === "pull")
|
|
2069
|
+
ctx.runner.computeNode(id);
|
|
2070
|
+
else
|
|
2071
|
+
ctx.triggerExternal?.(id, { type: "invalidate" });
|
|
2072
|
+
}
|
|
2073
|
+
catch { }
|
|
2074
|
+
}, [ctx, id, onInvalidate]);
|
|
2075
|
+
return (jsxRuntime.jsxs("div", { className: "flex items-center justify-center px-2 border-b border-solid border-gray-500 dark:border-gray-400 text-gray-600 dark:text-gray-300", style: {
|
|
2076
|
+
maxHeight: NODE_HEADER_HEIGHT_PX,
|
|
2077
|
+
minHeight: NODE_HEADER_HEIGHT_PX,
|
|
2078
|
+
}, children: [jsxRuntime.jsx("strong", { className: "flex-1 h-full text-sm", style: { lineHeight: `${NODE_HEADER_HEIGHT_PX}px` }, children: title }), jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [jsxRuntime.jsx("button", { className: "w-4 h-4 border border-gray-400 rounded text-[10px] leading-3 flex items-center justify-center", title: "Invalidate and re-run", onClick: (e) => {
|
|
2079
|
+
e.stopPropagation();
|
|
2080
|
+
handleInvalidate();
|
|
2081
|
+
}, children: "\u21BB" }), right, validation.issues && validation.issues.length > 0 && (jsxRuntime.jsx(IssueBadge, { level: validation.issues.some((i) => i.level === "error")
|
|
2082
|
+
? "error"
|
|
2083
|
+
: "warning", size: 12, className: "w-3 h-3", title: validation.issues
|
|
2084
|
+
.map((v) => `${v.code}: ${v.message}`)
|
|
2085
|
+
.join("; ") })), jsxRuntime.jsxs("span", { className: "text-[10px] opacity-70", children: ["(", id, ")"] })] })] }));
|
|
2086
|
+
}
|
|
2087
|
+
function DefaultNodeContent({ id, data, isConnectable, }) {
|
|
2088
|
+
useWorkbenchContext();
|
|
2043
2089
|
const { showValues, inputValues, outputValues, toString } = data;
|
|
2044
2090
|
const inputEntries = data.inputHandles ?? [];
|
|
2045
2091
|
const outputEntries = data.outputHandles ?? [];
|
|
@@ -2054,12 +2100,12 @@ function DefaultNodeContent({ data, isConnectable, }) {
|
|
|
2054
2100
|
const hasAny = vIssues.length > 0;
|
|
2055
2101
|
const hasErr = vIssues.some((v) => v.level === "error");
|
|
2056
2102
|
return cx("!w-3 !h-3 !bg-white !dark:bg-stone-900 !border-gray-500 dark:!border-gray-400", kind === "output" && "!rounded-none", hasAny && (hasErr ? "!border-red-500" : "!border-amber-500"));
|
|
2057
|
-
}, renderLabel: ({ kind, id }) => {
|
|
2103
|
+
}, renderLabel: ({ kind, id: handleId }) => {
|
|
2058
2104
|
const entries = kind === "input" ? inputEntries : outputEntries;
|
|
2059
|
-
const entry = entries.find((e) => e.id ===
|
|
2105
|
+
const entry = entries.find((e) => e.id === handleId);
|
|
2060
2106
|
if (!entry)
|
|
2061
|
-
return
|
|
2062
|
-
const vIssues = (kind === "input" ? validation.inputs : validation.outputs).filter((v) => v.handle ===
|
|
2107
|
+
return handleId;
|
|
2108
|
+
const vIssues = (kind === "input" ? validation.inputs : validation.outputs).filter((v) => v.handle === handleId);
|
|
2063
2109
|
const hasAny = vIssues.length > 0;
|
|
2064
2110
|
const hasErr = vIssues.some((v) => v.level === "error");
|
|
2065
2111
|
const title = vIssues
|
|
@@ -2076,7 +2122,7 @@ function DefaultNodeContent({ data, isConnectable, }) {
|
|
|
2076
2122
|
const txt = toString(resolved.typeId, resolved.value);
|
|
2077
2123
|
return typeof txt === "string" ? txt : String(txt);
|
|
2078
2124
|
})();
|
|
2079
|
-
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", { className: "truncate shrink-0", style: { maxWidth: "40%" }, children:
|
|
2125
|
+
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", { className: "truncate shrink-0", style: { maxWidth: "40%" }, children: handleId })] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("span", { className: "truncate shrink-0", style: { 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 }))] }));
|
|
2080
2126
|
} })] }));
|
|
2081
2127
|
}
|
|
2082
2128
|
|
|
@@ -2167,7 +2213,7 @@ function DefaultContextMenu({ open, clientPos, onAdd, onClose, }) {
|
|
|
2167
2213
|
}
|
|
2168
2214
|
|
|
2169
2215
|
function NodeContextMenu({ open, clientPos, nodeId, onClose, }) {
|
|
2170
|
-
const { wb, runner, engineKind } = useWorkbenchContext();
|
|
2216
|
+
const { wb, runner, engineKind, registry, outputsMap, outputTypesMap } = useWorkbenchContext();
|
|
2171
2217
|
const ref = React.useRef(null);
|
|
2172
2218
|
// outside click + ESC
|
|
2173
2219
|
React.useEffect(() => {
|
|
@@ -2202,39 +2248,181 @@ function NodeContextMenu({ open, clientPos, nodeId, onClose, }) {
|
|
|
2202
2248
|
const x = Math.min(clientPos.x, (typeof window !== "undefined" ? window.innerWidth : 0) -
|
|
2203
2249
|
(MENU_MIN_WIDTH + PADDING));
|
|
2204
2250
|
const y = Math.min(clientPos.y, (typeof window !== "undefined" ? window.innerHeight : 0) - 240);
|
|
2251
|
+
// Bake helpers
|
|
2252
|
+
const getBakeableOutputs = () => {
|
|
2253
|
+
try {
|
|
2254
|
+
const def = wb.export();
|
|
2255
|
+
const node = def.nodes.find((n) => n.nodeId === nodeId);
|
|
2256
|
+
if (!node)
|
|
2257
|
+
return [];
|
|
2258
|
+
const desc = registry.nodes.get(node.typeId);
|
|
2259
|
+
const handles = Object.keys(desc?.outputs || {});
|
|
2260
|
+
const out = [];
|
|
2261
|
+
for (const h of handles) {
|
|
2262
|
+
const tId = outputTypesMap?.[nodeId]?.[h];
|
|
2263
|
+
if (!tId)
|
|
2264
|
+
continue;
|
|
2265
|
+
if (tId.endsWith("[]")) {
|
|
2266
|
+
const base = tId.slice(0, -2);
|
|
2267
|
+
const tArr = registry.types.get(tId);
|
|
2268
|
+
const tElem = registry.types.get(base);
|
|
2269
|
+
const arrT = tArr?.bakeTarget;
|
|
2270
|
+
const elemT = tElem?.bakeTarget;
|
|
2271
|
+
if ((arrT && registry.nodes.has(arrT.nodeTypeId)) ||
|
|
2272
|
+
(elemT && registry.nodes.has(elemT.nodeTypeId)))
|
|
2273
|
+
out.push(h);
|
|
2274
|
+
}
|
|
2275
|
+
else {
|
|
2276
|
+
const t = registry.types.get(tId);
|
|
2277
|
+
const bt = t?.bakeTarget;
|
|
2278
|
+
if (bt && registry.nodes.has(bt.nodeTypeId))
|
|
2279
|
+
out.push(h);
|
|
2280
|
+
}
|
|
2281
|
+
}
|
|
2282
|
+
return out;
|
|
2283
|
+
}
|
|
2284
|
+
catch {
|
|
2285
|
+
return [];
|
|
2286
|
+
}
|
|
2287
|
+
};
|
|
2288
|
+
const doBake = async (handleId) => {
|
|
2289
|
+
try {
|
|
2290
|
+
const typeId = outputTypesMap?.[nodeId]?.[handleId];
|
|
2291
|
+
const raw = outputsMap?.[nodeId]?.[handleId];
|
|
2292
|
+
if (!typeId || raw === undefined)
|
|
2293
|
+
return;
|
|
2294
|
+
const unwrap = (v) => sparkGraph.isTypedOutput(v) ? sparkGraph.getTypedOutputValue(v) : v;
|
|
2295
|
+
const clone = (v) => typeof structuredClone === "function"
|
|
2296
|
+
? structuredClone(v)
|
|
2297
|
+
: JSON.parse(JSON.stringify(v));
|
|
2298
|
+
const coerceIfNeeded = async (fromType, toType, value) => {
|
|
2299
|
+
if (!toType || toType === fromType || !runner?.coerce)
|
|
2300
|
+
return value;
|
|
2301
|
+
try {
|
|
2302
|
+
return await runner.coerce(fromType, toType, value);
|
|
2303
|
+
}
|
|
2304
|
+
catch {
|
|
2305
|
+
return value;
|
|
2306
|
+
}
|
|
2307
|
+
};
|
|
2308
|
+
const pos = wb.getPositions?.()[nodeId] || { x: 0, y: 0 };
|
|
2309
|
+
const isArray = typeId.endsWith("[]");
|
|
2310
|
+
const baseTypeId = isArray ? typeId.slice(0, -2) : typeId;
|
|
2311
|
+
const tArr = isArray ? registry.types.get(typeId) : undefined;
|
|
2312
|
+
const tElem = registry.types.get(baseTypeId);
|
|
2313
|
+
const singleTarget = !isArray ? tElem?.bakeTarget : undefined;
|
|
2314
|
+
const arrTarget = isArray ? tArr?.bakeTarget : undefined;
|
|
2315
|
+
const elemTarget = isArray ? tElem?.bakeTarget : undefined;
|
|
2316
|
+
if (singleTarget) {
|
|
2317
|
+
const nodeDesc = registry.nodes.get(String(singleTarget.nodeTypeId));
|
|
2318
|
+
const inType = sparkGraph.getInputTypeId(nodeDesc?.inputs, String(singleTarget.inputHandle || "Value"));
|
|
2319
|
+
const coerced = await coerceIfNeeded(typeId, inType, unwrap(raw));
|
|
2320
|
+
const newId = wb.addNode({
|
|
2321
|
+
typeId: String(singleTarget.nodeTypeId),
|
|
2322
|
+
position: { x: pos.x + 180, y: pos.y },
|
|
2323
|
+
params: {},
|
|
2324
|
+
});
|
|
2325
|
+
runner.update(wb.export());
|
|
2326
|
+
await runner.whenIdle();
|
|
2327
|
+
runner.setInputs(newId, {
|
|
2328
|
+
[String(singleTarget.inputHandle || "Value")]: coerced,
|
|
2329
|
+
});
|
|
2330
|
+
return;
|
|
2331
|
+
}
|
|
2332
|
+
if (isArray && arrTarget) {
|
|
2333
|
+
const nodeDesc = registry.nodes.get(String(arrTarget.nodeTypeId));
|
|
2334
|
+
const inType = sparkGraph.getInputTypeId(nodeDesc?.inputs, String(arrTarget.inputHandle || "Value"));
|
|
2335
|
+
const coerced = await coerceIfNeeded(typeId, inType, unwrap(raw));
|
|
2336
|
+
const newId = `n${Math.random().toString(36).slice(2, 8)}`;
|
|
2337
|
+
wb.addNode({
|
|
2338
|
+
nodeId: newId,
|
|
2339
|
+
typeId: String(arrTarget.nodeTypeId),
|
|
2340
|
+
position: { x: pos.x + 180, y: pos.y },
|
|
2341
|
+
params: {},
|
|
2342
|
+
});
|
|
2343
|
+
runner.update(wb.export());
|
|
2344
|
+
await runner.whenIdle();
|
|
2345
|
+
runner.setInputs(newId, {
|
|
2346
|
+
[String(arrTarget.inputHandle || "Value")]: coerced,
|
|
2347
|
+
});
|
|
2348
|
+
return;
|
|
2349
|
+
}
|
|
2350
|
+
if (isArray && elemTarget && Array.isArray(raw)) {
|
|
2351
|
+
const nodeDesc = registry.nodes.get(String(elemTarget.nodeTypeId));
|
|
2352
|
+
const inType = sparkGraph.getInputTypeId(nodeDesc?.inputs, String(elemTarget.inputHandle || "Value"));
|
|
2353
|
+
const items = raw.map(unwrap);
|
|
2354
|
+
const coercedItems = await Promise.all(items.map((v) => coerceIfNeeded(baseTypeId, inType, v)));
|
|
2355
|
+
const COLS = 4;
|
|
2356
|
+
const DX = 180;
|
|
2357
|
+
const DY = 160;
|
|
2358
|
+
for (let idx = 0; idx < coercedItems.length; idx++) {
|
|
2359
|
+
const cv = coercedItems[idx];
|
|
2360
|
+
const col = idx % COLS;
|
|
2361
|
+
const row = Math.floor(idx / COLS);
|
|
2362
|
+
const newId = wb.addNode({
|
|
2363
|
+
typeId: String(elemTarget.nodeTypeId),
|
|
2364
|
+
position: { x: pos.x + (col + 1) * DX, y: pos.y + row * DY },
|
|
2365
|
+
params: {},
|
|
2366
|
+
initialInputs: {
|
|
2367
|
+
[String(elemTarget.inputHandle || "Value")]: clone(cv),
|
|
2368
|
+
},
|
|
2369
|
+
});
|
|
2370
|
+
runner.update(wb.export());
|
|
2371
|
+
await runner.whenIdle();
|
|
2372
|
+
runner.setInputs(newId, {
|
|
2373
|
+
[String(elemTarget.inputHandle || "Value")]: cv,
|
|
2374
|
+
});
|
|
2375
|
+
}
|
|
2376
|
+
return;
|
|
2377
|
+
}
|
|
2378
|
+
}
|
|
2379
|
+
catch { }
|
|
2380
|
+
};
|
|
2205
2381
|
// actions
|
|
2206
|
-
const handleDelete = () => {
|
|
2382
|
+
const handleDelete = React.useCallback(() => {
|
|
2207
2383
|
wb.removeNode(nodeId);
|
|
2208
2384
|
onClose();
|
|
2209
|
-
};
|
|
2210
|
-
const handleDuplicate = () => {
|
|
2385
|
+
}, [nodeId, wb, onClose]);
|
|
2386
|
+
const handleDuplicate = React.useCallback(() => {
|
|
2211
2387
|
const def = wb.export();
|
|
2212
2388
|
const n = def.nodes.find((n) => n.nodeId === nodeId);
|
|
2213
2389
|
if (!n)
|
|
2214
2390
|
return onClose();
|
|
2215
2391
|
const pos = wb.getPositions?.()[nodeId] || { x: 0, y: 0 };
|
|
2216
|
-
wb.addNode({
|
|
2392
|
+
wb.addNode({
|
|
2393
|
+
typeId: n.typeId,
|
|
2394
|
+
params: n.params,
|
|
2395
|
+
position: { x: pos.x + 24, y: pos.y + 24 },
|
|
2396
|
+
});
|
|
2217
2397
|
onClose();
|
|
2218
|
-
};
|
|
2219
|
-
|
|
2398
|
+
}, [nodeId, wb, onClose]);
|
|
2399
|
+
React.useCallback(async (handleId) => {
|
|
2400
|
+
await doBake(handleId);
|
|
2401
|
+
onClose();
|
|
2402
|
+
}, [doBake, onClose]);
|
|
2403
|
+
const handleCopyId = React.useCallback(async () => {
|
|
2220
2404
|
try {
|
|
2221
2405
|
await navigator.clipboard.writeText(nodeId);
|
|
2222
2406
|
}
|
|
2223
2407
|
catch { }
|
|
2224
2408
|
onClose();
|
|
2225
|
-
};
|
|
2226
|
-
const
|
|
2227
|
-
const handleRunPull = async () => {
|
|
2409
|
+
}, [nodeId, onClose]);
|
|
2410
|
+
const handleRunPull = React.useCallback(async () => {
|
|
2228
2411
|
try {
|
|
2229
2412
|
await runner.computeNode(nodeId);
|
|
2230
2413
|
}
|
|
2231
2414
|
catch { }
|
|
2232
2415
|
onClose();
|
|
2233
|
-
};
|
|
2416
|
+
}, [nodeId, runner, onClose]);
|
|
2417
|
+
const canRunPull = engineKind()?.toString() === "pull";
|
|
2418
|
+
const outs = getBakeableOutputs();
|
|
2234
2419
|
return (jsxRuntime.jsxs("div", { ref: ref, tabIndex: -1, className: "fixed z-[1000] bg-white border border-gray-300 rounded-lg shadow-lg p-1 min-w-[180px] text-sm text-gray-700", style: { left: x, top: y }, onClick: (e) => e.stopPropagation(), onMouseDown: (e) => e.stopPropagation(), onWheel: (e) => e.stopPropagation(), onContextMenu: (e) => {
|
|
2235
2420
|
e.preventDefault();
|
|
2236
2421
|
e.stopPropagation();
|
|
2237
|
-
}, children: [jsxRuntime.jsxs("div", { className: "px-2 py-1 font-semibold text-gray-700", children: ["Node (", nodeId, ")"] }), jsxRuntime.jsx("button", { className: "block w-full text-left px-2 py-1 hover:bg-gray-100", onClick: handleDelete, children: "Delete" }), jsxRuntime.jsx("button", { className: "block w-full text-left px-2 py-1 hover:bg-gray-100", onClick: handleDuplicate, children: "Duplicate" }), canRunPull && (jsxRuntime.jsx("button", { className: "block w-full text-left px-2 py-1 hover:bg-gray-100", onClick: handleRunPull, children: "Run (pull)" })), jsxRuntime.jsx("div", { className: "h-px bg-gray-200 my-1" }), jsxRuntime.jsx("button", { className: "block w-full text-left px-2 py-1 hover:bg-gray-100", onClick:
|
|
2422
|
+
}, children: [jsxRuntime.jsxs("div", { className: "px-2 py-1 font-semibold text-gray-700", children: ["Node (", nodeId, ")"] }), jsxRuntime.jsx("button", { className: "block w-full text-left px-2 py-1 hover:bg-gray-100", onClick: handleDelete, children: "Delete" }), jsxRuntime.jsx("button", { className: "block w-full text-left px-2 py-1 hover:bg-gray-100", onClick: handleDuplicate, children: "Duplicate" }), canRunPull && (jsxRuntime.jsx("button", { className: "block w-full text-left px-2 py-1 hover:bg-gray-100", onClick: handleRunPull, children: "Run (pull)" })), jsxRuntime.jsx("div", { className: "h-px bg-gray-200 my-1" }), outs.length > 0 && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: "px-2 py-1 font-semibold text-gray-700", children: "Bake" }), outs.map((h) => (jsxRuntime.jsxs("button", { className: "block w-full text-left px-2 py-1 hover:bg-gray-100", onClick: async () => {
|
|
2423
|
+
await doBake(h);
|
|
2424
|
+
onClose();
|
|
2425
|
+
}, children: ["Bake: ", h] }, h))), jsxRuntime.jsx("div", { className: "h-px bg-gray-200 my-1" })] })), jsxRuntime.jsx("button", { className: "block w-full text-left px-2 py-1 hover:bg-gray-100", onClick: handleCopyId, children: "Copy Node ID" })] }));
|
|
2238
2426
|
}
|
|
2239
2427
|
|
|
2240
2428
|
const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement, getDefaultNodeSize }, ref) => {
|
|
@@ -2464,10 +2652,21 @@ const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement, get
|
|
|
2464
2652
|
setNodeMenuOpen(false);
|
|
2465
2653
|
}
|
|
2466
2654
|
};
|
|
2467
|
-
const addNodeAt = (typeId, pos) => {
|
|
2655
|
+
const addNodeAt = React.useCallback((typeId, pos) => {
|
|
2468
2656
|
wb.addNode({ typeId, position: pos });
|
|
2469
|
-
};
|
|
2470
|
-
|
|
2657
|
+
}, [wb]);
|
|
2658
|
+
React.useCallback((inst) => {
|
|
2659
|
+
rfInstanceRef.current = inst;
|
|
2660
|
+
}, []);
|
|
2661
|
+
const onCloseMenu = React.useCallback(() => {
|
|
2662
|
+
setMenuOpen(false);
|
|
2663
|
+
}, []);
|
|
2664
|
+
const onCloseNodeMenu = React.useCallback(() => {
|
|
2665
|
+
setNodeMenuOpen(false);
|
|
2666
|
+
}, []);
|
|
2667
|
+
return (jsxRuntime.jsx("div", { className: "w-full h-full", onContextMenu: onContextMenu, children: jsxRuntime.jsx(react.ReactFlowProvider, { children: jsxRuntime.jsxs(react.ReactFlow, { nodes: throttled.nodes, edges: throttled.edges, nodeTypes: nodeTypes, selectionOnDrag: true, onInit: (inst) => {
|
|
2668
|
+
rfInstanceRef.current = inst;
|
|
2669
|
+
}, onConnect: onConnect, onEdgesChange: onEdgesChange, onEdgesDelete: onEdgesDelete, onNodesDelete: onNodesDelete, onNodesChange: onNodesChange, deleteKeyCode: ["Backspace", "Delete"], proOptions: { hideAttribution: true }, noDragClassName: "wb-nodrag", noWheelClassName: "wb-nowheel", noPanClassName: "wb-nopan", fitView: true, children: [jsxRuntime.jsx(react.Background, { id: "workbench-canvas-background", variant: react.BackgroundVariant.Dots, gap: 12, size: 1 }), jsxRuntime.jsx(react.MiniMap, {}), jsxRuntime.jsx(react.Controls, {}), jsxRuntime.jsx(DefaultContextMenu, { open: menuOpen, clientPos: menuPos, onAdd: addNodeAt, onClose: onCloseMenu }), jsxRuntime.jsx(NodeContextMenu, { open: nodeMenuOpen, clientPos: nodeMenuPos, nodeId: nodeAtMenu, onClose: onCloseNodeMenu })] }) }) }));
|
|
2471
2670
|
});
|
|
2472
2671
|
|
|
2473
2672
|
function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, example, onExampleChange, engine, onEngineChange, backendKind, onBackendKindChange, httpBaseUrl, onHttpBaseUrlChange, wsUrl, onWsUrlChange, debug, onDebugChange, showValues, onShowValuesChange, hideWorkbench, onHideWorkbenchChange, overrides, onInit, onChange, }) {
|
|
@@ -2641,6 +2840,7 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
|
|
|
2641
2840
|
r.registerEnum({
|
|
2642
2841
|
id: t.id,
|
|
2643
2842
|
options: t.options,
|
|
2843
|
+
bakeTarget: t.bakeTarget,
|
|
2644
2844
|
});
|
|
2645
2845
|
}
|
|
2646
2846
|
else {
|
|
@@ -2648,6 +2848,7 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
|
|
|
2648
2848
|
id: t.id,
|
|
2649
2849
|
displayName: t.displayName,
|
|
2650
2850
|
validate: (_v) => true,
|
|
2851
|
+
bakeTarget: t.bakeTarget,
|
|
2651
2852
|
});
|
|
2652
2853
|
}
|
|
2653
2854
|
}
|
|
@@ -2955,6 +3156,7 @@ exports.AbstractWorkbench = AbstractWorkbench;
|
|
|
2955
3156
|
exports.CLIWorkbench = CLIWorkbench;
|
|
2956
3157
|
exports.DefaultNode = DefaultNode;
|
|
2957
3158
|
exports.DefaultNodeContent = DefaultNodeContent;
|
|
3159
|
+
exports.DefaultNodeHeader = DefaultNodeHeader;
|
|
2958
3160
|
exports.DefaultUIExtensionRegistry = DefaultUIExtensionRegistry;
|
|
2959
3161
|
exports.InMemoryWorkbench = InMemoryWorkbench;
|
|
2960
3162
|
exports.Inspector = Inspector;
|