mirror of
https://github.com/supabase/supabase.git
synced 2026-05-11 19:26:38 +08:00
## Summary Adds PostHog click/open tracking for every interactive element in the Studio top bar. Previously only 5 of ~16 surfaces were tracked. ### New events (16) | Event | Surface | |---|---| | `home_logo_clicked` | Supabase logo | | `header_back_to_dashboard_clicked` | Mobile back chevron | | `header_exceeding_usage_badge_clicked` | "Exceeding usage limits" badge | | `organization_dropdown_opened` | Org dropdown trigger | | `project_dropdown_opened` | Project dropdown trigger | | `branch_dropdown_opened` | Branch dropdown trigger | | `merge_request_button_clicked` | MR trigger (separate from existing success event) | | `connect_button_clicked` | Connect CTA | | `feedback_dropdown_opened` | Feedback dropdown trigger | | `advisor_button_clicked` | Advisor toggle | | `inline_editor_button_clicked` | SQL editor toggle | | `assistant_button_clicked` | AI Assistant toggle | | `user_dropdown_opened` | Account dropdown | | `local_dropdown_opened` | Local-dev settings dropdown | | `local_version_popover_opened` | CLI version popover | ### Notes - Uses `useTrack` (per `telemetry-standards`), all event names use approved `_clicked` / `_opened` verbs. - Dropdown `onOpenChange` handlers guard against Radix's double-fire by only tracking when `open === true`. - `merge_request_button_clicked` fires on the trigger click; the existing `branch_create_merge_request_button_clicked` continues to fire on successful MR creation. - Pre-existing tracked surfaces (`command_menu_opened`, `help_button_clicked`, `header_upgrade_cta_clicked`, `send_feedback_button_clicked`) are unchanged. ## Test plan - [x] Spot-check each event fires once per interaction in PostHog Live Events - [x] Verify no double-fire on dropdown close <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Chores** * Added telemetry tracking for many header/navigation interactions (logo, back-to-dashboard, usage badge, connect/merge/advisor/assistant/inline-editor buttons, and multiple dropdowns/popovers). * **Tests** * Updated tests to stub telemetry calls so UI tests remain stable and deterministic. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
100 lines
3.2 KiB
TypeScript
100 lines
3.2 KiB
TypeScript
import { FlaskConical, Settings } from 'lucide-react'
|
|
import { useTheme } from 'next-themes'
|
|
import Link from 'next/link'
|
|
import { useRouter } from 'next/router'
|
|
import {
|
|
cn,
|
|
DropdownMenu,
|
|
DropdownMenuContent,
|
|
DropdownMenuGroup,
|
|
DropdownMenuItem,
|
|
DropdownMenuLabel,
|
|
DropdownMenuRadioGroup,
|
|
DropdownMenuRadioItem,
|
|
DropdownMenuSeparator,
|
|
DropdownMenuTrigger,
|
|
singleThemes,
|
|
Theme,
|
|
} from 'ui'
|
|
|
|
import { ButtonTooltip } from '../ui/ButtonTooltip'
|
|
import { useFeaturePreviewModal } from './App/FeaturePreview/FeaturePreviewContext'
|
|
import { ProfileImage } from '@/components/ui/ProfileImage'
|
|
import { useTrack } from '@/lib/telemetry/track'
|
|
import { useAppStateSnapshot } from '@/state/app-state'
|
|
|
|
export const LocalDropdown = ({
|
|
triggerClassName,
|
|
contentClassName,
|
|
}: {
|
|
triggerClassName?: string
|
|
contentClassName?: string
|
|
}) => {
|
|
const router = useRouter()
|
|
const { theme, setTheme } = useTheme()
|
|
const appStateSnapshot = useAppStateSnapshot()
|
|
const { toggleFeaturePreviewModal } = useFeaturePreviewModal()
|
|
const track = useTrack()
|
|
|
|
return (
|
|
<DropdownMenu
|
|
onOpenChange={(open) => {
|
|
if (open) track('header_local_dropdown_opened')
|
|
}}
|
|
>
|
|
<DropdownMenuTrigger className={cn('border shrink-0 px-3', triggerClassName)} asChild>
|
|
<ButtonTooltip
|
|
type="default"
|
|
className="[&>span]:flex px-0 py-0 rounded-full overflow-hidden h-8 w-8"
|
|
tooltip={{ content: { text: 'Settings' } }}
|
|
>
|
|
<ProfileImage className="w-8 h-8 rounded-md" />
|
|
</ButtonTooltip>
|
|
</DropdownMenuTrigger>
|
|
<DropdownMenuContent side="bottom" align="end" className={cn('w-44', contentClassName)}>
|
|
<DropdownMenuItem className="flex gap-2 cursor-pointer" asChild>
|
|
<Link
|
|
href="/account/me"
|
|
onClick={() => {
|
|
if (router.pathname !== '/account/me') {
|
|
appStateSnapshot.setLastRouteBeforeVisitingAccountPage(router.asPath)
|
|
}
|
|
}}
|
|
>
|
|
<Settings size={14} strokeWidth={1.5} className="text-foreground-lighter" />
|
|
Preferences
|
|
</Link>
|
|
</DropdownMenuItem>
|
|
<DropdownMenuItem
|
|
className="flex gap-2 cursor-pointer"
|
|
onClick={() => toggleFeaturePreviewModal(true)}
|
|
onSelect={() => toggleFeaturePreviewModal(true)}
|
|
>
|
|
<FlaskConical size={14} strokeWidth={1.5} className="text-foreground-lighter" />
|
|
Feature previews
|
|
</DropdownMenuItem>
|
|
<DropdownMenuSeparator />
|
|
<DropdownMenuGroup>
|
|
<DropdownMenuLabel>Theme</DropdownMenuLabel>
|
|
<DropdownMenuRadioGroup
|
|
value={theme}
|
|
onValueChange={(value) => {
|
|
setTheme(value)
|
|
}}
|
|
>
|
|
{singleThemes.map((theme: Theme) => (
|
|
<DropdownMenuRadioItem
|
|
key={theme.value}
|
|
value={theme.value}
|
|
className="cursor-pointer"
|
|
>
|
|
{theme.name}
|
|
</DropdownMenuRadioItem>
|
|
))}
|
|
</DropdownMenuRadioGroup>
|
|
</DropdownMenuGroup>
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
)
|
|
}
|