diff --git a/src/lib/graphql/generated/graphql.ts b/src/lib/graphql/generated/graphql.ts index c4808edf..b9e2e65f 100644 --- a/src/lib/graphql/generated/graphql.ts +++ b/src/lib/graphql/generated/graphql.ts @@ -519,9 +519,11 @@ export enum DownloadUpdateType { Dequeued = 'DEQUEUED', Error = 'ERROR', Finished = 'FINISHED', + Paused = 'PAUSED', Position = 'POSITION', Progress = 'PROGRESS', - Queued = 'QUEUED' + Queued = 'QUEUED', + Stopped = 'STOPPED' } export type DownloadUpdates = { @@ -1501,6 +1503,7 @@ export type PartialSettingsType = Settings & { flareSolverrTimeout?: Maybe; flareSolverrUrl?: Maybe; globalUpdateInterval?: Maybe; + /** @deprecated Removed - does not do anything */ gqlDebugLogsEnabled?: Maybe; initialOpenInBrowserEnabled?: Maybe; ip?: Maybe; @@ -1551,7 +1554,6 @@ export type PartialSettingsTypeInput = { flareSolverrTimeout?: InputMaybe; flareSolverrUrl?: InputMaybe; globalUpdateInterval?: InputMaybe; - gqlDebugLogsEnabled?: InputMaybe; initialOpenInBrowserEnabled?: InputMaybe; ip?: InputMaybe; localSourcePath?: InputMaybe; @@ -1925,6 +1927,7 @@ export type Settings = { flareSolverrTimeout?: Maybe; flareSolverrUrl?: Maybe; globalUpdateInterval?: Maybe; + /** @deprecated Removed - does not do anything */ gqlDebugLogsEnabled?: Maybe; initialOpenInBrowserEnabled?: Maybe; ip?: Maybe; @@ -1978,6 +1981,7 @@ export type SettingsType = Settings & { flareSolverrTimeout: Scalars['Int']['output']; flareSolverrUrl: Scalars['String']['output']; globalUpdateInterval: Scalars['Float']['output']; + /** @deprecated Removed - does not do anything */ gqlDebugLogsEnabled: Scalars['Boolean']['output']; initialOpenInBrowserEnabled: Scalars['Boolean']['output']; ip: Scalars['String']['output']; @@ -3512,6 +3516,11 @@ export type GetMigratableSourceMangasQueryVariables = Exact<{ export type GetMigratableSourceMangasQuery = { __typename?: 'Query', mangas: { __typename?: 'MangaNodeList', nodes: Array<{ __typename?: 'MangaType', id: number, title: string, thumbnailUrl?: string | null, sourceId: string, categories: { __typename?: 'CategoryNodeList', nodes: Array<{ __typename?: 'CategoryType', id: number }> } }> } }; +export type GetLibraryMangaCountQueryVariables = Exact<{ [key: string]: never; }>; + + +export type GetLibraryMangaCountQuery = { __typename?: 'Query', mangas: { __typename?: 'MangaNodeList', totalCount: number } }; + export type GetAboutQueryVariables = Exact<{ [key: string]: never; }>; diff --git a/src/lib/graphql/queries/MangaQuery.ts b/src/lib/graphql/queries/MangaQuery.ts index 352d92ed..0de01e99 100644 --- a/src/lib/graphql/queries/MangaQuery.ts +++ b/src/lib/graphql/queries/MangaQuery.ts @@ -239,3 +239,11 @@ export const GET_MIGRATABLE_SOURCE_MANGAS = gql` } } `; + +export const GET_LIBRARY_MANGA_COUNT = gql` + query GET_LIBRARY_MANGA_COUNT { + mangas(condition: { inLibrary: true }) { + totalCount + } + } +`; diff --git a/src/modules/library/screens/Library.tsx b/src/modules/library/screens/Library.tsx index 6a3993c2..4e2c54be 100644 --- a/src/modules/library/screens/Library.tsx +++ b/src/modules/library/screens/Library.tsx @@ -32,6 +32,8 @@ import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts' import { GetCategoriesLibraryQuery, GetCategoriesLibraryQueryVariables, + GetLibraryMangaCountQuery, + GetLibraryMangaCountQueryVariables, MangaChapterStatFieldsFragment, MangaType, } from '@/lib/graphql/generated/graphql.ts'; @@ -41,6 +43,7 @@ import { MANGA_CHAPTER_STAT_FIELDS } from '@/lib/graphql/fragments/MangaFragment import { useLibraryOptionsContext } from '@/modules/library/contexts/LibraryOptionsContext.tsx'; import { useMetadataServerSettings } from '@/modules/settings/services/ServerSettingsMetadata.ts'; import { getCategoryMetadata } from '@/modules/category/services/CategoryMetadata.ts'; +import { GET_LIBRARY_MANGA_COUNT } from '@/lib/graphql/queries/MangaQuery.ts'; const TitleWithSizeTag = styled('span')({ display: 'flex', @@ -73,10 +76,13 @@ export function Library() { (category) => category.id !== 0 || (category.id === 0 && category.mangas.totalCount), ); const tabs = tabsData ?? []; - const librarySize = useMemo( - () => tabs.map((tab) => tab.mangas.totalCount).reduce((prev, curr) => prev + curr, 0), - [tabs], - ); + + const librarySizeResponse = requestManager.useGetMangas< + GetLibraryMangaCountQuery, + GetLibraryMangaCountQueryVariables + >(GET_LIBRARY_MANGA_COUNT, {}); + + const librarySize = librarySizeResponse.data?.mangas.totalCount ?? 0; const [tabSearchParam, setTabSearchParam] = useQueryParam('tab', NumberParam); @@ -216,17 +222,25 @@ export function Library() { setTabSearchParam(newTab); }; - if (tabsError != null) { + if (tabsError != null || librarySizeResponse.error) { return ( refetchCategories().catch(defaultPromiseErrorHandler('Library::refetchCategories'))} + message={t('global.error.label.failed_to_load_data')} + messageExtra={tabsError?.message ?? librarySizeResponse.error?.message} + retry={() => { + if (tabsError) { + refetchCategories().catch(defaultPromiseErrorHandler('Library::refetchCategories')); + } + + if (librarySizeResponse.error) { + librarySizeResponse.refetch().catch(defaultPromiseErrorHandler('Library::refetchLibrarySize')); + } + }} /> ); } - if (areCategoriesLoading) { + if (areCategoriesLoading || librarySizeResponse.loading) { return ; }