diff --git a/CHANGELOG.md b/CHANGELOG.md index a8850a65..c4472832 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -711,3 +711,11 @@ Added: - Added source/CRS columns to the dataset inventory section and clearer "Dataset inventory", "QA/QC evidence" and "Artifact history" report headings. - Added regression coverage for report layout markers, print CSS and HTML escaping. - No API contracts, migrations, product capabilities, PDF/report-designer functionality, live provider fetching or AI/model dependency changes were introduced. + +## Sprint 67 map empty-state quick actions (2026-06-19) + +- Added ready vector/GeoJSON dataset quick actions to the Map workspace empty state. +- Reused the existing `openDatasetInMap` flow so selecting a quick action loads the persisted dataset layer without changing API contracts. +- Added responsive styling and regression coverage for the Map quick-action grid. +- Verified locally against the live demo state that the empty map state exposes two dataset actions and opens `demo_predicted_buildings.geojson` as a 2-feature map layer. +- No API contracts, migrations, product capabilities, live provider fetching or AI/model dependency changes were introduced. diff --git a/backend/tests/test_sprint67_map_empty_state_quick_actions.py b/backend/tests/test_sprint67_map_empty_state_quick_actions.py new file mode 100644 index 00000000..54bd8d6f --- /dev/null +++ b/backend/tests/test_sprint67_map_empty_state_quick_actions.py @@ -0,0 +1,33 @@ +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[2] + + +def test_map_empty_state_surfaces_ready_vector_dataset_actions() -> None: + map_workspace = (ROOT / "frontend" / "src" / "components" / "map" / "MapWorkspace.tsx").read_text( + encoding="utf-8" + ) + + assert "availableMapDatasets" in map_workspace + assert "onOpenDatasetInMap" in map_workspace + assert "map-empty-action-grid" in map_workspace + assert "Open a ready vector dataset" in map_workspace + assert "Open in map" in map_workspace + assert "No ready vector datasets available yet" in map_workspace + + +def test_app_passes_available_vector_datasets_to_map_workspace() -> None: + app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8") + + assert "availableMapDatasets" in app + assert "datasets.filter((dataset) => isVectorDatasetType(dataset.dataset_type) && dataset.status === 'ready')" in app + assert "availableMapDatasets={availableMapDatasets}" in app + assert "onOpenDatasetInMap={openDatasetInMap}" in app + + +def test_map_empty_action_grid_has_responsive_styles() -> None: + css = (ROOT / "frontend" / "src" / "styles" / "app.css").read_text(encoding="utf-8") + + assert ".map-empty-action-grid" in css + assert "repeat(auto-fit, minmax(11rem, 1fr))" in css diff --git a/docs/CODEX_EXECUTION_LOG.md b/docs/CODEX_EXECUTION_LOG.md index cbcd2456..7eae40ae 100644 --- a/docs/CODEX_EXECUTION_LOG.md +++ b/docs/CODEX_EXECUTION_LOG.md @@ -2545,3 +2545,29 @@ Limitations: Next recommended pass: - Continue with populated Map/Data interaction polish, especially making it easier to activate the demo vector layer from the map empty state. + +## Sprint 67 Map empty-state quick actions (2026-06-19) + +Changed: +- Added ready vector/GeoJSON dataset quick actions to the Map workspace empty state. +- Reused the existing `openDatasetInMap` frontend flow so quick actions load the same persisted dataset layer as the Data workspace button. +- Added width-aware `.map-empty-action-grid` styling for desktop and mobile. +- Added `backend/tests/test_sprint67_map_empty_state_quick_actions.py`. +- Updated `frontend/README.md`, `docs/TODO.md` and `CHANGELOG.md`. + +Tested: +- Red step: `python -m pytest backend/tests/test_sprint67_map_empty_state_quick_actions.py -q` failed on missing Map quick-action props, App wiring and CSS. +- `python -m pytest backend/tests/test_sprint67_map_empty_state_quick_actions.py backend/tests/test_sprint63_map_overlay_ergonomics.py backend/tests/test_sprint30_workbench_components.py -q` (`9 passed`) +- `cd frontend && npm run typecheck` +- `cd frontend && npm run build` +- Local Chrome/Playwright check against `http://127.0.0.1:5175` with live API proxy: Map empty state showed 2 ready dataset actions, clicking the first loaded `demo_predicted_buildings.geojson` as a 2-feature active layer, no console warnings/errors and no horizontal overflow. +- `bash scripts/run_readiness_check.sh` (`240 passed`) + +Open: +- Deploy Tower and verify the live Map quick action after deployment. + +Limitations: +- This is a frontend interaction polish pass only. It does not add map layers, backend endpoints, migrations, provider fetching or geospatial processing. + +Next recommended pass: +- Continue with Data catalog density polish, especially making selected/reference/candidate dataset roles easier to scan in populated demo projects. diff --git a/docs/TODO.md b/docs/TODO.md index e64c5c50..ffd4bca0 100644 --- a/docs/TODO.md +++ b/docs/TODO.md @@ -338,3 +338,4 @@ This file now starts with the current implementation status. Older preparation/b - [x] Add map/result overlay ergonomics for active layer provenance and feature property summaries. - [x] Add export/report handoff polish for artifact readiness, action grouping and export provenance. - [x] Polish lightweight HTML project report readability, print styling and handoff sections. +- [x] Add Map empty-state quick actions for ready vector datasets. diff --git a/frontend/README.md b/frontend/README.md index 55814d69..e840369e 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -234,6 +234,7 @@ The workbench now uses a task-based shell instead of a single long panel stack. - Stable navigation test anchors use `data-testid="workspace-nav-{workspace}"`. - Mobile workbench navigation uses horizontal rails for the primary nav and command bar, avoiding a tall menu stack before the active workspace content. - The Map workspace shows active layer source/provenance/draw-state context and selected-feature property chips before the raw JSON inspector. +- When the Map workspace has no active result layer, it lists ready vector/GeoJSON datasets as direct quick actions so populated demo projects can jump straight from the empty state to map inspection. ## Raster dependency visibility diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index c3ef02e7..0b4a5cb8 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -154,6 +154,10 @@ function App(): JSX.Element { [datasets, selectedDatasetId], ) const availableVectorDatasets = useMemo(() => datasets.filter((item) => isVectorDatasetType(item.dataset_type)), [datasets]) + const availableMapDatasets = useMemo( + () => datasets.filter((dataset) => isVectorDatasetType(dataset.dataset_type) && dataset.status === 'ready'), + [datasets], + ) const referenceDatasets = useMemo( () => availableVectorDatasets.filter((item) => item.dataset_role === 'reference'), [availableVectorDatasets], @@ -614,7 +618,9 @@ function App(): JSX.Element { mapFeatureCount={mapFeatureCount} areaFeatureCount={areaFeatureCount} selectedMapFeature={selectedMapFeature} + availableMapDatasets={availableMapDatasets} onSelectMapArea={setSelectedMapAreaId} + onOpenDatasetInMap={openDatasetInMap} onSetAreaLayerVisible={setAreaLayerVisible} onSetAreaLayerOpacity={setAreaLayerOpacity} onSetMapLayerVisible={setMapLayerVisible} diff --git a/frontend/src/components/map/MapWorkspace.tsx b/frontend/src/components/map/MapWorkspace.tsx index b5757e86..e37bdabe 100644 --- a/frontend/src/components/map/MapWorkspace.tsx +++ b/frontend/src/components/map/MapWorkspace.tsx @@ -1,5 +1,5 @@ import GeoMap from '../GeoMap' -import type { AreaRead } from '../../types' +import type { AreaRead, DatasetCreateResponse } from '../../types' interface MapWorkspaceProps { areas: AreaRead[] @@ -16,7 +16,9 @@ interface MapWorkspaceProps { mapFeatureCount: number areaFeatureCount: number selectedMapFeature: GeoJSON.Feature | null + availableMapDatasets: DatasetCreateResponse[] onSelectMapArea: (areaId: string) => void + onOpenDatasetInMap: (dataset: DatasetCreateResponse) => void onSetAreaLayerVisible: (visible: boolean) => void onSetAreaLayerOpacity: (opacity: number) => void onSetMapLayerVisible: (visible: boolean) => void @@ -39,7 +41,9 @@ export function MapWorkspace({ mapFeatureCount, areaFeatureCount, selectedMapFeature, + availableMapDatasets, onSelectMapArea, + onOpenDatasetInMap, onSetAreaLayerVisible, onSetAreaLayerOpacity, onSetMapLayerVisible, @@ -150,6 +154,21 @@ export function MapWorkspace({
Open a dataset, detection run, segmentation run or change result to draw it here.
+ {availableMapDatasets.length > 0 ? ( + <> +Open a ready vector dataset
+No ready vector datasets available yet. Upload or seed a vector dataset first.
+ )}