// noqa: js-006 - async init pattern is safe, loadData has try/catch // static/admin/js/logs.js // noqa: JS-003 - Uses ...baseData which is data() with safety check const logsLog = window.LogConfig?.loggers?.logs || console; function adminLogs() { // Get base data with safety check for standalone usage 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: [], stats: { total_count: 0, warning_count: 0, error_count: 0, critical_count: 0 }, selectedLog: null, filters: { level: '', module: '', search: '' }, pagination: { page: 1, per_page: 20, total: 0, pages: 0 }, logFiles: [], selectedFile: '', fileContent: null, // Computed: Total pages get totalPages() { return this.pagination.pages; }, // Computed: Start index for pagination display get startIndex() { if (this.pagination.total === 0) return 0; return (this.pagination.page - 1) * this.pagination.per_page + 1; }, // Computed: End index for pagination display get endIndex() { const end = this.pagination.page * this.pagination.per_page; return end > this.pagination.total ? this.pagination.total : end; }, // Computed: Page numbers for pagination get pageNumbers() { const pages = []; const totalPages = this.totalPages; const current = this.pagination.page; if (totalPages <= 7) { for (let i = 1; i <= totalPages; i++) { pages.push(i); } } else { pages.push(1); if (current > 3) { pages.push('...'); } const start = Math.max(2, current - 1); const end = Math.min(totalPages - 1, current + 1); for (let i = start; i <= end; i++) { pages.push(i); } if (current < totalPages - 2) { pages.push('...'); } pages.push(totalPages); } return pages; }, async init() { // Guard against multiple initialization if (window._adminLogsInitialized) { logsLog.warn('Already initialized, skipping'); return; } window._adminLogsInitialized = true; logsLog.info('=== LOGS PAGE INITIALIZING ==='); // Load platform settings for rows per page if (window.PlatformSettings) { this.pagination.per_page = await window.PlatformSettings.getRowsPerPage(); } 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.pagination.page - 1) * this.pagination.per_page); params.append('limit', this.pagination.per_page); const data = await apiClient.get(`/admin/logs/database?${params}`); this.logs = data.logs; this.pagination.total = data.total; this.pagination.pages = Math.ceil(this.pagination.total / this.pagination.per_page); logsLog.info(`Loaded ${this.logs.length} logs (total: ${this.pagination.total})`); } 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 const url = `/api/v1/admin/logs/files/${this.selectedFile}/download`; window.open(`${url}?token=${token}`, '_blank'); // noqa: sec-022 } catch (error) { logsLog.error('Failed to download log file:', error); this.error = 'Failed to download log file'; } }, resetFilters() { this.filters = { level: '', module: '', search: '' }; this.pagination.page = 1; this.loadLogs(); }, previousPage() { if (this.pagination.page > 1) { this.pagination.page--; this.loadLogs(); } }, nextPage() { if (this.pagination.page < this.totalPages) { this.pagination.page++; this.loadLogs(); } }, goToPage(pageNum) { if (pageNum !== '...' && pageNum >= 1 && pageNum <= this.totalPages) { this.pagination.page = pageNum; this.loadLogs(); } }, showLogDetail(log) { this.selectedLog = log; }, formatTimestamp(timestamp) { return new Date(timestamp).toLocaleString(); } }; } logsLog.info('Logs module loaded');