Commit Graph

734 Commits

Author SHA1 Message Date
Claude b68a131bae Initialize widget JS via onSwap helper
Port FastHTML's proc_htmx as onSwap(selector, initializeElement) in
utils.js, built on htmx.onLoad: it runs an initializer once per matching
element, on initial page load and inside every htmx-swapped fragment.

Migrate search_select.js, range_slider.js, filter_bar.js and
add_purchase.js to it, removing the hand-rolled DOMContentLoaded +
htmx:afterSwap listeners and per-element guard flags. This also fixes a
latent bug: both events passed the Event object as range_slider's
"force" parameter, so every htmx swap force-re-initialized all sliders
and stacked duplicate listeners. The collapse button's
window.initRangeSliders() call was a no-op (handles are positioned in
percentages, so hidden-init is safe) and is removed with the global.

Add e2e/test_widgets_e2e.py covering the onSwap lifecycle (initial-load
init, htmx-swap init, single-fire toggles) plus FilterSelect pills and
the add-purchase type toggle. The synthetic page in
test_search_select_e2e.py now loads htmx and search_select.js as a
module, matching the new initialization path.

https://claude.ai/code/session_01BKurBhE3Qj25p7Bfsg7EeK
2026-06-12 21:41:55 +00:00
Claude 88cf374f33 Vendor Alpine, Flowbite and Datepicker bundles locally
Serve alpinejs 3.15.12, @alpinejs/mask 3.15.12, flowbite 2.4.1 and
flowbite-datepicker 2.0.0 from games/static/js/ instead of jsdelivr, so
pages (and browser tests) work without network access. Adds the
StaticScript primitive for vendored UMD bundles, which cannot be loaded
as ES modules.

https://claude.ai/code/session_01BKurBhE3Qj25p7Bfsg7EeK
2026-06-12 21:40:35 +00:00
Claude be919c992d Document pytest-playwright browser testing in CLAUDE.md
https://claude.ai/code/session_01BKurBhE3Qj25p7Bfsg7EeK
2026-06-12 21:39:54 +00:00
Claude 0fa860c237 Add DateRangePicker component with segmented entry and calendar popup
Django CI/CD / test (push) Successful in 2m33s
Django CI/CD / build-and-push (push) Successful in 1m17s
Implements the DateRangePicker design: a DateRangeField that looks like a
single input but splits each date into DD/MM/YYYY part inputs (ordered by
the new common.time.dateformat_hyphenated), and a DateRangeCalendar popup
with a preset column (today, yesterday, last 7/30 days, this/last month,
this year), anchor-style range picking with an outlined/filled/muted range
track, and a Cancel / Clear / Select footer.

Typing fills each part's placeholder from the right (YYYY -> YY19 -> 1987),
auto-advances between parts, and Backspace/Delete reverts the active part.
The committed value lives in hidden ISO {prefix}-min/{prefix}-max inputs --
the same contract as DateRangeFilter, so filter_bar.js needs no changes.

As a tryout, the Purchased filter in PurchaseFilterBar now uses the
DateRangePicker; Refunded keeps the native-date DateRangeFilter, and the
native-path e2e tests were repointed at it.

Includes unit tests for the component family and the filter-bar
integration, plus Playwright e2e tests for segment entry, calendar
picking, presets, and footer actions.

https://claude.ai/code/session_017b75KJAu4kNNpZPu9NAPBM
2026-06-12 22:45:25 +02:00
lukas 15a97dee9a Use hours instead of minutes for playtime filters 2026-06-12 22:45:25 +02:00
lukas 1822ea8b51 Fix RangeSlider visual bugs 2026-06-12 22:45:25 +02:00
lukas f32a88b47d add make server 2026-06-12 22:45:25 +02:00
lukas 6dfd6c83c9 fix: ensure deselecting presence modifier re-enables string input 2026-06-12 22:45:25 +02:00
lukas 19f1cdd197 feat: migrate playevent_note to StringCriterion and add note string filter to SessionFilterBar 2026-06-12 22:45:25 +02:00
lukas b5546ed828 test: implement E2E Playwright tests for string multi-mode filters 2026-06-12 22:45:25 +02:00
lukas 9cb911401a feat: integrate StringFilter into PlatformFilterBar and PurchaseFilterBar 2026-06-12 22:45:25 +02:00
lukas 2190b9d590 feat: add client-side toggle logic and multi-mode serialization for string filters 2026-06-12 22:45:25 +02:00
lukas 0c109cf2a1 feat: implement StringFilter composite component with 4x2 grid radios 2026-06-12 22:45:25 +02:00
lukas e8a49df2cf test: add comprehensive unit tests for all 8 string criterion modifiers 2026-06-12 22:45:25 +02:00
lukas 3c7ccbdd2b docs: add implementation plan for unifying form checkboxes 2026-06-12 22:45:25 +02:00
lukas 1322e6e71c feat: replace all form BooleanFields with PrimitiveCheckboxWidget via mixin 2026-06-12 22:45:25 +02:00
lukas 58b274a452 refactor: allow Checkbox and Radio primitives to render headlessly without labels 2026-06-12 22:45:25 +02:00
lukas e309ff1b30 docs: add design spec and implementation plan for boolean filters improvement 2026-06-12 22:45:25 +02:00
lukas 35d314768f test: add explicit radio group and True/False choice checks for boolean fields 2026-06-12 22:45:25 +02:00
lukas f9032eef9e feat: add click-to-deselect behavior and update checked-radio serialization in JS 2026-06-12 22:45:25 +02:00
lukas 99af73781b feat: replace single boolean checkboxes with radio groups in all FilterBars 2026-06-12 22:45:25 +02:00
lukas 79d1be2852 feat: implement _parse_bool_nullable and _filter_boolean_radio helper 2026-06-12 22:45:25 +02:00
lukas ebfc9aebfc refactor: generalize Checkbox and add Radio primitive component 2026-06-12 22:45:25 +02:00
lukas 03adcf99a7 Implement date filters in purchase list 2026-06-12 22:45:25 +02:00
lukas b1a4da2704 Improve the layout of the purchase filter bar 2026-06-12 22:45:25 +02:00
lukas 3ce6da708f Improve the layout of the game filter bar 2026-06-12 22:45:25 +02:00
lukas ab079cb447 Use adhoc Component() less 2026-06-12 22:45:25 +02:00
lukas c2996fd91b Add more filters 2026-06-12 22:45:25 +02:00
lukas 22c688bd9a Fix filter bars 2026-06-12 22:45:25 +02:00
lukas 4e77934d06 feat: implement frontend filter bars and integration across all list views 2026-06-12 22:45:25 +02:00
lukas b8d807d302 feat: implement comprehensive filters and cross-entity queries 2026-06-12 22:45:25 +02:00
lukas 67b40255ed Comment staging URL on the open PR after deployment
Looks up the open PR for the pushed branch via the Gitea API using the
workflow token and posts the staging URL once (skips if the same
comment already exists).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 22:45:25 +02:00
lukas eda9d39cdc Install Playwright browsers in CI test jobs
The e2e tests launch chromium, but uv sync only installs the playwright
package, not the browser binaries, so CI failed with "Executable
doesn't exist" for the headless shell.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 22:45:25 +02:00
lukas 3a5b6e2d51 Add Gitea Actions workflows for staging deployments
Django CI/CD / test (push) Failing after 1m1s
Staging deployment / deploy (push) Successful in 59s
Staging deployment / teardown (push) Has been skipped
Django CI/CD / build-and-push (push) Has been skipped
Branch pushes deploy a per-branch staging instance at
tracker-<slug>.home.arpa via the NAS act_runner; branch deletion tears
it down. build.yml ports the GitHub CI workflow so prod image builds
keep running on Gitea now that .gitea/workflows/ exists (Gitea ignores
.github/workflows/ when it does).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 17:08:53 +02:00
lukas e45be806fc Add E2E tests
Django CI/CD / test (push) Failing after 1m1s
Django CI/CD / build-and-push (push) Has been skipped
2026-06-09 12:47:44 +02:00
lukas 83aefcb849 Improve Backspace behavior in single-select SearchSelect
Django CI/CD / test (push) Successful in 44s
Django CI/CD / build-and-push (push) Successful in 1m15s
2026-06-09 12:25:58 +02:00
lukas c7c196a054 Fix non-filter select visuals 2026-06-09 11:56:01 +02:00
lukas c639196266 Search select JavaScript improvements 2026-06-09 11:48:36 +02:00
lukas ed086c9702 Fix prefetch 2026-06-09 11:37:41 +02:00
lukas 6f4841eaaa Update uv.lock
Django CI/CD / test (push) Successful in 47s
Django CI/CD / build-and-push (push) Successful in 1m14s
2026-06-09 09:47:21 +02:00
lukas 5c9bf45c61 Fix contrast issues with search select dropdown 2026-06-09 09:41:30 +02:00
lukas bd228365ed Add pnpm to shell.nix 2026-06-09 09:31:38 +02:00
lukas 1c9fb474df Unify UI for filter modifiers
Django CI/CD / test (push) Successful in 40s
Django CI/CD / build-and-push (push) Successful in 1m16s
2026-06-09 08:47:20 +02:00
lukas 737dd9275b Fix includes all query returning duplicates 2026-06-09 08:47:20 +02:00
lukas 9f436b245d Decrease debounce for search select 2026-06-09 08:47:20 +02:00
lukas 7ebaa51eb0 Ignore .hermes folder 2026-06-09 08:47:20 +02:00
lukas a7ff2962a6 Add number of games filter to purchases 2026-06-09 08:47:20 +02:00
lukas 103219a5e7 Add includes only matcher mode 2026-06-09 08:47:20 +02:00
lukas 14efff8078 Fix filter stuff 2026-06-09 08:47:20 +02:00
Claude ba9b92d419 Align set-criterion modifiers with Stash (any/all/none) and harmonize EXCLUDES
Closes #10.

Backend (common/criteria.py):
- Treat `excludes` as an always-orthogonal AND'd negative across both
  MultiCriterion and ChoiceCriterion; the modifier now governs only the
  `value` (include) set. This removes the prior divergence where
  MultiCriterion.EXCLUDES dropped the excludes list and ChoiceCriterion.EXCLUDES
  swapped include/exclude into a positive.
- Fold INCLUDES / INCLUDES_ALL / EXCLUDES (+ EQUALS/NOT_EQUALS aliases) into the
  shared _SetCriterion base so the two subclasses cannot drift; remove _extra_q.

M2M "has all" (games/filters.py):
- PurchaseFilter._games_to_q builds a pk__in subquery with one join per value so
  INCLUDES_ALL on the many-to-many games field works in a single .filter()
  (a naive Q(games=a) & Q(games=b) collapses to one join and matches nothing).

UI (FilterSelect + filter_bar.js):
- Add an optional any/all/none match-mode <select> (INCLUDES/INCLUDES_ALL/
  EXCLUDES) rendered before the pills via a new `leading` slot on the shared
  combobox shell. A native control so its value is its state. readSearchSelect
  serialises it to data-match; filter_bar folds it into the criterion modifier.
  Orthogonal to the (Any)/(None) presence pseudo-options and the exclude channel.
- Enable it for the M2M Purchase.games field (INCLUDES_ALL is only meaningful
  for multi-valued relations). Styled with already-compiled utilities.

Tests: harmonized EXCLUDES + INCLUDES_ALL for both criterion types, a DB-backed
INCLUDES_ALL vs INCLUDES contrast on Purchase.games, and FilterSelect /
PurchaseFilterBar rendering + round-trip of the match mode.

https://claude.ai/code/session_01KwVrGFbq13mZdhDL9G6zhg
2026-06-09 08:47:20 +02:00