From f3aa0588861a5fb795216176125794859e48d235 Mon Sep 17 00:00:00 2001 From: Oscar Kilhed Date: Wed, 25 Jan 2023 23:29:07 +0100 Subject: [PATCH] XY Panel: Add and use schema for XY Panel configuration (#62148) * Add schema for XYChart * Minor cleanup * remove unessecary fields from ScatterFieldConfigVeneer, and cleaning up more * Fix counts Co-authored-by: sam boyer --- .../xychartpanelcfg/schema-reference.md | 132 ++++++++++++++++++ .../grafana-schema/src/common/common.gen.ts | 25 ++++ .../grafana-schema/src/common/dimensions.cue | 25 ++++ .../grafana-schema/src/veneer/common.types.ts | 9 ++ pkg/kindsys/report.json | 20 +-- .../plugins/panel/xychart/ManualEditor.tsx | 6 +- .../plugins/panel/xychart/XYChartPanel2.tsx | 6 +- public/app/plugins/panel/xychart/config.ts | 2 +- public/app/plugins/panel/xychart/dims.ts | 2 +- public/app/plugins/panel/xychart/module.tsx | 6 +- public/app/plugins/panel/xychart/panelcfg.cue | 79 +++++++++++ .../app/plugins/panel/xychart/panelcfg.gen.ts | 66 +++++++++ public/app/plugins/panel/xychart/scatter.ts | 17 ++- public/app/plugins/panel/xychart/types.ts | 27 +++- 14 files changed, 395 insertions(+), 27 deletions(-) create mode 100644 docs/sources/developers/kinds/composable/xychartpanelcfg/schema-reference.md create mode 100644 packages/grafana-schema/src/common/dimensions.cue create mode 100644 public/app/plugins/panel/xychart/panelcfg.cue create mode 100644 public/app/plugins/panel/xychart/panelcfg.gen.ts diff --git a/docs/sources/developers/kinds/composable/xychartpanelcfg/schema-reference.md b/docs/sources/developers/kinds/composable/xychartpanelcfg/schema-reference.md new file mode 100644 index 00000000000..19e2bfed332 --- /dev/null +++ b/docs/sources/developers/kinds/composable/xychartpanelcfg/schema-reference.md @@ -0,0 +1,132 @@ +--- +keywords: + - grafana + - schema +title: XYChartPanelCfg kind +--- +> Both documentation generation and kinds schemas are in active development and subject to change without prior notice. + +# XYChartPanelCfg kind + +## Maturity: experimental +## Version: 0.0 + +## Properties + +| Property | Type | Required | Description | +|-----------------------|--------------------------------|----------|---------------------------------------------------------| +| `PanelOptions` | [object](#paneloptions) | **Yes** | | +| `ScatterFieldConfig` | [object](#scatterfieldconfig) | **Yes** | | +| `ScatterSeriesConfig` | [object](#scatterseriesconfig) | **Yes** | | +| `ScatterShow` | string | **Yes** | Possible values are: `points`, `lines`, `points+lines`. | +| `SeriesMapping` | string | **Yes** | Possible values are: `auto`, `manual`. | +| `XYDimensionConfig` | [object](#xydimensionconfig) | **Yes** | | + +## PanelOptions + +### Properties + +| Property | Type | Required | Description | +|-----------------|-----------------------------------------------|----------|----------------------------------------| +| `dims` | [XYDimensionConfig](#xydimensionconfig) | No | | +| `seriesMapping` | string | No | Possible values are: `auto`, `manual`. | +| `series` | [ScatterSeriesConfig](#scatterseriesconfig)[] | No | | + +### ScatterSeriesConfig + +#### Properties + +| Property | Type | Required | Description | +|----------|--------|----------|-------------| +| `name` | string | No | | +| `x` | string | No | | +| `y` | string | No | | + +### XYDimensionConfig + +#### Properties + +| Property | Type | Required | Description | +|-----------|----------|----------|-------------| +| `frame` | integer | **Yes** | | +| `exclude` | string[] | No | | +| `x` | string | No | | + +## ScatterFieldConfig + +### Properties + +| Property | Type | Required | Description | +|--------------|-----------------------------------------------|----------|-------------------------------------------------------------| +| `labelValue` | [TextDimensionConfig](#textdimensionconfig) | No | | +| `label` | string | No | TODO docs Possible values are: `auto`, `never`, `always`. | +| `lineColor` | [ColorDimensionConfig](#colordimensionconfig) | No | This is actually an empty interface used mainly for naming? | +| `lineStyle` | [LineStyle](#linestyle) | No | TODO docs | +| `lineWidth` | integer | No | | +| `pointColor` | [ColorDimensionConfig](#colordimensionconfig) | No | This is actually an empty interface used mainly for naming? | +| `pointSize` | [ScaleDimensionConfig](#scaledimensionconfig) | No | | +| `show` | string | No | Possible values are: `points`, `lines`, `points+lines`. | + +### ColorDimensionConfig + +This is actually an empty interface used mainly for naming? + +| Property | Type | Required | Description | +|----------|------|----------|-------------| + +### ColorDimensionConfig + +This is actually an empty interface used mainly for naming? + +| Property | Type | Required | Description | +|----------|------|----------|-------------| + +### LineStyle + +TODO docs + +#### Properties + +| Property | Type | Required | Description | +|----------|----------|----------|--------------------------------------------------------| +| `dash` | number[] | No | | +| `fill` | string | No | Possible values are: `solid`, `dash`, `dot`, `square`. | + +### ScaleDimensionConfig + +#### Properties + +| Property | Type | Required | Description | +|----------|---------|----------|-------------| +| `max` | integer | No | | +| `min` | integer | No | | + +### TextDimensionConfig + +#### Properties + +| Property | Type | Required | Description | +|----------|--------|----------|----------------------------------------------------| +| `mode` | string | No | Possible values are: `fixed`, `field`, `template`. | + +## ScatterSeriesConfig + +### Properties + +| Property | Type | Required | Description | +|----------|--------|----------|-------------| +| `name` | string | No | | +| `x` | string | No | | +| `y` | string | No | | + +## XYDimensionConfig + +### Properties + +| Property | Type | Required | Description | +|-----------|----------|----------|-------------| +| `frame` | integer | **Yes** | | +| `exclude` | string[] | No | | +| `x` | string | No | | + + diff --git a/packages/grafana-schema/src/common/common.gen.ts b/packages/grafana-schema/src/common/common.gen.ts index 9557cee3648..b64a54dcc30 100644 --- a/packages/grafana-schema/src/common/common.gen.ts +++ b/packages/grafana-schema/src/common/common.gen.ts @@ -51,6 +51,27 @@ export interface DataQuery { refId: string; } +export interface BaseDimensionConfig { + field?: string; + fixed: (string | number); +} + +export interface ScaleDimensionConfig extends BaseDimensionConfig { + max: number; + min: number; +} + +/** + * This is actually an empty interface used mainly for naming? + */ +export interface ColorDimensionConfig extends BaseDimensionConfig {} + +export enum TextDimensionMode { + Field = 'field', + Fixed = 'fixed', + Template = 'template', +} + export interface MapLayerOptions { /** * Custom options depending on the type @@ -651,6 +672,10 @@ export interface DataSourceRef { uid?: string; } +export interface TextDimensionConfig extends BaseDimensionConfig { + mode: TextDimensionMode; +} + export interface FrameGeometrySource { /** * Path to Gazetteer diff --git a/packages/grafana-schema/src/common/dimensions.cue b/packages/grafana-schema/src/common/dimensions.cue new file mode 100644 index 00000000000..14899a59c47 --- /dev/null +++ b/packages/grafana-schema/src/common/dimensions.cue @@ -0,0 +1,25 @@ +package common + +BaseDimensionConfig: { + field?: string + fixed: string | number +}@cuetsy(kind="interface") + +ScaleDimensionConfig: { + BaseDimensionConfig + min: int32 + max: int32 +}@cuetsy(kind="interface") + +// This is actually an empty interface used mainly for naming? +ColorDimensionConfig: { + BaseDimensionConfig + _empty: _ +}@cuetsy(kind="interface") + +TextDimensionMode: "fixed" | "field" | "template" @cuetsy(kind="enum") + +TextDimensionConfig: { + BaseDimensionConfig + mode: TextDimensionMode +}@cuetsy(kind="interface") diff --git a/packages/grafana-schema/src/veneer/common.types.ts b/packages/grafana-schema/src/veneer/common.types.ts index 1e35686cbbe..5ae07a1e2c1 100644 --- a/packages/grafana-schema/src/veneer/common.types.ts +++ b/packages/grafana-schema/src/veneer/common.types.ts @@ -12,5 +12,14 @@ export interface DataQuery extends raw.DataQuery { // TODO remove explicit nulls datasource?: raw.DataSourceRef | null; } +export interface BaseDimensionConfig extends Omit { + fixed: T; +} + +export interface ScaleDimensionConfig extends BaseDimensionConfig, Omit {} + +export interface TextDimensionConfig extends BaseDimensionConfig, Omit {} + +export interface ColorDimensionConfig extends BaseDimensionConfig, Omit {} export * from '../common/common.gen'; diff --git a/pkg/kindsys/report.json b/pkg/kindsys/report.json index ce70bb1ffce..55cecf715c2 100644 --- a/pkg/kindsys/report.json +++ b/pkg/kindsys/report.json @@ -1621,7 +1621,9 @@ }, "xychartpanelcfg": { "category": "composable", - "codeowners": [], + "codeowners": [ + "grafana/grafana-bi-squad" + ], "currentVersion": [ 0, 0 @@ -1629,13 +1631,13 @@ "grafanaMaturityCount": 0, "lineageIsGroup": true, "links": { - "docs": "n/a", + "docs": "https://grafana.com/docs/grafana/next/developers/kinds/composable/xychartpanelcfg/schema-reference", "go": "n/a", - "schema": "n/a", - "ts": "n/a" + "schema": "https://github.com/grafana/grafana/tree/main/public/app/plugins/panel/xychart/panelcfg.cue", + "ts": "https://github.com/grafana/grafana/tree/main/public/app/plugins/panel/xychart/panelcfg.gen.ts" }, "machineName": "xychartpanelcfg", - "maturity": "planned", + "maturity": "experimental", "name": "XYChartPanelCfg", "pluralMachineName": "xychartpanelcfgs", "pluralName": "XYChartPanelCfgs", @@ -1790,9 +1792,10 @@ "newspanelcfg", "piechartpanelcfg", "statpanelcfg", - "textpanelcfg" + "textpanelcfg", + "xychartpanelcfg" ], - "count": 11 + "count": 12 }, "mature": { "name": "mature", @@ -1869,11 +1872,10 @@ "tracespanelcfg", "user", "welcomepanelcfg", - "xychartpanelcfg", "zipkindataquery", "zipkindatasourcecfg" ], - "count": 59 + "count": 58 }, "stable": { "name": "stable", diff --git a/public/app/plugins/panel/xychart/ManualEditor.tsx b/public/app/plugins/panel/xychart/ManualEditor.tsx index e80a8f0849f..91d13ce6e92 100644 --- a/public/app/plugins/panel/xychart/ManualEditor.tsx +++ b/public/app/plugins/panel/xychart/ManualEditor.tsx @@ -7,13 +7,13 @@ import { FieldNamePicker } from '@grafana/ui/src/components/MatchersUI/FieldName import { LayerName } from 'app/core/components/Layers/LayerName'; import { ColorDimensionEditor, ScaleDimensionEditor } from 'app/features/dimensions/editors'; -import { XYChartOptions, ScatterSeriesConfig, defaultScatterConfig } from './models.gen'; +import { PanelOptions, ScatterSeriesConfig, defaultScatterFieldConfig } from './types'; export const ManualEditor = ({ value, onChange, context, -}: StandardEditorProps) => { +}: StandardEditorProps) => { const [selected, setSelected] = useState(0); const style = useStyles2(getStyles); @@ -33,7 +33,7 @@ export const ManualEditor = ({ ...value, { pointColor: {} as any, - pointSize: defaultScatterConfig.pointSize, + pointSize: defaultScatterFieldConfig.pointSize, }, ]); setSelected(value.length); diff --git a/public/app/plugins/panel/xychart/XYChartPanel2.tsx b/public/app/plugins/panel/xychart/XYChartPanel2.tsx index 43ca1d6804e..cadfd88179e 100644 --- a/public/app/plugins/panel/xychart/XYChartPanel2.tsx +++ b/public/app/plugins/panel/xychart/XYChartPanel2.tsx @@ -26,11 +26,11 @@ import { FacetedData } from '@grafana/ui/src/components/uPlot/types'; import { CloseButton } from 'app/core/components/CloseButton/CloseButton'; import { TooltipView } from './TooltipView'; -import { SeriesMapping, XYChartOptions } from './models.gen'; +import { SeriesMapping } from './models.gen'; import { prepData, prepScatter, ScatterPanelInfo } from './scatter'; -import { ScatterHoverEvent, ScatterSeries } from './types'; +import { PanelOptions, ScatterHoverEvent, ScatterSeries } from './types'; -type Props = PanelProps; +type Props = PanelProps; const TOOLTIP_OFFSET = 10; export const XYChartPanel2: React.FC = (props: Props) => { diff --git a/public/app/plugins/panel/xychart/config.ts b/public/app/plugins/panel/xychart/config.ts index 5564bd0aaf8..3ce34627253 100644 --- a/public/app/plugins/panel/xychart/config.ts +++ b/public/app/plugins/panel/xychart/config.ts @@ -10,7 +10,7 @@ import { commonOptionsBuilder } from '@grafana/ui'; import { LineStyleEditor } from '../timeseries/LineStyleEditor'; -import { ScatterFieldConfig, ScatterShow } from './models.gen'; +import { ScatterFieldConfig, ScatterShow } from './types'; export function getScatterFieldConfig(cfg: ScatterFieldConfig): SetFieldConfigOptionsArgs { return { diff --git a/public/app/plugins/panel/xychart/dims.ts b/public/app/plugins/panel/xychart/dims.ts index b2228c63823..6d5434b582d 100644 --- a/public/app/plugins/panel/xychart/dims.ts +++ b/public/app/plugins/panel/xychart/dims.ts @@ -1,7 +1,7 @@ import { DataFrame, Field, FieldMatcher, FieldType, getFieldDisplayName } from '@grafana/data'; import { XYFieldMatchers } from '@grafana/ui/src/components/GraphNG/types'; -import { XYDimensionConfig } from './models.gen'; +import { XYDimensionConfig } from './types'; // TODO: fix import diff --git a/public/app/plugins/panel/xychart/module.tsx b/public/app/plugins/panel/xychart/module.tsx index b9a5ee2e886..545e68ac02d 100644 --- a/public/app/plugins/panel/xychart/module.tsx +++ b/public/app/plugins/panel/xychart/module.tsx @@ -5,10 +5,10 @@ import { AutoEditor } from './AutoEditor'; import { ManualEditor } from './ManualEditor'; import { XYChartPanel2 } from './XYChartPanel2'; import { getScatterFieldConfig } from './config'; -import { defaultScatterConfig, XYChartOptions, ScatterFieldConfig } from './models.gen'; +import { defaultScatterFieldConfig, PanelOptions, ScatterFieldConfig } from './types'; -export const plugin = new PanelPlugin(XYChartPanel2) - .useFieldConfig(getScatterFieldConfig(defaultScatterConfig)) +export const plugin = new PanelPlugin(XYChartPanel2) + .useFieldConfig(getScatterFieldConfig(defaultScatterFieldConfig)) .setPanelOptions((builder) => { builder .addRadio({ diff --git a/public/app/plugins/panel/xychart/panelcfg.cue b/public/app/plugins/panel/xychart/panelcfg.cue new file mode 100644 index 00000000000..55b1372d187 --- /dev/null +++ b/public/app/plugins/panel/xychart/panelcfg.cue @@ -0,0 +1,79 @@ +// Copyright 2023 Grafana Labs +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package grafanaplugin + +import ( + "github.com/grafana/grafana/packages/grafana-schema/src/common" + "github.com/grafana/grafana/pkg/plugins/pfs" +) + +// This file (with its sibling .cue files) implements pfs.GrafanaPlugin +pfs.GrafanaPlugin + +composableKinds: PanelCfg: { + maturity: "experimental" + + lineage: { + seqs: [ + { + schemas: [ + { + + SeriesMapping: "auto" | "manual" @cuetsy(kind="enum") + ScatterShow: "points" | "lines" | "points+lines" @cuetsy(kind="enum", memberNames="Points|Lines|PointsAndLines") + + XYDimensionConfig: { + frame: int32 & >=0 + x?: string + exclude?: [...string] + } @cuetsy(kind="interface") + + ScatterFieldConfig: { + common.HideableFieldConfig + common.AxisConfig + + show?: ScatterShow | *"points" + + pointSize?: common.ScaleDimensionConfig + lineColor?: common.ColorDimensionConfig + pointColor?: common.ColorDimensionConfig + labelValue?: common.TextDimensionConfig + + lineWidth?: int32 & >=0 + lineStyle?: common.LineStyle + label?: common.VisibilityMode | *"auto" + } @cuetsy(kind="interface",TSVeneer="type") + + ScatterSeriesConfig: { + ScatterFieldConfig + x?: string + y?: string + name?: string + } @cuetsy(kind="interface") + + PanelOptions: { + common.OptionsWithLegend + common.OptionsWithTooltip + + seriesMapping?: SeriesMapping + dims: XYDimensionConfig + series: [...ScatterSeriesConfig] + } @cuetsy(kind="interface") + }, + ] + }, + ] + } +} diff --git a/public/app/plugins/panel/xychart/panelcfg.gen.ts b/public/app/plugins/panel/xychart/panelcfg.gen.ts new file mode 100644 index 00000000000..74110143537 --- /dev/null +++ b/public/app/plugins/panel/xychart/panelcfg.gen.ts @@ -0,0 +1,66 @@ +// Code generated - EDITING IS FUTILE. DO NOT EDIT. +// +// Generated by: +// public/app/plugins/gen.go +// Using jennies: +// TSTypesJenny +// PluginTSTypesJenny +// +// Run 'make gen-cue' from repository root to regenerate. + +import * as common from '@grafana/schema'; + +export const PanelCfgModelVersion = Object.freeze([0, 0]); + +export enum SeriesMapping { + Auto = 'auto', + Manual = 'manual', +} + +export enum ScatterShow { + Lines = 'lines', + Points = 'points', + PointsAndLines = 'points+lines', +} + +export interface XYDimensionConfig { + exclude?: Array; + frame: number; + x?: string; +} + +export const defaultXYDimensionConfig: Partial = { + exclude: [], +}; + +export interface ScatterFieldConfig extends common.HideableFieldConfig, common.AxisConfig { + label?: common.VisibilityMode; + labelValue?: common.TextDimensionConfig; + lineColor?: common.ColorDimensionConfig; + lineStyle?: common.LineStyle; + lineWidth?: number; + pointColor?: common.ColorDimensionConfig; + pointSize?: common.ScaleDimensionConfig; + show?: ScatterShow; +} + +export const defaultScatterFieldConfig: Partial = { + label: common.VisibilityMode.Auto, + show: ScatterShow.Points, +}; + +export interface ScatterSeriesConfig extends ScatterFieldConfig { + name?: string; + x?: string; + y?: string; +} + +export interface PanelOptions extends common.OptionsWithLegend, common.OptionsWithTooltip { + dims: XYDimensionConfig; + series: Array; + seriesMapping?: SeriesMapping; +} + +export const defaultPanelOptions: Partial = { + series: [], +}; diff --git a/public/app/plugins/panel/xychart/scatter.ts b/public/app/plugins/panel/xychart/scatter.ts index e354d1abc3e..cc3e5c8d0bf 100644 --- a/public/app/plugins/panel/xychart/scatter.ts +++ b/public/app/plugins/panel/xychart/scatter.ts @@ -26,8 +26,15 @@ import { import { pointWithin, Quadtree, Rect } from '../barchart/quadtree'; import { isGraphable } from './dims'; -import { defaultScatterConfig, ScatterFieldConfig, ScatterShow, XYChartOptions } from './models.gen'; -import { DimensionValues, ScatterHoverCallback, ScatterSeries } from './types'; +import { + DimensionValues, + ScatterFieldConfig, + defaultScatterFieldConfig, + ScatterHoverCallback, + ScatterSeries, + PanelOptions, + ScatterShow, +} from './types'; export interface ScatterPanelInfo { error?: string; @@ -39,7 +46,7 @@ export interface ScatterPanelInfo { * This is called when options or structure rev changes */ export function prepScatter( - options: XYChartOptions, + options: PanelOptions, getData: () => DataFrame[], theme: GrafanaTheme2, ttip: ScatterHoverCallback, @@ -100,7 +107,7 @@ function getScatterSeries( ? config.theme2.visualization.getColorByName(dims.pointColorFixed) : getFieldSeriesColor(y, config.theme2).color; let pointColor: DimensionValues = () => seriesColor; - const fieldConfig: ScatterFieldConfig = { ...defaultScatterConfig, ...y.config.custom }; + const fieldConfig: ScatterFieldConfig = { ...defaultScatterFieldConfig, ...y.config.custom }; let pointColorMode = fieldColorModeRegistry.get(FieldColorModeId.PaletteClassic); if (dims.pointColorIndex) { const f = frames[frameIndex].fields[dims.pointColorIndex]; @@ -195,7 +202,7 @@ function getScatterSeries( }; } -function prepSeries(options: XYChartOptions, frames: DataFrame[]): ScatterSeries[] { +function prepSeries(options: PanelOptions, frames: DataFrame[]): ScatterSeries[] { let seriesIndex = 0; if (!frames.length) { throw 'Missing data'; diff --git a/public/app/plugins/panel/xychart/types.ts b/public/app/plugins/panel/xychart/types.ts index 7e4cfab97e9..34f102410ee 100644 --- a/public/app/plugins/panel/xychart/types.ts +++ b/public/app/plugins/panel/xychart/types.ts @@ -1,7 +1,14 @@ import { DataFrame, Field, FieldColorMode } from '@grafana/data'; -import { LineStyle, VisibilityMode } from '@grafana/schema'; +import { LineStyle, ScaleDimensionConfig, VisibilityMode } from '@grafana/schema'; import { VizLegendItem } from '@grafana/ui'; -import { ScaleDimensionConfig } from 'app/features/dimensions'; +import { DimensionSupplier } from 'app/features/dimensions'; + +import { + ScatterFieldConfig as GeneratedScatterFieldConfig, + ScatterSeriesConfig as GeneratedScatterSeriesConfig, + defaultScatterFieldConfig as generatedDefaultScatterFieldConfig, + PanelOptions as GeneratedPanelOptions, +} from './panelcfg.gen'; /** * @internal @@ -24,6 +31,20 @@ export interface LegendInfo { openEditor?: (evt: any) => void; } +export interface ScatterFieldConfig extends GeneratedScatterFieldConfig { + pointSymbol?: DimensionSupplier; +} + +export const defaultScatterFieldConfig: Partial = { + ...generatedDefaultScatterFieldConfig, +}; + +export interface ScatterSeriesConfig extends ScatterFieldConfig, GeneratedScatterSeriesConfig {} + +export interface PanelOptions extends Omit { + series: ScatterSeriesConfig[]; +} + // Using field where we will need formatting/scale/axis info // Use raw or DimensionValues when the values can be used directly export interface ScatterSeries { @@ -58,3 +79,5 @@ export interface ScatterSeries { }; }; } + +export { ScatterShow, SeriesMapping, XYDimensionConfig } from './panelcfg.gen';