@bian-womp/spark-workbench 0.2.26 → 0.2.27
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 +86 -12
- package/lib/cjs/index.cjs.map +1 -1
- package/lib/cjs/src/misc/Inspector.d.ts.map +1 -1
- package/lib/cjs/src/misc/WorkbenchStudio.d.ts.map +1 -1
- package/lib/cjs/src/misc/context/WorkbenchContext.d.ts +7 -1
- package/lib/cjs/src/misc/context/WorkbenchContext.d.ts.map +1 -1
- package/lib/cjs/src/misc/context/WorkbenchContext.provider.d.ts.map +1 -1
- package/lib/esm/index.js +86 -12
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/src/misc/Inspector.d.ts.map +1 -1
- package/lib/esm/src/misc/WorkbenchStudio.d.ts.map +1 -1
- package/lib/esm/src/misc/context/WorkbenchContext.d.ts +7 -1
- package/lib/esm/src/misc/context/WorkbenchContext.d.ts.map +1 -1
- package/lib/esm/src/misc/context/WorkbenchContext.provider.d.ts.map +1 -1
- package/package.json +4 -4
package/lib/cjs/index.cjs
CHANGED
|
@@ -1647,6 +1647,16 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, child
|
|
|
1647
1647
|
const [edgeStatus, setEdgeStatus] = React.useState({});
|
|
1648
1648
|
const [events, setEvents] = React.useState([]);
|
|
1649
1649
|
const clearEvents = React.useCallback(() => setEvents([]), []);
|
|
1650
|
+
const [systemErrors, setSystemErrors] = React.useState([]);
|
|
1651
|
+
const [registryErrors, setRegistryErrors] = React.useState([]);
|
|
1652
|
+
const clearSystemErrors = React.useCallback(() => setSystemErrors([]), []);
|
|
1653
|
+
const clearRegistryErrors = React.useCallback(() => setRegistryErrors([]), []);
|
|
1654
|
+
const removeSystemError = React.useCallback((index) => {
|
|
1655
|
+
setSystemErrors((prev) => prev.filter((_, idx) => idx !== index));
|
|
1656
|
+
}, []);
|
|
1657
|
+
const removeRegistryError = React.useCallback((index) => {
|
|
1658
|
+
setRegistryErrors((prev) => prev.filter((_, idx) => idx !== index));
|
|
1659
|
+
}, []);
|
|
1650
1660
|
// Fallback progress animation: drive progress to 100% over ~2 minutes
|
|
1651
1661
|
const FALLBACK_TOTAL_MS = 2 * 60 * 1000;
|
|
1652
1662
|
const [fallbackStarts, setFallbackStarts] = React.useState({});
|
|
@@ -1829,7 +1839,10 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, child
|
|
|
1829
1839
|
if (remoteDef && Array.isArray(remoteDef.nodes)) {
|
|
1830
1840
|
// Mutate current def in-place to avoid emitting graphChanged and causing update loop
|
|
1831
1841
|
const cur = wb.export();
|
|
1832
|
-
const byId = new Map((remoteDef.nodes || []).map((n) => [
|
|
1842
|
+
const byId = new Map((remoteDef.nodes || []).map((n) => [
|
|
1843
|
+
n.nodeId,
|
|
1844
|
+
n,
|
|
1845
|
+
]));
|
|
1833
1846
|
let changed = false;
|
|
1834
1847
|
for (const n of cur.nodes) {
|
|
1835
1848
|
const rn = byId.get(n.nodeId);
|
|
@@ -1861,6 +1874,8 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, child
|
|
|
1861
1874
|
const off2 = runner.on("error", (e) => {
|
|
1862
1875
|
const edgeError = e;
|
|
1863
1876
|
const nodeError = e;
|
|
1877
|
+
const registryError = e;
|
|
1878
|
+
const systemError = e;
|
|
1864
1879
|
if (edgeError.kind === "edge-convert") {
|
|
1865
1880
|
const edgeId = edgeError.edgeId;
|
|
1866
1881
|
setEdgeStatus((s) => ({
|
|
@@ -1868,7 +1883,7 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, child
|
|
|
1868
1883
|
[edgeId]: { ...s[edgeId], lastError: edgeError.err },
|
|
1869
1884
|
}));
|
|
1870
1885
|
}
|
|
1871
|
-
else if (nodeError.nodeId) {
|
|
1886
|
+
else if (nodeError.kind === "node-run" && nodeError.nodeId) {
|
|
1872
1887
|
const nodeId = nodeError.nodeId;
|
|
1873
1888
|
const runId = nodeError.runId;
|
|
1874
1889
|
setNodeStatus((s) => ({
|
|
@@ -1886,6 +1901,27 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, child
|
|
|
1886
1901
|
};
|
|
1887
1902
|
}
|
|
1888
1903
|
}
|
|
1904
|
+
else if (registryError.kind === "registry") {
|
|
1905
|
+
// Track registry errors for UI display
|
|
1906
|
+
setRegistryErrors((prev) => {
|
|
1907
|
+
// Avoid duplicates by checking message
|
|
1908
|
+
if (prev.some((err) => err.message === registryError.message)) {
|
|
1909
|
+
return prev;
|
|
1910
|
+
}
|
|
1911
|
+
return [...prev, registryError];
|
|
1912
|
+
});
|
|
1913
|
+
}
|
|
1914
|
+
else if (systemError.kind === "system") {
|
|
1915
|
+
// Track custom errors for UI display
|
|
1916
|
+
setSystemErrors((prev) => {
|
|
1917
|
+
// Avoid duplicates by checking message and code
|
|
1918
|
+
if (prev.some((err) => err.message === systemError.message &&
|
|
1919
|
+
err.code === systemError.code)) {
|
|
1920
|
+
return prev;
|
|
1921
|
+
}
|
|
1922
|
+
return [...prev, systemError];
|
|
1923
|
+
});
|
|
1924
|
+
}
|
|
1889
1925
|
return add("runner", "error")(e);
|
|
1890
1926
|
});
|
|
1891
1927
|
const off3 = runner.on("invalidate", (e) => {
|
|
@@ -2133,6 +2169,12 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, child
|
|
|
2133
2169
|
validationGlobal,
|
|
2134
2170
|
events,
|
|
2135
2171
|
clearEvents,
|
|
2172
|
+
systemErrors,
|
|
2173
|
+
registryErrors,
|
|
2174
|
+
clearSystemErrors,
|
|
2175
|
+
clearRegistryErrors,
|
|
2176
|
+
removeSystemError,
|
|
2177
|
+
removeRegistryError,
|
|
2136
2178
|
isRunning,
|
|
2137
2179
|
engineKind,
|
|
2138
2180
|
start,
|
|
@@ -2154,6 +2196,12 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, child
|
|
|
2154
2196
|
nodeStatus,
|
|
2155
2197
|
edgeStatus,
|
|
2156
2198
|
valuesTick,
|
|
2199
|
+
systemErrors,
|
|
2200
|
+
registryErrors,
|
|
2201
|
+
clearSystemErrors,
|
|
2202
|
+
clearRegistryErrors,
|
|
2203
|
+
removeSystemError,
|
|
2204
|
+
removeRegistryError,
|
|
2157
2205
|
inputsMap,
|
|
2158
2206
|
outputsMap,
|
|
2159
2207
|
validationByNode,
|
|
@@ -2220,7 +2268,7 @@ function Inspector({ debug, autoScroll, hideWorkbench, onAutoScrollChange, onHid
|
|
|
2220
2268
|
return String(value ?? "");
|
|
2221
2269
|
}
|
|
2222
2270
|
};
|
|
2223
|
-
const { registry, def, selectedNodeId, selectedEdgeId, inputsMap, outputsMap, outputTypesMap, nodeStatus, validationByNode, validationByEdge, validationGlobal, valuesTick, updateEdgeType, } = useWorkbenchContext();
|
|
2271
|
+
const { registry, def, selectedNodeId, selectedEdgeId, inputsMap, outputsMap, outputTypesMap, nodeStatus, validationByNode, validationByEdge, validationGlobal, valuesTick, updateEdgeType, systemErrors, registryErrors, clearSystemErrors, clearRegistryErrors, removeSystemError, removeRegistryError, } = useWorkbenchContext();
|
|
2224
2272
|
const nodeValidationIssues = validationByNode.issues;
|
|
2225
2273
|
const edgeValidationIssues = validationByEdge.issues;
|
|
2226
2274
|
const nodeValidationHandles = validationByNode;
|
|
@@ -2306,7 +2354,7 @@ function Inspector({ debug, autoScroll, hideWorkbench, onAutoScrollChange, onHid
|
|
|
2306
2354
|
}
|
|
2307
2355
|
catch { }
|
|
2308
2356
|
};
|
|
2309
|
-
return (jsxRuntime.jsxs("div", { className: `${widthClass} border-l border-gray-300 p-3 flex flex-col h-full min-h-0 overflow-hidden`, children: [contextPanel && jsxRuntime.jsx("div", { className: "mb-2", children: contextPanel }), jsxRuntime.jsx("div", { className: "font-semibold mb-2", children: "Inspector" }), jsxRuntime.jsxs("div", { className: "text-xs text-gray-500 mb-2", children: ["valuesTick: ", valuesTick] }), jsxRuntime.jsx("div", { className: "flex-1 overflow-auto", children: !selectedNode && !selectedEdge ? (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("div", { className: "text-gray-500", children: "Select a node or edge." }), globalValidationIssues && globalValidationIssues.length > 0 && (jsxRuntime.jsxs("div", { className: "mt-2 text-xs bg-red-50 border border-red-200 rounded px-2 py-1", children: [jsxRuntime.jsx("div", { className: "font-semibold mb-1", children: "Validation" }), jsxRuntime.jsx("ul", { className: "list-disc ml-4", children: globalValidationIssues.map((m, i) => (jsxRuntime.jsxs("li", { className: "flex items-center gap-1", children: [jsxRuntime.jsx(IssueBadge, { level: m.level, size: 24, className: "w-6 h-6" }), jsxRuntime.jsx("span", { children: `${m.code}: ${m.message}` }), !!m.data?.edgeId && (jsxRuntime.jsx("button", { className: "ml-2 text-[10px] px-1 py-[2px] border border-red-300 rounded text-red-700 hover:bg-red-50", onClick: (e) => {
|
|
2357
|
+
return (jsxRuntime.jsxs("div", { className: `${widthClass} border-l border-gray-300 p-3 flex flex-col h-full min-h-0 overflow-hidden`, children: [contextPanel && jsxRuntime.jsx("div", { className: "mb-2", children: contextPanel }), systemErrors.length > 0 && (jsxRuntime.jsxs("div", { className: "mb-2 space-y-1", children: [systemErrors.map((err, i) => (jsxRuntime.jsxs("div", { className: "text-xs text-red-700 bg-red-50 border border-red-200 rounded px-2 py-1 flex items-start justify-between gap-2", children: [jsxRuntime.jsxs("div", { className: "flex-1", children: [jsxRuntime.jsx("div", { className: "font-semibold", children: err.code ? `Error ${err.code}` : "Error" }), jsxRuntime.jsx("div", { className: "break-words", children: err.message })] }), jsxRuntime.jsx("button", { className: "text-red-500 hover:text-red-700 text-[10px] px-1", onClick: () => removeSystemError(i), title: "Dismiss", children: "\u00D7" })] }, i))), systemErrors.length > 1 && (jsxRuntime.jsx("button", { className: "text-xs text-red-600 hover:text-red-800 underline", onClick: clearSystemErrors, children: "Clear all" }))] })), registryErrors.length > 0 && (jsxRuntime.jsxs("div", { className: "mb-2 space-y-1", children: [registryErrors.map((err, i) => (jsxRuntime.jsxs("div", { className: "text-xs text-amber-700 bg-amber-50 border border-amber-200 rounded px-2 py-1 flex items-start justify-between gap-2", children: [jsxRuntime.jsxs("div", { className: "flex-1", children: [jsxRuntime.jsx("div", { className: "font-semibold", children: "Registry Error" }), jsxRuntime.jsx("div", { className: "break-words", children: err.message }), err.attempt && err.maxAttempts && (jsxRuntime.jsxs("div", { className: "text-[10px] text-amber-600 mt-1", children: ["Attempt ", err.attempt, " of ", err.maxAttempts] }))] }), jsxRuntime.jsx("button", { className: "text-amber-500 hover:text-amber-700 text-[10px] px-1", onClick: () => removeRegistryError(i), title: "Dismiss", children: "\u00D7" })] }, i))), registryErrors.length > 1 && (jsxRuntime.jsx("button", { className: "text-xs text-amber-600 hover:text-amber-800 underline", onClick: clearRegistryErrors, children: "Clear all" }))] })), jsxRuntime.jsx("div", { className: "font-semibold mb-2", children: "Inspector" }), jsxRuntime.jsxs("div", { className: "text-xs text-gray-500 mb-2", children: ["valuesTick: ", valuesTick] }), jsxRuntime.jsx("div", { className: "flex-1 overflow-auto", children: !selectedNode && !selectedEdge ? (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("div", { className: "text-gray-500", children: "Select a node or edge." }), globalValidationIssues && globalValidationIssues.length > 0 && (jsxRuntime.jsxs("div", { className: "mt-2 text-xs bg-red-50 border border-red-200 rounded px-2 py-1", children: [jsxRuntime.jsx("div", { className: "font-semibold mb-1", children: "Validation" }), jsxRuntime.jsx("ul", { className: "list-disc ml-4", children: globalValidationIssues.map((m, i) => (jsxRuntime.jsxs("li", { className: "flex items-center gap-1", children: [jsxRuntime.jsx(IssueBadge, { level: m.level, size: 24, className: "w-6 h-6" }), jsxRuntime.jsx("span", { children: `${m.code}: ${m.message}` }), !!m.data?.edgeId && (jsxRuntime.jsx("button", { className: "ml-2 text-[10px] px-1 py-[2px] border border-red-300 rounded text-red-700 hover:bg-red-50", onClick: (e) => {
|
|
2310
2358
|
e.stopPropagation();
|
|
2311
2359
|
deleteEdgeById(m.data?.edgeId);
|
|
2312
2360
|
}, title: "Delete referenced edge", children: "Delete edge" }))] }, i))) })] }))] })) : selectedEdge ? (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsxs("div", { className: "mb-2", children: [jsxRuntime.jsxs("div", { children: ["Edge: ", selectedEdge.id] }), jsxRuntime.jsxs("div", { children: [selectedEdge.source.nodeId, ".", selectedEdge.source.handle, " \u2192", " ", selectedEdge.target.nodeId, ".", selectedEdge.target.handle] }), jsxRuntime.jsx("div", { className: "mt-1", children: jsxRuntime.jsx("button", { className: "text-xs px-2 py-1 border border-red-300 rounded text-red-700 hover:bg-red-50", onClick: (e) => {
|
|
@@ -3156,11 +3204,8 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
|
|
|
3156
3204
|
return backendKind === "local";
|
|
3157
3205
|
});
|
|
3158
3206
|
// Expose init callback with setInitialGraph helper
|
|
3159
|
-
|
|
3207
|
+
// Note: This runs whenever runner changes (e.g., when Flow is enabled and backendOptions changes)
|
|
3160
3208
|
React.useEffect(() => {
|
|
3161
|
-
if (initCalled.current)
|
|
3162
|
-
return;
|
|
3163
|
-
initCalled.current = true;
|
|
3164
3209
|
if (!onInit)
|
|
3165
3210
|
return;
|
|
3166
3211
|
const setInitialGraph = async (d, inputs) => {
|
|
@@ -3606,7 +3651,19 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
|
|
|
3606
3651
|
function WorkbenchStudio({ engine, onEngineChange, example, onExampleChange, backendKind, onBackendKindChange, httpBaseUrl, onHttpBaseUrlChange, wsUrl, onWsUrlChange, debug, onDebugChange, showValues, onShowValuesChange, hideWorkbench, onHideWorkbenchChange, autoScroll, onAutoScrollChange, backendOptions, overrides, onInit, onChange, }) {
|
|
3607
3652
|
const [registry, setRegistry] = React.useState(sparkGraph.createSimpleGraphRegistry());
|
|
3608
3653
|
const [wb] = React.useState(() => new InMemoryWorkbench({ ui: new DefaultUIExtensionRegistry() }));
|
|
3654
|
+
// Store previous runner for cleanup
|
|
3655
|
+
const prevRunnerRef = React.useRef(null);
|
|
3609
3656
|
const runner = React.useMemo(() => {
|
|
3657
|
+
// Dispose previous runner if it exists
|
|
3658
|
+
if (prevRunnerRef.current) {
|
|
3659
|
+
try {
|
|
3660
|
+
prevRunnerRef.current.dispose();
|
|
3661
|
+
}
|
|
3662
|
+
catch (err) {
|
|
3663
|
+
console.warn("Error disposing previous runner:", err);
|
|
3664
|
+
}
|
|
3665
|
+
}
|
|
3666
|
+
let newRunner;
|
|
3610
3667
|
if (backendKind === "remote-http") {
|
|
3611
3668
|
const backend = {
|
|
3612
3669
|
kind: "remote-http",
|
|
@@ -3618,9 +3675,9 @@ function WorkbenchStudio({ engine, onEngineChange, example, onExampleChange, bac
|
|
|
3618
3675
|
onCustomEvent: backendOptions.onCustomEvent,
|
|
3619
3676
|
}),
|
|
3620
3677
|
};
|
|
3621
|
-
|
|
3678
|
+
newRunner = new RemoteGraphRunner(registry, backend);
|
|
3622
3679
|
}
|
|
3623
|
-
if (backendKind === "remote-ws") {
|
|
3680
|
+
else if (backendKind === "remote-ws") {
|
|
3624
3681
|
const backend = {
|
|
3625
3682
|
kind: "remote-ws",
|
|
3626
3683
|
url: wsUrl,
|
|
@@ -3631,10 +3688,27 @@ function WorkbenchStudio({ engine, onEngineChange, example, onExampleChange, bac
|
|
|
3631
3688
|
onCustomEvent: backendOptions.onCustomEvent,
|
|
3632
3689
|
}),
|
|
3633
3690
|
};
|
|
3634
|
-
|
|
3691
|
+
newRunner = new RemoteGraphRunner(registry, backend);
|
|
3692
|
+
}
|
|
3693
|
+
else {
|
|
3694
|
+
newRunner = new LocalGraphRunner(registry);
|
|
3635
3695
|
}
|
|
3636
|
-
|
|
3696
|
+
prevRunnerRef.current = newRunner;
|
|
3697
|
+
return newRunner;
|
|
3637
3698
|
}, [registry, backendKind, httpBaseUrl, wsUrl, backendOptions]);
|
|
3699
|
+
// Cleanup runner on unmount
|
|
3700
|
+
React.useEffect(() => {
|
|
3701
|
+
return () => {
|
|
3702
|
+
if (prevRunnerRef.current) {
|
|
3703
|
+
try {
|
|
3704
|
+
prevRunnerRef.current.dispose();
|
|
3705
|
+
}
|
|
3706
|
+
catch (err) {
|
|
3707
|
+
console.warn("Error disposing runner on unmount:", err);
|
|
3708
|
+
}
|
|
3709
|
+
}
|
|
3710
|
+
};
|
|
3711
|
+
}, []);
|
|
3638
3712
|
// Allow external UI registration (e.g., node renderers) with access to wb
|
|
3639
3713
|
React.useEffect(() => {
|
|
3640
3714
|
const baseRegisterUI = (_wb) => { };
|