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