Skip to content

Commit ca7b47f

Browse files
committed
story and test for useDeleteMany
1 parent fbbfb9c commit ca7b47f

File tree

2 files changed

+136
-2
lines changed

2 files changed

+136
-2
lines changed

packages/ra-core/src/dataProvider/useDeleteMany.spec.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { QueryClient, useMutationState } from '@tanstack/react-query';
66
import { CoreAdminContext } from '../core';
77
import { testDataProvider } from './testDataProvider';
88
import { useDeleteMany } from './useDeleteMany';
9-
import { MutationMode, Params } from './useDeleteMany.stories';
9+
import { MutationMode, Params, InvalidateList } from './useDeleteMany.stories';
1010

1111
describe('useDeleteMany', () => {
1212
it('returns a callback that can be used with update arguments', async () => {
@@ -390,5 +390,15 @@ describe('useDeleteMany', () => {
390390
});
391391
});
392392
});
393+
394+
it('invalidates getList query when dataProvider resolves in undoable mode', async () => {
395+
render(<InvalidateList mutationMode="undoable" />);
396+
fireEvent.click(await screen.findByText('Delete'));
397+
await screen.findByText('resources.posts.notifications.deleted');
398+
fireEvent.click(screen.getByText('Close'));
399+
await waitFor(() => {
400+
expect(screen.queryByText('1: Hello')).toBeNull();
401+
});
402+
});
393403
});
394404
});

packages/ra-core/src/dataProvider/useDeleteMany.stories.tsx

Lines changed: 125 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
import * as React from 'react';
22
import { useState } from 'react';
33
import { QueryClient, useIsMutating } from '@tanstack/react-query';
4+
import fakeRestDataProvider from 'ra-data-fakerest';
45

5-
import { CoreAdminContext } from '../core';
6+
import { CoreAdmin, CoreAdminContext, Resource } from '../core';
67
import { useDeleteMany } from './useDeleteMany';
78
import { useGetList } from './useGetList';
89
import type { DataProvider, MutationMode as MutationModeType } from '../types';
10+
import { TestMemoryRouter, useRedirect } from '../routing';
11+
import { useNotificationContext, useNotify } from '../notification';
12+
import { useTakeUndoableMutation } from './undo';
13+
import { EditBase, ListBase, RecordsIterator } from '../controller';
914

1015
export default { title: 'ra-core/dataProvider/useDeleteMany' };
1116

@@ -84,6 +89,125 @@ const MutationModeCore = () => {
8489
);
8590
};
8691

92+
const Notification = () => {
93+
const { notifications, resetNotifications } = useNotificationContext();
94+
const takeMutation = useTakeUndoableMutation();
95+
96+
return notifications.length > 0 ? (
97+
<>
98+
<div>{notifications[0].message}</div>
99+
<div style={{ display: 'flex', gap: '16px' }}>
100+
<button
101+
onClick={() => {
102+
if (notifications[0].notificationOptions?.undoable) {
103+
const mutation = takeMutation();
104+
if (mutation) {
105+
mutation({ isUndo: false });
106+
}
107+
}
108+
resetNotifications();
109+
}}
110+
>
111+
Close
112+
</button>
113+
</div>
114+
</>
115+
) : null;
116+
};
117+
118+
const DeleteButton = ({ mutationMode }: { mutationMode: MutationModeType }) => {
119+
const notify = useNotify();
120+
const redirect = useRedirect();
121+
const [deleteMany, { isPending }] = useDeleteMany();
122+
const handleClick = () => {
123+
deleteMany(
124+
'posts',
125+
{
126+
ids: [1],
127+
},
128+
{
129+
mutationMode,
130+
onSuccess: () => {
131+
notify('resources.posts.notifications.deleted', {
132+
type: 'info',
133+
undoable: mutationMode === 'undoable',
134+
});
135+
redirect('list', 'posts');
136+
},
137+
}
138+
);
139+
};
140+
return (
141+
<button onClick={handleClick} disabled={isPending}>
142+
Delete
143+
</button>
144+
);
145+
};
146+
147+
export const InvalidateList = ({
148+
mutationMode,
149+
}: {
150+
mutationMode: MutationModeType;
151+
}) => {
152+
const dataProvider = fakeRestDataProvider(
153+
{
154+
posts: [
155+
{ id: 1, title: 'Hello' },
156+
{ id: 2, title: 'World' },
157+
],
158+
},
159+
process.env.NODE_ENV !== 'test',
160+
process.env.NODE_ENV === 'test' ? 10 : 1000
161+
);
162+
163+
return (
164+
<TestMemoryRouter initialEntries={['/posts/1']}>
165+
<CoreAdmin dataProvider={dataProvider}>
166+
<Resource
167+
name="posts"
168+
edit={
169+
<EditBase>
170+
<div>
171+
<h1>Edit Post</h1>
172+
<DeleteButton mutationMode={mutationMode} />
173+
</div>
174+
</EditBase>
175+
}
176+
list={
177+
<ListBase loading={<p>Loading...</p>}>
178+
<RecordsIterator
179+
render={(record: any) => (
180+
<div
181+
style={{
182+
display: 'flex',
183+
gap: '8px',
184+
alignItems: 'center',
185+
}}
186+
>
187+
{record.id}: {record.title}
188+
</div>
189+
)}
190+
/>
191+
<Notification />
192+
</ListBase>
193+
}
194+
/>
195+
</CoreAdmin>
196+
</TestMemoryRouter>
197+
);
198+
};
199+
InvalidateList.args = {
200+
mutationMode: 'undoable',
201+
};
202+
InvalidateList.argTypes = {
203+
mutationMode: {
204+
control: {
205+
type: 'select',
206+
},
207+
options: ['pessimistic', 'optimistic', 'undoable'],
208+
},
209+
};
210+
87211
export const Params = ({ dataProvider }: { dataProvider?: DataProvider }) => {
88212
let posts = [
89213
{ id: 1, title: 'Hello' },

0 commit comments

Comments
 (0)