From 8626898e5e700645bfe417bd2d5d5e0ed288d0bf Mon Sep 17 00:00:00 2001 From: mrhid6 Date: Fri, 24 Jul 2026 15:25:29 +0100 Subject: [PATCH] feat(web): licence banner, settings page and feature gating --- web/app/(app)/layout.tsx | 6 +- web/app/(app)/servers/[id]/page.tsx | 19 ++++- web/app/(app)/settings/license/page.tsx | 95 +++++++++++++++++++++++++ web/components/LicenseBanner.tsx | 40 +++++++++++ web/components/Sidebar.tsx | 13 ++++ web/lib/api.ts | 25 +++++++ web/lib/useLicense.ts | 21 ++++++ web/tsconfig.tsbuildinfo | 2 +- 8 files changed, 217 insertions(+), 4 deletions(-) create mode 100644 web/app/(app)/settings/license/page.tsx create mode 100644 web/components/LicenseBanner.tsx create mode 100644 web/lib/useLicense.ts diff --git a/web/app/(app)/layout.tsx b/web/app/(app)/layout.tsx index f03b1bc..5716a50 100644 --- a/web/app/(app)/layout.tsx +++ b/web/app/(app)/layout.tsx @@ -1,4 +1,5 @@ import { AuthProvider } from "@/components/AuthProvider"; +import { LicenseBanner } from "@/components/LicenseBanner"; import { Sidebar } from "@/components/Sidebar"; export default function AppLayout({ @@ -10,7 +11,10 @@ export default function AppLayout({
-
{children}
+
+ + {children} +
); diff --git a/web/app/(app)/servers/[id]/page.tsx b/web/app/(app)/servers/[id]/page.tsx index a6ec005..d85707e 100644 --- a/web/app/(app)/servers/[id]/page.tsx +++ b/web/app/(app)/servers/[id]/page.tsx @@ -7,6 +7,7 @@ import Link from "next/link"; import { api, ServerStatus, GenerateKeyOptions, PackageUpdate, Inventory } from "@/lib/api"; import { Badge, Button, Card, CardHeader, CardTitle } from "@/components/ui"; import { Table, Thead, Tbody, Tr, Th, Td } from "@/components/ui"; +import { useLicense } from "@/lib/useLicense"; function statusVariant(status: ServerStatus) { switch (status) { @@ -307,6 +308,8 @@ export default function ServerDetailPage() { const [updateSuccess, setUpdateSuccess] = useState(false); const [showUpdatesModal, setShowUpdatesModal] = useState(false); const [applySuccess, setApplySuccess] = useState(false); + const { hasFeature } = useLicense(); + const consoleAllowed = hasFeature("console"); const { data: server, @@ -396,9 +399,21 @@ export default function ServerDetailPage() {

{server.ip_address}

+ {/* Rendered disabled rather than hidden when the licence does not + include the console: a customer cannot buy what they cannot see, + and a feature that vanishes reads as a bug. */} {server.console_protocols?.map((p) => ( - - +
+ + +
+

Usage

+ +
+ +
+

Add or replace a licence

+