|
|
|
|
@@ -4,188 +4,101 @@ 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 }, { refetchOnMount: false, refetchOnWindowFocus: false, refetchOnReconnect: false });
|
|
|
|
|
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" />
|
|
|
|
|
</td>
|
|
|
|
|
<td>
|
|
|
|
|
<span className="loading loading-dots loading-lg" />
|
|
|
|
|
</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>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function DockerCard({
|
|
|
|
|
containerInfo,
|
|
|
|
|
}: {
|
|
|
|
|
containerInfo: dockerRouterType["list"][number];
|
|
|
|
|
}) {
|
|
|
|
|
const { data: latest, isError, isLoading } = api.docker.latest.useQuery({ id: containerInfo.container.id }, { refetchOnMount: false, refetchOnWindowFocus: false, refetchOnReconnect: false });
|
|
|
|
|
const outdated = containerInfo.image.current.hash !== latest?.latest.hash;
|
|
|
|
|
const { data: latest, isError, isLoading, error } = api.docker.latest.useQuery({ id: containerInfo.container.id }, { refetchOnMount: false, refetchOnWindowFocus: false, refetchOnReconnect: false });
|
|
|
|
|
|
|
|
|
|
let latestFragment: JSX.Element | null = null;
|
|
|
|
|
if (isError) {
|
|
|
|
|
latestFragment = (
|
|
|
|
|
<>
|
|
|
|
|
<td>{"Error"}</td>
|
|
|
|
|
<td>{"Error"}</td>
|
|
|
|
|
</>
|
|
|
|
|
<div className="flex flex-row flex-wrap *:basis-1/2">
|
|
|
|
|
<dt>Tag</dt>
|
|
|
|
|
<dd>Error: {error.message}</dd>
|
|
|
|
|
|
|
|
|
|
<dt>Short Hash</dt>
|
|
|
|
|
<dd>Error: {error.message}</dd>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
} else if (isLoading) {
|
|
|
|
|
latestFragment = (
|
|
|
|
|
<>
|
|
|
|
|
<td>
|
|
|
|
|
<span className="loading loading-dots loading-lg" />
|
|
|
|
|
</td>
|
|
|
|
|
<td>
|
|
|
|
|
<span className="loading loading-dots loading-lg" />
|
|
|
|
|
</td>
|
|
|
|
|
</>
|
|
|
|
|
<div className="flex flex-row flex-wrap *:basis-1/2">
|
|
|
|
|
<dt>Tag</dt>
|
|
|
|
|
<dd className="loading loading-dots loading-sm" />
|
|
|
|
|
|
|
|
|
|
<dt>Short Hash</dt>
|
|
|
|
|
<dd className="loading loading-dots loading-sm" />
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
} else if (latest) {
|
|
|
|
|
latestFragment = (
|
|
|
|
|
<>
|
|
|
|
|
<td>{latest?.latest.tag}</td>
|
|
|
|
|
<td>{latest?.latest.hash}</td>
|
|
|
|
|
</>
|
|
|
|
|
<div className="flex flex-row flex-wrap *:basis-1/2">
|
|
|
|
|
<dt>Tag</dt>
|
|
|
|
|
<dd>{latest?.latest.tag ?? "Unknown"}</dd>
|
|
|
|
|
|
|
|
|
|
<dt>Short Hash</dt>
|
|
|
|
|
<dd>{latest?.latest.hash ?? "Unknown"}</dd>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const outdated = containerInfo.image.current.hash !== latest?.latest.hash;
|
|
|
|
|
const showWarning = isLoading || (!isError && !isLoading && (!latest?.latest.tag || !latest?.latest.hash));
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div key={containerInfo.container.name} className="card card-border w-96 bg-base-100">
|
|
|
|
|
<div className="card-body">
|
|
|
|
|
<h2 className="card-title">{containerInfo.container.name}</h2>
|
|
|
|
|
<div className="stats shadow">
|
|
|
|
|
<div className="stat">
|
|
|
|
|
<div className="stat-title">Image</div>
|
|
|
|
|
<div className="stat-value">{containerInfo.image.name}</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="stats shadow">
|
|
|
|
|
<div className="stat">
|
|
|
|
|
<div className="stat-title">Tag</div>
|
|
|
|
|
<div className="stat-value">{containerInfo.image.name}</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="stats shadow">
|
|
|
|
|
<div className="stat">
|
|
|
|
|
<div className="stat-title">Short Hash</div>
|
|
|
|
|
<div className="stat-value">{containerInfo.image.name}</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="stats shadow">
|
|
|
|
|
<div className="stat">
|
|
|
|
|
<div className="stat-title">Tag</div>
|
|
|
|
|
<div className="stat-value">{containerInfo.image.name}</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="stats shadow">
|
|
|
|
|
<div className="stat">
|
|
|
|
|
<div className="stat-title">Short Hash</div>
|
|
|
|
|
<div className="stat-value">{containerInfo.image.name}</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div
|
|
|
|
|
key={containerInfo.container.name}
|
|
|
|
|
className={`card card-outline card-compact w-80 border-t-8 bg-base-300 shadow-md ${showWarning ? "border-t-warning/80" : outdated ? "border-t-error/80" : "border-t-info/80"}`}
|
|
|
|
|
>
|
|
|
|
|
<dl className="card-body flex flex-col flex-wrap items-center justify-around text-base">
|
|
|
|
|
<h2 className="text-center text-3xl">{containerInfo.container.name}</h2>
|
|
|
|
|
<p>{containerInfo.image.name}</p>
|
|
|
|
|
<div className="divider divider-primary m-1" />
|
|
|
|
|
<h3 className="text-xl underline decoration-1 underline-offset-4">Current</h3>
|
|
|
|
|
<div className="flex flex-row flex-wrap *:basis-1/2">
|
|
|
|
|
<dt>Tag</dt>
|
|
|
|
|
<dd>{containerInfo.image.current.tag}</dd>
|
|
|
|
|
<dt>Short Hash</dt>
|
|
|
|
|
<dd>{containerInfo.image.current.hash}</dd>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="divider divider-primary m-0" />
|
|
|
|
|
<h3 className="text-xl underline decoration-1 underline-offset-4">Latest</h3>
|
|
|
|
|
{latestFragment}
|
|
|
|
|
</dl>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function DockerTable() {
|
|
|
|
|
const { data: list, isLoading: listLoading } = api.docker.list.useQuery(undefined, { refetchOnMount: false, refetchOnWindowFocus: false, refetchOnReconnect: false });
|
|
|
|
|
const { data: list, isLoading: listLoading, error } = api.docker.list.useQuery(undefined, { refetchOnMount: false, refetchOnWindowFocus: false, refetchOnReconnect: false });
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
{listLoading ? (
|
|
|
|
|
<>Loading data...</>
|
|
|
|
|
<>Loading docker container list...</>
|
|
|
|
|
) : (
|
|
|
|
|
<>
|
|
|
|
|
<div className="flex flex-row flex-wrap">
|
|
|
|
|
{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;
|
|
|
|
|
}
|
|
|
|
|
<div className={"flex flex-row flex-wrap justify-around gap-8"}>
|
|
|
|
|
{list ? (
|
|
|
|
|
list
|
|
|
|
|
.sort((ca, cb) => {
|
|
|
|
|
if (ca.container.name && cb.container.name) {
|
|
|
|
|
if (ca.container.name < cb.container.name) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
})
|
|
|
|
|
.map((containerInfo) => (
|
|
|
|
|
|
|
|
|
|
))
|
|
|
|
|
: null}
|
|
|
|
|
if (ca.container.name > cb.container.name) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
})
|
|
|
|
|
.map((containerInfo) => <DockerCard key={containerInfo.container.name} containerInfo={containerInfo} />)
|
|
|
|
|
) : (
|
|
|
|
|
<>Error loading docker container list: {error?.message}</>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
{/* <div className={"overflow-x-auto rounded-md border border-base-content/15 bg-base-100"}>
|
|
|
|
|
<table className="table-s table-pin-rows table border-separate border-spacing-0">
|
|
|
|
|
<thead>
|
|
|
|
|
<tr className="border-l-8 border-l-base-200">
|
|
|
|
|
<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>
|
|
|
|
|
</div> */}
|
|
|
|
|
</>
|
|
|
|
|
)}
|
|
|
|
|
</>
|
|
|
|
|
|