diff --git a/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewModal.tsx b/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewModal.tsx index c9c56da1053..8268f751053 100644 --- a/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewModal.tsx +++ b/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewModal.tsx @@ -8,11 +8,15 @@ import { TelemetryActions } from 'lib/constants/telemetry' import { useAppStateSnapshot } from 'state/app-state' import { Badge, Button, Modal, ScrollArea, cn } from 'ui' import { FEATURE_PREVIEWS, useFeaturePreviewContext } from './FeaturePreviewContext' +import { useParams } from 'common' +import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization' const FeaturePreviewModal = () => { const snap = useAppStateSnapshot() const featurePreviewContext = useFeaturePreviewContext() const { mutate: sendEvent } = useSendEventMutation() + const { ref: projectRef } = useParams() + const org = useSelectedOrganization() const enableFunctionsAssistant = useFlag('functionsAssistantV2') const selectedFeaturePreview = @@ -33,6 +37,7 @@ const FeaturePreviewModal = () => { ? TelemetryActions.FEATURE_PREVIEW_DISABLED : TelemetryActions.FEATURE_PREVIEW_ENABLED, properties: { feature: selectedFeatureKey }, + groups: { project: projectRef ?? 'Unknown', organization: org?.slug ?? 'Unknown' }, }) } @@ -51,7 +56,10 @@ const FeaturePreviewModal = () => { useEffect(() => { if (snap.showFeaturePreviewModal) { - sendEvent({ action: TelemetryActions.FEATURE_PREVIEWS_CLICKED }) + sendEvent({ + action: TelemetryActions.FEATURE_PREVIEWS_CLICKED, + groups: { project: projectRef ?? 'Unknown', organization: org?.slug ?? 'Unknown' }, + }) } }, [snap.showFeaturePreviewModal]) diff --git a/apps/studio/components/interfaces/Connect/DatabaseConnectionString.tsx b/apps/studio/components/interfaces/Connect/DatabaseConnectionString.tsx index c00d3c9d295..e48d17bfb4a 100644 --- a/apps/studio/components/interfaces/Connect/DatabaseConnectionString.tsx +++ b/apps/studio/components/interfaces/Connect/DatabaseConnectionString.tsx @@ -36,6 +36,7 @@ import { import { CodeBlockFileHeader, ConnectionPanel } from './ConnectionPanel' import { getConnectionStrings } from './DatabaseSettings.utils' import examples, { Example } from './DirectConnectionExamples' +import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization' const StepLabel = ({ number, @@ -52,6 +53,7 @@ const StepLabel = ({ export const DatabaseConnectionString = () => { const { ref: projectRef } = useParams() + const org = useSelectedOrganization() const state = useDatabaseSelectorStateSnapshot() const [selectedTab, setSelectedTab] = useState('uri') @@ -103,6 +105,7 @@ export const DatabaseConnectionString = () => { sendEvent({ action: TelemetryActions.CONNECTION_STRING_COPIED, properties: { connectionType, lang, connectionMethod }, + groups: { project: projectRef ?? 'Unknown', organization: org?.slug ?? 'Unknown' }, }) } diff --git a/apps/studio/components/interfaces/Integrations/CronJobs/CreateCronJobSheet.tsx b/apps/studio/components/interfaces/Integrations/CronJobs/CreateCronJobSheet.tsx index 582388d2284..a2e08a3938c 100644 --- a/apps/studio/components/interfaces/Integrations/CronJobs/CreateCronJobSheet.tsx +++ b/apps/studio/components/interfaces/Integrations/CronJobs/CreateCronJobSheet.tsx @@ -50,6 +50,7 @@ import { HTTPHeaderFieldsSection } from './HttpHeaderFieldsSection' import { HttpRequestSection } from './HttpRequestSection' import { SqlFunctionSection } from './SqlFunctionSection' import { SqlSnippetSection } from './SqlSnippetSection' +import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization' export interface CreateCronJobSheetProps { selectedCronJob?: Pick @@ -199,6 +200,7 @@ export const CreateCronJobSheet = ({ onClose, }: CreateCronJobSheetProps) => { const { project } = useProjectContext() + const org = useSelectedOrganization() const isEditing = !!selectedCronJob?.jobname const [showEnableExtensionModal, setShowEnableExtensionModal] = useState(false) @@ -336,6 +338,10 @@ export const CreateCronJobSheet = ({ type: values.type, schedule: schedule, }, + groups: { + project: project?.ref ?? 'Unknown', + organization: org?.slug ?? 'Unknown', + }, }) } else { sendEvent({ @@ -344,6 +350,10 @@ export const CreateCronJobSheet = ({ type: values.type, schedule: schedule, }, + groups: { + project: project?.ref ?? 'Unknown', + organization: org?.slug ?? 'Unknown', + }, }) } diff --git a/apps/studio/components/interfaces/Integrations/CronJobs/CronJobCard.tsx b/apps/studio/components/interfaces/Integrations/CronJobs/CronJobCard.tsx index 8cb42e571e6..24bab76d1f6 100644 --- a/apps/studio/components/interfaces/Integrations/CronJobs/CronJobCard.tsx +++ b/apps/studio/components/interfaces/Integrations/CronJobs/CronJobCard.tsx @@ -27,6 +27,7 @@ import { TimestampInfo } from 'ui-patterns' import { Input } from 'ui-patterns/DataInputs/Input' import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal' import { convertCronToString, getNextRun } from './CronJobs.utils' +import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization' interface CronJobCardProps { job: CronJob @@ -36,6 +37,7 @@ interface CronJobCardProps { export const CronJobCard = ({ job, onEditCronJob, onDeleteCronJob }: CronJobCardProps) => { const { ref } = useParams() + const org = useSelectedOrganization() const { project: selectedProject } = useProjectContext() const [toggleConfirmationModalShown, showToggleConfirmationModal] = useState(false) @@ -93,6 +95,10 @@ export const CronJobCard = ({ job, onEditCronJob, onDeleteCronJob }: CronJobCard onClick={() => { sendEvent({ action: TelemetryActions.CRON_JOB_HISTORY_CLICKED, + groups: { + project: selectedProject?.ref ?? 'Unknown', + organization: org?.slug ?? 'Unknown', + }, }) }} > @@ -107,6 +113,10 @@ export const CronJobCard = ({ job, onEditCronJob, onDeleteCronJob }: CronJobCard onClick={() => { sendEvent({ action: TelemetryActions.CRON_JOB_UPDATE_CLICKED, + groups: { + project: selectedProject?.ref ?? 'Unknown', + organization: org?.slug ?? 'Unknown', + }, }) onEditCronJob(job) }} @@ -118,6 +128,10 @@ export const CronJobCard = ({ job, onEditCronJob, onDeleteCronJob }: CronJobCard onClick={() => { sendEvent({ action: TelemetryActions.CRON_JOB_DELETE_CLICKED, + groups: { + project: selectedProject?.ref ?? 'Unknown', + organization: org?.slug ?? 'Unknown', + }, }) onDeleteCronJob(job) }} diff --git a/apps/studio/components/interfaces/Integrations/CronJobs/CronJobsTab.tsx b/apps/studio/components/interfaces/Integrations/CronJobs/CronJobsTab.tsx index 08bb78482d0..c323faf9dd6 100644 --- a/apps/studio/components/interfaces/Integrations/CronJobs/CronJobsTab.tsx +++ b/apps/studio/components/interfaces/Integrations/CronJobs/CronJobsTab.tsx @@ -12,6 +12,7 @@ import { TelemetryActions } from 'lib/constants/telemetry' import { Button, Input, Sheet, SheetContent } from 'ui' import { CronJobCard } from './CronJobCard' import { DeleteCronJob } from './DeleteCronJob' +import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization' const EMPTY_CRON_JOB = { jobname: '', @@ -22,6 +23,7 @@ const EMPTY_CRON_JOB = { export const CronjobsTab = () => { const { project } = useProjectContext() + const org = useSelectedOrganization() const [searchQuery, setSearchQuery] = useQueryState('search', parseAsString.withDefault('')) const [createCronJobSheetShown, setCreateCronJobSheetShown] = useQueryState( @@ -66,7 +68,10 @@ export const CronjobsTab = () => { : cronJobs ?? [] const onOpenCreateJobSheet = () => { - sendEvent({ action: TelemetryActions.CRON_JOB_CREATE_CLICKED }) + sendEvent({ + action: TelemetryActions.CRON_JOB_CREATE_CLICKED, + groups: { project: project?.ref ?? 'Unknown', organization: org?.slug ?? 'Unknown' }, + }) setCreateCronJobSheetShown(true) } diff --git a/apps/studio/components/interfaces/Integrations/CronJobs/DeleteCronJob.tsx b/apps/studio/components/interfaces/Integrations/CronJobs/DeleteCronJob.tsx index 41e333b7dae..b8c6e020baa 100644 --- a/apps/studio/components/interfaces/Integrations/CronJobs/DeleteCronJob.tsx +++ b/apps/studio/components/interfaces/Integrations/CronJobs/DeleteCronJob.tsx @@ -6,6 +6,7 @@ import { CronJob } from 'data/database-cron-jobs/database-cron-jobs-query' import { useSendEventMutation } from 'data/telemetry/send-event-mutation' import { TelemetryActions } from 'lib/constants/telemetry' import TextConfirmModal from 'ui-patterns/Dialogs/TextConfirmModal' +import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization' interface DeleteCronJobProps { cronJob: CronJob @@ -15,11 +16,15 @@ interface DeleteCronJobProps { export const DeleteCronJob = ({ cronJob, visible, onClose }: DeleteCronJobProps) => { const { project } = useProjectContext() + const org = useSelectedOrganization() const { mutate: sendEvent } = useSendEventMutation() const { mutate: deleteDatabaseCronJob, isLoading } = useDatabaseCronJobDeleteMutation({ onSuccess: () => { - sendEvent({ action: TelemetryActions.CRON_JOB_DELETED }) + sendEvent({ + action: TelemetryActions.CRON_JOB_DELETED, + groups: { project: project?.ref ?? 'Unknown', organization: org?.slug ?? 'Unknown' }, + }) toast.success(`Successfully removed cron job ${cronJob.jobname}`) onClose() }, diff --git a/apps/studio/components/interfaces/Realtime/Inspector/ChooseChannelPopover/index.tsx b/apps/studio/components/interfaces/Realtime/Inspector/ChooseChannelPopover/index.tsx index fd6b45f9ca6..0fb027cdeac 100644 --- a/apps/studio/components/interfaces/Realtime/Inspector/ChooseChannelPopover/index.tsx +++ b/apps/studio/components/interfaces/Realtime/Inspector/ChooseChannelPopover/index.tsx @@ -3,6 +3,7 @@ import { ChevronDown, ExternalLink } from 'lucide-react' import { Dispatch, SetStateAction, useState } from 'react' import { useForm } from 'react-hook-form' import * as z from 'zod' +import { useParams } from 'common' import { useSendEventMutation } from 'data/telemetry/send-event-mutation' import { @@ -22,6 +23,7 @@ import { import { RealtimeConfig } from '../useRealtimeMessages' import { DocsButton } from 'components/ui/DocsButton' import { TelemetryActions } from 'lib/constants/telemetry' +import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization' interface ChooseChannelPopoverProps { config: RealtimeConfig @@ -32,7 +34,8 @@ const FormSchema = z.object({ channel: z.string(), isPrivate: z.boolean() }) export const ChooseChannelPopover = ({ config, onChangeConfig }: ChooseChannelPopoverProps) => { const [open, setOpen] = useState(false) - + const { ref } = useParams() + const org = useSelectedOrganization() const { mutate: sendEvent } = useSendEventMutation() const form = useForm>({ @@ -52,7 +55,13 @@ export const ChooseChannelPopover = ({ config, onChangeConfig }: ChooseChannelPo const onSubmit = () => { setOpen(false) - sendEvent({ action: TelemetryActions.REALTIME_INSPECTOR_LISTEN_CHANNEL_CLICKED }) + sendEvent({ + action: TelemetryActions.REALTIME_INSPECTOR_LISTEN_CHANNEL_CLICKED, + groups: { + project: ref ?? 'Unknown', + organization: org?.slug ?? 'Unknown', + }, + }) onChangeConfig({ ...config, channelName: form.getValues('channel'), diff --git a/apps/studio/components/interfaces/Realtime/Inspector/Header.tsx b/apps/studio/components/interfaces/Realtime/Inspector/Header.tsx index a2b9d8b9031..1d4a8dec622 100644 --- a/apps/studio/components/interfaces/Realtime/Inspector/Header.tsx +++ b/apps/studio/components/interfaces/Realtime/Inspector/Header.tsx @@ -4,6 +4,8 @@ import { Dispatch, SetStateAction } from 'react' import { ButtonTooltip } from 'components/ui/ButtonTooltip' import { useSendEventMutation } from 'data/telemetry/send-event-mutation' import { TelemetryActions } from 'lib/constants/telemetry' +import { useParams } from 'common' +import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization' import { ChooseChannelPopover } from './ChooseChannelPopover' import { RealtimeFilterPopover } from './RealtimeFilterPopover' import { RealtimeTokensPopover } from './RealtimeTokensPopover' @@ -16,6 +18,8 @@ interface HeaderProps { export const Header = ({ config, onChangeConfig }: HeaderProps) => { const { mutate: sendEvent } = useSendEventMutation() + const { ref } = useParams() + const org = useSelectedOrganization() return (
@@ -32,7 +36,13 @@ export const Header = ({ config, onChangeConfig }: HeaderProps) => { onChangeConfig({ ...config, enabled: !config.enabled }) if (!config.enabled) { // the user has clicked to start listening - sendEvent({ action: TelemetryActions.REALTIME_INSPECTOR_LISTEN_CHANNEL_CLICKED }) + sendEvent({ + action: TelemetryActions.REALTIME_INSPECTOR_LISTEN_CHANNEL_CLICKED, + groups: { + project: ref ?? 'Unknown', + organization: org?.slug ?? 'Unknown', + }, + }) } }} tooltip={{ diff --git a/apps/studio/components/interfaces/Realtime/Inspector/MessageSelection.tsx b/apps/studio/components/interfaces/Realtime/Inspector/MessageSelection.tsx index 12b94305a53..7fd0fc4fd22 100644 --- a/apps/studio/components/interfaces/Realtime/Inspector/MessageSelection.tsx +++ b/apps/studio/components/interfaces/Realtime/Inspector/MessageSelection.tsx @@ -7,6 +7,8 @@ import { Button, cn } from 'ui' import type { LogData } from './Messages.types' import { SelectedRealtimeMessagePanel } from './SelectedRealtimeMessagePanel' import { TelemetryActions } from 'lib/constants/telemetry' +import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization' +import { useParams } from 'common' export interface MessageSelectionProps { log: LogData | null @@ -18,6 +20,8 @@ const MessageSelection = ({ log, onClose }: MessageSelectionProps) => { return JSON.stringify(log, null, 2) }, [log]) + const { ref } = useParams() + const org = useSelectedOrganization() const { mutate: sendEvent } = useSendEventMutation() return ( @@ -74,7 +78,10 @@ const MessageSelection = ({ log, onClose }: MessageSelectionProps) => { type="default" title="Copy log to clipboard" onClick={() => { - sendEvent({ action: TelemetryActions.REALTIME_INSPECTOR_COPY_MESSAGE_CLICKED }) + sendEvent({ + action: TelemetryActions.REALTIME_INSPECTOR_COPY_MESSAGE_CLICKED, + groups: { project: ref ?? 'Unknown', organization: org?.slug ?? 'Unknown' }, + }) }} />
diff --git a/apps/studio/components/interfaces/Realtime/Inspector/MessagesTable.tsx b/apps/studio/components/interfaces/Realtime/Inspector/MessagesTable.tsx index bf2d3378d90..fbbfd14b83f 100644 --- a/apps/studio/components/interfaces/Realtime/Inspector/MessagesTable.tsx +++ b/apps/studio/components/interfaces/Realtime/Inspector/MessagesTable.tsx @@ -14,6 +14,7 @@ import NoChannelEmptyState from './NoChannelEmptyState' import { ColumnRenderer } from './RealtimeMessageColumnRenderer' import { DocsButton } from 'components/ui/DocsButton' import { TelemetryActions } from 'lib/constants/telemetry' +import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization' export const isErrorLog = (l: LogData) => { return l.message === 'SYSTEM' && l.metadata?.status === 'error' @@ -110,6 +111,8 @@ const MessagesTable = ({ const [focusedLog, setFocusedLog] = useState(null) const stringData = JSON.stringify(data) + const { ref } = useParams() + const org = useSelectedOrganization() const { mutate: sendEvent } = useSendEventMutation() useEffect(() => { @@ -178,7 +181,13 @@ const MessagesTable = ({ isRowSelected={false} selectedCellIdx={undefined} onClick={() => { - sendEvent({ action: TelemetryActions.REALTIME_INSPECTOR_MESSAGE_CLICKED }) + sendEvent({ + action: TelemetryActions.REALTIME_INSPECTOR_MESSAGE_CLICKED, + groups: { + project: ref ?? 'Unknown', + organization: org?.slug ?? 'Unknown', + }, + }) setFocusedLog(row) }} /> diff --git a/apps/studio/components/interfaces/Realtime/Inspector/RealtimeFilterPopover/index.tsx b/apps/studio/components/interfaces/Realtime/Inspector/RealtimeFilterPopover/index.tsx index d78a39de764..a10173ec5f8 100644 --- a/apps/studio/components/interfaces/Realtime/Inspector/RealtimeFilterPopover/index.tsx +++ b/apps/studio/components/interfaces/Realtime/Inspector/RealtimeFilterPopover/index.tsx @@ -21,6 +21,8 @@ import { RealtimeConfig } from '../useRealtimeMessages' import { FilterSchema } from './FilterSchema' import { FilterTable } from './FilterTable' import { TelemetryActions } from 'lib/constants/telemetry' +import { useParams } from 'common' +import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization' interface RealtimeFilterPopoverProps { config: RealtimeConfig @@ -32,6 +34,8 @@ export const RealtimeFilterPopover = ({ config, onChangeConfig }: RealtimeFilter const [applyConfigOpen, setApplyConfigOpen] = useState(false) const [tempConfig, setTempConfig] = useState(config) + const { ref } = useParams() + const org = useSelectedOrganization() const { mutate: sendEvent } = useSendEventMutation() const onOpen = (v: boolean) => { @@ -201,7 +205,10 @@ export const RealtimeFilterPopover = ({ config, onChangeConfig }: RealtimeFilter visible={applyConfigOpen} onCancel={() => setApplyConfigOpen(false)} onConfirm={() => { - sendEvent({ action: TelemetryActions.REALTIME_INSPECTOR_FILTERS_APPLIED }) + sendEvent({ + action: TelemetryActions.REALTIME_INSPECTOR_FILTERS_APPLIED, + groups: { project: ref ?? 'Unknown', organization: org?.slug ?? 'Unknown' }, + }) onChangeConfig(tempConfig) setApplyConfigOpen(false) setOpen(false) diff --git a/apps/studio/components/interfaces/Realtime/Inspector/RealtimeTokensPopover/index.tsx b/apps/studio/components/interfaces/Realtime/Inspector/RealtimeTokensPopover/index.tsx index 637a00827ef..ed740ec281d 100644 --- a/apps/studio/components/interfaces/Realtime/Inspector/RealtimeTokensPopover/index.tsx +++ b/apps/studio/components/interfaces/Realtime/Inspector/RealtimeTokensPopover/index.tsx @@ -10,6 +10,8 @@ import { TelemetryActions } from 'lib/constants/telemetry' import { getRoleImpersonationJWT } from 'lib/role-impersonation' import { useRoleImpersonationStateSnapshot } from 'state/role-impersonation-state' import { RealtimeConfig } from '../useRealtimeMessages' +import { useParams } from 'common' +import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization' interface RealtimeTokensPopoverProps { config: RealtimeConfig @@ -28,6 +30,8 @@ export const RealtimeTokensPopover = ({ config, onChangeConfig }: RealtimeTokens ) const jwtSecret = postgrestConfig?.jwt_secret + const { ref } = useParams() + const org = useSelectedOrganization() const { mutate: sendEvent } = useSendEventMutation() // only send a telemetry event if the user changes the role. Don't send an event during initial render. @@ -35,7 +39,10 @@ export const RealtimeTokensPopover = ({ config, onChangeConfig }: RealtimeTokens useEffect(() => { if (isMounted.current) { - sendEvent({ action: TelemetryActions.REALTIME_INSPECTOR_DATABASE_ROLE_UPDATED }) + sendEvent({ + action: TelemetryActions.REALTIME_INSPECTOR_DATABASE_ROLE_UPDATED, + groups: { project: ref ?? 'Unknown', organization: org?.slug ?? 'Unknown' }, + }) } isMounted.current = true // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/apps/studio/components/interfaces/Realtime/Inspector/index.tsx b/apps/studio/components/interfaces/Realtime/Inspector/index.tsx index ef289600bcf..0a4b0d52b0e 100644 --- a/apps/studio/components/interfaces/Realtime/Inspector/index.tsx +++ b/apps/studio/components/interfaces/Realtime/Inspector/index.tsx @@ -7,12 +7,14 @@ import { Header } from './Header' import MessagesTable from './MessagesTable' import { SendMessageModal } from './SendMessageModal' import { RealtimeConfig, useRealtimeMessages } from './useRealtimeMessages' +import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization' /** * Acts as a container component for the entire log display */ export const RealtimeInspector = () => { const { ref } = useParams() + const org = useSelectedOrganization() const [sendMessageShown, setSendMessageShown] = useState(false) const [realtimeConfig, setRealtimeConfig] = useState({ @@ -51,7 +53,10 @@ export const RealtimeInspector = () => { visible={sendMessageShown} onSelectCancel={() => setSendMessageShown(false)} onSelectConfirm={(v) => { - sendEvent({ action: TelemetryActions.REALTIME_INSPECTOR_BROADCAST_SENT }) + sendEvent({ + action: TelemetryActions.REALTIME_INSPECTOR_BROADCAST_SENT, + groups: { project: ref ?? 'Unknown', organization: org?.slug ?? 'Unknown' }, + }) sendMessage(v.message, v.payload, () => setSendMessageShown(false)) }} /> diff --git a/apps/studio/components/interfaces/SQLEditor/SQLEditor.tsx b/apps/studio/components/interfaces/SQLEditor/SQLEditor.tsx index cd4d801be6b..0314665f56a 100644 --- a/apps/studio/components/interfaces/SQLEditor/SQLEditor.tsx +++ b/apps/studio/components/interfaces/SQLEditor/SQLEditor.tsx @@ -80,6 +80,7 @@ export const SQLEditor = () => { const os = detectOS() const router = useRouter() const { ref, id: urlId } = useParams() + const org = useSelectedOrganization() const { profile } = useProfile() const queryClient = useQueryClient() const project = useSelectedProject() @@ -423,6 +424,7 @@ export const SQLEditor = () => { sendEvent({ action: TelemetryActions.ASSISTANT_SQL_DIFF_HANDLER_EVALUATED, properties: { handlerAccepted: true }, + groups: { project: ref ?? 'Unknown', organization: org?.slug ?? 'Unknown' }, }) setSelectedDiffType(DiffType.Modification) @@ -447,6 +449,7 @@ export const SQLEditor = () => { sendEvent({ action: TelemetryActions.ASSISTANT_SQL_DIFF_HANDLER_EVALUATED, properties: { handlerAccepted: false }, + groups: { project: ref ?? 'Unknown', organization: org?.slug ?? 'Unknown' }, }) resetPrompt() closeDiff() diff --git a/apps/studio/components/interfaces/SQLEditor/SQLTemplates/SQLQuickstarts.tsx b/apps/studio/components/interfaces/SQLEditor/SQLTemplates/SQLQuickstarts.tsx index 5f1c2fba0b2..d1fe7c57df9 100644 --- a/apps/studio/components/interfaces/SQLEditor/SQLTemplates/SQLQuickstarts.tsx +++ b/apps/studio/components/interfaces/SQLEditor/SQLTemplates/SQLQuickstarts.tsx @@ -14,10 +14,12 @@ import { useProfile } from 'lib/profile' import { useSqlEditorV2StateSnapshot } from 'state/sql-editor-v2' import { createSqlSnippetSkeletonV2 } from '../SQLEditor.utils' import SQLCard from './SQLCard' +import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization' const SQLQuickstarts = () => { const router = useRouter() const { ref } = useParams() + const org = useSelectedOrganization() const { profile } = useProfile() const project = useSelectedProject() const [, quickStart] = partition(SQL_TEMPLATES, { type: 'template' }) @@ -79,6 +81,7 @@ const SQLQuickstarts = () => { sendEvent({ action: TelemetryActions.SQL_EDITOR_QUICKSTART_CLICKED, properties: { quickstartName: title }, + groups: { project: ref ?? 'Unknown', organization: org?.slug ?? 'Unknown' }, }) }} /> diff --git a/apps/studio/components/interfaces/SQLEditor/SQLTemplates/SQLTemplates.tsx b/apps/studio/components/interfaces/SQLEditor/SQLTemplates/SQLTemplates.tsx index fc8e1014ff3..85aa3b733ce 100644 --- a/apps/studio/components/interfaces/SQLEditor/SQLTemplates/SQLTemplates.tsx +++ b/apps/studio/components/interfaces/SQLEditor/SQLTemplates/SQLTemplates.tsx @@ -14,10 +14,12 @@ import { useSqlEditorV2StateSnapshot } from 'state/sql-editor-v2' import { createSqlSnippetSkeletonV2 } from '../SQLEditor.utils' import SQLCard from './SQLCard' import { TelemetryActions } from 'lib/constants/telemetry' +import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization' const SQLTemplates = () => { const router = useRouter() const { ref } = useParams() + const org = useSelectedOrganization() const { profile } = useProfile() const { project } = useProjectContext() const [sql] = partition(SQL_TEMPLATES, { type: 'template' }) @@ -79,6 +81,7 @@ const SQLTemplates = () => { sendEvent({ action: TelemetryActions.SQL_EDITOR_TEMPLATE_CLICKED, properties: { templateName: title }, + groups: { project: ref ?? 'Unknown', organization: org?.slug ?? 'Unknown' }, }) }} /> diff --git a/apps/studio/components/interfaces/SQLEditor/UtilityPanel/ResultsDropdown.tsx b/apps/studio/components/interfaces/SQLEditor/UtilityPanel/ResultsDropdown.tsx index 3a81ef9f474..56178a6db10 100644 --- a/apps/studio/components/interfaces/SQLEditor/UtilityPanel/ResultsDropdown.tsx +++ b/apps/studio/components/interfaces/SQLEditor/UtilityPanel/ResultsDropdown.tsx @@ -17,6 +17,8 @@ import { DropdownMenuTrigger, } from 'ui' import { TelemetryActions } from 'lib/constants/telemetry' +import { useParams } from 'common' +import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization' export type ResultsDropdownProps = { id: string @@ -29,6 +31,8 @@ const ResultsDropdown = ({ id }: ResultsDropdownProps) => { const result = snapV2.results?.[id]?.[0] ?? undefined const csvRef = useRef(null) + const { ref } = useParams() + const org = useSelectedOrganization() const { mutate: sendEvent } = useSendEventMutation() const csvData = useMemo(() => { @@ -67,7 +71,10 @@ const ResultsDropdown = ({ id }: ResultsDropdownProps) => { function onDownloadCSV() { csvRef.current?.link.click() - sendEvent({ action: TelemetryActions.SQL_EDITOR_RESULT_DOWNLOAD_CSV_CLICKED }) + sendEvent({ + action: TelemetryActions.SQL_EDITOR_RESULT_DOWNLOAD_CSV_CLICKED, + groups: { project: ref ?? 'Unknown', organization: org?.slug ?? 'Unknown' }, + }) } function onCopyAsMarkdown() { @@ -87,7 +94,10 @@ const ResultsDropdown = ({ id }: ResultsDropdownProps) => { copyToClipboard(markdownData, () => { toast.success('Copied results to clipboard') - sendEvent({ action: TelemetryActions.SQL_EDITOR_RESULT_COPY_MARKDOWN_CLICKED }) + sendEvent({ + action: TelemetryActions.SQL_EDITOR_RESULT_COPY_MARKDOWN_CLICKED, + groups: { project: ref ?? 'Unknown', organization: org?.slug ?? 'Unknown' }, + }) }) } } @@ -100,7 +110,10 @@ const ResultsDropdown = ({ id }: ResultsDropdownProps) => { copyToClipboard(JSON.stringify(result.rows, null, 2), () => { toast.success('Copied results to clipboard') - sendEvent({ action: TelemetryActions.SQL_EDITOR_RESULT_COPY_JSON_CLICKED }) + sendEvent({ + action: TelemetryActions.SQL_EDITOR_RESULT_COPY_JSON_CLICKED, + groups: { project: ref ?? 'Unknown', organization: org?.slug ?? 'Unknown' }, + }) }) } } diff --git a/apps/studio/components/ui/AIAssistantPanel/AIAssistant.tsx b/apps/studio/components/ui/AIAssistantPanel/AIAssistant.tsx index 0a8e2df82d2..4e04887e318 100644 --- a/apps/studio/components/ui/AIAssistantPanel/AIAssistant.tsx +++ b/apps/studio/components/ui/AIAssistantPanel/AIAssistant.tsx @@ -115,6 +115,8 @@ export const AIAssistant = ({ const currentTable = tables?.find((t) => t.id.toString() === entityId) const currentSchema = searchParams?.get('schema') ?? 'public' + const { ref } = useParams() + const org = useSelectedOrganization() const { mutate: sendEvent } = useSendEventMutation() const { @@ -178,10 +180,12 @@ export const AIAssistant = ({ if (content.includes('Help me to debug')) { sendEvent({ action: TelemetryActions.ASSISTANT_DEBUG_SUBMITTED, + groups: { project: ref ?? 'Unknown', organization: org?.slug ?? 'Unknown' }, }) } else { sendEvent({ action: TelemetryActions.ASSISTANT_PROMPT_SUBMITTED, + groups: { project: ref ?? 'Unknown', organization: org?.slug ?? 'Unknown' }, }) } } diff --git a/apps/studio/components/ui/QueryBlock/EditQueryButton.tsx b/apps/studio/components/ui/QueryBlock/EditQueryButton.tsx index 14ae1fbf43a..a850a67630a 100644 --- a/apps/studio/components/ui/QueryBlock/EditQueryButton.tsx +++ b/apps/studio/components/ui/QueryBlock/EditQueryButton.tsx @@ -17,6 +17,7 @@ import { TooltipContent, } from 'ui' import { ButtonTooltip } from '../ButtonTooltip' +import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization' interface EditQueryButtonProps { id?: string @@ -36,6 +37,7 @@ export const EditQueryButton = ({ id, sql, title }: EditQueryButtonProps) => { content: { side: 'bottom', text: 'Edit in SQL Editor' }, } + const org = useSelectedOrganization() const { mutate: sendEvent } = useSendEventMutation() const handleEditInSQLEditor = () => { @@ -77,6 +79,7 @@ export const EditQueryButton = ({ id, sql, title }: EditQueryButtonProps) => { isInSQLEditor, isInNewSnippet, }, + groups: { project: ref ?? 'Unknown', organization: org?.slug ?? 'Unknown' }, }) }} tooltip={tooltip} diff --git a/apps/studio/data/telemetry/send-event-mutation.ts b/apps/studio/data/telemetry/send-event-mutation.ts index c75ed581a45..f8d64c20256 100644 --- a/apps/studio/data/telemetry/send-event-mutation.ts +++ b/apps/studio/data/telemetry/send-event-mutation.ts @@ -113,6 +113,7 @@ export const useSendEventMutation = ({ (vars) => { const { action } = vars const properties = 'properties' in vars ? vars.properties : {} + const groups = 'groups' in vars ? vars.groups : {} const body: SendEventPayload = { action, @@ -128,6 +129,7 @@ export const useSendEventMutation = ({ viewport_width: isBrowser ? window.innerWidth : 0, }, custom_properties: properties as any, + groups, } return sendEvent({ body }) diff --git a/apps/studio/lib/constants/telemetry.ts b/apps/studio/lib/constants/telemetry.ts index 031464fbd50..7d91b1f0138 100644 --- a/apps/studio/lib/constants/telemetry.ts +++ b/apps/studio/lib/constants/telemetry.ts @@ -96,6 +96,10 @@ export interface ConnectionStringCopiedEvent { */ connectionMethod: 'direct' | 'transaction_pooler' | 'session_pooler' } + groups: { + project: string + organization: string + } } /** @@ -117,6 +121,10 @@ export interface CronJobCreatedEvent { */ schedule: string } + groups: { + project: string + organization: string + } } /** @@ -138,6 +146,10 @@ export interface CronJobUpdatedEvent { */ schedule: string } + groups: { + project: string + organization: string + } } /** @@ -149,6 +161,10 @@ export interface CronJobUpdatedEvent { */ export interface CronJobDeletedEvent { action: TelemetryActions.CRON_JOB_DELETED + groups: { + project: string + organization: string + } } /** @@ -160,6 +176,10 @@ export interface CronJobDeletedEvent { */ export interface CronJobCreateClickedEvent { action: TelemetryActions.CRON_JOB_CREATE_CLICKED + groups: { + project: string + organization: string + } } /** @@ -171,6 +191,10 @@ export interface CronJobCreateClickedEvent { */ export interface CronJobUpdateClickedEvent { action: TelemetryActions.CRON_JOB_UPDATE_CLICKED + groups: { + project: string + organization: string + } } /** @@ -182,6 +206,10 @@ export interface CronJobUpdateClickedEvent { */ export interface CronJobDeleteClickedEvent { action: TelemetryActions.CRON_JOB_DELETE_CLICKED + groups: { + project: string + organization: string + } } /** @@ -193,6 +221,10 @@ export interface CronJobDeleteClickedEvent { */ export interface CronJobHistoryClickedEvent { action: TelemetryActions.CRON_JOB_HISTORY_CLICKED + groups: { + project: string + organization: string + } } /** @@ -205,6 +237,10 @@ export interface CronJobHistoryClickedEvent { */ export interface FeaturePreviewsClickedEvent { action: TelemetryActions.FEATURE_PREVIEWS_CLICKED + groups: { + project: string + organization: string + } } /** @@ -223,6 +259,10 @@ export interface FeaturePreviewEnabledEvent { */ feature: string } + groups: { + project: string + organization: string + } } /** @@ -241,6 +281,10 @@ export interface FeaturePreviewDisabledEvent { */ feature: string } + groups: { + project: string + organization: string + } } /** @@ -318,6 +362,10 @@ export interface ProjectCreationSecondStepSubmittedEvent { */ export interface RealtimeInspectorListenChannelClickedEvent { action: TelemetryActions.REALTIME_INSPECTOR_LISTEN_CHANNEL_CLICKED + groups: { + project: string + organization: string + } } /** @@ -329,6 +377,10 @@ export interface RealtimeInspectorListenChannelClickedEvent { */ export interface RealtimeInspectorBroadcastSentEvent { action: TelemetryActions.REALTIME_INSPECTOR_BROADCAST_SENT + groups: { + project: string + organization: string + } } /** @@ -340,6 +392,10 @@ export interface RealtimeInspectorBroadcastSentEvent { */ export interface RealtimeInspectorMessageClickedEvent { action: TelemetryActions.REALTIME_INSPECTOR_MESSAGE_CLICKED + groups: { + project: string + organization: string + } } /** @@ -351,6 +407,10 @@ export interface RealtimeInspectorMessageClickedEvent { */ export interface RealtimeInspectorCopyMessageClickedEvent { action: TelemetryActions.REALTIME_INSPECTOR_COPY_MESSAGE_CLICKED + groups: { + project: string + organization: string + } } /** @@ -362,6 +422,10 @@ export interface RealtimeInspectorCopyMessageClickedEvent { */ export interface RealtimeInspectorFiltersAppliedEvent { action: TelemetryActions.REALTIME_INSPECTOR_FILTERS_APPLIED + groups: { + project: string + organization: string + } } /** @@ -373,6 +437,10 @@ export interface RealtimeInspectorFiltersAppliedEvent { */ export interface RealtimeInspectorDatabaseRoleUpdatedEvent { action: TelemetryActions.REALTIME_INSPECTOR_DATABASE_ROLE_UPDATED + groups: { + project: string + organization: string + } } /** @@ -390,6 +458,10 @@ export interface SqlEditorQuickstartClickedEvent { */ quickstartName: string } + groups: { + project: string + organization: string + } } /** @@ -407,6 +479,10 @@ export interface SqlEditorTemplateClickedEvent { */ templateName: string } + groups: { + project: string + organization: string + } } /** @@ -418,6 +494,10 @@ export interface SqlEditorTemplateClickedEvent { */ export interface SqlEditorResultDownloadCsvClickedEvent { action: TelemetryActions.SQL_EDITOR_RESULT_DOWNLOAD_CSV_CLICKED + groups: { + project: string + organization: string + } } /** @@ -429,6 +509,10 @@ export interface SqlEditorResultDownloadCsvClickedEvent { */ export interface SqlEditorResultCopyMarkdownClickedEvent { action: TelemetryActions.SQL_EDITOR_RESULT_COPY_MARKDOWN_CLICKED + groups: { + project: string + organization: string + } } /** @@ -440,6 +524,10 @@ export interface SqlEditorResultCopyMarkdownClickedEvent { */ export interface SqlEditorResultCopyJsonClickedEvent { action: TelemetryActions.SQL_EDITOR_RESULT_COPY_JSON_CLICKED + groups: { + project: string + organization: string + } } /** @@ -450,6 +538,10 @@ export interface SqlEditorResultCopyJsonClickedEvent { */ export interface AssistantPromptSubmittedEvent { action: TelemetryActions.ASSISTANT_PROMPT_SUBMITTED + groups: { + project: string + organization: string + } } /** @@ -460,6 +552,10 @@ export interface AssistantPromptSubmittedEvent { */ export interface AssistantDebugSubmittedEvent { action: TelemetryActions.ASSISTANT_DEBUG_SUBMITTED + groups: { + project: string + organization: string + } } /** @@ -494,6 +590,10 @@ export interface AssistantSqlDiffHandlerEvaluatedEvent { */ handlerAccepted: boolean } + groups: { + project: string + organization: string + } } /** @@ -511,4 +611,8 @@ export interface AssistantEditInSqlEditorClickedEvent { isInSQLEditor: boolean isInNewSnippet: boolean } + groups: { + project: string + organization: string + } } diff --git a/packages/api-types/types/api.d.ts b/packages/api-types/types/api.d.ts index 027d6dae1c3..badce548152 100644 --- a/packages/api-types/types/api.d.ts +++ b/packages/api-types/types/api.d.ts @@ -11602,6 +11602,10 @@ export interface components { custom_properties: { [key: string]: unknown } + groups?: { + organization?: string + project?: string + } page_title: string page_url: string pathname: string