Skip to content

Commit

Permalink
refactor: convert legacy-plugin-chart-event-flow to typescript (apach…
Browse files Browse the repository at this point in the history
…e#771)

* refactor: convert legacy-plugin-chart-event-flow to typescript

* retype TimeseriesDataRecord in ECharts
  • Loading branch information
ktmud authored and zhaoyongjie committed Nov 24, 2021
1 parent 6fc00a5 commit c057fe2
Show file tree
Hide file tree
Showing 10 changed files with 77 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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[];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<App
<EventFlowApp
width={width}
height={height}
data={data}
Expand All @@ -55,8 +51,3 @@ function CustomEventFlow(props) {
</div>
);
}

CustomEventFlow.propTypes = propTypes;
CustomEventFlow.defaultProps = defaultProps;

export default CustomEventFlow;
Original file line number Diff line number Diff line change
Expand Up @@ -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'),
Expand All @@ -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'],
Expand Down Expand Up @@ -86,6 +94,7 @@ export default {
[
{
name: 'all_columns',
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
config: {
type: 'SelectControl',
multi: true,
Expand All @@ -101,7 +110,7 @@ export default {
}),
commaChoosesOption: false,
freeForm: true,
},
} as SelectControlConfig<ColumnMeta>,
},
],
],
Expand All @@ -118,3 +127,5 @@ export default {
},
},
};

export default config;
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export default class EventFlowChartPlugin extends ChartPlugin {
constructor() {
super({
loadChart: () => import('./EventFlow'),
loadTransformProps: () => import('./transformProps.js'),
loadTransformProps: () => import('./transformProps'),
metadata,
controlPanel,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -30,10 +44,11 @@ export default function transformProps(chartProps) {

// map from the Superset form fields to <EventFlow />'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);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
declare module '*.png';
declare module '@data-ui/event-flow';
Original file line number Diff line number Diff line change
Expand Up @@ -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][];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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})$`,
Expand Down Expand Up @@ -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;
});
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,25 @@
* 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])
.filter(key => key !== '__timestamp')
.map(key => ({
name: key,
// @ts-ignore
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
data: rows.map(datum => [datum.__timestamp, datum[key]]),
}));
}

0 comments on commit c057fe2

Please sign in to comment.