Files
impakt/src/impakt/web/layout.py

158 lines
5.2 KiB
Python
Raw Normal View History

2026-04-10 15:34:06 -04:00
"""Top-level Dash layout builder.
2026-04-10 14:37:34 -04:00
2026-04-10 15:34:06 -04:00
Assembles all component modules into the complete page layout.
2026-04-10 15:59:59 -04:00
Two tabs:
- **Data**: Channel grid (left, resizable) + Plot area + Cursor values grid
- **Analysis**: Injury criteria + Protocol scoring + Export
2026-04-10 14:37:34 -04:00
"""
from __future__ import annotations
from typing import Any
import dash_bootstrap_components as dbc
2026-04-10 15:59:59 -04:00
from dash import dcc, html
2026-04-10 14:37:34 -04:00
2026-04-10 15:34:06 -04:00
from impakt.web.components.channel_grid import build_channel_grid
2026-04-10 16:54:40 -04:00
from impakt.web.components.channel_values import build_channel_values_panel
2026-04-10 15:34:06 -04:00
from impakt.web.components.criteria import build_criteria_panel
from impakt.web.components.header import (
build_header,
build_open_test_modal,
build_overlay_modal,
build_test_info_panel,
)
from impakt.web.components.plot_grid import build_plot_grid
2026-04-10 16:54:40 -04:00
from impakt.web.components.corridors import build_corridor_panel
from impakt.web.components.math_builder import build_math_panel
2026-04-10 15:34:06 -04:00
from impakt.web.components.report import build_report_panel
2026-04-10 16:54:40 -04:00
from impakt.web.components.templates import build_template_panel
2026-04-10 15:34:06 -04:00
from impakt.web.components.transforms import build_transform_panel
from impakt.web.state import AppState
2026-04-10 14:37:34 -04:00
2026-04-10 15:59:59 -04:00
def _build_data_tab(app_state: AppState) -> html.Div:
"""Build the Data tab: channels + transforms | plots + cursor grid."""
return html.Div(
[
# === Left panel: Channels + Transforms ===
html.Div(
[
build_channel_grid(app_state),
html.Div(style={"height": "8px"}),
build_transform_panel(),
],
id="left-panel",
style={
"width": "320px",
"minWidth": "200px",
"maxWidth": "600px",
"overflowY": "auto",
"flexShrink": "0",
"padding": "0 8px",
},
),
# === Splitter handle ===
html.Div(
id="splitter-handle",
style={
"width": "6px",
"cursor": "col-resize",
"backgroundColor": "#e9ecef",
"flexShrink": "0",
"position": "relative",
"zIndex": "10",
},
),
2026-04-10 16:54:40 -04:00
# === Right side: Plot area + Channel values table (full width) ===
2026-04-10 15:59:59 -04:00
html.Div(
[
build_plot_grid("1x1"),
2026-04-10 16:54:40 -04:00
build_channel_values_panel(),
2026-04-10 15:59:59 -04:00
],
style={
"flex": "1",
"minWidth": "0",
"overflowY": "auto",
"overflowX": "hidden",
"padding": "0 8px",
},
),
],
style={
"display": "flex",
"flexDirection": "row",
"height": "calc(100vh - 160px)",
"overflow": "hidden",
},
)
def _build_analysis_tab(app_state: AppState) -> html.Div:
2026-04-10 16:54:40 -04:00
"""Build the Analysis tab: criteria, corridors, math, templates, export."""
2026-04-10 15:59:59 -04:00
return html.Div(
[
dbc.Row(
[
2026-04-10 16:54:40 -04:00
dbc.Col([build_criteria_panel()], width=4),
dbc.Col([build_math_panel(app_state)], width=4),
dbc.Col([build_template_panel(app_state)], width=4),
],
className="mb-2",
),
dbc.Row(
[
dbc.Col([build_corridor_panel()], width=6),
dbc.Col([build_report_panel()], width=6),
],
2026-04-10 15:59:59 -04:00
),
],
style={"padding": "8px"},
)
2026-04-10 15:34:06 -04:00
def build_layout(app_state: AppState, template_names: list[str] | None = None) -> html.Div:
"""Build the complete page layout from components."""
2026-04-10 14:37:34 -04:00
return html.Div(
[
2026-04-10 15:34:06 -04:00
# --- Header ---
build_header(app_state, template_names),
# --- Modals ---
build_open_test_modal(),
build_overlay_modal(),
# --- Test info bar ---
html.Div(
build_test_info_panel(app_state),
className="px-3",
2026-04-10 14:37:34 -04:00
),
2026-04-10 15:59:59 -04:00
# --- Tabs ---
dbc.Tabs(
2026-04-10 14:37:34 -04:00
[
2026-04-10 15:59:59 -04:00
dbc.Tab(
_build_data_tab(app_state),
label="Data",
tab_id="tab-data",
tab_style={"fontSize": "13px"},
active_label_style={"fontWeight": "bold"},
2026-04-10 15:34:06 -04:00
),
2026-04-10 15:59:59 -04:00
dbc.Tab(
_build_analysis_tab(app_state),
label="Analysis",
tab_id="tab-analysis",
tab_style={"fontSize": "13px"},
active_label_style={"fontWeight": "bold"},
2026-04-10 14:37:34 -04:00
),
],
2026-04-10 15:59:59 -04:00
id="main-tabs",
active_tab="tab-data",
className="px-3 pt-1",
2026-04-10 14:37:34 -04:00
),
2026-04-10 15:34:06 -04:00
# --- Hidden stores ---
dcc.Store(id="selected-channels-store", data=[]),
2026-04-10 14:37:34 -04:00
dcc.Store(id="session-store", data={}),
2026-04-10 15:34:06 -04:00
dcc.Store(id="page-refresh-trigger", data={}),
dcc.Store(id="splitter-state", data={"width": 320}),
2026-04-10 14:37:34 -04:00
]
)