@@ -11,18 +11,28 @@ import HistoryContext from '../../../../contexts/HistoryContext';
1111
1212import routes , { createHref } from '../../../../routes' ;
1313
14- import { sendShardQuery , setShardQueryOptions } from '../../../../store/reducers/shardsWorkload' ;
14+ import {
15+ sendShardQuery ,
16+ setShardQueryOptions ,
17+ setTopShardFilters ,
18+ } from '../../../../store/reducers/shardsWorkload' ;
1519import { setCurrentSchemaPath , getSchema } from '../../../../store/reducers/schema' ;
20+ import type { IShardsWorkloadFilters } from '../../../../types/store/shardsWorkload' ;
1621
1722import type { EPathType } from '../../../../types/api/schema' ;
1823
19- import { DEFAULT_TABLE_SETTINGS } from '../../../../utils/constants' ;
24+ import { formatDateTime , formatNumber } from '../../../../utils' ;
25+ import { DEFAULT_TABLE_SETTINGS , HOUR_IN_SECONDS } from '../../../../utils/constants' ;
2026import { useAutofetcher , useTypedSelector } from '../../../../utils/hooks' ;
21- import { i18n } from '../../../../utils/i18n' ;
2227import { prepareQueryError } from '../../../../utils/query' ;
2328
29+ import { getDefaultNodePath } from '../../../Node/NodePages' ;
30+
2431import { isColumnEntityType } from '../../utils/schema' ;
2532
33+ import { DateRange , DateRangeValues } from './DateRange' ;
34+
35+ import i18n from './i18n' ;
2636import './TopShards.scss' ;
2737
2838const b = cn ( 'top-shards' ) ;
@@ -41,16 +51,15 @@ const tableColumnsNames = {
4151 CPUCores : 'CPUCores' ,
4252 DataSize : 'DataSize' ,
4353 Path : 'Path' ,
54+ NodeId : 'NodeId' ,
55+ PeakTime : 'PeakTime' ,
56+ InFlightTxCount : 'InFlightTxCount' ,
4457} ;
4558
4659function prepareCPUWorkloadValue ( value : string ) {
4760 return `${ ( Number ( value ) * 100 ) . toFixed ( 2 ) } %` ;
4861}
4962
50- function prepareDateSizeValue ( value : number ) {
51- return new Intl . NumberFormat ( i18n . lang ) . format ( value ) ;
52- }
53-
5463function stringToDataTableSortOrder ( value : string ) : SortOrder [ ] | undefined {
5564 return value
5665 ? value . split ( ',' ) . map ( ( columnId ) => ( {
@@ -87,10 +96,24 @@ export const TopShards = ({tenantPath, type}: TopShardsProps) => {
8796 const {
8897 loading,
8998 data : { result : data = undefined } = { } ,
99+ filters : storeFilters ,
90100 error,
91101 wasLoaded,
92102 } = useTypedSelector ( ( state ) => state . shardsWorkload ) ;
93103
104+ // default date range should be the last hour, but shouldn't propagate into URL until user interacts with the control
105+ // redux initial value can't be used, as it synchronizes with URL
106+ const [ filters , setFilters ] = useState < IShardsWorkloadFilters > ( ( ) => {
107+ if ( ! storeFilters ?. from && ! storeFilters ?. to ) {
108+ return {
109+ from : Date . now ( ) - HOUR_IN_SECONDS * 1000 ,
110+ to : Date . now ( ) ,
111+ } ;
112+ }
113+
114+ return storeFilters ;
115+ } ) ;
116+
94117 const [ sortOrder , setSortOrder ] = useState ( tableColumnsNames . CPUCores ) ;
95118
96119 useAutofetcher (
@@ -100,10 +123,11 @@ export const TopShards = ({tenantPath, type}: TopShardsProps) => {
100123 database : tenantPath ,
101124 path : currentSchemaPath ,
102125 sortOrder : stringToQuerySortOrder ( sortOrder ) ,
126+ filters,
103127 } ) ,
104128 ) ;
105129 } ,
106- [ dispatch , currentSchemaPath , tenantPath , sortOrder ] ,
130+ [ dispatch , tenantPath , currentSchemaPath , sortOrder , filters ] ,
107131 autorefresh ,
108132 ) ;
109133
@@ -115,7 +139,7 @@ export const TopShards = ({tenantPath, type}: TopShardsProps) => {
115139 data : undefined ,
116140 } ) ,
117141 ) ;
118- } , [ dispatch , currentSchemaPath , tenantPath ] ) ;
142+ } , [ dispatch , currentSchemaPath , tenantPath , filters ] ) ;
119143
120144 const history = useContext ( HistoryContext ) ;
121145
@@ -126,6 +150,11 @@ export const TopShards = ({tenantPath, type}: TopShardsProps) => {
126150 setSortOrder ( dataTableToStringSortOrder ( newSortOrder ) ) ;
127151 } ;
128152
153+ const handleDateRangeChange = ( value : DateRangeValues ) => {
154+ dispatch ( setTopShardFilters ( value ) ) ;
155+ setFilters ( value ) ;
156+ } ;
157+
129158 const tableColumns : Column < any > [ ] = useMemo ( ( ) => {
130159 const onSchemaClick = ( schemaPath : string ) => {
131160 return ( ) => {
@@ -161,7 +190,7 @@ export const TopShards = ({tenantPath, type}: TopShardsProps) => {
161190 name : tableColumnsNames . DataSize ,
162191 header : 'DataSize (B)' ,
163192 render : ( { value} ) => {
164- return prepareDateSizeValue ( value as number ) ;
193+ return formatNumber ( value as number ) ;
165194 } ,
166195 align : DataTable . RIGHT ,
167196 } ,
@@ -176,6 +205,29 @@ export const TopShards = ({tenantPath, type}: TopShardsProps) => {
176205 } ,
177206 sortable : false ,
178207 } ,
208+ {
209+ name : tableColumnsNames . NodeId ,
210+ render : ( { value : nodeId } ) => {
211+ return (
212+ < InternalLink to = { getDefaultNodePath ( nodeId as string ) } >
213+ { nodeId as string }
214+ </ InternalLink >
215+ ) ;
216+ } ,
217+ align : DataTable . RIGHT ,
218+ sortable : false ,
219+ } ,
220+ {
221+ name : tableColumnsNames . PeakTime ,
222+ render : ( { value} ) => formatDateTime ( new Date ( value as string ) . valueOf ( ) ) ,
223+ sortable : false ,
224+ } ,
225+ {
226+ name : tableColumnsNames . InFlightTxCount ,
227+ render : ( { value} ) => formatNumber ( value as number ) ,
228+ align : DataTable . RIGHT ,
229+ sortable : false ,
230+ } ,
179231 ] ;
180232 } , [ dispatch , history , tenantPath ] ) ;
181233
@@ -192,12 +244,12 @@ export const TopShards = ({tenantPath, type}: TopShardsProps) => {
192244 return renderLoader ( ) ;
193245 }
194246
195- if ( ! data || data . length === 0 || isColumnEntityType ( type ) ) {
196- return 'No data' ;
247+ if ( error && ! error . isCancelled ) {
248+ return < div className = "error" > { prepareQueryError ( error ) } </ div > ;
197249 }
198250
199- if ( error && ! error . isCancelled ) {
200- return prepareQueryError ( error ) ;
251+ if ( ! data || isColumnEntityType ( type ) ) {
252+ return i18n ( 'no-data' ) ;
201253 }
202254
203255 return (
@@ -216,6 +268,10 @@ export const TopShards = ({tenantPath, type}: TopShardsProps) => {
216268
217269 return (
218270 < div className = { b ( ) } >
271+ < div className = { b ( 'controls' ) } >
272+ { i18n ( 'description' ) }
273+ < DateRange from = { filters . from } to = { filters . to } onChange = { handleDateRangeChange } />
274+ </ div >
219275 { renderContent ( ) }
220276 </ div >
221277 ) ;
0 commit comments