diff --git a/packages/superset-ui-number-format/package.json b/packages/superset-ui-number-format/package.json index fbe051b6e7..714ffea018 100644 --- a/packages/superset-ui-number-format/package.json +++ b/packages/superset-ui-number-format/package.json @@ -27,7 +27,6 @@ }, "dependencies": { "@superset-ui/core": "^0.6.0", - "d3-format": "^1.3.2", - "lodash": "^4.17.11" + "d3-format": "^1.3.2" } } diff --git a/packages/superset-ui-number-format/src/NumberFormatter.js b/packages/superset-ui-number-format/src/NumberFormatter.js index 47b54b1108..98f5c98808 100644 --- a/packages/superset-ui-number-format/src/NumberFormatter.js +++ b/packages/superset-ui-number-format/src/NumberFormatter.js @@ -8,6 +8,7 @@ export default class NumberFormatter extends ExtensibleFunction { label, description = '', formatFunc = isRequired('config.formatFunc'), + isInvalid = false, } = {}) { super((...args) => this.format(...args)); @@ -15,6 +16,7 @@ export default class NumberFormatter extends ExtensibleFunction { this.label = label || id; this.description = description; this.formatFunc = formatFunc; + this.isInvalid = isInvalid; } format(value) { diff --git a/packages/superset-ui-number-format/src/NumberFormatterRegistry.js b/packages/superset-ui-number-format/src/NumberFormatterRegistry.js index 79f1ed9a42..f348f633d5 100644 --- a/packages/superset-ui-number-format/src/NumberFormatterRegistry.js +++ b/packages/superset-ui-number-format/src/NumberFormatterRegistry.js @@ -1,5 +1,5 @@ import { RegistryWithDefaultKey } from '@superset-ui/core'; -import D3NumberFormatter from './formatters/D3NumberFormatter'; +import createD3NumberFormatter from './factories/createD3NumberFormatter'; import { SI_3_DIGIT } from './NumberFormats'; const DEFAULT_FORMAT = SI_3_DIGIT; @@ -20,7 +20,9 @@ export default class NumberFormatterRegistry extends RegistryWithDefaultKey { } // Create new formatter if does not exist - const formatter = new D3NumberFormatter(targetFormat); + const formatter = createD3NumberFormatter({ + formatString: targetFormat, + }); this.registerValue(targetFormat, formatter); return formatter; diff --git a/packages/superset-ui-number-format/src/factories/createD3NumberFormatter.js b/packages/superset-ui-number-format/src/factories/createD3NumberFormatter.js new file mode 100644 index 0000000000..4e1d42d8cc --- /dev/null +++ b/packages/superset-ui-number-format/src/factories/createD3NumberFormatter.js @@ -0,0 +1,29 @@ +import { format as d3Format } from 'd3-format'; +import { isRequired } from '@superset-ui/core'; +import NumberFormatter from '../NumberFormatter'; + +export default function createD3NumberFormatter({ + description, + formatString = isRequired('formatString'), + label, +} = {}) { + let formatFunc; + let isInvalid = false; + + try { + formatFunc = d3Format(formatString); + } catch (e) { + formatFunc = value => `${value} (Invalid format: ${formatString})`; + isInvalid = true; + } + + const id = formatString; + + return new NumberFormatter({ + description, + formatFunc, + id, + isInvalid, + label, + }); +} diff --git a/packages/superset-ui-number-format/src/factories/createSiAtMostNDigitFormatter.js b/packages/superset-ui-number-format/src/factories/createSiAtMostNDigitFormatter.js new file mode 100644 index 0000000000..2ce6284044 --- /dev/null +++ b/packages/superset-ui-number-format/src/factories/createSiAtMostNDigitFormatter.js @@ -0,0 +1,18 @@ +import { format as d3Format } from 'd3-format'; +import NumberFormatter from '../NumberFormatter'; + +export default function createSiAtMostNDigitFormatter({ description, n = 3, id, label } = {}) { + const siFormatter = d3Format(`.${n}s`); + + return new NumberFormatter({ + description, + formatFunc: value => { + const si = siFormatter(value); + + // Removing trailing `.00` if any + return si.slice(-1) < 'A' ? parseFloat(si).toString() : si; + }, + id: id || `si_at_most_${n}_digit`, + label: label || `SI with at most ${n} significant digits`, + }); +} diff --git a/packages/superset-ui-number-format/src/formatters/D3NumberFormatter.js b/packages/superset-ui-number-format/src/formatters/D3NumberFormatter.js deleted file mode 100644 index cd56e0b2be..0000000000 --- a/packages/superset-ui-number-format/src/formatters/D3NumberFormatter.js +++ /dev/null @@ -1,42 +0,0 @@ -import isString from 'lodash/isString'; -import { format as d3Format } from 'd3-format'; -import { isRequired } from '@superset-ui/core'; -import NumberFormatter from '../NumberFormatter'; - -export default class D3NumberFormatter extends NumberFormatter { - /** - * Pass only the D3 format string to constructor - * - * new D3NumberFormatter('.2f'); - * - * or accompany it with human-readable label and description - * - * new D3NumberFormatter({ - * id: '.2f', - * label: 'Float with 2 decimal points', - * description: 'lorem ipsum dolor sit amet', - * }); - * - * @param {String|Object} configOrFormatString - */ - constructor(configOrFormatString = isRequired('configOrFormatString')) { - const config = isString(configOrFormatString) - ? { id: configOrFormatString } - : configOrFormatString; - - let formatFunc; - let isInvalid = false; - - const { id, label, description } = config; - - try { - formatFunc = d3Format(id); - } catch (e) { - formatFunc = () => `Invalid format: ${id}`; - isInvalid = true; - } - - super({ description, formatFunc, id, label }); - this.isInvalid = isInvalid; - } -} diff --git a/packages/superset-ui-number-format/src/formatters/SiAtMostNDigitFormatter.js b/packages/superset-ui-number-format/src/formatters/SiAtMostNDigitFormatter.js deleted file mode 100644 index 9eca35732d..0000000000 --- a/packages/superset-ui-number-format/src/formatters/SiAtMostNDigitFormatter.js +++ /dev/null @@ -1,19 +0,0 @@ -import { format as d3Format } from 'd3-format'; -import NumberFormatter from '../NumberFormatter'; - -export default class SiAtMostNDigitFormatter extends NumberFormatter { - constructor(n = 3) { - const siFormatter = d3Format(`.${n}s`); - - super({ - formatFunc: value => { - const si = siFormatter(value); - - // Removing trailing `.00` if any - return si.slice(-1) < 'A' ? parseFloat(si).toString() : si; - }, - id: `si_at_most_${n}_digit`, - label: `SI with at most ${n} significant digits`, - }); - } -} diff --git a/packages/superset-ui-number-format/test/NumberFormatterRegistrySingleton.test.js b/packages/superset-ui-number-format/test/NumberFormatterRegistrySingleton.test.js index 194b237789..e7f5bf27e2 100644 --- a/packages/superset-ui-number-format/test/NumberFormatterRegistrySingleton.test.js +++ b/packages/superset-ui-number-format/test/NumberFormatterRegistrySingleton.test.js @@ -17,7 +17,7 @@ describe('NumberFormatterRegistrySingleton', () => { }); it('returns a format function even given invalid format', () => { const format = getNumberFormatter('xkcd'); - expect(format(12345)).toEqual('Invalid format: xkcd'); + expect(format(12345)).toEqual('12345 (Invalid format: xkcd)'); }); }); describe('formatNumber(format, value)', () => { diff --git a/packages/superset-ui-number-format/test/factories/createD3NumberFormatter.test.js b/packages/superset-ui-number-format/test/factories/createD3NumberFormatter.test.js new file mode 100644 index 0000000000..9ad4349e76 --- /dev/null +++ b/packages/superset-ui-number-format/test/factories/createD3NumberFormatter.test.js @@ -0,0 +1,49 @@ +import createD3NumberFormatter from '../../src/factories/createD3NumberFormatter'; + +describe('D3NumberFormatter', () => { + describe('new D3NumberFormatter(config)', () => { + it('requires config.formatString', () => { + expect(() => createD3NumberFormatter()).toThrow(); + }); + describe('config.formatString', () => { + it('creates a NumberFormatter with the formatString as id', () => { + const formatter = createD3NumberFormatter({ formatString: '.2f' }); + expect(formatter.id).toEqual('.2f'); + }); + describe('if it is valid d3 formatString', () => { + it('uses d3.format(config.formatString) as format function', () => { + const formatter = createD3NumberFormatter({ formatString: '.2f' }); + expect(formatter.format(100)).toEqual('100.00'); + }); + }); + describe('if it is invalid d3 formatString', () => { + it('The format function displays error message', () => { + const formatter = createD3NumberFormatter({ formatString: 'i-am-groot' }); + expect(formatter.format(12345.67)).toEqual('12345.67 (Invalid format: i-am-groot)'); + }); + it('also set formatter.isInvalid to true', () => { + const formatter = createD3NumberFormatter({ formatString: 'i-am-groot' }); + expect(formatter.isInvalid).toEqual(true); + }); + }); + }); + describe('config.label', () => { + it('set label if specified', () => { + const formatter = createD3NumberFormatter({ + formatString: '.2f', + label: 'float formatter', + }); + expect(formatter.label).toEqual('float formatter'); + }); + }); + describe('config.description', () => { + it('set decription if specified', () => { + const formatter = createD3NumberFormatter({ + description: 'lorem ipsum', + formatString: '.2f', + }); + expect(formatter.description).toEqual('lorem ipsum'); + }); + }); + }); +}); diff --git a/packages/superset-ui-number-format/test/formatters/SiAtMostNDigitFormatter.test.js b/packages/superset-ui-number-format/test/factories/createSiAtMostNDigitFormatter.test.js similarity index 87% rename from packages/superset-ui-number-format/test/formatters/SiAtMostNDigitFormatter.test.js rename to packages/superset-ui-number-format/test/factories/createSiAtMostNDigitFormatter.test.js index cfa19e289f..35b7635a38 100644 --- a/packages/superset-ui-number-format/test/formatters/SiAtMostNDigitFormatter.test.js +++ b/packages/superset-ui-number-format/test/factories/createSiAtMostNDigitFormatter.test.js @@ -1,14 +1,14 @@ import NumberFormatter from '../../src/NumberFormatter'; -import SiAtMostNDigitFormatter from '../../src/formatters/SiAtMostNDigitFormatter'; +import createSiAtMostNDigitFormatter from '../../src/factories/createSiAtMostNDigitFormatter'; describe('SiAtMostNDigitFormatter', () => { describe('new SiAtMostNDigitFormatter(n)', () => { it('creates an instance of NumberFormatter', () => { - const formatter = new SiAtMostNDigitFormatter(3); + const formatter = createSiAtMostNDigitFormatter({ n: 4 }); expect(formatter).toBeInstanceOf(NumberFormatter); }); it('when n is specified, it formats number in SI format with at most n significant digits', () => { - const formatter = new SiAtMostNDigitFormatter(2); + const formatter = createSiAtMostNDigitFormatter({ n: 2 }); expect(formatter(10)).toBe('10'); expect(formatter(1)).toBe('1'); expect(formatter(1.0)).toBe('1'); @@ -28,7 +28,7 @@ describe('SiAtMostNDigitFormatter', () => { expect(formatter(-0.23)).toBe('-230m'); }); it('when n is not specified, it defaults to n=3', () => { - const formatter = new SiAtMostNDigitFormatter(3); + const formatter = createSiAtMostNDigitFormatter(); expect(formatter(10)).toBe('10'); expect(formatter(1)).toBe('1'); expect(formatter(1.0)).toBe('1'); diff --git a/packages/superset-ui-number-format/test/formatters/D3NumberFormatter.test.js b/packages/superset-ui-number-format/test/formatters/D3NumberFormatter.test.js deleted file mode 100644 index 7698ea800b..0000000000 --- a/packages/superset-ui-number-format/test/formatters/D3NumberFormatter.test.js +++ /dev/null @@ -1,28 +0,0 @@ -import D3NumberFormatter from '../../src/formatters/D3NumberFormatter'; - -describe('D3NumberFormatter', () => { - describe('new D3NumberFormatter(config)', () => { - it('requires configOrFormatString', () => { - expect(() => new D3NumberFormatter()).toThrow(); - }); - describe('if configOrFormatString is string', () => { - it('uses the input as d3.format string', () => { - const formatter = new D3NumberFormatter('.2f'); - expect(formatter.format(100)).toEqual('100.00'); - }); - }); - describe('if configOrFormatString is not string', () => { - it('requires field config.id', () => { - expect(() => new D3NumberFormatter({})).toThrow(); - }); - it('uses d3.format(config.id) as format function', () => { - const formatter = new D3NumberFormatter({ id: ',.4f' }); - expect(formatter.format(12345.67)).toEqual('12,345.6700'); - }); - it('if it is an invalid d3 format, the format function displays error message', () => { - const formatter = new D3NumberFormatter({ id: 'i-am-groot' }); - expect(formatter.format(12345.67)).toEqual('Invalid format: i-am-groot'); - }); - }); - }); -});