Include actual error in snackbar
This commit is contained in:
@@ -408,6 +408,7 @@
|
||||
"disabled": "Disabled",
|
||||
"discord": "Discord",
|
||||
"display": "Display",
|
||||
"error": "Error",
|
||||
"filter": "Filter",
|
||||
"finished": "Finished",
|
||||
"footnote": "{{value}}<0>$t(global.label.asterisk)</0>",
|
||||
@@ -415,6 +416,7 @@
|
||||
"github": "GitHub",
|
||||
"hidden": "Hidden",
|
||||
"horizontal": "Horizontal",
|
||||
"info": "Information",
|
||||
"left": "Left",
|
||||
"links": "Links",
|
||||
"load_in_progress": "Still loading required data…",
|
||||
@@ -435,10 +437,12 @@
|
||||
"sort": "Sort",
|
||||
"standard": "Standard",
|
||||
"started": "Started",
|
||||
"success": "Success",
|
||||
"type": "Type",
|
||||
"unknown": "Unknown",
|
||||
"username": "Username",
|
||||
"vertical": "Vertical"
|
||||
"vertical": "Vertical",
|
||||
"warning": "Warning"
|
||||
},
|
||||
"language": {
|
||||
"label": {
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
import { ApolloError } from '@apollo/client/errors';
|
||||
|
||||
export const jsonSaveParse = <T = any>(...args: Parameters<typeof JSON.parse>): T | null => {
|
||||
try {
|
||||
return JSON.parse(...args);
|
||||
@@ -13,3 +15,19 @@ export const jsonSaveParse = <T = any>(...args: Parameters<typeof JSON.parse>):
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
export const getErrorMessage = (error: unknown): string => {
|
||||
if (error instanceof ApolloError) {
|
||||
return `${error.name}: ${error.message}`;
|
||||
}
|
||||
|
||||
if (error instanceof Error) {
|
||||
return `${error.name}: ${error.message}`;
|
||||
}
|
||||
|
||||
if (error == null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return `${error}`;
|
||||
};
|
||||
|
||||
@@ -23,6 +23,7 @@ import { ABOUT_WEBUI, WEBUI_UPDATE_CHECK } from '@/lib/graphql/fragments/InfoFra
|
||||
import { VersionUpdateInfoDialog } from '@/modules/app-updates/components/VersionUpdateInfoDialog.tsx';
|
||||
import { useUpdateChecker } from '@/modules/app-updates/hooks/useUpdateChecker.tsx';
|
||||
import { useMetadataServerSettings } from '@/modules/settings/services/ServerSettingsMetadata.ts';
|
||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||
|
||||
const disabledUpdateCheck = () => Promise.resolve();
|
||||
|
||||
@@ -136,7 +137,9 @@ export const WebUIUpdateChecker = () => {
|
||||
onAction={() =>
|
||||
requestManager
|
||||
.updateWebUI()
|
||||
.response.catch(() => makeToast(t('settings.about.webui.label.update_failure'), 'error'))
|
||||
.response.catch((e) =>
|
||||
makeToast(t('settings.about.webui.label.update_failure'), 'error', getErrorMessage(e)),
|
||||
)
|
||||
}
|
||||
actionTitle={
|
||||
isUpdateInProgress
|
||||
|
||||
@@ -36,6 +36,7 @@ import { EmptyViewAbsoluteCentered } from '@/modules/core/components/placeholder
|
||||
import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts';
|
||||
import { ServerSettings } from '@/modules/settings/Settings.types.ts';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||
|
||||
type BackupSettingsType = Pick<ServerSettings, 'backupPath' | 'backupTime' | 'backupInterval' | 'backupTTL'>;
|
||||
|
||||
@@ -101,8 +102,8 @@ export function Backup() {
|
||||
setting: Setting,
|
||||
value: BackupSettingsType[Setting],
|
||||
) => {
|
||||
mutateSettings({ variables: { input: { settings: { [setting]: value } } } }).catch(() =>
|
||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error'),
|
||||
mutateSettings({ variables: { input: { settings: { [setting]: value } } } }).catch((e) =>
|
||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error', getErrorMessage(e)),
|
||||
);
|
||||
};
|
||||
|
||||
@@ -152,7 +153,7 @@ export function Backup() {
|
||||
|
||||
return true;
|
||||
} catch (e) {
|
||||
makeToast(t('settings.backup.action.validate.error.label.failure'), 'error');
|
||||
makeToast(t('settings.backup.action.validate.error.label.failure'), 'error', getErrorMessage(e));
|
||||
resetBackupState();
|
||||
}
|
||||
|
||||
@@ -167,7 +168,7 @@ export function Backup() {
|
||||
backupRestoreId = response.data?.restoreBackup.id;
|
||||
setTriggerReRender(Date.now());
|
||||
} catch (e) {
|
||||
makeToast(t('settings.backup.action.restore.error.label.failure'), 'error');
|
||||
makeToast(t('settings.backup.action.restore.error.label.failure'), 'error', getErrorMessage(e));
|
||||
} finally {
|
||||
resetBackupState();
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts'
|
||||
import { makeToast } from '@/modules/core/utils/Toast.ts';
|
||||
import { MetadataBrowseSettings } from '@/modules/browse/Browse.types.ts';
|
||||
import { ServerSettings as GqlServerSettings } from '@/modules/settings/Settings.types.ts';
|
||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||
|
||||
type ExtensionsSettings = Pick<GqlServerSettings, 'maxSourcesInParallel' | 'localSourcePath' | 'extensionRepos'>;
|
||||
|
||||
@@ -57,16 +58,16 @@ export const BrowseSettings = () => {
|
||||
setting: Setting,
|
||||
value: ExtensionsSettings[Setting],
|
||||
) => {
|
||||
mutateSettings({ variables: { input: { settings: { [setting]: value } } } }).catch(() =>
|
||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error'),
|
||||
mutateSettings({ variables: { input: { settings: { [setting]: value } } } }).catch((e) =>
|
||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error', getErrorMessage(e)),
|
||||
);
|
||||
};
|
||||
|
||||
const {
|
||||
settings: { hideLibraryEntries },
|
||||
} = useMetadataServerSettings();
|
||||
const updateMetadataServerSettings = createUpdateMetadataServerSettings<keyof MetadataBrowseSettings>(() =>
|
||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error'),
|
||||
const updateMetadataServerSettings = createUpdateMetadataServerSettings<keyof MetadataBrowseSettings>((e) =>
|
||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error', getErrorMessage(e)),
|
||||
);
|
||||
|
||||
if (loading) {
|
||||
|
||||
@@ -28,6 +28,7 @@ import {
|
||||
CategoryNameInfo,
|
||||
CategoryUpdateInclusionInfo,
|
||||
} from '@/modules/category/Category.types.ts';
|
||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||
|
||||
type CategoryType = CategoryIdInfo & CategoryNameInfo & CategoryUpdateInclusionInfo & CategoryDownloadInclusionInfo;
|
||||
|
||||
@@ -139,8 +140,8 @@ export const CategoriesInclusionSetting = ({
|
||||
await Promise.all(categoriesToUpdate.map((category) => updateCategory(category)));
|
||||
// TODO - update cache immediately
|
||||
// mutate(categoriesEndpoint, [...dialogCategories], { revalidate: false });
|
||||
} catch (error) {
|
||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error');
|
||||
} catch (e) {
|
||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error', getErrorMessage(e));
|
||||
// mutate(categoriesEndpoint, [...categories]);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -34,6 +34,7 @@ import {
|
||||
import { GET_CATEGORIES_BASE } from '@/lib/graphql/queries/CategoryQuery.ts';
|
||||
import { GET_MANGA_CATEGORIES } from '@/lib/graphql/queries/MangaQuery.ts';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||
|
||||
type BaseProps = {
|
||||
open: boolean;
|
||||
@@ -150,8 +151,8 @@ export function CategorySelect(props: CategorySelectProps) {
|
||||
onClose(true, addToCategories, removeFromCategories);
|
||||
|
||||
if (doNotShowAddToLibraryDialogAgain) {
|
||||
updateMetadataServerSettings('showAddToLibraryCategorySelectDialog', false).catch(() =>
|
||||
makeToast(t('search.error.label.failed_to_save_settings'), 'error'),
|
||||
updateMetadataServerSettings('showAddToLibraryCategorySelectDialog', false).catch((e) =>
|
||||
makeToast(t('search.error.label.failed_to_save_settings'), 'error', getErrorMessage(e)),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import { DirectionOffset, TranslationKey } from '@/Base.types.ts';
|
||||
import { MangaIdInfo } from '@/modules/manga/Manga.types.ts';
|
||||
import { ReaderResumeMode } from '@/modules/reader/types/Reader.types.ts';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||
|
||||
export type ChapterAction = 'download' | 'delete' | 'bookmark' | 'unbookmark' | 'mark_as_read' | 'mark_as_unread';
|
||||
|
||||
@@ -279,7 +280,11 @@ export class Chapters {
|
||||
await fnToExecute();
|
||||
makeToast(translate(actionToTranslationKey[action].success, { count: itemCount }), 'success');
|
||||
} catch (e) {
|
||||
makeToast(translate(actionToTranslationKey[action].error, { count: itemCount }), 'error');
|
||||
makeToast(
|
||||
translate(actionToTranslationKey[action].error, { count: itemCount }),
|
||||
'error',
|
||||
getErrorMessage(e),
|
||||
);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import { dateTimeFormatter } from '@/util/DateHelper.ts';
|
||||
import { MediaQuery } from '@/modules/core/utils/MediaQuery.tsx';
|
||||
|
||||
import { CategoryIdInfo } from '@/modules/category/Category.types.ts';
|
||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||
|
||||
const calcProgress = (status: UpdaterSubscription['updateStatusChanged'] | undefined) => {
|
||||
if (!status) {
|
||||
@@ -93,7 +94,7 @@ export function UpdateChecker({
|
||||
reFetchLastTimestamp().catch(defaultPromiseErrorHandler('UpdateChecker::reFetchLastTimestamp'));
|
||||
} catch (e) {
|
||||
lastRunningState = false;
|
||||
makeToast(t('global.error.label.update_failed'), 'error');
|
||||
makeToast(t('global.error.label.update_failed'), 'error', getErrorMessage(e));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -101,7 +102,7 @@ export function UpdateChecker({
|
||||
try {
|
||||
await requestManager.resetGlobalUpdate();
|
||||
} catch (e) {
|
||||
makeToast(t('library.error.label.stop_global_update'), 'error');
|
||||
makeToast(t('library.error.label.stop_global_update'), 'error', getErrorMessage(e));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (C) Contributors to the Suwayomi project
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
import { CustomContentProps, SnackbarContent, VariantType } from 'notistack';
|
||||
import { ForwardedRef, forwardRef, memo } from 'react';
|
||||
import Alert from '@mui/material/Alert';
|
||||
import AlertTitle from '@mui/material/AlertTitle';
|
||||
import Button from '@mui/material/Button';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { awaitConfirmation } from '@/modules/core/utils/AwaitableDialog.tsx';
|
||||
import { TranslationKey } from '@/Base.types.ts';
|
||||
import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts';
|
||||
|
||||
const MAX_DESCRIPTION_LENGTH = 255;
|
||||
|
||||
const SNACKBAR_VARIANT_TO_TRANSLATION_KEY: Record<VariantType, TranslationKey> = {
|
||||
default: 'global.label.info',
|
||||
info: 'global.label.info',
|
||||
success: 'global.label.success',
|
||||
warning: 'global.label.warning',
|
||||
error: 'global.label.error',
|
||||
};
|
||||
|
||||
export const SnackbarWithDescription = memo(
|
||||
forwardRef(
|
||||
(
|
||||
{
|
||||
id,
|
||||
message,
|
||||
description,
|
||||
variant,
|
||||
action,
|
||||
}: CustomContentProps & {
|
||||
// eslint-disable-next-line react/no-unused-prop-types
|
||||
description?: string;
|
||||
},
|
||||
ref: ForwardedRef<HTMLDivElement>,
|
||||
) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const severity = variant === 'default' ? undefined : variant;
|
||||
const finalAction = typeof action === 'function' ? action(id) : action;
|
||||
|
||||
const isDescriptionTooLong = (description?.length ?? 0) > MAX_DESCRIPTION_LENGTH;
|
||||
const actualDescription = isDescriptionTooLong
|
||||
? description?.slice(0, MAX_DESCRIPTION_LENGTH)
|
||||
: description;
|
||||
|
||||
return (
|
||||
<SnackbarContent ref={ref}>
|
||||
<Alert severity={severity} action={finalAction}>
|
||||
<AlertTitle>{message}</AlertTitle>
|
||||
{actualDescription}{' '}
|
||||
{isDescriptionTooLong ? (
|
||||
<Button
|
||||
onClick={() => {
|
||||
awaitConfirmation({
|
||||
title:
|
||||
typeof message === 'string'
|
||||
? message
|
||||
: t(SNACKBAR_VARIANT_TO_TRANSLATION_KEY[variant]),
|
||||
message: description ?? '',
|
||||
actions: {
|
||||
cancel: { show: false },
|
||||
confirm: { title: t('global.label.close') },
|
||||
},
|
||||
}).catch(
|
||||
defaultPromiseErrorHandler(
|
||||
`SnackbarWidthDescription: ${id} - ${message} - ${description}`,
|
||||
),
|
||||
);
|
||||
}}
|
||||
size="small"
|
||||
>
|
||||
{t('global.button.show_more')}
|
||||
</Button>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
</Alert>
|
||||
</SnackbarContent>
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
@@ -26,6 +26,7 @@ import { useMetadataServerSettings } from '@/modules/settings/services/ServerSet
|
||||
import { ReaderContextProvider } from '@/modules/reader/contexts/ReaderContextProvider.tsx';
|
||||
import { DIRECTION_TO_CACHE } from '@/modules/theme/ThemeDirectionCache.ts';
|
||||
import { AppHotkeysProvider } from '@/modules/hotkeys/contexts/AppHotkeysProvider.tsx';
|
||||
import { SnackbarWithDescription } from '@/modules/core/components/snackbar/SnackbarWithDescription.tsx';
|
||||
|
||||
interface Props {
|
||||
children: React.ReactNode;
|
||||
@@ -84,7 +85,15 @@ export const AppContext: React.FC<Props> = ({ children }) => {
|
||||
<LibraryOptionsContextProvider>
|
||||
<NavBarContextProvider>
|
||||
<ActiveDeviceContextProvider>
|
||||
<SnackbarProvider>
|
||||
<SnackbarProvider
|
||||
Components={{
|
||||
default: SnackbarWithDescription,
|
||||
info: SnackbarWithDescription,
|
||||
success: SnackbarWithDescription,
|
||||
warning: SnackbarWithDescription,
|
||||
error: SnackbarWithDescription,
|
||||
}}
|
||||
>
|
||||
<ReaderContextProvider>
|
||||
<AppHotkeysProvider>{children}</AppHotkeysProvider>
|
||||
</ReaderContextProvider>
|
||||
|
||||
@@ -8,12 +8,21 @@
|
||||
|
||||
import { enqueueSnackbar, OptionsObject, SnackbarKey } from 'notistack';
|
||||
|
||||
export function makeToast(message: string, severity?: OptionsObject['variant']): SnackbarKey;
|
||||
export function makeToast(message: string, options?: OptionsObject): SnackbarKey;
|
||||
export function makeToast(message: string, options: OptionsObject['variant'] | OptionsObject = 'default'): SnackbarKey {
|
||||
if (typeof options === 'string') {
|
||||
return enqueueSnackbar(message, { variant: options });
|
||||
}
|
||||
export function makeToast(message: string, severity?: OptionsObject['variant'], description?: string): SnackbarKey;
|
||||
export function makeToast(message: string, options?: OptionsObject, description?: string): SnackbarKey;
|
||||
export function makeToast(
|
||||
message: string,
|
||||
options: OptionsObject['variant'] | OptionsObject = 'default',
|
||||
description?: string,
|
||||
): SnackbarKey {
|
||||
const variant = typeof options === 'string' ? options : undefined;
|
||||
const snackbarOptions = typeof options === 'object' ? options : {};
|
||||
|
||||
return enqueueSnackbar(message, options);
|
||||
return enqueueSnackbar(message, {
|
||||
variant,
|
||||
...snackbarOptions,
|
||||
// @ts-ignore - TS2353, "notistack" is outdated and the provided way to define custom props is not working, however,
|
||||
// everything in the options object gets passed to the custom snackbar component
|
||||
description,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import { EmptyViewAbsoluteCentered } from '@/modules/core/components/placeholder
|
||||
import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts';
|
||||
import { DEFAULT_DEVICE } from '@/modules/device/services/Device.ts';
|
||||
import { MetadataServerSettingKeys, MetadataServerSettings } from '@/modules/settings/Settings.types.ts';
|
||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||
|
||||
export const DeviceSetting = () => {
|
||||
const { t } = useTranslation();
|
||||
@@ -63,8 +64,8 @@ export const DeviceSetting = () => {
|
||||
setActiveDevice(DEFAULT_DEVICE);
|
||||
}
|
||||
|
||||
updateMetadataServerSettings(setting, value).catch(() =>
|
||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error'),
|
||||
updateMetadataServerSettings(setting, value).catch((e) =>
|
||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error', getErrorMessage(e)),
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import { updateMetadataServerSettings } from '@/modules/settings/services/Server
|
||||
import { makeToast } from '@/modules/core/utils/Toast.ts';
|
||||
import { MetadataDownloadSettings } from '@/modules/downloads/Downloads.types.ts';
|
||||
import { MetadataServerSettings } from '@/modules/settings/Settings.types.ts';
|
||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||
|
||||
const MIN_LIMIT = 2;
|
||||
const MAX_LIMIT = 10;
|
||||
@@ -39,8 +40,8 @@ export const DownloadAheadSetting = ({
|
||||
|
||||
const updateSetting = (value: MetadataDownloadSettings['downloadAheadLimit']) => {
|
||||
persistDownloadAheadLimit(value === 0 ? currentDownloadAheadLimit : value);
|
||||
updateMetadataServerSettings('downloadAheadLimit', value).catch(() =>
|
||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error'),
|
||||
updateMetadataServerSettings('downloadAheadLimit', value).catch((e) =>
|
||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error', getErrorMessage(e)),
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts'
|
||||
import { ChapterDownloadStatus, ChapterIdInfo } from '@/modules/chapter/services/Chapters.ts';
|
||||
import { DownloaderState, DownloadState } from '@/lib/graphql/generated/graphql.ts';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||
|
||||
const HeightPreservingItem = ({ children, ...props }: BoxProps) => (
|
||||
// the height is necessary to prevent the item container from collapsing, which confuses Virtuoso measurements
|
||||
@@ -141,7 +142,7 @@ export const DownloadQueue: React.FC = () => {
|
||||
try {
|
||||
await requestManager.clearDownloads().response;
|
||||
} catch (e) {
|
||||
makeToast(t('download.queue.error.label.failed_delete_all'), 'error');
|
||||
makeToast(t('download.queue.error.label.failed_delete_all'), 'error', getErrorMessage(e));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -216,7 +217,7 @@ export const DownloadQueue: React.FC = () => {
|
||||
try {
|
||||
await requestManager.addChapterToDownloadQueue(chapter.id).response;
|
||||
} catch (e) {
|
||||
makeToast(t('download.queue.error.label.failed_to_remove'), 'error');
|
||||
makeToast(t('download.queue.error.label.failed_to_remove'), 'error', getErrorMessage(e));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -237,7 +238,7 @@ export const DownloadQueue: React.FC = () => {
|
||||
requestManager.deleteDownloadedChapter(chapter.id).response,
|
||||
]);
|
||||
} catch (e) {
|
||||
makeToast(t('download.queue.error.label.failed_to_retry'), 'error');
|
||||
makeToast(t('download.queue.error.label.failed_to_retry'), 'error', getErrorMessage(e));
|
||||
}
|
||||
|
||||
if (!isRunning) {
|
||||
|
||||
@@ -32,6 +32,7 @@ import { GetCategoriesSettingsQuery, GetCategoriesSettingsQueryVariables } from
|
||||
import { GET_CATEGORIES_SETTINGS } from '@/lib/graphql/queries/CategoryQuery.ts';
|
||||
import { MetadataDownloadSettings } from '@/modules/downloads/Downloads.types.ts';
|
||||
import { ServerSettings } from '@/modules/settings/Settings.types.ts';
|
||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||
|
||||
type DownloadSettingsType = Pick<
|
||||
ServerSettings,
|
||||
@@ -115,13 +116,13 @@ export const DownloadSettings = () => {
|
||||
setting: Setting,
|
||||
value: DownloadSettingsType[Setting],
|
||||
) => {
|
||||
mutateSettings({ variables: { input: { settings: { [setting]: value } } } }).catch(() =>
|
||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error'),
|
||||
mutateSettings({ variables: { input: { settings: { [setting]: value } } } }).catch((e) =>
|
||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error', getErrorMessage(e)),
|
||||
);
|
||||
};
|
||||
|
||||
const updateMetadataSetting = createUpdateMetadataServerSettings<keyof MetadataDownloadSettings>(() =>
|
||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error'),
|
||||
const updateMetadataSetting = createUpdateMetadataServerSettings<keyof MetadataDownloadSettings>((e) =>
|
||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error', getErrorMessage(e)),
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -32,6 +32,7 @@ import {
|
||||
INSTALLED_STATE_TO_TRANSLATION_KEY_MAP,
|
||||
} from '@/modules/extension/Extensions.constants.ts';
|
||||
import { getInstalledState } from '@/modules/extension/Extensions.utils.ts';
|
||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||
|
||||
interface IProps {
|
||||
extension: TExtension;
|
||||
@@ -84,7 +85,11 @@ export function ExtensionCard(props: IProps) {
|
||||
handleUpdate();
|
||||
} catch (e) {
|
||||
setInstalledState(getInstalledState(isInstalled, isObsolete, hasUpdate));
|
||||
makeToast(t(EXTENSION_ACTION_TO_FAILURE_TRANSLATION_KEY_MAP[action], { count: 1 }), 'error');
|
||||
makeToast(
|
||||
t(EXTENSION_ACTION_TO_FAILURE_TRANSLATION_KEY_MAP[action], { count: 1 }),
|
||||
'error',
|
||||
getErrorMessage(e),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ import {
|
||||
import { ExtensionAction, ExtensionGroupState, ExtensionState } from '@/modules/extension/Extensions.types.ts';
|
||||
import { EXTENSION_ACTION_TO_FAILURE_TRANSLATION_KEY_MAP } from '@/modules/extension/Extensions.constants.ts';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||
|
||||
const LANGUAGE = 0;
|
||||
const EXTENSIONS = 1;
|
||||
@@ -123,7 +124,7 @@ export function Extensions({ tabsMenuHeight }: { tabsMenuHeight: number }) {
|
||||
handleExtensionUpdate();
|
||||
makeToast(t('extension.label.installed_successfully'), 'success');
|
||||
})
|
||||
.catch(() => makeToast(t('extension.label.installation_failed'), 'error'));
|
||||
.catch((e) => makeToast(t('extension.label.installation_failed'), 'error', getErrorMessage(e)));
|
||||
} else {
|
||||
makeToast(t('global.error.label.invalid_file_type'), 'error');
|
||||
}
|
||||
@@ -263,7 +264,7 @@ export function Extensions({ tabsMenuHeight }: { tabsMenuHeight: number }) {
|
||||
requestManager
|
||||
.updateExtensions(extensionIds, { update: true })
|
||||
.response.then(() => handleExtensionUpdate())
|
||||
.catch(() =>
|
||||
.catch((e) =>
|
||||
makeToast(
|
||||
t(
|
||||
EXTENSION_ACTION_TO_FAILURE_TRANSLATION_KEY_MAP[
|
||||
@@ -271,6 +272,8 @@ export function Extensions({ tabsMenuHeight }: { tabsMenuHeight: number }) {
|
||||
],
|
||||
{ count: groupedExtensions.length },
|
||||
),
|
||||
'error',
|
||||
getErrorMessage(e),
|
||||
),
|
||||
)
|
||||
.finally(() => setUpdatingExtensionIds([]));
|
||||
|
||||
@@ -29,6 +29,7 @@ import { LibrarySortMode } from '@/modules/library/Library.types.ts';
|
||||
import { CategoryMetadataInfo } from '@/modules/category/Category.types.ts';
|
||||
import { statusToTranslationKey } from '@/modules/manga/Manga.constants.ts';
|
||||
import { GridLayout } from '@/modules/core/Core.types.ts';
|
||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||
|
||||
const TITLES: { [key in 'filter' | 'sort' | 'display']: TranslationKey } = {
|
||||
filter: 'global.label.filter',
|
||||
@@ -61,15 +62,15 @@ export const LibraryOptionsPanel = ({
|
||||
const loggedInTrackers = Trackers.getLoggedIn(trackerList.data?.trackers.nodes ?? []);
|
||||
|
||||
const categoryLibraryOptions = useGetCategoryMetadata(category);
|
||||
const updateCategoryLibraryOptions = createUpdateCategoryMetadata(category, () =>
|
||||
makeToast(t('global.error.label.failed_to_save_changes', 'error')),
|
||||
const updateCategoryLibraryOptions = createUpdateCategoryMetadata(category, (e) =>
|
||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error', getErrorMessage(e)),
|
||||
);
|
||||
|
||||
const {
|
||||
settings: { showTabSize },
|
||||
} = useMetadataServerSettings();
|
||||
const setSettingValue = createUpdateMetadataServerSettings<'showTabSize'>(() =>
|
||||
makeToast(t('search.error.label.failed_to_save_settings'), 'warning'),
|
||||
const setSettingValue = createUpdateMetadataServerSettings<'showTabSize'>((e) =>
|
||||
makeToast(t('search.error.label.failed_to_save_settings'), 'error', getErrorMessage(e)),
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -38,6 +38,7 @@ import { GET_CATEGORIES_SETTINGS } from '@/lib/graphql/queries/CategoryQuery.ts'
|
||||
import { GET_MANGAS_BASE } from '@/lib/graphql/queries/MangaQuery.ts';
|
||||
import { MetadataLibrarySettings } from '@/modules/library/Library.types.ts';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||
|
||||
const removeNonLibraryMangasFromCategories = async (): Promise<void> => {
|
||||
try {
|
||||
@@ -57,7 +58,7 @@ const removeNonLibraryMangasFromCategories = async (): Promise<void> => {
|
||||
}
|
||||
makeToast(translate('library.settings.advanced.database.cleanup.label.success'), 'success');
|
||||
} catch (e) {
|
||||
makeToast(translate('library.settings.advanced.database.cleanup.label.error'), 'error');
|
||||
makeToast(translate('library.settings.advanced.database.cleanup.label.error'), 'error', getErrorMessage(e));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -85,8 +86,8 @@ export function LibrarySettings() {
|
||||
request: { error: metadataServerSettingsError, refetch: refetchMetadataServerSettings },
|
||||
} = useMetadataServerSettings();
|
||||
|
||||
const setSettingValue = createUpdateMetadataServerSettings<keyof MetadataLibrarySettings>(() =>
|
||||
makeToast(t('search.error.label.failed_to_save_settings'), 'warning'),
|
||||
const setSettingValue = createUpdateMetadataServerSettings<keyof MetadataLibrarySettings>((e) =>
|
||||
makeToast(t('search.error.label.failed_to_save_settings'), 'error', getErrorMessage(e)),
|
||||
);
|
||||
|
||||
const loading = serverSettings.loading || areMetadataServerSettingsLoading || categories.loading;
|
||||
|
||||
@@ -35,7 +35,7 @@ export const TrackMangaButton = ({ manga }: { manga: MangaTrackRecordInfo & Pick
|
||||
|
||||
const handleClick = (openPopup: () => void) => {
|
||||
if (trackerList.error) {
|
||||
makeToast(t('tracking.error.label.could_not_load_track_info'), 'error');
|
||||
makeToast(t('tracking.error.label.could_not_load_track_info'), 'error', trackerList.error?.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import { awaitConfirmation } from '@/modules/core/utils/AwaitableDialog.tsx';
|
||||
import { GetCategoriesBaseQuery, GetCategoriesBaseQueryVariables, MangaType } from '@/lib/graphql/generated/graphql.ts';
|
||||
import { GET_CATEGORIES_BASE } from '@/lib/graphql/queries/CategoryQuery.ts';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||
|
||||
export const useManageMangaLibraryState = (
|
||||
manga: Pick<MangaType, 'id' | 'title'> & Partial<Pick<MangaType, 'inLibrary'>>,
|
||||
@@ -44,8 +45,8 @@ export const useManageMangaLibraryState = (
|
||||
})
|
||||
.response.then(() => makeToast(t('library.info.label.added_to_library'), 'success'))
|
||||
.then(() => setIsInLibrary(true))
|
||||
.catch(() => {
|
||||
makeToast(t('library.error.label.add_to_library'), 'error');
|
||||
.catch((e) => {
|
||||
makeToast(t('library.error.label.add_to_library'), 'error', getErrorMessage(e));
|
||||
});
|
||||
},
|
||||
[manga.id],
|
||||
@@ -86,7 +87,7 @@ export const useManageMangaLibraryState = (
|
||||
showAddToLibraryCategorySelectDialog = (await getMetadataServerSettings())
|
||||
.showAddToLibraryCategorySelectDialog;
|
||||
} catch (e) {
|
||||
makeToast(t('global.error.label.failed_to_load_data'), 'error');
|
||||
makeToast(t('global.error.label.failed_to_load_data'), 'error', getErrorMessage(e));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -101,7 +102,7 @@ export const useManageMangaLibraryState = (
|
||||
GetCategoriesBaseQueryVariables
|
||||
>(GET_CATEGORIES_BASE).response;
|
||||
} catch (e) {
|
||||
makeToast(t('category.error.label.request_failure'), 'error');
|
||||
makeToast(t('category.error.label.request_failure'), 'error', getErrorMessage(e));
|
||||
return;
|
||||
}
|
||||
const userCreatedCategories = Categories.getUserCreated(categories.data.categories.nodes);
|
||||
|
||||
@@ -34,6 +34,7 @@ import {
|
||||
MigrateMode,
|
||||
} from '@/modules/manga/Manga.types.ts';
|
||||
import { actionToTranslationKey } from '@/modules/manga/Manga.constants.ts';
|
||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||
|
||||
type MangaToMigrate = NonNullable<GetMangaToMigrateQuery['manga']>;
|
||||
type MangaToMigrateTo = NonNullable<GetMangaToMigrateToFetchMutation['fetchManga']>['manga'];
|
||||
@@ -481,7 +482,11 @@ export class Mangas {
|
||||
await fnToExecute();
|
||||
makeToast(translate(actionToTranslationKey[action].success, { count: itemCount }), 'success');
|
||||
} catch (e) {
|
||||
makeToast(translate(actionToTranslationKey[action].error, { count: itemCount }), 'error');
|
||||
makeToast(
|
||||
translate(actionToTranslationKey[action].error, { count: itemCount }),
|
||||
'error',
|
||||
getErrorMessage(e),
|
||||
);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import {
|
||||
} from '@/modules/settings/services/ServerSettingsMetadata.ts';
|
||||
import { makeToast } from '@/modules/core/utils/Toast.ts';
|
||||
import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx';
|
||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||
|
||||
const getMigratableSources = (
|
||||
mangas: TMigratableSourcesResult | undefined,
|
||||
@@ -80,8 +81,8 @@ export const Migration = ({ tabsMenuHeight }: { tabsMenuHeight: number }) => {
|
||||
const {
|
||||
settings: { migrateSortSettings },
|
||||
} = useMetadataServerSettings();
|
||||
const updateMetadataServerSettings = createUpdateMetadataServerSettings<'migrateSortSettings'>(() =>
|
||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error'),
|
||||
const updateMetadataServerSettings = createUpdateMetadataServerSettings<'migrateSortSettings'>((e) =>
|
||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error', getErrorMessage(e)),
|
||||
);
|
||||
const { sortBy, sortOrder } = migrateSortSettings;
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ import {
|
||||
import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts';
|
||||
import { Queue } from '@/lib/Queue.ts';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||
|
||||
const DIRECTION_TO_INVERTED: Record<Direction, Direction> = {
|
||||
ltr: 'rtl',
|
||||
@@ -279,8 +280,12 @@ export class ReaderService {
|
||||
}
|
||||
|
||||
if (commit) {
|
||||
updateReaderSettings(manga, setting, value, isGlobal, profile).catch(() =>
|
||||
makeToast(translate('reader.settings.error.label.failed_to_save_settings'), 'error'),
|
||||
updateReaderSettings(manga, setting, value, isGlobal, profile).catch((e) =>
|
||||
makeToast(
|
||||
translate('reader.settings.error.label.failed_to_save_settings'),
|
||||
'error',
|
||||
getErrorMessage(e),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -309,8 +314,8 @@ export class ReaderService {
|
||||
const deleteSetting = isGlobalSetting
|
||||
? () => requestManager.deleteGlobalMeta(key).response
|
||||
: () => requestManager.deleteMangaMeta(manga.id, key).response;
|
||||
deleteSetting().catch(() =>
|
||||
makeToast(translate('reader.settings.error.label.failed_to_save_settings'), 'error'),
|
||||
deleteSetting().catch((e) =>
|
||||
makeToast(translate('reader.settings.error.label.failed_to_save_settings'), 'error', getErrorMessage(e)),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import { GlobalUpdateSettingsInterval } from '@/modules/settings/components/glob
|
||||
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||
import { makeToast } from '@/modules/core/utils/Toast.ts';
|
||||
import { ServerSettings } from '@/modules/settings/Settings.types.ts';
|
||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||
|
||||
type LibrarySettingsType = Pick<ServerSettings, 'updateMangas'>;
|
||||
|
||||
@@ -42,8 +43,8 @@ export const GlobalUpdateSettings = ({
|
||||
) => {
|
||||
try {
|
||||
await mutateSettings({ variables: { input: { settings: { [setting]: value } } } });
|
||||
} catch (error) {
|
||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error');
|
||||
} catch (e) {
|
||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error', getErrorMessage(e));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import { CheckboxContainer } from '@/modules/core/components/inputs/CheckboxCont
|
||||
import { CheckboxInput } from '@/modules/core/components/inputs/CheckboxInput.tsx';
|
||||
import { TranslationKey } from '@/Base.types.ts';
|
||||
import { ServerSettings } from '@/modules/settings/Settings.types.ts';
|
||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||
|
||||
type GlobalUpdateSkipEntriesSettings = Pick<
|
||||
ServerSettings,
|
||||
@@ -90,8 +91,8 @@ export const GlobalUpdateSettingsEntries = ({ serverSettings }: { serverSettings
|
||||
|
||||
try {
|
||||
await mutateSettings({ variables: { input: { settings: dialogSettings } } });
|
||||
} catch (error) {
|
||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error');
|
||||
} catch (e) {
|
||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error', getErrorMessage(e));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import { NumberSetting } from '@/modules/core/components/settings/NumberSetting.
|
||||
import { getPersistedServerSetting, usePersistedValue } from '@/modules/core/hooks/usePersistedValue.tsx';
|
||||
import { makeToast } from '@/modules/core/utils/Toast.ts';
|
||||
import { ServerSettings } from '@/modules/settings/Settings.types.ts';
|
||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||
|
||||
const DEFAULT_VALUE = 23;
|
||||
const MIN_VALUE = 1;
|
||||
@@ -45,8 +46,8 @@ export const WebUIUpdateIntervalSetting = ({
|
||||
persistUpdateCheckInterval(
|
||||
webUIUpdateCheckInterval === 0 ? currentUpdateCheckInterval : webUIUpdateCheckInterval,
|
||||
);
|
||||
mutateSettings({ variables: { input: { settings: { webUIUpdateCheckInterval } } } }).catch(() =>
|
||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error'),
|
||||
mutateSettings({ variables: { input: { settings: { webUIUpdateCheckInterval } } } }).catch((e) =>
|
||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error', getErrorMessage(e)),
|
||||
);
|
||||
},
|
||||
[currentUpdateCheckInterval],
|
||||
|
||||
@@ -34,6 +34,7 @@ import { EmptyViewAbsoluteCentered } from '@/modules/core/components/placeholder
|
||||
import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts';
|
||||
import { makeToast } from '@/modules/core/utils/Toast.ts';
|
||||
import { MetadataThemeSettings } from '@/modules/theme/AppTheme.types.ts';
|
||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||
|
||||
export const Appearance = () => {
|
||||
const { t, i18n } = useTranslation();
|
||||
@@ -54,8 +55,8 @@ export const Appearance = () => {
|
||||
settings,
|
||||
request: { loading, error, refetch },
|
||||
} = useMetadataServerSettings();
|
||||
const updateMetadataSetting = createUpdateMetadataServerSettings<keyof MetadataThemeSettings>(() =>
|
||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error'),
|
||||
const updateMetadataSetting = createUpdateMetadataServerSettings<keyof MetadataThemeSettings>((e) =>
|
||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error', getErrorMessage(e)),
|
||||
);
|
||||
|
||||
const isDarkMode =
|
||||
|
||||
@@ -31,6 +31,7 @@ import {
|
||||
import { makeToast } from '@/modules/core/utils/Toast.ts';
|
||||
import { MetadataUpdateSettings } from '@/modules/app-updates/AppUpdateChecker.types.ts';
|
||||
import { ServerSettings as GqlServerSettings } from '@/modules/settings/Settings.types.ts';
|
||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||
|
||||
type ServerSettingsType = Pick<
|
||||
GqlServerSettings,
|
||||
@@ -112,7 +113,7 @@ export const ServerSettings = () => {
|
||||
} = useMetadataServerSettings();
|
||||
const updateMetadataServerSettings = createUpdateMetadataServerSettings<
|
||||
keyof Pick<MetadataUpdateSettings, 'serverInformAvailableUpdate'>
|
||||
>(() => makeToast(t('global.error.label.failed_to_save_changes'), 'error'));
|
||||
>((e) => makeToast(t('global.error.label.failed_to_save_changes'), 'error', getErrorMessage(e)));
|
||||
|
||||
const {
|
||||
data,
|
||||
@@ -136,8 +137,8 @@ export const ServerSettings = () => {
|
||||
setting: Setting,
|
||||
value: ServerSettingsType[Setting],
|
||||
) => {
|
||||
mutateSettings({ variables: { input: { settings: { [setting]: value } } } }).catch(() =>
|
||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error'),
|
||||
mutateSettings({ variables: { input: { settings: { [setting]: value } } } }).catch((e) =>
|
||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error', getErrorMessage(e)),
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ import { NavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.t
|
||||
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||
import { makeToast } from '@/modules/core/utils/Toast.ts';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||
|
||||
export function Settings() {
|
||||
const { t } = useTranslation();
|
||||
@@ -52,7 +53,7 @@ export function Settings() {
|
||||
await triggerClearServerCache();
|
||||
makeToast(t('settings.clear_cache.label.success'), 'success');
|
||||
} catch (e) {
|
||||
makeToast(t('settings.clear_cache.label.failure'), 'error');
|
||||
makeToast(t('settings.clear_cache.label.failure'), 'error', getErrorMessage(e));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ import {
|
||||
import { makeToast } from '@/modules/core/utils/Toast.ts';
|
||||
import { MetadataUpdateSettings } from '@/modules/app-updates/AppUpdateChecker.types.ts';
|
||||
import { ServerSettings } from '@/modules/settings/Settings.types.ts';
|
||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||
|
||||
type WebUISettingsType = Pick<
|
||||
ServerSettings,
|
||||
@@ -138,7 +139,7 @@ export const WebUISettings = () => {
|
||||
} = useMetadataServerSettings();
|
||||
const updateMetadataServerSettings = createUpdateMetadataServerSettings<
|
||||
keyof Pick<MetadataUpdateSettings, 'webUIInformAvailableUpdate'>
|
||||
>(() => makeToast(t('global.error.label.failed_to_save_changes'), 'error'));
|
||||
>((e) => makeToast(t('global.error.label.failed_to_save_changes'), 'error', getErrorMessage(e)));
|
||||
|
||||
const {
|
||||
data,
|
||||
@@ -158,8 +159,8 @@ export const WebUISettings = () => {
|
||||
requestManager.graphQLClient.client.cache.evict({ fieldName: 'checkForWebUIUpdate' });
|
||||
}
|
||||
|
||||
mutateSettings({ variables: { input: { settings: { [setting]: value } } } }).catch(() =>
|
||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error'),
|
||||
mutateSettings({ variables: { input: { settings: { [setting]: value } } } }).catch((e) =>
|
||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error', getErrorMessage(e)),
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import { GetCategoriesSettingsQueryVariables, GetSourceSettingsQuery } from '@/l
|
||||
import { GET_SOURCE_SETTINGS } from '@/lib/graphql/queries/SourceQuery.ts';
|
||||
import { makeToast } from '@/modules/core/utils/Toast.ts';
|
||||
import { PreferenceProps } from '@/modules/source/Source.types.ts';
|
||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||
|
||||
function getPrefComponent(type: string) {
|
||||
switch (type) {
|
||||
@@ -73,7 +74,9 @@ export function SourceConfigure() {
|
||||
(type, value) => {
|
||||
requestManager
|
||||
.setSourcePreferences(sourceId, { position, [type]: value })
|
||||
.response.catch(() => makeToast(t('global.error.label.failed_to_save_changes'), 'error'));
|
||||
.response.catch((e) =>
|
||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error', getErrorMessage(e)),
|
||||
);
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
|
||||
@@ -52,6 +52,7 @@ import { EmptyViewAbsoluteCentered } from '@/modules/core/components/placeholder
|
||||
import { MangaIdInfo } from '@/modules/manga/Manga.types.ts';
|
||||
import { GridLayout } from '@/modules/core/Core.types.ts';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||
|
||||
const DEFAULT_SOURCE: Pick<SourceType, 'id'> = { id: '-1' };
|
||||
|
||||
@@ -290,8 +291,8 @@ export function SourceMangas() {
|
||||
|
||||
const filters = source?.filters ?? [];
|
||||
const { savedSearches = {} } = useGetSourceMetadata(source ?? DEFAULT_SOURCE);
|
||||
const updateSourceMetadata = createUpdateSourceMetadata<'savedSearches'>(source ?? { id: '-1' }, () =>
|
||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error'),
|
||||
const updateSourceMetadata = createUpdateSourceMetadata<'savedSearches'>(source ?? { id: '-1' }, (e) =>
|
||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error', getErrorMessage(e)),
|
||||
);
|
||||
|
||||
const selectSavedSearch = useCallback(
|
||||
|
||||
@@ -19,7 +19,7 @@ import DialogActions from '@mui/material/DialogActions';
|
||||
import TextField from '@mui/material/TextField';
|
||||
import Link from '@mui/material/Link';
|
||||
import { jsonrepair } from 'jsonrepair';
|
||||
import { jsonSaveParse } from '@/lib/HelperFunctions.ts';
|
||||
import { getErrorMessage, jsonSaveParse } from '@/lib/HelperFunctions.ts';
|
||||
import { AppTheme, isThemeNameUnique } from '@/modules/theme/services/AppThemes.ts';
|
||||
import {
|
||||
createUpdateMetadataServerSettings,
|
||||
@@ -203,10 +203,11 @@ export const ThemeCreationDialog = ({
|
||||
);
|
||||
bindDialogProps.onClose(e);
|
||||
})
|
||||
.catch(() =>
|
||||
.catch((updateError) =>
|
||||
makeToast(
|
||||
t(dialogModeToTranslationKey[mode].failure, { theme: theme.getName() }),
|
||||
'error',
|
||||
getErrorMessage(updateError),
|
||||
),
|
||||
)
|
||||
.finally(() => setIsCreating(false));
|
||||
|
||||
@@ -21,6 +21,7 @@ import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts'
|
||||
import { CreateThemeButton } from '@/modules/theme/components/CreateThemeButton.tsx';
|
||||
import { ThemePreview } from '@/modules/theme/components/ThemePreview.tsx';
|
||||
import { MetadataThemeSettings } from '@/modules/theme/AppTheme.types.ts';
|
||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||
|
||||
export const ThemeList = () => {
|
||||
const { t } = useTranslation();
|
||||
@@ -80,10 +81,11 @@ export const ThemeList = () => {
|
||||
'success',
|
||||
),
|
||||
)
|
||||
.catch(() =>
|
||||
.catch((e) =>
|
||||
makeToast(
|
||||
t('settings.appearance.theme.delete.failure', { theme: theme.getName() }),
|
||||
'error',
|
||||
getErrorMessage(e),
|
||||
),
|
||||
);
|
||||
}}
|
||||
|
||||
@@ -25,6 +25,7 @@ import { createTheme } from '@/modules/theme/services/ThemeCreator.ts';
|
||||
import { ThemeCreationDialog } from '@/modules/theme/components/CreateThemeDialog.tsx';
|
||||
import { makeToast } from '@/modules/core/utils/Toast.ts';
|
||||
import { TypographyMaxLines } from '@/modules/core/components/TypographyMaxLines.tsx';
|
||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||
|
||||
const ThemePreviewBadge = styled(Box)(() => ({
|
||||
width: '15px',
|
||||
@@ -93,7 +94,13 @@ export const ThemePreview = ({ theme, onDelete }: { theme: AppTheme; onDelete: (
|
||||
makeToast(t('settings.appearance.theme.select.fonts.loading'), 'info');
|
||||
loadThemeFonts(theme.muiTheme)
|
||||
.then(() => setAppTheme(theme.id))
|
||||
.catch(() => makeToast(t('settings.appearance.theme.select.fonts.error'), 'error'));
|
||||
.catch((e) =>
|
||||
makeToast(
|
||||
t('settings.appearance.theme.select.fonts.error'),
|
||||
'error',
|
||||
getErrorMessage(e),
|
||||
),
|
||||
);
|
||||
}}
|
||||
>
|
||||
<Stack sx={{ height: '100%', m: 0 }}>
|
||||
|
||||
@@ -23,6 +23,7 @@ import { GET_TRACKERS_BIND } from '@/lib/graphql/queries/TrackerQuery.ts';
|
||||
import { GET_MANGA_TRACK_RECORDS } from '@/lib/graphql/queries/MangaQuery.ts';
|
||||
import { MangaIdInfo } from '@/modules/manga/Manga.types.ts';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||
|
||||
const getTrackerMode = (id: number, trackersInUse: number[], searchModeForTracker?: number): TrackerMode => {
|
||||
if (id === searchModeForTracker) {
|
||||
@@ -78,7 +79,7 @@ export const TrackManga = ({ manga }: { manga: MangaIdInfo & Pick<MangaType, 'ti
|
||||
fetchedLatestTrackDataRef.current = true;
|
||||
Promise.all(
|
||||
mangaTrackRecords.map((trackRecord) => requestManager.fetchTrackBind(trackRecord.id).response),
|
||||
).catch(() => makeToast(t('tracking.error.label.could_not_fetch_track_info'), 'error'));
|
||||
).catch((e) => makeToast(t('tracking.error.label.could_not_fetch_track_info'), 'error', getErrorMessage(e)));
|
||||
}, [mangaTrackRecords]);
|
||||
|
||||
const trackerComponents = useMemo(
|
||||
|
||||
@@ -34,6 +34,7 @@ import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts'
|
||||
import { MangaType } from '@/lib/graphql/generated/graphql.ts';
|
||||
|
||||
import { MangaIdInfo } from '@/modules/manga/Manga.types.ts';
|
||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||
|
||||
export const TrackerSearch = ({
|
||||
manga,
|
||||
@@ -90,7 +91,7 @@ export const TrackerSearch = ({
|
||||
makeToast(t('manga.action.track.add.label.success'), 'success');
|
||||
closeSearchMode();
|
||||
})
|
||||
.catch(() => makeToast(t('manga.action.track.add.label.error'), 'error'));
|
||||
.catch((e) => makeToast(t('manga.action.track.add.label.error'), 'error', getErrorMessage(e)));
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -25,6 +25,7 @@ import { PasswordTextField } from '@/modules/core/components/inputs/PasswordText
|
||||
import { makeToast } from '@/modules/core/utils/Toast.ts';
|
||||
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||
import { Trackers, TTrackerSearch } from '@/modules/tracker/services/Trackers.ts';
|
||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||
|
||||
export const SettingsTrackerCard = ({ tracker }: { tracker: TTrackerSearch }) => {
|
||||
const { t } = useTranslation();
|
||||
@@ -42,7 +43,7 @@ export const SettingsTrackerCard = ({ tracker }: { tracker: TTrackerSearch }) =>
|
||||
try {
|
||||
await logoutFromTracker({ variables: { trackerId: tracker.id } });
|
||||
} catch (e) {
|
||||
makeToast(t('tracking.action.logout.label.failure', { name: tracker.name }), 'error');
|
||||
makeToast(t('tracking.action.logout.label.failure', { name: tracker.name }), 'error', getErrorMessage(e));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -62,7 +63,7 @@ export const SettingsTrackerCard = ({ tracker }: { tracker: TTrackerSearch }) =>
|
||||
try {
|
||||
await loginTrackerCredentials({ variables: { input: { trackerId: tracker.id, username, password } } });
|
||||
} catch (e) {
|
||||
makeToast(t('tracking.action.login.label.failure', { name: tracker.name }), 'error');
|
||||
makeToast(t('tracking.action.login.label.failure', { name: tracker.name }), 'error', getErrorMessage(e));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ import { TypographyMaxLines } from '@/modules/core/components/TypographyMaxLines
|
||||
import { SelectSetting, SelectSettingValue } from '@/modules/core/components/settings/SelectSetting.tsx';
|
||||
import { CheckboxInput } from '@/modules/core/components/inputs/CheckboxInput.tsx';
|
||||
import { TrackRecordType } from '@/lib/graphql/generated/graphql.ts';
|
||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||
|
||||
const TrackerActiveLink = ({ children, url }: { children: React.ReactNode; url: string }) => (
|
||||
<Link href={url} rel="noreferrer" target="_blank" underline="none" color="inherit">
|
||||
@@ -69,7 +70,7 @@ const TrackerActiveRemoveBind = ({
|
||||
requestManager
|
||||
.unbindTracker(trackerRecordId, removeRemoteTracking)
|
||||
.response.then(() => makeToast(t('manga.action.track.remove.label.success'), 'success'))
|
||||
.catch(() => makeToast(t('manga.action.track.remove.label.error'), 'error'));
|
||||
.catch((e) => makeToast(t('manga.action.track.remove.label.error'), 'error', getErrorMessage(e)));
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -250,7 +251,9 @@ export const TrackerActiveCard = ({
|
||||
const updateTrackerBind = (patch: Parameters<typeof requestManager.updateTrackerBind>[1]) => {
|
||||
requestManager
|
||||
.updateTrackerBind(trackRecord.id, patch)
|
||||
.response.catch(() => makeToast(t('global.error.label.failed_to_save_changes'), 'error'));
|
||||
.response.catch((e) =>
|
||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error', getErrorMessage(e)),
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -12,6 +12,7 @@ import { useNavigate } from 'react-router-dom';
|
||||
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||
import { makeToast } from '@/modules/core/utils/Toast.ts';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||
|
||||
export const TrackerOAuthLogin = () => {
|
||||
const { t } = useTranslation();
|
||||
@@ -36,7 +37,7 @@ export const TrackerOAuthLogin = () => {
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
makeToast(t('tracking.action.login.label.failure', { name: trackerName }), 'error');
|
||||
makeToast(t('tracking.action.login.label.failure', { name: trackerName }), 'error', getErrorMessage(e));
|
||||
}
|
||||
|
||||
navigate(AppRoutes.tracker.path, { replace: true });
|
||||
|
||||
@@ -28,6 +28,7 @@ import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts'
|
||||
import { GET_TRACKERS_SETTINGS } from '@/lib/graphql/queries/TrackerQuery.ts';
|
||||
import { GetTrackersSettingsQuery } from '@/lib/graphql/generated/graphql.ts';
|
||||
import { MetadataTrackingSettings } from '@/modules/tracker/Tracker.types.ts';
|
||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||
|
||||
export const TrackingSettings = () => {
|
||||
const { t } = useTranslation();
|
||||
@@ -42,8 +43,8 @@ export const TrackingSettings = () => {
|
||||
loading: areMetadataServerSettingsLoading,
|
||||
request: { error: metadataServerSettingsError, refetch: refetchServerMetadataSettings },
|
||||
} = useMetadataServerSettings();
|
||||
const updateTrackingSettings = createUpdateMetadataServerSettings<keyof MetadataTrackingSettings>(() =>
|
||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error'),
|
||||
const updateTrackingSettings = createUpdateMetadataServerSettings<keyof MetadataTrackingSettings>((e) =>
|
||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error', getErrorMessage(e)),
|
||||
);
|
||||
|
||||
const {
|
||||
|
||||
@@ -38,6 +38,7 @@ import { ChapterIdInfo, ChapterMangaInfo } from '@/modules/chapter/services/Chap
|
||||
import { makeToast } from '@/modules/core/utils/Toast.ts';
|
||||
import { VirtuosoUtil } from '@/lib/virtuoso/Virtuoso.util.tsx';
|
||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||
|
||||
const groupByDate = (updates: Pick<ChapterType, 'fetchedAt'>[]): [date: string, items: number][] => {
|
||||
if (!updates.length) {
|
||||
@@ -115,14 +116,16 @@ export const Updates: React.FC = () => {
|
||||
try {
|
||||
await requestManager.addChapterToDownloadQueue(chapter.id).response;
|
||||
} catch (e) {
|
||||
makeToast(t('download.queue.error.label.failed_to_remove'), 'error');
|
||||
makeToast(t('download.queue.error.label.failed_to_remove'), 'error', getErrorMessage(e));
|
||||
}
|
||||
};
|
||||
|
||||
const downloadChapter = (chapter: ChapterIdInfo) => {
|
||||
requestManager
|
||||
.addChapterToDownloadQueue(chapter.id)
|
||||
.response.catch(() => makeToast(t('global.error.label.failed_to_save_changes'), 'error'));
|
||||
.response.catch((e) =>
|
||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error', getErrorMessage(e)),
|
||||
);
|
||||
};
|
||||
|
||||
const loadMore = useCallback(() => {
|
||||
|
||||
Reference in New Issue
Block a user