Polish export system 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 23:10:42 +02:00
parent 5544c92006
commit f99d206dc1
8 changed files with 554 additions and 278 deletions
+8
View File
@@ -7,6 +7,14 @@
# Changelog
## Sprint 89 Export/System density polish (2026-06-20)
- Grouped Export Center summary, handoff readiness, artifact actions, state cards and history into focused surfaces.
- Grouped Provider Capabilities into a system shell with registry state cards, capability cards and attribution/license provenance cards.
- Preserved existing export action, filter, preview/download and provider refresh workflows without API or persistence changes.
- Added static regression coverage for Export/System hierarchy and density contracts.
- No API contracts, migrations, backend behavior, provider fetching or AI model behavior changed.
## Sprint 88 AI Labs density polish (2026-06-20)
- Grouped Detection Lab and Segmentation Lab model registry, run controls, result loading and QA controls into focused surfaces.
@@ -0,0 +1,83 @@
from __future__ import annotations
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
def test_export_center_exposes_final_handoff_surfaces() -> None:
export_center = (ROOT / "frontend" / "src" / "components" / "exports" / "ExportCenter.tsx").read_text(
encoding="utf-8"
)
assert 'className="export-center"' in export_center
assert 'className="export-center-shell"' in export_center
assert 'className="export-summary-surface"' in export_center
assert 'aria-label="Export summary"' in export_center
assert 'className="export-handoff-surface"' in export_center
assert 'aria-label="Export handoff readiness"' in export_center
assert 'className="export-actions-surface"' in export_center
assert 'aria-label="Export artifact actions"' in export_center
assert 'className="export-state-stack"' in export_center
assert 'className="export-history-surface"' in export_center
assert 'aria-label="Export history"' in export_center
def test_provider_panel_exposes_final_system_surfaces() -> None:
provider_panel = (ROOT / "frontend" / "src" / "components" / "providers" / "ProviderPanel.tsx").read_text(
encoding="utf-8"
)
assert 'className="system-provider-panel"' in provider_panel
assert 'className="system-provider-shell"' in provider_panel
assert 'className="system-provider-state-stack"' in provider_panel
assert 'className="system-provider-capability-surface"' in provider_panel
assert 'aria-label="Provider capability registry"' in provider_panel
assert 'className="provider-provenance-grid"' in provider_panel
assert 'className="provider-provenance-card"' in provider_panel
assert 'className="provider-detail-stack"' in provider_panel
def test_export_system_preserves_existing_workflow_controls() -> None:
export_center = (ROOT / "frontend" / "src" / "components" / "exports" / "ExportCenter.tsx").read_text(
encoding="utf-8"
)
provider_panel = (ROOT / "frontend" / "src" / "components" / "providers" / "ProviderPanel.tsx").read_text(
encoding="utf-8"
)
assert "onExportDataset" in export_center
assert "onExportDetectionRun" in export_center
assert "onExportSegmentationRun" in export_center
assert "onExportProjectMetadata" in export_center
assert "onExportProjectReport" in export_center
assert "onPreviewContent" in export_center
assert "onDownload" in export_center
assert "exportTypeFilter" in export_center
assert "exportStatusFilter" in export_center
assert "exportSearchQuery" in export_center
assert "system-provider-list" in provider_panel
assert "system-provider-card" in provider_panel
assert "provider-layer-chip" in provider_panel
assert "provider.not_configured_reason" in provider_panel
def test_export_system_density_css_contracts() -> None:
css = (ROOT / "frontend" / "src" / "styles" / "app.css").read_text(encoding="utf-8")
assert ".export-center-shell" in css
assert ".export-summary-surface" in css
assert ".export-handoff-surface" in css
assert ".export-actions-surface" in css
assert ".export-state-stack" in css
assert ".export-history-surface" in css
assert ".export-center-shell .quality-summary-grid" in css
assert ".system-provider-shell" in css
assert ".system-provider-state-stack" in css
assert ".system-provider-capability-surface" in css
assert ".provider-detail-stack" in css
assert ".provider-provenance-grid" in css
assert ".provider-provenance-card" in css
assert "grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));" in css
assert "background: linear-gradient(180deg, #ffffff, #f7fbf8);" in css
+31
View File
@@ -3210,3 +3210,34 @@ Limitations:
Next recommended pass:
- Continue with export/system final visual consistency or live workflow guidance once this pass is deployed and visually checked.
## Sprint 89 Export/System density polish (2026-06-20)
Changed:
- Wrapped Export Center content in `export-center-shell`.
- Grouped export summary, handoff readiness, artifact actions, current state cards and history into focused `export-*` surfaces.
- Wrapped Provider Capabilities content in `system-provider-shell`.
- Replaced loose provider loading/error/empty text with shared `result-state` cards.
- Grouped provider registry content into `system-provider-capability-surface`.
- Split provider limitation/reason text and attribution/license data into `provider-detail-stack` and provenance cards.
- Added shared Export/System density CSS for compact summary, handoff, action, history and provider provenance grids.
- Added `backend/tests/test_sprint89_export_system_density.py`.
- Updated `frontend/README.md`, `docs/TODO.md` and `CHANGELOG.md`.
Tested:
- Red step: `python -m pytest backend/tests/test_sprint89_export_system_density.py -q` failed on missing Export/System shells, surfaces and CSS contracts.
- `python -m pytest backend/tests/test_sprint89_export_system_density.py backend/tests/test_sprint51_quality_export_polish.py backend/tests/test_sprint64_export_handoff_polish.py backend/tests/test_sprint76_export_system_mobile_polish.py backend/tests/test_sprint78_export_preview_readability.py -q` (`12 passed`)
- `cd frontend && npm run typecheck`
- `cd frontend && npm run build`
- In-app browser fallback note: the Browser click path timed out on the local workspace navigation CDP command, so rendered validation used local Chrome via Playwright.
- Local Chrome UI check against `http://127.0.0.1:5174` passed on desktop and mobile: Export/System shells and surfaces rendered with no horizontal overflow. Local console showed expected Vite proxy 500s because only the frontend server was running.
- Full readiness and Tower deploy pending in this pass.
Open:
- None known before full readiness/deploy validation.
Limitations:
- Frontend Export/System presentation hierarchy only; no export behavior, API contract, persistence, migration, provider fetching or AI/model changes.
Next recommended pass:
- Continue with end-to-end workflow guidance after this pass is deployed and visually checked.
+1
View File
@@ -78,6 +78,7 @@ This file now starts with the current implementation status. Older preparation/b
- [x] Add QA/QC workspace result hierarchy and filter density polish.
- [x] Add Change Detection panel hierarchy and analysis workspace density polish.
- [x] Add AI Labs Detection/Segmentation hierarchy and result density polish.
- [x] Add Export/System handoff hierarchy and provider registry density polish.
## Sprint 8 status
+2
View File
@@ -16,6 +16,8 @@ AI Labs uses the same mobile-density baseline for Detection and Segmentation mod
Exports and System provider capabilities now use compact, mobile-safe cards for handoff actions, artifact filters and provider metadata. Long provider limitations, export ids and artifact paths wrap inside their cards instead of widening the workbench.
Export Center now separates export summary, handoff readiness, artifact actions, current export states and export history into focused surfaces. Provider Capabilities uses the same system-workspace rhythm with loading/error/empty cards, provider capability cards and dedicated attribution/license provenance cards.
The right-side inspector also uses mobile-safe metadata and tool panels. Dataset filenames, checksums, bounds, job JSON, raster/vector operation inputs and inspector action groups wrap or scroll within the inspector instead of widening the workbench.
Export Preview shows a compact JSON summary before the payload and keeps large JSON/GeoJSON handoff artifacts inside a scroll-contained preview shell. HTML report artifacts remain download-only.
@@ -105,6 +105,7 @@ export function ExportCenter({
return (
<section className="export-center" data-testid="export-center">
<div className="export-center-shell">
<div className="panel-title-row">
<div>
<h2>Export Center</h2>
@@ -112,6 +113,8 @@ export function ExportCenter({
</div>
<span className="count-pill">{exports.length} exports</span>
</div>
<div className="export-summary-surface" aria-label="Export summary">
<div className="quality-summary-grid">
<div>
<span>GeoJSON</span>
@@ -126,6 +129,9 @@ export function ExportCenter({
<strong>{selectedDataset?.name ?? 'none'}</strong>
</div>
</div>
</div>
<div className="export-handoff-surface" aria-label="Export handoff readiness">
<div className="handoff-summary-card">
<div className="panel-title-row">
<div>
@@ -153,6 +159,15 @@ export function ExportCenter({
</div>
</div>
</div>
</div>
<div className="export-actions-surface" aria-label="Export artifact actions">
<div className="panel-title-row">
<div>
<h3>Artifact actions</h3>
<p className="muted">Create review artifacts from the current project, dataset or selected AI analysis run.</p>
</div>
</div>
<div className="export-action-grid">
<div className="handoff-action-grid">
<div className="handoff-action-card">
@@ -217,6 +232,9 @@ export function ExportCenter({
</div>
</div>
</div>
</div>
<div className="export-state-stack">
{loadingExports ? (
<div className="result-state result-state-loading">
<strong>Loading export registry.</strong>
@@ -242,6 +260,13 @@ export function ExportCenter({
<p>Create metadata, GeoJSON or HTML report artifacts once the active project has data to hand off.</p>
</div>
) : null}
</div>
<div className="export-history-surface" aria-label="Export history">
<div>
<h3>Export history</h3>
<p className="muted">Review persisted artifacts and open JSON previews where supported.</p>
</div>
{exports.length > 0 ? (
<div className="export-history-controls" aria-label="Export history filters">
<label>
@@ -337,6 +362,8 @@ export function ExportCenter({
</li>
))}
</ul>
</div>
</div>
</section>
)
}
@@ -15,6 +15,7 @@ export function ProviderPanel({
}: ProviderPanelProps): JSX.Element {
return (
<section className="system-provider-panel">
<div className="system-provider-shell">
<div className="panel-title-row">
<div>
<h2>Provider Capabilities</h2>
@@ -24,9 +25,29 @@ export function ProviderPanel({
Refresh providers
</button>
</div>
{loadingCapabilities ? <p>Loading provider capabilities...</p> : null}
{capabilitiesError ? <p className="error">{capabilitiesError}</p> : null}
{providers.length === 0 && !loadingCapabilities ? <p>No providers reported by backend</p> : null}
<div className="system-provider-state-stack">
{loadingCapabilities ? (
<div className="result-state result-state-loading">
<strong>Loading provider capabilities.</strong>
<p>Checking local, fixture and external provider registry states.</p>
</div>
) : null}
{capabilitiesError ? (
<div className="result-state result-state-error">
<strong>Provider registry unavailable.</strong>
<p>{capabilitiesError}</p>
</div>
) : null}
{providers.length === 0 && !loadingCapabilities ? (
<div className="result-state result-state-empty">
<strong>No providers reported by backend.</strong>
<p>Refresh provider capabilities after the backend is reachable.</p>
</div>
) : null}
</div>
<div className="system-provider-capability-surface" aria-label="Provider capability registry">
<ul className="system-provider-list">
{providers.map((provider) => (
<li className="system-provider-card" key={provider.provider_name}>
@@ -62,15 +83,27 @@ export function ProviderPanel({
</span>
))}
</div>
<div className="provider-detail-stack">
<div>limitation: {provider.limitation_message}</div>
<div>attribution: {provider.attribution}</div>
<div>license: {provider.license_note}</div>
{!provider.configured && provider.not_configured_reason ? (
<div>reason: {provider.not_configured_reason}</div>
) : null}
</div>
<div className="provider-provenance-grid">
<div className="provider-provenance-card">
<span>Attribution</span>
<strong>{provider.attribution}</strong>
</div>
<div className="provider-provenance-card">
<span>License</span>
<strong>{provider.license_note}</strong>
</div>
</div>
</li>
))}
</ul>
</div>
</div>
</section>
)
}
+91
View File
@@ -1766,6 +1766,60 @@ button.entity-card {
margin: 0.8rem 0;
}
.export-center-shell,
.system-provider-shell {
display: grid;
gap: 0.85rem;
min-width: 0;
}
.export-summary-surface,
.export-handoff-surface,
.export-actions-surface,
.export-history-surface,
.system-provider-capability-surface {
display: grid;
gap: 0.68rem;
min-width: 0;
border: 1px solid var(--line);
border-radius: 8px;
padding: 0.78rem;
background: linear-gradient(180deg, #ffffff, #f7fbf8);
box-shadow: 0 1px 0 rgba(19, 32, 24, 0.03);
}
.export-history-surface,
.system-provider-capability-surface {
background: #ffffff;
}
.export-center-shell .quality-summary-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
gap: 0.58rem;
margin: 0;
}
.export-handoff-surface .handoff-summary-card {
margin-top: 0;
border: 0;
padding: 0;
background: transparent;
box-shadow: none;
}
.export-actions-surface .export-action-grid {
margin: 0;
}
.export-state-stack,
.system-provider-state-stack,
.provider-detail-stack {
display: grid;
gap: 0.5rem;
min-width: 0;
}
.export-action-grid button {
min-height: 2.8rem;
text-align: left;
@@ -2045,6 +2099,43 @@ button.entity-card {
font-weight: 800;
}
.provider-detail-stack {
color: var(--muted);
font-size: 0.84rem;
line-height: 1.36;
}
.provider-provenance-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
gap: 0.5rem;
}
.provider-provenance-card {
min-width: 0;
border: 1px solid rgba(15, 118, 110, 0.16);
border-radius: 7px;
padding: 0.55rem;
background: #ffffff;
}
.provider-provenance-card span {
display: block;
color: var(--muted);
font-size: 0.68rem;
font-weight: 800;
letter-spacing: 0.05em;
text-transform: uppercase;
}
.provider-provenance-card strong {
display: block;
margin-top: 0.18rem;
overflow-wrap: anywhere;
font-size: 0.88rem;
line-height: 1.25;
}
.export-preview-panel .job-result {
max-height: 38rem;
}