From b8fb309dfb97eeb0aefa5924e99d0e385219b363 Mon Sep 17 00:00:00 2001 From: Sean Ahern Date: Thu, 3 Sep 2026 12:16:36 -0400 Subject: [PATCH 1/2] Preserve drive history group expansion --- AGENTS.md | 20 +++++++++++++------- driving_log/static/app.js | 27 +++++++++++++++++++++++++++ driving_log/templates/drives.html | 2 +- tests/test_browser.py | 20 ++++++++++++++++++++ 4 files changed, 61 insertions(+), 8 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index dd0e6b5..6c6776f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -16,10 +16,13 @@ PYTHONPATH=. .venv/bin/pytest -m "not browser" --cov --cov-report=term-missing - git diff --check ``` -Also run `pytest -m browser` with CI's WebKit setup when available. On this -Rocky host, the bundled WebKit cannot launch because of its system-library -requirements. Use a rootless `podman` (or Docker) installation and network -access to the Microsoft Playwright image to run WebKit in a matching container: +Also run `pytest -m browser` with CI's WebKit setup. On this Rocky host, the +bundled WebKit cannot launch because of its system-library requirements, but a +rootless `podman` installation and network access to the Microsoft Playwright +image are available. When working on this machine, presume that the +containerized WebKit procedure below can be run and attempt it before using any +fallback. A bundled-WebKit launch failure is not evidence that WebKit is +unavailable. ```sh WEBKIT_VERSION="$(.venv/bin/python -c 'from importlib.metadata import version; print(version("playwright"))')" @@ -34,8 +37,11 @@ podman stop driving-record-webkit The image and installed Python Playwright version must match because the run-server protocol is version-specific. `--network host` lets containerized -WebKit reach the temporary `127.0.0.1` server created by the tests. If this -setup is unavailable, state that limitation explicitly and run the project's -configured Chromium fallback only when the test documents it. +WebKit reach the temporary `127.0.0.1` server created by the tests. If sandbox +permissions prevent loopback binding or Podman execution, request escalation +and retry the same procedure. Use the project's configured Chromium fallback +only after the containerized WebKit procedure has been attempted and failed; +report the exact failing command and reason before doing so. If the procedure +cannot be run after that retry, state the limitation explicitly. Inspect each PR's GitHub check results after pushing; distinguish a pre-existing or unrelated failure from one introduced by the branch with log evidence. diff --git a/driving_log/static/app.js b/driving_log/static/app.js index 5d02fab..66e7cf7 100644 --- a/driving_log/static/app.js +++ b/driving_log/static/app.js @@ -333,6 +333,33 @@ }); }); + const driveGroups = document.querySelectorAll("details[data-drive-group-key]"); + if (driveGroups.length) { + const storageKey = `driving-log:expanded-drive-groups:${location.pathname}${location.search}`; + let expanded = new Set(); + try { + expanded = new Set(JSON.parse(sessionStorage.getItem(storageKey) || "[]")); + } catch (_) { + // Storage may be unavailable in private browsing or under a strict policy. + } + const saveExpanded = () => { + try { + sessionStorage.setItem(storageKey, JSON.stringify([...expanded])); + } catch (_) { + // The disclosure still works for this page when persistence is unavailable. + } + }; + driveGroups.forEach(group => { + const key = group.dataset.driveGroupKey; + if (expanded.has(key)) group.open = true; + group.addEventListener("toggle", () => { + if (group.open) expanded.add(key); + else expanded.delete(key); + saveExpanded(); + }); + }); + } + document.querySelectorAll("[data-cancel-form]").forEach(link => { const form = document.getElementById(link.dataset.cancelForm); if (!form) return; diff --git a/driving_log/templates/drives.html b/driving_log/templates/drives.html index ffb2888..297b56e 100644 --- a/driving_log/templates/drives.html +++ b/driving_log/templates/drives.html @@ -80,7 +80,7 @@

Drive history

{% if groups %}
{% for group in groups %} -
+
{{ group.label }}{{ group.drives | length }} drive{{ "" if group.drives|length == 1 else "s" }} · {{ format_minutes(group.minutes) }} · {{ group.percentage }}% of total
{% if group.day_minutes and group.night_minutes %}{{ format_minutes(group.day_minutes) }} day · {{ format_minutes(group.night_minutes) }} night{% elif group.day_minutes %}{{ format_minutes(group.day_minutes) }} day{% else %}{{ format_minutes(group.night_minutes) }} night{% endif %}
{% for item in group.drives %}{{ drive_row(item) }}{% endfor %}
diff --git a/tests/test_browser.py b/tests/test_browser.py index f18ff1b..818d9aa 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -485,6 +485,26 @@ def test_mobile_webkit_live_drive_recovery() -> None: assert recovered.locator('input[name="acknowledge_warnings"]').count() == 0 assert recovered.locator('input[name="supervisor_dl_number"]').count() == 0 assert recovered.locator('input[name="supervisor_dl_state"]').count() == 0 + recovered.get_by_role("button", name="Save completed drive").click() + recovered.get_by_role("heading", name="Student progress").wait_for() + for grouping in ( + "date", + "supervisor", + "day_night", + "part_of_day", + "road_type", + "weather", + "duration", + ): + recovered.goto(f"{url}/drives?group_by={grouping}") + group = recovered.locator("details[data-drive-group-key]").first + group.locator("summary").click() + assert group.get_attribute("open") == "" + group.locator(".drive-row").click() + recovered.get_by_role("heading", name="Drive details").wait_for() + recovered.go_back() + recovered.get_by_role("heading", name="Drive history").wait_for() + assert group.get_attribute("open") == "" recovered.goto(f"{url}/dmv") recovered.locator('select[name="display_name"]').select_option("Sean Ahern") recovered.locator('input[name="dl_number"]').fill("SYNTHETIC-1234") From 45effbb161dc2c6a89af63eabba6716f903d77c0 Mon Sep 17 00:00:00 2001 From: Sean Ahern Date: Thu, 3 Sep 2026 12:24:18 -0400 Subject: [PATCH 2/2] Strengthen drive history persistence regression --- tests/test_browser.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/test_browser.py b/tests/test_browser.py index 818d9aa..ec66b93 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -500,6 +500,9 @@ def test_mobile_webkit_live_drive_recovery() -> None: group = recovered.locator("details[data-drive-group-key]").first group.locator("summary").click() assert group.get_attribute("open") == "" + recovered.reload() + recovered.get_by_role("heading", name="Drive history").wait_for() + assert group.get_attribute("open") == "" group.locator(".drive-row").click() recovered.get_by_role("heading", name="Drive details").wait_for() recovered.go_back()