Polish live workbench shell layout
This commit is contained in:
@@ -614,3 +614,14 @@ Added:
|
|||||||
- Shortened displayed export paths while preserving the full path in the element title.
|
- 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.
|
- 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.
|
- 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")
|
app = app_path.read_text(encoding="utf-8")
|
||||||
|
|
||||||
assert not app_bytes.startswith(b"\xef\xbb\xbf")
|
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 "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
|
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
|
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:
|
def test_app_wires_dataset_quick_actions_to_existing_workspaces() -> None:
|
||||||
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
|
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
|||||||
@@ -2207,3 +2207,31 @@ Limitations:
|
|||||||
|
|
||||||
Next recommended pass:
|
Next recommended pass:
|
||||||
- Add export history filtering or retention controls if artifact history continues to grow during demo runs.
|
- 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.
|
||||||
|
|||||||
@@ -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] 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 map/dataset selection ergonomics from the workbench canvas and inspector.
|
||||||
- [x] Improve populated Data/Exports readability after a demo workflow run.
|
- [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.
|
- [ ] Add export history filtering or retention controls for long-running demo environments.
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useMemo, useState } from 'react'
|
import { useEffect, useMemo, useState } from 'react'
|
||||||
import './styles/app.css'
|
import './styles/app.css'
|
||||||
import { ChangeDetectionPanel } from './components/analysis/ChangeDetectionPanel'
|
import { ChangeDetectionPanel } from './components/analysis/ChangeDetectionPanel'
|
||||||
import { DatasetPanel } from './components/datasets/DatasetPanel'
|
import { DatasetPanel } from './components/datasets/DatasetPanel'
|
||||||
@@ -44,6 +44,10 @@ const workspaceNavItems: Array<{ key: WorkspaceKey; label: string; description:
|
|||||||
|
|
||||||
function App(): JSX.Element {
|
function App(): JSX.Element {
|
||||||
const [activeWorkspace, setActiveWorkspace] = useState<WorkspaceKey>('overview')
|
const [activeWorkspace, setActiveWorkspace] = useState<WorkspaceKey>('overview')
|
||||||
|
useEffect(() => {
|
||||||
|
window.scrollTo({ top: 0, left: 0 })
|
||||||
|
}, [activeWorkspace])
|
||||||
|
|
||||||
const {
|
const {
|
||||||
projects,
|
projects,
|
||||||
selectedProject,
|
selectedProject,
|
||||||
|
|||||||
+55
-25
@@ -519,38 +519,43 @@ section li strong + div {
|
|||||||
top: 0;
|
top: 0;
|
||||||
z-index: 20;
|
z-index: 20;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: minmax(16rem, 26rem) minmax(0, 1fr);
|
grid-template-columns: minmax(12rem, 18rem) minmax(0, 1fr);
|
||||||
gap: 1rem;
|
gap: 0.75rem;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-bottom: 1px solid var(--line);
|
border-bottom: 1px solid var(--line);
|
||||||
padding: 0.85rem 1rem;
|
padding: 0.55rem 0.85rem;
|
||||||
background: rgba(248, 251, 249, 0.96);
|
background: rgba(248, 251, 249, 0.96);
|
||||||
backdrop-filter: blur(12px);
|
backdrop-filter: blur(12px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.brand-block h1 {
|
.brand-block h1 {
|
||||||
font-size: 1.45rem;
|
font-size: 1.18rem;
|
||||||
line-height: 1.1;
|
line-height: 1.1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.brand-block .eyebrow {
|
||||||
|
margin-bottom: 0.12rem;
|
||||||
|
font-size: 0.66rem;
|
||||||
|
}
|
||||||
|
|
||||||
.context-bar {
|
.context-bar {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||||
gap: 0.65rem;
|
gap: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.context-bar > div {
|
.context-bar > div {
|
||||||
min-height: 4.2rem;
|
min-height: 3.2rem;
|
||||||
border: 1px solid var(--line);
|
border: 1px solid var(--line);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 0.62rem 0.72rem;
|
padding: 0.44rem 0.58rem;
|
||||||
background: #ffffff;
|
background: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.context-bar span {
|
.context-bar span {
|
||||||
display: block;
|
display: block;
|
||||||
color: var(--muted);
|
color: var(--muted);
|
||||||
font-size: 0.72rem;
|
font-size: 0.66rem;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
letter-spacing: 0.05em;
|
letter-spacing: 0.05em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
@@ -558,16 +563,16 @@ section li strong + div {
|
|||||||
|
|
||||||
.context-bar strong {
|
.context-bar strong {
|
||||||
display: block;
|
display: block;
|
||||||
margin-top: 0.3rem;
|
margin-top: 0.18rem;
|
||||||
font-size: 0.92rem;
|
font-size: 0.84rem;
|
||||||
line-height: 1.25;
|
line-height: 1.25;
|
||||||
}
|
}
|
||||||
|
|
||||||
.workbench-layout {
|
.workbench-layout {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 14rem minmax(0, 1fr) 24rem;
|
grid-template-columns: 12.5rem minmax(0, 1fr) 21rem;
|
||||||
gap: 0;
|
gap: 0;
|
||||||
height: calc(100vh - 5.95rem);
|
height: calc(100vh - 4.35rem);
|
||||||
min-height: 42rem;
|
min-height: 42rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -581,7 +586,7 @@ section li strong + div {
|
|||||||
|
|
||||||
.workbench-sidebar {
|
.workbench-sidebar {
|
||||||
border-right: 1px solid var(--line);
|
border-right: 1px solid var(--line);
|
||||||
padding: 0.85rem;
|
padding: 0.72rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.workbench-sidebar nav {
|
.workbench-sidebar nav {
|
||||||
@@ -592,9 +597,9 @@ section li strong + div {
|
|||||||
.nav-item {
|
.nav-item {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-height: 4.2rem;
|
min-height: 3.7rem;
|
||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
padding: 0.66rem 0.72rem;
|
padding: 0.58rem 0.62rem;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
@@ -610,7 +615,7 @@ section li strong + div {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.nav-item span {
|
.nav-item span {
|
||||||
font-size: 0.96rem;
|
font-size: 0.9rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-item small {
|
.nav-item small {
|
||||||
@@ -631,12 +636,12 @@ section li strong + div {
|
|||||||
min-width: 0;
|
min-width: 0;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
padding: 1rem;
|
padding: 0.85rem 1rem 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.workbench-inspector {
|
.workbench-inspector {
|
||||||
border-left: 1px solid var(--line);
|
border-left: 1px solid var(--line);
|
||||||
padding: 1rem;
|
padding: 0.85rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.workbench-inspector > section {
|
.workbench-inspector > section {
|
||||||
@@ -651,10 +656,10 @@ section li strong + div {
|
|||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
align-items: end;
|
align-items: end;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 0.85rem;
|
||||||
border: 1px solid var(--line);
|
border: 1px solid var(--line);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 0.85rem 1rem;
|
padding: 0.72rem 0.85rem;
|
||||||
background: #ffffff;
|
background: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1119,7 +1124,7 @@ button.entity-card {
|
|||||||
|
|
||||||
.map-toolbar {
|
.map-toolbar {
|
||||||
display: grid;
|
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;
|
gap: 0.75rem;
|
||||||
align-items: end;
|
align-items: end;
|
||||||
margin-bottom: 0.85rem;
|
margin-bottom: 0.85rem;
|
||||||
@@ -1165,7 +1170,7 @@ button.entity-card {
|
|||||||
|
|
||||||
.workbench-inspector-panel {
|
.workbench-inspector-panel {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 0.8rem;
|
gap: 0.68rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.inspector-header {
|
.inspector-header {
|
||||||
@@ -1230,10 +1235,10 @@ button.entity-card {
|
|||||||
|
|
||||||
.inspector-card {
|
.inspector-card {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 0.55rem;
|
gap: 0.48rem;
|
||||||
border: 1px solid var(--line);
|
border: 1px solid var(--line);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 0.8rem;
|
padding: 0.7rem;
|
||||||
background: #ffffff;
|
background: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1282,9 +1287,15 @@ button.entity-card {
|
|||||||
gap: 0.55rem;
|
gap: 0.55rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 1120px) {
|
@media (max-width: 1360px) {
|
||||||
.workbench-layout {
|
.workbench-layout {
|
||||||
grid-template-columns: 12rem minmax(0, 1fr);
|
grid-template-columns: 12rem minmax(0, 1fr);
|
||||||
|
height: auto;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.workbench-main {
|
||||||
|
overflow: visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
.workbench-inspector {
|
.workbench-inspector {
|
||||||
@@ -1292,6 +1303,25 @@ button.entity-card {
|
|||||||
border-top: 1px solid var(--line);
|
border-top: 1px solid var(--line);
|
||||||
border-left: 0;
|
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) {
|
@media (max-width: 980px) {
|
||||||
|
|||||||
Reference in New Issue
Block a user