From 19dc0c7d564c8ffe508d3645d7516873e57a917f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D1=82=D0=BE=D0=BD=20=D0=A2=D1=80=D0=BE=D1=88?= =?UTF-8?q?=D0=B8=D0=BD?= Date: Thu, 15 Oct 2026 01:05:54 +0300 Subject: [PATCH] v3.30.1: the batch status modal cosmetics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The v3.30.0 review follow-up, both items cosmetic: - The modal's title follows the run's kind, but a cleared report carries kind: null, so Clear flipped a delete/reinstall run to the install title. The last seen kind is remembered (_ramBatchLastKind, set in ramBatchRender) and the title falls back to it through the new ramBatchModalTitle() helper. - The two batch-state RU strings stopped being install-specific: 'Batch stopped'/'Batch finished' are now «Пакетная операция остановлена/завершена» (the v3.29.0 kinds can delete or reinstall), matching the help's own «Пакетная операция» wording. Test: the cleared title keeps the kind and a fresh page keeps the install default. 930 frontend + 945 Python; sw cache simple-v451. --- frontend/index.html | 26 +++++++++++++++++++------- frontend/sw.js | 2 +- frontend/tests/ram_batch.test.js | 28 +++++++++++++++++++++++++++- pyproject.toml | 2 +- pysim_simple_server/server.py | 2 +- 5 files changed, 49 insertions(+), 11 deletions(-) diff --git a/frontend/index.html b/frontend/index.html index 81ba33e..5d58271 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -1932,7 +1932,7 @@ // ===== Version ===== // Single source of truth for the PWA version: shown in the header and used // by the server version check in pysimConnect(). -const SIMPLE_VERSION = '3.30.0'; +const SIMPLE_VERSION = '3.30.1'; document.getElementById('app-version').textContent = 'v' + SIMPLE_VERSION; // ===== view history (the browser Back/Forward buttons) ===== @@ -10191,6 +10191,9 @@ let _ramBatchFetchAt = 0; // when the in-flight fetch started (the watchd let _ramBatchSummary = null; // /api/status.ram_batch let _ramBatchProgress = null; // /api/status.ram_progress let _ramBatchModalShown = false; // the batch status modal is open (v3.30.0) +let _ramBatchLastKind = null; // the last seen run kind: a cleared report + // (kind: null) keeps the modal's title right + // (v3.30.1) // A fetch that never settled must not block the report forever (v3.28.7). const RAM_BATCH_FETCH_STALE_MS = 10000; @@ -10213,6 +10216,13 @@ function ramBatchTitle(kind) { : t('Batch install (.cap file, per card)')); } +// The modal's title: the run's kind, falling back to the last one seen - a +// cleared report carries kind: null, and a delete/reinstall run must not flip +// to the install title (v3.30.1). +function ramBatchModalTitle(kind) { + return ramBatchTitle(kind || _ramBatchLastKind || 'install-cap'); +} + // ===== the batch status modal (v3.30.0) ===== // The same chrome as the single-operation modal, owned by the batch: the live // status on top (the current step or the waiting prompt) and the processed @@ -10224,7 +10234,7 @@ function ramBatchModalOpen() { if (!modal) return; // no modal in the document (tests) _ramBatchModalShown = true; document.getElementById('ram-op-title').textContent = - ramBatchTitle(ramBatchMergedState().kind || 'install-cap'); + ramBatchModalTitle(ramBatchMergedState().kind); document.getElementById('ram-op-status').textContent = t('Working...'); document.getElementById('ram-op-status').className = 'text-sm text-gray-600 dark:text-slate-400'; document.getElementById('ram-op-bar').style.width = '0%'; @@ -10245,7 +10255,7 @@ function ramBatchModalRender(st, okLabel, actLabel) { const statusEl = document.getElementById('ram-op-status'); if (!statusEl) return; document.getElementById('ram-op-title').textContent = - ramBatchTitle(st.kind || 'install-cap'); + ramBatchModalTitle(st.kind); const active = !!st.active; const phase = st.phase || (active ? 'waiting_card' : 'idle'); let status; @@ -10340,8 +10350,10 @@ function ramBatchRender() { const active = !!st.active; const phase = st.phase || (active ? 'waiting_card' : 'idle'); // The success labels follow the operation (v3.29.0): the counts bucket is - // 'installed' for every kind - "the operation succeeded". - const kind = st.kind || 'install-cap'; + // 'installed' for every kind - "the operation succeeded". The last seen + // kind is remembered for the modal's title (v3.30.1). + if (st.kind) _ramBatchLastKind = st.kind; + const kind = st.kind || _ramBatchLastKind || 'install-cap'; const okLabel = kind === 'delete' ? t('Deleted') : (kind === 'reinstall-app' ? t('Reinstalled') : t('Installed')); const actLabel = kind === 'delete' ? t('Deleting...') @@ -24671,8 +24683,8 @@ const LANG_RU = { 'not found': 'не найдено', 'Start batch': 'Запустить пакетную установку', 'Stopping...': 'Остановка…', - 'Batch stopped': 'Пакетная установка остановлена', - 'Batch finished': 'Пакетная установка завершена', + 'Batch stopped': 'Пакетная операция остановлена', + 'Batch finished': 'Пакетная операция завершена', 'Installing...': 'Установка…', 'Deleting...': 'Удаление…', 'Reinstalling...': 'Переустановка…', diff --git a/frontend/sw.js b/frontend/sw.js index 8207045..b717b14 100644 --- a/frontend/sw.js +++ b/frontend/sw.js @@ -1,4 +1,4 @@ -const CACHE = 'simple-v450'; +const CACHE = 'simple-v451'; const URLS = [ 'index.html', 'help.html', diff --git a/frontend/tests/ram_batch.test.js b/frontend/tests/ram_batch.test.js index c24fb13..885a72e 100644 --- a/frontend/tests/ram_batch.test.js +++ b/frontend/tests/ram_batch.test.js @@ -24,7 +24,8 @@ function extractFunc(src, name, asyncFn) { const ASYNC_FNS = ['ramBatchFetch', 'ramBatchStart', 'ramBatchStop', 'ramBatchClear']; let code = ''; for (const fn of ['ramIsBatchOp', 'ramBatchPanelVisible', 'ramBatchMergedState', - 'ramBatchTitle', 'ramBatchModalOpen', 'ramBatchModalRender', 'ramBatchStepsText', + 'ramBatchTitle', 'ramBatchModalTitle', 'ramBatchModalOpen', 'ramBatchModalRender', + 'ramBatchStepsText', 'ramBatchAttemptsHtml', 'ramBatchRender', 'ramBatchApplyStatus', 'ramBatchFetch', 'ramBatchStart', 'ramBatchStop', 'ramBatchClear', 'ramOpProgressText', 'ramOpModalClose', 'esc']) { @@ -99,6 +100,7 @@ const app = new Function('els', ` var pysimApplyAvailability = () => {}; var _ramOpActive = false; var _ramBatchModalShown = false; + var _ramBatchLastKind = null; var _ramBatchLast = null; var _ramBatchFetching = false; var _ramBatchFetchAt = 0; @@ -121,6 +123,7 @@ const app = new Function('els', ` sandbox.ramOpModalClose = ramOpModalClose; sandbox.isBatchModalShown = () => _ramBatchModalShown; sandbox.resetBatchModal = () => { _ramBatchModalShown = false; }; + sandbox.resetKind = () => { _ramBatchLastKind = null; }; sandbox.setProgress = v => { _ramBatchProgress = v; }; sandbox.ramBatchRender = ramBatchRender; sandbox.ramBatchApplyStatus = ramBatchApplyStatus; @@ -570,6 +573,29 @@ test('the batch modal follows the run: the step, the bar, the cards (v3.30.0)', assert.ok(!els['ram-op-batch-clear'].disabled); }); +test('a cleared report keeps the run kind in the modal title (v3.30.1)', () => { + clearEls(); + setModalEls(); + setPanelEls(); + app.setSummary(null); + app.ramBatchModalOpen(); + app.setLast({ kind: 'delete', active: false, phase: 'finished', attempts: [], + counts: { installed: 2 }, attempts_total: 2 }); + app.ramBatchRender(); + assert.strictEqual(els['ram-op-title'].textContent, 'Batch delete (per card)'); + // Clear empties the state (kind: null): the title must not flip to install + app.setLast({ kind: null, active: false, phase: 'idle', attempts: [], + counts: {}, attempts_total: 0 }); + app.ramBatchRender(); + assert.strictEqual(els['ram-op-title'].textContent, 'Batch delete (per card)'); + // a fresh page (no kind ever seen) keeps the install default + app.resetBatchModal(); + app.resetKind(); + app.setLast({ kind: null, active: false, phase: 'idle', attempts: [], counts: {}, attempts_total: 0 }); + app.ramBatchModalOpen(); + assert.strictEqual(els['ram-op-title'].textContent, 'Batch install (.cap file, per card)'); +}); + test('the batch modal stays open while the run is active (v3.30.0)', () => { clearEls(); setModalEls(); diff --git a/pyproject.toml b/pyproject.toml index c291d8d..b0fa5e6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "pysim-simple-server" -version = "3.30.0" +version = "3.30.1" description = "HTTP REST server wrapping pysim for the SIMple PWA" requires-python = ">=3.8" # pysim is a git-only dependency installed explicitly by setup.bat/setup.sh. diff --git a/pysim_simple_server/server.py b/pysim_simple_server/server.py index d135ed1..72916bf 100644 --- a/pysim_simple_server/server.py +++ b/pysim_simple_server/server.py @@ -37,7 +37,7 @@ from osmocom.tlv import BER_TLV_IE from osmocom.utils import rpad -VERSION = '3.30.0' +VERSION = '3.30.1' MAX_ENVELOPE_SEGMENTS = 5 # max SMS segments for outgoing C-APDU in ENVELOPE