Open enso devtools on call of toggleDevtools() (#11423)

This PR changes the behavior of `toggleDevtools()` function and shows `ensoDevtools` with `tanstack` devtools
This commit is contained in:
Sergei Garin 2024-10-28 18:53:40 +03:00 committed by GitHub
parent 12267c6d98
commit 5bf064f97f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 65 additions and 30 deletions

View File

@ -519,13 +519,11 @@ function AppRouter(props: AppRouterProps) {
<LocalBackendPathSynchronizer />
<VersionChecker />
{routes}
{detect.IS_DEV_MODE && (
<suspense.Suspense>
<errorBoundary.ErrorBoundary>
<devtools.EnsoDevtools />
</errorBoundary.ErrorBoundary>
</suspense.Suspense>
)}
<suspense.Suspense>
<errorBoundary.ErrorBoundary>
<devtools.EnsoDevtools />
</errorBoundary.ErrorBoundary>
</suspense.Suspense>
</errorBoundary.ErrorBoundary>
</DriveProvider>
</InputBindingsProvider>

View File

@ -24,6 +24,7 @@ import {
useEnableVersionChecker,
usePaywallDevtools,
useSetEnableVersionChecker,
useShowDevtools,
} from './EnsoDevtoolsProvider'
import * as ariaComponents from '#/components/AriaComponents'
@ -54,6 +55,9 @@ export function EnsoDevtools() {
const { authQueryKey, session } = authProvider.useAuth()
const queryClient = reactQuery.useQueryClient()
const { getFeature } = billing.usePaywallFeatures()
const showDevtools = useShowDevtools()
const { features, setFeature } = usePaywallDevtools()
const enableVersionChecker = useEnableVersionChecker()
const setEnableVersionChecker = useSetEnableVersionChecker()
@ -66,6 +70,10 @@ export function EnsoDevtools() {
const featureFlags = useFeatureFlags()
const setFeatureFlags = useSetFeatureFlags()
if (!showDevtools) {
return null
}
return (
<Portal>
<ariaComponents.DialogTrigger>

View File

@ -3,6 +3,8 @@
* This file provides a zustand store that contains the state of the Enso devtools.
*/
import type { PaywallFeatureName } from '#/hooks/billing'
import { IS_DEV_MODE } from 'enso-common/src/detect'
import * as React from 'react'
import * as zustand from 'zustand'
/** Configuration for a paywall feature. */
@ -16,13 +18,23 @@ export interface PaywallDevtoolsFeatureConfiguration {
/** The state of this zustand store. */
interface EnsoDevtoolsStore {
readonly showDevtools: boolean
readonly setShowDevtools: (showDevtools: boolean) => void
readonly toggleDevtools: () => void
readonly showVersionChecker: boolean | null
readonly paywallFeatures: Record<PaywallFeatureName, PaywallDevtoolsFeatureConfiguration>
readonly setPaywallFeature: (feature: PaywallFeatureName, isForceEnabled: boolean | null) => void
readonly setEnableVersionChecker: (showVersionChecker: boolean | null) => void
}
const ensoDevtoolsStore = zustand.createStore<EnsoDevtoolsStore>((set) => ({
export const ensoDevtoolsStore = zustand.createStore<EnsoDevtoolsStore>((set) => ({
showDevtools: IS_DEV_MODE,
setShowDevtools: (showDevtools) => {
set({ showDevtools })
},
toggleDevtools: () => {
set(({ showDevtools }) => ({ showDevtools: !showDevtools }))
},
showVersionChecker: false,
paywallFeatures: {
share: { isForceEnabled: null },
@ -67,3 +79,23 @@ export function usePaywallDevtools() {
setFeature: state.setPaywallFeature,
}))
}
/** A hook that provides access to the show devtools state. */
export function useShowDevtools() {
return zustand.useStore(ensoDevtoolsStore, (state) => state.showDevtools)
}
// =================================
// === DevtoolsProvider ===
// =================================
/**
* Provide the Enso devtools to the app.
*/
export function DevtoolsProvider(props: { children: React.ReactNode }) {
React.useEffect(() => {
window.toggleDevtools = ensoDevtoolsStore.getState().toggleDevtools
}, [])
return <>{props.children}</>
}

View File

@ -4,6 +4,7 @@ import * as React from 'react'
import * as reactQuery from '@tanstack/react-query'
import * as reactQueryDevtools from '@tanstack/react-query-devtools'
import * as errorBoundary from 'react-error-boundary'
import { useShowDevtools } from './EnsoDevtoolsProvider'
const ReactQueryDevtoolsProduction = React.lazy(() =>
import('@tanstack/react-query-devtools/build/modern/production.js').then((d) => ({
@ -13,19 +14,13 @@ const ReactQueryDevtoolsProduction = React.lazy(() =>
/** Show the React Query Devtools and provide the ability to show them in production. */
export function ReactQueryDevtools() {
const [showDevtools, setShowDevtools] = React.useState(false)
const showDevtools = useShowDevtools()
// It is safer to pass the client directly to the devtools
// since there might be a chance that we have multiple versions of `react-query`,
// in case we forget to update the devtools, npm messes up the versions,
// or there are hoisting issues.
const client = reactQuery.useQueryClient()
React.useEffect(() => {
window.toggleDevtools = () => {
setShowDevtools((old) => !old)
}
}, [])
return (
<errorBoundary.ErrorBoundary
fallbackRender={({ resetErrorBoundary }) => {

View File

@ -21,7 +21,7 @@ import LoggerProvider, { type Logger } from '#/providers/LoggerProvider'
import LoadingScreen from '#/pages/authentication/LoadingScreen'
import { ReactQueryDevtools } from '#/components/Devtools'
import { DevtoolsProvider, ReactQueryDevtools } from '#/components/Devtools'
import { ErrorBoundary } from '#/components/ErrorBoundary'
import { OfflineNotificationManager } from '#/components/OfflineNotificationManager'
import { Suspense } from '#/components/Suspense'
@ -113,21 +113,23 @@ export function run(props: DashboardProps) {
reactDOM.createRoot(root).render(
<React.StrictMode>
<QueryClientProvider client={queryClient}>
<ErrorBoundary>
<Suspense fallback={<LoadingScreen />}>
<OfflineNotificationManager>
<LoggerProvider logger={logger}>
<HttpClientProvider httpClient={httpClient}>
<UIProviders locale="en-US" portalRoot={portalRoot}>
<App {...props} supportsDeepLinks={actuallySupportsDeepLinks} />
</UIProviders>
</HttpClientProvider>
</LoggerProvider>
</OfflineNotificationManager>
</Suspense>
</ErrorBoundary>
<DevtoolsProvider>
<ErrorBoundary>
<Suspense fallback={<LoadingScreen />}>
<OfflineNotificationManager>
<LoggerProvider logger={logger}>
<HttpClientProvider httpClient={httpClient}>
<UIProviders locale="en-US" portalRoot={portalRoot}>
<App {...props} supportsDeepLinks={actuallySupportsDeepLinks} />
</UIProviders>
</HttpClientProvider>
</LoggerProvider>
</OfflineNotificationManager>
</Suspense>
</ErrorBoundary>
<ReactQueryDevtools />
<ReactQueryDevtools />
</DevtoolsProvider>
</QueryClientProvider>
</React.StrictMode>,
)