Make component return types honest; drop str/mark_safe leftovers
Cleanup of hacky leftovers from the node-tree migration (no behaviour
change):
- Return annotations: the component builders return Node subtrees, not
SafeText strings, but ~40 functions still declared `-> SafeText`. Correct
them to `-> Node` across filters / search_select / date_range_picker /
domain. The genuine string returners keep `-> SafeText`: the Alpine
selectors (GameStatusSelector / SessionDeviceSelector, which build f-string
markup) and the script-tag helpers (CsrfInput / ModuleScript /
ExternalScript / StaticScript).
- layout.render_page / layout.Page / AddForm now accept `Node` in their
`content` / `scripts` / `fields` parameters (TYPE_CHECKING import in
layout to avoid the components import cycle), matching what views already
pass.
- session._session_fields builds a `Fragment(*rows, separator="\n")` instead
of `mark_safe("\n".join(str(row) ...))` — keeps the tree intact so media
could bubble, per the Fragment convention.
- Inline SVG icon children use `Safe(...)` nodes instead of `mark_safe(...)`
strings (filters mode-toggle + collapse icons, date_range_picker calendar
icon).
- _filter_field reads the widget's own id from its node `.attributes`
(`_widget_id`) for the label's `for`, dropping the superfluous `for_widget`
argument that always rendered `for="None"`. Removes the two TODOs whose
premise ("the Component function can't expose the id") the class/node
refactor retired, plus RangeSlider's dead commented-out Label block.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -17,9 +17,8 @@ widget into a ``DateCriterion`` unchanged. All behaviour is wired by
|
||||
``games/static/js/date_range_picker.js``.
|
||||
"""
|
||||
|
||||
from django.utils.safestring import SafeText, mark_safe
|
||||
|
||||
from common.components.core import Element, HTMLAttribute, Media, Node
|
||||
from common.components.core import Element, HTMLAttribute, Media, Node, Safe
|
||||
from common.components.primitives import Div, Input, Span
|
||||
from common.time import DatePartSpec, date_parts
|
||||
|
||||
@@ -104,7 +103,7 @@ def _iso_part_values(iso_value: str, parts: list[DatePartSpec]) -> dict[str, str
|
||||
|
||||
def _segment_input(
|
||||
*, part: DatePartSpec, side: str, label: str, value: str
|
||||
) -> SafeText:
|
||||
) -> Node:
|
||||
side_label = "from" if side == "min" else "to"
|
||||
return Input(
|
||||
attributes=[
|
||||
@@ -125,11 +124,11 @@ def _segment_input(
|
||||
)
|
||||
|
||||
|
||||
def _segment_group(*, side: str, label: str, iso_value: str) -> SafeText:
|
||||
def _segment_group(*, side: str, label: str, iso_value: str) -> Node:
|
||||
"""One date's worth of segments (``DD - MM - YYYY``) for a range side."""
|
||||
parts = date_parts()
|
||||
initial_values = _iso_part_values(iso_value, parts)
|
||||
children: list[SafeText] = []
|
||||
children: list[Node] = []
|
||||
for index, part in enumerate(parts):
|
||||
if index > 0:
|
||||
children.append(
|
||||
@@ -161,7 +160,7 @@ def DateRangeField(
|
||||
input_name_prefix: str,
|
||||
min_value: str = "",
|
||||
max_value: str = "",
|
||||
) -> SafeText:
|
||||
) -> Node:
|
||||
"""The visible half of the DateRangePicker: a single-input-looking
|
||||
container holding two segmented dates, a calendar toggle, and the two
|
||||
hidden ISO inputs (``{prefix}-min`` / ``{prefix}-max``) that carry the
|
||||
@@ -210,13 +209,13 @@ def DateRangeField(
|
||||
"cursor-pointer shrink-0",
|
||||
),
|
||||
],
|
||||
children=[mark_safe(_CALENDAR_ICON_SVG)],
|
||||
children=[Safe(_CALENDAR_ICON_SVG)],
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def _calendar_nav_button(direction: str, arrow: str, label: str) -> SafeText:
|
||||
def _calendar_nav_button(direction: str, arrow: str, label: str) -> Node:
|
||||
return Element(
|
||||
"button",
|
||||
attributes=[
|
||||
@@ -229,7 +228,7 @@ def _calendar_nav_button(direction: str, arrow: str, label: str) -> SafeText:
|
||||
)
|
||||
|
||||
|
||||
def _footer_button(action: str, label: str, button_class: str) -> SafeText:
|
||||
def _footer_button(action: str, label: str, button_class: str) -> Node:
|
||||
return Element(
|
||||
"button",
|
||||
attributes=[
|
||||
@@ -241,7 +240,7 @@ def _footer_button(action: str, label: str, button_class: str) -> SafeText:
|
||||
)
|
||||
|
||||
|
||||
def DateRangeCalendar(*, input_name_prefix: str) -> SafeText:
|
||||
def DateRangeCalendar(*, input_name_prefix: str) -> Node:
|
||||
"""The popup half of the DateRangePicker: preset column, month grid
|
||||
(filled client-side into ``[data-date-range-grid]``), and the
|
||||
Cancel / Clear / Select footer. Hidden until the calendar toggle opens it."""
|
||||
|
||||
Reference in New Issue
Block a user