Prefer persisted sources in map federation
GeoIntel release gates / Compile, test, contracts and builds (push) Canceled after 0s
GeoIntel release gates / Python and npm vulnerability policy (push) Canceled after 0s
GeoIntel release gates / GIS image, SBOM and container scan (push) Canceled after 0s

This commit is contained in:
Codex
2026-07-19 02:08:52 +02:00
parent a823342b5b
commit 5f15753247
8 changed files with 96 additions and 21 deletions
+28 -15
View File
@@ -27,6 +27,7 @@ import {
getFeatureBBox,
getFeatureCollectionBBox,
getFeatureGeometrySummary,
isSelectionBoundedDataset,
normalizeBboxFromCorners,
operationalScopeProjectLabel,
parseBboxInput,
@@ -411,6 +412,9 @@ function datasetCoversSelectedArea(
selectedAreaName: string | null | undefined,
regionalScope = false,
): boolean {
if (isSelectionBoundedDataset(dataset.source_metadata)) {
return false
}
const selectedZones = selectedAreaCoverageZones(selectedAreaName)
const configuredZones = dataset.source_metadata?.['coverage_zones']
if (selectedZones && Array.isArray(configuredZones) && configuredZones.length > 0) {
@@ -929,19 +933,25 @@ export function MapWorkspace({
}
if (flandersScopeSelected && officialMapProducts.thematic.length > 0) {
for (const product of officialMapProducts.thematic) {
result[product.theme] = null
if (!result[product.theme]) {
result[product.theme] = null
}
}
}
if (flandersScopeSelected && officialMapProducts.grb.length > 0) {
for (const product of officialMapProducts.grb) {
result[product.key] = null
if (!result[product.key]) {
result[product.key] = null
}
}
}
if (officialMapProducts.officialVector.length > 0) {
for (const product of officialMapProducts.officialVector.filter((item) =>
productCoversZones(item.coverage_zones, selectedCoverageZones),
)) {
result[product.theme] = null
if (!result[product.theme]) {
result[product.theme] = null
}
}
}
return result
@@ -1077,7 +1087,9 @@ export function MapWorkspace({
}
return result
}, [onDemandProductsForZones, selectedCoverageZones])
const activeOnDemandMapProduct = onDemandProductMap.get(activeTheme.id) ?? null
const activeOnDemandMapProduct = themeDatasetMap[activeTheme.id]
? null
: onDemandProductMap.get(activeTheme.id) ?? null
const activeThemeMapStyle = DATA_THEME_MAP_STYLES[activeTheme.id]
const analysisOverlayActive = mapContentMode === 'analysis' && analysisLayerAvailable && Boolean(mapFeatureCollection)
const selectedOrthophotoProduct = orthophotoProducts.find((item) => item.key === selectedOrthophotoProductKey) ?? null
@@ -1665,6 +1677,16 @@ export function MapWorkspace({
: []
const availableThemes: Array<MapThemeQuery<DataThemeId>> = []
for (const theme of DATA_THEMES) {
const dataset = themeDatasetMap[theme.id]
if (dataset) {
availableThemes.push({
themeId: theme.id,
dataset,
partitioned: regionalScopeSelected
&& (isPartitionedRaster(dataset) || isPartitionedBathymetry(dataset)),
})
continue
}
const onDemandProducts = resolvedProducts.filter((product) => product.theme === theme.id)
if (onDemandProducts.length > 0) {
for (const onDemandProduct of onDemandProducts) {
@@ -1679,15 +1701,6 @@ export function MapWorkspace({
}
continue
}
const dataset = themeDatasetMap[theme.id]
if (dataset) {
availableThemes.push({
themeId: theme.id,
dataset,
partitioned: regionalScopeSelected
&& (isPartitionedRaster(dataset) || isPartitionedBathymetry(dataset)),
})
}
}
await loadThemeInsights(bbox, availableThemes, areaId)
}
@@ -1992,7 +2005,7 @@ export function MapWorkspace({
</small>
</div>
{officialMapProductsLoading && selectedProjectId ? (
<p className="geo-data-notice">Beschikbare Vlaamse kaartbronnen worden gecontroleerd</p>
<p className="geo-data-notice">Beschikbare officiële regionale kaartbronnen worden gecontroleerd</p>
) : null}
{officialMapProductsError && selectedProjectId ? (
<p className="error">{officialMapProductsError}</p>
@@ -2154,7 +2167,7 @@ export function MapWorkspace({
: regionalRasterThemeActive
? 'Teken een rechthoek; de juiste gemeentelijke rasters worden automatisch gecombineerd.'
: onDemandThemeActive
? 'Teken een rechthoek; officiële Vlaamse kaartbronnen worden begrensd opgehaald, bewaard en hergebruikt.'
? 'Teken een rechthoek; officiële regionale kaartbronnen worden begrensd opgehaald, bewaard en hergebruikt.'
: regionalBathymetryThemeActive
? 'Teken een rechthoek of analyseer Vlaanderen; alleen overlappende VHA-partities worden samengevoegd.'
: 'Sleep een rechthoek of analyseer het volledige werkgebied.'}
@@ -1,6 +1,7 @@
import { describe, expect, it } from 'vitest'
import {
bboxesEqual,
isSelectionBoundedDataset,
normalizeBboxFromCorners,
parseBboxInput,
productCoversZones,
@@ -63,4 +64,18 @@ describe('map workspace selection guards', () => {
expect(productCoversZones(['wallonia'], ['flanders', 'wallonia'])).toBe(true)
expect(productCoversZones(['brussels'], ['wallonia'])).toBe(false)
})
it('distinguishes selection-bounded acquisitions from reusable regional datasets', () => {
expect(isSelectionBoundedDataset({
geometry_clipped_to_selection: true,
bbox_epsg4326: [4.55, 50.58, 4.56, 50.59],
})).toBe(true)
expect(isSelectionBoundedDataset({
geometry_clipped_to_selection: false,
bbox_epsg4326: [2.5, 49.5, 6.4, 51.6],
})).toBe(false)
expect(isSelectionBoundedDataset({
geometry_clipped_to_selection: true,
})).toBe(false)
})
})
@@ -35,6 +35,14 @@ export function productCoversZones(productZones: string[], selectedZones: string
return selectedZones === null || selectedZones.some((zone) => productZones.includes(zone))
}
export function isSelectionBoundedDataset(
sourceMetadata: Record<string, unknown> | null | undefined,
): boolean {
return sourceMetadata?.['geometry_clipped_to_selection'] === true
&& Array.isArray(sourceMetadata?.['bbox_epsg4326'])
&& sourceMetadata['bbox_epsg4326'].length === 4
}
export function operationalScopeProjectLabel(project: ProjectRead): string {
if (project.name === MOL_PROJECT_NAME) {
return 'Mol'