Harden mobile workbench overflow
GeoIntel CI / docs-smoke (push) Has been cancelled
GeoIntel CI / contract-smoke (push) Has been cancelled

This commit is contained in:
Codex
2026-06-20 00:31:04 +02:00
parent 33d244b921
commit b42aedbec4
6 changed files with 114 additions and 2 deletions
+9
View File
@@ -7,6 +7,15 @@
# Changelog # Changelog
## Sprint 72 Mobile overflow hardening (2026-06-20)
- Clamped page-level horizontal overflow for the workbench shell on mobile.
- Kept sidebar navigation and workspace shortcut chips as contained horizontal scroll areas.
- Added wrapping/containment for long QA identifiers, dataset links and inspector values.
- Made inspector tabs two-column on narrow screens to avoid header overflow.
- Added static regression coverage for mobile overflow and long-identifier wrapping contracts.
- No API contracts, migrations, backend behavior, provider fetching or AI model behavior changed.
## Sprint 71 QA/QC metric card polish (2026-06-19) ## Sprint 71 QA/QC metric card polish (2026-06-19)
- Added core metric evidence cards for precision, recall, F1, mean IoU and false positive/negative counts. - Added core metric evidence cards for precision, recall, F1, mean IoU and false positive/negative counts.
@@ -0,0 +1,30 @@
from __future__ import annotations
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
def test_mobile_overflow_hardening_css_contracts() -> None:
css = (ROOT / "frontend" / "src" / "styles" / "app.css").read_text(encoding="utf-8")
assert "overflow-x: hidden;" in css
assert ".workbench-shell" in css
assert "max-width: 100vw;" in css
assert ".workbench-sidebar nav" in css
assert ".workspace-nav-cluster" in css
assert ".inspector-tabs" in css
assert "repeat(2, minmax(0, 1fr))" in css
assert "overflow-x: clip;" in css
assert "overscroll-behavior-x: contain;" in css
def test_long_identifier_wrapping_contracts() -> None:
css = (ROOT / "frontend" / "src" / "styles" / "app.css").read_text(encoding="utf-8")
assert ".quality-check-dataset-link" in css
assert ".quality-score-row strong" in css
assert ".inspector-field strong" in css
assert "overflow-wrap: anywhere;" in css
assert "word-break: break-word;" in css
+29
View File
@@ -2697,3 +2697,32 @@ Limitations:
Next recommended pass: Next recommended pass:
- Continue with QA/QC metric/result filtering or result-card density for long-lived demo projects. - Continue with QA/QC metric/result filtering or result-card density for long-lived demo projects.
## Sprint 72 Mobile overflow hardening (2026-06-20)
Changed:
- Clamped page-level horizontal overflow for `html`, `body` and the workbench shell.
- Kept mobile sidebar navigation and workspace shortcut chips as contained horizontal scroll regions with overscroll containment.
- Added min-width/max-width containment for the workbench layout, main area, inspector panel and card surfaces.
- Allowed long QA check IDs, dataset links and inspector values to wrap instead of widening result cards.
- Switched inspector tabs to a two-column layout on narrow screens.
- Added `backend/tests/test_sprint72_mobile_overflow_hardening.py`.
- Updated `frontend/README.md`, `docs/TODO.md` and `CHANGELOG.md`.
Tested:
- Red step: `python -m pytest backend/tests/test_sprint72_mobile_overflow_hardening.py -q` failed on missing mobile overflow and identifier wrapping contracts.
- `python -m pytest backend/tests/test_sprint72_mobile_overflow_hardening.py backend/tests/test_sprint71_quality_metric_polish.py backend/tests/test_sprint62_frontend_visual_polish.py backend/tests/test_sprint30_workbench_components.py -q` (`11 passed`)
- `cd frontend && npm run typecheck`
- `cd frontend && npm run build`
- Local browser check against `http://127.0.0.1:5176` with live API proxy at a 390px viewport: QA/QC workspace rendered 2 quality cards and 12 metric cards; body, shell, inspector, inspector panel and inspector tabs stayed within viewport width; sidebar/workspace nav retained contained horizontal scrolling; no console warnings/errors.
- Screenshot captured under `artifacts/sprint72-mobile-overflow-hardening/`.
- `bash scripts/run_readiness_check.sh` (`255 passed`)
Open:
- Redeploy Tower and verify live mobile overflow after deployment.
Limitations:
- Frontend CSS hardening only; no UI flow, API, persistence, migration, provider or AI/model changes.
Next recommended pass:
- Continue with QA/QC result filtering/density for long-lived demo projects, or a broader mobile visual pass across Data and Map once the overflow baseline is stable.
+1
View File
@@ -343,3 +343,4 @@ This file now starts with the current implementation status. Older preparation/b
- [x] Add Data catalog action polish for map, metadata, export and QA affordances. - [x] Add Data catalog action polish for map, metadata, export and QA affordances.
- [x] Add QA/QC handoff polish for candidate/reference context and persisted results. - [x] Add QA/QC handoff polish for candidate/reference context and persisted results.
- [x] Add QA/QC metric card polish for precision, recall, F1, IoU and error counts. - [x] Add QA/QC metric card polish for precision, recall, F1, IoU and error counts.
- [x] Add mobile overflow hardening for workbench navigation, inspector and long QA identifiers.
+2
View File
@@ -285,6 +285,8 @@ The frontend API client uses same-origin requests by default. In Docker Compose,
The QA/QC workspace promotes core metrics into evidence cards before the raw metric list, keeping precision, recall, F1, mean IoU and false positive/negative counts scan-friendly while preserving the persisted raw metrics. The QA/QC workspace promotes core metrics into evidence cards before the raw metric list, keeping precision, recall, F1, mean IoU and false positive/negative counts scan-friendly while preserving the persisted raw metrics.
The workbench shell clamps page-level horizontal overflow on mobile while keeping the sidebar and workspace shortcut rows intentionally scrollable. Long QA identifiers and inspector values wrap inside their cards instead of widening the viewport.
## Useful repository scripts ## Useful repository scripts
- `bash scripts/frontend_install.sh` - `bash scripts/frontend_install.sh`
+43 -2
View File
@@ -25,10 +25,12 @@
} }
html { html {
overflow-x: hidden;
background: var(--bg); background: var(--bg);
} }
body { body {
overflow-x: hidden;
margin: 0; margin: 0;
font-family: Inter, 'Avenir Next', 'Segoe UI', sans-serif; font-family: Inter, 'Avenir Next', 'Segoe UI', sans-serif;
color: var(--text); color: var(--text);
@@ -39,6 +41,11 @@ body {
text-rendering: optimizeLegibility; text-rendering: optimizeLegibility;
} }
.workbench-shell {
max-width: 100vw;
overflow-x: clip;
}
button, button,
input, input,
select, select,
@@ -514,7 +521,8 @@ section li strong + div {
.workbench-shell { .workbench-shell {
width: 100%; width: 100%;
max-width: none; max-width: 100vw;
overflow-x: clip;
padding: 0; padding: 0;
background: #eef4f1; background: #eef4f1;
} }
@@ -579,10 +587,13 @@ section li strong + div {
gap: 0; gap: 0;
height: calc(100vh - 4.35rem); height: calc(100vh - 4.35rem);
min-height: 42rem; min-height: 42rem;
max-width: 100vw;
min-width: 0;
} }
.workbench-sidebar, .workbench-sidebar,
.workbench-inspector { .workbench-inspector {
min-width: 0;
min-height: 0; min-height: 0;
overflow: auto; overflow: auto;
border-color: var(--line); border-color: var(--line);
@@ -640,6 +651,7 @@ section li strong + div {
.workbench-main { .workbench-main {
min-width: 0; min-width: 0;
min-height: 0; min-height: 0;
max-width: 100%;
overflow: auto; overflow: auto;
padding: 0.9rem 1.05rem 1.15rem; padding: 0.9rem 1.05rem 1.15rem;
} }
@@ -1066,6 +1078,7 @@ button.entity-card {
.export-card, .export-card,
.latest-export-card, .latest-export-card,
.empty-state { .empty-state {
min-width: 0;
padding: 0.85rem; padding: 0.85rem;
} }
@@ -1270,6 +1283,7 @@ button.entity-card {
.quality-dataset-name, .quality-dataset-name,
.quality-check-dataset-link { .quality-check-dataset-link {
overflow-wrap: anywhere; overflow-wrap: anywhere;
word-break: break-word;
} }
.quality-dataset-name { .quality-dataset-name {
@@ -1301,7 +1315,13 @@ button.entity-card {
font-size: 0.9rem; font-size: 0.9rem;
line-height: 1.25; line-height: 1.25;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: normal;
}
.quality-score-row strong,
.inspector-field strong {
overflow-wrap: anywhere;
word-break: break-word;
} }
.quality-metric-section { .quality-metric-section {
@@ -1710,11 +1730,17 @@ button.entity-card {
.workbench-inspector-panel { .workbench-inspector-panel {
display: grid; display: grid;
gap: 0.68rem; gap: 0.68rem;
max-width: 100%;
min-width: 0;
overflow-x: clip;
} }
.inspector-header { .inspector-header {
display: grid; display: grid;
gap: 0.2rem; gap: 0.2rem;
max-width: 100%;
min-width: 0;
overflow-x: clip;
} }
.inspector-header h2 { .inspector-header h2 {
@@ -1734,12 +1760,14 @@ button.entity-card {
} }
.inspector-tab { .inspector-tab {
min-width: 0;
min-height: 2.2rem; min-height: 2.2rem;
padding: 0.38rem 0.42rem; padding: 0.38rem 0.42rem;
background: #ffffff; background: #ffffff;
box-shadow: none; box-shadow: none;
font-size: 0.78rem; font-size: 0.78rem;
line-height: 1.2; line-height: 1.2;
overflow-wrap: anywhere;
} }
.inspector-tab-active { .inspector-tab-active {
@@ -1882,6 +1910,7 @@ button.entity-card {
position: sticky; position: sticky;
top: 5.8rem; top: 5.8rem;
z-index: 10; z-index: 10;
max-width: 100vw;
border-right: 0; border-right: 0;
border-bottom: 1px solid var(--line); border-bottom: 1px solid var(--line);
} }
@@ -1941,16 +1970,26 @@ button.entity-card {
padding: 0.75rem; padding: 0.75rem;
} }
.workbench-inspector {
overflow-x: hidden;
}
.context-bar, .context-bar,
.quick-action-grid, .quick-action-grid,
.workspace-nav-cluster { .workspace-nav-cluster {
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }
.inspector-tabs {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.workbench-sidebar nav { .workbench-sidebar nav {
display: flex; display: flex;
gap: 0.5rem; gap: 0.5rem;
max-width: 100%;
overflow-x: auto; overflow-x: auto;
overscroll-behavior-x: contain;
padding-bottom: 0.2rem; padding-bottom: 0.2rem;
} }
@@ -1961,7 +2000,9 @@ button.entity-card {
.workspace-nav-cluster { .workspace-nav-cluster {
display: flex; display: flex;
flex-wrap: nowrap; flex-wrap: nowrap;
max-width: 100%;
overflow-x: auto; overflow-x: auto;
overscroll-behavior-x: contain;
padding-bottom: 0.1rem; padding-bottom: 0.1rem;
} }