Fix text selection issue in runtime logs view
Apply the same selection preservation fix to the runtime logs component (get-logs.blade.php) that was applied to deployment logs: - Add hasActiveLogSelection() helper to detect active text selection - Skip re-render when user has text selected (preserves copy ability) - Add renderTrigger mechanism to ensure filtering works after refresh - Use x-effect for hidden state to properly react to Livewire updates 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
d40c2caca2
commit
5cc822c996
1 changed files with 27 additions and 2 deletions
|
|
@ -9,6 +9,7 @@
|
||||||
scrollDebounce: null,
|
scrollDebounce: null,
|
||||||
colorLogs: localStorage.getItem('coolify-color-logs') === 'true',
|
colorLogs: localStorage.getItem('coolify-color-logs') === 'true',
|
||||||
searchQuery: '',
|
searchQuery: '',
|
||||||
|
renderTrigger: 0,
|
||||||
containerName: '{{ $container ?? "logs" }}',
|
containerName: '{{ $container ?? "logs" }}',
|
||||||
makeFullscreen() {
|
makeFullscreen() {
|
||||||
this.fullscreen = !this.fullscreen;
|
this.fullscreen = !this.fullscreen;
|
||||||
|
|
@ -80,6 +81,18 @@
|
||||||
if (!this.searchQuery.trim()) return true;
|
if (!this.searchQuery.trim()) return true;
|
||||||
return line.toLowerCase().includes(this.searchQuery.toLowerCase());
|
return line.toLowerCase().includes(this.searchQuery.toLowerCase());
|
||||||
},
|
},
|
||||||
|
hasActiveLogSelection() {
|
||||||
|
const selection = window.getSelection();
|
||||||
|
if (!selection || selection.isCollapsed || !selection.toString().trim()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const logsContainer = document.getElementById('logs');
|
||||||
|
if (!logsContainer) return false;
|
||||||
|
|
||||||
|
// Check if selection is within the logs container
|
||||||
|
const range = selection.getRangeAt(0);
|
||||||
|
return logsContainer.contains(range.commonAncestorContainer);
|
||||||
|
},
|
||||||
decodeHtml(text) {
|
decodeHtml(text) {
|
||||||
// Decode HTML entities, handling double-encoding with max iteration limit to prevent DoS
|
// Decode HTML entities, handling double-encoding with max iteration limit to prevent DoS
|
||||||
let decoded = text;
|
let decoded = text;
|
||||||
|
|
@ -96,6 +109,12 @@
|
||||||
return decoded;
|
return decoded;
|
||||||
},
|
},
|
||||||
renderHighlightedLog(el, text) {
|
renderHighlightedLog(el, text) {
|
||||||
|
// Skip re-render if user has text selected in logs (preserves copy ability)
|
||||||
|
// But always render if the element is empty (initial render)
|
||||||
|
if (el.textContent && this.hasActiveLogSelection()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const decoded = this.decodeHtml(text);
|
const decoded = this.decodeHtml(text);
|
||||||
el.textContent = '';
|
el.textContent = '';
|
||||||
|
|
||||||
|
|
@ -167,6 +186,12 @@
|
||||||
this.$wire.getLogs(true);
|
this.$wire.getLogs(true);
|
||||||
this.logsLoaded = true;
|
this.logsLoaded = true;
|
||||||
}
|
}
|
||||||
|
// Re-render logs after Livewire updates
|
||||||
|
Livewire.hook('commit', ({ succeed }) => {
|
||||||
|
succeed(() => {
|
||||||
|
this.$nextTick(() => { this.renderTrigger++; });
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}">
|
}">
|
||||||
@if ($collapsible)
|
@if ($collapsible)
|
||||||
|
|
@ -350,8 +375,8 @@ class="text-gray-500 dark:text-gray-400 py-2">
|
||||||
|
|
||||||
@endphp
|
@endphp
|
||||||
<div data-log-line data-log-content="{{ $line }}"
|
<div data-log-line data-log-content="{{ $line }}"
|
||||||
|
x-effect="renderTrigger; searchQuery; $el.classList.toggle('hidden', !matchesSearch($el.dataset.logContent))"
|
||||||
x-bind:class="{
|
x-bind:class="{
|
||||||
'hidden': !matchesSearch($el.dataset.logContent),
|
|
||||||
'bg-red-500/10 dark:bg-red-500/15': colorLogs && getLogLevel($el.dataset.logContent) === 'error',
|
'bg-red-500/10 dark:bg-red-500/15': colorLogs && getLogLevel($el.dataset.logContent) === 'error',
|
||||||
'bg-yellow-500/10 dark:bg-yellow-500/15': colorLogs && getLogLevel($el.dataset.logContent) === 'warning',
|
'bg-yellow-500/10 dark:bg-yellow-500/15': colorLogs && getLogLevel($el.dataset.logContent) === 'warning',
|
||||||
'bg-purple-500/10 dark:bg-purple-500/15': colorLogs && getLogLevel($el.dataset.logContent) === 'debug',
|
'bg-purple-500/10 dark:bg-purple-500/15': colorLogs && getLogLevel($el.dataset.logContent) === 'debug',
|
||||||
|
|
@ -362,7 +387,7 @@ class="flex gap-2">
|
||||||
<span class="shrink-0 text-gray-500">{{ $timestamp }}</span>
|
<span class="shrink-0 text-gray-500">{{ $timestamp }}</span>
|
||||||
@endif
|
@endif
|
||||||
<span data-line-text="{{ $logContent }}"
|
<span data-line-text="{{ $logContent }}"
|
||||||
x-effect="searchQuery; renderHighlightedLog($el, $el.dataset.lineText)"
|
x-effect="renderTrigger; searchQuery; renderHighlightedLog($el, $el.dataset.lineText)"
|
||||||
class="whitespace-pre-wrap break-all"></span>
|
class="whitespace-pre-wrap break-all"></span>
|
||||||
</div>
|
</div>
|
||||||
@endforeach
|
@endforeach
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue