// Config Sidebar - Handles sidebar population and navigation class ConfigSidebar { constructor() { this.categoriesList = null; } populateSidebar() { //console.log('ConfigSidebar: Populating sidebar with categories...'); this.categoriesList = document.getElementById('config-categories-list'); if (!this.categoriesList) { console.error('ConfigSidebar: config-categories-list element not found'); return; } if (!window.configData || !window.configData.categories) { console.error('ConfigSidebar: No config data available for sidebar'); return; } this.categoriesList.innerHTML = ''; // Overview — the Admin landing (an ops/health board, not a config form). const overviewItem = document.createElement('div'); overviewItem.className = 'category'; overviewItem.setAttribute('data-category', 'overview'); overviewItem.innerHTML = ' Dashboard'; overviewItem.addEventListener('click', function () { window.history.pushState({}, '', window.adminPath('overview')); document.querySelectorAll('.category').forEach(function (item) { item.classList.remove('active'); }); this.classList.add('active'); window.configCategory = 'overview'; if (window.configManager && typeof window.configManager.renderConfig === 'function') { window.configManager.renderConfig('overview'); } }); this.categoriesList.appendChild(overviewItem); // System sits right under Overview — both are admin-landing surfaces // (Overview = ops/health summary, System = live host + per-app stats), // distinct from the config form pages or the Tools utilities below. const systemItem = document.createElement('div'); systemItem.className = 'category'; systemItem.setAttribute('data-category', 'system'); systemItem.innerHTML = ' System'; systemItem.addEventListener('click', function () { window.history.pushState({}, '', window.adminPath('system')); document.querySelectorAll('.category').forEach(function (item) { item.classList.remove('active'); }); this.classList.add('active'); window.configCategory = 'system'; if (window.configManager && typeof window.configManager.renderConfig === 'function') { window.configManager.renderConfig('system'); } }); this.categoriesList.appendChild(systemItem); // "Config" group heading above the configuration categories (mirrors the // "Tools" heading below). const configLabel = document.createElement('div'); configLabel.className = 'sidebar-group-label'; configLabel.textContent = 'Config'; this.categoriesList.appendChild(configLabel); // Convert categories object to array and sort by ORDER const categoriesArray = Object.entries(window.configData.categories).map(([key, value]) => ({ id: key, ...value })); // Sort by ORDER if available, otherwise by title categoriesArray.sort(function(a, b) { const orderA = parseInt(a.order) || 999; const orderB = parseInt(b.order) || 999; return orderA - orderB; }); var self = this; // Preserve 'this' context categoriesArray.forEach(function(category) { // Backup category has its own top-level page (/backup) which renders // these same fields dynamically — hide it from the /config sidebar to // avoid two surfaces for the same data. if (category.id === 'backup') return; const categoryItem = document.createElement('div'); categoryItem.className = 'category'; categoryItem.setAttribute('data-category', category.id); // Use correct icon from our new structure const iconName = category.icon || category.id; const iconPath = '/icons/config/' + iconName + '.svg'; categoryItem.innerHTML = '' + category.title + ' ' + category.title; categoryItem.addEventListener('click', function() { // Update URL without full page reload window.history.pushState({}, '', window.adminPath(category.id)); // Update active state document.querySelectorAll('.category').forEach(function(item) { item.classList.remove('active'); }); this.classList.add('active'); // Update global category and load dynamically window.configCategory = category.id; // Load config dynamically without page refresh if (window.configManager && typeof window.configManager.renderConfig === 'function') { window.configManager.renderConfig(category.id); } }); self.categoriesList.appendChild(categoryItem); }); // Tools group — admin pages that live in this area but aren't config // categories (rendered by their own controller, not the config form). const toolsLabel = document.createElement('div'); toolsLabel.className = 'sidebar-group-label'; toolsLabel.textContent = 'Tools'; self.categoriesList.appendChild(toolsLabel); const sshItem = document.createElement('div'); sshItem.className = 'category'; sshItem.setAttribute('data-category', 'ssh-access'); // Inline key icon (currentColor so it follows the theme — security.svg // hardcodes a fixed blue stroke and so visually goes missing on certain // themes; the other Tools/admin items all use inline SVGs). sshItem.innerHTML = ' SSH Access'; sshItem.addEventListener('click', function () { window.history.pushState({}, '', window.adminPath('ssh-access')); document.querySelectorAll('.category').forEach(function (item) { item.classList.remove('active'); }); this.classList.add('active'); window.configCategory = 'ssh-access'; if (window.configManager && typeof window.configManager.renderConfig === 'function') { window.configManager.renderConfig('ssh-access'); } }); self.categoriesList.appendChild(sshItem); const peersItem = document.createElement('div'); peersItem.className = 'category'; peersItem.setAttribute('data-category', 'peers'); peersItem.innerHTML = ' Peers'; peersItem.addEventListener('click', function () { window.history.pushState({}, '', window.adminPath('peers')); document.querySelectorAll('.category').forEach(function (item) { item.classList.remove('active'); }); this.classList.add('active'); window.configCategory = 'peers'; if (window.configManager && typeof window.configManager.renderConfig === 'function') { window.configManager.renderConfig('peers'); } }); self.categoriesList.appendChild(peersItem); // Set initial active category this.setActiveCategory(window.configCategory || 'overview'); //console.log('ConfigSidebar: Sidebar populated with ' + categoriesArray.length + ' categories'); } setActiveCategory(categoryId) { // Update active state document.querySelectorAll('.category').forEach(function(item) { item.classList.remove('active'); }); var activeItem = document.querySelector('[data-category="' + categoryId + '"]'); if (activeItem) { activeItem.classList.add('active'); } } } // Export to global scope window.ConfigSidebar = ConfigSidebar;