feat: Running tasks and steps UI (#165)

This commit is contained in:
Salih Altun
2024-04-07 21:52:59 +03:00
committed by GitHub
parent 112b44e41a
commit 533ed32d9c
32 changed files with 1523 additions and 225 deletions

View File

@@ -0,0 +1,84 @@
import { client } from "@/api/AxiosClient";
import {
ArtifactApiResponse,
ArtifactType,
StepApiResponse,
} from "@/api/types";
import { Skeleton } from "@/components/ui/skeleton";
import { artifactApiBaseUrl } from "@/util/env";
import { useQuery } from "@tanstack/react-query";
type Props = {
id: string;
};
function LatestScreenshot({ id }: Props) {
const {
data: screenshotUri,
isFetching,
isError,
} = useQuery<string | undefined>({
queryKey: ["task", id, "latestScreenshot"],
queryFn: async () => {
const steps: StepApiResponse[] = await client
.get(`/tasks/${id}/steps`)
.then((response) => response.data);
if (steps.length === 0) {
return;
}
const latestStep = steps[steps.length - 1];
if (!latestStep) {
return;
}
const artifacts: ArtifactApiResponse[] = await client
.get(`/tasks/${id}/steps/${latestStep.step_id}/artifacts`)
.then((response) => response.data);
const actionScreenshotUris = artifacts
?.filter(
(artifact) =>
artifact.artifact_type === ArtifactType.ActionScreenshot,
)
.map((artifact) => artifact.uri);
if (actionScreenshotUris.length > 0) {
return actionScreenshotUris[0];
}
const llmScreenshotUris = artifacts
?.filter(
(artifact) => artifact.artifact_type === ArtifactType.LLMScreenshot,
)
.map((artifact) => artifact.uri);
if (llmScreenshotUris.length > 0) {
return llmScreenshotUris[0];
}
return Promise.reject("No screenshots found");
},
refetchInterval: 2000,
});
if (isFetching) {
return <Skeleton className="w-full h-full" />;
}
if (isError || !screenshotUri || typeof screenshotUri !== "string") {
return null;
}
return (
<img
src={`${artifactApiBaseUrl}/artifact/image?path=${screenshotUri.slice(7)}`}
className="w-full h-full object-contain"
alt="Latest screenshot"
/>
);
}
export { LatestScreenshot };

View File

@@ -11,20 +11,15 @@ import {
CardTitle,
} from "@/components/ui/card";
import { PAGE_SIZE } from "../constants";
import { RunningTaskSkeleton } from "./RunningTaskSkeleton";
import { basicTimeFormat } from "@/util/timeFormat";
import { LatestScreenshot } from "./LatestScreenshot";
function RunningTasks() {
const navigate = useNavigate();
const [searchParams] = useSearchParams();
const page = searchParams.get("page") ? Number(searchParams.get("page")) : 1;
const {
data: tasks,
isPending,
isError,
error,
} = useQuery<Array<TaskApiResponse>>({
const { data: tasks } = useQuery<Array<TaskApiResponse>>({
queryKey: ["tasks", page],
queryFn: async () => {
return client
@@ -40,25 +35,13 @@ function RunningTasks() {
placeholderData: keepPreviousData,
});
if (isPending) {
return <RunningTaskSkeleton />;
}
const runningTasks = tasks?.filter((task) => task.status === Status.Running);
if (isError) {
return <div>Error: {error?.message}</div>;
}
if (!tasks) {
return null;
}
const runningTasks = tasks.filter((task) => task.status === Status.Running);
if (runningTasks.length === 0) {
if (runningTasks?.length === 0) {
return <div>No running tasks</div>;
}
return runningTasks.map((task) => {
return runningTasks?.map((task) => {
return (
<Card
key={task.task_id}
@@ -68,10 +51,17 @@ function RunningTasks() {
}}
>
<CardHeader>
<CardTitle>{task.request.url}</CardTitle>
<CardDescription></CardDescription>
<CardTitle>{task.task_id}</CardTitle>
<CardDescription className="whitespace-nowrap overflow-hidden text-ellipsis">
{task.request.url}
</CardDescription>
</CardHeader>
<CardContent>Goal: {task.request.navigation_goal}</CardContent>
<CardContent>
Latest screenshot:
<div className="w-40 h-40 border-2">
<LatestScreenshot id={task.task_id} />
</div>
</CardContent>
<CardFooter>Created: {basicTimeFormat(task.created_at)}</CardFooter>
</Card>
);