Harden raster pipeline readiness UI
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -2887,6 +2887,85 @@ button.entity-card {
|
||||
gap: 0.62rem;
|
||||
}
|
||||
|
||||
.raster-readiness-surface,
|
||||
.raster-guardrail-surface {
|
||||
display: grid;
|
||||
min-width: 0;
|
||||
gap: 0.65rem;
|
||||
border: 1px solid rgba(31, 92, 71, 0.18);
|
||||
border-radius: 8px;
|
||||
padding: 0.72rem;
|
||||
background: linear-gradient(180deg, #f8fbfa 0%, #ffffff 100%);
|
||||
}
|
||||
|
||||
.raster-readiness-surface .panel-title-row,
|
||||
.raster-guardrail-surface .panel-title-row {
|
||||
align-items: start;
|
||||
gap: 0.55rem;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.raster-readiness-surface h3,
|
||||
.raster-guardrail-surface h3 {
|
||||
margin: 0;
|
||||
font-size: 0.95rem;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.raster-readiness-surface p,
|
||||
.raster-guardrail-surface p {
|
||||
margin: 0;
|
||||
color: var(--muted);
|
||||
font-size: 0.82rem;
|
||||
line-height: 1.38;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.raster-readiness-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.raster-readiness-item,
|
||||
.raster-manifest-handoff {
|
||||
display: grid;
|
||||
min-width: 0;
|
||||
gap: 0.22rem;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
padding: 0.58rem;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.raster-readiness-item span,
|
||||
.raster-manifest-handoff span {
|
||||
color: var(--muted);
|
||||
font-size: 0.74rem;
|
||||
font-weight: 850;
|
||||
line-height: 1.2;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.raster-readiness-item strong,
|
||||
.raster-readiness-state {
|
||||
color: var(--text);
|
||||
font-size: 0.86rem;
|
||||
font-weight: 850;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.raster-guardrail-list {
|
||||
display: grid;
|
||||
gap: 0.4rem;
|
||||
margin: 0;
|
||||
padding-left: 1.05rem;
|
||||
color: var(--text);
|
||||
font-size: 0.84rem;
|
||||
line-height: 1.38;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.dataset-tool-group {
|
||||
display: grid;
|
||||
min-width: 0;
|
||||
|
||||
Reference in New Issue
Block a user