// app.js — entry point. Routes hash changes to view renderers and // keeps the top-nav active state in sync. import { onRoute } from "./state.js"; import { renderRemotes } from "./views/remotes.js"; import { renderBrowse } from "./views/browser.js"; import { renderJobs, renderNewJob, stopJobPolling } from "./views/jobs.js"; import { renderConfigureNew, renderConfigureEdit, } from "./views/configure.js"; const views = { remotes: renderRemotes, browse: renderBrowse, jobs: renderJobs, "jobs-new": renderNewJob, "configure-new": renderConfigureNew, "configure-edit": renderConfigureEdit, }; function setActiveNav(routeName) { const links = document.querySelectorAll("#nav-links a"); for (const a of links) { const target = a.dataset.route; let isActive = target === routeName; // "Configure" is active on both configure-new and configure-edit if (target === "configure" && routeName.startsWith("configure-")) { isActive = true; } a.classList.toggle("active", isActive); } } onRoute(async (route) => { setActiveNav(route.name); // Stop jobs polling when leaving the jobs view if (route.name !== "jobs") { stopJobPolling(); } const renderer = views[route.name] || renderRemotes; try { await renderer(route.params); } catch (e) { console.error("view error", e); const app = document.getElementById("app"); if (app) { app.innerHTML = `
${escapeHtml(e.message)}