CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-superset-ui--core

Core utilities and components for Apache Superset's frontend UI framework providing data visualization, formatting, and chart composition capabilities

Pending
Overview
Eval results
Files

plugin-system.mddocs/

Plugin System

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.

Overview

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.

Chart Plugin Architecture

ChartPlugin Class { .api }

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 };

ChartMetadata Class { .api }

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;
}

Chart Component System

SuperChart Component { .api }

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;
};

ChartProps Class { .api }

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;
}

Registry System

Chart Registries { .api }

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>;

Transform Functions

BuildQuery Function { .api }

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;
}

TransformProps Function { .api }

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  
}>;

Dynamic Loading Utilities

Loadable Renderer { .api }

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>;

Usage Examples

Creating a Basic Chart Plugin

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();

Lazy-Loaded Chart Plugin

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)
});

Using SuperChart Component

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}
    />
  );
};

Advanced Plugin with Control Panel

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
});

Plugin Registry Management

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);
};

Error Handling and Fallbacks

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);
  }}
/>

Related Documentation

  • Core Models & Utilities - Base Plugin class and Registry system
  • Dashboard Components - Dashboard integration with chart plugins
  • Data Connection - API integration for chart data
  • Data Formatting - Formatting utilities for chart display

Install with Tessl CLI

npx tessl i tessl/npm-superset-ui--core@0.18.1

docs

core-models.md

dashboard.md

data-connection.md

data-formatting.md

index.md

plugin-system.md

translation.md

ui-styling.md

validation-math.md

tile.json