Suggestions: Proposed PanelPlugin API (#113688)
* Suggestions: Update ownership of core files and improve some types * Suggestions: Proposed PanelPlugin API * get rid of .useSuggestionsConfig * update i18n * iterate on TypeScript types, add example in radialbar * tweak implementation, add commentary * actually, suggestions really does not need panel defaults * split suggestions handler into its own file and add tests for radialbar * small comment revision * fix test * add ds.hasData check back for state-timeline * restore a handful of comments that got lost in the merge shuffle * more updated commnets * remove pluginId from VisualizationSuggestion, whoops * fix getAllSuggestions test * update i18n * might as well restore description here * move fieldconfig back on radialbar * call them suppliers, remove boolean return type in favor of internal util * Update packages/grafana-data/src/panel/PanelPlugin.ts * Update packages/grafana-data/src/panel/PanelPlugin.ts * Update packages/grafana-data/src/panel/PanelPlugin.ts * tweak return type for setSuggestionSupplier to be this
This commit is contained in:
@@ -715,6 +715,8 @@ export {
|
||||
export {
|
||||
type VisualizationSuggestion,
|
||||
type VisualizationSuggestionsSupplier,
|
||||
type VisualizationSuggestionsSupplierFn,
|
||||
type PanelPluginVisualizationSuggestion,
|
||||
VisualizationSuggestionScore,
|
||||
VisualizationSuggestionsBuilder,
|
||||
VisualizationSuggestionsListAppender,
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
PanelPluginDataSupport,
|
||||
} from '../types/panel';
|
||||
import { GrafanaPlugin } from '../types/plugin';
|
||||
import { VisualizationSuggestionsSupplier } from '../types/suggestions';
|
||||
import { VisualizationSuggestionsSupplierFn, VisualizationSuggestionsSupplier } from '../types/suggestions';
|
||||
import { FieldConfigEditorBuilder, PanelOptionsEditorBuilder } from '../utils/OptionsUIBuilders';
|
||||
import { deprecationWarning } from '../utils/deprecationWarning';
|
||||
|
||||
@@ -363,11 +363,34 @@ export class PanelPlugin<
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets function that can return visualization examples and suggestions.
|
||||
* @alpha
|
||||
* @deprecated use VisualizationSuggestionsSupplierFn
|
||||
*/
|
||||
setSuggestionsSupplier(supplier: VisualizationSuggestionsSupplier) {
|
||||
this.suggestionsSupplier = supplier;
|
||||
setSuggestionsSupplier(supplier: VisualizationSuggestionsSupplier): this;
|
||||
/**
|
||||
* @alpha
|
||||
* sets function that can return visualization examples and suggestions.
|
||||
*/
|
||||
setSuggestionsSupplier(supplier: VisualizationSuggestionsSupplierFn<TOptions, TFieldConfigOptions>): this;
|
||||
setSuggestionsSupplier(
|
||||
supplier: VisualizationSuggestionsSupplier | VisualizationSuggestionsSupplierFn<TOptions, TFieldConfigOptions>
|
||||
): this {
|
||||
this.suggestionsSupplier =
|
||||
typeof supplier === 'function'
|
||||
? {
|
||||
getSuggestionsForData: (builder) => {
|
||||
const appender = builder.getListAppender<TOptions, TFieldConfigOptions>({
|
||||
pluginId: this.meta.id,
|
||||
name: this.meta.name,
|
||||
});
|
||||
|
||||
const result = supplier(builder.dataSummary);
|
||||
|
||||
if (Array.isArray(result)) {
|
||||
appender.appendAll(result);
|
||||
}
|
||||
},
|
||||
}
|
||||
: supplier;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -379,6 +402,14 @@ export class PanelPlugin<
|
||||
return this.suggestionsSupplier;
|
||||
}
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
* returns whether the plugin has configured suggestions
|
||||
*/
|
||||
hasSuggestions(): boolean {
|
||||
return this.suggestionsSupplier !== undefined;
|
||||
}
|
||||
|
||||
hasPluginId(pluginId: string) {
|
||||
return this.meta.id === pluginId;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { defaultsDeep } from 'lodash';
|
||||
|
||||
import { DataTransformerConfig } from '@grafana/schema';
|
||||
@@ -11,29 +10,45 @@ import { PanelData } from './panel';
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
* A suggestion for a visualization given some data. This represents the shape of the panel (including options and field config)
|
||||
* that will be used to show a small preview in the Grafana UI when suggesting visualizations in the Panel Editor.
|
||||
*/
|
||||
export interface VisualizationSuggestion<TOptions = any, TFieldConfig = any> {
|
||||
export interface VisualizationSuggestion<TOptions extends unknown = {}, TFieldConfig extends {} = {}> {
|
||||
/** Name of suggestion */
|
||||
name: string;
|
||||
name?: string;
|
||||
/** Description */
|
||||
description?: string;
|
||||
/** Panel plugin id */
|
||||
pluginId: string;
|
||||
/** Panel plugin options */
|
||||
options?: Partial<TOptions>;
|
||||
/** Panel plugin field options */
|
||||
fieldConfig?: FieldConfigSource<Partial<TFieldConfig>>;
|
||||
/** Data transformations */
|
||||
transformations?: DataTransformerConfig[];
|
||||
/** A value between 0-100 how suitable suggestion is */
|
||||
score?: VisualizationSuggestionScore;
|
||||
/** Options for how to render suggestion card */
|
||||
cardOptions?: {
|
||||
/** Tweak for small preview */
|
||||
previewModifier?: (suggestion: VisualizationSuggestion) => void;
|
||||
/**
|
||||
* Given that the suggestion is being rendered as a small preview, you may want to modify certain options
|
||||
* specifically for the smaller preview version of the visualization. In this method, you should directly
|
||||
* mutate the suggestion object which is passed in as the first argument.
|
||||
*/
|
||||
previewModifier?: (suggestion: VisualizationSuggestion<TOptions, TFieldConfig>) => void;
|
||||
icon?: string;
|
||||
imgSrc?: string;
|
||||
};
|
||||
/** A value between 0-100 how suitable suggestion is */
|
||||
score?: VisualizationSuggestionScore;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* the internal interface that the PanelPlugin transforms the supplied suggestions into.
|
||||
*/
|
||||
export interface PanelPluginVisualizationSuggestion<TOptions extends unknown = {}, TFieldConfig extends {} = {}>
|
||||
extends VisualizationSuggestion<TOptions, TFieldConfig> {
|
||||
/** Name of suggestion */
|
||||
name: string;
|
||||
/** Panel plugin id */
|
||||
pluginId: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -49,12 +64,13 @@ export enum VisualizationSuggestionScore {
|
||||
}
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
* @internal
|
||||
* TODO this will move into the grafana app code once suppliers are migrated.
|
||||
*/
|
||||
export class VisualizationSuggestionsBuilder {
|
||||
/** Summary stats for current data */
|
||||
dataSummary: PanelDataSummary;
|
||||
private list: VisualizationSuggestion[] = [];
|
||||
private list: PanelPluginVisualizationSuggestion[] = [];
|
||||
|
||||
constructor(
|
||||
/** Current data */
|
||||
@@ -65,7 +81,9 @@ export class VisualizationSuggestionsBuilder {
|
||||
this.dataSummary = getPanelDataSummary(data?.series);
|
||||
}
|
||||
|
||||
getListAppender<TOptions, TFieldConfig>(defaults: VisualizationSuggestion<TOptions, TFieldConfig>) {
|
||||
getListAppender<TOptions extends unknown, TFieldConfig extends {} = {}>(
|
||||
defaults: PanelPluginVisualizationSuggestion<TOptions, TFieldConfig>
|
||||
) {
|
||||
return new VisualizationSuggestionsListAppender<TOptions, TFieldConfig>(this.list, defaults);
|
||||
}
|
||||
|
||||
@@ -76,25 +94,43 @@ export class VisualizationSuggestionsBuilder {
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
* TODO: this name is temporary; it will become just "VisualizationSuggestionsSupplier" when the other interface is deleted.
|
||||
*
|
||||
* executed while rendering suggestions each time the DataFrame changes, this method
|
||||
* determines which suggestions can be shown for this PanelPlugin given the PanelDataSummary.
|
||||
*
|
||||
* - returns an array of VisualizationSuggestions
|
||||
* - boolean return equates to "show a single suggestion card for this panel plugin with the default options" (true = show, false or void = hide)
|
||||
*/
|
||||
export type VisualizationSuggestionsSupplierFn<TOptions extends unknown, TFieldConfig extends {} = {}> = (
|
||||
panelDataSummary: PanelDataSummary
|
||||
) => Array<VisualizationSuggestion<TOptions, TFieldConfig>> | void;
|
||||
|
||||
/**
|
||||
* @deprecated use VisualizationSuggestionsSupplierFn instead.
|
||||
*/
|
||||
export type VisualizationSuggestionsSupplier = {
|
||||
/**
|
||||
* Adds good suitable suggestions for the current data
|
||||
* Adds suitable suggestions for the current data
|
||||
*/
|
||||
getSuggestionsForData: (builder: VisualizationSuggestionsBuilder) => void;
|
||||
};
|
||||
|
||||
/**
|
||||
* Helps with typings and defaults
|
||||
* @alpha
|
||||
* @internal
|
||||
* TODO this will move into the grafana app code once suppliers are migrated.
|
||||
*/
|
||||
export class VisualizationSuggestionsListAppender<TOptions, TFieldConfig> {
|
||||
export class VisualizationSuggestionsListAppender<TOptions extends unknown, TFieldConfig extends {} = {}> {
|
||||
constructor(
|
||||
private list: VisualizationSuggestion[],
|
||||
private defaults: VisualizationSuggestion<TOptions, TFieldConfig>
|
||||
private defaults: Partial<PanelPluginVisualizationSuggestion<TOptions, TFieldConfig>> = {}
|
||||
) {}
|
||||
|
||||
append(overrides: Partial<VisualizationSuggestion<TOptions, TFieldConfig>>) {
|
||||
this.list.push(defaultsDeep(overrides, this.defaults));
|
||||
append(suggestion: VisualizationSuggestion<TOptions, TFieldConfig>) {
|
||||
this.list.push(defaultsDeep(suggestion, this.defaults));
|
||||
}
|
||||
|
||||
appendAll(suggestions: Array<VisualizationSuggestion<TOptions, TFieldConfig>>) {
|
||||
this.list.push(...suggestions.map((o) => defaultsDeep(o, this.defaults)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { FieldConfigSource, PanelData, VisualizationSuggestion } from '@grafana/data';
|
||||
import { FieldConfigSource, PanelData, PanelPluginVisualizationSuggestion } from '@grafana/data';
|
||||
|
||||
/**
|
||||
* Describes the properties that can be passed to the PanelDataErrorView.
|
||||
@@ -15,7 +15,7 @@ export interface PanelDataErrorViewProps {
|
||||
needsTimeField?: boolean;
|
||||
needsNumberField?: boolean;
|
||||
needsStringField?: boolean;
|
||||
suggestions?: VisualizationSuggestion[];
|
||||
suggestions?: PanelPluginVisualizationSuggestion[];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user