/** * ActivityLogView — Storico Attività * Displays the local SQLite activity log with filters, dual pagination, * and an expandable JSON detail panel. */ const ActivityLogView = { currentPage: 1, perPage: 50, filters: { esito: '', agente_id: '', da: '', a: '' }, async render() { this.currentPage = 1; const container = document.getElementById('view-container'); container.innerHTML = '

Caricamento storico...

'; await this._draw(); }, async _draw() { const container = document.getElementById('view-container'); try { const params = new URLSearchParams({ page: this.currentPage, per_page: this.perPage, }); if (this.filters.esito) params.set('esito', this.filters.esito); if (this.filters.agente_id) params.set('agente_id', this.filters.agente_id); if (this.filters.da) params.set('da', this.filters.da); if (this.filters.a) params.set('a', this.filters.a); const data = await App.api(`/api/attivita?${params}`); const { rows, total, page, per_page, total_pages } = data; container.innerHTML = this._buildHtml(rows, total, page, per_page, total_pages); this._bind(); } catch (err) { container.innerHTML = `

Errore caricamento: ${App.escapeHtml(err.message)}

`; } }, _buildHtml(rows, total, page, per_page, total_pages) { const filtersHtml = this._buildFilters(); const paginationHtml = this._buildPagination(total, page, per_page, total_pages); const tableHtml = rows.length === 0 ? `

Nessuna attività registrata.

` : `
${rows.map(r => this._buildRow(r)).join('')}
Data/Ora Agente Azione Esito
`; return `
Storico Attività ${total} record
${filtersHtml} ${paginationHtml} ${tableHtml} ${rows.length > 0 ? paginationHtml.replace(/id="pagination-top"/g,'id="pagination-bottom"') : ''} `; }, _buildRow(r) { const dt = r.creato_il ? new Date(r.creato_il).toLocaleString('it-IT') : '—'; const esitoBadge = r.esito === 'successo' ? `✓ successo` : `✕ errore`; return ` ${dt} ${App.escapeHtml(r.agente_nome || '—')} ${App.escapeHtml(r.titolo_azione)} ${esitoBadge}
${App.escapeHtml(this._prettyJson(r.azione))}
`; }, _prettyJson(str) { try { return JSON.stringify(JSON.parse(str), null, 2); } catch (_) { return str || ''; } }, _buildFilters() { return `
`; }, _buildPagination(total, page, per_page, total_pages) { if (total_pages <= 1) return ''; const from = (page - 1) * per_page + 1; const to = Math.min(page * per_page, total); const pageBtn = (p, label, disabled, active) => { const isDisabled = disabled || p === page; return ``; }; const pages = []; pages.push(pageBtn(1, '«', page === 1, false)); pages.push(pageBtn(page - 1, '‹', page === 1, false)); const rangeStart = Math.max(1, page - 2); const rangeEnd = Math.min(total_pages, page + 2); for (let p = rangeStart; p <= rangeEnd; p++) { pages.push(pageBtn(p, p, false, p === page)); } pages.push(pageBtn(page + 1, '›', page === total_pages, false)); pages.push(pageBtn(total_pages, '»', page === total_pages, false)); return `
Record ${from}–${to} di ${total}
${pages.join('')}
`; }, _bind() { // Filter apply document.getElementById('btn-apply-filters')?.addEventListener('click', () => { this.filters.esito = document.getElementById('filter-esito')?.value || ''; this.filters.da = document.getElementById('filter-da')?.value || ''; this.filters.a = document.getElementById('filter-a')?.value || ''; this.currentPage = 1; this._draw(); }); // Filter reset document.getElementById('btn-reset-filters')?.addEventListener('click', () => { this.filters = { esito: '', agente_id: '', da: '', a: '' }; this.currentPage = 1; this._draw(); }); // Detail expand/collapse document.querySelectorAll('.act-detail-btn').forEach(btn => { btn.addEventListener('click', () => { const rowId = btn.dataset.id; const detailRow = document.getElementById(`detail-${rowId}`); if (!detailRow) return; const isOpen = detailRow.style.display !== 'none'; detailRow.style.display = isOpen ? 'none' : 'table-row'; btn.textContent = isOpen ? '≡' : '✕'; }); }); // Pagination buttons (top and bottom share same .page-btn class) document.querySelectorAll('.page-btn').forEach(btn => { btn.addEventListener('click', () => { const p = parseInt(btn.dataset.page, 10); if (!isNaN(p)) { this.currentPage = p; this._draw(); document.getElementById('view-container')?.scrollIntoView({ behavior: 'smooth', block: 'start' }); } }); }); }, };