Clean up a little, quick things are quick, slow things show a loader
All checks were successful
Build and deploy / deploy (push) Successful in 1m23s
All checks were successful
Build and deploy / deploy (push) Successful in 1m23s
This commit is contained in:
89
src/app/_components/docker-table.tsx
Normal file
89
src/app/_components/docker-table.tsx
Normal file
@@ -0,0 +1,89 @@
|
||||
"use client";
|
||||
|
||||
import type { dockerRouterType } from "@/server/api/routers/docker";
|
||||
import { api } from "@/trpc/react";
|
||||
import type { JSX } from "react";
|
||||
|
||||
function DockerRow({
|
||||
containerInfo,
|
||||
}: {
|
||||
containerInfo: dockerRouterType['list'][number]
|
||||
}) {
|
||||
const { data: latest, isError, isLoading } = api.docker.latest.useQuery({ id: containerInfo.container.id });
|
||||
const outdated = containerInfo.image.current.hash !== latest?.latest.hash;
|
||||
|
||||
let latestFragment: JSX.Element | null = null;
|
||||
if (isError) {
|
||||
latestFragment = (
|
||||
<>
|
||||
<td>{"Error"}</td>
|
||||
<td>{"Error"}</td>
|
||||
</>
|
||||
)
|
||||
} else if (isLoading) {
|
||||
latestFragment = (
|
||||
<>
|
||||
<td><span className="loading loading-dots loading-lg"></span></td>
|
||||
<td><span className="loading loading-dots loading-lg"></span></td>
|
||||
</>
|
||||
)
|
||||
} else if (latest) {
|
||||
latestFragment = (
|
||||
<>
|
||||
<td>{latest?.latest.tag}</td>
|
||||
<td>{latest?.latest.hash}</td>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<tr key={containerInfo.container.name} className={`${outdated ? "bg-base-200" : null}`}>
|
||||
<td className={`border-l-8 ${isLoading ? "border-l-warning/80" : outdated ? "border-l-error/80" : "border-l-info/80"}`}>{containerInfo.container.name}</td>
|
||||
<td>{containerInfo.image.name}</td>
|
||||
<td>{containerInfo.image.current.tag}</td>
|
||||
<td>{containerInfo.image.current.hash}</td>
|
||||
{latestFragment}
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
export function DockerTable() {
|
||||
const { data: list, isLoading: listLoading } = api.docker.list.useQuery();
|
||||
return (
|
||||
<div className="overflow-x-auto rounded-md border border-base-content/15 bg-base-100">
|
||||
{!listLoading ? (
|
||||
<table className="table-s table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Image</th>
|
||||
<th>Tag</th>
|
||||
<th>Short Hash</th>
|
||||
<th>Tag</th>
|
||||
<th>Short Hash</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{list
|
||||
? list
|
||||
.sort((ca, cb) => {
|
||||
if (ca.container.name && cb.container.name) {
|
||||
if (ca.container.name < cb.container.name) {
|
||||
return -1;
|
||||
}
|
||||
if (ca.container.name > cb.container.name) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
})
|
||||
.map((containerInfo) => <DockerRow key={containerInfo.container.name} containerInfo={containerInfo} />)
|
||||
: null}
|
||||
</tbody>
|
||||
</table>
|
||||
) : (
|
||||
<>Loading data...</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -6,8 +6,8 @@ import { Geist } from "next/font/google";
|
||||
import { TRPCReactProvider } from "@/trpc/react";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Create T3 App",
|
||||
description: "Generated by create-t3-app",
|
||||
title: "DVDash",
|
||||
description: "Docker version dashboard",
|
||||
icons: [{ rel: "icon", url: "/favicon.ico" }],
|
||||
};
|
||||
|
||||
|
||||
@@ -1,61 +1,14 @@
|
||||
import { HydrateClient, api } from "@/trpc/server";
|
||||
import { DockerTable } from "@/app/_components/docker-table";
|
||||
import { api } from "@/trpc/server";
|
||||
|
||||
export default async function Home() {
|
||||
const list = await api.docker.list();
|
||||
|
||||
void api.docker.list.prefetch();
|
||||
|
||||
return (
|
||||
<HydrateClient>
|
||||
<main className="flex min-h-screen flex-col items-center justify-center">
|
||||
<div className="container flex flex-col items-center justify-center gap-12 px-4 py-16">
|
||||
{list ? (
|
||||
<div className="overflow-x-auto rounded-md border border-base-content/15 bg-base-100">
|
||||
<table className="table-s table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Image</th>
|
||||
<th>Tag</th>
|
||||
<th>Short Hash</th>
|
||||
<th>Tag</th>
|
||||
<th>Short Hash</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{list
|
||||
.sort((ca, cb) => {
|
||||
if (ca.containerName && cb.containerName) {
|
||||
if (ca.containerName < cb.containerName) {
|
||||
return -1;
|
||||
}
|
||||
if (ca.containerName > cb.containerName) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
})
|
||||
.map((containerInfo) => {
|
||||
const outdated = containerInfo.current.hash !== containerInfo.latest.hash;
|
||||
return (
|
||||
<tr key={containerInfo.containerName} className={`${outdated ? "bg-base-200" : null}`}>
|
||||
<td className={`border-l-8 ${outdated ? "border-l-error/80" : "border-l-info/80"}`}>{containerInfo.containerName}</td>
|
||||
<td>{containerInfo.imageName}</td>
|
||||
<td>{containerInfo.current.tag}</td>
|
||||
<td>{containerInfo.current.hash}</td>
|
||||
<td>{containerInfo.latest.tag}</td>
|
||||
<td>{containerInfo.latest.hash}</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
) : (
|
||||
"Loading tRPC query..."
|
||||
)}
|
||||
</div>
|
||||
</main>
|
||||
</HydrateClient>
|
||||
<main className="flex min-h-screen flex-col items-center justify-center">
|
||||
<div className="container flex flex-col items-center justify-center gap-12 px-4 py-16">
|
||||
<DockerTable />
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user