Polish workbench result states
GeoIntel CI / docs-smoke (push) Has been cancelled
GeoIntel CI / contract-smoke (push) Has been cancelled

This commit is contained in:
Codex
2026-06-20 03:10:45 +02:00
parent 8459b8bbd5
commit b3d1a1a5ee
10 changed files with 239 additions and 23 deletions
@@ -95,9 +95,24 @@ export function DetectionLab({
Refresh models
</button>
</div>
{loadingDetectionModels ? <p>Loading detection models...</p> : null}
{detectionModelError ? <p className="error">{detectionModelError}</p> : null}
{detectionModels.length === 0 && !loadingDetectionModels ? <p>No detection models reported by backend</p> : null}
{loadingDetectionModels ? (
<div className="result-state result-state-loading">
<strong>Loading detection models.</strong>
<p>Checking backend model registry availability.</p>
</div>
) : null}
{detectionModelError ? (
<div className="result-state result-state-error">
<strong>Detection model registry unavailable.</strong>
<p>{detectionModelError}</p>
</div>
) : null}
{detectionModels.length === 0 && !loadingDetectionModels ? (
<div className="result-state result-state-empty">
<strong>No detection models reported by backend.</strong>
<p>Refresh models after the backend is reachable.</p>
</div>
) : null}
<ul className="model-list">
{detectionModels.map((model) => (
<li className={model.configured ? 'model-card model-card-ready' : 'model-card'} key={model.model_id}>
@@ -164,7 +179,12 @@ export function DetectionLab({
Run detection
</button>
</div>
{detectionRunError ? <p className="error">{detectionRunError}</p> : null}
{detectionRunError ? (
<div className="result-state result-state-error">
<strong>Detection run failed.</strong>
<p>{detectionRunError}</p>
</div>
) : null}
{detectionRunResult ? (
<div className="result-summary-card">
<p>Status: {detectionRunResult.status}</p>
@@ -218,8 +238,16 @@ export function DetectionLab({
<button className="primary-action" type="button" onClick={onLoadResults} disabled={!selectedDetectionRunId || loadingDetectionResults}>
Load detections
</button>
{loadingDetectionResults ? <p>Loading detection results...</p> : null}
<p>Detections loaded: {detectionItems.length}</p>
{loadingDetectionResults ? (
<div className="result-state result-state-loading">
<strong>Loading detection results.</strong>
<p>Retrieving persisted detections for the selected run.</p>
</div>
) : null}
<div className="result-state result-state-ready">
<strong>Detections loaded: {detectionItems.length}</strong>
<p>{selectedDetectionRunId ? 'Loaded from persisted detection records.' : 'Select a detection run before loading results.'}</p>
</div>
{detectionItems.length > 0 ? (
<div className="table-scroll">
<table>
@@ -261,7 +289,12 @@ export function DetectionLab({
<button className="primary-action" type="button" onClick={onRunQa} disabled={runningDetectionQa || !selectedDetectionRunId || !detectionReferenceDatasetId}>
Compare detections to reference
</button>
{detectionQaError ? <p className="error">{detectionQaError}</p> : null}
{detectionQaError ? (
<div className="result-state result-state-error">
<strong>Detection QA failed.</strong>
<p>{detectionQaError}</p>
</div>
) : null}
{detectionQaResult ? (
<div className="result-summary-card">
<p>Status: {detectionQaResult.status}</p>
@@ -217,7 +217,18 @@ export function ExportCenter({
</div>
</div>
</div>
{exportError ? <p className="error">{exportError}</p> : null}
{loadingExports ? (
<div className="result-state result-state-loading">
<strong>Loading export registry.</strong>
<p>Retrieving persisted artifacts for the selected project.</p>
</div>
) : null}
{exportError ? (
<div className="result-state result-state-error">
<strong>Export action failed.</strong>
<p>{exportError}</p>
</div>
) : null}
{latestExport ? (
<div className="latest-export-card">
<span>Latest export</span>
@@ -226,7 +237,7 @@ export function ExportCenter({
</div>
) : null}
{exports.length === 0 ? (
<div className="empty-state">
<div className="result-state result-state-empty">
<strong>No exports registered yet.</strong>
<p>Create metadata, GeoJSON or HTML report artifacts once the active project has data to hand off.</p>
</div>
@@ -291,7 +302,7 @@ export function ExportCenter({
</div>
) : null}
{exports.length > 0 && filteredExports.length === 0 ? (
<div className="empty-state">
<div className="result-state result-state-empty">
<strong>No exports match the current filters.</strong>
<p>Clear the search, type or status filter to return to the latest artifacts.</p>
</div>
@@ -157,9 +157,14 @@ export function QualityResultsPanel({
Refresh QA/QC results
</button>
</div>
{qualityChecksError ? <p className="error">{qualityChecksError}</p> : null}
{qualityChecksError ? (
<div className="result-state result-state-error">
<strong>QA/QC results could not be loaded.</strong>
<p>{qualityChecksError}</p>
</div>
) : null}
{qualityChecks.length === 0 ? (
<div className="empty-state">
<div className="result-state result-state-empty">
<strong>No persisted QA/QC results yet</strong>
<p>Run dataset, detection or segmentation QA against a reference layer to populate this workspace.</p>
</div>
@@ -224,7 +229,7 @@ export function QualityResultsPanel({
</div>
) : null}
{qualityChecks.length > 0 && filteredQualityChecks.length === 0 ? (
<div className="empty-state">
<div className="result-state result-state-empty">
<strong>No QA/QC results match the current filters.</strong>
<p>Clear the search, status or check type filter to return to the latest quality results.</p>
</div>
@@ -95,9 +95,24 @@ export function SegmentationLab({
Refresh models
</button>
</div>
{loadingSegmentationModels ? <p>Loading segmentation models...</p> : null}
{segmentationModelError ? <p className="error">{segmentationModelError}</p> : null}
{segmentationModels.length === 0 && !loadingSegmentationModels ? <p>No segmentation models reported by backend</p> : null}
{loadingSegmentationModels ? (
<div className="result-state result-state-loading">
<strong>Loading segmentation models.</strong>
<p>Checking backend model registry availability.</p>
</div>
) : null}
{segmentationModelError ? (
<div className="result-state result-state-error">
<strong>Segmentation model registry unavailable.</strong>
<p>{segmentationModelError}</p>
</div>
) : null}
{segmentationModels.length === 0 && !loadingSegmentationModels ? (
<div className="result-state result-state-empty">
<strong>No segmentation models reported by backend.</strong>
<p>Refresh models after the backend is reachable.</p>
</div>
) : null}
<ul className="model-list">
{segmentationModels.map((model) => (
<li className={model.configured ? 'model-card model-card-ready' : 'model-card'} key={model.model_id}>
@@ -159,9 +174,17 @@ export function SegmentationLab({
</button>
</div>
{!selectedSegmentationModelConfigured ? (
<p>{selectedSegmentationModelLimitation ?? 'Select a configured segmentation model'}</p>
<div className="result-state result-state-empty">
<strong>Segmentation model is not ready.</strong>
<p>{selectedSegmentationModelLimitation ?? 'Select a configured segmentation model'}</p>
</div>
) : null}
{segmentationRunError ? (
<div className="result-state result-state-error">
<strong>Segmentation run failed.</strong>
<p>{segmentationRunError}</p>
</div>
) : null}
{segmentationRunError ? <p className="error">{segmentationRunError}</p> : null}
{segmentationRunResult ? (
<div className="result-summary-card">
<p>Status: {segmentationRunResult.status}</p>
@@ -215,8 +238,16 @@ export function SegmentationLab({
<button className="primary-action" type="button" onClick={onLoadResults} disabled={!selectedSegmentationRunId || loadingSegmentationResults}>
Load segmentations
</button>
{loadingSegmentationResults ? <p>Loading segmentation results...</p> : null}
<p>Segmentations loaded: {segmentationItems.length}</p>
{loadingSegmentationResults ? (
<div className="result-state result-state-loading">
<strong>Loading segmentation results.</strong>
<p>Retrieving persisted segmentation polygons for the selected run.</p>
</div>
) : null}
<div className="result-state result-state-ready">
<strong>Segmentations loaded: {segmentationItems.length}</strong>
<p>{selectedSegmentationRunId ? 'Loaded from persisted segmentation records.' : 'Select a segmentation run before loading results.'}</p>
</div>
{segmentationItems.length > 0 ? (
<div className="table-scroll">
<table>
@@ -262,7 +293,12 @@ export function SegmentationLab({
<button className="primary-action" type="button" onClick={onRunQa} disabled={runningSegmentationQa || !selectedSegmentationRunId || !segmentationReferenceDatasetId}>
Compare segmentations to reference
</button>
{segmentationQaError ? <p className="error">{segmentationQaError}</p> : null}
{segmentationQaError ? (
<div className="result-state result-state-error">
<strong>Segmentation QA failed.</strong>
<p>{segmentationQaError}</p>
</div>
) : null}
{segmentationQaResult ? (
<div className="result-summary-card">
<p>Status: {segmentationQaResult.status}</p>
+48 -2
View File
@@ -1070,7 +1070,8 @@ section th {
.quality-check-card,
.export-card,
.latest-export-card,
.empty-state {
.empty-state,
.result-state {
border: 1px solid var(--line);
border-radius: 8px;
background: var(--panel-soft);
@@ -1114,11 +1115,56 @@ button.entity-card {
.quality-check-card,
.export-card,
.latest-export-card,
.empty-state {
.empty-state,
.result-state {
min-width: 0;
padding: 0.85rem;
}
.result-state {
display: grid;
gap: 0.18rem;
background: #ffffff;
overflow-wrap: anywhere;
}
.result-state strong {
font-size: 0.92rem;
line-height: 1.25;
}
.result-state p {
margin: 0;
color: var(--muted);
font-size: 0.84rem;
line-height: 1.38;
}
.result-state-error {
border-color: rgba(153, 27, 27, 0.25);
background: rgba(153, 27, 27, 0.07);
}
.result-state-error strong,
.result-state-error p {
color: var(--danger);
}
.result-state-empty {
border-style: dashed;
background: var(--panel-soft);
}
.result-state-loading {
border-color: rgba(180, 83, 9, 0.24);
background: rgba(180, 83, 9, 0.08);
}
.result-state-ready {
border-color: rgba(15, 118, 110, 0.28);
background: var(--accent-soft);
}
.dataset-card,
.model-card,
.quality-check-card,