diff --git a/frontend/index.html b/frontend/index.html index d89b5d8..c256e51 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -119,7 +119,7 @@ body { font: 14px/1.5 system-ui, sans-serif; background: var(--bg); color: var(- .trace-left { flex: 1; display: flex; flex-direction: column; overflow: hidden; } /* APDU list */ -.apdu-list { flex: 1; overflow-y: auto; padding: 8px; } +.apdu-list { flex: 1 1 0; min-height: 0; 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.apdu-pair { background: var(--pair-row); } .apdu-entry:hover { background: var(--bg-panel); } @@ -149,7 +149,10 @@ body { font: 14px/1.5 system-ui, sans-serif; background: var(--bg); color: var(- .device-warn { padding: 8px 12px; font-size: 12px; color: var(--warn); background: var(--warning-bg); border-bottom: 1px solid var(--warn); } /* APDU detail panel */ -.apdu-detail { display: flex; flex-direction: column; max-height: 40%; overflow-y: auto; border-top: 2px solid var(--accent); background: var(--bg-panel); flex-shrink: 0; } +.apdu-detail { display: flex; flex-direction: column; flex: 0 0 var(--detail-height, 30%); overflow-y: auto; background: var(--bg-panel); } +/* Splitter bar */ +.splitter { height: 6px; cursor: row-resize; background: var(--border); flex-shrink: 0; } +.splitter:hover, .splitter.active { background: var(--accent); } .apdu-detail .detail-empty { padding: 24px; color: var(--text-muted); text-align: center; } .detail-header { display: flex; align-items: center; justify-content: space-between; padding: 8px 12px; background: var(--bg-input); border-bottom: 1px solid var(--border); } [data-theme="light"] .detail-header { background: #dbeafe; } @@ -308,6 +311,7 @@ body { font: 14px/1.5 system-ui, sans-serif; background: var(--bg); color: var(-
+
Click an APDU to see details
@@ -2613,7 +2617,7 @@ function onFilterChange() { } // ──────────────────── Versioning ──────────────────── -const PWA_VERSION = '1.22.11'; +const PWA_VERSION = '1.22.12'; const MIN_SERVER_VERSION = '1.0.0'; function parseVersion(v) { @@ -2968,6 +2972,39 @@ function init() { updateCaptureButton(); } +// ──────────────────── Splitter ──────────────────── +(function initSplitter() { + const splitter = el('splitter'); + const detail = el('apdu-detail'); + const left = splitter.parentElement; + const saved = parseFloat(localStorage.getItem('splitter-ratio')); + if (saved > 0.1 && saved < 0.8) { + left.style.setProperty('--detail-height', (saved * 100) + '%'); + } + let startY, startH; + function onMove(e) { + const dy = startY - e.clientY; + const total = left.clientHeight; + const h = Math.min(Math.max(startH + dy, total * 0.1), total * 0.8); + const ratio = h / total; + left.style.setProperty('--detail-height', (ratio * 100) + '%'); + localStorage.setItem('splitter-ratio', ratio); + } + function onUp() { + splitter.classList.remove('active'); + document.removeEventListener('mousemove', onMove); + document.removeEventListener('mouseup', onUp); + } + splitter.addEventListener('mousedown', e => { + e.preventDefault(); + startY = e.clientY; + startH = detail.offsetHeight; + splitter.classList.add('active'); + document.addEventListener('mousemove', onMove); + document.addEventListener('mouseup', onUp); + }); +})(); + init(); diff --git a/frontend/sw.js b/frontend/sw.js index 23dac27..f14fc83 100644 --- a/frontend/sw.js +++ b/frontend/sw.js @@ -1,4 +1,4 @@ -const CACHE = 'simtrace-analyser-v43'; +const CACHE = 'simtrace-analyser-v44'; const PRECACHE = [ 'index.html', diff --git a/pyproject.toml b/pyproject.toml index 1d0b9e3..54e91dc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.backends._legacy:_Backend" [project] name = "simtrace2-pysniff" -version = "1.22.11" +version = "1.22.12" description = "Python-based sniffing tool for SIMtrace2 hardware (SIM card communication sniffer)" readme = {file = "README.md", content-type = "text/markdown"} license = {text = "GPL-2.0-or-later"} diff --git a/simtrace2_pysniff/__init__.py b/simtrace2_pysniff/__init__.py index 523f11d..5206746 100644 --- a/simtrace2_pysniff/__init__.py +++ b/simtrace2_pysniff/__init__.py @@ -6,7 +6,7 @@ from .gsmtap import GsmtapSender, GsmtapReceiver from .pcap import PcapWriter from .dump import FileDumper, format_message -__version__ = '1.22.11' +__version__ = '1.22.12' __all__ = [ 'SniffSession', 'DeviceDisconnected', diff --git a/tests/test_pcap_import.py b/tests/test_pcap_import.py index 4f91296..34de92e 100644 --- a/tests/test_pcap_import.py +++ b/tests/test_pcap_import.py @@ -224,7 +224,7 @@ class TestImportEndpoint(unittest.TestCase): class TestVersion(unittest.TestCase): def test_package_version(self): from simtrace2_pysniff import __version__ - self.assertEqual(__version__, '1.22.11') + self.assertEqual(__version__, '1.22.12') def test_status_includes_version(self): import os