From b3548bfd524f59a30ccc013035acc4e10515b0a3 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 17 Jun 2026 21:45:21 +0200 Subject: [PATCH] Improve dataset selection ergonomics --- CHANGELOG.md | 9 ++++ .../test_sprint53_selection_ergonomics.py | 50 +++++++++++++++++++ docs/CODEX_EXECUTION_LOG.md | 25 ++++++++++ docs/TODO.md | 3 +- frontend/src/App.tsx | 21 ++++++++ .../src/components/datasets/DatasetPanel.tsx | 19 ++++++- .../inspector/WorkbenchInspector.tsx | 46 +++++++++++++++++ frontend/src/styles/app.css | 27 +++++++++- 8 files changed, 197 insertions(+), 3 deletions(-) create mode 100644 backend/tests/test_sprint53_selection_ergonomics.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 056466e2..00edefd1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -595,3 +595,12 @@ Added: - Added context cards for selected project, AOI, map feature, latest QA/QC result, latest export and selected detection/segmentation run state. - Added regression coverage for inspector wiring and tab structure. - No API contracts, migrations, product capabilities, live provider fetching or AI/model dependency changes were introduced. + +## Sprint 53 map/dataset selection ergonomics (2026-06-17) + +- Added active selected-state styling to dataset cards. +- Added dataset quick actions for opening the selected dataset in the Map workspace or Exports workspace. +- Added inspector navigation actions for Data, Map, QA/QC, Exports and AI Labs workspaces. +- Preserved existing dataset detail loading, map layer state, export actions and API client behavior. +- Added regression coverage for dataset quick actions and inspector navigation wiring. +- No API contracts, migrations, product capabilities, live provider fetching or AI/model dependency changes were introduced. diff --git a/backend/tests/test_sprint53_selection_ergonomics.py b/backend/tests/test_sprint53_selection_ergonomics.py new file mode 100644 index 00000000..e91c077a --- /dev/null +++ b/backend/tests/test_sprint53_selection_ergonomics.py @@ -0,0 +1,50 @@ +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[2] + + +def test_dataset_panel_exposes_map_and_export_quick_actions() -> None: + panel = (ROOT / "frontend" / "src" / "components" / "datasets" / "DatasetPanel.tsx").read_text( + encoding="utf-8" + ) + + assert "selectedDatasetId" in panel + assert "dataset-card-active" in panel + assert "onOpenDatasetInMap" in panel + assert "onOpenDatasetExport" in panel + assert "Open in map" in panel + assert "Export / QA" in panel + assert "disabled={!(dataset.dataset_type === 'vector' || dataset.dataset_type === 'geojson')}" in panel + + +def test_app_wires_dataset_quick_actions_to_existing_workspaces() -> None: + app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8") + + assert "const openDatasetInMap = (dataset: DatasetCreateResponse) => {" in app + assert "loadDatasetDetails(selectedProjectId, dataset)" in app + assert "setMapLayerVisible(true)" in app + assert "setActiveWorkspace('map')" in app + assert "const openDatasetExport = (dataset: DatasetCreateResponse) => {" in app + assert "setActiveWorkspace('exports')" in app + assert "selectedDatasetId={selectedDatasetId}" in app + assert "onOpenDatasetInMap={openDatasetInMap}" in app + assert "onOpenDatasetExport={openDatasetExport}" in app + + +def test_inspector_exposes_navigation_actions_without_api_calls() -> None: + inspector = ( + ROOT / "frontend" / "src" / "components" / "inspector" / "WorkbenchInspector.tsx" + ).read_text(encoding="utf-8") + + assert "onOpenDataWorkspace" in inspector + assert "onOpenMapWorkspace" in inspector + assert "onOpenQualityWorkspace" in inspector + assert "onOpenExportsWorkspace" in inspector + assert "onOpenAiWorkspace" in inspector + assert "Data catalog" in inspector + assert "Map layer" in inspector + assert "Open QA/QC" in inspector + assert "Open exports" in inspector + assert "Open AI Labs" in inspector + assert "fetch(" not in inspector diff --git a/docs/CODEX_EXECUTION_LOG.md b/docs/CODEX_EXECUTION_LOG.md index 7cf9ae55..b6232ee7 100644 --- a/docs/CODEX_EXECUTION_LOG.md +++ b/docs/CODEX_EXECUTION_LOG.md @@ -2147,3 +2147,28 @@ Limitations: Next recommended pass: - Verify the tabbed inspector live on Tower, then continue with map/dataset selection ergonomics. + +## Sprint 53 map/dataset selection ergonomics (2026-06-17) + +Changed: +- Added active-state styling to dataset cards so the selected dataset is visibly anchored in the catalog. +- Added dataset quick actions to open a dataset directly in the Map workspace or Exports workspace after loading details. +- Added inspector navigation actions to jump to Data, Map, QA/QC, Exports and AI Labs without hunting through the left navigation. +- Kept the existing dataset loading, map layer state, export flow and API clients unchanged. +- Added regression coverage for selection quick actions and inspector navigation wiring. + +Tested: +- `cd frontend && npm run typecheck` +- `cd backend && python -m pytest tests/test_sprint28_dataset_workflow_hook.py tests/test_sprint29_dataset_components.py tests/test_sprint52_workbench_inspector_tabs.py -q` +- `cd backend && python -m pytest tests/test_sprint53_selection_ergonomics.py -q` +- `cd frontend && npm run build` +- `bash scripts/run_readiness_check.sh` (`213 passed`) + +Open: +- Commit, push, deploy to Tower and verify browser-facing runtime. + +Limitations: +- This pass remains UI orchestration only. It does not add features, change API contracts, alter migrations, fetch live providers or enable new AI models. + +Next recommended pass: +- Verify dataset quick actions with demo data on Tower, then improve populated map/detail readability if needed. diff --git a/docs/TODO.md b/docs/TODO.md index 293bc3e1..89d8774b 100644 --- a/docs/TODO.md +++ b/docs/TODO.md @@ -322,4 +322,5 @@ This file now starts with the current implementation status. Older preparation/b - [x] Polish Data, Map and AI Labs workspaces. - [x] Polish QA/QC and Exports workspaces. - [x] Add selected-object inspector detail tabs for project, AOI, dataset, QA check, export and AI run context. -- [ ] Improve map/dataset selection ergonomics from the workbench canvas and inspector. +- [x] Improve map/dataset selection ergonomics from the workbench canvas and inspector. +- [ ] Improve populated map/detail readability after a demo workflow run. diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index dafd9f91..0ea35e96 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -385,6 +385,19 @@ function App(): JSX.Element { const selectedArea = areas.find((area) => area.id === selectedMapAreaId) ?? null const activeWorkspaceItem = workspaceNavItems.find((item) => item.key === activeWorkspace) ?? workspaceNavItems[0] + const openDatasetInMap = (dataset: DatasetCreateResponse) => { + if (selectedProjectId) { + loadDatasetDetails(selectedProjectId, dataset) + } + setMapLayerVisible(true) + setActiveWorkspace('map') + } + const openDatasetExport = (dataset: DatasetCreateResponse) => { + if (selectedProjectId) { + loadDatasetDetails(selectedProjectId, dataset) + } + setActiveWorkspace('exports') + } return (
@@ -510,6 +523,7 @@ function App(): JSX.Element {
) : null} @@ -705,6 +721,11 @@ function App(): JSX.Element { segmentationRuns={segmentationRuns} selectedSegmentationRunId={selectedSegmentationRunId} segmentationItems={segmentationItems} + onOpenDataWorkspace={() => setActiveWorkspace('data')} + onOpenMapWorkspace={() => setActiveWorkspace('map')} + onOpenQualityWorkspace={() => setActiveWorkspace('analysis')} + onOpenExportsWorkspace={() => setActiveWorkspace('exports')} + onOpenAiWorkspace={() => setActiveWorkspace('ai')} datasetDetailProps={{ areas, availableVectorTargets, diff --git a/frontend/src/components/datasets/DatasetPanel.tsx b/frontend/src/components/datasets/DatasetPanel.tsx index f07beb18..7395a33c 100644 --- a/frontend/src/components/datasets/DatasetPanel.tsx +++ b/frontend/src/components/datasets/DatasetPanel.tsx @@ -15,6 +15,7 @@ interface DatasetFormState { interface DatasetPanelProps { selectedProjectId: string | null + selectedDatasetId: string | null areas: AreaRead[] datasets: DatasetCreateResponse[] datasetForm: DatasetFormState @@ -23,6 +24,8 @@ interface DatasetPanelProps { onUploadDataset: (event: FormEvent) => void onLoadDatasetDetails: (projectId: string, dataset: DatasetCreateResponse) => void onRefreshMetadata: (datasetId: string) => void + onOpenDatasetInMap: (dataset: DatasetCreateResponse) => void + onOpenDatasetExport: (dataset: DatasetCreateResponse) => void } function formatBytes(value: number | null | undefined): string { @@ -52,6 +55,7 @@ function formatBounds(bounds: Record | null | undefined): string export function DatasetPanel({ selectedProjectId, + selectedDatasetId, areas, datasets, datasetForm, @@ -60,6 +64,8 @@ export function DatasetPanel({ onUploadDataset, onLoadDatasetDetails, onRefreshMetadata, + onOpenDatasetInMap, + onOpenDatasetExport, }: DatasetPanelProps) { const readyDatasets = datasets.filter((dataset) => dataset.status === 'ready').length @@ -124,7 +130,7 @@ export function DatasetPanel({ {datasets.length === 0 ?

No datasets yet

: null}