chore: UI lib - update telemetry (#34569)

* chore: update telemetry

* Add NEXT_PUBLIC_API_URL to turbo.json.

* add copy event

* Update command-copy-button.tsx

* Update command-copy-button.tsx

* move telemetry wrapper down to child layout

* update telemetry naming

---------

Co-authored-by: Ivan Vasilov <vasilov.ivan@gmail.com>
Co-authored-by: Pamela Chia <pamelachiamayyee@gmail.com>
This commit is contained in:
authored and GitHub committed 2025-03-31 15:51:19 +02:00
1 parent fe3e067c0c
commit 6a9e1a5741
9 files changed
+107 -2

No files matched your search

+2 -1
View File
@@ -1,4 +1,5 @@
# Default to local supabase for local development
NEXT_PUBLIC_SUPABASE_URL=http://localhost:54321
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0
NEXT_PUBLIC_BASE_PATH=/ui
NEXT_PUBLIC_BASE_PATH=/ui
NEXT_PUBLIC_API_URL="http://localhost:8080/platform"
+2
View File
@@ -1,5 +1,6 @@
import { Sidebar } from '@/components/sidebar'
import { SiteFooter } from '@/components/site-footer'
import { TelemetryWrapper } from './telemetry-wrapper'
interface AppLayoutProps {
children: React.ReactNode
@@ -24,6 +25,7 @@ export default function AppLayout({ children }: AppLayoutProps) {
</main>
</div>
<SiteFooter />
<TelemetryWrapper />
</>
)
}
@@ -0,0 +1,16 @@
'use client'
import { API_URL } from '@/lib/constants'
import { IS_PLATFORM, PageTelemetry } from 'common'
import { useConsent } from 'ui-patterns/ConsentToast'
export const TelemetryWrapper = () => {
const { hasAcceptedConsent } = useConsent()
return (
<PageTelemetry
API_URL={API_URL}
hasAcceptedConsent={hasAcceptedConsent}
enabled={IS_PLATFORM}
/>
)
}
+2 -1
View File
@@ -1,13 +1,14 @@
'use client'
import { AuthProvider } from 'common'
import { Provider as JotaiProvider } from 'jotai'
import { ThemeProvider as NextThemesProvider } from 'next-themes'
import { ThemeProviderProps } from 'next-themes/dist/types'
import { FrameworkProvider } from '@/context/framework-context'
import { MobileMenuProvider } from '@/context/mobile-menu-context'
import { AuthProvider } from 'common'
import { TooltipProvider } from 'ui'
import { useConsent } from 'ui-patterns/ConsentToast'
export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
return (
@@ -2,10 +2,13 @@
import { Check, Copy } from 'lucide-react'
import { useEffect, useState } from 'react'
import { useSendTelemetryEvent } from 'lib/telemetry'
import { Button_Shadcn_ } from 'ui'
export function CommandCopyButton({ command }: { command: string }) {
const [copied, setCopied] = useState(false)
const sendTelemetryEvent = useSendTelemetryEvent()
useEffect(() => {
if (copied) {
@@ -14,13 +17,56 @@ export function CommandCopyButton({ command }: { command: string }) {
}
}, [copied])
const parseCommandForTelemetry = (cmd: string) => {
// Extract framework from URL (e.g., 'nextjs' from 'password-based-auth-nextjs.json')
const frameworkMatch = cmd.match(/\/ui\/r\/.*?-(\w+)\.json/)
const framework = frameworkMatch
? (frameworkMatch[1] as 'nextjs' | 'react-router' | 'tanstack' | 'react')
: 'nextjs'
// Extract package manager from command prefix (npx, pnpm, yarn, bun)
const packageManager = cmd.startsWith('npx')
? ('npm' as const)
: cmd.startsWith('pnpm')
? ('pnpm' as const)
: cmd.startsWith('yarn')
? ('yarn' as const)
: cmd.startsWith('bun')
? ('bun' as const)
: ('npm' as const)
// Extract template title from URL (e.g., 'password-based-auth' from 'password-based-auth-nextjs.json')
const titleMatch = cmd.match(/\/ui\/r\/(.*?)-\w+\.json/)
const title = titleMatch ? titleMatch[1] : ''
return {
framework,
packageManager,
title,
}
}
return (
<Button_Shadcn_
variant="ghost"
size="icon"
onClick={() => {
// Copy command to clipboard
navigator.clipboard.writeText(command)
setCopied(true)
// Parse command and send telemetry event
const { framework, packageManager, title } = parseCommandForTelemetry(command)
sendTelemetryEvent({
action: 'supabase_ui_command_copy_button_clicked',
properties: {
templateTitle: title,
command: command,
framework,
packageManager,
},
})
}}
>
{copied ? <Check className="h-4 w-4" /> : <Copy className="h-4 w-4" />}
+1
View File
@@ -0,0 +1 @@
export const API_URL = process.env.NEXT_PUBLIC_API_URL!
+19
View File
@@ -0,0 +1,19 @@
'use client'
import { usePathname } from 'next/navigation'
import { useCallback } from 'react'
import { sendTelemetryEvent } from 'common'
import { TelemetryEvent } from 'common/telemetry-constants'
import { API_URL } from 'lib/constants'
export function useSendTelemetryEvent() {
const pathname = usePathname()
return useCallback(
(event: TelemetryEvent) => {
return sendTelemetryEvent(API_URL, event, pathname)
},
[pathname]
)
}
+18
View File
@@ -1223,6 +1223,23 @@ export interface EdgeFunctionTestSidePanelOpenedEvent {
}
}
/**
* User copied the command for a Supabase UI component.
*
* @group Events
* @source supabase-ui
* @page /ui/docs/{framework}/{templateTitle}
*/
export interface SupabaseUiCommandCopyButtonClickedEvent {
action: 'supabase_ui_command_copy_button_clicked'
properties: {
templateTitle: string
command: string
framework: 'nextjs' | 'react-router' | 'tanstack' | 'react'
packageManager: 'npm' | 'pnpm' | 'yarn' | 'bun'
}
}
/**
* @hidden
*/
@@ -1297,3 +1314,4 @@ export type TelemetryEvent =
| EdgeFunctionDeployUpdatesButtonClickedEvent
| EdgeFunctionTestSendButtonClickedEvent
| EdgeFunctionTestSidePanelOpenedEvent
| SupabaseUiCommandCopyButtonClickedEvent
+1
View File
@@ -130,6 +130,7 @@
"NEXT_PUBLIC_APP_URL",
"NEXT_PUBLIC_VERCEL_TARGET_ENV",
"NEXT_PUBLIC_VERCEL_BRANCH_URL",
"NEXT_PUBLIC_API_URL",
"NODE_ENV",
"HIDE_TAILWIND_INDICATOR",
// These envs are used in the packages