Add guided operational GIS workflow
GeoIntel CI / docs-smoke (push) Has been cancelled
GeoIntel CI / contract-smoke (push) Has been cancelled

This commit is contained in:
Codex
2026-07-04 23:52:25 +02:00
parent 069de33080
commit 14b66e642b
7 changed files with 219 additions and 4 deletions
@@ -308,6 +308,7 @@ export function MapWorkspace({
)
const selectedFeatureFilename = selectedFeatureStem === 'selected-feature' ? DEFAULT_SELECTED_FEATURE_FILENAME : `${selectedFeatureStem}.geojson`
const selectedMapDataset = availableMapDatasets.find((dataset) => dataset.id === selectedMapDatasetId) ?? null
const usesDefaultOsmBasemap = !import.meta.env.VITE_MAP_STYLE_URL
useEffect(() => {
setBboxInput(bboxToInputState(mapSelectionBbox))
@@ -437,6 +438,12 @@ export function MapWorkspace({
</div>
<div className="map-control-surface" aria-label="Map workspace controls">
{usesDefaultOsmBasemap ? (
<div className="basemap-policy-notice" aria-label="Basemap usage notice">
<strong>Local/demo basemap</strong>
<span>Public OpenStreetMap tiles are active. Configure VITE_MAP_STYLE_URL for production or heavier use.</span>
</div>
) : null}
<div className="map-toolbar">
<label>
Database layer
@@ -664,6 +671,92 @@ export function MapWorkspace({
</button>
</div>
{mapSelectionError ? <p className="error">{mapSelectionError}</p> : null}
<div className="guided-gis-flow" aria-label="Guided operational GIS workflow">
<div className="guided-gis-steps">
<div className={selectedMapDataset ? 'complete' : ''}>
<span>1</span>
<strong>Layer</strong>
<small>{selectedMapDataset ? selectedMapDataset.name : 'Select database layer'}</small>
</div>
<div className={currentSelectionBbox ? 'complete' : ''}>
<span>2</span>
<strong>Extent</strong>
<small>{currentSelectionBbox ? 'AOI/layer bbox ready' : 'Use AOI or layer extent'}</small>
</div>
<div className={mapSelectionResult ? 'complete' : ''}>
<span>3</span>
<strong>Query</strong>
<small>{mapSelectionResult ? `${mapSelectionResult.feature_count} persisted features` : 'Run PostGIS selection'}</small>
</div>
<div className={latestSelectionDatasetName ? 'complete' : ''}>
<span>4</span>
<strong>Dataset</strong>
<small>{latestSelectionDatasetName ?? 'Save query result'}</small>
</div>
<div className={mapSelectionQaResult ? 'complete' : ''}>
<span>5</span>
<strong>QA/QC</strong>
<small>{mapSelectionQaResult ? `F1 ${mapSelectionQaResult.f1_score ?? 'n/a'}` : 'Compare with reference'}</small>
</div>
<div className={latestSelectionExportPath ? 'complete' : ''}>
<span>6</span>
<strong>Export</strong>
<small>{latestSelectionExportPath ? 'GeoJSON artifact ready' : 'Save handoff artifact'}</small>
</div>
</div>
<div className="guided-gis-actions">
<button
className="secondary-action"
disabled={!mapSelectionResult || !currentSelectionBbox || selectionDatasetSaving}
type="button"
onClick={saveAreaSelectionDataset}
>
{selectionDatasetSaving ? 'Saving dataset...' : 'Save result dataset'}
</button>
<button
className="secondary-action"
disabled={!mapSelectionResult || !currentSelectionBbox || selectionExporting}
type="button"
onClick={saveAreaSelectionExport}
>
{selectionExporting ? 'Saving export...' : 'Save GeoJSON export'}
</button>
<label>
Reference
<select
value={selectedMapQaReferenceDatasetId}
onChange={(event) => onSelectMapQaReferenceDataset(event.target.value)}
disabled={!latestSelectionDatasetName || mapQaReferenceDatasets.length === 0 || mapSelectionQaRunning}
>
<option value="">Select reference</option>
{mapQaReferenceDatasets.map((dataset) => (
<option key={dataset.id} value={dataset.id}>
{dataset.name}
</option>
))}
</select>
</label>
<button
className="primary-action"
disabled={!latestSelectionDatasetName || !selectedMapQaReferenceDatasetId || mapSelectionQaRunning}
type="button"
onClick={onRunMapSelectionQa}
>
{mapSelectionQaRunning ? 'Running QA...' : 'Run QA/QC'}
</button>
<button
className="secondary-action"
disabled={!latestMapSelectionQualityCheckId}
type="button"
onClick={onOpenMapSelectionQualityEvidence}
>
Open evidence
</button>
</div>
{selectionDatasetError ? <p className="error">{selectionDatasetError}</p> : null}
{selectionExportError ? <p className="error">{selectionExportError}</p> : null}
{mapSelectionQaError ? <p className="error">{mapSelectionQaError}</p> : null}
</div>
</div>
<div className="bbox-select-surface" aria-label="Area selection and extract">
<div className="panel-title-row">