// 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}
`;
}
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');
}