Finish audit UI and live validation closure
This commit is contained in:
@@ -25,8 +25,29 @@ function detectionQualityInterpretation(f1: number | null | undefined): string {
|
||||
return 'Onvoldoende betrouwbaar voor operationeel gebruik.'
|
||||
}
|
||||
|
||||
function detectionStatusLabel(status: string): string {
|
||||
if (status === 'completed') return 'afgerond'
|
||||
if (status === 'success') return 'geslaagd'
|
||||
if (status === 'failed') return 'mislukt'
|
||||
if (status === 'running') return 'bezig'
|
||||
if (status === 'queued') return 'in wachtrij'
|
||||
return status.replace(/_/g, ' ')
|
||||
}
|
||||
|
||||
function persistedDetectionModelLabel(modelName: string | null | undefined): string {
|
||||
if (!modelName) return 'Gebouwdetectie'
|
||||
if (modelName === 'yolo-configured') return 'Lokaal gebouwmodel'
|
||||
if (modelName === 'manual-fixture-detector') return 'Testmodel'
|
||||
if (modelName === 'yolo-placeholder') return 'Niet-geconfigureerd gebouwmodel'
|
||||
return modelName
|
||||
}
|
||||
|
||||
function detectionClassLabel(className: string): string {
|
||||
if (className.toLowerCase() === 'building') return 'Gebouw'
|
||||
return className
|
||||
}
|
||||
|
||||
function formatDetectionRunLabel(run: DetectionRunRead): string {
|
||||
const status = run.status === 'completed' ? 'afgerond' : run.status
|
||||
const timestamp = run.finished_at ?? run.created_at
|
||||
const dateLabel = timestamp
|
||||
? new Intl.DateTimeFormat('nl-BE', {
|
||||
@@ -34,7 +55,7 @@ function formatDetectionRunLabel(run: DetectionRunRead): string {
|
||||
timeStyle: 'short',
|
||||
}).format(new Date(timestamp))
|
||||
: 'datum onbekend'
|
||||
return `${run.model_name || 'Gebouwdetectie'} · ${status} · ${dateLabel}`
|
||||
return `${persistedDetectionModelLabel(run.model_name)} · ${detectionStatusLabel(run.status)} · ${dateLabel}`
|
||||
}
|
||||
|
||||
interface CalibrationRow {
|
||||
@@ -753,18 +774,16 @@ export function DetectionLab({
|
||||
<th>Type</th>
|
||||
<th>Zekerheid</th>
|
||||
<th>Model</th>
|
||||
<th>Beeldtegel</th>
|
||||
<th>Herkomst</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{visibleDetectionItems.map((detection) => (
|
||||
<tr key={detection.id}>
|
||||
<td>{detection.class_name}</td>
|
||||
<td>{detectionClassLabel(detection.class_name)}</td>
|
||||
<td>{detection.confidence.toFixed(2)}</td>
|
||||
<td>{detection.model_name}</td>
|
||||
<td className="source-tile-cell" title={detection.source_tile_path ?? undefined}>
|
||||
{formatSourceTilePath(detection.source_tile_path)}
|
||||
</td>
|
||||
<td>{persistedDetectionModelLabel(detection.model_name)}</td>
|
||||
<td className="source-tile-cell">Luchtbeeldtegel</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
@@ -1119,11 +1138,3 @@ function downloadJsonFile(filename: string, payload: unknown): void {
|
||||
function formatNullableNumber(value: number | null, digits: number): string {
|
||||
return typeof value === 'number' && Number.isFinite(value) ? value.toFixed(digits) : 'n.v.t.'
|
||||
}
|
||||
|
||||
function formatSourceTilePath(path: string | null | undefined): string {
|
||||
if (!path) {
|
||||
return 'n.v.t.'
|
||||
}
|
||||
const parts = path.replace(/\\/g, '/').split('/').filter(Boolean)
|
||||
return parts[parts.length - 1] ?? path
|
||||
}
|
||||
|
||||
@@ -53,8 +53,29 @@ function segmentationRunLabel(run: SegmentationRunRead): string {
|
||||
const dateLabel = timestamp
|
||||
? new Intl.DateTimeFormat('nl-BE', { dateStyle: 'short', timeStyle: 'short' }).format(new Date(timestamp))
|
||||
: 'datum onbekend'
|
||||
const status = run.status === 'completed' ? 'afgerond' : run.status
|
||||
return `${run.model_name || 'Segmentatie'} · ${status} · ${dateLabel}`
|
||||
return `${persistedSegmentationModelLabel(run.model_name)} · ${analysisStatusLabel(run.status)} · ${dateLabel}`
|
||||
}
|
||||
|
||||
function analysisStatusLabel(status: string): string {
|
||||
if (status === 'completed') return 'afgerond'
|
||||
if (status === 'success') return 'geslaagd'
|
||||
if (status === 'failed') return 'mislukt'
|
||||
if (status === 'running') return 'bezig'
|
||||
if (status === 'queued') return 'in wachtrij'
|
||||
return status.replace(/_/g, ' ')
|
||||
}
|
||||
|
||||
function persistedSegmentationModelLabel(modelName: string | null | undefined): string {
|
||||
if (!modelName) return 'Segmentatie'
|
||||
if (modelName === 'fixture-segmenter') return 'Testsegmentatie'
|
||||
if (modelName === 'sam-placeholder') return 'SAM-model niet geconfigureerd'
|
||||
if (modelName === 'yolo-seg-placeholder') return 'YOLO-segmentatie niet geconfigureerd'
|
||||
return modelName
|
||||
}
|
||||
|
||||
function segmentationClassLabel(className: string): string {
|
||||
if (className.toLowerCase() === 'building') return 'Gebouw'
|
||||
return className
|
||||
}
|
||||
|
||||
export function SegmentationLab({
|
||||
@@ -371,17 +392,17 @@ export function SegmentationLab({
|
||||
<th>Zekerheid</th>
|
||||
<th>Oppervlakte m²</th>
|
||||
<th>Model</th>
|
||||
<th>Brontegel</th>
|
||||
<th>Herkomst</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{segmentationItems.map((segmentation) => (
|
||||
<tr key={segmentation.id}>
|
||||
<td>{segmentation.class_name}</td>
|
||||
<td>{segmentationClassLabel(segmentation.class_name)}</td>
|
||||
<td>{segmentation.confidence?.toFixed(2) ?? 'n.v.t.'}</td>
|
||||
<td>{segmentation.area_m2?.toFixed(2) ?? 'n.v.t.'}</td>
|
||||
<td>{segmentation.model_name}</td>
|
||||
<td>{segmentation.tile_index ?? 'n.v.t.'}</td>
|
||||
<td>{persistedSegmentationModelLabel(segmentation.model_name)}</td>
|
||||
<td>{segmentation.tile_index == null ? 'n.v.t.' : 'Luchtbeeldtegel'}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
|
||||
Reference in New Issue
Block a user