diff --git a/src/components/MangaCard.tsx b/src/components/MangaCard.tsx index 03973238..a161e56c 100644 --- a/src/components/MangaCard.tsx +++ b/src/components/MangaCard.tsx @@ -52,7 +52,7 @@ export const MangaCard = (props: MangaCardProps) => { mode === 'source', ); - const mangaLinkTo = getMangaLinkTo(mode, manga.id, manga.source?.id, manga.title); + const mangaLinkTo = getMangaLinkTo(mode, manga.id, manga.sourceId, manga.title); const nextChapterIndexToRead = firstUnreadChapter?.sourceOrder ?? 1; const isLatestChapterRead = chapters?.totalCount === latestReadChapter?.sourceOrder; diff --git a/src/components/MangaGrid.tsx b/src/components/MangaGrid.tsx index d2aaddff..f4468802 100644 --- a/src/components/MangaGrid.tsx +++ b/src/components/MangaGrid.tsx @@ -17,11 +17,11 @@ import { LoadingPlaceholder } from '@/components/util/LoadingPlaceholder'; import { MangaCard } from '@/components/MangaCard'; import { GridLayout } from '@/components/context/LibraryOptionsContext'; import { useLocalStorage, useSessionStorage } from '@/util/useStorage.tsx'; -import { TManga, TPartialManga } from '@/typings.ts'; import { SelectableCollectionReturnType } from '@/components/collection/useSelectableCollection.ts'; import { DEFAULT_FULL_FAB_HEIGHT } from '@/components/util/StyledFab.tsx'; import { AppStorage } from '@/util/AppStorage.ts'; import { MangaCardProps } from '@/components/manga/MangaCard.types.tsx'; +import { MangaType } from '@/lib/graphql/generated/graphql.ts'; const GridContainer = React.forwardRef(({ children, ...props }, ref) => ( @@ -46,12 +46,14 @@ const GridItemContainerWithDimension = ( ); }; +type TManga = MangaCardProps['manga']; + const createMangaCard = ( - manga: TPartialManga, + manga: TManga, gridLayout?: GridLayout, inLibraryIndicator?: boolean, isSelectModeActive: boolean = false, - selectedMangaIds?: TManga['id'][], + selectedMangaIds?: MangaType['id'][], handleSelection?: DefaultGridProps['handleSelection'], mode?: MangaCardProps['mode'], ) => ( @@ -68,13 +70,13 @@ const createMangaCard = ( type DefaultGridProps = Pick & { isLoading: boolean; - mangas: TPartialManga[]; + mangas: TManga[]; inLibraryIndicator?: boolean; GridItemContainer: (props: GridTypeMap['props'] & Partial) => JSX.Element; gridLayout?: GridLayout; isSelectModeActive?: boolean; - selectedMangaIds?: Required[]; - handleSelection?: SelectableCollectionReturnType['handleSelection']; + selectedMangaIds?: Required[]; + handleSelection?: SelectableCollectionReturnType['handleSelection']; }; const HorizontalGrid = forwardRef( diff --git a/src/components/chapter/ChapterList.tsx b/src/components/chapter/ChapterList.tsx index 4f84b393..7c394a5b 100644 --- a/src/components/chapter/ChapterList.tsx +++ b/src/components/chapter/ChapterList.tsx @@ -19,7 +19,6 @@ import DownloadIcon from '@mui/icons-material/Download'; import DoneAllIcon from '@mui/icons-material/DoneAll'; import PopupState, { bindMenu, bindTrigger } from 'material-ui-popup-state'; import Menu from '@mui/material/Menu'; -import { TManga } from '@/typings.ts'; import { requestManager } from '@/lib/requests/RequestManager.ts'; import { ChapterCard } from '@/components/chapter/ChapterCard.tsx'; import { ResumeFab } from '@/components/manga/ResumeFAB.tsx'; @@ -32,6 +31,7 @@ import { DownloadType, GetChaptersMangaQuery, GetChaptersMangaQueryVariables, + MangaScreenFieldsFragment, } from '@/lib/graphql/generated/graphql.ts'; import { useSelectableCollection } from '@/components/collection/useSelectableCollection.ts'; import { SelectableCollectionSelectAll } from '@/components/collection/SelectableCollectionSelectAll.tsx'; @@ -72,7 +72,10 @@ export interface IChapterWithMeta { } interface IProps { - manga: TManga; + manga: Pick< + MangaScreenFieldsFragment, + 'id' | 'firstUnreadChapter' | 'chapters' | 'latestReadChapter' | 'unreadCount' | 'downloadCount' + >; isRefreshing: boolean; } diff --git a/src/components/chapter/ChaptersDownloadActionMenuItems.tsx b/src/components/chapter/ChaptersDownloadActionMenuItems.tsx index fb9342c0..9c78d165 100644 --- a/src/components/chapter/ChaptersDownloadActionMenuItems.tsx +++ b/src/components/chapter/ChaptersDownloadActionMenuItems.tsx @@ -8,10 +8,10 @@ import MenuItem from '@mui/material/MenuItem'; import { useTranslation } from 'react-i18next'; -import { TManga } from '@/typings.ts'; import { useMetadataServerSettings } from '@/lib/metadata/metadataServerSettings.ts'; import { Mangas } from '@/lib/data/Mangas.ts'; import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts'; +import { MangaType } from '@/lib/graphql/generated/graphql.ts'; const DownloadRange = { NEXT_1: 1, @@ -25,7 +25,7 @@ export const ChaptersDownloadActionMenuItems = ({ mangaIds, closeMenu, }: { - mangaIds: TManga['id'][]; + mangaIds: MangaType['id'][]; closeMenu: () => void; }) => { const { t } = useTranslation(); diff --git a/src/components/library/LibraryMangaGrid.tsx b/src/components/library/LibraryMangaGrid.tsx index 73c41712..2f9f6480 100644 --- a/src/components/library/LibraryMangaGrid.tsx +++ b/src/components/library/LibraryMangaGrid.tsx @@ -9,14 +9,12 @@ import React, { useEffect, useLayoutEffect } from 'react'; import { StringParam, useQueryParam } from 'use-query-params'; import { useTranslation } from 'react-i18next'; -import { TManga } from '@/typings'; import { GridLayout, useLibraryOptionsContext } from '@/components/context/LibraryOptionsContext'; import { IMangaGridProps, MangaGrid } from '@/components/MangaGrid'; interface LibraryMangaGridProps - extends Required>, + extends Required>, Pick { - mangas: TManga[]; showFilteredOutMessage: boolean; isLoading: boolean; } diff --git a/src/components/library/useGetVisibleLibraryMangas.ts b/src/components/library/useGetVisibleLibraryMangas.ts index c71b8ea1..96811e8d 100644 --- a/src/components/library/useGetVisibleLibraryMangas.ts +++ b/src/components/library/useGetVisibleLibraryMangas.ts @@ -8,10 +8,11 @@ import { StringParam, useQueryParam } from 'use-query-params'; import { useMemo } from 'react'; -import { LibraryOptions, LibrarySortMode, NullAndUndefined, TManga } from '@/typings.ts'; +import { LibraryOptions, LibrarySortMode, NullAndUndefined } from '@/typings.ts'; import { useLibraryOptionsContext } from '@/components/context/LibraryOptionsContext.tsx'; import { useMetadataServerSettings } from '@/lib/metadata/metadataServerSettings.ts'; -import { Trackers } from '@/lib/data/Trackers.ts'; +import { ChapterType, MangaType, TrackRecordType } from '@/lib/graphql/generated/graphql.ts'; +import { MangaIdInfo } from '@/lib/data/Mangas.ts'; const triStateFilter = ( triState: NullAndUndefined, @@ -35,22 +36,26 @@ const triStateFilterNumber = (triState: NullAndUndefined, count?: numbe () => count === 0, ); -const queryFilter = (query: NullAndUndefined, { title }: TManga): boolean => { +type TMangaQueryFilter = Pick; +const queryFilter = (query: NullAndUndefined, { title }: TMangaQueryFilter): boolean => { if (!query) return true; return title.toLowerCase().includes(query.toLowerCase()); }; -const queryGenreFilter = (query: NullAndUndefined, { genre }: TManga): boolean => { +type TMangaQueryGenreFilter = Pick; +const queryGenreFilter = (query: NullAndUndefined, { genre }: TMangaQueryGenreFilter): boolean => { if (!query) return true; const queries = query.split(',').map((str) => str.toLowerCase().trim()); return queries.every((element) => genre.map((el) => el.toLowerCase()).includes(element)); }; -const trackerFilter = (trackFilters: LibraryOptions['tracker'], manga: TManga): boolean => +type TMangaTrackerFilter = { trackRecords: { nodes: Pick[] } }; +const trackerFilter = (trackFilters: LibraryOptions['tracker'], manga: TMangaTrackerFilter): boolean => Object.entries(trackFilters) .map(([trackFilterId, trackFilterState]) => { - const mangaTrackers = Trackers.getTrackers(manga.trackRecords.nodes); - const isTrackerBound = mangaTrackers.some((tracker) => tracker.id === Number(trackFilterId)); + const isTrackerBound = manga.trackRecords.nodes.some( + (trackRecord) => trackRecord.trackerId === Number(trackFilterId), + ); return triStateFilter( trackFilterState, @@ -60,15 +65,19 @@ const trackerFilter = (trackFilters: LibraryOptions['tracker'], manga: TManga): }) .every((matchesFilter) => matchesFilter); -const filterManga = ( - mangas: TManga[], +type TMangaFilter = TMangaQueryFilter & + TMangaQueryGenreFilter & + TMangaTrackerFilter & + Pick; +const filterManga = ( + mangas: Manga[], query: NullAndUndefined, unread: NullAndUndefined, downloaded: NullAndUndefined, bookmarked: NullAndUndefined, tracker: LibraryOptions['tracker'], ignoreFilters: boolean, -): TManga[] => +): Manga[] => mangas.filter((manga) => { const ignoreFiltersWhileSearching = ignoreFilters && query?.length; const matchesSearch = queryFilter(query, manga) || queryGenreFilter(query, manga); @@ -86,11 +95,16 @@ const sortByNumber = (a: number | string = 0, b: number | string = 0) => Number( const sortByString = (a: string, b: string): number => a.localeCompare(b); -const sortManga = ( - manga: TManga[], +type TMangaSort = Pick & { + lastReadChapter?: Pick | null; + latestUploadedChapter?: Pick | null; + latestFetchedChapter?: Pick | null; +}; +const sortManga = ( + manga: Manga[], sort: NullAndUndefined, desc: NullAndUndefined, -): TManga[] => { +): Manga[] => { const result = [...manga]; switch (sort) { @@ -125,7 +139,12 @@ const sortManga = ( return result; }; -export const useGetVisibleLibraryMangas = (mangas: TManga[]) => { +export const useGetVisibleLibraryMangas = ( + mangas: Manga[], +): { + visibleMangas: Manga[]; + showFilteredOutMessage: boolean; +} => { const [query] = useQueryParam('query', StringParam); const { options } = useLibraryOptionsContext(); const { unread, downloaded, bookmarked, tracker } = options; diff --git a/src/components/manga/MangaActionMenuItems.tsx b/src/components/manga/MangaActionMenuItems.tsx index 88e6a881..7e296fae 100644 --- a/src/components/manga/MangaActionMenuItems.tsx +++ b/src/components/manga/MangaActionMenuItems.tsx @@ -19,8 +19,14 @@ import SyncAltIcon from '@mui/icons-material/SyncAlt'; import { Link } from 'react-router-dom'; import SyncIcon from '@mui/icons-material/Sync'; import Dialog from '@mui/material/Dialog'; -import { TManga } from '@/typings.ts'; -import { actionToTranslationKey, MangaAction, MangaDownloadInfo, Mangas, MangaUnreadInfo } from '@/lib/data/Mangas.ts'; +import { + actionToTranslationKey, + MangaAction, + MangaDownloadInfo, + MangaIdInfo, + Mangas, + MangaUnreadInfo, +} from '@/lib/data/Mangas.ts'; import { SelectableCollectionReturnType } from '@/components/collection/useSelectableCollection.ts'; import { MenuItem } from '@/components/menu/MenuItem.tsx'; import { createGetMenuItemTitle, createIsMenuItemDisabled, createShouldShowMenuItem } from '@/components/menu/util.ts'; @@ -29,18 +35,19 @@ import { TrackManga } from '@/components/tracker/TrackManga.tsx'; import { useCategorySelect } from '@/components/navbar/action/useCategorySelect.tsx'; import { ChaptersDownloadActionMenuItems } from '@/components/chapter/ChaptersDownloadActionMenuItems.tsx'; import { NestedMenuItem } from '@/components/menu/NestedMenuItem.tsx'; +import { MangaChapterStatFieldsFragment, MangaType } from '@/lib/graphql/generated/graphql.ts'; const ACTION_DISABLES_SELECTION_MODE: MangaAction[] = ['remove_from_library'] as const; type BaseProps = { onClose: (selectionModeState: boolean) => void; setHideMenu: (hide: boolean) => void }; export type SingleModeProps = { - manga: Pick & MangaDownloadInfo & MangaUnreadInfo; - handleSelection?: SelectableCollectionReturnType['handleSelection']; + manga: Pick & MangaDownloadInfo & MangaUnreadInfo; + handleSelection?: SelectableCollectionReturnType['handleSelection']; }; type SelectModeProps = { - selectedMangas: TManga[]; + selectedMangas: MangaChapterStatFieldsFragment[]; }; type Props = @@ -82,7 +89,7 @@ export const MangaActionMenuItems = ({ onClose(true); }; - const performAction = (action: MangaAction, mangas: TManga[]) => { + const performAction = (action: MangaAction, mangas: MangaIdInfo[]) => { Mangas.performAction(action, manga ? [manga.id] : Mangas.getIds(mangas), { wasManuallyMarkedAsRead: true, }).catch(defaultPromiseErrorHandler(`MangaActionMenuItems:performAction(${action})`)); @@ -150,7 +157,7 @@ export const MangaActionMenuItems = ({ )} {isSingleMode && ( diff --git a/src/components/manga/MangaCard.types.tsx b/src/components/manga/MangaCard.types.tsx index 7b3b5e8c..c7a7f434 100644 --- a/src/components/manga/MangaCard.types.tsx +++ b/src/components/manga/MangaCard.types.tsx @@ -8,24 +8,37 @@ import { LongPressPointerHandlers, LongPressResult } from 'use-long-press/lib/use-long-press.types'; import { PopupState } from 'material-ui-popup-state/hooks'; -import { TManga, TPartialManga } from '@/typings.ts'; import { GridLayout } from '@/components/context/LibraryOptionsContext.tsx'; import { SelectableCollectionReturnType } from '@/components/collection/useSelectableCollection.ts'; import { useManageMangaLibraryState } from '@/components/manga/useManageMangaLibraryState.tsx'; +import { MangaChapterCountInfo, MangaThumbnailInfo } from '@/lib/data/Mangas.ts'; +import { ChapterType, MangaType } from '@/lib/graphql/generated/graphql.ts'; +import { SingleModeProps } from '@/components/manga/MangaActionMenuItems.tsx'; export type MangaCardMode = 'default' | 'source' | 'migrate.search' | 'migrate.select' | 'duplicate'; +type MangaCardBaseProps = Pick & + SingleModeProps['manga'] & + Partial> & + MangaChapterCountInfo & { + latestReadChapter?: Pick | null; + firstUnreadChapter?: Pick | null; + }; + +type MangaCardSpecificProps = MangaCardBaseProps & MangaThumbnailInfo; + export interface MangaCardProps { - manga: TPartialManga; + manga: MangaCardBaseProps; gridLayout?: GridLayout; inLibraryIndicator?: boolean; selected?: boolean | null; - handleSelection?: SelectableCollectionReturnType['handleSelection']; + handleSelection?: SelectableCollectionReturnType['handleSelection']; mode?: MangaCardMode; } -export type SpecificMangaCardProps = MangaCardProps & +export type SpecificMangaCardProps = Omit & Pick, 'isInLibrary'> & { + manga: MangaCardSpecificProps; longPressBind: LongPressResult; popupState: PopupState; handleClick: (event: React.MouseEvent | React.TouchEvent) => void; diff --git a/src/components/manga/MangaDetails.tsx b/src/components/manga/MangaDetails.tsx index 7e364519..deb4c762 100644 --- a/src/components/manga/MangaDetails.tsx +++ b/src/components/manga/MangaDetails.tsx @@ -10,22 +10,21 @@ import FavoriteIcon from '@mui/icons-material/Favorite'; import FavoriteBorderIcon from '@mui/icons-material/FavoriteBorder'; import PublicIcon from '@mui/icons-material/Public'; import { styled } from '@mui/material/styles'; -import React, { ComponentProps, useEffect, useMemo } from 'react'; +import { ComponentProps, useEffect, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { t as translate } from 'i18next'; import Link from '@mui/material/Link'; import Typography from '@mui/material/Typography'; import { useLongPress } from 'use-long-press'; -import { TManga } from '@/typings'; import { makeToast } from '@/components/util/Toast'; -import { Mangas } from '@/lib/data/Mangas.ts'; +import { Mangas, MangaThumbnailInfo, MangaTrackRecordInfo } from '@/lib/data/Mangas.ts'; import { SpinnerImage } from '@/components/util/SpinnerImage.tsx'; import { CustomIconButton } from '@/components/atoms/CustomIconButton'; import { TrackMangaButton } from '@/components/manga/TrackMangaButton.tsx'; import { useManageMangaLibraryState } from '@/components/manga/useManageMangaLibraryState.tsx'; import { Metadata as BaseMetadata } from '@/components/atoms/Metadata.tsx'; import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts'; -import { SourceType } from '@/lib/graphql/generated/graphql.ts'; +import { MangaType, SourceType } from '@/lib/graphql/generated/graphql.ts'; const DetailsWrapper = styled('div')(({ theme }) => ({ width: '100%', @@ -156,10 +155,6 @@ const OpenSourceButton = ({ url }: { url?: string | null }) => { return button; }; -interface IProps { - manga: TManga; -} - function getSourceName(source?: Pick | null): string { if (!source) { return translate('global.label.unknown'); @@ -172,7 +167,18 @@ function getValueOrUnknown(val?: string | null) { return val ?? translate('global.label.unknown'); } -export const MangaDetails: React.FC = ({ manga }) => { +export const MangaDetails = ({ + manga, +}: { + manga: Pick< + MangaType, + 'id' | 'title' | 'author' | 'artist' | 'status' | 'inLibrary' | 'realUrl' | 'description' | 'genre' + > & + MangaThumbnailInfo & + MangaTrackRecordInfo & { + source?: Pick | null; + }; +}) => { const { t } = useTranslation(); useEffect(() => { diff --git a/src/components/manga/MangaOptionButton.tsx b/src/components/manga/MangaOptionButton.tsx index 30ef7609..b83868fd 100644 --- a/src/components/manga/MangaOptionButton.tsx +++ b/src/components/manga/MangaOptionButton.tsx @@ -16,8 +16,8 @@ import MoreVertIcon from '@mui/icons-material/MoreVert'; import { PopupState } from 'material-ui-popup-state/hooks'; import { bindTrigger } from 'material-ui-popup-state'; import { SelectableCollectionReturnType } from '@/components/collection/useSelectableCollection.ts'; -import { TManga } from '@/typings.ts'; import { MediaQuery } from '@/lib/ui/MediaQuery.tsx'; +import { MangaType } from '@/lib/graphql/generated/graphql.ts'; export const MangaOptionButton = forwardRef( ( @@ -30,7 +30,7 @@ export const MangaOptionButton = forwardRef( }: { id: number; selected?: boolean | null; - handleSelection?: SelectableCollectionReturnType['handleSelection']; + handleSelection?: SelectableCollectionReturnType['handleSelection']; asCheckbox?: boolean; popupState: PopupState; }, diff --git a/src/components/manga/MangaToolbarMenu.tsx b/src/components/manga/MangaToolbarMenu.tsx index e8a3d6e9..3e08e74c 100644 --- a/src/components/manga/MangaToolbarMenu.tsx +++ b/src/components/manga/MangaToolbarMenu.tsx @@ -21,11 +21,11 @@ import { Link } from 'react-router-dom'; import SyncAltIcon from '@mui/icons-material/SyncAlt'; import { useTheme } from '@mui/material/styles'; import useMediaQuery from '@mui/material/useMediaQuery'; -import { TManga } from '@/typings.ts'; import { useCategorySelect } from '@/components/navbar/action/useCategorySelect.tsx'; +import { MangaType } from '@/lib/graphql/generated/graphql.ts'; interface IProps { - manga: TManga; + manga: Pick; onRefresh: () => any; refreshing: boolean; } @@ -64,7 +64,7 @@ export const MangaToolbarMenu = ({ manga, onRefresh, refreshing }: IProps) => { <> @@ -122,7 +122,7 @@ export const MangaToolbarMenu = ({ manga, onRefresh, refreshing }: IProps) => { diff --git a/src/components/manga/TrackMangaButton.tsx b/src/components/manga/TrackMangaButton.tsx index 3a57cd65..8a58fb6b 100644 --- a/src/components/manga/TrackMangaButton.tsx +++ b/src/components/manga/TrackMangaButton.tsx @@ -16,20 +16,21 @@ import { requestManager } from '@/lib/requests/RequestManager.ts'; import { makeToast } from '@/components/util/Toast.tsx'; import { TrackManga } from '@/components/tracker/TrackManga.tsx'; import { Trackers } from '@/lib/data/Trackers.ts'; -import { TManga } from '@/typings.ts'; import { CustomIconButton } from '@/components/atoms/CustomIconButton.tsx'; -import { GetTrackersSettingsQuery } from '@/lib/graphql/generated/graphql.ts'; +import { GetTrackersSettingsQuery, MangaType } from '@/lib/graphql/generated/graphql.ts'; import { GET_TRACKERS_SETTINGS } from '@/lib/graphql/queries/TrackerQuery.ts'; +import { MangaTrackRecordInfo } from '@/lib/data/Mangas.ts'; -export const TrackMangaButton = ({ manga }: { manga: TManga }) => { +export const TrackMangaButton = ({ manga }: { manga: MangaTrackRecordInfo & Pick }) => { const { t } = useTranslation(); const navigate = useNavigate(); const trackerList = requestManager.useGetTrackerList(GET_TRACKERS_SETTINGS); + const trackers = trackerList.data?.trackers.nodes ?? []; const mangaTrackers = manga.trackRecords.nodes; - const loggedInTrackers = Trackers.getLoggedIn(trackerList.data?.trackers.nodes ?? []); - const trackersInUse = Trackers.getLoggedIn(Trackers.getTrackers(mangaTrackers)); + const loggedInTrackers = Trackers.getLoggedIn(trackers); + const trackersInUse = Trackers.getLoggedIn(Trackers.getTrackers(mangaTrackers, trackers)); const handleClick = (openPopup: () => void) => { if (trackerList.error) { diff --git a/src/components/manga/useManageMangaLibraryState.tsx b/src/components/manga/useManageMangaLibraryState.tsx index cadf70ad..c1aed2a1 100644 --- a/src/components/manga/useManageMangaLibraryState.tsx +++ b/src/components/manga/useManageMangaLibraryState.tsx @@ -16,19 +16,18 @@ import { getMetadataServerSettings } from '@/lib/metadata/metadataServerSettings import { Categories } from '@/lib/data/Categories.ts'; import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts'; import { Mangas } from '@/lib/data/Mangas.ts'; -import { TManga } from '@/typings.ts'; import { awaitConfirmation } from '@/lib/ui/AwaitableDialog.tsx'; -import { GetCategoriesBaseQuery, GetCategoriesBaseQueryVariables } 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'; export const useManageMangaLibraryState = ( - manga: Pick, + manga: Pick & Partial>, confirmRemoval: boolean = false, ) => { const { t } = useTranslation(); const navigate = useNavigate(); - const [isInLibrary, setIsInLibrary] = useState(manga.inLibrary); + const [isInLibrary, setIsInLibrary] = useState(!!manga.inLibrary); const addToLibrary = useCallback( (didSubmit: boolean, addToCategories: number[] = [], removeFromCategories: number[] = []) => { @@ -162,6 +161,6 @@ export const useManageMangaLibraryState = ( * * To work around this issue, the currently known in library state gets returned here */ - isInLibrary: Mangas.getFromCache(manga.id)?.inLibrary ?? isInLibrary, + isInLibrary: Mangas.getFromCache(manga.id)?.inLibrary ?? isInLibrary, }; }; diff --git a/src/components/navbar/ReaderNavBar.tsx b/src/components/navbar/ReaderNavBar.tsx index 5cc7e9be..a62fdbc5 100644 --- a/src/components/navbar/ReaderNavBar.tsx +++ b/src/components/navbar/ReaderNavBar.tsx @@ -27,12 +27,13 @@ import ListItem from '@mui/material/ListItem'; import ListItemText from '@mui/material/ListItemText'; import Collapse from '@mui/material/Collapse'; import { useTranslation } from 'react-i18next'; -import { AllowedMetadataValueTypes, ChapterOffset, IReaderSettings, TManga } from '@/typings'; +import { AllowedMetadataValueTypes, ChapterOffset, IReaderSettings } from '@/typings'; import { ReaderSettingsOptions } from '@/components/reader/ReaderSettingsOptions'; import { useBackButton } from '@/util/useBackButton.ts'; import { Select } from '@/components/atoms/Select.tsx'; import { getOptionForDirection } from '@/theme.ts'; import { ChapterType } from '@/lib/graphql/generated/graphql.ts'; +import { MangaChapterCountInfo, MangaIdInfo } from '@/lib/data/Mangas.ts'; const Root = styled('div')({ zIndex: 10, @@ -123,7 +124,7 @@ const OpenDrawerButton = styled(IconButton)(({ theme }) => ({ interface IProps { settings: IReaderSettings; setSettingValue: (key: keyof IReaderSettings, value: AllowedMetadataValueTypes, persist?: boolean) => void; - manga: TManga; + manga: MangaIdInfo & MangaChapterCountInfo; chapter: Pick; chapters: Pick[]; curPage: number; diff --git a/src/components/navbar/action/CategorySelect.tsx b/src/components/navbar/action/CategorySelect.tsx index 588ac1a0..4f0efd82 100644 --- a/src/components/navbar/action/CategorySelect.tsx +++ b/src/components/navbar/action/CategorySelect.tsx @@ -25,8 +25,14 @@ import { CheckboxInput } from '@/components/atoms/CheckboxInput.tsx'; import { makeToast } from '@/components/util/Toast.tsx'; import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts'; import { updateMetadataServerSettings } from '@/lib/metadata/metadataServerSettings.ts'; -import { GetCategoriesBaseQuery, GetCategoriesBaseQueryVariables } from '@/lib/graphql/generated/graphql.ts'; +import { + GetCategoriesBaseQuery, + GetCategoriesBaseQueryVariables, + GetMangaCategoriesQuery, + GetMangaCategoriesQueryVariables, +} from '@/lib/graphql/generated/graphql.ts'; import { GET_CATEGORIES_BASE } from '@/lib/graphql/queries/CategoryQuery.ts'; +import { GET_MANGA_CATEGORIES } from '@/lib/graphql/queries/MangaQuery.ts'; type BaseProps = { open: boolean; @@ -47,7 +53,11 @@ export type CategorySelectProps = | (BaseProps & PropertiesNever & MultiMangaModeProps); const useGetMangaCategoryIds = (mangaId: number | undefined): number[] => { - const { data: mangaResult } = requestManager.useGetManga(mangaId ?? -1, { skip: mangaId === undefined }); + const { data: mangaResult } = requestManager.useGetManga( + GET_MANGA_CATEGORIES, + mangaId ?? -1, + { skip: mangaId === undefined }, + ); return useMemo(() => { if (mangaId === undefined || !mangaResult) { @@ -90,6 +100,7 @@ export function CategorySelect(props: CategorySelectProps) { const [doNotShowAddToLibraryDialogAgain, setDoNotShowAddToLibraryDialogAgain] = useState(false); const mangaCategoryIds = useGetMangaCategoryIds(mangaId); + const { data } = requestManager.useGetCategories( GET_CATEGORIES_BASE, ); diff --git a/src/components/source/BaseMangaGrid.tsx b/src/components/source/BaseMangaGrid.tsx new file mode 100644 index 00000000..fcc8a4ca --- /dev/null +++ b/src/components/source/BaseMangaGrid.tsx @@ -0,0 +1,17 @@ +/* + * 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 { MangaGrid, IMangaGridProps } from '@/components/MangaGrid'; + +type TMangaBaseGrid = Omit; + +export function BaseMangaGrid(props: Omit & { mangas: TMangaBaseGrid[] }) { + const { mangas } = props; + + return ; +} diff --git a/src/components/source/SourceMangaGrid.tsx b/src/components/source/SourceMangaGrid.tsx deleted file mode 100644 index dff95cd4..00000000 --- a/src/components/source/SourceMangaGrid.tsx +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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 { useTranslation } from 'react-i18next'; -import { MangaGrid, IMangaGridProps } from '@/components/MangaGrid'; -import { TPartialManga } from '@/typings.ts'; - -function filterManga(mangas: TPartialManga[]): TPartialManga[] { - return mangas; -} - -export function SourceMangaGrid(props: IMangaGridProps) { - const { t } = useTranslation(); - const { mangas, isLoading, hasNextPage, loadMore, message, messageExtra, gridLayout } = props; - - const filteredManga = filterManga(mangas); - const showFilteredOutMessage = filteredManga.length === 0 && mangas.length > 0; - - return ( - - ); -} diff --git a/src/components/tracker/TrackManga.tsx b/src/components/tracker/TrackManga.tsx index aafe5b6a..4b901033 100644 --- a/src/components/tracker/TrackManga.tsx +++ b/src/components/tracker/TrackManga.tsx @@ -16,11 +16,12 @@ import { EmptyViewAbsoluteCentered } from '@/components/util/EmptyViewAbsoluteCe import { LoadingPlaceholder } from '@/components/util/LoadingPlaceholder.tsx'; import { Trackers } from '@/lib/data/Trackers.ts'; import { TrackerCard, TrackerMode } from '@/components/tracker/TrackerCard.tsx'; -import { TManga } from '@/typings.ts'; import { makeToast } from '@/components/util/Toast.tsx'; import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts'; -import { GetTrackersBindQuery } from '@/lib/graphql/generated/graphql.ts'; +import { GetMangaTrackRecordsQuery, GetTrackersBindQuery, MangaType } from '@/lib/graphql/generated/graphql.ts'; import { GET_TRACKERS_BIND } from '@/lib/graphql/queries/TrackerQuery.ts'; +import { MangaIdInfo } from '@/lib/data/Mangas.ts'; +import { GET_MANGA_TRACK_RECORDS } from '@/lib/graphql/queries/MangaQuery.ts'; const getTrackerMode = (id: number, trackersInUse: number[], searchModeForTracker?: number): TrackerMode => { if (id === searchModeForTracker) { @@ -34,7 +35,7 @@ const getTrackerMode = (id: number, trackersInUse: number[], searchModeForTracke return TrackerMode.UNTRACKED; }; -export const TrackManga = ({ manga }: { manga: Pick }) => { +export const TrackManga = ({ manga }: { manga: MangaIdInfo & Pick }) => { const { t } = useTranslation(); const navigate = useNavigate(); @@ -43,26 +44,32 @@ export const TrackManga = ({ manga }: { manga: Pick(GET_TRACKERS_BIND, { notifyOnNetworkStatusChange: true, }); - const mangaTrackers = manga.trackRecords.nodes; + const trackers = trackerList.data?.trackers.nodes ?? []; - const loggedInTrackers = Trackers.getLoggedIn(trackerList.data?.trackers.nodes ?? []); - const trackersInUse = Trackers.getLoggedIn(Trackers.getTrackers(mangaTrackers)); + const mangaTrackRecordsList = requestManager.useGetManga( + GET_MANGA_TRACK_RECORDS, + manga.id, + ); + const mangaTrackRecords = mangaTrackRecordsList.data?.manga.trackRecords.nodes ?? []; + + const loggedInTrackers = Trackers.getLoggedIn(trackers); + const trackersInUse = Trackers.getLoggedIn(Trackers.getTrackers(mangaTrackRecords, trackers)); const trackersInUseIds = Trackers.getIds(trackersInUse); const isSearchActive = searchModeForTracker !== undefined; const OptionalDialogContent = useMemo(() => (isSearchActive ? Box : DialogContent), [isSearchActive]); useEffect(() => { - Promise.all(manga.trackRecords.nodes.map((trackRecord) => requestManager.fetchTrackBind(trackRecord.id))).catch( - () => makeToast(t('tracking.error.label.could_not_fetch_track_info'), 'error'), + Promise.all(mangaTrackRecords.map((trackRecord) => requestManager.fetchTrackBind(trackRecord.id))).catch(() => + makeToast(t('tracking.error.label.could_not_fetch_track_info'), 'error'), ); - }, [manga.id]); + }, [mangaTrackRecords]); const trackerComponents = useMemo( () => loggedInTrackers.map((tracker) => { const mode = getTrackerMode(tracker.id, trackersInUseIds, searchModeForTracker); - const trackRecord = Trackers.getTrackRecordFor(tracker, manga.trackRecords.nodes); + const trackRecord = Trackers.getTrackRecordFor(tracker, mangaTrackRecords); const isSearchForTracker = mode === TrackerMode.SEARCH; if (isSearchActive && !isSearchForTracker) { @@ -73,27 +80,39 @@ export const TrackManga = ({ manga }: { manga: Pick setSearchModeForTracker(id)} /> ); }), - [trackersInUseIds, searchModeForTracker, manga.id], + [trackersInUseIds, searchModeForTracker, mangaTrackRecords], ); - if (trackerList.error) { + const error = trackerList.error ?? mangaTrackRecordsList.error; + if (error) { return ( trackerList.refetch().catch(defaultPromiseErrorHandler('TrackManga::refetch'))} + messageExtra={error.message} + retry={() => { + if (trackerList.error) { + trackerList.refetch().catch(defaultPromiseErrorHandler('TrackManga::refetch: trackerList')); + } + + if (mangaTrackRecordsList.error) { + mangaTrackRecordsList + .refetch() + .catch(defaultPromiseErrorHandler('TrackManga::refetch: mangaTrackRecordsList')); + } + }} /> ); } - if (trackerList.loading) { + const loading = trackerList.loading || mangaTrackRecordsList.loading; + if (loading) { return ; } diff --git a/src/components/tracker/TrackerCard.tsx b/src/components/tracker/TrackerCard.tsx index a5de4447..2dc4d0d4 100644 --- a/src/components/tracker/TrackerCard.tsx +++ b/src/components/tracker/TrackerCard.tsx @@ -10,6 +10,8 @@ import { TrackerUntrackedCard } from '@/components/tracker/TrackerUntrackedCard. import { TrackerSearch } from '@/components/tracker/TrackerSearch.tsx'; import { TrackerActiveCard } from '@/components/tracker/TrackerActiveCard.tsx'; import { TTrackerBind, TTrackRecordBind } from '@/lib/data/Trackers.ts'; +import { MangaType } from '@/lib/graphql/generated/graphql.ts'; +import { MangaIdInfo } from '@/lib/data/Mangas.ts'; export enum TrackerMode { UNTRACKED, @@ -19,13 +21,13 @@ export enum TrackerMode { export const TrackerCard = ({ tracker, - mangaId, + manga, trackRecord, mode, setSearchMode, }: { tracker: TTrackerBind; - mangaId: number; + manga: MangaIdInfo & Pick; trackRecord?: TTrackRecordBind; mode: TrackerMode; setSearchMode: (id?: number) => void; @@ -37,7 +39,7 @@ export const TrackerCard = ({ if (mode === TrackerMode.SEARCH) { return ( setSearchMode(undefined)} @@ -46,7 +48,7 @@ export const TrackerCard = ({ } if (mode === TrackerMode.INFO && !trackRecord) { - throw new Error(`TrackerCard: unable to find track record for tracker "${tracker.id}" of manga "${mangaId}"}`); + throw new Error(`TrackerCard: unable to find track record for tracker "${tracker.id}" of manga "${manga.id}"}`); } return ( diff --git a/src/components/tracker/TrackerSearch.tsx b/src/components/tracker/TrackerSearch.tsx index ca0efe63..afc736c1 100644 --- a/src/components/tracker/TrackerSearch.tsx +++ b/src/components/tracker/TrackerSearch.tsx @@ -31,24 +31,23 @@ import { TrackerMangaCard } from '@/components/tracker/TrackerMangaCard.tsx'; import { DIALOG_PADDING } from '@/components/tracker/constants.ts'; import { getOptionForDirection } from '@/theme.ts'; import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts'; +import { MangaType } from '@/lib/graphql/generated/graphql.ts'; +import { MangaIdInfo } from '@/lib/data/Mangas.ts'; export const TrackerSearch = ({ - mangaId, + manga, tracker, closeSearchMode, trackedId, }: { - mangaId: number; + manga: MangaIdInfo & Pick; tracker: Pick; closeSearchMode: () => void; trackedId?: string; }) => { const { t } = useTranslation(); - // can't be undefined, since this can only be opened from the manga screen - const manga = requestManager.useGetManga(mangaId); - - const [searchString, setSearchString] = useState(manga.data!.manga.title); + const [searchString, setSearchString] = useState(manga.title); const [tmpSearchString, setTmpSearchString] = useState(searchString); const [selectedTrackerRemoteId, setSelectedTrackerRemoteId] = useState(trackedId); @@ -62,7 +61,7 @@ export const TrackerSearch = ({ setSelectedTrackerRemoteId(trackedId); return () => - trackerSearch.abortRequest(new Error(`MangaTrackerSearchCard(${tracker.id}, ${mangaId}): search changed`)); + trackerSearch.abortRequest(new Error(`MangaTrackerSearchCard(${tracker.id}, ${manga.id}): search changed`)); }, [searchString]); const [bindTracker, bindTrackerMutation] = requestManager.useBindTracker(); @@ -82,7 +81,7 @@ export const TrackerSearch = ({ return; } - bindTracker({ variables: { mangaId, remoteId: selectedTrackerRemoteId, trackerId: tracker.id } }) + bindTracker({ variables: { mangaId: manga.id, remoteId: selectedTrackerRemoteId, trackerId: tracker.id } }) .then(() => { makeToast(t('manga.action.track.add.label.success'), 'success'); closeSearchMode(); diff --git a/src/lib/data/Chapters.ts b/src/lib/data/Chapters.ts index 21e1db03..91adcee3 100644 --- a/src/lib/data/Chapters.ts +++ b/src/lib/data/Chapters.ts @@ -9,12 +9,13 @@ import { t as translate } from 'i18next'; import gql from 'graphql-tag'; import { DocumentNode } from '@apollo/client'; -import { ChapterOffset, TManga, TranslationKey } from '@/typings.ts'; +import { ChapterOffset, TranslationKey } from '@/typings.ts'; import { makeToast } from '@/components/util/Toast.tsx'; import { requestManager } from '@/lib/requests/RequestManager.ts'; import { getMetadataServerSettings } from '@/lib/metadata/metadataServerSettings.ts'; import { ChapterListFieldsFragment, ChapterType } from '@/lib/graphql/generated/graphql.ts'; import { CHAPTER_LIST_FIELDS } from '@/lib/graphql/fragments/ChapterFragments.ts'; +import { MangaIdInfo } from '@/lib/data/Mangas.ts'; export type ChapterAction = 'download' | 'delete' | 'bookmark' | 'unbookmark' | 'mark_as_read' | 'mark_as_unread'; @@ -209,7 +210,7 @@ export class Chapters { static async markAsRead( chapters: (ChapterDownloadInfo & ChapterBookmarkInfo)[], wasManuallyMarkedAsRead: boolean = false, - trackProgressMangaId?: TManga['id'], + trackProgressMangaId?: MangaIdInfo['id'], ): Promise { const { deleteChaptersManuallyMarkedRead, deleteChaptersWithBookmark, updateProgressManualMarkRead } = await getMetadataServerSettings(); @@ -279,7 +280,7 @@ export class Chapters { }: Action extends 'mark_as_read' ? { wasManuallyMarkedAsRead: boolean; - trackProgressMangaId?: TManga['id']; + trackProgressMangaId?: MangaIdInfo['id']; chapters: (ChapterDownloadInfo & ChapterBookmarkInfo & ChapterReadInfo)[]; } : { diff --git a/src/lib/data/Mangas.ts b/src/lib/data/Mangas.ts index 008d93ec..8b21a6cd 100644 --- a/src/lib/data/Mangas.ts +++ b/src/lib/data/Mangas.ts @@ -8,19 +8,26 @@ import { t as translate } from 'i18next'; import { DocumentNode } from '@apollo/client/core'; -import { MetadataMigrationSettings, TManga, TranslationKey } from '@/typings.ts'; +import { MetadataMigrationSettings, TranslationKey } from '@/typings.ts'; import { requestManager } from '@/lib/requests/RequestManager.ts'; import { ChapterConditionInput, + GetMangasBaseQuery, + GetMangasBaseQueryVariables, GetMangasChapterIdsWithStateQuery, GetMangaToMigrateQuery, GetMangaToMigrateToFetchMutation, + MangaBaseFieldsFragment, + MangaReaderFieldsFragment, + MangaType, + TrackRecordType, UpdateMangaCategoriesPatchInput, } from '@/lib/graphql/generated/graphql.ts'; import { Chapters } from '@/lib/data/Chapters.ts'; import { makeToast } from '@/components/util/Toast.tsx'; import { getMetadataServerSettings } from '@/lib/metadata/metadataServerSettings.ts'; -import { FULL_MANGA_FIELDS } from '@/lib/graphql/Fragments.ts'; +import { GET_MANGAS_BASE } from '@/lib/graphql/queries/MangaQuery.ts'; +import { MANGA_BASE_FIELDS } from '@/lib/graphql/fragments/MangaFragments.ts'; export type MangaAction = | 'download' @@ -108,10 +115,16 @@ export const actionToTranslationKey: { }, }; -export type MangaChapterCountInfo = { chapters: Pick }; -export type MangaDownloadInfo = Pick & MangaChapterCountInfo; -export type MangaUnreadInfo = Pick & MangaChapterCountInfo; -export type MangaThumbnailInfo = Pick; +export type TMangaReader = MangaReaderFieldsFragment; + +export type MangaIdInfo = Pick; +export type MangaChapterCountInfo = { chapters: Pick }; +export type MangaDownloadInfo = Pick & MangaChapterCountInfo; +export type MangaUnreadInfo = Pick & MangaChapterCountInfo; +export type MangaThumbnailInfo = Pick; +export type MangaTrackRecordInfo = MangaIdInfo & { + trackRecords: { nodes: Pick[] }; +}; export type MigrateMode = 'copy' | 'migrate'; @@ -162,14 +175,14 @@ type PerformActionOptions = Action extends 'mark_as_ : DefaultActionOption; export class Mangas { - static getIds(mangas: { id: number }[]): number[] { + static getIds(mangas: MangaIdInfo[]): number[] { return mangas.map((manga) => manga.id); } - static getFromCache( - id: number, - fragment: DocumentNode = FULL_MANGA_FIELDS, - fragmentName: string = 'FULL_MANGA_FIELDS', + static getFromCache( + id: MangaIdInfo['id'], + fragment: DocumentNode = MANGA_BASE_FIELDS, + fragmentName: string = 'MANGA_BASE_FIELDS', ): T | null { return requestManager.graphQLClient.client.cache.readFragment({ id: requestManager.graphQLClient.client.cache.identify({ @@ -236,8 +249,10 @@ export class Mangas { return requestManager.getValidImgUrlFor(thumbnailUrl); } - static getDuplicateLibraryMangas(title: string): ReturnType { - return requestManager.getMangas({ + static getDuplicateLibraryMangas( + title: string, + ): ReturnType> { + return requestManager.getMangas(GET_MANGAS_BASE, { condition: { inLibrary: true }, filter: { title: { likeInsensitive: title } }, }); @@ -429,7 +444,7 @@ export class Mangas { } static async migrate( - mangaId: number, + mangaId: MangaIdInfo['id'], mangaIdToMigrateTo: number, { mode, diff --git a/src/lib/data/Trackers.ts b/src/lib/data/Trackers.ts index 4084cfd3..4e782b62 100644 --- a/src/lib/data/Trackers.ts +++ b/src/lib/data/Trackers.ts @@ -49,12 +49,13 @@ export type TTrackerSearch = TTrackerBase & Pick; export type TTrackerBind = TTrackerBase & Pick; +type TrackerIdInfo = Pick; type LoggedInInfo = Pick; -type TrackRecordTrackerInfo = { tracker: TTrackerBind }; +type TrackRecordTrackerInfo = Pick; export class Trackers { - static getIds(trackers: { id: number }[]): number[] { + static getIds(trackers: TrackerIdInfo[]): number[] { return trackers.map((tracker) => tracker.id); } @@ -74,16 +75,19 @@ export class Trackers { return trackers.filter(this.isLoggedIn); } - static getTrackers( + static getTrackers( trackRecords: TrackRecord[], - ): TrackRecord['tracker'][] { - return trackRecords.map((trackRecord) => trackRecord.tracker); + trackers: Tracker[], + ): Tracker[] { + return trackRecords + .map((trackRecord) => trackers.find((tracker) => tracker.id === trackRecord.trackerId)) + .filter((tracker) => !!tracker); } static getTrackRecordFor( - tracker: { id: number }, + tracker: TrackerIdInfo, trackRecords: TrackRecord[], ): TrackRecord | undefined { - return trackRecords.find((trackRecord) => trackRecord.tracker.id === tracker.id); + return trackRecords.find((trackRecord) => trackRecord.trackerId === tracker.id); } } diff --git a/src/lib/graphql/Fragments.ts b/src/lib/graphql/Fragments.ts index cdc0dea7..a3d45127 100644 --- a/src/lib/graphql/Fragments.ts +++ b/src/lib/graphql/Fragments.ts @@ -7,9 +7,6 @@ */ import gql from 'graphql-tag'; -import { SOURCE_BASE_FIELDS } from '@/lib/graphql/fragments/SourceFragments.ts'; -import { TRACKER_BIND_FIELDS } from '@/lib/graphql/fragments/TrackFragments.ts'; -import { TRACK_RECORD_BIND_FIELDS } from '@/lib/graphql/fragments/TrackRecordFragments.ts'; export const PAGE_INFO = gql` fragment PAGE_INFO on PageInfo { @@ -27,147 +24,6 @@ export const GLOBAL_METADATA = gql` } `; -export const FULL_CATEGORY_FIELDS = gql` - fragment FULL_CATEGORY_FIELDS on CategoryType { - default - id - includeInUpdate - includeInDownload - name - order - meta { - key - value - } - mangas { - totalCount - } - } -`; - -export const FULL_TRACK_RECORD_FIELDS = gql` - ${TRACK_RECORD_BIND_FIELDS} - ${TRACKER_BIND_FIELDS} - - fragment FULL_TRACK_RECORD_FIELDS on TrackRecordType { - ...TRACK_RECORD_BIND_FIELDS - tracker { - ...TRACKER_BIND_FIELDS - } - } -`; - -export const BASE_MANGA_FIELDS = gql` - ${SOURCE_BASE_FIELDS} - ${FULL_TRACK_RECORD_FIELDS} - fragment BASE_MANGA_FIELDS on MangaType { - artist - author - chaptersLastFetchedAt - description - genre - id - inLibrary - inLibraryAt - initialized - lastFetchedAt - meta { - key - value - } - realUrl - source { - ...SOURCE_BASE_FIELDS - } - status - thumbnailUrl - thumbnailUrlLastFetched - title - url - trackRecords { - totalCount - nodes { - ...FULL_TRACK_RECORD_FIELDS - } - } - } -`; - -export const PARTIAL_MANGA_FIELDS = gql` - ${BASE_MANGA_FIELDS} - ${FULL_CATEGORY_FIELDS} - fragment PARTIAL_MANGA_FIELDS on MangaType { - ...BASE_MANGA_FIELDS - unreadCount - downloadCount - bookmarkCount - categories { - nodes { - ...FULL_CATEGORY_FIELDS - } - totalCount - } - chapters { - totalCount - } - } -`; - -export const FULL_CHAPTER_FIELDS = gql` - fragment FULL_CHAPTER_FIELDS on ChapterType { - chapterNumber - fetchedAt - id - isBookmarked - isDownloaded - isRead - lastPageRead - lastReadAt - mangaId - manga { - id - title - inLibrary - thumbnailUrl - lastFetchedAt - } - meta { - key - value - } - name - pageCount - realUrl - scanlator - sourceOrder - uploadDate - url - } -`; - -export const FULL_MANGA_FIELDS = gql` - ${PARTIAL_MANGA_FIELDS} - ${FULL_CHAPTER_FIELDS} - fragment FULL_MANGA_FIELDS on MangaType { - ...PARTIAL_MANGA_FIELDS - lastReadChapter { - ...FULL_CHAPTER_FIELDS - } - latestReadChapter { - ...FULL_CHAPTER_FIELDS - } - latestFetchedChapter { - ...FULL_CHAPTER_FIELDS - } - latestUploadedChapter { - ...FULL_CHAPTER_FIELDS - } - firstUnreadChapter { - ...FULL_CHAPTER_FIELDS - } - } -`; - export const ABOUT_WEBUI = gql` fragment ABOUT_WEBUI on AboutWebUI { channel diff --git a/src/lib/graphql/fragments/ChapterFragments.ts b/src/lib/graphql/fragments/ChapterFragments.ts index 0ed89fa5..b2acd4ac 100644 --- a/src/lib/graphql/fragments/ChapterFragments.ts +++ b/src/lib/graphql/fragments/ChapterFragments.ts @@ -7,19 +7,7 @@ */ import gql from 'graphql-tag'; - -const MANGA_BASE_FIELDS = gql` - fragment MANGA_BASE_FIELDS on MangaType { - id - title - - thumbnailUrl - thumbnailUrlLastFetched - - inLibrary - initialized - } -`; +import { MANGA_BASE_FIELDS } from '@/lib/graphql/fragments/MangaFragments.ts'; export const CHAPTER_BASE_FIELDS = gql` fragment CHAPTER_BASE_FIELDS on ChapterType { diff --git a/src/lib/graphql/fragments/MangaFragments.ts b/src/lib/graphql/fragments/MangaFragments.ts new file mode 100644 index 00000000..816c28c4 --- /dev/null +++ b/src/lib/graphql/fragments/MangaFragments.ts @@ -0,0 +1,144 @@ +/* + * 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 gql from 'graphql-tag'; + +export const MANGA_BASE_FIELDS = gql` + fragment MANGA_BASE_FIELDS on MangaType { + id + title + + thumbnailUrl + thumbnailUrlLastFetched + inLibrary + initialized + sourceId + } +`; + +export const MANGA_CHAPTER_STAT_FIELDS = gql` + fragment MANGA_CHAPTER_STAT_FIELDS on MangaType { + id + unreadCount + downloadCount + bookmarkCount + + chapters { + totalCount + } + } +`; + +export const MANGA_READER_FIELDS = gql` + ${MANGA_BASE_FIELDS} + + fragment MANGA_READER_FIELDS on MangaType { + ...MANGA_BASE_FIELDS + + meta { + key + value + } + + chapters { + totalCount + } + + trackRecords { + totalCount + } + } +`; + +export const MANGA_LIBRARY_FIELDS = gql` + ${MANGA_BASE_FIELDS} + ${MANGA_CHAPTER_STAT_FIELDS} + + fragment MANGA_LIBRARY_FIELDS on MangaType { + ...MANGA_BASE_FIELDS + ...MANGA_CHAPTER_STAT_FIELDS + + genre + lastFetchedAt + inLibraryAt + + trackRecords { + totalCount + + nodes { + id + trackerId + } + } + + firstUnreadChapter { + id + sourceOrder + } + lastReadChapter { + id + sourceOrder + lastReadAt + } + latestReadChapter { + id + sourceOrder + lastReadAt + } + latestFetchedChapter { + id + fetchedAt + } + latestUploadedChapter { + id + uploadDate + } + } +`; + +export const MANGA_SCREEN_FIELDS = gql` + ${MANGA_LIBRARY_FIELDS} + + fragment MANGA_SCREEN_FIELDS on MangaType { + ...MANGA_LIBRARY_FIELDS + + artist + author + description + + status + realUrl + + sourceId + source { + id + displayName + } + + trackRecords { + totalCount + + nodes { + id + trackerId + } + } + } +`; + +export const MANGA_LIBRARY_DUPLICATE_SCREEN_FIELDS = gql` + ${MANGA_BASE_FIELDS} + ${MANGA_CHAPTER_STAT_FIELDS} + + fragment MANGA_LIBRARY_DUPLICATE_SCREEN_FIELDS on MangaType { + ...MANGA_BASE_FIELDS + ...MANGA_CHAPTER_STAT_FIELDS + + description + } +`; diff --git a/src/lib/graphql/fragments/UpdaterFragments.ts b/src/lib/graphql/fragments/UpdaterFragments.ts index 89af5aa5..ee54a6bb 100644 --- a/src/lib/graphql/fragments/UpdaterFragments.ts +++ b/src/lib/graphql/fragments/UpdaterFragments.ts @@ -7,7 +7,7 @@ */ import gql from 'graphql-tag'; -import { FULL_MANGA_FIELDS } from '@/lib/graphql/Fragments.ts'; +import { MANGA_CHAPTER_STAT_FIELDS } from '@/lib/graphql/fragments/MangaFragments.ts'; const UPDATER_MANGA_FIELDS = gql` fragment UPDATER_MANGA_FIELDS on MangaType { @@ -19,7 +19,7 @@ const UPDATER_MANGA_FIELDS = gql` export const UPDATER_SUBSCRIPTION_FIELDS = gql` ${UPDATER_MANGA_FIELDS} - ${FULL_MANGA_FIELDS} + ${MANGA_CHAPTER_STAT_FIELDS} fragment UPDATER_SUBSCRIPTION_FIELDS on UpdateStatus { isRunning @@ -28,7 +28,7 @@ export const UPDATER_SUBSCRIPTION_FIELDS = gql` mangas { totalCount nodes { - ...FULL_MANGA_FIELDS + ...MANGA_CHAPTER_STAT_FIELDS } } } diff --git a/src/lib/graphql/generated/apollo-helpers.ts b/src/lib/graphql/generated/apollo-helpers.ts index 2c9a59b9..d1118e27 100644 --- a/src/lib/graphql/generated/apollo-helpers.ts +++ b/src/lib/graphql/generated/apollo-helpers.ts @@ -1,7 +1,7 @@ import {FieldPolicy, FieldReadFunction, Reference, TypePolicies, TypePolicy} from '@apollo/client/cache'; import { GetChaptersMangaQuery, GetDownloadStatusQueryVariables, GetGlobalMetadataQueryVariables, - GetMangaQueryVariables, GetSourceBrowseQueryVariables, GetUpdateStatusQueryVariables, GetWebuiUpdateStatusQueryVariables, + GetMangaScreenQueryVariables, GetSourceBrowseQueryVariables, GetUpdateStatusQueryVariables, GetWebuiUpdateStatusQueryVariables, } from "@/lib/graphql/generated/graphql.ts"; import {FieldFunctionOptions} from "@apollo/client/cache/inmemory/policies"; export type AboutServerPayloadKeySpecifier = ('buildTime' | 'buildType' | 'discord' | 'github' | 'name' | 'revision' | 'version' | AboutServerPayloadKeySpecifier)[]; @@ -583,7 +583,7 @@ export type QueryFieldPolicy = { extensions?: FieldPolicy | FieldReadFunction, getWebUIUpdateStatus?: FieldPolicy> | FieldReadFunction>, lastUpdateTimestamp?: FieldPolicy | FieldReadFunction, - manga?: FieldPolicy> | FieldReadFunction>, + manga?: FieldPolicy> | FieldReadFunction>, mangas?: FieldPolicy | FieldReadFunction, meta?: FieldPolicy> | FieldReadFunction>, metas?: FieldPolicy | FieldReadFunction, diff --git a/src/lib/graphql/generated/graphql.ts b/src/lib/graphql/generated/graphql.ts index c0d6cdd7..d1f1ee74 100644 --- a/src/lib/graphql/generated/graphql.ts +++ b/src/lib/graphql/generated/graphql.ts @@ -2588,20 +2588,6 @@ export type PageInfoFragment = { __typename?: 'PageInfo', endCursor?: string | n export type GlobalMetadataFragment = { __typename?: 'GlobalMetaType', key: string, value: string }; -export type FullCategoryFieldsFragment = { __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeOrExclude, includeInDownload: IncludeOrExclude, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }; - -export type UpdaterCategoryFieldsFragment = { __typename?: 'CategoryType', id: number, name: string, includeInUpdate: IncludeOrExclude, includeInDownload: IncludeOrExclude }; - -export type FullTrackRecordFieldsFragment = { __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string, tracker: { __typename?: 'TrackerType', icon: string, supportsTrackDeletion?: boolean | null, scores: Array, id: number, name: string, isLoggedIn: boolean, isTokenExpired: boolean, statuses: Array<{ __typename?: 'TrackStatusType', name: string, value: number }>, trackRecords: { __typename?: 'TrackRecordNodeList', nodes: Array<{ __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string }> } } }; - -export type BaseMangaFieldsFragment = { __typename?: 'MangaType', artist?: string | null, author?: string | null, chaptersLastFetchedAt?: string | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: string, initialized: boolean, lastFetchedAt?: string | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, thumbnailUrlLastFetched?: string | null, title: string, url: string, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', id: string, name: string, displayName: string } | null, trackRecords: { __typename?: 'TrackRecordNodeList', totalCount: number, nodes: Array<{ __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string, tracker: { __typename?: 'TrackerType', icon: string, supportsTrackDeletion?: boolean | null, scores: Array, id: number, name: string, isLoggedIn: boolean, isTokenExpired: boolean, statuses: Array<{ __typename?: 'TrackStatusType', name: string, value: number }>, trackRecords: { __typename?: 'TrackRecordNodeList', nodes: Array<{ __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string }> } } }> } }; - -export type PartialMangaFieldsFragment = { __typename?: 'MangaType', unreadCount: number, downloadCount: number, bookmarkCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: string | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: string, initialized: boolean, lastFetchedAt?: string | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, thumbnailUrlLastFetched?: string | null, title: string, url: string, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeOrExclude, includeInDownload: IncludeOrExclude, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', id: string, name: string, displayName: string } | null, trackRecords: { __typename?: 'TrackRecordNodeList', totalCount: number, nodes: Array<{ __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string, tracker: { __typename?: 'TrackerType', icon: string, supportsTrackDeletion?: boolean | null, scores: Array, id: number, name: string, isLoggedIn: boolean, isTokenExpired: boolean, statuses: Array<{ __typename?: 'TrackStatusType', name: string, value: number }>, trackRecords: { __typename?: 'TrackRecordNodeList', nodes: Array<{ __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string }> } } }> } }; - -export type FullChapterFieldsFragment = { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> }; - -export type FullMangaFieldsFragment = { __typename?: 'MangaType', unreadCount: number, downloadCount: number, bookmarkCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: string | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: string, initialized: boolean, lastFetchedAt?: string | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, thumbnailUrlLastFetched?: string | null, title: string, url: string, lastReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, latestReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, latestFetchedChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, latestUploadedChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, firstUnreadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeOrExclude, includeInDownload: IncludeOrExclude, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', id: string, name: string, displayName: string } | null, trackRecords: { __typename?: 'TrackRecordNodeList', totalCount: number, nodes: Array<{ __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string, tracker: { __typename?: 'TrackerType', icon: string, supportsTrackDeletion?: boolean | null, scores: Array, id: number, name: string, isLoggedIn: boolean, isTokenExpired: boolean, statuses: Array<{ __typename?: 'TrackStatusType', name: string, value: number }>, trackRecords: { __typename?: 'TrackRecordNodeList', nodes: Array<{ __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string }> } } }> } }; - export type AboutWebuiFragment = { __typename?: 'AboutWebUI', channel: string, tag: string }; export type WebuiUpdateCheckFragment = { __typename?: 'WebUIUpdateCheck', channel: string, tag: string, updateAvailable: boolean }; @@ -2618,8 +2604,6 @@ export type CategoryLibraryFieldsFragment = { __typename?: 'CategoryType', id: n export type CategorySettingFieldsFragment = { __typename?: 'CategoryType', includeInUpdate: IncludeOrExclude, includeInDownload: IncludeOrExclude, id: number, name: string, default: boolean, order: number }; -export type MangaBaseFieldsFragment = { __typename?: 'MangaType', id: number, title: string, thumbnailUrl?: string | null, thumbnailUrlLastFetched?: string | null, inLibrary: boolean, initialized: boolean }; - export type ChapterBaseFieldsFragment = { __typename?: 'ChapterType', id: number, name: string, mangaId: number, scanlator?: string | null, realUrl?: string | null, sourceOrder: number, chapterNumber: number }; export type ChapterStateFieldsFragment = { __typename?: 'ChapterType', id: number, isRead: boolean, isDownloaded: boolean, isBookmarked: boolean }; @@ -2628,12 +2612,24 @@ export type ChapterReaderFieldsFragment = { __typename?: 'ChapterType', lastPage export type ChapterListFieldsFragment = { __typename?: 'ChapterType', fetchedAt: string, uploadDate: string, id: number, name: string, mangaId: number, scanlator?: string | null, realUrl?: string | null, sourceOrder: number, chapterNumber: number, isRead: boolean, isDownloaded: boolean, isBookmarked: boolean }; -export type ChapterUpdateListFieldsFragment = { __typename?: 'ChapterType', fetchedAt: string, uploadDate: string, id: number, name: string, mangaId: number, scanlator?: string | null, realUrl?: string | null, sourceOrder: number, chapterNumber: number, isRead: boolean, isDownloaded: boolean, isBookmarked: boolean, manga: { __typename?: 'MangaType', id: number, title: string, thumbnailUrl?: string | null, thumbnailUrlLastFetched?: string | null, inLibrary: boolean, initialized: boolean } }; +export type ChapterUpdateListFieldsFragment = { __typename?: 'ChapterType', fetchedAt: string, uploadDate: string, id: number, name: string, mangaId: number, scanlator?: string | null, realUrl?: string | null, sourceOrder: number, chapterNumber: number, isRead: boolean, isDownloaded: boolean, isBookmarked: boolean, manga: { __typename?: 'MangaType', id: number, title: string, thumbnailUrl?: string | null, thumbnailUrlLastFetched?: string | null, inLibrary: boolean, initialized: boolean, sourceId: string } }; export type DownloadStatusFieldsFragment = { __typename?: 'DownloadStatus', state: DownloaderState, queue: Array<{ __typename?: 'DownloadType', progress: number, state: DownloadState, tries: number, chapter: { __typename?: 'ChapterType', id: number, name: string, sourceOrder: number, isDownloaded: boolean }, manga: { __typename?: 'MangaType', id: number, title: string, downloadCount: number } }> }; export type ExtensionListFieldsFragment = { __typename?: 'ExtensionType', pkgName: string, name: string, lang: string, versionCode: number, versionName: string, iconUrl: string, repo?: string | null, isNsfw: boolean, isInstalled: boolean, isObsolete: boolean, hasUpdate: boolean }; +export type MangaBaseFieldsFragment = { __typename?: 'MangaType', id: number, title: string, thumbnailUrl?: string | null, thumbnailUrlLastFetched?: string | null, inLibrary: boolean, initialized: boolean, sourceId: string }; + +export type MangaChapterStatFieldsFragment = { __typename?: 'MangaType', id: number, unreadCount: number, downloadCount: number, bookmarkCount: number, chapters: { __typename?: 'ChapterNodeList', totalCount: number } }; + +export type MangaReaderFieldsFragment = { __typename?: 'MangaType', id: number, title: string, thumbnailUrl?: string | null, thumbnailUrlLastFetched?: string | null, inLibrary: boolean, initialized: boolean, sourceId: string, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, trackRecords: { __typename?: 'TrackRecordNodeList', totalCount: number } }; + +export type MangaLibraryFieldsFragment = { __typename?: 'MangaType', genre: Array, lastFetchedAt?: string | null, inLibraryAt: string, id: number, title: string, thumbnailUrl?: string | null, thumbnailUrlLastFetched?: string | null, inLibrary: boolean, initialized: boolean, sourceId: string, unreadCount: number, downloadCount: number, bookmarkCount: number, trackRecords: { __typename?: 'TrackRecordNodeList', totalCount: number, nodes: Array<{ __typename?: 'TrackRecordType', id: number, trackerId: number }> }, firstUnreadChapter?: { __typename?: 'ChapterType', id: number, sourceOrder: number } | null, lastReadChapter?: { __typename?: 'ChapterType', id: number, sourceOrder: number, lastReadAt: string } | null, latestReadChapter?: { __typename?: 'ChapterType', id: number, sourceOrder: number, lastReadAt: string } | null, latestFetchedChapter?: { __typename?: 'ChapterType', id: number, fetchedAt: string } | null, latestUploadedChapter?: { __typename?: 'ChapterType', id: number, uploadDate: string } | null, chapters: { __typename?: 'ChapterNodeList', totalCount: number } }; + +export type MangaScreenFieldsFragment = { __typename?: 'MangaType', artist?: string | null, author?: string | null, description?: string | null, status: MangaStatus, realUrl?: string | null, sourceId: string, genre: Array, lastFetchedAt?: string | null, inLibraryAt: string, id: number, title: string, thumbnailUrl?: string | null, thumbnailUrlLastFetched?: string | null, inLibrary: boolean, initialized: boolean, unreadCount: number, downloadCount: number, bookmarkCount: number, source?: { __typename?: 'SourceType', id: string, displayName: string } | null, trackRecords: { __typename?: 'TrackRecordNodeList', totalCount: number, nodes: Array<{ __typename?: 'TrackRecordType', id: number, trackerId: number }> }, firstUnreadChapter?: { __typename?: 'ChapterType', id: number, sourceOrder: number } | null, lastReadChapter?: { __typename?: 'ChapterType', id: number, sourceOrder: number, lastReadAt: string } | null, latestReadChapter?: { __typename?: 'ChapterType', id: number, sourceOrder: number, lastReadAt: string } | null, latestFetchedChapter?: { __typename?: 'ChapterType', id: number, fetchedAt: string } | null, latestUploadedChapter?: { __typename?: 'ChapterType', id: number, uploadDate: string } | null, chapters: { __typename?: 'ChapterNodeList', totalCount: number } }; + +export type MangaLibraryDuplicateScreenFieldsFragment = { __typename?: 'MangaType', description?: string | null, id: number, title: string, thumbnailUrl?: string | null, thumbnailUrlLastFetched?: string | null, inLibrary: boolean, initialized: boolean, sourceId: string, unreadCount: number, downloadCount: number, bookmarkCount: number, chapters: { __typename?: 'ChapterNodeList', totalCount: number } }; + export type SourceBaseFieldsFragment = { __typename?: 'SourceType', id: string, name: string, displayName: string }; export type SourceMigratableFieldsFragment = { __typename?: 'SourceType', lang: string, iconUrl: string, id: string, name: string, displayName: string }; @@ -2656,7 +2652,7 @@ export type TrackRecordBindFieldsFragment = { __typename?: 'TrackRecordType', id export type UpdaterMangaFieldsFragment = { __typename?: 'MangaType', id: number, title: string, thumbnailUrl?: string | null }; -export type UpdaterSubscriptionFieldsFragment = { __typename?: 'UpdateStatus', isRunning: boolean, completeJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', unreadCount: number, downloadCount: number, bookmarkCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: string | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: string, initialized: boolean, lastFetchedAt?: string | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, thumbnailUrlLastFetched?: string | null, title: string, url: string, lastReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, latestReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, latestFetchedChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, latestUploadedChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, firstUnreadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeOrExclude, includeInDownload: IncludeOrExclude, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', id: string, name: string, displayName: string } | null, trackRecords: { __typename?: 'TrackRecordNodeList', totalCount: number, nodes: Array<{ __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string, tracker: { __typename?: 'TrackerType', icon: string, supportsTrackDeletion?: boolean | null, scores: Array, id: number, name: string, isLoggedIn: boolean, isTokenExpired: boolean, statuses: Array<{ __typename?: 'TrackStatusType', name: string, value: number }>, trackRecords: { __typename?: 'TrackRecordNodeList', nodes: Array<{ __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string }> } } }> } }> } }, failedJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', id: number, title: string, thumbnailUrl?: string | null }> } }, pendingJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', id: number, title: string, thumbnailUrl?: string | null }> } }, runningJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', id: number, title: string, thumbnailUrl?: string | null }> } } }; +export type UpdaterSubscriptionFieldsFragment = { __typename?: 'UpdateStatus', isRunning: boolean, completeJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', id: number, unreadCount: number, downloadCount: number, bookmarkCount: number, chapters: { __typename?: 'ChapterNodeList', totalCount: number } }> } }, failedJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', id: number, title: string, thumbnailUrl?: string | null }> } }, pendingJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', id: number, title: string, thumbnailUrl?: string | null }> } }, runningJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', id: number, title: string, thumbnailUrl?: string | null }> } } }; export type UpdaterStartStopFieldsFragment = { __typename?: 'UpdateStatus', isRunning: boolean }; @@ -2918,7 +2914,7 @@ export type GetMangaFetchMutationVariables = Exact<{ }>; -export type GetMangaFetchMutation = { __typename?: 'Mutation', fetchManga?: { __typename?: 'FetchMangaPayload', clientMutationId?: string | null, manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, bookmarkCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: string | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: string, initialized: boolean, lastFetchedAt?: string | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, thumbnailUrlLastFetched?: string | null, title: string, url: string, lastReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, latestReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, latestFetchedChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, latestUploadedChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, firstUnreadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeOrExclude, includeInDownload: IncludeOrExclude, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', id: string, name: string, displayName: string } | null, trackRecords: { __typename?: 'TrackRecordNodeList', totalCount: number, nodes: Array<{ __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string, tracker: { __typename?: 'TrackerType', icon: string, supportsTrackDeletion?: boolean | null, scores: Array, id: number, name: string, isLoggedIn: boolean, isTokenExpired: boolean, statuses: Array<{ __typename?: 'TrackStatusType', name: string, value: number }>, trackRecords: { __typename?: 'TrackRecordNodeList', nodes: Array<{ __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string }> } } }> } } } | null }; +export type GetMangaFetchMutation = { __typename?: 'Mutation', fetchManga?: { __typename?: 'FetchMangaPayload', clientMutationId?: string | null, manga: { __typename?: 'MangaType', artist?: string | null, author?: string | null, description?: string | null, status: MangaStatus, realUrl?: string | null, sourceId: string, genre: Array, lastFetchedAt?: string | null, inLibraryAt: string, id: number, title: string, thumbnailUrl?: string | null, thumbnailUrlLastFetched?: string | null, inLibrary: boolean, initialized: boolean, unreadCount: number, downloadCount: number, bookmarkCount: number, source?: { __typename?: 'SourceType', id: string, displayName: string } | null, trackRecords: { __typename?: 'TrackRecordNodeList', totalCount: number, nodes: Array<{ __typename?: 'TrackRecordType', id: number, trackerId: number }> }, firstUnreadChapter?: { __typename?: 'ChapterType', id: number, sourceOrder: number } | null, lastReadChapter?: { __typename?: 'ChapterType', id: number, sourceOrder: number, lastReadAt: string } | null, latestReadChapter?: { __typename?: 'ChapterType', id: number, sourceOrder: number, lastReadAt: string } | null, latestFetchedChapter?: { __typename?: 'ChapterType', id: number, fetchedAt: string } | null, latestUploadedChapter?: { __typename?: 'ChapterType', id: number, uploadDate: string } | null, chapters: { __typename?: 'ChapterNodeList', totalCount: number } } } | null }; export type GetMangaToMigrateToFetchMutationVariables = Exact<{ id: Scalars['Int']['input']; @@ -3000,7 +2996,7 @@ export type GetSourceMangasFetchMutationVariables = Exact<{ }>; -export type GetSourceMangasFetchMutation = { __typename?: 'Mutation', fetchSourceManga?: { __typename?: 'FetchSourceMangaPayload', clientMutationId?: string | null, hasNextPage: boolean, mangas: Array<{ __typename?: 'MangaType', artist?: string | null, author?: string | null, chaptersLastFetchedAt?: string | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: string, initialized: boolean, lastFetchedAt?: string | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, thumbnailUrlLastFetched?: string | null, title: string, url: string, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', id: string, name: string, displayName: string } | null, trackRecords: { __typename?: 'TrackRecordNodeList', totalCount: number, nodes: Array<{ __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string, tracker: { __typename?: 'TrackerType', icon: string, supportsTrackDeletion?: boolean | null, scores: Array, id: number, name: string, isLoggedIn: boolean, isTokenExpired: boolean, statuses: Array<{ __typename?: 'TrackStatusType', name: string, value: number }>, trackRecords: { __typename?: 'TrackRecordNodeList', nodes: Array<{ __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string }> } } }> } }> } | null }; +export type GetSourceMangasFetchMutation = { __typename?: 'Mutation', fetchSourceManga?: { __typename?: 'FetchSourceMangaPayload', clientMutationId?: string | null, hasNextPage: boolean, mangas: Array<{ __typename?: 'MangaType', id: number, title: string, thumbnailUrl?: string | null, thumbnailUrlLastFetched?: string | null, inLibrary: boolean, initialized: boolean, sourceId: string }> } | null }; export type UpdateSourcePreferencesMutationVariables = Exact<{ input: UpdateSourcePreferenceInput; @@ -3044,21 +3040,21 @@ export type TrackerBindMutationVariables = Exact<{ }>; -export type TrackerBindMutation = { __typename?: 'Mutation', bindTrack: { __typename?: 'BindTrackPayload', trackRecord: { __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string, tracker: { __typename?: 'TrackerType', id: number }, manga: { __typename?: 'MangaType', id: number, trackRecords: { __typename?: 'TrackRecordNodeList', totalCount: number, nodes: Array<{ __typename?: 'TrackRecordType', id: number }> } } } } }; +export type TrackerBindMutation = { __typename?: 'Mutation', bindTrack: { __typename?: 'BindTrackPayload', trackRecord: { __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string, manga: { __typename?: 'MangaType', id: number, trackRecords: { __typename?: 'TrackRecordNodeList', totalCount: number, nodes: Array<{ __typename?: 'TrackRecordType', id: number, trackerId: number }> } } } } }; export type TrackerUnbindMutationVariables = Exact<{ input: UnbindTrackInput; }>; -export type TrackerUnbindMutation = { __typename?: 'Mutation', unbindTrack: { __typename?: 'UnbindTrackPayload', trackRecord?: { __typename?: 'TrackRecordType', id: number, manga: { __typename?: 'MangaType', id: number, trackRecords: { __typename?: 'TrackRecordNodeList', totalCount: number, nodes: Array<{ __typename?: 'TrackRecordType', id: number }> } } } | null } }; +export type TrackerUnbindMutation = { __typename?: 'Mutation', unbindTrack: { __typename?: 'UnbindTrackPayload', trackRecord?: { __typename?: 'TrackRecordType', id: number, manga: { __typename?: 'MangaType', id: number, trackRecords: { __typename?: 'TrackRecordNodeList', totalCount: number, nodes: Array<{ __typename?: 'TrackRecordType', id: number, trackerId: number }> } } } | null } }; export type TrackerUpdateBindMutationVariables = Exact<{ input: UpdateTrackInput; }>; -export type TrackerUpdateBindMutation = { __typename?: 'Mutation', updateTrack: { __typename?: 'UpdateTrackPayload', trackRecord?: { __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string, manga: { __typename?: 'MangaType', id: number, trackRecords: { __typename?: 'TrackRecordNodeList', totalCount: number, nodes: Array<{ __typename?: 'TrackRecordType', id: number }> } } } | null } }; +export type TrackerUpdateBindMutation = { __typename?: 'Mutation', updateTrack: { __typename?: 'UpdateTrackPayload', trackRecord?: { __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string, manga: { __typename?: 'MangaType', id: number, trackRecords: { __typename?: 'TrackRecordNodeList', totalCount: number, nodes: Array<{ __typename?: 'TrackRecordType', id: number, trackerId: number }> } } } | null } }; export type TrackerFetchBindMutationVariables = Exact<{ recordId: Scalars['Int']['input']; @@ -3152,7 +3148,7 @@ export type GetCategoryMangasQueryVariables = Exact<{ }>; -export type GetCategoryMangasQuery = { __typename?: 'Query', category: { __typename?: 'CategoryType', id: number, mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', unreadCount: number, downloadCount: number, bookmarkCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: string | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: string, initialized: boolean, lastFetchedAt?: string | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, thumbnailUrlLastFetched?: string | null, title: string, url: string, lastReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, latestReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, latestFetchedChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, latestUploadedChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, firstUnreadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeOrExclude, includeInDownload: IncludeOrExclude, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', id: string, name: string, displayName: string } | null, trackRecords: { __typename?: 'TrackRecordNodeList', totalCount: number, nodes: Array<{ __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string, tracker: { __typename?: 'TrackerType', icon: string, supportsTrackDeletion?: boolean | null, scores: Array, id: number, name: string, isLoggedIn: boolean, isTokenExpired: boolean, statuses: Array<{ __typename?: 'TrackStatusType', name: string, value: number }>, trackRecords: { __typename?: 'TrackRecordNodeList', nodes: Array<{ __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string }> } } }> } }>, pageInfo: { __typename?: 'PageInfo', endCursor?: string | null, hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: string | null } } } }; +export type GetCategoryMangasQuery = { __typename?: 'Query', category: { __typename?: 'CategoryType', id: number, mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', genre: Array, lastFetchedAt?: string | null, inLibraryAt: string, id: number, title: string, thumbnailUrl?: string | null, thumbnailUrlLastFetched?: string | null, inLibrary: boolean, initialized: boolean, sourceId: string, unreadCount: number, downloadCount: number, bookmarkCount: number, trackRecords: { __typename?: 'TrackRecordNodeList', totalCount: number, nodes: Array<{ __typename?: 'TrackRecordType', id: number, trackerId: number }> }, firstUnreadChapter?: { __typename?: 'ChapterType', id: number, sourceOrder: number } | null, lastReadChapter?: { __typename?: 'ChapterType', id: number, sourceOrder: number, lastReadAt: string } | null, latestReadChapter?: { __typename?: 'ChapterType', id: number, sourceOrder: number, lastReadAt: string } | null, latestFetchedChapter?: { __typename?: 'ChapterType', id: number, fetchedAt: string } | null, latestUploadedChapter?: { __typename?: 'ChapterType', id: number, uploadDate: string } | null, chapters: { __typename?: 'ChapterNodeList', totalCount: number } }>, pageInfo: { __typename?: 'PageInfo', endCursor?: string | null, hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: string | null } } } }; export type GetChaptersReaderQueryVariables = Exact<{ after?: InputMaybe; @@ -3197,7 +3193,7 @@ export type GetChaptersUpdatesQueryVariables = Exact<{ }>; -export type GetChaptersUpdatesQuery = { __typename?: 'Query', chapters: { __typename?: 'ChapterNodeList', totalCount: number, nodes: Array<{ __typename?: 'ChapterType', fetchedAt: string, uploadDate: string, id: number, name: string, mangaId: number, scanlator?: string | null, realUrl?: string | null, sourceOrder: number, chapterNumber: number, isRead: boolean, isDownloaded: boolean, isBookmarked: boolean, manga: { __typename?: 'MangaType', id: number, title: string, thumbnailUrl?: string | null, thumbnailUrlLastFetched?: string | null, inLibrary: boolean, initialized: boolean } }>, pageInfo: { __typename?: 'PageInfo', endCursor?: string | null, hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: string | null } } }; +export type GetChaptersUpdatesQuery = { __typename?: 'Query', chapters: { __typename?: 'ChapterNodeList', totalCount: number, nodes: Array<{ __typename?: 'ChapterType', fetchedAt: string, uploadDate: string, id: number, name: string, mangaId: number, scanlator?: string | null, realUrl?: string | null, sourceOrder: number, chapterNumber: number, isRead: boolean, isDownloaded: boolean, isBookmarked: boolean, manga: { __typename?: 'MangaType', id: number, title: string, thumbnailUrl?: string | null, thumbnailUrlLastFetched?: string | null, inLibrary: boolean, initialized: boolean, sourceId: string } }>, pageInfo: { __typename?: 'PageInfo', endCursor?: string | null, hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: string | null } } }; export type GetMangasChapterIdsWithStateQueryVariables = Exact<{ mangaIds: Array | Scalars['Int']['input']; @@ -3251,12 +3247,33 @@ export type GetGlobalMetadatasQueryVariables = Exact<{ export type GetGlobalMetadatasQuery = { __typename?: 'Query', metas: { __typename?: 'GlobalMetaNodeList', totalCount: number, nodes: Array<{ __typename?: 'GlobalMetaType', key: string, value: string }>, pageInfo: { __typename?: 'PageInfo', endCursor?: string | null, hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: string | null } } }; -export type GetMangaQueryVariables = Exact<{ +export type GetMangaScreenQueryVariables = Exact<{ id: Scalars['Int']['input']; }>; -export type GetMangaQuery = { __typename?: 'Query', manga: { __typename?: 'MangaType', unreadCount: number, downloadCount: number, bookmarkCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: string | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: string, initialized: boolean, lastFetchedAt?: string | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, thumbnailUrlLastFetched?: string | null, title: string, url: string, lastReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, latestReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, latestFetchedChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, latestUploadedChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, firstUnreadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeOrExclude, includeInDownload: IncludeOrExclude, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', id: string, name: string, displayName: string } | null, trackRecords: { __typename?: 'TrackRecordNodeList', totalCount: number, nodes: Array<{ __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string, tracker: { __typename?: 'TrackerType', icon: string, supportsTrackDeletion?: boolean | null, scores: Array, id: number, name: string, isLoggedIn: boolean, isTokenExpired: boolean, statuses: Array<{ __typename?: 'TrackStatusType', name: string, value: number }>, trackRecords: { __typename?: 'TrackRecordNodeList', nodes: Array<{ __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string }> } } }> } } }; +export type GetMangaScreenQuery = { __typename?: 'Query', manga: { __typename?: 'MangaType', artist?: string | null, author?: string | null, description?: string | null, status: MangaStatus, realUrl?: string | null, sourceId: string, genre: Array, lastFetchedAt?: string | null, inLibraryAt: string, id: number, title: string, thumbnailUrl?: string | null, thumbnailUrlLastFetched?: string | null, inLibrary: boolean, initialized: boolean, unreadCount: number, downloadCount: number, bookmarkCount: number, source?: { __typename?: 'SourceType', id: string, displayName: string } | null, trackRecords: { __typename?: 'TrackRecordNodeList', totalCount: number, nodes: Array<{ __typename?: 'TrackRecordType', id: number, trackerId: number }> }, firstUnreadChapter?: { __typename?: 'ChapterType', id: number, sourceOrder: number } | null, lastReadChapter?: { __typename?: 'ChapterType', id: number, sourceOrder: number, lastReadAt: string } | null, latestReadChapter?: { __typename?: 'ChapterType', id: number, sourceOrder: number, lastReadAt: string } | null, latestFetchedChapter?: { __typename?: 'ChapterType', id: number, fetchedAt: string } | null, latestUploadedChapter?: { __typename?: 'ChapterType', id: number, uploadDate: string } | null, chapters: { __typename?: 'ChapterNodeList', totalCount: number } } }; + +export type GetMangaReaderQueryVariables = Exact<{ + id: Scalars['Int']['input']; +}>; + + +export type GetMangaReaderQuery = { __typename?: 'Query', manga: { __typename?: 'MangaType', id: number, title: string, thumbnailUrl?: string | null, thumbnailUrlLastFetched?: string | null, inLibrary: boolean, initialized: boolean, sourceId: string, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, trackRecords: { __typename?: 'TrackRecordNodeList', totalCount: number } } }; + +export type GetMangaTrackRecordsQueryVariables = Exact<{ + id: Scalars['Int']['input']; +}>; + + +export type GetMangaTrackRecordsQuery = { __typename?: 'Query', manga: { __typename?: 'MangaType', id: number, trackRecords: { __typename?: 'TrackRecordNodeList', totalCount: number, nodes: Array<{ __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string }> } } }; + +export type GetMangaCategoriesQueryVariables = Exact<{ + id: Scalars['Int']['input']; +}>; + + +export type GetMangaCategoriesQuery = { __typename?: 'Query', manga: { __typename?: 'MangaType', id: number, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', id: number }> } } }; export type GetMangaToMigrateQueryVariables = Exact<{ id: Scalars['Int']['input']; @@ -3268,7 +3285,7 @@ export type GetMangaToMigrateQueryVariables = Exact<{ export type GetMangaToMigrateQuery = { __typename?: 'Query', manga: { __typename?: 'MangaType', id: number, inLibrary: boolean, title: string, chapters?: { __typename?: 'ChapterNodeList', totalCount: number, nodes: Array<{ __typename?: 'ChapterType', id: number, chapterNumber: number, isRead: boolean, isDownloaded: boolean, isBookmarked: boolean, manga: { __typename?: 'MangaType', id: number } }> }, categories?: { __typename?: 'CategoryNodeList', nodes: Array<{ __typename?: 'CategoryType', id: number }> }, trackRecords?: { __typename?: 'TrackRecordNodeList', nodes: Array<{ __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number }> } } }; -export type GetMangasQueryVariables = Exact<{ +export type GetMangasBaseQueryVariables = Exact<{ after?: InputMaybe; before?: InputMaybe; condition?: InputMaybe; @@ -3281,14 +3298,44 @@ export type GetMangasQueryVariables = Exact<{ }>; -export type GetMangasQuery = { __typename?: 'Query', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', unreadCount: number, downloadCount: number, bookmarkCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: string | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: string, initialized: boolean, lastFetchedAt?: string | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, thumbnailUrlLastFetched?: string | null, title: string, url: string, lastReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, latestReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, latestFetchedChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, latestUploadedChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, firstUnreadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeOrExclude, includeInDownload: IncludeOrExclude, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', id: string, name: string, displayName: string } | null, trackRecords: { __typename?: 'TrackRecordNodeList', totalCount: number, nodes: Array<{ __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string, tracker: { __typename?: 'TrackerType', icon: string, supportsTrackDeletion?: boolean | null, scores: Array, id: number, name: string, isLoggedIn: boolean, isTokenExpired: boolean, statuses: Array<{ __typename?: 'TrackStatusType', name: string, value: number }>, trackRecords: { __typename?: 'TrackRecordNodeList', nodes: Array<{ __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string }> } } }> } }>, pageInfo: { __typename?: 'PageInfo', endCursor?: string | null, hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: string | null } } }; +export type GetMangasBaseQuery = { __typename?: 'Query', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', id: number, title: string, thumbnailUrl?: string | null, thumbnailUrlLastFetched?: string | null, inLibrary: boolean, initialized: boolean, sourceId: string }>, pageInfo: { __typename?: 'PageInfo', endCursor?: string | null, hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: string | null } } }; + +export type GetMangasLibraryQueryVariables = Exact<{ + after?: InputMaybe; + before?: InputMaybe; + condition?: InputMaybe; + filter?: InputMaybe; + first?: InputMaybe; + last?: InputMaybe; + offset?: InputMaybe; + orderBy?: InputMaybe; + orderByType?: InputMaybe; +}>; + + +export type GetMangasLibraryQuery = { __typename?: 'Query', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', genre: Array, lastFetchedAt?: string | null, inLibraryAt: string, id: number, title: string, thumbnailUrl?: string | null, thumbnailUrlLastFetched?: string | null, inLibrary: boolean, initialized: boolean, sourceId: string, unreadCount: number, downloadCount: number, bookmarkCount: number, trackRecords: { __typename?: 'TrackRecordNodeList', totalCount: number, nodes: Array<{ __typename?: 'TrackRecordType', id: number, trackerId: number }> }, firstUnreadChapter?: { __typename?: 'ChapterType', id: number, sourceOrder: number } | null, lastReadChapter?: { __typename?: 'ChapterType', id: number, sourceOrder: number, lastReadAt: string } | null, latestReadChapter?: { __typename?: 'ChapterType', id: number, sourceOrder: number, lastReadAt: string } | null, latestFetchedChapter?: { __typename?: 'ChapterType', id: number, fetchedAt: string } | null, latestUploadedChapter?: { __typename?: 'ChapterType', id: number, uploadDate: string } | null, chapters: { __typename?: 'ChapterNodeList', totalCount: number } }>, pageInfo: { __typename?: 'PageInfo', endCursor?: string | null, hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: string | null } } }; + +export type GetMangasDuplicatesQueryVariables = Exact<{ + after?: InputMaybe; + before?: InputMaybe; + condition?: InputMaybe; + filter?: InputMaybe; + first?: InputMaybe; + last?: InputMaybe; + offset?: InputMaybe; + orderBy?: InputMaybe; + orderByType?: InputMaybe; +}>; + + +export type GetMangasDuplicatesQuery = { __typename?: 'Query', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', description?: string | null, id: number, title: string, thumbnailUrl?: string | null, thumbnailUrlLastFetched?: string | null, inLibrary: boolean, initialized: boolean, sourceId: string, unreadCount: number, downloadCount: number, bookmarkCount: number, chapters: { __typename?: 'ChapterNodeList', totalCount: number } }>, pageInfo: { __typename?: 'PageInfo', endCursor?: string | null, hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: string | null } } }; export type GetMigratableSourceMangasQueryVariables = Exact<{ sourceId: Scalars['LongString']['input']; }>; -export type GetMigratableSourceMangasQuery = { __typename?: 'Query', mangas: { __typename?: 'MangaNodeList', nodes: Array<{ __typename?: 'MangaType', id: number, title: string, thumbnailUrl?: string | null, source?: { __typename?: 'SourceType', id: string } | null, categories: { __typename?: 'CategoryNodeList', nodes: Array<{ __typename?: 'CategoryType', id: number }> } }> } }; +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 GetAboutQueryVariables = Exact<{ [key: string]: never; }>; @@ -3367,7 +3414,7 @@ export type TrackerSearchQuery = { __typename?: 'Query', searchTracker: { __type export type GetUpdateStatusQueryVariables = Exact<{ [key: string]: never; }>; -export type GetUpdateStatusQuery = { __typename?: 'Query', updateStatus: { __typename?: 'UpdateStatus', isRunning: boolean, completeJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', unreadCount: number, downloadCount: number, bookmarkCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: string | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: string, initialized: boolean, lastFetchedAt?: string | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, thumbnailUrlLastFetched?: string | null, title: string, url: string, lastReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, latestReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, latestFetchedChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, latestUploadedChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, firstUnreadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeOrExclude, includeInDownload: IncludeOrExclude, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', id: string, name: string, displayName: string } | null, trackRecords: { __typename?: 'TrackRecordNodeList', totalCount: number, nodes: Array<{ __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string, tracker: { __typename?: 'TrackerType', icon: string, supportsTrackDeletion?: boolean | null, scores: Array, id: number, name: string, isLoggedIn: boolean, isTokenExpired: boolean, statuses: Array<{ __typename?: 'TrackStatusType', name: string, value: number }>, trackRecords: { __typename?: 'TrackRecordNodeList', nodes: Array<{ __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string }> } } }> } }> } }, failedJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', id: number, title: string, thumbnailUrl?: string | null }> } }, pendingJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', id: number, title: string, thumbnailUrl?: string | null }> } }, runningJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', id: number, title: string, thumbnailUrl?: string | null }> } } } }; +export type GetUpdateStatusQuery = { __typename?: 'Query', updateStatus: { __typename?: 'UpdateStatus', isRunning: boolean, completeJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', id: number, unreadCount: number, downloadCount: number, bookmarkCount: number, chapters: { __typename?: 'ChapterNodeList', totalCount: number } }> } }, failedJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', id: number, title: string, thumbnailUrl?: string | null }> } }, pendingJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', id: number, title: string, thumbnailUrl?: string | null }> } }, runningJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', id: number, title: string, thumbnailUrl?: string | null }> } } } }; export type GetLastUpdateTimestampQueryVariables = Exact<{ [key: string]: never; }>; @@ -3387,4 +3434,4 @@ export type WebuiUpdateSubscription = { __typename?: 'Subscription', webUIUpdate export type UpdaterSubscriptionVariables = Exact<{ [key: string]: never; }>; -export type UpdaterSubscription = { __typename?: 'Subscription', updateStatusChanged: { __typename?: 'UpdateStatus', isRunning: boolean, completeJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', unreadCount: number, downloadCount: number, bookmarkCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: string | null, description?: string | null, genre: Array, id: number, inLibrary: boolean, inLibraryAt: string, initialized: boolean, lastFetchedAt?: string | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, thumbnailUrlLastFetched?: string | null, title: string, url: string, lastReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, latestReadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, latestFetchedChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, latestUploadedChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, firstUnreadChapter?: { __typename?: 'ChapterType', chapterNumber: number, fetchedAt: string, id: number, isBookmarked: boolean, isDownloaded: boolean, isRead: boolean, lastPageRead: number, lastReadAt: string, mangaId: number, name: string, pageCount: number, realUrl?: string | null, scanlator?: string | null, sourceOrder: number, uploadDate: string, url: string, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, thumbnailUrl?: string | null, lastFetchedAt?: string | null }, meta: Array<{ __typename?: 'ChapterMetaType', key: string, value: string }> } | null, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', default: boolean, id: number, includeInUpdate: IncludeOrExclude, includeInDownload: IncludeOrExclude, name: string, order: number, meta: Array<{ __typename?: 'CategoryMetaType', key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> }, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', id: string, name: string, displayName: string } | null, trackRecords: { __typename?: 'TrackRecordNodeList', totalCount: number, nodes: Array<{ __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string, tracker: { __typename?: 'TrackerType', icon: string, supportsTrackDeletion?: boolean | null, scores: Array, id: number, name: string, isLoggedIn: boolean, isTokenExpired: boolean, statuses: Array<{ __typename?: 'TrackStatusType', name: string, value: number }>, trackRecords: { __typename?: 'TrackRecordNodeList', nodes: Array<{ __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string }> } } }> } }> } }, failedJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', id: number, title: string, thumbnailUrl?: string | null }> } }, pendingJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', id: number, title: string, thumbnailUrl?: string | null }> } }, runningJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', id: number, title: string, thumbnailUrl?: string | null }> } } } }; +export type UpdaterSubscription = { __typename?: 'Subscription', updateStatusChanged: { __typename?: 'UpdateStatus', isRunning: boolean, completeJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', id: number, unreadCount: number, downloadCount: number, bookmarkCount: number, chapters: { __typename?: 'ChapterNodeList', totalCount: number } }> } }, failedJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', id: number, title: string, thumbnailUrl?: string | null }> } }, pendingJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', id: number, title: string, thumbnailUrl?: string | null }> } }, runningJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', id: number, title: string, thumbnailUrl?: string | null }> } } } }; diff --git a/src/lib/graphql/mutations/MangaMutation.ts b/src/lib/graphql/mutations/MangaMutation.ts index b5027fc1..50419c5c 100644 --- a/src/lib/graphql/mutations/MangaMutation.ts +++ b/src/lib/graphql/mutations/MangaMutation.ts @@ -7,7 +7,7 @@ */ import gql from 'graphql-tag'; -import { FULL_MANGA_FIELDS } from '@/lib/graphql/Fragments'; +import { MANGA_SCREEN_FIELDS } from '@/lib/graphql/fragments/MangaFragments.ts'; export const DELETE_MANGA_METADATA = gql` mutation DELETE_MANGA_METADATA($input: DeleteMangaMetaInput!) { @@ -37,12 +37,13 @@ export const DELETE_MANGA_METADATA = gql` // makes the server fetch and return the manga export const GET_MANGA_FETCH = gql` - ${FULL_MANGA_FIELDS} + ${MANGA_SCREEN_FIELDS} + mutation GET_MANGA_FETCH($input: FetchMangaInput!) { fetchManga(input: $input) { clientMutationId manga { - ...FULL_MANGA_FIELDS + ...MANGA_SCREEN_FIELDS } } } diff --git a/src/lib/graphql/mutations/SourceMutation.ts b/src/lib/graphql/mutations/SourceMutation.ts index 903bd20e..5dae63eb 100644 --- a/src/lib/graphql/mutations/SourceMutation.ts +++ b/src/lib/graphql/mutations/SourceMutation.ts @@ -7,17 +7,18 @@ */ import gql from 'graphql-tag'; -import { BASE_MANGA_FIELDS } from '@/lib/graphql/Fragments'; import { SOURCE_SETTING_FIELDS } from '@/lib/graphql/fragments/SourceFragments.ts'; +import { MANGA_BASE_FIELDS } from '@/lib/graphql/fragments/MangaFragments.ts'; export const GET_SOURCE_MANGAS_FETCH = gql` - ${BASE_MANGA_FIELDS} + ${MANGA_BASE_FIELDS} + mutation GET_SOURCE_MANGAS_FETCH($input: FetchSourceMangaInput!) { fetchSourceManga(input: $input) { clientMutationId hasNextPage mangas { - ...BASE_MANGA_FIELDS + ...MANGA_BASE_FIELDS } } } diff --git a/src/lib/graphql/mutations/TrackerMutation.ts b/src/lib/graphql/mutations/TrackerMutation.ts index cf53436a..baf553ae 100644 --- a/src/lib/graphql/mutations/TrackerMutation.ts +++ b/src/lib/graphql/mutations/TrackerMutation.ts @@ -55,15 +55,13 @@ export const TRACKER_BIND = gql` bindTrack(input: { mangaId: $mangaId, remoteId: $remoteId, trackerId: $trackerId }) { trackRecord { ...TRACK_RECORD_BIND_FIELDS - tracker { - id - } manga { id trackRecords { totalCount nodes { id + trackerId } } } @@ -83,6 +81,7 @@ export const TRACKER_UNBIND = gql` totalCount nodes { id + trackerId } } } @@ -104,6 +103,7 @@ export const TRACKER_UPDATE_BIND = gql` totalCount nodes { id + trackerId } } } diff --git a/src/lib/graphql/queries/CategoryQuery.ts b/src/lib/graphql/queries/CategoryQuery.ts index ab20cd3b..e5775a1b 100644 --- a/src/lib/graphql/queries/CategoryQuery.ts +++ b/src/lib/graphql/queries/CategoryQuery.ts @@ -7,12 +7,13 @@ */ import gql from 'graphql-tag'; -import { FULL_MANGA_FIELDS, PAGE_INFO } from '@/lib/graphql/Fragments'; +import { PAGE_INFO } from '@/lib/graphql/Fragments'; import { CATEGORY_BASE_FIELDS, CATEGORY_LIBRARY_FIELDS, CATEGORY_SETTING_FIELDS, } from '@/lib/graphql/fragments/CategoryFragments.ts'; +import { MANGA_LIBRARY_FIELDS } from '@/lib/graphql/fragments/MangaFragments.ts'; export const GET_CATEGORIES_BASE = gql` ${CATEGORY_BASE_FIELDS} @@ -126,14 +127,15 @@ export const GET_CATEGORIES_SETTINGS = gql` `; export const GET_CATEGORY_MANGAS = gql` - ${FULL_MANGA_FIELDS} + ${MANGA_LIBRARY_FIELDS} ${PAGE_INFO} + query GET_CATEGORY_MANGAS($id: Int!) { category(id: $id) { id mangas { nodes { - ...FULL_MANGA_FIELDS + ...MANGA_LIBRARY_FIELDS } pageInfo { ...PAGE_INFO diff --git a/src/lib/graphql/queries/MangaQuery.ts b/src/lib/graphql/queries/MangaQuery.ts index 1ab34265..a1688af2 100644 --- a/src/lib/graphql/queries/MangaQuery.ts +++ b/src/lib/graphql/queries/MangaQuery.ts @@ -7,15 +7,68 @@ */ import gql from 'graphql-tag'; -import { FULL_CHAPTER_FIELDS, FULL_MANGA_FIELDS, PAGE_INFO } from '@/lib/graphql/Fragments'; +import { PAGE_INFO } from '@/lib/graphql/Fragments'; +import { + MANGA_BASE_FIELDS, + MANGA_LIBRARY_DUPLICATE_SCREEN_FIELDS, + MANGA_LIBRARY_FIELDS, + MANGA_READER_FIELDS, + MANGA_SCREEN_FIELDS, +} from '@/lib/graphql/fragments/MangaFragments.ts'; +import { TRACK_RECORD_BIND_FIELDS } from '@/lib/graphql/fragments/TrackRecordFragments.ts'; // returns the current manga from the database -export const GET_MANGA = gql` - ${FULL_MANGA_FIELDS} - ${FULL_CHAPTER_FIELDS} - query GET_MANGA($id: Int!) { +export const GET_MANGA_SCREEN = gql` + ${MANGA_SCREEN_FIELDS} + + query GET_MANGA_SCREEN($id: Int!) { manga(id: $id) { - ...FULL_MANGA_FIELDS + ...MANGA_SCREEN_FIELDS + } + } +`; + +// returns the current manga from the database +export const GET_MANGA_READER = gql` + ${MANGA_READER_FIELDS} + + query GET_MANGA_READER($id: Int!) { + manga(id: $id) { + ...MANGA_READER_FIELDS + } + } +`; + +// returns the current manga from the database +export const GET_MANGA_TRACK_RECORDS = gql` + ${TRACK_RECORD_BIND_FIELDS} + + query GET_MANGA_TRACK_RECORDS($id: Int!) { + manga(id: $id) { + id + + trackRecords { + totalCount + + nodes { + ...TRACK_RECORD_BIND_FIELDS + } + } + } + } +`; + +// returns the current manga from the database +export const GET_MANGA_CATEGORIES = gql` + query GET_MANGA_CATEGORIES($id: Int!) { + manga(id: $id) { + id + categories { + totalCount + nodes { + id + } + } } } `; @@ -62,11 +115,11 @@ export const GET_MANGA_TO_MIGRATE = gql` `; // returns the current manga from the database -export const GET_MANGAS = gql` - ${FULL_MANGA_FIELDS} - ${FULL_CHAPTER_FIELDS} +export const GET_MANGAS_BASE = gql` + ${MANGA_BASE_FIELDS} ${PAGE_INFO} - query GET_MANGAS( + + query GET_MANGAS_BASE( $after: Cursor $before: Cursor $condition: MangaConditionInput @@ -89,7 +142,83 @@ export const GET_MANGAS = gql` orderByType: $orderByType ) { nodes { - ...FULL_MANGA_FIELDS + ...MANGA_BASE_FIELDS + } + pageInfo { + ...PAGE_INFO + } + totalCount + } + } +`; + +// returns the current manga from the database +export const GET_MANGAS_LIBRARY = gql` + ${MANGA_LIBRARY_FIELDS} + ${PAGE_INFO} + + query GET_MANGAS_LIBRARY( + $after: Cursor + $before: Cursor + $condition: MangaConditionInput + $filter: MangaFilterInput + $first: Int + $last: Int + $offset: Int + $orderBy: MangaOrderBy + $orderByType: SortOrder + ) { + mangas( + after: $after + before: $before + condition: $condition + filter: $filter + first: $first + last: $last + offset: $offset + orderBy: $orderBy + orderByType: $orderByType + ) { + nodes { + ...MANGA_LIBRARY_FIELDS + } + pageInfo { + ...PAGE_INFO + } + totalCount + } + } +`; + +// returns the current manga from the database +export const GET_MANGAS_DUPLICATES = gql` + ${MANGA_LIBRARY_DUPLICATE_SCREEN_FIELDS} + ${PAGE_INFO} + + query GET_MANGAS_DUPLICATES( + $after: Cursor + $before: Cursor + $condition: MangaConditionInput + $filter: MangaFilterInput + $first: Int + $last: Int + $offset: Int + $orderBy: MangaOrderBy + $orderByType: SortOrder + ) { + mangas( + after: $after + before: $before + condition: $condition + filter: $filter + first: $first + last: $last + offset: $offset + orderBy: $orderBy + orderByType: $orderByType + ) { + nodes { + ...MANGA_LIBRARY_DUPLICATE_SCREEN_FIELDS } pageInfo { ...PAGE_INFO @@ -106,9 +235,7 @@ export const GET_MIGRATABLE_SOURCE_MANGAS = gql` id title thumbnailUrl - source { - id - } + sourceId categories { nodes { id diff --git a/src/lib/metadata/metadata.ts b/src/lib/metadata/metadata.ts index 6962466d..7a01e5c0 100644 --- a/src/lib/metadata/metadata.ts +++ b/src/lib/metadata/metadata.ts @@ -14,13 +14,13 @@ import { Metadata, MetadataHolder, MetadataKeyValuePair, - TManga, } from '@/typings.ts'; import { requestManager } from '@/lib/requests/RequestManager.ts'; import { MetaType, SourceType } from '@/lib/graphql/generated/graphql.ts'; import { DEFAULT_DEVICE, getActiveDevice } from '@/util/device.ts'; import { CategoryIdInfo } from '@/lib/data/Categories.ts'; import { ChapterIdInfo } from '@/lib/data/Chapters.ts'; +import { MangaIdInfo } from '@/lib/data/Mangas.ts'; const APP_METADATA_KEY_PREFIX = 'webUI_'; @@ -378,7 +378,7 @@ export const requestUpdateMetadataValue = async ( await requestManager.setGlobalMetadata(metadataKey, value).response; break; case 'manga': - await requestManager.setMangaMeta((metadataHolder as TManga).id, metadataKey, value).response; + await requestManager.setMangaMeta((metadataHolder as MangaIdInfo).id, metadataKey, value).response; break; case 'source': await requestManager.setSourceMeta((metadataHolder as Pick).id, metadataKey, value) @@ -400,7 +400,7 @@ export const requestUpdateServerMetadata = async (keysToValues: MetadataKeyValue requestUpdateMetadata({}, 'global', keysToValues); export const requestUpdateMangaMetadata = async ( - manga: TManga, + manga: MangaIdInfo & GqlMetaHolder, keysToValues: MetadataKeyValuePair[], ): Promise => requestUpdateMetadata(manga, 'manga', keysToValues); diff --git a/src/lib/metadata/readerSettings.ts b/src/lib/metadata/readerSettings.ts index 3e571b7c..ff99ae01 100644 --- a/src/lib/metadata/readerSettings.ts +++ b/src/lib/metadata/readerSettings.ts @@ -6,7 +6,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import { Metadata, IReaderSettings, MetadataKeyValuePair, GqlMetaHolder, TManga } from '@/typings.ts'; +import { Metadata, IReaderSettings, MetadataKeyValuePair, GqlMetaHolder } from '@/typings.ts'; import { requestManager } from '@/lib/requests/RequestManager.ts'; import { convertFromGqlMeta, @@ -15,6 +15,7 @@ import { requestUpdateServerMetadata, } from '@/lib/metadata/metadata.ts'; import { MetaType } from '@/lib/graphql/generated/graphql.ts'; +import { MangaIdInfo } from '@/lib/data/Mangas.ts'; type UndefinedReaderSettings = { [setting in keyof IReaderSettings]: IReaderSettings[setting] | undefined; @@ -109,7 +110,7 @@ export const checkAndHandleMissingStoredReaderSettings = async ( } if (metadataHolderType === 'manga') { - await requestUpdateMangaMetadata(metadataHolder as TManga, settingsToUpdate); + await requestUpdateMangaMetadata(metadataHolder as MangaIdInfo & GqlMetaHolder, settingsToUpdate); return; } diff --git a/src/lib/requests/RequestManager.ts b/src/lib/requests/RequestManager.ts index 975f7bd1..4c886d56 100644 --- a/src/lib/requests/RequestManager.ts +++ b/src/lib/requests/RequestManager.ts @@ -81,10 +81,6 @@ import { GetMangaChaptersFetchMutationVariables, GetMangaFetchMutation, GetMangaFetchMutationVariables, - GetMangaQuery, - GetMangaQueryVariables, - GetMangasQuery, - GetMangasQueryVariables, GetRestoreStatusQuery, GetRestoreStatusQueryVariables, GetServerSettingsQuery, @@ -197,6 +193,8 @@ import { GetChaptersUpdatesQueryVariables, GetSourcesListQuery, GetSourcesListQueryVariables, + GetMangasLibraryQuery, + GetMangasLibraryQueryVariables, } from '@/lib/graphql/generated/graphql.ts'; import { GET_GLOBAL_METADATAS } from '@/lib/graphql/queries/GlobalMetadataQuery.ts'; import { SET_GLOBAL_METADATA } from '@/lib/graphql/mutations/GlobalMetadataMutation.ts'; @@ -223,9 +221,9 @@ import { UPDATE_MANGAS_CATEGORIES, } from '@/lib/graphql/mutations/MangaMutation.ts'; import { - GET_MANGA, GET_MANGA_TO_MIGRATE, - GET_MANGAS, + GET_MANGA_TRACK_RECORDS, + GET_MANGAS_LIBRARY, GET_MIGRATABLE_SOURCE_MANGAS, } from '@/lib/graphql/queries/MangaQuery.ts'; import { @@ -283,7 +281,7 @@ import { DOWNLOAD_STATUS_SUBSCRIPTION } from '@/lib/graphql/subscriptions/Downlo import { UPDATER_SUBSCRIPTION } from '@/lib/graphql/subscriptions/UpdaterSubscription.ts'; import { GET_SERVER_SETTINGS } from '@/lib/graphql/queries/SettingsQuery.ts'; import { UPDATE_SERVER_SETTINGS } from '@/lib/graphql/mutations/SettingsMutation.ts'; -import { BASE_MANGA_FIELDS, GLOBAL_METADATA } from '@/lib/graphql/Fragments.ts'; +import { GLOBAL_METADATA } from '@/lib/graphql/Fragments.ts'; import { CLEAR_SERVER_CACHE } from '@/lib/graphql/mutations/ImageMutation.ts'; import { RESET_WEBUI_UPDATE_STATUS, UPDATE_WEBUI } from '@/lib/graphql/mutations/ServerInfoMutation.ts'; import { WEBUI_UPDATE_SUBSCRIPTION } from '@/lib/graphql/subscriptions/ServerInfoSubscription.ts'; @@ -301,9 +299,11 @@ import { TRACKER_UPDATE_BIND, } from '@/lib/graphql/mutations/TrackerMutation.ts'; import { ControlledPromise } from '@/lib/ControlledPromise.ts'; -import { MetadataMigrationSettings, TManga } from '@/typings.ts'; +import { MetadataMigrationSettings } from '@/typings.ts'; import { DOWNLOAD_STATUS_FIELDS } from '@/lib/graphql/fragments/DownloadFragments.ts'; import { EXTENSION_LIST_FIELDS } from '@/lib/graphql/fragments/ExtensionFragments.ts'; +import { MANGA_BASE_FIELDS } from '@/lib/graphql/fragments/MangaFragments.ts'; +import { MangaIdInfo } from '@/lib/data/Mangas.ts'; enum GQLMethod { QUERY = 'QUERY', @@ -1555,8 +1555,8 @@ export class RequestManager { (manga) => this.graphQLClient.client.cache.readFragment({ id: this.graphQLClient.client.cache.identify(manga), - fragment: BASE_MANGA_FIELDS, - fragmentName: 'BASE_MANGA_FIELDS', + fragment: MANGA_BASE_FIELDS, + fragmentName: 'MANGA_BASE_FIELDS', }) ?? manga, ), }, @@ -1630,18 +1630,20 @@ export class RequestManager { ); } - public useGetManga( + public useGetManga( + document: DocumentNode | TypedDocumentNode, mangaId: number | string, - options?: QueryHookOptions, - ): AbortableApolloUseQueryResponse { - return this.doRequest(GQLMethod.USE_QUERY, GET_MANGA, { id: Number(mangaId) }, options); + options?: QueryHookOptions, + ): AbortableApolloUseQueryResponse { + return this.doRequest(GQLMethod.USE_QUERY, document, { id: Number(mangaId) } as unknown as Variables, options); } - public getManga( + public getManga( + document: DocumentNode | TypedDocumentNode, mangaId: number | string, - options?: QueryOptions, - ): AbortabaleApolloQueryResponse { - return this.doRequest(GQLMethod.QUERY, GET_MANGA, { id: Number(mangaId) }, options); + options?: QueryOptions, + ): AbortabaleApolloQueryResponse { + return this.doRequest(GQLMethod.QUERY, document, { id: Number(mangaId) } as unknown as Variables, options); } public getMangaToMigrate( @@ -1712,18 +1714,20 @@ export class RequestManager { ); } - public useGetMangas( - variables: GetMangasQueryVariables, - options?: QueryHookOptions, - ): AbortableApolloUseQueryResponse { - return this.doRequest(GQLMethod.USE_QUERY, GET_MANGAS, variables, options); + public useGetMangas( + document: DocumentNode | TypedDocumentNode, + variables: Variables, + options?: QueryHookOptions, + ): AbortableApolloUseQueryResponse { + return this.doRequest(GQLMethod.USE_QUERY, document, variables, options); } - public getMangas( - variables: GetMangasQueryVariables, - options?: QueryOptions, - ): AbortabaleApolloQueryResponse { - return this.doRequest(GQLMethod.QUERY, GET_MANGAS, variables, options); + public getMangas( + document: DocumentNode | TypedDocumentNode, + variables: Variables, + options?: QueryOptions, + ): AbortabaleApolloQueryResponse { + return this.doRequest(GQLMethod.QUERY, document, variables, options); } public useGetMigratableSourceMangas( @@ -2014,7 +2018,7 @@ export class RequestManager { public updateChapters( ids: number[], - patch: UpdateChapterPatchInput & { chapterIdsToDelete?: number[]; trackProgressMangaId?: TManga['id'] }, + patch: UpdateChapterPatchInput & { chapterIdsToDelete?: number[]; trackProgressMangaId?: MangaIdInfo['id'] }, options?: MutationOptions, ): AbortableApolloMutationResponse { const { chapterIdsToDelete = [], trackProgressMangaId = -1, ...updatePatch } = patch; @@ -2144,8 +2148,8 @@ export class RequestManager { public useGetCategoryMangas( id: number, - options?: QueryHookOptions, - ): AbortableApolloUseQueryResponse { + options?: QueryHookOptions, + ): AbortableApolloUseQueryResponse { const isDefaultCategory = id === 0; if (isDefaultCategory) { // hacky way of loading the default category mangas - some stuff won't work but since that is not used anyway, it won't be a problem @@ -2165,10 +2169,10 @@ export class RequestManager { __typename: 'Query', } : undefined, - } as unknown as AbortableApolloUseQueryResponse; + } as unknown as AbortableApolloUseQueryResponse; } - return this.useGetMangas({ condition: { inLibrary: true, categoryIds: [id] } }, options); + return this.useGetMangas(GET_MANGAS_LIBRARY, { condition: { inLibrary: true, categoryIds: [id] } }, options); } public deleteCategory( @@ -2597,7 +2601,7 @@ export class RequestManager { GQLMethod.MUTATION, TRACKER_UNBIND, { input: { recordId, deleteRemoteTrack } }, - { refetchQueries: [GET_MANGA], ...options }, + { refetchQueries: [GET_MANGA_TRACK_RECORDS], ...options }, ); } diff --git a/src/screens/Library.tsx b/src/screens/Library.tsx index 5318d949..1760ee23 100644 --- a/src/screens/Library.tsx +++ b/src/screens/Library.tsx @@ -23,17 +23,22 @@ import { UpdateChecker } from '@/components/library/UpdateChecker'; import { useLibraryOptionsContext } from '@/components/context/LibraryOptionsContext'; import { NavBarContext } from '@/components/context/NavbarContext.tsx'; import { useSelectableCollection } from '@/components/collection/useSelectableCollection.ts'; -import { TManga } from '@/typings.ts'; import { SelectableCollectionSelectMode } from '@/components/collection/SelectableCollectionSelectMode.tsx'; import { useGetVisibleLibraryMangas } from '@/components/library/useGetVisibleLibraryMangas.ts'; import { SelectionFAB } from '@/components/collection/SelectionFAB.tsx'; -import { PARTIAL_MANGA_FIELDS } from '@/lib/graphql/Fragments.ts'; import { MangaActionMenuItems } from '@/components/manga/MangaActionMenuItems.tsx'; import { TabsMenu } from '@/components/tabs/TabsMenu.tsx'; import { TabsWrapper } from '@/components/tabs/TabsWrapper.tsx'; import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts'; -import { GetCategoriesLibraryQuery, GetCategoriesLibraryQueryVariables } from '@/lib/graphql/generated/graphql.ts'; +import { + GetCategoriesLibraryQuery, + GetCategoriesLibraryQueryVariables, + MangaChapterStatFieldsFragment, + MangaType, +} from '@/lib/graphql/generated/graphql.ts'; import { GET_CATEGORIES_LIBRARY } from '@/lib/graphql/queries/CategoryQuery.ts'; +import { Mangas } from '@/lib/data/Mangas.ts'; +import { MANGA_CHAPTER_STAT_FIELDS } from '@/lib/graphql/fragments/MangaFragments.ts'; const TitleWithSizeTag = styled('span')({ display: 'flex', @@ -95,7 +100,7 @@ export function Library() { handleSelectAll, handleSelection, clearSelection, - } = useSelectableCollection(mangas.length, { + } = useSelectableCollection(mangas.length, { itemIds: mangaIds, currentKey: activeTab?.id.toString(), }); @@ -107,14 +112,15 @@ export function Library() { const selectedMangas = useMemo( () => - selectedItemIds.map( - (id) => - requestManager.graphQLClient.client.cache.readFragment({ - id: requestManager.graphQLClient.client.cache.identify({ __typename: 'MangaType', id }), - fragment: PARTIAL_MANGA_FIELDS, - fragmentName: 'PARTIAL_MANGA_FIELDS', - })!, - ), + selectedItemIds + .map((id) => + Mangas.getFromCache( + id, + MANGA_CHAPTER_STAT_FIELDS, + 'MANGA_CHAPTER_STAT_FIELDS', + ), + ) + .filter((manga) => !!manga), [selectedItemIds.length, mangas], ); diff --git a/src/screens/Manga.tsx b/src/screens/Manga.tsx index 61d16906..1c5d75d8 100644 --- a/src/screens/Manga.tsx +++ b/src/screens/Manga.tsx @@ -24,6 +24,8 @@ import { MangaDetails } from '@/components/manga/MangaDetails'; import { MangaToolbarMenu } from '@/components/manga/MangaToolbarMenu'; import { EmptyViewAbsoluteCentered } from '@/components/util/EmptyViewAbsoluteCentered.tsx'; import { LoadingPlaceholder } from '@/components/util/LoadingPlaceholder'; +import { GetMangaScreenQuery } from '@/lib/graphql/generated/graphql.ts'; +import { GET_MANGA_SCREEN } from '@/lib/graphql/queries/MangaQuery.ts'; export const Manga: React.FC = () => { const { t } = useTranslation(); @@ -32,7 +34,13 @@ export const Manga: React.FC = () => { const { id } = useParams<{ id: string }>(); const autofetchedRef = useRef(false); - const { data, error: mangaError, loading: isLoading, networkStatus, refetch } = requestManager.useGetManga(id); + const { + data, + error: mangaError, + loading: isLoading, + networkStatus, + refetch, + } = requestManager.useGetManga(GET_MANGA_SCREEN, id); const isValidating = isNetworkRequestInFlight(networkStatus); const manga = data?.manga; diff --git a/src/screens/Migrate.tsx b/src/screens/Migrate.tsx index b4c18c9c..6c945223 100644 --- a/src/screens/Migrate.tsx +++ b/src/screens/Migrate.tsx @@ -14,8 +14,6 @@ import { requestManager } from '@/lib/requests/RequestManager.ts'; import { TMigratableSource } from '@/components/MigrationCard.tsx'; import { LoadingPlaceholder } from '@/components/util/LoadingPlaceholder.tsx'; import { EmptyViewAbsoluteCentered } from '@/components/util/EmptyViewAbsoluteCentered.tsx'; -import { MangaGrid } from '@/components/MangaGrid.tsx'; -import { TPartialManga } from '@/typings.ts'; import { GridLayouts } from '@/components/source/GridLayouts.tsx'; import { useLocalStorage } from '@/util/useStorage.tsx'; import { GridLayout } from '@/components/context/LibraryOptionsContext.tsx'; @@ -23,6 +21,7 @@ import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts import { GetSourceMigratableQuery, GetSourceMigratableQueryVariables } from '@/lib/graphql/generated/graphql.ts'; import { GET_SOURCE_MIGRATABLE } from '@/lib/graphql/queries/SourceQuery.ts'; import { SOURCE_BASE_FIELDS } from '@/lib/graphql/fragments/SourceFragments.ts'; +import { BaseMangaGrid } from '@/components/source/BaseMangaGrid.tsx'; export const Migrate = () => { const { t } = useTranslation(); @@ -117,11 +116,11 @@ export const Migrate = () => { } return ( - {}} isLoading={areMangasLoading} - mangas={(migratableSourceMangasData?.mangas.nodes ?? []) as TPartialManga[]} + mangas={migratableSourceMangasData?.mangas.nodes ?? []} gridLayout={gridLayout} mode="migrate.search" /> diff --git a/src/screens/Reader.tsx b/src/screens/Reader.tsx index 2b141986..933e814d 100644 --- a/src/screens/Reader.tsx +++ b/src/screens/Reader.tsx @@ -11,7 +11,7 @@ import { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'r import { useLocation, useNavigate, useParams } from 'react-router-dom'; import Box from '@mui/material/Box'; import { useTranslation } from 'react-i18next'; -import { AllowedMetadataValueTypes, ChapterOffset, IReaderSettings, ReaderType, TManga } from '@/typings'; +import { AllowedMetadataValueTypes, ChapterOffset, IReaderSettings, ReaderType } from '@/typings'; import { requestManager } from '@/lib/requests/RequestManager.ts'; import { checkAndHandleMissingStoredReaderSettings, @@ -31,6 +31,7 @@ import { useDebounce } from '@/util/useDebounce.ts'; import { GetChaptersReaderQuery, GetChaptersReaderQueryVariables, + GetMangaReaderQuery, UpdateChapterPatchInput, } from '@/lib/graphql/generated/graphql.ts'; import { useMetadataServerSettings } from '@/lib/metadata/metadataServerSettings.ts'; @@ -38,6 +39,8 @@ import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts import { Chapters } from '@/lib/data/Chapters.ts'; import { EmptyViewAbsoluteCentered } from '@/components/util/EmptyViewAbsoluteCentered.tsx'; import { GET_CHAPTERS_READER } from '@/lib/graphql/queries/ChapterQuery.ts'; +import { GET_MANGA_READER } from '@/lib/graphql/queries/MangaQuery.ts'; +import { TMangaReader } from '@/lib/data/Mangas.ts'; type TChapter = GetChaptersReaderQuery['chapters']['nodes'][number]; @@ -94,7 +97,7 @@ export function Reader() { lastReadAt: 0, chapters: { totalCount: 0 }, trackRecords: { totalCount: 0 }, - }) as unknown as TManga, + }) as unknown as TMangaReader, [mangaId], ); @@ -103,7 +106,7 @@ export function Reader() { loading: isMangaLoading, error: mangaError, refetch: refetchManga, - } = requestManager.useGetManga(mangaId); + } = requestManager.useGetManga(GET_MANGA_READER, mangaId); const loadedChapter = useRef(null); const isChapterLoaded = Number(mangaId) === loadedChapter.current?.mangaId && diff --git a/src/screens/SearchAll.tsx b/src/screens/SearchAll.tsx index 5cad0578..8368d007 100644 --- a/src/screens/SearchAll.tsx +++ b/src/screens/SearchAll.tsx @@ -19,7 +19,6 @@ import { langSortCmp, sourceDefualtLangs, sourceForcedDefaultLangs } from '@/uti import { translateExtensionLanguage } from '@/screens/util/Extensions'; import { AppbarSearch } from '@/components/util/AppbarSearch'; import { LangSelect } from '@/components/navbar/action/LangSelect'; -import { MangaGrid } from '@/components/MangaGrid'; import { useDebounce } from '@/util/useDebounce.ts'; import { NavBarContext } from '@/components/context/NavbarContext.tsx'; import { MangaCardProps } from '@/components/manga/MangaCard.types.tsx'; @@ -28,6 +27,7 @@ import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts import { LoadingPlaceholder } from '@/components/util/LoadingPlaceholder.tsx'; import { EmptyViewAbsoluteCentered } from '@/components/util/EmptyViewAbsoluteCentered.tsx'; import { SourceType } from '@/lib/graphql/generated/graphql.ts'; +import { BaseMangaGrid } from '@/components/source/BaseMangaGrid.tsx'; type SourceLoadingState = { isLoading: boolean; hasResults: boolean; emptySearch: boolean }; type SourceToLoadingStateMap = Map; @@ -166,7 +166,7 @@ const SourceSearchPreview = React.memo( } /> ) : ( - ({ display: 'flex', @@ -92,9 +93,9 @@ const SOURCE_CONTENT_TYPE_TO_ERROR_MSG_KEY: { [contentType in SourceContentType] [SourceContentType.SEARCH]: 'manga.error.label.no_matches', }; -const getUniqueMangas = (mangas: TPartialManga[]): TPartialManga[] => { - const mangaIdToManga: Record = {}; - const uniqueMangas: TPartialManga[] = []; +const getUniqueMangas = (mangas: Manga[]): Manga[] => { + const mangaIdToManga: Record = {}; + const uniqueMangas: Manga[] = []; mangas.forEach((manga) => { const isDuplicate = !!mangaIdToManga[manga.id]; @@ -470,7 +471,7 @@ export function SourceMangas() { {t('global.button.filter')} - {contentType === SourceContentType.SEARCH && ( => { +const findDuplicatesByTitle = >( + libraryMangas: Manga[], +): Record => { const titleToMangas = Object.groupBy(libraryMangas, ({ title }) => title.toLowerCase().trim()); return Object.fromEntries( Object.entries(titleToMangas) - .filter((titleToMangaMap): titleToMangaMap is [string, TManga[]] => (titleToMangaMap[1]?.length ?? 0) > 1) + .filter((titleToMangaMap): titleToMangaMap is [string, Manga[]] => (titleToMangaMap[1]?.length ?? 0) > 1) .map(([, mangas]) => [mangas[0].title, mangas]), ); }; -const findDuplicatesByTitleAndAlternativeTitles = (libraryMangas: TManga[]): Record => { - const idToDuplicateStatus: Record = {}; - const titleToMangas: Record = {}; +type TMangaDuplicate = Pick; +const findDuplicatesByTitleAndAlternativeTitles = ( + libraryMangas: Manga[], +): Record => { + const idToDuplicateStatus: Record = {}; + const titleToMangas: Record = {}; libraryMangas.forEach((mangaToCheck) => libraryMangas.forEach((libraryManga) => { @@ -123,10 +135,13 @@ export const LibraryDuplicates = () => { }; }, [t, gridLayout, checkAlternativeTitles]); - const { data, loading, error, refetch } = requestManager.useGetMangas({ condition: { inLibrary: true } }); + const { data, loading, error, refetch } = requestManager.useGetMangas< + GetMangasDuplicatesQuery, + GetMangasDuplicatesQueryVariables + >(GET_MANGAS_DUPLICATES, { condition: { inLibrary: true } }); const mangasByTitle = useMemo(() => { - const libraryMangas: TManga[] = data?.mangas.nodes ?? []; + const libraryMangas: TMangaDuplicate[] = data?.mangas.nodes ?? []; if (checkAlternativeTitles) { return findDuplicatesByTitleAndAlternativeTitles(libraryMangas); @@ -172,7 +187,7 @@ export const LibraryDuplicates = () => { itemContent={(index) => ( { {title} - {}} isLoading={false} gridLayout={gridLayout} + inLibraryIndicator={false} horizontal mode="duplicate" /> diff --git a/src/screens/settings/LibrarySettings.tsx b/src/screens/settings/LibrarySettings.tsx index 7b5109b1..4506f252 100644 --- a/src/screens/settings/LibrarySettings.tsx +++ b/src/screens/settings/LibrarySettings.tsx @@ -29,14 +29,23 @@ import { EmptyViewAbsoluteCentered } from '@/components/util/EmptyViewAbsoluteCe import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts'; import { LoadingPlaceholder } from '@/components/util/LoadingPlaceholder.tsx'; import { ListItemLink } from '@/components/util/ListItemLink.tsx'; -import { GetCategoriesSettingsQuery, GetCategoriesSettingsQueryVariables } from '@/lib/graphql/generated/graphql.ts'; +import { + GetCategoriesSettingsQuery, + GetCategoriesSettingsQueryVariables, + GetMangasBaseQuery, + GetMangasBaseQueryVariables, +} from '@/lib/graphql/generated/graphql.ts'; import { GET_CATEGORIES_SETTINGS } from '@/lib/graphql/queries/CategoryQuery.ts'; +import { GET_MANGAS_BASE } from '@/lib/graphql/queries/MangaQuery.ts'; const removeNonLibraryMangasFromCategories = async (): Promise => { try { - const nonLibraryMangas = await requestManager.getMangas({ - filter: { inLibrary: { equalTo: false }, categoryId: { isNull: false } }, - }).response; + const nonLibraryMangas = await requestManager.getMangas( + GET_MANGAS_BASE, + { + filter: { inLibrary: { equalTo: false }, categoryId: { isNull: false } }, + }, + ).response; const mangaIdsToRemove = Mangas.getIds(nonLibraryMangas.data.mangas.nodes); diff --git a/src/typings.ts b/src/typings.ts index 1017d85a..83a0288a 100644 --- a/src/typings.ts +++ b/src/typings.ts @@ -12,10 +12,10 @@ import { ParseKeys } from 'i18next'; import { Location } from 'react-router-dom'; import { GetChaptersReaderQuery, - GetMangaQuery, GetServerSettingsQuery, GetSourceBrowseQuery, GetSourceSettingsQuery, + MangaReaderFieldsFragment, MetaType, SourcePreferenceChangeInput, TrackerType, @@ -84,13 +84,6 @@ export type AppMetadataKeys = MetadataServerSettingKeys | MangaMetadataKeys | Se export type MetadataKeyValuePair = [AppMetadataKeys, AllowedMetadataValueTypes]; -export type TManga = GetMangaQuery['manga']; - -export type TPartialManga = OptionalProperty< - TManga, - 'unreadCount' | 'downloadCount' | 'bookmarkCount' | 'categories' | 'chapters' ->; - export interface INavbarOverride { status: boolean; value: any; @@ -187,7 +180,7 @@ export interface IReaderProps { curPage: number; initialPage: number; settings: IReaderSettings; - manga: TManga; + manga: MangaReaderFieldsFragment; chapter: GetChaptersReaderQuery['chapters']['nodes'][number]; nextChapter: () => void; prevChapter: () => void; diff --git a/tools/scripts/codegenFormatter.ts b/tools/scripts/codegenFormatter.ts index 899a3ce4..630a7ad6 100644 --- a/tools/scripts/codegenFormatter.ts +++ b/tools/scripts/codegenFormatter.ts @@ -42,7 +42,7 @@ const addImports = format( `import {FieldPolicy, FieldReadFunction, Reference, TypePolicies, TypePolicy} from '@apollo/client/cache'; import { \tGetChaptersMangaQuery, GetDownloadStatusQueryVariables, GetGlobalMetadataQueryVariables, -\tGetMangaQueryVariables, GetSourceBrowseQueryVariables, GetUpdateStatusQueryVariables, GetWebuiUpdateStatusQueryVariables, +\tGetMangaScreenQueryVariables, GetSourceBrowseQueryVariables, GetUpdateStatusQueryVariables, GetWebuiUpdateStatusQueryVariables, } from "@/lib/graphql/generated/graphql.ts"; import {FieldFunctionOptions} from "@apollo/client/cache/inmemory/policies";`, ); @@ -93,7 +93,7 @@ const fixTypingOfQueryTypePolicies = format( \textensions?: FieldPolicy | FieldReadFunction, \tgetWebUIUpdateStatus?: FieldPolicy> | FieldReadFunction>, \tlastUpdateTimestamp?: FieldPolicy | FieldReadFunction, -\tmanga?: FieldPolicy> | FieldReadFunction>, +\tmanga?: FieldPolicy> | FieldReadFunction>, \tmangas?: FieldPolicy | FieldReadFunction, \tmeta?: FieldPolicy> | FieldReadFunction>, \tmetas?: FieldPolicy | FieldReadFunction,