From c057fe289d79ad428b281f050421fce36f771c1c Mon Sep 17 00:00:00 2001 From: Jesse Yang Date: Tue, 8 Sep 2020 13:55:19 -0700 Subject: [PATCH] refactor: convert legacy-plugin-chart-event-flow to typescript (#771) * refactor: convert legacy-plugin-chart-event-flow to typescript * retype TimeseriesDataRecord in ECharts --- .../src/utils/columnChoices.ts | 2 +- .../src/chart/types/QueryResponse.ts | 4 ++ .../src/{EventFlow.jsx => EventFlow.tsx} | 39 +++++++------------ .../{controlPanel.jsx => controlPanel.tsx} | 31 ++++++++++----- .../src/{index.js => index.ts} | 2 +- .../{transformProps.js => transformProps.ts} | 27 ++++++++++--- .../src/types/external.d.ts | 2 + .../src/Timeseries/types.ts | 6 +-- .../plugin-chart-echarts/src/utils/prophet.ts | 14 +++---- .../plugin-chart-echarts/src/utils/series.ts | 6 ++- 10 files changed, 77 insertions(+), 56 deletions(-) rename superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-event-flow/src/{EventFlow.jsx => EventFlow.tsx} (64%) rename superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-event-flow/src/{controlPanel.jsx => controlPanel.tsx} (82%) rename superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-event-flow/src/{index.js => index.ts} (95%) rename superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-event-flow/src/{transformProps.js => transformProps.ts} (63%) create mode 100644 superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-event-flow/src/types/external.d.ts diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-chart-controls/src/utils/columnChoices.ts b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-chart-controls/src/utils/columnChoices.ts index 72e424fcbe3f..3c39cfdf1c55 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-chart-controls/src/utils/columnChoices.ts +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-chart-controls/src/utils/columnChoices.ts @@ -21,7 +21,7 @@ import { DatasourceMeta } from '../types'; /** * Convert Dataource columns to column choices */ -export default function columnChoices(datasource?: DatasourceMeta) { +export default function columnChoices(datasource?: DatasourceMeta | null) { return ( datasource?.columns .map(col => [col.column_name, col.verbose_name || col.column_name]) diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-core/src/chart/types/QueryResponse.ts b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-core/src/chart/types/QueryResponse.ts index e6b865664ce8..629d0b90e308 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-core/src/chart/types/QueryResponse.ts +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-core/src/chart/types/QueryResponse.ts @@ -9,6 +9,10 @@ export interface DataRecord { [key: string]: DataRecordValue; } +export interface TimeseriesDataRecord extends DataRecord { + __timestamp: number | string | Date | null; +} + // data record value filters from FilterBox export interface DataRecordFilters { [key: string]: DataRecordValue[]; diff --git a/superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-event-flow/src/EventFlow.jsx b/superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-event-flow/src/EventFlow.tsx similarity index 64% rename from superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-event-flow/src/EventFlow.jsx rename to superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-event-flow/src/EventFlow.tsx index 516460455301..c663e0a91870 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-event-flow/src/EventFlow.jsx +++ b/superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-event-flow/src/EventFlow.tsx @@ -16,30 +16,26 @@ * specific language governing permissions and limitations * under the License. */ -/* eslint-disable react/forbid-prop-types */ import React from 'react'; -import PropTypes from 'prop-types'; -import { App } from '@data-ui/event-flow'; -import { t } from '@superset-ui/core'; +import { App as EventFlowApp } from '@data-ui/event-flow'; +import { t, TimeseriesDataRecord } from '@superset-ui/core'; -const propTypes = { - data: PropTypes.array, - height: PropTypes.number, - /* eslint-disable-next-line */ - initialMinEventCount: PropTypes.number, - width: PropTypes.number, -}; -const defaultProps = { - data: null, - height: 400, - width: 400, -}; +export interface EventFlowProps { + data: TimeseriesDataRecord[]; + height: number; + width: number; + initialMinEventCount: number; +} -function CustomEventFlow(props) { - const { data, height, initialMinEventCount, width } = props; +export default function EventFlow({ + data, + initialMinEventCount, + height = 400, + width = 400, +}: EventFlowProps) { if (data) { return ( - ); } - -CustomEventFlow.propTypes = propTypes; -CustomEventFlow.defaultProps = defaultProps; - -export default CustomEventFlow; diff --git a/superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-event-flow/src/controlPanel.jsx b/superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx similarity index 82% rename from superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-event-flow/src/controlPanel.jsx rename to superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx index 4c5506e5d262..0b3b315329d9 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-event-flow/src/controlPanel.jsx +++ b/superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-event-flow/src/controlPanel.tsx @@ -17,10 +17,17 @@ * under the License. */ import React from 'react'; -import { t, validateNonEmpty, ColumnOption, columnChoices } from '@superset-ui/core'; -import { formatSelectOptionsForRange } from '@superset-ui/chart-controls'; +import { t, validateNonEmpty } from '@superset-ui/core'; +import { + formatSelectOptionsForRange, + ColumnOption, + columnChoices, + ControlPanelConfig, + SelectControlConfig, + ColumnMeta, +} from '@superset-ui/chart-controls'; -export default { +const config: ControlPanelConfig = { controlPanelSections: [ { label: t('Event definition'), @@ -32,14 +39,15 @@ export default { config: { type: 'SelectControl', label: t('Column containing event names'), - default: control => + description: t('Columns to display'), + mapStateToProps: state => ({ + choices: columnChoices(state?.datasource), + }), + // choices is from `mapStateToProps` + default: (control: { choices?: string[] }) => control.choices && control.choices.length > 0 ? control.choices[0][0] : null, + validators: [validateNonEmpty], }, - description: t('Columns to display'), - mapStateToProps: state => ({ - choices: columnChoices(state.datasource), - }), - validators: [validateNonEmpty], }, ], ['row_limit'], @@ -86,6 +94,7 @@ export default { [ { name: 'all_columns', + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions config: { type: 'SelectControl', multi: true, @@ -101,7 +110,7 @@ export default { }), commaChoosesOption: false, freeForm: true, - }, + } as SelectControlConfig, }, ], ], @@ -118,3 +127,5 @@ export default { }, }, }; + +export default config; diff --git a/superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-event-flow/src/index.js b/superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-event-flow/src/index.ts similarity index 95% rename from superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-event-flow/src/index.js rename to superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-event-flow/src/index.ts index 494ad1e130ae..16268861f856 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-event-flow/src/index.js +++ b/superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-event-flow/src/index.ts @@ -32,7 +32,7 @@ export default class EventFlowChartPlugin extends ChartPlugin { constructor() { super({ loadChart: () => import('./EventFlow'), - loadTransformProps: () => import('./transformProps.js'), + loadTransformProps: () => import('./transformProps'), metadata, controlPanel, }); diff --git a/superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-event-flow/src/transformProps.js b/superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-event-flow/src/transformProps.ts similarity index 63% rename from superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-event-flow/src/transformProps.js rename to superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-event-flow/src/transformProps.ts index d0fe07135805..dad2229e7943 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-event-flow/src/transformProps.js +++ b/superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-event-flow/src/transformProps.ts @@ -16,10 +16,24 @@ * specific language governing permissions and limitations * under the License. */ +import { ChartProps, TimeseriesDataRecord } from '@superset-ui/core'; import { cleanEvents, TS, EVENT_NAME, ENTITY_ID } from '@data-ui/event-flow'; -export default function transformProps(chartProps) { - const { formData, queryData, width, height } = chartProps; +export interface EventFlowFormData { + allColumnsX: string; + entity: string; + minLeafNodeEventCount: number; +} + +export interface EventFlowChartProps extends ChartProps { + formData: EventFlowFormData; + queryData: { + data: TimeseriesDataRecord[]; + }; +} + +export default function transformProps(chartProps: ChartProps) { + const { formData, queryData, width, height } = chartProps as EventFlowChartProps; const { allColumnsX, entity, minLeafNodeEventCount } = formData; const { data } = queryData; @@ -30,10 +44,11 @@ export default function transformProps(chartProps) { // map from the Superset form fields to 's expected data keys const accessorFunctions = { - [ENTITY_ID]: datum => String(datum[userKey]), - [EVENT_NAME]: datum => datum[eventNameKey], - // eslint-disable-next-line no-underscore-dangle - [TS]: datum => new Date(datum.__timestamp), + [ENTITY_ID]: (datum: TimeseriesDataRecord) => String(datum[userKey]), + [EVENT_NAME]: (datum: TimeseriesDataRecord) => datum[eventNameKey] as string, + [TS]: (datum: TimeseriesDataRecord): Date | null => + // eslint-disable-next-line no-underscore-dangle + datum.__timestamp || datum.__timestamp === 0 ? new Date(datum.__timestamp) : null, }; const cleanData = cleanEvents(data, accessorFunctions); diff --git a/superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-event-flow/src/types/external.d.ts b/superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-event-flow/src/types/external.d.ts new file mode 100644 index 000000000000..69bcffd0f862 --- /dev/null +++ b/superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-event-flow/src/types/external.d.ts @@ -0,0 +1,2 @@ +declare module '*.png'; +declare module '@data-ui/event-flow'; diff --git a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Timeseries/types.ts b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Timeseries/types.ts index 1279576e523c..9b31fa25690e 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Timeseries/types.ts +++ b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/Timeseries/types.ts @@ -16,15 +16,11 @@ * specific language governing permissions and limitations * under the License. */ -import { DataRecord, DataRecordValue } from '@superset-ui/core'; +import { DataRecordValue } from '@superset-ui/core'; import { EchartsProps } from '../types'; export type TimestampType = string | number | Date; -export interface TimeseriesDataRecord extends DataRecord { - __timestamp: TimestampType; -} - export type EchartsBaseTimeseriesSeries = { name: string; data: [Date, DataRecordValue][]; diff --git a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/utils/prophet.ts b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/utils/prophet.ts index cf3259274f2b..891dab55c80f 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/utils/prophet.ts +++ b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/utils/prophet.ts @@ -16,9 +16,8 @@ * specific language governing permissions and limitations * under the License. */ -import { DataRecord, NumberFormatter } from '@superset-ui/core'; +import { TimeseriesDataRecord, NumberFormatter } from '@superset-ui/core'; import { ForecastSeriesContext, ForecastSeriesEnum, ProphetValue } from '../types'; -import { TimeseriesDataRecord } from '../Timeseries/types'; const seriesTypeRegex = new RegExp( `(.+)(${ForecastSeriesEnum.ForecastLower}|${ForecastSeriesEnum.ForecastTrend}|${ForecastSeriesEnum.ForecastUpper})$`, @@ -87,26 +86,27 @@ export const formatProphetTooltipSeries = ({ return `${row.trim()}`; }; -export const rebaseTimeseriesDatum = (data: DataRecord[]): TimeseriesDataRecord[] => { +export function rebaseTimeseriesDatum(data: TimeseriesDataRecord[]) { const keys = data.length > 0 ? Object.keys(data[0]) : []; + // eslint-disable-next-line @typescript-eslint/no-unsafe-return return data.map(row => { const newRow: TimeseriesDataRecord = { __timestamp: '' }; keys.forEach(key => { const forecastContext = extractForecastSeriesContext(key); const lowerKey = `${forecastContext.name}${ForecastSeriesEnum.ForecastLower}`; - let value = row[key]; + let value = row[key] as number; if ( forecastContext.type === ForecastSeriesEnum.ForecastUpper && keys.includes(lowerKey) && value !== null && row[lowerKey] !== null ) { - // @ts-ignore - value -= row[lowerKey]; + value -= row[lowerKey] as number; } newRow[key] = value; }); + // eslint-disable-next-line @typescript-eslint/no-unsafe-return return newRow; }); -}; +} diff --git a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/utils/series.ts b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/utils/series.ts index 931895f23ede..be9e6147c97c 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/utils/series.ts +++ b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-echarts/src/utils/series.ts @@ -17,16 +17,17 @@ * specific language governing permissions and limitations * under the License. */ -import { TimeseriesDataRecord } from '../Timeseries/types'; +import { TimeseriesDataRecord } from '@superset-ui/core'; // eslint-disable-next-line import/prefer-default-export export function extractTimeseriesSeries( data: TimeseriesDataRecord[], ): echarts.EChartOption.Series[] { if (data.length === 0) return []; + // eslint-disable-next-line @typescript-eslint/no-unsafe-return const rows = data.map(datum => ({ ...datum, - __timestamp: new Date(datum.__timestamp), + __timestamp: datum.__timestamp || datum.__timestamp === 0 ? new Date(datum.__timestamp) : null, })); return Object.keys(rows[0]) @@ -34,6 +35,7 @@ export function extractTimeseriesSeries( .map(key => ({ name: key, // @ts-ignore + // eslint-disable-next-line @typescript-eslint/no-unsafe-return data: rows.map(datum => [datum.__timestamp, datum[key]]), })); }