Optionally migrate track bindings
This commit is contained in:
@@ -35,7 +35,7 @@ export const MigrateDialog = ({ mangaIdToMigrateTo, onClose }: { mangaIdToMigrat
|
||||
const mangaId = Number(mangaIdAsString);
|
||||
|
||||
const {
|
||||
settings: { migrateChapters, migrateCategories, deleteChapters },
|
||||
settings: { migrateChapters, migrateCategories, migrateTracking, deleteChapters },
|
||||
} = useMetadataServerSettings();
|
||||
|
||||
const [isMigrationInProcess, setIsMigrationInProcess] = useState(false);
|
||||
@@ -58,6 +58,7 @@ export const MigrateDialog = ({ mangaIdToMigrateTo, onClose }: { mangaIdToMigrat
|
||||
mode,
|
||||
migrateChapters,
|
||||
migrateCategories,
|
||||
migrateTracking,
|
||||
deleteChapters,
|
||||
});
|
||||
|
||||
@@ -84,6 +85,12 @@ export const MigrateDialog = ({ mangaIdToMigrateTo, onClose }: { mangaIdToMigrat
|
||||
checked={migrateCategories}
|
||||
onChange={(_, checked) => setMigrationFlag('migrateCategories', checked)}
|
||||
/>
|
||||
<CheckboxInput
|
||||
disabled={isMigrationInProcess}
|
||||
label={t('tracking.title')}
|
||||
checked={migrateTracking}
|
||||
onChange={(_, checked) => setMigrationFlag('migrateTracking', checked)}
|
||||
/>
|
||||
<CheckboxInput
|
||||
disabled={isMigrationInProcess}
|
||||
label={t('migrate.dialog.label.delete_downloaded')}
|
||||
|
||||
@@ -368,22 +368,66 @@ export class Mangas {
|
||||
throw new Error('Categories are missing');
|
||||
}
|
||||
|
||||
requestManager.updateMangasCategories([mangaToMigrateTo.id], {
|
||||
await requestManager.updateMangasCategories([mangaToMigrateTo.id], {
|
||||
addToCategories: mangaToMigrate.categories.nodes.map((category) => category.id),
|
||||
});
|
||||
}).response;
|
||||
}
|
||||
|
||||
private static async migrateTracking(
|
||||
mode: MigrateMode,
|
||||
mangaToMigrate: GetMangaToMigrateQuery['manga'],
|
||||
mangaToMigrateTo: GetMangaToMigrateToFetchMutation['fetchManga']['manga'],
|
||||
): Promise<void> {
|
||||
if (!mangaToMigrate.trackRecords) {
|
||||
throw new Error('TrackRecords of manga to migrate are missing');
|
||||
}
|
||||
|
||||
if (!mangaToMigrateTo.trackRecords) {
|
||||
throw new Error('TrackRecords of manga to migrate to are missing');
|
||||
}
|
||||
|
||||
const trackBindingsToAdd = mangaToMigrate.trackRecords.nodes.filter((trackRecordToMigrate) =>
|
||||
mangaToMigrateTo.trackRecords!.nodes.every(
|
||||
(trackRecord) => trackRecordToMigrate.remoteId !== trackRecord.remoteId,
|
||||
),
|
||||
);
|
||||
|
||||
await Promise.all([
|
||||
...(mode === 'migrate'
|
||||
? mangaToMigrate.trackRecords.nodes.map(
|
||||
(trackRecord) => requestManager.unbindTracker(trackRecord.id).response,
|
||||
)
|
||||
: []),
|
||||
...trackBindingsToAdd.map((trackRecord) =>
|
||||
requestManager.bindTracker(mangaToMigrateTo.id, trackRecord.trackerId, trackRecord.remoteId),
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
static async migrate(
|
||||
mangaId: number,
|
||||
mangaIdToMigrateTo: number,
|
||||
{ mode, migrateChapters, migrateCategories, deleteChapters }: Omit<MigrateOptions, 'mangaIdToMigrateTo'>,
|
||||
{
|
||||
mode,
|
||||
migrateChapters,
|
||||
migrateCategories,
|
||||
migrateTracking,
|
||||
deleteChapters,
|
||||
}: Omit<MigrateOptions, 'mangaIdToMigrateTo'>,
|
||||
): Promise<void> {
|
||||
return Mangas.executeAction('migrate', 1, async () => {
|
||||
const [{ data: mangaToMigrateData }, { data: mangaToMigrateToData }] = await Promise.all([
|
||||
requestManager.getMangaToMigrate(mangaId, { migrateChapters, migrateCategories, deleteChapters })
|
||||
.response,
|
||||
requestManager.getMangaToMigrateToFetch(mangaIdToMigrateTo, { migrateChapters, migrateCategories })
|
||||
.response,
|
||||
requestManager.getMangaToMigrate(mangaId, {
|
||||
migrateChapters,
|
||||
migrateCategories,
|
||||
migrateTracking,
|
||||
deleteChapters,
|
||||
}).response,
|
||||
requestManager.getMangaToMigrateToFetch(mangaIdToMigrateTo, {
|
||||
migrateChapters,
|
||||
migrateCategories,
|
||||
migrateTracking,
|
||||
}).response,
|
||||
]);
|
||||
|
||||
if (!mangaToMigrateData.manga || !mangaToMigrateToData?.fetchManga.manga) {
|
||||
@@ -407,6 +451,9 @@ export class Mangas {
|
||||
migrateCategories
|
||||
? Mangas.migrateCategories(mangaToMigrateData.manga, mangaToMigrateToData.fetchManga.manga)
|
||||
: undefined,
|
||||
migrateTracking
|
||||
? Mangas.migrateTracking(mode, mangaToMigrateData.manga, mangaToMigrateToData.fetchManga.manga)
|
||||
: undefined,
|
||||
!mangaToMigrateToData.fetchManga.manga.inLibrary
|
||||
? requestManager.updateManga(mangaIdToMigrateTo, { updateManga: { inLibrary: true } }).response
|
||||
: undefined,
|
||||
|
||||
@@ -2890,10 +2890,11 @@ export type GetMangaToMigrateToFetchMutationVariables = Exact<{
|
||||
id: Scalars['Int']['input'];
|
||||
migrateChapters: Scalars['Boolean']['input'];
|
||||
migrateCategories: Scalars['Boolean']['input'];
|
||||
migrateTracking: Scalars['Boolean']['input'];
|
||||
}>;
|
||||
|
||||
|
||||
export type GetMangaToMigrateToFetchMutation = { __typename?: 'Mutation', fetchManga: { __typename?: 'FetchMangaPayload', clientMutationId?: string | null, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, categories?: { __typename?: 'CategoryNodeList', nodes: Array<{ __typename?: 'CategoryType', id: number }> } } }, fetchChapters?: { __typename?: 'FetchChaptersPayload', chapters: Array<{ __typename?: 'ChapterType', id: number, chapterNumber: number, isRead: boolean, isDownloaded: boolean, isBookmarked: boolean, manga: { __typename?: 'MangaType', id: number } }> } };
|
||||
export type GetMangaToMigrateToFetchMutation = { __typename?: 'Mutation', fetchManga: { __typename?: 'FetchMangaPayload', clientMutationId?: string | null, manga: { __typename?: 'MangaType', id: number, title: string, inLibrary: boolean, categories?: { __typename?: 'CategoryNodeList', nodes: Array<{ __typename?: 'CategoryType', id: number }> }, trackRecords?: { __typename?: 'TrackRecordNodeList', nodes: Array<{ __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number }> } } }, fetchChapters?: { __typename?: 'FetchChaptersPayload', chapters: Array<{ __typename?: 'ChapterType', id: number, chapterNumber: number, isRead: boolean, isDownloaded: boolean, isBookmarked: boolean, manga: { __typename?: 'MangaType', id: number } }> } };
|
||||
|
||||
export type SetMangaMetadataMutationVariables = Exact<{
|
||||
input: SetMangaMetaInput;
|
||||
@@ -3181,10 +3182,11 @@ export type GetMangaToMigrateQueryVariables = Exact<{
|
||||
id: Scalars['Int']['input'];
|
||||
getChapterData: Scalars['Boolean']['input'];
|
||||
migrateCategories: Scalars['Boolean']['input'];
|
||||
migrateTracking: Scalars['Boolean']['input'];
|
||||
}>;
|
||||
|
||||
|
||||
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 }> } } };
|
||||
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<{
|
||||
after?: InputMaybe<Scalars['Cursor']['input']>;
|
||||
|
||||
@@ -50,7 +50,12 @@ export const GET_MANGA_FETCH = gql`
|
||||
|
||||
// makes the server fetch and return the manga
|
||||
export const GET_MANGA_TO_MIGRATE_TO_FETCH = gql`
|
||||
mutation GET_MANGA_TO_MIGRATE_TO_FETCH($id: Int!, $migrateChapters: Boolean!, $migrateCategories: Boolean!) {
|
||||
mutation GET_MANGA_TO_MIGRATE_TO_FETCH(
|
||||
$id: Int!
|
||||
$migrateChapters: Boolean!
|
||||
$migrateCategories: Boolean!
|
||||
$migrateTracking: Boolean!
|
||||
) {
|
||||
fetchManga(input: { id: $id }) {
|
||||
clientMutationId
|
||||
manga {
|
||||
@@ -62,6 +67,13 @@ export const GET_MANGA_TO_MIGRATE_TO_FETCH = gql`
|
||||
id
|
||||
}
|
||||
}
|
||||
trackRecords @include(if: $migrateTracking) {
|
||||
nodes {
|
||||
id
|
||||
remoteId
|
||||
trackerId
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fetchChapters(input: { mangaId: $id }) @include(if: $migrateChapters) {
|
||||
|
||||
@@ -22,7 +22,12 @@ export const GET_MANGA = gql`
|
||||
|
||||
// returns the current manga from the database
|
||||
export const GET_MANGA_TO_MIGRATE = gql`
|
||||
query GET_MANGA_TO_MIGRATE($id: Int!, $getChapterData: Boolean!, $migrateCategories: Boolean!) {
|
||||
query GET_MANGA_TO_MIGRATE(
|
||||
$id: Int!
|
||||
$getChapterData: Boolean!
|
||||
$migrateCategories: Boolean!
|
||||
$migrateTracking: Boolean!
|
||||
) {
|
||||
manga(id: $id) {
|
||||
id
|
||||
inLibrary
|
||||
@@ -45,6 +50,13 @@ export const GET_MANGA_TO_MIGRATE = gql`
|
||||
id
|
||||
}
|
||||
}
|
||||
trackRecords @include(if: $migrateTracking) {
|
||||
nodes {
|
||||
id
|
||||
remoteId
|
||||
trackerId
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -41,6 +41,7 @@ const GLOBAL_METADATA_KEYS: AppMetadataKeys[] = [
|
||||
// migration
|
||||
'migrateChapters',
|
||||
'migrateCategories',
|
||||
'migrateTracking',
|
||||
'deleteChapters',
|
||||
|
||||
// browse
|
||||
|
||||
@@ -37,6 +37,7 @@ export const getDefaultSettings = (): MetadataServerSettings => ({
|
||||
// migration
|
||||
migrateChapters: true,
|
||||
migrateCategories: true,
|
||||
migrateTracking: true,
|
||||
deleteChapters: true,
|
||||
|
||||
// browse
|
||||
|
||||
@@ -287,7 +287,7 @@ import {
|
||||
TRACKER_UPDATE_BIND,
|
||||
} from '@/lib/graphql/mutations/TrackerMutation.ts';
|
||||
import { ControlledPromise } from '@/lib/ControlledPromise.ts';
|
||||
import { TManga } from '@/typings.ts';
|
||||
import { MetadataMigrationSettings, TManga } from '@/typings.ts';
|
||||
|
||||
enum GQLMethod {
|
||||
QUERY = 'QUERY',
|
||||
@@ -1549,19 +1549,22 @@ export class RequestManager {
|
||||
{
|
||||
migrateChapters = false,
|
||||
migrateCategories = false,
|
||||
migrateTracking = false,
|
||||
deleteChapters = false,
|
||||
apolloOptions: options,
|
||||
}: {
|
||||
migrateChapters?: boolean;
|
||||
migrateCategories?: boolean;
|
||||
deleteChapters?: boolean;
|
||||
}: Partial<MetadataMigrationSettings> & {
|
||||
apolloOptions?: QueryOptions<GetMangaToMigrateQueryVariables, GetMangaToMigrateQuery>;
|
||||
} = {},
|
||||
): AbortabaleApolloQueryResponse<GetMangaToMigrateQuery> {
|
||||
return this.doRequest(
|
||||
GQLMethod.QUERY,
|
||||
GET_MANGA_TO_MIGRATE,
|
||||
{ id: Number(mangaId), getChapterData: migrateChapters || deleteChapters, migrateCategories },
|
||||
{
|
||||
id: Number(mangaId),
|
||||
getChapterData: migrateChapters || deleteChapters,
|
||||
migrateCategories,
|
||||
migrateTracking,
|
||||
},
|
||||
options,
|
||||
);
|
||||
}
|
||||
@@ -1587,10 +1590,9 @@ export class RequestManager {
|
||||
{
|
||||
migrateChapters = false,
|
||||
migrateCategories = false,
|
||||
migrateTracking = false,
|
||||
apolloOptions: options,
|
||||
}: {
|
||||
migrateChapters?: boolean;
|
||||
migrateCategories?: boolean;
|
||||
}: Partial<Omit<MetadataMigrationSettings, 'deleteChapters'>> & {
|
||||
apolloOptions?: MutationOptions<
|
||||
GetMangaToMigrateToFetchMutation,
|
||||
GetMangaToMigrateToFetchMutationVariables
|
||||
@@ -1604,6 +1606,7 @@ export class RequestManager {
|
||||
id: Number(mangaId),
|
||||
migrateChapters,
|
||||
migrateCategories,
|
||||
migrateTracking,
|
||||
},
|
||||
options,
|
||||
);
|
||||
@@ -2490,6 +2493,15 @@ export class RequestManager {
|
||||
return this.doRequest(GQLMethod.USE_MUTATION, TRACKER_BIND, undefined, options);
|
||||
}
|
||||
|
||||
public bindTracker(
|
||||
mangaId: number,
|
||||
trackerId: number,
|
||||
remoteId: string,
|
||||
options?: MutationOptions<TrackerBindMutation, TrackerBindMutationVariables>,
|
||||
): AbortableApolloMutationResponse<TrackerBindMutation> {
|
||||
return this.doRequest(GQLMethod.MUTATION, TRACKER_BIND, { mangaId, remoteId, trackerId }, options);
|
||||
}
|
||||
|
||||
public unbindTracker(
|
||||
recordId: number,
|
||||
deleteRemoteTrack?: boolean,
|
||||
|
||||
@@ -242,6 +242,7 @@ export type MetadataClientSettings = {
|
||||
export type MetadataMigrationSettings = {
|
||||
migrateChapters: boolean;
|
||||
migrateCategories: boolean;
|
||||
migrateTracking: boolean;
|
||||
deleteChapters: boolean;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user