Implement retry task (#600)
This commit is contained in:
13
skyvern-frontend/src/api/utils.ts
Normal file
13
skyvern-frontend/src/api/utils.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { Status, TaskApiResponse } from "./types";
|
||||||
|
|
||||||
|
const finalTaskStates: Array<Status> = [
|
||||||
|
Status.Canceled,
|
||||||
|
Status.Completed,
|
||||||
|
Status.Terminated,
|
||||||
|
Status.TimedOut,
|
||||||
|
Status.Failed,
|
||||||
|
];
|
||||||
|
|
||||||
|
export function taskIsFinalized(task: TaskApiResponse) {
|
||||||
|
return finalTaskStates.includes(task.status);
|
||||||
|
}
|
||||||
@@ -17,6 +17,7 @@ import { WorkflowsPageLayout } from "./routes/workflows/WorkflowsPageLayout";
|
|||||||
import { Workflows } from "./routes/workflows/Workflows";
|
import { Workflows } from "./routes/workflows/Workflows";
|
||||||
import { WorkflowPage } from "./routes/workflows/WorkflowPage";
|
import { WorkflowPage } from "./routes/workflows/WorkflowPage";
|
||||||
import { WorkflowRunParameters } from "./routes/workflows/WorkflowRunParameters";
|
import { WorkflowRunParameters } from "./routes/workflows/WorkflowRunParameters";
|
||||||
|
import { RetryTask } from "./routes/tasks/create/retry/RetryTask";
|
||||||
|
|
||||||
const router = createBrowserRouter([
|
const router = createBrowserRouter([
|
||||||
{
|
{
|
||||||
@@ -79,6 +80,10 @@ const router = createBrowserRouter([
|
|||||||
path: ":template",
|
path: ":template",
|
||||||
element: <CreateNewTaskFormPage />,
|
element: <CreateNewTaskFormPage />,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "retry/:taskId",
|
||||||
|
element: <RetryTask />,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
41
skyvern-frontend/src/routes/tasks/create/retry/RetryTask.tsx
Normal file
41
skyvern-frontend/src/routes/tasks/create/retry/RetryTask.tsx
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import { useParams } from "react-router-dom";
|
||||||
|
import { useTaskQuery } from "../../detail/hooks/useTaskQuery";
|
||||||
|
import { CreateNewTaskForm } from "../CreateNewTaskForm";
|
||||||
|
|
||||||
|
function RetryTask() {
|
||||||
|
const { taskId } = useParams();
|
||||||
|
const { data: task, isLoading } = useTaskQuery({ id: taskId });
|
||||||
|
|
||||||
|
if (isLoading) {
|
||||||
|
return <div>Fetching task details...</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!task) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CreateNewTaskForm
|
||||||
|
initialValues={{
|
||||||
|
url: task.request.url,
|
||||||
|
navigationGoal: task.request.navigation_goal,
|
||||||
|
navigationPayload:
|
||||||
|
typeof task.request.navigation_payload === "string"
|
||||||
|
? task.request.navigation_payload
|
||||||
|
: JSON.stringify(task.request.navigation_payload, null, 2),
|
||||||
|
dataExtractionGoal: task.request.data_extraction_goal,
|
||||||
|
extractedInformationSchema:
|
||||||
|
typeof task.request.extracted_information_schema === "string"
|
||||||
|
? task.request.extracted_information_schema
|
||||||
|
: JSON.stringify(
|
||||||
|
task.request.extracted_information_schema,
|
||||||
|
null,
|
||||||
|
2,
|
||||||
|
),
|
||||||
|
webhookCallbackUrl: task.request.webhook_callback_url,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { RetryTask };
|
||||||
@@ -19,9 +19,10 @@ import { useCredentialGetter } from "@/hooks/useCredentialGetter";
|
|||||||
import { cn } from "@/util/utils";
|
import { cn } from "@/util/utils";
|
||||||
import { ReloadIcon } from "@radix-ui/react-icons";
|
import { ReloadIcon } from "@radix-ui/react-icons";
|
||||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||||
import { NavLink, Outlet, useParams } from "react-router-dom";
|
import { Link, NavLink, Outlet, useParams } from "react-router-dom";
|
||||||
import { TaskInfo } from "./TaskInfo";
|
import { TaskInfo } from "./TaskInfo";
|
||||||
import { useTaskQuery } from "./hooks/useTaskQuery";
|
import { useTaskQuery } from "./hooks/useTaskQuery";
|
||||||
|
import { taskIsFinalized } from "@/api/utils";
|
||||||
|
|
||||||
function TaskDetails() {
|
function TaskDetails() {
|
||||||
const { taskId } = useParams();
|
const { taskId } = useParams();
|
||||||
@@ -84,6 +85,8 @@ function TaskDetails() {
|
|||||||
const taskIsRunningOrQueued =
|
const taskIsRunningOrQueued =
|
||||||
task?.status === Status.Running || task?.status === Status.Queued;
|
task?.status === Status.Running || task?.status === Status.Queued;
|
||||||
|
|
||||||
|
const taskHasTerminalState = task && taskIsFinalized(task);
|
||||||
|
|
||||||
const showFailureReason =
|
const showFailureReason =
|
||||||
task?.status === Status.Failed ||
|
task?.status === Status.Failed ||
|
||||||
task?.status === Status.Terminated ||
|
task?.status === Status.Terminated ||
|
||||||
@@ -138,6 +141,11 @@ function TaskDetails() {
|
|||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
)}
|
)}
|
||||||
|
{taskHasTerminalState && (
|
||||||
|
<Button variant="secondary" asChild>
|
||||||
|
<Link to={`/create/retry/${task.task_id}`}>Retry Task</Link>
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{taskIsLoading ? (
|
{taskIsLoading ? (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ import {
|
|||||||
TaskTemplateFormValues,
|
TaskTemplateFormValues,
|
||||||
taskTemplateFormSchema,
|
taskTemplateFormSchema,
|
||||||
} from "../create/TaskTemplateFormSchema";
|
} from "../create/TaskTemplateFormSchema";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
function createTaskTemplateRequestObject(
|
function createTaskTemplateRequestObject(
|
||||||
values: TaskTemplateFormValues,
|
values: TaskTemplateFormValues,
|
||||||
@@ -88,6 +89,7 @@ function TaskActions({ task }: Props) {
|
|||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const id = useId();
|
const id = useId();
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
|
const navigate = useNavigate();
|
||||||
const credentialGetter = useCredentialGetter();
|
const credentialGetter = useCredentialGetter();
|
||||||
const form = useForm<TaskTemplateFormValues>({
|
const form = useForm<TaskTemplateFormValues>({
|
||||||
resolver: zodResolver(taskTemplateFormSchema),
|
resolver: zodResolver(taskTemplateFormSchema),
|
||||||
@@ -154,6 +156,13 @@ function TaskActions({ task }: Props) {
|
|||||||
Save as Template
|
Save as Template
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
|
<DropdownMenuItem
|
||||||
|
onSelect={() => {
|
||||||
|
navigate(`/create/retry/${task.task_id}`);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Retry Task
|
||||||
|
</DropdownMenuItem>
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
|
|||||||
Reference in New Issue
Block a user