@bian-womp/spark-workbench 0.2.9 → 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 +172 -128
- 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.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/esm/index.js +172 -128
- 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.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/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);
|
|
@@ -2083,7 +2085,7 @@ function DefaultNodeHeader({ id, title, status, validation, right, onInvalidate,
|
|
|
2083
2085
|
.join("; ") })), jsxRuntime.jsxs("span", { className: "text-[10px] opacity-70", children: ["(", id, ")"] })] })] }));
|
|
2084
2086
|
}
|
|
2085
2087
|
function DefaultNodeContent({ id, data, isConnectable, }) {
|
|
2086
|
-
|
|
2088
|
+
useWorkbenchContext();
|
|
2087
2089
|
const { showValues, inputValues, outputValues, toString } = data;
|
|
2088
2090
|
const inputEntries = data.inputHandles ?? [];
|
|
2089
2091
|
const outputEntries = data.outputHandles ?? [];
|
|
@@ -2093,98 +2095,6 @@ function DefaultNodeContent({ id, data, isConnectable, }) {
|
|
|
2093
2095
|
outputs: []};
|
|
2094
2096
|
const isRunning = !!status.activeRuns;
|
|
2095
2097
|
const pct = Math.round(Math.max(0, Math.min(1, Number(status.progress) || 0)) * 100);
|
|
2096
|
-
const handleBake = React.useCallback(async (handleId) => {
|
|
2097
|
-
try {
|
|
2098
|
-
const typeId = ctx.outputTypesMap?.[id]?.[handleId];
|
|
2099
|
-
const rawValue = ctx.outputsMap?.[id]?.[handleId];
|
|
2100
|
-
if (!typeId || rawValue === undefined)
|
|
2101
|
-
return;
|
|
2102
|
-
const unwrap = (v) => sparkGraph.isTypedOutput(v) ? sparkGraph.getTypedOutputValue(v) : v;
|
|
2103
|
-
const clone = (v) => typeof structuredClone === "function"
|
|
2104
|
-
? structuredClone(v)
|
|
2105
|
-
: JSON.parse(JSON.stringify(v));
|
|
2106
|
-
const coerceIfNeeded = async (fromType, toType, value) => {
|
|
2107
|
-
if (!toType || toType === fromType || !ctx.runner?.coerce)
|
|
2108
|
-
return value;
|
|
2109
|
-
try {
|
|
2110
|
-
return await ctx.runner.coerce(fromType, toType, value);
|
|
2111
|
-
}
|
|
2112
|
-
catch {
|
|
2113
|
-
return value;
|
|
2114
|
-
}
|
|
2115
|
-
};
|
|
2116
|
-
const positions = ctx.wb.getPositions();
|
|
2117
|
-
const pos = positions[id] || { x: 0, y: 0 };
|
|
2118
|
-
const isArray = typeId.endsWith("[]");
|
|
2119
|
-
const baseTypeId = isArray ? typeId.slice(0, -2) : typeId;
|
|
2120
|
-
const tArr = isArray ? ctx.registry?.types.get(typeId) : undefined;
|
|
2121
|
-
const tElem = ctx.registry?.types.get(baseTypeId);
|
|
2122
|
-
const singleTarget = !isArray ? tElem?.bakeTarget : undefined;
|
|
2123
|
-
const arrTarget = isArray ? tArr?.bakeTarget : undefined;
|
|
2124
|
-
const elemTarget = isArray ? tElem?.bakeTarget : undefined;
|
|
2125
|
-
const makeTargetInfo = (bt) => {
|
|
2126
|
-
if (!bt)
|
|
2127
|
-
return undefined;
|
|
2128
|
-
const node = ctx.registry?.nodes.get(String(bt.nodeTypeId));
|
|
2129
|
-
const inType = sparkGraph.getInputTypeId(node?.inputs, String(bt.inputHandle || "Value"));
|
|
2130
|
-
return { bt, inType };
|
|
2131
|
-
};
|
|
2132
|
-
// Plan and execute
|
|
2133
|
-
if (singleTarget) {
|
|
2134
|
-
const info = makeTargetInfo(singleTarget);
|
|
2135
|
-
const v = unwrap(rawValue);
|
|
2136
|
-
const coerced = await coerceIfNeeded(typeId, info?.inType, v);
|
|
2137
|
-
ctx.wb.addNode({
|
|
2138
|
-
nodeId: undefined,
|
|
2139
|
-
typeId: String(singleTarget.nodeTypeId),
|
|
2140
|
-
position: { x: pos.x + 180, y: pos.y },
|
|
2141
|
-
params: {},
|
|
2142
|
-
initialInputs: {
|
|
2143
|
-
[String(singleTarget.inputHandle || "Value")]: clone(coerced),
|
|
2144
|
-
},
|
|
2145
|
-
});
|
|
2146
|
-
return;
|
|
2147
|
-
}
|
|
2148
|
-
if (isArray && arrTarget) {
|
|
2149
|
-
const info = makeTargetInfo(arrTarget);
|
|
2150
|
-
const v = unwrap(rawValue);
|
|
2151
|
-
const coerced = await coerceIfNeeded(typeId, info?.inType, v);
|
|
2152
|
-
ctx.wb.addNode({
|
|
2153
|
-
nodeId: undefined,
|
|
2154
|
-
typeId: String(arrTarget.nodeTypeId),
|
|
2155
|
-
position: { x: pos.x + 180, y: pos.y },
|
|
2156
|
-
params: {},
|
|
2157
|
-
initialInputs: {
|
|
2158
|
-
[String(arrTarget.inputHandle || "Value")]: clone(coerced),
|
|
2159
|
-
},
|
|
2160
|
-
});
|
|
2161
|
-
return;
|
|
2162
|
-
}
|
|
2163
|
-
if (isArray && elemTarget && Array.isArray(rawValue)) {
|
|
2164
|
-
const info = makeTargetInfo(elemTarget);
|
|
2165
|
-
const items = rawValue.map(unwrap);
|
|
2166
|
-
const coercedItems = await Promise.all(items.map((v) => coerceIfNeeded(baseTypeId, info?.inType, v)));
|
|
2167
|
-
const COLS = 4;
|
|
2168
|
-
const DX = 180;
|
|
2169
|
-
const DY = 160;
|
|
2170
|
-
coercedItems.forEach((cv, idx) => {
|
|
2171
|
-
const col = idx % COLS;
|
|
2172
|
-
const row = Math.floor(idx / COLS);
|
|
2173
|
-
ctx.wb.addNode({
|
|
2174
|
-
nodeId: undefined,
|
|
2175
|
-
typeId: String(elemTarget.nodeTypeId),
|
|
2176
|
-
position: { x: pos.x + (col + 1) * DX, y: pos.y + row * DY },
|
|
2177
|
-
params: {},
|
|
2178
|
-
initialInputs: {
|
|
2179
|
-
[String(elemTarget.inputHandle || "Value")]: clone(cv),
|
|
2180
|
-
},
|
|
2181
|
-
});
|
|
2182
|
-
});
|
|
2183
|
-
return;
|
|
2184
|
-
}
|
|
2185
|
-
}
|
|
2186
|
-
catch { }
|
|
2187
|
-
}, [ctx, id]);
|
|
2188
2098
|
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: cx("h-px", (isRunning || pct > 0) && "bg-blue-200 dark:bg-blue-900"), children: jsxRuntime.jsx("div", { className: cx("h-px transition-all", (isRunning || pct > 0) && "bg-blue-500"), style: { width: isRunning || pct > 0 ? `${pct}%` : 0 } }) }), jsxRuntime.jsx(NodeHandles, { data: data, isConnectable: isConnectable, getClassName: ({ kind, id }) => {
|
|
2189
2099
|
const vIssues = (kind === "input" ? validation.inputs : validation.outputs).filter((v) => v.handle === id);
|
|
2190
2100
|
const hasAny = vIssues.length > 0;
|
|
@@ -2212,26 +2122,7 @@ function DefaultNodeContent({ id, data, isConnectable, }) {
|
|
|
2212
2122
|
const txt = toString(resolved.typeId, resolved.value);
|
|
2213
2123
|
return typeof txt === "string" ? txt : String(txt);
|
|
2214
2124
|
})();
|
|
2215
|
-
|
|
2216
|
-
let canBake = false;
|
|
2217
|
-
if (tId?.endsWith("[]")) {
|
|
2218
|
-
const base = tId.slice(0, -2);
|
|
2219
|
-
const tArr = ctx.registry?.types.get(tId);
|
|
2220
|
-
const tElem = ctx.registry?.types.get(base);
|
|
2221
|
-
const arrTarget = tArr?.bakeTarget;
|
|
2222
|
-
const elemTarget = tElem?.bakeTarget;
|
|
2223
|
-
canBake = !!((arrTarget && ctx.registry?.nodes?.has?.(arrTarget.nodeTypeId)) ||
|
|
2224
|
-
(elemTarget && ctx.registry?.nodes?.has?.(elemTarget.nodeTypeId)));
|
|
2225
|
-
}
|
|
2226
|
-
else if (tId) {
|
|
2227
|
-
const t = ctx.registry?.types.get(tId);
|
|
2228
|
-
const target = t?.bakeTarget;
|
|
2229
|
-
canBake = !!(target && ctx.registry?.nodes?.has?.(target.nodeTypeId));
|
|
2230
|
-
}
|
|
2231
|
-
return (jsxRuntime.jsxs("span", { className: "flex items-center gap-1 w-full", children: [kind === "output" ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [canBake && (jsxRuntime.jsx("button", { onClick: (e) => {
|
|
2232
|
-
e.stopPropagation();
|
|
2233
|
-
handleBake(handleId);
|
|
2234
|
-
}, title: "Bake value", className: "pointer-events-auto border border-gray-300 rounded px-1 py-0.5 text-[10px] bg-white/80 hover:bg-white mr-2", children: "Bake" })), 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 }))] }));
|
|
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 }))] }));
|
|
2235
2126
|
} })] }));
|
|
2236
2127
|
}
|
|
2237
2128
|
|
|
@@ -2322,7 +2213,7 @@ function DefaultContextMenu({ open, clientPos, onAdd, onClose, }) {
|
|
|
2322
2213
|
}
|
|
2323
2214
|
|
|
2324
2215
|
function NodeContextMenu({ open, clientPos, nodeId, onClose, }) {
|
|
2325
|
-
const { wb, runner, engineKind } = useWorkbenchContext();
|
|
2216
|
+
const { wb, runner, engineKind, registry, outputsMap, outputTypesMap } = useWorkbenchContext();
|
|
2326
2217
|
const ref = React.useRef(null);
|
|
2327
2218
|
// outside click + ESC
|
|
2328
2219
|
React.useEffect(() => {
|
|
@@ -2357,39 +2248,181 @@ function NodeContextMenu({ open, clientPos, nodeId, onClose, }) {
|
|
|
2357
2248
|
const x = Math.min(clientPos.x, (typeof window !== "undefined" ? window.innerWidth : 0) -
|
|
2358
2249
|
(MENU_MIN_WIDTH + PADDING));
|
|
2359
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
|
+
};
|
|
2360
2381
|
// actions
|
|
2361
|
-
const handleDelete = () => {
|
|
2382
|
+
const handleDelete = React.useCallback(() => {
|
|
2362
2383
|
wb.removeNode(nodeId);
|
|
2363
2384
|
onClose();
|
|
2364
|
-
};
|
|
2365
|
-
const handleDuplicate = () => {
|
|
2385
|
+
}, [nodeId, wb, onClose]);
|
|
2386
|
+
const handleDuplicate = React.useCallback(() => {
|
|
2366
2387
|
const def = wb.export();
|
|
2367
2388
|
const n = def.nodes.find((n) => n.nodeId === nodeId);
|
|
2368
2389
|
if (!n)
|
|
2369
2390
|
return onClose();
|
|
2370
2391
|
const pos = wb.getPositions?.()[nodeId] || { x: 0, y: 0 };
|
|
2371
|
-
wb.addNode({
|
|
2392
|
+
wb.addNode({
|
|
2393
|
+
typeId: n.typeId,
|
|
2394
|
+
params: n.params,
|
|
2395
|
+
position: { x: pos.x + 24, y: pos.y + 24 },
|
|
2396
|
+
});
|
|
2372
2397
|
onClose();
|
|
2373
|
-
};
|
|
2374
|
-
|
|
2398
|
+
}, [nodeId, wb, onClose]);
|
|
2399
|
+
React.useCallback(async (handleId) => {
|
|
2400
|
+
await doBake(handleId);
|
|
2401
|
+
onClose();
|
|
2402
|
+
}, [doBake, onClose]);
|
|
2403
|
+
const handleCopyId = React.useCallback(async () => {
|
|
2375
2404
|
try {
|
|
2376
2405
|
await navigator.clipboard.writeText(nodeId);
|
|
2377
2406
|
}
|
|
2378
2407
|
catch { }
|
|
2379
2408
|
onClose();
|
|
2380
|
-
};
|
|
2381
|
-
const
|
|
2382
|
-
const handleRunPull = async () => {
|
|
2409
|
+
}, [nodeId, onClose]);
|
|
2410
|
+
const handleRunPull = React.useCallback(async () => {
|
|
2383
2411
|
try {
|
|
2384
2412
|
await runner.computeNode(nodeId);
|
|
2385
2413
|
}
|
|
2386
2414
|
catch { }
|
|
2387
2415
|
onClose();
|
|
2388
|
-
};
|
|
2416
|
+
}, [nodeId, runner, onClose]);
|
|
2417
|
+
const canRunPull = engineKind()?.toString() === "pull";
|
|
2418
|
+
const outs = getBakeableOutputs();
|
|
2389
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) => {
|
|
2390
2420
|
e.preventDefault();
|
|
2391
2421
|
e.stopPropagation();
|
|
2392
|
-
}, 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" })] }));
|
|
2393
2426
|
}
|
|
2394
2427
|
|
|
2395
2428
|
const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement, getDefaultNodeSize }, ref) => {
|
|
@@ -2619,10 +2652,21 @@ const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement, get
|
|
|
2619
2652
|
setNodeMenuOpen(false);
|
|
2620
2653
|
}
|
|
2621
2654
|
};
|
|
2622
|
-
const addNodeAt = (typeId, pos) => {
|
|
2655
|
+
const addNodeAt = React.useCallback((typeId, pos) => {
|
|
2623
2656
|
wb.addNode({ typeId, position: pos });
|
|
2624
|
-
};
|
|
2625
|
-
|
|
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 })] }) }) }));
|
|
2626
2670
|
});
|
|
2627
2671
|
|
|
2628
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, }) {
|