Polish QA and export workspaces
GeoIntel CI / docs-smoke (push) Has been cancelled
GeoIntel CI / contract-smoke (push) Has been cancelled

This commit is contained in:
Codex
2026-06-17 21:05:15 +02:00
parent a3df753732
commit e4b09c4e45
8 changed files with 391 additions and 68 deletions
@@ -54,57 +54,103 @@ export function ExportCenter({
onDownload,
}: ExportCenterProps): JSX.Element {
const canExportDataset = Boolean(selectedDataset && isVectorDatasetType(selectedDataset.dataset_type))
const geojsonExports = exports.filter((item) => item.export_type.includes('geojson')).length
const reportExports = exports.filter((item) => item.export_type === 'project_report_html').length
return (
<section data-testid="export-center">
<h2>Export Center</h2>
<button type="button" onClick={onRefresh} disabled={!selectedProjectId || loadingExports} data-testid="refresh-exports">
Refresh exports
</button>
<button
type="button"
onClick={onExportProjectMetadata}
disabled={!selectedProjectId || exporting}
data-testid="export-project-metadata"
>
Export project metadata JSON
</button>
<button type="button" onClick={onExportProjectReport} disabled={!selectedProjectId || exporting}>
Export project report HTML
</button>
<button type="button" onClick={onExportDataset} disabled={!canExportDataset || exporting}>
Export selected vector GeoJSON
</button>
<button type="button" onClick={onExportDetectionRun} disabled={!selectedDetectionRunId || exporting}>
Export selected detection run GeoJSON
</button>
<button type="button" onClick={onExportSegmentationRun} disabled={!selectedSegmentationRunId || exporting}>
Export selected segmentation run GeoJSON
</button>
<section className="export-center" data-testid="export-center">
<div className="panel-title-row">
<div>
<h2>Export Center</h2>
<p className="muted">Create handoff artifacts from persisted datasets, AI runs and project metadata.</p>
</div>
<span className="count-pill">{exports.length} exports</span>
</div>
<div className="quality-summary-grid">
<div>
<span>GeoJSON</span>
<strong>{geojsonExports}</strong>
</div>
<div>
<span>Reports</span>
<strong>{reportExports}</strong>
</div>
<div>
<span>Selected dataset</span>
<strong>{selectedDataset?.name ?? 'none'}</strong>
</div>
</div>
<div className="export-action-grid">
<button
type="button"
className="secondary-action"
onClick={onRefresh}
disabled={!selectedProjectId || loadingExports}
data-testid="refresh-exports"
>
Refresh exports
</button>
<button
type="button"
className="primary-action"
onClick={onExportProjectMetadata}
disabled={!selectedProjectId || exporting}
data-testid="export-project-metadata"
>
Export project metadata JSON
</button>
<button type="button" className="secondary-action" onClick={onExportProjectReport} disabled={!selectedProjectId || exporting}>
Export project report HTML
</button>
<button type="button" className="secondary-action" onClick={onExportDataset} disabled={!canExportDataset || exporting}>
Export selected vector GeoJSON
</button>
<button type="button" className="secondary-action" onClick={onExportDetectionRun} disabled={!selectedDetectionRunId || exporting}>
Export selected detection run GeoJSON
</button>
<button type="button" className="secondary-action" onClick={onExportSegmentationRun} disabled={!selectedSegmentationRunId || exporting}>
Export selected segmentation run GeoJSON
</button>
</div>
{exportError ? <p className="error">{exportError}</p> : null}
{latestExport ? (
<p>
Latest export: {latestExport.export_type} {'->'} {latestExport.path}
</p>
<div className="latest-export-card">
<span>Latest export</span>
<strong>{latestExport.export_type}</strong>
<p>{latestExport.path}</p>
</div>
) : null}
{exports.length === 0 ? <p>No exports registered yet.</p> : null}
<ul>
{exports.length === 0 ? (
<div className="empty-state">
<strong>No exports registered yet.</strong>
<p>Create metadata, GeoJSON or HTML report artifacts once the active project has data to hand off.</p>
</div>
) : null}
<ul className="export-list">
{exports.map((item) => (
<li key={item.id}>
<strong>{item.export_type}</strong>
<div>status: {item.status}</div>
<div>path: {item.storage_path}</div>
<div>export id: {item.id}</div>
{canPreviewJson(item) ? (
<button type="button" onClick={() => onPreviewContent(item.id)}>
Preview JSON content
<li className="export-card" key={item.id}>
<div className="export-card-header">
<div>
<strong>{item.export_type}</strong>
<div className="entity-meta">
<span>export id: {item.id}</span>
</div>
</div>
<span className={item.status === 'ready' ? 'status-badge status-badge-ready' : 'status-badge'}>{item.status}</span>
</div>
<p>{item.storage_path}</p>
<div className="button-row">
{canPreviewJson(item) ? (
<button type="button" className="secondary-action" onClick={() => onPreviewContent(item.id)}>
Preview JSON content
</button>
) : (
<span className="status-badge">download-only HTML artifact</span>
)}
<button type="button" className="primary-action" onClick={() => onDownload(item.id)}>
Download artifact
</button>
) : (
<div>Preview: download-only HTML artifact</div>
)}
<button type="button" onClick={() => onDownload(item.id)}>
Download artifact
</button>
</div>
</li>
))}
</ul>
@@ -8,8 +8,14 @@ export function ExportPreview({ content }: ExportPreviewProps): JSX.Element | nu
}
return (
<section>
<h2>Export Preview</h2>
<section className="export-preview-panel">
<div className="panel-title-row">
<div>
<h2>Export Preview</h2>
<p className="muted">JSON and GeoJSON content preview for the selected export artifact.</p>
</div>
<span className="count-pill">preview</span>
</div>
<pre className="job-result">{JSON.stringify(content, null, 2)}</pre>
</section>
)