Extract fetch logic into parent setting components
This commit is contained in:
@@ -23,6 +23,14 @@ import { IncludeOrExclude } from '@/lib/graphql/generated/graphql.ts';
|
|||||||
import { TCategory } from '@/typings.ts';
|
import { TCategory } from '@/typings.ts';
|
||||||
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||||
import { CheckboxContainer } from '@/components/settings/globalUpdate/CheckboxContainer.ts';
|
import { CheckboxContainer } from '@/components/settings/globalUpdate/CheckboxContainer.ts';
|
||||||
|
import {
|
||||||
|
CategoryDownloadInclusionInfo,
|
||||||
|
CategoryIdInfo,
|
||||||
|
CategoryNameInfo,
|
||||||
|
CategoryUpdateInclusionInfo,
|
||||||
|
} from '@/lib/data/Categories.ts';
|
||||||
|
|
||||||
|
type CategoryType = CategoryIdInfo & CategoryNameInfo & CategoryUpdateInclusionInfo & CategoryDownloadInclusionInfo;
|
||||||
|
|
||||||
const booleanToIncludeOrExcludeStatus = (status: boolean | null | undefined): IncludeOrExclude => {
|
const booleanToIncludeOrExcludeStatus = (status: boolean | null | undefined): IncludeOrExclude => {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
@@ -52,19 +60,11 @@ const includeInUpdateStatusToBoolean = (status: IncludeOrExclude): boolean | nul
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getCategoryUpdateInfo = (
|
const getCategoryUpdateInfo = (
|
||||||
categories: TCategory[],
|
categories: CategoryType[],
|
||||||
areIncluded: boolean,
|
areIncluded: boolean,
|
||||||
unsetCategories: number,
|
unsetCategories: number,
|
||||||
allCategories: number,
|
allCategories: number,
|
||||||
error: any,
|
|
||||||
) => {
|
) => {
|
||||||
if (error) {
|
|
||||||
return translate('global.error.label.failed_to_load_data');
|
|
||||||
}
|
|
||||||
if (allCategories === -1) {
|
|
||||||
return translate('global.label.loading');
|
|
||||||
}
|
|
||||||
|
|
||||||
const noSpecificallyIncludedCategories = areIncluded && !categories.length && unsetCategories;
|
const noSpecificallyIncludedCategories = areIncluded && !categories.length && unsetCategories;
|
||||||
const includesAllCategories = categories.length === allCategories;
|
const includesAllCategories = categories.length === allCategories;
|
||||||
if (noSpecificallyIncludedCategories || includesAllCategories) {
|
if (noSpecificallyIncludedCategories || includesAllCategories) {
|
||||||
@@ -80,18 +80,20 @@ const getCategoryUpdateInfo = (
|
|||||||
|
|
||||||
type CategoryIncludeField = keyof Pick<TCategory, 'includeInUpdate' | 'includeInDownload'>;
|
type CategoryIncludeField = keyof Pick<TCategory, 'includeInUpdate' | 'includeInDownload'>;
|
||||||
|
|
||||||
type CategoriesInclusionSettingProps = {
|
export type CategoriesInclusionSettingProps = {
|
||||||
|
categories: CategoryType[];
|
||||||
includeField: CategoryIncludeField;
|
includeField: CategoryIncludeField;
|
||||||
dialogText?: string;
|
dialogText?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const CategoriesInclusionSetting = (props: CategoriesInclusionSettingProps) => {
|
export const CategoriesInclusionSetting = ({
|
||||||
|
categories,
|
||||||
|
includeField,
|
||||||
|
dialogText,
|
||||||
|
}: CategoriesInclusionSettingProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const { includeField, dialogText } = props;
|
const [dialogCategories, setDialogCategories] = useState(categories);
|
||||||
const { data, error: requestError } = requestManager.useGetCategories();
|
|
||||||
const categories = data?.categories.nodes;
|
|
||||||
const [dialogCategories, setDialogCategories] = useState<TCategory[]>(categories ?? []);
|
|
||||||
const [isDialogOpen, setIsDialogOpen] = useState(false);
|
const [isDialogOpen, setIsDialogOpen] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -102,28 +104,23 @@ export const CategoriesInclusionSetting = (props: CategoriesInclusionSettingProp
|
|||||||
setDialogCategories(categories);
|
setDialogCategories(categories);
|
||||||
}, [categories]);
|
}, [categories]);
|
||||||
|
|
||||||
const unsetCategories: TCategory[] =
|
const unsetCategories = categories.filter((category) => category[includeField] === IncludeOrExclude.Unset);
|
||||||
categories?.filter((category) => category[includeField] === IncludeOrExclude.Unset) ?? [];
|
const excludedCategories = categories.filter((category) => category[includeField] === IncludeOrExclude.Exclude);
|
||||||
const excludedCategories: TCategory[] =
|
const includedCategories = categories.filter((category) => category[includeField] === IncludeOrExclude.Include);
|
||||||
categories?.filter((category) => category[includeField] === IncludeOrExclude.Exclude) ?? [];
|
|
||||||
const includedCategories: TCategory[] =
|
|
||||||
categories?.filter((category) => category[includeField] === IncludeOrExclude.Include) ?? [];
|
|
||||||
const excludedCategoriesText = getCategoryUpdateInfo(
|
const excludedCategoriesText = getCategoryUpdateInfo(
|
||||||
excludedCategories,
|
excludedCategories,
|
||||||
false,
|
false,
|
||||||
unsetCategories.length,
|
unsetCategories.length,
|
||||||
categories?.length ?? -1,
|
categories.length,
|
||||||
requestError,
|
|
||||||
);
|
);
|
||||||
const includedCategoriesText = getCategoryUpdateInfo(
|
const includedCategoriesText = getCategoryUpdateInfo(
|
||||||
includedCategories,
|
includedCategories,
|
||||||
true,
|
true,
|
||||||
unsetCategories.length,
|
unsetCategories.length,
|
||||||
categories?.length ?? -1,
|
categories.length,
|
||||||
requestError,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const updateCategory = (category: TCategory) =>
|
const updateCategory = (category: CategoryType) =>
|
||||||
requestManager.updateCategory(category.id, { [includeField]: category[includeField] }).response;
|
requestManager.updateCategory(category.id, { [includeField]: category[includeField] }).response;
|
||||||
|
|
||||||
const updateCategories = async () => {
|
const updateCategories = async () => {
|
||||||
@@ -150,7 +147,7 @@ export const CategoriesInclusionSetting = (props: CategoriesInclusionSettingProp
|
|||||||
};
|
};
|
||||||
|
|
||||||
const closeDialog = () => {
|
const closeDialog = () => {
|
||||||
setDialogCategories(categories ?? []);
|
setDialogCategories(categories);
|
||||||
setIsDialogOpen(false);
|
setIsDialogOpen(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -193,7 +190,7 @@ export const CategoriesInclusionSetting = (props: CategoriesInclusionSettingProp
|
|||||||
const categoryIndex = dialogCategories.findIndex(
|
const categoryIndex = dialogCategories.findIndex(
|
||||||
(category_) => category_ === category,
|
(category_) => category_ === category,
|
||||||
);
|
);
|
||||||
const updatedDialogCategories: TCategory[] = [
|
const updatedDialogCategories = [
|
||||||
...dialogCategories.slice(0, categoryIndex),
|
...dialogCategories.slice(0, categoryIndex),
|
||||||
{
|
{
|
||||||
...category,
|
...category,
|
||||||
|
|||||||
@@ -13,21 +13,21 @@ import ListItemText from '@mui/material/ListItemText';
|
|||||||
import Switch from '@mui/material/Switch';
|
import Switch from '@mui/material/Switch';
|
||||||
import { NumberSetting } from '@/components/settings/NumberSetting.tsx';
|
import { NumberSetting } from '@/components/settings/NumberSetting.tsx';
|
||||||
import { getPersistedServerSetting, usePersistedValue } from '@/util/usePersistedValue.tsx';
|
import { getPersistedServerSetting, usePersistedValue } from '@/util/usePersistedValue.tsx';
|
||||||
import { updateMetadataServerSettings, useMetadataServerSettings } from '@/lib/metadata/metadataServerSettings.ts';
|
import { updateMetadataServerSettings } from '@/lib/metadata/metadataServerSettings.ts';
|
||||||
import { MetadataDownloadSettings } from '@/typings.ts';
|
import { MetadataDownloadSettings, MetadataServerSettings } from '@/typings.ts';
|
||||||
import { makeToast } from '@/components/util/Toast.tsx';
|
import { makeToast } from '@/components/util/Toast.tsx';
|
||||||
|
|
||||||
const MIN_LIMIT = 2;
|
const MIN_LIMIT = 2;
|
||||||
const MAX_LIMIT = 10;
|
const MAX_LIMIT = 10;
|
||||||
const DEFAULT_LIMIT = MIN_LIMIT;
|
const DEFAULT_LIMIT = MIN_LIMIT;
|
||||||
|
|
||||||
export const DownloadAheadSetting = () => {
|
export const DownloadAheadSetting = ({
|
||||||
|
downloadAheadLimit,
|
||||||
|
}: {
|
||||||
|
downloadAheadLimit: MetadataServerSettings['downloadAheadLimit'];
|
||||||
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const {
|
|
||||||
settings: { downloadAheadLimit },
|
|
||||||
} = useMetadataServerSettings();
|
|
||||||
|
|
||||||
const shouldDownloadAhead = !!downloadAheadLimit;
|
const shouldDownloadAhead = !!downloadAheadLimit;
|
||||||
const [currentDownloadAheadLimit, persistDownloadAheadLimit] = usePersistedValue(
|
const [currentDownloadAheadLimit, persistDownloadAheadLimit] = usePersistedValue(
|
||||||
'lastDownloadAheadLimit',
|
'lastDownloadAheadLimit',
|
||||||
|
|||||||
@@ -12,7 +12,10 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import ListItem from '@mui/material/ListItem';
|
import ListItem from '@mui/material/ListItem';
|
||||||
import ListItemText from '@mui/material/ListItemText';
|
import ListItemText from '@mui/material/ListItemText';
|
||||||
import Switch from '@mui/material/Switch';
|
import Switch from '@mui/material/Switch';
|
||||||
import { CategoriesInclusionSetting } from '@/components/settings/CategoriesInclusionSetting.tsx';
|
import {
|
||||||
|
CategoriesInclusionSetting,
|
||||||
|
CategoriesInclusionSettingProps,
|
||||||
|
} from '@/components/settings/CategoriesInclusionSetting.tsx';
|
||||||
import { GlobalUpdateSettingsEntries } from '@/components/settings/globalUpdate/GlobalUpdateSettingsEntries.tsx';
|
import { GlobalUpdateSettingsEntries } from '@/components/settings/globalUpdate/GlobalUpdateSettingsEntries.tsx';
|
||||||
import { GlobalUpdateSettingsInterval } from '@/components/settings/globalUpdate/GlobalUpdateSettingsInterval.tsx';
|
import { GlobalUpdateSettingsInterval } from '@/components/settings/globalUpdate/GlobalUpdateSettingsInterval.tsx';
|
||||||
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||||
@@ -21,11 +24,16 @@ import { ServerSettings } from '@/typings.ts';
|
|||||||
|
|
||||||
type LibrarySettingsType = Pick<ServerSettings, 'updateMangas'>;
|
type LibrarySettingsType = Pick<ServerSettings, 'updateMangas'>;
|
||||||
|
|
||||||
export const GlobalUpdateSettings = () => {
|
export const GlobalUpdateSettings = ({
|
||||||
|
serverSettings,
|
||||||
|
categories,
|
||||||
|
}: {
|
||||||
|
serverSettings: ServerSettings;
|
||||||
|
categories: CategoriesInclusionSettingProps['categories'];
|
||||||
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const { data } = requestManager.useGetServerSettings();
|
const { updateMangas } = serverSettings;
|
||||||
const updateMangas = !!data?.settings.updateMangas;
|
|
||||||
const [mutateSettings] = requestManager.useUpdateServerSettings();
|
const [mutateSettings] = requestManager.useUpdateServerSettings();
|
||||||
|
|
||||||
const updateSetting = async <Setting extends keyof LibrarySettingsType>(
|
const updateSetting = async <Setting extends keyof LibrarySettingsType>(
|
||||||
@@ -47,9 +55,10 @@ export const GlobalUpdateSettings = () => {
|
|||||||
</ListSubheader>
|
</ListSubheader>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<GlobalUpdateSettingsInterval />
|
<GlobalUpdateSettingsInterval globalUpdateInterval={serverSettings.globalUpdateInterval} />
|
||||||
<GlobalUpdateSettingsEntries />
|
<GlobalUpdateSettingsEntries serverSettings={serverSettings} />
|
||||||
<CategoriesInclusionSetting
|
<CategoriesInclusionSetting
|
||||||
|
categories={categories}
|
||||||
includeField="includeInUpdate"
|
includeField="includeInUpdate"
|
||||||
dialogText={t('library.settings.global_update.categories.label.info')}
|
dialogText={t('library.settings.global_update.categories.label.info')}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -33,15 +33,7 @@ const settingToTextMap: { [setting in keyof GlobalUpdateSkipEntriesSettings]: Tr
|
|||||||
excludeCompleted: 'library.settings.global_update.entries.label.completed',
|
excludeCompleted: 'library.settings.global_update.entries.label.completed',
|
||||||
};
|
};
|
||||||
|
|
||||||
const getSkipMangasText = (settings: GlobalUpdateSkipEntriesSettings | undefined, isLoading: boolean, error: any) => {
|
const getSkipMangasText = (settings: GlobalUpdateSkipEntriesSettings) => {
|
||||||
if (error) {
|
|
||||||
return translate('global.error.label.failed_to_load_data');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!settings || isLoading) {
|
|
||||||
return translate('global.label.loading');
|
|
||||||
}
|
|
||||||
|
|
||||||
const skipSettings: string[] = [];
|
const skipSettings: string[] = [];
|
||||||
|
|
||||||
if (settings.excludeUnreadChapters) {
|
if (settings.excludeUnreadChapters) {
|
||||||
@@ -70,10 +62,10 @@ const extractSkipEntriesSettings = (serverSettings: ServerSettings): GlobalUpdat
|
|||||||
excludeUnreadChapters: serverSettings.excludeUnreadChapters,
|
excludeUnreadChapters: serverSettings.excludeUnreadChapters,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const GlobalUpdateSettingsEntries = () => {
|
export const GlobalUpdateSettingsEntries = ({ serverSettings }: { serverSettings: ServerSettings }) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { data, loading, error: requestError } = requestManager.useGetServerSettings();
|
|
||||||
const globalUpdateSettings = data ? extractSkipEntriesSettings(data.settings) : undefined;
|
const globalUpdateSettings = extractSkipEntriesSettings(serverSettings);
|
||||||
const [mutateSettings] = requestManager.useUpdateServerSettings();
|
const [mutateSettings] = requestManager.useUpdateServerSettings();
|
||||||
|
|
||||||
const [dialogSettings, setDialogSettings] = useState<GlobalUpdateSkipEntriesSettings>(
|
const [dialogSettings, setDialogSettings] = useState<GlobalUpdateSkipEntriesSettings>(
|
||||||
@@ -81,7 +73,7 @@ export const GlobalUpdateSettingsEntries = () => {
|
|||||||
);
|
);
|
||||||
const [isDialogOpen, setIsDialogOpen] = useState(false);
|
const [isDialogOpen, setIsDialogOpen] = useState(false);
|
||||||
|
|
||||||
const skipEntriesText = getSkipMangasText(globalUpdateSettings, loading, requestError);
|
const skipEntriesText = getSkipMangasText(globalUpdateSettings);
|
||||||
|
|
||||||
const updateSettings = async () => {
|
const updateSettings = async () => {
|
||||||
const didSettingsChange =
|
const didSettingsChange =
|
||||||
|
|||||||
@@ -15,16 +15,20 @@ import { useCallback } from 'react';
|
|||||||
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||||
import { NumberSetting } from '@/components/settings/NumberSetting.tsx';
|
import { NumberSetting } from '@/components/settings/NumberSetting.tsx';
|
||||||
import { getPersistedServerSetting, usePersistedValue } from '@/util/usePersistedValue.tsx';
|
import { getPersistedServerSetting, usePersistedValue } from '@/util/usePersistedValue.tsx';
|
||||||
|
import { ServerSettings } from '@/typings.ts';
|
||||||
|
|
||||||
const DEFAULT_INTERVAL_HOURS = 12;
|
const DEFAULT_INTERVAL_HOURS = 12;
|
||||||
const MIN_INTERVAL_HOURS = 6;
|
const MIN_INTERVAL_HOURS = 6;
|
||||||
const MAX_INTERVAL_HOURS = 24 * 7 * 4; // 1 month
|
const MAX_INTERVAL_HOURS = 24 * 7 * 4; // 1 month
|
||||||
|
|
||||||
export const GlobalUpdateSettingsInterval = () => {
|
export const GlobalUpdateSettingsInterval = ({
|
||||||
|
globalUpdateInterval,
|
||||||
|
}: {
|
||||||
|
globalUpdateInterval: ServerSettings['globalUpdateInterval'];
|
||||||
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const { data } = requestManager.useGetServerSettings();
|
const autoUpdateIntervalHours = globalUpdateInterval;
|
||||||
const autoUpdateIntervalHours = data?.settings.globalUpdateInterval;
|
|
||||||
const doAutoUpdates = !!autoUpdateIntervalHours;
|
const doAutoUpdates = !!autoUpdateIntervalHours;
|
||||||
const [mutateSettings] = requestManager.useUpdateServerSettings();
|
const [mutateSettings] = requestManager.useUpdateServerSettings();
|
||||||
const [currentAutoUpdateIntervalHours, persistAutoUpdateIntervalHours] = usePersistedValue(
|
const [currentAutoUpdateIntervalHours, persistAutoUpdateIntervalHours] = usePersistedValue(
|
||||||
@@ -35,18 +39,18 @@ export const GlobalUpdateSettingsInterval = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const updateSetting = useCallback(
|
const updateSetting = useCallback(
|
||||||
(globalUpdateInterval: number) => {
|
(newGlobalUpdateInterval: number) => {
|
||||||
persistAutoUpdateIntervalHours(
|
persistAutoUpdateIntervalHours(
|
||||||
globalUpdateInterval === 0 ? currentAutoUpdateIntervalHours : globalUpdateInterval,
|
newGlobalUpdateInterval === 0 ? currentAutoUpdateIntervalHours : newGlobalUpdateInterval,
|
||||||
);
|
);
|
||||||
mutateSettings({ variables: { input: { settings: { globalUpdateInterval } } } });
|
mutateSettings({ variables: { input: { settings: { globalUpdateInterval: newGlobalUpdateInterval } } } });
|
||||||
},
|
},
|
||||||
[currentAutoUpdateIntervalHours],
|
[currentAutoUpdateIntervalHours],
|
||||||
);
|
);
|
||||||
|
|
||||||
const setDoAutoUpdates = (enable: boolean) => {
|
const setDoAutoUpdates = (enable: boolean) => {
|
||||||
const globalUpdateInterval = enable ? currentAutoUpdateIntervalHours : 0;
|
const newGlobalUpdateInterval = enable ? currentAutoUpdateIntervalHours : 0;
|
||||||
updateSetting(globalUpdateInterval);
|
updateSetting(newGlobalUpdateInterval);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -15,16 +15,21 @@ import { useCallback } from 'react';
|
|||||||
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||||
import { NumberSetting } from '@/components/settings/NumberSetting.tsx';
|
import { NumberSetting } from '@/components/settings/NumberSetting.tsx';
|
||||||
import { getPersistedServerSetting, usePersistedValue } from '@/util/usePersistedValue.tsx';
|
import { getPersistedServerSetting, usePersistedValue } from '@/util/usePersistedValue.tsx';
|
||||||
|
import { ServerSettings } from '@/typings.ts';
|
||||||
|
|
||||||
const DEFAULT_VALUE = 23;
|
const DEFAULT_VALUE = 23;
|
||||||
const MIN_VALUE = 1;
|
const MIN_VALUE = 1;
|
||||||
const MAX_VALUE = 23; // 1 month
|
const MAX_VALUE = 23; // 1 month
|
||||||
|
|
||||||
export const WebUIUpdateIntervalSetting = ({ disabled = false }: { disabled?: boolean }) => {
|
export const WebUIUpdateIntervalSetting = ({
|
||||||
|
disabled = false,
|
||||||
|
updateCheckInterval,
|
||||||
|
}: {
|
||||||
|
disabled?: boolean;
|
||||||
|
updateCheckInterval: ServerSettings['webUIUpdateCheckInterval'];
|
||||||
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const { data } = requestManager.useGetServerSettings();
|
|
||||||
const updateCheckInterval = data?.settings.webUIUpdateCheckInterval;
|
|
||||||
const shouldAutoUpdate = !!updateCheckInterval;
|
const shouldAutoUpdate = !!updateCheckInterval;
|
||||||
const [mutateSettings] = requestManager.useUpdateServerSettings();
|
const [mutateSettings] = requestManager.useUpdateServerSettings();
|
||||||
const [currentUpdateCheckInterval, persistUpdateCheckInterval] = usePersistedValue(
|
const [currentUpdateCheckInterval, persistUpdateCheckInterval] = usePersistedValue(
|
||||||
|
|||||||
@@ -11,7 +11,10 @@ import { TCategory } from '@/typings.ts';
|
|||||||
export const DEFAULT_CATEGORY_ID = 0;
|
export const DEFAULT_CATEGORY_ID = 0;
|
||||||
|
|
||||||
export type CategoryIdInfo = Pick<TCategory, 'id'>;
|
export type CategoryIdInfo = Pick<TCategory, 'id'>;
|
||||||
|
export type CategoryNameInfo = Pick<TCategory, 'name'>;
|
||||||
export type CategoryDefaultInfo = Pick<TCategory, 'default'>;
|
export type CategoryDefaultInfo = Pick<TCategory, 'default'>;
|
||||||
|
export type CategoryUpdateInclusionInfo = Pick<TCategory, 'includeInUpdate'>;
|
||||||
|
export type CategoryDownloadInclusionInfo = Pick<TCategory, 'includeInDownload'>;
|
||||||
|
|
||||||
export class Categories {
|
export class Categories {
|
||||||
static getIds(categories: CategoryIdInfo[]): number[] {
|
static getIds(categories: CategoryIdInfo[]): number[] {
|
||||||
|
|||||||
@@ -65,12 +65,48 @@ export const DownloadSettings = () => {
|
|||||||
};
|
};
|
||||||
}, [t]);
|
}, [t]);
|
||||||
|
|
||||||
const { data, loading, error, refetch } = requestManager.useGetServerSettings({
|
const categories = requestManager.useGetCategories();
|
||||||
notifyOnNetworkStatusChange: true,
|
const serverSettings = requestManager.useGetServerSettings({ notifyOnNetworkStatusChange: true });
|
||||||
});
|
|
||||||
const downloadSettings = data ? extractDownloadSettings(data.settings) : undefined;
|
|
||||||
const [mutateSettings] = requestManager.useUpdateServerSettings();
|
const [mutateSettings] = requestManager.useUpdateServerSettings();
|
||||||
const { settings: metadataSettings } = useMetadataServerSettings();
|
const {
|
||||||
|
settings: metadataSettings,
|
||||||
|
loading: areMetadataServerSettingsLoading,
|
||||||
|
request: { error: metadataServerSettingsError, refetch: refetchMetadataServerSettings },
|
||||||
|
} = useMetadataServerSettings();
|
||||||
|
|
||||||
|
const loading = serverSettings.loading || areMetadataServerSettingsLoading || categories.loading;
|
||||||
|
if (loading) {
|
||||||
|
return <LoadingPlaceholder />;
|
||||||
|
}
|
||||||
|
|
||||||
|
const error = serverSettings.error ?? metadataServerSettingsError ?? categories.error;
|
||||||
|
if (error) {
|
||||||
|
return (
|
||||||
|
<EmptyView
|
||||||
|
message={t('global.error.label.failed_to_load_data')}
|
||||||
|
messageExtra={error.message}
|
||||||
|
retry={() => {
|
||||||
|
if (serverSettings.error) {
|
||||||
|
serverSettings
|
||||||
|
.refetch()
|
||||||
|
.catch(defaultPromiseErrorHandler('DownloadSettings::refetchServerSettings'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (metadataServerSettingsError) {
|
||||||
|
refetchMetadataServerSettings().catch(
|
||||||
|
defaultPromiseErrorHandler('refetchMetadataServerSettings::'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (categories.error) {
|
||||||
|
categories.refetch().catch(defaultPromiseErrorHandler('LibrarySettings::refetchCategories'));
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const downloadSettings = extractDownloadSettings(serverSettings.data!.settings);
|
||||||
|
|
||||||
const updateSetting = <Setting extends keyof DownloadSettingsType>(
|
const updateSetting = <Setting extends keyof DownloadSettingsType>(
|
||||||
setting: Setting,
|
setting: Setting,
|
||||||
@@ -85,20 +121,6 @@ export const DownloadSettings = () => {
|
|||||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error'),
|
makeToast(t('global.error.label.failed_to_save_changes'), 'error'),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (loading) {
|
|
||||||
return <LoadingPlaceholder />;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
return (
|
|
||||||
<EmptyView
|
|
||||||
message={t('global.error.label.failed_to_load_data')}
|
|
||||||
messageExtra={error.message}
|
|
||||||
retry={() => refetch().catch(defaultPromiseErrorHandler('DownloadSettings::refetch'))}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<List>
|
<List>
|
||||||
<TextSetting
|
<TextSetting
|
||||||
@@ -204,6 +226,7 @@ export const DownloadSettings = () => {
|
|||||||
/>
|
/>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
<CategoriesInclusionSetting
|
<CategoriesInclusionSetting
|
||||||
|
categories={categories.data!.categories.nodes}
|
||||||
includeField="includeInDownload"
|
includeField="includeInDownload"
|
||||||
dialogText={t('download.settings.auto_download.categories.label.include_in_download')}
|
dialogText={t('download.settings.auto_download.categories.label.include_in_download')}
|
||||||
/>
|
/>
|
||||||
@@ -215,7 +238,7 @@ export const DownloadSettings = () => {
|
|||||||
</ListSubheader>
|
</ListSubheader>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<DownloadAheadSetting />
|
<DownloadAheadSetting downloadAheadLimit={metadataSettings.downloadAheadLimit} />
|
||||||
</List>
|
</List>
|
||||||
</List>
|
</List>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -25,6 +25,9 @@ import {
|
|||||||
} from '@/lib/metadata/metadataServerSettings.ts';
|
} from '@/lib/metadata/metadataServerSettings.ts';
|
||||||
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||||
import { Mangas } from '@/lib/data/Mangas.ts';
|
import { Mangas } from '@/lib/data/Mangas.ts';
|
||||||
|
import { EmptyView } from '@/components/util/EmptyView';
|
||||||
|
import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts';
|
||||||
|
import { LoadingPlaceholder } from '@/components/util/LoadingPlaceholder.tsx';
|
||||||
|
|
||||||
const removeNonLibraryMangasFromCategories = async (): Promise<void> => {
|
const removeNonLibraryMangasFromCategories = async (): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
@@ -61,12 +64,50 @@ export function LibrarySettings() {
|
|||||||
|
|
||||||
useSetDefaultBackTo('settings');
|
useSetDefaultBackTo('settings');
|
||||||
|
|
||||||
const { settings } = useMetadataServerSettings();
|
const categories = requestManager.useGetCategories();
|
||||||
|
const serverSettings = requestManager.useGetServerSettings({ notifyOnNetworkStatusChange: true });
|
||||||
|
const {
|
||||||
|
settings,
|
||||||
|
loading: areMetadataServerSettingsLoading,
|
||||||
|
request: { error: metadataServerSettingsError, refetch: refetchMetadataServerSettings },
|
||||||
|
} = useMetadataServerSettings();
|
||||||
|
|
||||||
const setSettingValue = createUpdateMetadataServerSettings<keyof MetadataLibrarySettings>(() =>
|
const setSettingValue = createUpdateMetadataServerSettings<keyof MetadataLibrarySettings>(() =>
|
||||||
makeToast(t('search.error.label.failed_to_save_settings'), 'warning'),
|
makeToast(t('search.error.label.failed_to_save_settings'), 'warning'),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const loading = serverSettings.loading || areMetadataServerSettingsLoading || categories.loading;
|
||||||
|
if (loading) {
|
||||||
|
return <LoadingPlaceholder />;
|
||||||
|
}
|
||||||
|
|
||||||
|
const error = serverSettings.error ?? metadataServerSettingsError ?? categories.error;
|
||||||
|
if (error) {
|
||||||
|
return (
|
||||||
|
<EmptyView
|
||||||
|
message={t('global.error.label.failed_to_load_data')}
|
||||||
|
messageExtra={error.message}
|
||||||
|
retry={() => {
|
||||||
|
if (serverSettings.error) {
|
||||||
|
serverSettings
|
||||||
|
?.refetch()
|
||||||
|
.catch(defaultPromiseErrorHandler('LibrarySettings::refetchServerSettings'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (metadataServerSettingsError) {
|
||||||
|
refetchMetadataServerSettings().catch(
|
||||||
|
defaultPromiseErrorHandler('LibrarySettings::refetchMetadataServerSettings'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (categories.error) {
|
||||||
|
categories.refetch().catch(defaultPromiseErrorHandler('LibrarySettings::refetchCategories'));
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<List>
|
<List>
|
||||||
<List
|
<List
|
||||||
@@ -112,7 +153,10 @@ export function LibrarySettings() {
|
|||||||
/>
|
/>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
</List>
|
</List>
|
||||||
<GlobalUpdateSettings />
|
<GlobalUpdateSettings
|
||||||
|
serverSettings={serverSettings.data!.settings}
|
||||||
|
categories={categories.data!.categories.nodes}
|
||||||
|
/>
|
||||||
<List
|
<List
|
||||||
subheader={
|
subheader={
|
||||||
<ListSubheader component="div" id="library-advanced">
|
<ListSubheader component="div" id="library-advanced">
|
||||||
|
|||||||
Reference in New Issue
Block a user