feat: add reference data loading and filter state callbacks (Task 3.1)
This commit is contained in:
@@ -163,12 +163,12 @@ Drawer selection → update_drug_selection → app-state store → load_pathway_
|
||||
## Phase 3: Core Callbacks
|
||||
|
||||
### 3.1 Reference data loading + filter state management
|
||||
- [ ] Create `dash_app/callbacks/filters.py`:
|
||||
- [x] Create `dash_app/callbacks/filters.py`:
|
||||
- `load_reference_data` callback: fires on page load, calls `queries.load_initial_data()`, populates `reference-data` store + header indicators
|
||||
- `update_app_state` callback: fires when chart-type toggle or date dropdowns change, computes `date_filter_id` (e.g., `"all_6mo"`), updates `app-state` store
|
||||
- Chart type toggle: use `callback_context` to determine which button was clicked, set active class via `className`
|
||||
- [ ] Create `dash_app/callbacks/__init__.py` with `register_callbacks(app)` that imports and registers all callback modules
|
||||
- [ ] Wire `register_callbacks(app)` in `app.py`
|
||||
- [x] Create `dash_app/callbacks/__init__.py` with `register_callbacks(app)` that imports and registers all callback modules
|
||||
- [x] Wire `register_callbacks(app)` in `app.py`
|
||||
- **Checkpoint**: Page loads reference data, filter dropdowns update app-state store (verify via browser dev tools → dcc.Store)
|
||||
|
||||
### 3.2 Pathway data loading callback
|
||||
|
||||
@@ -27,6 +27,7 @@ app.layout = dmc.MantineProvider(
|
||||
}),
|
||||
dcc.Store(id="chart-data", storage_type="memory"),
|
||||
dcc.Store(id="reference-data", storage_type="session"),
|
||||
dcc.Location(id="url", refresh=False),
|
||||
|
||||
# Page structure
|
||||
make_header(),
|
||||
@@ -43,4 +44,8 @@ app.layout = dmc.MantineProvider(
|
||||
],
|
||||
)
|
||||
|
||||
from dash_app.callbacks import register_callbacks
|
||||
|
||||
register_callbacks(app)
|
||||
|
||||
server = app.server
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
"""Callback registration — imports all callback modules and wires them to the app."""
|
||||
|
||||
|
||||
def register_callbacks(app):
|
||||
"""Register all Dash callbacks with the app instance."""
|
||||
from dash_app.callbacks.filters import register_filter_callbacks
|
||||
|
||||
register_filter_callbacks(app)
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
"""Callbacks for reference data loading and filter state management."""
|
||||
from dash import Input, Output, State, callback, ctx, no_update
|
||||
|
||||
|
||||
def register_filter_callbacks(app):
|
||||
"""Register reference data loading and filter state callbacks."""
|
||||
|
||||
@app.callback(
|
||||
Output("reference-data", "data"),
|
||||
Output("header-record-count", "children"),
|
||||
Output("header-last-updated", "children"),
|
||||
Input("url", "pathname"), # fires once on page load
|
||||
)
|
||||
def load_reference_data(_pathname):
|
||||
"""Load reference data once on page load."""
|
||||
from dash_app.data.queries import load_initial_data
|
||||
|
||||
ref = load_initial_data()
|
||||
total = ref.get("total_records", 0)
|
||||
record_text = f"{total:,} records" if total else "Data loaded"
|
||||
last_updated = ref.get("last_updated", "")
|
||||
updated_text = last_updated[:10] if last_updated else "Unknown"
|
||||
|
||||
return ref, record_text, updated_text
|
||||
|
||||
@app.callback(
|
||||
Output("app-state", "data"),
|
||||
Output("chart-type-directory", "className"),
|
||||
Output("chart-type-indication", "className"),
|
||||
Input("chart-type-directory", "n_clicks"),
|
||||
Input("chart-type-indication", "n_clicks"),
|
||||
Input("filter-initiated", "value"),
|
||||
Input("filter-last-seen", "value"),
|
||||
State("app-state", "data"),
|
||||
)
|
||||
def update_app_state(
|
||||
_dir_clicks, _ind_clicks, initiated, last_seen, current_state
|
||||
):
|
||||
"""Update app-state when chart type toggle or date filters change."""
|
||||
if not current_state:
|
||||
current_state = {
|
||||
"chart_type": "directory",
|
||||
"initiated": "all",
|
||||
"last_seen": "6mo",
|
||||
"date_filter_id": "all_6mo",
|
||||
"selected_drugs": [],
|
||||
"selected_directorates": [],
|
||||
}
|
||||
|
||||
triggered_id = ctx.triggered_id
|
||||
|
||||
# Determine chart type from toggle pills
|
||||
chart_type = current_state.get("chart_type", "directory")
|
||||
if triggered_id == "chart-type-directory":
|
||||
chart_type = "directory"
|
||||
elif triggered_id == "chart-type-indication":
|
||||
chart_type = "indication"
|
||||
|
||||
# Compute date_filter_id from dropdown values
|
||||
date_filter_id = f"{initiated}_{last_seen}"
|
||||
|
||||
# Build updated state
|
||||
updated_state = {
|
||||
**current_state,
|
||||
"chart_type": chart_type,
|
||||
"initiated": initiated,
|
||||
"last_seen": last_seen,
|
||||
"date_filter_id": date_filter_id,
|
||||
}
|
||||
|
||||
# Toggle pill CSS classes
|
||||
base = "toggle-pill"
|
||||
active = f"{base} toggle-pill--active"
|
||||
dir_class = active if chart_type == "directory" else base
|
||||
ind_class = active if chart_type == "indication" else base
|
||||
|
||||
return updated_state, dir_class, ind_class
|
||||
Reference in New Issue
Block a user