Core utilities and components for Apache Superset's frontend UI framework providing data visualization, formatting, and chart composition capabilities
—
This module provides the comprehensive chart plugin system and dynamic loading infrastructure for Superset's extensible visualization framework. It includes chart plugins, component registries, the SuperChart rendering system, and support for both static and dynamically loaded chart components.
The plugin system is built around the ChartPlugin class that extends the base Plugin class, providing specialized functionality for chart visualization components. It supports lazy loading of chart components, build query functions, transform props, and control panels, enabling efficient code splitting and dynamic plugin registration.
Core plugin class for chart visualizations with support for lazy loading:
import { ChartPlugin, ChartMetadata } from '@superset-ui/core';
interface ChartPluginConfig<
FormData extends QueryFormData = QueryFormData,
Props extends ChartProps = ChartProps
> {
metadata: ChartMetadata;
// Build Query (choose one approach)
buildQuery?: BuildQueryFunction<FormData>;
loadBuildQuery?: PromiseOrValueLoader<ValueOrModuleWithValue<BuildQueryFunction<FormData>>>;
// Transform Props (choose one approach)
transformProps?: TransformProps<Props>;
loadTransformProps?: PromiseOrValueLoader<ValueOrModuleWithValue<TransformProps<Props>>>;
// Chart Component (choose one approach)
Chart?: ChartType;
loadChart?: PromiseOrValueLoader<ValueOrModuleWithValue<ChartType>>;
// Control Panel (choose one approach)
controlPanel?: ChartControlPanel;
loadControlPanel?: PromiseOrValueLoader<ValueOrModuleWithValue<ChartControlPanel>>;
}
class ChartPlugin<
FormData extends QueryFormData = QueryFormData,
Props extends ChartProps = ChartProps
> extends Plugin {
constructor(config: ChartPluginConfig<FormData, Props>);
// Override base Plugin methods
register(): this;
unregister(): this;
// Plugin configuration
configure(config: Partial<ChartPluginConfig<FormData, Props>>, replace?: boolean): this;
}
// Utility types for lazy loading
type PromiseOrValue<T> = Promise<T> | T;
type PromiseOrValueLoader<T> = () => PromiseOrValue<T>;
type ChartType = React.ComponentType<any>;
type ValueOrModuleWithValue<T> = T | { default: T };Metadata container that describes chart plugin capabilities and configuration:
import { ChartMetadata, Behavior } from '@superset-ui/core';
interface ChartMetadataConfig {
name: string; // Display name for the chart
description?: string; // Human-readable description
canBeAnnotationTypes?: string[]; // Supported annotation types
category?: string; // Chart category for grouping
credits?: string[]; // Attribution/credits
datasourceCount?: number; // Number of required data sources
deprecated?: boolean; // Whether chart is deprecated
exampleGallery?: ExampleImage[]; // Example gallery images
show?: boolean; // Whether to show in chart picker
supportedAnnotationTypes?: string[]; // Annotation types this chart supports
thumbnail?: string; // Thumbnail image URL
useLegacyApi?: boolean; // Whether to use legacy API format
behaviors?: Behavior[]; // Chart behavior capabilities
tags?: string[]; // Tags for categorization and search
}
class ChartMetadata {
constructor(config: ChartMetadataConfig);
// Metadata properties (all readonly)
readonly name: string;
readonly description?: string;
readonly canBeAnnotationTypes?: string[];
readonly category?: string;
readonly credits?: string[];
readonly datasourceCount?: number;
readonly deprecated?: boolean;
readonly exampleGallery?: ExampleImage[];
readonly show?: boolean;
readonly supportedAnnotationTypes?: string[];
readonly thumbnail?: string;
readonly useLegacyApi?: boolean;
readonly behaviors?: Behavior[];
readonly tags?: string[];
// Utility methods
clone(overrides?: Partial<ChartMetadataConfig>): ChartMetadata;
}
// Chart behavior enumeration
enum Behavior {
INTERACTIVE_CHART = 'INTERACTIVE_CHART',
NATIVE_FILTER = 'NATIVE_FILTER',
DRILL_TO_DETAIL = 'DRILL_TO_DETAIL',
DRILL_BY = 'DRILL_BY'
}
interface ExampleImage {
url: string;
caption?: string;
}Main chart rendering component that handles plugin loading and error boundaries:
import { SuperChart } from '@superset-ui/core';
interface SuperChartProps extends Omit<ChartPropsConfig, 'width' | 'height'> {
// Chart identification
chartType: string; // Registered chart type key
// Dimensions (auto-sizing if not specified)
width?: number | string;
height?: number | string;
// Error handling
disableErrorBoundary?: boolean; // Disable built-in error boundary
FallbackComponent?: React.ComponentType<FallbackPropsWithDimension>;
onErrorBoundary?: (error: Error, errorInfo: React.ErrorInfo) => void;
// Behavior configuration
debounceTime?: number; // Resize debounce time in ms
enableNoResults?: boolean; // Show "No Results" message
showOverflow?: boolean; // Show overflow content
// Refs for integration
parentRef?: React.RefObject<any>;
inputRef?: React.RefObject<any>;
// Layout wrapper
Wrapper?: React.ComponentType<WrapperProps>;
}
// SuperChart component
const SuperChart: React.ComponentType<SuperChartProps>;
// Dimension and wrapper types
interface WrapperProps extends Dimension {
children: React.ReactNode;
}
type FallbackPropsWithDimension = {
error: Error;
resetErrorBoundary: () => void;
width?: number;
height?: number;
};Props container that manages chart data and configuration:
import { ChartProps } from '@superset-ui/core';
interface ChartPropsConfig {
annotationData?: AnnotationData;
datasource?: Datasource;
initialValues?: any;
formData?: QueryFormData;
height?: number;
hooks?: ChartHooks;
ownCurrentState?: any;
ownState?: any;
queriesData?: ChartDataResponseResult[];
rawDatasource?: Datasource;
rawFormData?: QueryFormData;
width?: number;
}
class ChartProps {
constructor(config?: ChartPropsConfig & { [key: string]: any });
// Core properties
readonly annotationData: AnnotationData;
readonly datasource: Datasource;
readonly formData: QueryFormData;
readonly height: number;
readonly hooks: ChartHooks;
readonly initialValues: any;
readonly ownCurrentState: any;
readonly ownState: any;
readonly queriesData: ChartDataResponseResult[];
readonly rawDatasource: Datasource;
readonly rawFormData: QueryFormData;
readonly width: number;
}Specialized registries for managing different aspects of chart plugins:
import {
getChartComponentRegistry,
getChartMetadataRegistry,
getChartBuildQueryRegistry,
getChartTransformPropsRegistry,
getChartControlPanelRegistry
} from '@superset-ui/core';
// Chart component registry
function getChartComponentRegistry(): RegistryWithDefaultKey<ChartType>;
// Chart metadata registry
function getChartMetadataRegistry(): RegistryWithDefaultKey<ChartMetadata>;
// Build query function registry
function getChartBuildQueryRegistry(): RegistryWithDefaultKey<BuildQueryFunction>;
// Transform props function registry
function getChartTransformPropsRegistry(): RegistryWithDefaultKey<TransformProps>;
// Control panel configuration registry
function getChartControlPanelRegistry(): RegistryWithDefaultKey<ChartControlPanel>;Function type for building queries from form data:
type BuildQueryFunction<FormData extends QueryFormData = QueryFormData> = (
formData: FormData
) => QueryContext;
// Query context structure
interface QueryContext {
datasource: DatasourceInfo;
queries: Query[];
force?: boolean;
result_format?: QueryResultFormat;
result_type?: QueryResultType;
}
interface Query {
annotation_layers?: AnnotationLayer[];
applied_time_extras?: AppliedTimeExtra;
columns?: QueryColumn[];
extras?: QueryExtra;
filters?: QueryFilter[];
granularity?: string;
groupby?: QueryColumn[];
having?: string;
is_timeseries?: boolean;
limit?: number;
metrics?: QueryMetric[];
order_desc?: boolean;
orderby?: QueryOrderBy[];
post_processing?: PostProcessingRule[];
row_limit?: number;
series_columns?: QueryColumn[];
series_limit?: number;
series_limit_metric?: QueryMetric;
time_grain?: string;
time_range?: string;
timeseries_limit?: number;
timeseries_limit_metric?: QueryMetric;
url_params?: UrlParams;
where?: string;
}Function type for transforming query results into chart props:
type TransformProps<Props extends ChartProps = ChartProps> = (
chartProps: ChartProps
) => Props;
// Common transform props patterns
type TimeseriesTransformProps = TransformProps<{
data: TimeseriesDataRecord[];
width: number;
height: number;
// ... chart-specific props
}>;
type TableTransformProps = TransformProps<{
data: TableDataRecord[];
columns: TableColumnConfig[];
// ... table-specific props
}>;Utilities for creating lazy-loaded chart components:
import { createLoadableRenderer } from '@superset-ui/core';
function createLoadableRenderer<Props, FormData extends QueryFormData = QueryFormData>(config: {
loader: () => Promise<{ default: React.ComponentType<Props> }>;
loading?: React.ComponentType<any>;
fallback?: React.ComponentType<{ error: Error }>;
}): React.ComponentType<Props>;
// React component converter
function reactify(component: any): React.ComponentType<any>;import {
ChartPlugin,
ChartMetadata,
Behavior,
buildQueryContext,
QueryFormData
} from '@superset-ui/core';
// Define form data interface
interface BarChartFormData extends QueryFormData {
groupby: string[];
metrics: string[];
color_scheme?: string;
x_axis_label?: string;
y_axis_label?: string;
}
// Create chart metadata
const metadata = new ChartMetadata({
name: 'Bar Chart',
description: 'Simple bar chart visualization',
category: 'Evolution',
behaviors: [Behavior.INTERACTIVE_CHART, Behavior.DRILL_TO_DETAIL],
thumbnail: '/static/assets/images/viz_types/bar.png',
tags: ['Basic', 'Popular', 'Business']
});
// Build query function
const buildQuery = (formData: BarChartFormData) => {
return buildQueryContext(formData, {
queryFields: {
groupby: 'groupby',
metrics: 'metrics'
}
});
};
// Transform props function
const transformProps = (chartProps: ChartProps) => {
const { width, height, formData, queriesData } = chartProps;
const data = queriesData[0]?.data || [];
return {
width,
height,
data,
colorScheme: formData.color_scheme,
xAxisLabel: formData.x_axis_label,
yAxisLabel: formData.y_axis_label
};
};
// Chart component (simplified)
const BarChart: React.FC<any> = ({ width, height, data }) => (
<div style={{ width, height }}>
{/* Chart implementation */}
</div>
);
// Create and register plugin
const BarChartPlugin = new ChartPlugin({
metadata,
buildQuery,
transformProps,
Chart: BarChart
});
BarChartPlugin.register();import { ChartPlugin, ChartMetadata } from '@superset-ui/core';
// Create plugin with lazy loading
const LazyBarChartPlugin = new ChartPlugin({
metadata: new ChartMetadata({
name: 'Lazy Bar Chart',
description: 'Dynamically loaded bar chart',
category: 'Evolution'
}),
// Lazy load chart component
loadChart: () => import('./charts/BarChart').then(module => module.default),
// Lazy load build query function
loadBuildQuery: () => import('./queries/barChartQuery').then(module => module.buildQuery),
// Lazy load transform props
loadTransformProps: () => import('./transforms/barChartTransform').then(module => module.transformProps),
// Lazy load control panel
loadControlPanel: () => import('./controls/barChartControls').then(module => module.default)
});import React from 'react';
import { SuperChart, ChartDataResponseResult } from '@superset-ui/core';
interface DashboardChartProps {
chartId: number;
formData: QueryFormData;
queriesData: ChartDataResponseResult[];
width?: number;
height?: number;
}
const DashboardChart: React.FC<DashboardChartProps> = ({
chartId,
formData,
queriesData,
width = 400,
height = 300
}) => {
const handleChartError = (error: Error) => {
console.error(`Chart ${chartId} error:`, error);
};
return (
<SuperChart
chartType={formData.viz_type}
width={width}
height={height}
formData={formData}
queriesData={queriesData}
onErrorBoundary={handleChartError}
enableNoResults={true}
/>
);
};import {
ChartPlugin,
ChartMetadata,
ControlPanelConfig
} from '@superset-ui/core';
// Control panel configuration
const controlPanel: ControlPanelConfig = {
controlPanelSections: [
{
label: 'Query',
expanded: true,
controlSetRows: [
['metrics'],
['groupby'],
['limit', 'timeseries_limit_metric'],
['order_desc', 'contribution'],
['row_limit', null]
]
},
{
label: 'Chart Options',
expanded: true,
controlSetRows: [
['color_scheme'],
['show_legend', 'legend_position'],
['x_axis_label', 'y_axis_label']
]
}
],
controlOverrides: {
color_scheme: {
renderTrigger: true,
default: 'supersetColors'
}
}
};
// Advanced chart plugin
const AdvancedBarChartPlugin = new ChartPlugin({
metadata: new ChartMetadata({
name: 'Advanced Bar Chart',
description: 'Bar chart with extensive configuration options',
category: 'Evolution',
behaviors: [
Behavior.INTERACTIVE_CHART,
Behavior.DRILL_TO_DETAIL,
Behavior.DRILL_BY
]
}),
Chart: AdvancedBarChart,
buildQuery: buildAdvancedBarQuery,
transformProps: transformAdvancedBarProps,
controlPanel
});import {
getChartComponentRegistry,
getChartMetadataRegistry,
ChartPlugin
} from '@superset-ui/core';
// Register multiple plugins
const plugins = [BarChartPlugin, LineChartPlugin, PieChartPlugin];
plugins.forEach(plugin => plugin.register());
// Get registered chart types
const componentRegistry = getChartComponentRegistry();
const availableChartTypes = componentRegistry.keys();
// Get chart metadata
const metadataRegistry = getChartMetadataRegistry();
const barChartMetadata = metadataRegistry.get('bar');
// Unregister plugin
const unregisterPlugin = (chartType: string) => {
const componentRegistry = getChartComponentRegistry();
const metadataRegistry = getChartMetadataRegistry();
componentRegistry.remove(chartType);
metadataRegistry.remove(chartType);
};import React from 'react';
import { SuperChart, FallbackPropsWithDimension } from '@superset-ui/core';
// Custom fallback component
const ChartErrorFallback: React.FC<FallbackPropsWithDimension> = ({
error,
resetErrorBoundary,
width,
height
}) => (
<div
style={{
width,
height,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
border: '2px dashed #ccc'
}}
>
<h3>Chart Error</h3>
<p>{error.message}</p>
<button onClick={resetErrorBoundary}>
Try Again
</button>
</div>
);
// Use with SuperChart
<SuperChart
chartType="advanced_bar"
formData={formData}
queriesData={queriesData}
FallbackComponent={ChartErrorFallback}
onErrorBoundary={(error, errorInfo) => {
// Log error to monitoring service
console.error('Chart render error:', error, errorInfo);
}}
/>Install with Tessl CLI
npx tessl i tessl/npm-superset-ui--core@0.18.1