@@ -3,7 +3,9 @@ import styled from '@emotion/styled';
3
3
import { Alert } from 'sentry/components/core/alert' ;
4
4
import { Badge } from 'sentry/components/core/badge' ;
5
5
import { Button } from 'sentry/components/core/button' ;
6
+ import { LinkButton } from 'sentry/components/core/button/linkButton' ;
6
7
import { Flex } from 'sentry/components/core/layout' ;
8
+ import { useOrganizationSeerSetup } from 'sentry/components/events/autofix/useOrganizationSeerSetup' ;
7
9
import LoadingIndicator from 'sentry/components/loadingIndicator' ;
8
10
import { IconSeer , IconSync , IconThumb } from 'sentry/icons' ;
9
11
import { t } from 'sentry/locale' ;
@@ -23,6 +25,7 @@ export default function Ai() {
23
25
const replay = useReplayReader ( ) ;
24
26
const replayRecord = replay ?. getReplay ( ) ;
25
27
const project = useProjectFromId ( { project_id : replayRecord ?. project_id } ) ;
28
+ const { areAiFeaturesAllowed, setupAcknowledgement} = useOrganizationSeerSetup ( ) ;
26
29
const {
27
30
data : summaryData ,
28
31
isPending,
@@ -35,58 +38,56 @@ export default function Ai() {
35
38
replayRecord ?. id &&
36
39
project ?. slug &&
37
40
organization . features . includes ( 'replay-ai-summaries' ) &&
38
- organization . features . includes ( 'gen-ai-features' )
41
+ areAiFeaturesAllowed &&
42
+ setupAcknowledgement . orgHasAcknowledged
39
43
) ,
40
44
retry : false ,
41
45
} ) ;
42
46
43
- const openForm = useFeedbackForm ( ) ;
44
-
45
- const feedbackButton = ( { type} : { type : 'positive' | 'negative' } ) => {
46
- return openForm ? (
47
- < Button
48
- aria-label = { t ( 'Give feedback on the AI summary section' ) }
49
- icon = { < IconThumb direction = { type === 'positive' ? 'up' : 'down' } /> }
50
- title = { type === 'positive' ? t ( 'I like this' ) : t ( `I don't like this` ) }
51
- size = { 'xs' }
52
- onClick = { ( ) =>
53
- openForm ( {
54
- messagePlaceholder :
55
- type === 'positive'
56
- ? t ( 'What did you like about the AI summary and chapters?' )
57
- : t ( 'How can we make the AI summary and chapters work better for you?' ) ,
58
- tags : {
59
- [ 'feedback.source' ] : 'replay_ai_summary' ,
60
- [ 'feedback.owner' ] : 'replay' ,
61
- [ 'feedback.type' ] : type ,
62
- } ,
63
- } )
64
- }
65
- />
66
- ) : null ;
67
- } ;
68
-
69
- if (
70
- ! organization . features . includes ( 'replay-ai-summaries' ) ||
71
- ! organization . features . includes ( 'gen-ai-features' )
72
- ) {
47
+ if ( ! organization . features . includes ( 'replay-ai-summaries' ) || ! areAiFeaturesAllowed ) {
73
48
return (
74
49
< Wrapper data-test-id = "replay-details-ai-summary-tab" >
75
50
< EmptySummaryContainer >
76
- < Alert type = "info" showIcon = { false } >
77
- { t ( 'Replay AI summary is not available for this organization.' ) }
51
+ < Alert type = "warning" >
52
+ { t ( 'AI features are not available for this organization.' ) }
78
53
</ Alert >
79
54
</ EmptySummaryContainer >
80
55
</ Wrapper >
81
56
) ;
82
57
}
83
58
59
+ // If our `replay-ai-summaries` ff is enabled and the org has gen AI ff enabled,
60
+ // but the org hasn't acknowledged the gen AI features, then show CTA.
61
+ if ( ! setupAcknowledgement . orgHasAcknowledged ) {
62
+ return (
63
+ < Wrapper data-test-id = "replay-details-ai-summary-tab" >
64
+ < EmptySummaryContainer >
65
+ < CallToActionContainer >
66
+ < div >
67
+ < strong > { t ( 'AI-Powered Replay Summaries' ) } </ strong >
68
+ </ div >
69
+ < div >
70
+ { t (
71
+ 'Seer access is required to use replay summaries. Please view the Seer settings page for more information.'
72
+ ) }
73
+ </ div >
74
+ < div >
75
+ < LinkButton size = "sm" priority = "primary" to = "/settings/seer/" >
76
+ { t ( 'View Seer Settings' ) }
77
+ </ LinkButton >
78
+ </ div >
79
+ </ CallToActionContainer >
80
+ </ EmptySummaryContainer >
81
+ </ Wrapper >
82
+ ) ;
83
+ }
84
+
84
85
if ( replayRecord ?. project_id && ! project ) {
85
86
return (
86
87
< Wrapper data-test-id = "replay-details-ai-summary-tab" >
87
88
< EmptySummaryContainer >
88
- < Alert type = "error" showIcon = { false } >
89
- { t ( 'Project not found. Unable to load AI summary.' ) }
89
+ < Alert type = "error" >
90
+ { t ( 'Project not found. Unable to load replay summary.' ) }
90
91
</ Alert >
91
92
</ EmptySummaryContainer >
92
93
</ Wrapper >
@@ -107,9 +108,7 @@ export default function Ai() {
107
108
return (
108
109
< Wrapper data-test-id = "replay-details-ai-summary-tab" >
109
110
< EmptySummaryContainer >
110
- < Alert type = "error" showIcon = { false } >
111
- { t ( 'Failed to load AI summary' ) }
112
- </ Alert >
111
+ < Alert type = "error" > { t ( 'Failed to load replay summary' ) } </ Alert >
113
112
</ EmptySummaryContainer >
114
113
</ Wrapper >
115
114
) ;
@@ -142,8 +141,8 @@ export default function Ai() {
142
141
</ SummaryLeft >
143
142
< SummaryRight >
144
143
< Flex gap = { space ( 0.5 ) } >
145
- { feedbackButton ( { type : ' positive' } ) }
146
- { feedbackButton ( { type : ' negative' } ) }
144
+ < FeedbackButton type = " positive" />
145
+ < FeedbackButton type = " negative" />
147
146
</ Flex >
148
147
< Button
149
148
priority = "default"
@@ -170,6 +169,35 @@ export default function Ai() {
170
169
) ;
171
170
}
172
171
172
+ function FeedbackButton ( { type} : { type : 'positive' | 'negative' } ) {
173
+ const openForm = useFeedbackForm ( ) ;
174
+ if ( ! openForm ) {
175
+ return null ;
176
+ }
177
+
178
+ return (
179
+ < Button
180
+ aria-label = { t ( 'Give feedback on the replay summary section' ) }
181
+ icon = { < IconThumb direction = { type === 'positive' ? 'up' : 'down' } /> }
182
+ title = { type === 'positive' ? t ( 'I like this' ) : t ( `I don't like this` ) }
183
+ size = { 'xs' }
184
+ onClick = { ( ) =>
185
+ openForm ( {
186
+ messagePlaceholder :
187
+ type === 'positive'
188
+ ? t ( 'What did you like about the replay summary and chapters?' )
189
+ : t ( 'How can we make the replay summary and chapters work better for you?' ) ,
190
+ tags : {
191
+ [ 'feedback.source' ] : 'replay_ai_summary' ,
192
+ [ 'feedback.owner' ] : 'replay' ,
193
+ [ 'feedback.type' ] : type ,
194
+ } ,
195
+ } )
196
+ }
197
+ />
198
+ ) ;
199
+ }
200
+
173
201
const Wrapper = styled ( 'div' ) `
174
202
display: flex;
175
203
flex-direction: column;
@@ -248,3 +276,12 @@ const OverflowBody = styled('section')`
248
276
flex: 1 1 auto;
249
277
overflow: auto;
250
278
` ;
279
+
280
+ const CallToActionContainer = styled ( 'div' ) `
281
+ display: flex;
282
+ flex-direction: column;
283
+ gap: ${ space ( 2 ) } ;
284
+ padding: ${ space ( 2 ) } ;
285
+ align-items: center;
286
+ text-align: center;
287
+ ` ;
0 commit comments