feat: simplify regional end user workbench
This commit is contained in:
+100
-79
@@ -30,6 +30,8 @@ import { useQualityWorkflow } from './hooks/useQualityWorkflow'
|
||||
import { useSegmentationWorkflow } from './hooks/useSegmentationWorkflow'
|
||||
import { useWorkbenchBootstrap } from './hooks/useWorkbenchBootstrap'
|
||||
import { useViewportVectorLayer } from './hooks/useViewportVectorLayer'
|
||||
import { getDatasetDisplayName } from './lib/datasetDisplay'
|
||||
import { REGIONAL_WORKSPACE_LABEL, REGIONAL_WORKSPACE_PROJECT_NAME } from './config/primaryFocus'
|
||||
|
||||
function isVectorDatasetType(datasetType: string): boolean {
|
||||
return datasetType === 'vector' || datasetType === 'geojson'
|
||||
@@ -38,19 +40,20 @@ function isVectorDatasetType(datasetType: string): boolean {
|
||||
type WorkspaceKey = 'overview' | 'data' | 'map' | 'analysis' | 'ai' | 'exports' | 'system'
|
||||
|
||||
const workspaceNavItems: Array<{ key: WorkspaceKey; label: string; description: string }> = [
|
||||
{ key: 'overview', label: 'Overview', description: 'V1 readiness and next action' },
|
||||
{ key: 'data', label: 'Data', description: 'Projects, AOI and datasets' },
|
||||
{ key: 'map', label: 'Map', description: 'Layer review and inspection' },
|
||||
{ key: 'analysis', label: 'QA/QC', description: 'Quality checks and change detection' },
|
||||
{ key: 'ai', label: 'AI Labs', description: 'Detection and segmentation' },
|
||||
{ key: 'exports', label: 'Exports', description: 'Artifacts and downloads' },
|
||||
{ key: 'system', label: 'System', description: 'Provider capabilities' },
|
||||
{ key: 'overview', label: 'Status', description: 'Beschikbaarheid en aandachtspunten' },
|
||||
{ key: 'data', label: 'Bronnen', description: 'Gebieden en ingeladen gegevens' },
|
||||
{ key: 'map', label: 'Kaart', description: 'Selecteren, uitlezen en vergelijken' },
|
||||
{ key: 'analysis', label: 'Kwaliteit', description: 'Resultaten controleren' },
|
||||
{ key: 'ai', label: 'Beeldanalyse', description: 'Gebouwen herkennen op luchtbeelden' },
|
||||
{ key: 'exports', label: 'Downloads', description: 'Resultaten bewaren en delen' },
|
||||
{ key: 'system', label: 'Beheer', description: 'Databronnen en systeemstatus' },
|
||||
]
|
||||
|
||||
const workspaceNavGroups: Array<{ label: string; keys: WorkspaceKey[] }> = [
|
||||
{ label: 'Workspace', keys: ['overview', 'data', 'map'] },
|
||||
{ label: 'Analyze', keys: ['analysis', 'ai'] },
|
||||
{ label: 'Deliver', keys: ['exports', 'system'] },
|
||||
{ label: 'Verkennen', keys: ['map', 'data'] },
|
||||
{ label: 'Analyseren', keys: ['analysis', 'ai'] },
|
||||
{ label: 'Afronden', keys: ['exports'] },
|
||||
{ label: 'Beheer', keys: ['overview', 'system'] },
|
||||
]
|
||||
|
||||
function App(): JSX.Element {
|
||||
@@ -659,43 +662,45 @@ function App(): JSX.Element {
|
||||
target: 'exports',
|
||||
},
|
||||
]
|
||||
const projectContextLabel = selectedProject?.name ?? 'No project'
|
||||
const areaContextLabel = selectedArea?.name ?? (areas.length > 0 ? 'Select area' : 'No AOI')
|
||||
const datasetContextLabel = selectedDataset?.name ?? (datasets.length > 0 ? 'Select dataset' : 'No dataset')
|
||||
const projectContextLabel = selectedProject?.name === REGIONAL_WORKSPACE_PROJECT_NAME
|
||||
? REGIONAL_WORKSPACE_LABEL
|
||||
: selectedProject?.name ?? 'Geen werkruimte'
|
||||
const areaContextLabel = selectedArea?.name ?? (areas.length > 0 ? 'Kies een gebied' : 'Geen gebied')
|
||||
const datasetContextLabel = selectedDataset ? getDatasetDisplayName(selectedDataset) : datasets.length > 0 ? 'Kies een bron' : 'Geen bron'
|
||||
const layerContextLabel = mapFeatureCollection
|
||||
? `${mapFeatureCount} features`
|
||||
: viewportVectorLayerActive
|
||||
? 'Viewport layer selected'
|
||||
: 'No active layer'
|
||||
? 'Kaartlaag gekozen'
|
||||
: 'Geen actieve laag'
|
||||
|
||||
return (
|
||||
<div className="app-shell workbench-shell">
|
||||
<a className="skip-link" href="#workspace-main">
|
||||
Skip to workspace
|
||||
Ga naar de werkruimte
|
||||
</a>
|
||||
<header className="workbench-topbar">
|
||||
<div className="brand-block">
|
||||
<span className="brand-mark" aria-hidden="true">GI</span>
|
||||
<div>
|
||||
<h1>GeoIntel</h1>
|
||||
<p>GeoAI Workbench · Mol / Kempen</p>
|
||||
<p>GeoAI-werkruimte · Mol en de Kempen</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="context-bar" aria-label="Active workbench context">
|
||||
<div>
|
||||
<span>Project</span>
|
||||
<span>Werkruimte</span>
|
||||
<strong title={projectContextLabel}>{projectContextLabel}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>AOI</span>
|
||||
<span>Gebied</span>
|
||||
<strong title={areaContextLabel}>{areaContextLabel}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>Dataset</span>
|
||||
<span>Bron</span>
|
||||
<strong title={datasetContextLabel}>{datasetContextLabel}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>Layer</span>
|
||||
<span>Kaartlaag</span>
|
||||
<strong title={layerContextLabel}>{layerContextLabel}</strong>
|
||||
</div>
|
||||
</div>
|
||||
@@ -770,7 +775,7 @@ function App(): JSX.Element {
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<span>{selectedProject ? `Active project: ${selectedProject.name}` : 'Start with a project or load the demo workflow.'}</span>
|
||||
<span>{selectedProject ? `Actief bereik: ${projectContextLabel}` : 'De regionale gegevens worden ingeladen.'}</span>
|
||||
</div>
|
||||
|
||||
{activeWorkspace === 'overview' ? (
|
||||
@@ -784,6 +789,11 @@ function App(): JSX.Element {
|
||||
activeLayerFeatureCount={mapFeatureCount}
|
||||
selectedAreaHasGeometry={Boolean(areaFeatureCollection)}
|
||||
/>
|
||||
<details className="status-details-disclosure">
|
||||
<summary>
|
||||
<span>Volledige workflowstatus</span>
|
||||
<strong>{workflowGuidanceComplete ? 'voltooid' : 'optionele stappen open'}</strong>
|
||||
</summary>
|
||||
<section className="workflow-guidance-panel" aria-label="V1 workflow guidance">
|
||||
<div className="panel-title-row">
|
||||
<div>
|
||||
@@ -860,6 +870,7 @@ function App(): JSX.Element {
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
</details>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
@@ -958,7 +969,6 @@ function App(): JSX.Element {
|
||||
selectedMapDatasetId={selectedDataset && isVectorDatasetType(selectedDataset.dataset_type) ? selectedDataset.id : ''}
|
||||
selectedFeature={selectedMapFeature}
|
||||
onSelectMapArea={setSelectedMapAreaId}
|
||||
onSelectProject={selectProject}
|
||||
onOpenDatasetInMap={openDatasetInMap}
|
||||
onSetAreaLayerVisible={setAreaLayerVisible}
|
||||
onSetAreaLayerOpacity={setAreaLayerOpacity}
|
||||
@@ -981,22 +991,6 @@ function App(): JSX.Element {
|
||||
|
||||
{activeWorkspace === 'analysis' ? (
|
||||
<div className="workspace-grid workspace-grid-analysis">
|
||||
<ChangeDetectionPanel
|
||||
vectorDatasets={availableVectorDatasets}
|
||||
sourceDatasetId={changeSourceDatasetId}
|
||||
targetDatasetId={changeTargetDatasetId}
|
||||
iouThreshold={changeIouThreshold}
|
||||
includeUnchanged={changeIncludeUnchanged}
|
||||
running={runningChangeDetection}
|
||||
result={changeDetectionResult}
|
||||
error={changeDetectionError}
|
||||
onSourceDatasetChange={setChangeSourceDatasetId}
|
||||
onTargetDatasetChange={setChangeTargetDatasetId}
|
||||
onIouThresholdChange={setChangeIouThreshold}
|
||||
onIncludeUnchangedChange={setChangeIncludeUnchanged}
|
||||
onRun={runChangeDetection}
|
||||
/>
|
||||
|
||||
<QualityResultsPanel
|
||||
selectedProjectId={selectedProjectId}
|
||||
qualityChecks={qualityChecks}
|
||||
@@ -1008,6 +1002,27 @@ function App(): JSX.Element {
|
||||
evidenceLoading={qualityEvidenceLoading}
|
||||
evidenceError={qualityEvidenceError}
|
||||
/>
|
||||
<details className="secondary-analysis-disclosure">
|
||||
<summary>
|
||||
<span>Historische vectorlagen vergelijken</span>
|
||||
<strong>Geavanceerd</strong>
|
||||
</summary>
|
||||
<ChangeDetectionPanel
|
||||
vectorDatasets={availableVectorDatasets}
|
||||
sourceDatasetId={changeSourceDatasetId}
|
||||
targetDatasetId={changeTargetDatasetId}
|
||||
iouThreshold={changeIouThreshold}
|
||||
includeUnchanged={changeIncludeUnchanged}
|
||||
running={runningChangeDetection}
|
||||
result={changeDetectionResult}
|
||||
error={changeDetectionError}
|
||||
onSourceDatasetChange={setChangeSourceDatasetId}
|
||||
onTargetDatasetChange={setChangeTargetDatasetId}
|
||||
onIouThresholdChange={setChangeIouThreshold}
|
||||
onIncludeUnchangedChange={setChangeIncludeUnchanged}
|
||||
onRun={runChangeDetection}
|
||||
/>
|
||||
</details>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
@@ -1069,46 +1084,52 @@ function App(): JSX.Element {
|
||||
onApplyOperatorProfile={applyDetectionOperatorProfile}
|
||||
/>
|
||||
|
||||
<SegmentationLab
|
||||
segmentationModels={segmentationModels}
|
||||
loadingSegmentationModels={loadingSegmentationModels}
|
||||
segmentationModelError={segmentationModelError}
|
||||
selectedSegmentationDatasetId={selectedSegmentationDatasetId}
|
||||
selectedSegmentationModelId={selectedSegmentationModelId}
|
||||
segmentationTileManifestPath={segmentationTileManifestPath}
|
||||
segmentationConfidenceThreshold={segmentationConfidenceThreshold}
|
||||
runningSegmentation={runningSegmentation}
|
||||
segmentationRunResult={segmentationRunResult}
|
||||
segmentationRunError={segmentationRunError}
|
||||
segmentationRuns={segmentationRuns}
|
||||
selectedSegmentationRunId={selectedSegmentationRunId}
|
||||
segmentationItems={segmentationItems}
|
||||
segmentationClassFilter={segmentationClassFilter}
|
||||
segmentationMinConfidenceFilter={segmentationMinConfidenceFilter}
|
||||
loadingSegmentationResults={loadingSegmentationResults}
|
||||
segmentationReferenceDatasetId={segmentationReferenceDatasetId}
|
||||
segmentationQaResult={segmentationQaResult}
|
||||
segmentationQaError={segmentationQaError}
|
||||
runningSegmentationQa={runningSegmentationQa}
|
||||
selectedProjectId={selectedProjectId}
|
||||
rasterDatasets={rasterDatasets}
|
||||
referenceDatasets={referenceDatasets}
|
||||
selectedSegmentationModelConfigured={Boolean(selectedSegmentationModel?.configured)}
|
||||
selectedSegmentationModelLimitation={selectedSegmentationModel?.limitation_message ?? null}
|
||||
onLoadModels={loadSegmentationModels}
|
||||
onSelectDataset={setSelectedSegmentationDatasetId}
|
||||
onSelectModel={setSelectedSegmentationModelId}
|
||||
onSetTileManifestPath={setSegmentationTileManifestPath}
|
||||
onSetConfidenceThreshold={setSegmentationConfidenceThreshold}
|
||||
onRunSegmentation={runSegmentation}
|
||||
onLoadRuns={() => loadSegmentationRuns()}
|
||||
onSelectRun={setSelectedSegmentationRunId}
|
||||
onSetClassFilter={setSegmentationClassFilter}
|
||||
onSetMinConfidenceFilter={setSegmentationMinConfidenceFilter}
|
||||
onLoadResults={() => loadSegmentationResults()}
|
||||
onSelectReferenceDataset={setSegmentationReferenceDatasetId}
|
||||
onRunQa={runSegmentationQa}
|
||||
/>
|
||||
<details className="secondary-analysis-disclosure segmentation-disclosure">
|
||||
<summary>
|
||||
<span>Segmentatie van beeldvlakken</span>
|
||||
<strong>Nog niet geconfigureerd</strong>
|
||||
</summary>
|
||||
<SegmentationLab
|
||||
segmentationModels={segmentationModels}
|
||||
loadingSegmentationModels={loadingSegmentationModels}
|
||||
segmentationModelError={segmentationModelError}
|
||||
selectedSegmentationDatasetId={selectedSegmentationDatasetId}
|
||||
selectedSegmentationModelId={selectedSegmentationModelId}
|
||||
segmentationTileManifestPath={segmentationTileManifestPath}
|
||||
segmentationConfidenceThreshold={segmentationConfidenceThreshold}
|
||||
runningSegmentation={runningSegmentation}
|
||||
segmentationRunResult={segmentationRunResult}
|
||||
segmentationRunError={segmentationRunError}
|
||||
segmentationRuns={segmentationRuns}
|
||||
selectedSegmentationRunId={selectedSegmentationRunId}
|
||||
segmentationItems={segmentationItems}
|
||||
segmentationClassFilter={segmentationClassFilter}
|
||||
segmentationMinConfidenceFilter={segmentationMinConfidenceFilter}
|
||||
loadingSegmentationResults={loadingSegmentationResults}
|
||||
segmentationReferenceDatasetId={segmentationReferenceDatasetId}
|
||||
segmentationQaResult={segmentationQaResult}
|
||||
segmentationQaError={segmentationQaError}
|
||||
runningSegmentationQa={runningSegmentationQa}
|
||||
selectedProjectId={selectedProjectId}
|
||||
rasterDatasets={rasterDatasets}
|
||||
referenceDatasets={referenceDatasets}
|
||||
selectedSegmentationModelConfigured={Boolean(selectedSegmentationModel?.configured)}
|
||||
selectedSegmentationModelLimitation={selectedSegmentationModel?.limitation_message ?? null}
|
||||
onLoadModels={loadSegmentationModels}
|
||||
onSelectDataset={setSelectedSegmentationDatasetId}
|
||||
onSelectModel={setSelectedSegmentationModelId}
|
||||
onSetTileManifestPath={setSegmentationTileManifestPath}
|
||||
onSetConfidenceThreshold={setSegmentationConfidenceThreshold}
|
||||
onRunSegmentation={runSegmentation}
|
||||
onLoadRuns={() => loadSegmentationRuns()}
|
||||
onSelectRun={setSelectedSegmentationRunId}
|
||||
onSetClassFilter={setSegmentationClassFilter}
|
||||
onSetMinConfidenceFilter={setSegmentationMinConfidenceFilter}
|
||||
onLoadResults={() => loadSegmentationResults()}
|
||||
onSelectReferenceDataset={setSegmentationReferenceDatasetId}
|
||||
onRunQa={runSegmentationQa}
|
||||
/>
|
||||
</details>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user