mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 17:35:10 +03:00
feat: track new functions behaviour (#34239)
This commit is contained in:
1 parent
944adfa8f6
commit
db1f2b4c4e
5 files changed
+203
-8
No files matched your search
@@ -2,6 +2,8 @@ import { useParams } from 'common'
|
||||
import { ScaffoldSectionTitle } from 'components/layouts/Scaffold'
|
||||
import { ResourceItem } from 'components/ui/Resource/ResourceItem'
|
||||
import { ResourceList } from 'components/ui/Resource/ResourceList'
|
||||
import { useSendEventMutation } from 'data/telemetry/send-event-mutation'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useFlag } from 'hooks/ui/useFlag'
|
||||
import { Code, Terminal } from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
@@ -28,6 +30,9 @@ export const FunctionsEmptyState = () => {
|
||||
const { setAiAssistantPanel } = useAppStateSnapshot()
|
||||
const edgeFunctionCreate = useFlag('edgeFunctionCreate')
|
||||
|
||||
const { mutate: sendEvent } = useSendEventMutation()
|
||||
const org = useSelectedOrganization()
|
||||
|
||||
return (
|
||||
<>
|
||||
<Card>
|
||||
@@ -48,7 +53,17 @@ export const FunctionsEmptyState = () => {
|
||||
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button type="default">View CLI Instructions</Button>
|
||||
<Button
|
||||
type="default"
|
||||
onClick={() =>
|
||||
sendEvent({
|
||||
action: 'edge_function_via_cli_button_clicked',
|
||||
groups: { project: ref ?? 'Unknown', organization: org?.slug ?? 'Unknown' },
|
||||
})
|
||||
}
|
||||
>
|
||||
View CLI Instructions
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent size="large">
|
||||
<DialogSection padding="small">
|
||||
@@ -69,7 +84,7 @@ export const FunctionsEmptyState = () => {
|
||||
</p>
|
||||
<Button
|
||||
type="default"
|
||||
onClick={() =>
|
||||
onClick={() => {
|
||||
setAiAssistantPanel({
|
||||
open: true,
|
||||
initialInput: 'Create a new edge function that ...',
|
||||
@@ -83,7 +98,12 @@ export const FunctionsEmptyState = () => {
|
||||
],
|
||||
},
|
||||
})
|
||||
}
|
||||
sendEvent({
|
||||
action: 'edge_function_ai_assistant_button_clicked',
|
||||
properties: { origin: 'no_functions_block' },
|
||||
groups: { project: ref ?? 'Unknown', organization: org?.slug ?? 'Unknown' },
|
||||
})
|
||||
}}
|
||||
>
|
||||
Open Assistant
|
||||
</Button>
|
||||
@@ -99,7 +119,17 @@ export const FunctionsEmptyState = () => {
|
||||
<p className="text-sm text-foreground-light mb-4 mt-1">
|
||||
Create and edit functions directly in the browser. Download to local at any time.
|
||||
</p>
|
||||
<Button type="default" onClick={() => router.push(`/project/${ref}/functions/new`)}>
|
||||
<Button
|
||||
type="default"
|
||||
onClick={() => {
|
||||
router.push(`/project/${ref}/functions/new`)
|
||||
sendEvent({
|
||||
action: 'edge_function_via_editor_button_clicked',
|
||||
properties: { origin: 'no_functions_block' },
|
||||
groups: { project: ref ?? 'Unknown', organization: org?.slug ?? 'Unknown' },
|
||||
})
|
||||
}}
|
||||
>
|
||||
Open Editor
|
||||
</Button>
|
||||
</div>
|
||||
@@ -116,7 +146,13 @@ export const FunctionsEmptyState = () => {
|
||||
<ResourceItem
|
||||
key={template.name}
|
||||
media={<Code strokeWidth={1.5} size={16} className="-translate-y-[9px]" />}
|
||||
onClick={() => {}}
|
||||
onClick={() => {
|
||||
sendEvent({
|
||||
action: 'edge_function_template_clicked',
|
||||
properties: { templateName: template.name, origin: 'functions_page' },
|
||||
groups: { project: ref ?? 'Unknown', organization: org?.slug ?? 'Unknown' },
|
||||
})
|
||||
}}
|
||||
>
|
||||
<Link href={`/project/${ref}/functions/new?template=${template.value}`}>
|
||||
<p>{template.name}</p>
|
||||
|
||||
@@ -2,12 +2,14 @@ import { DragEvent, ReactNode, useState } from 'react'
|
||||
import { toast } from 'sonner'
|
||||
import { useParams } from 'common'
|
||||
import { useEdgeFunctionDeployMutation } from 'data/edge-functions/edge-functions-deploy-mutation'
|
||||
import { useSendEventMutation } from 'data/telemetry/send-event-mutation'
|
||||
import { ReportBlockContainer } from 'components/interfaces/Reports/ReportBlock/ReportBlockContainer'
|
||||
import { Button, CodeBlock, cn, CodeBlockLang } from 'ui'
|
||||
import { Code } from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
import { useProjectSettingsV2Query } from 'data/config/project-settings-v2-query'
|
||||
import { useEdgeFunctionQuery } from 'data/edge-functions/edge-function-query'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { Admonition } from 'ui-patterns'
|
||||
|
||||
interface EdgeFunctionBlockProps {
|
||||
@@ -43,6 +45,9 @@ export const EdgeFunctionBlock = ({
|
||||
const { data: settings } = useProjectSettingsV2Query({ projectRef: ref })
|
||||
const { data: existingFunction } = useEdgeFunctionQuery({ projectRef: ref, slug: functionName })
|
||||
|
||||
const { mutate: sendEvent } = useSendEventMutation()
|
||||
const org = useSelectedOrganization()
|
||||
|
||||
const { mutateAsync: deployFunction, isLoading: isDeploying } = useEdgeFunctionDeployMutation({
|
||||
onSuccess: () => {
|
||||
setIsDeployed(true)
|
||||
@@ -67,6 +72,11 @@ export const EdgeFunctionBlock = ({
|
||||
},
|
||||
files: [{ name: 'index.ts', content: code }],
|
||||
})
|
||||
sendEvent({
|
||||
action: 'edge_function_deploy_button_clicked',
|
||||
properties: { origin: 'functions_ai_assistant' },
|
||||
groups: { project: ref ?? 'Unknown', organization: org?.slug ?? 'Unknown' },
|
||||
})
|
||||
} catch (error) {
|
||||
toast.error(
|
||||
`Failed to deploy function: ${error instanceof Error ? error.message : 'Unknown error'}`
|
||||
|
||||
@@ -15,6 +15,8 @@ import { ButtonTooltip } from 'components/ui/ButtonTooltip'
|
||||
import { DocsButton } from 'components/ui/DocsButton'
|
||||
import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader'
|
||||
import { useEdgeFunctionsQuery } from 'data/edge-functions/edge-functions-query'
|
||||
import { useSendEventMutation } from 'data/telemetry/send-event-mutation'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useFlag } from 'hooks/ui/useFlag'
|
||||
import { useAppStateSnapshot } from 'state/app-state'
|
||||
import type { NextPageWithLayout } from 'types'
|
||||
@@ -43,6 +45,8 @@ const EdgeFunctionsPage: NextPageWithLayout = () => {
|
||||
isSuccess,
|
||||
} = useEdgeFunctionsQuery({ projectRef: ref })
|
||||
const edgeFunctionCreate = useFlag('edgeFunctionCreate')
|
||||
const { mutate: sendEvent } = useSendEventMutation()
|
||||
const org = useSelectedOrganization()
|
||||
|
||||
const hasFunctions = (functions ?? []).length > 0
|
||||
|
||||
@@ -74,7 +78,14 @@ const EdgeFunctionsPage: NextPageWithLayout = () => {
|
||||
</Dialog>
|
||||
{edgeFunctionCreate && (
|
||||
<DropdownMenuItem
|
||||
onSelect={() => router.push(`/project/${ref}/functions/new`)}
|
||||
onSelect={() => {
|
||||
router.push(`/project/${ref}/functions/new`)
|
||||
sendEvent({
|
||||
action: 'edge_function_via_editor_button_clicked',
|
||||
properties: { origin: 'secondary_action' },
|
||||
groups: { project: ref ?? 'Unknown', organization: org?.slug ?? 'Unknown' },
|
||||
})
|
||||
}}
|
||||
className="gap-4"
|
||||
>
|
||||
<Code className="shrink-0" size={16} strokeWidth={1.5} />
|
||||
@@ -106,7 +117,7 @@ const EdgeFunctionsPage: NextPageWithLayout = () => {
|
||||
type="default"
|
||||
className="px-1 pointer-events-auto"
|
||||
icon={<AiIconAnimation size={16} />}
|
||||
onClick={() =>
|
||||
onClick={() => {
|
||||
setAiAssistantPanel({
|
||||
open: true,
|
||||
initialInput: `Create a new edge function that ...`,
|
||||
@@ -120,7 +131,12 @@ const EdgeFunctionsPage: NextPageWithLayout = () => {
|
||||
],
|
||||
},
|
||||
})
|
||||
}
|
||||
sendEvent({
|
||||
action: 'edge_function_ai_assistant_button_clicked',
|
||||
properties: { origin: 'secondary_action' },
|
||||
groups: { project: ref ?? 'Unknown', organization: org?.slug ?? 'Unknown' },
|
||||
})
|
||||
}}
|
||||
tooltip={{
|
||||
content: {
|
||||
side: 'bottom',
|
||||
|
||||
@@ -13,7 +13,9 @@ import EdgeFunctionsLayout from 'components/layouts/EdgeFunctionsLayout/EdgeFunc
|
||||
import { PageLayout } from 'components/layouts/PageLayout/PageLayout'
|
||||
import FileExplorerAndEditor from 'components/ui/FileExplorerAndEditor/FileExplorerAndEditor'
|
||||
import { useEdgeFunctionDeployMutation } from 'data/edge-functions/edge-functions-deploy-mutation'
|
||||
import { useSendEventMutation } from 'data/telemetry/send-event-mutation'
|
||||
import { useOrgOptedIntoAi } from 'hooks/misc/useOrgOptedIntoAi'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useSelectedProject } from 'hooks/misc/useSelectedProject'
|
||||
import { useFlag } from 'hooks/ui/useFlag'
|
||||
import { BASE_PATH, IS_PLATFORM } from 'lib/constants'
|
||||
@@ -103,6 +105,8 @@ const NewFunctionPage = () => {
|
||||
const includeSchemaMetadata = isOptedInToAI || !IS_PLATFORM
|
||||
const { setAiAssistantPanel } = useAppStateSnapshot()
|
||||
const edgeFunctionCreate = useFlag('edgeFunctionCreate')
|
||||
const { mutate: sendEvent } = useSendEventMutation()
|
||||
const org = useSelectedOrganization()
|
||||
|
||||
const [files, setFiles] = useState<
|
||||
{ id: number; name: string; content: string; selected?: boolean }[]
|
||||
@@ -148,6 +152,11 @@ const NewFunctionPage = () => {
|
||||
},
|
||||
files: files.map(({ name, content }) => ({ name, content })),
|
||||
})
|
||||
sendEvent({
|
||||
action: 'edge_function_deploy_button_clicked',
|
||||
properties: { origin: 'functions_editor' },
|
||||
groups: { project: ref ?? 'Unknown', organization: org?.slug ?? 'Unknown' },
|
||||
})
|
||||
}
|
||||
|
||||
const handleChat = () => {
|
||||
@@ -167,6 +176,11 @@ const NewFunctionPage = () => {
|
||||
],
|
||||
},
|
||||
})
|
||||
sendEvent({
|
||||
action: 'edge_function_ai_assistant_button_clicked',
|
||||
properties: { origin: 'functions_editor_chat' },
|
||||
groups: { project: ref ?? 'Unknown', organization: org?.slug ?? 'Unknown' },
|
||||
})
|
||||
}
|
||||
|
||||
const onSelectTemplate = (templateValue: string) => {
|
||||
@@ -176,6 +190,11 @@ const NewFunctionPage = () => {
|
||||
prev.map((file) => (file.selected ? { ...file, content: template.content } : file))
|
||||
)
|
||||
setOpen(false)
|
||||
sendEvent({
|
||||
action: 'edge_function_template_clicked',
|
||||
properties: { templateName: template.name, origin: 'editor_page' },
|
||||
groups: { project: ref ?? 'Unknown', organization: org?.slug ?? 'Unknown' },
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1048,6 +1048,115 @@ export interface ReportsDatabaseGrafanaBannerClickedEvent {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* User clicked the deploy button for an Edge Function.
|
||||
*
|
||||
* @group Events
|
||||
* @source studio
|
||||
* @page /dashboard/project/{ref}/functions/new
|
||||
*/
|
||||
export interface EdgeFunctionDeployButtonClickedEvent {
|
||||
action: 'edge_function_deploy_button_clicked'
|
||||
properties: {
|
||||
/**
|
||||
* Click on Deploy can either happen:
|
||||
* 1. in the functions editor page
|
||||
* 2. in the chat button in the functions editor
|
||||
*/
|
||||
origin: 'functions_editor' | 'functions_ai_assistant'
|
||||
}
|
||||
groups: {
|
||||
project: string
|
||||
organization: string
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* User clicked the AI Assistant button to create an Edge Function.
|
||||
*
|
||||
* @group Events
|
||||
* @source studio
|
||||
* @page /dashboard/project/{ref}/functions
|
||||
*/
|
||||
export interface EdgeFunctionAiAssistantButtonClickedEvent {
|
||||
action: 'edge_function_ai_assistant_button_clicked'
|
||||
properties: {
|
||||
/**
|
||||
* Click on AI Assistant can either happen:
|
||||
* 1. on the main block when there are no functions
|
||||
* 2. in the secondary action section of the page
|
||||
* 3. on the chat button in the functions editor
|
||||
*/
|
||||
origin: 'no_functions_block' | 'secondary_action' | 'functions_editor_chat'
|
||||
}
|
||||
groups: {
|
||||
project: string
|
||||
organization: string
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* User clicked the button to go to the functions editor page to create an edge function.
|
||||
*
|
||||
* @group Events
|
||||
* @source studio
|
||||
* @page /dashboard/project/{ref}/functions
|
||||
*/
|
||||
export interface EdgeFunctionViaEditorButtonClickedEvent {
|
||||
action: 'edge_function_via_editor_button_clicked'
|
||||
properties: {
|
||||
/**
|
||||
* Click on Via Editor can either happen:
|
||||
* 1. on the main block when there are no functions
|
||||
* 2. in the secondary action section of the page
|
||||
*/
|
||||
origin: 'no_functions_block' | 'secondary_action'
|
||||
}
|
||||
groups: {
|
||||
project: string
|
||||
organization: string
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* User clicked on an Edge Function template.
|
||||
*
|
||||
* @group Events
|
||||
* @source studio
|
||||
* @page /dashboard/project/{ref}/functions
|
||||
*/
|
||||
export interface EdgeFunctionTemplateClickedEvent {
|
||||
action: 'edge_function_template_clicked'
|
||||
properties: {
|
||||
templateName: string
|
||||
/**
|
||||
* Where the edge function template was clicked from:
|
||||
* 1. functions page
|
||||
* 2. editor page
|
||||
*/
|
||||
origin: 'functions_page' | 'editor_page'
|
||||
}
|
||||
groups: {
|
||||
project: string
|
||||
organization: string
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* User clicked the button to create an edge function via CLI.
|
||||
*
|
||||
* @group Events
|
||||
* @source studio
|
||||
* @page /dashboard/project/{ref}/functions
|
||||
*/
|
||||
export interface EdgeFunctionViaCliButtonClickedEvent {
|
||||
action: 'edge_function_via_cli_button_clicked'
|
||||
groups: {
|
||||
project: string
|
||||
organization: string
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
@@ -1113,3 +1222,8 @@ export type TelemetryEvent =
|
||||
| StudioPricingPlanCtaClickedEvent
|
||||
| StudioPricingSidePanelOpenedEvent
|
||||
| ReportsDatabaseGrafanaBannerClickedEvent
|
||||
| EdgeFunctionDeployButtonClickedEvent
|
||||
| EdgeFunctionAiAssistantButtonClickedEvent
|
||||
| EdgeFunctionViaEditorButtonClickedEvent
|
||||
| EdgeFunctionTemplateClickedEvent
|
||||
| EdgeFunctionViaCliButtonClickedEvent
|
||||
Reference in new issue
Block a user