Files
Dorod-Sky/skyvern-frontend/src/routes/tasks/detail/TaskDetails.tsx

215 lines
6.3 KiB
TypeScript
Raw Normal View History

2024-05-07 11:31:05 -07:00
import { getClient } from "@/api/AxiosClient";
2024-07-11 08:03:18 -07:00
import { Status } from "@/api/types";
2024-06-26 15:57:24 -07:00
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
2024-06-03 10:56:26 -07:00
import { Label } from "@/components/ui/label";
import { Skeleton } from "@/components/ui/skeleton";
import { Textarea } from "@/components/ui/textarea";
2024-06-26 15:57:24 -07:00
import { toast } from "@/components/ui/use-toast";
2024-05-07 11:31:05 -07:00
import { useCredentialGetter } from "@/hooks/useCredentialGetter";
2024-06-03 10:56:26 -07:00
import { cn } from "@/util/utils";
2024-06-26 15:57:24 -07:00
import { ReloadIcon } from "@radix-ui/react-icons";
2024-07-11 08:03:18 -07:00
import { useMutation, useQueryClient } from "@tanstack/react-query";
2024-06-03 10:56:26 -07:00
import { NavLink, Outlet, useParams } from "react-router-dom";
2024-07-11 08:03:18 -07:00
import { TaskInfo } from "./TaskInfo";
import { useTaskQuery } from "./hooks/useTaskQuery";
2024-04-01 21:34:52 +03:00
function TaskDetails() {
const { taskId } = useParams();
2024-05-07 11:31:05 -07:00
const credentialGetter = useCredentialGetter();
2024-06-26 15:57:24 -07:00
const queryClient = useQueryClient();
2024-04-01 21:34:52 +03:00
const {
data: task,
isLoading: taskIsLoading,
2024-06-03 10:56:26 -07:00
isError: taskIsError,
2024-04-01 21:34:52 +03:00
error: taskError,
2024-07-11 08:03:18 -07:00
} = useTaskQuery({ id: taskId });
2024-04-01 21:34:52 +03:00
2024-06-26 15:57:24 -07:00
const cancelTaskMutation = useMutation({
mutationFn: async () => {
const client = await getClient(credentialGetter);
return client
.post(`/tasks/${taskId}/cancel`)
.then((response) => response.data);
},
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["task", taskId],
});
queryClient.invalidateQueries({
queryKey: ["tasks"],
});
toast({
variant: "success",
title: "Task Canceled",
description: "The task has been successfully canceled.",
});
},
onError: (error) => {
toast({
variant: "destructive",
title: "Error",
description: error.message,
});
},
});
2024-06-03 10:56:26 -07:00
if (taskIsError) {
2024-04-01 21:34:52 +03:00
return <div>Error: {taskError?.message}</div>;
}
const showExtractedInformation =
task?.status === Status.Completed && task.extracted_information !== null;
const extractedInformation = showExtractedInformation ? (
<div className="flex items-center">
<Label className="w-32 shrink-0 text-lg">Extracted Information</Label>
<Textarea
rows={5}
value={JSON.stringify(task.extracted_information, null, 2)}
readOnly
/>
</div>
) : null;
2024-06-26 15:57:24 -07:00
const taskIsRunningOrQueued =
task?.status === Status.Running || task?.status === Status.Queued;
const showFailureReason =
task?.status === Status.Failed ||
task?.status === Status.Terminated ||
task?.status === Status.TimedOut;
const failureReason = showFailureReason ? (
<div className="flex items-center">
<Label className="w-32 shrink-0 text-lg">Failure Reason</Label>
<Textarea
rows={5}
value={JSON.stringify(task.failure_reason, null, 2)}
readOnly
/>
</div>
) : null;
2024-04-01 21:34:52 +03:00
return (
2024-05-29 09:34:58 -07:00
<div className="flex flex-col gap-8">
<div className="flex items-center justify-between">
2024-06-26 15:57:24 -07:00
<div className="flex items-center gap-4">
<span className="text-lg">{taskId}</span>
2024-07-11 08:03:18 -07:00
{taskId && <TaskInfo id={taskId} />}
2024-06-26 15:57:24 -07:00
</div>
{taskIsRunningOrQueued && (
<Dialog>
<DialogTrigger asChild>
<Button variant="destructive">Cancel</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Are you sure?</DialogTitle>
<DialogDescription>
Are you sure you want to cancel this task?
</DialogDescription>
</DialogHeader>
<DialogFooter>
<DialogClose asChild>
<Button variant="secondary">Back</Button>
</DialogClose>
<Button
variant="destructive"
onClick={() => {
cancelTaskMutation.mutate();
}}
disabled={cancelTaskMutation.isPending}
>
{cancelTaskMutation.isPending && (
<ReloadIcon className="mr-2 h-4 w-4 animate-spin" />
)}
Cancel Task
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
)}
</div>
{taskIsLoading ? (
<div className="flex items-center gap-2">
<Skeleton className="h-32 w-32" />
<Skeleton className="h-32 w-full" />
</div>
) : (
<>
{extractedInformation}
{failureReason}
</>
)}
<div className="flex items-center justify-center">
<div className="inline-flex rounded border bg-muted p-1">
2024-06-03 10:56:26 -07:00
<NavLink
to="actions"
className={({ isActive }) => {
return cn(
"cursor-pointer rounded-md px-2 py-1 text-muted-foreground",
2024-06-03 10:56:26 -07:00
{
"bg-primary-foreground text-foreground": isActive,
},
);
}}
>
Actions
</NavLink>
<NavLink
to="recording"
className={({ isActive }) => {
return cn(
"cursor-pointer rounded-md px-2 py-1 text-muted-foreground",
2024-06-03 10:56:26 -07:00
{
"bg-primary-foreground text-foreground": isActive,
},
);
}}
>
Recording
</NavLink>
<NavLink
to="parameters"
className={({ isActive }) => {
return cn(
"cursor-pointer rounded-md px-2 py-1 text-muted-foreground",
2024-06-03 10:56:26 -07:00
{
"bg-primary-foreground text-foreground": isActive,
},
);
}}
>
Parameters
</NavLink>
2024-06-05 18:53:30 +03:00
<NavLink
to="diagnostics"
2024-06-05 18:53:30 +03:00
className={({ isActive }) => {
return cn(
"cursor-pointer rounded-md px-2 py-1 text-muted-foreground",
2024-06-05 18:53:30 +03:00
{
"bg-primary-foreground text-foreground": isActive,
},
);
}}
>
Diagnostics
2024-06-05 18:53:30 +03:00
</NavLink>
</div>
2024-06-03 10:56:26 -07:00
</div>
<Outlet />
2024-04-01 21:34:52 +03:00
</div>
);
}
export { TaskDetails };