Topbar: title trim, shorter search, the view selector pinned above the panel (v2.6.3)
- the header title drops its "UICC" prefix — "GSMTAP trace analyser" is enough - the trace topbar's search input is half its previous width (flex basis 33.333% -> 16.667%); the session name now ellipsizes instead of wrapping the tighter row - the side-panel view selector moved out of the scrollable side panel into the trace topbar: right-aligned over the panel at the panel's width (--side-panel-w: 260px, the negative right margin cancelling the topbar's 16px padding so the edges line up), so it stays visible at all times while the panel scrolls - tests: the topbar/selector position pins (the Files-view wiring test and style.test.js), the shared width variable, the halved search basis and the title; 527 Python + 61 Node tests - README/README_RUS: the selector's new place; PWA_VERSION/pyproject/ version.py 2.6.3, SW cache simtrace-analyser-v77
This commit is contained in:
1 parent
76c5647dd4
commit
475c136749
9 files changed
+65
-20
No files matched your search
@@ -199,8 +199,10 @@ in the stored wire shape and are skipped with a note in the import report.
|
||||
|
||||
### Files view (per-file tracking)
|
||||
|
||||
The Trace tab's side panel has a view selector (*Map* / *Stats* / **Files**;
|
||||
a drop-down, since three tab captions no longer fit). The Files view is a
|
||||
The Trace tab has a view selector (*Map* / *Stats* / **Files**) in its topbar,
|
||||
right-aligned over the side panel with the panel's width, so it stays visible
|
||||
while the panel scrolls (a drop-down, since three tab captions no longer
|
||||
fit). The Files view is a
|
||||
trace-wide timeline of file operations — every **Read**, **Update** and
|
||||
**Changed on card** row shows the same file name as the Map view, and clicking
|
||||
a row jumps straight to the APDU in the trace and leaves it highlighted
|
||||
|
||||
+4
-2
@@ -203,8 +203,10 @@ Application Layer* — два отдельных поля выбора, имен
|
||||
|
||||
### Просмотр файлов (сопровождение состояния файлов)
|
||||
|
||||
В боковой панели вкладки «Трассировка» появился выбор вида (*Map* / *Stats* /
|
||||
**Files** — выпадающий список, три подписи-вкладки уже не помещались). Вид
|
||||
В верхней панели вкладки «Трассировка» появился выбор вида (*Map* / *Stats* /
|
||||
**Files**) — он выровнен по правому краю над боковой панелью и имеет её
|
||||
ширину, поэтому виден всё время, пока панель прокручивается (выпадающий
|
||||
список, три подписи-вкладки уже не помещались). Вид
|
||||
Files — это таймлайн файловых операций по всей трассе: строки **Read**,
|
||||
**Update** и **Changed on card** показывают те же имена файлов, что и вид Map,
|
||||
а щелчок по строке переходит прямо к APDU в трассе и оставляет его
|
||||
|
||||
+20
-11
@@ -9,6 +9,11 @@
|
||||
<link rel="icon" type="image/png" href="favicon.png">
|
||||
<meta name="theme-color" content="#0f172a">
|
||||
<style>
|
||||
:root {
|
||||
/* Layout sizes (theme-independent) */
|
||||
--side-panel-w: 260px;
|
||||
}
|
||||
|
||||
:root, [data-theme="dark"] {
|
||||
--bg: #0f172a;
|
||||
--bg-panel: #1e293b;
|
||||
@@ -104,10 +109,11 @@ body { font: 14px/1.5 system-ui, sans-serif; background: var(--bg); color: var(-
|
||||
|
||||
/* Trace view */
|
||||
.trace-topbar { display: flex; gap: 12px; padding: 12px 16px; background: var(--bg-panel); align-items: center; flex-shrink: 0; }
|
||||
.trace-topbar input { flex: 0 1 33.333%; padding: 8px 12px; background: var(--bg-input); border: 1px solid var(--border); border-radius: 4px; color: var(--text); }
|
||||
.trace-topbar input { flex: 0 1 16.667%; padding: 8px 12px; background: var(--bg-input); border: 1px solid var(--border); border-radius: 4px; color: var(--text); }
|
||||
.trace-topbar input::placeholder { color: var(--text-muted); }
|
||||
.trace-topbar select { padding: 8px 12px; background: var(--bg-input); border: 1px solid var(--border); border-radius: 4px; color: var(--text); }
|
||||
.trace-topbar .filter-label { color: var(--text-muted); font-size: 13px; white-space: nowrap; }
|
||||
.trace-topbar #session-name-display { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||
.trace-topbar button { padding: 8px 16px; background: var(--accent); color: #fff; border: none; border-radius: 4px; cursor: pointer; font-weight: 600; }
|
||||
.trace-topbar button:hover { background: var(--accent-hover); }
|
||||
.trace-topbar button.stop { background: var(--danger); color: #fff; }
|
||||
@@ -171,7 +177,7 @@ body { font: 14px/1.5 system-ui, sans-serif; background: var(--bg); color: var(-
|
||||
.detail-body td.name { color: var(--accent); font-weight: 600; }
|
||||
|
||||
/* Side panel */
|
||||
.side-panel { width: 260px; background: var(--bg-panel); padding: 12px; overflow-y: auto; flex-shrink: 0; border-left: 1px solid var(--bg-input); }
|
||||
.side-panel { width: var(--side-panel-w); background: var(--bg-panel); padding: 12px; overflow-y: auto; flex-shrink: 0; border-left: 1px solid var(--bg-input); }
|
||||
.side-panel h3 { color: var(--accent); margin-bottom: 8px; font-size: 13px; text-transform: uppercase; letter-spacing: 1px; }
|
||||
.side-item { display: flex; justify-content: space-between; padding: 3px 8px; cursor: pointer; border-radius: 4px; font-size: 13px; }
|
||||
.side-item:hover { background: var(--bg-input); }
|
||||
@@ -179,8 +185,11 @@ body { font: 14px/1.5 system-ui, sans-serif; background: var(--bg); color: var(-
|
||||
.side-tabs { display: flex; margin-bottom: 8px; border-bottom: 1px solid var(--bg-input); }
|
||||
.side-tab { flex: 1; padding: 6px 0; background: none; border: none; color: var(--text-muted); cursor: pointer; font-size: 12px; text-transform: uppercase; letter-spacing: 1px; border-bottom: 2px solid transparent; }
|
||||
.side-tab.active { color: var(--accent); border-bottom-color: var(--accent); }
|
||||
.side-view-select { width: 100%; margin-bottom: 8px; padding: 6px 8px; background: var(--bg-input); color: var(--text);
|
||||
border: 1px solid var(--border); border-radius: 4px; font-size: 12px; text-transform: uppercase; letter-spacing: 1px; cursor: pointer; }
|
||||
/* Side-panel view selector: it lives in the trace topbar, right-aligned over
|
||||
the side panel with the panel's width, so it stays visible while the panel
|
||||
scrolls. The negative right margin cancels the topbar's 16px padding, so
|
||||
its right edge lines up with the panel's. */
|
||||
.trace-topbar .side-view-select { width: var(--side-panel-w); flex: 0 0 auto; margin-left: auto; margin-right: -16px; }
|
||||
.file-op { display: flex; align-items: baseline; gap: 6px; padding: 3px 8px; cursor: pointer; border-radius: 4px; font-size: 13px; word-break: break-word; }
|
||||
.file-op:hover { background: var(--bg-input); }
|
||||
.file-op-read { color: var(--text-muted); }
|
||||
@@ -330,7 +339,7 @@ body { font: 14px/1.5 system-ui, sans-serif; background: var(--bg); color: var(-
|
||||
<div class="header-tab" data-tab="sessions" data-l10n="Sessions">Sessions</div>
|
||||
<div class="header-tab" data-tab="settings" data-l10n="Settings">Settings</div>
|
||||
</div>
|
||||
<div class="header-title">UICC <a href="https://osmocom.org/projects/baseband/wiki/GSMTAP" target="_blank" rel="noopener">GSMTAP</a> <span data-l10n="trace analyser">trace analyser</span> <span class="pwa-version" id="pwa-version"></span></div>
|
||||
<div class="header-title"><a href="https://osmocom.org/projects/baseband/wiki/GSMTAP" target="_blank" rel="noopener">GSMTAP</a> <span data-l10n="trace analyser">trace analyser</span> <span class="pwa-version" id="pwa-version"></span></div>
|
||||
<div class="header-right">
|
||||
<span class="capture-chip" id="capture-chip" style="display:none"></span>
|
||||
<button id="install-btn" data-l10n="Install PWA">Install PWA</button>
|
||||
@@ -348,6 +357,11 @@ body { font: 14px/1.5 system-ui, sans-serif; background: var(--bg); color: var(-
|
||||
<option value="" data-l10n="All commands">All commands</option>
|
||||
</select>
|
||||
<span id="session-name-display" style="display:none; color:var(--text-muted); font-size:15px; font-weight:700;"></span>
|
||||
<select class="side-view-select" id="side-view-select" aria-label="Side panel view">
|
||||
<option value="map" data-l10n="Map">Map</option>
|
||||
<option value="stats" data-l10n="Stats">Stats</option>
|
||||
<option value="files" data-l10n="Files">Files</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="trace-main">
|
||||
<div class="trace-left">
|
||||
@@ -358,11 +372,6 @@ body { font: 14px/1.5 system-ui, sans-serif; background: var(--bg); color: var(-
|
||||
</div>
|
||||
</div>
|
||||
<div class="side-panel" id="side-panel">
|
||||
<select class="side-view-select" id="side-view-select" aria-label="Side panel view">
|
||||
<option value="map" data-l10n="Map">Map</option>
|
||||
<option value="stats" data-l10n="Stats">Stats</option>
|
||||
<option value="files" data-l10n="Files">Files</option>
|
||||
</select>
|
||||
<div id="type-counts">—</div>
|
||||
<div id="type-map" style="display:none">—</div>
|
||||
<div id="file-view" style="display:none">—</div>
|
||||
@@ -3216,7 +3225,7 @@ function onFilterChange() {
|
||||
}
|
||||
|
||||
// ──────────────────── Versioning ────────────────────
|
||||
const PWA_VERSION = '2.6.2';
|
||||
const PWA_VERSION = '2.6.3';
|
||||
const MIN_SERVER_VERSION = '2.3.0';
|
||||
|
||||
function parseVersion(v) {
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
const CACHE = 'simtrace-analyser-v76';
|
||||
const CACHE = 'simtrace-analyser-v77';
|
||||
|
||||
const PRECACHE = [
|
||||
'index.html',
|
||||
|
||||
@@ -324,8 +324,14 @@ test('Files view: the hex image respects the row limit', () => {
|
||||
assert.equal(view.end, 64);
|
||||
});
|
||||
|
||||
test('Files view: side-panel dropdown and the timeline are wired', () => {
|
||||
test('Files view: the view selector (topbar) and the timeline are wired', () => {
|
||||
assert.match(src, /<select class="side-view-select" id="side-view-select"[^>]*>/);
|
||||
// The selector is a topbar control (before the two-column trace area), so
|
||||
// it stays visible while the side panel scrolls.
|
||||
const topbar = src.indexOf('<div class="trace-topbar">');
|
||||
const sel = src.indexOf('id="side-view-select"');
|
||||
const main = src.indexOf('<div class="trace-main">');
|
||||
assert.ok(topbar >= 0 && topbar < sel && sel < main, 'selector in the topbar');
|
||||
assert.match(src, /<option value="files" data-l10n="Files">/);
|
||||
assert.doesNotMatch(src, /class="side-tab/);
|
||||
assert.match(src, /id="file-view"/);
|
||||
|
||||
@@ -21,3 +21,29 @@ test('no per-element scrollbar overrides or thin default remain', () => {
|
||||
assert.doesNotMatch(src, /\.side-panel::-webkit-scrollbar/);
|
||||
assert.doesNotMatch(src, /::-webkit-scrollbar \{ width: 6px/);
|
||||
});
|
||||
|
||||
// ── trace topbar layout ────────────────────────────────────────────────
|
||||
|
||||
test('the view selector sits over the side panel at the panel width', () => {
|
||||
// one layout variable keeps the two the same width
|
||||
assert.match(src, /--side-panel-w: 260px;/);
|
||||
assert.match(src, /\.side-panel \{ width: var\(--side-panel-w\);/);
|
||||
assert.match(src, /\.trace-topbar \.side-view-select \{ width: var\(--side-panel-w\); flex: 0 0 auto; margin-left: auto; margin-right: -16px; \}/);
|
||||
// the selector is a topbar control (before the two-column trace area,
|
||||
// which keeps it visible while the panel scrolls)
|
||||
const topbar = src.indexOf('<div class="trace-topbar">');
|
||||
const sel = src.indexOf('id="side-view-select"');
|
||||
const main = src.indexOf('<div class="trace-main">');
|
||||
assert.ok(topbar >= 0 && topbar < sel && sel < main, 'selector in the topbar');
|
||||
});
|
||||
|
||||
test('the search input is half its previous width', () => {
|
||||
assert.match(src, /\.trace-topbar input \{ flex: 0 1 16\.667%;/);
|
||||
// a long session name ellipsizes rather than wrapping the now tighter row
|
||||
assert.match(src, /\.trace-topbar #session-name-display \{ white-space: nowrap; overflow: hidden; text-overflow: ellipsis; \}/);
|
||||
});
|
||||
|
||||
test('the header title carries no UICC prefix', () => {
|
||||
assert.match(src, /<div class="header-title"><a href="https:\/\/osmocom\.org\/projects\/baseband\/wiki\/GSMTAP"/);
|
||||
assert.doesNotMatch(src, /class="header-title">UICC/);
|
||||
});
|
||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.backends._legacy:_Backend"
|
||||
|
||||
[project]
|
||||
name = "simtrace-analyser"
|
||||
version = "2.6.2"
|
||||
version = "2.6.3"
|
||||
description = "SIMtrace Analyser — APDU trace analyser for GSMTAP/PCAP captures (bundles the simtrace2-pysniff utility)"
|
||||
readme = {file = "README.md", content-type = "text/markdown"}
|
||||
license = {text = "GPL-2.0-or-later"}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
"""Single source of truth for the SIMtrace Analyser version."""
|
||||
|
||||
__version__ = '2.6.2'
|
||||
__version__ = '2.6.3'
|
||||
@@ -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__, '2.6.2')
|
||||
self.assertEqual(__version__, '2.6.3')
|
||||
|
||||
def test_status_includes_version(self):
|
||||
import os
|
||||
|
||||
Reference in new issue
Block a user