feat(web): licence banner, settings page and feature gating

This commit is contained in:
2026-07-24 15:25:29 +01:00
parent ee4dff09c9
commit 8626898e5e
8 changed files with 217 additions and 4 deletions
+40
View File
@@ -0,0 +1,40 @@
"use client";
import Link from "next/link";
import { useLicense } from "@/lib/useLicense";
export function LicenseBanner() {
const { license } = useLicense();
if (!license) return null;
if (license.state === "expired") {
const when = license.expires_at ? new Date(license.expires_at).toLocaleDateString() : "recently";
return (
<div className="bg-amber-900/40 px-4 py-2 text-sm text-amber-100">
Your Vantage licence expired on {when}. Your servers and monitors are still running,
but changes are disabled until it is renewed.{" "}
<Link href="/settings/license" className="underline">Add a licence</Link>
</div>
);
}
if (license.state === "invalid") {
return (
<div className="bg-red-900/40 px-4 py-2 text-sm text-red-100">
This instance has no valid licence. Changes are disabled.{" "}
<Link href="/settings/license" className="underline">Add a licence</Link>
</div>
);
}
if (typeof license.days_remaining === "number" && license.days_remaining <= 14) {
return (
<div className="bg-amber-900/25 px-4 py-2 text-sm text-amber-100">
Your licence expires in {license.days_remaining} day
{license.days_remaining === 1 ? "" : "s"}.
</div>
);
}
return null;
}
+13
View File
@@ -75,6 +75,18 @@ function AuditIcon() {
);
}
function LicenceIcon() {
return (
<svg className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M9 12.75 11.25 15 15 9.75M21 12c0 1.268-.63 2.39-1.593 3.068a3.745 3.745 0 0 1-1.043 3.296 3.745 3.745 0 0 1-3.296 1.043A3.745 3.745 0 0 1 12 21c-1.268 0-2.39-.63-3.068-1.593a3.746 3.746 0 0 1-3.296-1.043 3.745 3.745 0 0 1-1.043-3.296A3.745 3.745 0 0 1 3 12c0-1.268.63-2.39 1.593-3.068a3.745 3.745 0 0 1 1.043-3.296 3.746 3.746 0 0 1 3.296-1.043A3.746 3.746 0 0 1 12 3c1.268 0 2.39.63 3.068 1.593a3.746 3.746 0 0 1 3.296 1.043 3.746 3.746 0 0 1 1.043 3.296A3.745 3.745 0 0 1 21 12Z"
/>
</svg>
);
}
function SettingsIcon() {
return (
<svg className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
@@ -129,6 +141,7 @@ const navItems: NavItem[] = [
{ href: "/steps", label: "Steps", icon: <StepsIcon /> },
{ href: "/audit", label: "Audit Log", icon: <AuditIcon /> },
{ href: "/settings/instance", label: "Instance", icon: <InstanceIcon />, adminOnly: true },
{ href: "/settings/license", label: "Licence", icon: <LicenceIcon />, adminOnly: true },
{ href: "/settings", label: "Settings", icon: <SettingsIcon />, adminOnly: true },
];