send the map selection to change detection and show the modified class
The comparison hook runs before the selection state is declared in App, so the selection is read through a getter at the moment the run starts rather than captured at render. The panel gains the modified count, which until now was folded into removed plus added. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -305,6 +305,8 @@ function WorkbenchApp({ username, accessMode, loggingOut, onLogout }: WorkbenchA
|
|||||||
selectedProjectId,
|
selectedProjectId,
|
||||||
availableVectorDatasets,
|
availableVectorDatasets,
|
||||||
loadDatasetJobs,
|
loadDatasetJobs,
|
||||||
|
// Bind the comparison to whatever the operator has selected on the map.
|
||||||
|
getSelection: () => ({ bbox: mapSelectionBbox ?? null, areaId: selectedMapAreaId ?? null }),
|
||||||
})
|
})
|
||||||
const {
|
const {
|
||||||
qaCandidateDatasetId,
|
qaCandidateDatasetId,
|
||||||
|
|||||||
@@ -120,6 +120,10 @@ export function ChangeDetectionPanel({
|
|||||||
<span className="metric">{result.removed_count}</span>
|
<span className="metric">{result.removed_count}</span>
|
||||||
<span>Verdwenen</span>
|
<span>Verdwenen</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<span className="metric">{result.modified_count ?? 0}</span>
|
||||||
|
<span>Gewijzigd</span>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span className="metric">{result.unchanged_count}</span>
|
<span className="metric">{result.unchanged_count}</span>
|
||||||
<span>Ongewijzigd</span>
|
<span>Ongewijzigd</span>
|
||||||
|
|||||||
@@ -1,18 +1,29 @@
|
|||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { analysisApi } from '../services/api'
|
import { analysisApi } from '../services/api'
|
||||||
import type { ChangeDetectionSummary, DatasetCreateResponse } from '../types'
|
import type { ChangeDetectionSummary, DatasetCreateResponse, VectorSelectionBBox } from '../types'
|
||||||
import { formatError } from '../lib/formatError'
|
import { formatError } from '../lib/formatError'
|
||||||
|
|
||||||
interface ChangeDetectionWorkflowOptions {
|
interface ChangeDetectionWorkflowOptions {
|
||||||
selectedProjectId: string | null
|
selectedProjectId: string | null
|
||||||
availableVectorDatasets: DatasetCreateResponse[]
|
availableVectorDatasets: DatasetCreateResponse[]
|
||||||
loadDatasetJobs: (projectId: string, datasetId: string) => Promise<void>
|
loadDatasetJobs: (projectId: string, datasetId: string) => Promise<void>
|
||||||
|
/**
|
||||||
|
* Reads the active map selection when the comparison is started. Without a
|
||||||
|
* selection the comparison covers both datasets entire, which is rarely the
|
||||||
|
* question being asked and returns a payload no map can draw.
|
||||||
|
*
|
||||||
|
* A getter rather than a value because this hook runs before the selection
|
||||||
|
* state is declared in the component; it is only ever called from a user
|
||||||
|
* event, long after that binding is initialised.
|
||||||
|
*/
|
||||||
|
getSelection?: () => { bbox: VectorSelectionBBox | null; areaId: string | null }
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useChangeDetectionWorkflow({
|
export function useChangeDetectionWorkflow({
|
||||||
selectedProjectId,
|
selectedProjectId,
|
||||||
availableVectorDatasets,
|
availableVectorDatasets,
|
||||||
loadDatasetJobs,
|
loadDatasetJobs,
|
||||||
|
getSelection,
|
||||||
}: ChangeDetectionWorkflowOptions) {
|
}: ChangeDetectionWorkflowOptions) {
|
||||||
const [changeSourceDatasetId, setChangeSourceDatasetId] = useState('')
|
const [changeSourceDatasetId, setChangeSourceDatasetId] = useState('')
|
||||||
const [changeTargetDatasetId, setChangeTargetDatasetId] = useState('')
|
const [changeTargetDatasetId, setChangeTargetDatasetId] = useState('')
|
||||||
@@ -41,12 +52,15 @@ export function useChangeDetectionWorkflow({
|
|||||||
setChangeDetectionError(null)
|
setChangeDetectionError(null)
|
||||||
setChangeDetectionResult(null)
|
setChangeDetectionResult(null)
|
||||||
setRunningChangeDetection(true)
|
setRunningChangeDetection(true)
|
||||||
|
const selection = getSelection?.() ?? { bbox: null, areaId: null }
|
||||||
try {
|
try {
|
||||||
const job = await analysisApi.runChangeDetection({
|
const job = await analysisApi.runChangeDetection({
|
||||||
source_dataset_id: sourceDatasetId,
|
source_dataset_id: sourceDatasetId,
|
||||||
target_dataset_id: targetDatasetId,
|
target_dataset_id: targetDatasetId,
|
||||||
iou_threshold: changeIouThreshold,
|
iou_threshold: changeIouThreshold,
|
||||||
include_unchanged: changeIncludeUnchanged,
|
include_unchanged: changeIncludeUnchanged,
|
||||||
|
...(selection.bbox ? { bbox: selection.bbox } : {}),
|
||||||
|
...(selection.areaId ? { area_id: selection.areaId } : {}),
|
||||||
})
|
})
|
||||||
if (job.status !== 'success') {
|
if (job.status !== 'success') {
|
||||||
throw new Error(job.error_message || 'Change detection job failed')
|
throw new Error(job.error_message || 'Change detection job failed')
|
||||||
|
|||||||
@@ -1055,7 +1055,13 @@ export interface ChangeDetectionRequest {
|
|||||||
source_dataset_id: string
|
source_dataset_id: string
|
||||||
target_dataset_id: string
|
target_dataset_id: string
|
||||||
iou_threshold: number
|
iou_threshold: number
|
||||||
|
/** Below this the footprints are separate objects rather than one redrawn. */
|
||||||
|
modified_threshold?: number
|
||||||
include_unchanged: boolean
|
include_unchanged: boolean
|
||||||
|
/** Without a selection the comparison covers both datasets in full. */
|
||||||
|
bbox?: VectorSelectionBBox | null
|
||||||
|
area_id?: string | null
|
||||||
|
preview_limit?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ChangeDetectionSummary {
|
export interface ChangeDetectionSummary {
|
||||||
@@ -1065,8 +1071,15 @@ export interface ChangeDetectionSummary {
|
|||||||
target_feature_count: number
|
target_feature_count: number
|
||||||
added_count: number
|
added_count: number
|
||||||
removed_count: number
|
removed_count: number
|
||||||
|
/** A footprint that was redrawn, not demolished and rebuilt. */
|
||||||
|
modified_count?: number
|
||||||
unchanged_count: number
|
unchanged_count: number
|
||||||
iou_threshold: number
|
iou_threshold: number
|
||||||
|
modified_iou_threshold?: number | null
|
||||||
|
selection_area_id?: string | null
|
||||||
|
/** Counts cover the whole selection; the GeoJSON is capped. */
|
||||||
|
preview_limit?: number | null
|
||||||
|
preview_truncated?: boolean
|
||||||
warnings: string[]
|
warnings: string[]
|
||||||
generated_at: string
|
generated_at: string
|
||||||
geojson: GeoJSON.FeatureCollection
|
geojson: GeoJSON.FeatureCollection
|
||||||
|
|||||||
Reference in New Issue
Block a user