mirror of
https://github.com/enso-org/enso.git
synced 2024-11-22 22:10:15 +03:00
Add declarative api to invalidate queries in mutations (#10200)
In this PR: 1. We added support to declaratively invalidate queries after making a mutation 2. We pull ReactQueryDevtools up in the component tree to make it available during dashboard loading Also, this PR removes some rules in eslint
This commit is contained in:
parent
7a20bdc82f
commit
0f7bae3177
@ -453,11 +453,6 @@ export default [
|
||||
selector: ':not(TSModuleDeclaration)[declare=true]',
|
||||
message: 'No ambient declarations',
|
||||
},
|
||||
{
|
||||
selector: 'ExportDefaultDeclaration:has(Identifier.declaration)',
|
||||
message:
|
||||
'Use `export default` on the declaration, instead of as a separate statement',
|
||||
},
|
||||
],
|
||||
// This rule does not work with TypeScript, and TypeScript already does this.
|
||||
'no-undef': 'off',
|
||||
|
@ -88,7 +88,6 @@ import * as object from '#/utilities/object'
|
||||
import * as authServiceModule from '#/authentication/service'
|
||||
|
||||
import type * as types from '../../types/types'
|
||||
import * as reactQueryDevtools from './ReactQueryDevtools'
|
||||
|
||||
// ============================
|
||||
// === Global configuration ===
|
||||
@ -173,12 +172,6 @@ export default function App(props: AppProps) {
|
||||
},
|
||||
})
|
||||
|
||||
const routerFuture: Partial<router.FutureConfig> = {
|
||||
/* we want to use startTransition to enable concurrent rendering */
|
||||
/* eslint-disable-next-line @typescript-eslint/naming-convention */
|
||||
v7_startTransition: true,
|
||||
}
|
||||
|
||||
// Both `BackendProvider` and `InputBindingsProvider` depend on `LocalStorageProvider`.
|
||||
// Note that the `Router` must be the parent of the `AuthProvider`, because the `AuthProvider`
|
||||
// will redirect the user between the login/register pages and the dashboard.
|
||||
@ -193,15 +186,13 @@ export default function App(props: AppProps) {
|
||||
transition={toastify.Zoom}
|
||||
limit={3}
|
||||
/>
|
||||
<router.BrowserRouter basename={getMainPageUrl().pathname} future={routerFuture}>
|
||||
<router.BrowserRouter basename={getMainPageUrl().pathname}>
|
||||
<LocalStorageProvider>
|
||||
<ModalProvider>
|
||||
<AppRouter {...props} projectManagerRootDirectory={rootDirectoryPath} />
|
||||
</ModalProvider>
|
||||
</LocalStorageProvider>
|
||||
</router.BrowserRouter>
|
||||
|
||||
<reactQueryDevtools.ReactQueryDevtools />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
@ -19,6 +19,8 @@ import LoadingScreen from '#/pages/authentication/LoadingScreen'
|
||||
|
||||
import * as errorBoundary from '#/components/ErrorBoundary'
|
||||
|
||||
import * as reactQueryDevtools from './ReactQueryDevtools'
|
||||
|
||||
// =================
|
||||
// === Constants ===
|
||||
// =================
|
||||
@ -105,6 +107,8 @@ function run(props: Omit<app.AppProps, 'portalRoot'>) {
|
||||
)}
|
||||
</React.Suspense>
|
||||
</errorBoundary.ErrorBoundary>
|
||||
|
||||
<reactQueryDevtools.ReactQueryDevtools />
|
||||
</reactQuery.QueryClientProvider>
|
||||
</React.StrictMode>
|
||||
)
|
||||
|
@ -34,7 +34,6 @@ export function SetOrganizationNameModal() {
|
||||
const userPlan =
|
||||
session && 'user' in session && session.user?.plan != null ? session.user.plan : null
|
||||
|
||||
const queryClient = reactQuery.useQueryClient()
|
||||
const { data: organizationName } = reactQuery.useSuspenseQuery({
|
||||
queryKey: ['organization', userId],
|
||||
queryFn: () => {
|
||||
@ -51,7 +50,7 @@ export function SetOrganizationNameModal() {
|
||||
const submit = reactQuery.useMutation({
|
||||
mutationKey: ['organization', userId],
|
||||
mutationFn: (name: string) => backend.updateOrganization({ name }),
|
||||
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['organization', userId] }),
|
||||
meta: { invalidates: [['organization', userId]], awaitInvalidates: true },
|
||||
})
|
||||
|
||||
const shouldShowModal =
|
||||
|
@ -6,13 +6,78 @@
|
||||
|
||||
import * as reactQuery from '@tanstack/react-query'
|
||||
|
||||
declare module '@tanstack/react-query' {
|
||||
/**
|
||||
* Specifies the invalidation behavior of a mutation.
|
||||
*/
|
||||
interface Register {
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
readonly mutationMeta: {
|
||||
/**
|
||||
* List of query keys to invalidate when the mutation succeeds.
|
||||
*/
|
||||
readonly invalidates?: reactQuery.QueryKey[]
|
||||
/**
|
||||
* List of query keys to await invalidation before the mutation is considered successful.
|
||||
*
|
||||
* If `true`, all `invalidates` are awaited.
|
||||
*
|
||||
* If `false`, no invalidations are awaited.
|
||||
*
|
||||
* You can also provide an array of query keys to await.
|
||||
*
|
||||
* Queries that are not listed in invalidates will be ignored.
|
||||
* @default false
|
||||
*/
|
||||
readonly awaitInvalidates?: reactQuery.QueryKey[] | boolean
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-magic-numbers
|
||||
const DEFAULT_QUERY_STALE_TIME_MS = 2 * 60 * 1000
|
||||
|
||||
/**
|
||||
* Create a new React Query client.
|
||||
*/
|
||||
export function createReactQueryClient() {
|
||||
return new reactQuery.QueryClient({
|
||||
const queryClient: reactQuery.QueryClient = new reactQuery.QueryClient({
|
||||
mutationCache: new reactQuery.MutationCache({
|
||||
onSuccess: (_data, _variables, _context, mutation) => {
|
||||
const shouldAwaitInvalidates = mutation.meta?.awaitInvalidates ?? false
|
||||
const invalidates = mutation.meta?.invalidates ?? []
|
||||
const invalidatesToAwait = (() => {
|
||||
if (Array.isArray(shouldAwaitInvalidates)) {
|
||||
return shouldAwaitInvalidates
|
||||
} else {
|
||||
return shouldAwaitInvalidates ? invalidates : []
|
||||
}
|
||||
})()
|
||||
const invalidatesToIgnore = invalidates.filter(
|
||||
queryKey => !invalidatesToAwait.includes(queryKey)
|
||||
)
|
||||
|
||||
for (const queryKey of invalidatesToIgnore) {
|
||||
void queryClient.invalidateQueries({
|
||||
predicate: query => reactQuery.matchQuery({ queryKey }, query),
|
||||
})
|
||||
}
|
||||
|
||||
if (invalidatesToAwait.length > 0) {
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
return Promise.all(
|
||||
invalidatesToAwait.map(queryKey =>
|
||||
queryClient.invalidateQueries({
|
||||
predicate: query => reactQuery.matchQuery({ queryKey }, query),
|
||||
})
|
||||
)
|
||||
)
|
||||
}
|
||||
},
|
||||
}),
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
staleTime: DEFAULT_QUERY_STALE_TIME_MS,
|
||||
retry: (failureCount, error) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-magic-numbers
|
||||
const statusesToIgnore = [401, 403, 404]
|
||||
@ -28,4 +93,6 @@ export function createReactQueryClient() {
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
return queryClient
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user