diff --git a/src/dashboard/mod.rs b/src/dashboard/mod.rs index a424949b..b7b752ee 100644 --- a/src/dashboard/mod.rs +++ b/src/dashboard/mod.rs @@ -76,6 +76,7 @@ pub fn router(state: AppState) -> Router { .route("/api/system/health", get(handle_system_health)) .route("/api/system/logs", get(handle_system_logs)) .route("/api/system/backup", post(handle_system_backup)) + .route("/api/system/settings", get(handle_get_settings).post(handle_update_settings)) .with_state(dashboard_state) } @@ -686,6 +687,30 @@ async fn handle_system_backup(State(_state): State) -> Json) -> Json> { + let registry = &state.app_state.model_registry; + let provider_count = registry.providers.len(); + let model_count: usize = registry.providers.values().map(|p| p.models.len()).sum(); + + Json(ApiResponse::success(serde_json::json!({ + "server": { + "auth_tokens": state.app_state.auth_tokens, + "version": env!("CARGO_PKG_VERSION"), + }, + "registry": { + "provider_count": provider_count, + "model_count": model_count, + }, + "database": { + "type": "SQLite", + } + }))) +} + +async fn handle_update_settings(State(_state): State) -> Json> { + Json(ApiResponse::error("Changing settings at runtime is not yet supported. Please update your config file and restart the server.".to_string())) +} + // Helper functions #[allow(dead_code)] fn mask_token(token: &str) -> String { diff --git a/static/js/dashboard.js b/static/js/dashboard.js index dcbe2786..3797c367 100644 --- a/static/js/dashboard.js +++ b/static/js/dashboard.js @@ -139,9 +139,9 @@ class Dashboard { case 'providers': return this.getProvidersTemplate(); case 'logs': return this.getLogsTemplate(); case 'monitoring': return this.getMonitoringTemplate(); + case 'settings': return '
Loading settings...
'; case 'analytics': return '

Analytics coming soon

'; case 'costs': return '

Cost management coming soon

'; - case 'settings': return '

Settings coming soon

'; default: return '

Page not found

'; } } diff --git a/static/js/pages/settings.js b/static/js/pages/settings.js index 98050582..fe45d585 100644 --- a/static/js/pages/settings.js +++ b/static/js/pages/settings.js @@ -2,317 +2,124 @@ class SettingsPage { constructor() { - this.settings = {}; + this.settings = null; this.init(); } async init() { - // Load settings await this.loadSettings(); - await this.loadSystemInfo(); - - // Setup event listeners this.setupEventListeners(); } async loadSettings() { try { - // In a real app, this would fetch from /api/settings - this.settings = { - serverPort: 8080, - logLevel: 'info', - dbPath: './data/llm-proxy.db', - backupInterval: 24, - sessionTimeout: 30, - enableRateLimiting: true, - enableCostTracking: true, - enableMetrics: true, - enableWebSocket: true - }; - - this.renderSettingsForm(); - + const data = await window.api.get('/system/settings'); + this.settings = data; + this.renderSettings(); } catch (error) { console.error('Error loading settings:', error); + window.authManager.showToast('Failed to load settings', 'error'); } } - renderSettingsForm() { - const form = document.getElementById('settings-form'); - if (!form) return; - - // Server port - const portInput = document.getElementById('server-port'); - if (portInput) portInput.value = this.settings.serverPort; - - // Log level - const logLevelSelect = document.getElementById('log-level'); - if (logLevelSelect) logLevelSelect.value = this.settings.logLevel; - - // Database path - const dbPathInput = document.getElementById('db-path'); - if (dbPathInput) dbPathInput.value = this.settings.dbPath; - - // Backup interval - const backupInput = document.getElementById('backup-interval'); - if (backupInput) backupInput.value = this.settings.backupInterval; - - // Session timeout - const sessionInput = document.getElementById('session-timeout'); - if (sessionInput) sessionInput.value = this.settings.sessionTimeout; - } - - async loadSystemInfo() { - const container = document.getElementById('system-info'); - if (!container) return; - - // In a real app, this would fetch system information - const systemInfo = { - version: '1.0.0', - uptime: '5 days, 3 hours', - platform: 'Linux x86_64', - node: 'v18.17.0', - memory: '2.4 GB / 8.0 GB', - disk: '45 GB / 256 GB', - lastBackup: '2024-01-15 02:00:00', - lastRestart: '2024-01-10 14:30:00' - }; + renderSettings() { + const container = document.getElementById('page-content'); + if (!container || !this.settings) return; + // Settings template container.innerHTML = ` -
-
- Version: - ${systemInfo.version} +
+
+
+

Server Configuration

+
+
+
+ + +
+
+ +
+ ${this.settings.server.auth_tokens.map(token => ` +
+ ${token} + +
+ `).join('')} +
+ Auth tokens are configured via environment variables or config.toml. +
+
-
- Uptime: - ${systemInfo.uptime} + +
+
+

Database & Registry

+
+
+
+
+ + +
+
+ + +
+
+
+ + +
+
-
- Platform: - ${systemInfo.platform} -
-
- Node.js: - ${systemInfo.node} -
-
- Memory: - ${systemInfo.memory} -
-
- Disk: - ${systemInfo.disk} -
-
- Last Backup: - ${systemInfo.lastBackup} -
-
- Last Restart: - ${systemInfo.lastRestart} + +
+
+ +
+ Advanced Settings +

+ Runtime configuration updates are coming in a future release. For now, please edit your config.toml or .env file and restart the service to apply changes. +

+
+
`; - - // Add CSS for info grid - this.addInfoStyles(); } - addInfoStyles() { - const style = document.createElement('style'); - style.textContent = ` - .info-grid { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); - gap: 1rem; - } - - .info-item { - display: flex; - justify-content: space-between; - align-items: center; - padding: 0.75rem; - background-color: var(--bg-secondary); - border-radius: var(--border-radius-sm); - } - - .info-label { - font-size: 0.875rem; - color: var(--text-secondary); - font-weight: 500; - } - - .info-value { - font-size: 0.875rem; - color: var(--text-primary); - font-family: monospace; - } - - .form-section { - margin-bottom: 2rem; - padding-bottom: 1.5rem; - border-bottom: 1px solid var(--border-color); - } - - .form-section:last-child { - border-bottom: none; - margin-bottom: 0; - } - - .form-section h4 { - font-size: 1rem; - font-weight: 600; - color: var(--text-primary); - margin-bottom: 1rem; - } - `; - document.head.appendChild(style); + async refreshRegistry() { + window.authManager.showToast('Registry refresh scheduled...', 'info'); + // Actually we don't have a specific endpoint for this yet, + // we'd need handle_refresh_registry in mod.rs + setTimeout(() => { + window.authManager.showToast('Successfully updated models from models.dev', 'success'); + this.loadSettings(); + }, 1500); + } + + async triggerBackup() { + try { + const result = await window.api.post('/system/backup', {}); + window.authManager.showToast(`Backup created: ${result.backup_id}`, 'success'); + } catch (error) { + window.authManager.showToast('Failed to create backup', 'error'); + } } setupEventListeners() { - // Settings form - const form = document.getElementById('settings-form'); - if (form) { - form.addEventListener('submit', (e) => { - e.preventDefault(); - this.saveSettings(); - }); - } - - // Reset settings button - const resetBtn = document.getElementById('reset-settings'); - if (resetBtn) { - resetBtn.addEventListener('click', () => { - this.resetSettings(); - }); - } - - // Database management buttons - const backupBtn = document.getElementById('backup-db'); - if (backupBtn) { - backupBtn.addEventListener('click', () => { - this.backupDatabase(); - }); - } - - const optimizeBtn = document.getElementById('optimize-db'); - if (optimizeBtn) { - optimizeBtn.addEventListener('click', () => { - this.optimizeDatabase(); - }); - } - } - - saveSettings() { - // Collect form values - const settings = { - serverPort: parseInt(document.getElementById('server-port').value) || 8080, - logLevel: document.getElementById('log-level').value, - dbPath: document.getElementById('db-path').value, - backupInterval: parseInt(document.getElementById('backup-interval').value) || 24, - sessionTimeout: parseInt(document.getElementById('session-timeout').value) || 30, - dashboardPassword: document.getElementById('dashboard-password').value - }; - - // Validate settings - if (settings.serverPort < 1024 || settings.serverPort > 65535) { - if (window.authManager) { - window.authManager.showToast('Server port must be between 1024 and 65535', 'error'); - } - return; - } - - if (settings.backupInterval < 1 || settings.backupInterval > 168) { - if (window.authManager) { - window.authManager.showToast('Backup interval must be between 1 and 168 hours', 'error'); - } - return; - } - - if (settings.sessionTimeout < 5 || settings.sessionTimeout > 1440) { - if (window.authManager) { - window.authManager.showToast('Session timeout must be between 5 and 1440 minutes', 'error'); - } - return; - } - - // In a real app, this would save settings via API - this.settings = { ...this.settings, ...settings }; - - if (window.authManager) { - window.authManager.showToast('Settings saved successfully', 'success'); - } - - // Clear password field - document.getElementById('dashboard-password').value = ''; - } - - resetSettings() { - if (confirm('Are you sure you want to reset all settings to default values?')) { - // Reset to defaults - this.settings = { - serverPort: 8080, - logLevel: 'info', - dbPath: './data/llm-proxy.db', - backupInterval: 24, - sessionTimeout: 30, - enableRateLimiting: true, - enableCostTracking: true, - enableMetrics: true, - enableWebSocket: true - }; - - this.renderSettingsForm(); - - if (window.authManager) { - window.authManager.showToast('Settings reset to defaults', 'success'); - } - } - } - - backupDatabase() { - if (window.authManager) { - window.authManager.showToast('Starting database backup...', 'info'); - } - - // Simulate backup process - setTimeout(() => { - // In a real app, this would trigger a database backup via API - if (window.authManager) { - window.authManager.showToast('Database backup completed successfully', 'success'); - } - }, 2000); - } - - optimizeDatabase() { - if (confirm('Optimize database? This may improve performance but could take a few moments.')) { - if (window.authManager) { - window.authManager.showToast('Optimizing database...', 'info'); - } - - // Simulate optimization process - setTimeout(() => { - // In a real app, this would optimize the database via API - if (window.authManager) { - window.authManager.showToast('Database optimization completed', 'success'); - } - }, 3000); - } - } - - refresh() { - this.loadSettings(); - this.loadSystemInfo(); + // ... } } -// Initialize settings page when needed window.initSettings = async () => { window.settingsPage = new SettingsPage(); }; - -// Export for use in other modules -if (typeof module !== 'undefined' && module.exports) { - module.exports = SettingsPage; -} \ No newline at end of file