diff --git a/CHANGELOG.md b/CHANGELOG.md index 74cfe4c6..68cf9e20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,9 @@ render all 28 matching MapLibre partitions, deduplicate VMM into twelve scenario choices and analyse a drawn cross-boundary rectangle without first selecting a municipality. +- Forwarded the active Area through drawn, coordinate, manual, temporal, + derived-dataset and full-workflow selections so every result remains clipped + to the chosen municipality or approved regional boundary. - Preserved the distinction between DHMV height, modeled VMM scenario depth, permanent water, bathymetry and concurrent flood volume. diff --git a/backend/tests/test_sprint186_map_first_geographic_explorer.py b/backend/tests/test_sprint186_map_first_geographic_explorer.py index fc6a8bd9..a63a9b8e 100644 --- a/backend/tests/test_sprint186_map_first_geographic_explorer.py +++ b/backend/tests/test_sprint186_map_first_geographic_explorer.py @@ -36,7 +36,7 @@ def test_map_rectangle_drag_is_wired_to_automatic_analysis() -> None: assert "onMapBboxPreview={handleMapBboxPreview}" in workspace assert "onMapBboxSelect={handleMapBboxSelect}" in workspace - assert "void analyzeSelection(bbox)" in workspace + assert "void analyzeSelection(bbox, selectedMapArea?.id)" in workspace assert "map.on('mousedown'" in geomap assert "map.on('mousemove'" in geomap assert "map.on('mouseup'" in geomap diff --git a/backend/tests/test_sprint219_regional_raster_explorer.py b/backend/tests/test_sprint219_regional_raster_explorer.py index 95a92aae..45479331 100644 --- a/backend/tests/test_sprint219_regional_raster_explorer.py +++ b/backend/tests/test_sprint219_regional_raster_explorer.py @@ -33,6 +33,8 @@ def test_regional_map_uses_logical_partition_groups_and_exact_analysis() -> None assert "/datasets/raster/terrain/select" in api assert "/datasets/raster/flood-hazard/select" in api assert "Rasterlaag actief" in app + assert "void analyzeSelection(bbox, selectedMapArea?.id)" in workspace + assert "onDeriveMapSelectionDataset(bbox, selectedMapArea?.id)" in workspace def test_maplibre_supports_multiple_persisted_raster_overlays() -> None: diff --git a/docs/CODEX_EXECUTION_LOG.md b/docs/CODEX_EXECUTION_LOG.md index 84dbdb51..9abfc266 100644 --- a/docs/CODEX_EXECUTION_LOG.md +++ b/docs/CODEX_EXECUTION_LOG.md @@ -50,6 +50,11 @@ Validation evidence: deduplicated VMM scenarios, one 28-municipality MapLibre layer and zero console warnings/errors. A follow-up status-label fix makes a visible raster report `Rasterlaag actief` instead of `Geen actieve laag`. +- Interactive browser drawing over the central Kempen returned all fifteen + theme summaries, including 619.71 ha modeled pluvial T100 area, 18.26 m TAW + mean terrain height and 56,310 inhabitants. The boundary probe also exposed + and closed a frontend inconsistency: every selection and derive path now + forwards the active Area id for authoritative backend clipping. Next: - Use the now-complete regional current-state layers as the baseline for a diff --git a/frontend/README.md b/frontend/README.md index 156e88a3..6848e68c 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -528,6 +528,12 @@ combined cell statistics. A monolithic full-region 5 m calculation remains disabled because it exceeds the governed raster-cell limit; users draw a bounded rectangle without first choosing a municipality. +Every selection entry path forwards the active Area id. This includes dragged +and coordinate rectangles, manual bbox input, temporal comparison, saving a +derived selection Dataset and the advanced GIS workflow. Backend geometry +intersection therefore remains the authority for the municipality or regional +boundary even when a rectangle extends beyond it. + ## Useful repository scripts - `bash scripts/frontend_install.sh` diff --git a/frontend/src/components/map/MapWorkspace.tsx b/frontend/src/components/map/MapWorkspace.tsx index 28a1fc36..b0d1028e 100644 --- a/frontend/src/components/map/MapWorkspace.tsx +++ b/frontend/src/components/map/MapWorkspace.tsx @@ -676,7 +676,7 @@ interface MapWorkspaceProps { onRunMapSelectionExtract: (bbox: VectorSelectionBBox, areaId?: string) => Promise onClearMapSelectionExtract: () => void onExportMapSelection: (bbox: VectorSelectionBBox) => Promise - onDeriveMapSelectionDataset: (bbox: VectorSelectionBBox) => Promise + onDeriveMapSelectionDataset: (bbox: VectorSelectionBBox, areaId?: string) => Promise onSelectMapQaReferenceDataset: (datasetId: string) => void onRunMapSelectionQa: (candidateDataset?: DatasetCreateResponse | null) => Promise onOpenMapSelectionQualityEvidence: () => void @@ -1123,7 +1123,7 @@ export function MapWorkspace({ setSelectionBbox(bbox) setFirstSelectionCorner(null) setBboxSelectionMode(false) - void analyzeSelection(bbox) + void analyzeSelection(bbox, selectedMapArea?.id) } const runAreaExtract = () => { @@ -1131,7 +1131,7 @@ export function MapWorkspace({ if (!bbox) { return } - void analyzeSelection(bbox) + void analyzeSelection(bbox, selectedMapArea?.id) } const clearAreaSelection = () => { @@ -1183,7 +1183,7 @@ export function MapWorkspace({ if (!bbox) { return } - onDeriveMapSelectionDataset(bbox) + onDeriveMapSelectionDataset(bbox, selectedMapArea?.id) } const openSelectedDatabaseLayer = (datasetId: string) => { @@ -1251,8 +1251,7 @@ export function MapWorkspace({ if (!mapSelectionBbox || !earlierDatasetId || !laterDatasetId) { return } - const areaId = selectedAreaBbox && bboxesEqual(mapSelectionBbox, selectedAreaBbox) ? selectedMapAreaId : undefined - void compareTemporalSnapshots(earlierDatasetId, laterDatasetId, mapSelectionBbox, areaId) + void compareTemporalSnapshots(earlierDatasetId, laterDatasetId, mapSelectionBbox, selectedMapArea?.id) } const handleMapBboxPreview = (bbox: VectorSelectionBBox) => { @@ -1262,7 +1261,7 @@ export function MapWorkspace({ const handleMapBboxSelect = (bbox: VectorSelectionBBox) => { setFirstSelectionCorner(null) setBboxSelectionMode(false) - void analyzeSelection(bbox) + void analyzeSelection(bbox, selectedMapArea?.id) } const runQuickAoiExtract = () => { @@ -1271,7 +1270,7 @@ export function MapWorkspace({ return } setSelectionBbox(bbox) - void analyzeSelection(bbox, selectedAreaBbox ? selectedMapArea?.id : undefined) + void analyzeSelection(bbox, selectedMapArea?.id) } const runFullGisWorkflow = async () => { @@ -1310,7 +1309,7 @@ export function MapWorkspace({ try { setFullWorkflowStatus('1/4 Querying persisted vector_features...') setSelectionBbox(bbox) - const selection = await onRunMapSelectionExtract(bbox) + const selection = await onRunMapSelectionExtract(bbox, selectedMapArea?.id) if (!selection) { setFullWorkflowError('Persisted vector query did not complete.') setFullWorkflowStatus('Stopped at query.') @@ -1318,7 +1317,7 @@ export function MapWorkspace({ } setFullWorkflowStatus('2/4 Saving derived result dataset...') - const derived = await onDeriveMapSelectionDataset(bbox) + const derived = await onDeriveMapSelectionDataset(bbox, selectedMapArea?.id) if (!derived) { setFullWorkflowError('Derived result dataset was not created.') setFullWorkflowStatus('Stopped at dataset save.') diff --git a/frontend/src/hooks/useMapSelectionDataset.ts b/frontend/src/hooks/useMapSelectionDataset.ts index f0b61428..16f01cd3 100644 --- a/frontend/src/hooks/useMapSelectionDataset.ts +++ b/frontend/src/hooks/useMapSelectionDataset.ts @@ -24,7 +24,7 @@ export function useMapSelectionDataset({ const [selectionDatasetError, setSelectionDatasetError] = useState(null) const [latestSelectionDataset, setLatestSelectionDataset] = useState(null) - const deriveMapSelectionDataset = async (bbox: VectorSelectionBBox) => { + const deriveMapSelectionDataset = async (bbox: VectorSelectionBBox, areaId?: string) => { if (!selectedProjectId || !selectedDataset || !isVectorDatasetType(selectedDataset.dataset_type)) { setSelectionDatasetError('Select a vector dataset before saving the area as a dataset.') return null @@ -34,6 +34,7 @@ export function useMapSelectionDataset({ try { const derived = await datasetsApi.deriveVectorSelection(selectedProjectId, selectedDataset.id, { bbox: { ...bbox, crs: 'EPSG:4326' }, + area_id: areaId, limit: 250, output_name: `${selectedDataset.name.replace(/\.(geo)?json$/i, '')}-selection-dataset`, })