Log promise failures instead of ignoring them (#531)
In case the failure does not get handled, it should at least get logged, to prevent silently ignoring it
This commit is contained in:
@@ -16,6 +16,7 @@ import { Box } from '@mui/material';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { PartialExtension, TranslationKey } from '@/typings';
|
import { PartialExtension, TranslationKey } from '@/typings';
|
||||||
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||||
|
import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
extension: PartialExtension;
|
extension: PartialExtension;
|
||||||
@@ -108,10 +109,14 @@ export function ExtensionCard(props: IProps) {
|
|||||||
case ExtensionAction.INSTALL:
|
case ExtensionAction.INSTALL:
|
||||||
case ExtensionAction.UPDATE:
|
case ExtensionAction.UPDATE:
|
||||||
case ExtensionAction.UNINSTALL:
|
case ExtensionAction.UNINSTALL:
|
||||||
requestExtensionAction(installedState).catch(() => {});
|
requestExtensionAction(installedState).catch(
|
||||||
|
defaultPromiseErrorHandler(`ExtensionCard:handleButtonClick(${installedState})`),
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
case ExtensionState.OBSOLETE:
|
case ExtensionState.OBSOLETE:
|
||||||
requestExtensionAction(ExtensionAction.UNINSTALL).catch(() => {});
|
requestExtensionAction(ExtensionAction.UNINSTALL).catch(
|
||||||
|
defaultPromiseErrorHandler(`ExtensionCard:handleButtonClick(${installedState})`),
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { requestManager } from '@/lib/requests/RequestManager.ts';
|
|||||||
import { makeToast } from '@/components/util/Toast';
|
import { makeToast } from '@/components/util/Toast';
|
||||||
import { UpdaterSubscription } from '@/lib/graphql/generated/graphql.ts';
|
import { UpdaterSubscription } from '@/lib/graphql/generated/graphql.ts';
|
||||||
import { Progress } from '@/components/util/Progress';
|
import { Progress } from '@/components/util/Progress';
|
||||||
|
import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts';
|
||||||
|
|
||||||
const calcProgress = (status: UpdaterSubscription['updateStatusChanged'] | undefined) => {
|
const calcProgress = (status: UpdaterSubscription['updateStatusChanged'] | undefined) => {
|
||||||
if (!status) {
|
if (!status) {
|
||||||
@@ -64,14 +65,14 @@ export function UpdateChecker({ handleFinishedUpdate }: { handleFinishedUpdate?:
|
|||||||
lastRunningState = false;
|
lastRunningState = false;
|
||||||
handleFinishedUpdate?.();
|
handleFinishedUpdate?.();
|
||||||
// this re-fetch is necessary since a running update could have been triggered by the server or another client
|
// this re-fetch is necessary since a running update could have been triggered by the server or another client
|
||||||
reFetchLastTimestamp().catch(() => {});
|
reFetchLastTimestamp().catch(defaultPromiseErrorHandler('UpdateChecker::reFetchLastTimestamp'));
|
||||||
}, [status?.isRunning]);
|
}, [status?.isRunning]);
|
||||||
|
|
||||||
const onClick = async () => {
|
const onClick = async () => {
|
||||||
try {
|
try {
|
||||||
lastRunningState = true;
|
lastRunningState = true;
|
||||||
await requestManager.startGlobalUpdate().response;
|
await requestManager.startGlobalUpdate().response;
|
||||||
reFetchLastTimestamp().catch(() => {});
|
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');
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import { SelectableCollectionReturnType } from '@/components/collection/useSelec
|
|||||||
import { CategorySelect } from '@/components/navbar/action/CategorySelect.tsx';
|
import { CategorySelect } from '@/components/navbar/action/CategorySelect.tsx';
|
||||||
import { MenuItem } from '@/components/menu/MenuItem.tsx';
|
import { MenuItem } from '@/components/menu/MenuItem.tsx';
|
||||||
import { createGetMenuItemTitle, createIsMenuItemDisabled, createShouldShowMenuItem } from '@/components/menu/util.ts';
|
import { createGetMenuItemTitle, createIsMenuItemDisabled, createShouldShowMenuItem } from '@/components/menu/util.ts';
|
||||||
|
import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts';
|
||||||
|
|
||||||
const ACTION_DISABLES_SELECTION_MODE: MangaAction[] = ['remove_from_library'] as const;
|
const ACTION_DISABLES_SELECTION_MODE: MangaAction[] = ['remove_from_library'] as const;
|
||||||
|
|
||||||
@@ -63,7 +64,7 @@ export const MangaActionMenuItems = ({ manga, handleSelection, selectedMangas =
|
|||||||
const performAction = (action: MangaAction, mangas: TManga[]) => {
|
const performAction = (action: MangaAction, mangas: TManga[]) => {
|
||||||
Mangas.performAction(action, manga ? [manga.id] : Mangas.getIds(mangas), {
|
Mangas.performAction(action, manga ? [manga.id] : Mangas.getIds(mangas), {
|
||||||
wasManuallyMarkedAsRead: true,
|
wasManuallyMarkedAsRead: true,
|
||||||
}).catch(() => {});
|
}).catch(defaultPromiseErrorHandler(`MangaActionMenuItems:performAction(${action})`));
|
||||||
|
|
||||||
onClose(!ACTION_DISABLES_SELECTION_MODE.includes(action));
|
onClose(!ACTION_DISABLES_SELECTION_MODE.includes(action));
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||||
import { getVersion } from '@/screens/settings/About.tsx';
|
import { getVersion } from '@/screens/settings/About.tsx';
|
||||||
import { useLocalStorage } from '@/util/useLocalStorage.tsx';
|
import { useLocalStorage } from '@/util/useLocalStorage.tsx';
|
||||||
|
import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts';
|
||||||
|
|
||||||
const UPDATE_CHECK_INTERVAL = 1000 * 60 * 60 * 24; // 1 day
|
const UPDATE_CHECK_INTERVAL = 1000 * 60 * 60 * 24; // 1 day
|
||||||
|
|
||||||
@@ -54,7 +55,7 @@ export const ServerUpdateChecker = () => {
|
|||||||
let timeout: NodeJS.Timeout | undefined;
|
let timeout: NodeJS.Timeout | undefined;
|
||||||
const scheduleUpdateCheck = (timeoutMS: number) => {
|
const scheduleUpdateCheck = (timeoutMS: number) => {
|
||||||
timeout = setTimeout(() => {
|
timeout = setTimeout(() => {
|
||||||
checkForUpdate().catch(() => {});
|
checkForUpdate().catch(defaultPromiseErrorHandler('ServerUpdateChecker::checkForUpdate'));
|
||||||
setLastUpdateCheck(Date.now());
|
setLastUpdateCheck(Date.now());
|
||||||
scheduleUpdateCheck(UPDATE_CHECK_INTERVAL);
|
scheduleUpdateCheck(UPDATE_CHECK_INTERVAL);
|
||||||
}, timeoutMS);
|
}, timeoutMS);
|
||||||
|
|||||||
@@ -238,6 +238,7 @@ import { CLEAR_SERVER_CACHE } from '@/lib/graphql/mutations/ImageMutation.ts';
|
|||||||
import { RESET_WEBUI_UPDATE_STATUS, UPDATE_WEBUI } from '@/lib/graphql/mutations/ServerInfoMutation.ts';
|
import { RESET_WEBUI_UPDATE_STATUS, UPDATE_WEBUI } from '@/lib/graphql/mutations/ServerInfoMutation.ts';
|
||||||
import { WEBUI_UPDATE_SUBSCRIPTION } from '@/lib/graphql/subscriptions/ServerInfoSubscription.ts';
|
import { WEBUI_UPDATE_SUBSCRIPTION } from '@/lib/graphql/subscriptions/ServerInfoSubscription.ts';
|
||||||
import { GET_DOWNLOAD_STATUS } from '@/lib/graphql/queries/DownloaderQuery.ts';
|
import { GET_DOWNLOAD_STATUS } from '@/lib/graphql/queries/DownloaderQuery.ts';
|
||||||
|
import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts';
|
||||||
|
|
||||||
enum GQLMethod {
|
enum GQLMethod {
|
||||||
QUERY = 'QUERY',
|
QUERY = 'QUERY',
|
||||||
@@ -514,7 +515,7 @@ export class RequestManager {
|
|||||||
await revalidationPromise;
|
await revalidationPromise;
|
||||||
setActiveRevalidation(null);
|
setActiveRevalidation(null);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// ignore
|
defaultPromiseErrorHandler(`RequestManager..revalidatePages(${getVariablesFor(0)})`)(e);
|
||||||
} finally {
|
} finally {
|
||||||
setValidating(false);
|
setValidating(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import { ChapterType, DownloadType } from '@/lib/graphql/generated/graphql.ts';
|
|||||||
import { TChapter } from '@/typings.ts';
|
import { TChapter } from '@/typings.ts';
|
||||||
import { NavBarContext } from '@/components/context/NavbarContext.tsx';
|
import { NavBarContext } from '@/components/context/NavbarContext.tsx';
|
||||||
import { LoadingPlaceholder } from '@/components/util/LoadingPlaceholder.tsx';
|
import { LoadingPlaceholder } from '@/components/util/LoadingPlaceholder.tsx';
|
||||||
|
import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.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
|
||||||
@@ -203,7 +204,7 @@ export const DownloadQueue: React.FC = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
requestManager.startDownloads().response.catch(() => {});
|
requestManager.startDownloads().response.catch(defaultPromiseErrorHandler('DownloadQueue::startDownloads'));
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import { NavBarContext } from '@/components/context/NavbarContext.tsx';
|
|||||||
import { useDebounce } from '@/util/useDebounce.ts';
|
import { useDebounce } from '@/util/useDebounce.ts';
|
||||||
import { UpdateChapterPatchInput } from '@/lib/graphql/generated/graphql.ts';
|
import { UpdateChapterPatchInput } from '@/lib/graphql/generated/graphql.ts';
|
||||||
import { useMetadataServerSettings } from '@/util/metadataServerSettings.ts';
|
import { useMetadataServerSettings } from '@/util/metadataServerSettings.ts';
|
||||||
|
import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts';
|
||||||
|
|
||||||
const isDupChapter = async (chapterIndex: number, currentChapter: TChapter) => {
|
const isDupChapter = async (chapterIndex: number, currentChapter: TChapter) => {
|
||||||
const nextChapter = await requestManager.getChapter(currentChapter.manga.id, chapterIndex).response;
|
const nextChapter = await requestManager.getChapter(currentChapter.manga.id, chapterIndex).response;
|
||||||
@@ -209,7 +210,7 @@ export function Reader() {
|
|||||||
chapterIdToDelete: getChapterIdToDelete(),
|
chapterIdToDelete: getChapterIdToDelete(),
|
||||||
downloadAheadMangaId: shouldDownloadAhead ? chapter.manga.id : undefined,
|
downloadAheadMangaId: shouldDownloadAhead ? chapter.manga.id : undefined,
|
||||||
})
|
})
|
||||||
.response.catch(() => {});
|
.response.catch();
|
||||||
};
|
};
|
||||||
|
|
||||||
const setSettingValue = (key: keyof IReaderSettings, value: string | boolean) => {
|
const setSettingValue = (key: keyof IReaderSettings, value: string | boolean) => {
|
||||||
@@ -264,7 +265,9 @@ export function Reader() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!areDefaultSettingsLoading && !isMangaLoading) {
|
if (!areDefaultSettingsLoading && !isMangaLoading) {
|
||||||
checkAndHandleMissingStoredReaderSettings(manga, 'manga', defaultSettings).catch(() => {});
|
checkAndHandleMissingStoredReaderSettings(manga, 'manga', defaultSettings).catch(
|
||||||
|
defaultPromiseErrorHandler('Reader::checkAndHandleMissingStoredReaderSettings'),
|
||||||
|
);
|
||||||
setSettings(getReaderSettingsFor(manga, defaultSettings));
|
setSettings(getReaderSettingsFor(manga, defaultSettings));
|
||||||
}
|
}
|
||||||
}, [areDefaultSettingsLoading, isMangaLoading]);
|
}, [areDefaultSettingsLoading, isMangaLoading]);
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import { LoadingPlaceholder } from '@/components/util/LoadingPlaceholder';
|
|||||||
import { GetAboutQuery, UpdateState } from '@/lib/graphql/generated/graphql.ts';
|
import { GetAboutQuery, UpdateState } from '@/lib/graphql/generated/graphql.ts';
|
||||||
import { ABOUT_WEBUI, WEBUI_UPDATE_CHECK } from '@/lib/graphql/Fragments.ts';
|
import { ABOUT_WEBUI, WEBUI_UPDATE_CHECK } from '@/lib/graphql/Fragments.ts';
|
||||||
import { makeToast } from '@/components/util/Toast.tsx';
|
import { makeToast } from '@/components/util/Toast.tsx';
|
||||||
|
import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts';
|
||||||
|
|
||||||
type AboutServer = GetAboutQuery['aboutServer'];
|
type AboutServer = GetAboutQuery['aboutServer'];
|
||||||
|
|
||||||
@@ -224,7 +225,9 @@ export function About() {
|
|||||||
|
|
||||||
const resetUpdateStatus = isError || updateFinished;
|
const resetUpdateStatus = isError || updateFinished;
|
||||||
if (resetUpdateStatus) {
|
if (resetUpdateStatus) {
|
||||||
requestManager.resetWebUIUpdateStatus().response.catch(() => {});
|
requestManager
|
||||||
|
.resetWebUIUpdateStatus()
|
||||||
|
.response.catch(defaultPromiseErrorHandler('About::resetWebUIUpdateStatus'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!updateFinished) {
|
if (!updateFinished) {
|
||||||
@@ -326,7 +329,11 @@ export function About() {
|
|||||||
isUpdateAvailable={isWebUIUpdateAvailable}
|
isUpdateAvailable={isWebUIUpdateAvailable}
|
||||||
updateCheckError={webUIUpdateCheckError}
|
updateCheckError={webUIUpdateCheckError}
|
||||||
checkForUpdate={checkForWebUIUpdate}
|
checkForUpdate={checkForWebUIUpdate}
|
||||||
triggerUpdate={() => requestManager.updateWebUI().response.catch(() => {})}
|
triggerUpdate={() =>
|
||||||
|
requestManager
|
||||||
|
.updateWebUI()
|
||||||
|
.response.catch(defaultPromiseErrorHandler('About::updateWebUI'))
|
||||||
|
}
|
||||||
progress={webUIUpdateProgress}
|
progress={webUIUpdateProgress}
|
||||||
updateState={webUIUpdateState}
|
updateState={webUIUpdateState}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import {
|
|||||||
import { ReaderSettingsOptions } from '@/components/reader/ReaderSettingsOptions';
|
import { ReaderSettingsOptions } from '@/components/reader/ReaderSettingsOptions';
|
||||||
import { makeToast } from '@/components/util/Toast';
|
import { makeToast } from '@/components/util/Toast';
|
||||||
import { NavBarContext, useSetDefaultBackTo } from '@/components/context/NavbarContext';
|
import { NavBarContext, useSetDefaultBackTo } from '@/components/context/NavbarContext';
|
||||||
|
import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts';
|
||||||
|
|
||||||
export function DefaultReaderSettings() {
|
export function DefaultReaderSettings() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -58,7 +59,7 @@ export function DefaultReaderSettings() {
|
|||||||
{ meta: convertToGqlMeta(metadata)! },
|
{ meta: convertToGqlMeta(metadata)! },
|
||||||
'server',
|
'server',
|
||||||
getDefaultSettings(),
|
getDefaultSettings(),
|
||||||
).catch(() => {});
|
).catch(defaultPromiseErrorHandler('DefaultReaderSettings::checkAndHandleMissingStoredReaderSettings'));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ReaderSettingsOptions
|
<ReaderSettingsOptions
|
||||||
|
|||||||
10
src/util/defaultPromiseErrorHandler.ts
Normal file
10
src/util/defaultPromiseErrorHandler.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
/*
|
||||||
|
* 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/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const defaultPromiseErrorHandler = (name: string) => (error: any) =>
|
||||||
|
console.error(`${name} failed due to`, error);
|
||||||
Reference in New Issue
Block a user