1
1
import React from 'react' ;
2
2
import styled from 'react-emotion' ;
3
+ import { Location } from 'history' ;
3
4
4
- import { deepFreeze } from 'app/utils' ;
5
5
import { t } from 'app/locale' ;
6
6
import Count from 'app/components/count' ;
7
7
import DateTime from 'app/components/dateTime' ;
@@ -12,37 +12,28 @@ import getDynamicText from 'app/utils/getDynamicText';
12
12
import overflowEllipsis from 'app/styles/overflowEllipsis' ;
13
13
import pinIcon from 'app/../images/location-pin.png' ;
14
14
import space from 'app/styles/space' ;
15
- import { EventView } from 'app/types' ;
15
+ import { EventViewv1 , Organization } from 'app/types' ;
16
16
17
17
import { QueryLink } from './styles' ;
18
18
19
- // TODO(ts): add as const after babel upgrade
20
- export const MODAL_QUERY_KEYS = [ 'eventSlug' ] ;
19
+ export const MODAL_QUERY_KEYS = [ 'eventSlug' ] as const ;
21
20
export const PIN_ICON = `image://${ pinIcon } ` ;
22
- // TODO(ts): add as const after babel upgrade
23
- export const AGGREGATE_ALIASES = [ 'last_seen' , 'latest_event' ] ;
21
+ export const AGGREGATE_ALIASES = [ 'last_seen' , 'latest_event' ] as const ;
24
22
25
- // TODO(ts): eventually defer to TS compile-time check to ensure this is readonly instead
26
- // of deepfreezing it in runtime
27
- export const ALL_VIEWS : Readonly < Array < EventView > > = deepFreeze ( [
28
- {
29
- id : 'all' ,
30
- name : t ( 'All Events' ) ,
31
- data : {
32
- fields : [ 'title' , 'event.type' , 'project' , 'user' , 'timestamp' ] ,
33
- columnNames : [ 'title' , 'type' , 'project' , 'user' , 'time' ] ,
34
- sort : [ '-timestamp' ] ,
35
- } ,
36
- tags : [
37
- 'event.type' ,
38
- 'release' ,
39
- 'project.name' ,
40
- 'user.email' ,
41
- 'user.ip' ,
42
- 'environment' ,
43
- ] ,
44
- columnWidths : [ '3fr' , '80px' , '1fr' , '1fr' , '1.5fr' ] ,
23
+ export const DEFAULT_EVENT_VIEW_V1 : Readonly < EventViewv1 > = {
24
+ id : 'all' ,
25
+ name : t ( 'All Events' ) ,
26
+ data : {
27
+ fields : [ 'title' , 'event.type' , 'project' , 'user' , 'timestamp' ] ,
28
+ columnNames : [ 'title' , 'type' , 'project' , 'user' , 'time' ] ,
29
+ sort : [ '-timestamp' ] ,
45
30
} ,
31
+ tags : [ 'event.type' , 'release' , 'project.name' , 'user.email' , 'user.ip' , 'environment' ] ,
32
+ columnWidths : [ '3fr' , '80px' , '1fr' , '1fr' , '1.5fr' ] ,
33
+ } ;
34
+
35
+ export const ALL_VIEWS : Readonly < Array < EventViewv1 > > = [
36
+ DEFAULT_EVENT_VIEW_V1 ,
46
37
{
47
38
id : 'errors' ,
48
39
name : t ( 'Errors' ) ,
@@ -92,14 +83,47 @@ export const ALL_VIEWS: Readonly<Array<EventView>> = deepFreeze([
92
83
] ,
93
84
columnWidths : [ '3fr' , '1fr' , '70px' ] ,
94
85
} ,
95
- ] ) ;
86
+ ] ;
87
+
88
+ type EventData = { [ key : string ] : any } ;
89
+
90
+ type RenderFunctionBaggage = {
91
+ organization : Organization ;
92
+ location : Location ;
93
+ } ;
94
+
95
+ type FieldFormatterRenderFunction = (
96
+ field : string ,
97
+ data : EventData ,
98
+ baggage : RenderFunctionBaggage
99
+ ) => React . ReactNode ;
100
+
101
+ export type FieldFormatterRenderFunctionPartial = (
102
+ data : EventData ,
103
+ baggage : RenderFunctionBaggage
104
+ ) => React . ReactNode ;
105
+
106
+ type FieldFormatter = {
107
+ sortField : boolean ;
108
+ renderFunc : FieldFormatterRenderFunction ;
109
+ } ;
110
+
111
+ type FieldFormatters = {
112
+ boolean : FieldFormatter ;
113
+ integer : FieldFormatter ;
114
+ number : FieldFormatter ;
115
+ date : FieldFormatter ;
116
+ string : FieldFormatter ;
117
+ } ;
118
+
119
+ export type FieldTypes = keyof FieldFormatters ;
96
120
97
121
/**
98
122
* A mapping of field types to their rendering function.
99
123
* This mapping is used when a field is not defined in SPECIAL_FIELDS
100
124
* This mapping should match the output sentry.utils.snuba:get_json_type
101
125
*/
102
- export const FIELD_FORMATTERS = {
126
+ export const FIELD_FORMATTERS : FieldFormatters = {
103
127
boolean : {
104
128
sortField : true ,
105
129
renderFunc : ( field , data , { organization, location} ) => {
@@ -160,12 +184,31 @@ export const FIELD_FORMATTERS = {
160
184
} ,
161
185
} ;
162
186
187
+ type SpecialFieldRenderFunc = (
188
+ data : EventData ,
189
+ baggage : RenderFunctionBaggage
190
+ ) => React . ReactNode ;
191
+
192
+ type SpecialField = {
193
+ sortField : string | null ;
194
+ renderFunc : SpecialFieldRenderFunc ;
195
+ } ;
196
+
197
+ type SpecialFields = {
198
+ transaction : SpecialField ;
199
+ title : SpecialField ;
200
+ 'event.type' : SpecialField ;
201
+ project : SpecialField ;
202
+ user : SpecialField ;
203
+ last_seen : SpecialField ;
204
+ } ;
205
+
163
206
/**
164
207
* "Special fields" do not map 1:1 to an single column in the event database,
165
208
* they are a UI concept that combines the results of multiple fields and
166
209
* displays with a custom render function.
167
210
*/
168
- export const SPECIAL_FIELDS = {
211
+ export const SPECIAL_FIELDS : SpecialFields = {
169
212
transaction : {
170
213
sortField : 'transaction' ,
171
214
renderFunc : ( data , { location} ) => {
@@ -203,7 +246,7 @@ export const SPECIAL_FIELDS = {
203
246
) ;
204
247
} ,
205
248
} ,
206
- type : {
249
+ 'event. type' : {
207
250
sortField : 'event.type' ,
208
251
renderFunc : ( data , { location} ) => {
209
252
const target = {
@@ -218,7 +261,7 @@ export const SPECIAL_FIELDS = {
218
261
} ,
219
262
} ,
220
263
project : {
221
- sortField : false ,
264
+ sortField : null ,
222
265
renderFunc : ( data , { organization} ) => {
223
266
const project = organization . projects . find ( p => p . slug === data [ 'project.name' ] ) ;
224
267
return (
0 commit comments