Polish data workspace density
GeoIntel CI / docs-smoke (push) Has been cancelled
GeoIntel CI / contract-smoke (push) Has been cancelled

This commit is contained in:
Codex
2026-06-20 06:45:54 +02:00
parent fc3ddf3c49
commit 5a00d3525b
9 changed files with 400 additions and 220 deletions
+63 -49
View File
@@ -30,6 +30,8 @@ export function AreaPanel({
onUpdateAreaForm,
onSelectMapArea,
}: AreaPanelProps): JSX.Element {
const selectedArea = areas.find((area) => area.id === selectedMapAreaId)
return (
<section data-testid="area-panel">
<div className="panel-title-row">
@@ -41,58 +43,70 @@ export function AreaPanel({
</div>
<p className="muted">{selectedProject ? `Project: ${selectedProject.name}` : 'Select a project first'}</p>
<form className="compact-form" onSubmit={onCreateArea}>
<label>
AOI name
<input
value={areaForm.name}
onChange={(event) => onUpdateAreaForm({ ...areaForm, name: event.target.value })}
placeholder="AOI name"
/>
</label>
<label>
CRS
<input
value={areaForm.crs}
onChange={(event) => onUpdateAreaForm({ ...areaForm, crs: event.target.value })}
placeholder="EPSG:4326"
/>
</label>
<label>
GeoJSON geometry
<textarea
value={areaForm.geometry}
onChange={(event) => onUpdateAreaForm({ ...areaForm, geometry: event.target.value })}
rows={4}
/>
</label>
<button className="primary-action" type="submit" disabled={!selectedProjectId}>
Create area
</button>
</form>
<div className="data-selection-summary data-selection-summary-area">
<span>Shown on map</span>
<strong>{selectedArea?.name ?? 'No AOI selected'}</strong>
<small>{selectedArea?.area_m2 ? `${selectedArea.area_m2.toFixed(2)} m2` : 'Select an AOI with geometry for spatial review.'}</small>
</div>
<div className="data-panel-form-block">
<p className="data-section-label">Create spatial scope</p>
<form className="compact-form" onSubmit={onCreateArea}>
<label>
AOI name
<input
value={areaForm.name}
onChange={(event) => onUpdateAreaForm({ ...areaForm, name: event.target.value })}
placeholder="AOI name"
/>
</label>
<label>
CRS
<input
value={areaForm.crs}
onChange={(event) => onUpdateAreaForm({ ...areaForm, crs: event.target.value })}
placeholder="EPSG:4326"
/>
</label>
<label>
GeoJSON geometry
<textarea
value={areaForm.geometry}
onChange={(event) => onUpdateAreaForm({ ...areaForm, geometry: event.target.value })}
rows={4}
/>
</label>
<button className="primary-action" type="submit" disabled={!selectedProjectId}>
Create area
</button>
</form>
</div>
{loadingAreas ? <p>Loading areas...</p> : null}
{areas.length === 0 ? <p>No areas yet</p> : null}
<ul className="entity-list">
{areas.map((area) => (
<li className={selectedMapAreaId === area.id ? 'entity-card entity-card-active' : 'entity-card'} key={area.id}>
<strong>{area.name}</strong>
<div className="entity-meta">
<span>{area.area_m2 ? `${area.area_m2.toFixed(2)} m2` : 'n/a'}</span>
<span>{area.geometry?.type ?? area.geometry_type ?? 'n/a'}</span>
</div>
<button
className="secondary-action"
type="button"
onClick={() => onSelectMapArea(area.id)}
disabled={!area.geometry}
data-testid={`area-show-${area.id}`}
>
{selectedMapAreaId === area.id ? 'Shown on map' : 'Show on map'}
</button>
</li>
))}
</ul>
<div className="data-panel-list-block">
<p className="data-section-label">Saved AOIs</p>
<ul className="entity-list">
{areas.map((area) => (
<li className={selectedMapAreaId === area.id ? 'entity-card entity-card-active' : 'entity-card'} key={area.id}>
<strong>{area.name}</strong>
<div className="entity-meta">
<span>{area.area_m2 ? `${area.area_m2.toFixed(2)} m2` : 'n/a'}</span>
<span>{area.geometry?.type ?? area.geometry_type ?? 'n/a'}</span>
</div>
<button
className="secondary-action"
type="button"
onClick={() => onSelectMapArea(area.id)}
disabled={!area.geometry}
data-testid={`area-show-${area.id}`}
>
{selectedMapAreaId === area.id ? 'Shown on map' : 'Show on map'}
</button>
</li>
))}
</ul>
</div>
</section>
)
}
@@ -26,6 +26,8 @@ export function ProjectPanel({
onSelectProject,
onLoadDemoWorkflow,
}: ProjectPanelProps): JSX.Element {
const selectedProject = projects.find((project) => project.id === selectedProjectId)
return (
<section className="workspace-panel" data-testid="project-panel">
<div className="panel-title-row">
@@ -37,35 +39,44 @@ export function ProjectPanel({
</div>
{loadingProjects ? <p>Loading projects...</p> : null}
<form className="compact-form" onSubmit={onCreateProject}>
<label>
Name
<input
value={projectForm.name}
onChange={(event) => onUpdateProjectForm({ ...projectForm, name: event.target.value })}
placeholder="Project name"
/>
</label>
<label>
Description
<input
value={projectForm.description ?? ''}
onChange={(event) => onUpdateProjectForm({ ...projectForm, description: event.target.value })}
placeholder="Description"
/>
</label>
<label>
Region
<input
value={projectForm.region ?? 'Kempen'}
onChange={(event) => onUpdateProjectForm({ ...projectForm, region: event.target.value })}
placeholder="Region"
/>
</label>
<button className="primary-action" type="submit">
Create project
</button>
</form>
<div className="data-selection-summary data-selection-summary-project">
<span>Selected project</span>
<strong>{selectedProject?.name ?? 'No active project'}</strong>
<small>{selectedProject?.region ?? 'Create or load a project to start the workbench.'}</small>
</div>
<div className="data-panel-form-block">
<p className="data-section-label">Create context</p>
<form className="compact-form" onSubmit={onCreateProject}>
<label>
Name
<input
value={projectForm.name}
onChange={(event) => onUpdateProjectForm({ ...projectForm, name: event.target.value })}
placeholder="Project name"
/>
</label>
<label>
Description
<input
value={projectForm.description ?? ''}
onChange={(event) => onUpdateProjectForm({ ...projectForm, description: event.target.value })}
placeholder="Description"
/>
</label>
<label>
Region
<input
value={projectForm.region ?? 'Kempen'}
onChange={(event) => onUpdateProjectForm({ ...projectForm, region: event.target.value })}
placeholder="Region"
/>
</label>
<button className="primary-action" type="submit">
Create project
</button>
</form>
</div>
<div className="demo-actions">
<button className="secondary-action" type="button" onClick={onLoadDemoWorkflow} disabled={loadingDemoWorkflow} data-testid="load-demo-workflow">
@@ -74,28 +85,31 @@ export function ProjectPanel({
{demoWorkflowMessage ? <p>{demoWorkflowMessage}</p> : null}
</div>
<ul className="entity-list">
{projects.map((project) => (
<li key={project.id}>
<button
className={project.id === selectedProjectId ? 'entity-card entity-card-active' : 'entity-card'}
type="button"
onClick={() => onSelectProject(project.id)}
aria-pressed={project.id === selectedProjectId}
data-testid={`project-select-${project.id}`}
>
<strong>{project.name}</strong>
<span>{project.region || 'No region'}</span>
</button>
</li>
))}
{projects.length === 0 ? (
<li className="empty-state">
<strong>No projects yet</strong>
<p>Create a project or load the offline demo workflow to populate the workbench.</p>
</li>
) : null}
</ul>
<div className="data-panel-list-block">
<p className="data-section-label">Saved projects</p>
<ul className="entity-list">
{projects.map((project) => (
<li key={project.id}>
<button
className={project.id === selectedProjectId ? 'entity-card entity-card-active' : 'entity-card'}
type="button"
onClick={() => onSelectProject(project.id)}
aria-pressed={project.id === selectedProjectId}
data-testid={`project-select-${project.id}`}
>
<strong>{project.name}</strong>
<span>{project.region || 'No region'}</span>
</button>
</li>
))}
{projects.length === 0 ? (
<li className="empty-state">
<strong>No projects yet</strong>
<p>Create a project or load the offline demo workflow to populate the workbench.</p>
</li>
) : null}
</ul>
</div>
</section>
)
}