Skip to content

Fix filter count badge on Orders/Vouchers lists - #4834

Open
codesbyjit wants to merge 2 commits into
fossasia:devfrom
codesbyjit:fix/4832-filter-count-live-update
Open

Fix filter count badge on Orders/Vouchers lists #4834
codesbyjit wants to merge 2 commits into
fossasia:devfrom
codesbyjit:fix/4832-filter-count-live-update

Conversation

@codesbyjit

@codesbyjit codesbyjit commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Fixes #4832

This PR fixes the filter count badge on the All Orders list not updating live and showing an incorrect count, and adds the missing badge to the Vouchers list.

Root Cause

  • advanced_filter_count() in control/forms/filter.py counted the hidden browser_timezone field (always populated by JS) as an active filter, causing the badge to show n+1 instead of n.
  • The filter toggle/badge markup sits outside the [data-ajax-results-region] element that ajax-filter.js replaces on every AJAX filter request, so the badge was never updated until a full page reload.
  • control/views/vouchers.py never computed or passed advanced_filter_count to the template, and vouchers/index.html had no badge markup at all — so the Vouchers list showed no filter count, unlike Orders.

Changes

  • control/forms/filter.py: excluded technical/non-user-facing fields (browser_timezone, search, query, ordering) from advanced_filter_count() and advanced_filters_open_from_get(), fixing the incorrect count.
  • control/views/vouchers.py: added ctx['advanced_filter_count'] = advanced_filter_count(self.filter_form) so the Vouchers list can render a count.
  • control/templates/pretixcontrol/orders/index.html & .../vouchers/index.html: added a data-filter-count attribute on the Filters toggle button, and added the badge <span> to the Vouchers template (it was missing entirely).
  • static/eventyay-common/js/ajax-filter.js: added syncFilterBadge(), called after every AJAX filter/pagination/sort response, so the badge updates (create/update/remove) immediately instead of requiring a reload.

Testing

  • Applied filters on All Orders: badge now appears/updates instantly on AJAX submit, shows the correct count (no more n+1), and disappears on Clear filters — all without a page reload.
  • Applied filters on Vouchers (both "All vouchers" and "Voucher Tags" tabs): badge now appears and updates correctly, matching Orders behavior.
  • Verified count stays correct after a full page reload (server-side render matches client-side sync).

Screenshot

2026-08-11-003828_hyprshot 2026-08-11-003848_hyprshot 2026-08-11-003902_hyprshot

Summary by Sourcery

Fix filter count badges for orders and vouchers so they display and update the correct number of active filters, including during AJAX-based updates.

Bug Fixes:

  • Exclude non-user-facing technical fields from advanced filter count and open-state logic to fix off-by-one filter badge values.
  • Ensure the orders filter badge is synchronized after AJAX filtering, pagination, and sorting so it updates without a full page reload.
  • Add a filter count badge and server-side count computation to the vouchers list so its badge appears and reflects active filters, matching orders behavior.

Enhancements:

  • Centralize the list of fields ignored by advanced filter counting in a shared constant for consistent behavior across views and forms.

@sourcery-ai

sourcery-ai Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

This PR fixes incorrect and non-live filter count badges on the Orders list and adds working filter badges to Vouchers by excluding technical fields from the count, wiring voucher views to compute the count, updating templates to render badge state, and syncing the badge client-side after AJAX updates.

Sequence diagram for AJAX filter badge sync on Orders/Vouchers lists

sequenceDiagram
    actor Admin
    participant Browser
    participant ajax_filter_js as ajax_filter_js
    participant Server
    participant VoucherListView

    Admin->>Browser: Submit filter form
    Browser->>ajax_filter_js: fetchAndReplace(url, replaceUrlParams, form)
    ajax_filter_js->>Server: HTTP GET with filter params
    Server->>VoucherListView: dispatch request
    VoucherListView->>VoucherFilterForm: clean()
    VoucherListView->>advanced_filter_count: advanced_filter_count(filter_form)
    VoucherListView-->>Server: context with advanced_filter_count
    Server-->>ajax_filter_js: HTML response (updated results region)
    ajax_filter_js->>ajax_filter_js: getResultsContainer(tabContext.context)
    ajax_filter_js->>ajax_filter_js: replace resultsContainer with newContext
    ajax_filter_js->>ajax_filter_js: syncFilterBadge(tabContext.context, newContext)
    ajax_filter_js-->>Browser: Updated DOM (badge created/updated/removed)
Loading

File-Level Changes

Change Details Files
Make advanced filter open-state and count logic ignore technical fields so only user-facing filters are counted.
  • Introduce FILTER_COUNT_IGNORED_FIELDS tuple of non-user-facing filter keys
  • Use FILTER_COUNT_IGNORED_FIELDS in advanced_filters_open_from_get to skip ignored fields when deciding if panel should be open
  • Use FILTER_COUNT_IGNORED_FIELDS in advanced_filter_count so hidden/technical fields no longer contribute to the badge count
app/eventyay/control/forms/filter.py
Wire voucher views and templates to compute and display the advanced filter count badge.
  • Import advanced_filter_count in vouchers views
  • Populate advanced_filter_count in the vouchers list view context based on the active filter form
  • Render a badge span in the Vouchers filters toggle, bound to advanced_filter_count and hidden when the count is zero
app/eventyay/control/views/vouchers.py
app/eventyay/control/templates/pretixcontrol/vouchers/index.html
Ensure Orders and Vouchers filter toggles expose a data-filter-count attribute for client-side synchronization.
  • Add data-filter-count attribute to the Orders filter toggle button, seeded with advanced_filter_count
  • Leverage advanced_filter_count in the Vouchers template badge markup so server-rendered count matches client-side behavior
app/eventyay/control/templates/pretixcontrol/orders/index.html
app/eventyay/control/templates/pretixcontrol/vouchers/index.html
Synchronize the filter badge state after each AJAX filter operation so the badge updates without a full page reload.
  • Add syncFilterBadge helper that reads filter toggle/badge state from the new AJAX-rendered context and applies it to the existing page toggle
  • Update aria-expanded and data-filter-count attributes on the existing toggle after each AJAX response
  • Create, update, or remove the badge element based on the new count
  • Invoke syncFilterBadge in fetchAndReplace after replacing the results container and before reinitializing behaviors
app/eventyay/static/eventyay-common/js/ajax-filter.js

Assessment against linked issues

Issue Objective Addressed Explanation
#4832 Ensure the All Orders filter badge updates immediately after applying or removing filters via the AJAX interface (without requiring a full page reload).
#4832 Fix the incorrect All Orders filter count so that it reflects the actual number of user-selected filters instead of showing n+1.
#4832 Provide a consistent filter count badge for the Vouchers list that appears and updates correctly in line with the All Orders behavior.

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@github-actions

github-actions Bot commented Aug 10, 2026

Copy link
Copy Markdown

Thank you for contributing

Please complete the checklist. Screenshots in the PR description and completed AI reviews are checked automatically.

  • Show what changed — a screenshot or short screen recording of the updated functionality
  • Map structural updates — for architectural work, new directories, or file reorganization, include a diagram in the PR description (component, flow, or directory tree). Optional — only when your PR includes those kinds of changes
  • Request AI feedback — request or receive review from GitHub Copilot, Codex, or other automated reviewers you use

🤖 AI reviews

❌ 1 failed or rate-limited AI reviewer

Sourcery AI (@sourcery-ai[bot])

you have reached your weekly rate limit of 500000 diff characters.

ℹ️ Does not count toward the checklist

Sourcery AI (@sourcery-ai[bot]) — Sourcery AI code review bot


📎 Attached media (3)

Screenshots and screen recordings

🖼️ Screenshots

2026-08-11-003828_hyprshot

2026-08-11-003848_hyprshot

2026-08-11-003902_hyprshot


Thank you for your contribution feel free to reach out if you have any questions.

@github-actions github-actions Bot added backend Python/Django server-side code base Shared models, services, and core utilities control Organiser ticketing back-office fix Bug fix (fix/, fix-* branches) frontend JS, Vue, CSS, and HTML templates labels Aug 10, 2026

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 2 issues, and left some high level feedback:

  • In syncFilterBadge, the logic relies on a data-filter-count attribute, but the vouchers filter toggle template doesn’t set this attribute, so AJAX responses for vouchers will always yield a count of 0 and remove the badge; consider adding data-filter-count="{{ advanced_filter_count|default:0 }}" to the vouchers filter button as you did for orders.
  • To avoid divergence between server-rendered state and syncFilterBadge, you might want to derive the initial data-filter-count from the presence/value of [data-advanced-filter-count] when the attribute is missing, so the JS remains robust if a template forgets to set it.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `syncFilterBadge`, the logic relies on a `data-filter-count` attribute, but the vouchers filter toggle template doesn’t set this attribute, so AJAX responses for vouchers will always yield a count of 0 and remove the badge; consider adding `data-filter-count="{{ advanced_filter_count|default:0 }}`" to the vouchers filter button as you did for orders.
- To avoid divergence between server-rendered state and `syncFilterBadge`, you might want to derive the initial `data-filter-count` from the presence/value of `[data-advanced-filter-count]` when the attribute is missing, so the JS remains robust if a template forgets to set it.

## Individual Comments

### Comment 1
<location path="app/eventyay/static/eventyay-common/js/ajax-filter.js" line_range="108-117" />
<code_context>
+const syncFilterBadge = function(oldContext, newContext) {
</code_context>
<issue_to_address>
**issue (bug_risk):** Hidden state of the badge is not synchronized, which can leave an existing badge permanently hidden.

In the vouchers template, the badge is initially rendered with `hidden` when `advanced_filter_count` is falsy. `syncFilterBadge` only updates `textContent` and never updates `hidden`, so a badge that starts hidden will remain hidden even when `newCount > 0`. Please also toggle the `hidden` attribute based on `newCount` (remove it when `newCount > 0`, add it when `newCount === 0`) to keep server-rendered and client-updated states aligned.
</issue_to_address>

### Comment 2
<location path="app/eventyay/control/templates/pretixcontrol/vouchers/index.html" line_range="66-69" />
<code_context>
                                     data-advanced-filter-toggle
+                                    data-filter-count="{{ advanced_filter_count|default:0 }}"
                                     aria-controls="advanced-filter-advanced"
                                     aria-expanded="{% if advanced_filters_open %}true{% else %}false{% endif %}">
                                 <span class="fa fa-sliders" aria-hidden="true"></span>
</code_context>
<issue_to_address>
**issue (bug_risk):** Vouchers filter toggle does not expose `data-filter-count`, which `syncFilterBadge` relies on.

`syncFilterBadge` reads `data-filter-count` from the toggle element, but in the vouchers template only the inner badge span has a count (`data-advanced-filter-count`). This means the vouchers toggle always yields `NaN` and falls back to `0`, potentially desynchronizing badge counts between tabs. Adding `data-filter-count="{{ advanced_filter_count|default:0 }}"` to the vouchers button, matching the orders template, keeps the behavior consistent and prevents this desync.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread app/eventyay/static/eventyay-common/js/ajax-filter.js
Comment thread app/eventyay/control/templates/pretixcontrol/vouchers/index.html
@codesbyjit

Copy link
Copy Markdown
Contributor Author

@sourcery-ai review

@sourcery-ai

sourcery-ai Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Sorry @codesbyjit, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@ArnavBallinCode ArnavBallinCode changed the title Fix filter count badge on Orders/Vouchers lists #4832 Fix filter count badge on Orders/Vouchers lists Aug 10, 2026

@Aqil-Ahmad Aqil-Ahmad left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you need to add recording so it can be confirmed it works without reload

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend Python/Django server-side code base Shared models, services, and core utilities control Organiser ticketing back-office fix Bug fix (fix/, fix-* branches) frontend JS, Vue, CSS, and HTML templates

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

All Orders filter count is incorrect and requires page reload

2 participants