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(