diff --git a/react-compiler.config.js b/react-compiler.config.js index d15540781..1062f5da5 100644 --- a/react-compiler.config.js +++ b/react-compiler.config.js @@ -59,6 +59,7 @@ export const REACT_COMPILER_ENABLED_DIRS = [ "src/components/shared/Dialogs/MultilineTextInputDialog.tsx", "src/components/shared/HighlightText.tsx", "src/components/shared/AnnouncementBanners.tsx", + "src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskOverview/IOSection", // 11-20 useCallback/useMemo // "src/components/ui", // 12 diff --git a/src/components/shared/CopyText/CopyText.tsx b/src/components/shared/CopyText/CopyText.tsx index e43db4ea0..e411ee67a 100644 --- a/src/components/shared/CopyText/CopyText.tsx +++ b/src/components/shared/CopyText/CopyText.tsx @@ -9,6 +9,7 @@ import { copyToClipboard } from "@/utils/string"; interface CopyTextProps { children: string; + displayValue?: string; className?: string; alwaysShowButton?: boolean; compact?: boolean; @@ -17,6 +18,7 @@ interface CopyTextProps { export const CopyText = ({ children, + displayValue, className, alwaysShowButton = false, compact = false, @@ -61,7 +63,7 @@ export const CopyText = ({ isCopied && "text-emerald-400!", )} > - {children} + {displayValue ?? children} - - - {copyState.isCopied ? `${copyState.copyType} copied` : "Not copied"} - - {isOpen ? "Open" : "Closed"} - - ), -})); - -vi.mock("./IOCellDetails", () => ({ - default: () =>
Details
, -})); - -vi.mock("@/components/ui/collapsible", () => ({ - Collapsible: ({ children }: any) =>
{children}
, - CollapsibleContent: ({ children }: any) =>
{children}
, -})); - -describe("IOCell", () => { - const mockInputSpec: InputSpec = { - name: "test-input", - type: "String", - }; - - const mockArtifactData: ArtifactDataResponse = { - value: "test-value", - uri: "gs://bucket/path", - total_size: 1024, - is_dir: false, - }; - - beforeEach(() => { - vi.clearAllMocks(); - }); - - it("renders IOCell with header", () => { - render(); - - expect(screen.getByTestId("io-cell-header")).toBeInTheDocument(); - expect(screen.getByTestId("copy-name-btn")).toBeInTheDocument(); - }); - - it("renders IOCellDetails when artifactData is provided", () => { - render(); - - expect(screen.getByTestId("io-cell-details")).toBeInTheDocument(); - }); - - it("does not render IOCellDetails when artifactData is null", () => { - render(); - - expect(screen.queryByTestId("io-cell-details")).not.toBeInTheDocument(); - }); - - it("handles copy name functionality", () => { - render(); - - fireEvent.click(screen.getByTestId("copy-name-btn")); - - expect(copyToClipboard).toHaveBeenCalledWith("test-input"); - expect(screen.getByTestId("copy-state")).toHaveTextContent("Name copied"); - }); - - it("handles copy value functionality", () => { - render(); - - fireEvent.click(screen.getByTestId("copy-value-btn")); - - expect(copyToClipboard).toHaveBeenCalledWith("test-value"); - expect(screen.getByTestId("copy-state")).toHaveTextContent("Value copied"); - }); - - it("does not copy value when artifactData.value is null", () => { - const artifactDataWithoutValue = { ...mockArtifactData, value: null }; - render( - , - ); - - fireEvent.click(screen.getByTestId("copy-value-btn")); - - expect(copyToClipboard).not.toHaveBeenCalled(); - }); - - it("clears copied state after timeout", async () => { - vi.useFakeTimers(); - - render(); - - fireEvent.click(screen.getByTestId("copy-name-btn")); - expect(screen.getByTestId("copy-state")).toHaveTextContent("Name copied"); - - await act(async () => { - vi.advanceTimersByTime(1500); - }); - - expect(screen.getByTestId("copy-state")).toHaveTextContent("Not copied"); - - vi.useRealTimers(); - }); - - it("starts with collapsible closed", () => { - render(); - - expect(screen.getByTestId("is-open")).toHaveTextContent("Closed"); - }); - - it("clears timeout on unmount", () => { - const clearTimeoutSpy = vi.spyOn(global, "clearTimeout"); - - const { unmount } = render( - , - ); - - fireEvent.click(screen.getByTestId("copy-name-btn")); - unmount(); - - expect(clearTimeoutSpy).toHaveBeenCalled(); - }); - - it("manages copy state transitions correctly", () => { - render(); - - expect(screen.getByTestId("copy-state")).toHaveTextContent("Not copied"); - - fireEvent.click(screen.getByTestId("copy-name-btn")); - expect(screen.getByTestId("copy-state")).toHaveTextContent("Name copied"); - - fireEvent.click(screen.getByTestId("copy-value-btn")); - expect(screen.getByTestId("copy-state")).toHaveTextContent("Value copied"); - }); - - it("handles empty artifact data gracefully", () => { - const emptyArtifactData = { - ...mockArtifactData, - value: "", - uri: null, - }; - - render(); - - expect(screen.getByTestId("io-cell-header")).toBeInTheDocument(); - - expect(screen.getByTestId("io-cell-details")).toBeInTheDocument(); - - fireEvent.click(screen.getByTestId("copy-value-btn")); - expect(copyToClipboard).not.toHaveBeenCalled(); - }); -}); diff --git a/src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskOverview/IOSection/IOCell/IOCell.tsx b/src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskOverview/IOSection/IOCell/IOCell.tsx index 64152b1be..a15c330e6 100644 --- a/src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskOverview/IOSection/IOCell/IOCell.tsx +++ b/src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskOverview/IOSection/IOCell/IOCell.tsx @@ -1,116 +1,77 @@ -import { useCallback, useEffect, useRef, useState } from "react"; +import type { ArtifactNodeResponse } from "@/api/types.gen"; +import { CopyText } from "@/components/shared/CopyText/CopyText"; +import { BlockStack, InlineStack } from "@/components/ui/layout"; +import { Text } from "@/components/ui/typography"; +import { formatBytes } from "@/utils/string"; -import type { ArtifactDataResponse } from "@/api/types.gen"; -import { Collapsible, CollapsibleContent } from "@/components/ui/collapsible"; -import type { InputSpec, OutputSpec } from "@/utils/componentSpec"; -import { copyToClipboard } from "@/utils/string"; - -import IOCellDetails from "./IOCellDetails"; -import IOCellHeader from "./IOCellHeader"; +import ArtifactURI from "./ArtifactURI"; interface IOCellProps { - io: InputSpec | OutputSpec; - artifactData: ArtifactDataResponse | null | undefined; -} - -export interface IOCellCopyState { - isCopied: boolean; - isTooltipOpen: boolean; - copyType?: "Name" | "Value"; -} - -export interface IOCellActions { - handleCopyName: () => void; - handleCopyValue: () => void; - handleTooltipOpen: (open: boolean) => void; + name: string; + type?: string; + artifact: ArtifactNodeResponse | null | undefined; } -const IOCell = ({ io, artifactData }: IOCellProps) => { - const [isCopied, setIsCopied] = useState(false); - const [isTooltipOpen, setIsTooltipOpen] = useState(false); - const [copyType, setCopyType] = useState<"Name" | "Value">(); - const [isOpen, setIsOpen] = useState(false); - const tooltipTimerRef = useRef(null); - - const handleTooltipOpen = useCallback((open: boolean) => { - // When the tooltip is closed, we need to clear the copied state - if (!open) { - if (tooltipTimerRef.current) clearTimeout(tooltipTimerRef.current); - setIsCopied(false); - } - setIsTooltipOpen(open); - }, []); - - const handleCopy = useCallback((value: string, type: "Name" | "Value") => { - copyToClipboard(value); - setIsCopied(true); - setIsTooltipOpen(true); - setCopyType(type); - - // Clear any existing timer - if (tooltipTimerRef.current) clearTimeout(tooltipTimerRef.current); - - tooltipTimerRef.current = setTimeout(() => { - setIsTooltipOpen(false); - setCopyType(undefined); - setIsCopied(false); - }, 1500); - }, []); +const IOCell = ({ name, type, artifact }: IOCellProps) => { + const artifactData = artifact?.artifact_data; + const inlineValue = artifactData?.value; + const hasInlineValue = canShowInlineValue(inlineValue); - const handleCopyName = useCallback(() => { - handleCopy(io.name, "Name"); - }, [io.name, handleCopy]); - - const handleCopyValue = useCallback(() => { - if (!artifactData?.value) return; - - handleCopy(artifactData.value, "Value"); - }, [artifactData?.value, handleCopy]); - - useEffect(() => { - return () => { - if (tooltipTimerRef.current) clearTimeout(tooltipTimerRef.current); - }; - }, []); - - const copyState: IOCellCopyState = { - isCopied, - isTooltipOpen, - copyType, - }; - - const actions: IOCellActions = { - handleCopyName, - handleCopyValue, - handleTooltipOpen, - }; + const artifactType = + type ?? artifact?.type_name ?? (artifactData?.is_dir ? "Directory" : "Any"); return ( - - + + + + {name} + + + + + {artifactType} + + + {!!artifactData?.total_size && ( + + ({formatBytes(artifactData.total_size)}) + + )} + + + + {hasInlineValue && ( + + {inlineValue} + + )} - {artifactData && ( - - - + {!!artifactData?.uri && ( + )} - + ); }; export default IOCell; + +const canShowInlineValue = ( + value: string | null | undefined, +): value is string => { + if (!value) { + return false; + } + if (String(value).trim() !== "") { + return true; + } + return false; +}; diff --git a/src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskOverview/IOSection/IOCell/IOCellDetails.test.tsx b/src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskOverview/IOSection/IOCell/IOCellDetails.test.tsx deleted file mode 100644 index 0d51f28e3..000000000 --- a/src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskOverview/IOSection/IOCell/IOCellDetails.test.tsx +++ /dev/null @@ -1,190 +0,0 @@ -import { fireEvent, render, screen } from "@testing-library/react"; -import { beforeEach, describe, expect, it, vi } from "vitest"; - -import type { ArtifactDataResponse } from "@/api/types.gen"; -import type { InputSpec } from "@/utils/componentSpec"; - -import type { IOCellActions } from "./IOCell"; -import IOCellDetails from "./IOCellDetails"; - -vi.mock("./IOCodeViewer", () => ({ - default: ({ title, value }: any) => ( -
- {value} -
- ), -})); - -describe("IOCellDetails", () => { - const mockInputSpec: InputSpec = { - name: "test-input", - type: "String", - }; - - const mockArtifactData: ArtifactDataResponse = { - value: "test-value", - uri: "gs://bucket/path", - total_size: 1024, - is_dir: false, - }; - - const mockActions: IOCellActions = { - handleCopyName: vi.fn(), - handleCopyValue: vi.fn(), - handleTooltipOpen: vi.fn(), - }; - - beforeEach(() => { - vi.clearAllMocks(); - }); - - it("renders IOCodeViewer when value exists", () => { - render( - , - ); - - const codeViewer = screen.getByTestId("io-code-viewer"); - expect(codeViewer).toBeInTheDocument(); - expect(codeViewer).toHaveAttribute("data-title", "test-input"); - expect(codeViewer).toHaveAttribute("data-value", "test-value"); - }); - - it("calls handleCopyValue when code viewer area is clicked", () => { - render( - , - ); - - const codeViewer = screen.getByTestId("io-code-viewer"); - fireEvent.click(codeViewer.parentElement!); - - expect(mockActions.handleCopyValue).toHaveBeenCalledTimes(1); - }); - - it("does not render IOCodeViewer when value is null", () => { - const artifactWithoutValue = { ...mockArtifactData, value: null }; - - render( - , - ); - - expect(screen.queryByTestId("io-code-viewer")).not.toBeInTheDocument(); - }); - - it("does not render IOCodeViewer when value is empty string", () => { - const artifactWithEmptyValue = { ...mockArtifactData, value: "" }; - - render( - , - ); - - expect(screen.queryByTestId("io-code-viewer")).not.toBeInTheDocument(); - }); - - it("renders URI section when uri exists", () => { - render( - , - ); - - expect(screen.getByText("URI:")).toBeInTheDocument(); - expect(screen.getByText("gs://bucket/path")).toBeInTheDocument(); - }); - - it("does not render URI section when uri is null", () => { - const artifactWithoutUri = { ...mockArtifactData, uri: null }; - - render( - , - ); - - expect(screen.queryByText("URI:")).not.toBeInTheDocument(); - }); - - it("does not render URI section when uri is empty string", () => { - const artifactWithEmptyUri = { ...mockArtifactData, uri: "" }; - - render( - , - ); - - expect(screen.queryByText("URI:")).not.toBeInTheDocument(); - }); - - it("renders both sections when both value and URI exist", () => { - render( - , - ); - - expect(screen.getByTestId("io-code-viewer")).toBeInTheDocument(); - expect(screen.getByText("URI:")).toBeInTheDocument(); - }); - - it("renders only URI when value is null but URI exists", () => { - const artifactDataOnlyUri = { - ...mockArtifactData, - value: null, - uri: "gs://bucket/path", - }; - - render( - , - ); - - expect(screen.queryByTestId("io-code-viewer")).not.toBeInTheDocument(); - expect(screen.getByText("URI:")).toBeInTheDocument(); - }); - - it("renders only value when URI is null but value exists", () => { - const artifactDataOnlyValue = { - ...mockArtifactData, - value: "test-value", - uri: null, - }; - - render( - , - ); - - expect(screen.getByTestId("io-code-viewer")).toBeInTheDocument(); - expect(screen.queryByText("URI:")).not.toBeInTheDocument(); - }); -}); diff --git a/src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskOverview/IOSection/IOCell/IOCellDetails.tsx b/src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskOverview/IOSection/IOCell/IOCellDetails.tsx deleted file mode 100644 index 1c086526d..000000000 --- a/src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskOverview/IOSection/IOCell/IOCellDetails.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import type { ArtifactDataResponse } from "@/api/types.gen"; -import { BlockStack, InlineStack } from "@/components/ui/layout"; -import { Link } from "@/components/ui/link"; -import { Text } from "@/components/ui/typography"; -import type { InputSpec, OutputSpec } from "@/utils/componentSpec"; -import { convertArtifactUriToHTTPUrl } from "@/utils/URL"; - -import type { IOCellActions } from "./IOCell"; -import IOCodeViewer from "./IOCodeViewer"; - -interface IOCellDetailsProps { - io: InputSpec | OutputSpec; - artifactData: ArtifactDataResponse; - actions: IOCellActions; -} - -const IOCellDetails = ({ io, artifactData, actions }: IOCellDetailsProps) => { - const { handleCopyValue } = actions; - - return ( - - {artifactData.value && ( - - - - - - )} - - {artifactData.uri && ( - - URI: - - {artifactData.uri} - - - )} - - ); -}; - -export default IOCellDetails; diff --git a/src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskOverview/IOSection/IOCell/IOCellHeader.test.tsx b/src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskOverview/IOSection/IOCell/IOCellHeader.test.tsx deleted file mode 100644 index 75837cdc1..000000000 --- a/src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskOverview/IOSection/IOCell/IOCellHeader.test.tsx +++ /dev/null @@ -1,179 +0,0 @@ -import { fireEvent, render, screen } from "@testing-library/react"; -import { beforeEach, describe, expect, it, vi } from "vitest"; - -import type { ArtifactDataResponse } from "@/api/types.gen"; -import type { InputSpec } from "@/utils/componentSpec"; - -import type { IOCellActions, IOCellCopyState } from "./IOCell"; -import IOCellHeader from "./IOCellHeader"; - -vi.mock("@/components/ui/collapsible", () => ({ - CollapsibleTrigger: ({ children }: any) => , -})); - -describe("IOCellHeader", () => { - const mockInputSpec: InputSpec = { - name: "test-input", - type: "String", - }; - - const mockArtifactData: ArtifactDataResponse = { - value: "short-value", - uri: "gs://bucket/path", - total_size: 1024, - is_dir: false, - }; - - const mockCopyState: IOCellCopyState = { - isCopied: false, - isTooltipOpen: false, - copyType: undefined, - }; - - const mockActions: IOCellActions = { - handleCopyName: vi.fn(), - handleCopyValue: vi.fn(), - handleTooltipOpen: vi.fn(), - }; - - beforeEach(() => { - vi.clearAllMocks(); - }); - - it("renders the input name", () => { - render( - , - ); - - expect(screen.getByText("test-input")).toBeInTheDocument(); - }); - - it("calls handleCopyName when name is clicked", () => { - render( - , - ); - - const nameElement = screen.getByText("test-input"); - fireEvent.click(nameElement); - expect(mockActions.handleCopyName).toHaveBeenCalledTimes(1); - }); - - it("shows artifact metadata when artifactData is provided", () => { - const { container } = render( - , - ); - - expect(screen.getByText("Link")).toBeInTheDocument(); - expect(screen.getByText("short-value")).toBeInTheDocument(); - expect(container.textContent).toContain("String"); - }); - - it("does not render artifact metadata when artifactData is null", () => { - const { container } = render( - , - ); - - expect(screen.queryByText("Link")).not.toBeInTheDocument(); - expect(screen.queryByText("short-value")).not.toBeInTheDocument(); - expect(container.textContent).not.toContain("String"); - }); - - it("shows inline value for short strings", () => { - render( - , - ); - - expect(screen.getByText("short-value")).toBeInTheDocument(); - }); - - it("does not show inline value for long strings", () => { - const longValueData = { - ...mockArtifactData, - value: - "this is a very long string that should not be displayed inline because it exceeds the character limit", - }; - - render( - , - ); - - expect(screen.queryByText(longValueData.value)).not.toBeInTheDocument(); - }); - - it("shows inline value for integers", () => { - const integerInput = { ...mockInputSpec, type: "Integer" as const }; - const integerData = { ...mockArtifactData, value: "42" }; - - render( - , - ); - - expect(screen.getByText("42")).toBeInTheDocument(); - }); - - it("shows inline value for booleans", () => { - const booleanInput = { ...mockInputSpec, type: "Boolean" as const }; - const booleanData = { ...mockArtifactData, value: "true" }; - - render( - , - ); - - expect(screen.getByText("true")).toBeInTheDocument(); - }); - - it("does not render URI link when uri is null", () => { - const dataWithoutUri = { ...mockArtifactData, uri: null }; - - render( - , - ); - - expect(screen.queryByText("Link")).not.toBeInTheDocument(); - }); -}); diff --git a/src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskOverview/IOSection/IOCell/IOCellHeader.tsx b/src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskOverview/IOSection/IOCell/IOCellHeader.tsx deleted file mode 100644 index ba0c2cabd..000000000 --- a/src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskOverview/IOSection/IOCell/IOCellHeader.tsx +++ /dev/null @@ -1,152 +0,0 @@ -import type { ArtifactDataResponse } from "@/api/types.gen"; -import { CollapsibleTrigger } from "@/components/ui/collapsible"; -import { Icon } from "@/components/ui/icon"; -import { BlockStack, InlineStack } from "@/components/ui/layout"; -import { Link } from "@/components/ui/link"; -import { - Tooltip, - TooltipContent, - TooltipTrigger, -} from "@/components/ui/tooltip"; -import { cn } from "@/lib/utils"; -import type { - InputSpec, - OutputSpec, - TypeSpecType, -} from "@/utils/componentSpec"; -import { formatBytes } from "@/utils/string"; -import { convertArtifactUriToHTTPUrl } from "@/utils/URL"; - -import type { IOCellActions, IOCellCopyState } from "./IOCell"; - -interface IOCellHeaderProps { - io: InputSpec | OutputSpec; - artifactData: ArtifactDataResponse | null | undefined; - copyState: IOCellCopyState; - actions: IOCellActions; - isOpen?: boolean; -} - -const IOCellHeader = ({ - io, - artifactData, - copyState, - actions, - isOpen = false, -}: IOCellHeaderProps) => { - const { isCopied, isTooltipOpen, copyType } = copyState; - const { handleCopyName, handleTooltipOpen } = actions; - - const hasCollapsableContent = !canShowInlineValue( - artifactData?.value, - io.type, - ); - - const hasArtifactDetails = - (!!artifactData?.value && artifactData.value.trim() !== "") || - !!artifactData?.uri; - - return ( - - -
- - - - {io.name} - - - - {isCopied ? `${copyType} copied` : `Copy`} - - -
- - {artifactData && ( - - - {artifactData.uri && ( - <> - - Link - - • - - )} - - {artifactData.value && - canShowInlineValue(artifactData.value, io.type) && ( - <> - - {artifactData.value} - - • - - )} - - - {formatBytes(artifactData.total_size)} • - - - {io.type?.toString()} - - {hasArtifactDetails && ( - - - - )} - - - )} -
-
- ); -}; - -export default IOCellHeader; - -const canShowInlineValue = ( - value: string | null | undefined, - type: TypeSpecType | undefined, -) => { - if (!type || !value) { - return false; - } - if (type === "Integer" || type === "Boolean") { - return true; - } - if (type === "String" && value.length < 31 && value.trim() !== "") { - return true; - } - return false; -}; diff --git a/src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskOverview/IOSection/IOCell/index.ts b/src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskOverview/IOSection/IOCell/index.ts deleted file mode 100644 index ccca61d9d..000000000 --- a/src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskOverview/IOSection/IOCell/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./IOCell"; diff --git a/src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskOverview/IOSection/IOExtras.tsx b/src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskOverview/IOSection/IOExtras.tsx index 7e2c0902f..e50fabd46 100644 --- a/src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskOverview/IOSection/IOExtras.tsx +++ b/src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskOverview/IOSection/IOExtras.tsx @@ -1,10 +1,9 @@ import type { GetExecutionArtifactsResponse } from "@/api/types.gen"; -import { BlockStack, InlineStack } from "@/components/ui/layout"; -import { Link } from "@/components/ui/link"; -import { Heading, Paragraph } from "@/components/ui/typography"; +import { BlockStack } from "@/components/ui/layout"; +import { Heading } from "@/components/ui/typography"; import type { InputSpec, OutputSpec } from "@/utils/componentSpec"; -import { formatBytes } from "@/utils/string"; -import { convertArtifactUriToHTTPUrl } from "@/utils/URL"; + +import IOCell from "./IOCell/IOCell"; interface IOExtrasProps { inputs?: InputSpec[]; @@ -21,162 +20,27 @@ const IOExtras = ({ inputs, outputs, artifacts }: IOExtrasProps) => { artifacts.output_artifacts || {}, ).filter(([key]) => !outputs?.some((output) => output.name === key)); - const hasAdditionalInputs = additionalInputs.length > 0; - const hasAdditionalOutputs = additionalOutputs.length > 0; - - if (!hasAdditionalInputs && !hasAdditionalOutputs) { + if (!additionalInputs.length && !additionalOutputs.length) { return null; } + return ( <> - {hasAdditionalInputs && ( + {additionalInputs.length > 0 && ( Additional Input Artifacts -
- {additionalInputs.map(([key, artifact]) => ( - - - {key} - {artifact.type_name && ( - - Type: {artifact.type_name} - - )} - - - {artifact.artifact_data && ( - - {artifact.artifact_data.value !== undefined && ( - - - Value: - - - {JSON.stringify(artifact.artifact_data.value)} - - - )} - - {artifact.artifact_data.uri && ( - - - URI: - - - - {artifact.artifact_data.uri} - - - - )} - - {artifact.artifact_data.total_size && ( - - - Size: - - - {formatBytes(artifact.artifact_data.total_size)} - - - )} - - )} - - ))} -
+ {additionalInputs.map(([key, artifact]) => ( + + ))}
)} - {hasAdditionalOutputs && ( + {additionalOutputs.length > 0 && ( Additional Output Artifacts -
- {additionalOutputs.map(([key, artifact]) => ( - - - {key} - {artifact.type_name && ( - - Type: {artifact.type_name} - - )} - - - {artifact.artifact_data && ( - - {artifact.artifact_data.value !== undefined && ( - - - Value: - - - {JSON.stringify(artifact.artifact_data.value)} - - - )} - - {artifact.artifact_data.uri && ( - - - URI: - - - - {artifact.artifact_data.uri} - - - - )} - - {artifact.artifact_data.total_size && ( - - - Size: - - - {formatBytes(artifact.artifact_data.total_size)} - - - )} - - {artifact.artifact_data.is_dir && ( - - - Type: - - - Directory - - - )} - - )} - - ))} -
+ {additionalOutputs.map(([key, artifact]) => ( + + ))}
)} diff --git a/src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskOverview/IOSection/IOInputs.tsx b/src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskOverview/IOSection/IOInputs.tsx index 2d14d938f..a64a6c7f7 100644 --- a/src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskOverview/IOSection/IOInputs.tsx +++ b/src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskOverview/IOSection/IOInputs.tsx @@ -3,7 +3,7 @@ import { BlockStack } from "@/components/ui/layout"; import { Heading, Paragraph } from "@/components/ui/typography"; import type { InputSpec } from "@/utils/componentSpec"; -import IoCell from "./IOCell"; +import IOCell from "./IOCell/IOCell"; interface IOInputsProps { inputs?: InputSpec[]; @@ -25,10 +25,11 @@ const IOInputs = ({ inputs, artifacts }: IOInputsProps) => { const inputArtifact = artifacts.input_artifacts?.[input.name]; return ( - ); })} diff --git a/src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskOverview/IOSection/IOOutputs.tsx b/src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskOverview/IOSection/IOOutputs.tsx index 63dd3376f..0e9ebba79 100644 --- a/src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskOverview/IOSection/IOOutputs.tsx +++ b/src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskOverview/IOSection/IOOutputs.tsx @@ -3,7 +3,7 @@ import { BlockStack } from "@/components/ui/layout"; import { Heading, Paragraph } from "@/components/ui/typography"; import type { OutputSpec } from "@/utils/componentSpec"; -import IoCell from "./IOCell"; +import IOCell from "./IOCell/IOCell"; interface IOOutputsProps { outputs?: OutputSpec[]; @@ -25,10 +25,11 @@ const IOOutputs = ({ outputs, artifacts }: IOOutputsProps) => { const outputArtifact = artifacts?.output_artifacts?.[output.name]; return ( - ); })}