From fb29e0179ed0c6dca4f97065b775ff896ef7f370 Mon Sep 17 00:00:00 2001 From: Antti Kettunen Date: Sun, 3 May 2026 13:50:40 +0300 Subject: [PATCH] Tighten issue route typing - Remove the remaining Oxlint warnings in the issues route UI - Make promise handling explicit in navigation and refresh paths - Keep the issue snapshot shape aligned with the fields the UI reads --- webui/src/routes/issues/-issues.types.ts | 37 ++++++++++++++----- .../routes/issues/-ui/issue-detail-modal.tsx | 4 +- .../routes/issues/-ui/issue-domain-host.tsx | 5 ++- webui/src/routes/issues/-ui/issues-page.tsx | 10 ++--- 4 files changed, 38 insertions(+), 18 deletions(-) diff --git a/webui/src/routes/issues/-issues.types.ts b/webui/src/routes/issues/-issues.types.ts index 4189f029..8f587bfa 100644 --- a/webui/src/routes/issues/-issues.types.ts +++ b/webui/src/routes/issues/-issues.types.ts @@ -2,10 +2,34 @@ export type IssueStatus = 'open' | 'in_progress' | 'resolved' | 'dismissed'; export type IssueEntityType = 'track' | 'album' | 'artist'; export type IssuePriority = 'low' | 'normal' | 'high'; +export interface IssueTrackRow extends Record { + bitrate?: string | number; + disc_number?: string | number; + duration?: string | number; + format?: string; + id?: string | number; + title?: string; + track_number?: string | number; +} + export interface IssueSnapshot { [key: string]: unknown; - title?: string; + album_track_count?: string | number; + bitrate?: string | number; + bpm?: string | number; + disc_number?: string | number; + duration?: string | number; + file_path?: string; + format?: string; + genres?: string[]; + label?: string; name?: string; + record_type?: string; + title?: string; + track_count?: string | number; + tracks?: IssueTrackRow[]; + track_number?: string | number; + year?: string | number; artist_name?: string; album_title?: string; thumb_url?: string; @@ -16,14 +40,7 @@ export interface IssueSnapshot { spotify_track_id?: string; artist_id?: string | number; album_id?: string | number; - track_number?: string | number; - duration?: string | number; - format?: string; - bitrate?: string | number; - bpm?: string | number; quality?: string; - file_path?: string; - tracks?: Array>; artist_musicbrainz_id?: string; musicbrainz_release_id?: string; musicbrainz_recording_id?: string; @@ -44,8 +61,8 @@ export interface IssueRecord { category: string; title: string; description?: string | null; - status: IssueStatus | string; - priority: 'low' | 'normal' | 'high' | string; + status: string; + priority: string; snapshot_data: IssueSnapshot | string | null; created_at?: string; updated_at?: string; diff --git a/webui/src/routes/issues/-ui/issue-detail-modal.tsx b/webui/src/routes/issues/-ui/issue-detail-modal.tsx index 8cdf0452..6002d43a 100644 --- a/webui/src/routes/issues/-ui/issue-detail-modal.tsx +++ b/webui/src/routes/issues/-ui/issue-detail-modal.tsx @@ -9,7 +9,7 @@ import { launchAlbumWishlistWorkflow, } from '@/platform/workflows/album-workflows'; -import type { IssueRecord } from '../-issues.types'; +import type { IssueRecord, IssueTrackRow } from '../-issues.types'; import { deleteIssue, issueDetailQueryOptions, updateIssue } from '../-issues.api'; import { @@ -439,7 +439,7 @@ export function IssueDetailModal({ ); } -function renderTrackListing(trackRows: Array>) { +function renderTrackListing(trackRows: IssueTrackRow[]) { const nodes: ReactNode[] = []; let lastDisc: number | null = null; const hasMultiDisc = trackRows.some((track) => Number(track.disc_number || 1) > 1); diff --git a/webui/src/routes/issues/-ui/issue-domain-host.tsx b/webui/src/routes/issues/-ui/issue-domain-host.tsx index 49f29f04..6c150b8f 100644 --- a/webui/src/routes/issues/-ui/issue-domain-host.tsx +++ b/webui/src/routes/issues/-ui/issue-domain-host.tsx @@ -369,7 +369,10 @@ function getReportIssueFormError(errors: Array): string { if (!error) return ''; if (typeof error === 'string') return error; if (error instanceof Error) return error.message; - return String(error); + if (typeof error === 'number' || typeof error === 'boolean' || typeof error === 'bigint') { + return String(error); + } + return 'Unable to submit this issue'; } function notify(message: string, type: 'success' | 'error' | 'warning' | 'info' = 'info') { diff --git a/webui/src/routes/issues/-ui/issues-page.tsx b/webui/src/routes/issues/-ui/issues-page.tsx index 8c41be88..8395c366 100644 --- a/webui/src/routes/issues/-ui/issues-page.tsx +++ b/webui/src/routes/issues/-ui/issues-page.tsx @@ -33,7 +33,7 @@ export function IssuesPage() { const params = Route.useSearch(); const clearIssueSelection = () => { - navigate({ + void navigate({ to: Route.fullPath, search: (prev) => normalizeIssuesSearch({ ...prev, issueId: undefined }), replace: true, @@ -63,7 +63,7 @@ function IssueBoard() { useEffect(() => { const handleRefresh = () => { - queryClient.invalidateQueries({ queryKey: ['issues'] }); + void queryClient.invalidateQueries({ queryKey: ['issues'] }); }; window.addEventListener(REFRESH_EVENT, handleRefresh); @@ -80,14 +80,14 @@ function IssueBoard() { }); const openIssue = (issueId: number) => { - navigate({ + void navigate({ to: Route.fullPath, search: (prev) => normalizeIssuesSearch({ ...prev, issueId }), }); }; const onCategoryChange = (category: string) => { - navigate({ + void navigate({ to: Route.fullPath, search: (prev) => normalizeIssuesSearch({ @@ -99,7 +99,7 @@ function IssueBoard() { }; const onStatusChange = (status: IssueStatus | 'all') => { - navigate({ + void navigate({ to: Route.fullPath, search: (prev) => normalizeIssuesSearch({