mirror of
https://github.com/hanzoai/bootnode.git
synced 2026-10-25 02:31:30 +00:00
Names the two halves for what they are. The repo already holds both (12407e9 merged bootnode/bootnode into this history); this makes the frontend directory say so, so the layout reads the way the owner describes the system: backend and frontend separate, one repo. git mv throughout — 187 renames, history preserved. Every path reference follows: hanzo.yml build context and dockerfile, compose.yml, compose.prod.yml, start.sh, LLM.md, infra/k8s/web-deployments.yaml, infra/cloud/deploy.sh, and the Dockerfile's own COPY paths. Image and container names (bootnode-web, the -web tag suffix) are deliberately NOT renamed here: those are a deploy contract the App CR and ingress bind to on port 3001, and breaking them is a separate, staged change. Console builds green after the move; the Go tree builds. Co-authored-by: Hanzo Dev <[email protected]>
195 lines
7.8 KiB
TypeScript
195 lines
7.8 KiB
TypeScript
// The ONE console navigation.
|
|
//
|
|
// Shape and grouping are lux.cloud's: flat labelled groups, text rows, no
|
|
// icons and no expand/collapse. A nested tree hides half the product behind a
|
|
// disclosure triangle, and it made this app's own nav incomplete —
|
|
// /dashboard/settings, /dashboard/assets/{tokens,nfts},
|
|
// /dashboard/infrastructure/{lux,services,observability}, /chains and /agents
|
|
// were all reachable by URL and by nothing else. Every one of them is a row
|
|
// now.
|
|
//
|
|
// This list is the single source: the sidebar renders it, and the command
|
|
// palette indexes it (buildCommandItems). Adding a section = one entry, and it
|
|
// appears in both.
|
|
|
|
export type NavItem = {
|
|
name: string
|
|
href: string
|
|
description?: string
|
|
external?: boolean
|
|
/** Admin-only row — rendered only when the signed-in user holds `admin`. */
|
|
admin?: boolean
|
|
}
|
|
|
|
export type NavGroup = {
|
|
label: string
|
|
items: NavItem[]
|
|
}
|
|
|
|
export const DASHBOARD_NAVIGATION: NavGroup[] = [
|
|
{
|
|
label: "Overview",
|
|
items: [
|
|
{ name: "Overview", href: "/dashboard", description: "Command centre and quick actions" },
|
|
{ name: "Analytics", href: "/dashboard/analytics", description: "Usage, performance and chain telemetry" },
|
|
{ name: "Usage", href: "/dashboard/usage", description: "Compute units and quota consumption" },
|
|
{ name: "Markets", href: "/dashboard/markets", description: "Token markets and pricing" },
|
|
{ name: "Gas", href: "/dashboard/gas", description: "Gas prices across supported chains" },
|
|
],
|
|
},
|
|
{
|
|
label: "Infrastructure",
|
|
items: [
|
|
{ name: "Infrastructure", href: "/dashboard/infrastructure", description: "Everything you run, in one view" },
|
|
{ name: "Nodes", href: "/dashboard/infrastructure/nodes", description: "Deployed nodes and their health" },
|
|
{ name: "Networks", href: "/dashboard/infrastructure/networks", description: "Networks you participate in" },
|
|
{ name: "Clusters", href: "/dashboard/infrastructure/clusters", description: "Node clusters and regions" },
|
|
{ name: "Services", href: "/dashboard/infrastructure/services", description: "Managed services and endpoints" },
|
|
{ name: "Fleet Map", href: "/dashboard/infrastructure/lux", description: "Validator fleet by region" },
|
|
{ name: "Storage", href: "/dashboard/infrastructure/storage", description: "Object storage and buckets" },
|
|
{ name: "Volumes", href: "/dashboard/infrastructure/volumes", description: "Block volumes attached to nodes" },
|
|
],
|
|
},
|
|
{
|
|
label: "Observability",
|
|
items: [
|
|
{ name: "Monitoring", href: "/dashboard/monitoring", description: "Health checks, alerts and incidents" },
|
|
{
|
|
name: "Service Health",
|
|
href: "/dashboard/infrastructure/monitoring",
|
|
description: "Per-service uptime and latency",
|
|
},
|
|
{
|
|
name: "Observability",
|
|
href: "/dashboard/infrastructure/observability",
|
|
description: "Logs, traces and metrics",
|
|
},
|
|
],
|
|
},
|
|
{
|
|
label: "Assets",
|
|
items: [
|
|
{ name: "Assets", href: "/dashboard/assets", description: "Portfolio across every chain" },
|
|
{ name: "Tokens", href: "/dashboard/assets/tokens", description: "Fungible token balances" },
|
|
{ name: "NFTs", href: "/dashboard/assets/nfts", description: "Non-fungible holdings" },
|
|
{ name: "Wallets", href: "/dashboard/wallets", description: "Custody and signing wallets" },
|
|
{ name: "Staking", href: "/dashboard/staking", description: "Delegations and validator rewards" },
|
|
],
|
|
},
|
|
{
|
|
label: "Developer",
|
|
items: [
|
|
{ name: "API Keys", href: "/dashboard/api-keys", description: "Access credentials for the RPC gateway" },
|
|
{ name: "Webhooks", href: "/dashboard/webhooks", description: "Event delivery endpoints" },
|
|
{ name: "Chains", href: "/chains", description: "Every supported chain and its endpoints" },
|
|
{ name: "Agents", href: "/agents", description: "Autonomous agents and their runs" },
|
|
{ name: "Docs", href: "/docs", description: "SDKs, quickstarts and API reference" },
|
|
],
|
|
},
|
|
{
|
|
label: "Organization",
|
|
items: [
|
|
{ name: "Organization", href: "/dashboard/organization", description: "Your organization at a glance" },
|
|
{ name: "Team", href: "/dashboard/organization/team", description: "Members, roles and invitations" },
|
|
{ name: "Org Settings", href: "/dashboard/organization/settings", description: "Organization-wide settings" },
|
|
{ name: "Billing", href: "/dashboard/organization/billing", description: "Plans, invoices, tax and compliance" },
|
|
{ name: "Preferences", href: "/dashboard/settings", description: "Your personal console preferences" },
|
|
{ name: "Admin", href: "/admin", description: "Platform administration", admin: true },
|
|
],
|
|
},
|
|
]
|
|
|
|
/**
|
|
* Which single nav row is current for a given pathname.
|
|
*
|
|
* Two things this has to get right, both of which the obvious
|
|
* `pathname.startsWith(href)` per row gets wrong:
|
|
*
|
|
* 1. TRAILING SLASHES. The image serves clean URLs by materialising a
|
|
* directory index per page (see web/Dockerfile), so the browser's pathname
|
|
* is `/dashboard/`, not `/dashboard`. An equality test against the href
|
|
* never matched and the console rendered with nothing highlighted at all.
|
|
* 2. NESTING. `/dashboard/infrastructure/nodes` also starts with
|
|
* `/dashboard/infrastructure`, so a per-row predicate lights BOTH rows and
|
|
* the reader cannot tell where they are. Only the most specific match —
|
|
* the longest href — is current.
|
|
*
|
|
* Which makes this a selection over the whole nav, not a test per row.
|
|
*/
|
|
export function currentHref(pathname: string, hrefs: string[]): string | null {
|
|
const trim = (p: string) => (p.length > 1 ? p.replace(/\/+$/, "") : p)
|
|
const path = trim(pathname)
|
|
let best: string | null = null
|
|
for (const href of hrefs) {
|
|
const h = trim(href)
|
|
if (path === h || path.startsWith(h + "/")) {
|
|
if (best === null || h.length > trim(best).length) best = href
|
|
}
|
|
}
|
|
return best
|
|
}
|
|
|
|
/** Every href in the nav, in order. */
|
|
export function navHrefs(isAdmin = false): string[] {
|
|
return DASHBOARD_NAVIGATION.flatMap((g) => g.items.filter((i) => !i.admin || isAdmin).map((i) => i.href))
|
|
}
|
|
|
|
export interface DashboardCommandItem {
|
|
id: string
|
|
title: string
|
|
description: string
|
|
href: string
|
|
section: "Navigation" | "Actions"
|
|
keywords: string[]
|
|
}
|
|
|
|
export function buildCommandItems(): DashboardCommandItem[] {
|
|
const items: DashboardCommandItem[] = DASHBOARD_NAVIGATION.flatMap((group) =>
|
|
group.items.map((item) => ({
|
|
id: item.href,
|
|
title: group.label === item.name ? item.name : `${group.label} · ${item.name}`,
|
|
description: item.description ?? "",
|
|
href: item.href,
|
|
section: "Navigation" as const,
|
|
keywords: [group.label.toLowerCase(), item.name.toLowerCase(), item.href],
|
|
}))
|
|
)
|
|
|
|
items.push(
|
|
{
|
|
id: "deploy-node",
|
|
title: "Deploy New Node",
|
|
description: "Open node deploy experience with chain onboarding",
|
|
href: "/dashboard/infrastructure/nodes?deploy=1",
|
|
section: "Actions",
|
|
keywords: ["deploy", "node", "chain", "infrastructure"],
|
|
},
|
|
{
|
|
id: "open-billing",
|
|
title: "Open Billing Workspace",
|
|
description: "Business info, payment methods, invoices, tax and compliance",
|
|
href: "/dashboard/organization/billing",
|
|
section: "Actions",
|
|
keywords: ["billing", "invoice", "tax", "compliance", "payment"],
|
|
},
|
|
{
|
|
id: "new-api-key",
|
|
title: "Create API Key",
|
|
description: "Manage and rotate API credentials",
|
|
href: "/dashboard/api-keys?new=1",
|
|
section: "Actions",
|
|
keywords: ["api", "key", "credential"],
|
|
},
|
|
{
|
|
id: "new-webhook",
|
|
title: "Create Webhook",
|
|
description: "Add webhook destination for chain events",
|
|
href: "/dashboard/webhooks?new=1",
|
|
section: "Actions",
|
|
keywords: ["webhook", "event", "integration"],
|
|
}
|
|
)
|
|
|
|
return items
|
|
}
|