Harden raster pipeline readiness UI
GeoIntel CI / docs-smoke (push) Has been cancelled
GeoIntel CI / contract-smoke (push) Has been cancelled

This commit is contained in:
Codex
2026-06-22 03:17:41 +02:00
parent 58fa07f430
commit 330b67766d
7 changed files with 257 additions and 10 deletions
@@ -93,18 +93,106 @@ export function RasterControls({
onRunRasterNdwi,
onRunRasterNdbi,
}: RasterControlsProps) {
const previewState = rasterPreview ? 'ready' : 'not generated'
const rasterReadinessItems = [
{
label: 'Metadata profile',
state: selectedRasterMetadata ? 'ready' : 'inspect needed',
detail: selectedRasterMetadata
? `${selectedRasterMetadata.driver} | ${selectedRasterMetadata.width} x ${selectedRasterMetadata.height} | ${selectedRasterMetadata.band_count} bands`
: 'Run metadata inspection before derived raster operations.',
},
{
label: 'CRS readiness',
state: selectedRasterMetadata?.crs ? 'ready' : 'missing',
detail: selectedRasterMetadata?.crs ?? 'Raster CRS is required for safe map handoff and clipping.',
},
{
label: 'Preview artifact',
state: previewState,
detail: rasterPreview
? `${rasterPreview.preview.path} (${rasterPreview.preview.width ?? 'n/a'} x ${rasterPreview.preview.height ?? 'n/a'})`
: 'Generate a preview to confirm visual orientation before AI runs.',
},
{
label: 'Tile manifest handoff',
state: isRasterTileInputValid ? 'input valid' : 'input blocked',
detail: isRasterTileInputValid
? 'Tile generation will create the manifest path used by detection and segmentation requests.'
: 'Tile size must be positive and overlap must stay below tile size.',
},
{
label: 'Clip AOI',
state: areas.length > 0 ? 'available' : 'missing',
detail: areas.length > 0 ? `${areas.length} project area${areas.length === 1 ? '' : 's'} available.` : 'Create an area before clipping.',
},
]
const rasterGuardrailItems = [
!selectedDatasetId ? 'Select a raster dataset before running raster operations.' : null,
rasterUnavailableMessage ? `Raster unavailable: ${rasterUnavailableMessage}` : null,
selectedDatasetId && !selectedRasterMetadata ? 'Inspect metadata before reprojecting, clipping, tiling or computing indices.' : null,
selectedRasterMetadata && !selectedRasterMetadata?.crs ? 'CRS is missing; geospatial handoff should be fixed before downstream QA.' : null,
!rasterPreview ? 'Preview is not generated yet; create it before visual review.' : null,
!isRasterTileInputValid ? 'Tile settings are invalid; update tile size and overlap before generating a manifest.' : null,
areas.length === 0 ? 'No project area exists yet, so raster clipping is disabled.' : null,
].filter((item): item is string => Boolean(item))
return (
<div className="dataset-tool-panel raster-tool-panel">
<p>Raster driver: {selectedRasterMetadata?.driver ?? 'n/a'}</p>
<p>Raster size: {selectedRasterMetadata ? `${selectedRasterMetadata.width} x ${selectedRasterMetadata.height}` : 'n/a'}</p>
<p>Raster checksum: {selectedRasterMetadata?.checksum_sha256 ?? 'n/a'}</p>
<p>
Profile: CRS {selectedRasterMetadata?.crs ?? 'n/a'} | bands {selectedRasterMetadata?.band_count ?? 'n/a'} | dtype {
(selectedRasterMetadata?.dtype as string[] | undefined)?.join(', ') ?? 'n/a'}
</p>
<p>Bounds: {formatRasterBounds(selectedRasterMetadata?.bounds)}</p>
<p>Resolution: {selectedRasterMetadata?.resolution ? selectedRasterMetadata.resolution.join(', ') : 'n/a'}</p>
{rasterUnavailableMessage ? <p className="error">Raster unavailable: {rasterUnavailableMessage}</p> : null}
<section className="raster-readiness-surface" aria-label="Raster pipeline readiness">
<div className="panel-title-row">
<div>
<h3>Raster pipeline readiness</h3>
<p>Operational state for metadata, preview, clipping and tile-manifest handoff.</p>
</div>
</div>
<div className="raster-readiness-grid">
{rasterReadinessItems.map((item) => (
<div className="raster-readiness-item" key={item.label}>
<span>{item.label}</span>
<strong>{item.state}</strong>
<p>{item.detail}</p>
</div>
))}
</div>
<div className="raster-manifest-handoff">
<span>Tile manifest handoff</span>
<p>
Generated tile manifests remain backend artifacts and are referenced by path in detection/segmentation requests; this panel only prepares
and explains the handoff.
</p>
</div>
</section>
<section className="raster-guardrail-surface" aria-label="Processing guardrails">
<div className="panel-title-row">
<div>
<h3>Processing guardrails</h3>
<p>Checks that protect downstream GIS and AI operations from ambiguous raster state.</p>
</div>
</div>
{rasterGuardrailItems.length > 0 ? (
<ul className="raster-guardrail-list">
{rasterGuardrailItems.map((item) => (
<li key={item}>{item}</li>
))}
</ul>
) : (
<p className="raster-readiness-state">Raster controls are ready for safe operation.</p>
)}
</section>
<div className="dataset-tool-group">
<h4 className="dataset-tool-heading">Raster metadata</h4>
<p>Raster driver: {selectedRasterMetadata?.driver ?? 'n/a'}</p>
<p>Raster size: {selectedRasterMetadata ? `${selectedRasterMetadata.width} x ${selectedRasterMetadata.height}` : 'n/a'}</p>
<p>Raster checksum: {selectedRasterMetadata?.checksum_sha256 ?? 'n/a'}</p>
<p>
Profile: CRS {selectedRasterMetadata?.crs ?? 'n/a'} | bands {selectedRasterMetadata?.band_count ?? 'n/a'} | dtype {
(selectedRasterMetadata?.dtype as string[] | undefined)?.join(', ') ?? 'n/a'}
</p>
<p>Bounds: {formatRasterBounds(selectedRasterMetadata?.bounds)}</p>
<p>Resolution: {selectedRasterMetadata?.resolution ? selectedRasterMetadata.resolution.join(', ') : 'n/a'}</p>
{rasterUnavailableMessage ? <p className="error">Raster unavailable: {rasterUnavailableMessage}</p> : null}
</div>
<h3>Raster operations</h3>
<p>Available operations: inspect, stats, reproject, preview, clip by selected area, tile generation.</p>
<p>Preview: {rasterPreview?.preview.path ?? 'not generated'}</p>