Add overview workflow guidance
This commit is contained in:
@@ -7,6 +7,14 @@
|
|||||||
|
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## Sprint 90 workflow guidance polish (2026-06-20)
|
||||||
|
|
||||||
|
- Added an Overview workflow guidance rail for the V1 path: Project & AOI, Data, Map, QA / AI and Export.
|
||||||
|
- The guidance rail uses existing workspace navigation only; it does not add API calls, backend behavior or persistence.
|
||||||
|
- Added compact ready/waiting/next visual states based on already loaded project, dataset, map, QA/AI and export state.
|
||||||
|
- Added regression coverage for the guidance rail, existing workspace routing and responsive CSS contracts.
|
||||||
|
- No API contracts, migrations, backend behavior, provider fetching or AI model behavior changed.
|
||||||
|
|
||||||
## Sprint 89 Export/System density polish (2026-06-20)
|
## 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 Export Center summary, handoff readiness, artifact actions, state cards and history into focused surfaces.
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
|
||||||
|
|
||||||
|
def test_overview_exposes_end_to_end_workflow_guidance() -> None:
|
||||||
|
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
assert 'aria-label="V1 workflow guidance"' in app
|
||||||
|
assert 'className="workflow-guidance-panel"' in app
|
||||||
|
assert 'className="workflow-guidance-steps"' in app
|
||||||
|
assert "workflowGuidanceSteps.map" in app
|
||||||
|
assert "Project & AOI" in app
|
||||||
|
assert "Data" in app
|
||||||
|
assert "Map" in app
|
||||||
|
assert "QA / AI" in app
|
||||||
|
assert "Export" in app
|
||||||
|
|
||||||
|
|
||||||
|
def test_workflow_guidance_routes_to_existing_workspaces() -> None:
|
||||||
|
app = (ROOT / "frontend" / "src" / "App.tsx").read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
assert "target: 'data'" in app
|
||||||
|
assert "target: 'map'" in app
|
||||||
|
assert "target: 'analysis'" in app
|
||||||
|
assert "target: 'exports'" in app
|
||||||
|
assert "onOpenAiWorkspace={() => setActiveWorkspace('ai')}" in app
|
||||||
|
assert "onClick={() => setActiveWorkspace(step.target)}" in app
|
||||||
|
|
||||||
|
|
||||||
|
def test_workflow_guidance_has_responsive_contracts() -> None:
|
||||||
|
css = (ROOT / "frontend" / "src" / "styles" / "app.css").read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
assert ".workflow-guidance-panel" in css
|
||||||
|
assert ".workflow-guidance-steps" in css
|
||||||
|
assert ".workflow-guidance-step" in css
|
||||||
|
assert ".workflow-guidance-step-active" in css
|
||||||
|
assert ".workflow-step-status" in css
|
||||||
|
assert "grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));" in css
|
||||||
@@ -3245,3 +3245,34 @@ Limitations:
|
|||||||
|
|
||||||
Next recommended pass:
|
Next recommended pass:
|
||||||
- Continue with end-to-end workflow guidance after this pass is deployed and visually checked.
|
- Continue with end-to-end workflow guidance after this pass is deployed and visually checked.
|
||||||
|
|
||||||
|
## Sprint 90 workflow guidance polish (2026-06-20)
|
||||||
|
|
||||||
|
Changed:
|
||||||
|
- Added an Overview `workflow-guidance-panel` that shows the V1 flow from Project & AOI through Data, Map, QA / AI and Export.
|
||||||
|
- Added ready/waiting/next state labels from existing loaded project, dataset, map, QA/AI and export state.
|
||||||
|
- Routed the guidance cards through the existing `setActiveWorkspace` navigation only.
|
||||||
|
- Added compact responsive CSS for the guidance rail.
|
||||||
|
- Added `backend/tests/test_sprint90_workflow_guidance.py`.
|
||||||
|
- Updated `frontend/README.md`, `docs/TODO.md` and `CHANGELOG.md`.
|
||||||
|
|
||||||
|
Tested:
|
||||||
|
- Red step: `python -m pytest backend/tests/test_sprint90_workflow_guidance.py -q` failed on missing workflow guidance App and CSS contracts.
|
||||||
|
- `python -m pytest backend/tests/test_sprint90_workflow_guidance.py backend/tests/test_sprint83_workspace_panel_hierarchy.py backend/tests/test_sprint49_workbench_shell_refactor.py backend/tests/test_sprint62_frontend_visual_polish.py backend/tests/test_sprint82_shell_density_polish.py -q` (`13 passed`)
|
||||||
|
- `cd frontend && npm run typecheck`
|
||||||
|
- `cd frontend && npm run build`
|
||||||
|
- `bash scripts/run_readiness_check.sh` (`306 passed`; frontend typecheck/build passed; Alembic head `202606120900`; live smoke syntax passed)
|
||||||
|
- Local browser UI check against `http://127.0.0.1:5174` passed on desktop and mobile: workflow guidance panel rendered with five steps and no horizontal overflow. Local console showed expected Vite proxy 500s because only the frontend server was running.
|
||||||
|
- Tower deploy via `scripts/deploy_tower.ps1` rebuilt and restarted the all-in-one container on `http://192.168.10.150:1202` from commit `2a0e7e7`.
|
||||||
|
- Tower deploy live migration smoke passed with PostGIS `3.6 USE_GEOS=1 USE_PROJ=1 USE_STATS=1` and required runtime schema objects present.
|
||||||
|
- Browser runtime verification passed for frontend, proxied API and icon.
|
||||||
|
- Live browser UI check against `http://192.168.10.150:1202` passed on desktop and mobile: workflow guidance panel rendered with five steps, no horizontal overflow and no console warnings/errors.
|
||||||
|
|
||||||
|
Open:
|
||||||
|
- None known after full readiness, Tower deploy and live browser validation.
|
||||||
|
|
||||||
|
Limitations:
|
||||||
|
- Frontend Overview workflow guidance only; no API contract, persistence, migration, provider fetching or AI/model behavior changes.
|
||||||
|
|
||||||
|
Next recommended pass:
|
||||||
|
- After deploy and visual validation, continue with any remaining end-to-end workflow handoff polish surfaced by the live audit.
|
||||||
|
|||||||
@@ -361,3 +361,4 @@ This file now starts with the current implementation status. Older preparation/b
|
|||||||
- [x] Add QA/QC metric card polish for precision, recall, F1, IoU and error counts.
|
- [x] Add QA/QC metric card polish for precision, recall, F1, IoU and error counts.
|
||||||
- [x] Add mobile overflow hardening for workbench navigation, inspector and long QA identifiers.
|
- [x] Add mobile overflow hardening for workbench navigation, inspector and long QA identifiers.
|
||||||
- [x] Add QA/QC result filtering and density controls for long-running demo projects.
|
- [x] Add QA/QC result filtering and density controls for long-running demo projects.
|
||||||
|
- [x] Add Overview workflow guidance for the V1 project -> data -> map -> QA/AI -> export path.
|
||||||
|
|||||||
@@ -248,6 +248,7 @@ Detection Lab and Segmentation Lab now share the same AI workspace hierarchy: mo
|
|||||||
- The workbench shell includes a compact command bar, consistent raised/sunken surfaces, structured empty states and scroll-safe AI result tables to keep the V1 workflow usable across desktop and mobile widths.
|
- The workbench shell includes a compact command bar, consistent raised/sunken surfaces, structured empty states and scroll-safe AI result tables to keep the V1 workflow usable across desktop and mobile widths.
|
||||||
- The shell includes a keyboard skip link, an explicit primary workspace navigation label and compact horizontal context/navigation rails on narrow screens so active workspace content is reachable without a tall preamble.
|
- The shell includes a keyboard skip link, an explicit primary workspace navigation label and compact horizontal context/navigation rails on narrow screens so active workspace content is reachable without a tall preamble.
|
||||||
- The Overview workspace separates readiness, status tiles and recommended next actions into distinct visual hierarchy regions, keeping the first screen scannable without changing workflow behavior.
|
- The Overview workspace separates readiness, status tiles and recommended next actions into distinct visual hierarchy regions, keeping the first screen scannable without changing workflow behavior.
|
||||||
|
- The Overview workspace now also shows a compact workflow guidance rail for the V1 path from project and AOI setup through data, map review, QA/AI validation and export handoff.
|
||||||
- The Data workspace surfaces selected project, AOI and dataset context before creation/upload forms, then separates form and catalog/list regions for faster scanning.
|
- The Data workspace surfaces selected project, AOI and dataset context before creation/upload forms, then separates form and catalog/list regions for faster scanning.
|
||||||
- The Export Center includes a handoff readiness summary, grouped artifact actions and provenance-rich export cards so report/GeoJSON handoff stays understandable in long-running demo projects.
|
- The Export Center includes a handoff readiness summary, grouped artifact actions and provenance-rich export cards so report/GeoJSON handoff stays understandable in long-running demo projects.
|
||||||
|
|
||||||
|
|||||||
@@ -449,6 +449,67 @@ function App(): JSX.Element {
|
|||||||
}
|
}
|
||||||
setActiveWorkspace('exports')
|
setActiveWorkspace('exports')
|
||||||
}
|
}
|
||||||
|
const hasAnalysisOutput = qualityChecks.length > 0 || Boolean(changeDetectionResult) || detectionItems.length > 0 || segmentationItems.length > 0
|
||||||
|
const recommendedWorkflowTarget: WorkspaceKey = !selectedProjectId
|
||||||
|
? 'data'
|
||||||
|
: datasets.length === 0
|
||||||
|
? 'data'
|
||||||
|
: mapFeatureCount === 0 && areaFeatureCount === 0
|
||||||
|
? 'map'
|
||||||
|
: !hasAnalysisOutput
|
||||||
|
? 'analysis'
|
||||||
|
: exports.length === 0
|
||||||
|
? 'exports'
|
||||||
|
: 'exports'
|
||||||
|
const workflowGuidanceSteps: Array<{
|
||||||
|
step: string
|
||||||
|
title: string
|
||||||
|
detail: string
|
||||||
|
status: string
|
||||||
|
ready: boolean
|
||||||
|
target: WorkspaceKey
|
||||||
|
}> = [
|
||||||
|
{
|
||||||
|
step: '1',
|
||||||
|
title: 'Project & AOI',
|
||||||
|
detail: selectedProjectId ? `${areas.length} AOI record${areas.length === 1 ? '' : 's'} available` : 'Create or load a project context',
|
||||||
|
status: selectedProjectId ? 'ready' : 'next',
|
||||||
|
ready: Boolean(selectedProjectId),
|
||||||
|
target: 'data',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
step: '2',
|
||||||
|
title: 'Data',
|
||||||
|
detail: datasets.length > 0 ? `${datasets.length} dataset${datasets.length === 1 ? '' : 's'} loaded` : 'Upload source and reference datasets',
|
||||||
|
status: datasets.length > 0 ? 'ready' : 'waiting',
|
||||||
|
ready: datasets.length > 0,
|
||||||
|
target: 'data',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
step: '3',
|
||||||
|
title: 'Map',
|
||||||
|
detail: mapFeatureCount > 0 || areaFeatureCount > 0 ? `${mapFeatureCount + areaFeatureCount} active map feature${mapFeatureCount + areaFeatureCount === 1 ? '' : 's'}` : 'Inspect AOI and selected layer',
|
||||||
|
status: mapFeatureCount > 0 || areaFeatureCount > 0 ? 'ready' : 'waiting',
|
||||||
|
ready: mapFeatureCount > 0 || areaFeatureCount > 0,
|
||||||
|
target: 'map',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
step: '4',
|
||||||
|
title: 'QA / AI',
|
||||||
|
detail: hasAnalysisOutput ? 'QA, change, detection or segmentation output exists' : 'Run checks after data is ready',
|
||||||
|
status: hasAnalysisOutput ? 'ready' : 'waiting',
|
||||||
|
ready: hasAnalysisOutput,
|
||||||
|
target: 'analysis',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
step: '5',
|
||||||
|
title: 'Export',
|
||||||
|
detail: exports.length > 0 ? `${exports.length} export artifact${exports.length === 1 ? '' : 's'} recorded` : 'Package validated project outputs',
|
||||||
|
status: exports.length > 0 ? 'ready' : 'waiting',
|
||||||
|
ready: exports.length > 0,
|
||||||
|
target: 'exports',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="app-shell workbench-shell">
|
<div className="app-shell workbench-shell">
|
||||||
@@ -539,6 +600,40 @@ function App(): JSX.Element {
|
|||||||
activeLayerFeatureCount={mapFeatureCount}
|
activeLayerFeatureCount={mapFeatureCount}
|
||||||
selectedAreaHasGeometry={Boolean(areaFeatureCollection)}
|
selectedAreaHasGeometry={Boolean(areaFeatureCollection)}
|
||||||
/>
|
/>
|
||||||
|
<section className="workflow-guidance-panel" aria-label="V1 workflow guidance">
|
||||||
|
<div className="panel-title-row">
|
||||||
|
<div>
|
||||||
|
<p className="eyebrow">Workbench flow</p>
|
||||||
|
<h2>Project to export path</h2>
|
||||||
|
</div>
|
||||||
|
<span className="status-badge">
|
||||||
|
Next: {workspaceNavItems.find((item) => item.key === recommendedWorkflowTarget)?.label ?? 'Overview'}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="workflow-guidance-steps">
|
||||||
|
{workflowGuidanceSteps.map((step) => (
|
||||||
|
<button
|
||||||
|
key={`${step.step}-${step.title}`}
|
||||||
|
type="button"
|
||||||
|
className={
|
||||||
|
step.target === recommendedWorkflowTarget && !step.ready
|
||||||
|
? 'workflow-guidance-step workflow-guidance-step-active'
|
||||||
|
: step.ready
|
||||||
|
? 'workflow-guidance-step workflow-guidance-step-ready'
|
||||||
|
: 'workflow-guidance-step'
|
||||||
|
}
|
||||||
|
onClick={() => setActiveWorkspace(step.target)}
|
||||||
|
aria-label={`Open ${step.title} step`}
|
||||||
|
>
|
||||||
|
<span className="workflow-step-status">{step.status}</span>
|
||||||
|
<strong>
|
||||||
|
{step.step}. {step.title}
|
||||||
|
</strong>
|
||||||
|
<small>{step.detail}</small>
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
<section className="overview-actions">
|
<section className="overview-actions">
|
||||||
<div className="overview-action-copy">
|
<div className="overview-action-copy">
|
||||||
<p className="eyebrow">Recommended flow</p>
|
<p className="eyebrow">Recommended flow</p>
|
||||||
|
|||||||
@@ -835,6 +835,62 @@ section li strong + div {
|
|||||||
align-self: stretch;
|
align-self: stretch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.workflow-guidance-panel {
|
||||||
|
display: grid;
|
||||||
|
gap: 0.72rem;
|
||||||
|
border-left: 4px solid #2563eb;
|
||||||
|
background: linear-gradient(180deg, #ffffff, #f7fbf8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.workflow-guidance-panel .panel-title-row {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.workflow-guidance-steps {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
|
||||||
|
gap: 0.55rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.workflow-guidance-step {
|
||||||
|
display: grid;
|
||||||
|
align-content: start;
|
||||||
|
gap: 0.28rem;
|
||||||
|
min-height: 5.35rem;
|
||||||
|
border-color: var(--line);
|
||||||
|
padding: 0.62rem 0.68rem;
|
||||||
|
background: #ffffff;
|
||||||
|
text-align: left;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.workflow-guidance-step small {
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 0.78rem;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.workflow-guidance-step-active {
|
||||||
|
border-color: rgba(15, 118, 110, 0.46);
|
||||||
|
background: var(--accent-soft);
|
||||||
|
box-shadow: inset 0 0 0 1px rgba(15, 118, 110, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.workflow-guidance-step-ready {
|
||||||
|
border-color: rgba(21, 128, 61, 0.28);
|
||||||
|
background: #f2fbf5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.workflow-step-status {
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 0.68rem;
|
||||||
|
font-weight: 850;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
line-height: 1.2;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
.overview-actions {
|
.overview-actions {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: minmax(0, 1fr) minmax(16rem, 24rem);
|
grid-template-columns: minmax(0, 1fr) minmax(16rem, 24rem);
|
||||||
|
|||||||
Reference in New Issue
Block a user