Files

2.3 KiB

Nav Consistency Pattern (Jul 12, 2026)

Principle

All portal pages must load nav from /nav.html — the single source of truth for nav links, hamburger toggle, and nav CSS. The only exception is index.html (dashboard), which keeps an inline nav that matches nav.html link-for-link.

Current state (post-Jul 12 fix)

Page Nav source Status
index.html Inline (matches nav.html) OK — all 11 links + hamburger
services.html Fetched OK
servers.html Fetched OK
backups.html Fetched OK
audit.html, cost.html, cron.html, network.html, config.html, logs.html Fetched OK

Conversion procedure (inline → fetched)

  1. Replace the <nav class="ops-nav">...</nav> block with <div id="nav"></div>.

  2. Move initNav() into the fetch callback. The old pattern of calling window.initNav() before the nav HTML is injected is a race condition — it tries to wire up toggle listeners on elements that don't exist yet:

    // WRONG (initNav runs before nav HTML exists):
    window.initNav();
    //  ... later ...
    fetch('/nav.html')...
    
    // RIGHT (initNav runs AFTER nav HTML is injected):
    fetch('/nav.html').then(function(r) { return r.text(); }).then(function(h) {
      document.getElementById('nav').innerHTML = h;
      if (typeof window.initNav === 'function') window.initNav();
    }).catch(function(e) { console.warn('Nav failed:', e); });
    
  3. Keep window.initNav() — never use Ops.initNav() or bare initNav() inside a strict-IIFE. The nav init function is exported on window in app.js/utils.js.

Index.html: inline nav maintenance

The dashboard keeps inline nav. When /nav.html gains or loses links, update index.html's inline nav to match. Key elements:

  • class="nav-logo-text" on the brand span
  • Hamburger toggle: <button class="nav-toggle" id="navToggle" ...>
  • All 11 links with data-path attributes
  • class="nav-link" and target="_blank" on Grafana

Verification checklist

  • <div id="nav"> placeholder present (fetched pages only)
  • initNav() called AFTER .innerHTML = h in fetch callback
  • No orphan window.initNav() outside fetch block
  • index.html has all current nav.html links + hamburger toggle
  • HTTP 200 on all pages
  • /nav.html serves directly (not just through FastAPI proxy)