1
- import { useCallback , useRef } from 'react' ;
1
+ import { Fragment , type ReactElement , useCallback , useRef } from 'react' ;
2
+ import styled from '@emotion/styled' ;
2
3
import type { SeriesOption } from 'echarts' ;
3
4
import type { MarkLineOption } from 'echarts/types/dist/shared' ;
4
5
import type { EChartsInstance } from 'echarts-for-react' ;
5
6
7
+ import { DateTime } from 'sentry/components/dateTime' ;
6
8
import {
7
9
EventDrawerBody ,
8
10
EventDrawerContainer ,
@@ -12,10 +14,16 @@ import {
12
14
NavigationCrumbs ,
13
15
} from 'sentry/components/events/eventDrawer' ;
14
16
import { t , tn } from 'sentry/locale' ;
17
+ import { space } from 'sentry/styles/space' ;
15
18
import type { ReactEchartsRef , SeriesDataUnit } from 'sentry/types/echarts' ;
19
+ import type { ReleaseMetaBasic } from 'sentry/types/release' ;
20
+ import { useLocation } from 'sentry/utils/useLocation' ;
21
+ import { useNavigate } from 'sentry/utils/useNavigate' ;
16
22
import usePageFilters from 'sentry/utils/usePageFilters' ;
17
23
import { useReleaseStats } from 'sentry/utils/useReleaseStats' ;
18
24
import { formatVersion } from 'sentry/utils/versions/formatVersion' ;
25
+ import { Widget } from 'sentry/views/dashboards/widgets/widget/widget' ;
26
+ import type { ChartRendererProps } from 'sentry/views/releases/releaseBubbles/types' ;
19
27
20
28
import { ReleaseDrawerTable } from './releasesDrawerTable' ;
21
29
@@ -24,6 +32,14 @@ interface ReleasesDrawerListProps {
24
32
environments : readonly string [ ] ;
25
33
projects : readonly number [ ] ;
26
34
startTs : number ;
35
+ /**
36
+ * A renderer function that returns a chart. It is called with the trimmed
37
+ * list of releases and timeSeries. It currently uses the
38
+ * `TimeSeriesWidgetVisualization` components props. It's possible we change
39
+ * it to make the props more generic, e.g. pass start/end timestamps and do
40
+ * the series manipulation when we call the bubble hook.
41
+ */
42
+ chartRenderer ?: ( rendererProps : ChartRendererProps ) => ReactElement ;
27
43
}
28
44
29
45
type MarkLineDataCallbackFn = ( item : SeriesDataUnit ) => boolean ;
@@ -82,9 +98,12 @@ const unhighlightMarkLines = createMarkLineUpdater({});
82
98
export function ReleasesDrawerList ( {
83
99
startTs,
84
100
endTs,
101
+ chartRenderer,
85
102
projects,
86
103
environments,
87
104
} : ReleasesDrawerListProps ) {
105
+ const location = useLocation ( ) ;
106
+ const navigate = useNavigate ( ) ;
88
107
const start = new Date ( startTs ) ;
89
108
const end = new Date ( endTs ) ;
90
109
const pageFilters = usePageFilters ( ) ;
@@ -95,6 +114,18 @@ export function ReleasesDrawerList({
95
114
end : endTs ? new Date ( endTs ) . toISOString ( ) : null ,
96
115
} ,
97
116
} ) ;
117
+ const handleSelectRelease = useCallback (
118
+ ( nextSelectedRelease : string , projectId : string ) => {
119
+ navigate ( {
120
+ query : {
121
+ ...location . query ,
122
+ release : nextSelectedRelease ,
123
+ projectId,
124
+ } ,
125
+ } ) ;
126
+ } ,
127
+ [ navigate , location . query ]
128
+ ) ;
98
129
const chartRef = useRef < ReactEchartsRef | null > ( null ) ;
99
130
100
131
const handleMouseOverRelease = useCallback ( ( release : string ) => {
@@ -137,6 +168,42 @@ export function ReleasesDrawerList({
137
168
< Header > { title } </ Header >
138
169
</ EventNavigator >
139
170
< EventDrawerBody >
171
+ { chartRenderer ? (
172
+ < ChartContainer >
173
+ < Widget
174
+ Title = {
175
+ < Fragment >
176
+ { t ( 'Releases from ' ) }
177
+ < DateTime date = { start } /> < span > { t ( 'to' ) } </ span > < DateTime date = { end } />
178
+ </ Fragment >
179
+ }
180
+ Visualization = { chartRenderer ?.( {
181
+ ref : ( e : ReactEchartsRef | null ) => {
182
+ chartRef . current = e ;
183
+
184
+ if ( e ) {
185
+ // When chart is mounted, zoom the chart into the relevant
186
+ // bucket
187
+ e . getEchartsInstance ( ) . dispatchAction ( {
188
+ type : 'dataZoom' ,
189
+ batch : [
190
+ {
191
+ // data value at starting location
192
+ startValue : startTs ,
193
+ // data value at ending location
194
+ endValue : endTs ,
195
+ } ,
196
+ ] ,
197
+ } ) ;
198
+ }
199
+ } ,
200
+ releases,
201
+ start,
202
+ end,
203
+ } ) }
204
+ />
205
+ </ ChartContainer >
206
+ ) : null }
140
207
< ReleaseDrawerTable
141
208
projects = { projects }
142
209
environments = { environments }
@@ -149,3 +216,7 @@ export function ReleasesDrawerList({
149
216
</ EventDrawerContainer >
150
217
) ;
151
218
}
219
+
220
+ const ChartContainer = styled ( 'div' ) `
221
+ margin-bottom: ${ space ( 2 ) } ;
222
+ ` ;
0 commit comments