feat(web): auto fresh every 5 seconds for workflow display
This commit is contained in:
parent
825c8a63fb
commit
3c4bce630e
@ -1,4 +1,5 @@
|
||||
import { LoadingWrapper } from "@/components/LoadingWrapper";
|
||||
import { RouteRefresher } from "@/components/RouteRefresher";
|
||||
import { RunsTable } from "@/components/RunsTable";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
|
||||
@ -13,8 +14,11 @@ export default async function Page({
|
||||
|
||||
return (
|
||||
<Card className="w-full h-fit min-w-0">
|
||||
<CardHeader>
|
||||
<CardHeader className="relative">
|
||||
<CardTitle>Run</CardTitle>
|
||||
<div className="absolute right-6 top-6">
|
||||
<RouteRefresher interval={5000} />
|
||||
</div>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent>
|
||||
|
@ -54,7 +54,7 @@ export function LiveStatus({
|
||||
? `${data.json.event} - ${data.json.data.node}`
|
||||
: "-"}
|
||||
</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<TableCell className="truncate text-right">
|
||||
<StatusBadge status={status} />
|
||||
</TableCell>
|
||||
</>
|
||||
|
@ -12,6 +12,22 @@ export function PaginationControl(props: {
|
||||
totalPage: 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 (
|
||||
<Pagination>
|
||||
<PaginationContent>
|
||||
@ -22,9 +38,15 @@ export function PaginationControl(props: {
|
||||
: `?page=${props.currentPage}`
|
||||
}
|
||||
/>
|
||||
<PaginationLink href="#" isActive>
|
||||
{props.currentPage}
|
||||
{pageNumbers.map((page) => (
|
||||
<PaginationLink
|
||||
key={page}
|
||||
href={`?page=${page}`}
|
||||
isActive={props.currentPage === page}
|
||||
>
|
||||
{page}
|
||||
</PaginationLink>
|
||||
))}
|
||||
<PaginationItem>
|
||||
<PaginationEllipsis />
|
||||
</PaginationItem>
|
||||
|
41
web/src/components/RouteRefresher.tsx
Normal file
41
web/src/components/RouteRefresher.tsx
Normal 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>;
|
||||
}
|
@ -24,8 +24,12 @@ export async function RunDisplay({
|
||||
<DialogTrigger asChild className="appearance-none hover:cursor-pointer">
|
||||
<TableRow>
|
||||
<TableCell>{run.number}</TableCell>
|
||||
<TableCell className="font-medium">{run.machine?.name}</TableCell>
|
||||
<TableCell>{getRelativeTime(run.created_at)}</TableCell>
|
||||
<TableCell className="font-medium truncate">
|
||||
{run.machine?.name}
|
||||
</TableCell>
|
||||
<TableCell className="truncate">
|
||||
{getRelativeTime(run.created_at)}
|
||||
</TableCell>
|
||||
<TableCell>{run.version?.version}</TableCell>
|
||||
<LiveStatus run={run} />
|
||||
</TableRow>
|
||||
|
@ -15,7 +15,7 @@ import {
|
||||
} from "@/components/ui/table";
|
||||
import { parseAsInteger } from "next-usequerystate";
|
||||
|
||||
const itemPerPage = 4;
|
||||
const itemPerPage = 6;
|
||||
const pageParser = parseAsInteger.withDefault(1);
|
||||
|
||||
export async function RunsTable(props: {
|
||||
@ -33,7 +33,7 @@ export async function RunsTable(props: {
|
||||
});
|
||||
return (
|
||||
<div>
|
||||
<div className="overflow-auto h-[400px] w-full">
|
||||
<div className="overflow-auto h-fit w-full">
|
||||
<Table className="">
|
||||
{/* <TableCaption>A list of your recent runs.</TableCaption> */}
|
||||
<TableHeader className="bg-background top-0 sticky">
|
||||
@ -42,7 +42,7 @@ export async function RunsTable(props: {
|
||||
<TableHead className="">Machine</TableHead>
|
||||
<TableHead className="">Time</TableHead>
|
||||
<TableHead className="w-[100px]">Version</TableHead>
|
||||
<TableHead className="">Live Status</TableHead>
|
||||
<TableHead className="truncate">Live Status</TableHead>
|
||||
<TableHead className=" text-right">Status</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
|
Loading…
x
Reference in New Issue
Block a user