Add logic to reorder downloads (#495)
This commit is contained in:
@@ -160,6 +160,8 @@ import {
|
|||||||
WebuiUpdateSubscription,
|
WebuiUpdateSubscription,
|
||||||
ResetWebuiUpdateStatusMutation,
|
ResetWebuiUpdateStatusMutation,
|
||||||
ResetWebuiUpdateStatusMutationVariables,
|
ResetWebuiUpdateStatusMutationVariables,
|
||||||
|
GetDownloadStatusQuery,
|
||||||
|
GetDownloadStatusQueryVariables,
|
||||||
} 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';
|
||||||
@@ -221,10 +223,11 @@ import { DOWNLOAD_STATUS_SUBSCRIPTION } from '@/lib/graphql/subscriptions/Downlo
|
|||||||
import { UPDATER_SUBSCRIPTION } from '@/lib/graphql/subscriptions/UpdaterSubscription.ts';
|
import { UPDATER_SUBSCRIPTION } from '@/lib/graphql/subscriptions/UpdaterSubscription.ts';
|
||||||
import { GET_SERVER_SETTINGS } from '@/lib/graphql/queries/SettingsQuery.ts';
|
import { GET_SERVER_SETTINGS } from '@/lib/graphql/queries/SettingsQuery.ts';
|
||||||
import { UPDATE_SERVER_SETTINGS } from '@/lib/graphql/mutations/SettingsMutation.ts';
|
import { UPDATE_SERVER_SETTINGS } from '@/lib/graphql/mutations/SettingsMutation.ts';
|
||||||
import { BASE_MANGA_FIELDS, FULL_EXTENSION_FIELDS } from '@/lib/graphql/Fragments.ts';
|
import { BASE_MANGA_FIELDS, FULL_DOWNLOAD_STATUS, FULL_EXTENSION_FIELDS } from '@/lib/graphql/Fragments.ts';
|
||||||
import { CLEAR_SERVER_CACHE } from '@/lib/graphql/mutations/ImageMutation.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 { RESET_WEBUI_UPDATE_STATUS, UPDATE_WEBUI } from '@/lib/graphql/mutations/ServerInfoMutation.ts';
|
||||||
import { WEBUI_UPDATE_SUBSCRIPTION } from '@/lib/graphql/subscriptions/ServerInfoSubscription.ts';
|
import { WEBUI_UPDATE_SUBSCRIPTION } from '@/lib/graphql/subscriptions/ServerInfoSubscription.ts';
|
||||||
|
import { GET_DOWNLOAD_STATUS } from '@/lib/graphql/queries/DownloaderQuery.ts';
|
||||||
|
|
||||||
enum GQLMethod {
|
enum GQLMethod {
|
||||||
QUERY = 'QUERY',
|
QUERY = 'QUERY',
|
||||||
@@ -323,6 +326,7 @@ export const SPECIAL_ED_SOURCES = {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO - extract logic to reduce the size of this file... grew waaaaaaaaaaaaay too big peepoFat
|
||||||
// TODO - correctly update cache after all mutations instead of refetching queries
|
// TODO - correctly update cache after all mutations instead of refetching queries
|
||||||
export class RequestManager {
|
export class RequestManager {
|
||||||
public static readonly API_VERSION = '/api/v1/';
|
public static readonly API_VERSION = '/api/v1/';
|
||||||
@@ -1865,17 +1869,51 @@ export class RequestManager {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public reorderChapterInDownloadQueue(
|
public useReorderChapterInDownloadQueue(
|
||||||
chapterId: number,
|
options?: MutationHookOptions<ReorderChapterDownloadMutation, ReorderChapterDownloadMutationVariables>,
|
||||||
position: number,
|
): AbortableApolloUseMutationResponse<ReorderChapterDownloadMutation, ReorderChapterDownloadMutationVariables> {
|
||||||
options?: MutationOptions<ReorderChapterDownloadMutation, ReorderChapterDownloadMutationVariables>,
|
const [mutate, result] = this.doRequest(GQLMethod.USE_MUTATION, REORDER_CHAPTER_DOWNLOAD, undefined, options);
|
||||||
): AbortableApolloMutationResponse<ReorderChapterDownloadMutation> {
|
|
||||||
return this.doRequest<ReorderChapterDownloadMutation, ReorderChapterDownloadMutationVariables>(
|
const wrappedMutate = (mutationOptions: Parameters<typeof mutate>[0]) => {
|
||||||
GQLMethod.MUTATION,
|
const variables = mutationOptions?.variables?.input;
|
||||||
REORDER_CHAPTER_DOWNLOAD,
|
const cachedDownloadStatus = this.graphQLClient.client.readFragment<
|
||||||
{ input: { chapterId, to: position } },
|
DownloadStatusSubscription['downloadChanged']
|
||||||
options,
|
>({
|
||||||
);
|
id: 'DownloadStatus:{}',
|
||||||
|
fragment: FULL_DOWNLOAD_STATUS,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!variables) {
|
||||||
|
throw new Error('useReorderChapterInDownloadQueue: no variables passed');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cachedDownloadStatus) {
|
||||||
|
throw new Error('useReorderChapterInDownloadQueue: there are no cached results');
|
||||||
|
}
|
||||||
|
|
||||||
|
const movedIndex = cachedDownloadStatus.queue.findIndex(
|
||||||
|
({ chapter }) => chapter.id === variables.chapterId,
|
||||||
|
);
|
||||||
|
const chapterDownload = cachedDownloadStatus.queue[movedIndex];
|
||||||
|
const queueWithoutChapterDownload = cachedDownloadStatus.queue.toSpliced(movedIndex, 1);
|
||||||
|
const updatedQueue = queueWithoutChapterDownload.toSpliced(variables.to, 0, chapterDownload);
|
||||||
|
|
||||||
|
return mutate({
|
||||||
|
optimisticResponse: {
|
||||||
|
__typename: 'Mutation',
|
||||||
|
reorderChapterDownload: {
|
||||||
|
__typename: 'ReorderChapterDownloadPayload',
|
||||||
|
downloadStatus: {
|
||||||
|
...cachedDownloadStatus,
|
||||||
|
queue: updatedQueue,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
...mutationOptions,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return [wrappedMutate, result];
|
||||||
}
|
}
|
||||||
|
|
||||||
public addChaptersToDownloadQueue(
|
public addChaptersToDownloadQueue(
|
||||||
@@ -1983,6 +2021,12 @@ export class RequestManager {
|
|||||||
return this.doRequest(GQLMethod.USE_QUERY, GET_UPDATE_STATUS, {}, options);
|
return this.doRequest(GQLMethod.USE_QUERY, GET_UPDATE_STATUS, {}, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public useGetDownloadStatus(
|
||||||
|
options?: SubscriptionHookOptions<GetDownloadStatusQuery, GetDownloadStatusQueryVariables>,
|
||||||
|
): SubscriptionResult<GetDownloadStatusQuery, GetDownloadStatusQueryVariables> {
|
||||||
|
return this.doRequest(GQLMethod.USE_QUERY, GET_DOWNLOAD_STATUS, {}, options);
|
||||||
|
}
|
||||||
|
|
||||||
public useDownloadSubscription(
|
public useDownloadSubscription(
|
||||||
options?: SubscriptionHookOptions<DownloadStatusSubscription, DownloadStatusSubscriptionVariables>,
|
options?: SubscriptionHookOptions<DownloadStatusSubscription, DownloadStatusSubscriptionVariables>,
|
||||||
): SubscriptionResult<DownloadStatusSubscription, DownloadStatusSubscriptionVariables> {
|
): SubscriptionResult<DownloadStatusSubscription, DownloadStatusSubscriptionVariables> {
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ const typePolicies: StrictTypedTypePolicies = {
|
|||||||
WebUIUpdateInfo: { keyFields: [] },
|
WebUIUpdateInfo: { keyFields: [] },
|
||||||
WebUIUpdateCheck: { keyFields: [] },
|
WebUIUpdateCheck: { keyFields: [] },
|
||||||
SettingsType: { keyFields: [] },
|
SettingsType: { keyFields: [] },
|
||||||
|
DownloadStatus: { keyFields: [] },
|
||||||
|
DownloadType: { keyFields: ['chapter'] },
|
||||||
Query: {
|
Query: {
|
||||||
fields: {
|
fields: {
|
||||||
chapters: {
|
chapters: {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import PlayArrowIcon from '@mui/icons-material/PlayArrow';
|
|||||||
import { Card, CardActionArea, Stack, Box, Tooltip } from '@mui/material';
|
import { Card, CardActionArea, Stack, Box, Tooltip } from '@mui/material';
|
||||||
import IconButton from '@mui/material/IconButton';
|
import IconButton from '@mui/material/IconButton';
|
||||||
import React, { useContext, useEffect } from 'react';
|
import React, { useContext, useEffect } from 'react';
|
||||||
import { DragDropContext, Draggable, DraggableProvided } from 'react-beautiful-dnd';
|
import { DragDropContext, Draggable, DraggableProvided, DropResult } from 'react-beautiful-dnd';
|
||||||
import Typography from '@mui/material/Typography';
|
import Typography from '@mui/material/Typography';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@@ -97,9 +97,14 @@ const DownloadChapterItem = ({
|
|||||||
export const DownloadQueue: React.FC = () => {
|
export const DownloadQueue: React.FC = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const { data: downloaderData, loading: isLoading } = requestManager.useDownloadSubscription();
|
requestManager.useDownloadSubscription();
|
||||||
const queue = (downloaderData?.downloadChanged.queue as DownloadType[]) ?? [];
|
const [reorderDownload, { reset: revertReorder }] = requestManager.useReorderChapterInDownloadQueue();
|
||||||
const status = downloaderData?.downloadChanged.state ?? 'STARTED';
|
|
||||||
|
const { data: downloadStatusData, loading: isLoading } = requestManager.useGetDownloadStatus();
|
||||||
|
const downloaderData = downloadStatusData?.downloadStatus;
|
||||||
|
|
||||||
|
const queue = (downloaderData?.queue as DownloadType[]) ?? [];
|
||||||
|
const status = downloaderData?.state ?? 'STARTED';
|
||||||
const isQueueEmpty = !queue.length;
|
const isQueueEmpty = !queue.length;
|
||||||
|
|
||||||
const { setTitle, setAction } = useContext(NavBarContext);
|
const { setTitle, setAction } = useContext(NavBarContext);
|
||||||
@@ -156,7 +161,23 @@ export const DownloadQueue: React.FC = () => {
|
|||||||
return () => window.removeEventListener('error', ignoreError);
|
return () => window.removeEventListener('error', ignoreError);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const onDragEnd = () => {};
|
const categoryReorder = (list: DownloadType[], from: number, to: number) => {
|
||||||
|
if (from === to) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
reorderDownload({ variables: { input: { chapterId: list[from].chapter.id, to } } }).catch(() => {
|
||||||
|
revertReorder();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const onDragEnd = (result: DropResult) => {
|
||||||
|
if (!result.destination) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
categoryReorder(queue, result.source.index, result.destination.index);
|
||||||
|
};
|
||||||
|
|
||||||
const handleDelete = async (chapter: TChapter) => {
|
const handleDelete = async (chapter: TChapter) => {
|
||||||
const isRunning = status === 'STARTED';
|
const isRunning = status === 'STARTED';
|
||||||
|
|||||||
Reference in New Issue
Block a user