Breng de opstartkosten terug en geef de werkstand een schakelaar
De inlogpagina haalde 1,46 MB over de lijn, waaronder de volledige kaartmotor van 213 kB terwijl er geen kaart staat. De werkbank is nu een aparte brok die pas na aanmelden geladen wordt: de eerste JS-bundel gaat van 476 naar 30 kB, en met de beeldwerk uit een eerdere commit komt de inlogpagina op 344 kB. Bij het opstarten gingen 27 verzoeken de deur uit in drie golven. Alles werd vooraf opgehaald, ook voor werkbladen die de gebruiker misschien nooit opent, en twee daarvan werden dubbel opgevraagd door effecten die negentig milliseconde na elkaar liepen. Gelijktijdige en vlak opeenvolgende identieke GET-verzoeken delen nu één belofte, en elk werkblad haalt zijn eigen gegevens pas op wanneer het geopend wordt. Nu zestien verzoeken. Typen in het themazoekveld kostte 53 ms mediaan met uitschieters tot 127 ms, omdat die filterwaarde in het viewmodel van de hele werkruimte leefde. Het veld is een eigen component geworden dat zijn invoer zelf bijhoudt. React.memo om de kaart is geprobeerd en weer verwijderd: van de negentien props worden er te veel per render opnieuw gemaakt, dus de vergelijking sloeg nooit over. Verder: donker blijft de standaard maar er is nu een weg terug naar licht, de kaartondergrond schakelt mee zonder de datalagen te herbouwen, de onderste hero-afbeelding wordt pas opgehaald als hij in beeld komt, en de werkbank heeft een h1 zodat schermlezers een ankerpunt hebben. De tests op de bootstrap legden het oude gedrag vast en toetsen nu het nieuwe, van drie naar zeven gevallen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,10 +1,15 @@
|
||||
import { useEffect } from 'react'
|
||||
import { useEffect, useRef } from 'react'
|
||||
|
||||
type AsyncAction = () => Promise<unknown>
|
||||
type ProjectAction = (projectId: string) => Promise<unknown>
|
||||
|
||||
interface WorkbenchBootstrapOptions {
|
||||
restrictedMode?: boolean
|
||||
/** Het werkblad dat nu open staat. Bepaalt wat er geladen mag worden. */
|
||||
activeWorkspace?: string
|
||||
/** Meldt een mislukte laadactie, zodat de gebruiker het verschil ziet tussen
|
||||
"er is niets" en "het is niet gelukt". */
|
||||
onLoadError?: (onderdeel: string, fout: unknown) => void
|
||||
selectedProjectId: string | null
|
||||
selectedDetectionRunId: string
|
||||
detectionClassFilter: string
|
||||
@@ -32,6 +37,8 @@ interface WorkbenchBootstrapOptions {
|
||||
|
||||
export function useWorkbenchBootstrap({
|
||||
restrictedMode = false,
|
||||
activeWorkspace = 'map',
|
||||
onLoadError,
|
||||
selectedProjectId,
|
||||
selectedDetectionRunId,
|
||||
detectionClassFilter,
|
||||
@@ -56,13 +63,39 @@ export function useWorkbenchBootstrap({
|
||||
resetSegmentationForProject,
|
||||
resetExportsForProject,
|
||||
}: WorkbenchBootstrapOptions): void {
|
||||
const foutMelder = useRef(onLoadError)
|
||||
foutMelder.current = onLoadError
|
||||
|
||||
// Een mislukte laadactie werd overal met .catch(() => null) weggeslikt. De
|
||||
// gebruiker zag dan "Nog geen bronnen beschikbaar", precies hetzelfde scherm
|
||||
// als wanneer er echt niets is. Nu wordt de fout doorgegeven.
|
||||
const meld = (onderdeel: string) => (fout: unknown) => {
|
||||
foutMelder.current?.(onderdeel, fout)
|
||||
return null
|
||||
}
|
||||
|
||||
// Welke werkbladen welke gegevens nodig hebben. Alles werd voorheen bij het
|
||||
// opstarten opgehaald, ook voor werkbladen die de gebruiker nooit opent; dat
|
||||
// waren 27 verzoeken in drie golven voordat de kaart bruikbaar was.
|
||||
const bezocht = useRef(new Set<string>())
|
||||
bezocht.current.add(activeWorkspace)
|
||||
const geopend = (werkblad: string): boolean => bezocht.current.has(werkblad)
|
||||
|
||||
useEffect(() => {
|
||||
loadProjects().catch(() => null)
|
||||
loadCapabilities().catch(() => null)
|
||||
loadDetectionModels().catch(() => null)
|
||||
loadSegmentationModels().catch(() => null)
|
||||
loadProjects().catch(meld('werkruimtes'))
|
||||
}, [restrictedMode])
|
||||
|
||||
useEffect(() => {
|
||||
if (!geopend('system')) return
|
||||
loadCapabilities().catch(meld('bronkoppelingen'))
|
||||
}, [restrictedMode, activeWorkspace])
|
||||
|
||||
useEffect(() => {
|
||||
if (!geopend('ai')) return
|
||||
loadDetectionModels().catch(meld('detectiemodellen'))
|
||||
loadSegmentationModels().catch(meld('segmentatiemodellen'))
|
||||
}, [restrictedMode, activeWorkspace])
|
||||
|
||||
useEffect(() => {
|
||||
if (!selectedProjectId) {
|
||||
resetProjectData()
|
||||
@@ -77,18 +110,32 @@ export function useWorkbenchBootstrap({
|
||||
resetDetectionForProject()
|
||||
resetSegmentationForProject()
|
||||
resetExportsForProject()
|
||||
loadProjectData(selectedProjectId).catch(() => null)
|
||||
loadQualityChecks(selectedProjectId).catch(() => null)
|
||||
loadDetectionRuns(selectedProjectId).catch(() => null)
|
||||
loadSegmentationRuns(selectedProjectId).catch(() => null)
|
||||
loadExports(selectedProjectId).catch(() => null)
|
||||
loadProjectData(selectedProjectId).catch(meld('gebieden en bronnen'))
|
||||
}, [restrictedMode, selectedProjectId])
|
||||
|
||||
useEffect(() => {
|
||||
loadDetectionResults().catch(() => null)
|
||||
}, [restrictedMode, selectedDetectionRunId, detectionClassFilter, detectionMinConfidenceFilter])
|
||||
if (!selectedProjectId || !geopend('analysis')) return
|
||||
loadQualityChecks(selectedProjectId).catch(meld('kwaliteitscontroles'))
|
||||
}, [restrictedMode, selectedProjectId, activeWorkspace])
|
||||
|
||||
useEffect(() => {
|
||||
loadSegmentationResults().catch(() => null)
|
||||
}, [restrictedMode, selectedSegmentationRunId, segmentationClassFilter, segmentationMinConfidenceFilter])
|
||||
if (!selectedProjectId || !geopend('ai')) return
|
||||
loadDetectionRuns(selectedProjectId).catch(meld('detectieruns'))
|
||||
loadSegmentationRuns(selectedProjectId).catch(meld('segmentatieruns'))
|
||||
}, [restrictedMode, selectedProjectId, activeWorkspace])
|
||||
|
||||
useEffect(() => {
|
||||
if (!selectedProjectId || !geopend('exports')) return
|
||||
loadExports(selectedProjectId).catch(meld('downloads'))
|
||||
}, [restrictedMode, selectedProjectId, activeWorkspace])
|
||||
|
||||
useEffect(() => {
|
||||
if (!geopend('ai')) return
|
||||
loadDetectionResults().catch(meld('detectieresultaten'))
|
||||
}, [restrictedMode, activeWorkspace, selectedDetectionRunId, detectionClassFilter, detectionMinConfidenceFilter])
|
||||
|
||||
useEffect(() => {
|
||||
if (!geopend('ai')) return
|
||||
loadSegmentationResults().catch(meld('segmentatieresultaten'))
|
||||
}, [restrictedMode, activeWorkspace, selectedSegmentationRunId, segmentationClassFilter, segmentationMinConfidenceFilter])
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user