@@ -6,18 +6,16 @@ import {useHistory, useLocation} from 'react-router-dom';
66
77import { TenantTabsGroups , getTenantPath } from '../../containers/Tenant/TenantPages' ;
88import { parseQuery } from '../../routes' ;
9- import { topQueriesApi } from '../../store/reducers/executeTopQueries/executeTopQueries' ;
109import { TENANT_DIAGNOSTICS_TABS_IDS } from '../../store/reducers/tenant/constants' ;
11- import type { KeyValueRow } from '../../types/api/query' ;
1210import { cn } from '../../utils/cn' ;
13- import { useAutoRefreshInterval } from '../../utils/hooks' ;
14- import type { TimeFrame } from '../../utils/timeframes' ;
15- import { chartApi } from '../MetricChart/reducer' ;
16- import type { ChartDataStatus } from '../MetricChart/types' ;
1711
12+ import { QueriesActivityAlert } from './QueriesActivityAlert' ;
1813import { QueriesActivityCharts } from './QueriesActivityCharts' ;
14+ import { QueriesActivitySkeleton } from './QueriesActivitySkeleton' ;
1915import i18n from './i18n' ;
20- import { calculateLatency , calculateQueriesPerSecond , formatTrendValue } from './utils' ;
16+ import { useChartAvailability } from './useChartAvailability' ;
17+ import { useQueriesActivityData } from './useQueriesActivityData' ;
18+ import { formatTrendValue } from './utils' ;
2119
2220import './QueriesActivityBar.scss' ;
2321
@@ -30,93 +28,13 @@ interface QueriesActivityBarProps {
3028export function QueriesActivityBar ( { tenantName} : QueriesActivityBarProps ) {
3129 const history = useHistory ( ) ;
3230 const location = useLocation ( ) ;
33- const [ autoRefreshInterval ] = useAutoRefreshInterval ( ) ;
3431 const [ expanded , setExpanded ] = React . useState ( false ) ;
35- const [ queriesTimeFrame ] = React . useState < TimeFrame > ( '1h' ) ;
36- const [ latenciesTimeFrame ] = React . useState < TimeFrame > ( '1h' ) ;
37- const [ isActivityBarHidden , setIsActivityBarHidden ] = React . useState < boolean > ( true ) ;
38-
39- // Refetch data only if activity bar successfully loaded
40- const shouldRefresh = isActivityBarHidden ? 0 : autoRefreshInterval ;
41-
42- /**
43- * Activity bar should be hidden, if charts are not enabled:
44- * 1. GraphShard is not enabled
45- * 2. ydb version does not have /viewer/json/render endpoint (400, 404, CORS error, etc.)
46- *
47- * If at least one chart successfully loaded, activity bar should be shown
48- * @link https://github.com/ydb-platform/ydb-embedded-ui/issues/659
49- * @todo disable only for specific errors ('GraphShard is not enabled') after ydb-stable-24 is generally used
50- */
51- const handleChartDataStatusChange = React . useCallback ( ( chartStatus : ChartDataStatus ) => {
52- if ( chartStatus === 'success' ) {
53- setIsActivityBarHidden ( false ) ;
54- }
55- } , [ ] ) ;
56-
57- // Fetch running queries
58- const { data : runningQueriesData } = topQueriesApi . useGetRunningQueriesQuery (
59- {
60- database : tenantName ,
61- filters : { } ,
62- } ,
63- { pollingInterval : shouldRefresh } ,
64- ) ;
65-
66- // Fetch queries per second data for header metrics
67- const { data : queriesPerSecData } = chartApi . useGetChartDataQuery (
68- {
69- database : tenantName ,
70- metrics : [ { target : 'queries.requests' } ] ,
71- timeFrame : queriesTimeFrame ,
72- maxDataPoints : 30 ,
73- } ,
74- { pollingInterval : shouldRefresh } ,
75- ) ;
76-
77- // Fetch latency data for header metrics
78- const { data : latencyData } = chartApi . useGetChartDataQuery (
79- {
80- database : tenantName ,
81- metrics : [ { target : 'queries.latencies.p99' } ] ,
82- timeFrame : latenciesTimeFrame ,
83- maxDataPoints : 30 ,
84- } ,
85- { pollingInterval : shouldRefresh } ,
86- ) ;
87-
88- const runningQueriesCount = runningQueriesData ?. resultSets ?. [ 0 ] ?. result ?. length || 0 ;
8932
90- const qps = React . useMemo (
91- ( ) => calculateQueriesPerSecond ( queriesPerSecData ?. metrics ?. [ 0 ] ?. data ) ,
92- [ queriesPerSecData ?. metrics ?. [ 0 ] ?. data ] ,
93- ) ;
33+ // Check chart availability without rendering hidden components
34+ const areChartsAvailable = useChartAvailability ( tenantName ) ;
9435
95- const latency = React . useMemo (
96- ( ) => calculateLatency ( latencyData ?. metrics ?. [ 0 ] ?. data ) ,
97- [ latencyData ?. metrics ?. [ 0 ] ?. data ] ,
98- ) ;
99-
100- // Calculate unique applications and users
101- const uniqueApplications = React . useMemo ( ( ) => {
102- const apps = new Set < string > ( ) ;
103- runningQueriesData ?. resultSets ?. [ 0 ] ?. result ?. forEach ( ( row : KeyValueRow ) => {
104- if ( row . ApplicationName ) {
105- apps . add ( String ( row . ApplicationName ) ) ;
106- }
107- } ) ;
108- return apps . size ;
109- } , [ runningQueriesData ] ) ;
110-
111- const uniqueUsers = React . useMemo ( ( ) => {
112- const users = new Set < string > ( ) ;
113- runningQueriesData ?. resultSets ?. [ 0 ] ?. result ?. forEach ( ( row : KeyValueRow ) => {
114- if ( row . UserSID ) {
115- users . add ( String ( row . UserSID ) ) ;
116- }
117- } ) ;
118- return users . size ;
119- } , [ runningQueriesData ] ) ;
36+ const { runningQueriesCount, uniqueApplications, uniqueUsers, qps, latency} =
37+ useQueriesActivityData ( tenantName ) ;
12038
12139 const handleOpenRunningQueries = ( ) => {
12240 const queryParams = parseQuery ( location ) ;
@@ -132,8 +50,25 @@ export function QueriesActivityBar({tenantName}: QueriesActivityBarProps) {
13250 setExpanded ( ! expanded ) ;
13351 } ;
13452
53+ // Show skeleton while determining chart availability
54+ if ( areChartsAvailable === null ) {
55+ return < QueriesActivitySkeleton /> ;
56+ }
57+
58+ // Render compact alert-style mode when charts are not available
59+ if ( areChartsAvailable === false ) {
60+ return (
61+ < QueriesActivityAlert
62+ runningQueriesCount = { runningQueriesCount }
63+ uniqueApplications = { uniqueApplications }
64+ uniqueUsers = { uniqueUsers }
65+ />
66+ ) ;
67+ }
68+
69+ // Render expandable mode when charts are available
13570 return (
136- < div className = { b ( { expanded} ) } style = { { display : isActivityBarHidden ? 'none' : undefined } } >
71+ < div className = { b ( { expanded} ) } >
13772 < Card className = { b ( 'card' ) } type = "container" view = { expanded ? 'outlined' : 'raised' } >
13873 < div className = { b ( 'header' ) } onClick = { handleToggleExpanded } >
13974 < Flex justifyContent = "space-between" className = { b ( 'content-wrapper' ) } >
@@ -146,36 +81,36 @@ export function QueriesActivityBar({tenantName}: QueriesActivityBarProps) {
14681 </ Text >
14782 </ Flex >
14883
149- < div className = { b ( 'metrics' ) } >
150- < Label
151- theme = { runningQueriesCount > 0 ? 'success' : 'unknown' }
152- size = "s"
153- icon = { < Icon data = { CirclePlay } size = { 14 } /> }
154- >
155- { runningQueriesCount }
156- </ Label >
157-
158- < Label
159- theme = "clear"
160- size = "s"
161- icon = { < Icon data = { Rocket } size = { 14 } /> }
162- value = { formatTrendValue ( qps . trend . value ) }
163- >
164- { i18n ( 'value_per-sec' , { count : qps . value } ) }
165- </ Label >
166-
167- < Label
168- theme = "clear"
169- size = "s"
170- icon = { < Icon data = { Clock } size = { 14 } /> }
171- value = { formatTrendValue ( latency . trend . value ) }
172- >
173- { i18n ( 'value_ms' , { time : latency . value } ) }
174- </ Label >
175- </ div >
84+ < Flex alignItems = "center" gap = { 4 } className = { b ( 'header-metrics' ) } >
85+ < div className = { b ( 'metrics' ) } >
86+ < Label
87+ theme = { runningQueriesCount > 0 ? 'success' : 'unknown' }
88+ size = "s"
89+ icon = { < Icon data = { CirclePlay } size = { 14 } /> }
90+ >
91+ { runningQueriesCount }
92+ </ Label >
93+ < Label
94+ theme = "unknown"
95+ icon = { < Icon data = { Rocket } /> }
96+ size = "s"
97+ value = { formatTrendValue ( qps ?. trend ?. value ?? 0 ) }
98+ >
99+ { i18n ( 'value_per-sec' , { count : qps ?. value ?? '0' } ) }
100+ </ Label >
101+ < Label
102+ theme = "unknown"
103+ icon = { < Icon data = { Clock } /> }
104+ size = "s"
105+ value = { formatTrendValue ( latency ?. trend ?. value ?? 0 ) }
106+ >
107+ { i18n ( 'value_ms' , { time : latency ?. value ?? '0' } ) }
108+ </ Label >
109+ </ div >
110+
111+ < ArrowToggle direction = { expanded ? 'top' : 'bottom' } size = { 16 } />
112+ </ Flex >
176113 </ Flex >
177-
178- < ArrowToggle direction = { expanded ? 'top' : 'bottom' } />
179114 </ div >
180115
181116 { expanded && (
@@ -208,22 +143,20 @@ export function QueriesActivityBar({tenantName}: QueriesActivityBarProps) {
208143 { i18n ( 'field_users' ) }
209144 </ Label >
210145
211- < Button
212- view = "outlined"
213- size = "s"
214- onClick = { handleOpenRunningQueries }
215- className = { b ( 'open-queries-button' ) }
216- >
217- { i18n ( 'action_open-running-queries' ) }
218- </ Button >
146+ { runningQueriesCount > 0 && (
147+ < Button
148+ view = "outlined"
149+ size = "s"
150+ onClick = { handleOpenRunningQueries }
151+ className = { b ( 'open-queries-button' ) }
152+ >
153+ { i18n ( 'action_open-running-queries' ) }
154+ </ Button >
155+ ) }
219156 </ div >
220157 </ div >
221158 ) }
222- < QueriesActivityCharts
223- tenantName = { tenantName }
224- expanded = { expanded }
225- onChartDataStatusChange = { handleChartDataStatusChange }
226- />
159+ < QueriesActivityCharts tenantName = { tenantName } expanded = { expanded } />
227160 </ Card >
228161 </ div >
229162 ) ;
0 commit comments