blob: f9495e04790042b923509febb058d442c2beb34b [file] [log] [blame]
import { createSelector } from 'reselect';
import { convertKeysToCamelCase, Datasource } from '../..';
import { HandlerFunction, PlainObject, SetExtraFormDataHook } from '../types/Base';
import { QueryData, DataRecordFilters } from '..';
// TODO: more specific typing for these fields of ChartProps
type AnnotationData = PlainObject;
type SnakeCaseDatasource = PlainObject;
type CamelCaseFormData = PlainObject;
type SnakeCaseFormData = PlainObject;
type RawFormData = CamelCaseFormData | SnakeCaseFormData;
type ChartPropsSelector = (c: ChartPropsConfig) => ChartProps;
/** Optional field for event handlers, renderers */
type Hooks = {
/**
* sync active filters between chart and dashboard, "add" actually
* also handles "change" and "remove".
*/
onAddFilter?: (newFilters: DataRecordFilters, merge?: boolean) => void;
/** handle errors */
onError?: HandlerFunction;
/** use the vis as control to update state */
setControlValue?: HandlerFunction;
/** handle native filters */
setExtraFormData?: SetExtraFormDataHook;
/** handle tooltip */
setTooltip?: HandlerFunction;
} & PlainObject;
/**
* Preferred format for ChartProps config
*/
export interface ChartPropsConfig {
annotationData?: AnnotationData;
/** Datasource metadata */
datasource?: SnakeCaseDatasource;
/**
* Formerly called "filters", which was misleading because it is actually
* initial values of the filter_box and table vis
*/
initialValues?: DataRecordFilters;
/** Main configuration of the chart */
formData?: RawFormData;
/** Chart height */
height?: number;
/** Programmatic overrides such as event handlers, renderers */
hooks?: Hooks;
/** The data returned for all queries objects in the request */
queriesData?: QueryData[];
/** Chart width */
width?: number;
}
const DEFAULT_WIDTH = 800;
const DEFAULT_HEIGHT = 600;
export default class ChartProps<FormData extends RawFormData = RawFormData> {
static createSelector: () => ChartPropsSelector;
annotationData: AnnotationData;
datasource: Datasource;
rawDatasource: SnakeCaseDatasource;
initialValues: DataRecordFilters;
formData: CamelCaseFormData;
rawFormData: FormData;
height: number;
hooks: Hooks;
queriesData: QueryData[];
width: number;
constructor(config: ChartPropsConfig & { formData?: FormData } = {}) {
const {
annotationData = {},
datasource = {},
formData = {} as FormData,
hooks = {},
initialValues = {},
queriesData = [],
width = DEFAULT_WIDTH,
height = DEFAULT_HEIGHT,
} = config;
this.width = width;
this.height = height;
this.annotationData = annotationData;
this.datasource = convertKeysToCamelCase(datasource) as Datasource;
this.rawDatasource = datasource;
this.formData = convertKeysToCamelCase(formData);
this.rawFormData = formData;
this.hooks = hooks;
this.initialValues = initialValues;
this.queriesData = queriesData;
}
}
// eslint-disable-next-line func-name-matching
ChartProps.createSelector = function create(): ChartPropsSelector {
return createSelector(
(input: ChartPropsConfig) => input.annotationData,
input => input.datasource,
input => input.formData,
input => input.height,
input => input.hooks,
input => input.initialValues,
input => input.queriesData,
input => input.width,
(annotationData, datasource, formData, height, hooks, initialValues, queriesData, width) =>
new ChartProps({
annotationData,
datasource,
formData,
height,
hooks,
initialValues,
queriesData,
width,
}),
);
};