Refactor platform filtering logic: remove single platform ID and logic operator parameters, streamline multi-platform handling in API and frontend components.

This commit is contained in:
zurdi
2025-11-27 20:13:29 +00:00
parent 937ba54077
commit b4dd08d7b4
7 changed files with 18 additions and 89 deletions

View File

@@ -201,10 +201,6 @@ def get_roms(
str | None,
Query(description="Search term to filter roms."),
] = None,
platform_id: Annotated[
int | None,
Query(description="Platform internal id.", ge=1),
] = None,
platform_ids: Annotated[
list[int] | None,
Query(
@@ -361,13 +357,6 @@ def get_roms(
Query(description="Order direction, either 'asc' or 'desc'."),
] = "asc",
# Logic operators for multi-value filters
platforms_logic: Annotated[
str,
Query(
description="Logic operator for platforms filter: 'any' (OR) or 'all' (AND).",
alias="platforms_logic",
),
] = "any",
genres_logic: Annotated[
str,
Query(
@@ -480,7 +469,6 @@ def get_roms(
query = db_rom_handler.filter_roms(
query=query,
user_id=request.user.id,
platform_id=platform_id,
platform_ids=platform_ids,
collection_id=collection_id,
virtual_collection_id=virtual_collection_id,
@@ -502,7 +490,6 @@ def get_roms(
regions=regions,
languages=languages,
# Logic operators
platforms_logic=platforms_logic,
genres_logic=genres_logic,
franchises_logic=franchises_logic,
collections_logic=collections_logic,

View File

@@ -431,7 +431,6 @@ class DBRomsHandler(DBBaseHandler):
def filter_roms(
self,
query: Query,
platform_id: int | None = None,
platform_ids: Sequence[int] | None = None,
collection_id: int | None = None,
virtual_collection_id: str | None = None,
@@ -454,7 +453,6 @@ class DBRomsHandler(DBBaseHandler):
regions: Sequence[str] | None = None,
languages: Sequence[str] | None = None,
# Logic operators for multi-value filters
platforms_logic: str = "any",
genres_logic: str = "any",
franchises_logic: str = "any",
collections_logic: str = "any",
@@ -467,13 +465,9 @@ class DBRomsHandler(DBBaseHandler):
) -> Query[Rom]:
from handler.scan_handler import MetadataSource
# Handle platform filtering with priority for multi-platform
# Handle platform filtering - platform filtering always uses OR logic since ROMs belong to only one platform
if platform_ids:
query = self.filter_by_platform_ids(
query, platform_ids, match_all=(platforms_logic == "all")
)
elif platform_id:
query = self.filter_by_platform_id(query, platform_id)
query = self.filter_by_platform_ids(query, platform_ids, match_all=False)
if collection_id:
query = self.filter_by_collection_id(query, session, collection_id)

View File

@@ -14,8 +14,7 @@ defineProps<{
const { t } = useI18n();
const galleryFilterStore = storeGalleryFilter();
const { selectedPlatforms, filterPlatforms, platformsLogic } =
storeToRefs(galleryFilterStore);
const { selectedPlatforms, filterPlatforms } = storeToRefs(galleryFilterStore);
const emitter = inject<Emitter<Events>>("emitter");
</script>
@@ -84,42 +83,5 @@ const emitter = inject<Emitter<Events>>("emitter");
</v-chip>
</template>
</v-select>
<!-- AND/OR Logic Toggle - always visible -->
<v-btn-toggle
:model-value="platformsLogic"
mandatory
variant="outlined"
density="compact"
class="flex-shrink-0"
@update:model-value="
(value) => {
galleryFilterStore.setPlatformsLogic(value);
nextTick(() => emitter?.emit('filterRoms', null));
}
"
>
<v-tooltip
text="Match ANY of the selected platforms (OR logic)"
location="bottom"
open-delay="500"
>
<template #activator="{ props }">
<v-btn value="any" size="small" v-bind="props">
<v-icon size="x-large">mdi-set-none</v-icon>
</v-btn>
</template>
</v-tooltip>
<v-tooltip
text="Match ALL of the selected platforms (AND logic) - Note: Will return no results since a ROM belongs to only one platform"
location="bottom"
open-delay="500"
>
<template #activator="{ props }">
<v-btn value="all" size="small" v-bind="props">
<v-icon size="x-large">mdi-set-all</v-icon>
</v-btn>
</template>
</v-tooltip>
</v-btn-toggle>
</div>
</template>

View File

@@ -61,7 +61,6 @@ async function uploadRoms({
}
export interface GetRomsParams {
platformId?: number | null;
platformIds?: number[] | null;
collectionId?: number | null;
virtualCollectionId?: string | null;
@@ -99,7 +98,6 @@ export interface GetRomsParams {
selectedLanguages?: string[] | null;
selectedStatuses?: string[] | null;
// Logic operators for multi-value filters
platformsLogic?: string | null;
genresLogic?: string | null;
franchisesLogic?: string | null;
collectionsLogic?: string | null;
@@ -110,7 +108,6 @@ export interface GetRomsParams {
}
async function getRoms({
platformId = null,
platformIds = null,
collectionId = null,
virtualCollectionId = null,
@@ -146,7 +143,6 @@ async function getRoms({
selectedLanguages = null,
selectedStatuses = null,
// Logic operators
platformsLogic = null,
genresLogic = null,
franchisesLogic = null,
collectionsLogic = null,
@@ -166,7 +162,6 @@ async function getRoms({
};
const params = {
platform_id: platformId,
platform_ids:
platformIds && platformIds.length > 0 ? platformIds : undefined,
collection_id: collectionId,
@@ -187,10 +182,6 @@ async function getRoms({
region: getFilterArray(selectedRegion, selectedRegions),
language: getFilterArray(selectedLanguage, selectedLanguages),
// Logic operators
platforms_logic:
platformIds && platformIds.length > 1
? platformsLogic || "any"
: undefined,
genres_logic:
selectedGenres && selectedGenres.length > 1
? genresLogic || "any"

View File

@@ -87,10 +87,6 @@ class CachedApiService {
params.selectedLanguages,
),
// Logic operators
platforms_logic:
params.platformIds && params.platformIds.length > 1
? params.platformsLogic || "any"
: undefined,
genres_logic:
params.selectedGenres && params.selectedGenres.length > 1
? params.genresLogic || "any"

View File

@@ -53,7 +53,6 @@ const defaultFilterState = {
selectedStatus: null as string | null,
selectedStatuses: [] as string[],
// Logic operators for multi-select filters
platformsLogic: "any" as "any" | "all",
genresLogic: "any" as "any" | "all",
franchisesLogic: "any" as "any" | "all",
collectionsLogic: "any" as "any" | "all",
@@ -103,9 +102,6 @@ export default defineStore("galleryFilter", {
setSelectedFilterPlatforms(platforms: Platform[]) {
this.selectedPlatforms = platforms;
},
setPlatformsLogic(logic: "any" | "all") {
this.platformsLogic = logic;
},
setSelectedFilterGenre(genre: string) {
this.selectedGenre = genre;
},
@@ -405,7 +401,6 @@ export default defineStore("galleryFilter", {
this.filterMissing = null;
this.filterVerified = null;
// Reset logic operators to default
this.platformsLogic = "any";
this.genresLogic = "any";
this.franchisesLogic = "any";
this.collectionsLogic = "any";

View File

@@ -96,18 +96,23 @@ export default defineStore("roms", {
},
// Fetching multiple roms
_buildRequestParams(galleryFilter: GalleryFilterStore) {
// Determine platform IDs - use multiselect platforms if available, otherwise convert single platform to array
let platformIds: number[] | null = null;
if (galleryFilter.selectedPlatforms.length > 0) {
platformIds = galleryFilter.selectedPlatforms.map((p) => p.id);
} else {
const singlePlatformId =
this.currentPlatform?.id ??
galleryFilter.selectedPlatform?.id ??
null;
if (singlePlatformId) {
platformIds = [singlePlatformId];
}
}
const params = {
searchTerm: galleryFilter.searchTerm,
platformId:
galleryFilter.selectedPlatforms.length > 0
? null
: (this.currentPlatform?.id ??
galleryFilter.selectedPlatform?.id ??
null),
platformIds:
galleryFilter.selectedPlatforms.length > 0
? galleryFilter.selectedPlatforms.map((p) => p.id)
: null,
platformIds: platformIds,
collectionId: this.currentCollection?.id ?? null,
virtualCollectionId: this.currentVirtualCollection?.id ?? null,
smartCollectionId: this.currentSmartCollection?.id ?? null,
@@ -191,7 +196,6 @@ export default defineStore("roms", {
? galleryFilter.selectedStatuses
: null,
// Logic operators
platformsLogic: galleryFilter.platformsLogic,
genresLogic: galleryFilter.genresLogic,
franchisesLogic: galleryFilter.franchisesLogic,
collectionsLogic: galleryFilter.collectionsLogic,