From a96eae46af852ba22ba1f2427333bc7d03ebd6c1 Mon Sep 17 00:00:00 2001 From: Grace Guo Date: Wed, 11 Dec 2019 12:01:11 -0800 Subject: [PATCH] [dashboard] fix time granularity display values (#8806) * [dashboard] fix time granularity display values * fix review comments --- .../components/FilterIndicatorsContainer.jsx | 30 ++++++++++++++++++- .../dashboard/containers/FilterIndicators.jsx | 3 +- .../dashboard/reducers/dashboardFilters.js | 2 ++ .../src/dashboard/reducers/getInitialState.js | 1 + .../util/getFilterConfigsFromFormdata.js | 15 ++++++---- .../assets/src/dashboard/util/propShapes.jsx | 1 + superset/assets/src/explore/constants.js | 10 +++++++ superset/assets/src/explore/controls.jsx | 11 +++---- .../visualizations/FilterBox/FilterBox.jsx | 6 ++-- 9 files changed, 62 insertions(+), 17 deletions(-) diff --git a/superset/assets/src/dashboard/components/FilterIndicatorsContainer.jsx b/superset/assets/src/dashboard/components/FilterIndicatorsContainer.jsx index 795c645b4c..549d3838f0 100644 --- a/superset/assets/src/dashboard/components/FilterIndicatorsContainer.jsx +++ b/superset/assets/src/dashboard/components/FilterIndicatorsContainer.jsx @@ -26,6 +26,7 @@ import { FILTER_INDICATORS_DISPLAY_LENGTH } from '../util/constants'; import { getChartIdsInFilterScope } from '../util/activeDashboardFilters'; import { getDashboardFilterKey } from '../util/getDashboardFilterKey'; import { getFilterColorMap } from '../util/dashboardFiltersColorMap'; +import { TIME_FILTER_MAP } from '../../visualizations/FilterBox/FilterBox'; const propTypes = { // from props @@ -34,6 +35,7 @@ const propTypes = { chartStatus: PropTypes.string, // from redux + datasources: PropTypes.object.isRequired, setDirectPathToChild: PropTypes.func.isRequired, filterFieldOnFocus: PropTypes.object.isRequired, }; @@ -42,6 +44,11 @@ const defaultProps = { chartStatus: 'loading', }; +const TIME_GRANULARITY_FIELDS = [ + TIME_FILTER_MAP.granularity, + TIME_FILTER_MAP.time_grain_sqla, +]; + function sortByIndicatorLabel(indicator1, indicator2) { const s1 = (indicator1.label || indicator1.name).toLowerCase(); const s2 = (indicator2.label || indicator2.name).toLowerCase(); @@ -56,6 +63,7 @@ function sortByIndicatorLabel(indicator1, indicator2) { export default class FilterIndicatorsContainer extends React.PureComponent { getFilterIndicators() { const { + datasources = {}, dashboardFilters, chartId: currentChartId, filterFieldOnFocus, @@ -66,12 +74,12 @@ export default class FilterIndicatorsContainer extends React.PureComponent { } const dashboardFiltersColorMap = getFilterColorMap(); - const sortIndicatorsByEmptiness = Object.values(dashboardFilters).reduce( (indicators, dashboardFilter) => { const { chartId, componentId, + datasourceId, directPathToFilter, isDateFilter, isInstantFilter, @@ -79,6 +87,7 @@ export default class FilterIndicatorsContainer extends React.PureComponent { labels, scopes, } = dashboardFilter; + const datasource = datasources[datasourceId] || {}; if (currentChartId !== chartId) { Object.keys(columns) @@ -111,6 +120,25 @@ export default class FilterIndicatorsContainer extends React.PureComponent { name === filterFieldOnFocus.column, }; + // map time granularity value to datasource configure + if (isDateFilter && TIME_GRANULARITY_FIELDS.includes(name)) { + const timeGranularityConfig = + (name === TIME_FILTER_MAP.time_grain_sqla + ? datasource.time_grain_sqla + : datasource.granularity) || []; + const timeGranularityDisplayMapping = timeGranularityConfig.reduce( + (map, [key, value]) => ({ + ...map, + [key]: value, + }), + {}, + ); + + indicator.values = indicator.values.map( + value => timeGranularityDisplayMapping[value] || value, + ); + } + if (isEmpty(indicator.values)) { indicators[1].push(indicator); } else { diff --git a/superset/assets/src/dashboard/containers/FilterIndicators.jsx b/superset/assets/src/dashboard/containers/FilterIndicators.jsx index 80e3f77f0d..ebc8259adc 100644 --- a/superset/assets/src/dashboard/containers/FilterIndicators.jsx +++ b/superset/assets/src/dashboard/containers/FilterIndicators.jsx @@ -23,13 +23,14 @@ import FilterIndicatorsContainer from '../components/FilterIndicatorsContainer'; import { setDirectPathToChild } from '../actions/dashboardState'; function mapStateToProps( - { dashboardState, dashboardFilters, dashboardLayout, charts }, + { datasources, dashboardState, dashboardFilters, dashboardLayout, charts }, ownProps, ) { const chartId = ownProps.chartId; const chartStatus = (charts[chartId] || {}).chartStatus; return { + datasources, dashboardFilters, chartId, chartStatus, diff --git a/superset/assets/src/dashboard/reducers/dashboardFilters.js b/superset/assets/src/dashboard/reducers/dashboardFilters.js index 7886ddc241..2731e23ff4 100644 --- a/superset/assets/src/dashboard/reducers/dashboardFilters.js +++ b/superset/assets/src/dashboard/reducers/dashboardFilters.js @@ -41,6 +41,7 @@ export const dashboardFilter = { chartId: null, componentId: null, filterName: null, + datasourceId: null, directPathToFilter: [], isDateFilter: false, isInstantFilter: true, @@ -71,6 +72,7 @@ export default function dashboardFiltersReducer(dashboardFilters = {}, action) { ...dashboardFilter, chartId, componentId: component.id, + datasourceId: form_data.datasource, filterName: component.meta.sliceName, directPathToFilter, columns, diff --git a/superset/assets/src/dashboard/reducers/getInitialState.js b/superset/assets/src/dashboard/reducers/getInitialState.js index bc32adcc4c..4596f63614 100644 --- a/superset/assets/src/dashboard/reducers/getInitialState.js +++ b/superset/assets/src/dashboard/reducers/getInitialState.js @@ -223,6 +223,7 @@ export default function(bootstrapData) { ...dashboardFilter, chartId: key, componentId, + datasourceId: slice.form_data.datasource, filterName: slice.slice_name, directPathToFilter, columns, diff --git a/superset/assets/src/dashboard/util/getFilterConfigsFromFormdata.js b/superset/assets/src/dashboard/util/getFilterConfigsFromFormdata.js index 82f9fbc2f9..c8caeb3a34 100644 --- a/superset/assets/src/dashboard/util/getFilterConfigsFromFormdata.js +++ b/superset/assets/src/dashboard/util/getFilterConfigsFromFormdata.js @@ -17,11 +17,8 @@ * under the License. */ /* eslint-disable camelcase */ -import { - TIME_FILTER_MAP, - TIME_RANGE, - FILTER_LABELS, -} from '../../visualizations/FilterBox/FilterBox'; +import { TIME_FILTER_MAP } from '../../visualizations/FilterBox/FilterBox'; +import { TIME_FILTER_LABELS } from '../../explore/constants'; export default function getFilterConfigsFromFormdata(form_data = {}) { const { @@ -58,7 +55,13 @@ export default function getFilterConfigsFromFormdata(form_data = {}) { }; const updatedLabels = { ...configs.labels, - [TIME_FILTER_MAP.time_range]: FILTER_LABELS[TIME_RANGE], + ...Object.entries(TIME_FILTER_MAP).reduce( + (map, [key, value]) => ({ + ...map, + [value]: TIME_FILTER_LABELS[key], + }), + {}, + ), }; if (show_sqla_time_granularity) { diff --git a/superset/assets/src/dashboard/util/propShapes.jsx b/superset/assets/src/dashboard/util/propShapes.jsx index 6fb83e8c42..6b41b8a490 100644 --- a/superset/assets/src/dashboard/util/propShapes.jsx +++ b/superset/assets/src/dashboard/util/propShapes.jsx @@ -87,6 +87,7 @@ export const dashboardFilterPropShape = PropTypes.shape({ chartId: PropTypes.number.isRequired, componentId: PropTypes.string.isRequired, filterName: PropTypes.string.isRequired, + datasourceId: PropTypes.string.isRequired, directPathToFilter: PropTypes.arrayOf(PropTypes.string).isRequired, isDateFilter: PropTypes.bool.isRequired, isInstantFilter: PropTypes.bool.isRequired, diff --git a/superset/assets/src/explore/constants.js b/superset/assets/src/explore/constants.js index 468d02f5c2..8f1b3959bb 100644 --- a/superset/assets/src/explore/constants.js +++ b/superset/assets/src/explore/constants.js @@ -16,6 +16,8 @@ * specific language governing permissions and limitations * under the License. */ +import { t } from '@superset-ui/translation'; + export const AGGREGATES = { AVG: 'AVG', COUNT: 'COUNT ', @@ -57,3 +59,11 @@ export const sqlaAutoGeneratedMetricRegex = /^(LONG|DOUBLE|FLOAT)?(SUM|AVG|MAX|M export const druidAutoGeneratedMetricRegex = /^(LONG|DOUBLE|FLOAT)?(SUM|MAX|MIN|COUNT)\([A-Z0-9_."]*\)$/i; export const EXPLORE_ONLY_VIZ_TYPE = ['separator', 'markup']; + +export const TIME_FILTER_LABELS = { + time_range: t('Time Range'), + granularity_sqla: t('Time Column'), + time_grain_sqla: t('Time Grain'), + druid_time_origin: t('Origin'), + granularity: t('Time Granularity'), +}; diff --git a/superset/assets/src/explore/controls.jsx b/superset/assets/src/explore/controls.jsx index 05b5d6e04c..06c0c5c01f 100644 --- a/superset/assets/src/explore/controls.jsx +++ b/superset/assets/src/explore/controls.jsx @@ -72,6 +72,7 @@ import * as v from './validators'; import ColumnOption from '../components/ColumnOption'; import OptionDescription from '../components/OptionDescription'; import { DEFAULT_VIEWPORT } from '../explore/components/controls/ViewportControl'; +import { TIME_FILTER_LABELS } from './constants'; const categoricalSchemeRegistry = getCategoricalSchemeRegistry(); const sequentialSchemeRegistry = getSequentialSchemeRegistry(); @@ -814,7 +815,7 @@ export const controls = { druid_time_origin: { type: 'SelectControl', freeForm: true, - label: t('Origin'), + label: TIME_FILTER_LABELS.druid_time_origin, choices: [ ['', 'default'], ['now', 'now'], @@ -865,7 +866,7 @@ export const controls = { granularity: { type: 'SelectControl', freeForm: true, - label: t('Time Granularity'), + label: TIME_FILTER_LABELS.granularity, default: 'one day', choices: [ [null, 'all'], @@ -953,7 +954,7 @@ export const controls = { granularity_sqla: { type: 'SelectControl', - label: t('Time Column'), + label: TIME_FILTER_LABELS.granularity_sqla, description: t( 'The time column for the visualization. Note that you ' + 'can define arbitrary expression that return a DATETIME ' + @@ -983,7 +984,7 @@ export const controls = { time_grain_sqla: { type: 'SelectControl', - label: t('Time Grain'), + label: TIME_FILTER_LABELS.time_grain_sqla, default: 'P1D', description: t( 'The time granularity for the visualization. This ' + @@ -1025,7 +1026,7 @@ export const controls = { time_range: { type: 'DateFilterControl', freeForm: true, - label: t('Time range'), + label: TIME_FILTER_LABELS.time_range, default: t('Last week'), description: t( 'The time range for the visualization. All relative times, e.g. "Last month", ' + diff --git a/superset/assets/src/visualizations/FilterBox/FilterBox.jsx b/superset/assets/src/visualizations/FilterBox/FilterBox.jsx index 23896a18f6..036465c66e 100644 --- a/superset/assets/src/visualizations/FilterBox/FilterBox.jsx +++ b/superset/assets/src/visualizations/FilterBox/FilterBox.jsx @@ -31,6 +31,7 @@ import OnPasteSelect from '../../components/OnPasteSelect'; import VirtualizedRendererWrap from '../../components/VirtualizedRendererWrap'; import { getDashboardFilterKey } from '../../dashboard/util/getDashboardFilterKey'; import { getFilterColorMap } from '../../dashboard/util/dashboardFiltersColorMap'; +import { TIME_FILTER_LABELS } from '../../explore/constants'; import FilterBadgeIcon from '../../components/FilterBadgeIcon'; import './FilterBox.less'; @@ -46,9 +47,6 @@ export const TIME_FILTER_MAP = { // a shortcut to a map key, used by many components export const TIME_RANGE = TIME_FILTER_MAP.time_range; -export const FILTER_LABELS = { - [TIME_RANGE]: 'Time range', -}; const propTypes = { chartId: PropTypes.number.isRequired, @@ -165,7 +163,7 @@ class FilterBox extends React.Component { renderDateFilter() { const { showDateFilter, chartId } = this.props; - const label = t(FILTER_LABELS[TIME_RANGE]); + const label = TIME_FILTER_LABELS.time_range; if (showDateFilter) { return (