Style command + GET RESPONSE pairs in the APDU list; bump to 1.15.0
- Pair members (a command ending '61 XX' and its GET RESPONSE, via the server-side response_for link) get a subtle slate row tint (--pair-row, themed: rgba(148,163,184,.12) dark / rgba(100,116,139,.15) light); hover/selected still take precedence. - Paired GET RESPONSE rows are prefixed with '↳' marking them as a continuation of the previous command; orphaned GRs stay plain. - GET RESPONSE label uses cat-gr class: muted color, weight 600 like other command names. - Map view untouched (it skips GRs); detail view already shows "Response for". Version 1.15.0, SW cache simtrace-analyser-v20.
This commit is contained in:
1 parent
0e99e73fda
commit
f61ca9685c
5 files changed
+19
-7
No files matched your search
+15
-3
@@ -38,6 +38,7 @@
|
|||||||
--tr: #22d3ee;
|
--tr: #22d3ee;
|
||||||
--envelope: #fbbf24;
|
--envelope: #fbbf24;
|
||||||
--auth: #f87171;
|
--auth: #f87171;
|
||||||
|
--pair-row: rgba(148, 163, 184, 0.12);
|
||||||
}
|
}
|
||||||
[data-theme="light"] {
|
[data-theme="light"] {
|
||||||
--bg: #fafafa;
|
--bg: #fafafa;
|
||||||
@@ -68,6 +69,7 @@
|
|||||||
--tr: #0e7490;
|
--tr: #0e7490;
|
||||||
--envelope: #b45309;
|
--envelope: #b45309;
|
||||||
--auth: #dc2626;
|
--auth: #dc2626;
|
||||||
|
--pair-row: rgba(100, 116, 139, 0.15);
|
||||||
}
|
}
|
||||||
|
|
||||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
@@ -114,6 +116,7 @@ body { font: 14px/1.5 system-ui, sans-serif; background: var(--bg); color: var(-
|
|||||||
/* APDU list */
|
/* APDU list */
|
||||||
.apdu-list { flex: 1; overflow-y: auto; padding: 8px; }
|
.apdu-list { flex: 1; overflow-y: auto; padding: 8px; }
|
||||||
.apdu-entry { display: flex; gap: 12px; padding: 3px 12px; border-bottom: 1px solid var(--bg-panel); cursor: pointer; align-items: baseline; }
|
.apdu-entry { display: flex; gap: 12px; padding: 3px 12px; border-bottom: 1px solid var(--bg-panel); cursor: pointer; align-items: baseline; }
|
||||||
|
.apdu-entry.apdu-pair { background: var(--pair-row); }
|
||||||
.apdu-entry:hover { background: var(--bg-panel); }
|
.apdu-entry:hover { background: var(--bg-panel); }
|
||||||
.apdu-entry.selected { background: var(--bg-input); }
|
.apdu-entry.selected { background: var(--bg-input); }
|
||||||
[data-theme="light"] .apdu-entry.selected { background: #dbeafe; }
|
[data-theme="light"] .apdu-entry.selected { background: #dbeafe; }
|
||||||
@@ -125,6 +128,7 @@ body { font: 14px/1.5 system-ui, sans-serif; background: var(--bg); color: var(-
|
|||||||
.apdu-type.cat-tr { font-weight: 700; color: var(--tr); }
|
.apdu-type.cat-tr { font-weight: 700; color: var(--tr); }
|
||||||
.apdu-type.cat-envelope { color: var(--envelope); }
|
.apdu-type.cat-envelope { color: var(--envelope); }
|
||||||
.apdu-type.cat-auth { color: var(--auth); }
|
.apdu-type.cat-auth { color: var(--auth); }
|
||||||
|
.apdu-type.cat-gr { color: var(--text-muted); font-weight: 600; }
|
||||||
.apdu-data { font-family: monospace; color: var(--text-dim); word-break: break-all; flex: 1; }
|
.apdu-data { font-family: monospace; color: var(--text-dim); word-break: break-all; flex: 1; }
|
||||||
.apdu-sw { font-family: monospace; color: var(--text-muted); white-space: nowrap; min-width: 52px; }
|
.apdu-sw { font-family: monospace; color: var(--text-muted); white-space: nowrap; min-width: 52px; }
|
||||||
.apdu-sw.sw-ok { color: var(--green); }
|
.apdu-sw.sw-ok { color: var(--green); }
|
||||||
@@ -1084,6 +1088,7 @@ function command_cat(ins) {
|
|||||||
if (ins === '14' || ins === '10' || ins === 'aa') return 'tr'; // TERMINAL RESPONSE / PROFILE / CAPABILITY
|
if (ins === '14' || ins === '10' || ins === 'aa') return 'tr'; // TERMINAL RESPONSE / PROFILE / CAPABILITY
|
||||||
if (ins === 'c2') return 'envelope'; // ENVELOPE
|
if (ins === 'c2') return 'envelope'; // ENVELOPE
|
||||||
if (ins === '88' || ins === '89') return 'auth'; // AUTHENTICATE
|
if (ins === '88' || ins === '89') return 'auth'; // AUTHENTICATE
|
||||||
|
if (ins === 'c0') return 'gr'; // GET RESPONSE
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1349,9 +1354,16 @@ function renderMessages(skipScroll) {
|
|||||||
(cat ? ' cat-' + cat : '');
|
(cat ? ' cat-' + cat : '');
|
||||||
const errs = error_names(m);
|
const errs = error_names(m);
|
||||||
const errBadge = errs ? `<span class="apdu-err" title="${errs.join(', ')}">⚠</span>` : '';
|
const errBadge = errs ? `<span class="apdu-err" title="${errs.join(', ')}">⚠</span>` : '';
|
||||||
return `<div class="apdu-entry" data-idx="${idx}">
|
// Command + GET RESPONSE pairs: subtle tint on both members,
|
||||||
|
// ↳ prefix marks the response as a continuation of the previous
|
||||||
|
// command (server sets response_for when prior SW1 was '61').
|
||||||
|
const isGR = m.type === 'tpdu' && m.decoded &&
|
||||||
|
m.decoded.ins_name === 'GET RESPONSE' && m.decoded.response_for;
|
||||||
|
const pairCls = (isGR || isOriginalCommand(idx)) ? ' apdu-pair' : '';
|
||||||
|
const grLabel = isGR ? '↳ ' + label : label;
|
||||||
|
return `<div class="apdu-entry${pairCls}" data-idx="${idx}">
|
||||||
<span class="apdu-time">${fmt_elapsed(m.elapsed)}</span>
|
<span class="apdu-time">${fmt_elapsed(m.elapsed)}</span>
|
||||||
<span class="apdu-type ${typeCls}">${label}</span>
|
<span class="apdu-type ${typeCls}">${grLabel}</span>
|
||||||
<span class="apdu-sw ${sw_class(m)}">${sw_text(m)}</span>
|
<span class="apdu-sw ${sw_class(m)}">${sw_text(m)}</span>
|
||||||
<span class="apdu-data">${cmd_description(m)}</span>
|
<span class="apdu-data">${cmd_description(m)}</span>
|
||||||
${errBadge}
|
${errBadge}
|
||||||
@@ -1869,7 +1881,7 @@ function onFilterChange() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ──────────────────── Versioning ────────────────────
|
// ──────────────────── Versioning ────────────────────
|
||||||
const PWA_VERSION = '1.14.0';
|
const PWA_VERSION = '1.15.0';
|
||||||
const MIN_SERVER_VERSION = '1.0.0';
|
const MIN_SERVER_VERSION = '1.0.0';
|
||||||
|
|
||||||
function parseVersion(v) {
|
function parseVersion(v) {
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
const CACHE = 'simtrace-analyser-v17';
|
const CACHE = 'simtrace-analyser-v20';
|
||||||
|
|
||||||
const PRECACHE = [
|
const PRECACHE = [
|
||||||
'index.html',
|
'index.html',
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.backends._legacy:_Backend"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "simtrace2-pysniff"
|
name = "simtrace2-pysniff"
|
||||||
version = "1.14.0"
|
version = "1.15.0"
|
||||||
description = "Python-based sniffing tool for SIMtrace2 hardware (SIM card communication sniffer)"
|
description = "Python-based sniffing tool for SIMtrace2 hardware (SIM card communication sniffer)"
|
||||||
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"}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from .gsmtap import GsmtapSender, GsmtapReceiver
|
|||||||
from .pcap import PcapWriter
|
from .pcap import PcapWriter
|
||||||
from .dump import FileDumper, format_message
|
from .dump import FileDumper, format_message
|
||||||
|
|
||||||
__version__ = '1.14.0'
|
__version__ = '1.15.0'
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'SniffSession',
|
'SniffSession',
|
||||||
'DeviceDisconnected',
|
'DeviceDisconnected',
|
||||||
|
|||||||
@@ -197,7 +197,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__, '1.14.0')
|
self.assertEqual(__version__, '1.15.0')
|
||||||
|
|
||||||
def test_status_includes_version(self):
|
def test_status_includes_version(self):
|
||||||
import os
|
import os
|
||||||
|
|||||||
Reference in new issue
Block a user