fix(logs): track the All lines state locally and show loading in the lines control

The All button read $wire.numberOfLines, which does not update while the user
types or pastes a new number, so All stayed highlighted. Keep the state in
Alpine instead: All loads set it, and any input in the number field clears it
unless the value is -1.

Show a spinner in the All button while all logs load, and in place of the
Lines label while a new line count loads. Both keep their width.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Andras Bacsai
2026-09-28 11:18:57 +02:00
co-authored by Claude Opus 5.5
parent eed50d6781
commit 6c3249d324
2 changed files with 31 additions and 6 deletions
+17
View File
@@ -158,6 +158,9 @@ export function initializeRuntimeLogsComponent() {
containerName: config.containerName ?? 'logs',
findShortcutLabel: /Mac|iPhone|iPad/.test(navigator.platform) ? '⌘F' : 'Ctrl+F',
logsLoaded: false,
allLines: false,
loadingAll: false,
loadingLines: false,
loading: false,
fullscreen: false,
alwaysScroll: false,
@@ -178,6 +181,7 @@ export function initializeRuntimeLogsComponent() {
scrollMargin: 0,
init() {
this.allLines = Number(this.$wire.numberOfLines) === -1;
this.$watch('searchQuery', () => this.applyFilters());
this.$nextTick(() => this.mountVirtualizer());
streamTimer = setInterval(() => this.streamTick(), STREAM_INTERVAL_MS);
@@ -257,13 +261,26 @@ export function initializeRuntimeLogsComponent() {
}
},
async refreshLines() {
if (this.loading) return;
this.loadingLines = true;
try {
await this.refresh();
} finally {
this.loadingLines = false;
}
},
async showAllLogs() {
if (this.loading) return;
this.loading = true;
this.loadingAll = true;
try {
this.replaceLines(await this.$wire.showAllLogs());
this.allLines = true;
} finally {
this.loading = false;
this.loadingAll = false;
}
},
@@ -215,15 +215,23 @@
</div>
<div class="logs-viewer-end runtime-logs-viewer-end">
<div class="logs-viewer-meta">
<form x-on:submit.prevent="refresh()" class="logs-viewer-lines runtime-log-lines-group">
<span class="logs-viewer-lines-label">Lines</span>
<input type="number" wire:model="numberOfLines" placeholder="100" min="-1" max="50000"
<form x-on:submit.prevent="refreshLines()" class="logs-viewer-lines runtime-log-lines-group">
<span class="logs-viewer-lines-label relative" :aria-busy="loadingLines">
<span :class="loadingLines ? 'invisible' : ''">Lines</span>
<x-loading compact x-cloak x-show="loadingLines" aria-label="Loading logs"
class="absolute inset-0 text-inherit!" />
</span>
<input type="number" wire:model="numberOfLines" x-on:input="allLines = Number($event.target.value) === -1" placeholder="100" min="-1" max="50000"
title="Number of lines (max 50,000; use -1 for all)" {{ $streamLogs ? 'readonly' : '' }}
class="input logs-viewer-lines-input" />
<button type="button" x-on:click="showAllLogs()" title="Show all logs"
:class="$wire.numberOfLines == -1 ? 'runtime-log-lines-all-active' : ''"
:aria-pressed="$wire.numberOfLines == -1"
class="runtime-log-lines-all" {{ $streamLogs ? 'disabled' : '' }}>All</button>
:class="allLines ? 'runtime-log-lines-all-active' : ''"
:aria-pressed="allLines" :aria-busy="loadingAll"
class="runtime-log-lines-all relative" {{ $streamLogs ? 'disabled' : '' }}>
<span :class="loadingAll ? 'invisible' : ''">All</span>
<x-loading compact x-cloak x-show="loadingAll" aria-label="Loading all logs"
class="absolute inset-0 text-inherit!" />
</button>
</form>
</div>
<div class="logs-viewer-search relative">