1
1
import React from 'react' ;
2
2
3
3
import { NoSearchResults } from '@gravity-ui/illustrations' ;
4
+ import { skipToken } from '@reduxjs/toolkit/query' ;
5
+ import { isNil } from 'lodash' ;
4
6
5
7
import type { RenderControls } from '../../../../components/PaginatedTable' ;
6
8
import { ResizeablePaginatedTable } from '../../../../components/PaginatedTable' ;
7
9
import { partitionsApi } from '../../../../store/reducers/partitions/partitions' ;
8
- import type { TopicMessageMetadataItem } from '../../../../types/api/topic' ;
10
+ import { topicApi } from '../../../../store/reducers/topic' ;
11
+ import type { TopicDataRequest , TopicMessageMetadataItem } from '../../../../types/api/topic' ;
9
12
import { useAutoRefreshInterval } from '../../../../utils/hooks' ;
10
13
import { useSelectedColumns } from '../../../../utils/hooks/useSelectedColumns' ;
11
14
import { renderPaginatedTableErrorMessage } from '../../../../utils/renderPaginatedTableErrorMessage' ;
@@ -38,8 +41,8 @@ interface TopicDataProps {
38
41
39
42
export function TopicData ( { parentRef, path, database} : TopicDataProps ) {
40
43
const [ autoRefreshInterval ] = useAutoRefreshInterval ( ) ;
41
- const [ startOffset , setStartOffset ] = React . useState < number | undefined > ( undefined ) ;
42
- const [ endOffset , setEndOffset ] = React . useState < number | undefined > ( undefined ) ;
44
+ const [ startOffset , setStartOffset ] = React . useState ( 0 ) ;
45
+ const [ endOffset , setEndOffset ] = React . useState ( 0 ) ;
43
46
const [ fullValue , setFullValue ] = React . useState <
44
47
string | TopicMessageMetadataItem [ ] | undefined
45
48
> ( undefined ) ;
@@ -52,8 +55,24 @@ export function TopicData({parentRef, path, database}: TopicDataProps) {
52
55
topicDataFilter,
53
56
handleSelectedOffsetChange,
54
57
handleStartTimestampChange,
58
+ handleSelectedPartitionChange,
55
59
} = useTopicDataQueryParams ( ) ;
56
60
61
+ const queryParams = React . useMemo ( ( ) => {
62
+ if ( isNil ( selectedPartition ) ) {
63
+ return skipToken ;
64
+ }
65
+ const params : TopicDataRequest = { database, path, partition : selectedPartition , limit : 1 } ;
66
+ if ( startTimestamp ) {
67
+ params . read_timestamp = startTimestamp ;
68
+ } else {
69
+ params . offset = selectedOffset ?? 0 ;
70
+ }
71
+ return params ;
72
+ } , [ selectedPartition , selectedOffset , startTimestamp , database , path ] ) ;
73
+
74
+ const { currentData, isFetching} = topicApi . useGetTopicDataQuery ( queryParams ) ;
75
+
57
76
const {
58
77
data : partitions ,
59
78
isLoading : partitionsLoading ,
@@ -74,16 +93,19 @@ export function TopicData({parentRef, path, database}: TopicDataProps) {
74
93
}
75
94
} , [ selectedPartition , partitions ] ) ;
76
95
77
- const tableFilters = React . useMemo ( ( ) => {
78
- return {
79
- path,
80
- database,
81
- partition : selectedPartition ?? '' ,
82
- selectedOffset : safeParseNumber ( selectedOffset ) ,
83
- startTimestamp : safeParseNumber ( startTimestamp ) ,
84
- topicDataFilter,
85
- } ;
86
- } , [ path , database , selectedPartition , selectedOffset , startTimestamp , topicDataFilter ] ) ;
96
+ React . useEffect ( ( ) => {
97
+ if ( partitions && partitions . length && isNil ( selectedPartition ) ) {
98
+ handleSelectedPartitionChange ( partitions [ 0 ] . partitionId ) ;
99
+ handleSelectedOffsetChange ( undefined ) ;
100
+ handleStartTimestampChange ( undefined ) ;
101
+ }
102
+ } , [
103
+ partitions ,
104
+ selectedPartition ,
105
+ handleSelectedPartitionChange ,
106
+ handleSelectedOffsetChange ,
107
+ handleStartTimestampChange ,
108
+ ] ) ;
87
109
88
110
const { columnsToShow, columnsToSelect, setColumns} = useSelectedColumns (
89
111
getAllColumns ( setFullValue ) ,
@@ -93,6 +115,59 @@ export function TopicData({parentRef, path, database}: TopicDataProps) {
93
115
REQUIRED_TOPIC_DATA_COLUMNS ,
94
116
) ;
95
117
118
+ const emptyData = React . useMemo ( ( ) => ! currentData ?. Messages ?. length , [ currentData ] ) ;
119
+
120
+ const tableFilters = React . useMemo ( ( ) => {
121
+ return {
122
+ path,
123
+ database,
124
+ partition : selectedPartition ?? '' ,
125
+ isEmpty : emptyData ,
126
+ } ;
127
+ } , [ path , database , selectedPartition , emptyData ] ) ;
128
+
129
+ const scrollToOffset = React . useCallback (
130
+ ( newOffset : number ) => {
131
+ const scrollTop = ( newOffset - ( startOffset ?? 0 ) ) * 41 ;
132
+ const normalizedScrollTop = Math . max ( 0 , scrollTop ) ;
133
+ parentRef . current ?. scrollTo ( {
134
+ top : normalizedScrollTop ,
135
+ behavior : 'instant' ,
136
+ } ) ;
137
+ } ,
138
+ [ startOffset , parentRef ] ,
139
+ ) ;
140
+
141
+ React . useEffect ( ( ) => {
142
+ if ( isFetching ) {
143
+ return ;
144
+ }
145
+ const messages = currentData ?. Messages ;
146
+ if ( messages ?. length ) {
147
+ const messageOffset = safeParseNumber ( messages [ 0 ] . Offset ) ;
148
+ //scroll when table is already rendered and calculated it's state
149
+ setTimeout ( ( ) => {
150
+ scrollToOffset ( messageOffset ) ;
151
+ } , 0 ) ;
152
+ }
153
+ } , [ currentData , isFetching , scrollToOffset ] ) ;
154
+
155
+ const scrollToStartOffset = React . useCallback ( ( ) => {
156
+ parentRef . current ?. scrollTo ( {
157
+ top : 0 ,
158
+ behavior : 'smooth' ,
159
+ } ) ;
160
+ } , [ parentRef ] ) ;
161
+
162
+ const scrollToEndOffset = React . useCallback ( ( ) => {
163
+ if ( parentRef . current ) {
164
+ parentRef . current . scrollTo ( {
165
+ top : parentRef . current . scrollHeight - parentRef . current . clientHeight ,
166
+ behavior : 'smooth' ,
167
+ } ) ;
168
+ }
169
+ } , [ parentRef ] ) ;
170
+
96
171
const renderControls : RenderControls = ( ) => {
97
172
return (
98
173
< TopicDataControls
@@ -105,6 +180,8 @@ export function TopicData({parentRef, path, database}: TopicDataProps) {
105
180
partitionsError = { partitionsError }
106
181
initialOffset = { startOffset }
107
182
endOffset = { endOffset }
183
+ scrollToStartOffset = { scrollToStartOffset }
184
+ scrollToEndOffset = { scrollToEndOffset }
108
185
/>
109
186
) ;
110
187
} ;
@@ -132,19 +209,22 @@ export function TopicData({parentRef, path, database}: TopicDataProps) {
132
209
) ;
133
210
} ;
134
211
212
+ const getTopicData = React . useMemo (
213
+ ( ) => generateTopicDataGetter ( { setEndOffset, setStartOffset} ) ,
214
+ [ ] ,
215
+ ) ;
216
+
135
217
return (
136
218
< React . Fragment >
137
219
< FullValue value = { fullValue } onClose = { ( ) => setFullValue ( undefined ) } />
138
220
< ResizeablePaginatedTable
139
221
columnsWidthLSKey = { TOPIC_DATA_COLUMNS_WIDTH_LS_KEY }
140
222
parentRef = { parentRef }
141
223
columns = { columnsToShow }
142
- fetchData = { generateTopicDataGetter ( {
143
- setStartOffset,
144
- setEndOffset,
145
- initialOffset : startOffset ,
146
- } ) }
224
+ fetchData = { getTopicData }
225
+ initialEntitiesCount = { endOffset - startOffset }
147
226
limit = { 50 }
227
+ startOffset = { startOffset }
148
228
renderControls = { renderControls }
149
229
renderErrorMessage = { renderPaginatedTableErrorMessage }
150
230
renderEmptyDataMessage = { renderEmptyDataMessage }
0 commit comments