diff --git a/src/routes/v2/pages/Editor/nodes/TaskNode/context/TaskDetails/TaskDetails.tsx b/src/routes/v2/pages/Editor/nodes/TaskNode/context/TaskDetails/TaskDetails.tsx index 9dcdd8704..f6cacf383 100644 --- a/src/routes/v2/pages/Editor/nodes/TaskNode/context/TaskDetails/TaskDetails.tsx +++ b/src/routes/v2/pages/Editor/nodes/TaskNode/context/TaskDetails/TaskDetails.tsx @@ -1,6 +1,8 @@ import { observer } from "mobx-react-lite"; import { useEffect, useRef, useState } from "react"; +import type { SaveAction } from "@/components/shared/ComponentEditor/saveAction"; +import { SaveActionsView } from "@/components/shared/ComponentEditor/SaveActionsView"; import { StackingControls } from "@/components/shared/ReactFlow/FlowControls/StackingControls"; import { Button } from "@/components/ui/button"; import { Icon } from "@/components/ui/icon"; @@ -18,6 +20,7 @@ import { useSpec } from "@/routes/v2/shared/providers/SpecContext"; import { useSharedStores } from "@/routes/v2/shared/store/SharedStoreContext"; import { SYSTEM_ANNOTATIONS, ZINDEX_ANNOTATION } from "@/utils/annotations"; import type { HydratedComponentReference } from "@/utils/componentSpec"; +import { diffComponentIO } from "@/utils/componentSpecDiff"; import { tracking } from "@/utils/tracking"; import { getTaskYamlText } from "./components/actions/getTaskYamlText"; @@ -75,9 +78,37 @@ export const TaskDetails = observer(function TaskDetails({ const isSubgraphTask = task.subgraphSpec !== undefined; + const renderSaveActions = ({ + hydratedComponent, + onChoose, + }: { + hydratedComponent: HydratedComponentReference; + onChoose: (action: "update" | "import" | "place") => void; + }) => { + const { inputDiff, outputDiff } = diffComponentIO< + { name: string; type?: unknown }, + { name: string; type?: unknown } + >(task.resolvedComponentSpec, hydratedComponent.spec); + + return ( + + ); + }; + const handleComponentSaved = ( hydratedComponent: HydratedComponentReference, + action: SaveAction, ) => { + if (action !== "update") { + // "place" arrives once placement ships; nothing else applies in place. + return; + } + const result = replaceTask(spec, task.$id, hydratedComponent); const lostInputs = result.inputDiff?.lostEntities ?? []; @@ -182,6 +213,7 @@ export const TaskDetails = observer(function TaskDetails({ taskName={task.name} pythonCode={pythonCode} onComponentSaved={handleComponentSaved} + renderSaveActions={renderSaveActions} /> diff --git a/src/routes/v2/pages/Editor/nodes/TaskNode/context/TaskDetails/components/ComponentRefBar.tsx b/src/routes/v2/pages/Editor/nodes/TaskNode/context/TaskDetails/components/ComponentRefBar.tsx index 3dffbab27..6978324d9 100644 --- a/src/routes/v2/pages/Editor/nodes/TaskNode/context/TaskDetails/components/ComponentRefBar.tsx +++ b/src/routes/v2/pages/Editor/nodes/TaskNode/context/TaskDetails/components/ComponentRefBar.tsx @@ -1,7 +1,8 @@ -import { useState } from "react"; +import { type ReactNode, useState } from "react"; import { CodeViewer } from "@/components/shared/CodeViewer"; import { ComponentEditorDialog } from "@/components/shared/ComponentEditor/ComponentEditorDialog"; +import type { SaveAction } from "@/components/shared/ComponentEditor/saveAction"; import ComponentDetailsDialog from "@/components/shared/Dialogs/ComponentDetailsDialog"; import { TrimmedDigest } from "@/components/shared/ManageComponent/TrimmedDigest"; import { Button } from "@/components/ui/button"; @@ -38,7 +39,12 @@ interface ComponentRefBarProps { pythonCode: string | undefined; onComponentSaved?: ( hydratedComponent: HydratedComponentReference, + action: SaveAction, ) => void | Promise; + renderSaveActions?: (args: { + hydratedComponent: HydratedComponentReference; + onChoose: (action: "update" | "import" | "place") => void; + }) => ReactNode; } export function ComponentRefBar({ @@ -47,6 +53,7 @@ export function ComponentRefBar({ taskName, pythonCode, onComponentSaved, + renderSaveActions, }: ComponentRefBarProps) { const { track } = useAnalytics(); const notify = useToastNotification(); @@ -201,6 +208,7 @@ export function ComponentRefBar({ text={yamlText} onClose={() => setIsEditDialogOpen(false)} onComponentSaved={onComponentSaved} + renderSaveActions={renderSaveActions} /> )}