import * as plugins from '../plugins.js'; import * as shared from './shared/index.js'; import * as appstate from '../appstate.js'; import { DeesElement, customElement, html, state, css, cssManager, } from '@design.estate/dees-element'; @customElement('ops-view-logs') export class OpsViewLogs extends DeesElement { @state() accessor logState: appstate.ILogState = { recentLogs: [], isStreaming: false, filters: {}, }; @state() accessor filterLevel: string | undefined; @state() accessor filterCategory: string | undefined; @state() accessor filterLimit: number = 100; constructor() { super(); const subscription = appstate.logStatePart .select((stateArg) => stateArg) .subscribe((logState) => { this.logState = logState; }); this.rxSubscriptions.push(subscription); } public static styles = [ cssManager.defaultStyles, shared.viewHostCss, css` .controls { display: flex; gap: 16px; margin-bottom: 24px; flex-wrap: wrap; } .filterGroup { display: flex; align-items: center; gap: 8px; } `, ]; public render() { return html` Logs
this.fetchLogs()} > Refresh Logs
this.updateFilter('level', e.detail)} >
this.updateFilter('category', e.detail)} >
this.updateFilter('limit', e.detail)} >
`; } async connectedCallback() { super.connectedCallback(); this.fetchLogs(); } async updated(changedProperties: Map) { super.updated(changedProperties); if (changedProperties.has('logState')) { this.pushLogsToChart(); } } private async pushLogsToChart() { const chartLog = this.shadowRoot?.querySelector('dees-chart-log') as any; if (!chartLog) return; // Ensure the chart element has finished its own initialization await chartLog.updateComplete; chartLog.clearLogs(); const entries = this.getMappedLogEntries(); if (entries.length > 0) { chartLog.updateLog(entries); } } private getMappedLogEntries() { return this.logState.recentLogs.map((log) => ({ timestamp: new Date(log.timestamp).toISOString(), level: log.level as 'debug' | 'info' | 'warn' | 'error', message: log.message, source: log.category, })); } private async fetchLogs() { await appstate.logStatePart.dispatchAction(appstate.fetchRecentLogsAction, { limit: this.filterLimit, level: this.filterLevel as 'debug' | 'info' | 'warn' | 'error' | undefined, category: this.filterCategory as 'smtp' | 'dns' | 'security' | 'system' | 'email' | undefined, }); } private updateFilter(type: string, value: string) { const resolved = value === 'all' ? undefined : value; switch (type) { case 'level': this.filterLevel = resolved; break; case 'category': this.filterCategory = resolved; break; case 'limit': this.filterLimit = resolved ? parseInt(resolved, 10) : 100; break; } this.fetchLogs(); } }