Complete operational map result workflow
GeoIntel CI / docs-smoke (push) Canceled after 0s
GeoIntel CI / contract-smoke (push) Canceled after 0s

This commit is contained in:
Codex
2026-07-17 12:35:50 +02:00
parent 8266929b2e
commit a29c787238
33 changed files with 1121 additions and 107 deletions
+80 -14
View File
@@ -1,6 +1,6 @@
import { useEffect, useMemo, useState } from 'react'
import GeoMap from '../GeoMap'
import type { AreaRead, DatasetCreateResponse, DetectionQaResult, MapViewportState, OrthophotoAcquisitionResult, OrthophotoProductRead, ProjectRead, QaComparisonResult, VectorSelectionBBox, VectorSelectionMetric, VectorSelectionResponse } from '../../types'
import type { AreaRead, DatasetCreateResponse, DetectionQaResult, MapResultExportRequest, MapViewportState, OrthophotoAcquisitionResult, OrthophotoProductRead, ProjectRead, QaComparisonResult, VectorSelectionBBox, VectorSelectionMetric, VectorSelectionResponse } from '../../types'
import { featureCollectionBounds } from '../../lib/geojsonBounds'
import { useMapThemeSelectionInsights } from '../../hooks/useMapThemeSelectionInsights'
import { useTemporalComparison } from '../../hooks/useTemporalComparison'
@@ -708,7 +708,8 @@ interface MapWorkspaceProps {
onSetMapSelectionBbox: (bbox: VectorSelectionBBox | null) => void
onRunMapSelectionExtract: (bbox: VectorSelectionBBox, areaId?: string) => Promise<VectorSelectionResponse | null>
onClearMapSelectionExtract: () => void
onExportMapSelection: (bbox: VectorSelectionBBox) => Promise<unknown>
onExportMapSelection: (bbox: VectorSelectionBBox, areaId?: string) => Promise<unknown>
onPersistMapResult: (payload: MapResultExportRequest) => Promise<unknown>
onDeriveMapSelectionDataset: (bbox: VectorSelectionBBox, areaId?: string) => Promise<DatasetCreateResponse | null>
onSelectMapQaReferenceDataset: (datasetId: string) => void
onRunMapSelectionQa: (candidateDataset?: DatasetCreateResponse | null) => Promise<QaComparisonResult | null>
@@ -792,6 +793,7 @@ export function MapWorkspace({
onRunMapSelectionExtract,
onClearMapSelectionExtract,
onExportMapSelection,
onPersistMapResult,
onDeriveMapSelectionDataset,
onSelectMapQaReferenceDataset,
onRunMapSelectionQa,
@@ -1151,6 +1153,15 @@ export function MapWorkspace({
setBboxInput(bboxToInputState(bbox))
}
const areaIdForSelection = (bbox: VectorSelectionBBox | null): string | undefined => (
bbox
&& selectedMapArea
&& selectedAreaBbox
&& bboxesEqual(bbox, selectedAreaBbox)
? selectedMapArea.id
: undefined
)
const startBboxSelection = () => {
setFirstSelectionCorner(null)
clearThemeInsights()
@@ -1167,7 +1178,7 @@ export function MapWorkspace({
setSelectionBbox(bbox)
setFirstSelectionCorner(null)
setBboxSelectionMode(false)
void analyzeSelection(bbox, selectedMapArea?.id)
void analyzeSelection(bbox)
}
const runAreaExtract = () => {
@@ -1175,7 +1186,7 @@ export function MapWorkspace({
if (!bbox) {
return
}
void analyzeSelection(bbox, selectedMapArea?.id)
void analyzeSelection(bbox, areaIdForSelection(bbox))
}
const clearAreaSelection = () => {
@@ -1210,7 +1221,7 @@ export function MapWorkspace({
if (activeThemeDataset?.dataset_type === 'raster') {
downloadJsonFile(`${activeTheme.id}-analysis.json`, {
project_id: selectedProjectId,
area_id: selectedMapArea?.id ?? null,
area_id: areaIdForSelection(mapSelectionBbox) ?? null,
area_name: selectedMapArea?.name ?? null,
theme: activeTheme,
dataset_id: activeThemeDataset.id,
@@ -1238,12 +1249,54 @@ export function MapWorkspace({
copyText(JSON.stringify(temporalComparison ?? {}, null, 2))
}
const persistActiveResultAndOpenDownloads = async () => {
if (!selectedProjectId || !mapSelectionBbox) {
onOpenExports()
return
}
const areaId = areaIdForSelection(mapSelectionBbox)
const payload: MapResultExportRequest | null = analysisMode === 'evolution'
? temporalComparison && earlierDatasetId && laterDatasetId
? {
project_id: selectedProjectId,
mode: 'evolution',
bbox: { ...mapSelectionBbox, crs: 'EPSG:4326' },
earlier_dataset_id: earlierDatasetId,
later_dataset_id: laterDatasetId,
area_id: areaId,
theme_id: activeTheme.id,
name: `${activeTheme.id}-evolution`,
}
: null
: activeSelectionResult && activeThemeDataset
? {
project_id: selectedProjectId,
mode: 'current',
bbox: { ...mapSelectionBbox, crs: 'EPSG:4326' },
dataset_id: activeThemeDataset.id,
area_id: areaId,
partitioned: regionalRasterThemeActive,
product_key: String(activeThemeDataset.source_metadata?.['product_key'] ?? '') || undefined,
theme_id: activeTheme.id,
name: `${activeTheme.id}-analysis`,
}
: null
if (!payload) {
onOpenExports()
return
}
const persisted = await onPersistMapResult(payload)
if (persisted) {
onOpenExports()
}
}
const saveAreaSelectionExport = () => {
const bbox = parseBboxInput(bboxInput)
if (!bbox) {
return
}
onExportMapSelection(bbox)
onExportMapSelection(bbox, areaIdForSelection(bbox))
}
const saveAreaSelectionDataset = () => {
@@ -1251,7 +1304,7 @@ export function MapWorkspace({
if (!bbox) {
return
}
onDeriveMapSelectionDataset(bbox, selectedMapArea?.id)
onDeriveMapSelectionDataset(bbox, areaIdForSelection(bbox))
}
const openSelectedDatabaseLayer = (datasetId: string) => {
@@ -1319,7 +1372,12 @@ export function MapWorkspace({
if (!mapSelectionBbox || !earlierDatasetId || !laterDatasetId) {
return
}
void compareTemporalSnapshots(earlierDatasetId, laterDatasetId, mapSelectionBbox, selectedMapArea?.id)
void compareTemporalSnapshots(
earlierDatasetId,
laterDatasetId,
mapSelectionBbox,
areaIdForSelection(mapSelectionBbox),
)
}
const handleMapBboxPreview = (bbox: VectorSelectionBBox) => {
@@ -1329,7 +1387,7 @@ export function MapWorkspace({
const handleMapBboxSelect = (bbox: VectorSelectionBBox) => {
setFirstSelectionCorner(null)
setBboxSelectionMode(false)
void analyzeSelection(bbox, selectedMapArea?.id)
void analyzeSelection(bbox)
}
const runQuickAoiExtract = () => {
@@ -1338,7 +1396,7 @@ export function MapWorkspace({
return
}
setSelectionBbox(bbox)
void analyzeSelection(bbox, selectedMapArea?.id)
void analyzeSelection(bbox, areaIdForSelection(bbox))
}
const runFullGisWorkflow = async () => {
@@ -1377,7 +1435,8 @@ export function MapWorkspace({
try {
setFullWorkflowStatus('1/4 Querying persisted vector_features...')
setSelectionBbox(bbox)
const selection = await onRunMapSelectionExtract(bbox, selectedMapArea?.id)
const selectionAreaId = areaIdForSelection(bbox)
const selection = await onRunMapSelectionExtract(bbox, selectionAreaId)
if (!selection) {
setFullWorkflowError('Persisted vector query did not complete.')
setFullWorkflowStatus('Stopped at query.')
@@ -1385,7 +1444,7 @@ export function MapWorkspace({
}
setFullWorkflowStatus('2/4 Saving derived result dataset...')
const derived = await onDeriveMapSelectionDataset(bbox, selectedMapArea?.id)
const derived = await onDeriveMapSelectionDataset(bbox, selectionAreaId)
if (!derived) {
setFullWorkflowError('Derived result dataset was not created.')
setFullWorkflowStatus('Stopped at dataset save.')
@@ -1393,7 +1452,7 @@ export function MapWorkspace({
}
setFullWorkflowStatus('3/4 Saving GeoJSON export artifact...')
await onExportMapSelection(bbox)
await onExportMapSelection(bbox, selectionAreaId)
if (selectedMapQaReferenceDatasetId) {
setFullWorkflowStatus('4/4 Running QA/QC against selected reference...')
@@ -1982,7 +2041,14 @@ export function MapWorkspace({
<small>Stel een vraag over dit gebied of open je bewaarde resultaten.</small>
</span>
<button className="primary-action" type="button" onClick={onOpenAssistant}>Stel AI-vraag</button>
<button className="secondary-action" type="button" onClick={onOpenExports}>Open downloads</button>
<button
className="secondary-action"
type="button"
disabled={selectionExporting}
onClick={() => void persistActiveResultAndOpenDownloads()}
>
{selectionExporting ? 'Resultaat bewaren…' : 'Bewaar in downloads'}
</button>
</div>
) : null}
</>