Center consult page#
Will only be reachable for authenticated users.
from pathlib import Path
from urllib.parse import quote_plus
from myFasthtml import *
from myFasthtml import database
import libs.cdash as cdash
import libs.utils as utils
<<consult-page>>
<<consult-periods>>
<<consult-structure>>
<<consult-timetable>>
Consult page#
# @rt('/consult_page')
def consult_page(session, centers):
# Main consult page: select a center and show its coming_periods.
Center = centers.dataclass()
center_names = [c.center_name for c in centers()]
form = Form(
Select(
Option("Select a center", value="", selected=True, disabled=True),
*[Option(name, value=name) for name in center_names],
name="selected_name",
id="consult-db-select"
),
Button("Open", type="submit"),
hx_get="/consult/select_db",
hx_target="#coming-periods"
)
return Main(
cdash.top_menu(session['role']),
Div(utils.display_markdown("consult-t")),
Div(form, id="consult-db"),
H2("Coming periods"),
Div(id="coming-periods"), # filled by /consult/select_db
Div(id="periods-struct"), # filled by /consult/select_period
Div(id="timetables"), # filled by /consult/select_timetable
cls="container"
)
Consult panning periods + unused periods#
# @rt('/consult/select_db')
def consult_select_db(request, centers, db_path):
# HTMX endpoint: receive form with selected_db in request.form or query_params,
# return the coming_periods table for that DB. Each row has a Select action that
# posts period_type (and db) to /consult/select_period.
params = dict(request.query_params)
selected_name = params.get("selected_name")
if not selected_name:
return Div(P("No center selected."))
Center = centers.dataclass()
selected_db = centers[selected_name].gong_db_name
dbfile_path = Path(db_path) / selected_db
if not dbfile_path.exists():
return Div(P(f"Database not found: {selected_db}"))
db = database(str(dbfile_path))
# coming_periods table expected fields: start_date, period_type (adjust if field names differ)
cps = db.t.coming_periods()
pers = db.t.periods_struct()
# Get all period_types from periods_struct and find those not in current rows
try:
all_types = {p.get("period_type") for p in pers}
seen_types = {p.get("period_type") for p in cps}
missing_ptypes = sorted(all_types - seen_types)
except Exception:
missing_ptypes = []
# Add also unplanned periods for inspection
for mpt in missing_ptypes:
# Add a row with start_date as 'unplanned' and the missing period_type
cps.append({"start_date": "unplanned", "period_type": mpt})
rows = []
for cp in sorted(cps, key=lambda x: getattr(x, "start_date", "")):
start = cp.get("start_date")
ptype = cp.get("period_type")
# build select link that posts db and period_type to select_period endpoint
q_db = quote_plus(selected_db)
q_pt = quote_plus(ptype)
select_link = A(
"Select",
hx_get=f"/consult/select_period?db={q_db}&period_type={q_pt}",
hx_target="#periods-struct"
)
rows.append(Tr(Td(start), Td(ptype), Td(select_link)))
table = Table(
Thead(Tr(Th("Start date"), Th("Period type"), Th("Action"))),
Tbody(*rows)
)
return Div(
Div(table, id="coming-periods-table"),
Div("", hx_swap_oob="true", id="timetables"),
Div("", hx_swap_oob="true", id="periods-struct")
)
Consult structures#
# @rt('/consult/select_period')
def consult_select_period(request, db_path):
# HTMX endpoint: show periods_strust rows where period_type matches the selected period_type.
# Expects query params: db and period_type
params = dict(request.query_params)
db_name = params.get("db")
period_type = params.get("period_type")
if not db_name or not period_type:
return Div(P("Missing db or period_type parameter."))
dbfile_path = Path(db_path) / db_name
if not dbfile_path.exists():
return Div(P(f"Database not found: {db_name}"))
db = database(str(dbfile_path))
try:
# periods_struct expected fields: start_date, period_type, other fields...
rows_src = list(db.t.periods_struct())
except Exception:
rows_src = []
filtered = [r for r in rows_src if (r.get("period_type") or "").strip() == period_type.strip()]
if not filtered:
return Div(P(f"No periods found with period_type = {period_type}"))
tbl_rows = []
# choose some representative columns (adjust if your schema differs)
for r in sorted(filtered, key=lambda x: getattr(x, "start_date", "")):
ptype = r.get("period_type")
day = str(r.get("day"))
dtype = r.get("day_type")
# build select link that posts db, period_type and day_type to select_timetables
q_db = quote_plus(db_name)
q_pt = quote_plus(ptype)
q_dt = quote_plus(dtype)
select_link = A(
"Select",
hx_get=f"/consult/select_timetable?db={q_db}&period_type={q_pt}&day_type={q_dt}",
hx_target="#timetables"
)
tbl_rows.append(Tr(Td(ptype), Td(day), Td(dtype), Td(select_link)))
table = Table(
Thead(Tr(Th("Period type"), Th("Day"), Th("Day type"), Th("Action"))),
Tbody(*tbl_rows)
)
return Div(
Div("", hx_swap_oob="true", id="timetables"),
H3(f"Structure for period type:'{period_type}', in '{db_name}'"),
table, id="periods-struct-table"
)
# @rt('/consult/select_timetables')
def consult_select_timetable(request, db_path):
# HTMX endpoint: show timetables rows where period_type and day_type match.
# Expects query params: db, period_type, day_type
params = dict(request.query_params)
db_name = params.get("db")
period_type = params.get("period_type")
day_type = params.get("day_type")
if not db_name or not period_type or not day_type:
return Div(P("Missing db, period_type, or day_type parameter."))
dbfile_path = Path(db_path) / db_name
if not dbfile_path.exists():
return Div(P(f"Database not found: {db_name}"))
db = database(str(dbfile_path))
try:
timetables = list(db.t.timetables())
except Exception:
timetables = []
# Filter where period_type and day_type match
filtered = [
t for t in timetables
if (t.get("period_type").strip() == period_type.strip() and
t.get("day_type").strip() == day_type.strip())
]
if not filtered:
return Div(P(f"No timetables found with period_type = {period_type} and day_type = {day_type}"))
tbl_rows = []
for t in filtered:
# Display all fields from timetables row
if isinstance(t, dict):
cells = [Td(str(v)) for v in t.values()]
headers = list(t.keys())
else:
td_dict = getattr(t, "__dict__", {})
cells = [Td(str(v)) for v in td_dict.values()]
headers = list(td_dict.keys())
tbl_rows.append(Tr(*cells))
# Build headers
thead = Thead(Tr(*[Th(h) for h in headers]))
table = Table(thead, Tbody(*tbl_rows))
return Div(
H3(f"Timetable for period type: '{period_type}', day type: '{day_type}', in '{db_name}'"),
table,
id="timetables-table"
)