mirror of
https://github.com/Sonarr/Sonarr.git
synced 2026-04-18 21:35:27 -04:00
Use react-query for Languages
This commit is contained in:
@@ -6,7 +6,6 @@ import AppSectionState, {
|
||||
AppSectionSchemaState,
|
||||
PagedAppSectionState,
|
||||
} from 'App/State/AppSectionState';
|
||||
import Language from 'Language/Language';
|
||||
import AutoTagging, { AutoTaggingSpecification } from 'typings/AutoTagging';
|
||||
import CustomFormat from 'typings/CustomFormat';
|
||||
import CustomFormatSpecification from 'typings/CustomFormatSpecification';
|
||||
@@ -101,7 +100,6 @@ export interface ImportListExclusionsSettingsAppState
|
||||
}
|
||||
|
||||
export type IndexerFlagSettingsAppState = AppSectionState<IndexerFlag>;
|
||||
export type LanguageSettingsAppState = AppSectionState<Language>;
|
||||
|
||||
interface SettingsAppState {
|
||||
autoTaggings: AutoTaggingAppState;
|
||||
@@ -118,7 +116,6 @@ interface SettingsAppState {
|
||||
indexerFlags: IndexerFlagSettingsAppState;
|
||||
indexerOptions: IndexerOptionsAppState;
|
||||
indexers: IndexerAppState;
|
||||
languages: LanguageSettingsAppState;
|
||||
}
|
||||
|
||||
export default SettingsAppState;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import React from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import createLanguagesSelector from 'Store/Selectors/createLanguagesSelector';
|
||||
import { useLanguages } from 'Language/useLanguages';
|
||||
import FilterBuilderRowValue, {
|
||||
FilterBuilderRowValueProps,
|
||||
} from './FilterBuilderRowValue';
|
||||
@@ -13,7 +12,7 @@ type LanguageFilterBuilderRowValueProps<T> = Omit<
|
||||
function LanguageFilterBuilderRowValue<T>(
|
||||
props: LanguageFilterBuilderRowValueProps<T>
|
||||
) {
|
||||
const { items } = useSelector(createLanguagesSelector());
|
||||
const { data: items = [] } = useLanguages();
|
||||
|
||||
return <FilterBuilderRowValue {...props} tagList={items} />;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import Language from 'Language/Language';
|
||||
import createLanguagesSelector from 'Store/Selectors/createLanguagesSelector';
|
||||
import { useFilteredLanguages } from 'Language/useLanguages';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import EnhancedSelectInput, {
|
||||
EnhancedSelectInputValue,
|
||||
@@ -31,13 +30,11 @@ export default function LanguageSelectInput({
|
||||
onChange,
|
||||
...otherProps
|
||||
}: LanguageSelectInputProps) {
|
||||
const { items } = useSelector(
|
||||
createLanguagesSelector({
|
||||
Any: true,
|
||||
Original: true,
|
||||
Unknown: true,
|
||||
})
|
||||
);
|
||||
const { data: items = [] } = useFilteredLanguages({
|
||||
includeAny: true,
|
||||
includeOriginal: true,
|
||||
includeUnknown: true,
|
||||
});
|
||||
|
||||
const values = useMemo(() => {
|
||||
const result: EnhancedSelectInputValue<number | string>[] = items.map(
|
||||
|
||||
@@ -6,6 +6,7 @@ import { useTranslations } from 'App/useTranslations';
|
||||
import useCommands from 'Commands/useCommands';
|
||||
import useCustomFilters from 'Filters/useCustomFilters';
|
||||
import { useInitializeLanguage } from 'Language/useLanguageName';
|
||||
import { useLanguages } from 'Language/useLanguages';
|
||||
import useSeries from 'Series/useSeries';
|
||||
import { useQualityProfiles } from 'Settings/Profiles/Quality/useQualityProfiles';
|
||||
import { useUiSettings } from 'Settings/UI/useUiSettings';
|
||||
@@ -13,7 +14,6 @@ import { fetchCustomFilters } from 'Store/Actions/customFilterActions';
|
||||
import {
|
||||
fetchImportLists,
|
||||
fetchIndexerFlags,
|
||||
fetchLanguages,
|
||||
} from 'Store/Actions/settingsActions';
|
||||
import useSystemStatus from 'System/Status/useSystemStatus';
|
||||
import useTags from 'Tags/useTags';
|
||||
@@ -27,6 +27,7 @@ const createErrorsSelector = ({
|
||||
uiSettingsError,
|
||||
seriesError,
|
||||
qualityProfilesError,
|
||||
languagesError,
|
||||
}: {
|
||||
customFiltersError: ApiError | null;
|
||||
systemStatusError: ApiError | null;
|
||||
@@ -35,12 +36,12 @@ const createErrorsSelector = ({
|
||||
uiSettingsError: ApiError | null;
|
||||
seriesError: ApiError | null;
|
||||
qualityProfilesError: ApiError | null;
|
||||
languagesError: ApiError | null;
|
||||
}) =>
|
||||
createSelector(
|
||||
(state: AppState) => state.settings.languages.error,
|
||||
(state: AppState) => state.settings.importLists.error,
|
||||
(state: AppState) => state.settings.indexerFlags.error,
|
||||
(languagesError, importListsError, indexerFlagsError) => {
|
||||
(importListsError, indexerFlagsError) => {
|
||||
const hasError = !!(
|
||||
customFiltersError ||
|
||||
seriesError ||
|
||||
@@ -82,7 +83,7 @@ const useAppPage = () => {
|
||||
const { isFetched: isCustomFiltersFetched, error: customFiltersError } =
|
||||
useCustomFilters();
|
||||
|
||||
const { isSuccess: isSeriesFetched, error: seriesError } = useSeries();
|
||||
const { isFetched: isSeriesFetched, error: seriesError } = useSeries();
|
||||
|
||||
const { isFetched: isSystemStatusFetched, error: systemStatusError } =
|
||||
useSystemStatus();
|
||||
@@ -98,9 +99,11 @@ const useAppPage = () => {
|
||||
const { isFetched: isQualityProfilesFetched, error: qualityProfilesError } =
|
||||
useQualityProfiles();
|
||||
|
||||
const { isFetched: isLanguagesFetched, error: languagesError } =
|
||||
useLanguages();
|
||||
|
||||
const isAppStatePopulated = useSelector(
|
||||
(state: AppState) =>
|
||||
state.settings.languages.isPopulated &&
|
||||
state.settings.importLists.isPopulated &&
|
||||
state.settings.indexerFlags.isPopulated
|
||||
);
|
||||
@@ -113,7 +116,8 @@ const useAppPage = () => {
|
||||
isTagsFetched &&
|
||||
isTranslationsFetched &&
|
||||
isUiSettingsFetched &&
|
||||
isQualityProfilesFetched;
|
||||
isQualityProfilesFetched &&
|
||||
isLanguagesFetched;
|
||||
|
||||
const { hasError, errors } = useSelector(
|
||||
createErrorsSelector({
|
||||
@@ -124,6 +128,7 @@ const useAppPage = () => {
|
||||
translationsError,
|
||||
uiSettingsError,
|
||||
qualityProfilesError,
|
||||
languagesError,
|
||||
})
|
||||
);
|
||||
|
||||
@@ -142,7 +147,6 @@ const useAppPage = () => {
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(fetchCustomFilters());
|
||||
dispatch(fetchLanguages());
|
||||
dispatch(fetchImportLists());
|
||||
dispatch(fetchIndexerFlags());
|
||||
}, [dispatch]);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import Alert from 'Components/Alert';
|
||||
import Form from 'Components/Form/Form';
|
||||
import FormGroup from 'Components/Form/FormGroup';
|
||||
@@ -13,7 +12,7 @@ import ModalFooter from 'Components/Modal/ModalFooter';
|
||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import { inputTypes, kinds, sizes } from 'Helpers/Props';
|
||||
import Language from 'Language/Language';
|
||||
import createLanguagesSelector from 'Store/Selectors/createLanguagesSelector';
|
||||
import { useFilteredLanguages } from 'Language/useLanguages';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './SelectLanguageModalContent.css';
|
||||
|
||||
@@ -27,12 +26,15 @@ interface SelectLanguageModalContentProps {
|
||||
function SelectLanguageModalContent(props: SelectLanguageModalContentProps) {
|
||||
const { modalTitle, onLanguagesSelect, onModalClose } = props;
|
||||
|
||||
const { isFetching, isPopulated, error, items } = useSelector(
|
||||
createLanguagesSelector({
|
||||
Any: true,
|
||||
Original: true,
|
||||
})
|
||||
);
|
||||
const {
|
||||
data: items = [],
|
||||
isFetching,
|
||||
isFetched: isPopulated,
|
||||
error,
|
||||
} = useFilteredLanguages({
|
||||
includeAny: true,
|
||||
includeOriginal: true,
|
||||
});
|
||||
|
||||
const [languageIds, setLanguageIds] = useState(props.languageIds);
|
||||
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
import { useMemo } from 'react';
|
||||
import useApiQuery from 'Helpers/Hooks/useApiQuery';
|
||||
import Language from 'Language/Language';
|
||||
|
||||
interface LanguageFilter {
|
||||
[key: string]: boolean | undefined;
|
||||
includeAny: boolean;
|
||||
includeOriginal?: boolean;
|
||||
includeUnknown?: boolean;
|
||||
}
|
||||
|
||||
const PATH = '/language';
|
||||
|
||||
export const useLanguages = () => {
|
||||
return useApiQuery<Language[]>({
|
||||
path: PATH,
|
||||
queryOptions: {
|
||||
gcTime: Infinity,
|
||||
staleTime: Infinity,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const useFilteredLanguages = (
|
||||
excludeLanguages: LanguageFilter = { includeAny: true }
|
||||
) => {
|
||||
const { data, isFetching, isFetched, error } = useLanguages();
|
||||
|
||||
const filteredItems = useMemo(() => {
|
||||
if (!data) return [];
|
||||
|
||||
return data.filter((lang) => !excludeLanguages[lang.name]);
|
||||
}, [data, excludeLanguages]);
|
||||
|
||||
return {
|
||||
data: filteredItems,
|
||||
isFetching,
|
||||
isFetched,
|
||||
error,
|
||||
};
|
||||
};
|
||||
|
||||
export const useLanguageById = (id: number | undefined) => {
|
||||
const { data } = useLanguages();
|
||||
|
||||
return useMemo(() => {
|
||||
if (id === undefined || !data) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return data.find((language) => language.id === id);
|
||||
}, [data, id]);
|
||||
};
|
||||
|
||||
export const useLanguageByName = (name: string | undefined) => {
|
||||
const { data } = useLanguages();
|
||||
|
||||
return useMemo(() => {
|
||||
if (!name || !data) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return data.find((language) => language.name === name);
|
||||
}, [data, name]);
|
||||
};
|
||||
@@ -1,5 +1,4 @@
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import Alert from 'Components/Alert';
|
||||
import FieldSet from 'Components/FieldSet';
|
||||
import Form from 'Components/Form/Form';
|
||||
@@ -11,8 +10,8 @@ import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||
import PageContent from 'Components/Page/PageContent';
|
||||
import PageContentBody from 'Components/Page/PageContentBody';
|
||||
import { inputTypes, kinds } from 'Helpers/Props';
|
||||
import { useFilteredLanguages } from 'Language/useLanguages';
|
||||
import SettingsToolbar from 'Settings/SettingsToolbar';
|
||||
import createLanguagesSelector from 'Store/Selectors/createLanguagesSelector';
|
||||
import themes from 'Styles/Themes';
|
||||
import { InputChanged } from 'typings/inputs';
|
||||
import timeZoneOptions from 'Utilities/Date/timeZoneOptions';
|
||||
@@ -63,17 +62,15 @@ export const timeFormatOptions: EnhancedSelectInputValue<string>[] = [
|
||||
|
||||
function UISettings() {
|
||||
const {
|
||||
items,
|
||||
data: languageItems = [],
|
||||
isFetching: isLanguagesFetching,
|
||||
isPopulated: isLanguagesPopulated,
|
||||
isFetched: isLanguagesPopulated,
|
||||
error: languagesError,
|
||||
} = useSelector(
|
||||
createLanguagesSelector({
|
||||
Any: true,
|
||||
Original: true,
|
||||
Unknown: true,
|
||||
})
|
||||
);
|
||||
} = useFilteredLanguages({
|
||||
includeAny: true,
|
||||
includeOriginal: true,
|
||||
includeUnknown: true,
|
||||
});
|
||||
|
||||
const {
|
||||
isFetching: isSettingsFetching,
|
||||
@@ -94,13 +91,13 @@ function UISettings() {
|
||||
const error = languagesError || settingsError;
|
||||
|
||||
const languages = useMemo(() => {
|
||||
return items.map((item) => {
|
||||
return languageItems.map((item) => {
|
||||
return {
|
||||
key: item.id,
|
||||
value: item.name,
|
||||
};
|
||||
});
|
||||
}, [items]);
|
||||
}, [languageItems]);
|
||||
|
||||
const themeOptions = Object.keys(themes).map((theme) => ({
|
||||
key: theme,
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
import createFetchHandler from 'Store/Actions/Creators/createFetchHandler';
|
||||
import { createThunk } from 'Store/thunks';
|
||||
|
||||
//
|
||||
// Variables
|
||||
|
||||
const section = 'settings.languages';
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_LANGUAGES = 'settings/languages/fetchLanguages';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchLanguages = createThunk(FETCH_LANGUAGES);
|
||||
|
||||
//
|
||||
// Details
|
||||
|
||||
export default {
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
defaultState: {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
items: []
|
||||
},
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
actionHandlers: {
|
||||
[FETCH_LANGUAGES]: createFetchHandler(section, '/language')
|
||||
},
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
reducers: {
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
@@ -14,7 +14,6 @@ import importLists from './Settings/importLists';
|
||||
import indexerFlags from './Settings/indexerFlags';
|
||||
import indexerOptions from './Settings/indexerOptions';
|
||||
import indexers from './Settings/indexers';
|
||||
import languages from './Settings/languages';
|
||||
|
||||
export * from './Settings/autoTaggingSpecifications';
|
||||
export * from './Settings/autoTaggings';
|
||||
@@ -30,7 +29,6 @@ export * from './Settings/importListExclusions';
|
||||
export * from './Settings/indexerFlags';
|
||||
export * from './Settings/indexerOptions';
|
||||
export * from './Settings/indexers';
|
||||
export * from './Settings/languages';
|
||||
|
||||
//
|
||||
// Variables
|
||||
@@ -55,8 +53,7 @@ export const defaultState = {
|
||||
importListOptions: importListOptions.defaultState,
|
||||
indexerFlags: indexerFlags.defaultState,
|
||||
indexerOptions: indexerOptions.defaultState,
|
||||
indexers: indexers.defaultState,
|
||||
languages: languages.defaultState
|
||||
indexers: indexers.defaultState
|
||||
};
|
||||
|
||||
export const persistState = [
|
||||
@@ -80,8 +77,7 @@ export const actionHandlers = handleThunks({
|
||||
...importListOptions.actionHandlers,
|
||||
...indexerFlags.actionHandlers,
|
||||
...indexerOptions.actionHandlers,
|
||||
...indexers.actionHandlers,
|
||||
...languages.actionHandlers
|
||||
...indexers.actionHandlers
|
||||
});
|
||||
|
||||
//
|
||||
@@ -101,7 +97,6 @@ export const reducers = createHandleActions({
|
||||
...importListOptions.reducers,
|
||||
...indexerFlags.reducers,
|
||||
...indexerOptions.reducers,
|
||||
...indexers.reducers,
|
||||
...languages.reducers
|
||||
...indexers.reducers
|
||||
|
||||
}, defaultState, section);
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
import { createSelector } from 'reselect';
|
||||
import AppState from 'App/State/AppState';
|
||||
|
||||
interface LanguageFilter {
|
||||
[key: string]: boolean | undefined;
|
||||
Any: boolean;
|
||||
Original?: boolean;
|
||||
Unknown?: boolean;
|
||||
}
|
||||
|
||||
function createLanguagesSelector(
|
||||
excludeLanguages: LanguageFilter = { Any: true }
|
||||
) {
|
||||
return createSelector(
|
||||
(state: AppState) => state.settings.languages,
|
||||
(languages) => {
|
||||
const { isFetching, isPopulated, error, items } = languages;
|
||||
|
||||
const filteredLanguages = items.filter(
|
||||
(lang) => !excludeLanguages[lang.name]
|
||||
);
|
||||
|
||||
return {
|
||||
isFetching,
|
||||
isPopulated,
|
||||
error,
|
||||
items: filteredLanguages,
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export default createLanguagesSelector;
|
||||
Reference in New Issue
Block a user