@bian-womp/spark-workbench 0.2.1 → 0.2.3
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 +47 -42
- package/lib/cjs/index.cjs.map +1 -1
- package/lib/cjs/src/core/InMemoryWorkbench.d.ts +1 -0
- package/lib/cjs/src/core/InMemoryWorkbench.d.ts.map +1 -1
- package/lib/cjs/src/core/contracts.d.ts +5 -0
- package/lib/cjs/src/core/contracts.d.ts.map +1 -1
- package/lib/cjs/src/misc/Inspector.d.ts.map +1 -1
- package/lib/cjs/src/misc/context/WorkbenchContext.d.ts +1 -0
- 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/cjs/src/misc/hooks.d.ts.map +1 -1
- package/lib/esm/index.js +47 -42
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/src/core/InMemoryWorkbench.d.ts +1 -0
- package/lib/esm/src/core/InMemoryWorkbench.d.ts.map +1 -1
- package/lib/esm/src/core/contracts.d.ts +5 -0
- package/lib/esm/src/core/contracts.d.ts.map +1 -1
- package/lib/esm/src/misc/Inspector.d.ts.map +1 -1
- package/lib/esm/src/misc/context/WorkbenchContext.d.ts +1 -0
- 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/lib/esm/src/misc/hooks.d.ts.map +1 -1
- package/package.json +4 -4
package/lib/cjs/index.cjs
CHANGED
|
@@ -202,6 +202,20 @@ class InMemoryWorkbench extends AbstractWorkbench {
|
|
|
202
202
|
});
|
|
203
203
|
this.emit("validationChanged", this.validate());
|
|
204
204
|
}
|
|
205
|
+
updateEdgeType(edgeId, typeId) {
|
|
206
|
+
const e = this.def.edges.find((x) => x.id === edgeId);
|
|
207
|
+
if (!e)
|
|
208
|
+
return;
|
|
209
|
+
if (!typeId)
|
|
210
|
+
delete e.typeId;
|
|
211
|
+
else
|
|
212
|
+
e.typeId = typeId;
|
|
213
|
+
this.emit("graphChanged", {
|
|
214
|
+
def: this.def,
|
|
215
|
+
change: { type: "updateEdgeType", edgeId, typeId },
|
|
216
|
+
});
|
|
217
|
+
this.refreshValidation();
|
|
218
|
+
}
|
|
205
219
|
updateParams(nodeId, params) {
|
|
206
220
|
const n = this.def.nodes.find((n) => n.nodeId === nodeId);
|
|
207
221
|
if (!n)
|
|
@@ -780,23 +794,6 @@ function useWorkbenchBridge(wb) {
|
|
|
780
794
|
}
|
|
781
795
|
}
|
|
782
796
|
}
|
|
783
|
-
else if (type === "selectNodes") {
|
|
784
|
-
const ids = change.ids;
|
|
785
|
-
const selected = change.selected;
|
|
786
|
-
if (Array.isArray(ids) && typeof selected === "boolean") {
|
|
787
|
-
for (const id of ids) {
|
|
788
|
-
if (selected) {
|
|
789
|
-
if (!nextNodeIds.has(id)) {
|
|
790
|
-
nextNodeIds.add(id);
|
|
791
|
-
selectionChanged = true;
|
|
792
|
-
}
|
|
793
|
-
}
|
|
794
|
-
else if (nextNodeIds.delete(id)) {
|
|
795
|
-
selectionChanged = true;
|
|
796
|
-
}
|
|
797
|
-
}
|
|
798
|
-
}
|
|
799
|
-
}
|
|
800
797
|
else if (type === "remove") {
|
|
801
798
|
const id = change.id;
|
|
802
799
|
if (nextNodeIds.delete(id))
|
|
@@ -804,7 +801,10 @@ function useWorkbenchBridge(wb) {
|
|
|
804
801
|
}
|
|
805
802
|
}
|
|
806
803
|
if (selectionChanged) {
|
|
807
|
-
wb.setSelection({
|
|
804
|
+
wb.setSelection({
|
|
805
|
+
nodes: Array.from(nextNodeIds),
|
|
806
|
+
edges: current.edges,
|
|
807
|
+
});
|
|
808
808
|
}
|
|
809
809
|
}, [wb]);
|
|
810
810
|
const onEdgesDelete = React.useCallback((edges) => edges.forEach((e) => wb.disconnect(e.id)), [wb]);
|
|
@@ -829,23 +829,6 @@ function useWorkbenchBridge(wb) {
|
|
|
829
829
|
}
|
|
830
830
|
}
|
|
831
831
|
}
|
|
832
|
-
else if (type === "selectEdges") {
|
|
833
|
-
const ids = change.ids;
|
|
834
|
-
const selected = change.selected;
|
|
835
|
-
if (Array.isArray(ids) && typeof selected === "boolean") {
|
|
836
|
-
for (const id of ids) {
|
|
837
|
-
if (selected) {
|
|
838
|
-
if (!nextEdgeIds.has(id)) {
|
|
839
|
-
nextEdgeIds.add(id);
|
|
840
|
-
selectionChanged = true;
|
|
841
|
-
}
|
|
842
|
-
}
|
|
843
|
-
else if (nextEdgeIds.delete(id)) {
|
|
844
|
-
selectionChanged = true;
|
|
845
|
-
}
|
|
846
|
-
}
|
|
847
|
-
}
|
|
848
|
-
}
|
|
849
832
|
else if (type === "remove") {
|
|
850
833
|
const id = change.id;
|
|
851
834
|
if (nextEdgeIds.delete(id))
|
|
@@ -853,7 +836,10 @@ function useWorkbenchBridge(wb) {
|
|
|
853
836
|
}
|
|
854
837
|
}
|
|
855
838
|
if (selectionChanged) {
|
|
856
|
-
wb.setSelection({
|
|
839
|
+
wb.setSelection({
|
|
840
|
+
nodes: current.nodes,
|
|
841
|
+
edges: Array.from(nextEdgeIds),
|
|
842
|
+
});
|
|
857
843
|
}
|
|
858
844
|
}, [wb]);
|
|
859
845
|
const onNodesDelete = React.useCallback((nodes) => {
|
|
@@ -910,7 +896,9 @@ function useThrottledValue(value, intervalMs) {
|
|
|
910
896
|
const lastSetAtRef = React.useRef(0);
|
|
911
897
|
const timeoutRef = React.useRef(null);
|
|
912
898
|
React.useEffect(() => {
|
|
913
|
-
const now =
|
|
899
|
+
const now = typeof performance !== "undefined" && performance.now
|
|
900
|
+
? performance.now()
|
|
901
|
+
: Date.now();
|
|
914
902
|
const elapsed = now - lastSetAtRef.current;
|
|
915
903
|
if (elapsed >= intervalMs) {
|
|
916
904
|
lastSetAtRef.current = now;
|
|
@@ -921,7 +909,10 @@ function useThrottledValue(value, intervalMs) {
|
|
|
921
909
|
window.clearTimeout(timeoutRef.current);
|
|
922
910
|
}
|
|
923
911
|
timeoutRef.current = window.setTimeout(() => {
|
|
924
|
-
lastSetAtRef.current =
|
|
912
|
+
lastSetAtRef.current =
|
|
913
|
+
typeof performance !== "undefined" && performance.now
|
|
914
|
+
? performance.now()
|
|
915
|
+
: Date.now();
|
|
925
916
|
setThrottled(value);
|
|
926
917
|
timeoutRef.current = null;
|
|
927
918
|
}, Math.max(0, intervalMs - elapsed));
|
|
@@ -1400,6 +1391,7 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, children, }) {
|
|
|
1400
1391
|
});
|
|
1401
1392
|
wb.setPositions(pos);
|
|
1402
1393
|
}, [wb]);
|
|
1394
|
+
const updateEdgeType = React.useCallback((edgeId, typeId) => wb.updateEdgeType(edgeId, typeId), [wb]);
|
|
1403
1395
|
// Subscribe to runner/workbench events
|
|
1404
1396
|
React.useEffect(() => {
|
|
1405
1397
|
const add = (source, type) => (payload) => setEvents((prev) => {
|
|
@@ -1410,8 +1402,15 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, children, }) {
|
|
|
1410
1402
|
if (changeType === "moveNode" || changeType === "moveNodes")
|
|
1411
1403
|
return prev;
|
|
1412
1404
|
}
|
|
1405
|
+
const nextNo = prev.length > 0 ? (prev[0]?.no ?? 0) + 1 : 1;
|
|
1413
1406
|
const next = [
|
|
1414
|
-
{
|
|
1407
|
+
{
|
|
1408
|
+
no: nextNo,
|
|
1409
|
+
at: Date.now(),
|
|
1410
|
+
source,
|
|
1411
|
+
type,
|
|
1412
|
+
payload: structuredClone(payload),
|
|
1413
|
+
},
|
|
1415
1414
|
...prev,
|
|
1416
1415
|
];
|
|
1417
1416
|
return next.length > 200 ? next.slice(0, 200) : next;
|
|
@@ -1726,6 +1725,7 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, children, }) {
|
|
|
1726
1725
|
step,
|
|
1727
1726
|
flush,
|
|
1728
1727
|
runAutoLayout,
|
|
1728
|
+
updateEdgeType,
|
|
1729
1729
|
}), [
|
|
1730
1730
|
wb,
|
|
1731
1731
|
runner,
|
|
@@ -1752,6 +1752,7 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, children, }) {
|
|
|
1752
1752
|
step,
|
|
1753
1753
|
flush,
|
|
1754
1754
|
runAutoLayout,
|
|
1755
|
+
wb,
|
|
1755
1756
|
]);
|
|
1756
1757
|
return (jsxRuntime.jsx(WorkbenchContext.Provider, { value: value, children: children }));
|
|
1757
1758
|
}
|
|
@@ -1787,7 +1788,7 @@ function DebugEvents({ autoScroll, onAutoScrollChange, hideWorkbench, onHideWork
|
|
|
1787
1788
|
return String(v);
|
|
1788
1789
|
}
|
|
1789
1790
|
};
|
|
1790
|
-
return (jsxRuntime.jsxs("div", { className: "flex flex-col h-full min-h-0", children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-1", children: [jsxRuntime.jsx("div", { className: "font-semibold", children: "Events" }), jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsxs("label", { className: "flex items-center gap-1 text-xs text-gray-700", children: [jsxRuntime.jsx("input", { type: "checkbox", checked: hideWorkbench, onChange: (e) => onHideWorkbenchChange?.(e.target.checked) }), jsxRuntime.jsx("span", { children: "Hide workbench" })] }), jsxRuntime.jsxs("label", { className: "flex items-center gap-1 text-xs text-gray-700", children: [jsxRuntime.jsx("input", { type: "checkbox", checked: autoScroll, onChange: (e) => onAutoScrollChange?.(e.target.checked) }), jsxRuntime.jsx("span", { children: "Auto scroll" })] }), jsxRuntime.jsx("button", { onClick: clearEvents, className: "text-xs px-2 py-0.5 border border-gray-300 rounded", children: "Clear" })] })] }), jsxRuntime.jsx("div", { ref: scrollRef, className: "flex-1 overflow-auto text-[11px] leading-4 divide-y divide-gray-200", children: rows.map((ev
|
|
1791
|
+
return (jsxRuntime.jsxs("div", { className: "flex flex-col h-full min-h-0", children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-1", children: [jsxRuntime.jsx("div", { className: "font-semibold", children: "Events" }), jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsxs("label", { className: "flex items-center gap-1 text-xs text-gray-700", children: [jsxRuntime.jsx("input", { type: "checkbox", checked: hideWorkbench, onChange: (e) => onHideWorkbenchChange?.(e.target.checked) }), jsxRuntime.jsx("span", { children: "Hide workbench" })] }), jsxRuntime.jsxs("label", { className: "flex items-center gap-1 text-xs text-gray-700", children: [jsxRuntime.jsx("input", { type: "checkbox", checked: autoScroll, onChange: (e) => onAutoScrollChange?.(e.target.checked) }), jsxRuntime.jsx("span", { children: "Auto scroll" })] }), jsxRuntime.jsx("button", { onClick: clearEvents, className: "text-xs px-2 py-0.5 border border-gray-300 rounded", children: "Clear" })] })] }), jsxRuntime.jsx("div", { ref: scrollRef, className: "flex-1 overflow-auto text-[11px] leading-4 divide-y divide-gray-200", children: rows.map((ev) => (jsxRuntime.jsxs("div", { className: "opacity-85 odd:bg-gray-50 px-2 py-1", children: [jsxRuntime.jsxs("div", { className: "flex items-baseline gap-2", children: [jsxRuntime.jsx("span", { className: "w-12 shrink-0 text-right text-gray-500 select-none", children: ev.no }), jsxRuntime.jsxs("span", { className: "text-gray-500", children: [new Date(ev.at).toLocaleTimeString(), " \u00B7 ", ev.source, ":", ev.type] })] }), jsxRuntime.jsx("pre", { className: "m-0 whitespace-pre-wrap ml-12", children: renderPayload(ev.payload) })] }, `${ev.at}:${ev.no}`))) })] }));
|
|
1791
1792
|
}
|
|
1792
1793
|
|
|
1793
1794
|
function Inspector({ debug, autoScroll, hideWorkbench, onAutoScrollChange, onHideWorkbenchChange, toString, toElement, contextPanel, setInput, }) {
|
|
@@ -1802,7 +1803,7 @@ function Inspector({ debug, autoScroll, hideWorkbench, onAutoScrollChange, onHid
|
|
|
1802
1803
|
return String(value ?? "");
|
|
1803
1804
|
}
|
|
1804
1805
|
};
|
|
1805
|
-
const { registry, def, selectedNodeId, selectedEdgeId, inputsMap, outputsMap, outputTypesMap, nodeStatus, validationByNode, validationByEdge, validationGlobal, valuesTick, } = useWorkbenchContext();
|
|
1806
|
+
const { registry, def, selectedNodeId, selectedEdgeId, inputsMap, outputsMap, outputTypesMap, nodeStatus, validationByNode, validationByEdge, validationGlobal, valuesTick, updateEdgeType, } = useWorkbenchContext();
|
|
1806
1807
|
const nodeValidationIssues = validationByNode.issues;
|
|
1807
1808
|
const edgeValidationIssues = validationByEdge.issues;
|
|
1808
1809
|
const nodeValidationHandles = validationByNode;
|
|
@@ -1879,7 +1880,11 @@ function Inspector({ debug, autoScroll, hideWorkbench, onAutoScrollChange, onHid
|
|
|
1879
1880
|
setOriginals(nextOriginals);
|
|
1880
1881
|
}, [selectedNodeId, selectedDesc, valuesTick]);
|
|
1881
1882
|
const widthClass = debug ? "w-[480px]" : "w-[320px]";
|
|
1882
|
-
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 &&
|
|
1883
|
+
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}` })] }, 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.jsxs("div", { className: "flex items-center gap-2 mt-1", children: [jsxRuntime.jsxs("label", { className: "w-20 flex flex-col", children: [jsxRuntime.jsx("span", { children: "Type" }), jsxRuntime.jsx("span", { className: "text-gray-500 text-[11px]", children: "DataTypeId" })] }), jsxRuntime.jsxs("select", { className: "border border-gray-300 rounded px-2 py-1 focus:outline-none focus:ring-2 focus:ring-blue-500 w-full", value: selectedEdge.typeId ?? "", onChange: (e) => {
|
|
1884
|
+
const v = e.target.value;
|
|
1885
|
+
const next = v === "" ? undefined : v;
|
|
1886
|
+
updateEdgeType(selectedEdge.id, next);
|
|
1887
|
+
}, children: [jsxRuntime.jsx("option", { value: "", children: "(infer from source)" }), Array.from(registry.types.keys()).map((tid) => (jsxRuntime.jsx("option", { value: tid, children: tid }, tid)))] })] })] }), selectedEdgeValidation.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: selectedEdgeValidation.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}` })] }, i))) })] }))] })) : (jsxRuntime.jsxs("div", { children: [selectedNode && (jsxRuntime.jsxs("div", { className: "mb-2", children: [jsxRuntime.jsxs("div", { children: ["Node: ", selectedNode.nodeId] }), jsxRuntime.jsxs("div", { children: ["Type: ", selectedNode.typeId] }), !!selectedNodeStatus?.lastError && (jsxRuntime.jsx("div", { className: "mt-2 text-sm text-red-700 bg-red-50 border border-red-200 rounded px-2 py-1 break-words", children: String(selectedNodeStatus.lastError?.message ??
|
|
1883
1888
|
selectedNodeStatus.lastError) }))] })), jsxRuntime.jsxs("div", { className: "mb-2", children: [jsxRuntime.jsx("div", { className: "font-semibold mb-1", children: "Inputs" }), inputHandles.length === 0 ? (jsxRuntime.jsx("div", { className: "text-gray-500", children: "No inputs" })) : (inputHandles.map((h) => {
|
|
1884
1889
|
const typeId = sparkGraph.getInputTypeId(selectedDesc?.inputs, h);
|
|
1885
1890
|
const isLinked = def.edges.some((e) => e.target.nodeId === selectedNodeId &&
|