wip: domains page

This commit is contained in:
Derock 2024-01-24 22:19:07 -05:00
parent 59a66491b1
commit c2b84fbe9f
No known key found for this signature in database
5 changed files with 119 additions and 26 deletions

View file

@ -2,6 +2,7 @@
import { formatDistanceToNowStrict } from "date-fns";
import { ClipboardIcon } from "lucide-react";
import { useEffect, useState } from "react";
import { CgSpinner } from "react-icons/cg";
import { FaGear } from "react-icons/fa6";
import { toast } from "sonner";
@ -17,16 +18,28 @@ import { TableCell, TableRow } from "~/components/ui/table";
import { type RouterOutputs } from "~/trpc/shared";
export function ContainerEntry({
data: { container, previous, task, slot },
data: { container, previous, task },
}: {
data: RouterOutputs["projects"]["services"]["containers"]["latest"][number];
}) {
const mainContainer = container ?? previous[0]?.container;
const isRedeploying = container === undefined;
const isRedeploying =
container === undefined || task.taskState === "starting";
const [uptimeText, setUptimeText] = useState<string | null>(null);
useEffect(() => {
if (!mainContainer) return;
const interval = setInterval(() => {
setUptimeText(
formatDistanceToNowStrict(mainContainer.containerCreatedAt),
);
}, 1000);
return () => clearInterval(interval);
}, [mainContainer]);
return (
<>
<TableRow key={slot}>
<TableRow className="!border-b-0">
<TableCell
className="cursor-pointer font-mono text-sm text-muted-foreground"
onClick={() => {
@ -65,30 +78,17 @@ export function ContainerEntry({
strokeWidth={1.5}
className="py-auto mr-2 inline-block animate-spin stroke-muted-foreground"
/>
Redeploying
{previous[0]?.container?.error && (
<span>
{" "}
(previous container errored with:{" "}
{previous[0]?.container?.error})
</span>
)}
Container Deploying
</span>
) : (
task.taskState ?? task.taskMessage ?? "unknown"
)}
{container?.error && (
<span className="text-red-500">
{" "}
(errored with: {container.error})
<span className="capitalize">
{task.taskState ?? task.taskMessage ?? "unknown"}
</span>
)}
</TableCell>
<TableCell>{uptimeText ?? "N/A"}</TableCell>
<TableCell>{mainContainer?.node ?? "unknown"}</TableCell>
<TableCell>
{formatDistanceToNowStrict(mainContainer?.containerCreatedAt ?? 0)}
</TableCell>
<TableCell>{mainContainer?.cpu ?? "?"}</TableCell>
<TableCell>{mainContainer?.memory ?? "?"}</TableCell>
<TableCell>
@ -110,6 +110,23 @@ export function ContainerEntry({
</DropdownMenu>
</TableCell>
</TableRow>
{container?.error !== undefined ||
previous[0]?.container?.error !== undefined ? (
<TableRow className="hover:bg-inherit">
<TableCell></TableCell>
<TableCell colSpan={8} className="mb-4 text-red-500">
{container?.error
? "Container exited with:"
: "Previous container exited with:"}{" "}
<br />
<pre className="whitespace-pre-wrap font-mono text-xs">
{container?.error ?? previous[0]?.container?.error}
</pre>
<br />
</TableCell>
</TableRow>
) : undefined}
</>
);
}

View file

@ -30,11 +30,11 @@ export default function Containers() {
<TableHeader>
<TableRow>
<TableHead className="w-36">Container ID</TableHead>
<TableHead className="w-full">Status</TableHead>
<TableHead>Node</TableHead>
<TableHead className="w-[80%]">Status</TableHead>
<TableHead>Uptime</TableHead>
<TableHead>CPU Usage</TableHead>
<TableHead>Memory Usage</TableHead>
<TableHead>Node</TableHead>
<TableHead>CPU</TableHead>
<TableHead>Memory</TableHead>
<TableHead>Network (RX/TX)</TableHead>
<TableHead className="text-right">Actions</TableHead>
</TableRow>

View file

@ -0,0 +1,68 @@
"use client";
import { useFieldArray } from "react-hook-form";
import { z } from "zod";
import { Form } from "~/components/ui/form";
import { FormSubmit, SimpleFormField, useForm } from "~/hooks/forms";
const formValidator = z.object({
domains: z.array(
z.object({
domain: z
.string()
.regex(
/(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]/,
{ message: "Invalid domain name" },
),
internalPort: z.number().int().min(1).max(65535),
https: z.boolean(),
forceSSL: z.boolean(),
}),
),
});
export default function DomainsList(
{
// service,
}: {
// service: RouterOutputs["projects"]["services"]["get"];
},
) {
const form = useForm(formValidator, {
defaultValues: {},
});
const { fields, append, prepend, remove, swap, move, insert } = useFieldArray(
{
control: form.control,
name: "domains",
},
);
return (
<Form {...form}>
<form
onSubmit={form.handleSubmit(async (data) => {
console.log(data);
})}
className="grid grid-cols-2 gap-4"
>
<h1 className="col-span-2">Domains</h1>
{fields.map((field, index) => (
<div className="flex gap-4" key={field.id}>
<SimpleFormField
control={form.control}
name={`domains.${index}.domain`}
friendlyName="Domain"
required
className="flex-1"
/>
</div>
))}
<FormSubmit form={form} className="col-span-2" />
</form>
</Form>
);
}

View file

@ -0,0 +1,7 @@
export default function DomainsPage() {
return (
<div>
<Form
</div>
)
}

View file

@ -110,7 +110,8 @@ export async function buildDockerStackFile(
logging: {
driver: "json-file",
options: {
"max-size": service.loggingMaxSize,
"max-size":
service.loggingMaxSize === "-1" ? null : service.loggingMaxSize,
"max-file": service.loggingMaxFiles,
},
},