Laat een kapot paneel geen kapotte applicatie meer zijn

Er was nergens een error boundary: geen componentDidCatch, geen
getDerivedStateFromError. Eén component die gooit nam de hele werkbank mee,
inclusief de kaart en de navigatie. Nu blijft de schil staan, ziet de gebruiker
welk werkblad het liet afweten, en wist wegnavigeren de fout.

Daarnaast een patroon dat op zeven plekken half was toegepast: een optionele
keten die te vroeg stopt. report?.items?.filter(...) stond geguard, twintig
regels verderop stond report.items.map(...) zonder. Half geguard is de
eigenlijke fout, want het wekt zekerheid zonder die te bieden. Waar de lijst op
meerdere plekken gebruikt wordt staat nu één normalisatie aan de kop.

De brondetails hadden geen enkele afhandeling en werden met .catch(() => null)
overgeslagen; die melden nu wel. De overige elf catch-blokken bleken bovenop
hooks te staan die de fout al zelf opvangen en tonen, wat ik heb nagemeten door
een verzoek te laten mislukken.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Jens
2026-08-23 15:00:08 +02:00
co-authored by Claude Opus 5
parent 438d0ec083
commit f567a459b0
15 changed files with 294 additions and 26 deletions
+10 -3
View File
@@ -82,6 +82,13 @@ export function useDatasetWorkflow({
setErrorMessage,
isVectorDatasetType,
}: DatasetWorkflowOptions) {
// De detailgegevens van een bron werden bij een fout stilzwijgend
// overgeslagen; het paneel bleef dan leeg zonder dat iemand wist waarom.
const meldDetailFout = (fout: unknown) => {
setErrorMessage(fout instanceof Error ? fout.message : 'De brondetails konden niet worden geladen')
return null
}
const [selectedDatasetId, setSelectedDatasetId] = useState<string | null>(null)
const [selectedDataset, setSelectedDataset] = useState<DatasetCreateResponse | null>(null)
const [selectedDatasetSummary, setSelectedDatasetSummary] = useState<VectorSummary | null>(null)
@@ -145,7 +152,7 @@ export function useDatasetWorkflow({
datasets.find((dataset) => dataset.status === 'ready') ??
datasets[0]
if (defaultDataset) {
loadDatasetDetails(selectedProjectId, defaultDataset).catch(() => null)
loadDatasetDetails(selectedProjectId, defaultDataset).catch(meldDetailFout)
}
}, [datasets, isVectorDatasetType, selectedDatasetId, selectedProjectId])
@@ -284,7 +291,7 @@ export function useDatasetWorkflow({
await Promise.all([loadDatasetJobs(selectedProjectId, selectedDatasetId), loadProjectData(selectedProjectId)])
const refreshed = datasets.find((dataset) => dataset.id === selectedDatasetId)
if (refreshed) {
loadDatasetDetails(selectedProjectId, refreshed).catch(() => null)
loadDatasetDetails(selectedProjectId, refreshed).catch(meldDetailFout)
}
}
@@ -521,7 +528,7 @@ export function useDatasetWorkflow({
if (selectedDataset?.id === datasetId) {
setSelectedDataset(refreshed)
if (isVectorDatasetType(refreshed.dataset_type)) {
loadDatasetDetails(selectedProjectId, refreshed).catch(() => null)
loadDatasetDetails(selectedProjectId, refreshed).catch(meldDetailFout)
}
}
}
+2 -2
View File
@@ -77,8 +77,8 @@ export function useDemoWorkflow({
loadQualityChecks(result.project_id),
analysisLoads,
])
const candidateDataset = projectData?.datasets.find((dataset) => dataset.id === result.candidate_dataset_id)
const rasterDataset = projectData?.datasets.find((dataset) => dataset.id === result.raster_dataset_id)
const candidateDataset = projectData?.datasets?.find((dataset) => dataset.id === result.candidate_dataset_id)
const rasterDataset = projectData?.datasets?.find((dataset) => dataset.id === result.raster_dataset_id)
if (candidateDataset) {
await loadDatasetDetails(result.project_id, candidateDataset)
} else if (rasterDataset) {
+2 -2
View File
@@ -89,8 +89,8 @@ export function useMapWorkspaceState({
}
return 'Geen actieve kaartlaag'
}, [changeDetectionGeoJson, datasetLayerActive, detectionGeoJson, segmentationGeoJson, selectedDataset])
const mapFeatureCount = mapFeatureCollection?.features.length ?? 0
const areaFeatureCount = areaFeatureCollection?.features.length ?? 0
const mapFeatureCount = mapFeatureCollection?.features?.length ?? 0
const areaFeatureCount = areaFeatureCollection?.features?.length ?? 0
useEffect(() => {
setSelectedMapFeature(null)