This commit is contained in:
2026-04-29 11:08:00 +07:00
parent d09abd2500
commit 3141a14036

View File

@@ -758,8 +758,6 @@
<input type="file" id="file-input" accept=".log,.txt,.json,text/plain"> <input type="file" id="file-input" accept=".log,.txt,.json,text/plain">
</div> </div>
<div id="log-container">
<!-- Filter bar -->
<div id="filter-bar"> <div id="filter-bar">
<div id="search-wrap"> <div id="search-wrap">
<svg width="13" height="13" viewBox="0 0 16 16" fill="none"> <svg width="13" height="13" viewBox="0 0 16 16" fill="none">
@@ -810,8 +808,7 @@
<!-- Empty state / Table area --> <!-- Empty state / Table area -->
<div id="empty-state"> <div id="empty-state">
<svg width="48" height="48" viewBox="0 0 48 48" fill="none"> <svg width="48" height="48" viewBox="0 0 48 48" fill="none">
<rect x="6" y="6" width="36" height="36" rx="6" stroke="currentColor" stroke-width="1.5" <rect x="6" y="6" width="36" height="36" rx="6" stroke="currentColor" stroke-width="1.5" stroke-dasharray="5 3" />
stroke-dasharray="5 3" />
<path d="M16 20h16M16 24h10M16 28h12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" /> <path d="M16 20h16M16 24h10M16 28h12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" />
</svg> </svg>
<div class="es-title">No log file loaded</div> <div class="es-title">No log file loaded</div>
@@ -848,8 +845,6 @@
<div class="spinner"></div> <div class="spinner"></div>
<p>Loading Data...</p> <p>Loading Data...</p>
</div> </div>
</div>
<script> <script>
// ---- State ---- // ---- State ----
let allLogs = []; let allLogs = [];
@@ -863,6 +858,8 @@
let chart = null; let chart = null;
let chartBuckets = []; let chartBuckets = [];
const msg_len_limit = 100; const msg_len_limit = 100;
let currentPage = 1;
const PAGE_SIZE = 500;
// ---- Demo data generator ---- // ---- Demo data generator ----
function generateDemoLogs() { function generateDemoLogs() {
@@ -1148,6 +1145,7 @@
// ---- Filtering ---- // ---- Filtering ----
function applyTimeFilter(start, end) { function applyTimeFilter(start, end) {
showLoading() showLoading()
currentPage = 1;
timeFilter = { start, end }; timeFilter = { start, end };
const startD = new Date(start), endD = new Date(end); const startD = new Date(start), endD = new Date(end);
document.getElementById('time-badge-label').textContent = document.getElementById('time-badge-label').textContent =
@@ -1160,6 +1158,7 @@
function clearTimeFilter() { function clearTimeFilter() {
showLoading() showLoading()
currentPage = 1;
timeFilter = null; timeFilter = null;
document.getElementById('time-badge').classList.remove('visible'); document.getElementById('time-badge').classList.remove('visible');
if (chart) chart.resetZoom(); if (chart) chart.resetZoom();
@@ -1169,6 +1168,7 @@
} }
function applyFilters() { function applyFilters() {
currentPage = 1;
let regex = null; let regex = null;
const searchVal = document.getElementById('search').value; const searchVal = document.getElementById('search').value;
const searchEl = document.getElementById('search'); const searchEl = document.getElementById('search');
@@ -1204,11 +1204,15 @@
return sortDir === 'asc' ? (av > bv ? 1 : -1) : (av < bv ? 1 : -1); return sortDir === 'asc' ? (av > bv ? 1 : -1) : (av < bv ? 1 : -1);
}); });
const totalPages = Math.max(1, Math.ceil(sorted.length / PAGE_SIZE));
currentPage = Math.min(currentPage, totalPages);
const pageData = sorted.slice((currentPage - 1) * PAGE_SIZE, currentPage * PAGE_SIZE);
expandedRows.clear(); expandedRows.clear();
const tbody = document.getElementById('log-tbody'); const tbody = document.getElementById('log-tbody');
tbody.innerHTML = ''; tbody.innerHTML = '';
sorted.forEach((log, idx) => { pageData.forEach((log, idx) => {
const tr = document.createElement('tr'); const tr = document.createElement('tr');
tr.className = 'fade-in'; tr.className = 'fade-in';
tr.dataset.idx = idx; tr.dataset.idx = idx;
@@ -1221,6 +1225,8 @@
tbody.appendChild(tr); tbody.appendChild(tr);
}); });
renderPager(totalPages);
// Sort indicators // Sort indicators
document.querySelectorAll('thead th').forEach(th => { document.querySelectorAll('thead th').forEach(th => {
th.classList.remove('sort-asc', 'sort-desc'); th.classList.remove('sort-asc', 'sort-desc');
@@ -1228,6 +1234,37 @@
}); });
} }
function renderPager(totalPages) {
let el = document.getElementById('pager');
if (!el) {
el = document.createElement('div');
el.id = 'pager';
el.style.cssText = 'display:flex;align-items:center;gap:8px;padding:8px 20px;border-top:1px solid var(--border);background:var(--surface);font-size:11px;font-family:var(--font-mono);color:var(--text2);flex-shrink:0';
document.getElementById('status-bar').before(el);
}
const btn = (label, page, disabled) =>
`<button onclick="goPage(${page})" ${disabled ? 'disabled' : ''} style="padding:3px 9px;border-radius:var(--radius);border:1px solid var(--border2);background:${page === currentPage ? 'var(--accent-dim)' : 'transparent'};color:${page === currentPage ? 'var(--accent)' : 'var(--text2)'};cursor:${disabled ? 'default' : 'pointer'};font-family:var(--font-mono);font-size:11px">${label}</button>`;
const pages = [];
for (let p = 1; p <= totalPages; p++) {
if (p === 1 || p === totalPages || Math.abs(p - currentPage) <= 1) pages.push(p);
else if (pages[pages.length - 1] !== '…') pages.push('…');
}
el.innerHTML = btn('', currentPage - 1, currentPage === 1)
+ pages.map(p => p === '…' ? `<span style="color:var(--text3)">…</span>` : btn(p, p, false)).join('')
+ btn('', currentPage + 1, currentPage === totalPages)
+ `<span style="margin-left:8px;color:var(--text3)">page ${currentPage} / ${totalPages}</span>`;
}
window.goPage = function (p) {
const totalPages = Math.ceil(filteredLogs.length / PAGE_SIZE);
if (p < 1 || p > totalPages) return;
currentPage = p;
renderTable();
document.getElementById('dt-wrap').scrollTop = 0;
};
function toggleDetail(tr, log, idx) { function toggleDetail(tr, log, idx) {
if (expandedRows.has(idx)) { if (expandedRows.has(idx)) {
expandedRows.delete(idx); expandedRows.delete(idx);