From 84dee2710c9604a195a9921758a40c34c2404a28 Mon Sep 17 00:00:00 2001 From: "D. Rimron-Soutter" Date: Sat, 10 Jan 2026 21:53:31 +0000 Subject: [PATCH] Add genre column to entries Include genre data in entry search results and show it in the entries table layout. Signed-off-by: codex@lucy.xalior.com --- src/app/zxdb/entries/EntriesExplorer.tsx | 274 ++++++++++++++--------- src/server/repo/zxdb.ts | 41 ++++ 2 files changed, 212 insertions(+), 103 deletions(-) diff --git a/src/app/zxdb/entries/EntriesExplorer.tsx b/src/app/zxdb/entries/EntriesExplorer.tsx index a093e4a..26d1dd7 100644 --- a/src/app/zxdb/entries/EntriesExplorer.tsx +++ b/src/app/zxdb/entries/EntriesExplorer.tsx @@ -10,6 +10,8 @@ type Item = { id: number; title: string; isXrated: number; + genreId: number | null; + genreName?: string | null; machinetypeId: number | null; machinetypeName?: string | null; languageId: string | null; @@ -78,6 +80,25 @@ export default function EntriesExplorer({ const pageSize = 20; const totalPages = useMemo(() => (data ? Math.max(1, Math.ceil(data.total / data.pageSize)) : 1), [data]); + const activeFilters = useMemo(() => { + const chips: string[] = []; + if (q) chips.push(`q: ${q}`); + if (genreId !== "") { + const name = genres.find((g) => g.id === Number(genreId))?.name ?? `#${genreId}`; + chips.push(`genre: ${name}`); + } + if (languageId !== "") { + const name = languages.find((l) => l.id === languageId)?.name ?? languageId; + chips.push(`lang: ${name}`); + } + if (machinetypeId !== "") { + const name = machines.find((m) => m.id === Number(machinetypeId))?.name ?? `#${machinetypeId}`; + chips.push(`machine: ${name}`); + } + if (scope === "title_aliases") chips.push("scope: titles + aliases"); + if (scope === "title_aliases_origins") chips.push("scope: titles + aliases + origins"); + return chips; + }, [q, genreId, languageId, machinetypeId, scope, genres, languages, machines]); function updateUrl(nextPage = page) { const params = new URLSearchParams(); @@ -176,6 +197,16 @@ export default function EntriesExplorer({ fetchData(q, 1, true); } + function resetFilters() { + setQ(""); + setGenreId(""); + setLanguageId(""); + setMachinetypeId(""); + setSort("id_desc"); + setScope("title"); + setPage(1); + } + const prevHref = useMemo(() => { const params = new URLSearchParams(); if (q) params.set("q", q); @@ -209,121 +240,159 @@ export default function EntriesExplorer({ ]} /> -

Entries

-
-
- setQ(e.target.value)} - /> -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
- {loading && ( -
Loading...
- )} -
- - {facets && ( -
-
- Facets - - +
+
+

Entries

+
+ {data ? `${data.total.toLocaleString()} results` : "Loading results..."}
- )} - -
- {data && data.items.length === 0 && !loading && ( -
No results.
+ {activeFilters.length > 0 && ( +
+ {activeFilters.map((chip) => ( + {chip} + ))} + +
)} - {data && data.items.length > 0 && ( -
- - + + +
+
+
+
+
+
+ + setQ(e.target.value)} + /> +
+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ {facets && ( +
+
Facets
+
+ + +
+
+ )} + {loading &&
Loading...
} + +
+
+
+ +
+ {data && data.items.length === 0 && !loading && ( +
No results.
+ )} + {data && data.items.length > 0 && ( +
+
+ - + - - + + + {data.items.map((it) => ( + - +
IDID TitleMachineLanguageGenreMachineLanguage
- - - {it.machinetypeId != null ? ( - it.machinetypeName ? ( - {it.machinetypeName} + {it.genreId != null ? ( + it.genreName ? ( + {it.genreName} ) : ( - {it.machinetypeId} + {it.genreId} ) ) : ( - )} + {it.machinetypeId != null ? ( + it.machinetypeName ? ( + {it.machinetypeName} + ) : ( + {it.machinetypeId} + ) + ) : ( + - + )} + {it.languageId ? ( it.languageName ? ( @@ -339,14 +408,13 @@ export default function EntriesExplorer({ ))}
-
- )} +
+ )} +
-
- - Page {data?.page ?? 1} / {totalPages} - +
+ Page {data?.page ?? 1} / {totalPages}