Command filter: two presets, and a "Selected: N" summary (v2.7.2)

- the 'Proactive + events' preset is gone: the proactive one (FETCH,
  TERMINAL PROFILE and the SW 91xx initiators) plus the individual ENVELOPE
  entry cover it, and its Russian key is removed with it
- with several entries checked the filter button now reads "Selected: N"
  («Выбрано: N») instead of "N commands"; a single entry keeps showing its
  name and an empty selection stays "All commands"
- tests: the removed preset's case is replaced by an absence pin in the menu
  test, and the summary case follows the new wording; 527 Python + 72 Node
  tests
- README/README_RUS list two presets; PWA_VERSION/pyproject/version.py 2.7.2,
  SW cache simtrace-analyser-v82
This commit is contained in:
catarrh committed 2026-10-18 00:05:21 +03:00
1 parent 024527ada4
commit bc6fcc02c2
8 files changed
+14 -28

No files matched your search

+3 -4
View File
@@ -73,10 +73,9 @@ GSMTAP into this analyser.
COMPRION trace import (the Device Manager *ISO Protocol Layer* text export), COMPRION trace import (the Device Manager *ISO Protocol Layer* text export),
search and a **multi-select command filter** — pick any number of commands search and a **multi-select command filter** — pick any number of commands
and/or the conversation presets (*Proactive sessions*: FETCH, TERMINAL and/or the conversation presets (*Proactive sessions*: FETCH, TERMINAL
PROFILE and every command answered with SW 91xx; *Proactive + events*: the PROFILE and every command answered with SW 91xx; *File operations*: SELECT,
same plus ENVELOPE; *File operations*: SELECT, READ/UPDATE BINARY and READ/UPDATE BINARY and READ/UPDATE RECORD, with the GET RESPONSE carrying a
READ/UPDATE RECORD, with the GET RESPONSE carrying a selected command's selected command's data)
data)
- Installable PWA, dark theme, English/Russian UI - Installable PWA, dark theme, English/Russian UI
## Prerequisites ## Prerequisites
+1 -1
View File
@@ -76,7 +76,7 @@ SIM/UICC из UDP-потока GSMTAP (или импортирует файлы
«ISO Protocol Layer» из Device Manager), поиск и **фильтр команд с «ISO Protocol Layer» из Device Manager), поиск и **фильтр команд с
множественным выбором** — любые команды и/или готовые пресеты («Проактивные множественным выбором** — любые команды и/или готовые пресеты («Проактивные
сессии»: FETCH, TERMINAL PROFILE и все команды с ответом SW 91xx; сессии»: FETCH, TERMINAL PROFILE и все команды с ответом SW 91xx;
«Проактивные + события»: то же плюс ENVELOPE; «Файловые операции»: SELECT, «Файловые операции»: SELECT,
READ/UPDATE BINARY и READ/UPDATE RECORD, вместе с GET RESPONSE, несущим READ/UPDATE BINARY и READ/UPDATE RECORD, вместе с GET RESPONSE, несущим
данные выбранной команды) данные выбранной команды)
- Устанавливаемая PWA, тёмная тема, интерфейс на английском/русском - Устанавливаемая PWA, тёмная тема, интерфейс на английском/русском
+3 -9
View File
@@ -2353,11 +2353,6 @@ const FILTER_PRESETS = [
labels: ['FETCH', 'TERMINAL PROFILE'], labels: ['FETCH', 'TERMINAL PROFILE'],
test: m => _sw1(m) === 0x91, test: m => _sw1(m) === 0x91,
}, },
{
id: 'preset:proactive-events', name: 'Proactive + events',
labels: ['FETCH', 'TERMINAL PROFILE', 'ENVELOPE'],
test: m => _sw1(m) === 0x91,
},
{ {
id: 'preset:files', name: 'File operations', id: 'preset:files', name: 'File operations',
labels: ['SELECT', 'READ BINARY', 'READ RECORD', 'UPDATE BINARY', labels: ['SELECT', 'READ BINARY', 'READ RECORD', 'UPDATE BINARY',
@@ -2383,7 +2378,7 @@ function filterEntryName(entry) {
function filterSummary() { function filterSummary() {
if (!STATE.filter.size) return t('All commands'); if (!STATE.filter.size) return t('All commands');
if (STATE.filter.size === 1) return filterEntryName([...STATE.filter][0]); if (STATE.filter.size === 1) return filterEntryName([...STATE.filter][0]);
return t('{n} commands').replace('{n}', STATE.filter.size); return t('Selected: {n}').replace('{n}', STATE.filter.size);
} }
let _filterMenuSig = null; let _filterMenuSig = null;
@@ -3346,7 +3341,7 @@ function onSearchChange() {
} }
// ──────────────────── Versioning ──────────────────── // ──────────────────── Versioning ────────────────────
const PWA_VERSION = '2.7.1'; const PWA_VERSION = '2.7.2';
const MIN_SERVER_VERSION = '2.3.0'; const MIN_SERVER_VERSION = '2.3.0';
function parseVersion(v) { function parseVersion(v) {
@@ -3384,9 +3379,8 @@ const LANG_RU = {
'Presets': 'Пресеты', 'Presets': 'Пресеты',
'Commands': 'Команды', 'Commands': 'Команды',
'Proactive sessions': 'Проактивные сессии', 'Proactive sessions': 'Проактивные сессии',
'Proactive + events': 'Проактивные + события',
'File operations': 'Файловые операции', 'File operations': 'Файловые операции',
'{n} commands': 'команд: {n}', 'Selected: {n}': 'Выбрано: {n}',
'Filter': 'Фильтр', 'Filter': 'Фильтр',
'Start Capture': 'Начать захват', 'Start Capture': 'Начать захват',
'Stop Capture': 'Остановить захват', 'Stop Capture': 'Остановить захват',
+1 -1
View File
@@ -1,4 +1,4 @@
const CACHE = 'simtrace-analyser-v81'; const CACHE = 'simtrace-analyser-v82';
const PRECACHE = [ const PRECACHE = [
'index.html', 'index.html',
+3 -10
View File
@@ -100,13 +100,6 @@ test('FETCH and TERMINAL RESPONSE are separate commands now', () => {
assert.equal(matchesFilter(gr, 1, set), true); assert.equal(matchesFilter(gr, 1, set), true);
}); });
test('the proactive+events preset adds ENVELOPE', () => {
const set = new Set(['preset:proactive-events']);
assert.equal(matchesFilter(msg('ENVELOPE'), 0, set), true);
assert.equal(matchesFilter(msg('FETCH'), 0, set), true);
assert.equal(matchesFilter(msg('SELECT'), 0, set), false);
});
test('the file-operations preset covers the five commands and their replies', () => { test('the file-operations preset covers the five commands and their replies', () => {
const set = new Set(['preset:files']); const set = new Set(['preset:files']);
for (const name of ['SELECT', 'READ BINARY', 'READ RECORD', 'UPDATE BINARY', for (const name of ['SELECT', 'READ BINARY', 'READ RECORD', 'UPDATE BINARY',
@@ -137,7 +130,7 @@ test('the summary follows the selection', () => {
STATE.filter.add('preset:files'); STATE.filter.add('preset:files');
assert.equal(filterSummary(), 'File operations'); assert.equal(filterSummary(), 'File operations');
STATE.filter.add('cmd:FETCH'); STATE.filter.add('cmd:FETCH');
assert.equal(filterSummary(), '2 commands'); assert.equal(filterSummary(), 'Selected: 2');
}); });
test('the menu lists the presets and the commands with their counts', () => { test('the menu lists the presets and the commands with their counts', () => {
@@ -150,8 +143,8 @@ test('the menu lists the presets and the commands with their counts', () => {
el = id => (id === 'filter-menu' ? menu : btn); el = id => (id === 'filter-menu' ? menu : btn);
renderFilterMenu(true); renderFilterMenu(true);
assert.match(menu.innerHTML, /data-filter="preset:proactive"/); assert.match(menu.innerHTML, /data-filter="preset:proactive"/);
assert.match(menu.innerHTML, /data-filter="preset:proactive-events"/);
assert.match(menu.innerHTML, /data-filter="preset:files"/); assert.match(menu.innerHTML, /data-filter="preset:files"/);
assert.doesNotMatch(menu.innerHTML, /preset:proactive-events/);
assert.match(menu.innerHTML, /data-filter="cmd:SELECT"/); assert.match(menu.innerHTML, /data-filter="cmd:SELECT"/);
assert.match(menu.innerHTML, /<span class="filter-count">2<\/span>/); assert.match(menu.innerHTML, /<span class="filter-count">2<\/span>/);
assert.match(menu.innerHTML, /data-filter="all" checked>/); assert.match(menu.innerHTML, /data-filter="all" checked>/);
@@ -171,7 +164,7 @@ test('the filter strings carry Russian translations', () => {
keys.add(m[1].replace(/\\(['\\])/g, '$1')); keys.add(m[1].replace(/\\(['\\])/g, '$1'));
} }
for (const s of ['All commands', 'Presets', 'Commands', 'Proactive sessions', for (const s of ['All commands', 'Presets', 'Commands', 'Proactive sessions',
'Proactive + events', 'File operations', '{n} commands']) { 'File operations', 'Selected: {n}']) {
assert.ok(keys.has(s), 'no LANG_RU entry for: ' + s); assert.ok(keys.has(s), 'no LANG_RU entry for: ' + s);
} }
}); });
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.backends._legacy:_Backend"
[project] [project]
name = "simtrace-analyser" name = "simtrace-analyser"
version = "2.7.1" version = "2.7.2"
description = "SIMtrace Analyser — APDU trace analyser for GSMTAP/PCAP captures (bundles the simtrace2-pysniff utility)" description = "SIMtrace Analyser — APDU trace analyser for GSMTAP/PCAP captures (bundles the simtrace2-pysniff utility)"
readme = {file = "README.md", content-type = "text/markdown"} readme = {file = "README.md", content-type = "text/markdown"}
license = {text = "GPL-2.0-or-later"} license = {text = "GPL-2.0-or-later"}
+1 -1
View File
@@ -1,3 +1,3 @@
"""Single source of truth for the SIMtrace Analyser version.""" """Single source of truth for the SIMtrace Analyser version."""
__version__ = '2.7.1' __version__ = '2.7.2'
+1 -1
View File
@@ -224,7 +224,7 @@ class TestImportEndpoint(unittest.TestCase):
class TestVersion(unittest.TestCase): class TestVersion(unittest.TestCase):
def test_package_version(self): def test_package_version(self):
from simtrace2_pysniff import __version__ from simtrace2_pysniff import __version__
self.assertEqual(__version__, '2.7.1') self.assertEqual(__version__, '2.7.2')
def test_status_includes_version(self): def test_status_includes_version(self):
import os import os