Polish change detection density
This commit is contained in:
@@ -7,6 +7,14 @@
|
||||
|
||||
# Changelog
|
||||
|
||||
## Sprint 87 Change Detection density polish (2026-06-20)
|
||||
|
||||
- Grouped Change Detection heading, input controls, result states, summary and warnings into focused surfaces.
|
||||
- Reused shared result-state cards for not-enough-data and error states.
|
||||
- Added compact desktop/mobile grids for vector inputs and change summary metrics.
|
||||
- Added static regression coverage for Change Detection hierarchy and density contracts.
|
||||
- No API contracts, migrations, backend behavior, provider fetching or AI model behavior changed.
|
||||
|
||||
## 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.
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
|
||||
|
||||
def test_change_detection_panel_exposes_structured_surfaces() -> None:
|
||||
panel = (ROOT / "frontend" / "src" / "components" / "analysis" / "ChangeDetectionPanel.tsx").read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
|
||||
assert 'className="panel change-detection-shell"' in panel
|
||||
assert 'className="panel-header change-detection-heading"' in panel
|
||||
assert 'className="change-detection-input-surface"' in panel
|
||||
assert 'aria-label="Change detection input controls"' in panel
|
||||
assert 'className="change-detection-state-stack"' in panel
|
||||
assert 'className="change-detection-result-surface"' in panel
|
||||
assert 'aria-label="Change detection result summary"' in panel
|
||||
assert 'className="change-detection-warning-surface"' in panel
|
||||
|
||||
|
||||
def test_change_detection_panel_preserves_existing_compare_controls() -> None:
|
||||
panel = (ROOT / "frontend" / "src" / "components" / "analysis" / "ChangeDetectionPanel.tsx").read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
|
||||
assert "onSourceDatasetChange" in panel
|
||||
assert "onTargetDatasetChange" in panel
|
||||
assert "onIouThresholdChange" in panel
|
||||
assert "onIncludeUnchangedChange" in panel
|
||||
assert "onRun" in panel
|
||||
assert "Compare vectors" in panel
|
||||
assert "Upload at least two vector datasets to compare." in panel
|
||||
assert "result.added_count" in panel
|
||||
assert "result.removed_count" in panel
|
||||
assert "result.unchanged_count" in panel
|
||||
|
||||
|
||||
def test_change_detection_density_css_contracts() -> None:
|
||||
css = (ROOT / "frontend" / "src" / "styles" / "app.css").read_text(encoding="utf-8")
|
||||
|
||||
assert ".change-detection-shell" in css
|
||||
assert ".change-detection-heading" in css
|
||||
assert ".change-detection-input-surface" in css
|
||||
assert ".change-detection-state-stack" in css
|
||||
assert ".change-detection-result-surface" in css
|
||||
assert ".change-detection-warning-surface" in css
|
||||
assert ".change-detection-shell .form-grid" in css
|
||||
assert ".change-detection-shell .summary-grid" in css
|
||||
assert "grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));" in css
|
||||
assert "grid-template-columns: repeat(auto-fit, minmax(7.5rem, 1fr));" in css
|
||||
@@ -3143,3 +3143,35 @@ Limitations:
|
||||
|
||||
Next recommended pass:
|
||||
- Continue with Change Detection panel hierarchy and analysis workspace balance after this pass is deployed and visually checked.
|
||||
|
||||
## Sprint 87 Change Detection density polish (2026-06-20)
|
||||
|
||||
Changed:
|
||||
- Wrapped Change Detection input controls in `change-detection-input-surface`.
|
||||
- Replaced loose error/empty text with shared `result-state` cards inside `change-detection-state-stack`.
|
||||
- Wrapped result metrics in `change-detection-result-surface`.
|
||||
- Wrapped warning output in `change-detection-warning-surface`.
|
||||
- Added compact responsive CSS contracts for Change Detection form and summary grids.
|
||||
- Added `backend/tests/test_sprint87_change_detection_density.py`.
|
||||
- Updated `frontend/README.md`, `docs/TODO.md` and `CHANGELOG.md`.
|
||||
|
||||
Tested:
|
||||
- Live browser pre-check attempt against `http://192.168.10.150:1202` hit a transient browser automation click timeout on the QA/QC workspace nav; source review showed Change Detection was still the older header/form/summary stack.
|
||||
- Red step: `python -m pytest backend/tests/test_sprint87_change_detection_density.py -q` failed on missing Change Detection surface and density CSS contracts.
|
||||
- `python -m pytest backend/tests/test_sprint87_change_detection_density.py backend/tests/test_sprint18_change_detection.py backend/tests/test_sprint39_frontend_orchestration_hooks.py backend/tests/test_sprint86_quality_workspace_density.py backend/tests/test_sprint47_workbench_interaction_smoke.py -q` (`20 passed`)
|
||||
- `cd frontend && npm run typecheck`
|
||||
- `cd frontend && npm run build`
|
||||
- `bash scripts/run_readiness_check.sh` (`295 passed`; frontend typecheck/build passed; Alembic head `202606120900`; live smoke syntax passed)
|
||||
- Tower deploy via `scripts/deploy_tower.ps1` rebuilt and restarted the all-in-one container on `http://192.168.10.150:1202`.
|
||||
- Tower deploy live migration smoke passed with PostGIS `3.6 USE_GEOS=1 USE_PROJ=1 USE_STATS=1` and required runtime schema objects present.
|
||||
- Browser runtime verification passed for frontend, proxied API and icon.
|
||||
- Direct Chrome live UI check passed on desktop `1440x1000` and mobile `390x844`: Change Detection shell/input surface rendered, no horizontal overflow and no console warnings/errors.
|
||||
|
||||
Open:
|
||||
- None known after full readiness, Tower deploy and live browser validation.
|
||||
|
||||
Limitations:
|
||||
- Frontend Change Detection presentation hierarchy only; no change-detection behavior, API contract, persistence, migration, provider fetching or AI/model changes.
|
||||
|
||||
Next recommended pass:
|
||||
- Continue with AI Labs run-form hierarchy and detection/segmentation result density after this pass is deployed and visually checked.
|
||||
|
||||
@@ -76,6 +76,7 @@ This file now starts with the current implementation status. Older preparation/b
|
||||
- [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.
|
||||
- [x] Add Change Detection panel hierarchy and analysis workspace density polish.
|
||||
|
||||
## Sprint 8 status
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ Map workspace now surfaces the selected AOI, active layer and rendered feature s
|
||||
|
||||
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.
|
||||
|
||||
Change Detection now follows the same analysis workspace hierarchy: vector input controls, error/empty states, result metrics and warnings are separated into focused surfaces while the existing compare action and map overlay result flow remain unchanged.
|
||||
|
||||
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.
|
||||
|
||||
@@ -37,8 +37,8 @@ export function ChangeDetectionPanel({
|
||||
onRun,
|
||||
}: ChangeDetectionPanelProps): JSX.Element {
|
||||
return (
|
||||
<section className="panel">
|
||||
<div className="panel-header">
|
||||
<section className="panel change-detection-shell">
|
||||
<div className="panel-header change-detection-heading">
|
||||
<div>
|
||||
<p className="eyebrow">Analysis</p>
|
||||
<h2>Change Detection</h2>
|
||||
@@ -48,6 +48,7 @@ export function ChangeDetectionPanel({
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="change-detection-input-surface" aria-label="Change detection input controls">
|
||||
<div className="form-grid">
|
||||
<label>
|
||||
Source vector
|
||||
@@ -91,11 +92,25 @@ export function ChangeDetectionPanel({
|
||||
Include unchanged geometry
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{error ? <p className="error">{error}</p> : null}
|
||||
{!error && vectorDatasets.length < 2 ? <p className="muted">Upload at least two vector datasets to compare.</p> : null}
|
||||
<div className="change-detection-state-stack">
|
||||
{error ? (
|
||||
<div className="result-state result-state-error">
|
||||
<strong>Change detection failed.</strong>
|
||||
<p>{error}</p>
|
||||
</div>
|
||||
) : null}
|
||||
{!error && vectorDatasets.length < 2 ? (
|
||||
<div className="result-state result-state-empty">
|
||||
<strong>Not enough vector datasets</strong>
|
||||
<p>Upload at least two vector datasets to compare.</p>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
{result ? (
|
||||
<div className="change-detection-result-surface" aria-label="Change detection result summary">
|
||||
<div className="summary-grid">
|
||||
<div>
|
||||
<span className="metric">{result.added_count}</span>
|
||||
@@ -114,14 +129,18 @@ export function ChangeDetectionPanel({
|
||||
<span>Map features</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{result?.warnings.length ? (
|
||||
<div className="change-detection-warning-surface">
|
||||
<strong>Warnings</strong>
|
||||
<ul className="compact-list">
|
||||
{result.warnings.map((warning) => (
|
||||
<li key={warning}>{warning}</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
) : null}
|
||||
</section>
|
||||
)
|
||||
|
||||
@@ -1465,6 +1465,71 @@ button.entity-card {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.change-detection-shell {
|
||||
display: grid;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.change-detection-heading {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.change-detection-input-surface,
|
||||
.change-detection-result-surface,
|
||||
.change-detection-warning-surface {
|
||||
min-width: 0;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
padding: 0.72rem;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.change-detection-input-surface {
|
||||
background: linear-gradient(180deg, #ffffff, #f7fbf8);
|
||||
}
|
||||
|
||||
.change-detection-state-stack {
|
||||
display: grid;
|
||||
gap: 0.55rem;
|
||||
}
|
||||
|
||||
.change-detection-shell .form-grid {
|
||||
grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
|
||||
gap: 0.62rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.change-detection-shell .form-grid label {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.change-detection-shell .form-grid input,
|
||||
.change-detection-shell .form-grid select {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.change-detection-shell .summary-grid {
|
||||
grid-template-columns: repeat(auto-fit, minmax(7.5rem, 1fr));
|
||||
gap: 0.55rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.change-detection-warning-surface {
|
||||
border-color: rgba(180, 83, 9, 0.24);
|
||||
background: rgba(180, 83, 9, 0.08);
|
||||
}
|
||||
|
||||
.change-detection-warning-surface strong {
|
||||
display: block;
|
||||
color: #92400e;
|
||||
font-size: 0.88rem;
|
||||
}
|
||||
|
||||
.change-detection-warning-surface .compact-list {
|
||||
margin-top: 0.45rem;
|
||||
}
|
||||
|
||||
.quality-results-shell .quality-summary-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
@@ -2798,12 +2863,16 @@ button.entity-card {
|
||||
.quality-summary-surface,
|
||||
.quality-evidence-surface,
|
||||
.quality-control-surface,
|
||||
.quality-history-surface {
|
||||
.quality-history-surface,
|
||||
.change-detection-input-surface,
|
||||
.change-detection-result-surface,
|
||||
.change-detection-warning-surface {
|
||||
padding: 0.58rem;
|
||||
}
|
||||
|
||||
.quality-results-shell .quality-summary-grid,
|
||||
.quality-results-shell .quality-history-controls {
|
||||
.quality-results-shell .quality-history-controls,
|
||||
.change-detection-shell .form-grid {
|
||||
grid-template-columns: repeat(auto-fit, minmax(8.25rem, 1fr));
|
||||
gap: 0.5rem;
|
||||
}
|
||||
@@ -2811,7 +2880,8 @@ button.entity-card {
|
||||
.quality-results-shell .quality-handoff-grid,
|
||||
.quality-results-shell .quality-score-row,
|
||||
.quality-results-shell .quality-metric-grid,
|
||||
.quality-results-shell .metric-list {
|
||||
.quality-results-shell .metric-list,
|
||||
.change-detection-shell .summary-grid {
|
||||
grid-template-columns: repeat(auto-fit, minmax(7.5rem, 1fr));
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user