Polish QA workspace density
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 20:19:09 +02:00
parent c571dfe96c
commit 2cec332d5c
7 changed files with 369 additions and 186 deletions
+8
View File
@@ -7,6 +7,14 @@
# Changelog # Changelog
## Sprint 86 QA/QC workspace density polish (2026-06-20)
- Grouped QA/QC summary, dataset evidence, refresh/filter controls and result history into focused surfaces.
- Kept existing persisted quality check filters, refresh behavior, metric cards and history rendering unchanged.
- Added compact mobile breakpoint grids for QA/QC summary, handoff evidence, filters and metric/history rows.
- Added static regression coverage for QA/QC workspace hierarchy and density contracts.
- No API contracts, migrations, backend behavior, provider fetching or AI model behavior changed.
## Sprint 85 Map workspace density polish (2026-06-20) ## Sprint 85 Map workspace density polish (2026-06-20)
- Added a compact Map workspace context summary for selected AOI, active layer and rendered feature state. - Added a compact Map workspace context summary for selected AOI, active layer and rendered feature state.
@@ -0,0 +1,55 @@
from __future__ import annotations
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
def test_quality_results_panel_exposes_structured_surfaces() -> None:
panel = (ROOT / "frontend" / "src" / "components" / "quality" / "QualityResultsPanel.tsx").read_text(
encoding="utf-8"
)
assert 'className="quality-results-panel"' in panel
assert 'className="quality-results-shell"' in panel
assert 'className="quality-summary-surface"' in panel
assert 'aria-label="QA/QC result summary"' in panel
assert 'className="quality-evidence-surface"' in panel
assert 'aria-label="QA/QC dataset evidence"' in panel
assert 'className="quality-control-surface"' in panel
assert 'aria-label="QA/QC refresh and filters"' in panel
assert 'className="quality-result-state-stack"' in panel
assert 'className="quality-history-surface"' in panel
assert 'aria-label="QA/QC result history"' in panel
def test_quality_results_panel_preserves_existing_refresh_filter_and_history_state() -> None:
panel = (ROOT / "frontend" / "src" / "components" / "quality" / "QualityResultsPanel.tsx").read_text(
encoding="utf-8"
)
assert "onRefresh" in panel
assert "qualityStatusFilter" in panel
assert "qualityTypeFilter" in panel
assert "qualitySearchQuery" in panel
assert "visibleQualityChecks.map" in panel
assert "Show all QA/QC results" in panel
assert "No QA/QC results match the current filters." in panel
def test_quality_workspace_density_css_contracts() -> None:
css = (ROOT / "frontend" / "src" / "styles" / "app.css").read_text(encoding="utf-8")
assert ".quality-results-shell" in css
assert ".quality-summary-surface" in css
assert ".quality-evidence-surface" in css
assert ".quality-control-surface" in css
assert ".quality-history-surface" in css
assert ".quality-result-state-stack" in css
assert ".quality-results-shell .quality-summary-grid" in css
assert ".quality-results-shell .quality-handoff-grid" in css
assert ".quality-results-shell .quality-history-controls" in css
assert "grid-template-columns: repeat(auto-fit, minmax(8.25rem, 1fr));" in css
assert "grid-template-columns: repeat(auto-fit, minmax(7.5rem, 1fr));" in css
assert "background: linear-gradient(180deg, #ffffff, #f7fbf8);" in css
+29
View File
@@ -3108,3 +3108,32 @@ Limitations:
Next recommended pass: Next recommended pass:
- Continue with QA/QC workspace result hierarchy and filter density after this pass is deployed and visually checked. - Continue with QA/QC workspace result hierarchy and filter density after this pass is deployed and visually checked.
## Sprint 86 QA/QC workspace density polish (2026-06-20)
Changed:
- Wrapped QA/QC summary metrics in `quality-summary-surface`.
- Wrapped candidate/reference/latest comparison context in `quality-evidence-surface`.
- Wrapped refresh, result states, filters and list limit controls in `quality-control-surface`.
- Wrapped persisted quality check cards in `quality-history-surface`.
- Added compact mobile CSS contracts for QA/QC summary, handoff, filter, score, metric and raw metric grids.
- Added `backend/tests/test_sprint86_quality_workspace_density.py`.
- Updated `frontend/README.md`, `docs/TODO.md` and `CHANGELOG.md`.
Tested:
- Live browser pre-check against `http://192.168.10.150:1202` showed QA/QC workspace had no console errors or horizontal overflow, but summary, handoff, filters and history were still visually stacked at equal weight. Mobile measured summary at 210px, handoff at 295px and filters at 278px before the result history.
- Red step: `python -m pytest backend/tests/test_sprint86_quality_workspace_density.py -q` failed on missing QA/QC surface and density CSS contracts.
- `python -m pytest backend/tests/test_sprint86_quality_workspace_density.py -q` (`3 passed`)
- `python -m pytest backend/tests/test_sprint86_quality_workspace_density.py backend/tests/test_sprint70_quality_handoff_polish.py backend/tests/test_sprint71_quality_metric_polish.py backend/tests/test_sprint73_quality_result_filtering.py backend/tests/test_sprint81_result_state_polish.py backend/tests/test_sprint47_workbench_interaction_smoke.py -q` (`18 passed`)
- `cd frontend && npm run typecheck`
- `cd frontend && npm run build`
- Full readiness and Tower deploy pending in this pass.
Open:
- None known before full readiness/deploy validation.
Limitations:
- Frontend QA/QC workspace presentation hierarchy only; no quality-check behavior, API contract, persistence, migration, provider fetching or AI/model changes.
Next recommended pass:
- Continue with Change Detection panel hierarchy and analysis workspace balance after this pass is deployed and visually checked.
+1
View File
@@ -75,6 +75,7 @@ This file now starts with the current implementation status. Older preparation/b
- [x] Add Overview workspace panel hierarchy polish for readiness and recommended-action regions. - [x] Add Overview workspace panel hierarchy polish for readiness and recommended-action regions.
- [x] Add Data workspace selected-summary and panel density polish. - [x] Add Data workspace selected-summary and panel density polish.
- [x] Add Map workspace panel hierarchy and layer-control density polish. - [x] Add Map workspace panel hierarchy and layer-control density polish.
- [x] Add QA/QC workspace result hierarchy and filter density polish.
## Sprint 8 status ## Sprint 8 status
+2
View File
@@ -8,6 +8,8 @@ Data and Map workspaces include mobile-density CSS for file inputs, dataset acti
Map workspace now surfaces the selected AOI, active layer and rendered feature state before controls, then separates layer controls, provenance, the MapLibre frame and the feature inspector into focused surfaces. The underlying overlay, opacity and feature-selection behavior is unchanged. Map workspace now surfaces the selected AOI, active layer and rendered feature state before controls, then separates layer controls, provenance, the MapLibre frame and the feature inspector into focused surfaces. The underlying overlay, opacity and feature-selection behavior is unchanged.
QA/QC Results now separates persisted check summary, candidate/reference evidence, refresh/filter controls and result history into focused surfaces. Existing filters, refresh behavior, metric cards and stored result rendering are unchanged, with denser mobile grids for the same controls.
AI Labs uses the same mobile-density baseline for Detection and Segmentation model cards, run forms, QA/result summaries and scroll-safe result tables. This keeps long model ids, tile paths and artifact paths from widening the workbench on phones. AI Labs uses the same mobile-density baseline for Detection and Segmentation model cards, run forms, QA/result summaries and scroll-safe result tables. This keeps long model ids, tile paths and artifact paths from widening the workbench on phones.
Exports and System provider capabilities now use compact, mobile-safe cards for handoff actions, artifact filters and provider metadata. Long provider limitations, export ids and artifact paths wrap inside their cards instead of widening the workbench. Exports and System provider capabilities now use compact, mobile-safe cards for handoff actions, artifact filters and provider metadata. Long provider limitations, export ids and artifact paths wrap inside their cards instead of widening the workbench.
@@ -106,6 +106,7 @@ export function QualityResultsPanel({
return ( return (
<section className="quality-results-panel" data-testid="quality-results-panel"> <section className="quality-results-panel" data-testid="quality-results-panel">
<div className="quality-results-shell">
<div className="panel-title-row"> <div className="panel-title-row">
<div> <div>
<h2>QA/QC Results</h2> <h2>QA/QC Results</h2>
@@ -113,6 +114,8 @@ export function QualityResultsPanel({
</div> </div>
<span className="count-pill">{qualityChecks.length} checks</span> <span className="count-pill">{qualityChecks.length} checks</span>
</div> </div>
<div className="quality-summary-surface" aria-label="QA/QC result summary">
<div className="quality-summary-grid"> <div className="quality-summary-grid">
<div> <div>
<span>Completed</span> <span>Completed</span>
@@ -127,6 +130,9 @@ export function QualityResultsPanel({
<strong>{latestCheck?.status ?? 'waiting'}</strong> <strong>{latestCheck?.status ?? 'waiting'}</strong>
</div> </div>
</div> </div>
</div>
<div className="quality-evidence-surface" aria-label="QA/QC dataset evidence">
<div className="quality-handoff-grid" aria-label="QA/QC dataset handoff context"> <div className="quality-handoff-grid" aria-label="QA/QC dataset handoff context">
<div> <div>
<span>Candidate layers</span> <span>Candidate layers</span>
@@ -146,6 +152,9 @@ export function QualityResultsPanel({
</p> </p>
</div> </div>
</div> </div>
</div>
<div className="quality-control-surface" aria-label="QA/QC refresh and filters">
<div className="button-row"> <div className="button-row">
<button <button
type="button" type="button"
@@ -157,6 +166,8 @@ export function QualityResultsPanel({
Refresh QA/QC results Refresh QA/QC results
</button> </button>
</div> </div>
<div className="quality-result-state-stack">
{qualityChecksError ? ( {qualityChecksError ? (
<div className="result-state result-state-error"> <div className="result-state result-state-error">
<strong>QA/QC results could not be loaded.</strong> <strong>QA/QC results could not be loaded.</strong>
@@ -169,6 +180,8 @@ export function QualityResultsPanel({
<p>Run dataset, detection or segmentation QA against a reference layer to populate this workspace.</p> <p>Run dataset, detection or segmentation QA against a reference layer to populate this workspace.</p>
</div> </div>
) : null} ) : null}
</div>
{qualityChecks.length > 0 ? ( {qualityChecks.length > 0 ? (
<div className="quality-history-controls" aria-label="QA/QC result filters"> <div className="quality-history-controls" aria-label="QA/QC result filters">
<label> <label>
@@ -234,6 +247,13 @@ export function QualityResultsPanel({
<p>Clear the search, status or check type filter to return to the latest quality results.</p> <p>Clear the search, status or check type filter to return to the latest quality results.</p>
</div> </div>
) : null} ) : null}
</div>
<div className="quality-history-surface" aria-label="QA/QC result history">
<div className="panel-title-row">
<h3>Result history</h3>
<span className="count-pill">{visibleQualityChecks.length} shown</span>
</div>
<ul className="quality-check-list"> <ul className="quality-check-list">
{visibleQualityChecks.map((check) => ( {visibleQualityChecks.map((check) => (
<li className="quality-check-card" key={check.id}> <li className="quality-check-card" key={check.id}>
@@ -294,6 +314,8 @@ export function QualityResultsPanel({
</li> </li>
))} ))}
</ul> </ul>
</div>
</div>
</section> </section>
) )
} }
+71 -5
View File
@@ -1420,18 +1420,63 @@ button.entity-card {
overflow-wrap: anywhere; overflow-wrap: anywhere;
} }
.quality-summary-grid { .quality-results-shell {
display: grid;
gap: 0.75rem;
}
.quality-summary-surface,
.quality-evidence-surface,
.quality-control-surface,
.quality-history-surface {
min-width: 0;
border: 1px solid var(--line);
border-radius: 8px;
padding: 0.72rem;
background: #ffffff;
}
.quality-summary-surface {
background: linear-gradient(180deg, #ffffff, #f7fbf8);
}
.quality-evidence-surface {
background: #f8fbf9;
}
.quality-control-surface,
.quality-history-surface {
display: grid;
gap: 0.68rem;
}
.quality-control-surface .button-row,
.quality-control-surface .quality-history-controls,
.quality-control-surface .list-limit-banner {
margin-top: 0;
}
.quality-result-state-stack {
display: grid;
gap: 0.55rem;
}
.quality-results-shell .quality-check-list {
margin: 0;
}
.quality-results-shell .quality-summary-grid {
display: grid; display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr)); grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 0.65rem; gap: 0.65rem;
margin: 0.75rem 0; margin: 0;
} }
.quality-handoff-grid { .quality-results-shell .quality-handoff-grid {
display: grid; display: grid;
grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr)); grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
gap: 0.65rem; gap: 0.65rem;
margin: 0 0 0.75rem; margin: 0;
} }
.quality-summary-grid > div { .quality-summary-grid > div {
@@ -1446,7 +1491,7 @@ button.entity-card {
border: 1px solid rgba(15, 118, 110, 0.18); border: 1px solid rgba(15, 118, 110, 0.18);
border-radius: 8px; border-radius: 8px;
padding: 0.72rem; padding: 0.72rem;
background: #f8fbf9; background: #ffffff;
} }
.quality-summary-grid span, .quality-summary-grid span,
@@ -2750,6 +2795,27 @@ button.entity-card {
padding: 0.58rem; padding: 0.58rem;
} }
.quality-summary-surface,
.quality-evidence-surface,
.quality-control-surface,
.quality-history-surface {
padding: 0.58rem;
}
.quality-results-shell .quality-summary-grid,
.quality-results-shell .quality-history-controls {
grid-template-columns: repeat(auto-fit, minmax(8.25rem, 1fr));
gap: 0.5rem;
}
.quality-results-shell .quality-handoff-grid,
.quality-results-shell .quality-score-row,
.quality-results-shell .quality-metric-grid,
.quality-results-shell .metric-list {
grid-template-columns: repeat(auto-fit, minmax(7.5rem, 1fr));
gap: 0.5rem;
}
.layer-control-card { .layer-control-card {
padding: 0.52rem 0.58rem; padding: 0.52rem 0.58rem;
} }