mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
feat(dev-tools): rename devTelemetry() to devToolbar() and add devToolbarDefaultOn flag (#47494)
## What - Renames the `window.devTelemetry()` helper to `window.devToolbar()`. - Adds a `devToolbarDefaultOn` ConfigCat flag. When enabled, the dev toolbar shows automatically without the user having to run `window.devToolbar()` in the console. - The toolbar remains gated to `local` and `staging` environments only — the flag has no effect in production. ## Notes - The `localStorage` key (`dev-telemetry-toolbar-enabled`) is intentionally left unchanged so anyone who already enabled the toolbar keeps their setting. - Updated unit tests: renamed all references and added coverage for the `devToolbarDefaultOn` flag across local, staging, and prod. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added a new default-on option for the dev toolbar in local or staging environments when the feature flag is enabled. * The toolbar can now be opened from a new global trigger when available. * **Bug Fixes** * Improved toolbar enablement behavior across environments, including production, to avoid showing the trigger when it shouldn’t appear. * Updated cleanup behavior so the toolbar trigger is removed correctly after unmounting. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
9f1ce56322
commit
af324d4189
2 files changed
+60
-20
No files matched your search
@@ -4,10 +4,12 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
devTelemetry?: () => void
|
||||
devToolbar?: () => void
|
||||
}
|
||||
}
|
||||
|
||||
const flags = vi.hoisted(() => ({ devToolbarDefaultOn: false }))
|
||||
|
||||
// Mock common package
|
||||
vi.mock('common', async () => {
|
||||
return {
|
||||
@@ -16,6 +18,7 @@ vi.mock('common', async () => {
|
||||
posthog: {},
|
||||
configcat: {},
|
||||
}),
|
||||
useFlag: (name: string) => (name === 'devToolbarDefaultOn' ? flags.devToolbarDefaultOn : false),
|
||||
posthogClient: {
|
||||
subscribeToEvents: vi.fn(() => () => {}),
|
||||
},
|
||||
@@ -27,7 +30,7 @@ const originalEnv = process.env.NEXT_PUBLIC_ENVIRONMENT
|
||||
|
||||
/**
|
||||
* Helper to render the full component tree as used in production.
|
||||
* The Provider sets up window.devTelemetry and manages state.
|
||||
* The Provider sets up window.devToolbar and manages state.
|
||||
* The Trigger shows the activity icon in the header.
|
||||
* The Toolbar is the actual panel/sheet.
|
||||
*/
|
||||
@@ -73,7 +76,8 @@ describe('DevToolbar', () => {
|
||||
})
|
||||
|
||||
localStorage.clear()
|
||||
delete window.devTelemetry
|
||||
flags.devToolbarDefaultOn = false
|
||||
delete window.devToolbar
|
||||
vi.spyOn(console, 'warn').mockImplementation(() => {})
|
||||
vi.spyOn(console, 'error').mockImplementation(() => {})
|
||||
})
|
||||
@@ -101,11 +105,11 @@ describe('DevToolbar', () => {
|
||||
expect(container.querySelector('button')).toBeNull()
|
||||
})
|
||||
|
||||
it('does not register window.devTelemetry', async () => {
|
||||
it('does not register window.devToolbar', async () => {
|
||||
vi.resetModules()
|
||||
await renderFullToolbar()
|
||||
|
||||
expect(window.devTelemetry).toBeUndefined()
|
||||
expect(window.devToolbar).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -122,12 +126,12 @@ describe('DevToolbar', () => {
|
||||
expect(container.querySelector('button')).toBeNull()
|
||||
})
|
||||
|
||||
it('registers window.devTelemetry function', async () => {
|
||||
it('registers window.devToolbar function', async () => {
|
||||
vi.resetModules()
|
||||
await renderFullToolbar()
|
||||
|
||||
expect(window.devTelemetry).toBeDefined()
|
||||
expect(typeof window.devTelemetry).toBe('function')
|
||||
expect(window.devToolbar).toBeDefined()
|
||||
expect(typeof window.devToolbar).toBe('function')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -218,7 +222,41 @@ describe('DevToolbar', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('window.devTelemetry function', () => {
|
||||
describe('when devToolbarDefaultOn flag is enabled', () => {
|
||||
it('renders the trigger without calling window.devToolbar in local', async () => {
|
||||
process.env.NEXT_PUBLIC_ENVIRONMENT = 'local'
|
||||
flags.devToolbarDefaultOn = true
|
||||
|
||||
vi.resetModules()
|
||||
await renderFullToolbar()
|
||||
|
||||
const triggerButton = screen.getByRole('button')
|
||||
expect(triggerButton).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders the trigger without calling window.devToolbar in staging', async () => {
|
||||
process.env.NEXT_PUBLIC_ENVIRONMENT = 'staging'
|
||||
flags.devToolbarDefaultOn = true
|
||||
|
||||
vi.resetModules()
|
||||
await renderFullToolbar()
|
||||
|
||||
const triggerButton = screen.getByRole('button')
|
||||
expect(triggerButton).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('does not render the trigger in production even when flag is on', async () => {
|
||||
process.env.NEXT_PUBLIC_ENVIRONMENT = 'prod'
|
||||
flags.devToolbarDefaultOn = true
|
||||
|
||||
vi.resetModules()
|
||||
const { container } = await renderFullToolbar()
|
||||
|
||||
expect(container.querySelector('button')).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
describe('window.devToolbar function', () => {
|
||||
beforeEach(() => {
|
||||
process.env.NEXT_PUBLIC_ENVIRONMENT = 'local'
|
||||
})
|
||||
@@ -230,9 +268,9 @@ describe('DevToolbar', () => {
|
||||
// Trigger should not be visible initially
|
||||
expect(screen.queryByRole('button')).not.toBeInTheDocument()
|
||||
|
||||
// Call devTelemetry to enable
|
||||
// Call devToolbar to enable
|
||||
act(() => {
|
||||
window.devTelemetry?.()
|
||||
window.devToolbar?.()
|
||||
})
|
||||
|
||||
// Re-import and rerender to pick up state change
|
||||
@@ -256,17 +294,17 @@ describe('DevToolbar', () => {
|
||||
})
|
||||
|
||||
describe('cleanup', () => {
|
||||
it('removes window.devTelemetry on unmount', async () => {
|
||||
it('removes window.devToolbar on unmount', async () => {
|
||||
process.env.NEXT_PUBLIC_ENVIRONMENT = 'local'
|
||||
|
||||
vi.resetModules()
|
||||
const result = await renderFullToolbar()
|
||||
|
||||
expect(window.devTelemetry).toBeDefined()
|
||||
expect(window.devToolbar).toBeDefined()
|
||||
|
||||
result.unmount()
|
||||
|
||||
expect(window.devTelemetry).toBeUndefined()
|
||||
expect(window.devToolbar).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
|
||||
import { ensurePlatformSuffix, posthogClient, type ClientTelemetryEvent } from 'common'
|
||||
import { ensurePlatformSuffix, posthogClient, useFlag, type ClientTelemetryEvent } from 'common'
|
||||
import {
|
||||
createContext,
|
||||
useCallback,
|
||||
@@ -32,7 +32,7 @@ const SSE_BACKOFF_MULTIPLIER = 2
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
devTelemetry?: () => void
|
||||
devToolbar?: () => void
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,8 @@ export function DevToolbarProvider({ children, apiUrl }: DevToolbarProviderProps
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
const [events, setEvents] = useState<DevTelemetryEvent[]>([])
|
||||
|
||||
const isDefaultOn = useFlag('devToolbarDefaultOn')
|
||||
|
||||
const sseRetryDelayRef = useRef(SSE_INITIAL_RETRY_MS)
|
||||
const sseRetryTimeoutRef = useRef<NodeJS.Timeout | null>(null)
|
||||
|
||||
@@ -66,11 +68,11 @@ export function DevToolbarProvider({ children, apiUrl }: DevToolbarProviderProps
|
||||
try {
|
||||
stored = localStorage.getItem(STORAGE_KEY)
|
||||
} catch {}
|
||||
if (stored === 'true') {
|
||||
if (stored === 'true' || isDefaultOn) {
|
||||
setIsEnabled(true)
|
||||
}
|
||||
|
||||
window.devTelemetry = () => {
|
||||
window.devToolbar = () => {
|
||||
try {
|
||||
localStorage.setItem(STORAGE_KEY, 'true')
|
||||
} catch {}
|
||||
@@ -78,9 +80,9 @@ export function DevToolbarProvider({ children, apiUrl }: DevToolbarProviderProps
|
||||
}
|
||||
|
||||
return () => {
|
||||
delete window.devTelemetry
|
||||
delete window.devToolbar
|
||||
}
|
||||
}, [])
|
||||
}, [isDefaultOn])
|
||||
|
||||
const appendEvent = useCallback((event: DevTelemetryEvent) => {
|
||||
setEvents((prev) => {
|
||||
|
||||
Reference in new issue
Block a user