diff --git a/common/components/filters.py b/common/components/filters.py index f1de3c7..dc8784f 100644 --- a/common/components/filters.py +++ b/common/components/filters.py @@ -1479,6 +1479,8 @@ class PlayEventFilterBar(_FilterBarBase): def _playevent_fields(existing: dict) -> list: game_choice = _filter_get_choice(existing, "game") days_min, days_max = _parse_range(existing, "days_to_finish") + started_min, started_max = _parse_range(existing, "started") + ended_min, ended_max = _parse_range(existing, "ended") fields = [ Div( @@ -1495,6 +1497,24 @@ def _playevent_fields(existing: dict) -> list: ), ], ), + _filter_field( + "Started", + DateRangePicker( + label="Started", + input_name_prefix="filter-started", + min_value=started_min, + max_value=started_max, + ), + ), + _filter_field( + "Finished", + DateRangePicker( + label="Finished", + input_name_prefix="filter-ended", + min_value=ended_min, + max_value=ended_max, + ), + ), _filter_field( "Days to Finish", RangeSlider( diff --git a/games/filters.py b/games/filters.py index 8bd22e9..9a3cf45 100644 --- a/games/filters.py +++ b/games/filters.py @@ -899,8 +899,8 @@ class PlayEventFilter(OperatorFilter): NOT: PlayEventFilter | None = None game: MultiCriterion | None = None # filters on game_id - started: StringCriterion | None = None # date string - ended: StringCriterion | None = None # date string + started: DateCriterion | None = None # DateField, bare lookup + ended: DateCriterion | None = None # DateField, bare lookup days_to_finish: IntCriterion | None = None note: StringCriterion | None = None created_at: StringCriterion | None = None diff --git a/tests/test_filter_bars.py b/tests/test_filter_bars.py index 70b78a4..d2ba793 100644 --- a/tests/test_filter_bars.py +++ b/tests/test_filter_bars.py @@ -223,6 +223,59 @@ class FilterBarRenderingTest(TestCase): ) self._assert_shell(html, "/presets/playevents/list", "/presets/playevents/save") + def test_playevent_filter_bar_renders_date_inputs(self): + """PlayEventFilterBar surfaces started and ended as DateRangePicker + widgets whose -min/-max hidden inputs (the JS serializer contract) + carry the filter-started / filter-ended prefixes, in labelled fields.""" + from common.components import PlayEventFilterBar + + html = str( + PlayEventFilterBar( + filter_json="", preset_list_url="/l", preset_save_url="/s" + ) + ) + for name in ( + "filter-started-min", + "filter-started-max", + "filter-ended-min", + "filter-ended-max", + ): + self.assertIn(f'name="{name}"', html) + self.assertIn(f'id="{name}"', html) + self.assertIn(" { const dateRangeFields = [ { prefix: "filter-date-purchased", key: "date_purchased" }, { prefix: "filter-date-refunded", key: "date_refunded" }, + { prefix: "filter-started", key: "started" }, + { prefix: "filter-ended", key: "ended" }, ]; dateRangeFields.forEach((dateField) => { const valueMin = stringValue(form, dateField.prefix + "-min");