From 8607d097da022d6e5cc48eb7c551edbbcac8ec87 Mon Sep 17 00:00:00 2001 From: Pablo Colturi Date: Wed, 8 Jul 2026 12:18:47 +0200 Subject: [PATCH 01/11] Feat: free-text Coral plugin path with Browse - feat: make the local Coral plugin path a free-text field with a Browse button (accepts a plugin path or a value passed to -p, e.g. a comma-separated module list) - fix: stop the local probe requiring the Coral plugin path to be an existing file on disk - docs: note the field's dual use in run-coral-local.md and add a CHANGELOG entry --- CHANGELOG.md | 1 + docs/run-coral-local.md | 4 ++++ electron/utils/executionProbe.ts | 3 --- src/lib/components/SettingsModal.svelte | 24 +++++++++++++++++++----- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e0e2410..8ee5c88 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ See [docs/changelog-template.md](docs/changelog-template.md) for formatting your - [#112](https://github.com/2listic/dealiiX-platform/issues/112) The Project button group is now disabled when the user is not logged in, in addition to when no remote server is configured. - [#185](https://github.com/2listic/dealiiX-platform/pull/185) Parameter section duplicate logis is via a new duplicate button instead of via right-click. Duplicated sections can be deleted with a new delete button. Sections are set back to native `
`/`` elements for collapsible behaviour. - [#185](https://github.com/2listic/dealiiX-platform/pull/185) The execution modal now includes an editable parameters file name field, letting users override the file path per run without changing the global settings. +- The local **Coral plugin path** setting is now a free-text field with a Browse button (previously a file picker only), so it accepts either a plugin file path or an arbitrary value passed to the backend's `-p` flag (e.g. a comma-separated list of modules). The local probe no longer requires the plugin path to be an existing file on disk. ### Electron-Backend diff --git a/docs/run-coral-local.md b/docs/run-coral-local.md index 7c6bec1..a1c1701 100644 --- a/docs/run-coral-local.md +++ b/docs/run-coral-local.md @@ -41,6 +41,10 @@ Open **Settings** and set the following under **Execution Mode**: | Coral binary path | `/coral/build/core/coral` | | Coral plugin path | `/coral/build/backends/dealii/libcoral_backend_dealii.so` | +> The **Coral plugin path** field accepts a plugin file path (use **Browse**) or any free-text value +> passed to the backend's `-p` flag — for example a comma-separated list of module names. Type it +> directly when it isn't a file on disk. + Click **Save & Sync** to probe the binary, load the node registry into the sidebar, and confirm everything works. ## Manual testing diff --git a/electron/utils/executionProbe.ts b/electron/utils/executionProbe.ts index 2e004c8..71aea21 100644 --- a/electron/utils/executionProbe.ts +++ b/electron/utils/executionProbe.ts @@ -89,9 +89,6 @@ const fileMustExist = (filePath: string | undefined, label: string): void => { const probeLocalPaths = (execution: ExecutionSettings): void => { if (execution.backendKind === 'coral') { fileMustExist(execution.local.coralBinaryPath, 'Coral binary') - if (execution.local.coralPluginPath) { - fileMustExist(execution.local.coralPluginPath, 'Coral plugin') - } } else if (execution.backendKind === 'executable') { fileMustExist(execution.local.executablePath, 'Executable') } diff --git a/src/lib/components/SettingsModal.svelte b/src/lib/components/SettingsModal.svelte index d5bc5e1..ace4dcf 100644 --- a/src/lib/components/SettingsModal.svelte +++ b/src/lib/components/SettingsModal.svelte @@ -304,7 +304,7 @@ {/if}
- Coral plugin path + Coral plugin path or module list {#if showRemoteSettings} {:else}
-
- {localCoralPluginPath || 'No file selected'} -
- + +
{/if} +

+ A plugin path (.so) — use Browse — or a comma-separated + module list (e.g. module1,module2,module3). +

@@ -670,6 +678,12 @@ padding: 0 1rem; } + .field-hint { + margin: 0; + font-size: 0.8rem; + opacity: 0.7; + } + .button-container { margin-top: 2vh; } From 6e2d3d8d197fa5c634acb194bbe891a4c376ac28 Mon Sep 17 00:00:00 2001 From: Pablo Colturi Date: Wed, 8 Jul 2026 13:17:26 +0200 Subject: [PATCH 02/11] Feat: render primitive-typed nodes with an editable literal - feat: show the literal input for node_type "primitive" (NodeTypePyBackend.PRIMITIVE), not only elementary_constructor - fix: make numeric value validation null-safe so a null/empty primitive value no longer throws - docs: add CHANGELOG entry --- CHANGELOG.md | 1 + src/lib/components/nodes/UnifiedNode.svelte | 19 ++++++++++++------- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ee5c88..ae2c1a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ See [docs/changelog-template.md](docs/changelog-template.md) for formatting your - [#185](https://github.com/2listic/dealiiX-platform/pull/185) Parameter section duplicate logis is via a new duplicate button instead of via right-click. Duplicated sections can be deleted with a new delete button. Sections are set back to native `
`/`` elements for collapsible behaviour. - [#185](https://github.com/2listic/dealiiX-platform/pull/185) The execution modal now includes an editable parameters file name field, letting users override the file path per run without changing the global settings. - The local **Coral plugin path** setting is now a free-text field with a Browse button (previously a file picker only), so it accepts either a plugin file path or an arbitrary value passed to the backend's `-p` flag (e.g. a comma-separated list of modules). The local probe no longer requires the plugin path to be an existing file on disk. +- Nodes with `node_type: "primitive"` now render an editable literal field (a text box, or a checkbox for booleans) like elementary constructors, so registries that use the `primitive` node type are fully usable on the canvas. Numeric value validation is also null-safe, so it no longer errors when a value is empty. ### Electron-Backend diff --git a/src/lib/components/nodes/UnifiedNode.svelte b/src/lib/components/nodes/UnifiedNode.svelte index 34e5f04..c963101 100644 --- a/src/lib/components/nodes/UnifiedNode.svelte +++ b/src/lib/components/nodes/UnifiedNode.svelte @@ -56,6 +56,7 @@ import { nodeColors, NodeType, + NodeTypePyBackend, Type, isNumericType, } from '../../types/nodeTypes' @@ -95,8 +96,10 @@ let editNodeModalId = $derived(`edit-node-${id}`) - const isValidNum = (value: string) => { - const numValue = Number(value) + const isValidNum = (value: string | null | undefined) => { + // Primitive/elementary nodes may start with a null value; coerce so `.trim()` is always safe. + const safeValue = value ?? '' + const numValue = Number(safeValue) switch (data.type) { case Type.UNSIGNED_INT: case Type.UNSIGNED: @@ -104,14 +107,16 @@ !isNaN(numValue) && Number.isInteger(numValue) && numValue >= 0 && - value.trim() !== '' + safeValue.trim() !== '' ) case Type.INT: return ( - !isNaN(numValue) && Number.isInteger(numValue) && value.trim() !== '' + !isNaN(numValue) && + Number.isInteger(numValue) && + safeValue.trim() !== '' ) case (Type.DOUBLE, Type.FLOAT): - return !isNaN(numValue) && value.trim() !== '' + return !isNaN(numValue) && safeValue.trim() !== '' } } @@ -276,8 +281,8 @@ {/if} - - {#if data.node_type === NodeType.ELEMENTARY_CONSTRUCTOR} + + {#if data.node_type === NodeType.ELEMENTARY_CONSTRUCTOR || (data.node_type as string) === NodeTypePyBackend.PRIMITIVE}
{#if data.type === Type.BOOLEAN} Date: Wed, 8 Jul 2026 13:17:33 +0200 Subject: [PATCH 03/11] Chore: remove obsolete NOTE.md --- NOTE.md | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 NOTE.md diff --git a/NOTE.md b/NOTE.md deleted file mode 100644 index 0ccdee2..0000000 --- a/NOTE.md +++ /dev/null @@ -1,10 +0,0 @@ -## First Steps - -- Configuration of a local server on my PC, an endpoint `/alive_local` (FastAPI) -- Configuration of a remote server with endpoint `/alive_remote` (FastAPI) -- Configuration of a client application using Electron and SvelteFlow that will make SSH connections to a cluster and send data to the remote server - -The main objective of this initial end-to-end test is to test the client application, which should be able to: - -- Make SSH connections to different nodes in the cluster from the local machine. -- Send data obtained from the cluster to a remote server. From 3a304eebfa7944df1f3d2b4adf48f17340344a15 Mon Sep 17 00:00:00 2001 From: Pablo Colturi Date: Wed, 8 Jul 2026 13:34:34 +0200 Subject: [PATCH 04/11] Refactor: move Download Graph into an Import / Export group --- CHANGELOG.md | 1 + src/lib/components/layout/SidebarButtons.svelte | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ae2c1a7..682aa0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ See [docs/changelog-template.md](docs/changelog-template.md) for formatting your - [#185](https://github.com/2listic/dealiiX-platform/pull/185) The execution modal now includes an editable parameters file name field, letting users override the file path per run without changing the global settings. - The local **Coral plugin path** setting is now a free-text field with a Browse button (previously a file picker only), so it accepts either a plugin file path or an arbitrary value passed to the backend's `-p` flag (e.g. a comma-separated list of modules). The local probe no longer requires the plugin path to be an existing file on disk. - Nodes with `node_type: "primitive"` now render an editable literal field (a text box, or a checkbox for booleans) like elementary constructors, so registries that use the `primitive` node type are fully usable on the canvas. Numeric value validation is also null-safe, so it no longer errors when a value is empty. +- The **Download Graph** action moved from the Project group into the renamed **Import / Export** group, next to Import Graph. It no longer requires being logged in to a remote server, so the current graph can be exported to JSON while working locally. ### Electron-Backend diff --git a/src/lib/components/layout/SidebarButtons.svelte b/src/lib/components/layout/SidebarButtons.svelte index ede4aea..57691d5 100644 --- a/src/lib/components/layout/SidebarButtons.svelte +++ b/src/lib/components/layout/SidebarButtons.svelte @@ -240,7 +240,7 @@ // Create blob with JSON data + filename const blob = new Blob([jsonString], { type: 'application/json' }) const url = URL.createObjectURL(blob) - const filename = `${currentProjectState.name}.json` + const filename = `${currentProjectState.name || 'graph'}.json` // Create temporary anchor and trigger download const anchor = document.createElement('a') @@ -335,10 +335,6 @@ label="Load Projects" onclick={handleLoadProjects} /> - {/snippet} @@ -417,7 +413,7 @@ {#if isCoralMode} - + {#snippet icon()} {/snippet} @@ -430,6 +426,10 @@ label="Import Nodes" onclick={() => importNodesInput?.click()} /> + {/snippet} {/if} From d440492cbc8495af35eb40ec1e191e5daab07a6c Mon Sep 17 00:00:00 2001 From: Pablo Colturi Date: Thu, 9 Jul 2026 10:15:26 +0200 Subject: [PATCH 05/11] Fix: keep edges into 'any'-typed inputs when loading a graph - fix: validateGraphData accepts an 'any' target input, matching the live connection validation - test: add a coral-python functions graph + math registry fixture covering the any-typed print_result input --- CHANGELOG.md | 1 + src/lib/data/coralpyMathNodes.json | 296 ++++++++++++++++++++++ src/lib/utils/graphParser.test.ts | 22 ++ src/lib/utils/graphParser.ts | 8 +- test_files/network-coralpy-functions.json | 86 +++++++ 5 files changed, 411 insertions(+), 2 deletions(-) create mode 100644 src/lib/data/coralpyMathNodes.json create mode 100644 test_files/network-coralpy-functions.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 682aa0a..b7e9cf5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ See [docs/changelog-template.md](docs/changelog-template.md) for formatting your ### Canvas-graph +- Loading a graph no longer drops edges whose target input is typed `any`: import validation now accepts an `any` target input, matching the live connection validation used while drawing edges. - [#175](https://github.com/2listic/dealiiX-platform/issues/175) Per-level undo/redo history for the canvas. Each navigation level (root graph and each open subnetwork) keeps its own independent undo/redo stacks, capped at 50 entries. Undo (Ctrl/⌘+Z) and Redo (Ctrl/⌘+Shift+Z) are available as keyboard shortcuts and as items inside the Layout sidebar group button. ### UI/UX diff --git a/src/lib/data/coralpyMathNodes.json b/src/lib/data/coralpyMathNodes.json new file mode 100644 index 0000000..6ccd8a0 --- /dev/null +++ b/src/lib/data/coralpyMathNodes.json @@ -0,0 +1,296 @@ +{ + "int": { + "arguments": [], + "value": "", + "inputs": [], + "outputs": [-1], + "node_type": "primitive", + "type": "int" + }, + "float": { + "arguments": [], + "value": "", + "inputs": [], + "outputs": [-1], + "node_type": "primitive", + "type": "float" + }, + "str": { + "arguments": [], + "value": "", + "inputs": [], + "outputs": [-1], + "node_type": "primitive", + "type": "str" + }, + "bool": { + "arguments": [], + "value": "", + "inputs": [], + "outputs": [-1], + "node_type": "primitive", + "type": "bool" + }, + "any": { + "arguments": [], + "value": "", + "inputs": [], + "outputs": [-1], + "node_type": "primitive", + "type": "any" + }, + "none": { + "arguments": [], + "value": "", + "inputs": [], + "outputs": [-1], + "node_type": "primitive", + "type": "none" + }, + "print_result": { + "arguments": [ + { + "connection_type": "input", + "type": "any", + "name": "value" + } + ], + "inputs": [0], + "outputs": [], + "node_type": "function", + "type": "print_result" + }, + "add": { + "arguments": [ + { + "connection_type": "input", + "type": "float", + "name": "a" + }, + { + "connection_type": "input", + "type": "float", + "name": "b" + }, + { + "connection_type": "output", + "type": "float", + "name": "" + } + ], + "inputs": [0, 1], + "outputs": [2], + "node_type": "function", + "type": "add" + }, + "multiply": { + "arguments": [ + { + "connection_type": "input", + "type": "float", + "name": "a" + }, + { + "connection_type": "input", + "type": "float", + "name": "b" + }, + { + "connection_type": "output", + "type": "float", + "name": "" + } + ], + "inputs": [0, 1], + "outputs": [2], + "node_type": "function", + "type": "multiply" + }, + "math.sqrt": { + "arguments": [ + { + "connection_type": "input", + "type": "float", + "name": "x" + }, + { + "connection_type": "output", + "type": "float", + "name": "" + } + ], + "inputs": [0], + "outputs": [1], + "node_type": "function", + "type": "math.sqrt" + }, + "math.sin": { + "arguments": [ + { + "connection_type": "input", + "type": "float", + "name": "x" + }, + { + "connection_type": "output", + "type": "float", + "name": "" + } + ], + "inputs": [0], + "outputs": [1], + "node_type": "function", + "type": "math.sin" + }, + "math.cos": { + "arguments": [ + { + "connection_type": "input", + "type": "float", + "name": "x" + }, + { + "connection_type": "output", + "type": "float", + "name": "" + } + ], + "inputs": [0], + "outputs": [1], + "node_type": "function", + "type": "math.cos" + }, + "math.pow": { + "arguments": [ + { + "connection_type": "input", + "type": "float", + "name": "x" + }, + { + "connection_type": "input", + "type": "float", + "name": "y" + }, + { + "connection_type": "output", + "type": "float", + "name": "" + } + ], + "inputs": [0, 1], + "outputs": [2], + "node_type": "function", + "type": "math.pow" + }, + "test_tuple_return": { + "arguments": [ + { + "connection_type": "input", + "type": "float", + "name": "x" + }, + { + "connection_type": "input", + "type": "float", + "name": "y" + }, + { + "connection_type": "output", + "type": "float", + "name": "" + }, + { + "connection_type": "output", + "type": "float", + "name": "" + }, + { + "connection_type": "output", + "type": "float", + "name": "" + } + ], + "inputs": [0, 1], + "outputs": [2, 3, 4], + "node_type": "function", + "type": "test_tuple_return" + }, + "Calculator": { + "arguments": [ + { + "connection_type": "input", + "type": "float", + "name": "initial_value" + } + ], + "inputs": [0], + "outputs": [-1], + "node_type": "constructor", + "type": "Calculator" + }, + "Calculator.add_to_value": { + "arguments": [ + { + "connection_type": "input", + "type": "any", + "name": "self" + }, + { + "connection_type": "input", + "type": "float", + "name": "amount" + }, + { + "connection_type": "output", + "type": "float", + "name": "" + } + ], + "inputs": [0, 1], + "outputs": [2], + "node_type": "method", + "type": "Calculator.add_to_value" + }, + "Calculator.get_value": { + "arguments": [ + { + "connection_type": "input", + "type": "any", + "name": "self" + }, + { + "connection_type": "output", + "type": "float", + "name": "" + } + ], + "inputs": [0], + "outputs": [1], + "node_type": "method", + "type": "Calculator.get_value" + }, + "Calculator.multiply_value": { + "arguments": [ + { + "connection_type": "input", + "type": "any", + "name": "self" + }, + { + "connection_type": "input", + "type": "float", + "name": "factor" + }, + { + "connection_type": "output", + "type": "float", + "name": "" + } + ], + "inputs": [0, 1], + "outputs": [2], + "node_type": "method", + "type": "Calculator.multiply_value" + } +} diff --git a/src/lib/utils/graphParser.test.ts b/src/lib/utils/graphParser.test.ts index 30c207b..58ccf2b 100644 --- a/src/lib/utils/graphParser.test.ts +++ b/src/lib/utils/graphParser.test.ts @@ -7,6 +7,8 @@ import type { import validQualifiedGraph from '../../../test_files/network-mwe-simplified-qualified.json' import validQualifiedGraphNetworkNode from '../../../test_files/network-mwe-simplified-network-node-qualified.json' import defaultRegistry from '../data/defaultNodes.json' +import coralpyGraph from '../../../test_files/network-coralpy-functions.json' +import coralpyMathRegistry from '../data/coralpyMathNodes.json' const mockStore = vi.hoisted(() => ({ nodeDataByType: {} as Record, @@ -114,6 +116,26 @@ describe('validateGraphData', () => { }) }) + describe('coral-python lean graph with an "any"-typed input', () => { + beforeEach(() => { + mockStore.nodeDataByType = + coralpyMathRegistry as unknown as RegisteredNodes + vi.spyOn(console, 'warn').mockImplementation(() => {}) + }) + + it('keeps the edge into print_result (input typed "any"); all edges valid', () => { + // Edge "4" wires multiply's output into print_result, whose input is typed "any". + // Before the fix this was dropped as a type mismatch on load. + const [validEdges, invalidEdges] = validateGraphData( + coralpyGraph as unknown as Network + ) + expect(invalidEdges).toHaveLength(0) + expect(Object.keys(validEdges)).toHaveLength( + Object.keys(coralpyGraph.workflow.edges).length + ) + }) + }) + describe('graphs with network nodes', () => { beforeEach(() => { mockStore.nodeDataByType = defaultRegistry as unknown as RegisteredNodes diff --git a/src/lib/utils/graphParser.ts b/src/lib/utils/graphParser.ts index 298e4ce..c65bf63 100644 --- a/src/lib/utils/graphParser.ts +++ b/src/lib/utils/graphParser.ts @@ -24,6 +24,7 @@ import { } from './canvasNodeUtils' import { isSubGraphNodeDefinition, + Type, TypeField, type Network, type NetworkEdge, @@ -263,8 +264,11 @@ export const validateGraphData = ( ) } - // Check if types match - if (sourceOutputType !== targetInputArg.type) { + // Check if types match. A target input typed 'any' accepts any source. + if ( + targetInputArg.type !== Type.ANY && + sourceOutputType !== targetInputArg.type + ) { const errorMessage = `Edge id: ${edgeId} - Type mismatch - source output type '${sourceOutputType}' does not match target input '${targetInputArg.type}'` console.warn(errorMessage) invalidEdges.push({ diff --git a/test_files/network-coralpy-functions.json b/test_files/network-coralpy-functions.json new file mode 100644 index 0000000..3ff2b84 --- /dev/null +++ b/test_files/network-coralpy-functions.json @@ -0,0 +1,86 @@ +{ + "workflow": { + "nodes": { + "0": { + "type": "float", + "value": "3.0", + "position": { + "x": 304, + "y": 211.5 + } + }, + "1": { + "type": "print_result", + "position": { + "x": 1296.4665983931754, + "y": 434.97657339760724 + } + }, + "2": { + "type": "float", + "value": "2", + "position": { + "x": 333.5492862144865, + "y": 369.84117824551794 + } + }, + "3": { + "type": "add", + "position": { + "x": 653.5527639131286, + "y": 237.56010539744705 + } + }, + "5": { + "type": "float", + "value": "4", + "position": { + "x": 593.2481571735668, + "y": 508.9308357254747 + } + }, + "6": { + "type": "multiply", + "position": { + "x": 965.7750020324723, + "y": 322.1810858223159 + } + } + }, + "edges": { + "0": { + "source": 0, + "target": 3, + "source_output": 0, + "target_input": 0 + }, + "1": { + "source": 2, + "target": 3, + "source_output": 0, + "target_input": 1 + }, + "2": { + "source": 3, + "target": 6, + "source_output": 0, + "target_input": 0 + }, + "3": { + "source": 5, + "target": 6, + "source_output": 0, + "target_input": 1 + }, + "4": { + "source": 6, + "target": 1, + "source_output": 0, + "target_input": 0 + } + } + }, + "version": 1, + "author": "dealiix-platform", + "date_time_utc": "2025-12-16T15:14:12.580Z" +} From 9bd817e9aecb3c1fcf6890c5c4d046f533d7041d Mon Sep 17 00:00:00 2001 From: Pablo Colturi Date: Thu, 9 Jul 2026 10:24:57 +0200 Subject: [PATCH 06/11] Docs: link CHANGELOG entries to PR #209 --- CHANGELOG.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b7e9cf5..999a3f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ See [docs/changelog-template.md](docs/changelog-template.md) for formatting your ### Canvas-graph -- Loading a graph no longer drops edges whose target input is typed `any`: import validation now accepts an `any` target input, matching the live connection validation used while drawing edges. +- [#209](https://github.com/2listic/dealiiX-platform/pull/209) Loading a graph no longer drops edges whose target input is typed `any`: import validation now accepts an `any` target input, matching the live connection validation used while drawing edges. - [#175](https://github.com/2listic/dealiiX-platform/issues/175) Per-level undo/redo history for the canvas. Each navigation level (root graph and each open subnetwork) keeps its own independent undo/redo stacks, capped at 50 entries. Undo (Ctrl/⌘+Z) and Redo (Ctrl/⌘+Shift+Z) are available as keyboard shortcuts and as items inside the Layout sidebar group button. ### UI/UX @@ -16,9 +16,9 @@ See [docs/changelog-template.md](docs/changelog-template.md) for formatting your - [#112](https://github.com/2listic/dealiiX-platform/issues/112) The Project button group is now disabled when the user is not logged in, in addition to when no remote server is configured. - [#185](https://github.com/2listic/dealiiX-platform/pull/185) Parameter section duplicate logis is via a new duplicate button instead of via right-click. Duplicated sections can be deleted with a new delete button. Sections are set back to native `
`/`` elements for collapsible behaviour. - [#185](https://github.com/2listic/dealiiX-platform/pull/185) The execution modal now includes an editable parameters file name field, letting users override the file path per run without changing the global settings. -- The local **Coral plugin path** setting is now a free-text field with a Browse button (previously a file picker only), so it accepts either a plugin file path or an arbitrary value passed to the backend's `-p` flag (e.g. a comma-separated list of modules). The local probe no longer requires the plugin path to be an existing file on disk. -- Nodes with `node_type: "primitive"` now render an editable literal field (a text box, or a checkbox for booleans) like elementary constructors, so registries that use the `primitive` node type are fully usable on the canvas. Numeric value validation is also null-safe, so it no longer errors when a value is empty. -- The **Download Graph** action moved from the Project group into the renamed **Import / Export** group, next to Import Graph. It no longer requires being logged in to a remote server, so the current graph can be exported to JSON while working locally. +- [#209](https://github.com/2listic/dealiiX-platform/pull/209) The local **Coral plugin path** setting is now a free-text field with a Browse button (previously a file picker only), so it accepts either a plugin file path or an arbitrary value passed to the backend's `-p` flag (e.g. a comma-separated list of modules). The local probe no longer requires the plugin path to be an existing file on disk. +- [#209](https://github.com/2listic/dealiiX-platform/pull/209) Nodes with `node_type: "primitive"` now render an editable literal field (a text box, or a checkbox for booleans) like elementary constructors, so registries that use the `primitive` node type are fully usable on the canvas. Numeric value validation is also null-safe, so it no longer errors when a value is empty. +- [#209](https://github.com/2listic/dealiiX-platform/pull/209) The **Download Graph** action moved from the Project group into the renamed **Import / Export** group, next to Import Graph. It no longer requires being logged in to a remote server, so the current graph can be exported to JSON while working locally. ### Electron-Backend From e0650c00a56c88e15059c6ca6c261aabff57f7a9 Mon Sep 17 00:00:00 2001 From: Pablo Colturi Date: Fri, 10 Jul 2026 15:15:17 +0200 Subject: [PATCH 07/11] Chore: gitignore personal multi-root workspace file --- .gitignore | 3 +++ src/lib/utils/graphParser.test.ts | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 04292b5..24d11a2 100644 --- a/.gitignore +++ b/.gitignore @@ -36,6 +36,9 @@ dist-electron/ # Local environment variables (machine-specific paths) .env +# Personal multi-root workspace config (machine-specific sibling paths) +*.code-workspace + # Containers' shared folder containers/shared-data/* diff --git a/src/lib/utils/graphParser.test.ts b/src/lib/utils/graphParser.test.ts index 58ccf2b..6affe4a 100644 --- a/src/lib/utils/graphParser.test.ts +++ b/src/lib/utils/graphParser.test.ts @@ -7,7 +7,7 @@ import type { import validQualifiedGraph from '../../../test_files/network-mwe-simplified-qualified.json' import validQualifiedGraphNetworkNode from '../../../test_files/network-mwe-simplified-network-node-qualified.json' import defaultRegistry from '../data/defaultNodes.json' -import coralpyGraph from '../../../test_files/network-coralpy-functions.json' +import validCoralpyGraphFuncs from '../../../test_files/network-coralpy-functions.json' import coralpyMathRegistry from '../data/coralpyMathNodes.json' const mockStore = vi.hoisted(() => ({ @@ -127,11 +127,11 @@ describe('validateGraphData', () => { // Edge "4" wires multiply's output into print_result, whose input is typed "any". // Before the fix this was dropped as a type mismatch on load. const [validEdges, invalidEdges] = validateGraphData( - coralpyGraph as unknown as Network + validCoralpyGraphFuncs as unknown as Network ) expect(invalidEdges).toHaveLength(0) expect(Object.keys(validEdges)).toHaveLength( - Object.keys(coralpyGraph.workflow.edges).length + Object.keys(validCoralpyGraphFuncs.workflow.edges).length ) }) }) From 0498eb8598de88256d777276caa367d403e00fb2 Mon Sep 17 00:00:00 2001 From: Pablo Colturi Date: Mon, 13 Jul 2026 15:14:09 +0200 Subject: [PATCH 08/11] Fix: run Prettier via lint-staged in the pre-commit hook - fix: formatting changes now land in the same commit instead of being left unstaged after the commit was created - chore: add lint-staged, scoped to *.{ts,svelte,js,json,md} staged files - docs: update README, CLAUDE.md, CHANGELOG for the new pre-commit behaviour --- .husky/pre-commit | 2 +- CHANGELOG.md | 1 + CLAUDE.md | 2 +- README.md | 2 +- package-lock.json | 371 ++++++++++++++++++++++++++++++++++++++++++++-- package.json | 4 + 6 files changed, 364 insertions(+), 18 deletions(-) diff --git a/.husky/pre-commit b/.husky/pre-commit index 6836f86..f3bca30 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,3 +1,3 @@ npm run lint npm run check:electron -npx prettier . --write \ No newline at end of file +npx lint-staged \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 32c4712..c416dfb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ See [docs/changelog-template.md](docs/changelog-template.md) for formatting your ### Project-Structure - The renderer is now fully strict TypeScript. `jsconfig.json` renamed to `tsconfig.json` with `"strict": true` enabled; all Svelte component `