From ec48e27fbfdf041f088735a66f5a1bc47a634f14 Mon Sep 17 00:00:00 2001 From: Georges-Antoine Assi Date: Tue, 23 Sep 2025 22:45:10 -0400 Subject: [PATCH] [ROMM-2476] Add new index for rom-to-rom navigation --- backend/endpoints/rom.py | 11 ++- .../CustomLimitOffsetPage_SimpleRomSchema_.ts | 1 + .../components/Details/BackgroundHeader.vue | 14 ++-- frontend/src/stores/roms.ts | 81 ++++++++++--------- 4 files changed, 60 insertions(+), 47 deletions(-) diff --git a/backend/endpoints/rom.py b/backend/endpoints/rom.py index 753d3124f..795a28f4d 100644 --- a/backend/endpoints/rom.py +++ b/backend/endpoints/rom.py @@ -61,7 +61,7 @@ from handler.metadata import ( from logger.formatter import BLUE from logger.formatter import highlight as hl from logger.logger import log -from models.rom import RomFile +from models.rom import Rom, RomFile from utils.filesystem import sanitize_filename from utils.hashing import crc32_to_hex from utils.nginx import FileRedirectResponse, ZipContentLine, ZipResponse @@ -161,6 +161,7 @@ class CustomLimitOffsetParams(LimitOffsetParams): class CustomLimitOffsetPage[T: BaseModel](LimitOffsetPage[T]): char_index: dict[str, int] + rom_id_index: list[int] __params_type__ = CustomLimitOffsetParams @@ -312,14 +313,20 @@ def get_roms( ) char_index_dict = {char: index for (char, index) in char_index} + # Get all ROM IDs in order for the additional data with sync_session.begin() as session: + rom_id_index = session.scalars(query.with_only_columns(Rom.id)).all() # type: ignore + return paginate( session, query, transformer=lambda items: [ SimpleRomSchema.from_orm_with_request(i, request) for i in items ], - additional_data={"char_index": char_index_dict}, + additional_data={ + "char_index": char_index_dict, + "rom_id_index": rom_id_index, + }, ) diff --git a/frontend/src/__generated__/models/CustomLimitOffsetPage_SimpleRomSchema_.ts b/frontend/src/__generated__/models/CustomLimitOffsetPage_SimpleRomSchema_.ts index c75b087ca..8ae6d7dd5 100644 --- a/frontend/src/__generated__/models/CustomLimitOffsetPage_SimpleRomSchema_.ts +++ b/frontend/src/__generated__/models/CustomLimitOffsetPage_SimpleRomSchema_.ts @@ -9,5 +9,6 @@ export type CustomLimitOffsetPage_SimpleRomSchema_ = { limit: (number | null); offset: (number | null); char_index: Record; + rom_id_index: Array; }; diff --git a/frontend/src/components/Details/BackgroundHeader.vue b/frontend/src/components/Details/BackgroundHeader.vue index f53742b88..a8f528060 100644 --- a/frontend/src/components/Details/BackgroundHeader.vue +++ b/frontend/src/components/Details/BackgroundHeader.vue @@ -7,7 +7,7 @@ import storeRoms from "@/stores/roms"; import { getMissingCoverImage, getUnmatchedCoverImage } from "@/utils/covers"; const romsStore = storeRoms(); -const { currentRom, filteredRoms } = storeToRefs(romsStore); +const { currentRom, romIdIndex } = storeToRefs(romsStore); const router = useRouter(); const { smAndUp } = useDisplay(); @@ -23,18 +23,18 @@ const unmatchedCoverImage = computed(() => ); const currentRomIndex = computed(() => - filteredRoms.value.findIndex((rom) => rom.id === currentRom.value?.id), + romIdIndex.value.findIndex((rom) => rom === currentRom.value?.id), ); function previousRom() { if (currentRomIndex.value > 0) { - router.push(`/rom/${filteredRoms.value[currentRomIndex.value - 1].id}`); + router.push(`/rom/${romIdIndex.value[currentRomIndex.value - 1]}`); } } function nextRom() { - if (currentRomIndex.value < filteredRoms.value.length - 1) { - router.push(`/rom/${filteredRoms.value[currentRomIndex.value + 1].id}`); + if (currentRomIndex.value < romIdIndex.value.length - 1) { + router.push(`/rom/${romIdIndex.value[currentRomIndex.value + 1]}`); } } @@ -60,7 +60,7 @@ function nextRom() { mdi-arrow-right diff --git a/frontend/src/stores/roms.ts b/frontend/src/stores/roms.ts index 26983c9d6..568342282 100644 --- a/frontend/src/stores/roms.ts +++ b/frontend/src/stores/roms.ts @@ -37,6 +37,7 @@ const defaultRomsState = { fetchLimit: 72, characterIndex: {} as Record, selectedCharacter: null as string | null, + romIdIndex: [] as number[], orderBy: "name" as keyof SimpleRom, orderDir: "asc" as "asc" | "desc", }; @@ -150,49 +151,52 @@ export default defineStore("roms", { orderDir: this.orderDir, groupByMetaId: this._shouldGroupRoms() && this.onGalleryView, }) - .then(({ data: { items, offset, total, char_index } }) => { - if (!concat || this.fetchOffset === 0) { - this.allRoms = items; + .then( + ({ data: { items, offset, total, char_index, rom_id_index } }) => { + if (!concat || this.fetchOffset === 0) { + this.allRoms = items; - // Cache the first batch of roms for each context - if (this.currentPlatform) { - _romsCacheByPlatform.set( - this.currentPlatform.id, - items.map((rom) => rom.id), - ); - items.forEach((rom) => _romsCacheByID.set(rom.id, rom)); - } else if (this.currentCollection) { - _romsCacheByCollection.set( - this.currentCollection.id, - items.map((rom) => rom.id), - ); - items.forEach((rom) => _romsCacheByID.set(rom.id, rom)); - } else if (this.currentVirtualCollection) { - _romsCacheByVirtualCollection.set( - this.currentVirtualCollection.id, - items.map((rom) => rom.id), - ); - items.forEach((rom) => _romsCacheByID.set(rom.id, rom)); - } else if (this.currentSmartCollection) { - _romsCacheBySmartCollection.set( - this.currentSmartCollection.id, - items.map((rom) => rom.id), - ); - items.forEach((rom) => _romsCacheByID.set(rom.id, rom)); + // Cache the first batch of roms for each context + if (this.currentPlatform) { + _romsCacheByPlatform.set( + this.currentPlatform.id, + items.map((rom) => rom.id), + ); + items.forEach((rom) => _romsCacheByID.set(rom.id, rom)); + } else if (this.currentCollection) { + _romsCacheByCollection.set( + this.currentCollection.id, + items.map((rom) => rom.id), + ); + items.forEach((rom) => _romsCacheByID.set(rom.id, rom)); + } else if (this.currentVirtualCollection) { + _romsCacheByVirtualCollection.set( + this.currentVirtualCollection.id, + items.map((rom) => rom.id), + ); + items.forEach((rom) => _romsCacheByID.set(rom.id, rom)); + } else if (this.currentSmartCollection) { + _romsCacheBySmartCollection.set( + this.currentSmartCollection.id, + items.map((rom) => rom.id), + ); + items.forEach((rom) => _romsCacheByID.set(rom.id, rom)); + } + } else { + this.allRoms = this.allRoms.concat(items); } - } else { - this.allRoms = this.allRoms.concat(items); - } - // Update the offset and total roms in filtered database result - if (offset !== null) this.fetchOffset = offset + this.fetchLimit; - if (total !== null) this.fetchTotalRoms = total; + // Update the offset and total roms in filtered database result + if (offset !== null) this.fetchOffset = offset + this.fetchLimit; + if (total !== null) this.fetchTotalRoms = total; - // Set the character index for the current platform - this.characterIndex = char_index; + // Set the character index for the current platform + this.characterIndex = char_index; + this.romIdIndex = rom_id_index; - resolve(items); - }) + resolve(items); + }, + ) .catch((error) => { reject(error); }) @@ -273,6 +277,7 @@ export default defineStore("roms", { this.initialSearch = false; this.characterIndex = {}; this.selectedCharacter = null; + this.romIdIndex = []; this.resetPagination(); }, resetPagination() {