diff --git a/.betterer.results b/.betterer.results index 97a70b499c1..50c4ffb3006 100644 --- a/.betterer.results +++ b/.betterer.results @@ -924,6 +924,12 @@ exports[`better eslint`] = { "packages/grafana-ui/src/components/VizLegend/VizLegendListItem.tsx:5381": [ [0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "0"] ], + "packages/grafana-ui/src/components/VizLegend/VizLegendTable.tsx:5381": [ + [0, 0, 0, "Do not use any type assertions.", "0"], + [0, 0, 0, "Do not use any type assertions.", "1"], + [0, 0, 0, "Do not use any type assertions.", "2"], + [0, 0, 0, "Do not use any type assertions.", "3"] + ], "packages/grafana-ui/src/components/VizLegend/types.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "1"] diff --git a/packages/grafana-ui/src/components/VizLegend/VizLegendTable.tsx b/packages/grafana-ui/src/components/VizLegend/VizLegendTable.tsx index a8c29c7d10e..3a97ed9dfa0 100644 --- a/packages/grafana-ui/src/components/VizLegend/VizLegendTable.tsx +++ b/packages/grafana-ui/src/components/VizLegend/VizLegendTable.tsx @@ -1,14 +1,16 @@ import { css, cx } from '@emotion/css'; -import { orderBy } from 'lodash'; import React from 'react'; -import { DisplayValue, GrafanaTheme2 } from '@grafana/data'; +import { GrafanaTheme2 } from '@grafana/data'; import { useStyles2 } from '../../themes/ThemeContext'; import { Icon } from '../Icon/Icon'; import { LegendTableItem } from './VizLegendTableItem'; -import { VizLegendTableProps } from './types'; +import { VizLegendItem, VizLegendTableProps } from './types'; + +const nameSortKey = 'Name'; +const naturalCompare = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' }).compare; /** * @internal @@ -27,42 +29,53 @@ export const VizLegendTable = ({ isSortable, }: VizLegendTableProps): JSX.Element => { const styles = useStyles2(getStyles); - const stats: Record = {}; - const nameSortKey = 'Name'; + const header: Record = {}; if (isSortable) { - // placeholder displayValue for Name - stats[nameSortKey] = { description: 'name', numeric: 0, text: '' }; + header[nameSortKey] = ''; } for (const item of items) { if (item.getDisplayValues) { for (const displayValue of item.getDisplayValues()) { - stats[displayValue.title ?? '?'] = displayValue; + header[displayValue.title ?? '?'] = displayValue.description ?? ''; } } } - const sortedItems = sortKey - ? orderBy( - items, - (item) => { - if (sortKey === nameSortKey) { - return item.label; - } + if (sortKey != null) { + let itemVals = new Map(); - if (item.getDisplayValues) { - const stat = item.getDisplayValues().filter((stat) => stat.title === sortKey)[0]; + items.forEach((item) => { + if (sortKey === nameSortKey) { + itemVals.set(item, item.label); + } else if (item.getDisplayValues) { + const stat = item.getDisplayValues().find((stat) => stat.title === sortKey); + const val = stat == null || Number.isNaN(stat.numeric) ? -Infinity : stat.numeric; + itemVals.set(item, val); + } + }); - if (stat) { - return isNaN(stat.numeric) ? -Infinity : stat.numeric; - } - } - return undefined; - }, - sortDesc ? 'desc' : 'asc' - ) - : items; + let sortMult = sortDesc ? -1 : 1; + + if (sortKey === nameSortKey) { + // string sort + items.sort((a, b) => { + let aVal = itemVals.get(a) as string; + let bVal = itemVals.get(b) as string; + + return sortMult * naturalCompare(aVal, bVal); + }); + } else { + // numeric sort + items.sort((a, b) => { + let aVal = itemVals.get(a) as number; + let bVal = itemVals.get(b) as number; + + return sortMult * (aVal - bVal); + }); + } + } if (!itemRenderer) { /* eslint-disable-next-line react/display-name */ @@ -83,29 +96,26 @@ export const VizLegendTable = ({ {!isSortable && } - {Object.keys(stats).map((columnTitle) => { - const displayValue = stats[columnTitle]; - return ( - { - if (onToggleSort) { - onToggleSort(columnTitle); - } - }} - > - {columnTitle} - {sortKey === columnTitle && } - - ); - })} + {Object.keys(header).map((columnTitle) => ( + { + if (onToggleSort) { + onToggleSort(columnTitle); + } + }} + > + {columnTitle} + {sortKey === columnTitle && } + + ))} - {sortedItems.map(itemRenderer!)} + {items.map(itemRenderer!)} ); };