From 168f09df60d270d23699e5017ff14fb30114bd09 Mon Sep 17 00:00:00 2001 From: Harshith Mohan <26010946+harshithmohan@users.noreply.github.com> Date: Thu, 6 Aug 2026 21:22:32 +0530 Subject: [PATCH 01/12] refactor: convert LinkState enum to LinkStateType string union, add linked state --- .../LinkFilesWithProvider/Menu.tsx | 7 +-- .../LinkFilesWithProvider/ProviderName.tsx | 20 ++++--- .../LinkFilesWithProvider/TitleOptions.tsx | 10 ++-- .../UnrecognizedVideo.tsx | 30 +++++----- .../types/utilities/unrecognized-utility.ts | 11 +--- .../LinkFilesWithProvidersTab.tsx | 55 +++++++++---------- 6 files changed, 62 insertions(+), 71 deletions(-) diff --git a/src/components/Utilities/Unrecognized/LinkFilesWithProvider/Menu.tsx b/src/components/Utilities/Unrecognized/LinkFilesWithProvider/Menu.tsx index e6bfc30f1..76d9aa177 100644 --- a/src/components/Utilities/Unrecognized/LinkFilesWithProvider/Menu.tsx +++ b/src/components/Utilities/Unrecognized/LinkFilesWithProvider/Menu.tsx @@ -1,7 +1,6 @@ import { mdiMagnify, mdiPencil, mdiSelectAll, mdiSelection, mdiSelectionRemove, mdiTrayPlus } from '@mdi/js'; import MenuButton from '@/components/Utilities/Unrecognized/MenuButton'; -import { LinkState } from '@/core/types/utilities/unrecognized-utility'; import type { ManualLinkType } from '@/core/types/utilities/unrecognized-utility'; @@ -32,7 +31,7 @@ const Menu = (props: Props) => { name="Search for Release Info" keybinding="S" disabled={!selectedLinks.length - || !selectedLinks.some(link => [LinkState.Ready, LinkState.Init].includes(link.state))} + || !selectedLinks.some(link => ['ready', 'init', 'linked'].includes(link.state))} /> { /> {(selectedLinks.length > 0 - && !selectedLinks.some(link => [LinkState.Searching, LinkState.Submitting].includes(link.state))) && ( + && !selectedLinks.some(link => ['searching', 'submitting'].includes(link.state))) && ( { /> )} - {selectedLinks.some(link => link.state === LinkState.Ready) && ( + {selectedLinks.some(link => link.state === 'ready') && ( { const name = link.release.ProviderName; const editedByUser = name.startsWith('User+') || name.endsWith('+User'); - const providerName = name !== 'User' && ![LinkState.Searching].includes(link.state) + const providerName = name !== 'User' && link.state !== 'searching' ? name .replace(/^User\+/, '') .replace(/\+User$/, '') diff --git a/src/components/Utilities/Unrecognized/LinkFilesWithProvider/TitleOptions.tsx b/src/components/Utilities/Unrecognized/LinkFilesWithProvider/TitleOptions.tsx index 4db0c70eb..a8b305ea7 100644 --- a/src/components/Utilities/Unrecognized/LinkFilesWithProvider/TitleOptions.tsx +++ b/src/components/Utilities/Unrecognized/LinkFilesWithProvider/TitleOptions.tsx @@ -1,13 +1,11 @@ import { countBy } from 'lodash'; -import { LinkState } from '@/core/types/utilities/unrecognized-utility'; - -import type { ManualLinkType } from '@/core/types/utilities/unrecognized-utility'; +import type { LinkStateType, ManualLinkType } from '@/core/types/utilities/unrecognized-utility'; const TitleOptions = ({ links, selectedCount }: { links: ManualLinkType[], selectedCount: number }) => { - const countByStatus = countBy(links, link => link.state) as Record; - const submittedCount = countByStatus[LinkState.Submitted] ?? 0; - const pendingCount = (countByStatus[LinkState.Submitting] ?? 0) + (countByStatus[LinkState.Ready] ?? 0); + const countByStatus = countBy(links, link => link.state) as Record; + const submittedCount = countByStatus.submitted ?? 0; + const pendingCount = (countByStatus.submitting ?? 0) + (countByStatus.ready ?? 0); return (
diff --git a/src/components/Utilities/Unrecognized/LinkFilesWithProvider/UnrecognizedVideo.tsx b/src/components/Utilities/Unrecognized/LinkFilesWithProvider/UnrecognizedVideo.tsx index 37727040d..f4d2e1aff 100644 --- a/src/components/Utilities/Unrecognized/LinkFilesWithProvider/UnrecognizedVideo.tsx +++ b/src/components/Utilities/Unrecognized/LinkFilesWithProvider/UnrecognizedVideo.tsx @@ -1,8 +1,6 @@ import type { KeyboardEvent, MouseEvent } from 'react'; import cx from 'classnames'; -import { LinkState } from '@/core/types/utilities/unrecognized-utility'; - import CrossReference from './CrossReference'; import ProviderName from './ProviderName'; import VideoMetadata from './VideoMetadata'; @@ -16,29 +14,31 @@ type Props = { }; const linkStateClassMap = { - [LinkState.PreInit]: 'opacity-65 cursor-wait', - [LinkState.Init]: '', - [LinkState.Searching]: 'animate-pulse cursor-wait', - [LinkState.Ready]: 'cursor-pointer', - [LinkState.Submitting]: 'cursor-progress', - [LinkState.Submitted]: '', + 'pre-init': 'opacity-65 cursor-wait', + init: '', + searching: 'animate-pulse cursor-wait', + ready: 'cursor-pointer', + submitting: 'cursor-progress', + submitted: '', + linked: 'animate-pulse cursor-wait', } as const; const selectionDisabledStates = [ - LinkState.PreInit, - LinkState.Searching, - LinkState.Submitting, + 'pre-init', + 'searching', + 'submitting', + 'linked', ]; const UnrecognizedVideo = (props: Props) => { const { link, selected, toggleSelect } = props; let border = 'border-panel-border'; - if (link.state === LinkState.Submitted) { + if (link.state === 'submitted') { border = 'border-panel-text-important'; - } else if ([LinkState.Searching, LinkState.Submitting].includes(link.state)) { + } else if (['searching', 'submitting'].includes(link.state)) { border = 'border-panel-text-primary'; - } else if (link.state === LinkState.Ready) { + } else if (link.state === 'ready') { border = 'border-panel-text-warning'; } else if (selected) { border = 'border-panel-text-primary'; @@ -69,7 +69,7 @@ const UnrecognizedVideo = (props: Props) => { border, selected && 'bg-panel-background-selected-row!', !selected && linkStateClassMap[link.state], - [LinkState.Ready, LinkState.Submitting, LinkState.Submitted].includes(link.state) && 'bg-panel-background-alt', + ['ready', 'submitting', 'submitted'].includes(link.state) && 'bg-panel-background-alt', )} onMouseDown={handleMouseDown} onClick={handleSelect} diff --git a/src/core/types/utilities/unrecognized-utility.ts b/src/core/types/utilities/unrecognized-utility.ts index c3435ad2a..06899e20c 100644 --- a/src/core/types/utilities/unrecognized-utility.ts +++ b/src/core/types/utilities/unrecognized-utility.ts @@ -1,13 +1,6 @@ import type { FileType, ReleaseInfoType } from '@/core/types/api/file'; -export enum LinkState { - PreInit = 'pre-init', - Init = 'init', - Searching = 'searching', - Ready = 'ready', - Submitting = 'submitting', - Submitted = 'submitted', -} +export type LinkStateType = 'pre-init' | 'init' | 'searching' | 'ready' | 'submitting' | 'submitted' | 'linked'; export type ManualLinkProviderType = { id: string; @@ -20,5 +13,5 @@ export type ManualLinkType = { providers: ManualLinkProviderType[]; release: ReleaseInfoType; metadata?: string; - state: LinkState; + state: LinkStateType; }; diff --git a/src/pages/utilities/UnrecognizedUtilityTabs/LinkFilesWithProvidersTab.tsx b/src/pages/utilities/UnrecognizedUtilityTabs/LinkFilesWithProvidersTab.tsx index a3f10e89c..9730c672f 100644 --- a/src/pages/utilities/UnrecognizedUtilityTabs/LinkFilesWithProvidersTab.tsx +++ b/src/pages/utilities/UnrecognizedUtilityTabs/LinkFilesWithProvidersTab.tsx @@ -26,7 +26,6 @@ import { import { useReleaseInfoProvidersQuery } from '@/core/react-query/release-info/queries'; import { useSettingsQuery } from '@/core/react-query/settings/queries'; import { ReleaseSource } from '@/core/types/api/file'; -import { LinkState } from '@/core/types/utilities/unrecognized-utility'; import { handleShiftSelect } from '@/core/util'; import useNavigateVoid from '@/hooks/useNavigateVoid'; import useRowSelection from '@/hooks/useRowSelection'; @@ -108,7 +107,7 @@ const LinkFilesWithProvidersTab = () => { id: linkId, file, providers: settings.WebUI_Settings.releaseInfoProviders ?? [], - state: LinkState.PreInit, + state: 'pre-init', release, }; }); @@ -155,10 +154,10 @@ const LinkFilesWithProvidersTab = () => { }; const canSubmit = initialized - && links.some(link => link.state === LinkState.Ready); + && links.some(link => link.state === 'ready'); const allSubmitted = initialized - && links.every(link => link.state === LinkState.Submitted); + && links.every(link => link.state === 'submitted'); const navigateBack = () => { setRowSelection({}); @@ -166,11 +165,11 @@ const LinkFilesWithProvidersTab = () => { }; const handleCancel = () => { - if (links.some(link => [LinkState.Searching, LinkState.Submitting].includes(link.state))) { + if (links.some(link => ['searching', 'submitting'].includes(link.state))) { setLinks((draft) => { forEach(draft, (draft2) => { - if (draft2.state === LinkState.Submitting) draft2.state = LinkState.Ready; - else if (draft2.state === LinkState.Searching) draft2.state = LinkState.Init; + if (draft2.state === 'submitting') draft2.state = 'ready'; + else if (draft2.state === 'searching') draft2.state = 'init'; }); }); return; @@ -195,7 +194,7 @@ const LinkFilesWithProvidersTab = () => { if (!offlineImporterProviderId) { setLinks((draft) => { - draft[link.id].state = hasProvidersEnabled ? LinkState.Searching : LinkState.Init; + draft[link.id].state = hasProvidersEnabled ? 'searching' : 'init'; }); return; } @@ -208,12 +207,12 @@ const LinkFilesWithProvidersTab = () => { if (!data) return; setLinks((draft) => { draft[link.id].release = data; - draft[link.id].state = hasProvidersEnabled ? LinkState.Searching : LinkState.Init; + draft[link.id].state = hasProvidersEnabled ? 'searching' : 'init'; }); }) .catch(() => { setLinks((draft) => { - draft[link.id].state = hasProvidersEnabled ? LinkState.Searching : LinkState.Init; + draft[link.id].state = hasProvidersEnabled ? 'searching' : 'init'; }); }) .finally(() => currentlyInitializingLinks.delete(link.id)); @@ -232,7 +231,7 @@ const LinkFilesWithProvidersTab = () => { .then((data) => { if (!data) { setLinks((draft) => { - draft[link.id].state = LinkState.Init; + draft[link.id].state = 'init'; }); return; } @@ -260,12 +259,12 @@ const LinkFilesWithProvidersTab = () => { setLinks((draft) => { draft[link.id].release = finalData; - draft[link.id].state = LinkState.Ready; + draft[link.id].state = 'ready'; }); }) .catch(() => { setLinks((draft) => { - draft[link.id].state = LinkState.Init; + draft[link.id].state = 'init'; }); }) .finally(() => currentlySearchingLinks.delete(link.id)); @@ -278,12 +277,12 @@ const LinkFilesWithProvidersTab = () => { submitReleaseInfo({ fileId: link.file.ID, release: link.release }) .then(() => { setLinks((draft) => { - draft[link.id].state = LinkState.Submitted; + draft[link.id].state = 'submitted'; }); }) .catch(() => { setLinks((draft) => { - draft[link.id].state = LinkState.Ready; + draft[link.id].state = 'ready'; }); }) .finally(() => currentlySubmittingLinks.delete(link.id)); @@ -293,11 +292,11 @@ const LinkFilesWithProvidersTab = () => { if (!initialized || !links.length) return; links.forEach((link) => { - if (link.state === LinkState.PreInit) { + if (link.state === 'pre-init') { processPreInit(link); - } else if (link.state === LinkState.Searching) { + } else if (link.state === 'searching') { processSearch(link); - } else if (link.state === LinkState.Submitting) { + } else if (link.state === 'submitting') { processSubmit(link); } }); @@ -313,8 +312,8 @@ const LinkFilesWithProvidersTab = () => { setLinks((draft) => { forEach(draft, (draft2) => { - if (draft2.state === LinkState.Ready) { - draft2.state = LinkState.Submitting; + if (draft2.state === 'ready') { + draft2.state = 'submitting'; } }); }); @@ -326,7 +325,7 @@ const LinkFilesWithProvidersTab = () => { } else { if ( links.some( - link => [LinkState.PreInit, LinkState.Searching, LinkState.Submitting].includes(link.state), + link => ['pre-init', 'searching', 'submitting'].includes(link.state), ) ) { return; @@ -340,7 +339,7 @@ const LinkFilesWithProvidersTab = () => { const removeLinks = () => { if ( !selectedRows.length - || selectedRows.some(link => [LinkState.Searching, LinkState.Submitting].includes(link.state)) + || selectedRows.some(link => ['searching', 'submitting'].includes(link.state)) ) return; setLinks((draft) => { @@ -355,9 +354,9 @@ const LinkFilesWithProvidersTab = () => { if (!providers.some(provider => provider.enabled)) return; setLinks((draft) => { selectedRows.forEach((link) => { - if ([LinkState.Ready, LinkState.Init].includes(link.state)) { + if (['ready', 'init'].includes(link.state)) { draft[link.id].providers = providers; - draft[link.id].state = LinkState.Searching; + draft[link.id].state = 'searching'; } }); }); @@ -365,12 +364,12 @@ const LinkFilesWithProvidersTab = () => { }; const submitSelectedLinks = () => { - if (!selectedRows.length || !selectedRows.some(link => link.state === LinkState.Ready)) return; + if (!selectedRows.length || !selectedRows.some(link => link.state === 'ready')) return; setLinks((draft) => { selectedRows.forEach((link) => { - if (link.state === LinkState.Ready) { - draft[link.id].state = LinkState.Submitting; + if (link.state === 'ready') { + draft[link.id].state = 'submitting'; } }); }); @@ -378,7 +377,7 @@ const LinkFilesWithProvidersTab = () => { }; const openAutoSearch = () => { - if (!selectedRows.length || !selectedRows.some(link => [LinkState.Ready, LinkState.Init].includes(link.state))) { + if (!selectedRows.length || !selectedRows.some(link => ['ready', 'init'].includes(link.state))) { return; } setShowAutoSearchModal(true); From 69346cdf6d0598b971650d30388071c37f2a3bed Mon Sep 17 00:00:00 2001 From: Harshith Mohan <26010946+harshithmohan@users.noreply.github.com> Date: Thu, 6 Aug 2026 21:32:03 +0530 Subject: [PATCH 02/12] refactor: move link-with-providers to top-level utility route, add Edit Link button to FileSearch --- src/core/router/index.tsx | 3 ++- src/pages/dashboard/panels/UnrecognizedFiles.tsx | 3 +-- src/pages/utilities/FileSearch.tsx | 6 ++++++ .../UnrecognizedUtilityTabs/LinkFilesWithProvidersTab.tsx | 3 +-- .../utilities/UnrecognizedUtilityTabs/UnrecognizedTab.tsx | 2 +- 5 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/core/router/index.tsx b/src/core/router/index.tsx index fd5922e0e..933fab908 100644 --- a/src/core/router/index.tsx +++ b/src/core/router/index.tsx @@ -93,7 +93,7 @@ const router = sentryCreateBrowserRouter( } /> } /> } /> - } /> + } /> } /> } /> @@ -105,6 +105,7 @@ const router = sentryCreateBrowserRouter( } /> } /> } /> + } /> } /> diff --git a/src/pages/dashboard/panels/UnrecognizedFiles.tsx b/src/pages/dashboard/panels/UnrecognizedFiles.tsx index 7ac672fb6..8df1c919d 100644 --- a/src/pages/dashboard/panels/UnrecognizedFiles.tsx +++ b/src/pages/dashboard/panels/UnrecognizedFiles.tsx @@ -54,8 +54,7 @@ const FileItem = ({ file }: { file: FileType }) => {