158 lines
5.2 KiB
Python
158 lines
5.2 KiB
Python
"""Top-level Dash layout builder.
|
|
|
|
Assembles all component modules into the complete page layout.
|
|
Two tabs:
|
|
- **Data**: Channel grid (left, resizable) + Plot area + Cursor values grid
|
|
- **Analysis**: Injury criteria + Protocol scoring + Export
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
import dash_bootstrap_components as dbc
|
|
from dash import dcc, html
|
|
|
|
from impakt.web.components.channel_grid import build_channel_grid
|
|
from impakt.web.components.channel_values import build_channel_values_panel
|
|
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
|
|
from impakt.web.components.corridors import build_corridor_panel
|
|
from impakt.web.components.math_builder import build_math_panel
|
|
from impakt.web.components.report import build_report_panel
|
|
from impakt.web.components.templates import build_template_panel
|
|
from impakt.web.components.transforms import build_transform_panel
|
|
from impakt.web.state import AppState
|
|
|
|
|
|
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",
|
|
},
|
|
),
|
|
# === Right side: Plot area + Channel values table (full width) ===
|
|
html.Div(
|
|
[
|
|
build_plot_grid("1x1"),
|
|
build_channel_values_panel(),
|
|
],
|
|
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:
|
|
"""Build the Analysis tab: criteria, corridors, math, templates, export."""
|
|
return html.Div(
|
|
[
|
|
dbc.Row(
|
|
[
|
|
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),
|
|
],
|
|
),
|
|
],
|
|
style={"padding": "8px"},
|
|
)
|
|
|
|
|
|
def build_layout(app_state: AppState, template_names: list[str] | None = None) -> html.Div:
|
|
"""Build the complete page layout from components."""
|
|
|
|
return html.Div(
|
|
[
|
|
# --- 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",
|
|
),
|
|
# --- Tabs ---
|
|
dbc.Tabs(
|
|
[
|
|
dbc.Tab(
|
|
_build_data_tab(app_state),
|
|
label="Data",
|
|
tab_id="tab-data",
|
|
tab_style={"fontSize": "13px"},
|
|
active_label_style={"fontWeight": "bold"},
|
|
),
|
|
dbc.Tab(
|
|
_build_analysis_tab(app_state),
|
|
label="Analysis",
|
|
tab_id="tab-analysis",
|
|
tab_style={"fontSize": "13px"},
|
|
active_label_style={"fontWeight": "bold"},
|
|
),
|
|
],
|
|
id="main-tabs",
|
|
active_tab="tab-data",
|
|
className="px-3 pt-1",
|
|
),
|
|
# --- Hidden stores ---
|
|
dcc.Store(id="selected-channels-store", data=[]),
|
|
dcc.Store(id="session-store", data={}),
|
|
dcc.Store(id="page-refresh-trigger", data={}),
|
|
dcc.Store(id="splitter-state", data={"width": 320}),
|
|
]
|
|
)
|