superset-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From kri...@apache.org
Subject [incubator-superset] branch master updated: Use @superset-ui/number-format and @superset-ui/time-format for formatting. (#6470)
Date Tue, 04 Dec 2018 21:24:17 GMT
This is an automated email from the ASF dual-hosted git repository.

kristw pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git


The following commit(s) were added to refs/heads/master by this push:
     new fcec748  Use @superset-ui/number-format and @superset-ui/time-format for formatting.
 (#6470)
fcec748 is described below

commit fcec748b62b333fbfbba23c6d49cdf98f7d6a280
Author: Krist Wongsuphasawat <krist.wongz@gmail.com>
AuthorDate: Tue Dec 4 13:24:07 2018 -0800

    Use @superset-ui/number-format and @superset-ui/time-format for formatting.  (#6470)
    
    refactor: proxy all d3 number and time formatting calls
---
 superset/assets/package.json                       |   2 +
 .../assets/spec/javascripts/modules/dates_spec.js  |  52 +---------
 .../assets/spec/javascripts/modules/utils_spec.jsx |  52 ----------
 .../javascripts/visualizations/nvd3/utils_spec.js  |  26 ++++-
 .../src/explore/components/RowCountLabel.jsx       |   5 +-
 superset/assets/src/modules/dates.js               | 112 ---------------------
 superset/assets/src/modules/utils.js               |  64 ------------
 superset/assets/src/preamble.js                    |   4 +
 superset/assets/src/setup/setupFormatters.js       |  35 +++++++
 .../src/visualizations/BigNumber/BigNumber.jsx     |   4 +-
 .../src/visualizations/BigNumber/transformProps.js |   7 +-
 .../assets/src/visualizations/Calendar/Calendar.js |   8 +-
 superset/assets/src/visualizations/Chord/Chord.js  |   3 +-
 .../src/visualizations/CountryMap/CountryMap.js    |   4 +-
 .../assets/src/visualizations/Heatmap/Heatmap.js   |   5 +-
 .../src/visualizations/Partition/Partition.js      |   7 +-
 .../src/visualizations/PivotTable/PivotTable.js    |   5 +-
 superset/assets/src/visualizations/Rose/Rose.js    |   7 +-
 .../assets/src/visualizations/Sankey/Sankey.js     |   3 +-
 .../assets/src/visualizations/Sunburst/Sunburst.js |   5 +-
 superset/assets/src/visualizations/Table/Table.js  |  13 +--
 .../visualizations/TimeTable/FormattedNumber.jsx   |   4 +-
 .../src/visualizations/TimeTable/SparklineCell.jsx |   6 +-
 .../src/visualizations/TimeTable/TimeTable.jsx     |  10 +-
 .../assets/src/visualizations/Treemap/Treemap.js   |   3 +-
 .../assets/src/visualizations/WorldMap/WorldMap.js |   3 +-
 superset/assets/src/visualizations/nvd3/NVD3Vis.js |  27 ++---
 superset/assets/src/visualizations/nvd3/utils.js   |  15 ++-
 superset/assets/yarn.lock                          |  17 +++-
 29 files changed, 162 insertions(+), 346 deletions(-)

diff --git a/superset/assets/package.json b/superset/assets/package.json
index f1940c7..466ad3e 100644
--- a/superset/assets/package.json
+++ b/superset/assets/package.json
@@ -55,6 +55,8 @@
     "@superset-ui/color": "^0.7.0",
     "@superset-ui/connection": "^0.5.0",
     "@superset-ui/core": "^0.7.0",
+    "@superset-ui/number-format": "^0.7.2",
+    "@superset-ui/time-format": "^0.7.2",
     "@superset-ui/translation": "^0.7.0",
     "@vx/legend": "^0.0.170",
     "@vx/responsive": "0.0.172",
diff --git a/superset/assets/spec/javascripts/modules/dates_spec.js b/superset/assets/spec/javascripts/modules/dates_spec.js
index 3f39343..d9f97e7 100644
--- a/superset/assets/spec/javascripts/modules/dates_spec.js
+++ b/superset/assets/spec/javascripts/modules/dates_spec.js
@@ -1,60 +1,10 @@
 import {
-  tickMultiFormat,
-  formatDate,
-  formatDateVerbose,
   fDuration,
   now,
   epochTimeXHoursAgo,
   epochTimeXDaysAgo,
   epochTimeXYearsAgo,
- } from '../../../src/modules/dates';
-
-describe('tickMultiFormat', () => {
-  it('is a function', () => {
-    expect(typeof tickMultiFormat).toBe('function');
-  });
-});
-
-describe('formatDate', () => {
-  it('is a function', () => {
-    expect(typeof formatDate).toBe('function');
-  });
-
-  it('shows only year when 1st day of the year', () => {
-    expect(formatDate(new Date('2020-01-01'))).toBe('2020');
-  });
-
-  it('shows only month when 1st of month', () => {
-    expect(formatDate(new Date('2020-03-01'))).toBe('March');
-  });
-
-  it('does not show day of week when it is Sunday', () => {
-    expect(formatDate(new Date('2020-03-15'))).toBe('Mar 15');
-  });
-
-  it('shows weekday when it is not Sunday (and no ms/sec/min/hr)', () => {
-    expect(formatDate(new Date('2020-03-03'))).toBe('Tue 03');
-  });
-});
-
-describe('formatDateVerbose', () => {
-  it('is a function', () => {
-    expect(typeof formatDateVerbose).toBe('function');
-  });
-
-  it('shows only year when 1st day of the year', () => {
-    expect(formatDateVerbose(new Date('2020-01-01'))).toBe('2020');
-  });
-
-  it('shows month and year when 1st of month', () => {
-    expect(formatDateVerbose(new Date('2020-03-01'))).toBe('Mar 2020');
-  });
-
-  it('shows weekday when any day of the month', () => {
-    expect(formatDateVerbose(new Date('2020-03-03'))).toBe('Tue Mar 3');
-    expect(formatDateVerbose(new Date('2020-03-15'))).toBe('Sun Mar 15');
-  });
-});
+} from '../../../src/modules/dates';
 
 describe('fDuration', () => {
   it('is a function', () => {
diff --git a/superset/assets/spec/javascripts/modules/utils_spec.jsx b/superset/assets/spec/javascripts/modules/utils_spec.jsx
index ca16d86..79a2044 100644
--- a/superset/assets/spec/javascripts/modules/utils_spec.jsx
+++ b/superset/assets/spec/javascripts/modules/utils_spec.jsx
@@ -1,9 +1,5 @@
 import {
   formatSelectOptionsForRange,
-  d3format,
-  d3FormatPreset,
-  d3TimeFormatPreset,
-  defaultNumberFormatter,
   mainMetric,
   roundDecimal,
 } from '../../../src/modules/utils';
@@ -25,54 +21,6 @@ describe('utils', () => {
     });
   });
 
-  describe('d3format', () => {
-    it('returns a string formatted number as specified', () => {
-      expect(d3format('.3s', 1234)).toBe('1.23k');
-      expect(d3format('.3s', 1237)).toBe('1.24k');
-      expect(d3format('', 1237)).toBe('1.24k');
-      expect(d3format('.2efd2.ef.2.e', 1237)).toBe('1237 (Invalid format: .2efd2.ef.2.e)');
-    });
-  });
-
-  describe('d3FormatPreset', () => {
-    it('is a function', () => {
-      expect(typeof d3FormatPreset).toBe('function');
-    });
-    it('returns a working formatter', () => {
-      expect(d3FormatPreset('.3s')(3000000)).toBe('3.00M');
-    });
-  });
-
-  describe('d3TimeFormatPreset', () => {
-    it('is a function', () => {
-      expect(typeof d3TimeFormatPreset).toBe('function');
-    });
-    it('returns a working formatter', () => {
-      expect(d3FormatPreset('smart_date')(0)).toBe('1970');
-      expect(d3FormatPreset('%%GIBBERISH')(0)).toBe('0 (Invalid format: %%GIBBERISH)');
-    });
-  });
-
-  describe('defaultNumberFormatter', () => {
-    expect(defaultNumberFormatter(10)).toBe('10');
-    expect(defaultNumberFormatter(1)).toBe('1');
-    expect(defaultNumberFormatter(1.0)).toBe('1');
-    expect(defaultNumberFormatter(10.0)).toBe('10');
-    expect(defaultNumberFormatter(10001)).toBe('10.0k');
-    expect(defaultNumberFormatter(10100)).toBe('10.1k');
-    expect(defaultNumberFormatter(111000000)).toBe('111M');
-    expect(defaultNumberFormatter(0.23)).toBe('230m');
-
-    expect(defaultNumberFormatter(-10)).toBe('-10');
-    expect(defaultNumberFormatter(-1)).toBe('-1');
-    expect(defaultNumberFormatter(-1.0)).toBe('-1');
-    expect(defaultNumberFormatter(-10.0)).toBe('-10');
-    expect(defaultNumberFormatter(-10001)).toBe('-10.0k');
-    expect(defaultNumberFormatter(-10101)).toBe('-10.1k');
-    expect(defaultNumberFormatter(-111000000)).toBe('-111M');
-    expect(defaultNumberFormatter(-0.23)).toBe('-230m');
-  });
-
   describe('mainMetric', () => {
     it('is null when no options', () => {
       expect(mainMetric([])).toBeUndefined();
diff --git a/superset/assets/spec/javascripts/visualizations/nvd3/utils_spec.js b/superset/assets/spec/javascripts/visualizations/nvd3/utils_spec.js
index 43a824e..623be1f 100644
--- a/superset/assets/spec/javascripts/visualizations/nvd3/utils_spec.js
+++ b/superset/assets/spec/javascripts/visualizations/nvd3/utils_spec.js
@@ -1,11 +1,26 @@
-import { formatLabel, tryNumify } from '../../../../src/visualizations/nvd3/utils';
+import { getTimeOrNumberFormatter, formatLabel, tryNumify } from '../../../../src/visualizations/nvd3/utils';
 
 describe('nvd3/utils', () => {
-  const verboseMap = {
-    foo: 'Foo',
-    bar: 'Bar',
-  };
+  describe('getTimeOrNumberFormatter(format)', () => {
+    it('is a function', () => {
+      expect(typeof getTimeOrNumberFormatter).toBe('function');
+    });
+    it('returns a date formatter if format is smart_date', () => {
+      const time = new Date(Date.UTC(2018, 10, 21, 22, 11));
+      expect(getTimeOrNumberFormatter('smart_date')(time)).toBe('10:11');
+    });
+    it('returns a number formatter otherwise', () => {
+      expect(getTimeOrNumberFormatter('.3s')(3000000)).toBe('3.00M');
+      expect(getTimeOrNumberFormatter()(3000100)).toBe('3.00M');
+    });
+  });
+
   describe('formatLabel()', () => {
+    const verboseMap = {
+      foo: 'Foo',
+      bar: 'Bar',
+    };
+
     it('formats simple labels', () => {
       expect(formatLabel('foo')).toBe('foo');
       expect(formatLabel(['foo'])).toBe('foo');
@@ -22,6 +37,7 @@ describe('nvd3/utils', () => {
       expect(formatLabel(['foo', 'bar', 'baz', '2 hours offset'], verboseMap)).toBe('Foo,
Bar, baz, 2 hours offset');
     });
   });
+
   describe('tryNumify()', () => {
     it('tryNumify works as expected', () => {
       expect(tryNumify(5)).toBe(5);
diff --git a/superset/assets/src/explore/components/RowCountLabel.jsx b/superset/assets/src/explore/components/RowCountLabel.jsx
index aea9bc4..2eeb80d 100644
--- a/superset/assets/src/explore/components/RowCountLabel.jsx
+++ b/superset/assets/src/explore/components/RowCountLabel.jsx
@@ -1,12 +1,11 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import { Label } from 'react-bootstrap';
+import { getNumberFormatter } from '@superset-ui/number-format';
 import { t } from '@superset-ui/translation';
 
-import { defaultNumberFormatter } from '../../modules/utils';
 import TooltipWrapper from '../../components/TooltipWrapper';
 
-
 const propTypes = {
   rowcount: PropTypes.number,
   limit: PropTypes.number,
@@ -21,7 +20,7 @@ const defaultProps = {
 export default function RowCountLabel({ rowcount, limit, suffix }) {
   const limitReached = rowcount === limit;
   const bsStyle = (limitReached || rowcount === 0) ? 'danger' : 'default';
-  const formattedRowCount = defaultNumberFormatter(rowcount);
+  const formattedRowCount = getNumberFormatter()(rowcount);
   const tooltip = (
     <span>
       {limitReached &&
diff --git a/superset/assets/src/modules/dates.js b/superset/assets/src/modules/dates.js
index 311340b..f5063b0 100644
--- a/superset/assets/src/modules/dates.js
+++ b/superset/assets/src/modules/dates.js
@@ -1,4 +1,3 @@
-import d3 from 'd3';
 import moment from 'moment';
 
 export function UTC(dttm) {
@@ -12,117 +11,6 @@ export function UTC(dttm) {
   );
 }
 
-export const tickMultiFormat = (() => {
-  const formatMillisecond = d3.time.format('.%Lms');
-  const formatSecond = d3.time.format(':%Ss');
-  const formatMinute = d3.time.format('%I:%M');
-  const formatHour = d3.time.format('%I %p');
-  const formatDay = d3.time.format('%a %d');
-  const formatWeek = d3.time.format('%b %d');
-  const formatMonth = d3.time.format('%B');
-  const formatYear = d3.time.format('%Y');
-
-  return function tickMultiFormatConcise(date) {
-    let formatter;
-    if (d3.time.second(date) < date) {
-      formatter = formatMillisecond;
-    } else if (d3.time.minute(date) < date) {
-      formatter = formatSecond;
-    } else if (d3.time.hour(date) < date) {
-      formatter = formatMinute;
-    } else if (d3.time.day(date) < date) {
-      formatter = formatHour;
-    } else if (d3.time.month(date) < date) {
-      formatter = d3.time.week(date) < date ? formatDay : formatWeek;
-    } else if (d3.time.year(date) < date) {
-      formatter = formatMonth;
-    } else {
-      formatter = formatYear;
-    }
-
-    return formatter(date);
-  };
-})();
-
-export const tickMultiFormatVerbose = d3.time.format.multi([
-  [
-    '.%L',
-    function (d) {
-      return d.getMilliseconds();
-    },
-  ],
-  // If there are millisections, show  only them
-  [
-    ':%S',
-    function (d) {
-      return d.getSeconds();
-    },
-  ],
-  // If there are seconds, show only them
-  [
-    '%a %b %d, %I:%M %p',
-    function (d) {
-      return d.getMinutes() !== 0;
-    },
-  ],
-  // If there are non-zero minutes, show Date, Hour:Minute [AM/PM]
-  [
-    '%a %b %d, %I %p',
-    function (d) {
-      return d.getHours() !== 0;
-    },
-  ],
-  // If there are hours that are multiples of 3, show date and AM/PM
-  [
-    '%a %b %e',
-    function (d) {
-      return d.getDate() >= 10;
-    },
-  ],
-  // If not the first of the month: "Tue Mar 2"
-  [
-    '%a %b%e',
-    function (d) {
-      return d.getDate() > 1;
-    },
-  ],
-  // If >= 10th of the month, compensate for padding : "Sun Mar 15"
-  [
-    '%b %Y',
-    function (d) {
-      return d.getMonth() !== 0 && d.getDate() === 1;
-    },
-  ],
-  // If the first of the month: 'Mar 2020'
-  [
-    '%Y',
-    function () {
-      return true;
-    },
-  ],  // fall back on just year: '2020'
-]);
-export const formatDate = function (dttm) {
-  const d = UTC(new Date(dttm));
-  return tickMultiFormat(d);
-};
-
-export const formatDateVerbose = function (dttm) {
-  const d = UTC(new Date(dttm));
-  return tickMultiFormatVerbose(d);
-};
-
-export const formatDateThunk = function (format) {
-  if (!format) {
-    return formatDateVerbose;
-  }
-
-  const formatter = d3.time.format(format);
-  return (dttm) => {
-    const d = UTC(new Date(dttm));
-    return formatter(d);
-  };
-};
-
 export const fDuration = function (t1, t2, format = 'HH:mm:ss.SS') {
   const diffSec = t2 - t1;
   const duration = moment(new Date(diffSec));
diff --git a/superset/assets/src/modules/utils.js b/superset/assets/src/modules/utils.js
index 9fbd1c8..11d2eb3 100644
--- a/superset/assets/src/modules/utils.js
+++ b/superset/assets/src/modules/utils.js
@@ -1,70 +1,6 @@
 /* eslint camelcase: 0 */
 import $ from 'jquery';
-import { format as d3Format } from 'd3-format';
 import { select as d3Select } from 'd3-selection';
-import { timeFormat as d3TimeFormat } from 'd3-time-format';
-import { formatDate, UTC } from './dates';
-
-const siFormatter = d3Format('.3s');
-
-export function defaultNumberFormatter(n) {
-  let si = siFormatter(n);
-  // Removing trailing `.00` if any
-  if (si.slice(-1) < 'A') {
-    si = parseFloat(si).toString();
-  }
-  return si;
-}
-
-export function d3FormatPreset(format) {
-  // like d3Format, but with support for presets like 'smart_date'
-  if (format === 'smart_date') {
-    return formatDate;
-  }
-  if (format) {
-    try {
-      return d3Format(format);
-    } catch (e) {
-      // eslint-disable-next-line no-console
-      console.warn(e);
-      return value => `${value} (Invalid format: ${format})`;
-    }
-  }
-  return defaultNumberFormatter;
-}
-
-export const d3TimeFormatPreset = function (format) {
-  const effFormat = format || 'smart_date';
-  if (effFormat === 'smart_date') {
-    return formatDate;
-  }
-  const f = d3TimeFormat(effFormat);
-  return function (dttm) {
-    const d = UTC(new Date(dttm));
-    return f(d);
-  };
-};
-
-const formatters = {};
-
-export function d3format(format, number) {
-  format = format || '.3s';
-  // Formats a number and memoizes formatters to be reused
-  if (!(format in formatters)) {
-    try {
-      formatters[format] = d3Format(format);
-    } catch (e) {
-      // eslint-disable-next-line no-console
-      console.warn(e);
-      return `${number} (Invalid format: ${format})`;
-    }
-  }
-  try {
-    return formatters[format](number);
-  } catch (e) {
-    return `${number} (Invalid format: ${format})`;
-  }
-}
 
 /*
   Utility function that takes a d3 svg:text selection and a max width, and splits the
diff --git a/superset/assets/src/preamble.js b/superset/assets/src/preamble.js
index 9d80dc9..3e96e60 100644
--- a/superset/assets/src/preamble.js
+++ b/superset/assets/src/preamble.js
@@ -2,6 +2,7 @@ import 'abortcontroller-polyfill/dist/abortcontroller-polyfill-only';
 import { configure } from '@superset-ui/translation';
 import setupClient from './setup/setupClient';
 import setupColors from './setup/setupColors';
+import setupFormatters from './setup/setupFormatters';
 
 // Configure translation
 if (typeof window !== 'undefined') {
@@ -22,3 +23,6 @@ setupClient();
 
 // Setup color palettes
 setupColors();
+
+// Setup number formatters
+setupFormatters();
diff --git a/superset/assets/src/setup/setupFormatters.js b/superset/assets/src/setup/setupFormatters.js
new file mode 100644
index 0000000..dd1f39f
--- /dev/null
+++ b/superset/assets/src/setup/setupFormatters.js
@@ -0,0 +1,35 @@
+import { getNumberFormatter, getNumberFormatterRegistry, createSiAtMostNDigitFormatter, NumberFormats
} from '@superset-ui/number-format';
+import { getTimeFormatterRegistry, smartDateFormatter, smartDateVerboseFormatter } from '@superset-ui/time-format';
+
+export default function setupFormatters() {
+  const defaultNumberFormatter = createSiAtMostNDigitFormatter({ n: 3 });
+
+  getNumberFormatterRegistry()
+    .registerValue(defaultNumberFormatter.id, defaultNumberFormatter)
+    .setDefaultKey(defaultNumberFormatter.id)
+    // Add shims for format strings that are deprecated or common typos.
+    // Temporary solution until performing a db migration to fix this.
+    .registerValue('+,', getNumberFormatter(NumberFormats.INTEGER_CHANGE))
+    .registerValue(',0', getNumberFormatter(',.4~f'))
+    .registerValue('.', getNumberFormatter('.4~f'))
+    .registerValue(',#', getNumberFormatter(',.4~f'))
+    .registerValue(',2f', getNumberFormatter(',.4~f'))
+    .registerValue(',g', getNumberFormatter(',.4~f'))
+    .registerValue('int', getNumberFormatter(NumberFormats.INTEGER))
+    .registerValue(',.', getNumberFormatter(',.4~f'))
+    .registerValue('.0%f', getNumberFormatter('.1%'))
+    .registerValue('.1%f', getNumberFormatter('.1%'))
+    .registerValue('.r', getNumberFormatter('.4~f'))
+    .registerValue(',0s', getNumberFormatter(',.4~f'))
+    .registerValue('%%%', getNumberFormatter('.0%'))
+    .registerValue(',0f', getNumberFormatter(',.4~f'))
+    .registerValue(',1', getNumberFormatter(',.4~f'))
+    .registerValue('$,0', getNumberFormatter('$,.4f'))
+    .registerValue('$,0f', getNumberFormatter('$,.4f'))
+    .registerValue('$,.f', getNumberFormatter('$,.4f'));
+
+  getTimeFormatterRegistry()
+    .registerValue('smart_date', smartDateFormatter)
+    .registerValue('smart_date_verbose', smartDateVerboseFormatter)
+    .setDefaultKey('smart_date');
+}
diff --git a/superset/assets/src/visualizations/BigNumber/BigNumber.jsx b/superset/assets/src/visualizations/BigNumber/BigNumber.jsx
index 9c80e04..b6c79e6 100644
--- a/superset/assets/src/visualizations/BigNumber/BigNumber.jsx
+++ b/superset/assets/src/visualizations/BigNumber/BigNumber.jsx
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
 import shortid from 'shortid';
 import { XYChart, AreaSeries, CrossHair, LinearGradient } from '@data-ui/xy-chart';
 import { BRAND_COLOR } from '@superset-ui/color';
-import { formatDateVerbose } from '../../modules/dates';
+import { smartDateVerboseFormatter } from '@superset-ui/time-format';
 import { computeMaxFontSize } from '../../modules/visUtils';
 
 import './BigNumber.css';
@@ -26,7 +26,7 @@ const PROPORTION = {
 export function renderTooltipFactory(formatValue) {
   return function renderTooltip({ datum }) { // eslint-disable-line
     const { x: rawDate, y: rawValue } = datum;
-    const formattedDate = formatDateVerbose(rawDate);
+    const formattedDate = smartDateVerboseFormatter(rawDate);
     const value = formatValue(rawValue);
 
     return (
diff --git a/superset/assets/src/visualizations/BigNumber/transformProps.js b/superset/assets/src/visualizations/BigNumber/transformProps.js
index 92a88f3..cb5dcc2 100644
--- a/superset/assets/src/visualizations/BigNumber/transformProps.js
+++ b/superset/assets/src/visualizations/BigNumber/transformProps.js
@@ -1,6 +1,5 @@
 import * as color from 'd3-color';
-import { format as d3Format } from 'd3-format';
-import { d3FormatPreset } from '../../modules/utils';
+import { getNumberFormatter, NumberFormats } from '@superset-ui/number-format';
 import { renderTooltipFactory } from './BigNumber';
 
 const TIME_COLUMN = '__timestamp';
@@ -43,7 +42,7 @@ export default function transformProps(chartProps) {
         const compareValue = sortedData[compareIndex][metricName];
         percentChange = compareValue === 0
           ? 0 : (bigNumber - compareValue) / Math.abs(compareValue);
-        const formatPercentChange = d3Format('+.1%');
+        const formatPercentChange = getNumberFormatter(NumberFormats.PERCENT_CHANGE_1_POINT);
         formattedSubheader = `${formatPercentChange(percentChange)} ${compareSuffix}`;
       }
     }
@@ -62,7 +61,7 @@ export default function transformProps(chartProps) {
     className = 'negative';
   }
 
-  const formatValue = d3FormatPreset(yAxisFormat);
+  const formatValue = getNumberFormatter(yAxisFormat);
 
   return {
     width,
diff --git a/superset/assets/src/visualizations/Calendar/Calendar.js b/superset/assets/src/visualizations/Calendar/Calendar.js
index 6b7aada..0dd3944 100644
--- a/superset/assets/src/visualizations/Calendar/Calendar.js
+++ b/superset/assets/src/visualizations/Calendar/Calendar.js
@@ -2,8 +2,10 @@ import PropTypes from 'prop-types';
 import { extent as d3Extent, range as d3Range } from 'd3-array';
 import { select as d3Select } from 'd3-selection';
 import { getSequentialSchemeRegistry } from '@superset-ui/color';
+import { getNumberFormatter } from '@superset-ui/number-format';
+import { getTimeFormatter } from '@superset-ui/time-format';
 import CalHeatMap from '../../../vendor/cal-heatmap/cal-heatmap';
-import { d3TimeFormatPreset, d3FormatPreset } from '../../modules/utils'; import { UTC }
from '../../modules/dates';
+import { UTC } from '../../modules/dates';
 import '../../../vendor/cal-heatmap/cal-heatmap.css';
 import './Calendar.css';
 
@@ -53,8 +55,8 @@ function Calendar(element, props) {
     verboseMap,
   } = props;
 
-  const valueFormatter = d3FormatPreset(valueFormat);
-  const timeFormatter = d3TimeFormatPreset(timeFormat);
+  const valueFormatter = getNumberFormatter(valueFormat);
+  const timeFormatter = getTimeFormatter(timeFormat);
 
   const container = d3Select(element)
     .style('height', height);
diff --git a/superset/assets/src/visualizations/Chord/Chord.js b/superset/assets/src/visualizations/Chord/Chord.js
index 05d416e..84e399f 100644
--- a/superset/assets/src/visualizations/Chord/Chord.js
+++ b/superset/assets/src/visualizations/Chord/Chord.js
@@ -2,6 +2,7 @@
 import d3 from 'd3';
 import PropTypes from 'prop-types';
 import { CategoricalColorNamespace } from '@superset-ui/color';
+import { getNumberFormatter } from '@superset-ui/number-format';
 import './Chord.css';
 
 const propTypes = {
@@ -28,7 +29,7 @@ function Chord(element, props) {
 
   const div = d3.select(element);
   const { nodes, matrix } = data;
-  const f = d3.format(numberFormat);
+  const f = getNumberFormatter(numberFormat);
   const colorFn = CategoricalColorNamespace.getScale(colorScheme);
 
   const outerRadius = Math.min(width, height) / 2 - 10;
diff --git a/superset/assets/src/visualizations/CountryMap/CountryMap.js b/superset/assets/src/visualizations/CountryMap/CountryMap.js
index ff22bcf..830ff28 100644
--- a/superset/assets/src/visualizations/CountryMap/CountryMap.js
+++ b/superset/assets/src/visualizations/CountryMap/CountryMap.js
@@ -1,8 +1,8 @@
 import d3 from 'd3';
 import PropTypes from 'prop-types';
 import { extent as d3Extent } from 'd3-array';
-import { format as d3Format } from 'd3-format';
 import { getSequentialSchemeRegistry } from '@superset-ui/color';
+import { getNumberFormatter } from '@superset-ui/number-format';
 import './CountryMap.css';
 
 const propTypes = {
@@ -32,7 +32,7 @@ function CountryMap(element, props) {
   } = props;
 
   const container = element;
-  const format = d3Format(numberFormat);
+  const format = getNumberFormatter(numberFormat);
   const colorScale = getSequentialSchemeRegistry()
     .get(linearColorScheme)
     .createLinearScale(d3Extent(data, v => v.metric));
diff --git a/superset/assets/src/visualizations/Heatmap/Heatmap.js b/superset/assets/src/visualizations/Heatmap/Heatmap.js
index 4c8f6aa..3e7d7d7 100644
--- a/superset/assets/src/visualizations/Heatmap/Heatmap.js
+++ b/superset/assets/src/visualizations/Heatmap/Heatmap.js
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
 import 'd3-svg-legend';
 import d3tip from 'd3-tip';
 import { getSequentialSchemeRegistry } from '@superset-ui/color';
+import { getNumberFormatter, NumberFormats } from '@superset-ui/number-format';
 
 import '../../../stylesheets/d3tip.css';
 import './Heatmap.css';
@@ -85,7 +86,7 @@ function Heatmap(element, props) {
     bottom: 35,
     left: 35,
   };
-  const valueFormatter = d3.format(numberFormat);
+  const valueFormatter = getNumberFormatter(numberFormat);
 
   // Dynamically adjusts  based on max x / y category lengths
   function adjustMargins() {
@@ -152,7 +153,7 @@ function Heatmap(element, props) {
 
   const hmWidth = width - (margin.left + margin.right);
   const hmHeight = height - (margin.bottom + margin.top);
-  const fp = d3.format('.2%');
+  const fp = getNumberFormatter(NumberFormats.PERCENT);
 
   const xScale = ordScale('x', null, sortXAxis);
   const yScale = ordScale('y', null, sortYAxis);
diff --git a/superset/assets/src/visualizations/Partition/Partition.js b/superset/assets/src/visualizations/Partition/Partition.js
index 539c024..dbb2e42 100644
--- a/superset/assets/src/visualizations/Partition/Partition.js
+++ b/superset/assets/src/visualizations/Partition/Partition.js
@@ -3,7 +3,8 @@ import d3 from 'd3';
 import PropTypes from 'prop-types';
 import { hierarchy } from 'd3-hierarchy';
 import { CategoricalColorNamespace } from '@superset-ui/color';
-import { d3TimeFormatPreset } from '../../modules/utils';
+import { getNumberFormatter } from '@superset-ui/number-format';
+import { getTimeFormatter } from '@superset-ui/time-format';
 import './Partition.css';
 
 // Compute dx, dy, x, y for each node and
@@ -93,8 +94,8 @@ function Icicle(element, props) {
   // Chart options
   const chartType = timeSeriesOption;
   const hasTime = ['adv_anal', 'time_series'].indexOf(chartType) >= 0;
-  const format = d3.format(numberFormat);
-  const timeFormat = d3TimeFormatPreset(dateTimeFormat);
+  const format = getNumberFormatter(numberFormat);
+  const timeFormat = getTimeFormatter(dateTimeFormat);
   const colorFn = CategoricalColorNamespace.getScale(colorScheme);
 
   div.selectAll('*').remove();
diff --git a/superset/assets/src/visualizations/PivotTable/PivotTable.js b/superset/assets/src/visualizations/PivotTable/PivotTable.js
index 71d0cfa..b5326bc 100644
--- a/superset/assets/src/visualizations/PivotTable/PivotTable.js
+++ b/superset/assets/src/visualizations/PivotTable/PivotTable.js
@@ -2,7 +2,8 @@ import dt from 'datatables.net-bs';
 import 'datatables.net-bs/css/dataTables.bootstrap.css';
 import $ from 'jquery';
 import PropTypes from 'prop-types';
-import { d3format, fixDataTableBodyHeight } from '../../modules/utils';
+import { formatNumber } from '@superset-ui/number-format';
+import { fixDataTableBodyHeight } from '../../modules/utils';
 import './PivotTable.css';
 
 dt(window, $);
@@ -59,7 +60,7 @@ function PivotTable(element, props) {
       const format = columnFormats[metric] || numberFormat || '.3s';
       const tdText = $(this)[0].textContent;
       if (!Number.isNaN(tdText) && tdText !== '') {
-        $(this)[0].textContent = d3format(format, tdText);
+        $(this)[0].textContent = formatNumber(format, tdText);
         $(this).attr('data-sort', tdText);
       }
     });
diff --git a/superset/assets/src/visualizations/Rose/Rose.js b/superset/assets/src/visualizations/Rose/Rose.js
index 097c918..a99d03f 100644
--- a/superset/assets/src/visualizations/Rose/Rose.js
+++ b/superset/assets/src/visualizations/Rose/Rose.js
@@ -3,7 +3,8 @@ import d3 from 'd3';
 import PropTypes from 'prop-types';
 import nv from 'nvd3';
 import { CategoricalColorNamespace } from '@superset-ui/color';
-import { d3TimeFormatPreset } from '../../modules/utils';
+import { getNumberFormatter } from '@superset-ui/number-format';
+import { getTimeFormatter } from '@superset-ui/time-format';
 import './Rose.css';
 
 const propTypes = {
@@ -58,8 +59,8 @@ function Rose(element, props) {
     .sort((a, b) => a - b);
   const numGrains = times.length;
   const numGroups = datum[times[0]].length;
-  const format = d3.format(numberFormat);
-  const timeFormat = d3TimeFormatPreset(dateTimeFormat);
+  const format = getNumberFormatter(numberFormat);
+  const timeFormat = getTimeFormatter(dateTimeFormat);
   const colorFn = CategoricalColorNamespace.getScale(colorScheme);
 
   d3.select('.nvtooltip').remove();
diff --git a/superset/assets/src/visualizations/Sankey/Sankey.js b/superset/assets/src/visualizations/Sankey/Sankey.js
index f80d032..5e4c6eb 100644
--- a/superset/assets/src/visualizations/Sankey/Sankey.js
+++ b/superset/assets/src/visualizations/Sankey/Sankey.js
@@ -3,6 +3,7 @@ import d3 from 'd3';
 import PropTypes from 'prop-types';
 import { sankey as d3Sankey } from 'd3-sankey';
 import { CategoricalColorNamespace } from '@superset-ui/color';
+import { getNumberFormatter, NumberFormats } from '@superset-ui/number-format';
 import './Sankey.css';
 
 const propTypes = {
@@ -16,7 +17,7 @@ const propTypes = {
   colorScheme: PropTypes.string,
 };
 
-const formatNumber = d3.format(',.2f');
+const formatNumber = getNumberFormatter(NumberFormats.FLOAT);
 
 function Sankey(element, props) {
   const {
diff --git a/superset/assets/src/visualizations/Sunburst/Sunburst.js b/superset/assets/src/visualizations/Sunburst/Sunburst.js
index 29496a6..5e13c19 100644
--- a/superset/assets/src/visualizations/Sunburst/Sunburst.js
+++ b/superset/assets/src/visualizations/Sunburst/Sunburst.js
@@ -2,6 +2,7 @@
 import d3 from 'd3';
 import PropTypes from 'prop-types';
 import { CategoricalColorNamespace } from '@superset-ui/color';
+import { getNumberFormatter, NumberFormats } from '@superset-ui/number-format';
 import { wrapSvgText } from '../../modules/utils';
 import './Sunburst.css';
 
@@ -79,8 +80,8 @@ function Sunburst(element, props) {
     .innerRadius(d => Math.sqrt(d.y))
     .outerRadius(d => Math.sqrt(d.y + d.dy));
 
-  const formatNum = d3.format('.3s');
-  const formatPerc = d3.format('.3p');
+  const formatNum = getNumberFormatter(NumberFormats.SI_3_DIGIT);
+  const formatPerc = getNumberFormatter(NumberFormats.PERCENT_3_POINT);
 
   container.select('svg').remove();
 
diff --git a/superset/assets/src/visualizations/Table/Table.js b/superset/assets/src/visualizations/Table/Table.js
index 7056235..23cdc07 100644
--- a/superset/assets/src/visualizations/Table/Table.js
+++ b/superset/assets/src/visualizations/Table/Table.js
@@ -4,8 +4,9 @@ import PropTypes from 'prop-types';
 import dt from 'datatables.net-bs';
 import 'datatables.net-bs/css/dataTables.bootstrap.css';
 import dompurify from 'dompurify';
-import { format as d3Format } from 'd3-format';
-import { fixDataTableBodyHeight, d3TimeFormatPreset } from '../../modules/utils';
+import { getNumberFormatter, NumberFormats } from '@superset-ui/number-format';
+import { getTimeFormatter } from '@superset-ui/time-format';
+import { fixDataTableBodyHeight } from '../../modules/utils';
 import './Table.css';
 
 dt(window, $);
@@ -46,8 +47,8 @@ const propTypes = {
   ]),
 };
 
-const formatValue = d3Format(',.0d');
-const formatPercent = d3Format('.3p');
+const formatValue = getNumberFormatter(NumberFormats.INTEGER);
+const formatPercent = getNumberFormatter(NumberFormats.PERCENT_3_POINT);
 function NOOP() {}
 
 function TableVis(element, props) {
@@ -96,7 +97,7 @@ function TableVis(element, props) {
     }
   }
 
-  const tsFormatter = d3TimeFormatPreset(tableTimestampFormat);
+  const tsFormatter = getTimeFormatter(tableTimestampFormat);
 
   const div = d3.select(element);
   div.html('');
@@ -130,7 +131,7 @@ function TableVis(element, props) {
         html = `<span class="like-pre">${dompurify.sanitize(val)}</span>`;
       }
       if (isMetric) {
-        html = d3Format(format || '0.3s')(val);
+        html = getNumberFormatter(format)(val);
       }
       if (key[0] === '%') {
         html = formatPercent(val);
diff --git a/superset/assets/src/visualizations/TimeTable/FormattedNumber.jsx b/superset/assets/src/visualizations/TimeTable/FormattedNumber.jsx
index eabbb0e..a4751e5 100644
--- a/superset/assets/src/visualizations/TimeTable/FormattedNumber.jsx
+++ b/superset/assets/src/visualizations/TimeTable/FormattedNumber.jsx
@@ -1,6 +1,6 @@
 import React from 'react';
 import PropTypes from 'prop-types';
-import { d3format } from '../../modules/utils';
+import { formatNumber } from '@superset-ui/number-format';
 
 const propTypes = {
   num: PropTypes.number,
@@ -15,7 +15,7 @@ const defaultProps = {
 function FormattedNumber({ num, format }) {
   if (format) {
     return (
-      <span title={num}>{d3format(format, num)}</span>
+      <span title={num}>{formatNumber(format, num)}</span>
     );
   }
   return <span>{num}</span>;
diff --git a/superset/assets/src/visualizations/TimeTable/SparklineCell.jsx b/superset/assets/src/visualizations/TimeTable/SparklineCell.jsx
index 1a49e35..bc58c10 100644
--- a/superset/assets/src/visualizations/TimeTable/SparklineCell.jsx
+++ b/superset/assets/src/visualizations/TimeTable/SparklineCell.jsx
@@ -1,7 +1,7 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import { Sparkline, LineSeries, PointSeries, HorizontalReferenceLine, VerticalReferenceLine,
WithTooltip } from '@data-ui/sparkline';
-import { d3format } from '../../modules/utils';
+import { formatNumber } from '@superset-ui/number-format';
 import { getTextDimension } from '../../modules/visUtils';
 
 const propTypes = {
@@ -110,8 +110,8 @@ class SparklineCell extends React.Component {
         ? maxBound
         : data.reduce((acc, current) => Math.max(acc, current), data[0]);
 
-      minLabel = d3format(numberFormat, min);
-      maxLabel = d3format(numberFormat, max);
+      minLabel = formatNumber(numberFormat, min);
+      maxLabel = formatNumber(numberFormat, max);
       labelLength = Math.max(
         getSparklineTextWidth(minLabel),
         getSparklineTextWidth(maxLabel),
diff --git a/superset/assets/src/visualizations/TimeTable/TimeTable.jsx b/superset/assets/src/visualizations/TimeTable/TimeTable.jsx
index 38bf058..667b377 100644
--- a/superset/assets/src/visualizations/TimeTable/TimeTable.jsx
+++ b/superset/assets/src/visualizations/TimeTable/TimeTable.jsx
@@ -3,10 +3,10 @@ import PropTypes from 'prop-types';
 import Mustache from 'mustache';
 import { scaleLinear } from 'd3-scale';
 import { Table, Thead, Th, Tr, Td } from 'reactable';
+import { formatNumber } from '@superset-ui/number-format';
+import { formatTime } from '@superset-ui/time-format';
 
 import MetricOption from '../../components/MetricOption';
-import { formatDateThunk } from '../../modules/dates';
-import { d3format } from '../../modules/utils';
 import InfoTooltipWithTrigger from '../../components/InfoTooltipWithTrigger';
 import FormattedNumber from './FormattedNumber';
 import SparklineCell from './SparklineCell';
@@ -113,8 +113,6 @@ class TimeTable extends React.PureComponent {
       sparkData = entries.map(d => d[valueField]);
     }
 
-    const formatDate = formatDateThunk(column.dateFormat);
-
     return (
       <Td
         column={column.key}
@@ -131,8 +129,8 @@ class TimeTable extends React.PureComponent {
           showYAxis={column.showYAxis}
           renderTooltip={({ index }) => (
             <div>
-              <strong>{d3format(column.d3format, sparkData[index])}</strong>
-              <div>{formatDate(entries[index].time)}</div>
+              <strong>{formatNumber(column.d3format, sparkData[index])}</strong>
+              <div>{formatTime(column.dateFormat, entries[index].time)}</div>
             </div>
           )}
         />
diff --git a/superset/assets/src/visualizations/Treemap/Treemap.js b/superset/assets/src/visualizations/Treemap/Treemap.js
index 17669d6..7ac0e1b 100644
--- a/superset/assets/src/visualizations/Treemap/Treemap.js
+++ b/superset/assets/src/visualizations/Treemap/Treemap.js
@@ -2,6 +2,7 @@
 import d3 from 'd3';
 import PropTypes from 'prop-types';
 import { CategoricalColorNamespace } from '@superset-ui/color';
+import { getNumberFormatter } from '@superset-ui/number-format';
 import './Treemap.css';
 
 // Declare PropTypes for recursive data structures
@@ -67,7 +68,7 @@ function Treemap(element, props) {
     treemapRatio,
   } = props;
   const div = d3.select(element);
-  const formatNumber = d3.format(numberFormat);
+  const formatNumber = getNumberFormatter(numberFormat);
   const colorFn = CategoricalColorNamespace.getScale(colorScheme);
   const data = clone(rawData);
 
diff --git a/superset/assets/src/visualizations/WorldMap/WorldMap.js b/superset/assets/src/visualizations/WorldMap/WorldMap.js
index b2cb2c0..91f654b 100644
--- a/superset/assets/src/visualizations/WorldMap/WorldMap.js
+++ b/superset/assets/src/visualizations/WorldMap/WorldMap.js
@@ -1,6 +1,7 @@
 import d3 from 'd3';
 import PropTypes from 'prop-types';
 import Datamap from 'datamaps/dist/datamaps.world.min';
+import { getNumberFormatter } from '@superset-ui/number-format';
 import './WorldMap.css';
 
 const propTypes = {
@@ -17,7 +18,7 @@ const propTypes = {
   showBubbles: PropTypes.bool,
 };
 
-const formatter = d3.format('.3s');
+const formatter = getNumberFormatter();
 
 function WorldMap(element, props) {
   const {
diff --git a/superset/assets/src/visualizations/nvd3/NVD3Vis.js b/superset/assets/src/visualizations/nvd3/NVD3Vis.js
index 526406b..5fbfed0 100644
--- a/superset/assets/src/visualizations/nvd3/NVD3Vis.js
+++ b/superset/assets/src/visualizations/nvd3/NVD3Vis.js
@@ -6,11 +6,11 @@ import moment from 'moment';
 import PropTypes from 'prop-types';
 import { t } from '@superset-ui/translation';
 import { CategoricalColorNamespace } from '@superset-ui/color';
+import { getNumberFormatter, formatNumber, NumberFormats } from '@superset-ui/number-format';
+import { getTimeFormatter, smartDateVerboseFormatter } from '@superset-ui/time-format';
 import 'nvd3/build/nv.d3.min.css';
 
 import ANNOTATION_TYPES, { applyNativeColumns } from '../../modules/AnnotationTypes';
-import { formatDateVerbose } from '../../modules/dates';
-import { d3TimeFormatPreset, d3FormatPreset } from '../../modules/utils';
 import { isTruthy } from '../../utils/common';
 import {
   cleanColorInput,
@@ -20,6 +20,7 @@ import {
   generateMultiLineTooltipContent,
   generateRichLineTooltipContent,
   getMaxLabelSize,
+  getTimeOrNumberFormatter,
   hideTooltips,
   tipFactory,
   tryNumify,
@@ -175,7 +176,7 @@ const propTypes = {
 };
 
 const NOOP = () => {};
-const formatter = d3.format('.3s');
+const formatter = getNumberFormatter();
 
 function nvd3Vis(element, props) {
   const {
@@ -342,7 +343,7 @@ function nvd3Vis(element, props) {
         if (pieLabelType !== 'key_percent' && pieLabelType !== 'key_value') {
           chart.labelType(pieLabelType);
         } else if (pieLabelType === 'key_value') {
-          chart.labelType(d => `${d.data.x}: ${d3.format('.3s')(d.data.y)}`);
+          chart.labelType(d => `${d.data.x}: ${formatNumber(NumberFormats.SI, d.data.y)}`);
         }
 
         if (pieLabelType === 'percent' || pieLabelType === 'key_percent') {
@@ -377,8 +378,8 @@ function nvd3Vis(element, props) {
             xField,
             yField,
             sizeField,
-            xFormatter: d3FormatPreset(xAxisFormat),
-            yFormatter: d3FormatPreset(yAxisFormat),
+            xFormatter: getTimeOrNumberFormatter(xAxisFormat),
+            yFormatter: getTimeOrNumberFormatter(yAxisFormat),
             sizeFormatter: formatter,
           }));
         chart.pointRange([5, maxBubbleSize ** 2]);
@@ -458,11 +459,11 @@ function nvd3Vis(element, props) {
 
     let xAxisFormatter;
     if (isTimeSeries) {
-      xAxisFormatter = d3TimeFormatPreset(xAxisFormat);
+      xAxisFormatter = getTimeFormatter(xAxisFormat);
       // In tooltips, always use the verbose time format
-      chart.interactiveLayer.tooltip.headerFormatter(formatDateVerbose);
+      chart.interactiveLayer.tooltip.headerFormatter(smartDateVerboseFormatter);
     } else {
-      xAxisFormatter = d3FormatPreset(xAxisFormat);
+      xAxisFormatter = getTimeOrNumberFormatter(xAxisFormat);
     }
     if (chart.x2Axis && chart.x2Axis.tickFormat) {
       chart.x2Axis.tickFormat(xAxisFormatter);
@@ -472,11 +473,11 @@ function nvd3Vis(element, props) {
       chart.xAxis.tickFormat(xAxisFormatter);
     }
 
-    let yAxisFormatter = d3FormatPreset(yAxisFormat);
+    let yAxisFormatter = getTimeOrNumberFormatter(yAxisFormat);
     if (chart.yAxis && chart.yAxis.tickFormat) {
       if (contribution || comparisonType === 'percentage') {
         // When computing a "Percentage" or "Contribution" selected, we force a percentage
format
-        yAxisFormatter = d3.format('.1%');
+        yAxisFormatter = getNumberFormatter(NumberFormats.PERCENT_1_POINT);
       }
       chart.yAxis.tickFormat(yAxisFormatter);
     }
@@ -519,8 +520,8 @@ function nvd3Vis(element, props) {
     }
 
     if (isVizTypes(['dual_line', 'line_multi'])) {
-      const yAxisFormatter1 = d3.format(yAxisFormat);
-      const yAxisFormatter2 = d3.format(yAxis2Format);
+      const yAxisFormatter1 = getNumberFormatter(yAxisFormat);
+      const yAxisFormatter2 = getNumberFormatter(yAxis2Format);
       chart.yAxis1.tickFormat(yAxisFormatter1);
       chart.yAxis2.tickFormat(yAxisFormatter2);
       const yAxisFormatters = data.map(datum => (
diff --git a/superset/assets/src/visualizations/nvd3/utils.js b/superset/assets/src/visualizations/nvd3/utils.js
index 52e0c3e..86ee61f 100644
--- a/superset/assets/src/visualizations/nvd3/utils.js
+++ b/superset/assets/src/visualizations/nvd3/utils.js
@@ -1,6 +1,8 @@
 import d3 from 'd3';
 import d3tip from 'd3-tip';
 import dompurify from 'dompurify';
+import { getNumberFormatter } from '@superset-ui/number-format';
+import { smartDateFormatter } from '@superset-ui/time-format';
 
 // Regexp for the label added to time shifted series
 // (1 hour offset, 2 days offset, etc.)
@@ -14,8 +16,19 @@ export function cleanColorInput(value) {
     .join(', ');
 }
 
+/**
+ * If format is smart_date, format date
+ * Otherwise, format number with the given format name
+ * @param {*} format
+ */
+export function getTimeOrNumberFormatter(format) {
+  return (format === 'smart_date')
+    ? smartDateFormatter
+    : getNumberFormatter(format);
+}
+
 export function drawBarValues(svg, data, stacked, axisFormat) {
-  const format = d3.format(axisFormat || '.3s');
+  const format = getNumberFormatter(axisFormat);
   const countSeriesDisplayed = data.length;
 
   const totalStackedValues = stacked && data.length !== 0 ?
diff --git a/superset/assets/yarn.lock b/superset/assets/yarn.lock
index dec3789..9cdccb9 100644
--- a/superset/assets/yarn.lock
+++ b/superset/assets/yarn.lock
@@ -432,6 +432,21 @@
   dependencies:
     lodash "^4.17.11"
 
+"@superset-ui/number-format@^0.7.2":
+  version "0.7.2"
+  resolved "https://registry.yarnpkg.com/@superset-ui/number-format/-/number-format-0.7.2.tgz#c193181d4bdc6eb63a48996012fae7baac5ad802"
+  dependencies:
+    "@superset-ui/core" "^0.7.0"
+    d3-format "^1.3.2"
+
+"@superset-ui/time-format@^0.7.2":
+  version "0.7.2"
+  resolved "https://registry.yarnpkg.com/@superset-ui/time-format/-/time-format-0.7.2.tgz#f5d21a8c46d76fc9603f2377f927ebf11593b4e1"
+  dependencies:
+    "@superset-ui/core" "^0.7.0"
+    d3-time "^1.0.10"
+    d3-time-format "^2.1.3"
+
 "@superset-ui/translation@^0.7.0":
   version "0.7.0"
   resolved "https://registry.yarnpkg.com/@superset-ui/translation/-/translation-0.7.0.tgz#8b9426a97d523df5aefe9242084264897efe252c"
@@ -3546,7 +3561,7 @@ d3-time-format@2, d3-time-format@^2.1.3:
   dependencies:
     d3-time "1"
 
-d3-time@1:
+d3-time@1, d3-time@^1.0.10:
   version "1.0.10"
   resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-1.0.10.tgz#8259dd71288d72eeacfd8de281c4bf5c7393053c"
 


Mime
View raw message