From 21ca65a0151944a3a46303c7c4d3aa16220a57cd Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Mon, 29 Dec 2025 16:54:05 -0800 Subject: [PATCH] Use react-query for Quality Profiles --- .../ImportSeries/Import/ImportSeries.tsx | 7 +- frontend/src/App/State/SettingsAppState.ts | 12 +- .../Builder/QualityFilterBuilderRowValue.tsx | 18 +-- .../QualityProfileFilterBuilderRowValue.tsx | 15 +- .../Form/Select/QualityProfileSelectInput.tsx | 89 ++++++------ frontend/src/Components/Page/ErrorPage.tsx | 3 +- frontend/src/Helpers/Hooks/useAppPage.ts | 21 ++- .../Quality/SelectQualityModalContent.tsx | 48 ++----- .../Overview/SeriesIndexOverviewInfo.tsx | 4 +- .../Index/Posters/SeriesIndexPosterInfo.tsx | 4 +- .../src/Series/Index/useSeriesIndexItem.ts | 7 +- .../src/Series/useSeriesQualityProfile.ts | 8 ++ .../useRemotePathMappings.ts | 2 +- .../Manage/ManageImportListsModalRow.tsx | 7 +- .../Quality/EditQualityProfileModal.tsx | 3 + .../EditQualityProfileModalContent.tsx | 134 ++++++------------ .../Profiles/Quality/QualityProfile.tsx | 14 +- .../Quality/QualityProfileItemDragSource.tsx | 2 +- .../Quality/QualityProfileItemGroup.tsx | 2 +- .../Profiles/Quality/QualityProfileItems.tsx | 2 +- .../Profiles/Quality/QualityProfileName.tsx | 7 +- .../Profiles/Quality/QualityProfiles.tsx | 54 +++---- .../Profiles/Quality/useQualityProfiles.ts | 130 +++++++++++++++++ .../Profiles/Release/useReleaseProfiles.ts | 2 +- frontend/src/Settings/useProviderSettings.ts | 32 ++--- frontend/src/Store/Actions/settingsActions.js | 11 +- .../Selectors/createQualityProfileSelector.ts | 24 ---- .../createSeriesQualityProfileSelector.ts | 21 --- .../src/Utilities/Quality/getQualities.ts | 2 +- frontend/src/typings/QualityProfile.ts | 36 ----- 30 files changed, 318 insertions(+), 403 deletions(-) create mode 100644 frontend/src/Series/useSeriesQualityProfile.ts create mode 100644 frontend/src/Settings/Profiles/Quality/useQualityProfiles.ts delete mode 100644 frontend/src/Store/Selectors/createQualityProfileSelector.ts delete mode 100644 frontend/src/Store/Selectors/createSeriesQualityProfileSelector.ts delete mode 100644 frontend/src/typings/QualityProfile.ts diff --git a/frontend/src/AddSeries/ImportSeries/Import/ImportSeries.tsx b/frontend/src/AddSeries/ImportSeries/Import/ImportSeries.tsx index 922f066f8..84d0c5170 100644 --- a/frontend/src/AddSeries/ImportSeries/Import/ImportSeries.tsx +++ b/frontend/src/AddSeries/ImportSeries/Import/ImportSeries.tsx @@ -1,18 +1,17 @@ import React, { useEffect, useMemo, useRef } from 'react'; -import { useSelector } from 'react-redux'; import { useParams } from 'react-router'; import { setAddSeriesOption, useAddSeriesOption, } from 'AddSeries/addSeriesOptionsStore'; import { SelectProvider } from 'App/Select/SelectContext'; -import AppState from 'App/State/AppState'; import Alert from 'Components/Alert'; import LoadingIndicator from 'Components/Loading/LoadingIndicator'; import PageContent from 'Components/Page/PageContent'; import PageContentBody from 'Components/Page/PageContentBody'; import { kinds } from 'Helpers/Props'; import useRootFolders, { useRootFolder } from 'RootFolder/useRootFolders'; +import { useQualityProfilesData } from 'Settings/Profiles/Quality/useQualityProfiles'; import translate from 'Utilities/String/translate'; import ImportSeriesFooter from './ImportSeriesFooter'; import { clearImportSeries } from './importSeriesStore'; @@ -48,9 +47,7 @@ function ImportSeries() { }; }, [rootFolders, rootFolderId]); - const qualityProfiles = useSelector( - (state: AppState) => state.settings.qualityProfiles.items - ); + const qualityProfiles = useQualityProfilesData(); const defaultQualityProfileId = useAddSeriesOption('qualityProfileId'); diff --git a/frontend/src/App/State/SettingsAppState.ts b/frontend/src/App/State/SettingsAppState.ts index ecf68edac..9fa3e09ae 100644 --- a/frontend/src/App/State/SettingsAppState.ts +++ b/frontend/src/App/State/SettingsAppState.ts @@ -1,6 +1,5 @@ import AppSectionState, { AppSectionDeleteState, - AppSectionItemSchemaState, AppSectionItemState, AppSectionListState, AppSectionSaveState, @@ -8,6 +7,7 @@ import AppSectionState, { PagedAppSectionState, } from 'App/State/AppSectionState'; import Language from 'Language/Language'; +import { QualityProfileModel } from 'Settings/Profiles/Quality/useQualityProfiles'; import AutoTagging, { AutoTaggingSpecification } from 'typings/AutoTagging'; import CustomFormat from 'typings/CustomFormat'; import CustomFormatSpecification from 'typings/CustomFormatSpecification'; @@ -20,7 +20,6 @@ import Indexer from 'typings/Indexer'; import IndexerFlag from 'typings/IndexerFlag'; import Notification from 'typings/Notification'; import QualityDefinition from 'typings/QualityDefinition'; -import QualityProfile from 'typings/QualityProfile'; import DownloadClientOptions from 'typings/Settings/DownloadClientOptions'; import General from 'typings/Settings/General'; import IndexerOptions from 'typings/Settings/IndexerOptions'; @@ -105,16 +104,10 @@ export interface QualityDefinitionsAppState extends AppSectionState, AppSectionSaveState { pendingChanges: { - [key: number]: Partial; + [key: number]: Partial; }; } -export interface QualityProfilesAppState - extends AppSectionState, - AppSectionItemSchemaState, - AppSectionDeleteState, - AppSectionSaveState {} - export interface CustomFormatAppState extends AppSectionState, AppSectionDeleteState, @@ -163,7 +156,6 @@ interface SettingsAppState { namingExamples: NamingExamplesAppState; notifications: NotificationAppState; qualityDefinitions: QualityDefinitionsAppState; - qualityProfiles: QualityProfilesAppState; } export default SettingsAppState; diff --git a/frontend/src/Components/Filter/Builder/QualityFilterBuilderRowValue.tsx b/frontend/src/Components/Filter/Builder/QualityFilterBuilderRowValue.tsx index c2546e536..b2b42beec 100644 --- a/frontend/src/Components/Filter/Builder/QualityFilterBuilderRowValue.tsx +++ b/frontend/src/Components/Filter/Builder/QualityFilterBuilderRowValue.tsx @@ -1,7 +1,5 @@ -import React, { useEffect, useMemo } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; -import AppState from 'App/State/AppState'; -import { fetchQualityProfileSchema } from 'Store/Actions/settingsActions'; +import React, { useMemo } from 'react'; +import { useQualityProfileSchema } from 'Settings/Profiles/Quality/useQualityProfiles'; import getQualities from 'Utilities/Quality/getQualities'; import FilterBuilderRowValue, { FilterBuilderRowValueProps, @@ -15,22 +13,12 @@ type QualityFilterBuilderRowValueProps = Omit< function QualityFilterBuilderRowValue( props: QualityFilterBuilderRowValueProps ) { - const dispatch = useDispatch(); - - const { isSchemaPopulated, schema } = useSelector( - (state: AppState) => state.settings.qualityProfiles - ); + const { schema } = useQualityProfileSchema(true); const tagList = useMemo(() => { return getQualities(schema.items); }, [schema]); - useEffect(() => { - if (!isSchemaPopulated) { - dispatch(fetchQualityProfileSchema()); - } - }, [isSchemaPopulated, dispatch]); - return ; } diff --git a/frontend/src/Components/Filter/Builder/QualityProfileFilterBuilderRowValue.tsx b/frontend/src/Components/Filter/Builder/QualityProfileFilterBuilderRowValue.tsx index 20a076eb2..d426d95da 100644 --- a/frontend/src/Components/Filter/Builder/QualityProfileFilterBuilderRowValue.tsx +++ b/frontend/src/Components/Filter/Builder/QualityProfileFilterBuilderRowValue.tsx @@ -1,21 +1,10 @@ import React from 'react'; -import { useSelector } from 'react-redux'; -import { createSelector } from 'reselect'; -import AppState from 'App/State/AppState'; +import { useQualityProfilesData } from 'Settings/Profiles/Quality/useQualityProfiles'; import sortByProp from 'Utilities/Array/sortByProp'; import FilterBuilderRowValue, { FilterBuilderRowValueProps, } from './FilterBuilderRowValue'; -function createQualityProfilesSelector() { - return createSelector( - (state: AppState) => state.settings.qualityProfiles.items, - (qualityProfiles) => { - return qualityProfiles; - } - ); -} - type QualityProfileFilterBuilderRowValueProps = Omit< FilterBuilderRowValueProps, 'tagList' @@ -24,7 +13,7 @@ type QualityProfileFilterBuilderRowValueProps = Omit< function QualityProfileFilterBuilderRowValue( props: QualityProfileFilterBuilderRowValueProps ) { - const qualityProfiles = useSelector(createQualityProfilesSelector()); + const qualityProfiles = useQualityProfilesData(); const tagList = qualityProfiles .map(({ id, name }) => ({ id, name })) diff --git a/frontend/src/Components/Form/Select/QualityProfileSelectInput.tsx b/frontend/src/Components/Form/Select/QualityProfileSelectInput.tsx index a1dcc6dbc..e356f4567 100644 --- a/frontend/src/Components/Form/Select/QualityProfileSelectInput.tsx +++ b/frontend/src/Components/Form/Select/QualityProfileSelectInput.tsx @@ -1,10 +1,6 @@ -import React, { useCallback, useEffect } from 'react'; -import { useSelector } from 'react-redux'; -import { createSelector } from 'reselect'; -import { QualityProfilesAppState } from 'App/State/SettingsAppState'; -import createSortedSectionSelector from 'Store/Selectors/createSortedSectionSelector'; +import React, { useCallback, useEffect, useMemo } from 'react'; +import { useQualityProfilesData } from 'Settings/Profiles/Quality/useQualityProfiles'; import { EnhancedSelectInputChanged } from 'typings/inputs'; -import QualityProfile from 'typings/QualityProfile'; import sortByProp from 'Utilities/Array/sortByProp'; import translate from 'Utilities/String/translate'; import EnhancedSelectInput, { @@ -12,49 +8,46 @@ import EnhancedSelectInput, { EnhancedSelectInputValue, } from './EnhancedSelectInput'; -function createQualityProfilesSelector( +const useValues = ( includeNoChange: boolean, includeNoChangeDisabled: boolean, includeMixed: boolean -) { - return createSelector( - createSortedSectionSelector( - 'settings.qualityProfiles', - sortByProp('name') - ), - (qualityProfiles: QualityProfilesAppState) => { - const values: EnhancedSelectInputValue[] = - qualityProfiles.items.map((qualityProfile) => { - return { - key: qualityProfile.id, - value: qualityProfile.name, - }; - }); +) => { + const qualityProfiles = useQualityProfilesData(); - if (includeNoChange) { - values.unshift({ - key: 'noChange', - get value() { - return translate('NoChange'); - }, - isDisabled: includeNoChangeDisabled, - }); - } + return useMemo(() => { + const values: EnhancedSelectInputValue[] = qualityProfiles + .sort(sortByProp('name')) + .map((qualityProfile) => { + return { + key: qualityProfile.id, + value: qualityProfile.name, + }; + }); - if (includeMixed) { - values.unshift({ - key: 'mixed', - get value() { - return `(${translate('Mixed')})`; - }, - isDisabled: true, - }); - } - - return values; + if (includeNoChange) { + values.unshift({ + key: 'noChange', + get value() { + return translate('NoChange'); + }, + isDisabled: includeNoChangeDisabled, + }); } - ); -} + + if (includeMixed) { + values.unshift({ + key: 'mixed', + get value() { + return `(${translate('Mixed')})`; + }, + isDisabled: true, + }); + } + + return values; + }, [qualityProfiles, includeNoChange, includeNoChangeDisabled, includeMixed]); +}; export interface QualityProfileSelectInputProps extends Omit< @@ -79,12 +72,10 @@ function QualityProfileSelectInput({ onChange, ...otherProps }: QualityProfileSelectInputProps) { - const values = useSelector( - createQualityProfilesSelector( - includeNoChange, - includeNoChangeDisabled, - includeMixed - ) + const values = useValues( + includeNoChange, + includeNoChangeDisabled, + includeMixed ); const handleChange = useCallback( diff --git a/frontend/src/Components/Page/ErrorPage.tsx b/frontend/src/Components/Page/ErrorPage.tsx index 9ee82ed13..bbcc585cf 100644 --- a/frontend/src/Components/Page/ErrorPage.tsx +++ b/frontend/src/Components/Page/ErrorPage.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import { Error } from 'App/State/AppSectionState'; import { ApiError } from 'Utilities/Fetch/fetchJson'; import getErrorMessage from 'Utilities/Object/getErrorMessage'; import translate from 'Utilities/String/translate'; @@ -12,7 +11,7 @@ interface ErrorPageProps { seriesError: ApiError | null; customFiltersError: ApiError | null; tagsError: ApiError | null; - qualityProfilesError?: Error; + qualityProfilesError: ApiError | null; uiSettingsError: ApiError | null; systemStatusError: ApiError | null; } diff --git a/frontend/src/Helpers/Hooks/useAppPage.ts b/frontend/src/Helpers/Hooks/useAppPage.ts index 200bb61db..cd554f188 100644 --- a/frontend/src/Helpers/Hooks/useAppPage.ts +++ b/frontend/src/Helpers/Hooks/useAppPage.ts @@ -6,13 +6,13 @@ import { useTranslations } from 'App/useTranslations'; import useCommands from 'Commands/useCommands'; import useCustomFilters from 'Filters/useCustomFilters'; import useSeries from 'Series/useSeries'; +import { useQualityProfiles } from 'Settings/Profiles/Quality/useQualityProfiles'; import { useUiSettings } from 'Settings/UI/useUiSettings'; import { fetchCustomFilters } from 'Store/Actions/customFilterActions'; import { fetchImportLists, fetchIndexerFlags, fetchLanguages, - fetchQualityProfiles, } from 'Store/Actions/settingsActions'; import useSystemStatus from 'System/Status/useSystemStatus'; import useTags from 'Tags/useTags'; @@ -25,6 +25,7 @@ const createErrorsSelector = ({ translationsError, uiSettingsError, seriesError, + qualityProfilesError, }: { customFiltersError: ApiError | null; systemStatusError: ApiError | null; @@ -32,18 +33,13 @@ const createErrorsSelector = ({ translationsError: ApiError | null; uiSettingsError: ApiError | null; seriesError: ApiError | null; + qualityProfilesError: ApiError | null; }) => createSelector( - (state: AppState) => state.settings.qualityProfiles.error, (state: AppState) => state.settings.languages.error, (state: AppState) => state.settings.importLists.error, (state: AppState) => state.settings.indexerFlags.error, - ( - qualityProfilesError, - languagesError, - importListsError, - indexerFlagsError - ) => { + (languagesError, importListsError, indexerFlagsError) => { const hasError = !!( customFiltersError || seriesError || @@ -97,9 +93,11 @@ const useAppPage = () => { const { isFetched: isUiSettingsFetched, error: uiSettingsError } = useUiSettings(); + const { isFetched: isQualityProfilesFetched, error: qualityProfilesError } = + useQualityProfiles(); + const isAppStatePopulated = useSelector( (state: AppState) => - state.settings.qualityProfiles.isPopulated && state.settings.languages.isPopulated && state.settings.importLists.isPopulated && state.settings.indexerFlags.isPopulated @@ -112,7 +110,8 @@ const useAppPage = () => { isSystemStatusFetched && isTagsFetched && isTranslationsFetched && - isUiSettingsFetched; + isUiSettingsFetched && + isQualityProfilesFetched; const { hasError, errors } = useSelector( createErrorsSelector({ @@ -122,6 +121,7 @@ const useAppPage = () => { tagsError, translationsError, uiSettingsError, + qualityProfilesError, }) ); @@ -140,7 +140,6 @@ const useAppPage = () => { useEffect(() => { dispatch(fetchCustomFilters()); - dispatch(fetchQualityProfiles()); dispatch(fetchLanguages()); dispatch(fetchImportLists()); dispatch(fetchIndexerFlags()); diff --git a/frontend/src/InteractiveImport/Quality/SelectQualityModalContent.tsx b/frontend/src/InteractiveImport/Quality/SelectQualityModalContent.tsx index 2e7379c2f..befa264fd 100644 --- a/frontend/src/InteractiveImport/Quality/SelectQualityModalContent.tsx +++ b/frontend/src/InteractiveImport/Quality/SelectQualityModalContent.tsx @@ -1,7 +1,4 @@ -import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; -import { createSelector } from 'reselect'; -import AppState from 'App/State/AppState'; +import React, { useCallback, useMemo, useState } from 'react'; import Alert from 'Components/Alert'; import Form from 'Components/Form/Form'; import FormGroup from 'Components/Form/FormGroup'; @@ -16,30 +13,11 @@ import ModalFooter from 'Components/Modal/ModalFooter'; import ModalHeader from 'Components/Modal/ModalHeader'; import { inputTypes, kinds } from 'Helpers/Props'; import Quality, { QualityModel } from 'Quality/Quality'; -import { fetchQualityProfileSchema } from 'Store/Actions/settingsActions'; +import { useQualityProfileSchema } from 'Settings/Profiles/Quality/useQualityProfiles'; import { InputChanged } from 'typings/inputs'; import getQualities from 'Utilities/Quality/getQualities'; import translate from 'Utilities/String/translate'; -function createQualitySchemaSelector() { - return createSelector( - (state: AppState) => state.settings.qualityProfiles, - (qualityProfiles) => { - const { isSchemaFetching, isSchemaPopulated, schemaError, schema } = - qualityProfiles; - - const items = getQualities(schema.items); - - return { - isFetching: isSchemaFetching, - isPopulated: isSchemaPopulated, - error: schemaError, - items, - }; - } - ); -} - interface SelectQualityModalContentProps { qualityId: number; proper: boolean; @@ -56,18 +34,12 @@ function SelectQualityModalContent(props: SelectQualityModalContentProps) { const [proper, setProper] = useState(props.proper); const [real, setReal] = useState(props.real); - const { isFetching, isPopulated, error, items } = useSelector( - createQualitySchemaSelector() - ); - const dispatch = useDispatch(); + const { schema, isSchemaFetching, isSchemaFetched, schemaError } = + useQualityProfileSchema(true); - useEffect( - () => { - dispatch(fetchQualityProfileSchema()); - }, - // eslint-disable-next-line react-hooks/exhaustive-deps - [] - ); + const items = useMemo(() => { + return getQualities(schema.items); + }, [schema]); const qualityOptions = useMemo(() => { return items.map(({ id, name }): EnhancedSelectInputValue => { @@ -119,13 +91,13 @@ function SelectQualityModalContent(props: SelectQualityModalContentProps) { {modalTitle} - Select Quality - {isFetching ? : null} + {isSchemaFetching ? : null} - {!isFetching && error ? ( + {!isSchemaFetching && schemaError ? ( {translate('QualitiesLoadError')} ) : null} - {isPopulated && !error ? ( + {isSchemaFetched && !schemaError ? (
{translate('Quality')} diff --git a/frontend/src/Series/Index/Overview/SeriesIndexOverviewInfo.tsx b/frontend/src/Series/Index/Overview/SeriesIndexOverviewInfo.tsx index d233c0fde..7a7665859 100644 --- a/frontend/src/Series/Index/Overview/SeriesIndexOverviewInfo.tsx +++ b/frontend/src/Series/Index/Overview/SeriesIndexOverviewInfo.tsx @@ -1,12 +1,12 @@ import React, { useMemo } from 'react'; import { IconName } from 'Components/Icon'; import { icons } from 'Helpers/Props'; +import { QualityProfileModel } from 'Settings/Profiles/Quality/useQualityProfiles'; import { UiSettingsModel, useUiSettingsValues, } from 'Settings/UI/useUiSettings'; import dimensions from 'Styles/Variables/dimensions'; -import QualityProfile from 'typings/QualityProfile'; import formatDateTime from 'Utilities/Date/formatDateTime'; import getRelativeDate from 'Utilities/Date/getRelativeDate'; import formatBytes from 'Utilities/Number/formatBytes'; @@ -39,7 +39,7 @@ interface SeriesIndexOverviewInfoProps { monitored: boolean; nextAiring?: string; network?: string; - qualityProfile?: QualityProfile; + qualityProfile?: QualityProfileModel; previousAiring?: string; added?: string; seasonCount: number; diff --git a/frontend/src/Series/Index/Posters/SeriesIndexPosterInfo.tsx b/frontend/src/Series/Index/Posters/SeriesIndexPosterInfo.tsx index 9af64f5be..e0bbf09f6 100644 --- a/frontend/src/Series/Index/Posters/SeriesIndexPosterInfo.tsx +++ b/frontend/src/Series/Index/Posters/SeriesIndexPosterInfo.tsx @@ -1,7 +1,7 @@ import React from 'react'; import SeriesTagList from 'Components/SeriesTagList'; import Language from 'Language/Language'; -import QualityProfile from 'typings/QualityProfile'; +import { QualityProfileModel } from 'Settings/Profiles/Quality/useQualityProfiles'; import formatDateTime from 'Utilities/Date/formatDateTime'; import getRelativeDate from 'Utilities/Date/getRelativeDate'; import formatBytes from 'Utilities/Number/formatBytes'; @@ -12,7 +12,7 @@ interface SeriesIndexPosterInfoProps { originalLanguage?: Language; network?: string; showQualityProfile: boolean; - qualityProfile?: QualityProfile; + qualityProfile?: QualityProfileModel; previousAiring?: string; added?: string; seasonCount: number; diff --git a/frontend/src/Series/Index/useSeriesIndexItem.ts b/frontend/src/Series/Index/useSeriesIndexItem.ts index 3a3ac1602..ac23edb05 100644 --- a/frontend/src/Series/Index/useSeriesIndexItem.ts +++ b/frontend/src/Series/Index/useSeriesIndexItem.ts @@ -1,16 +1,13 @@ import { maxBy } from 'lodash'; -import { useSelector } from 'react-redux'; import CommandNames from 'Commands/CommandNames'; import { useCommandExecuting } from 'Commands/useCommands'; import { Season } from 'Series/Series'; import { useSingleSeries } from 'Series/useSeries'; -import createSeriesQualityProfileSelector from 'Store/Selectors/createSeriesQualityProfileSelector'; +import useSeriesQualityProfile from 'Series/useSeriesQualityProfile'; export function useSeriesIndexItem(seriesId: number) { const series = useSingleSeries(seriesId); - const qualityProfile = useSelector( - createSeriesQualityProfileSelector(series) - ); + const qualityProfile = useSeriesQualityProfile(series); const isRefreshingSeries = useCommandExecuting(CommandNames.RefreshSeries, { seriesIds: [seriesId], diff --git a/frontend/src/Series/useSeriesQualityProfile.ts b/frontend/src/Series/useSeriesQualityProfile.ts new file mode 100644 index 000000000..ff8f6331a --- /dev/null +++ b/frontend/src/Series/useSeriesQualityProfile.ts @@ -0,0 +1,8 @@ +import { useQualityProfile } from 'Settings/Profiles/Quality/useQualityProfiles'; +import Series from './Series'; + +const useSeriesQualityProfile = (series: Series | undefined) => { + return useQualityProfile(series?.qualityProfileId); +}; + +export default useSeriesQualityProfile; diff --git a/frontend/src/Settings/DownloadClients/RemotePathMappings/useRemotePathMappings.ts b/frontend/src/Settings/DownloadClients/RemotePathMappings/useRemotePathMappings.ts index cc0dc891b..b6d3de3a6 100644 --- a/frontend/src/Settings/DownloadClients/RemotePathMappings/useRemotePathMappings.ts +++ b/frontend/src/Settings/DownloadClients/RemotePathMappings/useRemotePathMappings.ts @@ -23,7 +23,7 @@ const NEW_REMOTE_PATH_MAPPING: RemotePathMappingModel = { export const useRemotePathMapping = () => {}; export const useRemotePathMappings = () => { - return useProviderSettings(PATH); + return useProviderSettings({ path: PATH }); }; export const useManageRemotePathMappings = (id: number) => { diff --git a/frontend/src/Settings/ImportLists/ImportLists/Manage/ManageImportListsModalRow.tsx b/frontend/src/Settings/ImportLists/ImportLists/Manage/ManageImportListsModalRow.tsx index 2421de7ff..56afb362f 100644 --- a/frontend/src/Settings/ImportLists/ImportLists/Manage/ManageImportListsModalRow.tsx +++ b/frontend/src/Settings/ImportLists/ImportLists/Manage/ManageImportListsModalRow.tsx @@ -1,12 +1,11 @@ import React, { useCallback } from 'react'; -import { useSelector } from 'react-redux'; import { useSelect } from 'App/Select/SelectContext'; import SeriesTagList from 'Components/SeriesTagList'; import TableRowCell from 'Components/Table/Cells/TableRowCell'; import TableSelectCell from 'Components/Table/Cells/TableSelectCell'; import Column from 'Components/Table/Column'; import TableRow from 'Components/Table/TableRow'; -import { createQualityProfileSelectorForHook } from 'Store/Selectors/createQualityProfileSelector'; +import { useQualityProfile } from 'Settings/Profiles/Quality/useQualityProfiles'; import ImportList from 'typings/ImportList'; import { SelectStateInputProps } from 'typings/props'; import translate from 'Utilities/String/translate'; @@ -37,9 +36,7 @@ function ManageImportListsModalRow(props: ManageImportListsModalRowProps) { const { toggleSelected, useIsSelected } = useSelect(); const isSelected = useIsSelected(id); - const qualityProfile = useSelector( - createQualityProfileSelectorForHook(qualityProfileId) - ); + const qualityProfile = useQualityProfile(qualityProfileId); const onSelectedChangeWrapper = useCallback( ({ id, value, shiftKey }: SelectStateInputProps) => { diff --git a/frontend/src/Settings/Profiles/Quality/EditQualityProfileModal.tsx b/frontend/src/Settings/Profiles/Quality/EditQualityProfileModal.tsx index 7f5a4ee0b..4735da319 100644 --- a/frontend/src/Settings/Profiles/Quality/EditQualityProfileModal.tsx +++ b/frontend/src/Settings/Profiles/Quality/EditQualityProfileModal.tsx @@ -7,6 +7,7 @@ import EditQualityProfileModalContent from './EditQualityProfileModalContent'; interface EditQualityProfileModalProps { id?: number; + cloneId?: number; isOpen: boolean; onDeleteQualityProfilePress?: () => void; onModalClose: () => void; @@ -14,6 +15,7 @@ interface EditQualityProfileModalProps { function EditQualityProfileModal({ id, + cloneId, isOpen, onDeleteQualityProfilePress, onModalClose, @@ -44,6 +46,7 @@ function EditQualityProfileModal({ > void; onDeleteQualityProfilePress?: () => void; onModalClose: () => void; @@ -59,19 +53,21 @@ interface EditQualityProfileModalContentProps { function EditQualityProfileModalContent({ id, + cloneId, onContentHeightChange, onDeleteQualityProfilePress, onModalClose, }: EditQualityProfileModalContentProps) { - const dispatch = useDispatch(); - - const { error, isFetching, isPopulated, isSaving, saveError, item } = - useSelector( - createProviderSettingsSelectorHook< - QualityProfile, - QualityProfilesAppState - >('qualityProfiles', id) - ); + const { + item, + isSaving, + saveError, + isSchemaFetching, + isSchemaFetched, + schemaError, + updateValue, + saveProvider, + } = useManageQualityProfile(id, cloneId); const isInUse = useQualityProfileInUse(id); @@ -132,15 +128,15 @@ function EditQualityProfileModalContent({ const handleInputChange = useCallback( ({ name, value }: InputChanged) => { - // @ts-expect-error - actions are not typed - dispatch(setQualityProfileValue({ name, value })); + // @ts-expect-error - change is not yet typed + updateValue(name, value); }, - [dispatch] + [updateValue] ); const handleSavePress = useCallback(() => { - dispatch(saveQualityProfile({ id })); - }, [id, dispatch]); + saveProvider(); + }, [saveProvider]); const handleCutoffChange = useCallback( ({ name, value }: InputChanged) => { @@ -153,10 +149,10 @@ function EditQualityProfileModalContent({ 'id' in cutoffItem ? cutoffItem.id : cutoffItem.quality.id; // @ts-expect-error - actions are not typed - dispatch(setQualityProfileValue({ name, value: cutoffId })); + updateValue(name, cutoffId); } }, - [items, dispatch] + [items, updateValue] ); const handleItemAllowedChange = useCallback( @@ -172,15 +168,9 @@ function EditQualityProfileModalContent({ return item; }); - dispatch( - // @ts-expect-error - actions are not typed - setQualityProfileValue({ - name: 'items', - value: newItems, - }) - ); + updateValue('items', newItems); }, - [items, dispatch] + [items, updateValue] ); const handleGroupAllowedChange = useCallback( @@ -196,15 +186,9 @@ function EditQualityProfileModalContent({ return item; }); - dispatch( - // @ts-expect-error - actions are not typed - setQualityProfileValue({ - name: 'items', - value: newItems, - }) - ); + updateValue('items', newItems); }, - [items, dispatch] + [items, updateValue] ); const handleGroupNameChange = useCallback( @@ -220,10 +204,9 @@ function EditQualityProfileModalContent({ return item; }); - // @ts-expect-error - actions are not typed - dispatch(setQualityProfileValue({ name: 'items', value: newItems })); + updateValue('items', newItems); }, - [items, dispatch] + [items, updateValue] ); const handleSizeChange = useCallback( @@ -253,15 +236,9 @@ function EditQualityProfileModalContent({ }; }); - dispatch( - // @ts-expect-error - actions are not typed - setQualityProfileValue({ - name: 'items', - value: newItems, - }) - ); + updateValue('items', newItems); }, - [items, dispatch] + [items, updateValue] ); const handleCreateGroupPress = useCallback( @@ -288,10 +265,9 @@ function EditQualityProfileModalContent({ return item; }); - // @ts-expect-error - actions are not typed - dispatch(setQualityProfileValue({ name: 'items', value: newItems })); + updateValue('items', newItems); }, - [items, dispatch] + [items, updateValue] ); const handleDeleteGroupPress = useCallback( @@ -308,10 +284,9 @@ function EditQualityProfileModalContent({ [] ); - // @ts-expect-error - actions are not typed - dispatch(setQualityProfileValue({ name: 'items', value: newItems })); + updateValue('items', newItems); }, - [items, dispatch] + [items, updateValue] ); const handleDragMove = useCallback((options: DragMoveState) => { @@ -443,13 +418,7 @@ function EditQualityProfileModalContent({ dropGroup.items.splice(dropItemIndex, 0, item); } - dispatch( - // @ts-expect-error - actions are not typed - setQualityProfileValue({ - name: 'items', - value: newItems, - }) - ); + updateValue('items', newItems); } setDndState({ @@ -458,7 +427,7 @@ function EditQualityProfileModalContent({ dropPosition: null, }); }, - [dragQualityIndex, dropQualityIndex, items, dispatch] + [dragQualityIndex, dropQualityIndex, items, updateValue] ); const handleChangeMode = useCallback((newMode: EditQualityProfileMode) => { @@ -478,15 +447,9 @@ function EditQualityProfileModalContent({ return formatItem; }); - dispatch( - // @ts-expect-error - actions are not typed - setQualityProfileValue({ - name: 'formatItems', - value: newFormatItems, - }) - ); + updateValue('formatItems', newFormatItems); }, - [formatItems, dispatch] + [formatItems, updateValue] ); useEffect(() => { @@ -523,12 +486,6 @@ function EditQualityProfileModalContent({ } }, [bodyHeight, mode]); - useEffect(() => { - if (!id && !isPopulated) { - dispatch(fetchQualityProfileSchema()); - } - }, [id, isPopulated, dispatch]); - useEffect(() => { if (wasSaving && !isSaving && !saveError) { onModalClose(); @@ -554,11 +511,10 @@ function EditQualityProfileModalContent({ cutoffId = 'id' in firstAllowed ? firstAllowed.id : firstAllowed.quality.id; - // @ts-expect-error - actions are not typed - dispatch(setQualityProfileValue({ name: 'cutoff', value: cutoffId })); + updateValue('cutoff', cutoffId); } } - }, [cutoff, items, dispatch]); + }, [cutoff, items, updateValue]); return ( @@ -568,15 +524,15 @@ function EditQualityProfileModalContent({
- {isPopulated ? null : } + {isSchemaFetched ? null : } - {!isFetching && error ? ( + {!isSchemaFetching && schemaError ? ( {translate('AddQualityProfileError')} ) : null} - {isPopulated && !error ? ( + {isSchemaFetched && !schemaError ? (
diff --git a/frontend/src/Settings/Profiles/Quality/QualityProfile.tsx b/frontend/src/Settings/Profiles/Quality/QualityProfile.tsx index 75d6d0634..36e0d6b02 100644 --- a/frontend/src/Settings/Profiles/Quality/QualityProfile.tsx +++ b/frontend/src/Settings/Profiles/Quality/QualityProfile.tsx @@ -1,15 +1,16 @@ import React, { useCallback, useState } from 'react'; -import { useDispatch } from 'react-redux'; import Card from 'Components/Card'; import Label from 'Components/Label'; import IconButton from 'Components/Link/IconButton'; import ConfirmModal from 'Components/Modal/ConfirmModal'; import Tooltip from 'Components/Tooltip/Tooltip'; import { icons, kinds, tooltipPositions } from 'Helpers/Props'; -import { deleteQualityProfile } from 'Store/Actions/settingsActions'; -import { QualityProfileItems } from 'typings/QualityProfile'; import translate from 'Utilities/String/translate'; import EditQualityProfileModal from './EditQualityProfileModal'; +import { + QualityProfileItems, + useDeleteQualityProfile, +} from './useQualityProfiles'; import styles from './QualityProfile.css'; interface QualityProfileProps { @@ -18,7 +19,6 @@ interface QualityProfileProps { upgradeAllowed: boolean; cutoff: number; items: QualityProfileItems; - isDeleting: boolean; onCloneQualityProfilePress: (id: number) => void; } @@ -32,7 +32,7 @@ function QualityProfile({ isDeleting, onCloneQualityProfilePress, }: QualityProfileProps) { - const dispatch = useDispatch(); + const { deleteQualityProfile } = useDeleteQualityProfile(id); const [isEditQualityProfileModalOpen, setIsEditQualityProfileModalOpen] = useState(false); @@ -57,8 +57,8 @@ function QualityProfile({ }, []); const handleConfirmDeleteQualityProfile = useCallback(() => { - dispatch(deleteQualityProfile({ id })); - }, [id, dispatch]); + deleteQualityProfile(); + }, [deleteQualityProfile]); const handleCloneQualityProfilePress = useCallback(() => { onCloneQualityProfilePress(id); diff --git a/frontend/src/Settings/Profiles/Quality/QualityProfileItemDragSource.tsx b/frontend/src/Settings/Profiles/Quality/QualityProfileItemDragSource.tsx index 66670ac9c..e948740cd 100644 --- a/frontend/src/Settings/Profiles/Quality/QualityProfileItemDragSource.tsx +++ b/frontend/src/Settings/Profiles/Quality/QualityProfileItemDragSource.tsx @@ -4,10 +4,10 @@ import { DragSourceMonitor, useDrag, useDrop, XYCoord } from 'react-dnd'; import DragType from 'Helpers/DragType'; import useMeasure from 'Helpers/Hooks/useMeasure'; import { qualityProfileItemHeight } from 'Styles/Variables/dimensions'; -import { QualityProfileQualityItem } from 'typings/QualityProfile'; import QualityProfileItem from './QualityProfileItem'; import QualityProfileItemGroup from './QualityProfileItemGroup'; import { SizeChanged } from './QualityProfileItemSize'; +import { QualityProfileQualityItem } from './useQualityProfiles'; import styles from './QualityProfileItemDragSource.css'; export interface DragMoveState { diff --git a/frontend/src/Settings/Profiles/Quality/QualityProfileItemGroup.tsx b/frontend/src/Settings/Profiles/Quality/QualityProfileItemGroup.tsx index 1db6f0599..06a840a2c 100644 --- a/frontend/src/Settings/Profiles/Quality/QualityProfileItemGroup.tsx +++ b/frontend/src/Settings/Profiles/Quality/QualityProfileItemGroup.tsx @@ -8,12 +8,12 @@ import Label from 'Components/Label'; import IconButton from 'Components/Link/IconButton'; import { icons } from 'Helpers/Props'; import { InputChanged } from 'typings/inputs'; -import { QualityProfileQualityItem } from 'typings/QualityProfile'; import translate from 'Utilities/String/translate'; import QualityProfileItemDragSource, { DragMoveState, } from './QualityProfileItemDragSource'; import { SizeChanged } from './QualityProfileItemSize'; +import { QualityProfileQualityItem } from './useQualityProfiles'; import styles from './QualityProfileItemGroup.css'; interface QualityProfileItemGroupProps { diff --git a/frontend/src/Settings/Profiles/Quality/QualityProfileItems.tsx b/frontend/src/Settings/Profiles/Quality/QualityProfileItems.tsx index 42598f119..89cf3e110 100644 --- a/frontend/src/Settings/Profiles/Quality/QualityProfileItems.tsx +++ b/frontend/src/Settings/Profiles/Quality/QualityProfileItems.tsx @@ -7,11 +7,11 @@ import Icon from 'Components/Icon'; import Button from 'Components/Link/Button'; import { icons, kinds, sizes } from 'Helpers/Props'; import { Failure } from 'typings/pending'; -import { QualityProfileItems as Items } from 'typings/QualityProfile'; import translate from 'Utilities/String/translate'; import QualityProfileItemDragSource, { QualityProfileItemDragSourceActionProps, } from './QualityProfileItemDragSource'; +import { QualityProfileItems as Items } from './useQualityProfiles'; import styles from './QualityProfileItems.css'; export type EditQualityProfileMode = 'default' | 'editGroups' | 'editSizes'; diff --git a/frontend/src/Settings/Profiles/Quality/QualityProfileName.tsx b/frontend/src/Settings/Profiles/Quality/QualityProfileName.tsx index bbb3e6f08..bcbf75870 100644 --- a/frontend/src/Settings/Profiles/Quality/QualityProfileName.tsx +++ b/frontend/src/Settings/Profiles/Quality/QualityProfileName.tsx @@ -1,16 +1,13 @@ import React from 'react'; -import { useSelector } from 'react-redux'; -import { createQualityProfileSelectorForHook } from 'Store/Selectors/createQualityProfileSelector'; import translate from 'Utilities/String/translate'; +import { useQualityProfile } from './useQualityProfiles'; interface QualityProfileNameProps { qualityProfileId: number; } function QualityProfileName({ qualityProfileId }: QualityProfileNameProps) { - const qualityProfile = useSelector( - createQualityProfileSelectorForHook(qualityProfileId) - ); + const qualityProfile = useQualityProfile(qualityProfileId); return {qualityProfile?.name ?? translate('Unknown')}; } diff --git a/frontend/src/Settings/Profiles/Quality/QualityProfiles.tsx b/frontend/src/Settings/Profiles/Quality/QualityProfiles.tsx index fad09d099..f4ad8eee7 100644 --- a/frontend/src/Settings/Profiles/Quality/QualityProfiles.tsx +++ b/frontend/src/Settings/Profiles/Quality/QualityProfiles.tsx @@ -1,55 +1,40 @@ -import React, { useCallback, useEffect, useState } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; -import { QualityProfilesAppState } from 'App/State/SettingsAppState'; +import React, { useCallback, useState } from 'react'; import Card from 'Components/Card'; import FieldSet from 'Components/FieldSet'; import Icon from 'Components/Icon'; import PageSectionContent from 'Components/Page/PageSectionContent'; import { icons } from 'Helpers/Props'; -import { - cloneQualityProfile, - fetchQualityProfiles, -} from 'Store/Actions/settingsActions'; -import createSortedSectionSelector from 'Store/Selectors/createSortedSectionSelector'; -import QualityProfileModel from 'typings/QualityProfile'; import sortByProp from 'Utilities/Array/sortByProp'; import translate from 'Utilities/String/translate'; import EditQualityProfileModal from './EditQualityProfileModal'; import QualityProfile from './QualityProfile'; +import { useQualityProfiles } from './useQualityProfiles'; import styles from './QualityProfiles.css'; function QualityProfiles() { - const dispatch = useDispatch(); + const { data, error, isFetching, isFetched } = useQualityProfiles(); - const { error, isFetching, isPopulated, isDeleting, items } = useSelector( - createSortedSectionSelector( - 'settings.qualityProfiles', - sortByProp('name') - ) - ) as QualityProfilesAppState; + // Sort the data by name + const sortedItems = data ? data.sort(sortByProp('name')) : []; const [isQualityProfileModalOpen, setIsQualityProfileModalOpen] = useState(false); + const [cloneProfileId, setCloneProfileId] = useState(null); - const handleEditQualityProfilePress = useCallback(() => { + const handleAddQualityProfilePress = useCallback(() => { + setCloneProfileId(null); setIsQualityProfileModalOpen(true); }, []); - const handleEditQualityProfileClosePress = useCallback(() => { + const handleAddQualityProfileClosePress = useCallback(() => { + setCloneProfileId(null); setIsQualityProfileModalOpen(false); }, []); - const handleCloneQualityProfilePress = useCallback( - (id: number) => { - dispatch(cloneQualityProfile({ id })); - setIsQualityProfileModalOpen(true); - }, - [dispatch] - ); - - useEffect(() => { - dispatch(fetchQualityProfiles()); - }, [dispatch]); + const handleCloneQualityProfilePress = useCallback((id: number) => { + setCloneProfileId(id); + setIsQualityProfileModalOpen(true); + }, []); return (
@@ -57,15 +42,15 @@ function QualityProfiles() { errorMessage={translate('QualityProfilesLoadError')} error={error} isFetching={isFetching} - isPopulated={isPopulated} + isPopulated={isFetched} >
- {items.map((item) => { + {sortedItems.map((item) => { return ( ); @@ -73,7 +58,7 @@ function QualityProfiles() {
@@ -83,7 +68,8 @@ function QualityProfiles() {
diff --git a/frontend/src/Settings/Profiles/Quality/useQualityProfiles.ts b/frontend/src/Settings/Profiles/Quality/useQualityProfiles.ts new file mode 100644 index 000000000..f6bfd1ba9 --- /dev/null +++ b/frontend/src/Settings/Profiles/Quality/useQualityProfiles.ts @@ -0,0 +1,130 @@ +import ModelBase from 'App/ModelBase'; +import useApiQuery from 'Helpers/Hooks/useApiQuery'; +import Quality from 'Quality/Quality'; +import { + useDeleteProvider, + useManageProviderSettings, + useProviderSettings, +} from 'Settings/useProviderSettings'; +import { QualityProfileFormatItem } from 'typings/CustomFormat'; +import translate from 'Utilities/String/translate'; + +export interface QualityProfileQualityItem { + quality: Quality; + allowed: boolean; + minSize: number | null; + maxSize: number | null; + preferredSize: number | null; +} + +export interface QualityProfileGroup { + id: number; + items: QualityProfileQualityItem[]; + allowed: boolean; + name: string; +} + +export type QualityProfileItems = ( + | QualityProfileQualityItem + | QualityProfileGroup +)[]; + +export interface QualityProfileModel extends ModelBase { + name: string; + upgradeAllowed: boolean; + cutoff: number; + items: QualityProfileItems; + minFormatScore: number; + cutoffFormatScore: number; + minUpgradeFormatScore: number; + formatItems: QualityProfileFormatItem[]; +} + +const PATH = '/qualityprofile'; + +export const useQualityProfile = (id: number | undefined) => { + const { data } = useQualityProfiles(); + + if (id === undefined) { + return undefined; + } + + return data.find((profile) => profile.id === id); +}; + +export const useQualityProfilesData = () => { + const { data } = useQualityProfiles(); + + return data; +}; + +export const useQualityProfiles = () => { + return useProviderSettings({ + path: PATH, + queryOptions: { + gcTime: Infinity, + staleTime: 5 * 60 * 1000, + }, + }); +}; + +export const useManageQualityProfile = ( + id: number | undefined, + cloneId: number | undefined +) => { + const { schema, isSchemaFetching, isSchemaFetched, schemaError } = + useQualityProfileSchema(cloneId == null); + + const profile = useQualityProfile(cloneId); + + if (cloneId && !profile) { + throw new Error(`Quality Profile with ID ${cloneId} not found`); + } + + const manage = useManageProviderSettings( + id, + cloneId && profile + ? { + ...profile, + id: 0, + name: translate('DefaultNameCopiedProfile', { + name: profile.name, + }), + } + : schema, + PATH + ); + + return { + ...manage, + isSchemaFetching: cloneId ? false : isSchemaFetching, + isSchemaFetched: cloneId ? true : isSchemaFetched, + schemaError: cloneId ? undefined : schemaError, + }; +}; + +export const useDeleteQualityProfile = (id: number) => { + const result = useDeleteProvider(id, PATH); + + return { + ...result, + deleteQualityProfile: result.deleteProvider, + }; +}; + +export const useQualityProfileSchema = (enabled: boolean) => { + const { isFetching, isFetched, error, data } = + useApiQuery({ + path: `${PATH}/schema`, + queryOptions: { + enabled, + }, + }); + + return { + isSchemaFetching: isFetching, + isSchemaFetched: isFetched, + schemaError: error, + schema: data ?? ({} as QualityProfileModel), + }; +}; diff --git a/frontend/src/Settings/Profiles/Release/useReleaseProfiles.ts b/frontend/src/Settings/Profiles/Release/useReleaseProfiles.ts index 8dc06acfb..5fe0453c3 100644 --- a/frontend/src/Settings/Profiles/Release/useReleaseProfiles.ts +++ b/frontend/src/Settings/Profiles/Release/useReleaseProfiles.ts @@ -37,7 +37,7 @@ export const useReleaseProfilesWithIds = (ids: number[]) => { }; export const useReleaseProfiles = () => { - return useProviderSettings(PATH); + return useProviderSettings({ path: PATH }); }; export const useManageReleaseProfile = (id: number) => { diff --git a/frontend/src/Settings/useProviderSettings.ts b/frontend/src/Settings/useProviderSettings.ts index bd8b72c27..fac373ce9 100644 --- a/frontend/src/Settings/useProviderSettings.ts +++ b/frontend/src/Settings/useProviderSettings.ts @@ -2,19 +2,19 @@ import { useQueryClient } from '@tanstack/react-query'; import { useCallback, useMemo } from 'react'; import ModelBase from 'App/ModelBase'; import useApiMutation from 'Helpers/Hooks/useApiMutation'; -import useApiQuery from 'Helpers/Hooks/useApiQuery'; +import useApiQuery, { QueryOptions } from 'Helpers/Hooks/useApiQuery'; import { usePendingChangesStore } from 'Helpers/Hooks/usePendingChangesStore'; import selectSettings from 'Store/Selectors/selectSettings'; export const useProvider = ( - id: number, + id: number | undefined, defaultProvider: T, path: string ) => { - const { data } = useProviderSettings(path); + const { data } = useProviderSettings({ path }); return useMemo(() => { - if (id === 0) { + if (!id) { return defaultProvider; } @@ -28,10 +28,10 @@ export const useProvider = ( }, [data, defaultProvider, id]); }; -export const useProviderSettings = (path: string) => { - const result = useApiQuery({ - path, - }); +export const useProviderSettings = ( + options: QueryOptions +) => { + const result = useApiQuery(options); return { ...result, @@ -47,18 +47,18 @@ export const useSaveProviderSettings = ( const queryClient = useQueryClient(); const { mutate, isPending, error } = useApiMutation({ - path: id === 0 ? path : `${path}/${id}`, - method: id === 0 ? 'POST' : 'PUT', + path: id ? `${path}/${id}` : path, + method: id ? 'PUT' : 'POST', mutationOptions: { onSuccess: (updatedSettings: T) => { queryClient.setQueryData([path], (oldData = []) => { - if (id === 0) { - return [...oldData, updatedSettings]; + if (id) { + return oldData.map((item) => + item.id === updatedSettings.id ? updatedSettings : item + ); } - return oldData.map((item) => - item.id === updatedSettings.id ? updatedSettings : item - ); + return [...oldData, updatedSettings]; }); onSuccess?.(); }, @@ -73,7 +73,7 @@ export const useSaveProviderSettings = ( }; export const useManageProviderSettings = ( - id: number, + id: number | undefined, defaultProvider: T, path: string ) => { diff --git a/frontend/src/Store/Actions/settingsActions.js b/frontend/src/Store/Actions/settingsActions.js index acfb673c3..bf3ade40b 100644 --- a/frontend/src/Store/Actions/settingsActions.js +++ b/frontend/src/Store/Actions/settingsActions.js @@ -21,7 +21,6 @@ import naming from './Settings/naming'; import namingExamples from './Settings/namingExamples'; import notifications from './Settings/notifications'; import qualityDefinitions from './Settings/qualityDefinitions'; -import qualityProfiles from './Settings/qualityProfiles'; export * from './Settings/autoTaggingSpecifications'; export * from './Settings/autoTaggings'; @@ -44,7 +43,6 @@ export * from './Settings/naming'; export * from './Settings/namingExamples'; export * from './Settings/notifications'; export * from './Settings/qualityDefinitions'; -export * from './Settings/qualityProfiles'; // // Variables @@ -76,8 +74,7 @@ export const defaultState = { naming: naming.defaultState, namingExamples: namingExamples.defaultState, notifications: notifications.defaultState, - qualityDefinitions: qualityDefinitions.defaultState, - qualityProfiles: qualityProfiles.defaultState + qualityDefinitions: qualityDefinitions.defaultState }; export const persistState = [ @@ -108,8 +105,7 @@ export const actionHandlers = handleThunks({ ...naming.actionHandlers, ...namingExamples.actionHandlers, ...notifications.actionHandlers, - ...qualityDefinitions.actionHandlers, - ...qualityProfiles.actionHandlers + ...qualityDefinitions.actionHandlers }); // @@ -136,7 +132,6 @@ export const reducers = createHandleActions({ ...naming.reducers, ...namingExamples.reducers, ...notifications.reducers, - ...qualityDefinitions.reducers, - ...qualityProfiles.reducers + ...qualityDefinitions.reducers }, defaultState, section); diff --git a/frontend/src/Store/Selectors/createQualityProfileSelector.ts b/frontend/src/Store/Selectors/createQualityProfileSelector.ts deleted file mode 100644 index b913e0c46..000000000 --- a/frontend/src/Store/Selectors/createQualityProfileSelector.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { createSelector } from 'reselect'; -import AppState from 'App/State/AppState'; - -export function createQualityProfileSelectorForHook(qualityProfileId: number) { - return createSelector( - (state: AppState) => state.settings.qualityProfiles.items, - (qualityProfiles) => { - return qualityProfiles.find((profile) => profile.id === qualityProfileId); - } - ); -} - -function createQualityProfileSelector() { - return createSelector( - (_: AppState, { qualityProfileId }: { qualityProfileId: number }) => - qualityProfileId, - (state: AppState) => state.settings.qualityProfiles.items, - (qualityProfileId, qualityProfiles) => { - return qualityProfiles.find((profile) => profile.id === qualityProfileId); - } - ); -} - -export default createQualityProfileSelector; diff --git a/frontend/src/Store/Selectors/createSeriesQualityProfileSelector.ts b/frontend/src/Store/Selectors/createSeriesQualityProfileSelector.ts deleted file mode 100644 index 86de2c316..000000000 --- a/frontend/src/Store/Selectors/createSeriesQualityProfileSelector.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { createSelector } from 'reselect'; -import AppState from 'App/State/AppState'; -import Series from 'Series/Series'; -import QualityProfile from 'typings/QualityProfile'; - -function createSeriesQualityProfileSelector(series?: Series) { - return createSelector( - (state: AppState) => state.settings.qualityProfiles.items, - (qualityProfiles: QualityProfile[]) => { - if (!series) { - return undefined; - } - - return qualityProfiles.find( - (profile) => profile.id === series.qualityProfileId - ); - } - ); -} - -export default createSeriesQualityProfileSelector; diff --git a/frontend/src/Utilities/Quality/getQualities.ts b/frontend/src/Utilities/Quality/getQualities.ts index 3fb4a21e7..ff78ef395 100644 --- a/frontend/src/Utilities/Quality/getQualities.ts +++ b/frontend/src/Utilities/Quality/getQualities.ts @@ -1,5 +1,5 @@ import Quality from 'Quality/Quality'; -import { QualityProfileItems } from 'typings/QualityProfile'; +import { QualityProfileItems } from 'Settings/Profiles/Quality/useQualityProfiles'; export default function getQualities(qualities?: QualityProfileItems) { if (!qualities) { diff --git a/frontend/src/typings/QualityProfile.ts b/frontend/src/typings/QualityProfile.ts deleted file mode 100644 index c63c99432..000000000 --- a/frontend/src/typings/QualityProfile.ts +++ /dev/null @@ -1,36 +0,0 @@ -import Quality from 'Quality/Quality'; -import { QualityProfileFormatItem } from './CustomFormat'; - -export interface QualityProfileQualityItem { - quality: Quality; - allowed: boolean; - minSize: number | null; - maxSize: number | null; - preferredSize: number | null; -} - -export interface QualityProfileGroup { - id: number; - items: QualityProfileQualityItem[]; - allowed: boolean; - name: string; -} - -export type QualityProfileItems = ( - | QualityProfileQualityItem - | QualityProfileGroup -)[]; - -interface QualityProfile { - name: string; - upgradeAllowed: boolean; - cutoff: number; - items: QualityProfileItems; - minFormatScore: number; - cutoffFormatScore: number; - minUpgradeFormatScore: number; - formatItems: QualityProfileFormatItem[]; - id: number; -} - -export default QualityProfile;