@@ -3,7 +3,7 @@ import React from 'react';
33import { Flex , Tabs } from '@gravity-ui/uikit' ;
44import { skipToken } from '@reduxjs/toolkit/query' ;
55import { Helmet } from 'react-helmet-async' ;
6- import { useLocation , useParams } from 'react-router-dom' ;
6+ import { useParams } from 'react-router-dom' ;
77import { StringParam , useQueryParams } from 'use-query-params' ;
88import { z } from 'zod' ;
99
@@ -13,12 +13,14 @@ import {ResponseError} from '../../components/Errors/ResponseError';
1313import { InternalLink } from '../../components/InternalLink' ;
1414import { LoaderWrapper } from '../../components/LoaderWrapper/LoaderWrapper' ;
1515import { PageMetaWithAutorefresh } from '../../components/PageMeta/PageMeta' ;
16- import { getTabletPagePath , parseQuery } from '../../routes' ;
16+ import { getTabletPagePath } from '../../routes' ;
1717import { selectIsUserAllowedToMakeChanges } from '../../store/reducers/authentication/authentication' ;
1818import { setHeaderBreadcrumbs } from '../../store/reducers/header/header' ;
1919import { tabletApi } from '../../store/reducers/tablet' ;
2020import { EFlag } from '../../types/api/enums' ;
21- import type { EType } from '../../types/api/tablet' ;
21+ import type { TTabletStateInfo } from '../../types/api/tablet' ;
22+ import { EType } from '../../types/api/tablet' ;
23+ import type { ITabletPreparedHistoryItem } from '../../types/store/tablet' ;
2224import { cn } from '../../utils/cn' ;
2325import { CLUSTER_DEFAULT_TITLE } from '../../utils/constants' ;
2426import { useAutoRefreshInterval , useTypedDispatch , useTypedSelector } from '../../utils/hooks' ;
@@ -56,185 +58,174 @@ const TABLET_PAGE_TABS = [
5658] ;
5759
5860const tabletTabSchema = z . nativeEnum ( TABLET_TABS_IDS ) . catch ( TABLET_TABS_IDS . history ) ;
61+ const eTypeSchema = z . nativeEnum ( EType ) . or ( z . undefined ( ) ) . catch ( undefined ) ;
5962
60- export const Tablet = ( ) => {
63+ export function Tablet ( ) {
6164 const dispatch = useTypedDispatch ( ) ;
62- const location = useLocation ( ) ;
63- const isUserAllowedToMakeChanges = useTypedSelector ( selectIsUserAllowedToMakeChanges ) ;
6465
6566 const { id} = useParams < { id : string } > ( ) ;
6667
67- const [ { activeTab} , setParams ] = useQueryParams ( {
68- activeTab : StringParam ,
68+ const [
69+ {
70+ nodeId : queryNodeId ,
71+ tenantName : queryTenantName ,
72+ type : queryTabletType ,
73+ clusterName : queryClusterName ,
74+ } ,
75+ ] = useQueryParams ( {
76+ nodeId : StringParam ,
77+ tenantName : StringParam ,
78+ type : StringParam ,
79+ clusterName : StringParam ,
6980 } ) ;
7081
71- const tabletTab = tabletTabSchema . parse ( activeTab ) ;
72-
73- const {
74- nodeId : queryNodeId ,
75- tenantName : queryTenantName ,
76- type : queryTabletType ,
77- clusterName : queryClusterName ,
78- } = parseQuery ( location ) ;
79-
8082 const [ autoRefreshInterval ] = useAutoRefreshInterval ( ) ;
81- const { currentData, isFetching, error, refetch } = tabletApi . useGetTabletQuery (
83+ const { currentData, isFetching, error} = tabletApi . useGetTabletQuery (
8284 { id, database : queryTenantName ?. toString ( ) } ,
8385 { pollingInterval : autoRefreshInterval } ,
8486 ) ;
8587
8688 const loading = isFetching && currentData === undefined ;
87- const { id : tabletId , data : tablet = { } , history = [ ] } = currentData || { } ;
89+ const { data : tablet = { } , history = [ ] } = currentData || { } ;
8890
8991 const { currentData : tenantPath } = tabletApi . useGetTabletDescribeQuery (
9092 tablet . TenantId ? { tenantId : tablet . TenantId } : skipToken ,
9193 ) ;
9294
93- const hasHiveId = hasHive ( tablet . HiveId ) ;
95+ const nodeId = tablet . NodeId ?? queryNodeId ;
96+ const tenantName = ( tenantPath || queryTenantName ) ?? undefined ;
9497
95- const noAdvancedInfo = ! isUserAllowedToMakeChanges || ! hasHiveId ;
96-
97- React . useEffect ( ( ) => {
98- if ( loading ) {
99- return ;
100- }
101- if ( noAdvancedInfo && TABLET_PAGE_TABS . find ( ( { id} ) => id === tabletTab ) ?. isAdvanced ) {
102- setParams ( { activeTab : TABLET_TABS_IDS . history } ) ;
103- }
104- } , [ noAdvancedInfo , tabletTab , setParams , loading ] ) ;
105-
106- const {
107- currentData : advancedData ,
108- refetch : refetchAdvancedInfo ,
109- isFetching : isFetchingAdvancedData ,
110- } = tabletApi . useGetAdvancedTableInfoQuery (
111- { id, hiveId : tablet . HiveId } ,
112- {
113- pollingInterval : autoRefreshInterval ,
114- skip : noAdvancedInfo || activeTab !== 'channels' ,
115- } ,
116- ) ;
117-
118- const refetchTabletInfo = React . useCallback ( async ( ) => {
119- await Promise . all ( [ refetch ( ) , refetchAdvancedInfo ( ) ] ) ;
120- } , [ refetch , refetchAdvancedInfo ] ) ;
121-
122- const nodeId = tablet . NodeId ?. toString ( ) || queryNodeId ?. toString ( ) ;
123- const tenantName = tenantPath || queryTenantName ?. toString ( ) ;
124-
125- const type = tablet . Type || ( queryTabletType ?. toString ( ) as EType | undefined ) ;
98+ const tabletType = tablet . Type || eTypeSchema . parse ( queryTabletType ) ;
12699
127100 React . useEffect ( ( ) => {
128101 dispatch (
129102 setHeaderBreadcrumbs ( 'tablet' , {
130103 nodeIds : nodeId ? [ nodeId ] : [ ] ,
131104 tenantName,
132105 tabletId : id ,
133- tabletType : type ,
106+ tabletType,
134107 } ) ,
135108 ) ;
136- } , [ dispatch , tenantName , id , nodeId , type ] ) ;
109+ } , [ dispatch , tenantName , id , nodeId , tabletType ] ) ;
137110
138- const renderPageMeta = ( ) => {
139- const { Leader, Type} = tablet ;
140- const database = tenantName ? `${ i18n ( 'tablet.meta-database' ) } : ${ tenantName } ` : undefined ;
141- const type = Type ? Type : undefined ;
142- const follower = Leader === false ? i18n ( 'tablet.meta-follower' ) . toUpperCase ( ) : undefined ;
111+ const { Leader, Type} = tablet ;
112+ const database = tenantName ? `${ i18n ( 'tablet.meta-database' ) } : ${ tenantName } ` : undefined ;
113+ const type = Type ? Type : undefined ;
114+ const follower = Leader === false ? i18n ( 'tablet.meta-follower' ) . toUpperCase ( ) : undefined ;
143115
144- return < PageMetaWithAutorefresh items = { [ database , type , follower ] } /> ;
145- } ;
146-
147- const renderHelmet = ( ) => {
148- return (
116+ return (
117+ < Flex gap = { 5 } direction = "column" className = { b ( ) } >
149118 < Helmet >
150119 < title > { `${ id } — ${ i18n ( 'tablet.header' ) } — ${
151120 tenantName || queryClusterName || CLUSTER_DEFAULT_TITLE
152121 } `} </ title >
153122 </ Helmet >
154- ) ;
155- } ;
156-
157- const renderTabs = ( ) => {
158- return (
159- //block wrapper for tabs
160- < div >
161- < Tabs
162- size = "l"
163- items = { TABLET_PAGE_TABS . filter ( ( { isAdvanced} ) =>
164- isAdvanced ? ! noAdvancedInfo : true ,
165- ) }
166- activeTab = { tabletTab }
167- wrapTo = { ( { id} , tabNode ) => {
168- const path = tabletId
169- ? getTabletPagePath ( tabletId , { activeTab : id } )
170- : undefined ;
171- return (
172- < InternalLink to = { path } key = { id } >
173- { tabNode }
174- </ InternalLink >
175- ) ;
176- } }
123+ < PageMetaWithAutorefresh items = { [ database , type , follower ] } />
124+ < LoaderWrapper loading = { loading } size = "l" >
125+ { error ? < ResponseError error = { error } /> : null }
126+ { currentData ? < TabletContent id = { id } tablet = { tablet } history = { history } /> : null }
127+ </ LoaderWrapper >
128+ </ Flex >
129+ ) ;
130+ }
131+
132+ function TabletContent ( {
133+ id,
134+ tablet,
135+ history,
136+ } : {
137+ id : string ;
138+ tablet : TTabletStateInfo ;
139+ history : ITabletPreparedHistoryItem [ ] ;
140+ } ) {
141+ const isEmpty = ! Object . keys ( tablet ) . length ;
142+ const { Overall, HiveId} = tablet ;
143+
144+ return (
145+ < EmptyStateWrapper
146+ title = { i18n ( 'emptyState' ) }
147+ className = { b ( 'placeholder' ) }
148+ isEmpty = { isEmpty }
149+ >
150+ < Flex gap = { 5 } direction = "column" >
151+ < EntityPageTitle
152+ entityName = { i18n ( 'tablet.header' ) }
153+ status = { Overall ?? EFlag . Grey }
154+ id = { id }
177155 />
178- </ div >
179- ) ;
180- } ;
181-
182- const renderTabsContent = ( ) => {
183- switch ( tabletTab ) {
184- case 'channels' : {
185- return (
186- < LoaderWrapper
187- loading = { isFetchingAdvancedData && advancedData === undefined }
188- size = "l"
189- >
190- < TabletStorageInfo data = { advancedData } />
191- </ LoaderWrapper >
192- ) ;
193- }
194- case 'history' : {
195- return < TabletTable history = { history } /> ;
196- }
197- default :
198- return null ;
199- }
200- } ;
156+ < TabletControls tablet = { tablet } />
157+ < TabletInfo tablet = { tablet } />
158+ </ Flex >
159+ < TabletTabs id = { id } hiveId = { HiveId } history = { history } />
160+ </ EmptyStateWrapper >
161+ ) ;
162+ }
163+
164+ function TabletTabs ( {
165+ id,
166+ hiveId,
167+ history,
168+ } : {
169+ id : string ;
170+ hiveId ?: string ;
171+ history : ITabletPreparedHistoryItem [ ] ;
172+ } ) {
173+ const [ { activeTab} , setParams ] = useQueryParams ( { activeTab : StringParam } ) ;
174+ const isUserAllowedToMakeChanges = useTypedSelector ( selectIsUserAllowedToMakeChanges ) ;
175+
176+ const noAdvancedInfo = ! isUserAllowedToMakeChanges || ! hasHive ( hiveId ) ;
201177
202- const renderView = ( ) => {
203- if ( error && ! currentData ) {
204- return < ResponseError error = { error } /> ;
178+ let tabletTab = tabletTabSchema . parse ( activeTab ) ;
179+ if ( noAdvancedInfo && TABLET_PAGE_TABS . find ( ( tab ) => tab . id === tabletTab ) ?. isAdvanced ) {
180+ tabletTab = TABLET_TABS_IDS . history ;
181+ }
182+
183+ React . useEffect ( ( ) => {
184+ if ( activeTab !== tabletTab ) {
185+ setParams ( { activeTab : tabletTab } , 'replaceIn' ) ;
205186 }
187+ } , [ activeTab , tabletTab , setParams ] ) ;
206188
207- const { TabletId, Overall} = tablet ;
208- return (
209- < React . Fragment >
210- { error ? < ResponseError error = { error } /> : null }
211- < Flex gap = { 5 } direction = "column" >
212- < EntityPageTitle
213- entityName = { i18n ( 'tablet.header' ) }
214- status = { Overall ?? EFlag . Grey }
215- id = { TabletId }
216- />
217- < TabletControls tablet = { tablet } fetchData = { refetchTabletInfo } />
218- < TabletInfo tablet = { tablet } />
219- </ Flex >
220- </ React . Fragment >
221- ) ;
222- } ;
223189 return (
224- < Flex gap = { 5 } direction = "column" className = { b ( ) } >
225- { renderHelmet ( ) }
226- { renderPageMeta ( ) }
227- < LoaderWrapper loading = { loading } size = "l" >
228- < EmptyStateWrapper
229- title = { i18n ( 'emptyState' ) }
230- className = { b ( 'placeholder' ) }
231- isEmpty = { ! tablet || ! Object . keys ( tablet ) . length }
232- >
233- { renderView ( ) }
234- { renderTabs ( ) }
235- { renderTabsContent ( ) }
236- </ EmptyStateWrapper >
237- </ LoaderWrapper >
190+ < Flex gap = { 5 } direction = "column" >
191+ < Tabs
192+ size = "l"
193+ items = { TABLET_PAGE_TABS . filter ( ( { isAdvanced} ) =>
194+ isAdvanced ? ! noAdvancedInfo : true ,
195+ ) }
196+ activeTab = { tabletTab }
197+ wrapTo = { ( tab , tabNode ) => {
198+ const path = getTabletPagePath ( id , { activeTab : tab . id } ) ;
199+ return (
200+ < InternalLink to = { path } key = { tab . id } >
201+ { tabNode }
202+ </ InternalLink >
203+ ) ;
204+ } }
205+ />
206+ { tabletTab === 'history' ? < TabletTable history = { history } /> : null }
207+ { tabletTab === 'channels' && ! noAdvancedInfo ? (
208+ < Channels id = { id } hiveId = { hiveId } />
209+ ) : null }
238210 </ Flex >
239211 ) ;
240- } ;
212+ }
213+
214+ function Channels ( { id, hiveId} : { id : string ; hiveId : string } ) {
215+ const [ autoRefreshInterval ] = useAutoRefreshInterval ( ) ;
216+ const { currentData, error, isFetching} = tabletApi . useGetAdvancedTableInfoQuery (
217+ { id, hiveId} ,
218+ {
219+ pollingInterval : autoRefreshInterval ,
220+ } ,
221+ ) ;
222+
223+ const loading = isFetching && currentData === undefined ;
224+
225+ return (
226+ < LoaderWrapper loading = { loading } size = "l" >
227+ { error ? < ResponseError error = { error } /> : null }
228+ { currentData ? < TabletStorageInfo data = { currentData } /> : null }
229+ </ LoaderWrapper >
230+ ) ;
231+ }
0 commit comments