Skip to content

Commit

Permalink
QoL: Add "Rename/Move" action to "Edit Group" and "Edit Series" modal (
Browse files Browse the repository at this point in the history
…#1179)

* QoL: Add "Rename/Move" action to "Edit Group" and "Edit Series" modal

This allow to call default renamer, on related files from Collection tab, making easier to rename files after organized in shoko groups

* refactor to use the dedicated endpoint

* Display message when targeting unsupported server version

* Apply suggestions from code review

Co-authored-by: Harshith Mohan <26010946+harshithmohan@users.noreply.github.com>

* Apply suggestions from code review

---------

Co-authored-by: ElementalCrisis <9443295+ElementalCrisis@users.noreply.github.com>
Co-authored-by: Harshith Mohan <26010946+harshithmohan@users.noreply.github.com>
  • Loading branch information
3 people authored Feb 14, 2025
1 parent b8bdeac commit 650680b
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 1 deletion.
4 changes: 4 additions & 0 deletions src/components/Collection/Group/EditGroupModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useDispatch, useSelector } from 'react-redux';
import cx from 'classnames';
import { map } from 'lodash';

import FileActionsTab from '@/components/Collection/Group/EditGroupTabs/FileActionsTab';
import NameTab from '@/components/Collection/Group/EditGroupTabs/NameTab';
import SeriesTab from '@/components/Collection/Group/EditGroupTabs/SeriesTab';
import ModalPanel from '@/components/Panels/ModalPanel';
Expand All @@ -14,6 +15,7 @@ import type { RootState } from '@/core/store';
const tabs = {
name: 'Name',
series: 'Series',
file_actions: 'File Actions',
};

const renderTab = (activeTab: string, groupId: number) => {
Expand All @@ -24,6 +26,8 @@ const renderTab = (activeTab: string, groupId: number) => {
switch (activeTab) {
case 'series':
return <SeriesTab groupId={groupId} />;
case 'file_actions':
return <FileActionsTab groupId={groupId} />;
case 'name':
default:
return <NameTab groupId={groupId} />;
Expand Down
23 changes: 23 additions & 0 deletions src/components/Collection/Group/EditGroupTabs/Action.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react';
import cx from 'classnames';

const Action = (
{ description, name, onClick, scroll }: { name: string, description: string, scroll?: boolean, onClick: () => void },
) => (
<div
className={cx(
'flex flex-row justify-between gap-y-2 cursor-pointer hover:text-panel-text-primary transition-colors',
scroll ? 'mr-4' : '',
)}
onClick={onClick}
>
<div className="flex w-full flex-col gap-y-1">
<div className="flex justify-between">
<div>{name}</div>
</div>
<div className="text-sm text-panel-text opacity-65">{description}</div>
</div>
</div>
);

export default React.memo(Action);
29 changes: 29 additions & 0 deletions src/components/Collection/Group/EditGroupTabs/FileActionsTab.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from 'react';

import Action from '@/components/Collection/Group/EditGroupTabs/Action';
import toast from '@/components/Toast';
import { useRelocateGroupFilesMutation } from '@/core/react-query/group/mutations';
import useIsFeatureSupported, { FeatureType } from '@/hooks/useIsFeatureSupported';

type Props = {
groupId: number;
};

const FileActionsTab = ({ groupId }: Props) => {
const { mutate: relocateGroupFiles } = useRelocateGroupFilesMutation(groupId);
const showUnsupportedToast = () => {
toast.error(`This feature require server version >= ${FeatureType.RelocateSeriesFiles}`);
};

return (
<div className="flex h-[22rem] grow flex-col gap-y-4 overflow-y-auto">
<Action
name="Rename/Move Files"
description="Rename/Move every file associated with the group."
onClick={useIsFeatureSupported(FeatureType.RelocateSeriesFiles) ? relocateGroupFiles : showUnsupportedToast}
/>
</div>
);
};

export default FileActionsTab;
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import React from 'react';

import Action from '@/components/Collection/Series/EditSeriesTabs/Action';
import { useRehashSeriesFilesMutation, useRescanSeriesFilesMutation } from '@/core/react-query/series/mutations';
import toast from '@/components/Toast';
import {
useRehashSeriesFilesMutation,
useRelocateSeriesFilesMutation,
useRescanSeriesFilesMutation,
} from '@/core/react-query/series/mutations';
import useIsFeatureSupported, { FeatureType } from '@/hooks/useIsFeatureSupported';

type Props = {
seriesId: number;
Expand All @@ -10,6 +16,10 @@ type Props = {
const FileActionsTab = ({ seriesId }: Props) => {
const { mutate: rehashSeriesFiles } = useRehashSeriesFilesMutation(seriesId);
const { mutate: rescanSeriesFiles } = useRescanSeriesFilesMutation(seriesId);
const { mutate: relocateSeriesFiles } = useRelocateSeriesFilesMutation(seriesId);
const showUnsupportedToast = () => {
toast.error(`This feature require server version >= ${FeatureType.RelocateSeriesFiles}`);
};

return (
<div className="flex h-[22rem] grow flex-col gap-y-4 overflow-y-auto">
Expand All @@ -23,6 +33,11 @@ const FileActionsTab = ({ seriesId }: Props) => {
description="Rehashes every file associated with the series."
onClick={rehashSeriesFiles}
/>
<Action
name="Rename/Move Files"
description="Rename/Move every file associated with the group."
onClick={useIsFeatureSupported(FeatureType.RelocateSeriesFiles) ? relocateSeriesFiles : showUnsupportedToast}
/>
</div>
);
};
Expand Down
17 changes: 17 additions & 0 deletions src/core/react-query/group/mutations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { axios } from '@/core/axios';
import { invalidateQueries } from '@/core/react-query/queryClient';

import type { MoveSeriesGroupRequestType, PatchGroupRequestType } from '@/core/react-query/group/types';
import type { SeriesType } from '@/core/types/api/series';

// TODO: FIX INVALIDATIONS

Expand Down Expand Up @@ -57,3 +58,19 @@ export const useMoveGroupMutation = () =>
toast.success('Moved series into new group!');
},
});

export const useRelocateGroupFilesMutation = (groupId: number) =>
useMutation({
mutationFn: async () => {
const targetSeries = await axios.get<unknown, SeriesType[]>(`Group/${groupId}/Series`, {
params: { recursive: true },
});

return Promise.all(
targetSeries.map(
series => axios.post(`Series/${series.IDs.ID}/File/Relocate`),
),
);
},
onSuccess: () => toast.success('Group files renamed/moved!'),
});
6 changes: 6 additions & 0 deletions src/core/react-query/series/mutations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,3 +148,9 @@ export const useSyncSeriesTraktMutation = (seriesId: number) =>
mutationFn: () => axios.post(`Series/${seriesId}/Trakt/Sync`),
onSuccess: () => toast.success('Trakt sync queued!'),
});

export const useRelocateSeriesFilesMutation = (seriesId: number) =>
useMutation({
mutationFn: () => axios.post(`Series/${seriesId}/File/Relocate`),
onSuccess: () => toast.success('Series files renamed/moved!'),
});
1 change: 1 addition & 0 deletions src/hooks/useIsFeatureSupported.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type { VersionType } from '@/core/types/api/init';

export enum FeatureType {
Placeholder = '5.0.0.0', // This is as a placeholder so the string conversion for `parseServerVersion` works and also serves as an example
RelocateSeriesFiles = '5.1.0.35',
}

const useIsFeatureSupported = (feature: FeatureType) => {
Expand Down

0 comments on commit 650680b

Please sign in to comment.