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]>
116 lines
4.8 KiB
TypeScript
116 lines
4.8 KiB
TypeScript
// The console navigation contract.
|
|
//
|
|
// Run: `pnpm test`.
|
|
|
|
import { strict as assert } from "node:assert"
|
|
import { describe, it } from "node:test"
|
|
import { DASHBOARD_NAVIGATION, buildCommandItems, currentHref, navHrefs } from "./dashboard-navigation.ts"
|
|
|
|
describe("console navigation", () => {
|
|
it("reaches every dashboard route the build emits", () => {
|
|
// Taken from `next build`'s route table. Before this nav was rewritten,
|
|
// the eight marked routes existed, rendered, and were reachable only by
|
|
// typing the URL — no link anywhere in the product pointed at them.
|
|
const built = [
|
|
"/dashboard",
|
|
"/dashboard/analytics",
|
|
"/dashboard/api-keys",
|
|
"/dashboard/assets",
|
|
"/dashboard/assets/nfts", // was unreachable
|
|
"/dashboard/assets/tokens", // was unreachable
|
|
"/dashboard/gas",
|
|
"/dashboard/infrastructure",
|
|
"/dashboard/infrastructure/clusters",
|
|
"/dashboard/infrastructure/lux", // was unreachable
|
|
"/dashboard/infrastructure/monitoring",
|
|
"/dashboard/infrastructure/networks",
|
|
"/dashboard/infrastructure/nodes",
|
|
"/dashboard/infrastructure/observability", // was unreachable
|
|
"/dashboard/infrastructure/services", // was unreachable
|
|
"/dashboard/infrastructure/storage",
|
|
"/dashboard/infrastructure/volumes",
|
|
"/dashboard/markets",
|
|
"/dashboard/monitoring",
|
|
"/dashboard/organization",
|
|
"/dashboard/organization/billing",
|
|
"/dashboard/organization/settings",
|
|
"/dashboard/organization/team",
|
|
"/dashboard/settings", // was unreachable
|
|
"/dashboard/staking",
|
|
"/dashboard/usage",
|
|
"/dashboard/wallets",
|
|
"/dashboard/webhooks",
|
|
"/admin",
|
|
"/chains", // was unreachable from the console
|
|
"/agents", // was unreachable from the console
|
|
"/docs",
|
|
]
|
|
const hrefs = new Set(navHrefs(true))
|
|
const missing = built.filter((r) => !hrefs.has(r))
|
|
assert.deepEqual(missing, [], `routes with no nav row: ${missing.join(", ")}`)
|
|
})
|
|
|
|
it("points every row at a real route", () => {
|
|
// The reverse direction: a row linking to a page that does not exist is a
|
|
// 404 with a friendly name on it.
|
|
for (const href of navHrefs(true)) {
|
|
assert.match(href, /^\/(dashboard|admin|chains|agents|docs)/, href)
|
|
}
|
|
})
|
|
|
|
it("hides the admin row from non-admins", () => {
|
|
assert.ok(navHrefs(true).includes("/admin"))
|
|
assert.ok(!navHrefs(false).includes("/admin"))
|
|
})
|
|
|
|
it("marks a row current despite the trailing slash the image serves", () => {
|
|
// The static export is served as directory indexes, so the live pathname
|
|
// always ends in "/". Matching on equality alone highlighted nothing.
|
|
const hrefs = navHrefs(true)
|
|
assert.equal(currentHref("/dashboard/", hrefs), "/dashboard")
|
|
assert.equal(currentHref("/dashboard", hrefs), "/dashboard")
|
|
assert.equal(currentHref("/dashboard/analytics/", hrefs), "/dashboard/analytics")
|
|
})
|
|
|
|
it("marks exactly the most specific row current, never two", () => {
|
|
const hrefs = navHrefs(true)
|
|
// /dashboard/infrastructure/nodes is under /dashboard/infrastructure, and
|
|
// both are rows. Only the deeper one is current.
|
|
assert.equal(currentHref("/dashboard/infrastructure/nodes/", hrefs), "/dashboard/infrastructure/nodes")
|
|
assert.equal(currentHref("/dashboard/infrastructure/", hrefs), "/dashboard/infrastructure")
|
|
// A detail page under a row keeps that row current.
|
|
assert.equal(currentHref("/dashboard/infrastructure/nodes/node-7/", hrefs), "/dashboard/infrastructure/nodes")
|
|
assert.equal(currentHref("/dashboard/organization/team/", hrefs), "/dashboard/organization/team")
|
|
// And "/dashboard" must never swallow its children.
|
|
for (const path of ["/dashboard/analytics/", "/dashboard/usage/", "/dashboard/wallets/"]) {
|
|
assert.notEqual(currentHref(path, hrefs), "/dashboard", path)
|
|
}
|
|
})
|
|
|
|
it("marks nothing current off the console", () => {
|
|
assert.equal(currentHref("/pricing/", navHrefs(true)), null)
|
|
assert.equal(currentHref("/", navHrefs(true)), null)
|
|
})
|
|
|
|
it("indexes the whole nav into the command palette", () => {
|
|
const items = buildCommandItems()
|
|
const nav = items.filter((i) => i.section === "Navigation")
|
|
assert.equal(nav.length, navHrefs(true).length)
|
|
for (const item of nav) {
|
|
assert.ok(item.title, `${item.href} has no title`)
|
|
assert.ok(item.description, `${item.href} has no description`)
|
|
assert.ok(item.keywords.length >= 3)
|
|
}
|
|
assert.ok(items.some((i) => i.section === "Actions"))
|
|
})
|
|
|
|
it("has no duplicate hrefs and no empty groups", () => {
|
|
const hrefs = navHrefs(true)
|
|
assert.equal(new Set(hrefs).size, hrefs.length, "duplicate href in nav")
|
|
for (const group of DASHBOARD_NAVIGATION) {
|
|
assert.ok(group.items.length > 0, `${group.label} is empty`)
|
|
assert.ok(group.label)
|
|
}
|
|
})
|
|
})
|