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.
This commit is contained in:
2026-10-15 10:08:46 +02:00
parent 43498037be
commit e85b18092f
10 changed files with 111 additions and 39 deletions
+48 -30
View File
@@ -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({
</Button>
</div>
{live && name ? (
<div className="flex items-center gap-2 pl-1 text-xs text-muted-foreground">
<span className="shrink-0">now</span>
{current === undefined ? (
<span className="flex-1">—</span>
) : (
<span className="min-w-0 flex-1">
<ValuePreview value={current.value} dtype={spec.dtype} />
</span>
)}
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon-sm"
aria-label="Publish this value now"
disabled={publish.isPending || declared.initial === null}
onClick={() =>
publish.mutate({ message, value: declared.initial })
}
>
<ArrowUpFromLine />
</Button>
</TooltipTrigger>
<TooltipContent>Put this value into the flow now</TooltipContent>
</Tooltip>
</div>
) : null}
<div className="flex items-center gap-2 pl-1 text-xs text-muted-foreground">
<Segmented
label="Written by"
value={declared.origin ?? "run"}
options={ORIGINS}
onChange={(origin) =>
onChange({ ...declared, origin: origin as typeof declared.origin })
}
/>
{live && name ? (
<>
<span className="shrink-0">now</span>
{current === undefined ? (
<span className="flex-1">—</span>
) : (
<span className="min-w-0 flex-1">
<ValuePreview value={current.value} dtype={spec.dtype} />
</span>
)}
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon-sm"
aria-label="Publish this value now"
disabled={publish.isPending || declared.initial === null}
onClick={() =>
publish.mutate({ message, value: declared.initial })
}
>
<ArrowUpFromLine />
</Button>
</TooltipTrigger>
<TooltipContent>Put this value into the flow now</TooltipContent>
</Tooltip>
</>
) : null}
</div>
</div>
)
}
@@ -338,8 +355,9 @@ export function BoundarySections({
<div className="flex items-center justify-between">
<span className={PANEL_SECTION}>Inputs</span>
<InfoTip label="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.
</InfoTip>
<Button
variant="ghost"
+9 -2
View File
@@ -94,9 +94,16 @@ export function initialText(inputs: FlowInput_Input[]): Record<string, string> {
)
}
/** The declared inputs worth drawing a field for. */
/**
* The declared inputs worth drawing a field for.
*
* A panel input is a control's to write, so a run keeps its starting value
* and the form does not offer it as a parameter.
*/
export function declaredInputs(definition: FlowDef_Input): FlowInput_Input[] {
return (definition.inputs ?? []).filter((one) => one.spec?.name)
return (definition.inputs ?? []).filter(
(one) => one.spec?.name && one.origin !== "panel",
)
}
/**
+5 -2
View File
@@ -91,11 +91,14 @@ export function deriveEdges(nodes: NodeDef_Input[], flow: string): Edge[] {
*/
export function boundaryKey(doc: {
mode?: string | null
inputs?: { spec?: MessageSpec | null }[] | null
inputs?: { spec?: MessageSpec | null; origin?: string }[] | null
outputs?: string[] | null
}): string {
const inputs = (doc.inputs ?? [])
.map((one) => `${one.spec?.name ?? ""}:${one.spec?.dtype ?? ""}`)
.map(
(one) =>
`${one.spec?.name ?? ""}:${one.spec?.dtype ?? ""}:${one.origin ?? ""}`,
)
.join(",")
return `${doc.mode ?? "live"}|${inputs}|${(doc.outputs ?? []).join(",")}`
}
+2 -1
View File
@@ -62,7 +62,8 @@ function boundaryOf(
kind: "input",
id: `input:${message}`,
label: displayName(flow, message),
detail: declared.spec?.dtype ?? "float",
// What writes it, so a control's input does not read as a run's.
detail: `${declared.origin ?? "run"} · ${declared.spec?.dtype ?? "float"}`,
provides: [message],
requires: [],
})