Skip to content

Improve History filtering, sorting, and live updates - #12287

Open
XxUnkn0wnxX wants to merge 14 commits into
pymedusa:developfrom
XxUnkn0wnxX:feature/history-title-filtering-corrections
Open

XxUnkn0wnxX wants to merge 14 commits into
pymedusa:developfrom
XxUnkn0wnxX:feature/history-title-filtering-corrections

Conversation

@XxUnkn0wnxX

@XxUnkn0wnxX XxUnkn0wnxX commented Aug 22, 2026 •

Copy link
Copy Markdown
Contributor
  • PR is based on the DEVELOP branch
  • Don't send big changes all at once. Split up big PRs into multiple smaller PRs that are easier to manage and review
  • Read the contribution guide

Closes #12266

🎯 Why

History displays Medusa's show title, but the Episode filter previously searched only the stored release/resource text. A user could copy the title shown in the table and still get no result when the downloaded release used a Romaji, scene, or alternate title.

Testing that filtering path also exposed correctness gaps in the same History API, store, and layout flow. Detailed Provider sorting could fall back to natural database order, Compact sorting operated on raw rows instead of completed groups, malformed saved sorts could prevent the page from mounting, and live Compact events could not safely be inserted into aggregated rows.

This change keeps those related History behaviors together so title matching, filters, sorting, pagination, saved preferences, and live refreshes share one consistent request contract.

🛠️ What changed

🔎 Title and column filtering

  • Episode searches match stored release text, the displayed show name, known aliases, canonical show identifiers, and rendered episode identifiers through the row's stored show identity.
  • Matching remains case-insensitive and partial without hardcoding indexer prefixes.
  • Episode, Action, Provider, Quality, Size, and Client Status continue to narrow the result together with AND behavior.
  • Episode and Provider inputs normalize accidental outer whitespace while retaining intentional text inside matching quote or backtick wrappers.
  • Size accepts strict < or > comparisons with unitless MB or explicit, case-insensitive MB/GB units and up to two decimal places. Invalid input does not replace the active filter.
  • Client Status distinguishes a cleared field from zero-valued Snatched. Nonzero selections use contains-all bitmask matching while allowing additional stored states.
  • Layout changes carry only compatible Episode, paging, and sort state; unsupported layout-specific filters and sorts return to safe defaults.

🔄 Sorting, grouping, and live updates

  • Validates the one-field History sort shape and direction before constructing SQL, while preserving the existing forgiving fallback for malformed or unsupported sorts.
  • Corrects the providerId mapping used by Detailed Provider sorting.
  • Includes season-zero episodes in Compact grouping and derives each group's Time from its newest child event.
  • Sorts Compact Time and Subtitled values after grouping and before pagination, with deterministic tie handling.
  • Orders rendered Compact child events newest-first without mutating the API response array.
  • Keeps Detailed and Compact visibility preferences layout-scoped, validates saved sort state, and carries only compatible sort state when switching layouts.
  • Serializes zero-valued Snatched as [0] / ['Snatched'] in live History events while preserving None and composed masks.
  • Refetches the exact active Compact query after a live event instead of inserting raw event data into an aggregated table.
  • Ignores stale History responses, keeps loading attached to the newest request, and clamps/refetches pages when the result count shrinks.
  • Detailed live updates reload the current server query so newly displayed rows still satisfy the active filters, sort, and page.
🧪 Expected filter behavior
Input Expected result
Displayed English title Rows for that show even when the stored release uses another known title
Romaji, scene, or known alias The same show's rows through its stored identity
Partial or mixed-case title Case-insensitive partial matching
Direct release fragment Matching release/resource rows
Canonical show identifier Rows for the exact supported indexer and show ID
Canonical rendered episode identifier Rows for the exact show, season, and episode
Episode plus another column A progressively narrower result set

Unquoted outer spaces are treated as accidental. Complete matching wrappers ('...', "...", or backticks) retain spaces inside the pair. Internal apostrophes and punctuation remain ordinary title text.

For Size, <300 and >400 continue to mean MB, while values such as >1.3gb, <900.45 MB, and >2.4GB use the requested unit. Incomplete or malformed text leaves the currently applied comparison unchanged until corrected or cleared.

Clearing Client Status applies no status predicate. Snatched matches the exact stored zero state, while one or more nonzero selections require those bits and still allow additional stored states.

✅ Validation

  • Combined History API and websocket suite: 284 passed.
  • Focused History frontend suites: passed.
  • Full frontend Jest suite: 38/38 suites passed; 269 passed, 1 existing skip, and 82 snapshots passed.
  • Full ESLint: zero errors and six existing warnings in untouched files.
  • Stylelint and focused Flake8 E/F/W checks: passed.
  • Development theme build/check: passed on a clean repeat; dark and light runtime bundles are byte-identical.
  • Direct merge simulation into the current develop: passed with zero conflicts.
  • Merge simulation with the independent table-row hover branch: passed with zero conflicts.
  • Firefox Developer Edition integration QA passed across filtering, sorting, layout transitions, saved preferences, pagination, and Compact live refresh.
  • Fork validation: all 26 GitHub Actions jobs and both Codecov coverage checks passed for the promoted feature head.
  • git diff --check: passed.

Live data did not contain an exact zero-status Snatched row or a visible season-zero Compact group during the final browser pass. Both paths are covered by the in-memory API and websocket regression suites without manufacturing database rows.

📦 Scope

  • Most of the diff size is regression coverage; production changes are confined to the History API, store, components, and generated runtime bundles.
  • The only non-History change is a Generic Provider test fix. The larger suite can take longer than that test's 60-second collection-time tolerance on Windows, so it now compares against the parser's execution-time clock; provider behavior is unchanged.
  • No database schema or migration changes.
  • No dependency, logging, timezone, download-client, or scheduler changes.
  • No table-hover styling changes; that was merged separately in table row hover colors.

🔗 Related issue

Match Episode searches against release text, canonical show names, known aliases, and registry-backed series slugs while keeping each History column isolated and stackable.

Normalize text boundaries, validate Size comparisons consistently in the browser and API, preserve filter-aware pagination, add focused regression coverage, and rebuild the development runtime bundles.
Reload the active Detailed query for live History events, reject stale responses, clamp out-of-range pages, and carry only compatible search, sort, page, and per-page state between Detailed and Compact layouts.

Restore newest-first Date sorting after clear, remove the obsolete filter-cookie write, canonicalize malformed text on established transitions, expand component and store coverage, and rebuild the development runtime bundles.
Empty matching wrappers used to disappear as soon as the second quote was
entered. For example, typing "" immediately rewrote the visible field to
blank, so a user could not place the cursor between the pair and continue.

Keep '', "", and `` visible while they are still being edited while retaining
an empty effective filter. For example, "" can now become "caramelise"
without the field rewriting itself first.

Canonicalize a still-empty pair only when another History filter, sort, or
layout change is committed. Completed wrappers and existing malformed or
internal punctuation behavior remain unchanged.

Cover Episode and Provider editing plus every filter, sort, and layout reset
path for all three wrapper forms.
Before this change, the Detailed History Size field accepted only whole, unitless MB comparisons.

Accept unitless MB and case-insensitive MB or GB values with optional spacing and one or two decimal places. Examples include <300, >1.3gb, <900.45 MB, and >2.4GB. Matching outer quote or backtick wrappers remain optional and are stripped before validation.

Use exact Decimal byte thresholds, strict comparison rounding, and one shared safe input cap of 8589934591.99 for every unit. Keep valid flexible input visible, defer malformed cleanup until another filter, sort, or layout action, and show both MB and GB forms in the placeholder.

Cover parser boundaries, filtering, numeric sorting, frontend normalization, trigger cleanup, layout transitions, and the rebuilt dark and light development bundles.
Before this change, clearing the Client Status field and selecting Snatched both reduced to zero, so the backend skipped an explicit Snatched filter. Nonzero selections used exact equality and therefore missed rows with additional status flags, while stored zero values rendered without a label.

Treat an empty selection as no filter, match Snatched as exact zero, and use contains-all bitmask matching for nonzero selections while allowing extra stored flags. Keep Snatched mutually exclusive with nonzero choices, restore active selections when Detailed History is recreated, and serialize zero as Snatched.

Add backend coverage for every supported flag, composed masks, invalid values, filter stacking, and serialization. Add frontend coverage for clear/zero behavior, all selections, mutual exclusion, remount restoration, sort preservation, and existing filter composition.
Validate History sort shapes and directions, restore Provider sorting, include season-zero groups, and sort Compact Time and Subtitled aggregates before pagination. Extend the title-filter API suite with focused grouping and malformed-request coverage.
Use the Compact column labels for visibility cookies, reject malformed layout-specific sort cookies, and render child history rows newest-first without mutating the source data.
Serialize the zero-valued Snatched client status as [0]/['Snatched']
while preserving None and composed client-status masks.
Aggregated Compact rows refetch the exact active query without inserting raw websocket data; stale responses/loading and out-of-range pages remain guarded/clamped.
Regenerates dark/light development runtimes from the rebased corrections source.
Human-time expectations used a UTC value captured during test collection. On slower Windows jobs, the expanded suite can take longer than the 60-second tolerance before this parametrization runs, causing otherwise correct parser results to fail.

Compare human-time results with a fresh UTC reference captured at execution time. This changes test timing only and does not alter Generic Provider behavior.
@XxUnkn0wnxX XxUnkn0wnxX mentioned this pull request Aug 22, 2026
3 tasks done
@XxUnkn0wnxX
XxUnkn0wnxX force-pushed the feature/history-title-filtering-corrections branch from 2204e1b to cd79e82 Compare September 10, 2026 20:09
@XxUnkn0wnxX
XxUnkn0wnxX force-pushed the feature/history-title-filtering-corrections branch 2 times, most recently from 45e1a83 to 93cffff Compare October 2, 2026 20:09
@XxUnkn0wnxX
XxUnkn0wnxX force-pushed the feature/history-title-filtering-corrections branch from 93cffff to b416bef Compare October 8, 2026 06:04
Preserve the History feature changes while aligning with the 1.0.27 release.
The separate import-spacing fix is replayed after this replacement merge.

Validation: 451 focused backend tests, 187 frontend tests and one snapshot;
environment, lint, generated-asset and isolated runtime checks. Fork staging
PR #19 passed all 26 Actions jobs and both Codecov checks.
@XxUnkn0wnxX
XxUnkn0wnxX force-pushed the feature/history-title-filtering-corrections branch from b416bef to c485b59 Compare October 19, 2026 02:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant