diff --git a/src/routes/v2/pages/RunView/nodes/IONode/context/RunViewInputDetails.tsx b/src/routes/v2/pages/RunView/nodes/IONode/context/RunViewInputDetails.tsx index 293701fd86..05f1031f61 100644 --- a/src/routes/v2/pages/RunView/nodes/IONode/context/RunViewInputDetails.tsx +++ b/src/routes/v2/pages/RunView/nodes/IONode/context/RunViewInputDetails.tsx @@ -6,6 +6,8 @@ import { CopyText } from "@/components/shared/CopyText/CopyText"; import { Icon } from "@/components/ui/icon"; import { BlockStack, InlineStack } from "@/components/ui/layout"; import { Text } from "@/components/ui/typography"; +import { useExecutionData } from "@/providers/ExecutionDataProvider"; +import { resolveInputValue } from "@/routes/v2/shared/nodes/IONode/resolveInputValue"; import { useSpec } from "@/routes/v2/shared/providers/SpecContext"; import { tracking } from "@/utils/tracking"; @@ -17,6 +19,7 @@ export const RunViewInputDetails = observer(function RunViewInputDetails({ entityId, }: RunViewInputDetailsProps) { const spec = useSpec(); + const { details } = useExecutionData(); const input = spec?.inputs.find((i) => i.$id === entityId); if (!input) { @@ -30,6 +33,7 @@ export const RunViewInputDetails = observer(function RunViewInputDetails({ } const type = input.type ? String(input.type) : undefined; + const value = resolveInputValue(input, details?.task_spec.arguments); return ( )} - {input.defaultValue && ( + {value !== undefined && ( + + + Value + + + {value} + + + )} + + {input.defaultValue !== undefined && ( Default Value diff --git a/src/routes/v2/shared/nodes/IONode/IONode.tsx b/src/routes/v2/shared/nodes/IONode/IONode.tsx index 11e6bd6bc5..ce71c89c0f 100644 --- a/src/routes/v2/shared/nodes/IONode/IONode.tsx +++ b/src/routes/v2/shared/nodes/IONode/IONode.tsx @@ -2,6 +2,7 @@ import { type Node, type NodeProps } from "@xyflow/react"; import { observer } from "mobx-react-lite"; import { type MouseEvent } from "react"; +import { useExecutionDataOptional } from "@/providers/ExecutionDataProvider"; import { useIsDetailedView } from "@/routes/v2/shared/hooks/useIsDetailedView"; import type { IONodeData } from "@/routes/v2/shared/nodes/types"; import { useSpec } from "@/routes/v2/shared/providers/SpecContext"; @@ -10,6 +11,7 @@ import { useSharedStores } from "@/routes/v2/shared/store/SharedStoreContext"; import { IONodeCard } from "./IONodeCard"; import { IONodeSimplified } from "./IONodeSimplified"; +import { resolveInputValue } from "./resolveInputValue"; type IONodeType = Node; type IONodeProps = NodeProps; @@ -19,7 +21,7 @@ export interface IONodeViewProps { name: string; type?: string; description?: string; - defaultValue?: string; + value?: string; connectedValue: string | null; isInput: boolean; selected: boolean; @@ -43,6 +45,7 @@ export const IONode = observer(function IONode({ const showContent = useIsDetailedView(); const spec = useSpec(); + const executionData = useExecutionDataOptional(); const isInput = ioType === "input"; const entity = isInput @@ -76,9 +79,9 @@ export const IONode = observer(function IONode({ } } - const defaultValue = + const value = isInput && entity && "defaultValue" in entity - ? (entity.defaultValue ?? undefined) + ? resolveInputValue(entity, executionData?.details?.task_spec.arguments) : undefined; const isSelected = isEditorVisualNodeSelected(editor, id, !!selected); @@ -88,7 +91,7 @@ export const IONode = observer(function IONode({ name, type, description, - defaultValue, + value, connectedValue, isInput, selected: isSelected, diff --git a/src/routes/v2/shared/nodes/IONode/IONodeCard.tsx b/src/routes/v2/shared/nodes/IONode/IONodeCard.tsx index 8da36c854a..1d2f607b83 100644 --- a/src/routes/v2/shared/nodes/IONode/IONodeCard.tsx +++ b/src/routes/v2/shared/nodes/IONode/IONodeCard.tsx @@ -12,7 +12,7 @@ export function IONodeCard({ name, type, description, - defaultValue, + value, connectedValue, isInput, selected, @@ -75,9 +75,7 @@ export function IONodeCard({ font="mono" className="truncate text-ink-fixed/70" > - {isInput - ? (defaultValue ?? "No value") - : (connectedValue ?? "No value")} + {isInput ? (value ?? "No value") : (connectedValue ?? "No value")} diff --git a/src/routes/v2/shared/nodes/IONode/resolveInputValue.test.ts b/src/routes/v2/shared/nodes/IONode/resolveInputValue.test.ts new file mode 100644 index 0000000000..27fddbb89f --- /dev/null +++ b/src/routes/v2/shared/nodes/IONode/resolveInputValue.test.ts @@ -0,0 +1,39 @@ +import { describe, expect, it } from "vitest"; + +import { Input } from "@/models/componentSpec/entities/input"; + +import { resolveInputValue } from "./resolveInputValue"; + +function createInput() { + return new Input({ + $id: "input-template-params", + name: "template_params", + value: "configured value", + defaultValue: "default value", + }); +} + +describe("resolveInputValue", () => { + it("prefers the run argument over the configured and default values", () => { + const input = createInput(); + + expect(resolveInputValue(input, { template_params: "run value" })).toBe( + "run value", + ); + }); + + it("preserves an empty run argument instead of showing the default", () => { + const input = createInput(); + + expect(resolveInputValue(input, { template_params: "" })).toBe(""); + }); + + it("falls back to the configured value and then the default", () => { + const input = createInput(); + + expect(resolveInputValue(input)).toBe("configured value"); + + input.setValue(undefined); + expect(resolveInputValue(input)).toBe("default value"); + }); +}); diff --git a/src/routes/v2/shared/nodes/IONode/resolveInputValue.ts b/src/routes/v2/shared/nodes/IONode/resolveInputValue.ts new file mode 100644 index 0000000000..2ff88208a0 --- /dev/null +++ b/src/routes/v2/shared/nodes/IONode/resolveInputValue.ts @@ -0,0 +1,14 @@ +import type { TaskSpecOutput } from "@/api/types.gen"; +import type { Input } from "@/models/componentSpec/entities/input"; +import { getArgumentValue } from "@/utils/nodes/taskArguments"; + +export function resolveInputValue( + input: Input, + taskArguments?: TaskSpecOutput["arguments"] | null, +): string | undefined { + return ( + getArgumentValue(taskArguments ?? undefined, input.name) ?? + input.value ?? + input.defaultValue + ); +}