@bian-womp/spark-workbench 0.1.2 → 0.1.4
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 +76 -12
- package/lib/cjs/index.cjs.map +1 -1
- package/lib/cjs/src/examples/reactflow/WorkbenchStudio.d.ts.map +1 -1
- package/lib/cjs/src/misc/Inspector.d.ts.map +1 -1
- package/lib/esm/index.js +77 -13
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/src/examples/reactflow/WorkbenchStudio.d.ts.map +1 -1
- package/lib/esm/src/misc/Inspector.d.ts.map +1 -1
- package/package.json +7 -8
package/lib/cjs/index.cjs
CHANGED
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
var sparkGraph = require('@bian-womp/spark-graph');
|
|
4
4
|
var jsxRuntime = require('react/jsx-runtime');
|
|
5
5
|
var React = require('react');
|
|
6
|
+
var sparkRemote = require('@bian-womp/spark-remote');
|
|
6
7
|
var ReactFlow = require('reactflow');
|
|
7
8
|
require('reactflow/dist/style.css');
|
|
8
9
|
var cx = require('classnames');
|
|
9
10
|
var react = require('@phosphor-icons/react');
|
|
10
|
-
var sparkRemote = require('@bian-womp/spark-remote');
|
|
11
11
|
|
|
12
12
|
class DefaultUIExtensionRegistry {
|
|
13
13
|
constructor() {
|
|
@@ -1157,7 +1157,8 @@ function Inspector({ debug, autoScroll, hideWorkbench, onAutoScrollChange, onHid
|
|
|
1157
1157
|
return (jsxRuntime.jsxs("div", { className: `${widthClass} border-l border-gray-300 p-3 flex flex-col h-full min-h-0 overflow-hidden`, children: [jsxRuntime.jsx("div", { className: "font-semibold mb-2", children: "Inspector" }), 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", { children: ["Type: ", selectedEdge.typeId] })] }), 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 ??
|
|
1158
1158
|
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) => {
|
|
1159
1159
|
const typeId = (selectedDesc?.inputs ?? {})[h];
|
|
1160
|
-
const isLinked = def.edges.some((e) => e.target.nodeId === selectedNodeId &&
|
|
1160
|
+
const isLinked = def.edges.some((e) => e.target.nodeId === selectedNodeId &&
|
|
1161
|
+
e.target.handle === h);
|
|
1161
1162
|
const commonProps = {
|
|
1162
1163
|
style: { flex: 1 },
|
|
1163
1164
|
disabled: isLinked,
|
|
@@ -1176,7 +1177,7 @@ function Inspector({ debug, autoScroll, hideWorkbench, onAutoScrollChange, onHid
|
|
|
1176
1177
|
const orig = originals[h] ?? toDisplay(typeId, current);
|
|
1177
1178
|
setDrafts((d) => ({ ...d, [h]: orig }));
|
|
1178
1179
|
};
|
|
1179
|
-
const isEnum = typeId?.
|
|
1180
|
+
const isEnum = typeId?.includes("enum:");
|
|
1180
1181
|
const inIssues = selectedNodeHandleValidation.inputs.filter((m) => m.handle === h);
|
|
1181
1182
|
const hasValidation = inIssues.length > 0;
|
|
1182
1183
|
const hasErr = inIssues.some((m) => m.level === "error");
|
|
@@ -1539,6 +1540,60 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
|
|
|
1539
1540
|
setExampleState(key);
|
|
1540
1541
|
onExampleChange?.(key);
|
|
1541
1542
|
}, [runner, wb, onExampleChange, runAutoLayout]);
|
|
1543
|
+
const hydrateFromBackend = React.useCallback(async (kind, base) => {
|
|
1544
|
+
try {
|
|
1545
|
+
const transport = kind === "remote-http"
|
|
1546
|
+
? new sparkRemote.HttpPollingTransport(base)
|
|
1547
|
+
: new sparkRemote.WebSocketTransport(base);
|
|
1548
|
+
await transport.connect();
|
|
1549
|
+
const rr = new sparkRemote.RemoteRunner(transport);
|
|
1550
|
+
const desc = await rr.describeRegistry();
|
|
1551
|
+
const r = new sparkGraph.Registry();
|
|
1552
|
+
// Types
|
|
1553
|
+
for (const t of desc.types) {
|
|
1554
|
+
r.registerType({
|
|
1555
|
+
id: t.id,
|
|
1556
|
+
displayName: t.displayName,
|
|
1557
|
+
validate: (_v) => true,
|
|
1558
|
+
});
|
|
1559
|
+
}
|
|
1560
|
+
// Categories: create placeholders for display name
|
|
1561
|
+
for (const c of desc.categories || []) {
|
|
1562
|
+
// If you later expose real category descriptors, register them here
|
|
1563
|
+
// For now, rely on ComputeCategory for behavior
|
|
1564
|
+
const category = {
|
|
1565
|
+
id: c.id,
|
|
1566
|
+
displayName: c.displayName,
|
|
1567
|
+
createRuntime: () => ({
|
|
1568
|
+
async onInputsChanged() { },
|
|
1569
|
+
}),
|
|
1570
|
+
policy: { mode: "push", asyncConcurrency: "switch" },
|
|
1571
|
+
};
|
|
1572
|
+
r.categories.register(category);
|
|
1573
|
+
}
|
|
1574
|
+
// Coercions (client-side no-op to satisfy validation) if provided
|
|
1575
|
+
for (const c of desc.coercions) {
|
|
1576
|
+
r.registerCoercion(c.from, c.to, (v) => v);
|
|
1577
|
+
}
|
|
1578
|
+
// Nodes (use no-op impl for compute)
|
|
1579
|
+
for (const n of desc.nodes) {
|
|
1580
|
+
r.registerNode({
|
|
1581
|
+
id: n.id,
|
|
1582
|
+
categoryId: n.categoryId,
|
|
1583
|
+
displayName: n.displayName,
|
|
1584
|
+
inputs: n.inputs || {},
|
|
1585
|
+
outputs: n.outputs || {},
|
|
1586
|
+
impl: () => { },
|
|
1587
|
+
});
|
|
1588
|
+
}
|
|
1589
|
+
setRegistry(r);
|
|
1590
|
+
wb.setRegistry(r);
|
|
1591
|
+
await transport.close();
|
|
1592
|
+
}
|
|
1593
|
+
catch (err) {
|
|
1594
|
+
console.error("Failed to hydrate registry from backend:", err);
|
|
1595
|
+
}
|
|
1596
|
+
}, [setRegistry, wb]);
|
|
1542
1597
|
// Ensure initial example is loaded (and sync when example prop changes)
|
|
1543
1598
|
React.useEffect(() => {
|
|
1544
1599
|
applyExample(example ?? "simple");
|
|
@@ -1561,6 +1616,15 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
|
|
|
1561
1616
|
// ignore
|
|
1562
1617
|
}
|
|
1563
1618
|
}, [engine, runner, wb]);
|
|
1619
|
+
// When switching to remote backend, auto-hydrate registry from backend
|
|
1620
|
+
React.useEffect(() => {
|
|
1621
|
+
if (backendKind === "remote-http" && httpBaseUrl) {
|
|
1622
|
+
void hydrateFromBackend("remote-http", httpBaseUrl);
|
|
1623
|
+
}
|
|
1624
|
+
else if (backendKind === "remote-ws" && wsUrl) {
|
|
1625
|
+
void hydrateFromBackend("remote-ws", wsUrl);
|
|
1626
|
+
}
|
|
1627
|
+
}, [backendKind, httpBaseUrl, wsUrl, hydrateFromBackend]);
|
|
1564
1628
|
React.useEffect(() => {
|
|
1565
1629
|
if (autoLayoutRan.current)
|
|
1566
1630
|
return;
|
|
@@ -1597,33 +1661,33 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
|
|
|
1597
1661
|
.map(map);
|
|
1598
1662
|
};
|
|
1599
1663
|
switch (typeId) {
|
|
1600
|
-
case "float": {
|
|
1664
|
+
case "base.float": {
|
|
1601
1665
|
const n = Number(raw);
|
|
1602
1666
|
value = Number.isFinite(n) ? n : 0;
|
|
1603
1667
|
break;
|
|
1604
1668
|
}
|
|
1605
|
-
case "bool": {
|
|
1669
|
+
case "base.bool": {
|
|
1606
1670
|
value = Boolean(raw);
|
|
1607
1671
|
break;
|
|
1608
1672
|
}
|
|
1609
|
-
case "string": {
|
|
1673
|
+
case "base.string": {
|
|
1610
1674
|
value = String(raw);
|
|
1611
1675
|
break;
|
|
1612
1676
|
}
|
|
1613
|
-
case "float[]": {
|
|
1677
|
+
case "base.float[]": {
|
|
1614
1678
|
value = parseArray(String(raw), (x) => Number(x));
|
|
1615
1679
|
break;
|
|
1616
1680
|
}
|
|
1617
|
-
case "bool[]": {
|
|
1681
|
+
case "base.bool[]": {
|
|
1618
1682
|
value = parseArray(String(raw), (x) => /^(true|1)$/i.test(x));
|
|
1619
1683
|
break;
|
|
1620
1684
|
}
|
|
1621
|
-
case "vec3": {
|
|
1685
|
+
case "base.vec3": {
|
|
1622
1686
|
const arr = parseArray(String(raw), (x) => Number(x));
|
|
1623
1687
|
value = [arr[0] ?? 0, arr[1] ?? 0, arr[2] ?? 0];
|
|
1624
1688
|
break;
|
|
1625
1689
|
}
|
|
1626
|
-
case "vec3[]": {
|
|
1690
|
+
case "base.vec3[]": {
|
|
1627
1691
|
try {
|
|
1628
1692
|
const parsed = JSON.parse(String(raw));
|
|
1629
1693
|
if (Array.isArray(parsed)) {
|
|
@@ -1655,13 +1719,13 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
|
|
|
1655
1719
|
const toDisplay = React.useCallback((typeId, value) => {
|
|
1656
1720
|
if (value === undefined || value === null)
|
|
1657
1721
|
return "";
|
|
1658
|
-
if (typeId && typeId.
|
|
1722
|
+
if (typeId && typeId.includes("enum:")) {
|
|
1659
1723
|
const n = Number(value);
|
|
1660
1724
|
const label = registry.getEnumLabel(typeId, n);
|
|
1661
1725
|
return label ?? String(n);
|
|
1662
1726
|
}
|
|
1663
1727
|
const round4 = (n) => Math.round(Number(n) * 10000) / 10000;
|
|
1664
|
-
if (typeId === "vec3" && Array.isArray(value)) {
|
|
1728
|
+
if (typeId === "base.vec3" && Array.isArray(value)) {
|
|
1665
1729
|
const a = value;
|
|
1666
1730
|
return [round4(a[0] ?? 0), round4(a[1] ?? 0), round4(a[2] ?? 0)].join(",");
|
|
1667
1731
|
}
|