From a98a241d5ef791c91c294255a17819b6f9a35b50 Mon Sep 17 00:00:00 2001 From: librelad Date: Sat, 30 May 2026 01:52:43 +0100 Subject: [PATCH] chore(webui): remove dead controllers (app-manager.js, config-router.js) Both are orphans with zero inbound references (verified by grep across the whole frontend): app-manager.js only self-assigns window.appManager and is in no loader/scripts array; config-router.js only self-defines ConfigRouter and is referenced nowhere (config-manager owns rendering directly). First, safest step of the feature reorganization. Co-Authored-By: Claude Opus 4.8 Signed-off-by: librelad --- .../frontend/js/components/app/app-manager.js | 363 ------------------ .../js/components/config/config-router.js | 291 -------------- 2 files changed, 654 deletions(-) delete mode 100755 containers/libreportal/frontend/js/components/app/app-manager.js delete mode 100755 containers/libreportal/frontend/js/components/config/config-router.js diff --git a/containers/libreportal/frontend/js/components/app/app-manager.js b/containers/libreportal/frontend/js/components/app/app-manager.js deleted file mode 100755 index 1398ecc..0000000 --- a/containers/libreportal/frontend/js/components/app/app-manager.js +++ /dev/null @@ -1,363 +0,0 @@ -// App Manager - Dynamic app loading with beautiful styling -class AppManager { - constructor() { - this.cache = new Map(); - } - - getRandomLoadingMessage() { - const messages = [ - "Preparing your application settings...", - "Gathering application information...", - "Loading application configuration...", - "Setting up your app management panel...", - "Loading the perfect app settings...", - "Crafting your application experience...", - "Preparing your app control panel...", - "Loading application details...", - "Setting up your app workspace...", - "Configuring your application environment..." - ]; - - return messages[Math.floor(Math.random() * messages.length)]; - } - - async loadApp(appName) { - //console.log(`AppManager: Loading ${appName} app...`); - - // Check cache first - if (this.cache.has(appName)) { - //console.log(`AppManager: Using cached ${appName} app`); - return this.cache.get(appName); - } - - try { - // Load app data from apps.json - const response = await fetch('/data/apps/generated/apps.json', { cache: 'no-store' }); - if (!response.ok) { - throw new Error(`Failed to load apps.json: ${response.status}`); - } - - const appsData = await response.json(); - - // Try multiple ways to find the app - let app = appsData.apps.find(app => - app.name.toLowerCase().includes(appName.toLowerCase()) || - app.command.toLowerCase().includes(appName.toLowerCase()) || - app.name === appName || - app.name.toLowerCase() === appName.toLowerCase() - ); - - if (!app) { - // Try case-insensitive exact match - app = appsData.apps.find(app => - app.name.toLowerCase() === appName.toLowerCase() || - app.command.toLowerCase().includes(appName.toLowerCase()) - ); - } - - if (!app) { - //console.log(`Available apps:`, appsData.apps.map(a => ({ name: a.name, command: a.command }))); - throw new Error(`App ${appName} not found`); - } - - //console.log(`AppManager: Loaded ${appName} app:`, app); - - // Cache the result - this.cache.set(appName, app); - - return app; - } catch (error) { - console.error(`AppManager: Error loading ${appName} app:`, error); - return null; - } - } - - async renderApp(appName) { - //console.log(`AppManager: Rendering ${appName} app...`); - - const configSection = document.getElementById('config-section'); - if (!configSection) { - console.error('AppManager: config-section element not found'); - return; - } - - // Show loading with enhanced visual - configSection.innerHTML = ` -
-
-
-
- Loading application... -
-
- ${this.getRandomLoadingMessage()} -
-
- -
- `; - - // Update loading bar if available - if (typeof router !== 'undefined' && router.updateProgress) { - router.updateProgress(60); - } - - try { - // Load app data - const app = await this.loadApp(appName); - - // Update loading bar - if (typeof router !== 'undefined' && router.updateProgress) { - router.updateProgress(70); - } - - if (!app) { - configSection.innerHTML = '
Application not found
'; - return; - } - - // App config comes from apps.json (window.apps), not a separate - // per-app JSON. Pass null — the renderer's config section is gated - // on appConfig?.config keys so it just skips that section. - if (typeof router !== 'undefined' && router.updateProgress) { - router.updateProgress(80); - } - - await this.renderWithOriginalStyling(appName, app, null); - - // Final progress update - if (typeof router !== 'undefined' && router.updateProgress) { - router.updateProgress(80); - } - - //console.log(`AppManager: Successfully rendered ${appName} app`); - - } catch (error) { - console.error(`AppManager: Error rendering ${appName} app:`, error); - configSection.innerHTML = `
Failed to load ${appName} application: ${error.message}
`; - } - } - - async renderWithOriginalStyling(appName, app, appConfig) { - const configSection = document.getElementById('config-section'); - - // Render using the original app-config system - let formHTML = ` -
-

${app.displayName || app.name} Application

-

${app.description || 'Manage settings and configuration for ' + (app.displayName || app.name)}

-
-
-
- `; - - // App information section - formHTML += ` -
-

Application Information

-

Basic information about this application

-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
-
- `; - - // Configuration section if available - if (appConfig && appConfig.config && Object.keys(appConfig.config).length > 0) { - // Use ConfigShared if available for beautiful rendering - if (typeof ConfigShared !== 'undefined') { - const groupedConfigs = ConfigShared.groupConfigKeys(appConfig.config); - const categoryOrder = ConfigShared.extractCategoryOrder(appConfig.config); - - for (const category of categoryOrder) { - const keys = groupedConfigs[category]; - if (keys && keys.length > 0 && category !== 'Hidden/Unused Options') { - const displayCategory = ConfigShared.formatCategoryName(category); - const categoryDescription = await ConfigShared.getCategoryDescription(category); - - formHTML += ` -
-

${displayCategory}

-

${categoryDescription}

-
- ${ConfigShared.generateFieldsForCategory(keys, category, appConfig.config, (fieldId, key, value, title, description, options, config) => ConfigShared.generateField(fieldId, key, value, title, description, options, config))} -
-
- `; - } - } - } else { - // Fallback simple rendering - formHTML += ` -
-

Configuration

-

Application-specific settings

-
-
- -
- -
-
-
-
- `; - } - } else { - // No configuration available - formHTML += ` -
-

Configuration

-

No specific configuration available for this application

-
-
- -
- -
-
-
-
- `; - } - - formHTML += ` -
-
- - -
-
- `; - - configSection.innerHTML = formHTML; - } - - static async saveAppConfig(appName) { - //console.log(`AppManager: Saving ${appName} config...`); - - const form = document.getElementById(`app-form-${appName}`); - if (!form) { - console.error('AppManager: Form not found'); - return; - } - - // Show success message - if (typeof ConfigShared !== 'undefined' && ConfigShared.showNotification) { - ConfigShared.showNotification('Application configuration saved successfully!', 'success'); - } else { - // Fallback message - const message = document.createElement('div'); - message.className = 'config-message success'; - message.textContent = 'Application configuration saved successfully!'; - - const actionsDiv = form.parentElement.querySelector('.config-actions'); - actionsDiv.insertBefore(message, actionsDiv.firstChild); - - // Remove message after 3 seconds - setTimeout(() => { - if (message.parentNode) { - message.parentNode.removeChild(message); - } - }, 3000); - } - } - - static async resetAppConfig(appName) { - //console.log(`AppManager: Resetting ${appName} config...`); - - if (confirm('Are you sure you want to reset all settings to their default values?')) { - // Reload the page to reset - window.location.reload(); - } - } - - async loadScript(src) { - // Check if script is already loaded - const scriptId = src.replace(/[^a-zA-Z0-9]/g, '_'); - if (document.getElementById(scriptId)) { - //console.log(`Script ${src} already loaded, skipping`); - return; - } - - //console.log(`Loading script: ${src}`); - - return new Promise((resolve, reject) => { - const script = document.createElement('script'); - script.src = src; - script.id = scriptId; - script.onload = () => { - //console.log(`Script loaded successfully: ${src}`); - resolve(); - }; - script.onerror = (error) => { - console.error(`Script failed to load: ${src}`, error); - reject(new Error(`Failed to load script: ${src}`)); - }; - document.head.appendChild(script); - }); - } -} - -// Global instance -window.appManager = new AppManager(); diff --git a/containers/libreportal/frontend/js/components/config/config-router.js b/containers/libreportal/frontend/js/components/config/config-router.js deleted file mode 100755 index d465aaa..0000000 --- a/containers/libreportal/frontend/js/components/config/config-router.js +++ /dev/null @@ -1,291 +0,0 @@ -// Configuration Router - Loads appropriate config component based on URL -class ConfigRouter { - constructor() { - this.currentComponent = null; - } - - async init() { - //console.log('ConfigRouter: Initializing...'); - // Get current category from query parameter or global variable - const searchParams = new URLSearchParams(window.location.search); - let currentCategory = searchParams.get('config') || window.configCategory || 'general'; - - //console.log(`Initial parsing - searchParams.get('config'): ${searchParams.get('config')}`); - //console.log(`Window location search: ${window.location.search}`); - //console.log(`Initial currentCategory: ${currentCategory}`); - - // Handle the case where URL is config?=backup (malformed but common) - // Check if we got the category from URL params, not from fallback - const gotFromUrlParams = searchParams.get('config') !== null; - - if (!gotFromUrlParams && window.location.search.includes('?=')) { - //console.log(`URL contains ?= and no valid config param, attempting regex match...`); - const pathMatch = window.location.search.match(/\?=([^&]+)/); - //console.log(`Regex match result:`, pathMatch); - //console.log(`Regex test result:`, /\?=([^&]+)/.test(window.location.search)); - if (pathMatch && pathMatch[1]) { - currentCategory = pathMatch[1]; - //console.log(`Updated currentCategory from regex: ${currentCategory}`); - } else { - //console.log(`Regex failed to match, currentCategory remains: ${currentCategory}`); - } - } else { - //console.log(`Got category from URL params (${gotFromUrlParams}) or URL doesn't contain ?=, keeping: ${currentCategory}`); - } - - //console.log(`Config router init: final category=${currentCategory}`); - - // Backup config moved to /backup — redirect old URL/bookmarks. - if (currentCategory === 'backup') { - if (window.librePortalSPA && typeof window.librePortalSPA.navigate === 'function') { - window.librePortalSPA.navigate('/backup', true); - } else { - window.location.href = '/backup'; - } - return; - } - - // Load categories for sidebar - await this.loadConfigCategories(); - - // Set active category in sidebar - this.setActiveCategory(currentCategory); - - // Load appropriate config component - await this.loadConfigComponent(currentCategory); - } - - async loadConfigCategories() { - try { - //console.log('Loading config categories from: data/config/generated/configs.json'); - - // Start loading bar - if (typeof router !== 'undefined' && router.updateProgress) { - router.updateProgress(20); - } - - // Load unified config file - const response = await fetch('/data/config/generated/configs.json'); - //console.log('Response status:', response.status, response.statusText); - //console.log('Response ok:', response.ok); - - if (!response.ok) { - throw new Error(`HTTP ${response.status}: ${response.statusText}`); - } - - const text = await response.text(); - //console.log('Raw response text:', text); - //console.log('Text length:', text.length); - //console.log('First 100 chars:', text.substring(0, 100)); - - if (!text || text.trim() === '') { - throw new Error('Empty response from configs.json'); - } - - const data = JSON.parse(text); - const categories = data.categories; - - //console.log('Parsed categories:', categories); - - if (typeof router !== 'undefined' && router.updateProgress) { - router.updateProgress(60); - } - - const categoriesList = document.getElementById('config-categories-list'); - if (!categoriesList) { - console.error('config-categories-list element not found'); - return; - } - - categoriesList.innerHTML = ''; - - // Convert categories object to array and sort by ORDER - const categoriesArray = Object.entries(categories).map(([key, value]) => ({ - id: key, - ...value - })); - - // Sort by ORDER if available, otherwise by title - categoriesArray.sort((a, b) => { - const orderA = parseInt(a.order) || 999; - const orderB = parseInt(b.order) || 999; - return orderA - orderB; - }); - - categoriesArray.forEach(category => { - 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`; - //console.log(`Category: ${category.id}, Icon path: ${iconPath}`); - categoryItem.innerHTML = ` - ${category.title} - ${category.title} - `; - - categoryItem.addEventListener('click', () => { - //console.log(`Category clicked: ${category.id}`); - this.navigateToCategory(category.id); - }); - - categoriesList.appendChild(categoryItem); - }); - - if (typeof router !== 'undefined' && router.updateProgress) { - router.updateProgress(80); - } - - } catch (error) { - console.error('Error loading config categories:', error); - if (typeof router !== 'undefined' && router.hideLoadingBar) { - router.hideLoadingBar(); - } - } - } - - setActiveCategory(categoryId) { - // Update active state - document.querySelectorAll('.category').forEach(item => { - item.classList.remove('active'); - }); - document.querySelector(`[data-category="${categoryId}"]`)?.classList.add('active'); - } - - navigateToCategory(categoryId) { - //console.log(`Config router: navigating to ${categoryId} (SPA mode)`); - - // Update URL without full page reload using query parameter - const url = `/config?=${categoryId}`; - //console.log(`Updating URL to: ${url}`); - window.history.pushState({}, '', url); - - // Set active category - this.setActiveCategory(categoryId); - - // Load config content dynamically - this.loadConfigComponent(categoryId); - } - - async loadConfigComponent(categoryId) { - try { - //console.log(`Config router: Loading component for ${categoryId}`); - - // Start loading bar - if (typeof router !== 'undefined' && router.updateProgress) { - router.updateProgress(10); - router.showLoadingBar(); - } - - // Clear current content - const configSection = document.getElementById('config-section'); - if (configSection) { - configSection.innerHTML = '
Loading configuration...
'; - } - - // Update progress - if (typeof router !== 'undefined' && router.updateProgress) { - router.updateProgress(30); - } - - // Use the simple config manager - if (window.configManager) { - //console.log(`Using ConfigManager for ${categoryId}`); - if (typeof router !== 'undefined' && router.updateProgress) { - router.updateProgress(50); - } - - await window.configManager.renderConfig(categoryId); - - if (typeof router !== 'undefined' && router.updateProgress) { - router.updateProgress(90); - } - } else { - // Fallback - try to load config manager - //console.log('ConfigManager not available, loading it...'); - if (typeof router !== 'undefined' && router.updateProgress) { - router.updateProgress(40); - } - - await new Promise((resolve) => { - const script = document.createElement('script'); - script.src = '/js/components/config/config-manager.js'; - script.onload = async () => { - if (window.configManager) { - if (typeof router !== 'undefined' && router.updateProgress) { - router.updateProgress(60); - } - await window.configManager.renderConfig(categoryId); - if (typeof router !== 'undefined' && router.updateProgress) { - router.updateProgress(90); - } - } - resolve(); - }; - document.head.appendChild(script); - }); - } - - // Complete loading - if (typeof router !== 'undefined' && router.updateProgress) { - router.updateProgress(100); - setTimeout(() => { - router.hideLoadingBar(); - }, 500); // Small delay to show completion - } - - } catch (error) { - console.error(`Error loading config component for ${categoryId}:`, error); - const configSection = document.getElementById('config-section'); - if (configSection) { - configSection.innerHTML = `
Failed to load ${categoryId} configuration: ${error.message}
`; - } - if (typeof router !== 'undefined' && router.hideLoadingBar) { - router.hideLoadingBar(); - } - } - } - - async loadConfigComponentManual(categoryId) { - const configSection = document.getElementById('config-section'); - - // This method is no longer needed since we use ConfigManager for all categories - // The individual config classes have been removed - //console.log(`ConfigRouter: loadConfigComponentManual called for ${categoryId} - delegating to ConfigManager`); - - // Use ConfigManager for all categories now - if (window.configManager) { - await window.configManager.renderConfig(categoryId); - } else { - configSection.innerHTML = '
ConfigManager not available
'; - } - - // Hide loading bar - if (typeof router !== 'undefined' && router.hideLoadingBar) { - router.hideLoadingBar(); - } - } - - async loadScript(src) { - // Check if script is already loaded - const scriptId = src.replace(/[^a-zA-Z0-9]/g, '_'); - if (document.getElementById(scriptId)) { - //console.log(`Script ${src} already loaded, skipping`); - return; - } - - return new Promise((resolve, reject) => { - const script = document.createElement('script'); - script.src = src; - script.id = scriptId; - script.onload = resolve; - script.onerror = reject; - document.head.appendChild(script); - }); - } -} - -// Export for global access -window.ConfigRouter = ConfigRouter;