From 0bf8907f2f6d7a17a1e3efa1c03a5af06daa8190 Mon Sep 17 00:00:00 2001 From: Lily Kuang Date: Thu, 27 Apr 2023 09:17:33 -0700 Subject: [PATCH] feat: format timestamps in drill by breadcrumbs (#23698) --- .../src/BoxPlot/transformProps.ts | 1 + .../src/Funnel/transformProps.ts | 4 +++- .../src/Gauge/transformProps.ts | 3 +++ .../src/Graph/EchartsGraph.tsx | 20 +++++++++++++++- .../src/Graph/transformProps.ts | 10 ++++++-- .../EchartsMixedTimeseries.tsx | 17 +++++++++---- .../src/MixedTimeseries/transformProps.ts | 6 ++++- .../src/Pie/transformProps.ts | 1 + .../src/Radar/transformProps.ts | 1 + .../src/Sunburst/EchartsSunburst.tsx | 20 +++++++++++++--- .../src/Sunburst/transformProps.ts | 1 + .../src/Timeseries/EchartsTimeseries.tsx | 16 ++++++++++--- .../src/Timeseries/transformProps.ts | 1 + .../src/Treemap/EchartsTreemap.tsx | 13 +++++++++- .../src/Treemap/transformProps.ts | 1 + .../plugins/plugin-chart-echarts/src/types.ts | 1 + .../src/utils/eventHandlers.ts | 24 +++++++++++++++---- 17 files changed, 120 insertions(+), 20 deletions(-) diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/transformProps.ts index 54a1cbfd20..0edeadb7fa 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/transformProps.ts @@ -297,5 +297,6 @@ export default function transformProps( selectedValues, onContextMenu, refs, + coltypeMapping, }; } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/transformProps.ts index 07da17d252..ac2f650e32 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/transformProps.ts @@ -37,6 +37,7 @@ import { import { extractGroupbyLabel, getChartPadding, + getColtypesMapping, getLegendProps, sanitizeHtml, } from '../utils/series'; @@ -95,7 +96,7 @@ export default function transformProps( emitCrossFilters, } = chartProps; const data: DataRecord[] = queriesData[0].data || []; - + const coltypeMapping = getColtypesMapping(queriesData[0]); const { colorScheme, groupby, @@ -244,5 +245,6 @@ export default function transformProps( selectedValues, onContextMenu, refs, + coltypeMapping, }; } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/transformProps.ts index 6ff97bf0c5..27e6c9f197 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/transformProps.ts @@ -46,6 +46,7 @@ import { import { OpacityEnum } from '../constants'; import { getDefaultTooltip } from '../utils/tooltip'; import { Refs } from '../types'; +import { getColtypesMapping } from '../utils/series'; const setIntervalBoundsAndColors = ( intervals: string, @@ -130,6 +131,7 @@ export default function transformProps( }: EchartsGaugeFormData = { ...DEFAULT_GAUGE_FORM_DATA, ...formData }; const refs: Refs = {}; const data = (queriesData[0]?.data || []) as DataRecord[]; + const coltypeMapping = getColtypesMapping(queriesData[0]); const numberFormatter = getNumberFormatter(numberFormat); const colorFn = CategoricalColorNamespace.getScale(colorScheme as string); const axisLineWidth = calculateAxisLineWidth(data, fontSize, overlap); @@ -341,5 +343,6 @@ export default function transformProps( selectedValues: filterState.selectedValues || [], onContextMenu, refs, + coltypeMapping, }; } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Graph/EchartsGraph.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Graph/EchartsGraph.tsx index 8e90bf1791..308d28f719 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Graph/EchartsGraph.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Graph/EchartsGraph.tsx @@ -17,9 +17,15 @@ * under the License. */ import React from 'react'; +import { + getColumnLabel, + getNumberFormatter, + getTimeFormatter, +} from '@superset-ui/core'; import { EventHandlers } from '../types'; import Echart from '../components/Echart'; import { GraphChartTransformedProps } from './types'; +import { formatSeriesName } from '../utils/series'; type DataRow = { source?: string; @@ -46,6 +52,7 @@ export default function EchartsGraph({ filterState, emitCrossFilters, refs, + coltypeMapping, }: GraphChartTransformedProps) { const getCrossFilterDataMask = (node: DataRow | undefined) => { if (!node?.name || !node?.col) { @@ -143,7 +150,18 @@ export default function EchartsGraph({ drillToDetail: drillToDetailFilters, crossFilter: getCrossFilterDataMask(node), drillBy: node && { - filters: [{ col: node.col, op: '==', val: node.name }], + filters: [ + { + col: node.col, + op: '==', + val: node.name, + formattedVal: formatSeriesName(node.name, { + timeFormatter: getTimeFormatter(formData.dateFormat), + numberFormatter: getNumberFormatter(formData.numberFormat), + coltype: coltypeMapping?.[getColumnLabel(node.col)], + }), + }, + ], groupbyFieldName: node.col === formData.source ? 'source' : 'target', }, diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Graph/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Graph/transformProps.ts index d61c229f07..256b984f7d 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Graph/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Graph/transformProps.ts @@ -34,7 +34,12 @@ import { EchartsGraphChartProps, } from './types'; import { DEFAULT_GRAPH_SERIES_OPTION } from './constants'; -import { getChartPadding, getLegendProps, sanitizeHtml } from '../utils/series'; +import { + getChartPadding, + getColtypesMapping, + getLegendProps, + sanitizeHtml, +} from '../utils/series'; import { getDefaultTooltip } from '../utils/tooltip'; import { Refs } from '../types'; @@ -174,7 +179,7 @@ export default function transformProps( theme, } = chartProps; const data: DataRecord[] = queriesData[0].data || []; - + const coltypeMapping = getColtypesMapping(queriesData[0]); const { source, target, @@ -343,5 +348,6 @@ export default function transformProps( filterState, refs, emitCrossFilters, + coltypeMapping, }; } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/EchartsMixedTimeseries.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/EchartsMixedTimeseries.tsx index 02583d4162..8686042611 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/EchartsMixedTimeseries.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/EchartsMixedTimeseries.tsx @@ -19,14 +19,17 @@ import React, { useCallback } from 'react'; import { AxisType, - DataRecordValue, - DTTM_ALIAS, BinaryQueryObjectFilterClause, + DTTM_ALIAS, + DataRecordValue, + getColumnLabel, + getNumberFormatter, + getTimeFormatter, } from '@superset-ui/core'; import { EchartsMixedTimeseriesChartTransformedProps } from './types'; import Echart from '../components/Echart'; import { EventHandlers } from '../types'; -import { currentSeries } from '../utils/series'; +import { currentSeries, formatSeriesName } from '../utils/series'; export default function EchartsMixedTimeseries({ height, @@ -45,6 +48,7 @@ export default function EchartsMixedTimeseries({ xValueFormatter, xAxis, refs, + coltypeMapping, }: EchartsMixedTimeseriesChartTransformedProps) { const isFirstQuery = useCallback( (seriesIndex: number) => seriesIndex < seriesBreakdown, @@ -125,7 +129,7 @@ export default function EchartsMixedTimeseries({ mouseover: params => { currentSeries.name = params.seriesName; }, - contextmenu: eventParams => { + contextmenu: async eventParams => { if (onContextMenu) { eventParams.event.stop(); const { data, seriesName, seriesIndex } = eventParams; @@ -167,6 +171,11 @@ export default function EchartsMixedTimeseries({ col: dimension, op: '==', val: values[i], + formattedVal: formatSeriesName(values[i], { + timeFormatter: getTimeFormatter(formData.dateFormat), + numberFormatter: getNumberFormatter(formData.numberFormat), + coltype: coltypeMapping?.[getColumnLabel(dimension)], + }), }), ); onContextMenu(pointerEvent.clientX, pointerEvent.clientY, { diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/transformProps.ts index fee6183a2c..a924292980 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/transformProps.ts @@ -105,7 +105,10 @@ export default function transformProps( const data1 = (queriesData[0].data || []) as TimeseriesDataRecord[]; const data2 = (queriesData[1].data || []) as TimeseriesDataRecord[]; const annotationData = getAnnotationData(chartProps); - + const coltypeMapping = { + ...getColtypesMapping(queriesData[0]), + ...getColtypesMapping(queriesData[1]), + }; const { area, areaB, @@ -523,5 +526,6 @@ export default function transformProps( type: xAxisType, }, refs, + coltypeMapping, }; } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Pie/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Pie/transformProps.ts index 76765cd801..7d30917b18 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Pie/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Pie/transformProps.ts @@ -345,5 +345,6 @@ export default function transformProps( onContextMenu, refs, emitCrossFilters, + coltypeMapping, }; } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Radar/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Radar/transformProps.ts index 56d4be05ce..c8c3c7ed15 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Radar/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Radar/transformProps.ts @@ -259,5 +259,6 @@ export default function transformProps( selectedValues, onContextMenu, refs, + coltypeMapping, }; } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/EchartsSunburst.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/EchartsSunburst.tsx index 7f40574665..29677d2564 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/EchartsSunburst.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/EchartsSunburst.tsx @@ -17,10 +17,16 @@ * under the License. */ import React, { useCallback } from 'react'; -import { BinaryQueryObjectFilterClause } from '@superset-ui/core'; +import { + BinaryQueryObjectFilterClause, + getColumnLabel, + getNumberFormatter, + getTimeFormatter, +} from '@superset-ui/core'; import { SunburstTransformedProps } from './types'; import Echart from '../components/Echart'; import { EventHandlers, TreePathInfo } from '../types'; +import { formatSeriesName } from '../utils/series'; export const extractTreePathInfo = (treePathInfo: TreePathInfo[] | undefined) => (treePathInfo ?? []) @@ -39,6 +45,7 @@ export default function EchartsSunburst(props: SunburstTransformedProps) { onContextMenu, refs, emitCrossFilters, + coltypeMapping, } = props; const { columns } = formData; @@ -102,7 +109,7 @@ export default function EchartsSunburst(props: SunburstTransformedProps) { const { treePathInfo } = props; handleChange(treePathInfo); }, - contextmenu: eventParams => { + contextmenu: async eventParams => { if (onContextMenu) { eventParams.event.stop(); const { data, treePathInfo } = eventParams; @@ -120,10 +127,17 @@ export default function EchartsSunburst(props: SunburstTransformedProps) { formattedVal: path, }), ); + const val = treePath[treePath.length - 1]; drillByFilters.push({ col: columns[treePath.length - 1], op: '==', - val: treePath[treePath.length - 1], + val, + formattedVal: formatSeriesName(val, { + timeFormatter: getTimeFormatter(formData.dateFormat), + numberFormatter: getNumberFormatter(formData.numberFormat), + coltype: + coltypeMapping?.[getColumnLabel(columns[treePath.length - 1])], + }), }); } onContextMenu(pointerEvent.clientX, pointerEvent.clientY, { diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/transformProps.ts index 51e89f8c6c..a12a757e44 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/transformProps.ts @@ -377,5 +377,6 @@ export default function transformProps( selectedValues: filterState.selectedValues || [], onContextMenu, refs, + coltypeMapping, }; } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/EchartsTimeseries.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/EchartsTimeseries.tsx index 202d627569..7f75d27105 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/EchartsTimeseries.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/EchartsTimeseries.tsx @@ -21,6 +21,9 @@ import { DTTM_ALIAS, BinaryQueryObjectFilterClause, AxisType, + getTimeFormatter, + getColumnLabel, + getNumberFormatter, } from '@superset-ui/core'; import { ViewRootGroup } from 'echarts/types/src/util/types'; import GlobalModel from 'echarts/types/src/model/Global'; @@ -28,7 +31,7 @@ import ComponentModel from 'echarts/types/src/model/Component'; import { EchartsHandler, EventHandlers } from '../types'; import Echart from '../components/Echart'; import { TimeseriesChartTransformedProps } from './types'; -import { currentSeries } from '../utils/series'; +import { currentSeries, formatSeriesName } from '../utils/series'; import { ExtraControls } from '../components/ExtraControls'; const TIMER_DURATION = 300; @@ -50,6 +53,7 @@ export default function EchartsTimeseries({ xAxis, refs, emitCrossFilters, + coltypeMapping, }: TimeseriesChartTransformedProps) { const { stack } = formData; const echartRef = useRef(null); @@ -196,7 +200,7 @@ export default function EchartsTimeseries({ handleDoubleClickChange(); } }, - contextmenu: eventParams => { + contextmenu: async eventParams => { if (onContextMenu) { eventParams.event.stop(); const { data, seriesName } = eventParams; @@ -232,10 +236,16 @@ export default function EchartsTimeseries({ }), ); formData.groupby.forEach((dimension, i) => { + const val = labelMap[seriesName][i]; drillByFilters.push({ col: dimension, op: '==', - val: labelMap[seriesName][i], + val, + formattedVal: formatSeriesName(values[i], { + timeFormatter: getTimeFormatter(formData.dateFormat), + numberFormatter: getNumberFormatter(formData.numberFormat), + coltype: coltypeMapping?.[getColumnLabel(dimension)], + }), }); }); diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts index 84b97fae52..ac096a0697 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts @@ -533,5 +533,6 @@ export default function transformProps( type: xAxisType, }, refs, + coltypeMapping: dataTypes, }; } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/EchartsTreemap.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/EchartsTreemap.tsx index f9363bd4b6..00dcc11aac 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/EchartsTreemap.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/EchartsTreemap.tsx @@ -19,6 +19,9 @@ import { DataRecordValue, BinaryQueryObjectFilterClause, + getTimeFormatter, + getColumnLabel, + getNumberFormatter, } from '@superset-ui/core'; import React, { useCallback } from 'react'; import Echart from '../components/Echart'; @@ -26,6 +29,7 @@ import { NULL_STRING } from '../constants'; import { EventHandlers } from '../types'; import { extractTreePathInfo } from './constants'; import { TreemapTransformedProps } from './types'; +import { formatSeriesName } from '../utils/series'; export default function EchartsTreemap({ echartOptions, @@ -38,6 +42,8 @@ export default function EchartsTreemap({ setDataMask, selectedValues, width, + formData, + coltypeMapping, }: TreemapTransformedProps) { const getCrossFilterDataMask = useCallback( (data, treePathInfo) => { @@ -108,7 +114,7 @@ export default function EchartsTreemap({ const { data, treePathInfo } = props; handleChange(data, treePathInfo); }, - contextmenu: eventParams => { + contextmenu: async eventParams => { if (onContextMenu) { eventParams.event.stop(); const { data, treePathInfo } = eventParams; @@ -129,6 +135,11 @@ export default function EchartsTreemap({ col: groupby[i], op: '==', val, + formattedVal: formatSeriesName(val, { + timeFormatter: getTimeFormatter(formData.dateFormat), + numberFormatter: getNumberFormatter(formData.numberFormat), + coltype: coltypeMapping?.[getColumnLabel(groupby[i])], + }), }); }); onContextMenu(pointerEvent.clientX, pointerEvent.clientY, { diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/transformProps.ts index b220b55b3d..89088be5fa 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/transformProps.ts @@ -294,5 +294,6 @@ export default function transformProps( selectedValues: filterState.selectedValues || [], onContextMenu, refs, + coltypeMapping, }; } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/types.ts b/superset-frontend/plugins/plugin-chart-echarts/src/types.ts index 142c41c17d..4b96f73bb9 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/types.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/types.ts @@ -131,6 +131,7 @@ export interface BaseTransformedProps { refs: Refs; width: number; emitCrossFilters?: boolean; + coltypeMapping?: Record; } export type CrossFilterTransformedProps = { diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/utils/eventHandlers.ts b/superset-frontend/plugins/plugin-chart-echarts/src/utils/eventHandlers.ts index 7651bd83bd..98e14d59ed 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/utils/eventHandlers.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/utils/eventHandlers.ts @@ -21,12 +21,18 @@ import { ContextMenuFilters, DataMask, QueryFormColumn, + QueryFormData, + getColumnLabel, + getNumberFormatter, + getTimeFormatter, } from '@superset-ui/core'; + import { BaseTransformedProps, CrossFilterTransformedProps, EventHandlers, } from '../types'; +import { formatSeriesName } from './series'; export type Event = { name: string; @@ -106,6 +112,8 @@ export const contextMenuEventHandler = getCrossFilterDataMask: ( value: string, ) => ContextMenuFilters['crossFilter'], + formData: QueryFormData, + coltypeMapping?: Record, ) => (e: Event) => { if (onContextMenu) { @@ -114,14 +122,18 @@ export const contextMenuEventHandler = const drillFilters: BinaryQueryObjectFilterClause[] = []; if (groupby.length > 0) { const values = labelMap[e.name]; - groupby.forEach((dimension, i) => + groupby.forEach((dimension, i) => { drillFilters.push({ col: dimension, op: '==', val: values[i], - formattedVal: String(values[i]), - }), - ); + formattedVal: formatSeriesName(values[i], { + timeFormatter: getTimeFormatter(formData.dateFormat), + numberFormatter: getNumberFormatter(formData.numberFormat), + coltype: coltypeMapping?.[getColumnLabel(dimension)], + }), + }); + }); } onContextMenu(pointerEvent.clientX, pointerEvent.clientY, { drillToDetail: drillFilters, @@ -141,6 +153,8 @@ export const allEventHandlers = ( labelMap, emitCrossFilters, selectedValues, + coltypeMapping, + formData, } = transformedProps; const eventHandlers: EventHandlers = { click: clickEventHandler( @@ -153,6 +167,8 @@ export const allEventHandlers = ( onContextMenu, labelMap, getCrossFilterDataMask(selectedValues, groupby, labelMap), + formData, + coltypeMapping, ), }; return eventHandlers;