@@ -9,6 +9,7 @@ import {CopyToClipboardButton} from 'sentry/components/copyToClipboardButton';
9
9
import { Alert } from 'sentry/components/core/alert' ;
10
10
import { Button } from 'sentry/components/core/button' ;
11
11
import {
12
+ type AutofixFeedback ,
12
13
type AutofixRepository ,
13
14
type AutofixRootCauseData ,
14
15
type AutofixRootCauseSelection ,
@@ -20,13 +21,15 @@ import {
20
21
type AutofixResponse ,
21
22
makeAutofixQueryKey ,
22
23
} from 'sentry/components/events/autofix/useAutofix' ;
23
- import { IconCheckmark , IconClose , IconEdit , IconFocus } from 'sentry/icons' ;
24
+ import { IconCheckmark , IconClose , IconFocus , IconInput , IconThumb } from 'sentry/icons' ;
24
25
import { t } from 'sentry/locale' ;
25
26
import { space } from 'sentry/styles/space' ;
26
27
import { singleLineRenderer } from 'sentry/utils/marked' ;
27
28
import { setApiQueryData , useMutation , useQueryClient } from 'sentry/utils/queryClient' ;
28
29
import testableTransition from 'sentry/utils/testableTransition' ;
29
30
import useApi from 'sentry/utils/useApi' ;
31
+ import { useFeedbackForm } from 'sentry/utils/useFeedbackForm' ;
32
+ import { Divider } from 'sentry/views/issueDetails/divider' ;
30
33
31
34
import AutofixHighlightPopup from './autofixHighlightPopup' ;
32
35
import { AutofixTimeline } from './autofixTimeline' ;
@@ -39,6 +42,7 @@ type AutofixRootCauseProps = {
39
42
rootCauseSelection : AutofixRootCauseSelection ;
40
43
runId : string ;
41
44
agentCommentThread ?: CommentThread ;
45
+ feedback ?: AutofixFeedback ;
42
46
previousDefaultStepIndex ?: number ;
43
47
previousInsightCount ?: number ;
44
48
terminationReason ?: string ;
@@ -144,6 +148,59 @@ export function useSelectCause({groupId, runId}: {groupId: string; runId: string
144
148
} ) ;
145
149
}
146
150
151
+ export function useUpdateRootCauseFeedback ( {
152
+ groupId,
153
+ runId,
154
+ } : {
155
+ groupId : string ;
156
+ runId : string ;
157
+ } ) {
158
+ const api = useApi ( ) ;
159
+ const queryClient = useQueryClient ( ) ;
160
+
161
+ return useMutation ( {
162
+ mutationFn : ( params : { action : 'root_cause_thumbs_up' | 'root_cause_thumbs_down' } ) => {
163
+ return api . requestPromise ( `/issues/${ groupId } /autofix/update/` , {
164
+ method : 'POST' ,
165
+ data : {
166
+ run_id : runId ,
167
+ payload : {
168
+ type : 'feedback' ,
169
+ action : params . action ,
170
+ } ,
171
+ } ,
172
+ } ) ;
173
+ } ,
174
+ onMutate : params => {
175
+ queryClient . setQueryData ( makeAutofixQueryKey ( groupId ) , ( data : AutofixResponse ) => {
176
+ if ( ! data || ! data . autofix ) {
177
+ return data ;
178
+ }
179
+
180
+ return {
181
+ ...data ,
182
+ autofix : {
183
+ ...data . autofix ,
184
+ feedback : {
185
+ ...data . autofix . feedback ,
186
+ root_cause_thumbs_up : params . action === 'root_cause_thumbs_up' ,
187
+ root_cause_thumbs_down : params . action === 'root_cause_thumbs_down' ,
188
+ } ,
189
+ } ,
190
+ } ;
191
+ } ) ;
192
+ } ,
193
+ onSuccess : ( ) => {
194
+ queryClient . invalidateQueries ( {
195
+ queryKey : makeAutofixQueryKey ( groupId ) ,
196
+ } ) ;
197
+ } ,
198
+ onError : ( ) => {
199
+ addErrorMessage ( t ( 'Something went wrong when updating the root cause feedback.' ) ) ;
200
+ } ,
201
+ } ) ;
202
+ }
203
+
147
204
export function replaceHeadersWithBold ( markdown : string ) {
148
205
const headerRegex = / ^ ( # { 1 , 6 } ) \s + ( .* ) $ / gm;
149
206
const boldMarkdown = markdown . replace ( headerRegex , ( _match , _hashes , content ) => {
@@ -201,7 +258,7 @@ function RootCauseDescription({
201
258
) ;
202
259
}
203
260
204
- function formatRootCauseText (
261
+ export function formatRootCauseText (
205
262
cause : AutofixRootCauseData | undefined ,
206
263
customRootCause ?: string
207
264
) {
@@ -259,9 +316,74 @@ function CopyRootCauseButton({
259
316
return null ;
260
317
}
261
318
const text = formatRootCauseText ( cause , customRootCause ) ;
262
- return < CopyToClipboardButton size = "sm" text = { text } borderless /> ;
319
+ return (
320
+ < CopyToClipboardButton
321
+ size = "sm"
322
+ text = { text }
323
+ borderless
324
+ title = "Copy root cause as Markdown"
325
+ />
326
+ ) ;
263
327
}
264
328
329
+ function ThumbsUpDownButtons ( {
330
+ feedback,
331
+ groupId,
332
+ runId,
333
+ } : {
334
+ groupId : string ;
335
+ runId : string ;
336
+ feedback ?: AutofixFeedback ;
337
+ } ) {
338
+ const { mutate : handleUpdateRootCauseFeedback } = useUpdateRootCauseFeedback ( {
339
+ groupId,
340
+ runId,
341
+ } ) ;
342
+ const openForm = useFeedbackForm ( ) ;
343
+
344
+ return (
345
+ < ButtonBar >
346
+ < Button
347
+ size = "sm"
348
+ borderless
349
+ onClick = { ( ) => handleUpdateRootCauseFeedback ( { action : 'root_cause_thumbs_up' } ) }
350
+ title = { t ( 'This root cause analysis is helpful' ) }
351
+ >
352
+ {
353
+ < IconThumb
354
+ color = { feedback ?. root_cause_thumbs_up ? 'green400' : 'gray300' }
355
+ size = "sm"
356
+ direction = "up"
357
+ fill = "red"
358
+ />
359
+ }
360
+ </ Button >
361
+ < Button
362
+ size = "sm"
363
+ borderless
364
+ onClick = { ( ) => {
365
+ handleUpdateRootCauseFeedback ( { action : 'root_cause_thumbs_down' } ) ;
366
+ openForm ?.( {
367
+ messagePlaceholder : t ( 'How can we make Autofix better for you?' ) ,
368
+ tags : {
369
+ [ 'feedback.source' ] : 'issue_details_ai_autofix_root_cause' ,
370
+ [ 'feedback.owner' ] : 'ml-ai' ,
371
+ } ,
372
+ } ) ;
373
+ } }
374
+ title = { t ( 'This root cause is incorrect or not helpful' ) }
375
+ >
376
+ {
377
+ < IconThumb
378
+ color = { feedback ?. root_cause_thumbs_down ? 'red400' : 'gray300' }
379
+ size = "sm"
380
+ direction = "down"
381
+ />
382
+ }
383
+ </ Button >
384
+ </ ButtonBar >
385
+ ) ;
386
+ }
265
387
function AutofixRootCauseDisplay ( {
266
388
causes,
267
389
groupId,
@@ -270,6 +392,7 @@ function AutofixRootCauseDisplay({
270
392
previousDefaultStepIndex,
271
393
previousInsightCount,
272
394
agentCommentThread,
395
+ feedback,
273
396
} : AutofixRootCauseProps ) {
274
397
const { mutate : handleContinue , isPending} = useSelectCause ( { groupId, runId} ) ;
275
398
const [ isEditing , setIsEditing ] = useState ( false ) ;
@@ -318,6 +441,10 @@ function AutofixRootCauseDisplay({
318
441
{ t ( 'Root Cause' ) }
319
442
</ HeaderText >
320
443
< ButtonBar >
444
+ < ThumbsUpDownButtons feedback = { feedback } groupId = { groupId } runId = { runId } />
445
+ < DividerWrapper >
446
+ < Divider />
447
+ </ DividerWrapper >
321
448
< CopyRootCauseButton cause = { cause } isEditing = { isEditing } />
322
449
< EditButton
323
450
size = "sm"
@@ -333,7 +460,7 @@ function AutofixRootCauseDisplay({
333
460
}
334
461
} }
335
462
>
336
- { isEditing ? < IconClose size = "sm" /> : < IconEdit size = "sm" /> }
463
+ { isEditing ? < IconClose size = "sm" /> : < IconInput size = "sm" /> }
337
464
</ EditButton >
338
465
{ isEditing && (
339
466
< Button
@@ -503,3 +630,7 @@ const TextArea = styled('textarea')`
503
630
const EditButton = styled ( Button ) `
504
631
color: ${ p => p . theme . subText } ;
505
632
` ;
633
+
634
+ const DividerWrapper = styled ( 'div' ) `
635
+ margin: 0 ${ space ( 1 ) } ;
636
+ ` ;
0 commit comments