feat(library): add filter UI for install, platform, controls, and activity - #602
Conversation
… and activity Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 06a78f8. Configure here.
| {hasActiveLibraryFilters | ||
| ? t("library.empty.tryAdjustingFilters") | ||
| : t("library.empty.noGamesMatch", { query: searchQuery })} | ||
| </p> |
There was a problem hiding this comment.
Wrong empty state with search
Medium Severity
When the search yields no rows but library filters stay selected, the grid empty state uses the “no games match those filters” copy instead of the search miss message. Parent games is already search-filtered, so an empty list with a non-empty query usually means search failed, not filters alone.
Reviewed by Cursor Bugbot for commit 06a78f8. Configure here.
| } else if (game.playType?.trim()) { | ||
| const key = normalizeLibraryFilterValue(game.playType); | ||
| if (key) upsertLibraryFilterOption(playTypeOptions, `play:${key}`, formatLibraryPlayTypeLabel(game.playType)); | ||
| } |
There was a problem hiding this comment.
Play type filter mismatch
Medium Severity
Play Type options and matching use different rules. Titles counted as “Install to Play” via gameRequiresInstallToPlay can still match a “Cloud Launch” (or other) play filter because matching compares normalized game.playType without applying the install heuristic used when building options.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 06a78f8. Configure here.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 06a78f8c47
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| } | ||
|
|
||
| if (groupId === "activity") { | ||
| return value === "played" ? Boolean(game.lastPlayed) : !game.lastPlayed; |
There was a problem hiding this comment.
Include local playtime in activity filters
When a user launches a game in this client, usePlaytime records lastPlayedAt locally and sortLibraryGames already uses that value for the library's last-played ordering, but this new activity filter only checks the catalog game.lastPlayed field. For games played locally before the GFN library metadata refreshes, the game is still treated as Never Played and disappears when the user selects the Played filter; the activity filter needs to consider the same local playtime source passed from App.
Useful? React with 👍 / 👎.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>


This PR adds a filter dropdown to the library page allowing users to filter games by play type (Install to Play, Cloud Launch), platform (Steam, Epic, Xbox, etc.), controls (Keyboard & Mouse, Controller, Touch), and play activity (Played, Never Played).
LibraryFilterGroupandLibraryFilterOptioninterfaces for filter structureplayType,availableStores,supportedControls,lastPlayed)visibleLibraryGamesmemo to filter grid based on active filtersChanges:
locales/en.json: Addedlibrary.filterGroups,library.filterOptions,library.filters,library.activeFilters,library.clearFilters,library.removeFilter,library.filteredGameCount,library.empty.noFilteredGames,library.empty.tryAdjustingFiltersopennow-stable/src/renderer/src/App.tsx: PassallGamesprop toLibraryPagefor filter generationopennow-stable/src/renderer/src/components/LibraryPage.tsx: Added filter UI, state management, and filtering logicopennow-stable/src/renderer/src/styles.css: Added.library-filter-dropdown,.library-filter-chip,.library-active-filtersstylesNote
Low Risk
Renderer-only library UI and client-side filtering; no auth, session, or backend changes.
Overview
Adds desktop library filtering alongside search and sort: a Filters dropdown with grouped chips (play type, platform/store, controls, played vs never played), counts per option, and a removable active filters bar with clear-all.
Filter options are derived from the full library (
allGamesfromApp) while the grid uses search/sort results then applies filters with OR within a group and AND across groups. Selection resets when options disappear, selection follows the first visible game when the current pick is filtered out, and empty states distinguish no matches for filters vs search.New i18n strings and library-specific CSS mirror the store filter dropdown pattern; controller mode is unchanged (existing Y-hold store filter only).
Reviewed by Cursor Bugbot for commit 06a78f8. Configure here.