Skip to content

Commit bf9c8e9

Browse files
committed
feat: copy submit pipeline arguments from custom run id
1 parent 685d821 commit bf9c8e9

File tree

1 file changed

+116
-39
lines changed

1 file changed

+116
-39
lines changed

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

Lines changed: 116 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { useMutation } from "@tanstack/react-query";
2-
import { type ChangeEvent, useState } from "react";
2+
import { type ChangeEvent, type KeyboardEvent, 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,15 +23,21 @@ 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 useToastNotification from "@/hooks/useToastNotification";
2729
import { cn } from "@/lib/utils";
2830
import { useBackend } from "@/providers/BackendProvider";
29-
import { fetchExecutionDetails } from "@/services/executionService";
31+
import {
32+
fetchExecutionDetails,
33+
fetchPipelineRun,
34+
} from "@/services/executionService";
3035
import type { PipelineRun } from "@/types/pipelineRun";
3136
import type { ComponentSpec, InputSpec } from "@/utils/componentSpec";
3237
import { getArgumentValue } from "@/utils/nodes/taskArguments";
3338

39+
type TaskArguments = TaskSpecOutput["arguments"];
40+
3441
interface SubmitTaskArgumentsDialogProps {
3542
open: boolean;
3643
onCancel: () => void;
@@ -160,34 +167,69 @@ const CopyFromRunPopover = ({
160167
const pipelineName = componentSpec.name;
161168

162169
const [popoverOpen, setPopoverOpen] = useState(false);
170+
const [customRunId, setCustomRunId] = useState("");
163171

164-
const { mutate: copyFromRunMutation, isPending: isCopyingFromRun } =
165-
useMutation({
166-
mutationFn: async (run: PipelineRun) => {
167-
const executionDetails = await fetchExecutionDetails(
168-
String(run.root_execution_id),
169-
backendUrl,
172+
const {
173+
mutate: copyFromRunMutation,
174+
isPending: isCopyingFromRun,
175+
isError,
176+
} = useMutation({
177+
/**
178+
* @param run - The run to copy arguments from. Can be a run ID or a run object.
179+
* @returns
180+
*/
181+
mutationFn: async (run: PipelineRun | string) => {
182+
const executionId =
183+
typeof run === "string"
184+
? (await fetchPipelineRun(run, backendUrl)).root_execution_id
185+
: String(run.root_execution_id);
186+
187+
const executionDetails = await fetchExecutionDetails(
188+
executionId,
189+
backendUrl,
190+
);
191+
return executionDetails.task_spec.arguments;
192+
},
193+
onSuccess: (runArguments: TaskArguments) => {
194+
if (runArguments) {
195+
const componentSpecInputs = new Set(
196+
componentSpec.inputs?.map((input) => input.name) ?? [],
170197
);
171-
return executionDetails.task_spec.arguments;
172-
},
173-
onSuccess: (runArguments) => {
174-
if (runArguments) {
175-
const newArgs = Object.fromEntries(
176-
Object.entries(runArguments)
177-
.map(([name, _]) => [name, getArgumentValue(runArguments, name)])
178-
.filter(
179-
(entry): entry is [string, string] => entry[1] !== undefined,
180-
),
181-
);
182-
onCopy(newArgs);
183-
}
184-
setPopoverOpen(false);
185-
},
186-
onError: (error) => {
187-
console.error("Failed to fetch run arguments:", error);
188-
setPopoverOpen(false);
189-
},
190-
});
198+
199+
const newArgs = Object.fromEntries(
200+
Object.entries(runArguments)
201+
.map(
202+
([name, _]) =>
203+
[name, getArgumentValue(runArguments, name)] as const,
204+
)
205+
.filter(
206+
(entry): entry is [string, string] =>
207+
entry[1] !== undefined && componentSpecInputs.has(entry[0]),
208+
),
209+
);
210+
211+
onCopy(newArgs);
212+
}
213+
setPopoverOpen(false);
214+
setCustomRunId("");
215+
},
216+
onError: (error) => {
217+
console.error("Failed to fetch run arguments:", error);
218+
},
219+
});
220+
221+
const handleCustomRunIdSubmit = () => {
222+
const trimmedId = customRunId.trim();
223+
if (trimmedId) {
224+
copyFromRunMutation(trimmedId);
225+
}
226+
};
227+
228+
const handleKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {
229+
if (e.key === "Enter") {
230+
handleCustomRunIdSubmit();
231+
}
232+
};
191233

192234
return (
193235
<Popover open={popoverOpen} onOpenChange={setPopoverOpen}>
@@ -198,17 +240,52 @@ const CopyFromRunPopover = ({
198240
</Button>
199241
</PopoverTrigger>
200242
<PopoverContent className="w-100" align="end">
201-
<PipelineRunsList
202-
pipelineName={pipelineName}
203-
onRunClick={copyFromRunMutation}
204-
showTitle={false}
205-
showMoreButton={true}
206-
overviewConfig={{
207-
showName: false,
208-
showTaskStatusBar: false,
209-
}}
210-
disabled={isCopyingFromRun}
211-
/>
243+
<BlockStack gap="4">
244+
<BlockStack gap="2">
245+
<Paragraph size="sm" weight="semibold">
246+
Enter run ID
247+
</Paragraph>
248+
<InlineStack gap="2" fill>
249+
<Input
250+
placeholder="Run ID"
251+
value={customRunId}
252+
onChange={(e) => setCustomRunId(e.target.value)}
253+
onKeyDown={handleKeyDown}
254+
disabled={isCopyingFromRun}
255+
className={cn(isError && "border-red-300", "flex-1")}
256+
/>
257+
<Button
258+
size="sm"
259+
onClick={handleCustomRunIdSubmit}
260+
disabled={isCopyingFromRun || !customRunId.trim()}
261+
>
262+
{isCopyingFromRun ? <Spinner /> : <Icon name="ArrowRight" />}
263+
</Button>
264+
</InlineStack>
265+
{isError && (
266+
<Paragraph size="xs" tone="critical">
267+
Failed to fetch run. Please check the run ID.
268+
</Paragraph>
269+
)}
270+
</BlockStack>
271+
272+
<BlockStack gap="2">
273+
<Paragraph size="sm" weight="semibold">
274+
Or select from recent runs
275+
</Paragraph>
276+
<PipelineRunsList
277+
pipelineName={pipelineName}
278+
onRunClick={copyFromRunMutation}
279+
showTitle={false}
280+
showMoreButton={true}
281+
overviewConfig={{
282+
showName: false,
283+
showTaskStatusBar: false,
284+
}}
285+
disabled={isCopyingFromRun}
286+
/>
287+
</BlockStack>
288+
</BlockStack>
212289
</PopoverContent>
213290
</Popover>
214291
);

0 commit comments

Comments
 (0)