From 692280cd325648c836f388eb050de1ff359d76f8 Mon Sep 17 00:00:00 2001 From: Adela Almasan <88068998+adela-almasan@users.noreply.github.com> Date: Wed, 28 Aug 2024 14:26:55 -0600 Subject: [PATCH] BarGauge: Add legend support (#92449) --- .../visualizations/bar-gauge/index.md | 4 ++ .../panelcfg/x/BarGaugePanelCfg_types.gen.ts | 2 +- .../grafana-ui/src/options/builder/legend.tsx | 5 +- .../plugins/panel/bargauge/BarGaugeLegend.tsx | 58 +++++++++++++++++++ .../panel/bargauge/BarGaugePanel.test.tsx | 8 ++- .../plugins/panel/bargauge/BarGaugePanel.tsx | 56 ++++++++++++------ public/app/plugins/panel/bargauge/module.tsx | 1 + .../app/plugins/panel/bargauge/panelcfg.cue | 8 +++ .../plugins/panel/bargauge/panelcfg.gen.ts | 2 +- 9 files changed, 120 insertions(+), 24 deletions(-) create mode 100644 public/app/plugins/panel/bargauge/BarGaugeLegend.tsx diff --git a/docs/sources/panels-visualizations/visualizations/bar-gauge/index.md b/docs/sources/panels-visualizations/visualizations/bar-gauge/index.md index e01345c485c..a3eeed23498 100644 --- a/docs/sources/panels-visualizations/visualizations/bar-gauge/index.md +++ b/docs/sources/panels-visualizations/visualizations/bar-gauge/index.md @@ -141,6 +141,10 @@ Automatically show y-axis scrollbar when there's a large amount of data. This option only applies when bar size is set to manual. {{% /admonition %}} +## Legend options + +{{< docs/shared lookup="visualizations/legend-options-1.md" source="grafana" version="" >}} + ## Standard options {{< docs/shared lookup="visualizations/standard-options.md" source="grafana" version="" >}} diff --git a/packages/grafana-schema/src/raw/composable/bargauge/panelcfg/x/BarGaugePanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/bargauge/panelcfg/x/BarGaugePanelCfg_types.gen.ts index f34fac40264..fbff065bcdd 100644 --- a/packages/grafana-schema/src/raw/composable/bargauge/panelcfg/x/BarGaugePanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/bargauge/panelcfg/x/BarGaugePanelCfg_types.gen.ts @@ -12,7 +12,7 @@ import * as common from '@grafana/schema'; export const pluginVersion = "11.3.0-pre"; -export interface Options extends common.SingleStatBaseOptions { +export interface Options extends common.OptionsWithLegend, common.SingleStatBaseOptions { displayMode: common.BarGaugeDisplayMode; maxVizHeight: number; minVizHeight: number; diff --git a/packages/grafana-ui/src/options/builder/legend.tsx b/packages/grafana-ui/src/options/builder/legend.tsx index dea6b45a2c0..d79edc65328 100644 --- a/packages/grafana-ui/src/options/builder/legend.tsx +++ b/packages/grafana-ui/src/options/builder/legend.tsx @@ -6,7 +6,8 @@ import { LegendDisplayMode, OptionsWithLegend } from '@grafana/schema'; */ export function addLegendOptions( builder: PanelOptionsEditorBuilder, - includeLegendCalcs = true + includeLegendCalcs = true, + showLegend = true ) { builder .addBooleanSwitch({ @@ -14,7 +15,7 @@ export function addLegendOptions( name: 'Visibility', category: ['Legend'], description: '', - defaultValue: true, + defaultValue: showLegend, }) .addRadio({ path: 'legend.displayMode', diff --git a/public/app/plugins/panel/bargauge/BarGaugeLegend.tsx b/public/app/plugins/panel/bargauge/BarGaugeLegend.tsx new file mode 100644 index 00000000000..6aa9609656d --- /dev/null +++ b/public/app/plugins/panel/bargauge/BarGaugeLegend.tsx @@ -0,0 +1,58 @@ +import { memo } from 'react'; + +import { DataFrame, FieldType, getFieldSeriesColor } from '@grafana/data'; +import { Field } from '@grafana/data/'; +import { AxisPlacement, VizLegendOptions } from '@grafana/schema'; +import { useTheme2, VizLayout, VizLayoutLegendProps, VizLegend, VizLegendItem } from '@grafana/ui'; +import { getDisplayValuesForCalcs } from '@grafana/ui/src/components/uPlot/utils'; + +interface BarGaugeLegendProps extends VizLegendOptions, Omit { + data: DataFrame[]; + colorField?: Field | null; +} + +export const BarGaugeLegend = memo( + ({ data, placement, calcs, displayMode, ...vizLayoutLegendProps }: BarGaugeLegendProps) => { + const theme = useTheme2(); + let legendItems: VizLegendItem[] = []; + + data.forEach((series, frameIndex) => { + series.fields.forEach((field, i) => { + const fieldIndex = i + 1; + + if (field.type === FieldType.time || field.config.custom?.hideFrom?.legend) { + return; + } + + const label = field.state?.displayName ?? field.name; + const color = getFieldSeriesColor(field, theme).color; + + const item: VizLegendItem = { + label: label.toString(), + color, + yAxis: field.config.custom?.axisPlacement === AxisPlacement.Right ? 2 : 1, + disabled: field.state?.hideFrom?.viz, + getDisplayValues: () => getDisplayValuesForCalcs(calcs, field, theme), + getItemKey: () => `${label}-${frameIndex}-${fieldIndex}`, + }; + + legendItems.push(item); + }); + }); + + return ( + + + + ); + } +); + +BarGaugeLegend.displayName = 'BarGaugeLegend'; diff --git a/public/app/plugins/panel/bargauge/BarGaugePanel.test.tsx b/public/app/plugins/panel/bargauge/BarGaugePanel.test.tsx index 35df060a347..7aa6ff9145b 100644 --- a/public/app/plugins/panel/bargauge/BarGaugePanel.test.tsx +++ b/public/app/plugins/panel/bargauge/BarGaugePanel.test.tsx @@ -3,7 +3,7 @@ import { uniqueId } from 'lodash'; import { dateMath, dateTime, EventBus, LoadingState, TimeRange, toDataFrame, VizOrientation } from '@grafana/data'; import { selectors } from '@grafana/e2e-selectors'; -import { BarGaugeDisplayMode, BarGaugeValueMode } from '@grafana/schema'; +import { BarGaugeDisplayMode, BarGaugeValueMode, LegendDisplayMode, LegendPlacement } from '@grafana/schema'; import { BarGaugeNamePlacement, BarGaugeSizing } from '@grafana/schema/dist/esm/common/common.gen'; import { BarGaugePanel, BarGaugePanelProps } from './BarGaugePanel'; @@ -105,6 +105,12 @@ function buildPanelData(overrideValues?: Partial): BarGaugeP valueMode: BarGaugeValueMode.Color, namePlacement: BarGaugeNamePlacement.Auto, sizing: BarGaugeSizing.Auto, + legend: { + showLegend: false, + placement: 'bottom' as LegendPlacement, + calcs: [], + displayMode: LegendDisplayMode.List, + }, }, transparent: false, timeRange, diff --git a/public/app/plugins/panel/bargauge/BarGaugePanel.tsx b/public/app/plugins/panel/bargauge/BarGaugePanel.tsx index 035f9f9b69a..4c2fba704d9 100644 --- a/public/app/plugins/panel/bargauge/BarGaugePanel.tsx +++ b/public/app/plugins/panel/bargauge/BarGaugePanel.tsx @@ -2,22 +2,23 @@ import { isNumber } from 'lodash'; import { PureComponent } from 'react'; import { + DisplayProcessor, + DisplayValue, DisplayValueAlignmentFactors, + FieldConfig, FieldDisplay, getDisplayValueAlignmentFactors, getFieldDisplayValues, PanelProps, - FieldConfig, - DisplayProcessor, - DisplayValue, VizOrientation, } from '@grafana/data'; import { BarGaugeSizing } from '@grafana/schema'; -import { BarGauge, DataLinksContextMenu, VizRepeater, VizRepeaterRenderValueProps } from '@grafana/ui'; +import { BarGauge, DataLinksContextMenu, VizLayout, VizRepeater, VizRepeaterRenderValueProps } from '@grafana/ui'; import { DataLinksContextMenuApi } from '@grafana/ui/src/components/DataLinks/DataLinksContextMenu'; import { config } from 'app/core/config'; -import { Options, defaultOptions } from './panelcfg.gen'; +import { BarGaugeLegend } from './BarGaugeLegend'; +import { defaultOptions, Options } from './panelcfg.gen'; export class BarGaugePanel extends PureComponent { renderComponent = ( @@ -123,26 +124,43 @@ export class BarGaugePanel extends PureComponent { return { minVizWidth, minVizHeight, maxVizHeight }; } + getLegend() { + const { options, data } = this.props; + const { legend } = options; + + if (legend.showLegend && data && data.series.length > 0) { + return ; + } + + return null; + } + render() { const { height, width, options, data, renderCounter } = this.props; const { minVizWidth, minVizHeight, maxVizHeight } = this.calcBarSize(); return ( - + + {(vizWidth: number, vizHeight: number) => { + return ( + + ); + }} + ); } } diff --git a/public/app/plugins/panel/bargauge/module.tsx b/public/app/plugins/panel/bargauge/module.tsx index be5cd7b3443..cf2605b7121 100644 --- a/public/app/plugins/panel/bargauge/module.tsx +++ b/public/app/plugins/panel/bargauge/module.tsx @@ -14,6 +14,7 @@ export const plugin = new PanelPlugin(BarGaugePanel) .setPanelOptions((builder) => { addStandardDataReduceOptions(builder); addOrientationOption(builder); + commonOptionsBuilder.addLegendOptions(builder, true, false); commonOptionsBuilder.addTextSizeOptions(builder); builder diff --git a/public/app/plugins/panel/bargauge/panelcfg.cue b/public/app/plugins/panel/bargauge/panelcfg.cue index 984dd1020a4..e22cfba6973 100644 --- a/public/app/plugins/panel/bargauge/panelcfg.cue +++ b/public/app/plugins/panel/bargauge/panelcfg.cue @@ -26,6 +26,14 @@ composableKinds: PanelCfg: { version: [0, 0] schema: { Options: { + common.OptionsWithLegend + + //// trying to set nested default, not working + //common.OptionsWithLegend | *{ + // legend: common.VizLegendOptions | *{ + // showLegend: false + // } + //} common.SingleStatBaseOptions displayMode: common.BarGaugeDisplayMode & (*"gradient" | _) valueMode: common.BarGaugeValueMode & (*"color" | _) diff --git a/public/app/plugins/panel/bargauge/panelcfg.gen.ts b/public/app/plugins/panel/bargauge/panelcfg.gen.ts index eb6f40ef6a5..ece366579a3 100644 --- a/public/app/plugins/panel/bargauge/panelcfg.gen.ts +++ b/public/app/plugins/panel/bargauge/panelcfg.gen.ts @@ -10,7 +10,7 @@ import * as common from '@grafana/schema'; -export interface Options extends common.SingleStatBaseOptions { +export interface Options extends common.OptionsWithLegend, common.SingleStatBaseOptions { displayMode: common.BarGaugeDisplayMode; maxVizHeight: number; minVizHeight: number;