From 5a71ec8ffdb8cdee688de7f9185e11bc171510b6 Mon Sep 17 00:00:00 2001 From: ricoberger Date: Sat, 24 Apr 2021 21:08:04 +0200 Subject: [PATCH] Improve legend at Prometheus query page Instead of the simple list, we are now using a table for the legend at the Prometheus query page. This is simular to the normal table legend type. We are now also using the color of the selected metric, when only one metric is displayed in the corresponding chart. --- CHANGELOG.md | 1 + .../prometheus/PrometheusChartDefault.tsx | 10 ++- .../PrometheusChartDefaultLegend.tsx | 18 ++--- .../plugins/prometheus/PrometheusPageData.tsx | 80 ++++++++++++++----- app/src/plugins/prometheus/helpers.ts | 12 +++ 5 files changed, 88 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d3b2c66e..4e8b2ecf6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ NOTE: As semantic versioning states all 0.y.z releases can contain breaking chan ### Changed - [#46](https://github.com/kobsio/kobs/pull/46): Support multiple types for the legend in a Prometheus chart and use a custom component to render the legend. +- [#47](https://github.com/kobsio/kobs/pull/47): Display the legend at the Prometheus page as table and use color of selected metric in chart. ## [v0.2.0](https://github.com/kobsio/kobs/releases/tag/v0.2.0) (2021-04-23) diff --git a/app/src/plugins/prometheus/PrometheusChartDefault.tsx b/app/src/plugins/prometheus/PrometheusChartDefault.tsx index 58151982b..824d4f591 100644 --- a/app/src/plugins/prometheus/PrometheusChartDefault.tsx +++ b/app/src/plugins/prometheus/PrometheusChartDefault.tsx @@ -26,6 +26,7 @@ export interface IPrometheusChartDefaultProps { unit: string; stacked: boolean; legend: string; + color?: string; metrics: Metrics.AsObject[]; } @@ -44,6 +45,7 @@ const PrometheusChartDefault: React.FunctionComponent { const refChart = useRef(null); @@ -131,7 +133,13 @@ const PrometheusChartDefault: React.FunctionComponent - {stacked ? {series} : {series}} + {color && series.length === 1 ? ( + {series} + ) : stacked ? ( + {series} + ) : ( + {series} + )} { - return colors[index % colors.length]; -}; +import { getLegendColorClass } from 'plugins/prometheus/helpers'; interface ILegendItem { childName: string; @@ -29,7 +19,11 @@ export interface IPrometheusChartDefaultLegendProps { toogleMetric: (index: string) => void; } -// +// PrometheusChartDefaultLegend is the component, which renders the legend for the default Prometheus chart. The user +// can decide between the following options: disabled, bottom and table. The bottom option is the default one. +// NOTE: The height of the legend + the chart must be 336px. When the legend is disabled the space is completly used by +// the chart. For the bottom and table option the legend height is 50px/80px plus a margin of 16px. The remaining space +// is used by the chart. const PrometheusChartDefaultLegend: React.FunctionComponent = ({ legend, legendData, diff --git a/app/src/plugins/prometheus/PrometheusPageData.tsx b/app/src/plugins/prometheus/PrometheusPageData.tsx index 4395ddcf0..a31424e94 100644 --- a/app/src/plugins/prometheus/PrometheusPageData.tsx +++ b/app/src/plugins/prometheus/PrometheusPageData.tsx @@ -1,17 +1,25 @@ import { + Button, + ButtonVariant, Card, CardBody, Flex, FlexItem, - SimpleList, - SimpleListItem, ToggleGroup, ToggleGroupItem, } from '@patternfly/react-core'; +import { EyeSlashIcon, SquareIcon } from '@patternfly/react-icons'; import React, { useState } from 'react'; +import { TableComposable, TableVariant, Tbody, Td, Th, Thead, Tr } from '@patternfly/react-table'; import { Metrics } from 'proto/prometheus_grpc_web_pb'; import PrometheusChartDefault from 'plugins/prometheus/PrometheusChartDefault'; +import { getLegendColorClass } from 'plugins/prometheus/helpers'; + +interface ISelectedMetrics { + color?: string; + metrics: Metrics.AsObject[]; +} interface IPrometheusPageDataProps { metrics: Metrics.AsObject[]; @@ -27,15 +35,15 @@ const PrometheusPageData: React.FunctionComponent = ({ }: IPrometheusPageDataProps) => { const [type, setType] = useState('line'); const [stacked, setStacked] = useState(false); - const [selectedMetrics, setSelectedMetrics] = useState([]); + const [selectedMetrics, setSelectedMetrics] = useState({ color: undefined, metrics: metrics }); // select is used to select a single metric, which should be shown in the rendered chart. If the currently selected // metric is clicked again, the filter will be removed and all metrics will be shown in the chart. - const select = (metric: Metrics.AsObject): void => { - if (selectedMetrics.length === 1 && selectedMetrics[0].label === metric.label) { - setSelectedMetrics(metrics); + const select = (metric: Metrics.AsObject, color: string): void => { + if (selectedMetrics.metrics.length === 1 && selectedMetrics.metrics[0].label === metric.label) { + setSelectedMetrics({ color: undefined, metrics: metrics }); } else { - setSelectedMetrics([metric]); + setSelectedMetrics({ color: color, metrics: [metric] }); } }; @@ -69,23 +77,55 @@ const PrometheusPageData: React.FunctionComponent = ({ unit="" stacked={stacked} legend="disabled" - metrics={selectedMetrics.length === 0 ? metrics : selectedMetrics} + color={selectedMetrics.metrics.length === 1 ? selectedMetrics.color : undefined} + metrics={selectedMetrics.metrics} />

 

- - {metrics.map((metric, index) => ( - select(metric)} - isActive={selectedMetrics.length === 1 && selectedMetrics[0].label === metric.label} - > - {metric.label === '{}' && metrics.length === queries.length ? queries[index] : metric.label} - {metric.dataList[metric.dataList.length - 1].y} - - ))} - + + + + Name + Min + Max + Avg + Current + + + + {metrics.map((metric, index) => ( + + + + + {metric.min} + {metric.max} + {metric.avg} + {metric.dataList[metric.dataList.length - 1].y} + + ))} + + ); diff --git a/app/src/plugins/prometheus/helpers.ts b/app/src/plugins/prometheus/helpers.ts index 47154ae33..111882247 100644 --- a/app/src/plugins/prometheus/helpers.ts +++ b/app/src/plugins/prometheus/helpers.ts @@ -1,3 +1,5 @@ +import { ChartThemeColor, getDarkThemeColors } from '@patternfly/react-charts'; + import { Chart, Data, Query, Spec, Variable } from 'proto/prometheus_grpc_web_pb'; import { Plugin } from 'proto/plugins_grpc_web_pb'; @@ -120,3 +122,13 @@ export const transformData = (data: Data.AsObject[], isHidden?: boolean): IData[ return { x: d.x, y: isNaN(d.y) || isHidden ? null : d.y }; }); }; + +// colors is an array with all the supported colors for a chart. These are the same colors as they are used for the +// bars, lines and areas in a chart. +export const colors = getDarkThemeColors(ChartThemeColor.multiOrdered).area.colorScale; + +// getLegendColorClass returns the color class for an item in the legend. When we have more series then colors, we start +// again with the first color. +export const getLegendColorClass = (index: number): string => { + return colors[index % colors.length]; +};