Merge pull request #13423 from strapi/features/ML-folder-bulk-move

ML: Add bulk move hook
This commit is contained in:
Gustav Hansen 2022-05-31 13:44:24 +02:00 committed by GitHub
commit 5f6d3779fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 284 additions and 0 deletions

View File

@ -0,0 +1,223 @@
import React from 'react';
import { IntlProvider } from 'react-intl';
import { QueryClientProvider, QueryClient, useQueryClient } from 'react-query';
import { renderHook, act } from '@testing-library/react-hooks';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import { NotificationsProvider, useNotification } from '@strapi/helper-plugin';
import { axiosInstance } from '../../utils';
import { useBulkMove } from '../useBulkMove';
const FIXTURE_ASSETS = [
{
id: 1,
type: 'asset',
},
{
id: 2,
type: 'asset',
},
];
const FIXTURE_FOLDERS = [
{
id: 11,
type: 'folder',
},
{
id: 12,
type: 'folder',
},
];
const FIXTURE_DESTINATION_FOLDER_ID = 1;
console.error = jest.fn().mockImplementation();
jest.mock('../../utils', () => ({
...jest.requireActual('../../utils'),
axiosInstance: {
post: jest.fn((url, payload) => {
const res = { data: { data: {} } };
if (payload?.fileIds) {
res.data.data.files = FIXTURE_ASSETS;
}
if (payload?.folderIds) {
res.data.data.folders = FIXTURE_FOLDERS;
}
return Promise.resolve(res);
}),
},
}));
const notificationStatusMock = jest.fn();
jest.mock('@strapi/helper-plugin', () => ({
...jest.requireActual('@strapi/helper-plugin'),
useNotification: () => notificationStatusMock,
}));
const refetchQueriesMock = jest.fn();
jest.mock('react-query', () => ({
...jest.requireActual('react-query'),
useQueryClient: () => ({
refetchQueries: refetchQueriesMock,
}),
}));
const client = new QueryClient({
defaultOptions: {
queries: {
retry: false,
},
},
});
// eslint-disable-next-line react/prop-types
function ComponentFixture({ children }) {
return (
<Router>
<Route>
<QueryClientProvider client={client}>
<NotificationsProvider toggleNotification={() => jest.fn()}>
<IntlProvider locale="en" messages={{}}>
{children}
</IntlProvider>
</NotificationsProvider>
</QueryClientProvider>
</Route>
</Router>
);
}
function setup(...args) {
return new Promise(resolve => {
act(() => {
resolve(renderHook(() => useBulkMove(...args), { wrapper: ComponentFixture }));
});
});
}
describe('useBulkMove', () => {
beforeEach(() => {
jest.clearAllMocks();
});
test('does call the proper endpoint', async () => {
const {
result: { current },
} = await setup();
const { move } = current;
await act(async () => {
await move(FIXTURE_DESTINATION_FOLDER_ID, FIXTURE_ASSETS);
});
expect(axiosInstance.post).toHaveBeenCalledWith(
'/upload/actions/bulk-move',
expect.any(Object)
);
});
test('does properly collect all asset ids', async () => {
const {
result: { current },
} = await setup();
const { move } = current;
await act(async () => {
await move(FIXTURE_DESTINATION_FOLDER_ID, FIXTURE_ASSETS);
});
expect(axiosInstance.post).toHaveBeenCalledWith(expect.any(String), {
destinationFolderId: FIXTURE_DESTINATION_FOLDER_ID,
fileIds: FIXTURE_ASSETS.map(({ id }) => id),
});
});
test('does properly collect all folder ids', async () => {
const {
result: { current },
} = await setup();
const { move } = current;
await act(async () => {
await move(FIXTURE_DESTINATION_FOLDER_ID, FIXTURE_FOLDERS);
});
expect(axiosInstance.post).toHaveBeenCalledWith(expect.any(String), {
destinationFolderId: FIXTURE_DESTINATION_FOLDER_ID,
folderIds: FIXTURE_FOLDERS.map(({ id }) => id),
});
});
test('does properly collect folder and asset ids', async () => {
const {
result: { current },
} = await setup();
const { move } = current;
await act(async () => {
await move(FIXTURE_DESTINATION_FOLDER_ID, [...FIXTURE_FOLDERS, ...FIXTURE_ASSETS]);
});
expect(axiosInstance.post).toHaveBeenCalledWith(expect.any(String), {
destinationFolderId: FIXTURE_DESTINATION_FOLDER_ID,
fileIds: FIXTURE_ASSETS.map(({ id }) => id),
folderIds: FIXTURE_FOLDERS.map(({ id }) => id),
});
});
test('does re-fetch assets, if files were deleted', async () => {
const toggleNotification = useNotification();
const queryClient = useQueryClient();
const {
result: { current },
waitFor,
} = await setup();
const { move } = current;
await act(async () => {
await move(FIXTURE_DESTINATION_FOLDER_ID, FIXTURE_ASSETS);
});
await waitFor(() =>
expect(queryClient.refetchQueries).toHaveBeenCalledWith(['upload', 'assets'], {
active: true,
})
);
await waitFor(() => expect(toggleNotification).toHaveBeenCalled());
});
test('does re-fetch folders, if folders were deleted', async () => {
const queryClient = useQueryClient();
const toggleNotification = useNotification();
const {
result: { current },
waitFor,
} = await setup();
const { move } = current;
await act(async () => {
await move(FIXTURE_DESTINATION_FOLDER_ID, FIXTURE_FOLDERS);
});
await waitFor(() =>
expect(queryClient.refetchQueries).toHaveBeenCalledWith(['upload', 'folders'], {
active: true,
})
);
await waitFor(() => expect(toggleNotification).toHaveBeenCalled());
});
});

View File

@ -0,0 +1,61 @@
import { useMutation, useQueryClient } from 'react-query';
import { useNotification } from '@strapi/helper-plugin';
import pluginId from '../pluginId';
import { axiosInstance, getRequestUrl, getTrad } from '../utils';
export const useBulkMove = () => {
const toggleNotification = useNotification();
const queryClient = useQueryClient();
const url = getRequestUrl('actions/bulk-move');
const bulkMoveQuery = ({ destinationFolderId, filesAndFolders }) => {
const payload = filesAndFolders.reduce((acc, selected) => {
const { id, type } = selected;
const key = type === 'asset' ? 'fileIds' : 'folderIds';
if (!acc[key]) {
acc[key] = [];
}
acc[key].push(id);
return acc;
}, {});
return axiosInstance.post(url, { ...payload, destinationFolderId });
};
const mutation = useMutation(bulkMoveQuery, {
onSuccess: res => {
const {
data: { data },
} = res;
if (data?.files?.length > 0) {
queryClient.refetchQueries([pluginId, 'assets'], { active: true });
queryClient.refetchQueries([pluginId, 'asset-count'], { active: true });
}
if (data?.folders?.length > 0) {
queryClient.refetchQueries([pluginId, 'folders'], { active: true });
}
toggleNotification({
type: 'success',
message: {
id: getTrad('modal.move.success-label'),
defaultMessage: 'Changes successfully saved',
},
});
},
onError: error => {
toggleNotification({ type: 'warning', message: error.message });
},
});
const move = (destinationFolderId, filesAndFolders) =>
mutation.mutateAsync({ destinationFolderId, filesAndFolders });
return { ...mutation, move };
};