Polish live workbench shell layout
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 23:16:23 +02:00
parent 6d43de4b5c
commit ae7e4bf5a3
7 changed files with 115 additions and 28 deletions
+11
View File
@@ -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.
@@ -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<WorkspaceKey>('overview')" in app
@@ -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")
+28
View File
@@ -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.
+1
View File
@@ -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.
+5 -1
View File
@@ -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<WorkspaceKey>('overview')
useEffect(() => {
window.scrollTo({ top: 0, left: 0 })
}, [activeWorkspace])
const {
projects,
selectedProject,
+55 -25
View File
@@ -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) {