diff --git a/CHANGELOG.md b/CHANGELOG.md index 57b62061..e6e5b286 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,14 @@ # Changelog +## Sprint 80 Operation form readability polish (2026-06-20) + +- Added structured headings, helper text, field wrappers and action rows to dense raster operation controls. +- Added the same form readability structure to vector clip, buffer and intersect controls. +- Added compact CSS contracts for dataset tool headings, helper text, field grids, action rows and inline error blocks. +- Added static regression coverage for raster/vector operation form readability contracts. +- No API contracts, migrations, backend behavior, provider fetching or AI model behavior changed. + ## Sprint 79 Accessibility focus polish (2026-06-20) - Added a shared visible focus-ring contract for primary buttons, workspace navigation, command chips, inspector tabs and dataset action buttons. diff --git a/backend/tests/test_sprint80_operation_form_readability.py b/backend/tests/test_sprint80_operation_form_readability.py new file mode 100644 index 00000000..1eb41a6a --- /dev/null +++ b/backend/tests/test_sprint80_operation_form_readability.py @@ -0,0 +1,49 @@ +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[2] + + +def test_dataset_operation_form_css_contracts() -> None: + css = (ROOT / "frontend" / "src" / "styles" / "app.css").read_text(encoding="utf-8") + + assert ".dataset-tool-heading" in css + assert ".dataset-tool-helper" in css + assert ".dataset-tool-field" in css + assert ".dataset-tool-label" in css + assert ".dataset-tool-error" in css + assert ".dataset-tool-action-row" in css + assert ".dataset-tool-grid" in css + assert "grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));" in css + assert "overflow-wrap: anywhere;" in css + + +def test_raster_controls_expose_readable_operation_groups() -> None: + raster_controls = (ROOT / "frontend" / "src" / "components" / "datasets" / "RasterControls.tsx").read_text( + encoding="utf-8" + ) + + assert 'className="dataset-tool-heading"' in raster_controls + assert 'className="dataset-tool-helper"' in raster_controls + assert 'className="dataset-tool-grid"' in raster_controls + assert 'className="dataset-tool-field"' in raster_controls + assert 'className="dataset-tool-label"' in raster_controls + assert 'className="dataset-tool-action-row"' in raster_controls + assert 'className="dataset-tool-error"' in raster_controls + assert "Target CRS for the derived raster artifact." in raster_controls + assert "Tile size must be > 0." in raster_controls + + +def test_vector_controls_expose_readable_operation_groups() -> None: + vector_controls = (ROOT / "frontend" / "src" / "components" / "datasets" / "VectorControls.tsx").read_text( + encoding="utf-8" + ) + + assert 'className="dataset-tool-heading"' in vector_controls + assert 'className="dataset-tool-helper"' in vector_controls + assert 'className="dataset-tool-grid"' in vector_controls + assert 'className="dataset-tool-field"' in vector_controls + assert 'className="dataset-tool-label"' in vector_controls + assert 'className="dataset-tool-action-row"' in vector_controls + assert "Clip features to the selected project area." in vector_controls + assert "Intersect with another persisted vector dataset." in vector_controls diff --git a/docs/CODEX_EXECUTION_LOG.md b/docs/CODEX_EXECUTION_LOG.md index f5495319..864afd01 100644 --- a/docs/CODEX_EXECUTION_LOG.md +++ b/docs/CODEX_EXECUTION_LOG.md @@ -2929,3 +2929,29 @@ Limitations: Next recommended pass: - Continue with form-level validation/readability polish for dense raster/vector operation panels. + +## Sprint 80 Operation form readability polish (2026-06-20) + +Changed: +- Added structured headings, helper text, field wrappers, responsive field grids and action rows to raster operation controls. +- Added equivalent readability structure to vector clip, buffer and intersect controls. +- Added inline dataset tool error styling for raster clip/tile validation messages. +- Added `backend/tests/test_sprint80_operation_form_readability.py`. +- Updated `frontend/README.md`, `docs/TODO.md` and `CHANGELOG.md`. + +Tested: +- Red step: `python -m pytest backend/tests/test_sprint80_operation_form_readability.py -q` failed on missing form readability CSS and markup contracts. +- `python -m pytest backend/tests/test_sprint80_operation_form_readability.py -q` (`3 passed`) +- `python -m pytest backend/tests/test_sprint80_operation_form_readability.py backend/tests/test_sprint77_inspector_mobile_polish.py backend/tests/test_sprint29_dataset_components.py backend/tests/test_sprint28_dataset_workflow_hook.py backend/tests/test_vector_operations_service.py backend/tests/test_raster_operations_service.py -q` (`37 passed`) +- `cd frontend && npm run typecheck` +- `cd frontend && npm run build` +- `bash scripts/run_readiness_check.sh` (`273 passed`; frontend typecheck/build passed; Alembic single head `202606120900`) + +Open: +- Run full readiness, redeploy Tower and verify live runtime smoke after deployment. + +Limitations: +- Frontend readability/presentation polish only; no raster/vector operation behavior, API contract, persistence, migration, provider fetching or AI/model changes. + +Next recommended pass: +- Continue with compact empty/error-state polish across QA, exports and AI lab result panels. diff --git a/docs/TODO.md b/docs/TODO.md index 03587345..09b8c22f 100644 --- a/docs/TODO.md +++ b/docs/TODO.md @@ -69,6 +69,7 @@ This file now starts with the current implementation status. Older preparation/b - [x] Add inspector mobile polish for dataset metadata, raster/vector tools and action groups. - [x] Add export preview readability polish for large JSON/GeoJSON handoff artifacts. - [x] Add accessibility focus polish for primary workbench keyboard navigation. +- [x] Add raster/vector operation form readability polish for dense tool panels. ## Sprint 8 status diff --git a/frontend/README.md b/frontend/README.md index e7ae7c8d..1f1eced7 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -16,6 +16,8 @@ Export Preview shows a compact JSON summary before the payload and keeps large J Primary workbench navigation, overview shortcuts, inspector tabs and dataset action buttons now share visible keyboard focus styling. Inspector tabs are also bound to tab panels with ARIA metadata. +Raster and vector operation panels use structured group headings, compact helper text, field grids, action rows and inline error blocks so dense GIS controls remain scannable in the inspector. + ## Scope implemented - API client layer (`src/services/api`) - Project and area list/create flows diff --git a/frontend/src/components/datasets/RasterControls.tsx b/frontend/src/components/datasets/RasterControls.tsx index fc4fb484..a8796fc1 100644 --- a/frontend/src/components/datasets/RasterControls.tsx +++ b/frontend/src/components/datasets/RasterControls.tsx @@ -133,29 +133,39 @@ export function RasterControls({ ) : null}
- - - +

Reproject raster

+

Create a derived raster in a target CRS with the selected resampling method.

+
+ + +
+
+ +
-
- - - - +

Generate tiles

+

Create a tile manifest for downstream detection or segmentation runs.

+
+ + + +
+
+ +
{!isRasterTileInputValid ? ( -

+

Tile size must be {'>'} 0 and overlap must be {'>='} 0 and smaller than tile size.

) : null} @@ -209,46 +230,61 @@ export function RasterControls({

Use available band indexes from the raster file (1-based).

-

NDVI

- - - +

NDVI

+

Vegetation index from NIR and red bands.

+
+ + +
+
+ +
-

NDWI

- - - +

NDWI

+

Water index from NIR and green bands.

+
+ + +
+
+ +
-

NDBI

- - - +

NDBI

+

Built-up index from SWIR and NIR bands.

+
+ + +
+
+ +
diff --git a/frontend/src/components/datasets/VectorControls.tsx b/frontend/src/components/datasets/VectorControls.tsx index 40ae5df5..9c0a6526 100644 --- a/frontend/src/components/datasets/VectorControls.tsx +++ b/frontend/src/components/datasets/VectorControls.tsx @@ -27,38 +27,57 @@ export function VectorControls({

Vector operations

- - +

Clip vector

+

Clip features to the selected project area.

+
+ +
+
+ +
-
- - +

Buffer vector

+

Create a 25m buffer using the existing vector operation defaults.

+
+ +
+
+
+

Intersect vector

+

Intersect with another persisted vector dataset.

+
+ +
+
+ +
) diff --git a/frontend/src/styles/app.css b/frontend/src/styles/app.css index 756f52b0..30d506fa 100644 --- a/frontend/src/styles/app.css +++ b/frontend/src/styles/app.css @@ -2148,16 +2148,69 @@ button.entity-card { background: #ffffff; } +.dataset-tool-heading { + margin: 0; + font-size: 0.92rem; + line-height: 1.25; +} + +.dataset-tool-helper { + margin: 0; + color: var(--muted); + font-size: 0.82rem; + line-height: 1.38; + overflow-wrap: anywhere; +} + +.dataset-tool-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); + gap: 0.52rem; +} + .dataset-tool-group label { min-width: 0; } +.dataset-tool-field { + display: grid; + gap: 0.22rem; + min-width: 0; +} + +.dataset-tool-label { + color: var(--text); + font-size: 0.78rem; + font-weight: 800; + line-height: 1.25; +} + .dataset-tool-group input, .dataset-tool-group select { width: 100%; min-width: 0; } +.dataset-tool-error { + margin: 0; + border: 1px solid rgba(153, 27, 27, 0.24); + border-radius: 8px; + padding: 0.52rem 0.62rem; + background: rgba(153, 27, 27, 0.07); + color: var(--danger); + font-size: 0.82rem; + font-weight: 750; + line-height: 1.35; + overflow-wrap: anywhere; +} + +.dataset-tool-action-row { + display: flex; + flex-wrap: wrap; + gap: 0.5rem; + align-items: center; +} + .dataset-tool-group button { width: fit-content; max-width: 100%;