From b70bd1a832dcdd4ef24a7bb63d3a1ac798709dbd Mon Sep 17 00:00:00 2001 From: Jenn Mueng Date: Fri, 30 May 2025 14:46:59 +0700 Subject: [PATCH] feat(autofix): Add key analytics events --- .../events/autofix/autofixChanges.tsx | 2 + .../events/autofix/autofixHighlightPopup.tsx | 11 ++++ .../events/autofix/autofixInsightCards.tsx | 33 +++++++++++ .../events/autofix/autofixRootCause.tsx | 4 ++ .../events/autofix/autofixSolution.tsx | 55 +++++++++++++++---- .../group/groupSummaryWithAutofix.tsx | 8 +++ 6 files changed, 103 insertions(+), 10 deletions(-) diff --git a/static/app/components/events/autofix/autofixChanges.tsx b/static/app/components/events/autofix/autofixChanges.tsx index 657cb91b8b7ee7..68f14291fd9042 100644 --- a/static/app/components/events/autofix/autofixChanges.tsx +++ b/static/app/components/events/autofix/autofixChanges.tsx @@ -283,6 +283,8 @@ export function AutofixChanges({ borderless title={t('Chat with Seer')} onClick={handleSelectFirstChange} + analyticsEventName="Autofix: Changes Chat" + analyticsEventKey="autofix.changes.chat" > diff --git a/static/app/components/events/autofix/autofixHighlightPopup.tsx b/static/app/components/events/autofix/autofixHighlightPopup.tsx index ed8893a546c60c..bc40db10034322 100644 --- a/static/app/components/events/autofix/autofixHighlightPopup.tsx +++ b/static/app/components/events/autofix/autofixHighlightPopup.tsx @@ -25,6 +25,7 @@ import LoadingIndicator from 'sentry/components/loadingIndicator'; import {IconClose} from 'sentry/icons'; import {t} from 'sentry/locale'; import {space} from 'sentry/styles/space'; +import {trackAnalytics} from 'sentry/utils/analytics'; import testableTransition from 'sentry/utils/testableTransition'; import useApi from 'sentry/utils/useApi'; import useMedia from 'sentry/utils/useMedia'; @@ -140,6 +141,8 @@ function AutofixHighlightPopupContent({ isFocused, onShouldPersistChange, }: Props & {isFocused?: boolean}) { + const organization = useOrganization(); + const {mutate: submitComment} = useCommentThread({groupId, runId}); const {mutate: closeCommentThread} = useCloseCommentThread({groupId, runId}); @@ -247,6 +250,14 @@ function AutofixHighlightPopupContent({ is_agent_comment: isAgentComment ?? false, }); setComment(''); + + trackAnalytics('autofix.comment_thread.submit', { + organization, + group_id: groupId, + run_id: runId, + step_index: stepIndex, + is_agent_comment: isAgentComment ?? false, + }); }; const handleContainerClick = (e: React.MouseEvent) => { diff --git a/static/app/components/events/autofix/autofixInsightCards.tsx b/static/app/components/events/autofix/autofixInsightCards.tsx index 8b2878d26aea68..540cf0caa51297 100644 --- a/static/app/components/events/autofix/autofixInsightCards.tsx +++ b/static/app/components/events/autofix/autofixInsightCards.tsx @@ -16,6 +16,7 @@ import {useTypingAnimation} from 'sentry/components/events/autofix/useTypingAnim import {IconChevron, IconClose} from 'sentry/icons'; import {t, tn} from 'sentry/locale'; import {space} from 'sentry/styles/space'; +import {trackAnalytics} from 'sentry/utils/analytics'; import {singleLineRenderer} from 'sentry/utils/marked/marked'; import {MarkedText} from 'sentry/utils/marked/markedText'; import {useMutation, useQueryClient} from 'sentry/utils/queryClient'; @@ -166,6 +167,14 @@ function AutofixInsightCard({ size="sm" title={t('Redo work from here')} aria-label={t('Redo work from here')} + analyticsEventName="Autofix: Insight Card Rethink Open" + analyticsEventKey="autofix.insight.rethink_open" + analyticsParams={{ + insight_card_index: index, + step_index: stepIndex, + group_id: groupId, + run_id: runId, + }} > {'\u23CE'} @@ -213,6 +222,14 @@ function AutofixInsightCard({ icon={} aria-label={t('Edit insight')} title={t('Rethink the answer from here')} + analyticsEventName="Autofix: Insight Card Rethink" + analyticsEventKey="autofix.insight.rethink" + analyticsParams={{ + insight_card_index: index, + step_index: stepIndex, + group_id: groupId, + run_id: runId, + }} /> @@ -307,6 +324,8 @@ function CollapsibleChainLink({ const [newInsightText, setNewInsightText] = useState(''); const {mutate: updateInsight} = useUpdateInsightCard({groupId, runId}); + const organization = useOrganization(); + const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); setIsAdding(false); @@ -317,6 +336,13 @@ function CollapsibleChainLink({ insightCount !== undefined && insightCount > 0 ? insightCount : null, }); setNewInsightText(''); + + trackAnalytics('autofix.step.rethink', { + step_index: stepIndex, + group_id: groupId, + run_id: runId, + organization, + }); }; const handleCancel = () => { @@ -405,6 +431,13 @@ function CollapsibleChainLink({ onClick={() => setIsAdding(true)} title={t('Give feedback and rethink the answer')} aria-label={t('Give feedback and rethink the answer')} + analyticsEventName="Autofix: Step Rethink Open" + analyticsEventKey="autofix.step.rethink_open" + analyticsParams={{ + step_index: stepIndex, + group_id: groupId, + run_id: runId, + }} > {t('Rethink this answer')} diff --git a/static/app/components/events/autofix/autofixRootCause.tsx b/static/app/components/events/autofix/autofixRootCause.tsx index afdeb9517700b9..f3d071fbcdea7c 100644 --- a/static/app/components/events/autofix/autofixRootCause.tsx +++ b/static/app/components/events/autofix/autofixRootCause.tsx @@ -175,6 +175,8 @@ function CopyRootCauseButton({ text={text} borderless title="Copy root cause as Markdown" + analyticsEventName="Autofix: Copy Root Cause as Markdown" + analyticsEventKey="autofix.root_cause.copy" /> ); } @@ -245,6 +247,8 @@ function AutofixRootCauseDisplay({ borderless title={t('Chat with Seer')} onClick={handleSelectDescription} + analyticsEventName="Autofix: Root Cause Chat" + analyticsEventKey="autofix.root_cause.chat" > diff --git a/static/app/components/events/autofix/autofixSolution.tsx b/static/app/components/events/autofix/autofixSolution.tsx index 3444b2004047dd..a8efb0663c6845 100644 --- a/static/app/components/events/autofix/autofixSolution.tsx +++ b/static/app/components/events/autofix/autofixSolution.tsx @@ -26,6 +26,7 @@ import {Timeline} from 'sentry/components/timeline'; import {IconAdd, IconChat, IconFix} from 'sentry/icons'; import {t} from 'sentry/locale'; import {space} from 'sentry/styles/space'; +import {trackAnalytics} from 'sentry/utils/analytics'; import {singleLineRenderer} from 'sentry/utils/marked/marked'; import {valueIsEqual} from 'sentry/utils/object/valueIsEqual'; import {setApiQueryData, useMutation, useQueryClient} from 'sentry/utils/queryClient'; @@ -305,6 +306,8 @@ function CopySolutionButton({ text={text} borderless title="Copy solution as Markdown" + analyticsEventName="Autofix: Copy Solution as Markdown" + analyticsEventKey="autofix.solution.copy" /> ); } @@ -320,6 +323,8 @@ function AutofixSolutionDisplay({ solutionSelected, agentCommentThread, }: Omit) { + const organization = useOrganization(); + const {repos} = useAutofixRepos(groupId); const {mutate: handleContinue, isPending} = useSelectSolution({groupId, runId}); const [isEditing, _setIsEditing] = useState(false); @@ -367,6 +372,12 @@ function AutofixSolutionDisplay({ // Clear the input setInstructions(''); + + trackAnalytics('autofix.solution.add_step', { + organization, + solution: solutionItems, + newStep, + }); } }; @@ -375,17 +386,37 @@ function AutofixSolutionDisplay({ handleAddInstruction(); }; - const handleDeleteItem = useCallback((index: number) => { - setSolutionItems(current => current.filter((_, i) => i !== index)); - }, []); + const handleDeleteItem = useCallback( + (index: number) => { + setSolutionItems(current => current.filter((_, i) => i !== index)); - const handleToggleActive = useCallback((index: number) => { - setSolutionItems(current => - current.map((item, i) => - i === index ? {...item, is_active: item.is_active === false ? true : false} : item - ) - ); - }, []); + trackAnalytics('autofix.solution.delete_step', { + organization, + solution: solutionItems, + deletedStep: solutionItems[index], + }); + }, + [organization, solutionItems] + ); + + const handleToggleActive = useCallback( + (index: number) => { + setSolutionItems(current => + current.map((item, i) => + i === index + ? {...item, is_active: item.is_active === false ? true : false} + : item + ) + ); + + trackAnalytics('autofix.solution.toggle_step', { + organization, + solution: solutionItems, + toggledStep: solutionItems[index], + }); + }, + [organization, solutionItems] + ); useEffect(() => { setSolutionItems( @@ -439,6 +470,8 @@ function AutofixSolutionDisplay({ borderless title={t('Chat with Seer')} onClick={handleSelectDescription} + analyticsEventName="Autofix: Solution Chat" + analyticsEventKey="autofix.solution.chat" > @@ -476,6 +509,8 @@ function AutofixSolutionDisplay({ solution: solutionItems, }); }} + analyticsEventName="Autofix: Code It Up" + analyticsEventKey="autofix.solution.code" > {t('Code It Up')} diff --git a/static/app/components/group/groupSummaryWithAutofix.tsx b/static/app/components/group/groupSummaryWithAutofix.tsx index 7b657c58e908ee..397f9a15e473aa 100644 --- a/static/app/components/group/groupSummaryWithAutofix.tsx +++ b/static/app/components/group/groupSummaryWithAutofix.tsx @@ -45,6 +45,8 @@ interface InsightCardObject { id: string; insight: string | null | undefined; title: string; + copyAnalyticsEventKey?: string; + copyAnalyticsEventName?: string; copyText?: string | null; copyTitle?: string | null; icon?: React.ReactNode; @@ -175,6 +177,8 @@ function AutofixSummary({ }, copyTitle: t('Copy root cause as Markdown'), copyText: rootCauseCopyText, + copyAnalyticsEventName: 'Autofix: Copy Root Cause as Markdown', + copyAnalyticsEventKey: 'autofix.root_cause.copy', }, ...(solutionDescription || solutionIsLoading @@ -200,6 +204,8 @@ function AutofixSummary({ }, copyTitle: t('Copy solution as Markdown'), copyText: solutionCopyText, + copyAnalyticsEventName: 'Autofix: Copy Solution as Markdown', + copyAnalyticsEventKey: 'autofix.solution.copy', }, ] : []), @@ -256,6 +262,8 @@ function AutofixSummary({ onClick={e => { e.stopPropagation(); }} + analyticsEventName={card.copyAnalyticsEventName} + analyticsEventKey={card.copyAnalyticsEventKey} /> )}