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 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WgBfkm4rCmtd1T4vHWjEPx
This commit is contained in:
@@ -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',
|
||||
|
||||
@@ -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';
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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",
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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(",")}`
|
||||
}
|
||||
|
||||
@@ -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: [],
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user