🚧 Refactor the UI menu
This commit is contained in:
+78
-4
@@ -6,6 +6,63 @@ import { RolesPage } from "./pages/Roles";
|
||||
import { GroupsPage } from "./pages/Groups";
|
||||
import { BrokerConfigPage } from "./pages/BrokerConfig";
|
||||
|
||||
// Navigation structure per spec section 57. Entries with a `to` route are
|
||||
// implemented; entries without one are planned pages, rendered greyed out
|
||||
// so the full target information architecture stays visible.
|
||||
const NAV_SECTIONS: {
|
||||
title: string;
|
||||
items: { label: string; to?: string; hint?: string }[];
|
||||
}[] = [
|
||||
{
|
||||
title: "Broker",
|
||||
items: [
|
||||
{ label: "Status", hint: "Dashboard / $SYS monitoring (Release 3)" },
|
||||
{ label: "Configuration", to: "/broker" },
|
||||
{ label: "Listeners", to: "/broker#listeners" },
|
||||
{ label: "Bridges", hint: "Bridge management (post-MVP)" },
|
||||
{ label: "Revisions", to: "/broker#revisions" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "MQTT Security",
|
||||
items: [
|
||||
{ label: "Clients", to: "/clients" },
|
||||
{ label: "Groups", to: "/groups" },
|
||||
{ label: "Roles", to: "/roles" },
|
||||
{ label: "ACL Simulator", hint: "ACL simulator (post-MVP)" },
|
||||
{ label: "Authentication", hint: "Auth mechanism configuration (Release 2)" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Certificates",
|
||||
items: [
|
||||
{ label: "Authorities", hint: "PKI (Release 2)" },
|
||||
{ label: "Server Certificates", hint: "PKI (Release 2)" },
|
||||
{ label: "Client Certificates", hint: "PKI (Release 2)" },
|
||||
{ label: "CSRs", hint: "CSR signing (Release 2)" },
|
||||
{ label: "Revocations", hint: "CRL management (Release 2)" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Tools",
|
||||
items: [
|
||||
{ label: "Topic Explorer", hint: "Test console (post-MVP)" },
|
||||
{ label: "Connection Test", hint: "Connectivity tester (post-MVP)" },
|
||||
{ label: "Client Provisioning", hint: "Provisioning wizard (post-MVP)" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Administration",
|
||||
items: [
|
||||
{ label: "Users", hint: "User management page (Release 3)" },
|
||||
{ label: "Roles", hint: "Management roles admin (Release 3)" },
|
||||
{ label: "Audit Log", hint: "Audit viewer (Release 3)" },
|
||||
{ label: "Backup", hint: "Backup/restore (Release 3)" },
|
||||
{ label: "System", hint: "System settings (Release 3)" },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
function Layout({ children }: { children: React.ReactNode }) {
|
||||
const { session, logout } = useAuth();
|
||||
return (
|
||||
@@ -13,10 +70,27 @@ function Layout({ children }: { children: React.ReactNode }) {
|
||||
<aside className="sidebar">
|
||||
<h1>MQTT Management</h1>
|
||||
<nav>
|
||||
<NavLink to="/clients">Clients</NavLink>
|
||||
<NavLink to="/groups">Groups</NavLink>
|
||||
<NavLink to="/roles">Roles & ACLs</NavLink>
|
||||
<NavLink to="/broker">Broker configuration</NavLink>
|
||||
{NAV_SECTIONS.map((section) => (
|
||||
<div key={section.title} className="nav-section">
|
||||
<h2>{section.title}</h2>
|
||||
{section.items.map((item) =>
|
||||
item.to ? (
|
||||
<NavLink key={item.label} to={item.to}>
|
||||
{item.label}
|
||||
</NavLink>
|
||||
) : (
|
||||
<button
|
||||
key={item.label}
|
||||
className="nav-disabled"
|
||||
disabled
|
||||
title={item.hint}
|
||||
>
|
||||
{item.label}
|
||||
</button>
|
||||
),
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</nav>
|
||||
<p style={{ marginTop: "2rem", fontSize: "0.8rem", opacity: 0.7 }}>
|
||||
{session?.username} ({session?.role})
|
||||
|
||||
@@ -113,7 +113,7 @@ export function BrokerConfigPage() {
|
||||
<div className="banner error">{(addListener.error as Error).message}</div>
|
||||
)}
|
||||
|
||||
<h3 style={{ marginTop: "2rem" }}>Listeners</h3>
|
||||
<h3 id="listeners" style={{ marginTop: "2rem" }}>Listeners</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -231,7 +231,7 @@ export function BrokerConfigPage() {
|
||||
<div className="banner error">{(deploy.error as Error).message}</div>
|
||||
)}
|
||||
|
||||
<h3 style={{ marginTop: "2rem" }}>Revisions</h3>
|
||||
<h3 id="revisions" style={{ marginTop: "2rem" }}>Revisions</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
@@ -39,6 +39,40 @@ body {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* --- Grouped navigation (spec section 57) --- */
|
||||
.nav-section {
|
||||
margin-bottom: 0.9rem;
|
||||
}
|
||||
|
||||
.nav-section h2 {
|
||||
font-size: 0.68rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.07em;
|
||||
color: #7b8794;
|
||||
margin: 0.5rem 0 0.25rem;
|
||||
padding-left: 0.6rem;
|
||||
}
|
||||
|
||||
/* Unimplemented pages: greyed out, not clickable, tooltip explains why. */
|
||||
.nav-section button.nav-disabled {
|
||||
display: block;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: #616e7c;
|
||||
padding: 0.45rem 0.6rem;
|
||||
margin: 0.1rem 0;
|
||||
border-radius: 6px;
|
||||
opacity: 0.55;
|
||||
}
|
||||
|
||||
/* Anchor targets inside pages: keep headings clear of the viewport top. */
|
||||
h3[id] {
|
||||
scroll-margin-top: 1rem;
|
||||
}
|
||||
|
||||
.sidebar nav a.active,
|
||||
.sidebar nav a:hover {
|
||||
background: #323f4b;
|
||||
|
||||
Reference in New Issue
Block a user