迁移配置设置
本指南探讨了如何将配置设置转换为从 AngularJS 或 Angular(已弃用)升级到我们当前构建插件的 React 方法。在讨论此过程中可能出现的各种问题时,您将了解 Grafana 迁移处理工具如何使转换变得更容易。
迁移处理器
背景
面板插件有两种类型的插件配置迁移
- AngularJS 到 React
- 插件版本更新
当加载一个面板时,该面板 JSON 中指定的插件版本与当前运行时版本不同,将调用迁移处理器。此处理器需要返回一个有效的对象,不得抛出任何错误。
我们强烈建议您在升级插件可能对现有面板造成问题时使用迁移处理器。通过使用迁移处理器,您将提供更好的用户体验。
使用指定部分
当将面板插件从AngularJS转换为React时,在JSON中有一个特定的位置用于编辑自定义选项。之前,在使用Angular插件的配置中,插件可以将自定义对象存储在任何位置,但现在这些对象必须使用指定的部分。
Grafana默认使用相同指定的部分为所有其组件。您添加的任何自定义组件都必须使用此相同的定位。
当Grafana加载一个面板时,在向用户显示任何内容之前,它会调用一个迁移处理程序。此调用允许自动将旧的面板配置转换为正在加载的新版本。如果您不提供迁移处理程序,则用户将获得面板的所有默认值,他们必须手动修复每个面板。
深入了解Angular到React迁移
当仪表板中的面板使用较旧的AngularJS版本的插件,但实际上正在运行最新版本的React时,需要进行修改。在这种情况下,尽可能修改旧配置以与新插件轻松协同工作。理想情况下,用户不需要重新配置他们的面板。
介绍Polystat示例
Angular插件通常有一个panel.config
对象,它包含特定于插件的设置。例如,Polystat面板插件,被称为grafana-polystat-panel
,是一个从AngularJS面板开始并移植到React的示例插件。该插件的React版本使用`module.ts`中的.setMigrationHandler
如下所示
.setMigrationHandler(PolystatPanelMigrationHandler)
基于Angular的Polystat面板(v1.x)在“panel.polystat”对象中存储了大部分配置。您的插件应在迁移处理程序中检测到该对象,以便您可以触发转换为新的基于React的插件配置。
React面板将所有内容存储在panel.options
中。如果此对象不存在,则迁移处理程序至少应返回一个有效的空对象。如果此对象存在,则它应仅返回当前的panel.options
。如果新版本删除了或添加了新功能,此时有机会修改React配置。
panel.options
是一个名为PanelModel
的接口,其类型是针对您的面板插件自定义的。
在Polystat示例中更改字体
当安装插件的新版本时,Grafana服务器调用迁移处理程序来添加或删除配置项。更改不会在仪表板中持久保存,因此您必须“保存”它们以防止迁移在每次加载时修改面板。
例如:当使用AngularJS编写时,Polystat插件有一个硬编码的字体,即Roboto,但在Grafana的新版本中被移除。这导致插件在Grafana的新版本中运行时输出被错误渲染。为了解决这个问题,Grafana增加了一个新的选择器,允许用户选择字体,但在之前的版本中全局配置没有这个设置。
在这种情况下,迁移处理程序应该检测选项是否存在,如果不存在,则插入一个默认值。这个默认值会根据所使用的Grafana版本返回一个有效的配置。
步骤 1:检测Grafana的运行时版本
您的插件可以访问变量 config.buildInfo.version
以确定Grafana的运行版本。迁移处理程序可以使用此值来设置有效的默认值。
可能多个Grafana版本已经应用了回滚补丁,因此它们可能移除了插件预期的一个功能。在先前的示例中,这是Roboto字体。
迁移处理程序获取运行时版本并使用semver来确定要使用哪种字体。旧版本中没有新版的Inter作为字体,因此Roboto是最安全的选项。新版本已移除Roboto,因此插件应加载Inter。
这里有两种情况
情况 1:用户选择Roboto字体运行面板
在这种情况下,用户正在运行当前的Grafana(9.4.3)并选择了一个Roboto字体的面板。插件可以根据运行时提供不同的选择选项。
Polystat面板在其module.ts
中有一个根据运行时进行的条件检查
.addSelect({
path: 'globalTextFontFamily',
name: 'Font Family',
description: 'Font used for rendered text',
category: ['Text'],
defaultValue: GLOBAL_TEXT_FONT_FAMILY,
settings: {
options: FontFamilyOptions,
},
showIf: () => hasRobotoFont() === false,
})
.addSelect({
path: 'globalTextFontFamily',
name: 'Font Family',
description: 'Font used for rendered text',
category: ['Text'],
defaultValue: GLOBAL_TEXT_FONT_FAMILY_LEGACY,
settings: {
options: FontFamilyOptionsLegacy,
},
showIf: () => hasRobotoFont() === true,
})
情况 2:Grafana自动将字体切换为Inter
在这种情况下,用户升级了Grafana(从v9.3.10升级到v9.4.3),迁移自动切换到使用Inter,并且在字体选择器中不显示Roboto。如果升级到9.4.0或更高版本,则使用Inter;否则使用Roboto。
Polystat中的MigrationHandler
包含以下代码
import { config } from "@grafana/runtime";
import { satisfies, coerce } from "semver";
export const PolystatPanelMigrationHandler = (panel: PanelModel<PolystatOptions>): Partial<PolystatOptions> => {
// set default font to inter, and check if it available, set to roboto if not
options.globalTooltipsFontFamily = FontFamilies.INTER;
if (hasRobotoFont()) {
options.globalTooltipsFontFamily = FontFamilies.ROBOTO;
}
}
export const hasRobotoFont = () => {
const version = coerce(config.buildInfo.version);
if (version !== null) {
if (satisfies(version, "<9.4.0")) {
return true;
}
}
return false;
};
步骤 2:检测缺失的配置
插件的新版本可能添加了面板尚未定义的新配置选项。迁移处理程序可以用来添加这些新选项,并使用“安全”的默认值。
options.globalTooltipsFontFamily = FontFamilies.INTER;
if (hasRobotoFont()) {
options.globalTooltipsFontFamily = FontFamilies.ROBOTO;
}
export const PolystatPanelMigrationHandler = (panel: PanelModel<PolystatOptions>): Partial<PolystatOptions> => {
if (panel.options.NewFeature === undefined) {
// add default for new feature
panel.options.NewFeature = 5.0;
}
...
return panel.options;
}
步骤 3:检测无效的配置
由于插件正在加载并接收整个配置,因此可以遍历配置并确保值是合法的。
export const PolystatPanelMigrationHandler = (panel: PanelModel<PolystatOptions>): Partial<PolystatOptions> => {
// iterate and validate
let validConfigOptions = {
fontSize: 2,
fontFamily: 3,
defaultInvalid: 'a'
};
for (const anOption in panel.options) {
if (!validConfigOptions.includes(anOption)) {
// remove this option
console.log(`removing ${anOption}`);
delete panel.options.anOption;
}
}
return panel.options;
}
步骤 4:设置安全默认值
有时插件会删除功能或修改选项的有效选择。可以使用迁移处理程序来根据需要调整配置。
export const PolystatPanelMigrationHandler = (panel: PanelModel<PolystatOptions>): Partial<PolystatOptions> => {
const featureOptions = [
'SelectionA',
'SelectionB',
'SelectionC'
];
// detect if a config setting is using a value that has been removed,
// and set a safe default
const removedOption = 'a removed option in selector';
if (!featureOptions.includes(panel.options.aSelectionSetting) {
panel.options.aSelectionSetting = featureOptions[0];
}
// new feature added, set a safe default for it
if (panel.options.aSelectionSetting === undefined) {
// add default for new feature
panel.options.aSelectionSetting = featureOptions[0];
}
return panel.options;
}