Polish QA metric evidence cards
GeoIntel CI / docs-smoke (push) Has been cancelled
GeoIntel CI / contract-smoke (push) Has been cancelled

This commit is contained in:
Codex
2026-06-19 05:09:11 +02:00
parent 3c5853348e
commit 6446c78035
7 changed files with 191 additions and 3 deletions
@@ -1,5 +1,14 @@
import { useMemo } from 'react'
import type { DatasetCreateResponse, QualityCheckRead } from '../../types'
import type { DatasetCreateResponse, MetricRead, QualityCheckRead } from '../../types'
const CORE_METRIC_ORDER = [
'precision',
'recall',
'f1',
'mean_iou',
'false_positive_count',
'false_negative_count',
]
interface QualityResultsPanelProps {
selectedProjectId: string | null
@@ -10,6 +19,29 @@ interface QualityResultsPanelProps {
onRefresh: () => void
}
function qualityMetricLabel(metricKey: string): string {
const labels: Record<string, string> = {
precision: 'Precision',
recall: 'Recall',
f1: 'F1',
mean_iou: 'Mean IoU',
false_positive_count: 'False positives',
false_negative_count: 'False negatives',
}
return labels[metricKey] ?? metricKey.replaceAll('_', ' ')
}
function qualityMetricValue(metric: MetricRead | undefined): string {
if (!metric || metric.metric_value === null || metric.metric_value === undefined) {
return 'n/a'
}
const value = Number(metric.metric_value)
if (!Number.isFinite(value)) {
return String(metric.metric_value)
}
return Number.isInteger(value) ? String(value) : value.toFixed(3)
}
export function QualityResultsPanel({
selectedProjectId,
qualityChecks,
@@ -123,11 +155,27 @@ export function QualityResultsPanel({
<strong>{check.id}</strong>
</div>
</div>
<div className="quality-metric-section">
<span>Metric evidence</span>
<div className="quality-metric-grid">
{CORE_METRIC_ORDER.map((metricKey) => {
const metric = check.metrics.find((item) => item.metric_key === metricKey)
const isCriticalCount = metricKey === 'false_positive_count' || metricKey === 'false_negative_count'
return (
<div className={isCriticalCount ? 'quality-metric-card quality-metric-card-critical' : 'quality-metric-card'} key={metricKey}>
<span>{qualityMetricLabel(metricKey)}</span>
<strong>{qualityMetricValue(metric)}</strong>
</div>
)
})}
</div>
</div>
<span className="metric-list-label">Raw metrics</span>
<ul className="metric-list">
{check.metrics.map((metric) => (
<li key={metric.id}>
<span>{metric.metric_key}</span>
<strong>{metric.metric_value ?? 'n/a'}</strong>
<span>{qualityMetricLabel(metric.metric_key)}</span>
<strong>{qualityMetricValue(metric)}</strong>
</li>
))}
</ul>
+58
View File
@@ -1304,6 +1304,64 @@ button.entity-card {
white-space: nowrap;
}
.quality-metric-section {
margin-top: 0.75rem;
}
.metric-list-label,
.quality-metric-section > span {
display: block;
color: var(--muted);
font-size: 0.72rem;
font-weight: 800;
letter-spacing: 0.05em;
text-transform: uppercase;
}
.quality-metric-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(7.5rem, 1fr));
gap: 0.5rem;
margin-top: 0.45rem;
}
.quality-metric-card {
min-width: 0;
border: 1px solid rgba(15, 118, 110, 0.18);
border-radius: 8px;
padding: 0.58rem;
background: #f8fbf9;
}
.quality-metric-card-critical {
border-color: rgba(185, 28, 28, 0.18);
background: #fff7ed;
}
.quality-metric-card span {
display: block;
color: var(--muted);
font-size: 0.7rem;
font-weight: 800;
letter-spacing: 0.04em;
text-transform: uppercase;
}
.quality-metric-card strong {
display: block;
margin-top: 0.24rem;
overflow: hidden;
color: var(--ink);
font-size: 1.08rem;
line-height: 1.15;
text-overflow: ellipsis;
white-space: nowrap;
}
.metric-list-label {
margin-top: 0.82rem;
}
.metric-list {
grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
margin-top: 0.75rem;