diff --git a/public/app/features/canvas/elements/metricValue.tsx b/public/app/features/canvas/elements/metricValue.tsx index fe424f705df..893d0bbd408 100644 --- a/public/app/features/canvas/elements/metricValue.tsx +++ b/public/app/features/canvas/elements/metricValue.tsx @@ -13,15 +13,14 @@ import { TextDimensionEditor } from 'app/features/dimensions/editors/TextDimensi import { CanvasElementItem, CanvasElementProps, defaultBgColor, defaultTextColor } from '../element'; import { ElementState } from '../runtime/element'; - -import { Align, TextBoxConfig, TextBoxData, VAlign } from './textBox'; +import { Align, TextConfig, TextData, VAlign } from '../types'; // eslint-disable-next-line const dummyFieldSettings: StandardEditorsRegistryItem = { settings: {}, } as StandardEditorsRegistryItem; -const MetricValueDisplay = (props: CanvasElementProps) => { +const MetricValueDisplay = (props: CanvasElementProps) => { const { data, isSelected } = props; const styles = useStyles2(getStyles(data)); @@ -40,7 +39,7 @@ const MetricValueDisplay = (props: CanvasElementProps) => { +const MetricValueEdit = (props: CanvasElementProps) => { let { data, config } = props; const context = usePanelContext(); let panelData: DataFrame[]; @@ -89,7 +88,7 @@ const MetricValueEdit = (props: CanvasElementProps) ); }; -const getStyles = (data: TextBoxData | undefined) => (theme: GrafanaTheme2) => ({ +const getStyles = (data: TextData | undefined) => (theme: GrafanaTheme2) => ({ container: css` position: absolute; height: 100%; @@ -112,7 +111,7 @@ const getStyles = (data: TextBoxData | undefined) => (theme: GrafanaTheme2) => ( `, }); -export const metricValueItem: CanvasElementItem = { +export const metricValueItem: CanvasElementItem = { id: 'metric-value', name: 'Metric Value', description: 'Display a field value', @@ -148,8 +147,8 @@ export const metricValueItem: CanvasElementItem = { }, }), - prepareData: (ctx: DimensionContext, cfg: TextBoxConfig) => { - const data: TextBoxData = { + prepareData: (ctx: DimensionContext, cfg: TextConfig) => { + const data: TextData = { text: cfg.text ? ctx.getText(cfg.text).value() : '', align: cfg.align ?? Align.Center, valign: cfg.valign ?? VAlign.Middle, diff --git a/public/app/features/canvas/elements/textBox.tsx b/public/app/features/canvas/elements/rectangle.tsx similarity index 76% rename from public/app/features/canvas/elements/textBox.tsx rename to public/app/features/canvas/elements/rectangle.tsx index 852e94f2201..8e75e27667c 100644 --- a/public/app/features/canvas/elements/textBox.tsx +++ b/public/app/features/canvas/elements/rectangle.tsx @@ -7,39 +7,11 @@ import { config } from 'app/core/config'; import { DimensionContext } from 'app/features/dimensions/context'; import { ColorDimensionEditor } from 'app/features/dimensions/editors/ColorDimensionEditor'; import { TextDimensionEditor } from 'app/features/dimensions/editors/TextDimensionEditor'; -import { ColorDimensionConfig, TextDimensionConfig } from 'app/features/dimensions/types'; import { CanvasElementItem, CanvasElementProps, defaultBgColor, defaultTextColor } from '../element'; +import { Align, TextConfig, TextData, VAlign } from '../types'; -export enum Align { - Left = 'left', - Center = 'center', - Right = 'right', -} - -export enum VAlign { - Top = 'top', - Middle = 'middle', - Bottom = 'bottom', -} - -export interface TextBoxData { - text?: string; - color?: string; - size?: number; // 0 or missing will "auto size" - align: Align; - valign: VAlign; -} - -export interface TextBoxConfig { - text?: TextDimensionConfig; - color?: ColorDimensionConfig; - size?: number; // 0 or missing will "auto size" - align: Align; - valign: VAlign; -} - -class TextBoxDisplay extends PureComponent> { +class RectangleDisplay extends PureComponent> { render() { const { data } = this.props; const styles = getStyles(config.theme2, data); @@ -65,12 +37,12 @@ const getStyles = stylesFactory((theme: GrafanaTheme2, data) => ({ color: ${data?.color}; `, })); -export const textBoxItem: CanvasElementItem = { - id: 'text-box', - name: 'Text', - description: 'Text box', +export const rectangleItem: CanvasElementItem = { + id: 'rectangle', + name: 'Rectangle', + description: 'Rectangle', - display: TextBoxDisplay, + display: RectangleDisplay, defaultSize: { width: 240, @@ -94,8 +66,8 @@ export const textBoxItem: CanvasElementItem = { }), // Called when data changes - prepareData: (ctx: DimensionContext, cfg: TextBoxConfig) => { - const data: TextBoxData = { + prepareData: (ctx: DimensionContext, cfg: TextConfig) => { + const data: TextData = { text: cfg.text ? ctx.getText(cfg.text).value() : '', align: cfg.align ?? Align.Center, valign: cfg.valign ?? VAlign.Middle, @@ -111,7 +83,7 @@ export const textBoxItem: CanvasElementItem = { // Heatmap overlay options registerOptionsUI: (builder) => { - const category = ['Text box']; + const category = ['Rectangle']; builder .addCustomEditor({ category, diff --git a/public/app/features/canvas/registry.ts b/public/app/features/canvas/registry.ts index 8ed20d197b6..28f6a71683f 100644 --- a/public/app/features/canvas/registry.ts +++ b/public/app/features/canvas/registry.ts @@ -7,7 +7,7 @@ import { droneSideItem } from './elements/droneSide'; import { droneTopItem } from './elements/droneTop'; import { iconItem } from './elements/icon'; import { metricValueItem } from './elements/metricValue'; -import { textBoxItem } from './elements/textBox'; +import { rectangleItem } from './elements/rectangle'; import { windTurbineItem } from './elements/windTurbine'; export const DEFAULT_CANVAS_ELEMENT_CONFIG: CanvasElementOptions = { @@ -19,7 +19,7 @@ export const DEFAULT_CANVAS_ELEMENT_CONFIG: CanvasElementOptions = { export const defaultElementItems = [ metricValueItem, // default for now - textBoxItem, + rectangleItem, iconItem, ]; diff --git a/public/app/features/canvas/types.ts b/public/app/features/canvas/types.ts index 24185c5448d..5e2af18d89e 100644 --- a/public/app/features/canvas/types.ts +++ b/public/app/features/canvas/types.ts @@ -1,4 +1,4 @@ -import { ColorDimensionConfig, ResourceDimensionConfig } from 'app/features/dimensions/types'; +import { ColorDimensionConfig, ResourceDimensionConfig, TextDimensionConfig } from 'app/features/dimensions/types'; export interface Placement { top?: number; @@ -58,3 +58,31 @@ export enum QuickPlacement { HorizontalCenter = 'hcenter', VerticalCenter = 'vcenter', } + +export enum Align { + Left = 'left', + Center = 'center', + Right = 'right', +} + +export enum VAlign { + Top = 'top', + Middle = 'middle', + Bottom = 'bottom', +} + +export interface TextData { + text?: string; + color?: string; + size?: number; // 0 or missing will "auto size" + align: Align; + valign: VAlign; +} + +export interface TextConfig { + text?: TextDimensionConfig; + color?: ColorDimensionConfig; + size?: number; // 0 or missing will "auto size" + align: Align; + valign: VAlign; +} diff --git a/public/app/plugins/panel/canvas/migrations.ts b/public/app/plugins/panel/canvas/migrations.ts new file mode 100644 index 00000000000..29e805d4841 --- /dev/null +++ b/public/app/plugins/panel/canvas/migrations.ts @@ -0,0 +1,22 @@ +import { PanelModel } from '@grafana/data'; + +import { PanelOptions } from './models.gen'; + +export const canvasMigrationHandler = (panel: PanelModel): Partial => { + const pluginVersion = panel?.pluginVersion ?? ''; + + // Rename text-box to rectangle + // Initial plugin version is empty string for first migration + if (pluginVersion === '') { + const root = panel.options?.root; + if (root?.elements) { + for (const element of root.elements) { + if (element.type === 'text-box') { + element.type = 'rectangle'; + } + } + } + } + + return panel.options; +}; diff --git a/public/app/plugins/panel/canvas/module.tsx b/public/app/plugins/panel/canvas/module.tsx index 318efb6321c..aa0488ab356 100644 --- a/public/app/plugins/panel/canvas/module.tsx +++ b/public/app/plugins/panel/canvas/module.tsx @@ -4,6 +4,7 @@ import { FrameState } from 'app/features/canvas/runtime/frame'; import { CanvasPanel, InstanceState } from './CanvasPanel'; import { getElementEditor } from './editor/elementEditor'; import { getLayerEditor } from './editor/layerEditor'; +import { canvasMigrationHandler } from './migrations'; import { PanelOptions } from './models.gen'; export const addStandardCanvasEditorOptions = (builder: PanelOptionsEditorBuilder) => { @@ -25,6 +26,7 @@ export const addStandardCanvasEditorOptions = (builder: PanelOptionsEditorBuilde export const plugin = new PanelPlugin(CanvasPanel) .setNoPadding() // extend to panel edges .useFieldConfig() + .setMigrationHandler(canvasMigrationHandler) .setPanelOptions((builder, context) => { const state: InstanceState = context.instanceState;