Add retry logic to existing error handling

This commit is contained in:
schroda
2024-04-27 22:14:42 +02:00
parent 7531edbd59
commit 58f5e9ff79
4 changed files with 42 additions and 6 deletions

View File

@@ -18,6 +18,7 @@ import { Trackers } from '@/lib/data/Trackers.ts';
import { TrackerCard, TrackerMode } from '@/components/tracker/TrackerCard.tsx'; import { TrackerCard, TrackerMode } from '@/components/tracker/TrackerCard.tsx';
import { TManga } from '@/typings.ts'; import { TManga } from '@/typings.ts';
import { makeToast } from '@/components/util/Toast.tsx'; import { makeToast } from '@/components/util/Toast.tsx';
import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.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) {
@@ -37,7 +38,7 @@ export const TrackManga = ({ manga }: { manga: Pick<TManga, 'id' | 'trackRecords
const [searchModeForTracker, setSearchModeForTracker] = useState<number>(); const [searchModeForTracker, setSearchModeForTracker] = useState<number>();
const trackerList = requestManager.useGetTrackerList(); const trackerList = requestManager.useGetTrackerList({ notifyOnNetworkStatusChange: true });
const mangaTrackers = manga.trackRecords.nodes; const mangaTrackers = manga.trackRecords.nodes;
const loggedInTrackers = Trackers.getLoggedIn(trackerList.data?.trackers.nodes ?? []); const loggedInTrackers = Trackers.getLoggedIn(trackerList.data?.trackers.nodes ?? []);
@@ -79,7 +80,13 @@ export const TrackManga = ({ manga }: { manga: Pick<TManga, 'id' | 'trackRecords
); );
if (trackerList.error) { if (trackerList.error) {
return <EmptyView message={trackerList.error.message} />; return (
<EmptyView
message={t('global.error.label.failed_to_load_data')}
messageExtra={trackerList.error.message}
retry={() => trackerList.refetch().catch(defaultPromiseErrorHandler('TrackManga::refetch'))}
/>
);
} }
if (trackerList.loading) { if (trackerList.loading) {

View File

@@ -25,6 +25,7 @@ import { makeToast } from '@/components/util/Toast.tsx';
import { TrackerMangaCard } from '@/components/tracker/TrackerMangaCard.tsx'; import { TrackerMangaCard } from '@/components/tracker/TrackerMangaCard.tsx';
import { DIALOG_PADDING } from '@/components/tracker/constants.ts'; import { DIALOG_PADDING } from '@/components/tracker/constants.ts';
import { getOptionForDirection } from '@/theme.ts'; import { getOptionForDirection } from '@/theme.ts';
import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts';
export const TrackerSearch = ({ export const TrackerSearch = ({
mangaId, mangaId,
@@ -114,6 +115,9 @@ export const TrackerSearch = ({
<EmptyView <EmptyView
message={t('global.error.label.failed_to_load_data')} message={t('global.error.label.failed_to_load_data')}
messageExtra={trackerSearch.error.message} messageExtra={trackerSearch.error.message}
retry={() =>
trackerSearch.refetch().catch(defaultPromiseErrorHandler('TrackerSearch::refetch'))
}
/> />
)} )}
<List sx={{ padding: 0 }}> <List sx={{ padding: 0 }}>

View File

@@ -20,6 +20,7 @@ import { TPartialManga } from '@/typings.ts';
import { GridLayouts } from '@/components/source/GridLayouts.tsx'; import { GridLayouts } from '@/components/source/GridLayouts.tsx';
import { useLocalStorage } from '@/util/useStorage.tsx'; import { useLocalStorage } from '@/util/useStorage.tsx';
import { GridLayout } from '@/components/context/LibraryOptionsContext.tsx'; import { GridLayout } from '@/components/context/LibraryOptionsContext.tsx';
import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts';
export const Migrate = () => { export const Migrate = () => {
const { t } = useTranslation(); const { t } = useTranslation();
@@ -46,7 +47,8 @@ export const Migrate = () => {
data: migratableSourceData, data: migratableSourceData,
loading: isSourceLoading, loading: isSourceLoading,
error: sourceError, error: sourceError,
} = requestManager.useGetSource(paramSourceId, { skip: !!isKnownSource }); refetch: refetchSource,
} = requestManager.useGetSource(paramSourceId, { skip: !!isKnownSource, notifyOnNetworkStatusChange: true });
const { sourceId, name } = { const { sourceId, name } = {
sourceId: paramSourceId, sourceId: paramSourceId,
@@ -59,8 +61,10 @@ export const Migrate = () => {
data: migratableSourceMangasData, data: migratableSourceMangasData,
loading: areMangasLoading, loading: areMangasLoading,
error: mangasError, error: mangasError,
refetch: refetchMangas,
} = requestManager.useGetMigratableSourceMangas(sourceId, { } = requestManager.useGetMigratableSourceMangas(sourceId, {
skip: !isKnownSource, skip: !isKnownSource,
notifyOnNetworkStatusChange: true,
}); });
useEffect(() => { useEffect(() => {
@@ -94,7 +98,21 @@ export const Migrate = () => {
const hasError = hasErrorSource || mangasError; const hasError = hasErrorSource || mangasError;
if (hasError) { if (hasError) {
const error = (hasErrorSource ? sourceError : mangasError)!; const error = (hasErrorSource ? sourceError : mangasError)!;
return <EmptyView message={t('global.error.label.failed_to_load_data')} messageExtra={error.message} />; return (
<EmptyView
message={t('global.error.label.failed_to_load_data')}
messageExtra={error.message}
retry={() => {
if (hasErrorSource) {
refetchSource().catch(defaultPromiseErrorHandler('Migrate::refetchSource'));
}
if (mangasError) {
refetchMangas().catch(defaultPromiseErrorHandler('Migrate::refetchMangas'));
}
}}
/>
);
} }
return ( return (

View File

@@ -15,6 +15,7 @@ import { EmptyView } from '@/components/util/EmptyView.tsx';
import { GetMigratableSourcesQuery } from '@/lib/graphql/generated/graphql.ts'; import { GetMigratableSourcesQuery } from '@/lib/graphql/generated/graphql.ts';
import { MigrationCard, TMigratableSource } from '@/components/MigrationCard.tsx'; import { MigrationCard, TMigratableSource } from '@/components/MigrationCard.tsx';
import { StyledGroupItemWrapper } from '@/components/virtuoso/StyledGroupItemWrapper.tsx'; import { StyledGroupItemWrapper } from '@/components/virtuoso/StyledGroupItemWrapper.tsx';
import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts';
type TMigratableSourcesResult = GetMigratableSourcesQuery['mangas']['nodes']; type TMigratableSourcesResult = GetMigratableSourcesQuery['mangas']['nodes'];
type TMigratableSources = Record<string, TMigratableSource>; type TMigratableSources = Record<string, TMigratableSource>;
@@ -43,7 +44,7 @@ const getMigratableSources = (mangas?: TMigratableSourcesResult): TMigratableSou
export const Migration = () => { export const Migration = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const { data, loading, error } = requestManager.useGetMigratableSources({ const { data, loading, error, refetch } = requestManager.useGetMigratableSources({
notifyOnNetworkStatusChange: true, notifyOnNetworkStatusChange: true,
}); });
const migratableSources = useMemo(() => getMigratableSources(data?.mangas.nodes), [data?.mangas.nodes]); const migratableSources = useMemo(() => getMigratableSources(data?.mangas.nodes), [data?.mangas.nodes]);
@@ -53,7 +54,13 @@ export const Migration = () => {
} }
if (error) { if (error) {
return <EmptyView message={t('global.error.label.failed_to_load_data')} messageExtra={error.message} />; return (
<EmptyView
message={t('global.error.label.failed_to_load_data')}
messageExtra={error.message}
retry={() => refetch().catch(defaultPromiseErrorHandler('Migration::refetch'))}
/>
);
} }
return ( return (