// ── Router ──────────────────────────────────────────────────────────────────── function navigate(page, vmid) { document.querySelectorAll('.page').forEach(p => p.classList.remove('active')); if (page === 'dashboard') { document.getElementById('page-dashboard').classList.add('active'); history.pushState({ page: 'dashboard' }, '', '/'); renderDashboard(); } else if (page === 'instance') { document.getElementById('page-detail').classList.add('active'); history.pushState({ page: 'instance', vmid }, '', `/instance/${vmid}`); renderDetailPage(vmid); } else if (page === 'jobs') { document.getElementById('page-jobs').classList.add('active'); history.pushState({ page: 'jobs' }, '', '/jobs'); renderJobsPage(); } } function handleRoute() { const m = window.location.pathname.match(/^\/instance\/(\d+)/); if (window.location.pathname === '/jobs') { document.getElementById('page-jobs').classList.add('active'); renderJobsPage(); } else if (m) { document.getElementById('page-detail').classList.add('active'); renderDetailPage(parseInt(m[1], 10)); } else { document.getElementById('page-dashboard').classList.add('active'); renderDashboard(); } } window.addEventListener('popstate', e => { document.querySelectorAll('.page').forEach(p => p.classList.remove('active')); if (e.state?.page === 'instance') { document.getElementById('page-detail').classList.add('active'); renderDetailPage(e.state.vmid); } else if (e.state?.page === 'jobs') { document.getElementById('page-jobs').classList.add('active'); renderJobsPage(); } else { document.getElementById('page-dashboard').classList.add('active'); renderDashboard(); } }); // ── Bootstrap ───────────────────────────────────────────────────────────────── if (VERSION) { const label = /^\d/.test(VERSION) ? `v${VERSION}` : VERSION; document.getElementById('nav-version').textContent = label; } fetch('/api/jobs').then(r => r.json()).then(_updateJobsNavDot).catch(() => {}); handleRoute();