From 76b05b80a4e0f0842a812a4038038368dd1e69e5 Mon Sep 17 00:00:00 2001 From: Adela Almasan <88068998+adela-almasan@users.noreply.github.com> Date: Tue, 6 Jun 2023 15:16:16 -0500 Subject: [PATCH] Legend: Sort by name (#69490) --- .../configure-legend/index.md | 4 +- .../src/components/VizLegend/VizLegend.tsx | 2 + .../components/VizLegend/VizLegendTable.tsx | 19 ++++++++- .../src/components/VizLegend/types.ts | 1 + .../src/components/uPlot/PlotLegend.tsx | 1 + .../app/plugins/panel/barchart/utils.test.ts | 41 ------------------- public/app/plugins/panel/barchart/utils.ts | 14 ------- 7 files changed, 22 insertions(+), 60 deletions(-) diff --git a/docs/sources/panels-visualizations/configure-legend/index.md b/docs/sources/panels-visualizations/configure-legend/index.md index 59e2898fac4..93ad1a8e458 100644 --- a/docs/sources/panels-visualizations/configure-legend/index.md +++ b/docs/sources/panels-visualizations/configure-legend/index.md @@ -69,10 +69,8 @@ By default, Grafana specifies the color of your series data, which you can chang You can change legend mode to **Table** and choose [calculations]({{< relref "../../calculation-types/" >}}) to be displayed in the legend. Click the calculation name header in the legend table to sort the values in the table in ascending or descending order. -The sort order affects the positions of the bars in the Bar chart panel as well as the order of stacked series in the Time series and Bar chart panels. - {{% admonition type="note" %}} -This feature is only supported in these panels: Bar chart, Histogram, Time series, XY Chart. +This feature is only supported in these panels: Bar chart, Histogram, Time series. {{% /admonition %}} ![Sort legend series](/static/img/docs/legend/legend-series-sort-8-3.png). diff --git a/packages/grafana-ui/src/components/VizLegend/VizLegend.tsx b/packages/grafana-ui/src/components/VizLegend/VizLegend.tsx index b3fadcbe6be..140e5c3df37 100644 --- a/packages/grafana-ui/src/components/VizLegend/VizLegend.tsx +++ b/packages/grafana-ui/src/components/VizLegend/VizLegend.tsx @@ -25,6 +25,7 @@ export function VizLegend({ className, itemRenderer, readonly, + isSortable, }: LegendProps) { const { eventBus, onToggleSeriesVisibility, onToggleLegendSort } = usePanelContext(); @@ -96,6 +97,7 @@ export function VizLegend({ onLabelMouseOut={onMouseOut} itemRenderer={itemRenderer} readonly={readonly} + isSortable={isSortable} /> ); case LegendDisplayMode.List: diff --git a/packages/grafana-ui/src/components/VizLegend/VizLegendTable.tsx b/packages/grafana-ui/src/components/VizLegend/VizLegendTable.tsx index b384ca4f998..a425bb936f4 100644 --- a/packages/grafana-ui/src/components/VizLegend/VizLegendTable.tsx +++ b/packages/grafana-ui/src/components/VizLegend/VizLegendTable.tsx @@ -24,9 +24,16 @@ export const VizLegendTable = ({ onLabelMouseOver, onLabelMouseOut, readonly, + isSortable, }: VizLegendTableProps): JSX.Element => { const styles = useStyles2(getStyles); const stats: Record = {}; + const nameSortKey = 'Name'; + + if (isSortable) { + // placeholder displayValue for Name + stats[nameSortKey] = { description: 'name', numeric: 0, text: '' }; + } for (const item of items) { if (item.getDisplayValues) { @@ -40,6 +47,10 @@ export const VizLegendTable = ({ ? orderBy( items, (item) => { + if (sortKey === nameSortKey) { + return item.label; + } + if (item.getDisplayValues) { const stat = item.getDisplayValues().filter((stat) => stat.title === sortKey)[0]; return stat && stat.numeric; @@ -68,14 +79,14 @@ export const VizLegendTable = ({ - + {!isSortable && } {Object.keys(stats).map((columnTitle) => { const displayValue = stats[columnTitle]; return (
{ @@ -113,6 +124,10 @@ const getStyles = (theme: GrafanaTheme2) => ({ text-align: right; white-space: nowrap; `, + nameHeader: css` + text-align: left; + padding-left: 30px; + `, // This needs to be padding-right - icon size(xs==12) to avoid jumping withIcon: css` padding-right: 4px; diff --git a/packages/grafana-ui/src/components/VizLegend/types.ts b/packages/grafana-ui/src/components/VizLegend/types.ts index d7a7c0c3b7f..d64a96f1d5f 100644 --- a/packages/grafana-ui/src/components/VizLegend/types.ts +++ b/packages/grafana-ui/src/components/VizLegend/types.ts @@ -30,6 +30,7 @@ export interface VizLegendTableProps extends VizLegendBaseProps { sortBy?: string; sortDesc?: boolean; onToggleSort?: (sortBy: string) => void; + isSortable?: boolean; } export interface LegendProps extends VizLegendBaseProps, VizLegendTableProps { diff --git a/packages/grafana-ui/src/components/uPlot/PlotLegend.tsx b/packages/grafana-ui/src/components/uPlot/PlotLegend.tsx index 327af272497..40feb299f7a 100644 --- a/packages/grafana-ui/src/components/uPlot/PlotLegend.tsx +++ b/packages/grafana-ui/src/components/uPlot/PlotLegend.tsx @@ -150,6 +150,7 @@ export const PlotLegend = React.memo( displayMode={displayMode} sortBy={vizLayoutLegendProps.sortBy} sortDesc={vizLayoutLegendProps.sortDesc} + isSortable={true} /> ); diff --git a/public/app/plugins/panel/barchart/utils.test.ts b/public/app/plugins/panel/barchart/utils.test.ts index d979cef829c..99edf5007ea 100644 --- a/public/app/plugins/panel/barchart/utils.test.ts +++ b/public/app/plugins/panel/barchart/utils.test.ts @@ -226,47 +226,6 @@ describe('BarChart utils', () => { `); }); - it('should sort fields when legend sortBy and sortDesc are set', () => { - const frame = new MutableDataFrame({ - fields: [ - { name: 'string', type: FieldType.string, values: ['a', 'b', 'c'] }, - { name: 'a', values: [-10, 20, 10], state: { calcs: { min: -10 } } }, - { name: 'b', values: [20, 20, 20], state: { calcs: { min: 20 } } }, - { name: 'c', values: [10, 10, 10], state: { calcs: { min: 10 } } }, - ], - }); - - const resultAsc = prepareBarChartDisplayValues([frame], createTheme(), { - legend: { sortBy: 'Min', sortDesc: false }, - } as Options); - const displayValuesAsc = assertIsDefined('viz' in resultAsc ? resultAsc : null).viz[0]; - expect(displayValuesAsc.fields[0].type).toBe(FieldType.string); - expect(displayValuesAsc.fields[1].name).toBe('a'); - expect(displayValuesAsc.fields[2].name).toBe('c'); - expect(displayValuesAsc.fields[3].name).toBe('b'); - - const displayLegendValuesAsc = assertIsDefined('legend' in resultAsc ? resultAsc : null).legend; - expect(displayLegendValuesAsc.fields[0].type).toBe(FieldType.string); - expect(displayLegendValuesAsc.fields[1].name).toBe('a'); - expect(displayLegendValuesAsc.fields[2].name).toBe('c'); - expect(displayLegendValuesAsc.fields[3].name).toBe('b'); - - const resultDesc = prepareBarChartDisplayValues([frame], createTheme(), { - legend: { sortBy: 'Min', sortDesc: true }, - } as Options); - const displayValuesDesc = assertIsDefined('viz' in resultDesc ? resultDesc : null).viz[0]; - expect(displayValuesDesc.fields[0].type).toBe(FieldType.string); - expect(displayValuesDesc.fields[1].name).toBe('b'); - expect(displayValuesDesc.fields[2].name).toBe('c'); - expect(displayValuesDesc.fields[3].name).toBe('a'); - - const displayLegendValuesDesc = assertIsDefined('legend' in resultDesc ? resultDesc : null).legend; - expect(displayLegendValuesDesc.fields[0].type).toBe(FieldType.string); - expect(displayLegendValuesDesc.fields[1].name).toBe('b'); - expect(displayLegendValuesDesc.fields[2].name).toBe('c'); - expect(displayLegendValuesDesc.fields[3].name).toBe('a'); - }); - it('should remove unit from legend values when stacking is percent', () => { const frame = new MutableDataFrame({ fields: [ diff --git a/public/app/plugins/panel/barchart/utils.ts b/public/app/plugins/panel/barchart/utils.ts index 3e48e0e3ddc..5bef200938e 100644 --- a/public/app/plugins/panel/barchart/utils.ts +++ b/public/app/plugins/panel/barchart/utils.ts @@ -1,4 +1,3 @@ -import { orderBy } from 'lodash'; import uPlot, { Padding } from 'uplot'; import { @@ -11,7 +10,6 @@ import { getFieldSeriesColor, GrafanaTheme2, outerJoinDataFrames, - reduceField, TimeZone, VizOrientation, } from '@grafana/data'; @@ -474,18 +472,6 @@ export function prepareBarChartDisplayValues( } } - if (isLegendOrdered(options.legend)) { - const sortKey = options.legend.sortBy!.toLowerCase(); - const reducers = options.legend.calcs ?? [sortKey]; - fields = orderBy( - fields, - (field) => { - return reduceField({ field, reducers })[sortKey]; - }, - options.legend.sortDesc ? 'desc' : 'asc' - ); - } - let legendFields: Field[] = fields; if (options.stacking === StackingMode.Percent) { legendFields = fields.map((field) => {