Repository navigation
🌱 refactor(nav): move sidebar navigation from page-map.ts into per-project nav.yaml data files - #7096
Conversation
…yaml data files
page-map.ts hard-coded ten per-project NAV_STRUCTURE_* literals (663 LOC).
Each project's sidebar now lives in a nav.yaml next to the content it
describes, and page-map.ts loads and validates it at build time.
- docs/content/nav.yaml (KubeStellar) and docs/content/<project>/nav.yaml
for a2a, kubeflex, multi-plugin, kubestellar-mcp and console, generated
verbatim from the former literals (same {title, items} schema).
- docs/content/{contributing,community,news}/nav.yaml for the three
cross-project sections, appended to every project's nav in that order.
- PROJECTS[projectId].navPath (ProjectConfig) points at the project's nav,
matching the contentPath/basePath pattern from #7037, so a new ProjectId
fails to compile until it supplies a nav.
- src/lib/nav.ts: schema, validator and loader (nextra-free so scripts can
reuse it). A missing or malformed nav.yaml throws NavFileError naming the
file, section and item — a build error instead of an undefined spread.
- GENERAL_SECTIONS / isGeneralSectionFile replace the four hand-repeated
startsWith('contributing/') || ... triples in page-map.ts. Top-level
sections are anchored under /docs by title, derived from the loaded
general navs rather than a hard-coded ['Contributing','Community','News'].
- js-yaml moves from devDependencies to dependencies: page-map runs in the
search API route at request time.
buildPageMap() output for all six projects is byte-identical before and
after (verified by snapshotting the full pageMap/routeMap/filePaths).
Tests: src/__tests__/nav.test.ts covers every rejection path of the
loader (100% lines, 97% branches) and asserts every real nav entry points
at an existing page; versions.shape-invariants pins navPath ==
<contentPath>/nav.yaml and the file existing; the source drift-guard now
pins the single GENERAL_SECTIONS definition instead of the literal triples.
Fixes #7080
Hive-Run: #7080
Hive-Plan: architect/page-map-nav-data-files
Hive-Spec: kubestellar-docs-nav#7080
Signed-off-by: Andrew Anderson <andy@clubanderson.com>
…-parsing page-map.ts The link checker extracted NAV_STRUCTURE_* blocks from page-map.ts source with a regex and mapped them through a hand-maintained PROJECT_FOR_NAV table. That table silently missed A2A (the `[A-Z_]+` name pattern cannot match `A2A`) and never included the contributing/community/news navs, so their nav-slug routes were absent from the route set. Now navSourcesFor(PROJECTS, GENERAL_SECTIONS) lists every nav.yaml the site loads, parseNavStructure() validates it with the same src/lib/nav loader the build uses, and navAliasEntries() applies buildPageMap's title->slug rule. No parallel table to keep in sync. Verified against main: the old route set is a strict subset of the new one (0 routes lost; 90 added, all from a2a and the three shared navs). `npm run check-links` still reports 0 broken links. Hive-Run: #7080 Hive-Plan: architect/page-map-nav-data-files Hive-Spec: kubestellar-docs-nav#7080 Signed-off-by: Andrew Anderson <andy@clubanderson.com>
CONTRIBUTING.md and the docs-structure page told authors to edit NAV_STRUCTURE in src/app/docs/page-map.ts. Update every reference, example and workflow to the nav.yaml files and their schema. Hive-Run: #7080 Hive-Plan: architect/page-map-nav-data-files Hive-Spec: kubestellar-docs-nav#7080 Signed-off-by: Andrew Anderson <andy@clubanderson.com>
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
✅ Deploy Preview for kubestellar-docs ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
There was a problem hiding this comment.
Copilot review overview
🔵 Needs a closer look
Unresolved moderate issues remain in navigation alias generation, CI path coverage, and filesystem error handling.
Review effort: Lite
Findings: None
What changed in this PR
Refactors sidebar navigation from TypeScript literals into validated per-project nav.yaml files.
Changes:
- Adds YAML parsing, validation, and project
navPathconfiguration. - Updates page-map generation and internal-link checking.
- Adds navigation data, tests, dependency updates, and documentation.
| File | Summary |
|---|---|
src/lib/nav.ts |
Adds navigation schema, validation, and loading; filesystem errors should be wrapped as NavFileError. |
src/config/versions/types.ts |
Adds required navPath configuration. |
src/config/versions/lookup.ts |
Defines project navigation paths. |
src/app/docs/page-map.ts |
Builds page and route maps from YAML navigation. |
src/__tests__/versions.shape-invariants.test.ts |
Tests navigation path invariants. |
src/__tests__/page-map-project-arms.test.ts |
Updates project navigation coverage. |
src/__tests__/page-map-general-section-arms.test.ts |
Tests shared navigation sections. |
src/__tests__/page-map-defensive-arms-drift.test.ts |
Guards against navigation implementation drift. |
src/__tests__/nav.test.ts |
Tests parsing, validation, loading, and real navigation files. |
src/__tests__/check-internal-links-helpers.test.ts |
Tests YAML-based link helper behavior. |
scripts/check-internal-links.ts |
Reads navigation YAML sources for link checking. |
scripts/check-internal-links-helpers.ts |
Generates navigation aliases; unresolved issues affect nested folder paths, section context, and CI path filters. |
scripts/check-internal-links-helpers.test.ts |
Tests navigation alias generation. |
package.json |
Promotes js-yaml to a runtime dependency. |
package-lock.json |
Updates dependency lock data. |
docs/content/news/nav.yaml |
Defines News navigation. |
docs/content/nav.yaml |
Defines KubeStellar navigation. |
docs/content/multi-plugin/nav.yaml |
Defines Multi-plugin navigation. |
docs/content/kubestellar-mcp/nav.yaml |
Defines KubeStellar MCP navigation. |
docs/content/kubeflex/nav.yaml |
Defines KubeFlex navigation. |
docs/content/contributing/nav.yaml |
Defines Contributing navigation. |
docs/content/contributing/documentation/docs-structure-inc.md |
Documents the YAML navigation structure. |
docs/content/console/nav.yaml |
Defines Console navigation. |
docs/content/community/nav.yaml |
Defines Community navigation. |
docs/content/a2a/nav.yaml |
Defines A2A navigation. |
CONTRIBUTING.md |
Documents navigation authoring workflows. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
📖 Preview LinksThe following documentation pages were changed in this PR:
|
- loadNavFile now wraps readFileSync failures (EISDIR, EACCES, ...) in NavFileError naming the file, matching the missing-file and YAML-parse branches; test added. - check-internal-links workflow path filters now include scripts/check-internal-links-helpers.ts, src/lib/nav.ts and src/config/versions/** (the old src/config/versions.ts path no longer exists after the versions/ split) so nav/link-check changes trigger it. Addresses Copilot review summary on #7096. Signed-off-by: Andrew Anderson <andy@clubanderson.com>
|
Pushed d50296b for the two concrete items in the Copilot review summary:
On alias generation:
|
|
@clubanderson: The following test failed, say
DetailsInstructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here. |
|
Thank you for your contribution! Your PR has been merged. Check out what's new:
Stay connected: Slack #kubestellar-dev | Multi-Cluster Survey |
…7204) buildPageMap()/getNavStructure() (src/app/docs/page-map.ts) load and parse every project's sidebar nav.yaml at request time from SlugLayout (every /docs/<project>/* page render) and from /api/search, not just at build time, since the nav.yaml data-file refactor (#7096). A missing or malformed nav.yaml throws NavFileError there uncaught: page renders hit only the client-side global-error.tsx boundary (console.error in the visitor's browser), producing no server log and no docs_api_requests_total sample, since that metric is wired only into /api/* route handlers. Meanwhile /api/healthz kept reporting 200 the whole time, because it only checked that docs/content exists and is non-empty -- the content directory itself is untouched by a bad nav.yaml. Extend the readiness check to also call loadNavFile() (src/lib/nav.ts) for every project's navPath and the shared contributing/community/news navs, returning 503 naming the offending file on failure. This gives an orchestrator a way to detect and route around an instance with a broken nav.yaml before it serves a broken sidebar/search to users, instead of only finding out from a browser console log. Cross-references the dependency in runbooks/deploy-rollback.md. Signed-off-by: operations <operations@hive.kubestellar.io> Co-authored-by: operations <operations@hive.kubestellar.io>
📌 Fixes
Fixes #7080
📝 Summary of Changes
src/app/docs/page-map.tshard-coded ten per-projectNAV_STRUCTURE_*literals (663 LOC). Sidebar navigation is now data: each project's nav lives in anav.yamlnext to the content it describes, andpage-map.ts(251 LOC) loads and validates it at build time.docs/content/nav.yamlPROJECTS.kubestellar.navPath)docs/content/{a2a,kubeflex,multi-plugin,kubestellar-mcp,console}/nav.yamlPROJECTS[id].navPath)docs/content/{contributing,community,news}/nav.yamlGENERAL_SECTIONS)The YAML uses the same
{ title, items: [{ Title: path.md }] }schema as the old literals (and mkdocsnav:), generated verbatim from them.buildPageMap()output for all six projects is byte-identical before and after — verified by snapshotting the fullpageMap/routeMap/filePathsonmainand on this branch andcmp-ing the JSON.Changes Made
nav.yamlfiles underdocs/content/, each with a header comment describing the schema and path base.PROJECTS[projectId].navPath(ProjectConfig) — mandatory field matching thecontentPath/basePathpattern from [architect] page-map.ts has 3 parallel switch(projectId) shadows of PROJECTS with silent default arms #7037, so a newProjectIdfails to compile until it supplies a nav (issue point 4; the oldNAV_STRUCTURE_BY_PROJECTlookup is gone).src/lib/nav.ts— schema types,validateNavSections/parseNavYaml/loadNavFile. A missing or malformed nav throwsNavFileErrornaming the file, section and item (Invalid sidebar nav file docs/content/console/nav.yaml: section[2] "Guides".items[1] "Bad": value must be a path string or a list of items) — a build error rather than anundefinedspread. Nextra-free soscripts/can reuse it under plaintsx.GENERAL_SECTIONS+isGeneralSectionFilereplace the four hand-repeatedstartsWith('contributing/') || startsWith('community/') || startsWith('news/')triples and the['Contributing','Community','News']title list (issue point 3). Top-level anchoring under/docs/<slug>is still by title, but the title set is derived from the loaded general navs.scripts/check-internal-links*.ts—navSourcesFor(PROJECTS, GENERAL_SECTIONS)+parseNavStructure()read the samenav.yamlfiles the site loads, replacing the regex overpage-map.tssource and the hand-maintainedPROJECT_FOR_NAVtable (issue follow-up 1).js-yamlmoved fromdevDependenciestodependencies—page-mapruns in the search API route at request time. Version unchanged (^5.2.2; ships its own types).CONTRIBUTING.mdanddocs/content/contributing/documentation/docs-structure-inc.mdnow describenav.yaml(schema, examples, workflows) instead ofNAV_STRUCTURE.src/__tests__/nav.test.ts— every rejection path of the loader (100 % lines / 97 % branches, above thesrc/lib/**floor), loads all nine real navs, and asserts every nav entry points at an existing page (the inverse of the [guide] docs site missing all kubestellar-mcp command reference pages — 11 docs unnavigable #5001/[guide] docs site console nav missing ~23 of 41 docs pages — auth, security, setup, troubleshooting unreachable #5002/[guide] kubestellar-mcp docs site nav missing architecture and contributor guide sections #5067 failure mode).versions.shape-invariants—navPath === <contentPath>/nav.yamland the file exists, for every project.page-map-defensive-arms-drift— now pins the singleGENERAL_SECTIONSmechanism and assertspage-map.tscontains no hard-coded prefix literals orNAV_STRUCTURE_.check-internal-links-helperstests (both copies) rewritten fornavSourcesFor/navAliasEntries/parseNavStructure, same invariants (section × entry + bare form, external/absolute skipped,.md/.mdxonly, slugify parity).Checklist
Security Considerations
js-yamlwas already a devDependency at the same version; only its section inpackage.jsonchanged.yaml.load(safe schema by default in js-yaml ≥4) is used; noloadAll/custom types.Screenshots or Logs (if applicable)
👀 Reviewer Notes
NAV_STRUCTURE_([A-Z_]+)capturedAforNAV_STRUCTURE_A2A(no digit in the class), so the A2A nav was silently skipped;CONTRIBUTING/COMMUNITY/NEWShad noPROJECT_FOR_NAVentry and were skipped too. Compared againstmain, the old nav-alias route set is a strict subset of the new one: 0 routes lost, 90 added, all from A2A and the three shared navs. Route count in the output went 973 → 1048 for that reason.Communitysection still anchors its folder under/docs/community(its children were already under/docs/kubeflex/community/…).page-map-routes.test.tspins this; changing it is out of scope for a behaviour-preserving refactor — happy to file a follow-up.docs/content/<section>/nav.yaml(next to the pages) rather thandocs/content/_shared/<section>/nav.yaml, so authors edit the nav in the directory they're already in. The kubestellar nav is atdocs/content/nav.yaml(= itscontentPath) rather thandocs/content/kubestellar/nav.yaml, because its entries are relative todocs/content/; the invariantnavPath === contentPath + '/nav.yaml'then holds uniformly and is tested.generate-shared-config.tsvalidating that every MDX underdocs/content/<project>/is listed innav.yamlorunlisted: true. The loader now makes that a small follow-up.package-lock.jsonchurn isnpm install --package-lock-onlyre-hoisting js-yaml 4.x under@eslint/eslintrcnow that 5.x is a prod dep;npm civerified clean.— hive: backend=copilot model=claude-fable-5.1