Polish inspector mobile layout
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 02:07:24 +02:00
parent c7d00fd8dc
commit 27b9219383
8 changed files with 166 additions and 10 deletions
+8
View File
@@ -7,6 +7,14 @@
# Changelog
## Sprint 77 Inspector mobile visual polish (2026-06-20)
- Added compact inspector action button grids for narrow screens.
- Added mobile-safe wrapping for dataset filenames, checksums, bounds, persisted export paths and loaded feature/job JSON.
- Added structured raster/vector tool panel classes so operation inputs and buttons stay inside the inspector.
- Added static regression coverage for inspector mobile CSS and dataset tool markup contracts.
- No API contracts, migrations, backend behavior, provider fetching or AI model behavior changed.
## Sprint 76 Export/System mobile visual polish (2026-06-20)
- Added scan-friendly Provider Capabilities cards with structured status, authority, geometry, query mode and layer chips.
@@ -0,0 +1,46 @@
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
def test_inspector_mobile_density_css_contracts() -> None:
css = (ROOT / "frontend" / "src" / "styles" / "app.css").read_text(encoding="utf-8")
assert ".inspector-card .button-row" in css
assert ".inspector-card .button-row button" in css
assert ".inspector-field strong" in css
assert ".dataset-detail-panel p" in css
assert ".dataset-detail-panel li" in css
assert ".dataset-detail-panel .job-result" in css
assert ".dataset-tool-panel" in css
assert ".dataset-tool-group" in css
assert ".dataset-tool-group label" in css
assert ".dataset-tool-group input," in css
assert ".dataset-tool-group select" in css
assert ".dataset-tool-group button" in css
assert "overflow-wrap: anywhere;" in css
assert "max-height: 18rem;" in css
def test_inspector_components_keep_mobile_tool_markup() -> None:
inspector = (ROOT / "frontend" / "src" / "components" / "inspector" / "WorkbenchInspector.tsx").read_text(
encoding="utf-8"
)
dataset_detail = (ROOT / "frontend" / "src" / "components" / "datasets" / "DatasetDetailPanel.tsx").read_text(
encoding="utf-8"
)
raster_controls = (ROOT / "frontend" / "src" / "components" / "datasets" / "RasterControls.tsx").read_text(
encoding="utf-8"
)
vector_controls = (ROOT / "frontend" / "src" / "components" / "datasets" / "VectorControls.tsx").read_text(
encoding="utf-8"
)
assert 'className="workbench-inspector-panel"' in inspector
assert 'className="inspector-action-bar"' in inspector
assert 'className="dataset-detail-panel"' in dataset_detail
assert 'className="dataset-tool-panel raster-tool-panel"' in raster_controls
assert 'className="dataset-tool-group"' in raster_controls
assert 'className="dataset-tool-panel vector-tool-panel"' in vector_controls
assert 'className="dataset-tool-group"' in vector_controls
+25
View File
@@ -2850,3 +2850,28 @@ Limitations:
Next recommended pass:
- Continue with right-side inspector mobile polish, especially long dataset/vector/raster metadata and action groups.
## Sprint 77 Inspector mobile visual polish (2026-06-20)
Changed:
- Added compact inspector action button grids and mobile-safe wrapping for long inspector values.
- Added scroll/wrap containment for dataset detail text, job JSON and loaded feature metadata.
- Added `dataset-tool-panel` and `dataset-tool-group` classes to raster/vector operation controls.
- Added CSS containment for raster/vector tool labels, inputs, selects and buttons inside the inspector.
- Added `backend/tests/test_sprint77_inspector_mobile_polish.py`.
- Updated `frontend/README.md`, `docs/TODO.md` and `CHANGELOG.md`.
Tested:
- Red step: `python -m pytest backend/tests/test_sprint77_inspector_mobile_polish.py -q` failed on missing inspector mobile CSS and dataset tool markup contracts.
- `python -m pytest backend/tests/test_sprint77_inspector_mobile_polish.py backend/tests/test_sprint76_export_system_mobile_polish.py backend/tests/test_sprint75_ai_labs_mobile_polish.py backend/tests/test_sprint72_mobile_overflow_hardening.py backend/tests/test_sprint52_workbench_inspector_tabs.py backend/tests/test_sprint30_workbench_components.py backend/tests/test_sprint29_dataset_components.py -q` (`18 passed`)
- `cd frontend && npm run typecheck`
- `cd frontend && npm run build`
Open:
- Run full readiness, redeploy Tower and verify live runtime smoke after deployment.
Limitations:
- Frontend presentation polish only; no dataset workflow, raster/vector operation behavior, API, persistence, migration, provider fetching or AI/model changes.
Next recommended pass:
- Continue with report/export preview readability polish, especially large JSON/HTML handoff artifacts.
+1
View File
@@ -66,6 +66,7 @@ This file now starts with the current implementation status. Older preparation/b
- [x] Add Data/Map mobile visual polish for upload forms, action grids and map toolbar density.
- [x] Add AI Labs mobile visual polish for model cards, lab forms and result tables.
- [x] Add Export/System mobile visual polish for export actions and provider capability cards.
- [x] Add inspector mobile polish for dataset metadata, raster/vector tools and action groups.
## Sprint 8 status
+2
View File
@@ -10,6 +10,8 @@ AI Labs uses the same mobile-density baseline for Detection and Segmentation mod
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.
The right-side inspector also uses mobile-safe metadata and tool panels. Dataset filenames, checksums, bounds, job JSON, raster/vector operation inputs and inspector action groups wrap or scroll within the inspector instead of widening the workbench.
## Scope implemented
- API client layer (`src/services/api`)
- Project and area list/create flows
@@ -94,7 +94,7 @@ export function RasterControls({
onRunRasterNdbi,
}: RasterControlsProps) {
return (
<div>
<div className="dataset-tool-panel raster-tool-panel">
<p>Raster driver: {selectedRasterMetadata?.driver ?? 'n/a'}</p>
<p>Raster size: {selectedRasterMetadata ? `${selectedRasterMetadata.width} x ${selectedRasterMetadata.height}` : 'n/a'}</p>
<p>Raster checksum: {selectedRasterMetadata?.checksum_sha256 ?? 'n/a'}</p>
@@ -132,7 +132,7 @@ export function RasterControls({
</ul>
</div>
) : null}
<div>
<div className="dataset-tool-group">
<label>
Reproject CRS
<input
@@ -153,7 +153,7 @@ export function RasterControls({
Reproject raster
</button>
</div>
<div>
<div className="dataset-tool-group">
<label>
Clip area
<select value={selectedClipAreaId} onChange={(event) => onSetSelectedClipAreaId(event.target.value)}>
@@ -169,7 +169,7 @@ export function RasterControls({
</button>
{areas.length === 0 ? <p className="error">Create an area before raster clipping.</p> : null}
</div>
<div>
<div className="dataset-tool-group">
<label>
Tile size
<input
@@ -208,7 +208,7 @@ export function RasterControls({
<h4>Spectral indices</h4>
<div>
<p>Use available band indexes from the raster file (1-based).</p>
<div>
<div className="dataset-tool-group">
<p>NDVI</p>
<label>
Nir band
@@ -222,7 +222,7 @@ export function RasterControls({
Compute NDVI
</button>
</div>
<div>
<div className="dataset-tool-group">
<p>NDWI</p>
<label>
Nir band
@@ -236,7 +236,7 @@ export function RasterControls({
Compute NDWI
</button>
</div>
<div>
<div className="dataset-tool-group">
<p>NDBI</p>
<label>
Swir band
@@ -24,9 +24,9 @@ export function VectorControls({
onRunVectorIntersect,
}: VectorControlsProps) {
return (
<div>
<div className="dataset-tool-panel vector-tool-panel">
<h3>Vector operations</h3>
<div>
<div className="dataset-tool-group">
<label>
Clip area
<select value={selectedClipAreaId} onChange={(event) => onSetSelectedClipAreaId(event.target.value)}>
@@ -44,7 +44,7 @@ export function VectorControls({
<button type="button" onClick={onRunVectorBuffer}>
Run buffer (25m)
</button>
<div>
<div className="dataset-tool-group">
<label>
Intersect target
<select value={selectedIntersectTargetId} onChange={(event) => onSetSelectedIntersectTargetId(event.target.value)}>
+74
View File
@@ -2001,12 +2001,27 @@ button.entity-card {
}
.inspector-field strong {
min-width: 0;
overflow: hidden;
font-size: 0.88rem;
line-height: 1.28;
overflow-wrap: anywhere;
text-overflow: ellipsis;
}
.inspector-card .button-row {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(7.5rem, 1fr));
gap: 0.42rem;
}
.inspector-card .button-row button {
width: 100%;
min-width: 0;
min-height: 2.2rem;
margin-top: 0;
}
.workbench-inspector-panel .dataset-detail-panel {
border: 0;
padding: 0;
@@ -2020,6 +2035,51 @@ button.entity-card {
gap: 0.55rem;
}
.dataset-detail-panel p,
.dataset-detail-panel li {
min-width: 0;
overflow-wrap: anywhere;
}
.dataset-detail-panel .job-result {
max-height: 18rem;
overflow: auto;
white-space: pre-wrap;
overflow-wrap: anywhere;
}
.dataset-tool-panel {
display: grid;
min-width: 0;
gap: 0.62rem;
}
.dataset-tool-group {
display: grid;
min-width: 0;
gap: 0.5rem;
border: 1px solid var(--line);
border-radius: 8px;
padding: 0.62rem;
background: #ffffff;
}
.dataset-tool-group label {
min-width: 0;
}
.dataset-tool-group input,
.dataset-tool-group select {
width: 100%;
min-width: 0;
}
.dataset-tool-group button {
width: fit-content;
max-width: 100%;
min-width: 0;
}
@media (max-width: 1360px) {
.workbench-layout {
grid-template-columns: 12rem minmax(0, 1fr);
@@ -2151,6 +2211,20 @@ button.entity-card {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.inspector-card,
.dataset-tool-group {
padding: 0.58rem;
}
.inspector-action-bar,
.inspector-card .button-row {
grid-template-columns: repeat(auto-fit, minmax(7.5rem, 1fr));
}
.dataset-tool-group button {
width: 100%;
}
.workbench-sidebar nav {
display: flex;
gap: 0.5rem;