Add map QA evidence drilldown
This commit is contained in:
@@ -7,6 +7,13 @@
|
|||||||
|
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## Sprint 110 Map QA evidence drilldown (2026-06-25)
|
||||||
|
|
||||||
|
- Extended the Map workspace QA/QC shortcut with inline evidence after comparing a saved derived selection dataset.
|
||||||
|
- The result now shows quality-check id, matches, false positives, false negatives, mean IoU and QA warnings beside precision/recall/F1.
|
||||||
|
- Added an `Open QA/QC evidence` handoff to the existing QA/QC workspace drilldown instead of creating a parallel QA detail system.
|
||||||
|
- No backend API contracts, migrations, provider fetching, AI behavior or new product domains were introduced.
|
||||||
|
|
||||||
## Sprint 109 Map selection QA shortcut (2026-06-25)
|
## Sprint 109 Map selection QA shortcut (2026-06-25)
|
||||||
|
|
||||||
- Added a Map workspace QA/QC shortcut for saved derived selection datasets.
|
- Added a Map workspace QA/QC shortcut for saved derived selection datasets.
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
|
||||||
|
|
||||||
|
def read_text(relative_path: str) -> str:
|
||||||
|
return (ROOT / relative_path).read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
def test_map_qa_result_exposes_quality_check_evidence_contract():
|
||||||
|
types = read_text("frontend/src/types.ts")
|
||||||
|
hook = read_text("frontend/src/hooks/useMapSelectionQa.ts")
|
||||||
|
workspace = read_text("frontend/src/components/map/MapWorkspace.tsx")
|
||||||
|
app = read_text("frontend/src/App.tsx")
|
||||||
|
|
||||||
|
assert "quality_check_id?: string" in types
|
||||||
|
assert "latestMapSelectionQualityCheckId" in hook
|
||||||
|
assert "parsed.quality_check_id" in hook
|
||||||
|
assert "setLatestMapSelectionQualityCheckId" in hook
|
||||||
|
|
||||||
|
assert "onOpenMapSelectionQualityEvidence" in app
|
||||||
|
assert "setActiveWorkspace('analysis')" in app
|
||||||
|
assert "latestMapSelectionQualityCheckId={latestMapSelectionQualityCheckId}" in app
|
||||||
|
assert "onOpenMapSelectionQualityEvidence={openMapSelectionQualityEvidence}" in app
|
||||||
|
|
||||||
|
assert "QA evidence" in workspace
|
||||||
|
assert "Quality check id" in workspace
|
||||||
|
assert "Mean IoU" in workspace
|
||||||
|
assert "False positives" in workspace
|
||||||
|
assert "False negatives" in workspace
|
||||||
|
assert "Map selection QA warnings" in workspace
|
||||||
|
assert "Open QA/QC evidence" in workspace
|
||||||
|
|
||||||
|
|
||||||
|
def test_map_qa_evidence_keeps_backend_contract_unchanged():
|
||||||
|
app = read_text("frontend/src/App.tsx")
|
||||||
|
api_contracts = read_text("docs/API_CONTRACTS.md")
|
||||||
|
|
||||||
|
assert "/api/v1/qa/detections-vs-reference" in api_contracts
|
||||||
|
assert "qaApi.runQa" not in app
|
||||||
@@ -1,3 +1,26 @@
|
|||||||
|
## Sprint 110 Map QA evidence drilldown (2026-06-25)
|
||||||
|
|
||||||
|
Changed:
|
||||||
|
- Extended `QaComparisonResult` frontend typing with optional `quality_check_id`, matching the existing backend QA result payload.
|
||||||
|
- Updated `useMapSelectionQa` to keep the latest persisted map-selection quality-check id after a successful QA/QC comparison.
|
||||||
|
- Extended the Map workspace QA/QC result state with inline evidence: quality-check id, matches, false positives, false negatives, mean IoU and QA warnings.
|
||||||
|
- Added `Open QA/QC evidence` handoff from Map workspace to the existing QA/QC workspace drilldown, avoiding a parallel QA detail system.
|
||||||
|
- Added compact styling for the Map QA evidence and warning surface.
|
||||||
|
- Updated `frontend/README.md`, `CHANGELOG.md` and `docs/TODO.md`.
|
||||||
|
- Added regression coverage in `backend/tests/test_sprint110_map_qa_evidence_drilldown.py`.
|
||||||
|
|
||||||
|
Validation:
|
||||||
|
- RED: `python -m pytest backend\tests\test_sprint110_map_qa_evidence_drilldown.py -q` failed before implementation because the hook/evidence wiring was absent.
|
||||||
|
- `python -m pytest backend\tests\test_sprint110_map_qa_evidence_drilldown.py -q` passed: 2 tests.
|
||||||
|
|
||||||
|
Limitations:
|
||||||
|
- The Map evidence handoff opens the existing QA/QC workspace; selecting a specific historical check inside that workspace remains governed by the QA/QC panel's own latest-check behavior.
|
||||||
|
- False-positive and false-negative geometries are summarized by persisted metrics/findings; dedicated map overlays for unmatched evidence remain future work.
|
||||||
|
- No backend API contract, migration, provider fetching, AI dependency, real model behavior or new product domain was added.
|
||||||
|
|
||||||
|
Next recommended pass:
|
||||||
|
- Add optional unmatched-evidence map overlays once the QA persistence model stores explicit matched/unmatched feature ids or geometries.
|
||||||
|
|
||||||
## Sprint 109 Map selection QA shortcut (2026-06-25)
|
## Sprint 109 Map selection QA shortcut (2026-06-25)
|
||||||
|
|
||||||
Changed:
|
Changed:
|
||||||
|
|||||||
@@ -376,3 +376,4 @@ This file now starts with the current implementation status. Older preparation/b
|
|||||||
- [x] Persist map area selections as Export Center handoff artifacts.
|
- [x] Persist map area selections as Export Center handoff artifacts.
|
||||||
- [x] Persist map area selections as reusable derived vector datasets indexed into `vector_features`.
|
- [x] Persist map area selections as reusable derived vector datasets indexed into `vector_features`.
|
||||||
- [x] Add Map workspace QA/QC shortcut for saved derived selection datasets.
|
- [x] Add Map workspace QA/QC shortcut for saved derived selection datasets.
|
||||||
|
- [x] Add Map workspace QA/QC evidence drilldown handoff for saved selection comparisons.
|
||||||
|
|||||||
@@ -281,6 +281,7 @@ AI Lab run controls explicitly explain when no raster dataset is available, inst
|
|||||||
- After an area extract, `Save area export` persists the selected FeatureCollection as a normal Export Center artifact (`vector_selection_geojson`) so the handoff remains in project export history.
|
- After an area extract, `Save area export` persists the selected FeatureCollection as a normal Export Center artifact (`vector_selection_geojson`) so the handoff remains in project export history.
|
||||||
- `Save as dataset` persists the same selected FeatureCollection as a derived vector dataset, selects it in the workbench and keeps it queryable through backend `vector_features` for later QA/QC or analysis.
|
- `Save as dataset` persists the same selected FeatureCollection as a derived vector dataset, selects it in the workbench and keeps it queryable through backend `vector_features` for later QA/QC or analysis.
|
||||||
- Once a map selection has been saved as a derived dataset, the Map workspace can run QA/QC against a selected reference dataset without switching workspaces. The action reuses the existing QA comparison endpoint and shows precision, recall, F1 and persisted quality-check status inline.
|
- Once a map selection has been saved as a derived dataset, the Map workspace can run QA/QC against a selected reference dataset without switching workspaces. The action reuses the existing QA comparison endpoint and shows precision, recall, F1 and persisted quality-check status inline.
|
||||||
|
- Map selection QA results also show persisted quality-check id, matches, false positives, false negatives, mean IoU and QA warnings. `Open QA/QC evidence` hands operators to the existing QA/QC evidence drilldown for the full parameters/findings record.
|
||||||
- The Data catalog shows a compact selected/reference/candidate/source summary and scan-friendly badges. Persisted `reference` datasets are shown as Reference, non-reference vector/GeoJSON layers are shown as QA Candidates for workbench scanning, and raster/other uploads remain Source.
|
- The Data catalog shows a compact selected/reference/candidate/source summary and scan-friendly badges. Persisted `reference` datasets are shown as Reference, non-reference vector/GeoJSON layers are shown as QA Candidates for workbench scanning, and raster/other uploads remain Source.
|
||||||
- Dataset cards explain the recommended next action and use compact two-line action buttons for inspect, map, export/QA and metadata refresh. Disabled actions keep a visible reason, such as `Vector/GeoJSON only`.
|
- Dataset cards explain the recommended next action and use compact two-line action buttons for inspect, map, export/QA and metadata refresh. Disabled actions keep a visible reason, such as `Vector/GeoJSON only`.
|
||||||
- Raster controls show the latest generated tile manifest path from persisted `raster.tile` jobs and can hand that path directly to Detection Lab or Segmentation Lab with the selected raster dataset.
|
- Raster controls show the latest generated tile manifest path from persisted `raster.tile` jobs and can hand that path directly to Detection Lab or Segmentation Lab with the selected raster dataset.
|
||||||
|
|||||||
@@ -405,6 +405,7 @@ function App(): JSX.Element {
|
|||||||
mapSelectionQaRunning,
|
mapSelectionQaRunning,
|
||||||
mapSelectionQaError,
|
mapSelectionQaError,
|
||||||
mapSelectionQaResult,
|
mapSelectionQaResult,
|
||||||
|
latestMapSelectionQualityCheckId,
|
||||||
runMapSelectionQa,
|
runMapSelectionQa,
|
||||||
setSelectedMapQaReferenceDatasetId,
|
setSelectedMapQaReferenceDatasetId,
|
||||||
} = useMapSelectionQa({
|
} = useMapSelectionQa({
|
||||||
@@ -413,6 +414,9 @@ function App(): JSX.Element {
|
|||||||
loadQualityChecks,
|
loadQualityChecks,
|
||||||
loadProjectData,
|
loadProjectData,
|
||||||
})
|
})
|
||||||
|
const openMapSelectionQualityEvidence = () => {
|
||||||
|
setActiveWorkspace('analysis')
|
||||||
|
}
|
||||||
const {
|
const {
|
||||||
loadingDemoWorkflow,
|
loadingDemoWorkflow,
|
||||||
demoWorkflowMessage,
|
demoWorkflowMessage,
|
||||||
@@ -845,6 +849,7 @@ function App(): JSX.Element {
|
|||||||
mapSelectionQaRunning={mapSelectionQaRunning}
|
mapSelectionQaRunning={mapSelectionQaRunning}
|
||||||
mapSelectionQaError={mapSelectionQaError}
|
mapSelectionQaError={mapSelectionQaError}
|
||||||
mapSelectionQaResult={mapSelectionQaResult}
|
mapSelectionQaResult={mapSelectionQaResult}
|
||||||
|
latestMapSelectionQualityCheckId={latestMapSelectionQualityCheckId}
|
||||||
availableMapDatasets={availableMapDatasets}
|
availableMapDatasets={availableMapDatasets}
|
||||||
selectedFeature={selectedMapFeature}
|
selectedFeature={selectedMapFeature}
|
||||||
onSelectMapArea={setSelectedMapAreaId}
|
onSelectMapArea={setSelectedMapAreaId}
|
||||||
@@ -861,6 +866,7 @@ function App(): JSX.Element {
|
|||||||
onDeriveMapSelectionDataset={deriveMapSelectionDataset}
|
onDeriveMapSelectionDataset={deriveMapSelectionDataset}
|
||||||
onSelectMapQaReferenceDataset={setSelectedMapQaReferenceDatasetId}
|
onSelectMapQaReferenceDataset={setSelectedMapQaReferenceDatasetId}
|
||||||
onRunMapSelectionQa={runMapSelectionQa}
|
onRunMapSelectionQa={runMapSelectionQa}
|
||||||
|
onOpenMapSelectionQualityEvidence={openMapSelectionQualityEvidence}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
|
|||||||
@@ -202,6 +202,7 @@ interface MapWorkspaceProps {
|
|||||||
mapSelectionQaRunning: boolean
|
mapSelectionQaRunning: boolean
|
||||||
mapSelectionQaError: string | null
|
mapSelectionQaError: string | null
|
||||||
mapSelectionQaResult: QaComparisonResult | null
|
mapSelectionQaResult: QaComparisonResult | null
|
||||||
|
latestMapSelectionQualityCheckId: string | null
|
||||||
availableMapDatasets: DatasetCreateResponse[]
|
availableMapDatasets: DatasetCreateResponse[]
|
||||||
onSelectMapArea: (areaId: string) => void
|
onSelectMapArea: (areaId: string) => void
|
||||||
onOpenDatasetInMap: (dataset: DatasetCreateResponse) => void
|
onOpenDatasetInMap: (dataset: DatasetCreateResponse) => void
|
||||||
@@ -217,6 +218,7 @@ interface MapWorkspaceProps {
|
|||||||
onDeriveMapSelectionDataset: (bbox: VectorSelectionBBox) => void
|
onDeriveMapSelectionDataset: (bbox: VectorSelectionBBox) => void
|
||||||
onSelectMapQaReferenceDataset: (datasetId: string) => void
|
onSelectMapQaReferenceDataset: (datasetId: string) => void
|
||||||
onRunMapSelectionQa: () => void
|
onRunMapSelectionQa: () => void
|
||||||
|
onOpenMapSelectionQualityEvidence: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export function MapWorkspace({
|
export function MapWorkspace({
|
||||||
@@ -250,6 +252,7 @@ export function MapWorkspace({
|
|||||||
mapSelectionQaRunning,
|
mapSelectionQaRunning,
|
||||||
mapSelectionQaError,
|
mapSelectionQaError,
|
||||||
mapSelectionQaResult,
|
mapSelectionQaResult,
|
||||||
|
latestMapSelectionQualityCheckId,
|
||||||
availableMapDatasets,
|
availableMapDatasets,
|
||||||
onSelectMapArea,
|
onSelectMapArea,
|
||||||
onOpenDatasetInMap,
|
onOpenDatasetInMap,
|
||||||
@@ -265,6 +268,7 @@ export function MapWorkspace({
|
|||||||
onDeriveMapSelectionDataset,
|
onDeriveMapSelectionDataset,
|
||||||
onSelectMapQaReferenceDataset,
|
onSelectMapQaReferenceDataset,
|
||||||
onRunMapSelectionQa,
|
onRunMapSelectionQa,
|
||||||
|
onOpenMapSelectionQualityEvidence,
|
||||||
}: MapWorkspaceProps): JSX.Element {
|
}: MapWorkspaceProps): JSX.Element {
|
||||||
const [bboxSelectionMode, setBboxSelectionMode] = useState(false)
|
const [bboxSelectionMode, setBboxSelectionMode] = useState(false)
|
||||||
const [firstSelectionCorner, setFirstSelectionCorner] = useState<[number, number] | null>(null)
|
const [firstSelectionCorner, setFirstSelectionCorner] = useState<[number, number] | null>(null)
|
||||||
@@ -685,23 +689,65 @@ export function MapWorkspace({
|
|||||||
</button>
|
</button>
|
||||||
{mapSelectionQaError ? <p className="error">{mapSelectionQaError}</p> : null}
|
{mapSelectionQaError ? <p className="error">{mapSelectionQaError}</p> : null}
|
||||||
{mapSelectionQaResult ? (
|
{mapSelectionQaResult ? (
|
||||||
<div className="feature-extract-grid" aria-label="Map selection QA result">
|
<div className="map-selection-qa-evidence" aria-label="Map selection QA result">
|
||||||
<div>
|
<div className="panel-title-row">
|
||||||
<span>Precision</span>
|
<div>
|
||||||
<strong>{mapSelectionQaResult.precision ?? 'n/a'}</strong>
|
<p className="eyebrow">QA evidence</p>
|
||||||
|
<h4>Saved selection comparison</h4>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
className="secondary-action"
|
||||||
|
disabled={!latestMapSelectionQualityCheckId}
|
||||||
|
type="button"
|
||||||
|
onClick={onOpenMapSelectionQualityEvidence}
|
||||||
|
>
|
||||||
|
Open QA/QC evidence
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="feature-extract-grid">
|
||||||
<span>Recall</span>
|
<div>
|
||||||
<strong>{mapSelectionQaResult.recall ?? 'n/a'}</strong>
|
<span>Precision</span>
|
||||||
</div>
|
<strong>{mapSelectionQaResult.precision ?? 'n/a'}</strong>
|
||||||
<div>
|
</div>
|
||||||
<span>F1</span>
|
<div>
|
||||||
<strong>{mapSelectionQaResult.f1_score ?? 'n/a'}</strong>
|
<span>Recall</span>
|
||||||
</div>
|
<strong>{mapSelectionQaResult.recall ?? 'n/a'}</strong>
|
||||||
<div>
|
</div>
|
||||||
<span>Quality check</span>
|
<div>
|
||||||
<strong>{mapSelectionQaResult.status}</strong>
|
<span>F1</span>
|
||||||
|
<strong>{mapSelectionQaResult.f1_score ?? 'n/a'}</strong>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>Mean IoU</span>
|
||||||
|
<strong>{mapSelectionQaResult.mean_iou ?? 'n/a'}</strong>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>Matches</span>
|
||||||
|
<strong>{mapSelectionQaResult.matches}</strong>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>False positives</span>
|
||||||
|
<strong>{mapSelectionQaResult.false_positives}</strong>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>False negatives</span>
|
||||||
|
<strong>{mapSelectionQaResult.false_negatives}</strong>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>Quality check id</span>
|
||||||
|
<strong>{latestMapSelectionQualityCheckId ?? 'not persisted'}</strong>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{mapSelectionQaResult.warnings.length > 0 ? (
|
||||||
|
<div className="map-selection-qa-warnings" aria-label="Map selection QA warnings">
|
||||||
|
<span>Map selection QA warnings</span>
|
||||||
|
<ul>
|
||||||
|
{mapSelectionQaResult.warnings.map((warning) => (
|
||||||
|
<li key={warning}>{warning}</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ export function useMapSelectionQa({
|
|||||||
const [mapSelectionQaRunning, setMapSelectionQaRunning] = useState(false)
|
const [mapSelectionQaRunning, setMapSelectionQaRunning] = useState(false)
|
||||||
const [mapSelectionQaError, setMapSelectionQaError] = useState<string | null>(null)
|
const [mapSelectionQaError, setMapSelectionQaError] = useState<string | null>(null)
|
||||||
const [mapSelectionQaResult, setMapQaResult] = useState<QaComparisonResult | null>(null)
|
const [mapSelectionQaResult, setMapQaResult] = useState<QaComparisonResult | null>(null)
|
||||||
|
const [latestMapSelectionQualityCheckId, setLatestMapSelectionQualityCheckId] = useState<string | null>(null)
|
||||||
|
|
||||||
const runMapSelectionQa = async () => {
|
const runMapSelectionQa = async () => {
|
||||||
if (!selectedProjectId) {
|
if (!selectedProjectId) {
|
||||||
@@ -42,6 +43,7 @@ export function useMapSelectionQa({
|
|||||||
setMapSelectionQaRunning(true)
|
setMapSelectionQaRunning(true)
|
||||||
setMapSelectionQaError(null)
|
setMapSelectionQaError(null)
|
||||||
setMapQaResult(null)
|
setMapQaResult(null)
|
||||||
|
setLatestMapSelectionQualityCheckId(null)
|
||||||
try {
|
try {
|
||||||
const request: QaComparisonRequest = {
|
const request: QaComparisonRequest = {
|
||||||
candidate_dataset_id: latestSelectionDataset.id,
|
candidate_dataset_id: latestSelectionDataset.id,
|
||||||
@@ -65,6 +67,7 @@ export function useMapSelectionQa({
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
setMapQaResult(parsed)
|
setMapQaResult(parsed)
|
||||||
|
setLatestMapSelectionQualityCheckId(parsed.quality_check_id ?? null)
|
||||||
await loadQualityChecks(selectedProjectId)
|
await loadQualityChecks(selectedProjectId)
|
||||||
await loadProjectData(selectedProjectId)
|
await loadProjectData(selectedProjectId)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -79,6 +82,7 @@ export function useMapSelectionQa({
|
|||||||
mapSelectionQaRunning,
|
mapSelectionQaRunning,
|
||||||
mapSelectionQaError,
|
mapSelectionQaError,
|
||||||
mapSelectionQaResult,
|
mapSelectionQaResult,
|
||||||
|
latestMapSelectionQualityCheckId,
|
||||||
runMapSelectionQa,
|
runMapSelectionQa,
|
||||||
setSelectedMapQaReferenceDatasetId,
|
setSelectedMapQaReferenceDatasetId,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2690,10 +2690,56 @@ button.entity-card {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.map-selection-qa-surface .error,
|
.map-selection-qa-surface .error,
|
||||||
.map-selection-qa-surface .feature-extract-grid {
|
.map-selection-qa-surface .map-selection-qa-evidence {
|
||||||
grid-column: 1 / -1;
|
grid-column: 1 / -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.map-selection-qa-evidence {
|
||||||
|
display: grid;
|
||||||
|
gap: 0.62rem;
|
||||||
|
min-width: 0;
|
||||||
|
border: 1px solid rgba(15, 118, 110, 0.2);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 0.68rem;
|
||||||
|
background: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.map-selection-qa-evidence .panel-title-row {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.map-selection-qa-evidence .secondary-action {
|
||||||
|
width: fit-content;
|
||||||
|
max-width: 100%;
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.map-selection-qa-warnings {
|
||||||
|
display: grid;
|
||||||
|
gap: 0.36rem;
|
||||||
|
min-width: 0;
|
||||||
|
border-top: 1px solid var(--line);
|
||||||
|
padding-top: 0.58rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.map-selection-qa-warnings span {
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 0.72rem;
|
||||||
|
font-weight: 850;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.map-selection-qa-warnings ul {
|
||||||
|
display: grid;
|
||||||
|
gap: 0.28rem;
|
||||||
|
margin: 0;
|
||||||
|
padding-left: 1.1rem;
|
||||||
|
color: var(--text);
|
||||||
|
font-size: 0.82rem;
|
||||||
|
line-height: 1.35;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 720px) {
|
@media (max-width: 720px) {
|
||||||
.map-selection-qa-surface {
|
.map-selection-qa-surface {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
|
|||||||
@@ -601,6 +601,7 @@ export interface QaComparisonResult {
|
|||||||
unsupported_geometry: boolean
|
unsupported_geometry: boolean
|
||||||
unsupported_geometries: string[]
|
unsupported_geometries: string[]
|
||||||
generated_at: string
|
generated_at: string
|
||||||
|
quality_check_id?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MetricRead {
|
export interface MetricRead {
|
||||||
|
|||||||
Reference in New Issue
Block a user