// static/admin/js/logs.js const logsLog = window.LogConfig?.loggers?.logs || console; function adminLogs() { // Get base data const baseData = typeof data === 'function' ? data() : {}; return { // Inherit base layout functionality from init-alpine.js ...baseData, // Logs-specific state currentPage: 'logs', loading: true, error: null, successMessage: null, logSource: 'database', logs: [], totalLogs: 0, stats: { total_count: 0, warning_count: 0, error_count: 0, critical_count: 0 }, selectedLog: null, filters: { level: '', module: '', search: '', skip: 0, limit: 50 }, logFiles: [], selectedFile: '', fileContent: null, async init() { logsLog.info('=== LOGS PAGE INITIALIZING ==='); await this.loadStats(); await this.loadLogs(); }, async refresh() { this.error = null; this.successMessage = null; await this.loadStats(); if (this.logSource === 'database') { await this.loadLogs(); } else { await this.loadFileLogs(); } }, async loadStats() { try { const data = await apiClient.get('/admin/logs/statistics?days=7'); this.stats = data; logsLog.info('Log statistics loaded:', this.stats); } catch (error) { logsLog.error('Failed to load log statistics:', error); } }, async loadLogs() { this.loading = true; this.error = null; try { const params = new URLSearchParams(); if (this.filters.level) params.append('level', this.filters.level); if (this.filters.module) params.append('module', this.filters.module); if (this.filters.search) params.append('search', this.filters.search); params.append('skip', this.filters.skip); params.append('limit', this.filters.limit); const data = await apiClient.get(`/admin/logs/database?${params}`); this.logs = data.logs; this.totalLogs = data.total; logsLog.info(`Loaded ${this.logs.length} logs (total: ${this.totalLogs})`); } catch (error) { logsLog.error('Failed to load logs:', error); this.error = error.response?.data?.detail || 'Failed to load logs'; } finally { this.loading = false; } }, async loadFileLogs() { this.loading = true; this.error = null; try { const data = await apiClient.get('/admin/logs/files'); this.logFiles = data.files; if (this.logFiles.length > 0 && !this.selectedFile) { this.selectedFile = this.logFiles[0].filename; await this.loadFileContent(); } logsLog.info(`Loaded ${this.logFiles.length} log files`); } catch (error) { logsLog.error('Failed to load log files:', error); this.error = error.response?.data?.detail || 'Failed to load log files'; } finally { this.loading = false; } }, async loadFileContent() { if (!this.selectedFile) return; this.loading = true; this.error = null; try { const data = await apiClient.get(`/admin/logs/files/${this.selectedFile}?lines=500`); this.fileContent = data; logsLog.info(`Loaded file content for ${this.selectedFile}`); } catch (error) { logsLog.error('Failed to load file content:', error); this.error = error.response?.data?.detail || 'Failed to load file content'; } finally { this.loading = false; } }, async downloadLogFile() { if (!this.selectedFile) return; try { const token = localStorage.getItem('admin_token'); // Note: window.open bypasses apiClient, so we need the full path window.open(`/api/v1/admin/logs/files/${this.selectedFile}/download?token=${token}`, '_blank'); } catch (error) { logsLog.error('Failed to download log file:', error); this.error = 'Failed to download log file'; } }, resetFilters() { this.filters = { level: '', module: '', search: '', skip: 0, limit: 50 }; this.loadLogs(); }, nextPage() { this.filters.skip += this.filters.limit; this.loadLogs(); }, previousPage() { this.filters.skip = Math.max(0, this.filters.skip - this.filters.limit); this.loadLogs(); }, showLogDetail(log) { this.selectedLog = log; }, formatTimestamp(timestamp) { return new Date(timestamp).toLocaleString(); } }; } logsLog.info('Logs module loaded');