Skip to content

Commit d4fa437

Browse files
committed
feat: copy submit pipeline arguments from custom run id
1 parent a5d0cd3 commit d4fa437

File tree

1 file changed

+124
-39
lines changed

1 file changed

+124
-39
lines changed

src/components/shared/Submitters/Oasis/components/SubmitTaskArgumentsDialog.tsx

Lines changed: 124 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { useMutation } from "@tanstack/react-query";
22
import { useCallback, useMemo, useState } from "react";
33

4+
import type { TaskSpecOutput } from "@/api/types.gen";
45
import { PipelineRunsList } from "@/components/shared/PipelineRunDisplay/PipelineRunsList";
56
import { typeSpecToString } from "@/components/shared/ReactFlow/FlowCanvas/TaskNode/ArgumentsEditor/utils";
67
import { getArgumentsFromInputs } from "@/components/shared/ReactFlow/FlowCanvas/utils/getArgumentsFromInputs";
@@ -22,14 +23,20 @@ import {
2223
PopoverTrigger,
2324
} from "@/components/ui/popover";
2425
import { ScrollArea } from "@/components/ui/scroll-area";
26+
import { Spinner } from "@/components/ui/spinner";
2527
import { Paragraph } from "@/components/ui/typography";
2628
import { cn } from "@/lib/utils";
2729
import { useBackend } from "@/providers/BackendProvider";
28-
import { fetchExecutionDetails } from "@/services/executionService";
30+
import {
31+
fetchExecutionDetails,
32+
fetchPipelineRun,
33+
} from "@/services/executionService";
2934
import type { PipelineRun } from "@/types/pipelineRun";
3035
import type { ComponentSpec, InputSpec } from "@/utils/componentSpec";
3136
import { getArgumentValue } from "@/utils/nodes/taskArguments";
3237

38+
type TaskArguments = TaskSpecOutput["arguments"];
39+
3340
interface SubmitTaskArgumentsDialogProps {
3441
open: boolean;
3542
onCancel: () => void;
@@ -89,7 +96,12 @@ export const SubmitTaskArgumentsDialog = ({
8996
<InlineStack align="end" className="w-full">
9097
<CopyFromRunPopover
9198
componentSpec={componentSpec}
92-
onCopy={setTaskArguments}
99+
onCopy={(newArgs) => {
100+
setTaskArguments((prev) => ({
101+
...prev,
102+
...newArgs,
103+
}));
104+
}}
93105
/>
94106
</InlineStack>
95107
</BlockStack>
@@ -137,34 +149,72 @@ const CopyFromRunPopover = ({
137149
const pipelineName = componentSpec.name;
138150

139151
const [popoverOpen, setPopoverOpen] = useState(false);
152+
const [customRunId, setCustomRunId] = useState("");
153+
154+
const {
155+
mutate: copyFromRunMutation,
156+
isPending: isCopyingFromRun,
157+
isError,
158+
} = useMutation({
159+
/**
160+
* @param run - The run to copy arguments from. Can be a run ID or a run object.
161+
* @returns
162+
*/
163+
mutationFn: async (run: PipelineRun | string) => {
164+
const executionId =
165+
typeof run === "string"
166+
? (await fetchPipelineRun(run, backendUrl)).root_execution_id
167+
: String(run.root_execution_id);
140168

141-
const { mutate: copyFromRunMutation, isPending: isCopyingFromRun } =
142-
useMutation({
143-
mutationFn: async (run: PipelineRun) => {
144-
const executionDetails = await fetchExecutionDetails(
145-
String(run.root_execution_id),
146-
backendUrl,
169+
const executionDetails = await fetchExecutionDetails(
170+
executionId,
171+
backendUrl,
172+
);
173+
return executionDetails.task_spec.arguments;
174+
},
175+
onSuccess: (runArguments: TaskArguments) => {
176+
if (runArguments) {
177+
const componentSpecInputs = new Set(
178+
componentSpec.inputs?.map((input) => input.name) ?? [],
147179
);
148-
return executionDetails.task_spec.arguments;
149-
},
150-
onSuccess: (runArguments) => {
151-
if (runArguments) {
152-
const newArgs = Object.fromEntries(
153-
Object.entries(runArguments)
154-
.map(([name, _]) => [name, getArgumentValue(runArguments, name)])
155-
.filter(
156-
(entry): entry is [string, string] => entry[1] !== undefined,
157-
),
158-
);
159-
onCopy(newArgs);
160-
}
161-
setPopoverOpen(false);
162-
},
163-
onError: (error) => {
164-
console.error("Failed to fetch run arguments:", error);
165-
setPopoverOpen(false);
166-
},
167-
});
180+
181+
const newArgs = Object.fromEntries(
182+
Object.entries(runArguments)
183+
.map(
184+
([name, _]) =>
185+
[name, getArgumentValue(runArguments, name)] as const,
186+
)
187+
.filter(
188+
(entry): entry is [string, string] =>
189+
entry[1] !== undefined && componentSpecInputs.has(entry[0]),
190+
),
191+
);
192+
193+
onCopy(newArgs);
194+
}
195+
setPopoverOpen(false);
196+
setCustomRunId("");
197+
},
198+
onError: (error) => {
199+
console.error("Failed to fetch run arguments:", error);
200+
},
201+
});
202+
203+
const handleCustomRunIdSubmit = useCallback(() => {
204+
const trimmedId = customRunId.trim();
205+
if (trimmedId) {
206+
copyFromRunMutation(trimmedId);
207+
}
208+
}, [customRunId, copyFromRunMutation]);
209+
210+
const handleKeyDown = useCallback(
211+
(e: React.KeyboardEvent<HTMLInputElement>) => {
212+
if (e.key === "Enter") {
213+
handleCustomRunIdSubmit();
214+
}
215+
},
216+
[handleCustomRunIdSubmit],
217+
);
168218

169219
return (
170220
<Popover open={popoverOpen} onOpenChange={setPopoverOpen}>
@@ -175,17 +225,52 @@ const CopyFromRunPopover = ({
175225
</Button>
176226
</PopoverTrigger>
177227
<PopoverContent className="w-100" align="end">
178-
<PipelineRunsList
179-
pipelineName={pipelineName}
180-
onRunClick={copyFromRunMutation}
181-
showTitle={false}
182-
showMoreButton={true}
183-
overviewConfig={{
184-
showName: false,
185-
showTaskStatusBar: false,
186-
}}
187-
disabled={isCopyingFromRun}
188-
/>
228+
<BlockStack gap="4">
229+
<BlockStack gap="2">
230+
<Paragraph size="sm" weight="semibold">
231+
Enter run ID
232+
</Paragraph>
233+
<InlineStack gap="2" fill>
234+
<Input
235+
placeholder="Run ID"
236+
value={customRunId}
237+
onChange={(e) => setCustomRunId(e.target.value)}
238+
onKeyDown={handleKeyDown}
239+
disabled={isCopyingFromRun}
240+
className={cn(isError && "border-red-300", "flex-1")}
241+
/>
242+
<Button
243+
size="sm"
244+
onClick={handleCustomRunIdSubmit}
245+
disabled={isCopyingFromRun || !customRunId.trim()}
246+
>
247+
{isCopyingFromRun ? <Spinner /> : <Icon name="ArrowRight" />}
248+
</Button>
249+
</InlineStack>
250+
{isError && (
251+
<Paragraph size="xs" tone="critical">
252+
Failed to fetch run. Please check the run ID.
253+
</Paragraph>
254+
)}
255+
</BlockStack>
256+
257+
<BlockStack gap="2">
258+
<Paragraph size="sm" weight="semibold">
259+
Or select from recent runs
260+
</Paragraph>
261+
<PipelineRunsList
262+
pipelineName={pipelineName}
263+
onRunClick={copyFromRunMutation}
264+
showTitle={false}
265+
showMoreButton={true}
266+
overviewConfig={{
267+
showName: false,
268+
showTaskStatusBar: false,
269+
}}
270+
disabled={isCopyingFromRun}
271+
/>
272+
</BlockStack>
273+
</BlockStack>
189274
</PopoverContent>
190275
</Popover>
191276
);

0 commit comments

Comments
 (0)