feat(web): auto fresh every 5 seconds for workflow display

This commit is contained in:
BennyKok 2024-01-06 01:53:21 +08:00
parent 825c8a63fb
commit 3c4bce630e
6 changed files with 81 additions and 10 deletions

View File

@ -1,4 +1,5 @@
import { LoadingWrapper } from "@/components/LoadingWrapper"; import { LoadingWrapper } from "@/components/LoadingWrapper";
import { RouteRefresher } from "@/components/RouteRefresher";
import { RunsTable } from "@/components/RunsTable"; import { RunsTable } from "@/components/RunsTable";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
@ -13,8 +14,11 @@ export default async function Page({
return ( return (
<Card className="w-full h-fit min-w-0"> <Card className="w-full h-fit min-w-0">
<CardHeader> <CardHeader className="relative">
<CardTitle>Run</CardTitle> <CardTitle>Run</CardTitle>
<div className="absolute right-6 top-6">
<RouteRefresher interval={5000} />
</div>
</CardHeader> </CardHeader>
<CardContent> <CardContent>

View File

@ -54,7 +54,7 @@ export function LiveStatus({
? `${data.json.event} - ${data.json.data.node}` ? `${data.json.event} - ${data.json.data.node}`
: "-"} : "-"}
</TableCell> </TableCell>
<TableCell className="text-right"> <TableCell className="truncate text-right">
<StatusBadge status={status} /> <StatusBadge status={status} />
</TableCell> </TableCell>
</> </>

View File

@ -12,6 +12,22 @@ export function PaginationControl(props: {
totalPage: number; totalPage: number;
currentPage: number; currentPage: number;
}) { }) {
let startPage = Math.max(props.currentPage - 2, 1);
let endPage = Math.min(startPage + 3, props.totalPage);
if (props.currentPage <= 2) {
endPage = Math.min(4, props.totalPage);
}
if (props.currentPage > props.totalPage - 2) {
startPage = Math.max(props.totalPage - 3, 1);
}
const pageNumbers = Array.from(
{ length: endPage - startPage + 1 },
(_, i) => startPage + i
);
return ( return (
<Pagination> <Pagination>
<PaginationContent> <PaginationContent>
@ -22,9 +38,15 @@ export function PaginationControl(props: {
: `?page=${props.currentPage}` : `?page=${props.currentPage}`
} }
/> />
<PaginationLink href="#" isActive> {pageNumbers.map((page) => (
{props.currentPage} <PaginationLink
key={page}
href={`?page=${page}`}
isActive={props.currentPage === page}
>
{page}
</PaginationLink> </PaginationLink>
))}
<PaginationItem> <PaginationItem>
<PaginationEllipsis /> <PaginationEllipsis />
</PaginationItem> </PaginationItem>

View File

@ -0,0 +1,41 @@
"use client";
import { LoadingIcon } from "@/components/LoadingIcon";
import { useRouter } from "next/navigation";
import { useEffect, useTransition } from "react";
export function RouteRefresher(props: { interval: number }) {
const [isPending, startTransition] = useTransition();
const router = useRouter();
useEffect(() => {
let timeout: NodeJS.Timeout;
const refresh = () => {
console.log("refreshing");
startTransition(() => {
router.refresh();
});
timeout = setTimeout(refresh, props.interval);
};
const handleVisibilityChange = () => {
if (document.hidden) {
clearTimeout(timeout);
} else {
refresh();
}
};
window.addEventListener("visibilitychange", handleVisibilityChange);
refresh();
return () => {
clearTimeout(timeout);
window.removeEventListener("visibilitychange", handleVisibilityChange);
};
}, [props.interval, router]);
return <div>{isPending && <LoadingIcon />}</div>;
}

View File

@ -24,8 +24,12 @@ export async function RunDisplay({
<DialogTrigger asChild className="appearance-none hover:cursor-pointer"> <DialogTrigger asChild className="appearance-none hover:cursor-pointer">
<TableRow> <TableRow>
<TableCell>{run.number}</TableCell> <TableCell>{run.number}</TableCell>
<TableCell className="font-medium">{run.machine?.name}</TableCell> <TableCell className="font-medium truncate">
<TableCell>{getRelativeTime(run.created_at)}</TableCell> {run.machine?.name}
</TableCell>
<TableCell className="truncate">
{getRelativeTime(run.created_at)}
</TableCell>
<TableCell>{run.version?.version}</TableCell> <TableCell>{run.version?.version}</TableCell>
<LiveStatus run={run} /> <LiveStatus run={run} />
</TableRow> </TableRow>

View File

@ -15,7 +15,7 @@ import {
} from "@/components/ui/table"; } from "@/components/ui/table";
import { parseAsInteger } from "next-usequerystate"; import { parseAsInteger } from "next-usequerystate";
const itemPerPage = 4; const itemPerPage = 6;
const pageParser = parseAsInteger.withDefault(1); const pageParser = parseAsInteger.withDefault(1);
export async function RunsTable(props: { export async function RunsTable(props: {
@ -33,7 +33,7 @@ export async function RunsTable(props: {
}); });
return ( return (
<div> <div>
<div className="overflow-auto h-[400px] w-full"> <div className="overflow-auto h-fit w-full">
<Table className=""> <Table className="">
{/* <TableCaption>A list of your recent runs.</TableCaption> */} {/* <TableCaption>A list of your recent runs.</TableCaption> */}
<TableHeader className="bg-background top-0 sticky"> <TableHeader className="bg-background top-0 sticky">
@ -42,7 +42,7 @@ export async function RunsTable(props: {
<TableHead className="">Machine</TableHead> <TableHead className="">Machine</TableHead>
<TableHead className="">Time</TableHead> <TableHead className="">Time</TableHead>
<TableHead className="w-[100px]">Version</TableHead> <TableHead className="w-[100px]">Version</TableHead>
<TableHead className="">Live Status</TableHead> <TableHead className="truncate">Live Status</TableHead>
<TableHead className=" text-right">Status</TableHead> <TableHead className=" text-right">Status</TableHead>
</TableRow> </TableRow>
</TableHeader> </TableHeader>