Skip to content

Commit a96c782

Browse files
authored
feat(ai): Single source of truth for AI conditions (#81158)
Unifies all AI condition generating to a single hook used between issue summary, and the button + drawer. Fixes getsentry/seer#1485 where the autofix setup didn't immediately show up after consenting.
1 parent de94c64 commit a96c782

File tree

4 files changed

+118
-129
lines changed

4 files changed

+118
-129
lines changed

static/app/components/group/groupSummary.tsx

Lines changed: 14 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
import styled from '@emotion/styled';
22

3-
import {useAutofixSetup} from 'sentry/components/events/autofix/useAutofixSetup';
43
import Placeholder from 'sentry/components/placeholder';
54
import {IconFatal, IconFocus, IconSpan} from 'sentry/icons';
65
import {t} from 'sentry/locale';
76
import {space} from 'sentry/styles/space';
8-
import {IssueCategory} from 'sentry/types/group';
7+
import type {Event} from 'sentry/types/event';
8+
import type {Group} from 'sentry/types/group';
9+
import type {Project} from 'sentry/types/project';
910
import marked from 'sentry/utils/marked';
1011
import {type ApiQueryKey, useApiQuery} from 'sentry/utils/queryClient';
1112
import useOrganization from 'sentry/utils/useOrganization';
13+
import {useAiConfig} from 'sentry/views/issueDetails/streamline/useAiConfig';
1214

1315
interface GroupSummaryData {
1416
groupId: string;
@@ -18,14 +20,6 @@ interface GroupSummaryData {
1820
whatsWrong?: string | null;
1921
}
2022

21-
const isSummaryEnabled = (
22-
hasGenAIConsent: boolean,
23-
hideAiFeatures: boolean,
24-
groupCategory: IssueCategory
25-
) => {
26-
return hasGenAIConsent && !hideAiFeatures && groupCategory === IssueCategory.ERROR;
27-
};
28-
2923
export const makeGroupSummaryQueryKey = (
3024
organizationSlug: string,
3125
groupId: string
@@ -34,30 +28,26 @@ export const makeGroupSummaryQueryKey = (
3428
{method: 'POST'},
3529
];
3630

37-
export function useGroupSummary(groupId: string, groupCategory: IssueCategory) {
31+
export function useGroupSummary(
32+
group: Group,
33+
event: Event | null | undefined,
34+
project: Project
35+
) {
3836
const organization = useOrganization();
39-
// We piggyback and use autofix's genai consent check for now.
40-
const {
41-
data: autofixSetupData,
42-
isPending: isAutofixSetupLoading,
43-
isError: isAutofixSetupError,
44-
} = useAutofixSetup({groupId});
4537

46-
const hasGenAIConsent = autofixSetupData?.genAIConsent.ok ?? false;
47-
const hideAiFeatures = organization.hideAiFeatures;
38+
const aiConfig = useAiConfig(group, event, project);
4839

4940
const queryData = useApiQuery<GroupSummaryData>(
50-
makeGroupSummaryQueryKey(organization.slug, groupId),
41+
makeGroupSummaryQueryKey(organization.slug, group.id),
5142
{
5243
staleTime: Infinity, // Cache the result indefinitely as it's unlikely to change if it's already computed
53-
enabled: isSummaryEnabled(hasGenAIConsent, hideAiFeatures, groupCategory),
44+
enabled: aiConfig.hasSummary,
5445
}
5546
);
5647
return {
5748
...queryData,
58-
isPending: isAutofixSetupLoading || queryData.isPending,
59-
isError: queryData.isError || isAutofixSetupError,
60-
hasGenAIConsent,
49+
isPending: aiConfig.isAutofixSetupLoading || queryData.isPending,
50+
isError: queryData.isError,
6151
};
6252
}
6353

static/app/views/issueDetails/streamline/solutionsHubDrawer.tsx

Lines changed: 9 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import AutofixFeedback from 'sentry/components/events/autofix/autofixFeedback';
1313
import {AutofixSetupContent} from 'sentry/components/events/autofix/autofixSetupModal';
1414
import {AutofixSteps} from 'sentry/components/events/autofix/autofixSteps';
1515
import {useAiAutofix} from 'sentry/components/events/autofix/useAutofix';
16-
import {useAutofixSetup} from 'sentry/components/events/autofix/useAutofixSetup';
1716
import {DrawerBody, DrawerHeader} from 'sentry/components/globalDrawer/components';
1817
import {GroupSummary, useGroupSummary} from 'sentry/components/group/groupSummary';
1918
import HookOrDefault from 'sentry/components/hookOrDefault';
@@ -22,18 +21,15 @@ import LoadingIndicator from 'sentry/components/loadingIndicator';
2221
import {IconDocs} from 'sentry/icons';
2322
import {t, tct} from 'sentry/locale';
2423
import {space} from 'sentry/styles/space';
25-
import {EntryType, type Event} from 'sentry/types/event';
24+
import type {Event} from 'sentry/types/event';
2625
import type {Group} from 'sentry/types/group';
27-
import type {Organization} from 'sentry/types/organization';
2826
import type {Project} from 'sentry/types/project';
2927
import {getShortEventId} from 'sentry/utils/events';
3028
import {getConfigForIssueType} from 'sentry/utils/issueTypeConfig';
31-
import {getRegionDataFromOrganization} from 'sentry/utils/regions';
3229
import useRouteAnalyticsParams from 'sentry/utils/routeAnalytics/useRouteAnalyticsParams';
33-
import useOrganization from 'sentry/utils/useOrganization';
3430
import {MIN_NAV_HEIGHT} from 'sentry/views/issueDetails/streamline/eventTitle';
3531
import Resources from 'sentry/views/issueDetails/streamline/resources';
36-
import {useIsSampleEvent} from 'sentry/views/issueDetails/utils';
32+
import {useAiConfig} from 'sentry/views/issueDetails/streamline/useAiConfig';
3733

3834
interface AutofixStartBoxProps {
3935
groupId: string;
@@ -102,34 +98,6 @@ function AutofixStartBox({onSend, groupId}: AutofixStartBoxProps) {
10298
);
10399
}
104100

105-
const shouldDisplayAiAutofixForOrganization = (organization: Organization) => {
106-
return (
107-
organization.features.includes('gen-ai-features') &&
108-
organization.genAIConsent &&
109-
!organization.hideAiFeatures &&
110-
getRegionDataFromOrganization(organization)?.name !== 'de'
111-
);
112-
};
113-
114-
// Autofix requires the event to have stack trace frames in order to work correctly.
115-
export function hasStacktraceWithFrames(event: Event) {
116-
for (const entry of event.entries) {
117-
if (entry.type === EntryType.EXCEPTION) {
118-
if (entry.data.values?.some(value => value.stacktrace?.frames?.length)) {
119-
return true;
120-
}
121-
}
122-
123-
if (entry.type === EntryType.THREADS) {
124-
if (entry.data.values?.some(thread => thread.stacktrace?.frames?.length)) {
125-
return true;
126-
}
127-
}
128-
}
129-
130-
return false;
131-
}
132-
133101
interface SolutionsHubDrawerProps {
134102
event: Event;
135103
group: Group;
@@ -147,31 +115,15 @@ export function SolutionsHubDrawer({group, project, event}: SolutionsHubDrawerPr
147115
data: summaryData,
148116
isError,
149117
isPending: isSummaryLoading,
150-
} = useGroupSummary(group.id, group.issueCategory);
151-
const {data: setupData, isPending: isSetupLoading} = useAutofixSetup({
152-
groupId: group.id,
153-
});
118+
} = useGroupSummary(group, event, project);
119+
const aiConfig = useAiConfig(group, event, project);
154120

155121
useRouteAnalyticsParams({
156122
autofix_status: autofixData?.status ?? 'none',
157123
});
158124

159125
const config = getConfigForIssueType(group, project);
160126

161-
const hasConsent = Boolean(setupData?.genAIConsent.ok);
162-
const isAutofixSetupComplete = setupData?.integration.ok && hasConsent;
163-
164-
const hasSummary = (summaryData || isSummaryLoading) && !isError && hasConsent;
165-
166-
const organization = useOrganization();
167-
const isSampleError = useIsSampleEvent();
168-
169-
const displayAiAutofix =
170-
shouldDisplayAiAutofixForOrganization(organization) &&
171-
config.autofix &&
172-
hasStacktraceWithFrames(event) &&
173-
!isSampleError;
174-
175127
return (
176128
<SolutionsDrawerContainer className="solutions-drawer-container">
177129
<SolutionsDrawerHeader>
@@ -240,15 +192,15 @@ export function SolutionsHubDrawer({group, project, event}: SolutionsHubDrawerPr
240192
</ButtonBar>
241193
)}
242194
</HeaderText>
243-
{isSetupLoading ? (
195+
{aiConfig.isAutofixSetupLoading ? (
244196
<div data-test-id="ai-setup-loading-indicator">
245197
<LoadingIndicator />
246198
</div>
247-
) : !hasConsent ? (
199+
) : aiConfig.needsGenAIConsent ? (
248200
<AiSetupDataConsent groupId={group.id} />
249201
) : (
250202
<Fragment>
251-
{hasSummary && (
203+
{aiConfig.hasSummary && (
252204
<StyledCard>
253205
<GroupSummary
254206
data={summaryData}
@@ -257,9 +209,9 @@ export function SolutionsHubDrawer({group, project, event}: SolutionsHubDrawerPr
257209
/>
258210
</StyledCard>
259211
)}
260-
{displayAiAutofix && (
212+
{aiConfig.hasAutofix && (
261213
<Fragment>
262-
{!isAutofixSetupComplete ? (
214+
{aiConfig.needsAutofixSetup ? (
263215
<AutofixSetupContent groupId={group.id} projectId={project.id} />
264216
) : !autofixData ? (
265217
<AutofixStartBox onSend={triggerAutofix} groupId={group.id} />

static/app/views/issueDetails/streamline/solutionsSection.tsx

Lines changed: 20 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import styled from '@emotion/styled';
44
import FeatureBadge from 'sentry/components/badge/featureBadge';
55
import {Button} from 'sentry/components/button';
66
import {Chevron} from 'sentry/components/chevron';
7-
import {useAutofixSetup} from 'sentry/components/events/autofix/useAutofixSetup';
87
import useDrawer from 'sentry/components/globalDrawer';
98
import {GroupSummary, useGroupSummary} from 'sentry/components/group/groupSummary';
109
import Placeholder from 'sentry/components/placeholder';
@@ -15,15 +14,11 @@ import type {Group} from 'sentry/types/group';
1514
import type {Project} from 'sentry/types/project';
1615
import {getConfigForIssueType} from 'sentry/utils/issueTypeConfig';
1716
import {singleLineRenderer} from 'sentry/utils/marked';
18-
import {getRegionDataFromOrganization} from 'sentry/utils/regions';
19-
import useOrganization from 'sentry/utils/useOrganization';
2017
import Resources from 'sentry/views/issueDetails/streamline/resources';
2118
import {SidebarSectionTitle} from 'sentry/views/issueDetails/streamline/sidebar';
22-
import {
23-
hasStacktraceWithFrames,
24-
SolutionsHubDrawer,
25-
} from 'sentry/views/issueDetails/streamline/solutionsHubDrawer';
26-
import {useHasStreamlinedUI, useIsSampleEvent} from 'sentry/views/issueDetails/utils';
19+
import {SolutionsHubDrawer} from 'sentry/views/issueDetails/streamline/solutionsHubDrawer';
20+
import {useAiConfig} from 'sentry/views/issueDetails/streamline/useAiConfig';
21+
import {useHasStreamlinedUI} from 'sentry/views/issueDetails/utils';
2722

2823
export default function SolutionsSection({
2924
group,
@@ -34,7 +29,6 @@ export default function SolutionsSection({
3429
group: Group;
3530
project: Project;
3631
}) {
37-
const organization = useOrganization();
3832
const [isExpanded, setIsExpanded] = useState(false);
3933
const openButtonRef = useRef<HTMLButtonElement>(null);
4034
const {openDrawer} = useDrawer();
@@ -66,62 +60,39 @@ export default function SolutionsSection({
6660
);
6761
};
6862

69-
const hasGenAIConsent = organization.genAIConsent;
7063
const {
7164
data: summaryData,
7265
isPending: isSummaryLoading,
7366
isError: isSummaryError,
74-
} = useGroupSummary(group.id, group.issueCategory);
75-
const {data: autofixSetupData, isPending: isAutofixSetupLoading} = useAutofixSetup({
76-
groupId: group.id,
77-
});
67+
} = useGroupSummary(group, event, project);
7868

79-
const isSampleError = useIsSampleEvent();
80-
const hasStacktrace = event && hasStacktraceWithFrames(event);
69+
const aiConfig = useAiConfig(group, event, project);
8170

82-
const issueTypeConfig = getConfigForIssueType(group, group.project);
71+
const issueTypeConfig = getConfigForIssueType(group, project);
8372

84-
const areAiFeaturesAllowed =
85-
!organization.hideAiFeatures &&
86-
getRegionDataFromOrganization(organization)?.name !== 'de';
87-
88-
const isSummaryEnabled = issueTypeConfig.issueSummary.enabled;
89-
const isAutofixEnabled = issueTypeConfig.autofix;
90-
const hasResources = issueTypeConfig.resources;
91-
92-
const hasSummary = hasGenAIConsent && isSummaryEnabled && areAiFeaturesAllowed;
93-
const hasAutofix =
94-
isAutofixEnabled && areAiFeaturesAllowed && hasStacktrace && !isSampleError;
95-
96-
const needsGenAIConsent =
97-
!hasGenAIConsent && (isSummaryEnabled || isAutofixEnabled) && areAiFeaturesAllowed;
98-
99-
const needsAutofixSetup =
100-
isAutofixEnabled &&
101-
!isAutofixSetupLoading &&
102-
(!autofixSetupData?.genAIConsent.ok || !autofixSetupData?.integration.ok) &&
103-
areAiFeaturesAllowed;
104-
105-
const showCtaButton = needsGenAIConsent || hasAutofix || (hasSummary && hasResources);
106-
const isButtonLoading = isAutofixSetupLoading;
73+
const showCtaButton =
74+
aiConfig.needsGenAIConsent ||
75+
aiConfig.hasAutofix ||
76+
(aiConfig.hasSummary && aiConfig.hasResources);
77+
const isButtonLoading = aiConfig.isAutofixSetupLoading;
10778

10879
const getButtonText = () => {
109-
if (needsGenAIConsent) {
80+
if (aiConfig.needsGenAIConsent) {
11081
return t('Set up Sentry AI');
11182
}
11283

113-
if (isAutofixEnabled) {
114-
if (needsAutofixSetup) {
84+
if (aiConfig.hasAutofix) {
85+
if (aiConfig.needsAutofixSetup) {
11586
return t('Set up Autofix');
11687
}
117-
return hasResources ? t('Open Resources & Autofix') : t('Open Autofix');
88+
return aiConfig.hasResources ? t('Open Resources & Autofix') : t('Open Autofix');
11889
}
11990

12091
return t('Open Resources');
12192
};
12293

12394
const renderContent = () => {
124-
if (needsGenAIConsent) {
95+
if (aiConfig.needsGenAIConsent) {
12596
return (
12697
<Summary>
12798
<HeadlineText
@@ -135,7 +106,8 @@ export default function SolutionsSection({
135106
);
136107
}
137108

138-
if (hasSummary) {
109+
// Show the summary's loading state if we're still loading the autofix setup
110+
if (aiConfig.hasSummary) {
139111
return (
140112
<Summary>
141113
<GroupSummary
@@ -148,7 +120,7 @@ export default function SolutionsSection({
148120
);
149121
}
150122

151-
if (!hasSummary && hasResources) {
123+
if (!aiConfig.hasSummary && issueTypeConfig.resources) {
152124
return (
153125
<ResourcesWrapper isExpanded={isExpanded}>
154126
<ResourcesContent isExpanded={isExpanded}>
@@ -173,7 +145,7 @@ export default function SolutionsSection({
173145
<SidebarSectionTitle style={{marginTop: 0}}>
174146
<HeaderContainer>
175147
{t('Solutions Hub')}
176-
{hasSummary && (
148+
{aiConfig.hasSummary && (
177149
<StyledFeatureBadge
178150
type="beta"
179151
title={tct(

0 commit comments

Comments
 (0)