Tasks page implementation (#120)

This commit is contained in:
Salih Altun
2024-04-01 21:34:52 +03:00
committed by GitHub
parent 14ea1e2417
commit f175545399
55 changed files with 5040 additions and 41 deletions

View File

@@ -0,0 +1,151 @@
import { client } from "@/api/AxiosClient";
import { TaskApiResponse } from "@/api/types";
import { keepPreviousData, useQuery } from "@tanstack/react-query";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import {
Pagination,
PaginationContent,
PaginationItem,
PaginationLink,
PaginationNext,
PaginationPrevious,
} from "@/components/ui/pagination";
import { useNavigate, useSearchParams } from "react-router-dom";
import { TaskListSkeleton } from "./TaskListSkeleton";
import { RunningTasks } from "../running/RunningTasks";
import { cn } from "@/util/utils";
import { PAGE_SIZE } from "../constants";
import { TaskStatusBadge } from "@/components/TaskStatusBadge";
import { basicTimeFormat } from "@/util/timeFormat";
function TaskList() {
const navigate = useNavigate();
const [searchParams, setSearchParams] = useSearchParams();
const page = searchParams.get("page") ? Number(searchParams.get("page")) : 1;
const {
data: tasks,
isPending,
isError,
error,
} = useQuery<Array<TaskApiResponse>>({
queryKey: ["tasks", page],
queryFn: async () => {
return client
.get("/tasks", {
params: {
page,
page_size: PAGE_SIZE,
},
})
.then((response) => response.data);
},
refetchInterval: 3000,
placeholderData: keepPreviousData,
});
if (isPending) {
return <TaskListSkeleton />;
}
if (isError) {
return <div>Error: {error?.message}</div>;
}
if (!tasks) {
return null;
}
const resolvedTasks = tasks.filter(
(task) =>
task.status === "completed" ||
task.status === "failed" ||
task.status === "terminated",
);
return (
<div className="flex flex-col gap-4">
<h1 className="text-2xl py-2 border-b-2">Running Tasks</h1>
<div className="grid grid-cols-4 gap-4">
<RunningTasks />
</div>
<h1 className="text-2xl py-2 border-b-2">Task History</h1>
<Table>
<TableHeader>
<TableRow>
<TableHead className="w-1/3">URL</TableHead>
<TableHead className="w-1/3">Status</TableHead>
<TableHead className="w-1/3">Created At</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{tasks.length === 0 ? (
<TableRow>
<TableCell colSpan={3}>No tasks found</TableCell>
</TableRow>
) : (
resolvedTasks.map((task) => {
return (
<TableRow
key={task.task_id}
className="cursor-pointer w-4"
onClick={() => {
navigate(task.task_id);
}}
>
<TableCell className="w-1/3">{task.request.url}</TableCell>
<TableCell className="w-1/3">
<TaskStatusBadge status={task.status} />
</TableCell>
<TableCell className="w-1/3">
{basicTimeFormat(task.created_at)}
</TableCell>
</TableRow>
);
})
)}
</TableBody>
</Table>
<Pagination>
<PaginationContent>
<PaginationItem>
<PaginationPrevious
href="#"
className={cn({ "cursor-not-allowed": page === 1 })}
onClick={() => {
if (page === 1) {
return;
}
const params = new URLSearchParams();
params.set("page", String(Math.max(1, page - 1)));
setSearchParams(params);
}}
/>
</PaginationItem>
<PaginationItem>
<PaginationLink href="#">{page}</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationNext
href="#"
onClick={() => {
const params = new URLSearchParams();
params.set("page", String(page + 1));
setSearchParams(params);
}}
/>
</PaginationItem>
</PaginationContent>
</Pagination>
</div>
);
}
export { TaskList };

View File

@@ -0,0 +1,46 @@
import { Skeleton } from "@/components/ui/skeleton";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
const pageSizeArray = new Array(15).fill(null); // doesn't matter the value
function TaskListSkeleton() {
return (
<div className="flex flex-col gap-2">
<Table>
<TableHeader>
<TableRow>
<TableHead className="w-1/3">URL</TableHead>
<TableHead className="w-1/3">Status</TableHead>
<TableHead className="w-1/3">Created At</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{pageSizeArray.map((_, index) => {
return (
<TableRow key={index}>
<TableCell className="w-1/3">
<Skeleton className="w-full h-full" />
</TableCell>
<TableCell className="w-1/3">
<Skeleton className="w-full h-full" />
</TableCell>
<TableCell className="w-1/3">
<Skeleton className="w-full h-full" />
</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
</div>
);
}
export { TaskListSkeleton };