diff --git a/internal/web/handler.go b/internal/web/handler.go index dbffa38..7e7a8ea 100644 --- a/internal/web/handler.go +++ b/internal/web/handler.go @@ -949,7 +949,7 @@ const queryLogHTML = ` .panel-actions { display: flex; align-items: center; gap: .65rem; flex-wrap: wrap; } .panel-actions .spacer { flex: 1; } .table-panel { padding: 1rem; } - .tabulator-shell { border: 1px solid #1e293b; border-radius: .75rem; overflow: hidden; } + .tabulator-shell { border: 1px solid #1e293b; border-radius: .75rem; overflow: hidden; width: 100%; } #requests-table { width: 100%; } button { display: inline-flex; align-items: center; justify-content: center; gap: .35rem; border-radius: .45rem; padding: .3rem .75rem; font-size: .9rem; white-space: nowrap; background: #2563eb; color: white; border: 0; cursor: pointer; } button.secondary { background: #475569; } @@ -989,13 +989,17 @@ const queryLogHTML = ` .action-icon { width: 1.9rem; height: 1.9rem; padding: 0; border-radius: .5rem; display: inline-flex; align-items: center; justify-content: center; border: 0; cursor: pointer; font-size: .95rem; } .action-icon.block { background: #dc2626; color: white; } .action-icon.unblock { background: #475569; color: white; } - .tabulator { background: transparent; border: 0; font-size: .92rem; } + .tabulator { background: transparent; border: 0; font-size: .92rem; width: 100% !important; } .tabulator .tabulator-header { background: #0f172a; border-bottom: 1px solid #334155; } + .tabulator .tabulator-header .tabulator-header-contents { width: 100% !important; } + .tabulator .tabulator-header .tabulator-header-contents .tabulator-headers { display: block; min-width: 100% !important; width: 100% !important; } .tabulator .tabulator-header .tabulator-col { background: #0f172a; border-right: 1px solid #1e293b; } .tabulator .tabulator-header .tabulator-col.tabulator-sortable:hover { background: #111827; } .tabulator .tabulator-header .tabulator-col .tabulator-col-content { padding: .75rem .65rem; } .tabulator .tabulator-row { background: #111827; border-bottom: 1px solid #1e293b; } .tabulator .tabulator-row:nth-child(even) { background: rgba(15, 23, 42, .55); } + .tabulator .tabulator-tableholder { width: 100% !important; } + .tabulator .tabulator-tableholder .tabulator-table { min-width: 100% !important; width: 100% !important; } .tabulator .tabulator-cell { padding: .55rem .65rem; border-right: 1px solid #1e293b; color: #e2e8f0; } .tabulator .tabulator-footer { background: #0b1120; border-top: 1px solid #334155; color: #cbd5e1; } .tabulator .tabulator-footer .tabulator-paginator { color: #cbd5e1; } @@ -1409,6 +1413,16 @@ const queryLogHTML = ` return; } window.requestAnimationFrame(function() { + const header = document.querySelector('#requests-table .tabulator-header .tabulator-headers'); + if (header) { + header.style.width = '100%'; + header.style.minWidth = '100%'; + } + const body = document.querySelector('#requests-table .tabulator-tableholder .tabulator-table'); + if (body) { + body.style.width = '100%'; + body.style.minWidth = '100%'; + } table.redraw(true); }); } @@ -1656,6 +1670,10 @@ const queryLogHTML = ` scheduleRefresh(); }); + table.on('columnVisibilityChanged', function() { + relayoutTable(); + }); + table.on('dataLoadError', function(error) { document.getElementById('table-status').textContent = String(error || 'Unable to load requests.'); scheduleRefresh(); diff --git a/internal/web/handler_test.go b/internal/web/handler_test.go index bfef234..b6b94bb 100644 --- a/internal/web/handler_test.go +++ b/internal/web/handler_test.go @@ -199,6 +199,9 @@ func TestHandlerServesOverviewAndManualActions(t *testing.T) { if !strings.Contains(queryLogBody, `/assets/tabulator/tabulator.min.js`) || !strings.Contains(queryLogBody, `/assets/tabulator/tabulator_midnight.min.css`) { t.Fatalf("requests log page should load local tabulator assets") } + if !strings.Contains(queryLogBody, `.tabulator .tabulator-tableholder .tabulator-table { min-width: 100% !important; width: 100% !important; }`) { + t.Fatalf("requests log page should keep the tabulator body at full width") + } if !strings.Contains(queryLogBody, "Source") || !strings.Contains(queryLogBody, "Bots") || !strings.Contains(queryLogBody, "HTTP status") { t.Fatalf("requests log page should expose source, bot, and status filters") }