Comprehensive plugin architecture supporting panel plugins, data source plugins, and app plugins with configuration, context, extension systems, and React integration for extending Grafana functionality.
Base class and utilities for creating panel plugins.
/**
* Base class for panel plugins
*/
class PanelPlugin<TOptions = any, TFieldOptions = any> extends GrafanaPlugin<PanelPluginMeta> {
/** Panel component */
panel: ComponentType<PanelProps<TOptions>>;
/**
* Sets field configuration options for the panel
* @param builder - Field config builder function
* @returns This plugin instance for chaining
*/
setFieldConfigOptions(builder: (builder: FieldConfigEditorBuilder<TFieldOptions>) => void): this;
/**
* Sets panel options configuration
* @param builder - Panel options builder function
* @returns This plugin instance for chaining
*/
setPanelOptions(builder: (builder: PanelOptionsEditorBuilder<TOptions>) => void): this;
/**
* Sets panel editor component
* @param editor - Editor component
* @returns This plugin instance for chaining
*/
setEditor(editor: ComponentType<PanelEditorProps<TOptions>>): this;
/**
* Sets migration handler for panel options
* @param handler - Migration handler function
* @returns This plugin instance for chaining
*/
setMigrationHandler(handler: PanelMigrationHandler<TOptions>): this;
/**
* Sets data support configuration
* @param config - Data support configuration
* @returns This plugin instance for chaining
*/
setDataSupport(config: PanelPluginDataSupport): this;
/**
* Sets no data message
* @param message - No data message
* @returns This plugin instance for chaining
*/
setNoPadding(noPadding?: boolean): this;
}Usage Examples:
import { PanelPlugin, FieldType, PanelProps } from "@grafana/data";
interface SimpleOptions {
text: string;
showSeriesCount: boolean;
seriesCountSize: string;
}
// Panel component
function SimplePanel({ options, data, width, height }: PanelProps<SimpleOptions>) {
return (
<div style={{ width, height }}>
<h2>{options.text}</h2>
{options.showSeriesCount && (
<p style={{ fontSize: options.seriesCountSize }}>
Series count: {data.series.length}
</p>
)}
</div>
);
}
// Plugin configuration
export const plugin = new PanelPlugin<SimpleOptions>(SimplePanel)
.setPanelOptions((builder) => {
return builder
.addTextInput({
path: 'text',
name: 'Simple text option',
description: 'Description of panel option',
defaultValue: 'Default value',
})
.addBooleanSwitch({
path: 'showSeriesCount',
name: 'Show series counter',
defaultValue: false,
})
.addRadio({
path: 'seriesCountSize',
defaultValue: '12px',
name: 'Series counter size',
settings: {
options: [
{ value: '12px', label: 'Small' },
{ value: '14px', label: 'Medium' },
{ value: '16px', label: 'Large' },
],
},
showIf: (config) => config.showSeriesCount,
});
});Base class and utilities for creating data source plugins.
/**
* Base class for data source plugins
*/
class DataSourcePlugin<
TOptions extends DataSourceJsonData = DataSourceJsonData,
TQuery extends DataQuery = DataQuery
> extends GrafanaPlugin<DataSourcePluginMeta<TOptions>> {
/** Plugin components */
components: DataSourcePluginComponents<TOptions, TQuery>;
/**
* Sets query editor component
* @param QueryEditor - Query editor component
* @returns This plugin instance for chaining
*/
setQueryEditor(QueryEditor: ComponentType<QueryEditorProps<any, TQuery, TOptions>>): this;
/**
* Sets config editor component
* @param ConfigEditor - Config editor component
* @returns This plugin instance for chaining
*/
setConfigEditor(ConfigEditor: ComponentType<DataSourcePluginOptionsEditorProps<TOptions>>): this;
/**
* Sets query editor help component
* @param QueryEditorHelp - Help component
* @returns This plugin instance for chaining
*/
setQueryEditorHelp(QueryEditorHelp: ComponentType<QueryEditorHelpProps>): this;
/**
* Sets metadata inspector component
* @param MetadataInspector - Inspector component
* @returns This plugin instance for chaining
*/
setMetadataInspector(MetadataInspector: ComponentType<MetadataInspectorProps>): this;
/**
* Sets variable support
* @param variableSupport - Variable support configuration
* @returns This plugin instance for chaining
*/
setVariableSupport(variableSupport: VariableSupport): this;
/**
* Sets annotation support
* @param annotationSupport - Annotation support configuration
* @returns This plugin instance for chaining
*/
setAnnotationSupport(annotationSupport: AnnotationSupport): this;
}
/**
* Base class for data source API implementations
*/
abstract class DataSourceApi<
TQuery extends DataQuery = DataQuery,
TOptions extends DataSourceJsonData = DataSourceJsonData
> {
/** Data source name */
name: string;
/** Data source ID */
id: number;
/** Data source type */
type: string;
/** Data source UID */
uid: string;
/** Instance settings */
instanceSettings: DataSourceInstanceSettings<TOptions>;
constructor(instanceSettings: DataSourceInstanceSettings<TOptions>);
/**
* Main query method
* @param request - Query request
* @returns Observable of query response
*/
abstract query(request: DataQueryRequest<TQuery>): Observable<DataQueryResponse>;
/**
* Test data source connection
* @returns Promise of test result
*/
abstract testDatasource(): Promise<TestDataSourceResponse>;
/**
* Import queries from another format
* @param queries - Queries to import
* @param originMeta - Origin metadata
* @returns Imported queries
*/
importQueries?(queries: TQuery[], originMeta: PluginMeta): Promise<TQuery[]>;
/**
* Export queries to another format
* @param queries - Queries to export
* @returns Exported queries
*/
exportQueries?(queries: TQuery[]): Promise<TQuery[]>;
/**
* Get metric find values
* @param query - Metric find query
* @param options - Additional options
* @returns Promise of metric find values
*/
metricFindQuery?(query: any, options?: any): Promise<MetricFindValue[]>;
/**
* Get tag keys
* @param options - Tag keys options
* @returns Promise of tag keys
*/
getTagKeys?(options: DataSourceGetTagKeysOptions): Promise<MetricFindValue[]>;
/**
* Get tag values
* @param options - Tag values options
* @returns Promise of tag values
*/
getTagValues?(options: DataSourceGetTagValuesOptions): Promise<MetricFindValue[]>;
}Base class for application plugins.
/**
* Base class for app plugins
*/
class AppPlugin<T extends KeyValue = KeyValue> extends GrafanaPlugin<AppPluginMeta> {
/** Root component */
root?: ComponentType<AppRootProps>;
/**
* Sets root component
* @param root - Root component
* @returns This plugin instance for chaining
*/
setRootPage(root: ComponentType<AppRootProps>): this;
/**
* Adds config page
* @param tab - Tab configuration
* @returns This plugin instance for chaining
*/
addConfigPage(tab: PluginConfigPage<T>): this;
/**
* Sets channel handler
* @param handler - Channel handler
* @returns This plugin instance for chaining
*/
setChannelHandler(handler: any): this;
}Context providers and hooks for plugin development.
/**
* Plugin context provider for general plugins
*/
function PluginContextProvider({ children, meta }: PluginContextProviderProps): JSX.Element;
/**
* Data source plugin context provider
*/
function DataSourcePluginContextProvider({
children,
instanceSettings
}: DataSourcePluginContextProviderProps): JSX.Element;
/**
* Hook to access plugin context
* @returns Plugin context
*/
function usePluginContext(): PluginContextType;
/**
* Type guard for data source plugin context
* @param context - Plugin context to check
* @returns True if context is data source plugin context
*/
function isDataSourcePluginContext(
context: PluginContextType
): context is DataSourcePluginContextType;Usage Examples:
import React from 'react';
import {
PluginContextProvider,
usePluginContext,
DataSourcePluginContextProvider
} from "@grafana/data";
// General plugin context usage
function MyPanelComponent() {
const pluginContext = usePluginContext();
return (
<div>
<h3>Plugin: {pluginContext.meta.name}</h3>
<p>Version: {pluginContext.meta.info.version}</p>
</div>
);
}
// Wrapped with context provider
function PanelWithContext({ meta, children }) {
return (
<PluginContextProvider meta={meta}>
<MyPanelComponent />
</PluginContextProvider>
);
}
// Data source plugin context
function QueryEditorComponent() {
const context = usePluginContext();
if (isDataSourcePluginContext(context)) {
const { instanceSettings } = context;
return (
<div>
<h3>Data Source: {instanceSettings.name}</h3>
<p>Type: {instanceSettings.type}</p>
</div>
);
}
return <div>Not a data source plugin</div>;
}Utility functions for plugin options and configuration.
/**
* Gets panel options with default values applied
* @param options - Panel options
* @returns Options with defaults
*/
function getPanelOptionsWithDefaults(options: any): any;
/**
* Filters field config overrides
* @param fieldConfig - Field configuration
* @param panelId - Panel ID for filtering
* @returns Filtered field config
*/
function filterFieldConfigOverrides(fieldConfig: FieldConfigSource, panelId: string): FieldConfigSource;
/**
* Restores custom override rules
* @param fieldConfig - Field configuration
* @param panelId - Panel ID
* @returns Field config with restored rules
*/
function restoreCustomOverrideRules(fieldConfig: FieldConfigSource, panelId: string): FieldConfigSource;
/**
* Checks if property is custom field property
* @param prop - Property to check
* @returns True if custom property
*/
function isCustomFieldProp(prop: string): boolean;
/**
* Checks if property is standard field property
* @param prop - Property to check
* @returns True if standard property
*/
function isStandardFieldProp(prop: string): boolean;
/**
* Creates field config registry
* @returns Field config registry
*/
function createFieldConfigRegistry(): FieldConfigOptionsRegistry;/**
* Base plugin class
*/
abstract class GrafanaPlugin<T extends PluginMeta> {
/** Plugin metadata */
meta: T;
constructor(meta: T);
}
/**
* Plugin context types
*/
type PluginContextType = {
meta: PluginMeta;
} | DataSourcePluginContextType;
type DataSourcePluginContextType = {
meta: DataSourcePluginMeta;
instanceSettings: DataSourceInstanceSettings;
};
/**
* Plugin context interfaces
*/
interface PluginContext {
meta: PluginMeta;
}
interface PluginContextProviderProps {
children: React.ReactNode;
meta: PluginMeta;
}
interface DataSourcePluginContextProviderProps {
children: React.ReactNode;
instanceSettings: DataSourceInstanceSettings;
}
/**
* Panel plugin interfaces
*/
interface PanelProps<TOptions = any> {
/** Panel data */
data: PanelData;
/** Panel options */
options: TOptions;
/** Panel width */
width: number;
/** Panel height */
height: number;
/** Field configuration */
fieldConfig: FieldConfigSource;
/** Panel ID */
id: number;
/** Time range */
timeRange: TimeRange;
/** Time zone */
timeZone: TimeZone;
/** Transparent background */
transparent: boolean;
/** Render counter */
renderCounter: number;
/** Replace variables function */
replaceVariables: InterpolateFunction;
/** Event bus */
eventBus: EventBus;
/** Panel title */
title: string;
/** On options change callback */
onOptionsChange: (options: TOptions) => void;
/** On field config change callback */
onFieldConfigChange: (config: FieldConfigSource) => void;
/** On change time range callback */
onChangeTimeRange: (timeRange: TimeRange) => void;
}
interface PanelEditorProps<TOptions = any> {
/** Panel options */
options: TOptions;
/** Panel data */
data?: PanelData;
/** Field configuration */
fieldConfig: FieldConfigSource;
/** On options change callback */
onOptionsChange: (options: TOptions) => void;
/** On field config change callback */
onFieldConfigChange: (config: FieldConfigSource) => void;
}
interface PanelData {
/** Data series */
series: DataFrame[];
/** Loading state */
state: LoadingState;
/** Time range */
timeRange: TimeRange;
/** Error information */
error?: DataQueryError;
/** Request information */
request?: DataQueryRequest;
/** Annotations */
annotations?: DataFrame[];
}
/**
* Data source plugin interfaces
*/
interface DataSourcePluginComponents<TOptions, TQuery> {
/** Query editor component */
QueryEditor?: ComponentType<QueryEditorProps<any, TQuery, TOptions>>;
/** Config editor component */
ConfigEditor?: ComponentType<DataSourcePluginOptionsEditorProps<TOptions>>;
/** Query editor help component */
QueryEditorHelp?: ComponentType<QueryEditorHelpProps>;
/** Metadata inspector component */
MetadataInspector?: ComponentType<MetadataInspectorProps>;
/** Variable query editor component */
VariableQueryEditor?: ComponentType<any>;
/** Annotation query editor component */
AnnotationQueryEditor?: ComponentType<any>;
}
interface QueryEditorProps<DS, TQuery extends DataQuery, TOptions> {
/** Data source instance */
datasource: DS;
/** Query object */
query: TQuery;
/** On query change callback */
onChange: (query: TQuery) => void;
/** On run query callback */
onRunQuery: () => void;
/** Data source options */
options?: TOptions;
/** Query range */
range?: TimeRange;
/** Additional data */
data?: PanelData;
}
/**
* Plugin metadata interfaces
*/
interface PluginMeta {
/** Plugin ID */
id: string;
/** Plugin name */
name: string;
/** Plugin type */
type: PluginType;
/** Plugin info */
info: PluginMetaInfo;
/** Plugin includes */
includes?: PluginInclude[];
/** Plugin state */
state?: PluginState;
/** Plugin signature */
signature?: PluginSignatureStatus;
/** Plugin signature type */
signatureType?: PluginSignatureType;
/** Plugin signature org */
signatureOrg?: string;
/** Module path */
module: string;
/** Base URL */
baseUrl: string;
/** Plugin dependencies */
dependencies?: PluginDependencies;
/** Plugin category */
category?: string;
/** Angular detection */
angular?: AngularMeta;
}
interface PanelPluginMeta extends PluginMeta {
/** Panel plugin specific options */
skipDataQuery?: boolean;
hideFromList?: boolean;
sort: number;
}
interface DataSourcePluginMeta<T extends DataSourceJsonData = DataSourceJsonData> extends PluginMeta {
/** Streaming support */
streaming?: boolean;
/** Mixed data source support */
mixed?: boolean;
/** Metrics support */
metrics?: boolean;
/** Logs support */
logs?: boolean;
/** Traces support */
tracing?: boolean;
/** Annotations support */
annotations?: boolean;
/** Alerting support */
alerting?: boolean;
/** Query options */
queryOptions?: {
maxDataPoints?: boolean;
minInterval?: boolean;
cacheTimeout?: boolean;
};
/** Built-in */
builtIn?: boolean;
}
interface AppPluginMeta extends PluginMeta {
/** Enabled status */
enabled?: boolean;
/** Pinned to navbar */
pinned?: boolean;
}
/**
* Standard option configuration
*/
interface StandardOptionConfig {
/** Display name */
displayName: string;
/** Property path */
path: string;
/** Description */
description?: string;
/** Default value */
defaultValue?: any;
/** Custom settings */
settings?: any;
/** Show condition */
showIf?: (options: any) => boolean;
/** Category */
category?: string[];
}
/**
* Set field config options arguments
*/
interface SetFieldConfigOptionsArgs<TFieldOptions> {
/** Standard options */
standardOptions?: StandardOptionConfig[];
/** Use field options */
useFieldOptions?: (builder: FieldConfigEditorBuilder<TFieldOptions>) => void;
}
/**
* Option defaults
*/
interface OptionDefaults {
[key: string]: any;
}
/**
* Plugin enums
*/
enum PluginType {
panel = 'panel',
datasource = 'datasource',
app = 'app',
renderer = 'renderer',
secretsmanager = 'secretsmanager'
}
enum PluginState {
alpha = 'alpha',
beta = 'beta',
stable = 'stable',
deprecated = 'deprecated'
}
enum PluginSignatureStatus {
internal = 'internal',
valid = 'valid',
invalid = 'invalid',
modified = 'modified',
unsigned = 'unsigned'
}
enum PluginSignatureType {
grafana = 'grafana',
commercial = 'commercial',
community = 'community',
private = 'private'
}
enum CoreApp {
CloudAlerting = 'cloud-alerting',
UnifiedAlerting = 'unified-alerting',
Dashboard = 'dashboard',
Explore = 'explore',
Correlations = 'correlations',
Unknown = 'unknown',
PanelEditor = 'panel-editor',
PanelViewer = 'panel-viewer'
}
enum FeatureState {
alpha = 'alpha',
beta = 'beta',
stable = 'stable',
deprecated = 'deprecated'
}