feat(web): patching page with policies, windows and runs
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
"use client";
|
||||
|
||||
import { Suspense } from "react";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import { useAuth } from "@/components/AuthProvider";
|
||||
import { Card, CenteredSpinner } from "@/components/ui";
|
||||
import { PolicyList } from "@/components/patching/PolicyList";
|
||||
import { WindowList } from "@/components/patching/WindowList";
|
||||
import { RunList } from "@/components/patching/RunList";
|
||||
|
||||
const TABS = [
|
||||
{ id: "policies", label: "Policies" },
|
||||
{ id: "windows", label: "Windows" },
|
||||
{ id: "runs", label: "Runs" },
|
||||
] as const;
|
||||
|
||||
type TabId = (typeof TABS)[number]["id"];
|
||||
|
||||
// useSearchParams is only allowed inside a Suspense boundary, as on the
|
||||
// servers page.
|
||||
export default function PatchingPage() {
|
||||
return (
|
||||
<Suspense fallback={<CenteredSpinner label="Loading patching" />}>
|
||||
<PatchingInner />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
|
||||
function PatchingInner() {
|
||||
const router = useRouter();
|
||||
const params = useSearchParams();
|
||||
const { isAdmin } = useAuth();
|
||||
const tab: TabId = (TABS.find((t) => t.id === params.get("tab"))?.id ?? "policies") as TabId;
|
||||
|
||||
return (
|
||||
<div className="p-4 sm:p-6 lg:p-8">
|
||||
<div className="mb-6">
|
||||
<h1 className="text-2xl font-semibold text-text-primary">Patching</h1>
|
||||
<p className="mt-1 max-w-2xl text-sm text-text-secondary">
|
||||
Patch servers inside maintenance windows. Every patch Vantage performs, scheduled or clicked, is recorded as a run with a result for each server.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div role="tablist" aria-label="Patching" className="mb-4 flex gap-1 border-b border-border">
|
||||
{TABS.map((t) => (
|
||||
<button
|
||||
key={t.id}
|
||||
role="tab"
|
||||
id={`patching-tab-${t.id}`}
|
||||
aria-selected={tab === t.id}
|
||||
onClick={() => router.replace(`/patching?tab=${t.id}`)}
|
||||
className={`-mb-px border-b-2 px-4 py-2 text-sm transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-accent ${
|
||||
tab === t.id ? "border-accent text-text-primary" : "border-transparent text-text-secondary hover:text-text-primary"
|
||||
}`}
|
||||
>
|
||||
{t.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<Card padding={false} role="tabpanel" aria-labelledby={`patching-tab-${tab}`}>
|
||||
{tab === "policies" && <PolicyList canEdit={isAdmin} />}
|
||||
{tab === "windows" && <WindowList canEdit={isAdmin} />}
|
||||
{tab === "runs" && <RunList />}
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user