diff --git a/src/app/[locale]/admin/layout.tsx b/src/app/[locale]/admin/layout.tsx new file mode 100644 index 0000000..3681a9f --- /dev/null +++ b/src/app/[locale]/admin/layout.tsx @@ -0,0 +1,44 @@ +import { redirect } from "next/navigation"; + +import { getCurrentUser } from "@/lib/auth/session"; + +export const dynamic = "force-dynamic"; + +export default async function AdminLayout({ + children, +}: { + children: React.ReactNode; +}) { + const user = await getCurrentUser(); + if (!user || !user.is_admin) { + redirect("/dashboard"); + } + return ( +
+ {nodes.length} node{nodes.length !== 1 ? "s" : ""} registered +
+{total} total jobs
+| Node | +Status | +Slots | +Heartbeat | +Active Job | +Tags | +Actions | +
|---|---|---|---|---|---|---|
|
+ {node.name}
+ {node.id.slice(0, 8)}…
+ |
+ + + {node.status} + + | ++ {node.slots_used} / {node.slots_total} + | ++ {heartbeatAge(node.last_heartbeat)} + | ++ {node.active_job_id ? node.active_job_id.slice(0, 12) + "…" : "—"} + | +
+
+ {(node.tags ?? []).map((t) => (
+
+ {t}
+
+ ))}
+
+ |
+
+
+
+
+
+ |
+
| Job ID | +Project | +Step | +Progress | +Quality | +Node | +Created | +Actions | +
|---|---|---|---|---|---|---|---|
| + {job.id.slice(0, 12)}… + | ++ {job.saved_project_id.slice(0, 12)}… + | ++ + {job.step} + + | +
+
+
+ {job.error_message && (
+
+
+
+
+ {job.progress}%
+
+ + {job.error_message} + + )} + |
+ + {job.quality} / {job.resolution} + | ++ {job.node_id ? job.node_id.slice(0, 8) + "…" : "—"} + | ++ {relativeTime(job.created_at)} + | +
+
+ {canRetry && (
+
+ )}
+ {canCancel && (
+
+ )}
+
+ |
+