Redesign task view (#407)

This commit is contained in:
Kerem Yilmaz
2024-06-03 10:56:26 -07:00
committed by GitHub
parent 05dbea8384
commit 1333e89c12
14 changed files with 647 additions and 180 deletions

View File

@@ -1,26 +1,14 @@
import { getClient } from "@/api/AxiosClient";
import { Status, TaskApiResponse } from "@/api/types";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import { keepPreviousData, useQuery } from "@tanstack/react-query";
import { useParams } from "react-router-dom";
import { StatusBadge } from "@/components/StatusBadge";
import { basicTimeFormat } from "@/util/timeFormat";
import { StepArtifactsLayout } from "./StepArtifactsLayout";
import { getRecordingURL, getScreenshotURL } from "./artifactUtils";
import { Skeleton } from "@/components/ui/skeleton";
import { Input } from "@/components/ui/input";
import { ZoomableImage } from "@/components/ZoomableImage";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Separator } from "@/components/ui/separator";
import { Label } from "@/components/ui/label";
import { Skeleton } from "@/components/ui/skeleton";
import { Textarea } from "@/components/ui/textarea";
import { useCredentialGetter } from "@/hooks/useCredentialGetter";
import { cn } from "@/util/utils";
import { keepPreviousData, useQuery } from "@tanstack/react-query";
import { NavLink, Outlet, useParams } from "react-router-dom";
function TaskDetails() {
const { taskId } = useParams();
@@ -28,8 +16,8 @@ function TaskDetails() {
const {
data: task,
isFetching: isTaskFetching,
isError: isTaskError,
isFetching: taskIsFetching,
isError: taskIsError,
error: taskError,
} = useQuery<TaskApiResponse>({
queryKey: ["task", taskId, "details"],
@@ -49,171 +37,89 @@ function TaskDetails() {
placeholderData: keepPreviousData,
});
if (isTaskError) {
if (taskIsError) {
return <div>Error: {taskError?.message}</div>;
}
return (
<div className="flex flex-col gap-8">
<div className="flex items-center">
<Label className="w-32 shrink-0 text-lg">Task ID</Label>
<Input value={taskId} readOnly />
</div>
<div className="flex items-center">
<Label className="w-32 text-lg">Status</Label>
{isTaskFetching ? (
<div className="flex items-center gap-4">
<Input value={taskId} className="w-52" readOnly />
{taskIsFetching ? (
<Skeleton className="w-32 h-8" />
) : task ? (
<StatusBadge status={task?.status} />
) : null}
</div>
{task?.status === Status.Completed ? (
<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>
{task?.status === Status.Completed ? (
<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}
{task?.status === Status.Failed ||
task?.status === Status.Terminated ? (
<div className="flex items-center">
<Label>Failure Reason</Label>
<Textarea
rows={5}
value={JSON.stringify(task.failure_reason)}
readOnly
/>
</div>
) : null}
</div>
<div className="flex justify-center items-center">
<div className="inline-flex border rounded bg-muted p-1">
<NavLink
to="actions"
className={({ isActive }) => {
return cn(
"cursor-pointer px-2 py-1 rounded-md text-muted-foreground",
{
"bg-primary-foreground text-foreground": isActive,
},
);
}}
>
Actions
</NavLink>
<NavLink
to="recording"
className={({ isActive }) => {
return cn(
"cursor-pointer px-2 py-1 rounded-md text-muted-foreground",
{
"bg-primary-foreground text-foreground": isActive,
},
);
}}
>
Recording
</NavLink>
<NavLink
to="parameters"
className={({ isActive }) => {
return cn(
"cursor-pointer px-2 py-1 rounded-md text-muted-foreground",
{
"bg-primary-foreground text-foreground": isActive,
},
);
}}
>
Parameters
</NavLink>
</div>
) : null}
{task?.status === Status.Failed || task?.status === Status.Terminated ? (
<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)}
readOnly
/>
</div>
) : null}
{task ? (
<Card>
<CardHeader className="border-b-2">
<CardTitle className="text-xl">Task Artifacts</CardTitle>
<CardDescription>
Recording and final screenshot of the task
</CardDescription>
</CardHeader>
<CardContent>
<Tabs defaultValue="recording">
<TabsList>
<TabsTrigger value="recording">Recording</TabsTrigger>
<TabsTrigger value="final-screenshot">
Final Screenshot
</TabsTrigger>
</TabsList>
<TabsContent value="recording">
{task.recording_url ? (
<video
width={800}
height={450}
src={getRecordingURL(task)}
controls
/>
) : (
<div>No recording available</div>
)}
</TabsContent>
<TabsContent value="final-screenshot">
{task ? (
<div className="h-[450px] w-[800px] overflow-hidden">
{task.screenshot_url ? (
<ZoomableImage
src={getScreenshotURL(task)}
alt="screenshot"
className="object-cover w-full h-full"
/>
) : (
<p>No screenshot available</p>
)}
</div>
) : null}
</TabsContent>
</Tabs>
</CardContent>
</Card>
) : null}
<Card>
<CardHeader className="border-b-2">
<CardTitle className="text-lg">Steps</CardTitle>
<CardDescription>Task Steps and Step Artifacts</CardDescription>
</CardHeader>
<CardContent className="min-h-96">
<StepArtifactsLayout />
</CardContent>
</Card>
<Card>
<CardHeader className="border-b-2">
<CardTitle className="text-xl">Parameters</CardTitle>
<CardDescription>Task URL and Input Parameters</CardDescription>
</CardHeader>
<CardContent className="py-8">
{task ? (
<div className="flex flex-col gap-8">
<div className="flex items-center">
<Label className="w-40 shrink-0">URL</Label>
<Input value={task.request.url} readOnly />
</div>
<Separator />
<div className="flex items-center">
<Label className="w-40 shrink-0">Created at</Label>
<Input value={basicTimeFormat(task.created_at)} readOnly />
</div>
<Separator />
<div className="flex items-center">
<Label className="w-40 shrink-0">Navigation Goal</Label>
<Textarea
rows={5}
value={task.request.navigation_goal ?? ""}
readOnly
/>
</div>
<Separator />
<div className="flex items-center">
<Label className="w-40 shrink-0">Navigation Payload</Label>
<Textarea
rows={5}
value={
typeof task.request.navigation_payload === "object"
? JSON.stringify(task.request.navigation_payload, null, 2)
: task.request.navigation_payload
}
readOnly
/>
</div>
<Separator />
<div className="flex items-center">
<Label className="w-40 shrink-0">Data Extraction Goal</Label>
<Textarea
rows={5}
value={task.request.data_extraction_goal ?? ""}
readOnly
/>
</div>
<div className="flex items-center">
<Label className="w-40 shrink-0">
Extracted Information Schema
</Label>
<Textarea
rows={5}
value={
typeof task.request.extracted_information_schema ===
"object"
? JSON.stringify(
task.request.extracted_information_schema,
null,
2,
)
: task.request.extracted_information_schema
}
readOnly
/>
</div>
</div>
) : null}
</CardContent>
</Card>
</div>
<Outlet />
</div>
);
}