Numeric range filters could only express BETWEEN/GREATER_THAN/LESS_THAN via the RangeSlider widget — no way to match NULL/missing values (the original ask in #32) or exact/not-between. The criteria backend already supported all 8 numeric modifiers + value2, so this is a UI swap. - Add NumberFilter component, modeled 1:1 on StringFilter: an 8-modifier radio grid plus two number inputs, with the second input revealed only for BETWEEN/NOT_BETWEEN and both disabled for IS_NULL/NOT_NULL. Initial state is server-rendered so the widget never flashes. - Migrate all 17 numeric range fields (game/session/purchase/playevent) to NumberFilter; drop the now-dead min/max aggregate queries. - filter-bar.ts: serialize numberFields by modifier (mirroring textFields) and wire the modifier radios via event delegation on the persistent custom element so they survive htmx swaps of the inner bar body. Apply the same delegation fix to the existing string filters. - Remove RangeSlider entirely: component, range-slider.ts, its custom element registration/props, and the range-slider e2e tests. Backward compatible: old slider filters stored {value, value2, modifier}, the same JSON shape NumberFilter reads, so saved presets keep working. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+3
-14
@@ -153,27 +153,16 @@ class RealComponentMediaTest(unittest.TestCase):
|
||||
)
|
||||
self.assertEqual(media.js, ("dist/elements/date-range-picker.js",))
|
||||
|
||||
def test_range_slider_declares_its_script(self):
|
||||
from common.components.filters import RangeSlider
|
||||
|
||||
media = collect_media(
|
||||
RangeSlider(
|
||||
label="Year", input_name_prefix="year", range_min=2000, range_max=2025
|
||||
)
|
||||
)
|
||||
self.assertEqual(media.js, ("dist/elements/range-slider.js",))
|
||||
|
||||
def test_filter_bar_collects_chrome_and_widget_media(self):
|
||||
"""A FilterBar's media merges its own chrome script with the scripts that
|
||||
bubble up from the FilterSelect and RangeSlider widgets it contains —
|
||||
exactly the set the view used to thread by hand. (FilterBar wraps its DB
|
||||
aggregates in try/except, so it builds without a database.)"""
|
||||
bubble up from the FilterSelect widgets it contains — exactly the set the
|
||||
view used to thread by hand. (NumberFilter/StringFilter declare no media;
|
||||
their behavior lives in the always-present filter-bar element.)"""
|
||||
from common.components import FilterBar
|
||||
|
||||
media = collect_media(FilterBar())
|
||||
self.assertIn("dist/elements/filter-bar.js", media.js)
|
||||
self.assertIn("dist/elements/search-select.js", media.js)
|
||||
self.assertIn("dist/elements/range-slider.js", media.js)
|
||||
|
||||
|
||||
class HtpyStyleSugarTest(unittest.TestCase):
|
||||
|
||||
Reference in New Issue
Block a user