Polish QA workspace density
This commit is contained in:
@@ -7,6 +7,14 @@
|
||||
|
||||
# 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)
|
||||
|
||||
- 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
|
||||
@@ -3108,3 +3108,38 @@ Limitations:
|
||||
|
||||
Next recommended pass:
|
||||
- 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`
|
||||
- First full readiness run caught a compatibility regression in `backend/tests/test_sprint51_quality_export_polish.py`: the root `quality-results-panel` class was no longer exact. Kept the old root class and moved the new shell into a wrapper.
|
||||
- `python -m pytest backend/tests/test_sprint51_quality_export_polish.py backend/tests/test_sprint86_quality_workspace_density.py backend/tests/test_sprint70_quality_handoff_polish.py backend/tests/test_sprint73_quality_result_filtering.py -q` (`11 passed`)
|
||||
- `cd frontend && npm run typecheck`
|
||||
- `cd frontend && npm run build`
|
||||
- `bash scripts/run_readiness_check.sh` (`292 passed`; frontend typecheck/build passed; Alembic single head `202606120900`)
|
||||
- `powershell -NoProfile -ExecutionPolicy Bypass -File scripts/deploy_tower.ps1` rebuilt and redeployed the Tower all-in-one container on port 1202, then passed live migration smoke and browser runtime verification.
|
||||
- Final live browser check against `http://192.168.10.150:1202` passed on desktop and mobile viewports: no console warnings/errors, no horizontal document overflow, QA/QC shell/surfaces present and two persisted quality check cards rendered.
|
||||
|
||||
Open:
|
||||
- None for this pass.
|
||||
|
||||
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.
|
||||
|
||||
@@ -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 Data workspace selected-summary and panel 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
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
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.
|
||||
|
||||
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 (
|
||||
<section className="quality-results-panel" data-testid="quality-results-panel">
|
||||
<div className="quality-results-shell">
|
||||
<div className="panel-title-row">
|
||||
<div>
|
||||
<h2>QA/QC Results</h2>
|
||||
@@ -113,6 +114,8 @@ export function QualityResultsPanel({
|
||||
</div>
|
||||
<span className="count-pill">{qualityChecks.length} checks</span>
|
||||
</div>
|
||||
|
||||
<div className="quality-summary-surface" aria-label="QA/QC result summary">
|
||||
<div className="quality-summary-grid">
|
||||
<div>
|
||||
<span>Completed</span>
|
||||
@@ -127,6 +130,9 @@ export function QualityResultsPanel({
|
||||
<strong>{latestCheck?.status ?? 'waiting'}</strong>
|
||||
</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>
|
||||
<span>Candidate layers</span>
|
||||
@@ -146,6 +152,9 @@ export function QualityResultsPanel({
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="quality-control-surface" aria-label="QA/QC refresh and filters">
|
||||
<div className="button-row">
|
||||
<button
|
||||
type="button"
|
||||
@@ -157,6 +166,8 @@ export function QualityResultsPanel({
|
||||
Refresh QA/QC results
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="quality-result-state-stack">
|
||||
{qualityChecksError ? (
|
||||
<div className="result-state result-state-error">
|
||||
<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>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
{qualityChecks.length > 0 ? (
|
||||
<div className="quality-history-controls" aria-label="QA/QC result filters">
|
||||
<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>
|
||||
</div>
|
||||
) : 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">
|
||||
{visibleQualityChecks.map((check) => (
|
||||
<li className="quality-check-card" key={check.id}>
|
||||
@@ -294,6 +314,8 @@ export function QualityResultsPanel({
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1420,18 +1420,63 @@ button.entity-card {
|
||||
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;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 0.65rem;
|
||||
margin: 0.75rem 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.quality-handoff-grid {
|
||||
.quality-results-shell .quality-handoff-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
|
||||
gap: 0.65rem;
|
||||
margin: 0 0 0.75rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.quality-summary-grid > div {
|
||||
@@ -1446,7 +1491,7 @@ button.entity-card {
|
||||
border: 1px solid rgba(15, 118, 110, 0.18);
|
||||
border-radius: 8px;
|
||||
padding: 0.72rem;
|
||||
background: #f8fbf9;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.quality-summary-grid span,
|
||||
@@ -2750,6 +2795,27 @@ button.entity-card {
|
||||
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 {
|
||||
padding: 0.52rem 0.58rem;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user