feat(admin): refactor logs viewer with table display and detailed dialog

Backend changes:
- Update LogsHandler.php to parse Monolog logs using regex
- Add parseLogLines() method to extract structured data from logs
- Support ISO 8601 format with microseconds and timezone
- Parse JSON context with nested objects and escaped characters support
- Add formatDateTime() method for readable date formatting
- Add findJsonEnd() method for correct JSON object extraction
- Return data in JSON format instead of plain string

Frontend changes:
- Update logs.js store: change data structure from string to array of objects
- Add loading flag for loading indicator
- Remove caching check for data freshness

- Completely refactor LogsViewer.vue component:
  * Replace textarea with PrimeVue DataTable with pagination and sorting
  * Add "Actions" column with view button (eye icon)
  * Use Badge component for log levels with color indicators
  * Remove "Context" column from table (unreadable in table view)
  * Add dialog with detailed log information:
    - Date and time (formatted and raw)
    - Level with color indicator
    - Channel
    - Message
    - Context (formatted JSON)
    - Raw string
  * Add word wrap for all text fields in dialog
  * Dialog closes on outside click (dismissableMask)
  * Configure pagination: 15 records per page by default

UX improvements:
- Improved log readability with structured display
- Easy navigation through large number of records via pagination
- Quick access to detailed information through dialog
- Color-coded levels for quick visual assessment
This commit is contained in:
2025-11-24 00:07:12 +03:00
committed by Nikita Kiselev
parent 7a5eebec91
commit b39a344a7d
3 changed files with 328 additions and 11 deletions

View File

@@ -3,14 +3,19 @@ import {apiGet} from "@/utils/http.js";
export const useLogsStore = defineStore('logs', {
state: () => ({
lines: '',
logs: [],
loading: false,
}),
actions: {
async fetchLogsFromServer() {
if (this.lines) return;
const response = await apiGet('getLogs');
this.lines = response.data;
this.loading = true;
try {
const response = await apiGet('getLogs');
this.logs = response.data || [];
} finally {
this.loading = false;
}
},
},
});