diff --git a/IMPLEMENTATION_PLAN.md b/IMPLEMENTATION_PLAN.md
index 9ba9fcd..3a89469 100644
--- a/IMPLEMENTATION_PLAN.md
+++ b/IMPLEMENTATION_PLAN.md
@@ -265,16 +265,16 @@ Comprehensive review and improvement of all Plotly charts in the Dash dashboard.
- **Checkpoint**: Patient Pathways has 9 tabs (Icicle through Doses, no Trends). `python run_dash.py` starts cleanly. PASSED.
### E.2 Add Trends sidebar nav item + view container
-- [ ] Add `"trends"` icon SVG to `_ICONS` dict in `dash_app/components/sidebar.py` — use a line chart icon: ``
-- [ ] Add `_sidebar_item("Trends", "trends", active=False, item_id="nav-trends")` to sidebar children
-- [ ] Add `html.Div(id="trends-view", style={"display": "none"}, children=[...])` to `app.py` layout inside `view-container`, after `trust-comparison-view`
-- [ ] Update `switch_view()` in `dash_app/callbacks/navigation.py`:
+- [x] Add `"trends"` icon SVG to `_ICONS` dict in `dash_app/components/sidebar.py` — use a line chart icon: ``
+- [x] Add `_sidebar_item("Trends", "trends", active=False, item_id="nav-trends")` to sidebar children
+- [x] Add `html.Div(id="trends-view", style={"display": "none"}, children=[...])` to `app.py` layout inside `view-container`, after `trust-comparison-view`
+- [x] Update `switch_view()` in `dash_app/callbacks/navigation.py`:
- Add `Output("trends-view", "style")` and `Output("nav-trends", "className")` — now 3 views, 3 nav items (6 outputs total)
- Handle 3-way switching: `"patient-pathways"`, `"trust-comparison"`, `"trends"`
-- [ ] Update `update_app_state()` in `dash_app/callbacks/filters.py`:
+- [x] Update `update_app_state()` in `dash_app/callbacks/filters.py`:
- Add `Input("nav-trends", "n_clicks")`
- Add `elif triggered_id == "nav-trends": active_view = "trends"` case
-- **Checkpoint**: 3 sidebar items visible. Clicking "Trends" switches to empty trends view. `python run_dash.py` starts cleanly.
+- **Checkpoint**: 3 sidebar items visible. Clicking "Trends" switches to empty trends view. `python run_dash.py` starts cleanly. PASSED.
### E.3 Create Trends landing page — directorate-level trends
- [ ] Create `dash_app/components/trends.py`:
@@ -354,8 +354,8 @@ Comprehensive review and improvement of all Plotly charts in the Dash dashboard.
- [x] `python run_dash.py` starts cleanly
### Phase E
-- [ ] Trends tab removed from Patient Pathways (9 tabs remain)
-- [ ] 3rd sidebar item "Trends" visible and functional
+- [x] Trends tab removed from Patient Pathways (9 tabs remain)
+- [x] 3rd sidebar item "Trends" visible and functional
- [ ] Trends landing page shows directorate-level line chart with metric toggle
- [ ] Clicking a directorate drills into drug-level trends
- [ ] Back button returns to directorate overview
diff --git a/dash_app/app.py b/dash_app/app.py
index bd014a2..549c53f 100644
--- a/dash_app/app.py
+++ b/dash_app/app.py
@@ -29,6 +29,7 @@ app.layout = dmc.MantineProvider(
"selected_trusts": [],
"active_view": "patient-pathways",
"selected_comparison_directorate": None,
+ "selected_trends_directorate": None,
}),
dcc.Store(id="chart-data", storage_type="memory"),
dcc.Store(id="reference-data", storage_type="session"),
@@ -64,6 +65,14 @@ app.layout = dmc.MantineProvider(
make_tc_dashboard(),
],
),
+ # Trends view (hidden initially)
+ html.Div(
+ id="trends-view",
+ style={"display": "none"},
+ children=[
+ html.H3("Trends", style={"padding": "24px"}),
+ ],
+ ),
],
),
make_footer(),
diff --git a/dash_app/callbacks/filters.py b/dash_app/callbacks/filters.py
index 824dd09..5f83d41 100644
--- a/dash_app/callbacks/filters.py
+++ b/dash_app/callbacks/filters.py
@@ -75,13 +75,14 @@ def register_filter_callbacks(app):
Input("trust-chips", "value"),
Input("nav-patient-pathways", "n_clicks"),
Input("nav-trust-comparison", "n_clicks"),
+ Input("nav-trends", "n_clicks"),
Input({"type": "tc-selector", "index": ALL}, "n_clicks"),
Input("tc-back-btn", "n_clicks"),
State("app-state", "data"),
)
def update_app_state(
_dir_clicks, _ind_clicks, initiated, last_seen, selected_drugs,
- selected_trusts, _nav_pp_clicks, _nav_tc_clicks,
+ selected_trusts, _nav_pp_clicks, _nav_tc_clicks, _nav_trends_clicks,
_tc_selector_clicks, _tc_back_clicks, current_state
):
"""Update app-state when any filter, nav, or TC selector changes."""
@@ -96,6 +97,7 @@ def register_filter_callbacks(app):
"selected_trusts": [],
"active_view": "patient-pathways",
"selected_comparison_directorate": None,
+ "selected_trends_directorate": None,
}
triggered_id = ctx.triggered_id
@@ -114,6 +116,8 @@ def register_filter_callbacks(app):
active_view = "patient-pathways"
elif triggered_id == "nav-trust-comparison":
active_view = "trust-comparison"
+ elif triggered_id == "nav-trends":
+ active_view = "trends"
# Trust Comparison directorate selection
selected_comparison_directorate = current_state.get("selected_comparison_directorate")
diff --git a/dash_app/callbacks/navigation.py b/dash_app/callbacks/navigation.py
index 2bfe3ae..8efb790 100644
--- a/dash_app/callbacks/navigation.py
+++ b/dash_app/callbacks/navigation.py
@@ -1,4 +1,4 @@
-"""Callbacks for view switching between Patient Pathways and Trust Comparison."""
+"""Callbacks for view switching between Patient Pathways, Trust Comparison, and Trends."""
from dash import Input, Output
@@ -8,22 +8,27 @@ def register_navigation_callbacks(app):
@app.callback(
Output("patient-pathways-view", "style"),
Output("trust-comparison-view", "style"),
+ Output("trends-view", "style"),
Output("nav-patient-pathways", "className"),
Output("nav-trust-comparison", "className"),
+ Output("nav-trends", "className"),
Input("app-state", "data"),
)
def switch_view(app_state):
"""Show/hide views and update sidebar active state based on active_view."""
- if not app_state:
- return {}, {"display": "none"}, "sidebar__item sidebar__item--active", "sidebar__item"
-
- view = app_state.get("active_view", "patient-pathways")
show = {}
hide = {"display": "none"}
active_cls = "sidebar__item sidebar__item--active"
inactive_cls = "sidebar__item"
+ if not app_state:
+ return show, hide, hide, active_cls, inactive_cls, inactive_cls
+
+ view = app_state.get("active_view", "patient-pathways")
+
if view == "patient-pathways":
- return show, hide, active_cls, inactive_cls
- else:
- return hide, show, inactive_cls, active_cls
+ return show, hide, hide, active_cls, inactive_cls, inactive_cls
+ elif view == "trust-comparison":
+ return hide, show, hide, inactive_cls, active_cls, inactive_cls
+ else: # trends
+ return hide, hide, show, inactive_cls, inactive_cls, active_cls
diff --git a/dash_app/components/sidebar.py b/dash_app/components/sidebar.py
index 6197848..1c4ac02 100644
--- a/dash_app/components/sidebar.py
+++ b/dash_app/components/sidebar.py
@@ -20,6 +20,7 @@ def _svg_icon(svg_body):
_ICONS = {
"pathway": '',
"compare": '',
+ "trends": '',
}
@@ -41,6 +42,10 @@ def make_sidebar():
"Trust Comparison", "compare",
active=False, item_id="nav-trust-comparison",
),
+ _sidebar_item(
+ "Trends", "trends",
+ active=False, item_id="nav-trends",
+ ),
],
),
html.Div(