Merge pull request #3001 from rommapp/romm-2976

[ROMM-2976] Fix no games displayed for status filter
This commit is contained in:
Georges-Antoine Assi
2026-02-07 22:50:23 -05:00
committed by GitHub
8 changed files with 182 additions and 364 deletions

View File

@@ -25,25 +25,25 @@ lint:
- dotenv-linter@4.0.0
- hadolint@2.14.0
- markdownlint@0.47.0
- eslint@9.39.2
- eslint@9.34.0
- actionlint@1.7.10
- bandit@1.9.2
- black@25.12.0
- checkov@3.2.497
- bandit@1.9.3
- black@26.1.0
- checkov@3.2.500
- git-diff-check
- isort@7.0.0
- mypy@1.19.1
- osv-scanner@2.3.2
- prettier@3.8.0:
- prettier@3.8.1:
packages:
- "@trivago/prettier-plugin-sort-imports@6.0.2"
- "@vue/compiler-sfc@3.5.26"
- ruff@0.14.13
- "@vue/compiler-sfc@3.5.27"
- ruff@0.15.0
- shellcheck@0.11.0
- shfmt@3.6.0
- taplo@0.10.0
- trivy@0.68.2
- trufflehog@3.92.5
- trivy@0.69.1
- trufflehog@3.93.1
- yamllint@1.38.0
ignore:
- linters: [ALL]

View File

@@ -424,13 +424,20 @@ class DBRomsHandler(DBBaseHandler):
condition = op(RomMetadata.age_ratings, values, session=session)
return query.filter(~condition) if match_none else query.filter(condition)
def _filter_by_status(self, query: Query, statuses: Sequence[str]):
"""Filter by one or more user statuses using OR logic."""
if not statuses:
def _filter_by_status(
self,
query: Query,
*,
session: Session,
values: Sequence[str],
match_all: bool = False,
match_none: bool = False,
):
if not values:
return query
status_filters = []
for selected_status in statuses:
for selected_status in values:
if selected_status == "now_playing":
status_filters.append(RomUser.now_playing.is_(True))
elif selected_status == "backlogged":
@@ -440,11 +447,17 @@ class DBRomsHandler(DBBaseHandler):
else:
status_filters.append(RomUser.status == selected_status)
# If hidden is in the list, don't apply the hidden filter at the end
if "hidden" in statuses:
return query.filter(or_(*status_filters))
comb = and_ if match_all else or_
condition = comb(*status_filters)
return query.filter(or_(*status_filters), RomUser.hidden.is_(False))
# Apply negation if match_none, otherwise apply condition
query = query.filter(~condition) if match_none else query.filter(condition)
# Don't apply the hidden filter is hidden is set
if "hidden" in values:
return query
return query.filter(or_(RomUser.hidden.is_(False), RomUser.hidden.is_(None)))
def _filter_by_regions(
self,
@@ -740,7 +753,13 @@ class DBRomsHandler(DBBaseHandler):
# The RomUser table is already joined if user_id is set
if statuses and user_id:
query = self._filter_by_status(query, statuses)
query = self._filter_by_status(
query,
session=session,
values=statuses,
match_all=(statuses_logic == "all"),
match_none=(statuses_logic == "none"),
)
elif user_id:
query = query.filter(
or_(RomUser.hidden.is_(False), RomUser.hidden.is_(None))

File diff suppressed because it is too large Load Diff

View File

@@ -66,7 +66,7 @@
"globals": "^16.0.0",
"openapi-typescript-codegen": "^0.29.0",
"typescript": "^5.7.3",
"typescript-eslint": "^8.42.0",
"typescript-eslint": "^8.54.0",
"vite": "^6.4.1",
"vite-plugin-mkcert": "^1.17.8",
"vite-plugin-pwa": "^0.21.1",
@@ -75,6 +75,6 @@
"vue-tsc": "^2.2.8"
},
"engines": {
"node": "18"
"node": ">18"
}
}

View File

@@ -2,7 +2,7 @@
import { debounce } from "lodash";
import type { Emitter } from "mitt";
import { storeToRefs } from "pinia";
import { inject, nextTick, onMounted } from "vue";
import { inject, nextTick, onMounted, ref } from "vue";
import { useI18n } from "vue-i18n";
import { useRouter } from "vue-router";
import { useDisplay } from "vuetify";
@@ -21,6 +21,7 @@ import storeGalleryFilter, {
import storePlatforms from "@/stores/platforms";
import storeRoms from "@/stores/roms";
import type { Events } from "@/types/emitter";
import { romStatusMap, type PlayingStatus } from "@/utils";
withDefaults(
defineProps<{
@@ -180,6 +181,13 @@ const onFilterChange = debounce(
emitter?.on("filterRoms", onFilterChange);
const mappedStatuses = ref(
filterStatuses.value.map((s) => ({
title: romStatusMap[s as PlayingStatus].text,
value: s,
})),
);
const filters = [
{
label: t("platform.genre"),
@@ -248,7 +256,7 @@ const filters = [
{
label: t("platform.status"),
selected: selectedStatuses,
items: filterStatuses,
items: mappedStatuses,
logic: statusesLogic,
setLogic: (logic: FilterLogicOperator) =>
galleryFilterStore.setStatusesLogic(logic),

View File

@@ -13,7 +13,6 @@ import storeCollections from "@/stores/collections";
import storeGalleryFilter from "@/stores/galleryFilter";
import storeRoms from "@/stores/roms";
import type { Events } from "@/types/emitter";
import { getStatusKeyForText } from "@/utils";
const { t } = useI18n();
const galleryFilterStore = storeGalleryFilter();
@@ -172,10 +171,7 @@ async function createSmartCollection() {
filterCriteria.age_ratings_logic = ageRatingsLogic.value;
}
if (selectedStatuses.value && selectedStatuses.value.length > 0) {
const statusKeys = selectedStatuses.value
.filter((s): s is string => s !== null)
.map((s) => getStatusKeyForText(s))
.filter((key) => key !== null);
const statusKeys = selectedStatuses.value;
if (statusKeys.length > 0) {
filterCriteria.selected_status = statusKeys;
}

View File

@@ -29,7 +29,7 @@ const defaultFilterState = {
filterRegions: [] as string[],
filterLanguages: [] as string[],
filterPlayerCounts: [] as string[],
filterStatuses: Object.values(romStatusMap).map((status) => status.text),
filterStatuses: Object.keys(romStatusMap),
filterMatched: null as boolean | null, // null = all, true = matched, false = unmatched
filterFavorites: null as boolean | null, // null = all, true = favorites, false = not favorites
filterDuplicates: null as boolean | null, // null = all, true = duplicates, false = not duplicates

View File

@@ -630,7 +630,11 @@ export function isRuffleEmulationSupported(
return ["flash", "browser"].includes(slug.toLowerCase());
}
type PlayingStatus = RomUserStatus | "backlogged" | "now_playing" | "hidden";
export type PlayingStatus =
| RomUserStatus
| "backlogged"
| "now_playing"
| "hidden";
/**
* Map of ROM statuses to their corresponding emoji, text, and i18n key.
@@ -669,13 +673,6 @@ export const romStatusMap: Record<
hidden: { emoji: "👻", text: "Hidden", i18nKey: "rom.status-hidden" },
};
/**
* Inverse map of ROM statuses from text to status key.
*/
const inverseRomStatusMap = Object.fromEntries(
Object.entries(romStatusMap).map(([key, value]) => [value.text, key]),
) as Record<string, PlayingStatus>;
/**
* Get the emoji for a given ROM status.
*
@@ -710,17 +707,6 @@ export function getI18nKeyForStatus(status: PlayingStatus): string | null {
return romStatusMap[status]?.i18nKey ?? null;
}
/**
* Get the status key for a given text.
*
* @param text The text to convert.
* @returns The corresponding status key.
*/
export function getStatusKeyForText(text: string | null) {
if (!text) return null;
return inverseRomStatusMap[text];
}
export function isNintendoDSFile(rom: SimpleRom): boolean {
return ["cia", "nds", "3ds", "dsi"].includes(rom.fs_extension.toLowerCase());
}