Files
Dorod-Sky/skyvern-frontend/src/routes/tasks/create/SavedTasks.tsx
2024-09-26 22:28:54 +03:00

157 lines
4.5 KiB
TypeScript

import { getClient } from "@/api/AxiosClient";
import { queryClient } from "@/api/QueryClient";
import { WorkflowApiResponse } from "@/api/types";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { toast } from "@/components/ui/use-toast";
import { useCredentialGetter } from "@/hooks/useCredentialGetter";
import { PlusIcon, ReloadIcon } from "@radix-ui/react-icons";
import { useMutation, useQuery } from "@tanstack/react-query";
import { useNavigate } from "react-router-dom";
import { stringify as convertToYAML } from "yaml";
import { SavedTaskCard } from "./SavedTaskCard";
import { useState } from "react";
import { cn } from "@/util/utils";
function createEmptyTaskTemplate() {
return {
title: "New Template",
description: "",
is_saved_task: true,
webhook_callback_url: null,
proxy_location: "RESIDENTIAL",
workflow_definition: {
parameters: [
{
parameter_type: "workflow",
workflow_parameter_type: "json",
key: "navigation_payload",
default_value: "null",
},
],
blocks: [
{
block_type: "task",
label: "New Template",
url: "https://example.com",
navigation_goal: "",
data_extraction_goal: null,
data_schema: null,
},
],
},
};
}
function SavedTasks() {
const credentialGetter = useCredentialGetter();
const navigate = useNavigate();
const [hovering, setHovering] = useState(false);
const { data } = useQuery<Array<WorkflowApiResponse>>({
queryKey: ["savedTasks"],
queryFn: async () => {
const client = await getClient(credentialGetter);
return client
.get("/workflows?only_saved_tasks=true")
.then((response) => response.data);
},
});
const mutation = useMutation({
mutationFn: async () => {
const request = createEmptyTaskTemplate();
const client = await getClient(credentialGetter);
const yaml = convertToYAML(request);
return client
.post<string, { data: { workflow_permanent_id: string } }>(
"/workflows",
yaml,
{
headers: {
"Content-Type": "text/plain",
},
},
)
.then((response) => response.data);
},
onError: (error) => {
toast({
variant: "destructive",
title: "There was an error while saving changes",
description: error.message,
});
},
onSuccess: (response) => {
toast({
title: "New template created",
description: "Your template was created successfully",
});
queryClient.invalidateQueries({
queryKey: ["savedTasks"],
});
navigate(`/create/${response.workflow_permanent_id}`);
},
});
return (
<div className="grid grid-cols-4 gap-4">
<Card
className="border-0"
onMouseEnter={() => setHovering(true)}
onMouseLeave={() => setHovering(false)}
onMouseOver={() => setHovering(true)}
onMouseOut={() => setHovering(false)}
>
<CardHeader
className={cn("rounded-t-md bg-slate-elevation1", {
"bg-slate-900": hovering,
})}
>
<CardTitle className="font-normal">New Template</CardTitle>
<CardDescription className="overflow-hidden text-ellipsis whitespace-nowrap text-slate-400">
Create your own template
</CardDescription>
</CardHeader>
<CardContent
className={cn(
"flex h-36 cursor-pointer items-center justify-center rounded-b-md bg-slate-elevation3 p-4 text-sm text-slate-300",
{
"bg-slate-800": hovering,
},
)}
onClick={() => {
if (mutation.isPending) {
return;
}
mutation.mutate();
}}
>
{!mutation.isPending && <PlusIcon className="h-12 w-12" />}
{mutation.isPending && (
<ReloadIcon className="h-12 w-12 animate-spin" />
)}
</CardContent>
</Card>
{data?.map((workflow) => {
return (
<SavedTaskCard
key={workflow.workflow_permanent_id}
workflowId={workflow.workflow_permanent_id}
title={workflow.title}
description={workflow.description}
url={workflow.workflow_definition.blocks[0]?.url ?? ""}
/>
);
})}
</div>
);
}
export { SavedTasks };