import * as React from 'react';
import { QueryClient, useIsMutating } from '@tanstack/react-query';
import { CoreAdmin, CoreAdminContext, Resource } from '../core';
import { useUpdateMany } from './useUpdateMany';
import { useGetList } from './useGetList';
import { useState } from 'react';
import { useGetOne } from './useGetOne';
import { useTakeUndoableMutation } from './undo';
import type { DataProvider, MutationMode as MutationModeType } from '../types';
import fakeRestDataProvider from 'ra-data-fakerest';
import { TestMemoryRouter, useRedirect } from '../routing';
import { useNotificationContext, useNotify } from '../notification';
import { EditBase, ListBase, RecordsIterator } from '../controller';
export default { title: 'ra-core/dataProvider/useUpdateMany' };
export const UndefinedValues = () => {
const data = [
{ id: 1, title: 'foo' },
{ id: 2, title: 'bar' },
];
const dataProvider = {
getList: async () => ({ data, total: 2 }),
updateMany: () => new Promise(() => {}), // never resolve to see only optimistic update
} as any;
return (
);
};
const UndefinedValuesCore = () => {
const { data } = useGetList('posts');
const [updateMany, { isPending }] = useUpdateMany();
const handleClick = () => {
updateMany(
'posts',
{
ids: [1, 2],
data: { id: undefined, title: 'world' },
},
{ mutationMode: 'optimistic' }
);
};
return (
<>
{JSON.stringify(data)}
>
);
};
export const WithMiddlewares = ({
timeout = 1000,
mutationMode,
shouldError,
}: {
timeout?: number;
mutationMode: 'optimistic' | 'pessimistic' | 'undoable';
shouldError?: boolean;
}) => {
const posts = [{ id: 1, title: 'Hello', author: 'John Doe' }];
const dataProvider = {
getOne: () => {
return Promise.resolve({
data: posts[0],
});
},
updateMany: (resource, params) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (shouldError) {
return reject(new Error('something went wrong'));
}
posts[0].title = params.data.title;
resolve({ data: [1] });
}, timeout);
});
},
} as any;
return (
);
};
WithMiddlewares.args = {
timeout: 1000,
mutationMode: 'optimistic',
shouldError: false,
};
WithMiddlewares.argTypes = {
timeout: {
control: { type: 'number' },
},
mutationMode: {
options: ['optimistic', 'pessimistic', 'undoable'],
control: { type: 'select' },
},
shouldError: {
control: { type: 'boolean' },
},
};
const WithMiddlewaresCore = ({
mutationMode,
}: {
mutationMode: 'optimistic' | 'pessimistic' | 'undoable';
}) => {
const isMutating = useIsMutating();
const [notification, setNotification] = useState(false);
const [success, setSuccess] = useState();
const [error, setError] = useState();
const takeMutation = useTakeUndoableMutation();
const { data, refetch } = useGetOne('posts', { id: 1 });
const [updateMany, { isPending }] = useUpdateMany(
'posts',
{
ids: [1],
data: { title: 'Hello World' },
},
{
mutationMode,
// @ts-ignore
getMutateWithMiddlewares: mutate => async (resource, params) => {
return mutate(resource, {
...params,
data: { title: `${params.data.title} from middleware` },
});
},
}
);
const handleClick = () => {
updateMany(
'posts',
{
ids: [1],
data: { title: 'Hello World' },
},
{
onSuccess: () => setSuccess('success'),
onError: e => {
setError(e);
setSuccess('');
},
}
);
if (mutationMode === 'undoable') {
setNotification(true);
}
};
return (
<>
- title
- {data?.title}
- author
- {data?.author}
{notification ? (
<>
>
) : (
)}
{success && {success}
}
{error && {error.message}
}
{isMutating !== 0 && mutating
}
>
);
};
export const MutationMode = () => {
const data = [
{ id: 1, title: 'foo' },
{ id: 2, title: 'bar' },
];
const dataProvider = {
getList: async () => ({ data, total: 2 }),
updateMany: () => new Promise(() => {}), // never resolve to see only optimistic update
} as any;
return (
);
};
const MutationModeCore = () => {
const { data } = useGetList('posts');
const [mutationMode, setMutationMode] =
React.useState('pessimistic');
const [updateMany, { isPending }] = useUpdateMany(
'posts',
{
ids: [1, 2],
data: { id: undefined, title: 'world' },
},
{ mutationMode }
);
const handleClick = () => {
updateMany();
};
return (
<>
{JSON.stringify(data)}
>
);
};
export const Params = ({ dataProvider }: { dataProvider?: DataProvider }) => {
const data = [
{ id: 1, title: 'foo' },
{ id: 2, title: 'bar' },
];
const defaultDataProvider = {
getList: async () => ({ data, total: 2 }),
updateMany: () => new Promise(() => {}), // never resolve to see only optimistic update
} as any;
return (
);
};
const ParamsCore = () => {
const { data } = useGetList('posts');
const [params, setParams] = React.useState({});
const [updateMany, { isPending }] = useUpdateMany(
'posts',
{
ids: [1, 2],
data: { id: undefined, title: 'world' },
meta: params.meta,
},
{ mutationMode: 'optimistic' }
);
const handleClick = () => {
updateMany();
};
return (
<>
{JSON.stringify(data)}
>
);
};
const Notification = () => {
const { notifications, resetNotifications } = useNotificationContext();
const takeMutation = useTakeUndoableMutation();
return notifications.length > 0 ? (
<>
{notifications[0].message}
>
) : null;
};
const UpdateButton = ({ mutationMode }: { mutationMode: MutationModeType }) => {
const notify = useNotify();
const redirect = useRedirect();
const [updateMany, { isPending }] = useUpdateMany();
const handleClick = () => {
updateMany(
'posts',
{
ids: [1],
data: { title: 'Hello updated' },
},
{
mutationMode,
onSuccess: () => {
// Show undoable notification like controllers do
notify('resources.posts.notifications.updated', {
type: 'info',
undoable: mutationMode === 'undoable',
});
// Redirect to list after mutation succeeds
redirect('list', 'posts');
},
}
);
};
return (
);
};
export const InvalidateList = ({
mutationMode,
}: {
mutationMode: MutationModeType;
}) => {
const dataProvider = fakeRestDataProvider(
{
posts: [
{ id: 1, title: 'Hello' },
{ id: 2, title: 'World' },
],
},
process.env.NODE_ENV !== 'test',
process.env.NODE_ENV === 'test' ? 10 : 1000
);
return (
Edit Post
}
list={
Loading...}>
(
{record.id}: {record.title}
)}
/>
}
/>
);
};
InvalidateList.args = {
mutationMode: 'undoable',
};
InvalidateList.argTypes = {
mutationMode: {
control: {
type: 'select',
},
options: ['pessimistic', 'optimistic', 'undoable'],
},
};