1
- import { EuiProgress , EuiTab , EuiTabs } from '@elastic/eui'
2
- import React from 'react'
1
+ import { EuiProgress } from '@elastic/eui'
2
+ import React , { useCallback , useEffect , useMemo } from 'react'
3
3
import { useDispatch , useSelector } from 'react-redux'
4
+ import { isNull , last } from 'lodash'
5
+ import cx from 'classnames'
4
6
5
- import { streamSelector , setStreamViewType , streamGroupsSelector } from 'uiSrc/slices/browser/stream'
6
- import { connectedInstanceSelector } from 'uiSrc/slices/instances/instances'
7
+ import {
8
+ streamSelector ,
9
+ streamGroupsSelector ,
10
+ streamRangeSelector ,
11
+ streamDataSelector ,
12
+ fetchMoreStreamEntries ,
13
+ updateStart ,
14
+ updateEnd ,
15
+ fetchStreamEntries
16
+ } from 'uiSrc/slices/browser/stream'
7
17
import { StreamViewType } from 'uiSrc/slices/interfaces/stream'
8
18
9
- import { streamViewTypeTabs } from './constants'
19
+ import { connectedInstanceSelector } from 'uiSrc/slices/instances/instances'
20
+ import { getNextId , getTimestampFromId } from 'uiSrc/utils/streamUtils'
21
+ import { SortOrder } from 'uiSrc/constants'
22
+ import { SCAN_COUNT_DEFAULT } from 'uiSrc/constants/api'
23
+ import { selectedKeyDataSelector } from 'uiSrc/slices/browser/keys'
24
+ import { sendEventTelemetry , TelemetryEvent } from 'uiSrc/telemetry'
25
+ import { GetStreamEntriesResponse } from 'apiSrc/modules/browser/dto/stream.dto'
26
+ import RangeFilter from 'uiSrc/components/range-filter'
10
27
import ConsumersViewWrapper from './consumers-view'
11
28
import GroupsViewWrapper from './groups-view'
29
+ import MessagesViewWrapper from './messages-view'
12
30
import StreamDataViewWrapper from './stream-data-view'
13
31
import StreamTabs from './stream-tabs'
14
32
33
+ import styles from './styles.module.scss'
34
+
15
35
export interface Props {
16
36
isFooterOpen : boolean
17
37
}
18
38
19
39
const StreamDetailsWrapper = ( props : Props ) => {
20
- const { id : instanceId } = useSelector ( connectedInstanceSelector )
21
- const { viewType, loading } = useSelector ( streamSelector )
40
+ const { viewType, loading, sortOrder : entryColumnSortOrder } = useSelector ( streamSelector )
22
41
const { loading : loadingGroups } = useSelector ( streamGroupsSelector )
42
+ const { start, end } = useSelector ( streamRangeSelector )
43
+ const {
44
+ firstEntry,
45
+ lastEntry,
46
+ entries,
47
+ } = useSelector ( streamDataSelector )
48
+ const { name : key } = useSelector ( selectedKeyDataSelector ) ?? { name : '' }
49
+ const { id : instanceId } = useSelector ( connectedInstanceSelector )
23
50
24
51
const dispatch = useDispatch ( )
25
52
53
+ const firstEntryTimeStamp = useMemo ( ( ) => getTimestampFromId ( firstEntry ?. id ) , [ firstEntry ?. id ] )
54
+ const lastEntryTimeStamp = useMemo ( ( ) => getTimestampFromId ( lastEntry ?. id ) , [ lastEntry ?. id ] )
55
+
56
+ const startNumber = useMemo ( ( ) => ( start === '' ? 0 : parseInt ( start , 10 ) ) , [ start ] )
57
+ const endNumber = useMemo ( ( ) => ( end === '' ? 0 : parseInt ( end , 10 ) ) , [ end ] )
58
+
59
+ const shouldFilterRender = ! isNull ( firstEntry )
60
+ && ( firstEntry . id !== '' )
61
+ && ! isNull ( lastEntry )
62
+ && lastEntry . id !== ''
63
+
64
+ useEffect ( ( ) => {
65
+ if ( isNull ( firstEntry ) ) {
66
+ dispatch ( updateStart ( '' ) )
67
+ }
68
+ if ( start === '' && firstEntry ?. id !== '' ) {
69
+ dispatch ( updateStart ( firstEntryTimeStamp . toString ( ) ) )
70
+ }
71
+ } , [ firstEntryTimeStamp ] )
72
+
73
+ useEffect ( ( ) => {
74
+ if ( isNull ( lastEntry ) ) {
75
+ dispatch ( updateEnd ( '' ) )
76
+ }
77
+ if ( end === '' && lastEntry ?. id !== '' ) {
78
+ dispatch ( updateEnd ( lastEntryTimeStamp . toString ( ) ) )
79
+ }
80
+ } , [ lastEntryTimeStamp ] )
81
+
82
+ const loadMoreItems = ( ) => {
83
+ const lastLoadedEntryId = last ( entries ) ?. id
84
+ const lastLoadedEntryTimeStamp = getTimestampFromId ( lastLoadedEntryId )
85
+
86
+ const lastRangeEntryTimestamp = end ? parseInt ( end , 10 ) : getTimestampFromId ( lastEntry ?. id )
87
+ const firstRangeEntryTimestamp = start ? parseInt ( start , 10 ) : getTimestampFromId ( firstEntry ?. id )
88
+ const shouldLoadMore = ( ) => {
89
+ if ( ! lastLoadedEntryTimeStamp ) {
90
+ return false
91
+ }
92
+ return entryColumnSortOrder === SortOrder . ASC
93
+ ? lastLoadedEntryTimeStamp <= lastRangeEntryTimestamp
94
+ : lastLoadedEntryTimeStamp >= firstRangeEntryTimestamp
95
+ }
96
+ const nextId = getNextId ( lastLoadedEntryId , entryColumnSortOrder )
97
+
98
+ if ( shouldLoadMore ( ) ) {
99
+ dispatch (
100
+ fetchMoreStreamEntries (
101
+ key ,
102
+ entryColumnSortOrder === SortOrder . DESC ? start : nextId ,
103
+ entryColumnSortOrder === SortOrder . DESC ? nextId : end ,
104
+ SCAN_COUNT_DEFAULT ,
105
+ entryColumnSortOrder ,
106
+ )
107
+ )
108
+ }
109
+ }
110
+
111
+ const filterTelemetry = ( data : GetStreamEntriesResponse ) => {
112
+ sendEventTelemetry ( {
113
+ event : TelemetryEvent . STREAM_DATA_FILTERED ,
114
+ eventData : {
115
+ databaseId : instanceId ,
116
+ total : data . total ,
117
+ }
118
+ } )
119
+ }
120
+
121
+ const resetFilterTelemetry = ( data : GetStreamEntriesResponse ) => {
122
+ sendEventTelemetry ( {
123
+ event : TelemetryEvent . STREAM_DATA_FILTER_RESET ,
124
+ eventData : {
125
+ databaseId : instanceId ,
126
+ total : data . total ,
127
+ }
128
+ } )
129
+ }
130
+
131
+ const loadEntries = ( telemetryAction ?: ( data : GetStreamEntriesResponse ) => void ) => {
132
+ dispatch ( fetchStreamEntries (
133
+ key ,
134
+ SCAN_COUNT_DEFAULT ,
135
+ entryColumnSortOrder ,
136
+ false ,
137
+ telemetryAction
138
+ ) )
139
+ }
140
+
141
+ const handleChangeStartFilter = useCallback (
142
+ ( value : number , shouldSentEventTelemetry : boolean ) => {
143
+ dispatch ( updateStart ( value . toString ( ) ) )
144
+ loadEntries ( shouldSentEventTelemetry ? filterTelemetry : undefined )
145
+ } ,
146
+ [ ]
147
+ )
148
+
149
+ const handleChangeEndFilter = useCallback (
150
+ ( value : number , shouldSentEventTelemetry : boolean ) => {
151
+ dispatch ( updateEnd ( value . toString ( ) ) )
152
+ loadEntries ( shouldSentEventTelemetry ? filterTelemetry : undefined )
153
+ } ,
154
+ [ ]
155
+ )
156
+
157
+ const handleResetFilter = useCallback (
158
+ ( ) => {
159
+ dispatch ( updateStart ( firstEntryTimeStamp . toString ( ) ) )
160
+ dispatch ( updateEnd ( lastEntryTimeStamp . toString ( ) ) )
161
+ loadEntries ( resetFilterTelemetry )
162
+ } ,
163
+ [ lastEntryTimeStamp , firstEntryTimeStamp ]
164
+ )
165
+
166
+ const handleUpdateRangeMin = useCallback (
167
+ ( min : number ) => {
168
+ dispatch ( updateStart ( min . toString ( ) ) )
169
+ } ,
170
+ [ ]
171
+ )
172
+
173
+ const handleUpdateRangeMax = useCallback (
174
+ ( max : number ) => {
175
+ dispatch ( updateEnd ( max . toString ( ) ) )
176
+ } ,
177
+ [ ]
178
+ )
179
+
26
180
return (
27
- < >
181
+ < div className = { styles . container } >
28
182
{ ( loading || loadingGroups ) && (
29
183
< EuiProgress
30
184
color = "primary"
@@ -33,17 +187,38 @@ const StreamDetailsWrapper = (props: Props) => {
33
187
data-testid = "progress-key-stream"
34
188
/>
35
189
) }
190
+ { shouldFilterRender ? (
191
+ < RangeFilter
192
+ max = { lastEntryTimeStamp }
193
+ min = { firstEntryTimeStamp }
194
+ start = { startNumber }
195
+ end = { endNumber }
196
+ handleChangeStart = { handleChangeStartFilter }
197
+ handleChangeEnd = { handleChangeEndFilter }
198
+ handleResetFilter = { handleResetFilter }
199
+ handleUpdateRangeMax = { handleUpdateRangeMax }
200
+ handleUpdateRangeMin = { handleUpdateRangeMin }
201
+ />
202
+ )
203
+ : (
204
+ < div className = { styles . rangeWrapper } >
205
+ < div className = { cx ( styles . sliderTrack , styles . mockRange ) } />
206
+ </ div >
207
+ ) }
36
208
< StreamTabs />
37
209
{ viewType === StreamViewType . Data && (
38
- < StreamDataViewWrapper { ...props } />
210
+ < StreamDataViewWrapper loadMoreItems = { loadMoreItems } { ...props } />
39
211
) }
40
212
{ viewType === StreamViewType . Groups && (
41
213
< GroupsViewWrapper { ...props } />
42
214
) }
43
215
{ viewType === StreamViewType . Consumers && (
44
216
< ConsumersViewWrapper { ...props } />
45
217
) }
46
- </ >
218
+ { viewType === StreamViewType . Messages && (
219
+ < MessagesViewWrapper { ...props } />
220
+ ) }
221
+ </ div >
47
222
)
48
223
}
49
224
0 commit comments