From 91e7d6a8024ce73c57081fbd3c178f54bb44d781 Mon Sep 17 00:00:00 2001 From: eust-w Date: Mon, 30 Mar 2026 03:18:54 +0800 Subject: [PATCH] :sparkles: feat: show custom node contracts in the editor --- Makefile | 2 +- README.md | 1 + apps/web/src/runtime/app.tsx | 31 +++++++++++++++++++ .../src/runtime/custom-node-presenter.test.ts | 27 ++++++++++++++++ apps/web/src/runtime/custom-node-presenter.ts | 26 ++++++++++++++++ ...nformation-architecture-and-key-screens.md | 1 + 6 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 apps/web/src/runtime/custom-node-presenter.test.ts create mode 100644 apps/web/src/runtime/custom-node-presenter.ts diff --git a/Makefile b/Makefile index 2b59ebb..f4f3059 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ bootstrap: test: python3 -m unittest discover -s tests -p 'test_*.py' pnpm --filter api test - pnpm --filter web test src/features/assets/assets-page.test.tsx src/features/workflows/workflow-editor-page.test.tsx src/features/explore/explore-page.test.tsx src/runtime/workflow-editor-state.test.ts src/runtime/i18n.test.ts + pnpm --filter web test src/features/assets/assets-page.test.tsx src/features/workflows/workflow-editor-page.test.tsx src/features/explore/explore-page.test.tsx src/runtime/workflow-editor-state.test.ts src/runtime/i18n.test.ts src/runtime/custom-node-presenter.test.ts pnpm --filter web build pnpm --filter worker test diff --git a/README.md b/README.md index 3ab8ce3..690cf6a 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,7 @@ The shell now also exposes a dedicated Nodes page for project-scoped custom cont The Workflows workspace now includes a template gallery. Projects can start from default or saved templates, or create a blank workflow directly. The workflow editor center panel now uses a real draggable node canvas with zoom, pan, mini-map, dotted background, handle-based edge creation, persisted node positions, and localized validation feedback instead of a static list of node cards. The workflow editor right panel now also supports saving the current workflow draft as a reusable workflow template, in addition to editing per-node runtime settings and Python hooks. +When a custom node is selected on the canvas, the right panel now also exposes its declared input contract, output contract, artifact type, and container source so the operator can confirm compatibility without leaving the editor. The node library now supports both click-to-append and drag-and-drop placement into the canvas. When a node is inserted from the library, the editor now seeds its default runtime contract directly into the workflow draft, so custom Docker nodes keep their declared executor type and I/O contract without extra manual edits. V1 connection rules block self-edges, duplicate edges, cycles, incoming edges into source nodes, outgoing edges from export nodes, and multiple upstream edges into ordinary nodes, while allowing multi-input set nodes such as `union-assets`, `intersect-assets`, and `difference-assets` plus any custom node whose runtime contract declares `inputMode=multi_asset_set`. The Runs workspace now shows project-scoped run history, run-level aggregated summaries, cancel/retry controls, and run detail views with persisted task summaries, stdout/stderr sections, result previews, and artifact links into Explore. Selected run tasks now expose the frozen node definition id, executor config snapshot, and code-hook metadata that were captured when the run was created. diff --git a/apps/web/src/runtime/app.tsx b/apps/web/src/runtime/app.tsx index 9eab12c..2f9dca0 100644 --- a/apps/web/src/runtime/app.tsx +++ b/apps/web/src/runtime/app.tsx @@ -18,6 +18,11 @@ import { type CustomNodeValidationIssue, validateCustomNodeDefinition, } from "../../../../packages/contracts/src/custom-node.ts"; +import { + formatCustomNodeInputModeKey, + formatCustomNodeOutputModeKey, + formatCustomNodeSourceKindKey, +} from "./custom-node-presenter.ts"; import { localizeNodeDefinition, type TranslationKey, @@ -1352,6 +1357,24 @@ function WorkflowEditorPage(props: { () => getEffectiveNodeRuntimeConfig(selectedNodeRaw, selectedNodeRuntimeConfig), [selectedNodeRaw, selectedNodeRuntimeConfig], ); + const selectedNodeContract = useMemo( + () => + (selectedNodeEffectiveRuntimeConfig.executorConfig as { + contract?: { + inputMode?: string; + outputMode?: string; + artifactType?: string; + }; + } | undefined)?.contract, + [selectedNodeEffectiveRuntimeConfig], + ); + const selectedNodeSourceKind = useMemo( + () => + (selectedNodeEffectiveRuntimeConfig.executorConfig as { + kind?: string; + } | undefined)?.kind, + [selectedNodeEffectiveRuntimeConfig], + ); const canvasNodes = useMemo>( () => draft.logicGraph.nodes.map((node) => { @@ -1669,6 +1692,14 @@ function WorkflowEditorPage(props: {

{selectedNode.description}

{t("category")}: {selectedNode.category}

{t("definition")}: {selectedNodeDefinitionId}

+ {selectedNodeContract ? ( + <> +

{t("customNodeInputMode")}: {t(formatCustomNodeInputModeKey(selectedNodeContract.inputMode))}

+

{t("customNodeOutputMode")}: {t(formatCustomNodeOutputModeKey(selectedNodeContract.outputMode))}

+

{t("customNodeArtifactType")}: {selectedNodeContract.artifactType ?? t("none")}

+

{t("customNodeSourceKind")}: {t(formatCustomNodeSourceKindKey(selectedNodeSourceKind))}

+ + ) : null}