From 451bd05261bcd6b8a263680676527e92da4eaf11 Mon Sep 17 00:00:00 2001 From: Shayna Chambless Date: Tue, 7 Oct 2025 16:09:53 -0700 Subject: [PATCH 01/10] old --- .../events/groupingInfo/groupingInfo.tsx | 4 +- .../events/groupingInfo/groupingSummary.tsx | 11 +----- .../groupingInfo/useEventGroupingInfo.tsx | 38 +++++++++++++++++-- 3 files changed, 38 insertions(+), 15 deletions(-) diff --git a/static/app/components/events/groupingInfo/groupingInfo.tsx b/static/app/components/events/groupingInfo/groupingInfo.tsx index ddf07bd67752d0..cc47a1d51b872d 100644 --- a/static/app/components/events/groupingInfo/groupingInfo.tsx +++ b/static/app/components/events/groupingInfo/groupingInfo.tsx @@ -39,8 +39,8 @@ export default function GroupingInfo({ projectSlug, }); - const variants = groupInfo - ? Object.values(groupInfo).sort((a, b) => { + const variants = groupInfo?.variants + ? Object.values(groupInfo.variants).sort((a, b) => { // Sort contributing variants before non-contributing ones if (a.contributes && !b.contributes) { return -1; diff --git a/static/app/components/events/groupingInfo/groupingSummary.tsx b/static/app/components/events/groupingInfo/groupingSummary.tsx index a139f192f5767a..8fe4461e7a48d8 100644 --- a/static/app/components/events/groupingInfo/groupingSummary.tsx +++ b/static/app/components/events/groupingInfo/groupingSummary.tsx @@ -23,21 +23,14 @@ export function GroupInfoSummary({ projectSlug, }); const groupedBy = groupInfo - ? Object.values(groupInfo) + ? Object.values(groupInfo.variants) .filter(variant => variant.contributes && variant.description !== null) .map(variant => variant.description!) .sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase())) .join(', ') : t('nothing'); - const groupingConfig = - showGroupingConfig && groupInfo - ? ( - Object.values(groupInfo).find( - variant => 'config' in variant && variant.config?.id - ) as any - )?.config?.id - : null; + const groupingConfig = groupInfo?.grouping_config; if (isPending && !hasPerformanceGrouping) { return ( diff --git a/static/app/components/events/groupingInfo/useEventGroupingInfo.tsx b/static/app/components/events/groupingInfo/useEventGroupingInfo.tsx index bfa8aca59befdd..20dc0b57798629 100644 --- a/static/app/components/events/groupingInfo/useEventGroupingInfo.tsx +++ b/static/app/components/events/groupingInfo/useEventGroupingInfo.tsx @@ -8,7 +8,29 @@ import type {Group} from 'sentry/types/group'; import {useApiQuery} from 'sentry/utils/queryClient'; import useOrganization from 'sentry/utils/useOrganization'; -type EventGroupingInfoResponse = Record; +type EventGroupingInfoResponseOld = Record; +type EventGroupingInfoResponse = { + grouping_config: string; + variants: Record; +}; + +function eventGroupingInfoResponseOldToNew( + old: EventGroupingInfoResponseOld | null +): EventGroupingInfoResponse | null { + const grouping_config = old + ? ( + Object.values(old).find( + variant => 'config' in variant && variant.config?.id + ) as any + )?.config?.id + : null; + return old + ? { + grouping_config, + variants: old, + } + : null; +} function generatePerformanceGroupInfo({ event, @@ -16,7 +38,7 @@ function generatePerformanceGroupInfo({ }: { event: Event; group: Group | undefined; -}): EventGroupingInfoResponse | null { +}): EventGroupingInfoResponseOld | null { if (!event.occurrence) { return null; } @@ -61,7 +83,7 @@ export function useEventGroupingInfo({ const hasPerformanceGrouping = event.occurrence && event.type === 'transaction'; - const {data, isPending, isError, isSuccess} = useApiQuery( + const {data, isPending, isError, isSuccess} = useApiQuery( [`/projects/${organization.slug}/${projectSlug}/events/${event.id}/grouping-info/`], {enabled: !hasPerformanceGrouping, staleTime: Infinity} ); @@ -70,5 +92,13 @@ export function useEventGroupingInfo({ ? generatePerformanceGroupInfo({group, event}) : (data ?? null); - return {groupInfo, isPending, isError, isSuccess, hasPerformanceGrouping}; + const groupInfoNew = eventGroupingInfoResponseOldToNew(groupInfo); + + return { + groupInfo: groupInfoNew, + isPending, + isError, + isSuccess, + hasPerformanceGrouping, + }; } From ad35eecf732d2f584b1d11e1b28bf98cfb85aa88 Mon Sep 17 00:00:00 2001 From: Shayna Chambless Date: Tue, 7 Oct 2025 16:11:30 -0700 Subject: [PATCH 02/10] showGroupingCOnfig --- static/app/components/events/groupingInfo/groupingSummary.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/app/components/events/groupingInfo/groupingSummary.tsx b/static/app/components/events/groupingInfo/groupingSummary.tsx index 8fe4461e7a48d8..8c37f18747e047 100644 --- a/static/app/components/events/groupingInfo/groupingSummary.tsx +++ b/static/app/components/events/groupingInfo/groupingSummary.tsx @@ -30,7 +30,7 @@ export function GroupInfoSummary({ .join(', ') : t('nothing'); - const groupingConfig = groupInfo?.grouping_config; + const groupingConfig = showGroupingConfig && groupInfo?.grouping_config; if (isPending && !hasPerformanceGrouping) { return ( From be9c508849551a5b27db3f130236281c95b3d557 Mon Sep 17 00:00:00 2001 From: Shayna Chambless Date: Tue, 7 Oct 2025 16:14:29 -0700 Subject: [PATCH 03/10] fix --- static/app/components/events/groupingInfo/groupingSummary.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/app/components/events/groupingInfo/groupingSummary.tsx b/static/app/components/events/groupingInfo/groupingSummary.tsx index 8c37f18747e047..3e63cf01c400ba 100644 --- a/static/app/components/events/groupingInfo/groupingSummary.tsx +++ b/static/app/components/events/groupingInfo/groupingSummary.tsx @@ -22,7 +22,7 @@ export function GroupInfoSummary({ group, projectSlug, }); - const groupedBy = groupInfo + const groupedBy = groupInfo?.variants ? Object.values(groupInfo.variants) .filter(variant => variant.contributes && variant.description !== null) .map(variant => variant.description!) From fdc486e8acf2b2a1fdc14714117fc9ce463356d0 Mon Sep 17 00:00:00 2001 From: Shayna Chambless Date: Tue, 7 Oct 2025 16:22:49 -0700 Subject: [PATCH 04/10] type --- .../groupingInfo/useEventGroupingInfo.tsx | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/static/app/components/events/groupingInfo/useEventGroupingInfo.tsx b/static/app/components/events/groupingInfo/useEventGroupingInfo.tsx index 20dc0b57798629..00b7cfd9be66d9 100644 --- a/static/app/components/events/groupingInfo/useEventGroupingInfo.tsx +++ b/static/app/components/events/groupingInfo/useEventGroupingInfo.tsx @@ -31,6 +31,11 @@ function eventGroupingInfoResponseOldToNew( } : null; } +function isOld( + data: EventGroupingInfoResponseOld | EventGroupingInfoResponse | null +): boolean { + return data ? !('grouping_config' in data) : false; +} function generatePerformanceGroupInfo({ event, @@ -83,16 +88,20 @@ export function useEventGroupingInfo({ const hasPerformanceGrouping = event.occurrence && event.type === 'transaction'; - const {data, isPending, isError, isSuccess} = useApiQuery( - [`/projects/${organization.slug}/${projectSlug}/events/${event.id}/grouping-info/`], - {enabled: !hasPerformanceGrouping, staleTime: Infinity} - ); + const {data, isPending, isError, isSuccess} = useApiQuery< + EventGroupingInfoResponseOld | EventGroupingInfoResponse + >([`/projects/${organization.slug}/${projectSlug}/events/${event.id}/grouping-info/`], { + enabled: !hasPerformanceGrouping, + staleTime: Infinity, + }); const groupInfo = hasPerformanceGrouping ? generatePerformanceGroupInfo({group, event}) : (data ?? null); - const groupInfoNew = eventGroupingInfoResponseOldToNew(groupInfo); + const groupInfoNew = isOld(groupInfo) + ? eventGroupingInfoResponseOldToNew(groupInfo as EventGroupingInfoResponseOld) + : (groupInfo as EventGroupingInfoResponse); return { groupInfo: groupInfoNew, From e393d053bd890a2220baad1345c26a0521f2aebf Mon Sep 17 00:00:00 2001 From: Shayna Chambless Date: Tue, 7 Oct 2025 16:42:13 -0700 Subject: [PATCH 05/10] type --- .../app/components/events/groupingInfo/useEventGroupingInfo.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/app/components/events/groupingInfo/useEventGroupingInfo.tsx b/static/app/components/events/groupingInfo/useEventGroupingInfo.tsx index 00b7cfd9be66d9..4569737f5ba330 100644 --- a/static/app/components/events/groupingInfo/useEventGroupingInfo.tsx +++ b/static/app/components/events/groupingInfo/useEventGroupingInfo.tsx @@ -43,7 +43,7 @@ function generatePerformanceGroupInfo({ }: { event: Event; group: Group | undefined; -}): EventGroupingInfoResponseOld | null { +}): EventGroupingInfoResponseOld | EventGroupingInfoResponse | null { if (!event.occurrence) { return null; } From 84b87827c8a2f2cd8478ca7a777eff4a28d0db94 Mon Sep 17 00:00:00 2001 From: Shayna Chambless Date: Tue, 7 Oct 2025 16:43:47 -0700 Subject: [PATCH 06/10] add comment --- .../components/events/groupingInfo/useEventGroupingInfo.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/static/app/components/events/groupingInfo/useEventGroupingInfo.tsx b/static/app/components/events/groupingInfo/useEventGroupingInfo.tsx index 4569737f5ba330..d8d3252c82db2d 100644 --- a/static/app/components/events/groupingInfo/useEventGroupingInfo.tsx +++ b/static/app/components/events/groupingInfo/useEventGroupingInfo.tsx @@ -14,6 +14,7 @@ type EventGroupingInfoResponse = { variants: Record; }; +// temporary function to convert the old response structure to the new one function eventGroupingInfoResponseOldToNew( old: EventGroupingInfoResponseOld | null ): EventGroupingInfoResponse | null { @@ -31,6 +32,8 @@ function eventGroupingInfoResponseOldToNew( } : null; } + +// temporary function to check if the respinse is old type function isOld( data: EventGroupingInfoResponseOld | EventGroupingInfoResponse | null ): boolean { From ed5435b5ff6050090eea195509d6ec8a5cac8ffe Mon Sep 17 00:00:00 2001 From: Shayna Chambless Date: Wed, 8 Oct 2025 12:57:14 -0700 Subject: [PATCH 07/10] fixes --- .../groupingInfo/useEventGroupingInfo.tsx | 47 ++++++++++--------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/static/app/components/events/groupingInfo/useEventGroupingInfo.tsx b/static/app/components/events/groupingInfo/useEventGroupingInfo.tsx index d8d3252c82db2d..7bd1e7de757321 100644 --- a/static/app/components/events/groupingInfo/useEventGroupingInfo.tsx +++ b/static/app/components/events/groupingInfo/useEventGroupingInfo.tsx @@ -36,7 +36,7 @@ function eventGroupingInfoResponseOldToNew( // temporary function to check if the respinse is old type function isOld( data: EventGroupingInfoResponseOld | EventGroupingInfoResponse | null -): boolean { +): data is EventGroupingInfoResponseOld { return data ? !('grouping_config' in data) : false; } @@ -46,7 +46,7 @@ function generatePerformanceGroupInfo({ }: { event: Event; group: Group | undefined; -}): EventGroupingInfoResponseOld | EventGroupingInfoResponse | null { +}): EventGroupingInfoResponse | null { if (!event.occurrence) { return null; } @@ -57,21 +57,24 @@ function generatePerformanceGroupInfo({ return group ? { - [group.issueType]: { - contributes: true, - description: t('performance problem'), - hash: event.occurrence?.fingerprint[0] || '', - hashMismatch: false, - hint: null, - key: group.issueType, - type: EventGroupVariantType.PERFORMANCE_PROBLEM, - evidence: { - op: evidenceData?.op, - parent_span_ids: evidenceData?.parentSpanIds, - cause_span_ids: evidenceData?.causeSpanIds, - offender_span_ids: evidenceData?.offenderSpanIds, - desc: t('performance problem'), - fingerprint: hash, + grouping_config: 'performance', + variants: { + [group.issueType]: { + contributes: true, + description: t('performance problem'), + hash: event.occurrence?.fingerprint[0] || '', + hashMismatch: false, + hint: null, + key: group.issueType, + type: EventGroupVariantType.PERFORMANCE_PROBLEM, + evidence: { + op: evidenceData?.op, + parent_span_ids: evidenceData?.parentSpanIds, + cause_span_ids: evidenceData?.causeSpanIds, + offender_span_ids: evidenceData?.offenderSpanIds, + desc: t('performance problem'), + fingerprint: hash, + }, }, }, } @@ -98,16 +101,16 @@ export function useEventGroupingInfo({ staleTime: Infinity, }); - const groupInfo = hasPerformanceGrouping + const groupInfoRaw = hasPerformanceGrouping ? generatePerformanceGroupInfo({group, event}) : (data ?? null); - const groupInfoNew = isOld(groupInfo) - ? eventGroupingInfoResponseOldToNew(groupInfo as EventGroupingInfoResponseOld) - : (groupInfo as EventGroupingInfoResponse); + const groupInfo = isOld(groupInfoRaw) + ? eventGroupingInfoResponseOldToNew(groupInfoRaw) + : groupInfoRaw; return { - groupInfo: groupInfoNew, + groupInfo, isPending, isError, isSuccess, From ed5de2e2e527e63b0e5737375ef908787ffe5398 Mon Sep 17 00:00:00 2001 From: Shayna Chambless Date: Wed, 8 Oct 2025 13:13:22 -0700 Subject: [PATCH 08/10] testing --- .../groupingInfo/groupingInfoSection.spec.tsx | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/static/app/components/events/groupingInfo/groupingInfoSection.spec.tsx b/static/app/components/events/groupingInfo/groupingInfoSection.spec.tsx index 0c5a5c5ed90bd1..7f24fd75c6d2b8 100644 --- a/static/app/components/events/groupingInfo/groupingInfoSection.spec.tsx +++ b/static/app/components/events/groupingInfo/groupingInfoSection.spec.tsx @@ -67,4 +67,59 @@ describe('EventGroupingInfo', () => { // Should not make grouping-info request expect(groupingInfoRequest).not.toHaveBeenCalled(); }); + + it('works with new groupingInfo format', async () => { + groupingInfoRequest = MockApiClient.addMockResponse({ + url: `/projects/org-slug/project-slug/events/${event.id}/grouping-info/`, + body: { + grouping_config: 'default:XXXX', + variants: { + app: { + contributes: true, + description: 'variant description', + hash: '123', + hashMismatch: false, + key: 'key', + type: EventGroupVariantType.CHECKSUM, + }, + }, + }, + }); + render(); + + expect(await screen.findByText('variant description')).toBeInTheDocument(); + expect(screen.getByText('123')).toBeInTheDocument(); + }); + it('gets performance new grouping info from group/event data', async () => { + groupingInfoRequest = MockApiClient.addMockResponse({ + url: `/projects/org-slug/project-slug/events/${event.id}/grouping-info/`, + body: { + grouping_config: null, + variants: { + app: { + contributes: true, + description: 'variant description', + hash: '123', + hashMismatch: false, + key: 'key', + type: EventGroupVariantType.CHECKSUM, + }, + }, + }, + }); + const perfEvent = EventFixture({ + type: 'transaction', + occurrence: {fingerprint: ['123'], evidenceData: {op: 'bad-op'}}, + }); + const perfGroup = GroupFixture({issueCategory: IssueCategory.PERFORMANCE}); + + render( + + ); + + expect(await screen.findByText('performance problem')).toBeInTheDocument(); + expect(screen.getByText('123')).toBeInTheDocument(); + // Should not make grouping-info request + expect(groupingInfoRequest).not.toHaveBeenCalled(); + }); }); From bf44c8c24218e53487aa6c781f5546324865b5b9 Mon Sep 17 00:00:00 2001 From: Shayna Chambless Date: Wed, 8 Oct 2025 14:07:20 -0700 Subject: [PATCH 09/10] grouping config type --- .../events/groupingInfo/groupingSummary.tsx | 2 +- .../events/groupingInfo/useEventGroupingInfo.tsx | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/static/app/components/events/groupingInfo/groupingSummary.tsx b/static/app/components/events/groupingInfo/groupingSummary.tsx index 3e63cf01c400ba..b96f4331df6718 100644 --- a/static/app/components/events/groupingInfo/groupingSummary.tsx +++ b/static/app/components/events/groupingInfo/groupingSummary.tsx @@ -30,7 +30,7 @@ export function GroupInfoSummary({ .join(', ') : t('nothing'); - const groupingConfig = showGroupingConfig && groupInfo?.grouping_config; + const groupingConfig = showGroupingConfig && groupInfo?.grouping_config?.id; if (isPending && !hasPerformanceGrouping) { return ( diff --git a/static/app/components/events/groupingInfo/useEventGroupingInfo.tsx b/static/app/components/events/groupingInfo/useEventGroupingInfo.tsx index 7bd1e7de757321..8f676d241ca906 100644 --- a/static/app/components/events/groupingInfo/useEventGroupingInfo.tsx +++ b/static/app/components/events/groupingInfo/useEventGroupingInfo.tsx @@ -2,6 +2,7 @@ import {t} from 'sentry/locale'; import { EventGroupVariantType, type Event, + type EventGroupingConfig, type EventGroupVariant, } from 'sentry/types/event'; import type {Group} from 'sentry/types/group'; @@ -10,7 +11,7 @@ import useOrganization from 'sentry/utils/useOrganization'; type EventGroupingInfoResponseOld = Record; type EventGroupingInfoResponse = { - grouping_config: string; + grouping_config: EventGroupingConfig | null; variants: Record; }; @@ -19,11 +20,8 @@ function eventGroupingInfoResponseOldToNew( old: EventGroupingInfoResponseOld | null ): EventGroupingInfoResponse | null { const grouping_config = old - ? ( - Object.values(old).find( - variant => 'config' in variant && variant.config?.id - ) as any - )?.config?.id + ? (Object.values(old).find(variant => 'config' in variant && variant.config) as any) + ?.config : null; return old ? { @@ -57,7 +55,7 @@ function generatePerformanceGroupInfo({ return group ? { - grouping_config: 'performance', + grouping_config: null, variants: { [group.issueType]: { contributes: true, From 19d8a9756a9cb66ed610579757153020ed268b2c Mon Sep 17 00:00:00 2001 From: Shayna Chambless Date: Wed, 8 Oct 2025 15:26:13 -0700 Subject: [PATCH 10/10] change back to string --- .../components/events/groupingInfo/groupingSummary.tsx | 2 +- .../events/groupingInfo/useEventGroupingInfo.tsx | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/static/app/components/events/groupingInfo/groupingSummary.tsx b/static/app/components/events/groupingInfo/groupingSummary.tsx index b96f4331df6718..3e63cf01c400ba 100644 --- a/static/app/components/events/groupingInfo/groupingSummary.tsx +++ b/static/app/components/events/groupingInfo/groupingSummary.tsx @@ -30,7 +30,7 @@ export function GroupInfoSummary({ .join(', ') : t('nothing'); - const groupingConfig = showGroupingConfig && groupInfo?.grouping_config?.id; + const groupingConfig = showGroupingConfig && groupInfo?.grouping_config; if (isPending && !hasPerformanceGrouping) { return ( diff --git a/static/app/components/events/groupingInfo/useEventGroupingInfo.tsx b/static/app/components/events/groupingInfo/useEventGroupingInfo.tsx index 8f676d241ca906..c7daffa6360cf4 100644 --- a/static/app/components/events/groupingInfo/useEventGroupingInfo.tsx +++ b/static/app/components/events/groupingInfo/useEventGroupingInfo.tsx @@ -2,7 +2,6 @@ import {t} from 'sentry/locale'; import { EventGroupVariantType, type Event, - type EventGroupingConfig, type EventGroupVariant, } from 'sentry/types/event'; import type {Group} from 'sentry/types/group'; @@ -11,7 +10,7 @@ import useOrganization from 'sentry/utils/useOrganization'; type EventGroupingInfoResponseOld = Record; type EventGroupingInfoResponse = { - grouping_config: EventGroupingConfig | null; + grouping_config: string | null; variants: Record; }; @@ -20,8 +19,11 @@ function eventGroupingInfoResponseOldToNew( old: EventGroupingInfoResponseOld | null ): EventGroupingInfoResponse | null { const grouping_config = old - ? (Object.values(old).find(variant => 'config' in variant && variant.config) as any) - ?.config + ? ( + Object.values(old).find( + variant => 'config' in variant && variant.config?.id + ) as any + )?.config?.id : null; return old ? {