const pageCache = {}; const APP_VERSION = '0.4.1'; const PAGE_BASE = '/dashboard/pages/'; async function loadPage(name) { if (pageCache[name]) return pageCache[name]; try { await loadScript(`${PAGE_BASE}${name}.js`); pageCache[name] = true; } catch (err) { showToast(`Failed to load page: ${name}`, 'error'); throw err; } } function loadScript(src) { return new Promise((resolve, reject) => { const versioned = `${src}?v=${APP_VERSION}`; if (document.querySelector(`script[src="${versioned}"]`)) { resolve(); return; } const script = document.createElement('script'); script.src = versioned; script.onload = () => resolve(); script.onerror = () => reject(new Error(`Failed to load ${src}`)); document.body.appendChild(script); }); } async function navigate(page) { const hash = page || window.location.hash.slice(1) || 'dashboard'; if (!hash) { window.location.hash = 'dashboard'; return; } // Show loading bar const bar = document.getElementById('topLoadingBar'); if (bar) { bar.classList.add('active'); bar.style.width = '30%'; } document.querySelectorAll('.nav-item, .bottom-nav-item').forEach(el => el.classList.remove('active')); const navItem = document.querySelector(`[data-page="${hash}"]`); if (navItem) navItem.classList.add('active'); const info = PAGE_TITLES[hash] || { title: 'Unknown', breadcrumb: '' }; document.getElementById('pageTitle').textContent = info.title; document.getElementById('pageBreadcrumb').textContent = info.breadcrumb; const content = document.getElementById('pageContent'); content.innerHTML = `
Loading ${info.title}...
`; try { await loadPage(hash); const renderFn = window[`render${capitalize(hash.replace(/-./g, m => m[1].toUpperCase()))}`]; if (renderFn) { content.innerHTML = ''; content.className = 'page-content page-enter'; if (bar) bar.style.width = '70%'; await renderFn(); if (bar) { bar.style.width = '100%'; setTimeout(() => { bar.style.width = '0'; bar.classList.remove('active'); }, 400); } } else { content.innerHTML = `
🔍
Page not found
The page "${hash}" doesn't have a render function
`; if (bar) { bar.style.width = '0'; bar.classList.remove('active'); } } } catch (err) { content.innerHTML = `
Failed to load
${escapeHtml(err.message)}
`; if (bar) { bar.style.width = '0'; bar.classList.remove('active'); } } } function capitalize(str) { return str.charAt(0).toUpperCase() + str.slice(1); } async function updateAgentStatus() { try { const status = await api.getStatus(); const agents = status.agents || []; const bar = document.getElementById('agentStatusBar'); const online = agents.filter(a => a.status === 'online').length; const total = agents.length; const dot = bar.querySelector('.agent-dot'); if (online === total) { dot.className = 'agent-dot online'; bar.querySelector('span').textContent = 'All agents online'; } else if (online > 0) { dot.className = 'agent-dot warning'; bar.querySelector('span').textContent = `${online}/${total} online`; } else { dot.className = 'agent-dot offline'; bar.querySelector('span').textContent = 'All agents offline'; } const badge = document.getElementById('skillCount'); if (badge && status.skills_count !== undefined) badge.textContent = status.skills_count; } catch { const bar = document.getElementById('agentStatusBar'); if (bar) { bar.querySelector('.agent-dot').className = 'agent-dot offline'; bar.querySelector('span').textContent = 'Disconnected'; } } } window.addEventListener('hashchange', () => navigate()); window.addEventListener('DOMContentLoaded', () => { loadTheme(); navigate(window.location.hash.slice(1) || 'dashboard'); updateAgentStatus(); setInterval(updateAgentStatus, 15000); });