跳过至主要内容

构建自定义面板选项编辑器

Grafana 插件平台附带一系列编辑器,允许您的用户自定义面板。标准编辑器涵盖了最常见的选项类型,例如文本输入和布尔开关。如果您找不到所需的编辑器,可以自己构建一个。

面板选项编辑器基础知识

最简单的编辑器是一个 React 组件,它接受两个道具

  • value: 选项的当前值
  • onChange: 更新选项的值

以下示例中的编辑器允许用户通过单击按钮来切换布尔值

src/SimpleEditor.tsx
import React from 'react';
import { Button } from '@grafana/ui';
import { StandardEditorProps } from '@grafana/data';

export const SimpleEditor = ({ value, onChange }: StandardEditorProps<boolean>) => {
return <Button onClick={() => onChange(!value)}>{value ? 'Disable' : 'Enable'}</Button>;
};

要使用自定义面板选项编辑器,请在 module.ts 文件中的 OptionsUIBuilder 对象上使用 addCustomEditor,并将 editor 属性设置为自定义编辑器组件的名称。

src/module.ts
export const plugin = new PanelPlugin<SimpleOptions>(SimplePanel).setPanelOptions((builder) => {
return builder.addCustomEditor({
id: 'label',
path: 'label',
name: 'Label',
editor: SimpleEditor,
});
});

向面板选项编辑器添加设置

您可以使用自定义编辑器来定制多个可能的设置。要向编辑器添加设置,请将 StandardEditorProps 的第二个模板变量设置为一个包含要配置的设置的接口。通过 item 道具访问编辑器设置。

以下是一个编辑器的示例,它使用一系列数字填充下拉菜单。Settings 接口定义了 fromto 属性的范围。

src/SimpleEditor.tsx
interface Settings {
from: number;
to: number;
}

type Props = StandardEditorProps<number, Settings>;

export const SimpleEditor = ({ item, value, onChange }: Props) => {
const options: Array<SelectableValue<number>> = [];

// Default values
const from = item.settings?.from ?? 1;
const to = item.settings?.to ?? 10;

for (let i = from; i <= to; i++) {
options.push({
label: i.toString(),
value: i,
});
}

return <Select options={options} value={value} onChange={(selectableValue) => onChange(selectableValue.value)} />;
};

现在,您可以通过将 settings 属性配置为调用 addCustomEditor 来为每个选项配置编辑器

src/module.ts
export const plugin = new PanelPlugin<SimpleOptions>(SimplePanel).setPanelOptions((builder) => {
return builder.addCustomEditor({
id: 'index',
path: 'index',
name: 'Index',
editor: SimpleEditor,
settings: {
from: 1,
to: 10,
},
});
});

在面板选项编辑器中使用查询结果

选项编辑器可以访问上次查询的结果。这使您可以根据数据源返回的数据动态更新编辑器。

编辑器上下文可以通过 context 道具获得。数据源返回的数据帧位于 context.data 下。

src/SimpleEditor.tsx
export const SimpleEditor = ({ item, value, onChange, context }: StandardEditorProps<string>) => {
const options: SelectableValue<string>[] = [];

if (context.data) {
const frames = context.data;

for (let i = 0; i < frames.length; i++) {
options.push({
label: frames[i].name,
value: frames[i].name,
});
}
}

return <Select options={options} value={value} onChange={(selectableValue) => onChange(selectableValue.value)} />;
};