diff --git a/CHANGELOG.md b/CHANGELOG.md index 9925d32c..ddb7eca7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -614,3 +614,14 @@ Added: - Shortened displayed export paths while preserving the full path in the element title. - Added regression coverage for populated-state Data layout, export limiting and export preview empty state. - No API contracts, migrations, product capabilities, live provider fetching or AI/model dependency changes were introduced. + +## Sprint 55 live visual shell polish (2026-06-17) + +- Audited the live workbench visually in Browser on `http://192.168.10.150:1202`. +- Compacted the top context bar and primary navigation so the workbench has more usable canvas space. +- Moved the inspector below the workspace on standard desktop widths instead of forcing a cramped three-column layout. +- Preserved the side inspector behavior for wider screens. +- Improved Map workspace control wrapping so the map/status controls do not clip at 1280px. +- Reset page scroll on workspace changes so workspaces open from their heading instead of inheriting stale scroll positions. +- Added regression coverage for the standard-desktop layout and workspace scroll reset. +- No API contracts, migrations, product capabilities, live provider fetching or AI/model dependency changes were introduced. diff --git a/backend/tests/test_sprint39_frontend_orchestration_hooks.py b/backend/tests/test_sprint39_frontend_orchestration_hooks.py index 3a12f0e4..bd7aa74d 100644 --- a/backend/tests/test_sprint39_frontend_orchestration_hooks.py +++ b/backend/tests/test_sprint39_frontend_orchestration_hooks.py @@ -35,9 +35,10 @@ def test_app_entrypoint_has_clean_encoding_and_react_imports() -> None: app = app_path.read_text(encoding="utf-8") assert not app_bytes.startswith(b"\xef\xbb\xbf") - assert "import { useMemo, useState } from 'react'" in app + assert "import { useEffect, useMemo, useState } from 'react'" in app assert "FormEvent" not in app - assert "useEffect" not in app + assert app.count("useEffect(") == 1 + assert "window.scrollTo({ top: 0, left: 0 })" in app assert "const [activeWorkspace, setActiveWorkspace] = useState('overview')" in app diff --git a/backend/tests/test_sprint53_selection_ergonomics.py b/backend/tests/test_sprint53_selection_ergonomics.py index 27d48e15..671ca729 100644 --- a/backend/tests/test_sprint53_selection_ergonomics.py +++ b/backend/tests/test_sprint53_selection_ergonomics.py @@ -27,6 +27,18 @@ def test_data_workspace_keeps_catalog_wide_enough_for_populated_state() -> None: assert ".dataset-card .button-row" in css +def test_shell_preserves_workspace_width_on_standard_desktop_viewports() -> None: + css = (ROOT / "frontend" / "src" / "styles" / "app.css").read_text(encoding="utf-8") + app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8") + + assert "grid-template-columns: 12.5rem minmax(0, 1fr) 21rem" in css + assert "@media (max-width: 1360px)" in css + assert ".workbench-inspector {\n grid-column: 1 / -1;" in css + assert "height: auto;" in css + assert "window.scrollTo({ top: 0, left: 0 })" in app + assert "}, [activeWorkspace])" in app + + def test_app_wires_dataset_quick_actions_to_existing_workspaces() -> None: app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8") diff --git a/docs/CODEX_EXECUTION_LOG.md b/docs/CODEX_EXECUTION_LOG.md index fc8ef7b3..81c26dc3 100644 --- a/docs/CODEX_EXECUTION_LOG.md +++ b/docs/CODEX_EXECUTION_LOG.md @@ -2207,3 +2207,31 @@ Limitations: Next recommended pass: - Add export history filtering or retention controls if artifact history continues to grow during demo runs. + +## Sprint 55 live visual shell polish (2026-06-17) + +Changed: +- Performed a Browser-based visual audit of the live Tower workbench at `http://192.168.10.150:1202`. +- Confirmed the main visual defect was the cramped three-column desktop shell: left navigation, central workspace and inspector competed for width at 1280px. +- Compacted the sticky top context bar and left navigation. +- Changed the standard desktop breakpoint so the inspector moves below the workspace up to 1360px, while remaining a side panel on wider displays. +- Made the Map toolbar wrap responsively instead of forcing four controls into a narrow row. +- Added a workspace-change scroll reset so switching pages starts at the workspace heading instead of inheriting stale scroll position. +- Added regression coverage for the standard desktop shell width and scroll-reset behavior. + +Tested: +- Local Browser visual audit against `http://127.0.0.1:5177` using the live Tower API proxy. +- Verified Overview, Data, Map and Exports workspaces visually after the shell changes. +- Browser console error/warning check returned no entries. +- `cd frontend && npm run typecheck` +- `cd backend && python -m pytest tests/test_sprint53_selection_ergonomics.py tests/test_sprint50_workspace_usability_polish.py -q` +- `cd frontend && npm run build` + +Open: +- Run full readiness, deploy Tower and verify the live visual shell on `http://192.168.10.150:1202`. + +Limitations: +- This pass remains UI shell polish only. It does not add features, change API contracts, alter migrations, fetch live providers or enable new AI models. + +Next recommended pass: +- Continue with export history filtering or retention controls if repeated demo runs keep growing artifact history. diff --git a/docs/TODO.md b/docs/TODO.md index 084d9421..67468d4a 100644 --- a/docs/TODO.md +++ b/docs/TODO.md @@ -324,4 +324,5 @@ This file now starts with the current implementation status. Older preparation/b - [x] Add selected-object inspector detail tabs for project, AOI, dataset, QA check, export and AI run context. - [x] Improve map/dataset selection ergonomics from the workbench canvas and inspector. - [x] Improve populated Data/Exports readability after a demo workflow run. +- [x] Improve live visual shell width, scroll behavior and Map workspace layout at 1280px. - [ ] Add export history filtering or retention controls for long-running demo environments. diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 0ea35e96..b876726a 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,4 +1,4 @@ -import { useMemo, useState } from 'react' +import { useEffect, useMemo, useState } from 'react' import './styles/app.css' import { ChangeDetectionPanel } from './components/analysis/ChangeDetectionPanel' import { DatasetPanel } from './components/datasets/DatasetPanel' @@ -44,6 +44,10 @@ const workspaceNavItems: Array<{ key: WorkspaceKey; label: string; description: function App(): JSX.Element { const [activeWorkspace, setActiveWorkspace] = useState('overview') + useEffect(() => { + window.scrollTo({ top: 0, left: 0 }) + }, [activeWorkspace]) + const { projects, selectedProject, diff --git a/frontend/src/styles/app.css b/frontend/src/styles/app.css index a0e8a20f..af81c75e 100644 --- a/frontend/src/styles/app.css +++ b/frontend/src/styles/app.css @@ -519,38 +519,43 @@ section li strong + div { top: 0; z-index: 20; display: grid; - grid-template-columns: minmax(16rem, 26rem) minmax(0, 1fr); - gap: 1rem; + grid-template-columns: minmax(12rem, 18rem) minmax(0, 1fr); + gap: 0.75rem; align-items: center; border-bottom: 1px solid var(--line); - padding: 0.85rem 1rem; + padding: 0.55rem 0.85rem; background: rgba(248, 251, 249, 0.96); backdrop-filter: blur(12px); } .brand-block h1 { - font-size: 1.45rem; + font-size: 1.18rem; line-height: 1.1; } +.brand-block .eyebrow { + margin-bottom: 0.12rem; + font-size: 0.66rem; +} + .context-bar { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); - gap: 0.65rem; + gap: 0.5rem; } .context-bar > div { - min-height: 4.2rem; + min-height: 3.2rem; border: 1px solid var(--line); border-radius: 8px; - padding: 0.62rem 0.72rem; + padding: 0.44rem 0.58rem; background: #ffffff; } .context-bar span { display: block; color: var(--muted); - font-size: 0.72rem; + font-size: 0.66rem; font-weight: 800; letter-spacing: 0.05em; text-transform: uppercase; @@ -558,16 +563,16 @@ section li strong + div { .context-bar strong { display: block; - margin-top: 0.3rem; - font-size: 0.92rem; + margin-top: 0.18rem; + font-size: 0.84rem; line-height: 1.25; } .workbench-layout { display: grid; - grid-template-columns: 14rem minmax(0, 1fr) 24rem; + grid-template-columns: 12.5rem minmax(0, 1fr) 21rem; gap: 0; - height: calc(100vh - 5.95rem); + height: calc(100vh - 4.35rem); min-height: 42rem; } @@ -581,7 +586,7 @@ section li strong + div { .workbench-sidebar { border-right: 1px solid var(--line); - padding: 0.85rem; + padding: 0.72rem; } .workbench-sidebar nav { @@ -592,9 +597,9 @@ section li strong + div { .nav-item { display: block; width: 100%; - min-height: 4.2rem; + min-height: 3.7rem; border-color: transparent; - padding: 0.66rem 0.72rem; + padding: 0.58rem 0.62rem; background: transparent; box-shadow: none; text-align: left; @@ -610,7 +615,7 @@ section li strong + div { } .nav-item span { - font-size: 0.96rem; + font-size: 0.9rem; } .nav-item small { @@ -631,12 +636,12 @@ section li strong + div { min-width: 0; min-height: 0; overflow: auto; - padding: 1rem; + padding: 0.85rem 1rem 1rem; } .workbench-inspector { border-left: 1px solid var(--line); - padding: 1rem; + padding: 0.85rem; } .workbench-inspector > section { @@ -651,10 +656,10 @@ section li strong + div { gap: 1rem; align-items: end; justify-content: space-between; - margin-bottom: 1rem; + margin-bottom: 0.85rem; border: 1px solid var(--line); border-radius: 8px; - padding: 0.85rem 1rem; + padding: 0.72rem 0.85rem; background: #ffffff; } @@ -1119,7 +1124,7 @@ button.entity-card { .map-toolbar { display: grid; - grid-template-columns: minmax(12rem, 1fr) minmax(10rem, 0.8fr) minmax(10rem, 0.8fr) minmax(14rem, 1fr); + grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr)); gap: 0.75rem; align-items: end; margin-bottom: 0.85rem; @@ -1165,7 +1170,7 @@ button.entity-card { .workbench-inspector-panel { display: grid; - gap: 0.8rem; + gap: 0.68rem; } .inspector-header { @@ -1230,10 +1235,10 @@ button.entity-card { .inspector-card { display: grid; - gap: 0.55rem; + gap: 0.48rem; border: 1px solid var(--line); border-radius: 8px; - padding: 0.8rem; + padding: 0.7rem; background: #ffffff; } @@ -1282,9 +1287,15 @@ button.entity-card { gap: 0.55rem; } -@media (max-width: 1120px) { +@media (max-width: 1360px) { .workbench-layout { grid-template-columns: 12rem minmax(0, 1fr); + height: auto; + min-height: 0; + } + + .workbench-main { + overflow: visible; } .workbench-inspector { @@ -1292,6 +1303,25 @@ button.entity-card { border-top: 1px solid var(--line); border-left: 0; } + + .workbench-inspector-panel { + max-width: none; + } + + .inspector-tab-panel { + grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr)); + } + + .workbench-inspector-panel .dataset-detail-panel, + .inspector-action-bar { + grid-column: 1 / -1; + } + + .inspector-header h2, + .inspector-tabs, + .inspector-action-bar { + position: static; + } } @media (max-width: 980px) {