feat(execution): reuse editor node renderers

This commit is contained in:
Lucio Lelii 2026-09-30 10:18:16 +02:00
parent 732398300f
commit 758832edf7
2 changed files with 20 additions and 7 deletions

View File

@ -4,9 +4,12 @@
import { DEFAULT_NODE_CAPABILITIES, RESOURCE_NODE_CAPABILITIES } from '@models/flow';
import { HFNode } from '@models/nodes';
import { ContainerNodeComponent } from '@shared/nodes/container-node/container-node';
import { GenericNodeComponent } from '@shared/nodes/generic-node/generic-node';
import { ResourceNodeComponent } from '@shared/nodes/resource-node/resource-node';
import { vi } from 'vitest';
import { isResourceNode, refreshLoopMarkers, resolveNodeCapabilities, ReteRuntimeContext, syncResourceLinkPresentation } from './rete-editor';
import { isResourceNode, nodeRendererFor, refreshLoopMarkers, resolveNodeCapabilities, ReteRuntimeContext, syncResourceLinkPresentation } from './rete-editor';
function makeNode(typeName: string, nodeFamily: 'block' | 'container' | 'resource'): HFNode {
return { data: { typeName, nodeFamily } } as unknown as HFNode;
@ -72,6 +75,14 @@ describe('resolveNodeCapabilities', () => {
});
});
describe('node renderers', () => {
it('uses the editor Resource card rather than the execution-only step card', () => {
expect(nodeRendererFor('resource')).toBe(ResourceNodeComponent);
expect(nodeRendererFor('container')).toBe(ContainerNodeComponent);
expect(nodeRendererFor('block')).toBe(GenericNodeComponent);
});
});
describe('isResourceNode', () => {
it('is what the node is, not what its type can do: a resource is never among the flow\'s blocks', () => {
const runtime = makeRuntime();

View File

@ -41,7 +41,6 @@ import { EditorStateHolder } from "@stores/flow-editor";
import { ContainerNodeComponent } from "@shared/nodes/container-node/container-node";
import { GenericNodeComponent } from "@shared/nodes/generic-node/generic-node";
import { ResourceNodeComponent } from "@shared/nodes/resource-node/resource-node";
import { TaskStepNodeComponent } from "@shared/nodes/task-step-node/task-step-node";
import { CustomSocket } from "@shared/custom-socket/custom-socket";
import { CustomConnectionComponent } from "@shared/custom-connection/custom-connection";
import { deleteSchemaValueByPath, setSchemaValueByPath } from "@shared/nodes/schema-driven-fields";
@ -80,6 +79,13 @@ export type ReteRuntimeContext = {
restoringConnections?: number;
};
/** The execution canvas uses the editor's node cards too; readonly controls behaviour, not shape. */
export function nodeRendererFor(nodeFamily: unknown) {
if (nodeFamily === 'container') return ContainerNodeComponent;
if (nodeFamily === 'resource') return ResourceNodeComponent;
return GenericNodeComponent;
}
/**
* What the editor keeps on a Rete connection beyond Rete's own fields. `loop` travels to and from
* the flow; `__loopBack` and `__readonly` are worked out here for the connection component to draw.
@ -133,11 +139,7 @@ export async function createEditor(
}),
customize: {
node(context: any) {
if (nodeView === "execution") return TaskStepNodeComponent;
const nodeFamily = context?.payload?.data?.nodeFamily;
if (nodeFamily === "container") return ContainerNodeComponent;
if (nodeFamily === "resource") return ResourceNodeComponent;
return GenericNodeComponent;
return nodeRendererFor(context?.payload?.data?.nodeFamily);
},
connection() {
return CustomConnectionComponent;