Reduce requested category data in queries

This commit is contained in:
schroda
2024-07-01 21:40:27 +02:00
parent 03cfc9b80c
commit 9b8ace003d
19 changed files with 253 additions and 73 deletions

View File

@@ -15,6 +15,7 @@ const config: CodegenConfig = {
'src/lib/graphql/queries/**', 'src/lib/graphql/queries/**',
'src/lib/graphql/mutations/**', 'src/lib/graphql/mutations/**',
'src/lib/graphql/subscriptions/**', 'src/lib/graphql/subscriptions/**',
'src/lib/graphql/fragments/**',
'src/lib/graphql/Fragments.ts', 'src/lib/graphql/Fragments.ts',
], ],
ignoreNoDocuments: true, ignoreNoDocuments: true,
@@ -38,4 +39,5 @@ const config: CodegenConfig = {
}, },
}; };
// eslint-disable-next-line import/no-default-export
export default config; export default config;

View File

@@ -22,8 +22,8 @@ import { UpdaterSubscription } from '@/lib/graphql/generated/graphql.ts';
import { Progress } from '@/components/util/Progress'; import { Progress } from '@/components/util/Progress';
import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts'; import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts';
import { dateTimeFormatter } from '@/util/date.ts'; import { dateTimeFormatter } from '@/util/date.ts';
import { TCategory } from '@/typings.ts';
import { MediaQuery } from '@/lib/ui/MediaQuery.tsx'; import { MediaQuery } from '@/lib/ui/MediaQuery.tsx';
import { CategoryIdInfo } from '@/lib/data/Categories.ts';
const calcProgress = (status: UpdaterSubscription['updateStatusChanged'] | undefined) => { const calcProgress = (status: UpdaterSubscription['updateStatusChanged'] | undefined) => {
if (!status) { if (!status) {
@@ -44,7 +44,7 @@ export function UpdateChecker({
categoryId, categoryId,
handleFinishedUpdate, handleFinishedUpdate,
}: { }: {
categoryId?: TCategory['id']; categoryId?: CategoryIdInfo['id'];
handleFinishedUpdate?: () => void; handleFinishedUpdate?: () => void;
}) { }) {
const { t } = useTranslation(); const { t } = useTranslation();
@@ -85,7 +85,7 @@ export function UpdateChecker({
reFetchLastTimestamp().catch(defaultPromiseErrorHandler('UpdateChecker::reFetchLastTimestamp')); reFetchLastTimestamp().catch(defaultPromiseErrorHandler('UpdateChecker::reFetchLastTimestamp'));
}, [status?.isRunning]); }, [status?.isRunning]);
const startUpdate = async (category?: TCategory['id']) => { const startUpdate = async (category?: CategoryIdInfo['id']) => {
try { try {
lastRunningState = true; lastRunningState = true;
await requestManager.startGlobalUpdate(category !== undefined ? [category] : undefined).response; await requestManager.startGlobalUpdate(category !== undefined ? [category] : undefined).response;
@@ -104,7 +104,7 @@ export function UpdateChecker({
} }
}; };
const onClick = async (category?: TCategory['id']) => { const onClick = async (category?: CategoryIdInfo['id']) => {
if (isRunning) { if (isRunning) {
stopUpdate(); stopUpdate();
} else { } else {

View File

@@ -18,6 +18,8 @@ import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts
import { Mangas } from '@/lib/data/Mangas.ts'; import { Mangas } from '@/lib/data/Mangas.ts';
import { TManga } from '@/typings.ts'; import { TManga } from '@/typings.ts';
import { awaitConfirmation } from '@/lib/ui/AwaitableDialog.tsx'; import { awaitConfirmation } from '@/lib/ui/AwaitableDialog.tsx';
import { GetCategoriesBaseQuery, GetCategoriesBaseQueryVariables } from '@/lib/graphql/generated/graphql.ts';
import { GET_CATEGORIES_BASE } from '@/lib/graphql/queries/CategoryQuery.ts';
export const useManageMangaLibraryState = ( export const useManageMangaLibraryState = (
manga: Pick<TManga, 'id' | 'title' | 'inLibrary'>, manga: Pick<TManga, 'id' | 'title' | 'inLibrary'>,
@@ -87,9 +89,16 @@ export const useManageMangaLibraryState = (
return; return;
} }
let categories: Awaited<ReturnType<typeof requestManager.getCategories>['response']>; let categories: Awaited<
ReturnType<
typeof requestManager.getCategories<GetCategoriesBaseQuery, GetCategoriesBaseQueryVariables>
>['response']
>;
try { try {
categories = await requestManager.getCategories().response; categories = await requestManager.getCategories<
GetCategoriesBaseQuery,
GetCategoriesBaseQueryVariables
>(GET_CATEGORIES_BASE).response;
} catch (e) { } catch (e) {
makeToast(t('category.error.label.request_failure'), 'error'); makeToast(t('category.error.label.request_failure'), 'error');
return; return;

View File

@@ -25,6 +25,8 @@ import { CheckboxInput } from '@/components/atoms/CheckboxInput.tsx';
import { makeToast } from '@/components/util/Toast.tsx'; import { makeToast } from '@/components/util/Toast.tsx';
import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts'; import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts';
import { updateMetadataServerSettings } from '@/lib/metadata/metadataServerSettings.ts'; import { updateMetadataServerSettings } from '@/lib/metadata/metadataServerSettings.ts';
import { GetCategoriesBaseQuery, GetCategoriesBaseQueryVariables } from '@/lib/graphql/generated/graphql.ts';
import { GET_CATEGORIES_BASE } from '@/lib/graphql/queries/CategoryQuery.ts';
type BaseProps = { type BaseProps = {
open: boolean; open: boolean;
@@ -88,7 +90,9 @@ export function CategorySelect(props: CategorySelectProps) {
const [doNotShowAddToLibraryDialogAgain, setDoNotShowAddToLibraryDialogAgain] = useState(false); const [doNotShowAddToLibraryDialogAgain, setDoNotShowAddToLibraryDialogAgain] = useState(false);
const mangaCategoryIds = useGetMangaCategoryIds(mangaId); const mangaCategoryIds = useGetMangaCategoryIds(mangaId);
const { data } = requestManager.useGetCategories(); const { data } = requestManager.useGetCategories<GetCategoriesBaseQuery, GetCategoriesBaseQueryVariables>(
GET_CATEGORIES_BASE,
);
const categoriesData = data?.categories.nodes; const categoriesData = data?.categories.nodes;
const allCategories = useMemo(() => Categories.getUserCreated(categoriesData ?? []), [categoriesData]); const allCategories = useMemo(() => Categories.getUserCreated(categoriesData ?? []), [categoriesData]);

View File

@@ -20,7 +20,6 @@ import { t as translate } from 'i18next';
import { ThreeStateCheckboxInput } from '@/components/atoms/ThreeStateCheckboxInput.tsx'; import { ThreeStateCheckboxInput } from '@/components/atoms/ThreeStateCheckboxInput.tsx';
import { makeToast } from '@/components/util/Toast.tsx'; import { makeToast } from '@/components/util/Toast.tsx';
import { IncludeOrExclude } from '@/lib/graphql/generated/graphql.ts'; import { IncludeOrExclude } from '@/lib/graphql/generated/graphql.ts';
import { TCategory } from '@/typings.ts';
import { requestManager } from '@/lib/requests/RequestManager.ts'; import { requestManager } from '@/lib/requests/RequestManager.ts';
import { CheckboxContainer } from '@/components/settings/globalUpdate/CheckboxContainer.ts'; import { CheckboxContainer } from '@/components/settings/globalUpdate/CheckboxContainer.ts';
import { import {
@@ -78,7 +77,7 @@ const getCategoryUpdateInfo = (
return categories.map((category) => category.name).join(', '); return categories.map((category) => category.name).join(', ');
}; };
type CategoryIncludeField = keyof Pick<TCategory, 'includeInUpdate' | 'includeInDownload'>; type CategoryIncludeField = keyof Pick<CategoryType, 'includeInUpdate' | 'includeInDownload'>;
export type CategoriesInclusionSettingProps = { export type CategoriesInclusionSettingProps = {
categories: CategoryType[]; categories: CategoryType[];

View File

@@ -6,15 +6,15 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
import { TCategory } from '@/typings.ts'; import { CategoryType } from '@/lib/graphql/generated/graphql.ts';
export const DEFAULT_CATEGORY_ID = 0; export const DEFAULT_CATEGORY_ID = 0;
export type CategoryIdInfo = Pick<TCategory, 'id'>; export type CategoryIdInfo = Pick<CategoryType, 'id'>;
export type CategoryNameInfo = Pick<TCategory, 'name'>; export type CategoryNameInfo = Pick<CategoryType, 'name'>;
export type CategoryDefaultInfo = Pick<TCategory, 'default'>; export type CategoryDefaultInfo = Pick<CategoryType, 'default'>;
export type CategoryUpdateInclusionInfo = Pick<TCategory, 'includeInUpdate'>; export type CategoryUpdateInclusionInfo = Pick<CategoryType, 'includeInUpdate'>;
export type CategoryDownloadInclusionInfo = Pick<TCategory, 'includeInDownload'>; export type CategoryDownloadInclusionInfo = Pick<CategoryType, 'includeInDownload'>;
export class Categories { export class Categories {
static getIds(categories: CategoryIdInfo[]): number[] { static getIds(categories: CategoryIdInfo[]): number[] {

View File

@@ -0,0 +1,42 @@
/*
* 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 CATEGORY_BASE_FIELDS = gql`
fragment CATEGORY_BASE_FIELDS on CategoryType {
id
name
default
order
}
`;
export const CATEGORY_LIBRARY_FIELDS = gql`
${CATEGORY_BASE_FIELDS}
fragment CATEGORY_LIBRARY_FIELDS on CategoryType {
...CATEGORY_BASE_FIELDS
mangas {
totalCount
}
}
`;
export const CATEGORY_SETTING_FIELDS = gql`
${CATEGORY_BASE_FIELDS}
fragment CATEGORY_SETTING_FIELDS on CategoryType {
...CATEGORY_BASE_FIELDS
includeInUpdate
includeInDownload
}
`;

View File

@@ -1,6 +1,6 @@
import {FieldPolicy, FieldReadFunction, Reference, TypePolicies, TypePolicy} from '@apollo/client/cache'; import {FieldPolicy, FieldReadFunction, Reference, TypePolicies, TypePolicy} from '@apollo/client/cache';
import { import {
GetCategoryQueryVariables, GetChapterQueryVariables, GetChapterQueryVariables,
GetChaptersQuery, GetDownloadStatusQueryVariables, GetExtensionQueryVariables, GetGlobalMetadataQueryVariables, GetChaptersQuery, GetDownloadStatusQueryVariables, GetExtensionQueryVariables, GetGlobalMetadataQueryVariables,
GetMangaQueryVariables, GetSourceQueryVariables, GetUpdateStatusQueryVariables, GetWebuiUpdateStatusQueryVariables, GetMangaQueryVariables, GetSourceQueryVariables, GetUpdateStatusQueryVariables, GetWebuiUpdateStatusQueryVariables,
} from "@/lib/graphql/generated/graphql.ts"; } from "@/lib/graphql/generated/graphql.ts";
@@ -574,7 +574,7 @@ export type QueryFieldPolicy = {
aboutServer?: FieldPolicy<any> | FieldReadFunction<any>, aboutServer?: FieldPolicy<any> | FieldReadFunction<any>,
aboutWebUI?: FieldPolicy<any> | FieldReadFunction<any>, aboutWebUI?: FieldPolicy<any> | FieldReadFunction<any>,
categories?: FieldPolicy<any> | FieldReadFunction<any>, categories?: FieldPolicy<any> | FieldReadFunction<any>,
category?: FieldPolicy<Reference, Reference, Reference, FieldFunctionOptions<GetCategoryQueryVariables>> | FieldReadFunction<Reference, Reference, FieldFunctionOptions<GetCategoryQueryVariables>>, category?: FieldPolicy<any> | FieldReadFunction<any>,
chapter?: FieldPolicy<Reference, Reference, Reference, FieldFunctionOptions<GetChapterQueryVariables>> | FieldReadFunction<Reference, Reference, FieldFunctionOptions<GetChapterQueryVariables>>, chapter?: FieldPolicy<Reference, Reference, Reference, FieldFunctionOptions<GetChapterQueryVariables>> | FieldReadFunction<Reference, Reference, FieldFunctionOptions<GetChapterQueryVariables>>,
chapters?: FieldPolicy<GetChaptersQuery['chapters']> | FieldReadFunction<GetChaptersQuery['chapters']>, chapters?: FieldPolicy<GetChaptersQuery['chapters']> | FieldReadFunction<GetChaptersQuery['chapters']>,
checkForServerUpdates?: FieldPolicy<any> | FieldReadFunction<any>, checkForServerUpdates?: FieldPolicy<any> | FieldReadFunction<any>,

View File

@@ -2632,6 +2632,12 @@ export type WebuiUpdateStatusFragment = { __typename?: 'WebUIUpdateStatus', prog
export type ServerSettingsFragment = { __typename?: 'SettingsType', ip: string, port: number, socksProxyEnabled: boolean, socksProxyVersion: number, socksProxyHost: string, socksProxyPort: string, socksProxyUsername: string, socksProxyPassword: string, webUIFlavor: WebUiFlavor, initialOpenInBrowserEnabled: boolean, webUIInterface: WebUiInterface, electronPath: string, webUIChannel: WebUiChannel, webUIUpdateCheckInterval: number, downloadAsCbz: boolean, downloadsPath: string, autoDownloadNewChapters: boolean, excludeEntryWithUnreadChapters: boolean, autoDownloadNewChaptersLimit: number, autoDownloadIgnoreReUploads?: boolean | null, extensionRepos: Array<string>, maxSourcesInParallel: number, excludeUnreadChapters: boolean, excludeNotStarted: boolean, excludeCompleted: boolean, globalUpdateInterval: number, updateMangas: boolean, basicAuthEnabled: boolean, basicAuthUsername: string, basicAuthPassword: string, debugLogsEnabled: boolean, gqlDebugLogsEnabled: boolean, systemTrayEnabled: boolean, backupPath: string, backupTime: string, backupInterval: number, backupTTL: number, localSourcePath: string, flareSolverrEnabled: boolean, flareSolverrUrl: string, flareSolverrTimeout: number, flareSolverrSessionName: string, flareSolverrSessionTtl: number }; export type ServerSettingsFragment = { __typename?: 'SettingsType', ip: string, port: number, socksProxyEnabled: boolean, socksProxyVersion: number, socksProxyHost: string, socksProxyPort: string, socksProxyUsername: string, socksProxyPassword: string, webUIFlavor: WebUiFlavor, initialOpenInBrowserEnabled: boolean, webUIInterface: WebUiInterface, electronPath: string, webUIChannel: WebUiChannel, webUIUpdateCheckInterval: number, downloadAsCbz: boolean, downloadsPath: string, autoDownloadNewChapters: boolean, excludeEntryWithUnreadChapters: boolean, autoDownloadNewChaptersLimit: number, autoDownloadIgnoreReUploads?: boolean | null, extensionRepos: Array<string>, maxSourcesInParallel: number, excludeUnreadChapters: boolean, excludeNotStarted: boolean, excludeCompleted: boolean, globalUpdateInterval: number, updateMangas: boolean, basicAuthEnabled: boolean, basicAuthUsername: string, basicAuthPassword: string, debugLogsEnabled: boolean, gqlDebugLogsEnabled: boolean, systemTrayEnabled: boolean, backupPath: string, backupTime: string, backupInterval: number, backupTTL: number, localSourcePath: string, flareSolverrEnabled: boolean, flareSolverrUrl: string, flareSolverrTimeout: number, flareSolverrSessionName: string, flareSolverrSessionTtl: number };
export type CategoryBaseFieldsFragment = { __typename?: 'CategoryType', id: number, name: string, default: boolean, order: number };
export type CategoryLibraryFieldsFragment = { __typename?: 'CategoryType', id: number, name: string, default: boolean, order: number, mangas: { __typename?: 'MangaNodeList', totalCount: number } };
export type CategorySettingFieldsFragment = { __typename?: 'CategoryType', includeInUpdate: IncludeOrExclude, includeInDownload: IncludeOrExclude, id: number, name: string, default: boolean, order: number };
export type CreateBackupMutationVariables = Exact<{ export type CreateBackupMutationVariables = Exact<{
input: CreateBackupInput; input: CreateBackupInput;
}>; }>;
@@ -2651,7 +2657,7 @@ export type CreateCategoryMutationVariables = Exact<{
}>; }>;
export type CreateCategoryMutation = { __typename?: 'Mutation', createCategory?: { __typename?: 'CreateCategoryPayload', clientMutationId?: string | null, category: { __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 } } } | null }; export type CreateCategoryMutation = { __typename?: 'Mutation', createCategory?: { __typename?: 'CreateCategoryPayload', clientMutationId?: string | null, category: { __typename?: 'CategoryType', includeInUpdate: IncludeOrExclude, includeInDownload: IncludeOrExclude, id: number, name: string, default: boolean, order: number } } | null };
export type DeleteCategoryMutationVariables = Exact<{ export type DeleteCategoryMutationVariables = Exact<{
input: DeleteCategoryInput; input: DeleteCategoryInput;
@@ -3074,7 +3080,7 @@ export type GetRestoreStatusQueryVariables = Exact<{
export type GetRestoreStatusQuery = { __typename?: 'Query', restoreStatus?: { __typename?: 'BackupRestoreStatus', mangaProgress: number, state: BackupRestoreState, totalManga: number } | null }; export type GetRestoreStatusQuery = { __typename?: 'Query', restoreStatus?: { __typename?: 'BackupRestoreStatus', mangaProgress: number, state: BackupRestoreState, totalManga: number } | null };
export type GetCategoriesQueryVariables = Exact<{ export type GetCategoriesBaseQueryVariables = Exact<{
after?: InputMaybe<Scalars['Cursor']['input']>; after?: InputMaybe<Scalars['Cursor']['input']>;
before?: InputMaybe<Scalars['Cursor']['input']>; before?: InputMaybe<Scalars['Cursor']['input']>;
condition?: InputMaybe<CategoryConditionInput>; condition?: InputMaybe<CategoryConditionInput>;
@@ -3087,14 +3093,37 @@ export type GetCategoriesQueryVariables = Exact<{
}>; }>;
export type GetCategoriesQuery = { __typename?: 'Query', 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 } }>, pageInfo: { __typename?: 'PageInfo', endCursor?: string | null, hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: string | null } } }; export type GetCategoriesBaseQuery = { __typename?: 'Query', categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', id: number, name: string, default: boolean, order: number }>, pageInfo: { __typename?: 'PageInfo', endCursor?: string | null, hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: string | null } } };
export type GetCategoryQueryVariables = Exact<{ export type GetCategoriesLibraryQueryVariables = Exact<{
id: Scalars['Int']['input']; after?: InputMaybe<Scalars['Cursor']['input']>;
before?: InputMaybe<Scalars['Cursor']['input']>;
condition?: InputMaybe<CategoryConditionInput>;
filter?: InputMaybe<CategoryFilterInput>;
first?: InputMaybe<Scalars['Int']['input']>;
last?: InputMaybe<Scalars['Int']['input']>;
offset?: InputMaybe<Scalars['Int']['input']>;
orderBy?: InputMaybe<CategoryOrderBy>;
orderByType?: InputMaybe<SortOrder>;
}>; }>;
export type GetCategoryQuery = { __typename?: 'Query', category: { __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 GetCategoriesLibraryQuery = { __typename?: 'Query', categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', id: number, name: string, default: boolean, order: number, mangas: { __typename?: 'MangaNodeList', totalCount: number } }>, pageInfo: { __typename?: 'PageInfo', endCursor?: string | null, hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: string | null } } };
export type GetCategoriesSettingsQueryVariables = Exact<{
after?: InputMaybe<Scalars['Cursor']['input']>;
before?: InputMaybe<Scalars['Cursor']['input']>;
condition?: InputMaybe<CategoryConditionInput>;
filter?: InputMaybe<CategoryFilterInput>;
first?: InputMaybe<Scalars['Int']['input']>;
last?: InputMaybe<Scalars['Int']['input']>;
offset?: InputMaybe<Scalars['Int']['input']>;
orderBy?: InputMaybe<CategoryOrderBy>;
orderByType?: InputMaybe<SortOrder>;
}>;
export type GetCategoriesSettingsQuery = { __typename?: 'Query', categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', includeInUpdate: IncludeOrExclude, includeInDownload: IncludeOrExclude, id: number, name: string, default: boolean, order: number }>, pageInfo: { __typename?: 'PageInfo', endCursor?: string | null, hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: string | null } } };
export type GetCategoryMangasQueryVariables = Exact<{ export type GetCategoryMangasQueryVariables = Exact<{
id: Scalars['Int']['input']; id: Scalars['Int']['input'];

View File

@@ -7,15 +7,15 @@
*/ */
import gql from 'graphql-tag'; import gql from 'graphql-tag';
import { FULL_CATEGORY_FIELDS } from '@/lib/graphql/Fragments'; import { CATEGORY_SETTING_FIELDS } from '@/lib/graphql/fragments/CategoryFragments.ts';
export const CREATE_CATEGORY = gql` export const CREATE_CATEGORY = gql`
${FULL_CATEGORY_FIELDS} ${CATEGORY_SETTING_FIELDS}
mutation CREATE_CATEGORY($input: CreateCategoryInput!) { mutation CREATE_CATEGORY($input: CreateCategoryInput!) {
createCategory(input: $input) { createCategory(input: $input) {
clientMutationId clientMutationId
category { category {
...FULL_CATEGORY_FIELDS ...CATEGORY_SETTING_FIELDS
} }
} }
} }

View File

@@ -7,12 +7,18 @@
*/ */
import gql from 'graphql-tag'; import gql from 'graphql-tag';
import { FULL_CATEGORY_FIELDS, FULL_MANGA_FIELDS, PAGE_INFO } from '@/lib/graphql/Fragments'; import { FULL_MANGA_FIELDS, PAGE_INFO } from '@/lib/graphql/Fragments';
import {
CATEGORY_BASE_FIELDS,
CATEGORY_LIBRARY_FIELDS,
CATEGORY_SETTING_FIELDS,
} from '@/lib/graphql/fragments/CategoryFragments.ts';
export const GET_CATEGORIES = gql` export const GET_CATEGORIES_BASE = gql`
${FULL_CATEGORY_FIELDS} ${CATEGORY_BASE_FIELDS}
${PAGE_INFO} ${PAGE_INFO}
query GET_CATEGORIES(
query GET_CATEGORIES_BASE(
$after: Cursor $after: Cursor
$before: Cursor $before: Cursor
$condition: CategoryConditionInput $condition: CategoryConditionInput
@@ -35,7 +41,7 @@ export const GET_CATEGORIES = gql`
orderByType: $orderByType orderByType: $orderByType
) { ) {
nodes { nodes {
...FULL_CATEGORY_FIELDS ...CATEGORY_BASE_FIELDS
} }
pageInfo { pageInfo {
...PAGE_INFO ...PAGE_INFO
@@ -45,11 +51,76 @@ export const GET_CATEGORIES = gql`
} }
`; `;
export const GET_CATEGORY = gql` export const GET_CATEGORIES_LIBRARY = gql`
${FULL_CATEGORY_FIELDS} ${CATEGORY_LIBRARY_FIELDS}
query GET_CATEGORY($id: Int!) { ${PAGE_INFO}
category(id: $id) {
...FULL_CATEGORY_FIELDS query GET_CATEGORIES_LIBRARY(
$after: Cursor
$before: Cursor
$condition: CategoryConditionInput
$filter: CategoryFilterInput
$first: Int
$last: Int
$offset: Int
$orderBy: CategoryOrderBy
$orderByType: SortOrder
) {
categories(
after: $after
before: $before
condition: $condition
filter: $filter
first: $first
last: $last
offset: $offset
orderBy: $orderBy
orderByType: $orderByType
) {
nodes {
...CATEGORY_LIBRARY_FIELDS
}
pageInfo {
...PAGE_INFO
}
totalCount
}
}
`;
export const GET_CATEGORIES_SETTINGS = gql`
${CATEGORY_SETTING_FIELDS}
${PAGE_INFO}
query GET_CATEGORIES_SETTINGS(
$after: Cursor
$before: Cursor
$condition: CategoryConditionInput
$filter: CategoryFilterInput
$first: Int
$last: Int
$offset: Int
$orderBy: CategoryOrderBy
$orderByType: SortOrder
) {
categories(
after: $after
before: $before
condition: $condition
filter: $filter
first: $first
last: $last
offset: $offset
orderBy: $orderBy
orderByType: $orderByType
) {
nodes {
...CATEGORY_SETTING_FIELDS
}
pageInfo {
...PAGE_INFO
}
totalCount
} }
} }
`; `;

View File

@@ -14,7 +14,6 @@ import {
Metadata, Metadata,
MetadataHolder, MetadataHolder,
MetadataKeyValuePair, MetadataKeyValuePair,
TCategory,
TChapter, TChapter,
TManga, TManga,
TPartialSource, TPartialSource,
@@ -22,6 +21,7 @@ import {
import { requestManager } from '@/lib/requests/RequestManager.ts'; import { requestManager } from '@/lib/requests/RequestManager.ts';
import { MetaType } from '@/lib/graphql/generated/graphql.ts'; import { MetaType } from '@/lib/graphql/generated/graphql.ts';
import { DEFAULT_DEVICE, getActiveDevice } from '@/util/device.ts'; import { DEFAULT_DEVICE, getActiveDevice } from '@/util/device.ts';
import { CategoryIdInfo } from '@/lib/data/Categories.ts';
const APP_METADATA_KEY_PREFIX = 'webUI_'; const APP_METADATA_KEY_PREFIX = 'webUI_';
@@ -370,7 +370,7 @@ export const requestUpdateMetadataValue = async (
switch (holderType) { switch (holderType) {
case 'category': case 'category':
await requestManager.setCategoryMeta((metadataHolder as TCategory).id, metadataKey, value).response; await requestManager.setCategoryMeta((metadataHolder as CategoryIdInfo).id, metadataKey, value).response;
break; break;
case 'chapter': case 'chapter':
await requestManager.setChapterMeta((metadataHolder as TChapter).id, metadataKey, value).response; await requestManager.setChapterMeta((metadataHolder as TChapter).id, metadataKey, value).response;
@@ -410,7 +410,7 @@ export const requestUpdateChapterMetadata = async (
): Promise<void[]> => requestUpdateMetadata(chapter, 'chapter', keysToValues); ): Promise<void[]> => requestUpdateMetadata(chapter, 'chapter', keysToValues);
export const requestUpdateCategoryMetadata = async ( export const requestUpdateCategoryMetadata = async (
category: TCategory, category: CategoryIdInfo & GqlMetaHolder,
keysToValues: MetadataKeyValuePair[], keysToValues: MetadataKeyValuePair[],
): Promise<void[]> => requestUpdateMetadata(category, 'category', keysToValues); ): Promise<void[]> => requestUpdateMetadata(category, 'category', keysToValues);

View File

@@ -65,8 +65,6 @@ import {
FilterChangeInput, FilterChangeInput,
GetAboutQuery, GetAboutQuery,
GetAboutQueryVariables, GetAboutQueryVariables,
GetCategoriesQuery,
GetCategoriesQueryVariables,
GetCategoryMangasQuery, GetCategoryMangasQuery,
GetCategoryMangasQueryVariables, GetCategoryMangasQueryVariables,
GetChapterPagesFetchMutation, GetChapterPagesFetchMutation,
@@ -199,6 +197,8 @@ import {
GetServerSettingsQueryVariables, GetServerSettingsQueryVariables,
SetSourceMetadataMutation, SetSourceMetadataMutation,
SetSourceMetadataMutationVariables, SetSourceMetadataMutationVariables,
GetCategoriesSettingsQuery,
GetCategoriesSettingsQueryVariables,
} from '@/lib/graphql/generated/graphql.ts'; } from '@/lib/graphql/generated/graphql.ts';
import { GET_GLOBAL_METADATAS } from '@/lib/graphql/queries/GlobalMetadataQuery.ts'; import { GET_GLOBAL_METADATAS } from '@/lib/graphql/queries/GlobalMetadataQuery.ts';
import { SET_GLOBAL_METADATA } from '@/lib/graphql/mutations/GlobalMetadataMutation.ts'; import { SET_GLOBAL_METADATA } from '@/lib/graphql/mutations/GlobalMetadataMutation.ts';
@@ -230,7 +230,12 @@ import {
GET_MANGAS, GET_MANGAS,
GET_MIGRATABLE_SOURCE_MANGAS, GET_MIGRATABLE_SOURCE_MANGAS,
} from '@/lib/graphql/queries/MangaQuery.ts'; } from '@/lib/graphql/queries/MangaQuery.ts';
import { GET_CATEGORIES, GET_CATEGORY_MANGAS } from '@/lib/graphql/queries/CategoryQuery.ts'; import {
GET_CATEGORIES_BASE,
GET_CATEGORIES_LIBRARY,
GET_CATEGORIES_SETTINGS,
GET_CATEGORY_MANGAS,
} from '@/lib/graphql/queries/CategoryQuery.ts';
import { import {
GET_SOURCE_MANGAS_FETCH, GET_SOURCE_MANGAS_FETCH,
SET_SOURCE_METADATA, SET_SOURCE_METADATA,
@@ -2063,28 +2068,30 @@ export class RequestManager {
); );
} }
public useGetCategories( public useGetCategories<Data, Variables extends OperationVariables>(
options?: QueryHookOptions<GetCategoriesQuery, GetCategoriesQueryVariables>, document: DocumentNode | TypedDocumentNode<Data, Variables>,
): AbortableApolloUseQueryResponse<GetCategoriesQuery, GetCategoriesQueryVariables> { options?: QueryHookOptions<Data, Variables>,
return this.doRequest<GetCategoriesQuery, GetCategoriesQueryVariables>( ): AbortableApolloUseQueryResponse<Data, Variables> {
return this.doRequest<Data, Variables>(
GQLMethod.USE_QUERY, GQLMethod.USE_QUERY,
GET_CATEGORIES, document,
{ {
orderBy: CategoryOrderBy.Order, orderBy: CategoryOrderBy.Order,
}, } as unknown as Variables,
options, options,
); );
} }
public getCategories( public getCategories<Data, Variables extends OperationVariables>(
options?: QueryOptions<GetCategoriesQueryVariables, GetCategoriesQuery>, document: DocumentNode | TypedDocumentNode<Data, Variables>,
): AbortabaleApolloQueryResponse<GetCategoriesQuery> { options?: QueryOptions<Variables, Data>,
return this.doRequest( ): AbortabaleApolloQueryResponse<Data> {
return this.doRequest<Data, Variables>(
GQLMethod.QUERY, GQLMethod.QUERY,
GET_CATEGORIES, document,
{ {
orderBy: CategoryOrderBy.Order, orderBy: CategoryOrderBy.Order,
}, } as unknown as Variables,
options, options,
); );
} }
@@ -2097,7 +2104,7 @@ export class RequestManager {
GQLMethod.MUTATION, GQLMethod.MUTATION,
CREATE_CATEGORY, CREATE_CATEGORY,
{ input }, { input },
{ refetchQueries: [GET_CATEGORIES], ...options }, { refetchQueries: [GET_CATEGORIES_BASE, GET_CATEGORIES_LIBRARY, GET_CATEGORIES_SETTINGS], ...options },
); );
} }
@@ -2108,16 +2115,16 @@ export class RequestManager {
GQLMethod.USE_MUTATION, GQLMethod.USE_MUTATION,
UPDATE_CATEGORY_ORDER, UPDATE_CATEGORY_ORDER,
undefined, undefined,
options, { refetchQueries: [GET_CATEGORIES_BASE, GET_CATEGORIES_LIBRARY], ...options },
); );
const wrappedMutate = (mutateOptions: Parameters<typeof mutate>[0]) => { const wrappedMutate = (mutateOptions: Parameters<typeof mutate>[0]) => {
const variables = mutateOptions?.variables?.input; const variables = mutateOptions?.variables?.input;
const cachedCategories = this.graphQLClient.client.readQuery< const cachedCategories = this.graphQLClient.client.readQuery<
GetCategoriesQuery, GetCategoriesSettingsQuery,
GetCategoriesQueryVariables GetCategoriesSettingsQueryVariables
>({ >({
query: GET_CATEGORIES, query: GET_CATEGORIES_SETTINGS,
variables: { orderBy: CategoryOrderBy.Order }, variables: { orderBy: CategoryOrderBy.Order },
})?.categories.nodes; })?.categories.nodes;
@@ -2138,10 +2145,10 @@ export class RequestManager {
return mutate({ return mutate({
update: (cache) => { update: (cache) => {
cache.updateQuery<GetCategoriesQuery, GetCategoriesQueryVariables>( cache.updateQuery<GetCategoriesSettingsQuery, GetCategoriesSettingsQueryVariables>(
{ {
id: cache.identify({ __typename: 'CategoryNodeList' }), id: cache.identify({ __typename: 'CategoryNodeList' }),
query: GET_CATEGORIES, query: GET_CATEGORIES_SETTINGS,
variables: { orderBy: CategoryOrderBy.Order }, variables: { orderBy: CategoryOrderBy.Order },
}, },
(data) => ({ (data) => ({
@@ -2205,7 +2212,7 @@ export class RequestManager {
DELETE_CATEGORY, DELETE_CATEGORY,
{ input: { categoryId } }, { input: { categoryId } },
{ {
refetchQueries: [GET_CATEGORIES], refetchQueries: [GET_CATEGORIES_BASE, GET_CATEGORIES_LIBRARY, GET_CATEGORIES_SETTINGS],
...options, ...options,
}, },
); );

View File

@@ -32,6 +32,8 @@ import { MangaActionMenuItems } from '@/components/manga/MangaActionMenuItems.ts
import { TabsMenu } from '@/components/tabs/TabsMenu.tsx'; import { TabsMenu } from '@/components/tabs/TabsMenu.tsx';
import { TabsWrapper } from '@/components/tabs/TabsWrapper.tsx'; import { TabsWrapper } from '@/components/tabs/TabsWrapper.tsx';
import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts'; import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts';
import { GetCategoriesLibraryQuery, GetCategoriesLibraryQueryVariables } from '@/lib/graphql/generated/graphql.ts';
import { GET_CATEGORIES_LIBRARY } from '@/lib/graphql/queries/CategoryQuery.ts';
const TitleWithSizeTag = styled('span')({ const TitleWithSizeTag = styled('span')({
display: 'flex', display: 'flex',
@@ -51,7 +53,12 @@ export function Library() {
error: tabsError, error: tabsError,
loading: areCategoriesLoading, loading: areCategoriesLoading,
refetch: refetchCategories, refetch: refetchCategories,
} = requestManager.useGetCategories({ notifyOnNetworkStatusChange: true }); } = requestManager.useGetCategories<GetCategoriesLibraryQuery, GetCategoriesLibraryQueryVariables>(
GET_CATEGORIES_LIBRARY,
{
notifyOnNetworkStatusChange: true,
},
);
const tabsData = categoriesResponse?.categories.nodes.filter( const tabsData = categoriesResponse?.categories.nodes.filter(
(category) => category.id !== 0 || (category.id === 0 && category.mangas.totalCount), (category) => category.id !== 0 || (category.id === 0 && category.mangas.totalCount),
); );

View File

@@ -33,10 +33,12 @@ import { requestManager } from '@/lib/requests/RequestManager.ts';
import { StrictModeDroppable } from '@/lib/StrictModeDroppable'; import { StrictModeDroppable } from '@/lib/StrictModeDroppable';
import { DEFAULT_FULL_FAB_HEIGHT } from '@/components/util/StyledFab'; import { DEFAULT_FULL_FAB_HEIGHT } from '@/components/util/StyledFab';
import { NavBarContext } from '@/components/context/NavbarContext'; import { NavBarContext } from '@/components/context/NavbarContext';
import { TCategory } from '@/typings.ts';
import { LoadingPlaceholder } from '@/components/util/LoadingPlaceholder.tsx'; import { LoadingPlaceholder } from '@/components/util/LoadingPlaceholder.tsx';
import { EmptyViewAbsoluteCentered } from '@/components/util/EmptyViewAbsoluteCentered.tsx'; import { EmptyViewAbsoluteCentered } from '@/components/util/EmptyViewAbsoluteCentered.tsx';
import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts'; import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts';
import { GetCategoriesSettingsQuery, GetCategoriesSettingsQueryVariables } from '@/lib/graphql/generated/graphql.ts';
import { GET_CATEGORIES_SETTINGS } from '@/lib/graphql/queries/CategoryQuery.ts';
import { CategoryIdInfo } from '@/lib/data/Categories.ts';
const getItemStyle = ( const getItemStyle = (
isDragging: boolean, isDragging: boolean,
@@ -65,7 +67,10 @@ export function Categories() {
}; };
}, [t]); }, [t]);
const { data, loading, error, refetch } = requestManager.useGetCategories({ notifyOnNetworkStatusChange: true }); const { data, loading, error, refetch } = requestManager.useGetCategories<
GetCategoriesSettingsQuery,
GetCategoriesSettingsQueryVariables
>(GET_CATEGORIES_SETTINGS, { notifyOnNetworkStatusChange: true });
const categories = useMemo(() => { const categories = useMemo(() => {
const res = [...(data?.categories.nodes ?? [])]; const res = [...(data?.categories.nodes ?? [])];
if (res.length > 0 && res[0].name === 'Default') { if (res.length > 0 && res[0].name === 'Default') {
@@ -81,7 +86,7 @@ export function Categories() {
const [reorderCategory, { reset: revertReorder }] = requestManager.useReorderCategory(); const [reorderCategory, { reset: revertReorder }] = requestManager.useReorderCategory();
const theme = useTheme(); const theme = useTheme();
const categoryReorder = (list: TCategory[], from: number, to: number) => { const categoryReorder = (list: CategoryIdInfo[], from: number, to: number) => {
const reorderedCategory = list[from]; const reorderedCategory = list[from];
reorderCategory({ variables: { input: { id: reorderedCategory.id, position: to + 1 } } }).catch(() => reorderCategory({ variables: { input: { id: reorderedCategory.id, position: to + 1 } } }).catch(() =>

View File

@@ -29,6 +29,8 @@ import { NumberSetting } from '@/components/settings/NumberSetting.tsx';
import { LoadingPlaceholder } from '@/components/util/LoadingPlaceholder.tsx'; import { LoadingPlaceholder } from '@/components/util/LoadingPlaceholder.tsx';
import { EmptyViewAbsoluteCentered } from '@/components/util/EmptyViewAbsoluteCentered.tsx'; import { EmptyViewAbsoluteCentered } from '@/components/util/EmptyViewAbsoluteCentered.tsx';
import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts'; import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts';
import { GetCategoriesSettingsQuery, GetCategoriesSettingsQueryVariables } from '@/lib/graphql/generated/graphql.ts';
import { GET_CATEGORIES_SETTINGS } from '@/lib/graphql/queries/CategoryQuery.ts';
type DownloadSettingsType = Pick< type DownloadSettingsType = Pick<
ServerSettings, ServerSettings,
@@ -63,7 +65,9 @@ export const DownloadSettings = () => {
}; };
}, [t]); }, [t]);
const categories = requestManager.useGetCategories(); const categories = requestManager.useGetCategories<GetCategoriesSettingsQuery, GetCategoriesSettingsQueryVariables>(
GET_CATEGORIES_SETTINGS,
);
const serverSettings = requestManager.useGetServerSettings({ notifyOnNetworkStatusChange: true }); const serverSettings = requestManager.useGetServerSettings({ notifyOnNetworkStatusChange: true });
const [mutateSettings] = requestManager.useUpdateServerSettings(); const [mutateSettings] = requestManager.useUpdateServerSettings();
const { const {

View File

@@ -29,6 +29,8 @@ import { EmptyViewAbsoluteCentered } from '@/components/util/EmptyViewAbsoluteCe
import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts'; import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts';
import { LoadingPlaceholder } from '@/components/util/LoadingPlaceholder.tsx'; import { LoadingPlaceholder } from '@/components/util/LoadingPlaceholder.tsx';
import { ListItemLink } from '@/components/util/ListItemLink.tsx'; import { ListItemLink } from '@/components/util/ListItemLink.tsx';
import { GetCategoriesSettingsQuery, GetCategoriesSettingsQueryVariables } from '@/lib/graphql/generated/graphql.ts';
import { GET_CATEGORIES_SETTINGS } from '@/lib/graphql/queries/CategoryQuery.ts';
const removeNonLibraryMangasFromCategories = async (): Promise<void> => { const removeNonLibraryMangasFromCategories = async (): Promise<void> => {
try { try {
@@ -63,7 +65,9 @@ export function LibrarySettings() {
}; };
}, [t]); }, [t]);
const categories = requestManager.useGetCategories(); const categories = requestManager.useGetCategories<GetCategoriesSettingsQuery, GetCategoriesSettingsQueryVariables>(
GET_CATEGORIES_SETTINGS,
);
const serverSettings = requestManager.useGetServerSettings({ notifyOnNetworkStatusChange: true }); const serverSettings = requestManager.useGetServerSettings({ notifyOnNetworkStatusChange: true });
const { const {
settings, settings,

View File

@@ -11,7 +11,6 @@ import { SvgIconTypeMap } from '@mui/material/SvgIcon';
import { ParseKeys } from 'i18next'; import { ParseKeys } from 'i18next';
import { Location } from 'react-router-dom'; import { Location } from 'react-router-dom';
import { import {
GetCategoryQuery,
GetChapterQuery, GetChapterQuery,
GetExtensionQuery, GetExtensionQuery,
GetMangaQuery, GetMangaQuery,
@@ -190,8 +189,6 @@ export enum IncludeInGlobalUpdate {
UNSET = -1, UNSET = -1,
} }
export type TCategory = GetCategoryQuery['category'];
export interface ICategory { export interface ICategory {
id: number; id: number;
order: number; order: number;

View File

@@ -41,7 +41,7 @@ const addImports = format(
`import { FieldPolicy, FieldReadFunction, TypePolicies, TypePolicy } from '@apollo/client/cache';`, `import { FieldPolicy, FieldReadFunction, TypePolicies, TypePolicy } from '@apollo/client/cache';`,
`import {FieldPolicy, FieldReadFunction, Reference, TypePolicies, TypePolicy} from '@apollo/client/cache'; `import {FieldPolicy, FieldReadFunction, Reference, TypePolicies, TypePolicy} from '@apollo/client/cache';
import { import {
\tGetCategoryQueryVariables, GetChapterQueryVariables, \tGetChapterQueryVariables,
\tGetChaptersQuery, GetDownloadStatusQueryVariables, GetExtensionQueryVariables, GetGlobalMetadataQueryVariables, \tGetChaptersQuery, GetDownloadStatusQueryVariables, GetExtensionQueryVariables, GetGlobalMetadataQueryVariables,
\tGetMangaQueryVariables, GetSourceQueryVariables, GetUpdateStatusQueryVariables, GetWebuiUpdateStatusQueryVariables, \tGetMangaQueryVariables, GetSourceQueryVariables, GetUpdateStatusQueryVariables, GetWebuiUpdateStatusQueryVariables,
} from "@/lib/graphql/generated/graphql.ts"; } from "@/lib/graphql/generated/graphql.ts";
@@ -84,7 +84,7 @@ const fixTypingOfQueryTypePolicies = format(
\taboutServer?: FieldPolicy<any> | FieldReadFunction<any>, \taboutServer?: FieldPolicy<any> | FieldReadFunction<any>,
\taboutWebUI?: FieldPolicy<any> | FieldReadFunction<any>, \taboutWebUI?: FieldPolicy<any> | FieldReadFunction<any>,
\tcategories?: FieldPolicy<any> | FieldReadFunction<any>, \tcategories?: FieldPolicy<any> | FieldReadFunction<any>,
\tcategory?: FieldPolicy<Reference, Reference, Reference, FieldFunctionOptions<GetCategoryQueryVariables>> | FieldReadFunction<Reference, Reference, FieldFunctionOptions<GetCategoryQueryVariables>>, \tcategory?: FieldPolicy<any> | FieldReadFunction<any>,
\tchapter?: FieldPolicy<Reference, Reference, Reference, FieldFunctionOptions<GetChapterQueryVariables>> | FieldReadFunction<Reference, Reference, FieldFunctionOptions<GetChapterQueryVariables>>, \tchapter?: FieldPolicy<Reference, Reference, Reference, FieldFunctionOptions<GetChapterQueryVariables>> | FieldReadFunction<Reference, Reference, FieldFunctionOptions<GetChapterQueryVariables>>,
\tchapters?: FieldPolicy<GetChaptersQuery['chapters']> | FieldReadFunction<GetChaptersQuery['chapters']>, \tchapters?: FieldPolicy<GetChaptersQuery['chapters']> | FieldReadFunction<GetChaptersQuery['chapters']>,
\tcheckForServerUpdates?: FieldPolicy<any> | FieldReadFunction<any>, \tcheckForServerUpdates?: FieldPolicy<any> | FieldReadFunction<any>,