From f5be932df35acb35fc5c83ede85954bf4ff80c1d Mon Sep 17 00:00:00 2001 From: stroblme Date: Thu, 15 Oct 2026 10:08:46 +0200 Subject: [PATCH] Flow inputs carry an origin hint, run or panel The Inputs editor and the canvas label show it, and the run forms leave panel inputs out. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01WgBfkm4rCmtd1T4vHWjEPx --- backend/fluksio/flow/schemas.py | 9 +++ docs/concepts/flows.md | 7 +- docs/concepts/values.md | 6 +- docs/interface/flow-editor.md | 2 +- frontend/src/client/schemas.gen.ts | 14 ++++ frontend/src/client/types.gen.ts | 13 ++++ frontend/src/components/Flow/FlowBoundary.tsx | 78 ++++++++++++------- frontend/src/components/Flow/RunDialog.tsx | 11 ++- frontend/src/components/Flow/deriveEdges.ts | 7 +- frontend/src/components/Flow/endpoints.ts | 3 +- 10 files changed, 111 insertions(+), 39 deletions(-) diff --git a/backend/fluksio/flow/schemas.py b/backend/fluksio/flow/schemas.py index 73c6ab3..00d5f1d 100644 --- a/backend/fluksio/flow/schemas.py +++ b/backend/fluksio/flow/schemas.py @@ -267,6 +267,15 @@ class FlowInput(BaseModel): spec: MessageSpec initial: Any | None = None + origin: Literal["run", "panel"] = Field( + default="run", + description=( + "What writes it. A run input is a parameter a run passes in, a " + "panel input is written by a dashboard or panel control. A hint " + "only: run forms leave panel inputs out, the engine treats both " + "the same." + ), + ) class FlowDef(BaseModel): diff --git a/docs/concepts/flows.md b/docs/concepts/flows.md index 50e6b62..34b00e9 100644 --- a/docs/concepts/flows.md +++ b/docs/concepts/flows.md @@ -96,13 +96,18 @@ Declare messages supplied by dashboard controls, the API or run parameters as the flow's **Inputs**. Give live inputs a starting value: ```json -{"inputs": [{"spec": {"name": "setpoint", "dtype": "float"}, "initial": 21.0}]} +{"inputs": [{"spec": {"name": "setpoint", "dtype": "float"}, "initial": 21.0, "origin": "panel"}]} ``` This seeds `house.setpoint` in flow `house` if it has no value yet. Later publications replace it. Batch inputs are run parameters, and batch outputs select the run's result. See [Where a node's values come from](values.md). +`origin` says what writes an input: `run` (the default) for a parameter a run +passes in, `panel` for a dashboard or panel control. The canvas labels each +input with it, and the run form leaves panel inputs out, so a run keeps their +starting value. The engine treats both the same. + ## Drafts and publishing - **Saving** stores a draft; the engine keeps running the published version. diff --git a/docs/concepts/values.md b/docs/concepts/values.md index 1628f71..33ff8a8 100644 --- a/docs/concepts/values.md +++ b/docs/concepts/values.md @@ -47,8 +47,10 @@ The initial value seeds an unset live message. Later publications take over; changing the starting value does not overwrite a value already in state. Use **Publish this value now** in the input row to send it immediately. -The canvas draws flow inputs as labelled endpoints. Without a producer or -declared input, a consuming node reports `unconnected_input`. +The canvas draws flow inputs as labelled endpoints, marked `run` or `panel` +by what writes them. A panel input is one a dashboard or panel control writes, +and the run form does not ask for it. Without a producer or declared input, a +consuming node reports `unconnected_input`. A batch flow's inputs are run parameters. Its **Result** section selects the messages returned when the run finishes. See [Runs](runs.md). diff --git a/docs/interface/flow-editor.md b/docs/interface/flow-editor.md index eb9168b..e13f3b1 100644 --- a/docs/interface/flow-editor.md +++ b/docs/interface/flow-editor.md @@ -80,7 +80,7 @@ Open **Flow settings** from the pencil button in the dock. |---|---| | **Running** | starts or stops the published live flow's subscriptions, schedules and webhooks | | **Mode** | chooses continuous `live` operation or requested `batch` runs | -| **Inputs** | declares external messages and starting values; batch inputs become run parameters | +| **Inputs** | declares external messages, their starting values and whether a run or a panel writes them; run inputs become run parameters | | **Result** | selects batch output messages | | **Contents** | shows the node count and message namespace | diff --git a/frontend/src/client/schemas.gen.ts b/frontend/src/client/schemas.gen.ts index 9276ad3..5b91d4a 100644 --- a/frontend/src/client/schemas.gen.ts +++ b/frontend/src/client/schemas.gen.ts @@ -1355,6 +1355,13 @@ export const FlowInput_InputSchema = { } ], title: 'Initial' + }, + origin: { + type: 'string', + enum: ['run', 'panel'], + title: 'Origin', + description: 'What writes it. A run input is a parameter a run passes in, a panel input is written by a dashboard or panel control. A hint only: run forms leave panel inputs out, the engine treats both the same.', + default: 'run' } }, type: 'object', @@ -1376,6 +1383,13 @@ export const FlowInput_OutputSchema = { } ], title: 'Initial' + }, + origin: { + type: 'string', + enum: ['run', 'panel'], + title: 'Origin', + description: 'What writes it. A run input is a parameter a run passes in, a panel input is written by a dashboard or panel control. A hint only: run forms leave panel inputs out, the engine treats both the same.', + default: 'run' } }, type: 'object', diff --git a/frontend/src/client/types.gen.ts b/frontend/src/client/types.gen.ts index 5e02060..f69e78a 100644 --- a/frontend/src/client/types.gen.ts +++ b/frontend/src/client/types.gen.ts @@ -391,14 +391,27 @@ export type FlowDetail = { export type FlowInput_Input = { spec: MessageSpec; initial?: (unknown | null); + /** + * What writes it. A run input is a parameter a run passes in, a panel input is written by a dashboard or panel control. A hint only: run forms leave panel inputs out, the engine treats both the same. + */ + origin?: 'run' | 'panel'; }; +/** + * What writes it. A run input is a parameter a run passes in, a panel input is written by a dashboard or panel control. A hint only: run forms leave panel inputs out, the engine treats both the same. + */ +export type origin = 'run' | 'panel'; + /** * A message the flow starts with rather than computes. */ export type FlowInput_Output = { spec: MessageSpec; initial?: (unknown | null); + /** + * What writes it. A run input is a parameter a run passes in, a panel input is written by a dashboard or panel control. A hint only: run forms leave panel inputs out, the engine treats both the same. + */ + origin?: 'run' | 'panel'; }; /** diff --git a/frontend/src/components/Flow/FlowBoundary.tsx b/frontend/src/components/Flow/FlowBoundary.tsx index 5374db9..f647789 100644 --- a/frontend/src/components/Flow/FlowBoundary.tsx +++ b/frontend/src/components/Flow/FlowBoundary.tsx @@ -6,6 +6,7 @@ import { MessagesService } from "@/client" import { Button } from "@/components/ui/button" import { Checkbox } from "@/components/ui/checkbox" import { Input } from "@/components/ui/input" +import { Segmented } from "@/components/ui/segmented" import { Select, SelectContent, @@ -160,6 +161,12 @@ function usePublishInput() { }) } +/** What writes an input: a run passing it in, or a control on a panel. */ +const ORIGINS = [ + ["run", "run"], + ["panel", "panel"], +] as const + function InputRow({ flow, declared, @@ -231,34 +238,44 @@ function InputRow({ - {live && name ? ( -
- now - {current === undefined ? ( - — - ) : ( - - - - )} - - - - - Put this value into the flow now - -
- ) : null} +
+ + onChange({ ...declared, origin: origin as typeof declared.origin }) + } + /> + {live && name ? ( + <> + now + {current === undefined ? ( + — + ) : ( + + + + )} + + + + + Put this value into the flow now + + + ) : null} +
) } @@ -338,8 +355,9 @@ export function BoundarySections({
Inputs - Messages that arrive from outside, such as a dashboard control, a - run or the API, and the value the flow starts from. + Messages that arrive from outside, and the value the flow starts + from. A run passes a run input in, a dashboard or panel control + writes a panel input.