mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
ValueFormats: dynamically create units (#20763)
* update fixed * update fixed * update fixed * don't change any tests * add mising space * Custom unit formats * return a string for kbn * return a string for kbn * return a string for kbn * Simplify unit tests * More units * fix more tests * fix more tests * fix more tests * format values * format values * TimeSeries to string * more kbn tests * use the formatted value * BarGauge: Fixed font size calculations * support prefix * add si support * avoid npe * BarGauge/BigValue: value formatting * fix some tests * fix tests * remove displayDateFormat * another unicode char * Graph: Use react unit picker * Updated unit picker * Fixed build errors * more formatting * graph2 tooltip formatting * optional chaining
This commit is contained in:
committed by
Torkel Ödegaard
parent
3289ee8b77
commit
d7c76dacad
@@ -11,6 +11,7 @@ import {
|
||||
ColorPicker,
|
||||
SeriesColorPickerPopoverWithTheme,
|
||||
SecretFormField,
|
||||
UnitPicker,
|
||||
DataLinksEditor,
|
||||
DataSourceHttpSettings,
|
||||
} from '@grafana/ui';
|
||||
@@ -61,6 +62,11 @@ export function registerAngularDirectives() {
|
||||
'onColorChange',
|
||||
'onToggleAxis',
|
||||
]);
|
||||
react2AngularDirective('unitPicker', UnitPicker, [
|
||||
'value',
|
||||
'width',
|
||||
['onChange', { watchDepth: 'reference', wrapApply: true }],
|
||||
]);
|
||||
react2AngularDirective('metricSelect', MetricSelect, [
|
||||
'options',
|
||||
'onChange',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { getFlotTickDecimals } from 'app/core/utils/ticks';
|
||||
import _ from 'lodash';
|
||||
import { getValueFormat, ValueFormatter, stringToJsRegex, DecimalCount } from '@grafana/data';
|
||||
import { getValueFormat, ValueFormatter, stringToJsRegex, DecimalCount, formattedValueToString } from '@grafana/data';
|
||||
|
||||
function matchSeriesOverride(aliasOrRegex: string, seriesAlias: string) {
|
||||
if (!aliasOrRegex) {
|
||||
@@ -339,7 +339,7 @@ export default class TimeSeries {
|
||||
if (!_.isFinite(value)) {
|
||||
value = null; // Prevent NaN formatting
|
||||
}
|
||||
return this.valueFormater(value, this.decimals, this.scaledDecimals);
|
||||
return formattedValueToString(this.valueFormater(value, this.decimals, this.scaledDecimals));
|
||||
}
|
||||
|
||||
isMsResolutionNeeded() {
|
||||
|
||||
52
public/app/core/utils/kbn.test.ts
Normal file
52
public/app/core/utils/kbn.test.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import kbn from './kbn';
|
||||
import { DecimalCount, TimeZone } from '@grafana/data';
|
||||
|
||||
interface ValueFormatTest {
|
||||
id: string;
|
||||
decimals?: DecimalCount;
|
||||
scaledDecimals?: DecimalCount;
|
||||
timeZone?: TimeZone;
|
||||
value: number;
|
||||
result: string;
|
||||
}
|
||||
|
||||
const formatTests: ValueFormatTest[] = [
|
||||
// Currancy
|
||||
{ id: 'currencyUSD', decimals: 2, value: 1532.82, result: '$1.53K' },
|
||||
{ id: 'currencyKRW', decimals: 2, value: 1532.82, result: '₩1.53K' },
|
||||
|
||||
// Typical
|
||||
{ id: 'ms', decimals: 4, value: 0.0024, result: '0.0024 ms' },
|
||||
{ id: 'ms', decimals: 0, value: 100, result: '100 ms' },
|
||||
{ id: 'ms', decimals: 2, value: 1250, result: '1.25 s' },
|
||||
{ id: 'ms', decimals: 1, value: 10000086.123, result: '2.8 hour' },
|
||||
{ id: 'ms', decimals: 0, value: 1200, result: '1 s' },
|
||||
{ id: 'short', decimals: 0, scaledDecimals: -1, value: 98765, result: '98.77 K' },
|
||||
{ id: 'short', decimals: 0, scaledDecimals: 0, value: 9876543, result: '9.876543 Mil' },
|
||||
{ id: 'kbytes', decimals: 3, value: 10000000, result: '9.537 GiB' },
|
||||
{ id: 'deckbytes', decimals: 3, value: 10000000, result: '10.000 GB' },
|
||||
{ id: 'megwatt', decimals: 3, value: 1000, result: '1.000 GW' },
|
||||
{ id: 'kohm', decimals: 3, value: 1000, result: '1.000 MΩ' },
|
||||
{ id: 'Mohm', decimals: 3, value: 1000, result: '1.000 GΩ' },
|
||||
|
||||
{ id: 'farad', decimals: 3, value: 1000, result: '1.000 kF' },
|
||||
{ id: 'µfarad', decimals: 3, value: 1000, result: '1.000 mF' },
|
||||
{ id: 'nfarad', decimals: 3, value: 1000, result: '1.000 µF' },
|
||||
{ id: 'pfarad', decimals: 3, value: 1000, result: '1.000 nF' },
|
||||
{ id: 'ffarad', decimals: 3, value: 1000, result: '1.000 pF' },
|
||||
|
||||
{ id: 'henry', decimals: 3, value: 1000, result: '1.000 kH' },
|
||||
{ id: 'mhenry', decimals: 3, value: 1000, result: '1.000 H' },
|
||||
{ id: 'µhenry', decimals: 3, value: 1000, result: '1.000 mH' },
|
||||
];
|
||||
|
||||
describe('Chcek KBN value formats', () => {
|
||||
for (const test of formatTests) {
|
||||
describe(`value format: ${test.id}`, () => {
|
||||
it(`should translate ${test.value} as ${test.result}`, () => {
|
||||
const result = kbn.valueFormats[test.id](test.value, test.decimals, test.scaledDecimals);
|
||||
expect(result).toBe(test.result);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -6,6 +6,8 @@ import {
|
||||
stringToJsRegex,
|
||||
TimeRange,
|
||||
deprecationWarning,
|
||||
DecimalCount,
|
||||
formattedValueToString,
|
||||
} from '@grafana/data';
|
||||
|
||||
const kbn: any = {};
|
||||
@@ -308,7 +310,10 @@ if (typeof Proxy !== 'undefined') {
|
||||
|
||||
const formatter = getValueFormat(name);
|
||||
if (formatter) {
|
||||
return formatter;
|
||||
// Return the results as a simple string
|
||||
return (value: number, decimals?: DecimalCount, scaledDecimals?: DecimalCount, isUtc?: boolean) => {
|
||||
return formattedValueToString(formatter(value, decimals, scaledDecimals, isUtc));
|
||||
};
|
||||
}
|
||||
|
||||
// default to look here
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<div ng-if="yaxis.show">
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label width-6">Unit</label>
|
||||
<div class="gf-form-dropdown-typeahead max-width-20" ng-model="yaxis.format" dropdown-typeahead2="ctrl.unitFormats" dropdown-typeahead-on-select="ctrl.setUnitFormat(yaxis, $subItem)"></div>
|
||||
<unit-picker onChange="ctrl.setUnitFormat(yaxis)" value="yaxis.format" width="20" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -49,9 +49,11 @@ export class AxesEditorCtrl {
|
||||
}
|
||||
}
|
||||
|
||||
setUnitFormat(axis: { format: any }, subItem: { value: any }) {
|
||||
axis.format = subItem.value;
|
||||
this.panelCtrl.render();
|
||||
setUnitFormat(axis: { format: any }) {
|
||||
return (unit: string) => {
|
||||
axis.format = unit;
|
||||
this.panelCtrl.render();
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
@@ -35,6 +35,7 @@ import {
|
||||
getDisplayProcessor,
|
||||
getFlotPairsConstant,
|
||||
PanelEvents,
|
||||
formattedValueToString,
|
||||
} from '@grafana/data';
|
||||
import { GraphContextMenuCtrl } from './GraphContextMenuCtrl';
|
||||
import { TimeSrv } from 'app/features/dashboard/services/TimeSrv';
|
||||
@@ -862,7 +863,7 @@ class GraphElement {
|
||||
if (!formatter) {
|
||||
throw new Error(`Unit '${format}' is not supported`);
|
||||
}
|
||||
return formatter(val, axis.tickDecimals, axis.scaledDecimals);
|
||||
return formattedValueToString(formatter(val, axis.tickDecimals, axis.scaledDecimals));
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ export const getGraphSeriesModel = (
|
||||
|
||||
const displayProcessor = getDisplayProcessor({
|
||||
config: {
|
||||
unit: fieldOptions?.defaults?.unit,
|
||||
decimals: legendOptions.decimals,
|
||||
},
|
||||
});
|
||||
@@ -68,7 +69,6 @@ export const getGraphSeriesModel = (
|
||||
|
||||
return {
|
||||
...statDisplayValue,
|
||||
text: statDisplayValue.text,
|
||||
title: stat,
|
||||
};
|
||||
});
|
||||
@@ -104,7 +104,7 @@ export const getGraphSeriesModel = (
|
||||
type: timeField.type,
|
||||
isUtc: timeZone === 'utc',
|
||||
config: {
|
||||
dateDisplayFormat: useMsDateFormat ? MS_DATE_TIME_FORMAT : DEFAULT_DATE_TIME_FORMAT,
|
||||
unit: `time:${useMsDateFormat ? MS_DATE_TIME_FORMAT : DEFAULT_DATE_TIME_FORMAT}`,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
GrafanaThemeType,
|
||||
stringToJsRegex,
|
||||
ScopedVars,
|
||||
formattedValueToString,
|
||||
} from '@grafana/data';
|
||||
import { ColumnStyle } from '@grafana/ui/src/components/Table/TableCellBuilder';
|
||||
import { TemplateSrv } from 'app/features/templating/template_srv';
|
||||
@@ -188,7 +189,7 @@ export class TableRenderer {
|
||||
}
|
||||
|
||||
this.setColorState(v, column.style);
|
||||
return valueFormatter(v, column.style.decimals, null);
|
||||
return formattedValueToString(valueFormatter(v, column.style.decimals, null));
|
||||
};
|
||||
}
|
||||
|
||||
@@ -226,7 +227,11 @@ export class TableRenderer {
|
||||
}
|
||||
|
||||
formatColumnValue(colIndex: number, value: any) {
|
||||
return this.formatters[colIndex] ? this.formatters[colIndex](value) : value;
|
||||
const fmt = this.formatters[colIndex];
|
||||
if (fmt) {
|
||||
return fmt(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
renderCell(columnIndex: number, rowIndex: number, value: any, addWidthHack = false) {
|
||||
|
||||
Reference in New Issue
Block a user