caf7ada287
- Drug modal: size 70%, sm chips in 4-col SimpleGrid layout - Trust modal: size lg, md chips in vertical Stack layout - Directorate modal: size 70%, larger badges and text - CSS: modal title full-width, chip nowrap, scroll padding
261 lines
8.3 KiB
Python
261 lines
8.3 KiB
Python
"""Filter selection modals using Dash Mantine Components.
|
|
|
|
Three separate modals replace the single drawer:
|
|
- Drug Selection modal: 42 drugs in a ChipGroup with search filter
|
|
- Trust Selection modal: 7 trusts in a ChipGroup
|
|
- Directorate Browser modal: nested accordion with indication sub-items and drug fragment badges
|
|
|
|
Component IDs are preserved from the drawer so existing callbacks work unchanged:
|
|
- all-drugs-chips, trust-chips, drug-fragment pattern, clear-drug-filters
|
|
"""
|
|
|
|
from dash import html
|
|
import dash_mantine_components as dmc
|
|
|
|
from dash_app.data.card_browser import build_directorate_tree, get_all_drugs, get_all_trusts
|
|
|
|
|
|
def _make_directorate_accordion_item(directorate: str, indications: dict[str, list[str]]) -> dmc.AccordionItem:
|
|
"""Create an AccordionItem for a single directorate with nested indication panels."""
|
|
panels = []
|
|
for search_term, fragments in indications.items():
|
|
panels.append(
|
|
dmc.AccordionItem(
|
|
value=f"{directorate}|{search_term}",
|
|
children=[
|
|
dmc.AccordionControl(
|
|
search_term.title(),
|
|
className="modal-indication",
|
|
),
|
|
dmc.AccordionPanel(
|
|
dmc.Group(
|
|
gap="xs",
|
|
children=[
|
|
dmc.Badge(
|
|
frag,
|
|
id={"type": "drug-fragment", "index": f"{directorate}|{search_term}|{frag}"},
|
|
variant="light",
|
|
size="md",
|
|
className="modal-drug-badge",
|
|
style={"cursor": "pointer"},
|
|
)
|
|
for frag in fragments
|
|
],
|
|
),
|
|
),
|
|
],
|
|
)
|
|
)
|
|
|
|
return dmc.AccordionItem(
|
|
value=directorate,
|
|
children=[
|
|
dmc.AccordionControl(
|
|
dmc.Group(
|
|
gap="xs",
|
|
children=[
|
|
dmc.Text(directorate.title(), fw=600, size="md"),
|
|
dmc.Badge(
|
|
str(len(indications)),
|
|
size="sm",
|
|
variant="light",
|
|
color="gray",
|
|
),
|
|
],
|
|
),
|
|
),
|
|
dmc.AccordionPanel(
|
|
dmc.Accordion(
|
|
variant="separated",
|
|
children=panels,
|
|
),
|
|
),
|
|
],
|
|
)
|
|
|
|
|
|
def make_drug_modal():
|
|
"""Build the drug selection modal."""
|
|
drugs = get_all_drugs()
|
|
|
|
return dmc.Modal(
|
|
id="drug-modal",
|
|
opened=False,
|
|
centered=True,
|
|
size="70%",
|
|
title=dmc.Group(
|
|
justify="space-between",
|
|
style={"width": "100%"},
|
|
children=[
|
|
dmc.Text("Select Drugs", fw=600, size="lg"),
|
|
dmc.Badge(
|
|
id="drug-modal-count",
|
|
children=f"0 of {len(drugs)} selected",
|
|
variant="light",
|
|
color="blue",
|
|
),
|
|
],
|
|
),
|
|
overlayProps={"backgroundOpacity": 0.55, "blur": 3},
|
|
children=[
|
|
html.Div(
|
|
className="modal-chips-scroll",
|
|
children=[
|
|
dmc.Text(
|
|
f"{len(drugs)} drugs from pathway data",
|
|
size="xs",
|
|
c="dimmed",
|
|
mb=8,
|
|
),
|
|
dmc.ChipGroup(
|
|
id="all-drugs-chips",
|
|
multiple=True,
|
|
value=[],
|
|
children=[
|
|
dmc.SimpleGrid(
|
|
cols=4,
|
|
spacing="sm",
|
|
verticalSpacing="xs",
|
|
children=[
|
|
dmc.Chip(drug, value=drug, size="sm")
|
|
for drug in drugs
|
|
],
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
dmc.Space(h=12),
|
|
dmc.Group(
|
|
justify="flex-end",
|
|
children=[
|
|
dmc.Button(
|
|
"Clear Selection",
|
|
id="clear-drug-selection",
|
|
variant="subtle",
|
|
color="gray",
|
|
size="sm",
|
|
),
|
|
],
|
|
),
|
|
],
|
|
)
|
|
|
|
|
|
def make_trust_modal():
|
|
"""Build the trust selection modal."""
|
|
trusts = get_all_trusts()
|
|
|
|
return dmc.Modal(
|
|
id="trust-modal",
|
|
opened=False,
|
|
centered=True,
|
|
size="lg",
|
|
title=dmc.Group(
|
|
justify="space-between",
|
|
style={"width": "100%"},
|
|
children=[
|
|
dmc.Text("Select Trusts", fw=600, size="lg"),
|
|
dmc.Badge(
|
|
id="trust-modal-count",
|
|
children=f"0 of {len(trusts)} selected",
|
|
variant="light",
|
|
color="blue",
|
|
),
|
|
],
|
|
),
|
|
overlayProps={"backgroundOpacity": 0.55, "blur": 3},
|
|
children=[
|
|
dmc.ChipGroup(
|
|
id="trust-chips",
|
|
multiple=True,
|
|
value=[],
|
|
children=[
|
|
dmc.Stack(
|
|
gap="xs",
|
|
children=[
|
|
dmc.Chip(trust, value=trust, size="md")
|
|
for trust in trusts
|
|
],
|
|
),
|
|
],
|
|
),
|
|
dmc.Space(h=12),
|
|
dmc.Group(
|
|
justify="flex-end",
|
|
children=[
|
|
dmc.Button(
|
|
"Clear Selection",
|
|
id="clear-trust-selection",
|
|
variant="subtle",
|
|
color="gray",
|
|
size="sm",
|
|
),
|
|
],
|
|
),
|
|
],
|
|
)
|
|
|
|
|
|
def make_directorate_modal():
|
|
"""Build the directorate browser modal with nested accordion."""
|
|
directorate_tree = build_directorate_tree()
|
|
|
|
directorate_items = [
|
|
_make_directorate_accordion_item(directorate, indications)
|
|
for directorate, indications in directorate_tree.items()
|
|
]
|
|
|
|
total_indications = sum(len(v) for v in directorate_tree.values())
|
|
|
|
return dmc.Modal(
|
|
id="directorate-modal",
|
|
opened=False,
|
|
centered=True,
|
|
size="70%",
|
|
title=dmc.Text("Browse by Directorate", fw=600, size="lg"),
|
|
overlayProps={"backgroundOpacity": 0.55, "blur": 3},
|
|
children=[
|
|
html.Div(
|
|
className="modal-chips-scroll",
|
|
children=[
|
|
dmc.Text(
|
|
f"{len(directorate_tree)} directorates \u00b7 {total_indications} indications",
|
|
size="xs",
|
|
c="dimmed",
|
|
mb=8,
|
|
),
|
|
dmc.Accordion(
|
|
variant="separated",
|
|
children=directorate_items,
|
|
className="modal-directorate-accordion",
|
|
),
|
|
],
|
|
),
|
|
dmc.Space(h=12),
|
|
dmc.Group(
|
|
justify="flex-end",
|
|
children=[
|
|
dmc.Button(
|
|
"Clear All Filters",
|
|
id="clear-drug-filters",
|
|
variant="subtle",
|
|
color="red",
|
|
size="sm",
|
|
),
|
|
],
|
|
),
|
|
],
|
|
)
|
|
|
|
|
|
def make_modals():
|
|
"""Return all three filter modals as a list of components."""
|
|
return html.Div(
|
|
children=[
|
|
make_drug_modal(),
|
|
make_trust_modal(),
|
|
make_directorate_modal(),
|
|
],
|
|
)
|