feat(ui): refine governed workbench and dual-screen flows

This commit is contained in:
Jens
2026-08-30 06:00:28 +02:00
parent 80a2d1654d
commit a0884d64c9
48 changed files with 1360 additions and 184 deletions
@@ -13,8 +13,11 @@ import {
analysisModelDisplayName,
toAnalysisModelOption,
} from '../models/modelOptions'
import { getDatasetSelectionLabel } from '../../lib/datasetDisplay'
interface SegmentationLabProps {
managementLocked?: boolean
blockedInferenceDatasetCount?: number
segmentationModels: SegmentationModelCapability[]
loadingSegmentationModels: boolean
segmentationModelError: string | null
@@ -92,6 +95,8 @@ function segmentationClassLabel(className: string): string {
}
export function SegmentationLab({
managementLocked = false,
blockedInferenceDatasetCount = 0,
segmentationModels,
loadingSegmentationModels,
segmentationModelError,
@@ -145,7 +150,7 @@ export function SegmentationLab({
? analysisModelAvailabilityMessage(selectedSegmentationModel)
: selectedSegmentationModelLimitation ?? 'Het gekozen segmentatiemodel is niet geconfigureerd'
const segmentationRunReady =
Boolean(selectedProjectId) && segmentationHasDataset && segmentationModelUiRunnable && segmentationHasTileManifest
Boolean(selectedProjectId) && segmentationHasDataset && segmentationModelUiRunnable
const segmentationJobActive = segmentationJob?.status === 'queued' || segmentationJob?.status === 'running'
const segmentationRunBlockedReason = !selectedProjectId
? 'Kies eerst een werkruimte'
@@ -155,9 +160,7 @@ export function SegmentationLab({
? 'Het fixturemodel is alleen bedoeld voor expliciete tests en demo’s'
: !selectedSegmentationModelConfigured
? selectedSegmentationModelAvailability
: !segmentationHasTileManifest
? 'Koppel eerst het beeldtegelmanifest van het gekozen rasterbestand'
: null
: null
return (
<section className="workspace-panel ai-lab-shell segmentation-lab-shell">
@@ -249,9 +252,9 @@ export function SegmentationLab({
: selectedSegmentationModelAvailability}
</strong>
</div>
<div className={segmentationHasTileManifest ? 'lab-readiness-item lab-readiness-item-ready' : 'lab-readiness-item'}>
<div className={segmentationHasDataset ? 'lab-readiness-item lab-readiness-item-ready' : 'lab-readiness-item'}>
<span>Beeldtegels</span>
<strong>{segmentationHasTileManifest ? 'Technisch manifest gekoppeld' : 'Koppel het tegelmanifest van het rasterbestand'}</strong>
<strong>{segmentationHasTileManifest ? 'Technisch manifest gekoppeld' : segmentationHasDataset ? 'Worden automatisch voorbereid' : 'Wachten op een rasterbestand'}</strong>
</div>
</div>
</div>
@@ -262,17 +265,28 @@ export function SegmentationLab({
{rasterDatasets.length === 0 ? (
<div className="result-state result-state-empty">
<strong>Geen rasterbestand beschikbaar voor segmentatie.</strong>
<p>Voeg eerst een rasterbestand toe onder Bronnen.</p>
{blockedInferenceDatasetCount > 0 ? (
<p>{blockedInferenceDatasetCount} rasterbestand(en) zijn vooraf uitgesloten door fixture-, quarantaine-, validatie- of provenancegegevens. De volledige servergate blijft beslissend.</p>
) : null}
<p>{managementLocked
? 'Ga naar Kaart en maak een begrensde officiële bronselectie. De synthetische demo-context blijft bewust uitgesloten van geconfigureerde modelinference.'
: 'Voeg eerst een gevalideerd rasterbestand toe onder Bronnen of haal via Kaart een begrensde officiële bron op.'}</p>
</div>
) : null}
<div className="lab-form-grid">
<label>
Rasterbestand
<select value={selectedSegmentationDatasetId} onChange={(event) => onSelectDataset(event.target.value)}>
<select
value={selectedSegmentationDatasetId}
onChange={(event) => {
onSelectDataset(event.target.value)
onSetTileManifestPath('')
}}
>
<option value="">Kies een rasterbestand</option>
{rasterDatasets.map((dataset) => (
<option key={dataset.id} value={dataset.id}>
{dataset.name}
{getDatasetSelectionLabel(dataset)}
</option>
))}
</select>
@@ -298,7 +312,7 @@ export function SegmentationLab({
/>
</label>
</div>
<details className="technical-inline-details">
{!managementLocked ? <details className="technical-inline-details">
<summary>Technische beeldtegelinstelling</summary>
<label>
Beeldtegelmanifest
@@ -309,7 +323,7 @@ export function SegmentationLab({
onChange={(event) => onSetTileManifestPath(event.target.value)}
/>
</label>
</details>
</details> : null}
<button
className="primary-action"
type="button"
@@ -319,7 +333,7 @@ export function SegmentationLab({
{segmentationJob?.status === 'queued'
? 'Wachten op NVIDIA GPU…'
: runningSegmentation
? 'GPU-segmentatie wordt verwerkt…'
? segmentationHasTileManifest ? 'GPU-segmentatie wordt verwerkt…' : 'Beeldtegels voorbereiden…'
: 'Segmentatie starten'}
</button>
</div>
@@ -480,7 +494,7 @@ export function SegmentationLab({
<option value="">Kies een referentielaag</option>
{referenceDatasets.map((dataset) => (
<option key={dataset.id} value={dataset.id}>
{dataset.name}
{getDatasetSelectionLabel(dataset)}
</option>
))}
</select>