diff --git a/renderer/app.js b/renderer/app.js index 8d5871e..c5578ac 100644 --- a/renderer/app.js +++ b/renderer/app.js @@ -811,8 +811,7 @@ function renderQueueTable() { _lastVisibleRange = { start: -1, end: -1 }; } } else { - // Virtual scrolling for large queues — force re-render - _lastVisibleRange = { start: -1, end: -1 }; + // Virtual scrolling for large queues — in-place update when range unchanged _renderVirtualRows(tbody); } @@ -847,8 +846,18 @@ function _renderVirtualRows(tbody) { const startIdx = Math.max(0, Math.floor(scrollTop / VIRTUAL_ROW_HEIGHT) - VIRTUAL_OVERSCAN); const endIdx = Math.min(totalRows, Math.ceil((scrollTop + viewportHeight) / VIRTUAL_ROW_HEIGHT) + VIRTUAL_OVERSCAN); - // Only re-render if visible range changed - if (startIdx === _lastVisibleRange.start && endIdx === _lastVisibleRange.end) return; + // Same range — try in-place update to avoid hover flicker + if (startIdx === _lastVisibleRange.start && endIdx === _lastVisibleRange.end) { + const rows = tbody.querySelectorAll('.queue-row'); + if (rows.length === endIdx - startIdx) { + for (let i = 0; i < rows.length; i++) { + const job = _sortedJobsCache[startIdx + i]; + if (rows[i].dataset.jobId !== job.id) { break; } // identity mismatch, full rebuild below + _updateRowInPlace(rows[i], job); + } + return; + } + } _lastVisibleRange = { start: startIdx, end: endIdx }; const topPad = startIdx * VIRTUAL_ROW_HEIGHT;