1
- import type { ReactNode } from 'react' ;
2
1
import { Fragment , useEffect , useRef } from 'react' ;
3
2
import { useTheme } from '@emotion/react' ;
4
3
import styled from '@emotion/styled' ;
5
4
6
5
import { openNavigateToExternalLinkModal } from 'sentry/actionCreators/modal' ;
7
6
import AnalyticsArea from 'sentry/components/analyticsArea' ;
8
7
import ErrorBoundary from 'sentry/components/errorBoundary' ;
8
+ import { getOrderedContextItems } from 'sentry/components/events/contexts' ;
9
+ import ContextCard from 'sentry/components/events/contexts/contextCard' ;
10
+ import EventTagsTree from 'sentry/components/events/eventTags/eventTagsTree' ;
9
11
import CrashReportSection from 'sentry/components/feedback/feedbackItem/crashReportSection' ;
10
12
import FeedbackActivitySection from 'sentry/components/feedback/feedbackItem/feedbackActivitySection' ;
11
13
import FeedbackItemHeader from 'sentry/components/feedback/feedbackItem/feedbackItemHeader' ;
12
- import Section from 'sentry/components/feedback/feedbackItem/feedbackItemSection' ;
14
+ import FeedbackItemSection from 'sentry/components/feedback/feedbackItem/feedbackItemSection' ;
13
15
import FeedbackReplay from 'sentry/components/feedback/feedbackItem/feedbackReplay' ;
14
16
import MessageSection from 'sentry/components/feedback/feedbackItem/messageSection' ;
15
- import TagsSection from 'sentry/components/feedback/feedbackItem/tagsSection' ;
16
17
import TraceDataSection from 'sentry/components/feedback/feedbackItem/traceDataSection' ;
18
+ import { KeyValueData } from 'sentry/components/keyValueData' ;
17
19
import PanelItem from 'sentry/components/panels/panelItem' ;
18
20
import QuestionTooltip from 'sentry/components/questionTooltip' ;
19
21
import TextCopyInput from 'sentry/components/textCopyInput' ;
@@ -22,16 +24,16 @@ import {t} from 'sentry/locale';
22
24
import { space } from 'sentry/styles/space' ;
23
25
import type { Event } from 'sentry/types/event' ;
24
26
import type { Group } from 'sentry/types/group' ;
27
+ import type { Project } from 'sentry/types/project' ;
25
28
import type { FeedbackIssue } from 'sentry/utils/feedback/types' ;
26
29
import useOrganization from 'sentry/utils/useOrganization' ;
27
30
28
31
interface Props {
29
32
eventData : Event | undefined ;
30
33
feedbackItem : FeedbackIssue ;
31
- tags : Record < string , string | ReactNode > ;
32
34
}
33
35
34
- export default function FeedbackItem ( { feedbackItem, eventData, tags } : Props ) {
36
+ export default function FeedbackItem ( { feedbackItem, eventData} : Props ) {
35
37
const organization = useOrganization ( ) ;
36
38
const url =
37
39
eventData ?. contexts ?. feedback ?. url ??
@@ -59,12 +61,17 @@ export default function FeedbackItem({feedbackItem, eventData, tags}: Props) {
59
61
< AnalyticsArea name = "details" >
60
62
< FeedbackItemHeader eventData = { eventData } feedbackItem = { feedbackItem } />
61
63
< OverflowPanelItem ref = { overflowRef } >
62
- < Section >
64
+ < FeedbackItemSection sectionKey = "message" >
63
65
< MessageSection eventData = { eventData } feedbackItem = { feedbackItem } />
64
- </ Section >
66
+ </ FeedbackItemSection >
65
67
66
68
{ ! crashReportId || ( crashReportId && url ) ? (
67
- < Section icon = { < IconLink size = "xs" /> } title = { t ( 'URL' ) } >
69
+ < FeedbackItemSection
70
+ collapsible
71
+ icon = { < IconLink size = "xs" /> }
72
+ sectionKey = "url"
73
+ title = { t ( 'URL' ) }
74
+ >
68
75
< TextCopyInput
69
76
style = { urlIsLink ? { color : theme . blue400 } : undefined }
70
77
onClick = {
@@ -78,19 +85,24 @@ export default function FeedbackItem({feedbackItem, eventData, tags}: Props) {
78
85
>
79
86
{ displayUrl }
80
87
</ TextCopyInput >
81
- </ Section >
88
+ </ FeedbackItemSection >
82
89
) : null }
83
90
84
91
{ crashReportId && feedbackItem . project ? (
85
- < Section icon = { < IconFire size = "xs" /> } title = { t ( 'Linked Error' ) } >
92
+ < FeedbackItemSection
93
+ collapsible
94
+ icon = { < IconFire size = "xs" /> }
95
+ sectionKey = "crash-report"
96
+ title = { t ( 'Linked Error' ) }
97
+ >
86
98
< ErrorBoundary mini >
87
99
< CrashReportSection
88
100
organization = { organization }
89
101
crashReportId = { crashReportId }
90
102
projectSlug = { feedbackItem . project . slug }
91
103
/>
92
104
</ ErrorBoundary >
93
- </ Section >
105
+ </ FeedbackItemSection >
94
106
) : null }
95
107
96
108
< FeedbackReplay
@@ -105,13 +117,41 @@ export default function FeedbackItem({feedbackItem, eventData, tags}: Props) {
105
117
</ ErrorBoundary >
106
118
) : null }
107
119
108
- < Section icon = { < IconTag size = "xs" /> } title = { t ( 'Tags' ) } >
109
- < TagsSection tags = { tags } />
110
- </ Section >
120
+ { eventData && feedbackItem . project ? (
121
+ < FeedbackItemSection
122
+ collapsible
123
+ icon = { < IconTag size = "xs" /> }
124
+ sectionKey = "tags"
125
+ title = { t ( 'Tags' ) }
126
+ >
127
+ < EventTagsTree
128
+ event = { eventData }
129
+ projectSlug = { feedbackItem . project . slug }
130
+ tags = { eventData . tags }
131
+ />
132
+ </ FeedbackItemSection >
133
+ ) : null }
134
+
135
+ { eventData ? (
136
+ < FeedbackItemSection
137
+ collapsible
138
+ icon = { < IconTag size = "xs" /> }
139
+ sectionKey = "context"
140
+ title = { t ( 'Context' ) }
141
+ >
142
+ < FeedbackItemContexts
143
+ feedbackItem = { feedbackItem }
144
+ eventData = { eventData }
145
+ project = { feedbackItem . project }
146
+ />
147
+ </ FeedbackItemSection >
148
+ ) : null }
111
149
112
150
{ feedbackItem . project ? (
113
- < Section
151
+ < FeedbackItemSection
152
+ collapsible
114
153
icon = { < IconChat size = "xs" /> }
154
+ sectionKey = "activity"
115
155
title = {
116
156
< Fragment >
117
157
{ t ( 'Internal Activity' ) }
@@ -125,14 +165,48 @@ export default function FeedbackItem({feedbackItem, eventData, tags}: Props) {
125
165
}
126
166
>
127
167
< FeedbackActivitySection feedbackItem = { feedbackItem as unknown as Group } />
128
- </ Section >
168
+ </ FeedbackItemSection >
129
169
) : null }
130
170
</ OverflowPanelItem >
131
171
</ AnalyticsArea >
132
172
</ Fragment >
133
173
) ;
134
174
}
135
175
176
+ function FeedbackItemContexts ( {
177
+ eventData,
178
+ feedbackItem,
179
+ project,
180
+ } : {
181
+ eventData : Event ;
182
+ feedbackItem : FeedbackIssue ;
183
+ project : undefined | Project ;
184
+ } ) {
185
+ const cards = getOrderedContextItems ( eventData ) . map (
186
+ ( { alias, type, value : contextValue } ) => (
187
+ < ContextCard
188
+ key = { alias }
189
+ type = { type }
190
+ alias = { alias }
191
+ value = { contextValue }
192
+ event = { eventData }
193
+ group = { feedbackItem as unknown as Group }
194
+ project = { project }
195
+ />
196
+ )
197
+ ) ;
198
+
199
+ if ( ! cards . length ) {
200
+ return null ;
201
+ }
202
+
203
+ return (
204
+ < ErrorBoundary mini message = { t ( 'There was a problem loading event context.' ) } >
205
+ < KeyValueData . Container > { cards } </ KeyValueData . Container >
206
+ </ ErrorBoundary >
207
+ ) ;
208
+ }
209
+
136
210
// 0 padding-bottom because <ActivitySection> has space(2) built-in.
137
211
const OverflowPanelItem = styled ( PanelItem ) `
138
212
overflow: auto;
0 commit comments