@centreon/ui 23.10.26 → 23.10.27-MON-19397-add-optimistic-ui-on-mutate.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -58,9 +58,8 @@ const useFetchQuery = <T extends object>({
|
|
|
58
58
|
}: UseFetchQueryProps<T>): UseFetchQueryState<T> => {
|
|
59
59
|
const { showErrorMessage } = useSnackbar();
|
|
60
60
|
|
|
61
|
-
const queryData = useQuery<T | ResponseError, Error>(
|
|
62
|
-
|
|
63
|
-
({ signal }): Promise<T | ResponseError> =>
|
|
61
|
+
const queryData = useQuery<T | ResponseError, Error>({
|
|
62
|
+
queryFn: ({ signal }): Promise<T | ResponseError> =>
|
|
64
63
|
customFetch<T>({
|
|
65
64
|
catchError,
|
|
66
65
|
decoder,
|
|
@@ -69,10 +68,9 @@ const useFetchQuery = <T extends object>({
|
|
|
69
68
|
headers: new Headers(fetchHeaders),
|
|
70
69
|
signal
|
|
71
70
|
}),
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
);
|
|
71
|
+
queryKey: getQueryKey(),
|
|
72
|
+
...queryOptions
|
|
73
|
+
});
|
|
76
74
|
|
|
77
75
|
const queryClient = useQueryClient();
|
|
78
76
|
|
|
@@ -115,4 +115,27 @@ describe('useFetchQuery', () => {
|
|
|
115
115
|
expect(mockedShowErrorMessage).not.toHaveBeenCalled();
|
|
116
116
|
});
|
|
117
117
|
});
|
|
118
|
+
|
|
119
|
+
it('calls the `onMutate` callback when the mutation has been successfully sent', async () => {
|
|
120
|
+
fetchMock.once(JSON.stringify({}));
|
|
121
|
+
const onMutate = jest.fn();
|
|
122
|
+
|
|
123
|
+
const { result } = renderMutationQuery<User>({
|
|
124
|
+
getEndpoint: () => '/endpoint',
|
|
125
|
+
method: Method.POST,
|
|
126
|
+
optimisticUI: {
|
|
127
|
+
onMutate,
|
|
128
|
+
queryKeyToInvalidate: ['key']
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
result.current.mutate(user);
|
|
133
|
+
|
|
134
|
+
await waitFor(() => {
|
|
135
|
+
expect(onMutate).toHaveBeenCalledWith({
|
|
136
|
+
email: 'john@doe.com',
|
|
137
|
+
name: 'John Doe'
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
});
|
|
118
141
|
});
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import 'ulog';
|
|
2
|
-
import { useEffect } from 'react';
|
|
2
|
+
import { startTransition, useEffect } from 'react';
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
QueryClient,
|
|
6
|
+
QueryKey,
|
|
7
|
+
useMutation,
|
|
8
|
+
useQueryClient
|
|
9
|
+
} from '@tanstack/react-query';
|
|
5
10
|
import { JsonDecoder } from 'ts.data.json';
|
|
6
11
|
import anylogger from 'anylogger';
|
|
7
12
|
import { includes } from 'ramda';
|
|
@@ -17,6 +22,19 @@ export enum Method {
|
|
|
17
22
|
PUT = 'PUT'
|
|
18
23
|
}
|
|
19
24
|
|
|
25
|
+
interface OptimisticUIProps<T> {
|
|
26
|
+
onError?: (error, variables, context) => void;
|
|
27
|
+
onMutate?: (variables) => unknown;
|
|
28
|
+
onSettled?: (
|
|
29
|
+
data: T | ResponseError | undefined,
|
|
30
|
+
error: unknown,
|
|
31
|
+
variables: void,
|
|
32
|
+
context: unknown
|
|
33
|
+
) => unknown;
|
|
34
|
+
onSuccess?: (data, variables, context) => void;
|
|
35
|
+
queryKeyToInvalidate: QueryKey;
|
|
36
|
+
}
|
|
37
|
+
|
|
20
38
|
export interface UseMutationQueryProps<T> {
|
|
21
39
|
catchError?: (props: CatchErrorProps) => void;
|
|
22
40
|
decoder?: JsonDecoder.Decoder<T>;
|
|
@@ -25,6 +43,7 @@ export interface UseMutationQueryProps<T> {
|
|
|
25
43
|
getEndpoint: (payload) => string;
|
|
26
44
|
httpCodesBypassErrorSnackbar?: Array<number>;
|
|
27
45
|
method: Method;
|
|
46
|
+
optimisticUI?: OptimisticUIProps<T>;
|
|
28
47
|
}
|
|
29
48
|
|
|
30
49
|
const log = anylogger('API Request');
|
|
@@ -34,6 +53,7 @@ export interface UseMutationQueryState<T> {
|
|
|
34
53
|
isMutating: boolean;
|
|
35
54
|
mutate: (payload) => void;
|
|
36
55
|
mutateAsync: (payload) => Promise<T | ResponseError>;
|
|
56
|
+
queryClient: QueryClient;
|
|
37
57
|
}
|
|
38
58
|
|
|
39
59
|
const useMutationQuery = <T extends object>({
|
|
@@ -43,12 +63,15 @@ const useMutationQuery = <T extends object>({
|
|
|
43
63
|
defaultFailureMessage,
|
|
44
64
|
fetchHeaders,
|
|
45
65
|
httpCodesBypassErrorSnackbar = [],
|
|
46
|
-
method
|
|
66
|
+
method,
|
|
67
|
+
optimisticUI
|
|
47
68
|
}: UseMutationQueryProps<T>): UseMutationQueryState<T> => {
|
|
48
69
|
const { showErrorMessage } = useSnackbar();
|
|
49
70
|
|
|
50
|
-
const
|
|
51
|
-
|
|
71
|
+
const queryClient = useQueryClient();
|
|
72
|
+
|
|
73
|
+
const queryData = useMutation<T | ResponseError>({
|
|
74
|
+
mutationFn: (payload): Promise<T | ResponseError> =>
|
|
52
75
|
customFetch<T>({
|
|
53
76
|
catchError,
|
|
54
77
|
decoder,
|
|
@@ -61,8 +84,20 @@ const useMutationQuery = <T extends object>({
|
|
|
61
84
|
isMutation: true,
|
|
62
85
|
method,
|
|
63
86
|
payload
|
|
64
|
-
})
|
|
65
|
-
|
|
87
|
+
}),
|
|
88
|
+
onError: optimisticUI?.onError,
|
|
89
|
+
onMutate: optimisticUI?.onMutate,
|
|
90
|
+
onSettled: optimisticUI?.onSettled,
|
|
91
|
+
onSuccess: (data, variables, context) => {
|
|
92
|
+
startTransition(() => {
|
|
93
|
+
queryClient.invalidateQueries({
|
|
94
|
+
queryKey: optimisticUI?.queryKeyToInvalidate
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
optimisticUI?.onSuccess?.(data, variables, context);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
66
101
|
|
|
67
102
|
const manageError = (): void => {
|
|
68
103
|
const data = queryData.data as ResponseError | undefined;
|
|
@@ -87,7 +122,8 @@ const useMutationQuery = <T extends object>({
|
|
|
87
122
|
isError: (queryData.data as ResponseError | undefined)?.isError || false,
|
|
88
123
|
isMutating: queryData.isLoading,
|
|
89
124
|
mutate: queryData.mutate,
|
|
90
|
-
mutateAsync: queryData.mutateAsync
|
|
125
|
+
mutateAsync: queryData.mutateAsync,
|
|
126
|
+
queryClient
|
|
91
127
|
};
|
|
92
128
|
};
|
|
93
129
|
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { useQueryClient } from '@tanstack/react-query';
|
|
2
|
+
|
|
3
|
+
import { ListingModel } from '..';
|
|
4
|
+
|
|
5
|
+
interface ApplyListingMutationProps<T> {
|
|
6
|
+
getNewData: (listing: ListingModel<T>) => ListingModel<T>;
|
|
7
|
+
page: number;
|
|
8
|
+
queryKey: Array<string>;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface RollBackListingMutation {
|
|
12
|
+
context;
|
|
13
|
+
page: number;
|
|
14
|
+
queryKey: Array<string>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface UseOptimisticListingMutationState<T> {
|
|
18
|
+
applyListingMutation: (props: ApplyListingMutationProps<T>) => Promise<{
|
|
19
|
+
previousListing: ListingModel<T>;
|
|
20
|
+
}>;
|
|
21
|
+
rollBackListingMutation: (props: RollBackListingMutation) => void;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const useOptimisticListingMutation = <
|
|
25
|
+
T extends { id: string | number }
|
|
26
|
+
>(): UseOptimisticListingMutationState<T> => {
|
|
27
|
+
const queryClient = useQueryClient();
|
|
28
|
+
|
|
29
|
+
const applyListingMutation = async ({
|
|
30
|
+
page,
|
|
31
|
+
queryKey,
|
|
32
|
+
getNewData
|
|
33
|
+
}: ApplyListingMutationProps<T>): Promise<{
|
|
34
|
+
previousListing: ListingModel<T>;
|
|
35
|
+
}> => {
|
|
36
|
+
await queryClient.cancelQueries({ queryKey });
|
|
37
|
+
const previousListing = queryClient.getQueriesData(
|
|
38
|
+
queryKey
|
|
39
|
+
)[0][1] as ListingModel<T>;
|
|
40
|
+
|
|
41
|
+
const newData = getNewData(previousListing);
|
|
42
|
+
|
|
43
|
+
queryClient.setQueryData([...queryKey, page], newData);
|
|
44
|
+
|
|
45
|
+
return { previousListing };
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const rollBackListingMutation = ({
|
|
49
|
+
context,
|
|
50
|
+
page,
|
|
51
|
+
queryKey
|
|
52
|
+
}: RollBackListingMutation): void => {
|
|
53
|
+
queryClient.setQueryData([...queryKey, page], context?.previousListing);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
applyListingMutation,
|
|
58
|
+
rollBackListingMutation
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export default useOptimisticListingMutation;
|
package/src/index.ts
CHANGED
|
@@ -124,6 +124,7 @@ export { default as Responsive } from './Responsive';
|
|
|
124
124
|
export { default as useFetchQuery } from './api/useFetchQuery';
|
|
125
125
|
export { default as useMutationQuery, Method } from './api/useMutationQuery';
|
|
126
126
|
export { default as QueryProvider } from './api/QueryProvider';
|
|
127
|
+
export { default as useOptimisticListingMutation } from './api/useOptimisticListingMutation';
|
|
127
128
|
export {
|
|
128
129
|
default as FileDropZone,
|
|
129
130
|
transformFileListToArray
|