v3.32.6: the empty preset banner no longer flashes on the RAM view
ramOpChanged() (v3.28.0) un-hid #ram-preset-warning by the operation kind, but the banner's text and visibility belong to spPresetWarningRender() (which already suppresses it for the batch ops). With no warning text the empty amber box stayed visible until the next status poll re-hid it - a flash on every RAM view / operation switch. The visibility is content-driven again: the setHidden line is gone and the renderer is called. Pinned in frontend/tests/ram.test.js with the real renderer (the pre-fix code fails the test). 1016 Python + 954 frontend green; simple-v464.
This commit is contained in:
@@ -9,6 +9,18 @@ every change carries a descriptive commit message.
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [3.32.6] — 2026-10-23
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- The empty amber **preset-mismatch banner** no longer flashes on the SCP80/RAM view.
|
||||||
|
`ramOpChanged()` (v3.28.0) un-hid `#ram-preset-warning` by the operation kind, but the
|
||||||
|
banner's text *and* visibility belong to `spPresetWarningRender()` (which also handles
|
||||||
|
the batch suppression): with no warning text the empty bordered box stayed visible until
|
||||||
|
the next status poll re-hid it — on every RAM view and operation switch. The visibility
|
||||||
|
is content-driven again; `frontend/tests/ram.test.js` pins it (the pre-fix code fails
|
||||||
|
the test).
|
||||||
|
|
||||||
## [3.32.5] — 2026-10-21
|
## [3.32.5] — 2026-10-21
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|||||||
+6
-2
@@ -1943,7 +1943,7 @@
|
|||||||
// ===== Version =====
|
// ===== Version =====
|
||||||
// Single source of truth for the PWA version: shown in the header and used
|
// Single source of truth for the PWA version: shown in the header and used
|
||||||
// by the server version check in pysimConnect().
|
// by the server version check in pysimConnect().
|
||||||
const SIMPLE_VERSION = '3.32.5';
|
const SIMPLE_VERSION = '3.32.6';
|
||||||
document.getElementById('app-version').textContent = 'v' + SIMPLE_VERSION;
|
document.getElementById('app-version').textContent = 'v' + SIMPLE_VERSION;
|
||||||
|
|
||||||
// ===== view history (the browser Back/Forward buttons) =====
|
// ===== view history (the browser Back/Forward buttons) =====
|
||||||
@@ -10180,10 +10180,14 @@ function ramOpChanged() {
|
|||||||
// The batch resolves the preset per card (by ICCID): its selector and the
|
// The batch resolves the preset per card (by ICCID): its selector and the
|
||||||
// single-card Execute button do not apply, and the batch panel takes over.
|
// single-card Execute button do not apply, and the batch panel takes over.
|
||||||
setHidden('ram-preset-cell', isBatch);
|
setHidden('ram-preset-cell', isBatch);
|
||||||
setHidden('ram-preset-warning', isBatch);
|
|
||||||
setHidden('ram-exec-btn', isBatch);
|
setHidden('ram-exec-btn', isBatch);
|
||||||
setHidden('ram-batch-panel', !isBatch);
|
setHidden('ram-batch-panel', !isBatch);
|
||||||
if (isBatch) ramBatchFetch();
|
if (isBatch) ramBatchFetch();
|
||||||
|
// The preset-mismatch banner is content-driven: spPresetWarningRender owns
|
||||||
|
// its text *and* its visibility (the batch suppression included). Toggling
|
||||||
|
// `hidden` by the op kind here showed an empty amber box until the next
|
||||||
|
// render - the flash on every RAM view / op switch (v3.32.6).
|
||||||
|
spPresetWarningRender();
|
||||||
// The Execute button's .cap gate applies to the install-cap and compat ops.
|
// The Execute button's .cap gate applies to the install-cap and compat ops.
|
||||||
if (typeof pysimApplyAvailability === 'function') pysimApplyAvailability();
|
if (typeof pysimApplyAvailability === 'function') pysimApplyAvailability();
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
const CACHE = 'simple-v463';
|
const CACHE = 'simple-v464';
|
||||||
const URLS = [
|
const URLS = [
|
||||||
'index.html',
|
'index.html',
|
||||||
'help.html',
|
'help.html',
|
||||||
|
|||||||
@@ -553,6 +553,59 @@ test('ramOpChanged clears the executed status only on a real op change', () => {
|
|||||||
assert.ok(!els['ram-install-params'].classList.contains('hidden'));
|
assert.ok(!els['ram-install-params'].classList.contains('hidden'));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('the RAM preset banner is content-driven (no empty amber flash)', () => {
|
||||||
|
// A view / op switch used to un-hide #ram-preset-warning by the op kind
|
||||||
|
// (v3.28.0): with no warning text the empty bordered box stayed visible
|
||||||
|
// until the next status poll rendered it away - the amber block flashing
|
||||||
|
// on every SCP80/RAM view change. Its visibility belongs to the renderer.
|
||||||
|
const els = fakeRamDocument(['ram-op', 'ram-card-sel', 'ram-preset-warning',
|
||||||
|
'ram-install-params', 'ram-cap-rows', 'ram-compat-rows', 'ram-app-rows',
|
||||||
|
'ram-delete-rows', 'ram-del-package-row', 'ram-preset-cell', 'ram-exec-btn',
|
||||||
|
'ram-batch-panel', 'ram-result', 'ram-explorer', 'ram-steps', 'ram-progress',
|
||||||
|
'sp-preset-warning', 'tar-preset-warning']);
|
||||||
|
els['ram-preset-warning'].classList.add('hidden');
|
||||||
|
const prev = {
|
||||||
|
cards: globalThis.cards,
|
||||||
|
t: globalThis.t,
|
||||||
|
iccid: globalThis._pysimCardIccid,
|
||||||
|
batchFetch: globalThis.ramBatchFetch,
|
||||||
|
};
|
||||||
|
globalThis.cards = [];
|
||||||
|
globalThis._pysimCardIccid = null; // no card session: no warning text
|
||||||
|
globalThis.t = s => s;
|
||||||
|
globalThis.ramBatchFetch = () => {};
|
||||||
|
// The real renderer, defined where the extracted ramOpChanged finds it
|
||||||
|
// (a plain function body sees only the globals).
|
||||||
|
const src = ['cardsNormIccid', 'spPresetWarning', 'ramIsBatchOp', 'ramPresetIdx',
|
||||||
|
'spPresetIdx', 'tarPresetIdx', 'spPresetWarningRender']
|
||||||
|
.map(f => extractFunc(html, f)).join('\n');
|
||||||
|
const real = new Function(src + '\nreturn spPresetWarningRender;')();
|
||||||
|
let calls = 0;
|
||||||
|
globalThis.spPresetWarningRender = () => { calls++; return real(); };
|
||||||
|
try {
|
||||||
|
_ramOpLast = 'explore';
|
||||||
|
els['ram-op'].value = 'explore';
|
||||||
|
ramOpChanged();
|
||||||
|
assert.strictEqual(calls, 1, 'the content-driven renderer must own the banner');
|
||||||
|
assert.ok(els['ram-preset-warning'].classList.contains('hidden'),
|
||||||
|
'an empty banner must not be un-hidden by the op dispatch');
|
||||||
|
// a batch op keeps it hidden as well (the preset resolves per card)
|
||||||
|
els['ram-op'].value = 'batch';
|
||||||
|
ramOpChanged();
|
||||||
|
assert.ok(els['ram-preset-warning'].classList.contains('hidden'));
|
||||||
|
// the visibility is never toggled here by the op kind again
|
||||||
|
assert.ok(!extractFunc(html, 'ramOpChanged').includes("'ram-preset-warning'"));
|
||||||
|
} finally {
|
||||||
|
globalThis.spPresetWarningRender = () => {};
|
||||||
|
if (prev.cards === undefined) delete globalThis.cards; else globalThis.cards = prev.cards;
|
||||||
|
if (prev.t === undefined) delete globalThis.t; else globalThis.t = prev.t;
|
||||||
|
if (prev.iccid === undefined) delete globalThis._pysimCardIccid;
|
||||||
|
else globalThis._pysimCardIccid = prev.iccid;
|
||||||
|
if (prev.batchFetch === undefined) delete globalThis.ramBatchFetch;
|
||||||
|
else globalThis.ramBatchFetch = prev.batchFetch;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test('ramRender keeps the selected card preset across rebuilds', () => {
|
test('ramRender keeps the selected card preset across rebuilds', () => {
|
||||||
const els = fakeRamDocument(['ram-card-sel', 'ram-op', 'ram-install-params', 'ram-result', 'ram-explorer', 'ram-steps', 'ram-progress']);
|
const els = fakeRamDocument(['ram-card-sel', 'ram-op', 'ram-install-params', 'ram-result', 'ram-explorer', 'ram-steps', 'ram-progress']);
|
||||||
globalThis.cards = [{ name: 'A' }, { name: 'B' }, { name: 'C' }];
|
globalThis.cards = [{ name: 'A' }, { name: 'B' }, { name: 'C' }];
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "pysim-simple-server"
|
name = "pysim-simple-server"
|
||||||
version = "3.32.5"
|
version = "3.32.6"
|
||||||
description = "HTTP REST server wrapping pysim for the SIMple PWA"
|
description = "HTTP REST server wrapping pysim for the SIMple PWA"
|
||||||
license = { text = "GPL-2.0-or-later" }
|
license = { text = "GPL-2.0-or-later" }
|
||||||
requires-python = ">=3.9"
|
requires-python = ">=3.9"
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ from osmocom.tlv import BER_TLV_IE
|
|||||||
from osmocom.utils import rpad
|
from osmocom.utils import rpad
|
||||||
|
|
||||||
|
|
||||||
VERSION = '3.32.5'
|
VERSION = '3.32.6'
|
||||||
|
|
||||||
MAX_ENVELOPE_SEGMENTS = 5 # max SMS segments for outgoing C-APDU in ENVELOPE
|
MAX_ENVELOPE_SEGMENTS = 5 # max SMS segments for outgoing C-APDU in ENVELOPE
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user