From 84887d85189769f25182be1ac0d0cf18c9dc8639 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: Fri, 2 Oct 2026 11:13:18 +0300 Subject: [PATCH] v3.11.0 editor polish: keyset editor as a header table, in sync with TAR The keyset rows were a stack of flex divs with no column labels. They are now a fixed-layout table like the TAR table: a thead with # (keyset number, with its tooltip), KIc, KID, KIc key, KID key, Counter and the action column, and rows of py-1 px-2 cells with w-full inputs (the columns drive the widths: 40/56/56 px, the two key columns split the remainder, 112 px for the 10-digit counter). Ids and behaviour are unchanged (the number span still toggles its red flag, the inputs keep their handlers). Guards: html.test.js checks the keyset table headers and tbody; cards_form.test.js checks the row markup. sw cache simple-v366. Tests: 665 Python + 788 frontend green; the whole inline PWA script syntax-checked. --- frontend/index.html | 33 ++++++++++++++++++++----------- frontend/sw.js | 2 +- frontend/tests/cards_form.test.js | 10 ++++++++++ frontend/tests/html.test.js | 6 ++++++ 4 files changed, 39 insertions(+), 12 deletions(-) diff --git a/frontend/index.html b/frontend/index.html index 9a855de..22eafa1 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -1683,7 +1683,18 @@
SCP80 (GSM 03.48, ETSI TS 102 225) OTA keysets — each with its own number and counter -
+ + + + + + + + + + + +
#KIcKIDKIc keyKID keyCounter

KIc and KID must carry the same keyset number (their high nibble) in the range 01-0F — TS 102 225 A.2; each keyset has its own counter on the card (Annex A.1).

@@ -11815,17 +11826,17 @@ function spKeysetOptionsHtml(preset, kicHex, kidHex) { let _cardsKeysetCount = 0; function cardsKeysetRowHtml(ks, i) { - const cls = 'border border-gray-300 dark:border-slate-600 text-sm rounded px-2 py-1.5 dark:bg-slate-800 font-mono'; + const cls = 'w-full border border-gray-300 dark:border-slate-600 text-sm rounded px-2 py-1.5 dark:bg-slate-800 font-mono'; const kvn = spKeysetKvnOf(ks.kic); - return '
' + - '' + (kvn === null ? '?' : kvn) + '' + - '' + - '' + - '' + - '' + - '' + - '' + - '
'; + return '' + + '' + (kvn === null ? '?' : kvn) + '' + + '' + + '' + + '' + + '' + + '' + + '' + + ''; } function cardsKeysetRowsRender(keysets) { diff --git a/frontend/sw.js b/frontend/sw.js index 2e0a30f..e86e597 100644 --- a/frontend/sw.js +++ b/frontend/sw.js @@ -1,4 +1,4 @@ -const CACHE = 'simple-v365'; +const CACHE = 'simple-v366'; const URLS = [ 'index.html', 'help.html', diff --git a/frontend/tests/cards_form.test.js b/frontend/tests/cards_form.test.js index dd3777c..52c26b9 100644 --- a/frontend/tests/cards_form.test.js +++ b/frontend/tests/cards_form.test.js @@ -539,6 +539,16 @@ test('the TAR row values are left-aligned like the headers', () => { assert.match(out, //); + assert.match(scp80, //); + for (const h of ['KIc', 'KID', 'KIc key', 'KID key', 'Counter']) { + assert.match(scp80, new RegExp('>' + h + '')); + } assert.match(scp81, /id="cards-psk-id"/); assert.match(scp81, /id="cards-psk-key"/); // the PSK explanation lives inside the SCP81 group, not outside it