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'], }, };