mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Legend: Sort by name (#69490)
This commit is contained in:
parent
c0a1fc2cbd
commit
76b05b80a4
@ -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 %}}
|
||||
|
||||
.
|
||||
|
@ -25,6 +25,7 @@ export function VizLegend<T>({
|
||||
className,
|
||||
itemRenderer,
|
||||
readonly,
|
||||
isSortable,
|
||||
}: LegendProps<T>) {
|
||||
const { eventBus, onToggleSeriesVisibility, onToggleLegendSort } = usePanelContext();
|
||||
|
||||
@ -96,6 +97,7 @@ export function VizLegend<T>({
|
||||
onLabelMouseOut={onMouseOut}
|
||||
itemRenderer={itemRenderer}
|
||||
readonly={readonly}
|
||||
isSortable={isSortable}
|
||||
/>
|
||||
);
|
||||
case LegendDisplayMode.List:
|
||||
|
@ -24,9 +24,16 @@ export const VizLegendTable = <T extends unknown>({
|
||||
onLabelMouseOver,
|
||||
onLabelMouseOut,
|
||||
readonly,
|
||||
isSortable,
|
||||
}: VizLegendTableProps<T>): JSX.Element => {
|
||||
const styles = useStyles2(getStyles);
|
||||
const stats: Record<string, DisplayValue> = {};
|
||||
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 = <T extends unknown>({
|
||||
? 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 = <T extends unknown>({
|
||||
<table className={cx(styles.table, className)}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
{!isSortable && <th></th>}
|
||||
{Object.keys(stats).map((columnTitle) => {
|
||||
const displayValue = stats[columnTitle];
|
||||
return (
|
||||
<th
|
||||
title={displayValue.description}
|
||||
key={columnTitle}
|
||||
className={cx(styles.header, onToggleSort && styles.headerSortable, {
|
||||
className={cx(styles.header, onToggleSort && styles.headerSortable, isSortable && styles.nameHeader, {
|
||||
[styles.withIcon]: sortKey === columnTitle,
|
||||
})}
|
||||
onClick={() => {
|
||||
@ -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;
|
||||
|
@ -30,6 +30,7 @@ export interface VizLegendTableProps<T> extends VizLegendBaseProps<T> {
|
||||
sortBy?: string;
|
||||
sortDesc?: boolean;
|
||||
onToggleSort?: (sortBy: string) => void;
|
||||
isSortable?: boolean;
|
||||
}
|
||||
|
||||
export interface LegendProps<T = any> extends VizLegendBaseProps<T>, VizLegendTableProps<T> {
|
||||
|
@ -150,6 +150,7 @@ export const PlotLegend = React.memo(
|
||||
displayMode={displayMode}
|
||||
sortBy={vizLayoutLegendProps.sortBy}
|
||||
sortDesc={vizLayoutLegendProps.sortDesc}
|
||||
isSortable={true}
|
||||
/>
|
||||
</VizLayout.Legend>
|
||||
);
|
||||
|
@ -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: [
|
||||
|
@ -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) => {
|
||||
|
Loading…
Reference in New Issue
Block a user