blob: 286a96db357679a730a248ff190d1cf91003f553 [file] [log] [blame]
import { ComponentType } from 'react';
import { isRequired, Plugin, QueryFormData } from '../..';
import ChartMetadata from './ChartMetadata';
import getChartMetadataRegistry from '../registries/ChartMetadataRegistrySingleton';
import getChartBuildQueryRegistry from '../registries/ChartBuildQueryRegistrySingleton';
import getChartComponentRegistry from '../registries/ChartComponentRegistrySingleton';
import getChartControlPanelRegistry from '../registries/ChartControlPanelRegistrySingleton';
import getChartTransformPropsRegistry from '../registries/ChartTransformPropsRegistrySingleton';
import { BuildQueryFunction, TransformProps } from '../types/TransformFunction';
import { ChartControlPanel } from './ChartControlPanel';
import { ChartProps } from '..';
function IDENTITY<T>(x: T) {
return x;
}
const EMPTY = {};
export type PromiseOrValue<T> = Promise<T> | T;
export type PromiseOrValueLoader<T> = () => PromiseOrValue<T>;
export type ChartType = ComponentType<any>;
type ValueOrModuleWithValue<T> = T | { default: T };
interface ChartPluginConfig<
FormData extends QueryFormData = QueryFormData,
Props extends ChartProps = ChartProps
> {
metadata: ChartMetadata;
/** Use buildQuery for immediate value. For lazy-loading, use loadBuildQuery. */
buildQuery?: BuildQueryFunction<FormData>;
/** Use loadBuildQuery for dynamic import (lazy-loading) */
loadBuildQuery?: PromiseOrValueLoader<ValueOrModuleWithValue<BuildQueryFunction<FormData>>>;
/** Use transformProps for immediate value. For lazy-loading, use loadTransformProps. */
transformProps?: TransformProps<Props>;
/** Use loadTransformProps for dynamic import (lazy-loading) */
loadTransformProps?: PromiseOrValueLoader<ValueOrModuleWithValue<TransformProps<Props>>>;
/** Use Chart for immediate value. For lazy-loading, use loadChart. */
Chart?: ChartType;
/** Use loadChart for dynamic import (lazy-loading) */
loadChart?: PromiseOrValueLoader<ValueOrModuleWithValue<ChartType>>;
/** Control panel configuration object */
controlPanel?: ChartControlPanel;
}
/**
* Loaders of the form `() => import('foo')` may return esmodules
* which require the value to be extracted as `module.default`
* */
function sanitizeLoader<T>(
loader: PromiseOrValueLoader<ValueOrModuleWithValue<T>>,
): PromiseOrValueLoader<T> {
return () => {
const loaded = loader();
return loaded instanceof Promise
? (loaded.then(module => ('default' in module && module.default) || module) as Promise<T>)
: (loaded as T);
};
}
export default class ChartPlugin<
FormData extends QueryFormData = QueryFormData,
Props extends ChartProps = ChartProps
> extends Plugin {
controlPanel: ChartControlPanel;
metadata: ChartMetadata;
loadBuildQuery?: PromiseOrValueLoader<BuildQueryFunction<FormData>>;
loadTransformProps: PromiseOrValueLoader<TransformProps<Props>>;
loadChart: PromiseOrValueLoader<ChartType>;
constructor(config: ChartPluginConfig<FormData, Props>) {
super();
const {
metadata,
buildQuery,
loadBuildQuery,
transformProps = IDENTITY,
loadTransformProps,
Chart,
loadChart,
controlPanel = EMPTY,
} = config;
this.controlPanel = controlPanel;
this.metadata = metadata;
this.loadBuildQuery =
(loadBuildQuery && sanitizeLoader(loadBuildQuery)) ||
(buildQuery && sanitizeLoader(() => buildQuery)) ||
undefined;
this.loadTransformProps = sanitizeLoader(loadTransformProps ?? (() => transformProps));
if (loadChart) {
this.loadChart = sanitizeLoader<ChartType>(loadChart);
} else if (Chart) {
this.loadChart = () => Chart;
} else {
throw new Error('Chart or loadChart is required');
}
}
register() {
const key: string = this.config.key || isRequired('config.key');
getChartMetadataRegistry().registerValue(key, this.metadata);
getChartComponentRegistry().registerLoader(key, this.loadChart);
getChartControlPanelRegistry().registerValue(key, this.controlPanel);
getChartTransformPropsRegistry().registerLoader(key, this.loadTransformProps);
if (this.loadBuildQuery) {
getChartBuildQueryRegistry().registerLoader(key, this.loadBuildQuery);
}
return this;
}
unregister() {
const key: string = this.config.key || isRequired('config.key');
getChartMetadataRegistry().remove(key);
getChartComponentRegistry().remove(key);
getChartControlPanelRegistry().remove(key);
getChartTransformPropsRegistry().remove(key);
getChartBuildQueryRegistry().remove(key);
return this;
}
configure(config: { [key: string]: unknown }, replace?: boolean) {
super.configure(config, replace);
return this;
}
}