Polish workbench visual shell
GeoIntel CI / docs-smoke (push) Has been cancelled
GeoIntel CI / contract-smoke (push) Has been cancelled

This commit is contained in:
Codex
2026-06-18 23:24:08 +02:00
parent c85953f389
commit 6fa41e11e4
11 changed files with 317 additions and 70 deletions
@@ -70,7 +70,7 @@ export function DatasetPanel({
const readyDatasets = datasets.filter((dataset) => dataset.status === 'ready').length
return (
<section data-testid="dataset-panel">
<section className="workspace-panel" data-testid="dataset-panel">
<div className="panel-title-row">
<div>
<p className="eyebrow">Data catalog</p>
@@ -127,7 +127,12 @@ export function DatasetPanel({
</form>
{loadingDatasets ? <p>Loading datasets...</p> : null}
{datasets.length === 0 ? <p>No datasets yet</p> : null}
{datasets.length === 0 ? (
<div className="empty-state">
<strong>No datasets yet</strong>
<p>Upload vector, GeoJSON or raster data after selecting a project.</p>
</div>
) : null}
<ul className="dataset-list">
{datasets.map((dataset) => (
<li className={dataset.id === selectedDatasetId ? 'dataset-card dataset-card-active' : 'dataset-card'} key={dataset.id}>
@@ -144,7 +149,7 @@ export function DatasetPanel({
{dataset.status === 'ready' ? 'ready' : dataset.status === 'failed' ? 'failed' : 'pending'}
</span>
</div>
<div className="dataset-metrics">
<div className="dataset-metrics data-density-grid">
<span>size: {formatBytes(dataset.size_bytes)}</span>
<span>features: {dataset.feature_count ?? dataset.vector_summary?.feature_count ?? 'n/a'}</span>
<span>bbox: {formatBounds(dataset.bounds_json ?? dataset.vector_summary?.bounds_json)}</span>
@@ -85,7 +85,7 @@ export function DetectionLab({
onRunQa,
}: DetectionLabProps): JSX.Element {
return (
<section>
<section className="workspace-panel">
<div className="panel-title-row">
<div>
<p className="eyebrow">Object detection</p>
@@ -166,7 +166,7 @@ export function DetectionLab({
</div>
{detectionRunError ? <p className="error">{detectionRunError}</p> : null}
{detectionRunResult ? (
<div>
<div className="result-summary-card">
<p>Status: {detectionRunResult.status}</p>
<p>Message: {detectionRunResult.message}</p>
<p>Analysis run: {detectionRunResult.analysis_run_id}</p>
@@ -221,26 +221,28 @@ export function DetectionLab({
{loadingDetectionResults ? <p>Loading detection results...</p> : null}
<p>Detections loaded: {detectionItems.length}</p>
{detectionItems.length > 0 ? (
<table>
<thead>
<tr>
<th>Class</th>
<th>Confidence</th>
<th>Model</th>
<th>Source tile</th>
</tr>
</thead>
<tbody>
{detectionItems.map((detection) => (
<tr key={detection.id}>
<td>{detection.class_name}</td>
<td>{detection.confidence.toFixed(2)}</td>
<td>{detection.model_name}</td>
<td>{detection.source_tile_path || 'n/a'}</td>
<div className="table-scroll">
<table>
<thead>
<tr>
<th>Class</th>
<th>Confidence</th>
<th>Model</th>
<th>Source tile</th>
</tr>
))}
</tbody>
</table>
</thead>
<tbody>
{detectionItems.map((detection) => (
<tr key={detection.id}>
<td>{detection.class_name}</td>
<td>{detection.confidence.toFixed(2)}</td>
<td>{detection.model_name}</td>
<td>{detection.source_tile_path || 'n/a'}</td>
</tr>
))}
</tbody>
</table>
</div>
) : null}
</div>
<div className="lab-block">
@@ -261,7 +263,7 @@ export function DetectionLab({
</button>
{detectionQaError ? <p className="error">{detectionQaError}</p> : null}
{detectionQaResult ? (
<div>
<div className="result-summary-card">
<p>Status: {detectionQaResult.status}</p>
<p>Quality check: {detectionQaResult.quality_check_id}</p>
<p>Precision: {detectionQaResult.precision?.toFixed(3) ?? 'n/a'}</p>
@@ -27,7 +27,7 @@ export function ProjectPanel({
onLoadDemoWorkflow,
}: ProjectPanelProps): JSX.Element {
return (
<section data-testid="project-panel">
<section className="workspace-panel" data-testid="project-panel">
<div className="panel-title-row">
<div>
<p className="eyebrow">Context</p>
@@ -89,7 +89,12 @@ export function ProjectPanel({
</button>
</li>
))}
{projects.length === 0 ? <li>No projects yet</li> : null}
{projects.length === 0 ? (
<li className="empty-state">
<strong>No projects yet</strong>
<p>Create a project or load the offline demo workflow to populate the workbench.</p>
</li>
) : null}
</ul>
</section>
)
@@ -85,7 +85,7 @@ export function SegmentationLab({
onRunQa,
}: SegmentationLabProps): JSX.Element {
return (
<section>
<section className="workspace-panel">
<div className="panel-title-row">
<div>
<p className="eyebrow">Polygon segmentation</p>
@@ -163,7 +163,7 @@ export function SegmentationLab({
) : null}
{segmentationRunError ? <p className="error">{segmentationRunError}</p> : null}
{segmentationRunResult ? (
<div>
<div className="result-summary-card">
<p>Status: {segmentationRunResult.status}</p>
<p>Message: {segmentationRunResult.message}</p>
<p>Analysis run: {segmentationRunResult.analysis_run_id}</p>
@@ -218,30 +218,32 @@ export function SegmentationLab({
{loadingSegmentationResults ? <p>Loading segmentation results...</p> : null}
<p>Segmentations loaded: {segmentationItems.length}</p>
{segmentationItems.length > 0 ? (
<table>
<thead>
<tr>
<th>Class</th>
<th>Confidence</th>
<th>Area m2</th>
<th>Model</th>
<th>Tile</th>
<th>Mask path</th>
</tr>
</thead>
<tbody>
{segmentationItems.map((segmentation) => (
<tr key={segmentation.id}>
<td>{segmentation.class_name}</td>
<td>{segmentation.confidence?.toFixed(2) ?? 'n/a'}</td>
<td>{segmentation.area_m2?.toFixed(2) ?? 'n/a'}</td>
<td>{segmentation.model_name}</td>
<td>{segmentation.source_tile_path || (segmentation.tile_index ?? 'n/a')}</td>
<td>{segmentation.mask_path || 'n/a'}</td>
<div className="table-scroll">
<table>
<thead>
<tr>
<th>Class</th>
<th>Confidence</th>
<th>Area m2</th>
<th>Model</th>
<th>Tile</th>
<th>Mask path</th>
</tr>
))}
</tbody>
</table>
</thead>
<tbody>
{segmentationItems.map((segmentation) => (
<tr key={segmentation.id}>
<td>{segmentation.class_name}</td>
<td>{segmentation.confidence?.toFixed(2) ?? 'n/a'}</td>
<td>{segmentation.area_m2?.toFixed(2) ?? 'n/a'}</td>
<td>{segmentation.model_name}</td>
<td>{segmentation.source_tile_path || (segmentation.tile_index ?? 'n/a')}</td>
<td>{segmentation.mask_path || 'n/a'}</td>
</tr>
))}
</tbody>
</table>
</div>
) : null}
</div>
<div className="lab-block">
@@ -262,7 +264,7 @@ export function SegmentationLab({
</button>
{segmentationQaError ? <p className="error">{segmentationQaError}</p> : null}
{segmentationQaResult ? (
<div>
<div className="result-summary-card">
<p>Status: {segmentationQaResult.status}</p>
<p>Quality check: {segmentationQaResult.quality_check_id}</p>
<p>Precision: {segmentationQaResult.precision?.toFixed(3) ?? 'n/a'}</p>