Harden detection result review
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import type {
|
||||
DatasetCreateResponse,
|
||||
DetectionModelCapability,
|
||||
@@ -12,6 +13,9 @@ import type {
|
||||
import type { DetectionCalibrationRunRow } from '../../hooks/useDetectionWorkflow'
|
||||
import { DETECTION_OPERATOR_PROFILES, type DetectionOperatorProfile } from './detectionProfiles'
|
||||
|
||||
const DETECTION_PAGE_SIZE_OPTIONS = [25, 50, 100] as const
|
||||
const DEFAULT_DETECTION_PAGE_SIZE = 50
|
||||
|
||||
interface CalibrationRow {
|
||||
analysisRunId: string
|
||||
qualityCheckId: string
|
||||
@@ -152,6 +156,18 @@ export function DetectionLab({
|
||||
const bestF1Candidate = bestCalibrationRow(calibrationRows, 'f1')
|
||||
const bestPrecisionCandidate = bestCalibrationRow(calibrationRows, 'precision')
|
||||
const lowestFalsePositivePressureCandidate = bestLowestCalibrationRow(calibrationRows, 'falsePositives')
|
||||
const [detectionResultPage, setDetectionResultPage] = useState(1)
|
||||
const [detectionPageSize, setDetectionPageSize] = useState(DEFAULT_DETECTION_PAGE_SIZE)
|
||||
const detectionPageCount = Math.max(1, Math.ceil(detectionItems.length / detectionPageSize))
|
||||
const currentDetectionPage = Math.min(detectionResultPage, detectionPageCount)
|
||||
const detectionPageStart = (currentDetectionPage - 1) * detectionPageSize
|
||||
const detectionPageEnd = Math.min(detectionPageStart + detectionPageSize, detectionItems.length)
|
||||
const visibleDetectionItems = detectionItems.slice(detectionPageStart, detectionPageEnd)
|
||||
|
||||
useEffect(() => {
|
||||
setDetectionResultPage(1)
|
||||
}, [selectedDetectionRunId, detectionClassFilter, detectionMinConfidenceFilter, detectionItems])
|
||||
|
||||
const detectionHasTileManifest =
|
||||
!detectionRequiresTileManifest || detectionTileManifestPath.trim().length > 0
|
||||
const detectionRunReady =
|
||||
@@ -744,28 +760,73 @@ export function DetectionLab({
|
||||
</div>
|
||||
</div>
|
||||
{detectionItems.length > 0 ? (
|
||||
<div className="table-scroll">
|
||||
<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="pagination-toolbar" aria-label="Detection result pagination">
|
||||
<p className="pagination-summary" aria-live="polite">
|
||||
<strong>{detectionPageStart + 1}-{detectionPageEnd}</strong>
|
||||
<span>of {detectionItems.length}</span>
|
||||
</p>
|
||||
<label className="pagination-page-size">
|
||||
Rows
|
||||
<select
|
||||
value={detectionPageSize}
|
||||
onChange={(event) => {
|
||||
setDetectionPageSize(Number(event.target.value))
|
||||
setDetectionResultPage(1)
|
||||
}}
|
||||
>
|
||||
{DETECTION_PAGE_SIZE_OPTIONS.map((pageSize) => (
|
||||
<option key={pageSize} value={pageSize}>{pageSize}</option>
|
||||
))}
|
||||
</select>
|
||||
</label>
|
||||
<div className="pagination-actions">
|
||||
<button
|
||||
className="secondary-action pagination-button"
|
||||
type="button"
|
||||
aria-label="Previous detection results page"
|
||||
title="Previous page"
|
||||
disabled={currentDetectionPage <= 1}
|
||||
onClick={() => setDetectionResultPage(currentDetectionPage - 1)}
|
||||
>
|
||||
{'<'}
|
||||
</button>
|
||||
<span>Page {currentDetectionPage} of {detectionPageCount}</span>
|
||||
<button
|
||||
className="secondary-action pagination-button"
|
||||
type="button"
|
||||
aria-label="Next detection results page"
|
||||
title="Next page"
|
||||
disabled={currentDetectionPage >= detectionPageCount}
|
||||
onClick={() => setDetectionResultPage(currentDetectionPage + 1)}
|
||||
>
|
||||
{'>'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="table-scroll">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Class</th>
|
||||
<th>Confidence</th>
|
||||
<th>Model</th>
|
||||
<th>Source tile</th>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</thead>
|
||||
<tbody>
|
||||
{visibleDetectionItems.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>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user