feat(formatting): Add memory units adaptive formatter to format bytes (#30559)
This commit is contained in:
parent
47c1e09c75
commit
0e9c0f621a
|
|
@ -57,6 +57,8 @@ export const D3_FORMAT_OPTIONS: [string, string][] = [
|
|||
...d3Formatted,
|
||||
['DURATION', t('Duration in ms (66000 => 1m 6s)')],
|
||||
['DURATION_SUB', t('Duration in ms (1.40008 => 1ms 400µs 80ns)')],
|
||||
['MEMORY_DECIMAL', t('Memory in bytes - decimal (1024B => 1.024kB)')],
|
||||
['MEMORY_BINARY', t('Memory in bytes - binary (1024B => 1KiB)')],
|
||||
];
|
||||
|
||||
export const D3_TIME_FORMAT_DOCS = t(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import NumberFormatter from '../NumberFormatter';
|
||||
|
||||
export default function createMemoryFormatter(
|
||||
config: {
|
||||
description?: string;
|
||||
id?: string;
|
||||
label?: string;
|
||||
binary?: boolean;
|
||||
decimals?: number;
|
||||
} = {},
|
||||
) {
|
||||
const { description, id, label, binary, decimals = 2 } = config;
|
||||
|
||||
return new NumberFormatter({
|
||||
description,
|
||||
formatFunc: value => {
|
||||
if (value === 0) return '0B';
|
||||
|
||||
const sign = value > 0 ? '' : '-';
|
||||
const absValue = Math.abs(value);
|
||||
|
||||
const suffixes = binary
|
||||
? ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']
|
||||
: ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB', 'RB', 'QB'];
|
||||
const base = binary ? 1024 : 1000;
|
||||
|
||||
const i = Math.min(
|
||||
suffixes.length - 1,
|
||||
Math.floor(Math.log(absValue) / Math.log(base)),
|
||||
);
|
||||
return `${sign}${parseFloat((absValue / Math.pow(base, i)).toFixed(decimals))}${suffixes[i]}`;
|
||||
},
|
||||
id: id ?? 'memory_format',
|
||||
label: label ?? `Memory formatter`,
|
||||
});
|
||||
}
|
||||
|
|
@ -31,5 +31,6 @@ export {
|
|||
export { default as NumberFormatterRegistry } from './NumberFormatterRegistry';
|
||||
export { default as createD3NumberFormatter } from './factories/createD3NumberFormatter';
|
||||
export { default as createDurationFormatter } from './factories/createDurationFormatter';
|
||||
export { default as createMemoryFormatter } from './factories/createMemoryFormatter';
|
||||
export { default as createSiAtMostNDigitFormatter } from './factories/createSiAtMostNDigitFormatter';
|
||||
export { default as createSmartNumberFormatter } from './factories/createSmartNumberFormatter';
|
||||
|
|
|
|||
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { NumberFormatter, createMemoryFormatter } from '@superset-ui/core';
|
||||
|
||||
test('creates an instance of MemoryFormatter', () => {
|
||||
const formatter = createMemoryFormatter();
|
||||
expect(formatter).toBeInstanceOf(NumberFormatter);
|
||||
});
|
||||
|
||||
test('formats bytes in human readable format with default options', () => {
|
||||
const formatter = createMemoryFormatter();
|
||||
expect(formatter(0)).toBe('0B');
|
||||
expect(formatter(50)).toBe('50B');
|
||||
expect(formatter(555)).toBe('555B');
|
||||
expect(formatter(1000)).toBe('1kB');
|
||||
expect(formatter(1111)).toBe('1.11kB');
|
||||
expect(formatter(1024)).toBe('1.02kB');
|
||||
expect(formatter(1337)).toBe('1.34kB');
|
||||
expect(formatter(1999)).toBe('2kB');
|
||||
expect(formatter(10 * 1000)).toBe('10kB');
|
||||
expect(formatter(100 * 1000)).toBe('100kB');
|
||||
expect(formatter(Math.pow(1000, 2))).toBe('1MB');
|
||||
expect(formatter(Math.pow(1000, 3))).toBe('1GB');
|
||||
expect(formatter(Math.pow(1000, 4))).toBe('1TB');
|
||||
expect(formatter(Math.pow(1000, 5))).toBe('1PB');
|
||||
expect(formatter(Math.pow(1000, 6))).toBe('1EB');
|
||||
expect(formatter(Math.pow(1000, 7))).toBe('1ZB');
|
||||
expect(formatter(Math.pow(1000, 8))).toBe('1YB');
|
||||
expect(formatter(Math.pow(1000, 9))).toBe('1RB');
|
||||
expect(formatter(Math.pow(1000, 10))).toBe('1QB');
|
||||
expect(formatter(Math.pow(1000, 11))).toBe('1000QB');
|
||||
expect(formatter(Math.pow(1000, 12))).toBe('1000000QB');
|
||||
});
|
||||
|
||||
test('formats negative bytes in human readable format with default options', () => {
|
||||
const formatter = createMemoryFormatter();
|
||||
expect(formatter(-50)).toBe('-50B');
|
||||
});
|
||||
|
||||
test('formats float bytes in human readable format with default options', () => {
|
||||
const formatter = createMemoryFormatter();
|
||||
expect(formatter(10.666)).toBe('10.67B');
|
||||
expect(formatter(1200.666)).toBe('1.2kB');
|
||||
});
|
||||
|
||||
test('formats bytes in human readable format with additional binary option', () => {
|
||||
const formatter = createMemoryFormatter({ binary: true });
|
||||
expect(formatter(0)).toBe('0B');
|
||||
expect(formatter(50)).toBe('50B');
|
||||
expect(formatter(555)).toBe('555B');
|
||||
expect(formatter(1000)).toBe('1000B');
|
||||
expect(formatter(1111)).toBe('1.08KiB');
|
||||
expect(formatter(1024)).toBe('1KiB');
|
||||
expect(formatter(1337)).toBe('1.31KiB');
|
||||
expect(formatter(2047)).toBe('2KiB');
|
||||
expect(formatter(10 * 1024)).toBe('10KiB');
|
||||
expect(formatter(100 * 1024)).toBe('100KiB');
|
||||
expect(formatter(Math.pow(1024, 2))).toBe('1MiB');
|
||||
expect(formatter(Math.pow(1024, 3))).toBe('1GiB');
|
||||
expect(formatter(Math.pow(1024, 4))).toBe('1TiB');
|
||||
expect(formatter(Math.pow(1024, 5))).toBe('1PiB');
|
||||
expect(formatter(Math.pow(1024, 6))).toBe('1EiB');
|
||||
expect(formatter(Math.pow(1024, 7))).toBe('1ZiB');
|
||||
expect(formatter(Math.pow(1024, 8))).toBe('1YiB');
|
||||
expect(formatter(Math.pow(1024, 9))).toBe('1024YiB');
|
||||
expect(formatter(Math.pow(1024, 10))).toBe('1048576YiB');
|
||||
});
|
||||
|
||||
test('formats bytes in human readable format with additional decimals option', () => {
|
||||
const formatter0decimals = createMemoryFormatter({ decimals: 0 });
|
||||
expect(formatter0decimals(0)).toBe('0B');
|
||||
expect(formatter0decimals(1111)).toBe('1kB');
|
||||
|
||||
const formatter3decimals = createMemoryFormatter({ decimals: 3 });
|
||||
expect(formatter3decimals(0)).toBe('0B');
|
||||
expect(formatter3decimals(1111)).toBe('1.111kB');
|
||||
});
|
||||
|
|
@ -21,6 +21,7 @@ import {
|
|||
createD3NumberFormatter,
|
||||
createDurationFormatter,
|
||||
createSiAtMostNDigitFormatter,
|
||||
createMemoryFormatter,
|
||||
formatNumber,
|
||||
getNumberFormatter,
|
||||
getNumberFormatterRegistry,
|
||||
|
|
@ -35,6 +36,7 @@ describe('index', () => {
|
|||
createD3NumberFormatter,
|
||||
createDurationFormatter,
|
||||
createSiAtMostNDigitFormatter,
|
||||
createMemoryFormatter,
|
||||
formatNumber,
|
||||
getNumberFormatter,
|
||||
getNumberFormatterRegistry,
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import {
|
|||
createSmartDateFormatter,
|
||||
createSmartDateVerboseFormatter,
|
||||
createSmartDateDetailedFormatter,
|
||||
createMemoryFormatter,
|
||||
} from '@superset-ui/core';
|
||||
import { FormatLocaleDefinition } from 'd3-format';
|
||||
import { TimeLocaleDefinition } from 'd3-time-format';
|
||||
|
|
@ -76,7 +77,9 @@ export default function setupFormatters(
|
|||
.registerValue(
|
||||
'DURATION_SUB',
|
||||
createDurationFormatter({ formatSubMilliseconds: true }),
|
||||
);
|
||||
)
|
||||
.registerValue('MEMORY_DECIMAL', createMemoryFormatter({ binary: false }))
|
||||
.registerValue('MEMORY_BINARY', createMemoryFormatter({ binary: true }));
|
||||
|
||||
const timeFormatterRegistry = getTimeFormatterRegistry();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue