feat: format timestamps in drill by breadcrumbs (#23698)

This commit is contained in:
Lily Kuang 2023-04-27 09:17:33 -07:00 committed by GitHub
parent 5f035499ac
commit 0bf8907f2f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 120 additions and 20 deletions

View File

@ -297,5 +297,6 @@ export default function transformProps(
selectedValues, selectedValues,
onContextMenu, onContextMenu,
refs, refs,
coltypeMapping,
}; };
} }

View File

@ -37,6 +37,7 @@ import {
import { import {
extractGroupbyLabel, extractGroupbyLabel,
getChartPadding, getChartPadding,
getColtypesMapping,
getLegendProps, getLegendProps,
sanitizeHtml, sanitizeHtml,
} from '../utils/series'; } from '../utils/series';
@ -95,7 +96,7 @@ export default function transformProps(
emitCrossFilters, emitCrossFilters,
} = chartProps; } = chartProps;
const data: DataRecord[] = queriesData[0].data || []; const data: DataRecord[] = queriesData[0].data || [];
const coltypeMapping = getColtypesMapping(queriesData[0]);
const { const {
colorScheme, colorScheme,
groupby, groupby,
@ -244,5 +245,6 @@ export default function transformProps(
selectedValues, selectedValues,
onContextMenu, onContextMenu,
refs, refs,
coltypeMapping,
}; };
} }

View File

@ -46,6 +46,7 @@ import {
import { OpacityEnum } from '../constants'; import { OpacityEnum } from '../constants';
import { getDefaultTooltip } from '../utils/tooltip'; import { getDefaultTooltip } from '../utils/tooltip';
import { Refs } from '../types'; import { Refs } from '../types';
import { getColtypesMapping } from '../utils/series';
const setIntervalBoundsAndColors = ( const setIntervalBoundsAndColors = (
intervals: string, intervals: string,
@ -130,6 +131,7 @@ export default function transformProps(
}: EchartsGaugeFormData = { ...DEFAULT_GAUGE_FORM_DATA, ...formData }; }: EchartsGaugeFormData = { ...DEFAULT_GAUGE_FORM_DATA, ...formData };
const refs: Refs = {}; const refs: Refs = {};
const data = (queriesData[0]?.data || []) as DataRecord[]; const data = (queriesData[0]?.data || []) as DataRecord[];
const coltypeMapping = getColtypesMapping(queriesData[0]);
const numberFormatter = getNumberFormatter(numberFormat); const numberFormatter = getNumberFormatter(numberFormat);
const colorFn = CategoricalColorNamespace.getScale(colorScheme as string); const colorFn = CategoricalColorNamespace.getScale(colorScheme as string);
const axisLineWidth = calculateAxisLineWidth(data, fontSize, overlap); const axisLineWidth = calculateAxisLineWidth(data, fontSize, overlap);
@ -341,5 +343,6 @@ export default function transformProps(
selectedValues: filterState.selectedValues || [], selectedValues: filterState.selectedValues || [],
onContextMenu, onContextMenu,
refs, refs,
coltypeMapping,
}; };
} }

View File

@ -17,9 +17,15 @@
* under the License. * under the License.
*/ */
import React from 'react'; import React from 'react';
import {
getColumnLabel,
getNumberFormatter,
getTimeFormatter,
} from '@superset-ui/core';
import { EventHandlers } from '../types'; import { EventHandlers } from '../types';
import Echart from '../components/Echart'; import Echart from '../components/Echart';
import { GraphChartTransformedProps } from './types'; import { GraphChartTransformedProps } from './types';
import { formatSeriesName } from '../utils/series';
type DataRow = { type DataRow = {
source?: string; source?: string;
@ -46,6 +52,7 @@ export default function EchartsGraph({
filterState, filterState,
emitCrossFilters, emitCrossFilters,
refs, refs,
coltypeMapping,
}: GraphChartTransformedProps) { }: GraphChartTransformedProps) {
const getCrossFilterDataMask = (node: DataRow | undefined) => { const getCrossFilterDataMask = (node: DataRow | undefined) => {
if (!node?.name || !node?.col) { if (!node?.name || !node?.col) {
@ -143,7 +150,18 @@ export default function EchartsGraph({
drillToDetail: drillToDetailFilters, drillToDetail: drillToDetailFilters,
crossFilter: getCrossFilterDataMask(node), crossFilter: getCrossFilterDataMask(node),
drillBy: 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: groupbyFieldName:
node.col === formData.source ? 'source' : 'target', node.col === formData.source ? 'source' : 'target',
}, },

View File

@ -34,7 +34,12 @@ import {
EchartsGraphChartProps, EchartsGraphChartProps,
} from './types'; } from './types';
import { DEFAULT_GRAPH_SERIES_OPTION } from './constants'; 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 { getDefaultTooltip } from '../utils/tooltip';
import { Refs } from '../types'; import { Refs } from '../types';
@ -174,7 +179,7 @@ export default function transformProps(
theme, theme,
} = chartProps; } = chartProps;
const data: DataRecord[] = queriesData[0].data || []; const data: DataRecord[] = queriesData[0].data || [];
const coltypeMapping = getColtypesMapping(queriesData[0]);
const { const {
source, source,
target, target,
@ -343,5 +348,6 @@ export default function transformProps(
filterState, filterState,
refs, refs,
emitCrossFilters, emitCrossFilters,
coltypeMapping,
}; };
} }

View File

@ -19,14 +19,17 @@
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import { import {
AxisType, AxisType,
DataRecordValue,
DTTM_ALIAS,
BinaryQueryObjectFilterClause, BinaryQueryObjectFilterClause,
DTTM_ALIAS,
DataRecordValue,
getColumnLabel,
getNumberFormatter,
getTimeFormatter,
} from '@superset-ui/core'; } from '@superset-ui/core';
import { EchartsMixedTimeseriesChartTransformedProps } from './types'; import { EchartsMixedTimeseriesChartTransformedProps } from './types';
import Echart from '../components/Echart'; import Echart from '../components/Echart';
import { EventHandlers } from '../types'; import { EventHandlers } from '../types';
import { currentSeries } from '../utils/series'; import { currentSeries, formatSeriesName } from '../utils/series';
export default function EchartsMixedTimeseries({ export default function EchartsMixedTimeseries({
height, height,
@ -45,6 +48,7 @@ export default function EchartsMixedTimeseries({
xValueFormatter, xValueFormatter,
xAxis, xAxis,
refs, refs,
coltypeMapping,
}: EchartsMixedTimeseriesChartTransformedProps) { }: EchartsMixedTimeseriesChartTransformedProps) {
const isFirstQuery = useCallback( const isFirstQuery = useCallback(
(seriesIndex: number) => seriesIndex < seriesBreakdown, (seriesIndex: number) => seriesIndex < seriesBreakdown,
@ -125,7 +129,7 @@ export default function EchartsMixedTimeseries({
mouseover: params => { mouseover: params => {
currentSeries.name = params.seriesName; currentSeries.name = params.seriesName;
}, },
contextmenu: eventParams => { contextmenu: async eventParams => {
if (onContextMenu) { if (onContextMenu) {
eventParams.event.stop(); eventParams.event.stop();
const { data, seriesName, seriesIndex } = eventParams; const { data, seriesName, seriesIndex } = eventParams;
@ -167,6 +171,11 @@ export default function EchartsMixedTimeseries({
col: dimension, col: dimension,
op: '==', op: '==',
val: values[i], val: values[i],
formattedVal: formatSeriesName(values[i], {
timeFormatter: getTimeFormatter(formData.dateFormat),
numberFormatter: getNumberFormatter(formData.numberFormat),
coltype: coltypeMapping?.[getColumnLabel(dimension)],
}),
}), }),
); );
onContextMenu(pointerEvent.clientX, pointerEvent.clientY, { onContextMenu(pointerEvent.clientX, pointerEvent.clientY, {

View File

@ -105,7 +105,10 @@ export default function transformProps(
const data1 = (queriesData[0].data || []) as TimeseriesDataRecord[]; const data1 = (queriesData[0].data || []) as TimeseriesDataRecord[];
const data2 = (queriesData[1].data || []) as TimeseriesDataRecord[]; const data2 = (queriesData[1].data || []) as TimeseriesDataRecord[];
const annotationData = getAnnotationData(chartProps); const annotationData = getAnnotationData(chartProps);
const coltypeMapping = {
...getColtypesMapping(queriesData[0]),
...getColtypesMapping(queriesData[1]),
};
const { const {
area, area,
areaB, areaB,
@ -523,5 +526,6 @@ export default function transformProps(
type: xAxisType, type: xAxisType,
}, },
refs, refs,
coltypeMapping,
}; };
} }

View File

@ -345,5 +345,6 @@ export default function transformProps(
onContextMenu, onContextMenu,
refs, refs,
emitCrossFilters, emitCrossFilters,
coltypeMapping,
}; };
} }

View File

@ -259,5 +259,6 @@ export default function transformProps(
selectedValues, selectedValues,
onContextMenu, onContextMenu,
refs, refs,
coltypeMapping,
}; };
} }

View File

@ -17,10 +17,16 @@
* under the License. * under the License.
*/ */
import React, { useCallback } from 'react'; 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 { SunburstTransformedProps } from './types';
import Echart from '../components/Echart'; import Echart from '../components/Echart';
import { EventHandlers, TreePathInfo } from '../types'; import { EventHandlers, TreePathInfo } from '../types';
import { formatSeriesName } from '../utils/series';
export const extractTreePathInfo = (treePathInfo: TreePathInfo[] | undefined) => export const extractTreePathInfo = (treePathInfo: TreePathInfo[] | undefined) =>
(treePathInfo ?? []) (treePathInfo ?? [])
@ -39,6 +45,7 @@ export default function EchartsSunburst(props: SunburstTransformedProps) {
onContextMenu, onContextMenu,
refs, refs,
emitCrossFilters, emitCrossFilters,
coltypeMapping,
} = props; } = props;
const { columns } = formData; const { columns } = formData;
@ -102,7 +109,7 @@ export default function EchartsSunburst(props: SunburstTransformedProps) {
const { treePathInfo } = props; const { treePathInfo } = props;
handleChange(treePathInfo); handleChange(treePathInfo);
}, },
contextmenu: eventParams => { contextmenu: async eventParams => {
if (onContextMenu) { if (onContextMenu) {
eventParams.event.stop(); eventParams.event.stop();
const { data, treePathInfo } = eventParams; const { data, treePathInfo } = eventParams;
@ -120,10 +127,17 @@ export default function EchartsSunburst(props: SunburstTransformedProps) {
formattedVal: path, formattedVal: path,
}), }),
); );
const val = treePath[treePath.length - 1];
drillByFilters.push({ drillByFilters.push({
col: columns[treePath.length - 1], col: columns[treePath.length - 1],
op: '==', 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, { onContextMenu(pointerEvent.clientX, pointerEvent.clientY, {

View File

@ -377,5 +377,6 @@ export default function transformProps(
selectedValues: filterState.selectedValues || [], selectedValues: filterState.selectedValues || [],
onContextMenu, onContextMenu,
refs, refs,
coltypeMapping,
}; };
} }

View File

@ -21,6 +21,9 @@ import {
DTTM_ALIAS, DTTM_ALIAS,
BinaryQueryObjectFilterClause, BinaryQueryObjectFilterClause,
AxisType, AxisType,
getTimeFormatter,
getColumnLabel,
getNumberFormatter,
} from '@superset-ui/core'; } from '@superset-ui/core';
import { ViewRootGroup } from 'echarts/types/src/util/types'; import { ViewRootGroup } from 'echarts/types/src/util/types';
import GlobalModel from 'echarts/types/src/model/Global'; 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 { EchartsHandler, EventHandlers } from '../types';
import Echart from '../components/Echart'; import Echart from '../components/Echart';
import { TimeseriesChartTransformedProps } from './types'; import { TimeseriesChartTransformedProps } from './types';
import { currentSeries } from '../utils/series'; import { currentSeries, formatSeriesName } from '../utils/series';
import { ExtraControls } from '../components/ExtraControls'; import { ExtraControls } from '../components/ExtraControls';
const TIMER_DURATION = 300; const TIMER_DURATION = 300;
@ -50,6 +53,7 @@ export default function EchartsTimeseries({
xAxis, xAxis,
refs, refs,
emitCrossFilters, emitCrossFilters,
coltypeMapping,
}: TimeseriesChartTransformedProps) { }: TimeseriesChartTransformedProps) {
const { stack } = formData; const { stack } = formData;
const echartRef = useRef<EchartsHandler | null>(null); const echartRef = useRef<EchartsHandler | null>(null);
@ -196,7 +200,7 @@ export default function EchartsTimeseries({
handleDoubleClickChange(); handleDoubleClickChange();
} }
}, },
contextmenu: eventParams => { contextmenu: async eventParams => {
if (onContextMenu) { if (onContextMenu) {
eventParams.event.stop(); eventParams.event.stop();
const { data, seriesName } = eventParams; const { data, seriesName } = eventParams;
@ -232,10 +236,16 @@ export default function EchartsTimeseries({
}), }),
); );
formData.groupby.forEach((dimension, i) => { formData.groupby.forEach((dimension, i) => {
const val = labelMap[seriesName][i];
drillByFilters.push({ drillByFilters.push({
col: dimension, col: dimension,
op: '==', op: '==',
val: labelMap[seriesName][i], val,
formattedVal: formatSeriesName(values[i], {
timeFormatter: getTimeFormatter(formData.dateFormat),
numberFormatter: getNumberFormatter(formData.numberFormat),
coltype: coltypeMapping?.[getColumnLabel(dimension)],
}),
}); });
}); });

View File

@ -533,5 +533,6 @@ export default function transformProps(
type: xAxisType, type: xAxisType,
}, },
refs, refs,
coltypeMapping: dataTypes,
}; };
} }

View File

@ -19,6 +19,9 @@
import { import {
DataRecordValue, DataRecordValue,
BinaryQueryObjectFilterClause, BinaryQueryObjectFilterClause,
getTimeFormatter,
getColumnLabel,
getNumberFormatter,
} from '@superset-ui/core'; } from '@superset-ui/core';
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import Echart from '../components/Echart'; import Echart from '../components/Echart';
@ -26,6 +29,7 @@ import { NULL_STRING } from '../constants';
import { EventHandlers } from '../types'; import { EventHandlers } from '../types';
import { extractTreePathInfo } from './constants'; import { extractTreePathInfo } from './constants';
import { TreemapTransformedProps } from './types'; import { TreemapTransformedProps } from './types';
import { formatSeriesName } from '../utils/series';
export default function EchartsTreemap({ export default function EchartsTreemap({
echartOptions, echartOptions,
@ -38,6 +42,8 @@ export default function EchartsTreemap({
setDataMask, setDataMask,
selectedValues, selectedValues,
width, width,
formData,
coltypeMapping,
}: TreemapTransformedProps) { }: TreemapTransformedProps) {
const getCrossFilterDataMask = useCallback( const getCrossFilterDataMask = useCallback(
(data, treePathInfo) => { (data, treePathInfo) => {
@ -108,7 +114,7 @@ export default function EchartsTreemap({
const { data, treePathInfo } = props; const { data, treePathInfo } = props;
handleChange(data, treePathInfo); handleChange(data, treePathInfo);
}, },
contextmenu: eventParams => { contextmenu: async eventParams => {
if (onContextMenu) { if (onContextMenu) {
eventParams.event.stop(); eventParams.event.stop();
const { data, treePathInfo } = eventParams; const { data, treePathInfo } = eventParams;
@ -129,6 +135,11 @@ export default function EchartsTreemap({
col: groupby[i], col: groupby[i],
op: '==', op: '==',
val, val,
formattedVal: formatSeriesName(val, {
timeFormatter: getTimeFormatter(formData.dateFormat),
numberFormatter: getNumberFormatter(formData.numberFormat),
coltype: coltypeMapping?.[getColumnLabel(groupby[i])],
}),
}); });
}); });
onContextMenu(pointerEvent.clientX, pointerEvent.clientY, { onContextMenu(pointerEvent.clientX, pointerEvent.clientY, {

View File

@ -294,5 +294,6 @@ export default function transformProps(
selectedValues: filterState.selectedValues || [], selectedValues: filterState.selectedValues || [],
onContextMenu, onContextMenu,
refs, refs,
coltypeMapping,
}; };
} }

View File

@ -131,6 +131,7 @@ export interface BaseTransformedProps<F> {
refs: Refs; refs: Refs;
width: number; width: number;
emitCrossFilters?: boolean; emitCrossFilters?: boolean;
coltypeMapping?: Record<string, number>;
} }
export type CrossFilterTransformedProps = { export type CrossFilterTransformedProps = {

View File

@ -21,12 +21,18 @@ import {
ContextMenuFilters, ContextMenuFilters,
DataMask, DataMask,
QueryFormColumn, QueryFormColumn,
QueryFormData,
getColumnLabel,
getNumberFormatter,
getTimeFormatter,
} from '@superset-ui/core'; } from '@superset-ui/core';
import { import {
BaseTransformedProps, BaseTransformedProps,
CrossFilterTransformedProps, CrossFilterTransformedProps,
EventHandlers, EventHandlers,
} from '../types'; } from '../types';
import { formatSeriesName } from './series';
export type Event = { export type Event = {
name: string; name: string;
@ -106,6 +112,8 @@ export const contextMenuEventHandler =
getCrossFilterDataMask: ( getCrossFilterDataMask: (
value: string, value: string,
) => ContextMenuFilters['crossFilter'], ) => ContextMenuFilters['crossFilter'],
formData: QueryFormData,
coltypeMapping?: Record<string, number>,
) => ) =>
(e: Event) => { (e: Event) => {
if (onContextMenu) { if (onContextMenu) {
@ -114,14 +122,18 @@ export const contextMenuEventHandler =
const drillFilters: BinaryQueryObjectFilterClause[] = []; const drillFilters: BinaryQueryObjectFilterClause[] = [];
if (groupby.length > 0) { if (groupby.length > 0) {
const values = labelMap[e.name]; const values = labelMap[e.name];
groupby.forEach((dimension, i) => groupby.forEach((dimension, i) => {
drillFilters.push({ drillFilters.push({
col: dimension, col: dimension,
op: '==', op: '==',
val: values[i], 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, { onContextMenu(pointerEvent.clientX, pointerEvent.clientY, {
drillToDetail: drillFilters, drillToDetail: drillFilters,
@ -141,6 +153,8 @@ export const allEventHandlers = (
labelMap, labelMap,
emitCrossFilters, emitCrossFilters,
selectedValues, selectedValues,
coltypeMapping,
formData,
} = transformedProps; } = transformedProps;
const eventHandlers: EventHandlers = { const eventHandlers: EventHandlers = {
click: clickEventHandler( click: clickEventHandler(
@ -153,6 +167,8 @@ export const allEventHandlers = (
onContextMenu, onContextMenu,
labelMap, labelMap,
getCrossFilterDataMask(selectedValues, groupby, labelMap), getCrossFilterDataMask(selectedValues, groupby, labelMap),
formData,
coltypeMapping,
), ),
}; };
return eventHandlers; return eventHandlers;