@@ -42,8 +42,10 @@ import {
4242} from '@patternfly/react-core' ;
4343import { ChartLineIcon , CompressIcon } from '@patternfly/react-icons' ;
4444import {
45+ IFormatterValueType ,
4546 InnerScrollContainer ,
4647 ISortBy ,
48+ ITransform ,
4749 sortable ,
4850 Table ,
4951 TableGridBreakpoint ,
@@ -109,6 +111,11 @@ import {
109111 t_global_spacer_sm ,
110112 t_global_font_family_mono ,
111113} from '@patternfly/react-tokens' ;
114+ import { QueryParamProvider , StringParam , useQueryParam } from 'use-query-params' ;
115+ import { ReactRouter5Adapter } from 'use-query-params/adapters/react-router-5' ;
116+ import { GraphUnits , isGraphUnit } from './metrics/units' ;
117+ import { SimpleSelect , SimpleSelectOption } from '@patternfly/react-templates' ;
118+ import { valueFormatter } from './console/console-shared/src/components/query-browser/QueryBrowserTooltip' ;
112119
113120// Stores information about the currently focused query input
114121let focusedQuery ;
@@ -205,7 +212,7 @@ const devQueries = (activeNamespace: string) => {
205212 ] ;
206213} ;
207214
208- export const PreDefinedQueriesDropdown = ( ) => {
215+ const PreDefinedQueriesDropdown = ( ) => {
209216 const [ activeNamespace ] = useActiveNamespace ( ) ;
210217 const { perspective } = usePerspective ( ) ;
211218
@@ -570,7 +577,12 @@ const QueryKebab: React.FC<{ index: number }> = ({ index }) => {
570577 return < KebabDropdown dropdownItems = { dropdownItems } /> ;
571578} ;
572579
573- export const QueryTable : React . FC < QueryTableProps > = ( { index, namespace, customDatasource } ) => {
580+ export const QueryTable : React . FC < QueryTableProps > = ( {
581+ index,
582+ namespace,
583+ customDatasource,
584+ units,
585+ } ) => {
574586 const { t } = useTranslation ( process . env . I18N_NAMESPACE ) ;
575587 const { perspective } = usePerspective ( ) ;
576588
@@ -579,6 +591,7 @@ export const QueryTable: React.FC<QueryTableProps> = ({ index, namespace, custom
579591 const [ page , setPage ] = React . useState ( 1 ) ;
580592 const [ perPage , setPerPage ] = React . useState ( 50 ) ;
581593 const [ sortBy , setSortBy ] = React . useState < ISortBy > ( { } ) ;
594+ const valueFormat = valueFormatter ( units ) ;
582595
583596 const isEnabled = useSelector ( ( state : MonitoringState ) =>
584597 getLegacyObserveState ( perspective , state ) ?. getIn ( [
@@ -699,16 +712,39 @@ export const QueryTable: React.FC<QueryTableProps> = ({ index, namespace, custom
699712 ) ;
700713 }
701714
702- const transforms = [ sortable , wrappable ] ;
715+ const transforms : ITransform [ ] = [ sortable , wrappable ] ;
703716
704717 const buttonCell = ( labels ) => ( { title : < SeriesButton index = { index } labels = { labels } /> } ) ;
705718
706719 let columns , rows ;
707720 if ( data . resultType === 'scalar' ) {
708- columns = [ '' , { title : t ( 'Value' ) , transforms } ] ;
721+ columns = [
722+ '' ,
723+ {
724+ title : t ( 'Value' ) ,
725+ transforms,
726+ cellTransforms : [
727+ ( data : IFormatterValueType ) => {
728+ const val = data ?. title ? data . title : data ;
729+ return ! Number . isNaN ( Number ( val ) ) ? valueFormat ( Number ( val ) ) : val ;
730+ } ,
731+ ] ,
732+ } ,
733+ ] ;
709734 rows = [ [ buttonCell ( { } ) , _ . get ( result , '[1]' ) ] ] ;
710735 } else if ( data . resultType === 'string' ) {
711- columns = [ { title : t ( 'Value' ) , transforms } ] ;
736+ columns = [
737+ {
738+ title : t ( 'Value' ) ,
739+ transforms,
740+ cellTransforms : [
741+ ( data : IFormatterValueType ) => {
742+ const val = data ?. title ? data . title : data ;
743+ return ! Number . isNaN ( Number ( val ) ) ? valueFormat ( Number ( val ) ) : val ;
744+ } ,
745+ ] ,
746+ } ,
747+ ] ;
712748 rows = [ [ result ?. [ 1 ] ] ] ;
713749 } else {
714750 const allLabelKeys = _ . uniq ( _ . flatMap ( result , ( { metric } ) => Object . keys ( metric ) ) ) . sort ( ) ;
@@ -719,7 +755,16 @@ export const QueryTable: React.FC<QueryTableProps> = ({ index, namespace, custom
719755 title : < span > { k === '__name__' ? t ( 'Name' ) : k } </ span > ,
720756 transforms,
721757 } ) ) ,
722- { title : t ( 'Value' ) , transforms } ,
758+ {
759+ title : t ( 'Value' ) ,
760+ transforms,
761+ cellTransforms : [
762+ ( data : IFormatterValueType ) => {
763+ const val = data ?. title ? data . title : data ;
764+ return ! Number . isNaN ( Number ( val ) ) ? valueFormat ( Number ( val ) ) : val ;
765+ } ,
766+ ] ,
767+ } ,
723768 ] ;
724769
725770 let rowMapper ;
@@ -810,7 +855,13 @@ export const QueryTable: React.FC<QueryTableProps> = ({ index, namespace, custom
810855 style = { { fontFamily : t_global_font_family_mono . var } }
811856 key = { `cell-${ rowIndex } -${ cellIndex } ` }
812857 >
813- { typeof cell === 'string' ? cell : cell ?. title }
858+ { columns [ cellIndex ] . cellTransforms
859+ ? columns [ cellIndex ] . cellTransforms [ 0 ] (
860+ typeof cell === 'string' ? cell : cell ?. title ,
861+ )
862+ : typeof cell === 'string'
863+ ? cell
864+ : cell ?. title }
814865 </ Td >
815866 ) ) }
816867 </ Tr >
@@ -836,10 +887,11 @@ const PromQLExpressionInput = (props) => (
836887 />
837888) ;
838889
839- const Query : React . FC < { index : number ; customDatasource ?: CustomDataSource } > = ( {
840- index,
841- customDatasource,
842- } ) => {
890+ const Query : React . FC < {
891+ index : number ;
892+ customDatasource ?: CustomDataSource ;
893+ units : GraphUnits ;
894+ } > = ( { index, customDatasource, units } ) => {
843895 const { t } = useTranslation ( process . env . I18N_NAMESPACE ) ;
844896 const { perspective } = usePerspective ( ) ;
845897
@@ -924,13 +976,6 @@ const Query: React.FC<{ index: number; customDatasource?: CustomDataSource }> =
924976
925977 // If namespace is defined getPrometheusURL() will use the
926978 // PROMETHEUS_TENANCY_BASE_PATH for the developer view
927- const queryTable = (
928- < QueryTable
929- index = { index }
930- customDatasource = { customDatasource }
931- namespace = { perspective === 'dev' ? activeNamespace : undefined }
932- />
933- ) ;
934979
935980 return (
936981 < DataListItem aria-labelledby = { `query-item-${ queryId } ` } isExpanded = { isExpanded } >
@@ -968,7 +1013,12 @@ const Query: React.FC<{ index: number; customDatasource?: CustomDataSource }> =
9681013 id = { `query-expand-${ queryId } ` }
9691014 isHidden = { ! isExpanded }
9701015 >
971- { queryTable }
1016+ < QueryTable
1017+ index = { index }
1018+ customDatasource = { customDatasource }
1019+ namespace = { perspective === 'dev' ? activeNamespace : undefined }
1020+ units = { units }
1021+ />
9721022 </ DataListContent >
9731023 </ DataListItem >
9741024 ) ;
@@ -978,7 +1028,8 @@ const QueryBrowserWrapper: React.FC<{
9781028 customDataSourceName : string ;
9791029 customDataSource : CustomDataSource ;
9801030 customDatasourceError : boolean ;
981- } > = ( { customDataSourceName, customDataSource, customDatasourceError } ) => {
1031+ units : GraphUnits ;
1032+ } > = ( { customDataSourceName, customDataSource, customDatasourceError, units } ) => {
9821033 const { t } = useTranslation ( process . env . I18N_NAMESPACE ) ;
9831034 const { perspective } = usePerspective ( ) ;
9841035
@@ -1090,6 +1141,7 @@ const QueryBrowserWrapper: React.FC<{
10901141 defaultTimespan = { 30 * 60 * 1000 }
10911142 disabledSeries = { disabledSeries }
10921143 queries = { queryStrings }
1144+ units = { units }
10931145 showStackedControl
10941146 />
10951147 ) ;
@@ -1121,7 +1173,10 @@ const RunQueriesButton: React.FC = () => {
11211173 ) ;
11221174} ;
11231175
1124- const QueriesList : React . FC < { customDatasource ?: CustomDataSource } > = ( { customDatasource } ) => {
1176+ const QueriesList : React . FC < { customDatasource ?: CustomDataSource ; units : GraphUnits } > = ( {
1177+ customDatasource,
1178+ units,
1179+ } ) => {
11251180 const { perspective } = usePerspective ( ) ;
11261181 const count = useSelector (
11271182 ( state : MonitoringState ) =>
@@ -1133,7 +1188,12 @@ const QueriesList: React.FC<{ customDatasource?: CustomDataSource }> = ({ custom
11331188 { _ . range ( count ) . map ( ( index ) => {
11341189 const reversedIndex = count - index - 1 ;
11351190 return (
1136- < Query index = { reversedIndex } key = { reversedIndex } customDatasource = { customDatasource } />
1191+ < Query
1192+ index = { reversedIndex }
1193+ key = { reversedIndex }
1194+ customDatasource = { customDatasource }
1195+ units = { units }
1196+ />
11371197 ) ;
11381198 } ) }
11391199 </ DataList >
@@ -1153,12 +1213,51 @@ const IntervalDropdown = () => {
11531213 return < DropDownPollInterval setInterval = { setInterval } selectedInterval = { pollInterval } /> ;
11541214} ;
11551215
1216+ const GraphUnitsDropDown : React . FC = ( ) => {
1217+ const { t } = useTranslation ( process . env . I18N_NAMESPACE ) ;
1218+ const [ selectedUnits , setUnits ] = useQueryParam ( QueryParams . Units , StringParam ) ;
1219+
1220+ const initialOptions = React . useMemo < SimpleSelectOption [ ] > ( ( ) => {
1221+ const intervalOptions : SimpleSelectOption [ ] = [
1222+ { content : t ( 'Bytes Binary (KiB, MiB)' ) , value : 'bytes' } ,
1223+ { content : t ( 'Bytes Decimal (kb, MB)' ) , value : 'Bytes' } ,
1224+ { content : t ( 'Bytes Binary Per Second (KiB/s, MiB/s)' ) , value : 'bps' } ,
1225+ { content : t ( 'Bytes Decimal Per Second (kB/s, MB/s)' ) , value : 'Bps' } ,
1226+ { content : t ( 'Packets Per Second' ) , value : 'pps' } ,
1227+ { content : t ( 'Miliseconds' ) , value : 'ms' } ,
1228+ { content : t ( 'Seconds' ) , value : 's' } ,
1229+ { content : t ( 'Percentage' ) , value : 'percentunit' } ,
1230+ { content : t ( 'No Units' ) , value : 'short' } ,
1231+ ] ;
1232+ return intervalOptions . map ( ( o ) => ( { ...o , selected : o . value === selectedUnits } ) ) ;
1233+ } , [ selectedUnits , t ] ) ;
1234+
1235+ const onSelect = ( _ev , selection : string ) => {
1236+ setUnits ( selection ) ;
1237+ } ;
1238+
1239+ return (
1240+ < SimpleSelect
1241+ initialOptions = { initialOptions }
1242+ onSelect = { ( _ev , selection : string ) => onSelect ( _ev , selection ) }
1243+ toggleWidth = "300px"
1244+ />
1245+ ) ;
1246+ } ;
1247+
11561248const MetricsPage_ : React . FC = ( ) => {
11571249 const { t } = useTranslation ( process . env . I18N_NAMESPACE ) ;
1250+ const [ units , setUnits ] = useQueryParam ( QueryParams . Units , StringParam ) ;
11581251
11591252 const dispatch = useDispatch ( ) ;
11601253 const { perspective } = usePerspective ( ) ;
11611254
1255+ React . useEffect ( ( ) => {
1256+ if ( ! isGraphUnit ( units ) ) {
1257+ setUnits ( 'short' ) ;
1258+ }
1259+ } , [ units , setUnits ] ) ;
1260+
11621261 // Clear queries on unmount
11631262 React . useEffect ( ( ) => {
11641263 return ( ) => {
@@ -1240,6 +1339,11 @@ const MetricsPage_: React.FC = () => {
12401339 </ SplitItem >
12411340 ) }
12421341 < SplitItem isFilled />
1342+ < SplitItem >
1343+ < Tooltip content = { < > { t ( 'This dropdown only formats results.' ) } </ > } >
1344+ < GraphUnitsDropDown />
1345+ </ Tooltip >
1346+ </ SplitItem >
12431347 < SplitItem >
12441348 < IntervalDropdown />
12451349 </ SplitItem >
@@ -1258,6 +1362,7 @@ const MetricsPage_: React.FC = () => {
12581362 customDataSource = { customDataSource }
12591363 customDataSourceName = { customDataSourceName }
12601364 customDatasourceError = { customDatasourceError }
1365+ units = { units as GraphUnits }
12611366 />
12621367 </ StackItem >
12631368 < StackItem >
@@ -1275,24 +1380,32 @@ const MetricsPage_: React.FC = () => {
12751380 </ Flex >
12761381 </ StackItem >
12771382 < StackItem >
1278- < QueriesList customDatasource = { customDataSource } />
1383+ < QueriesList customDatasource = { customDataSource } units = { units as GraphUnits } />
12791384 </ StackItem >
12801385 </ Stack >
12811386 </ PageSection >
12821387 </ >
12831388 ) ;
12841389} ;
1285- export const MetricsPage = withFallback ( MetricsPage_ ) ;
1390+
1391+ const MetricsPage = withFallback ( MetricsPage_ ) ;
1392+
1393+ const MetricsPageWrapper_ : React . FC = ( ) => (
1394+ < QueryParamProvider adapter = { ReactRouter5Adapter } >
1395+ < MetricsPage />
1396+ </ QueryParamProvider >
1397+ ) ;
12861398
12871399type QueryTableProps = {
12881400 index : number ;
12891401 namespace ?: string ;
12901402 customDatasource ?: CustomDataSource ;
1403+ units : GraphUnits ;
12911404} ;
12921405
12931406type SeriesButtonProps = {
12941407 index : number ;
12951408 labels : PrometheusLabels ;
12961409} ;
12971410
1298- export default MetricsPage ;
1411+ export default MetricsPageWrapper_ ;
0 commit comments