Polish workbench workspace usability
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 20:57:43 +02:00
parent 76f9b49538
commit a3df753732
14 changed files with 751 additions and 296 deletions
@@ -61,70 +61,106 @@ export function DatasetPanel({
onLoadDatasetDetails,
onRefreshMetadata,
}: DatasetPanelProps) {
const readyDatasets = datasets.filter((dataset) => dataset.status === 'ready').length
return (
<section data-testid="dataset-panel">
<h2>Datasets</h2>
<form onSubmit={onUploadDataset}>
<select
value={datasetForm.datasetType}
onChange={(event) => onDatasetFormChange((previous) => ({ ...previous, datasetType: event.target.value }))}
>
<option value="vector">vector</option>
<option value="geojson">geojson</option>
<option value="raster">raster</option>
</select>
<input
value={datasetForm.source}
onChange={(event) => onDatasetFormChange((previous) => ({ ...previous, source: event.target.value }))}
placeholder="user_upload"
/>
<select
value={datasetForm.areaId}
onChange={(event) => onDatasetFormChange((previous) => ({ ...previous, areaId: event.target.value }))}
>
<option value="">No area</option>
{areas.map((area) => (
<option key={area.id} value={area.id}>
{area.name}
</option>
))}
</select>
<input
type="file"
accept=".geojson,.json,.tif,.tiff,.geotiff"
onChange={(event) => onDatasetFormChange((previous) => ({ ...previous, file: event.target.files?.[0] ?? null }))}
/>
<button type="submit" disabled={!selectedProjectId}>
<div className="panel-title-row">
<div>
<p className="eyebrow">Data catalog</p>
<h2>Datasets</h2>
</div>
<span className="count-pill">{readyDatasets}/{datasets.length} ready</span>
</div>
<form className="dataset-upload-form" onSubmit={onUploadDataset}>
<label>
Type
<select
value={datasetForm.datasetType}
onChange={(event) => onDatasetFormChange((previous) => ({ ...previous, datasetType: event.target.value }))}
>
<option value="vector">vector</option>
<option value="geojson">geojson</option>
<option value="raster">raster</option>
</select>
</label>
<label>
Source
<input
value={datasetForm.source}
onChange={(event) => onDatasetFormChange((previous) => ({ ...previous, source: event.target.value }))}
placeholder="user_upload"
/>
</label>
<label>
AOI
<select
value={datasetForm.areaId}
onChange={(event) => onDatasetFormChange((previous) => ({ ...previous, areaId: event.target.value }))}
>
<option value="">No area</option>
{areas.map((area) => (
<option key={area.id} value={area.id}>
{area.name}
</option>
))}
</select>
</label>
<label className="file-input-label">
File
<input
type="file"
accept=".geojson,.json,.tif,.tiff,.geotiff"
onChange={(event) => onDatasetFormChange((previous) => ({ ...previous, file: event.target.files?.[0] ?? null }))}
/>
</label>
<button className="primary-action" type="submit" disabled={!selectedProjectId}>
Upload dataset
</button>
</form>
{loadingDatasets ? <p>Loading datasets...</p> : null}
{datasets.length === 0 ? <p>No datasets yet</p> : null}
<ul>
<ul className="dataset-list">
{datasets.map((dataset) => (
<li key={dataset.id}>
<strong>{dataset.name}</strong>
<div>type: {dataset.dataset_type}</div>
<div>status: {dataset.status}</div>
<div>readiness: {dataset.status === 'ready' ? 'ready' : dataset.status === 'failed' ? 'failed' : 'pending'}</div>
<div>size: {formatBytes(dataset.size_bytes)}</div>
<div>features: {dataset.feature_count ?? dataset.vector_summary?.feature_count ?? 'n/a'}</div>
<div>bbox: {formatBounds(dataset.bounds_json ?? dataset.vector_summary?.bounds_json)}</div>
<button
type="button"
onClick={() => onLoadDatasetDetails(selectedProjectId ?? '', dataset)}
data-testid={`dataset-select-${dataset.id}`}
>
Select / details
</button>
<button
type="button"
onClick={() => onRefreshMetadata(dataset.id)}
disabled={dataset.dataset_type === 'raster'}
>
Refresh metadata
</button>
<li className="dataset-card" key={dataset.id}>
<div className="dataset-card-header">
<div>
<strong>{dataset.name}</strong>
<div className="entity-meta">
<span>{dataset.dataset_type}</span>
<span>{dataset.dataset_role ?? 'source'}</span>
<span>{dataset.status}</span>
</div>
</div>
<span className={dataset.status === 'ready' ? 'status-badge status-badge-ready' : 'status-badge'}>
{dataset.status === 'ready' ? 'ready' : dataset.status === 'failed' ? 'failed' : 'pending'}
</span>
</div>
<div className="dataset-metrics">
<span>size: {formatBytes(dataset.size_bytes)}</span>
<span>features: {dataset.feature_count ?? dataset.vector_summary?.feature_count ?? 'n/a'}</span>
<span>bbox: {formatBounds(dataset.bounds_json ?? dataset.vector_summary?.bounds_json)}</span>
</div>
<div className="button-row">
<button
className="primary-action"
type="button"
onClick={() => onLoadDatasetDetails(selectedProjectId ?? '', dataset)}
data-testid={`dataset-select-${dataset.id}`}
>
Select / details
</button>
<button
className="secondary-action"
type="button"
onClick={() => onRefreshMetadata(dataset.id)}
disabled={dataset.dataset_type === 'raster'}
>
Refresh metadata
</button>
</div>
</li>
))}
</ul>