From 07478b280c2e7c971394c9e07904a41a385a7138 Mon Sep 17 00:00:00 2001 From: "D. Rimron-Soutter" Date: Wed, 17 Dec 2025 20:22:00 +0000 Subject: [PATCH] Fix build errors --- drizzle.config.ts | 2 +- src/app/registers/[hex]/page.tsx | 1 - src/app/zxdb/ZxdbExplorer.tsx | 1 - src/app/zxdb/entries/EntriesExplorer.tsx | 2 - src/app/zxdb/entries/[id]/EntryDetail.tsx | 2 +- src/app/zxdb/labels/[id]/LabelDetail.tsx | 24 ++++++---- src/app/zxdb/releases/ReleasesExplorer.tsx | 5 +- src/components/Navbar.tsx | 3 +- src/env.ts | 1 - src/server/repo/zxdb.ts | 53 +++++++++++----------- 10 files changed, 44 insertions(+), 50 deletions(-) diff --git a/drizzle.config.ts b/drizzle.config.ts index ce5c448..76603a1 100644 --- a/drizzle.config.ts +++ b/drizzle.config.ts @@ -6,7 +6,7 @@ import type { Config } from "drizzle-kit"; export default { schema: "./src/server/schema/**/*.ts", out: "./drizzle", - driver: "mysql2", + dialect: "mysql", dbCredentials: { // Read from env at runtime when using drizzle-kit url: process.env.ZXDB_URL!, diff --git a/src/app/registers/[hex]/page.tsx b/src/app/registers/[hex]/page.tsx index 14d02a5..4e87538 100644 --- a/src/app/registers/[hex]/page.tsx +++ b/src/app/registers/[hex]/page.tsx @@ -1,6 +1,5 @@ import { notFound } from 'next/navigation'; import Link from 'next/link'; -import { Register } from '@/utils/register_parser'; import RegisterDetail from '@/app/registers/RegisterDetail'; import {Container, Row} from "react-bootstrap"; import { getRegisters } from '@/services/register.service'; diff --git a/src/app/zxdb/ZxdbExplorer.tsx b/src/app/zxdb/ZxdbExplorer.tsx index 9a8bfc5..789e226 100644 --- a/src/app/zxdb/ZxdbExplorer.tsx +++ b/src/app/zxdb/ZxdbExplorer.tsx @@ -62,7 +62,6 @@ export default function ZxdbExplorer({ const json: Paged = await res.json(); setData(json); } catch (e) { - // eslint-disable-next-line no-console console.error(e); setData({ items: [], page: 1, pageSize, total: 0 }); } finally { diff --git a/src/app/zxdb/entries/EntriesExplorer.tsx b/src/app/zxdb/entries/EntriesExplorer.tsx index 1eba2c7..84de55e 100644 --- a/src/app/zxdb/entries/EntriesExplorer.tsx +++ b/src/app/zxdb/entries/EntriesExplorer.tsx @@ -91,7 +91,6 @@ export default function EntriesExplorer({ const json: Paged = await res.json(); setData(json); } catch (e) { - // eslint-disable-next-line no-console console.error(e); setData({ items: [], page: 1, pageSize, total: 0 }); } finally { @@ -105,7 +104,6 @@ export default function EntriesExplorer({ setData(initial); setPage(initial.page); } - // eslint-disable-next-line react-hooks/exhaustive-deps }, [initial]); // Client fetch when filters/paging/sort change; also keep URL in sync diff --git a/src/app/zxdb/entries/[id]/EntryDetail.tsx b/src/app/zxdb/entries/[id]/EntryDetail.tsx index 71c8f0b..e5473ec 100644 --- a/src/app/zxdb/entries/[id]/EntryDetail.tsx +++ b/src/app/zxdb/entries/[id]/EntryDetail.tsx @@ -68,7 +68,7 @@ export type EntryDetailData = { }[]; }; -export default function EntryDetailClient({ data }: { data: EntryDetailData }) { +export default function EntryDetailClient({ data }: { data: EntryDetailData | null }) { if (!data) return
Not found
; return ( diff --git a/src/app/zxdb/labels/[id]/LabelDetail.tsx b/src/app/zxdb/labels/[id]/LabelDetail.tsx index bb896f0..ef98eec 100644 --- a/src/app/zxdb/labels/[id]/LabelDetail.tsx +++ b/src/app/zxdb/labels/[id]/LabelDetail.tsx @@ -17,10 +17,14 @@ export default function LabelDetailClient({ id, initial, initialTab, initialQ }: const router = useRouter(); // Names are now delivered by SSR payload to minimize pop-in. - if (!initial || !initial.label) return
Not found
; + // Hooks must be called unconditionally + const current = useMemo | null>( + () => (tab === "authored" ? initial?.authored : initial?.published) ?? null, + [initial, tab] + ); + const totalPages = useMemo(() => (current ? Math.max(1, Math.ceil(current.total / current.pageSize)) : 1), [current]); - const current = useMemo(() => (tab === "authored" ? initial.authored : initial.published), [initial, tab]); - const totalPages = useMemo(() => Math.max(1, Math.ceil(current.total / current.pageSize)), [current]); + if (!initial || !initial.label) return
Not found
; return (
@@ -98,19 +102,19 @@ export default function LabelDetailClient({ id, initial, initialTab, initialQ }:
- Page {current.page} / {totalPages} + Page {current ? current.page : 1} / {totalPages}
{ const p = new URLSearchParams(); p.set("tab", tab); if (q) p.set("q", q); p.set("page", String(Math.max(1, current.page - 1))); return p.toString(); })()}`} + className={`btn btn-sm btn-outline-secondary ${current && current.page <= 1 ? "disabled" : ""}`} + aria-disabled={current ? current.page <= 1 : true} + href={`/zxdb/labels/${id}?${(() => { const p = new URLSearchParams(); p.set("tab", tab); if (q) p.set("q", q); p.set("page", String(Math.max(1, (current ? current.page : 1) - 1))); return p.toString(); })()}`} > Prev = totalPages ? "disabled" : ""}`} - aria-disabled={current.page >= totalPages} - href={`/zxdb/labels/${id}?${(() => { const p = new URLSearchParams(); p.set("tab", tab); if (q) p.set("q", q); p.set("page", String(Math.min(totalPages, current.page + 1))); return p.toString(); })()}`} + className={`btn btn-sm btn-outline-secondary ${current && current.page >= totalPages ? "disabled" : ""}`} + aria-disabled={current ? current.page >= totalPages : true} + href={`/zxdb/labels/${id}?${(() => { const p = new URLSearchParams(); p.set("tab", tab); if (q) p.set("q", q); p.set("page", String(Math.min(totalPages, (current ? current.page : 1) + 1))); return p.toString(); })()}`} > Next diff --git a/src/app/zxdb/releases/ReleasesExplorer.tsx b/src/app/zxdb/releases/ReleasesExplorer.tsx index b730adc..413e509 100644 --- a/src/app/zxdb/releases/ReleasesExplorer.tsx +++ b/src/app/zxdb/releases/ReleasesExplorer.tsx @@ -104,7 +104,6 @@ export default function ReleasesExplorer({ const json: Paged = await res.json(); setData(json); } catch (e) { - // eslint-disable-next-line no-console console.error(e); setData({ items: [], page: 1, pageSize, total: 0 }); } finally { @@ -117,7 +116,6 @@ export default function ReleasesExplorer({ setData(initial); setPage(initial.page); } - // eslint-disable-next-line react-hooks/exhaustive-deps }, [initial]); useEffect(() => { @@ -141,7 +139,6 @@ export default function ReleasesExplorer({ } updateUrl(page); fetchData(q, page); - // eslint-disable-next-line react-hooks/exhaustive-deps }, [page, year, sort, dLanguageId, dMachinetypeId, filetypeId, schemetypeId, sourcetypeId, casetypeId, isDemo]); function onSubmit(e: React.FormEvent) { @@ -286,7 +283,7 @@ export default function ReleasesExplorer({
- { setSort(e.target.value as typeof sort); setPage(1); }}> diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx index fed7974..79efc22 100644 --- a/src/components/Navbar.tsx +++ b/src/components/Navbar.tsx @@ -1,8 +1,7 @@ "use client"; import Link from "next/link"; -import * as Icon from "react-bootstrap-icons"; -import { Navbar, Nav, Container, Dropdown } from "react-bootstrap"; +import { Navbar, Nav, Container } from "react-bootstrap"; import ThemeDropdown from "@/components/ThemeDropdown"; export default function NavbarClient() { diff --git a/src/env.ts b/src/env.ts index 1a515a3..9a08723 100644 --- a/src/env.ts +++ b/src/env.ts @@ -26,7 +26,6 @@ function formatErrors(errors: z.ZodFormattedError, string>) const parsed = serverSchema.safeParse(process.env); if (!parsed.success) { // Fail fast with helpful output in server context - // eslint-disable-next-line no-console console.error("❌ Invalid environment variables:\n" + formatErrors(parsed.error.format())); throw new Error("Invalid environment variables"); } diff --git a/src/server/repo/zxdb.ts b/src/server/repo/zxdb.ts index b45027d..0689cd0 100644 --- a/src/server/repo/zxdb.ts +++ b/src/server/repo/zxdb.ts @@ -1,5 +1,5 @@ import { and, desc, eq, like, sql, asc } from "drizzle-orm"; -import { alias } from "drizzle-orm/mysql-core"; +// import { alias } from "drizzle-orm/mysql-core"; import { db } from "@/server/db"; import { entries, @@ -88,7 +88,7 @@ export async function searchEntries(params: SearchParams): Promise { - let q1 = db + const q1 = db .select({ id: entries.id, title: entries.title, @@ -100,12 +100,12 @@ export async function searchEntries(params: SearchParams): Promise`count(*)` }) @@ -373,9 +373,10 @@ export async function getEntryById(id: number): Promise { const downloadsBySeq = new Map(); for (const row of downloadRows) { - const arr = downloadsBySeq.get(row.releaseSeq) ?? []; + const key = Number(row.releaseSeq); + const arr = downloadsBySeq.get(key) ?? []; arr.push(row); - downloadsBySeq.set(row.releaseSeq, arr); + downloadsBySeq.set(key, arr); } // Build a map of downloads grouped by release_seq @@ -386,22 +387,22 @@ export async function getEntryById(id: number): Promise { type: { id: null, name: null }, language: { id: null, name: null }, machinetype: { id: null, name: null }, - year: (r.year) ?? null, + year: r.year != null ? Number(r.year) : null, comments: null, downloads: (downloadsBySeq.get(Number(r.releaseSeq)) ?? []).map((d) => ({ - id: d.id, + id: Number(d.id), link: d.link, - size: d.size ?? null, + size: d.size != null ? Number(d.size) : null, md5: d.md5 ?? null, comments: d.comments ?? null, isDemo: !!d.isDemo, - type: { id: d.filetypeId, name: d.filetypeName }, + type: { id: Number(d.filetypeId), name: d.filetypeName }, language: { id: (d.dlLangId) ?? null, name: (d.dlLangName) ?? null }, - machinetype: { id: (d.dlMachineId) ?? null, name: (d.dlMachineName) ?? null }, + machinetype: { id: d.dlMachineId != null ? Number(d.dlMachineId) : null, name: (d.dlMachineName) ?? null }, scheme: { id: (d.schemeId) ?? null, name: (d.schemeName) ?? null }, source: { id: (d.sourceId) ?? null, name: (d.sourceName) ?? null }, case: { id: (d.caseId) ?? null, name: (d.caseName) ?? null }, - year: (d.year) ?? null, + year: d.year != null ? Number(d.year) : null, })), })); @@ -437,19 +438,19 @@ export async function getEntryById(id: number): Promise { : [], releases: releasesData, downloadsFlat: downloadFlatRows.map((d) => ({ - id: d.id, + id: Number(d.id), link: d.link, - size: d.size ?? null, + size: d.size != null ? Number(d.size) : null, md5: d.md5 ?? null, comments: d.comments ?? null, isDemo: !!d.isDemo, - type: { id: d.filetypeId, name: d.filetypeName }, + type: { id: Number(d.filetypeId), name: d.filetypeName }, language: { id: (d.dlLangId) ?? null, name: (d.dlLangName) ?? null }, - machinetype: { id: (d.dlMachineId) ?? null, name: (d.dlMachineName) ?? null }, + machinetype: { id: d.dlMachineId != null ? Number(d.dlMachineId) : null, name: (d.dlMachineName) ?? null }, scheme: { id: (d.schemeId) ?? null, name: (d.schemeName) ?? null }, source: { id: (d.sourceId) ?? null, name: (d.sourceName) ?? null }, case: { id: (d.caseId) ?? null, name: (d.caseName) ?? null }, - year: (d.year) ?? null, + year: d.year != null ? Number(d.year) : null, releaseSeq: Number(d.releaseSeq), })), }; @@ -457,7 +458,7 @@ export async function getEntryById(id: number): Promise { // ----- Labels ----- -export interface LabelDetail extends LabelSummary {} +export type LabelDetail = LabelSummary; export interface LabelSearchParams { q?: string; @@ -482,20 +483,18 @@ export async function searchLabels(params: LabelSearchParams): Promise`count(distinct ${sql.identifier("label_id")})` }) - .from(sql`search_by_names`) - .where(like(sql.identifier("label_name"), pattern)); + .select({ total: sql`count(*)` }) + .from(labels) + .where(sql`${labels.id} in (select distinct label_id from search_by_names where label_name like ${pattern})`); const total = Number(countRows[0]?.total ?? 0); const items = await db .select({ id: labels.id, name: labels.name, labeltypeId: labels.labeltypeId }) - .from(sql`search_by_names`) - .innerJoin(labels, eq(labels.id, sql.identifier("label_id"))) - .where(like(sql.identifier("label_name"), pattern)) - .groupBy(labels.id) + .from(labels) + .where(sql`${labels.id} in (select distinct label_id from search_by_names where label_name like ${pattern})`) .orderBy(labels.name) .limit(pageSize) .offset(offset);