// Dashboard functionality // loadSystemInfo() and updateDiskChart() live in data-loader.js — that version // uses waitForDashboardElements() so it doesn't fire before the dashboard HTML // is in the DOM. Defining them here too overrode the safer version and produced // the spurious "Disk chart elements not found" errors when called from non-dashboard pages. // Load installed apps and render icon grid on dashboard async function loadInstalledApps() { if (!window.apps || window.apps.length === 0) { try { const response = await fetch('/data/apps/generated/apps.json', { cache: 'no-store' }); const data = await response.json(); window.apps = data.apps || []; } catch (e) { return; } } renderInstalledApps(); } function renderInstalledApps() { const section = document.getElementById('frontpage-apps-section'); const container = document.getElementById('frontpage-apps-container'); if (!section || !container) return; const installed = (window.apps || []).filter(a => a.installed); if (installed.length === 0) return; container.innerHTML = installed.map(app => createInstalledAppCard(app)).join(''); section.style.display = ''; populateDashboardServiceButtons(installed); } function createInstalledAppCard(app) { const appName = app.command.split(' ').pop(); let icon = app.icon || '/core/icons/apps/default.svg'; if (!icon.startsWith('/')) icon = '/' + icon; const shortName = app.name.split(' - ')[0].trim(); return `
${shortName}
${shortName}
`; } async function populateDashboardServiceButtons(installedApps) { let services = []; if (window.serviceButtons) { if (window.serviceButtons.services.length === 0) await window.serviceButtons.loadServices(); services = window.serviceButtons.services; } else { try { const res = await fetch('/data/apps/generated/apps-services.json', { cache: 'no-store' }); const data = await res.json(); services = data.services || []; } catch (e) { return; } } const proto = s => ['http', 'https'].includes((s.protocol || '').toLowerCase()) ? s.protocol.toLowerCase() : 'http'; installedApps.forEach(app => { const appName = app.command.split(' ').pop(); const shortName = app.name.split(' - ')[0].trim(); const overlay = document.getElementById(`frontpage-overlay-${appName}`); if (!overlay) return; const appServices = services.filter(s => s.app === appName && s.buttonEnabled === true); // Multi-button render via the shared expandServiceLinks() helper. const serviceButtons = appServices.flatMap(s => window.expandServiceLinks(s).map(({ url, label }) => ` ${label} `) ).filter(Boolean).join(''); overlay.innerHTML = serviceButtons + ``; }); } // Setup event listeners function setupEventListeners() { setupMobileMenu(); loadInstalledApps(); } // Navigate to app page using SPA router function navigateToApp(appName) { // Use proper SPA navigation to the app page if (window.librePortalSPA && typeof window.librePortalSPA.navigate === 'function') { window.librePortalSPA.navigate(`/app/${appName}`); } else if (window.navigateToRoute && typeof window.navigateToRoute === 'function') { window.navigateToRoute(`app/${appName}`); } else { // Fallback to direct navigation window.location.href = `/app/${appName}`; } } // Filter apps by search term (removed - not used in dashboard) function filterApps(searchTerm) { //console.log('Filter apps functionality removed from dashboard'); } // Filter apps by category (removed - not used in dashboard) function filterAppsByCategory(category) { //console.log('Filter apps by category functionality removed from dashboard'); } // Populate category filter (removed - not used in dashboard) function populateCategoryFilter() { //console.log('Category filter population removed from dashboard'); }