From 15c85e874c7015ccd1328a156e33202e4873e4e1 Mon Sep 17 00:00:00 2001 From: kodi Date: Sat, 14 Mar 2026 16:12:40 +0100 Subject: [PATCH] fix: log/tasks rendering --- .../test_ui_smoke_golden.cpython-313.pyc | Bin 45823 -> 46767 bytes .../tests/golden/test_ui_smoke_golden.py | 10 +++++++ webui/html/app.js | 26 ++++++++++++++++-- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/webui/backend/tests/golden/__pycache__/test_ui_smoke_golden.cpython-313.pyc b/webui/backend/tests/golden/__pycache__/test_ui_smoke_golden.cpython-313.pyc index cf7f37e935bcae0ef49f2854540642cfc278a9a4..73f90cf00fecc8259858481109a081a17d84121e 100644 GIT binary patch delta 1148 zcmaJW5q=WnYp5O2P#{aqd^k%y@oH5jk|SsqbhJtQRvn{*I}Rh-4c8s1@V3CDE1u?*W&?D%)8Jxr3d)B-b1EvpXv4T4 zVe|!PgC;LB5WLHqM-7GNmabc=m;#iQ&lC*ChV3n1m>emH0EPW4CXRs zGv;z8R%S%Q2R2<>A$7G&Z{8{|wNAdB zkMPA6ZaBJkZ(9qM#+S8NY!u6}9jr&-Eu6QNFPB!Ztc5%C{ppbf5&43=)ZYbZ|7j-;`=hm)<$A-D zH|P|Zn-eyY&in c>}CHe)wTt7Y(L#cU$QT&6zT+@LHcWd19w@GD*ylh delta 540 zcmZ4gmg)afCce+Syj%=GU{SF(b8-7dzBeXJe+)POF;SG5yf;W>vY~GTn4aq^0HPU} zPF@$JJo%|_4Oq0)Phj%=DB;O7{35|Li@zY4)_~GJ{mA!0_)iPC5W4Eb9GV!Bcsmb2PvwIx?oZdOzMM412Aa_CXK+PF_<&~lcpeY^6%sr zpf$pivr@Dt3#O?sT2B^8Q)RXZWt$ujt;}p2$_}ROLOH;+eJCfGb_nGH(~hCslNY3_ zPIgRJVRW9Hmafm~;?5ZC3dC-c=cTKIdG27|IVjHq%=?!v&*(W>E<=^k3rH#o3jjsE zO_@NU%D|w&kj|jtv$-OJk!|zpyqTPv*H>OqVNBTEGB1vKa{2=P&HRfDm?w8Fi>b6fkmoF4CrV8-0Qms diff --git a/webui/backend/tests/golden/test_ui_smoke_golden.py b/webui/backend/tests/golden/test_ui_smoke_golden.py index 9e27de0..03d3b30 100644 --- a/webui/backend/tests/golden/test_ui_smoke_golden.py +++ b/webui/backend/tests/golden/test_ui_smoke_golden.py @@ -246,6 +246,8 @@ class UiSmokeGoldenTest(unittest.TestCase): self.assertIn('async function loadTasksForSettings()', app_js) self.assertIn('async function loadLogsAndTasksForSettings()', app_js) self.assertIn('function scheduleSettingsLogsPolling()', app_js) + self.assertIn('lastHistoryRenderKey: ""', app_js) + self.assertIn('lastTasksRenderKey: ""', app_js) self.assertIn('function openZipDownloadModal(selectedItems)', app_js) self.assertIn('function openSingleFileDownloadModal(selectedItem)', app_js) self.assertIn('function markZipDownloadReady(fileName)', app_js) @@ -300,6 +302,14 @@ class UiSmokeGoldenTest(unittest.TestCase): self.assertIn('return "Multi-item ZIP";', app_js) self.assertIn('details.push(`Current: ${task.current_item}`);', app_js) self.assertIn('details.push(`${task.done_items}/${task.total_items} items`);', app_js) + self.assertIn('if (settingsState.lastHistoryRenderKey === renderKey) {', app_js) + self.assertIn('if (settingsState.lastTasksRenderKey === renderKey) {', app_js) + self.assertIn('const scrollTop = elements.logsList.scrollTop;', app_js) + self.assertIn('const scrollTop = elements.tasksList.scrollTop;', app_js) + self.assertIn('elements.logsList.scrollTop = scrollTop;', app_js) + self.assertIn('elements.tasksList.scrollTop = scrollTop;', app_js) + self.assertIn('if (!settingsState.tasksLoaded) {', app_js) + self.assertIn('if (!settingsState.logsLoaded) {', app_js) self.assertIn('downloadModal.logsButton.onclick = () => {', app_js) self.assertIn('openSettings("logs");', app_js) self.assertIn('function applyContextMenuSelection()', app_js) diff --git a/webui/html/app.js b/webui/html/app.js index 750c628..6ba4795 100644 --- a/webui/html/app.js +++ b/webui/html/app.js @@ -103,6 +103,8 @@ let settingsState = { logsLoaded: false, tasksLoaded: false, logsPollTimer: null, + lastHistoryRenderKey: "", + lastTasksRenderKey: "", showThumbnails: false, preferredStartupPathLeft: null, preferredStartupPathRight: null, @@ -3804,12 +3806,18 @@ function formatTaskLine(task) { function renderHistoryItems(items) { const elements = settingsElements(); + const renderKey = JSON.stringify(Array.isArray(items) ? items : []); + if (settingsState.lastHistoryRenderKey === renderKey) { + return; + } + const scrollTop = elements.logsList.scrollTop; elements.logsList.innerHTML = ""; if (!Array.isArray(items) || items.length === 0) { const empty = document.createElement("div"); empty.className = "popup-meta"; empty.textContent = "No history entries yet."; elements.logsList.append(empty); + settingsState.lastHistoryRenderKey = renderKey; return; } for (const item of items) { @@ -3834,16 +3842,24 @@ function renderHistoryItems(items) { } elements.logsList.append(row); } + settingsState.lastHistoryRenderKey = renderKey; + elements.logsList.scrollTop = scrollTop; } function renderTaskItems(items) { const elements = settingsElements(); + const renderKey = JSON.stringify(Array.isArray(items) ? items : []); + if (settingsState.lastTasksRenderKey === renderKey) { + return; + } + const scrollTop = elements.tasksList.scrollTop; elements.tasksList.innerHTML = ""; if (!Array.isArray(items) || items.length === 0) { const empty = document.createElement("div"); empty.className = "popup-meta"; empty.textContent = "No tasks yet."; elements.tasksList.append(empty); + settingsState.lastTasksRenderKey = renderKey; return; } for (const task of items) { @@ -3868,6 +3884,8 @@ function renderTaskItems(items) { } elements.tasksList.append(row); } + settingsState.lastTasksRenderKey = renderKey; + elements.tasksList.scrollTop = scrollTop; } async function loadHistoryForSettings() { @@ -3885,8 +3903,12 @@ async function loadTasksForSettings() { async function loadLogsAndTasksForSettings() { const elements = settingsElements(); elements.logsError.textContent = ""; - elements.tasksList.innerHTML = ''; - elements.logsList.innerHTML = ''; + if (!settingsState.tasksLoaded) { + elements.tasksList.innerHTML = ''; + } + if (!settingsState.logsLoaded) { + elements.logsList.innerHTML = ''; + } try { await Promise.all([loadTasksForSettings(), loadHistoryForSettings()]); } catch (err) {