ui: the preset list highlights the equipped card's preset

The Cards list now marks the row whose ICCID matches the equipped card
(cardsFindByIccid handles digits / spaced / raw EF hex alike): an emerald row
tint plus a small dot with a "The equipped card's preset" tooltip in the Name
cell.  There is no highlight while the ICCID is unknown (no card, unreadable
EF.ICCID) or when no preset matches - the amber banner already covers that.

pysimCardStateUpdate() re-renders the list when the ICCID actually changes, so
a visible Cards tab follows equip/removal live (opening the tab re-renders
anyway through switchTab).

Tests: cards_iccid.test.js drives cardsRender with a fake tbody - the matching
preset is highlighted (both ICCID forms), the others stay plain and no ICCID
means no highlight; card_state.test.js stubs cardsRender.  Help EN/RU and the
repo AGENTS updated; sw cache simple-v344.
This commit is contained in:
2026-10-01 21:50:29 +03:00
parent 12da7ed593
commit 39723406b4
6 changed files with 45 additions and 6 deletions
+1
View File
@@ -51,6 +51,7 @@ code += extractFunc(html, 'cardsScp81Complete') + '\n';
code += extractFunc(html, 'pysimSetServerAvailable') + '\n';
code += '\nglobalThis.esc = s => s;\n';
code += 'globalThis.t = s => s;\n';
code += 'globalThis.cardsRender = () => {};\n'; // equipped-preset highlight
eval(code);
function fakeIndicator() {
+27 -1
View File
@@ -24,7 +24,8 @@ function extractFunc(src, name) {
let code = '';
for (const fn of ['swapNibbles', 'encIccid', 'decIccid',
'cardsNormIccid', 'cardsFindByIccid', 'cardsFindDuplicateIccid',
'cardsIccidFromCard', 'cardsAutoSelectByIccid']) {
'cardsIccidFromCard', 'cardsAutoSelectByIccid', 'cardsRender',
'esc', 'spKeysetList', 'spKeysetKvnOf', 'cardsTarValue', 'cardsScp81Complete']) {
code += extractFunc(html, fn) + '\n';
}
eval(code);
@@ -169,3 +170,28 @@ test('the card-state update wires the ICCID into the preset selection', () => {
'the auto-selection must cover the TAR probe view');
assert.ok(html.includes("(data.iccid ? ' | ICCID: <b>' + esc(data.iccid) + '</b>' : '')"));
});
test('cardsRender highlights the equipped card preset', () => {
globalThis.t = s => s;
const els = { 'cards-tbody': { innerHTML: '' } };
globalThis.document = { getElementById: id => els[id] || null };
globalThis.cards = [
{ name: 'other', iccid: '1111111111111111111', spi1: '16', spi2: '01', keysets: [] },
{ name: 'live', iccid: DIGITS, spi1: '16', spi2: '01', keysets: [] },
];
globalThis._pysimCardIccid = DIGITS;
cardsRender();
let rows = els['cards-tbody'].innerHTML.split('</tr>');
assert.ok(!/bg-emerald-50/.test(rows[0]), 'the other preset must stay plain');
assert.match(rows[1], /bg-emerald-50/);
assert.match(rows[1], /The equipped card's preset/);
// the same card stored as raw EF hex matches too
globalThis.cards[1].iccid = RAW_HEX;
cardsRender();
rows = els['cards-tbody'].innerHTML.split('</tr>');
assert.match(rows[1], /bg-emerald-50/);
// no readable ICCID -> no highlight
globalThis._pysimCardIccid = null;
cardsRender();
assert.ok(!/bg-emerald-50/.test(els['cards-tbody'].innerHTML));
});