mirror of https://github.com/portainer/portainer
refactor(app): add rq mutation helpers [EE-3176] (#6923)
parent
b01180bb29
commit
0ffb84aaa6
|
@ -1,37 +1,18 @@
|
||||||
import { ReactQueryDevtools } from 'react-query/devtools';
|
import { ReactQueryDevtools } from 'react-query/devtools';
|
||||||
import {
|
import { QueryClientProvider } from 'react-query';
|
||||||
MutationCache,
|
|
||||||
QueryCache,
|
|
||||||
QueryClient,
|
|
||||||
QueryClientProvider,
|
|
||||||
} from 'react-query';
|
|
||||||
import { UIRouterContextComponent } from '@uirouter/react-hybrid';
|
import { UIRouterContextComponent } from '@uirouter/react-hybrid';
|
||||||
import { PropsWithChildren, StrictMode, useState, useEffect } from 'react';
|
import { PropsWithChildren, StrictMode } from 'react';
|
||||||
|
|
||||||
import { UserProvider } from '@/portainer/hooks/useUser';
|
import { UserProvider } from '@/portainer/hooks/useUser';
|
||||||
import { UIStateProvider } from '@/portainer/hooks/UIStateProvider';
|
import { UIStateProvider } from '@/portainer/hooks/UIStateProvider';
|
||||||
import { notifyError } from '@/portainer/services/notifications';
|
|
||||||
|
|
||||||
const queryClient = new QueryClient({
|
import { createQueryClient } from './react-query';
|
||||||
mutationCache: new MutationCache({
|
|
||||||
onError: (error, variable, context, mutation) => {
|
const queryClient = createQueryClient();
|
||||||
handleError(error, mutation.meta?.error);
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
queryCache: new QueryCache({
|
|
||||||
onError: (error, mutation) => {
|
|
||||||
handleError(error, mutation.meta?.error);
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
export function RootProvider({ children }: PropsWithChildren<unknown>) {
|
export function RootProvider({ children }: PropsWithChildren<unknown>) {
|
||||||
const [showReactQueryDevtools, setShowReactQueryDevtools] = useState(false);
|
const showReactQueryDevtools =
|
||||||
useEffect(() => {
|
process.env.SHOW_REACT_QUERY_DEV_TOOLS === 'true';
|
||||||
if (process.env.SHOW_REACT_QUERY_DEV_TOOLS === 'true') {
|
|
||||||
setShowReactQueryDevtools(true);
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StrictMode>
|
<StrictMode>
|
||||||
|
@ -46,20 +27,3 @@ export function RootProvider({ children }: PropsWithChildren<unknown>) {
|
||||||
</StrictMode>
|
</StrictMode>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleError(error: unknown, errorMeta?: unknown) {
|
|
||||||
if (errorMeta && typeof errorMeta === 'object') {
|
|
||||||
if (!('title' in errorMeta)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { title, message } = errorMeta as {
|
|
||||||
title: unknown;
|
|
||||||
message?: unknown;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (typeof title === 'string') {
|
|
||||||
notifyError(title, error as Error, message as string);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
import {
|
||||||
|
MutationCache,
|
||||||
|
MutationOptions,
|
||||||
|
QueryCache,
|
||||||
|
QueryClient,
|
||||||
|
QueryKey,
|
||||||
|
QueryOptions,
|
||||||
|
} from 'react-query';
|
||||||
|
|
||||||
|
import { notifyError } from '@/portainer/services/notifications';
|
||||||
|
|
||||||
|
export function withError(fallbackMessage?: string, title = 'Failure') {
|
||||||
|
return {
|
||||||
|
onError(error: unknown) {
|
||||||
|
notifyError(title, error as Error, fallbackMessage);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function withGlobalError(fallbackMessage?: string, title = 'Failure') {
|
||||||
|
return {
|
||||||
|
meta: {
|
||||||
|
error: { message: fallbackMessage, title },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
type OptionalReadonly<T> = T | Readonly<T>;
|
||||||
|
|
||||||
|
export function withInvalidate(
|
||||||
|
queryClient: QueryClient,
|
||||||
|
queryKeysToInvalidate: OptionalReadonly<string[]>[]
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
onSuccess() {
|
||||||
|
return queryKeysToInvalidate.map((keys) =>
|
||||||
|
queryClient.invalidateQueries(keys)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function mutationOptions<
|
||||||
|
TData = unknown,
|
||||||
|
TError = unknown,
|
||||||
|
TVariables = void,
|
||||||
|
TContext = unknown
|
||||||
|
>(...options: MutationOptions<TData, TError, TVariables, TContext>[]) {
|
||||||
|
return mergeOptions(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function queryOptions<
|
||||||
|
TQueryFnData = unknown,
|
||||||
|
TError = unknown,
|
||||||
|
TData = TQueryFnData,
|
||||||
|
TQueryKey extends QueryKey = QueryKey
|
||||||
|
>(...options: QueryOptions<TQueryFnData, TError, TData, TQueryKey>[]) {
|
||||||
|
return mergeOptions(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
function mergeOptions<T>(...options: T[]) {
|
||||||
|
return options.reduce(
|
||||||
|
(acc, option) => ({
|
||||||
|
...acc,
|
||||||
|
...option,
|
||||||
|
}),
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createQueryClient() {
|
||||||
|
return new QueryClient({
|
||||||
|
mutationCache: new MutationCache({
|
||||||
|
onError: (error, variable, context, mutation) => {
|
||||||
|
handleError(error, mutation.meta?.error);
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
queryCache: new QueryCache({
|
||||||
|
onError: (error, mutation) => {
|
||||||
|
handleError(error, mutation.meta?.error);
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleError(error: unknown, errorMeta?: unknown) {
|
||||||
|
if (errorMeta && typeof errorMeta === 'object') {
|
||||||
|
const { title = 'Failure', message } = errorMeta as {
|
||||||
|
title?: string;
|
||||||
|
message?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
notifyError(title, error as Error, message);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue