Dashboards API: Add v2alpha2 (#108121)

* Dashboards API: Register v2alpha2 API

* Prepare conversion functions

* Fix test

* Move to the bottom the v2aplha2 until is ready

---------

Co-authored-by: Ivan Ortega <ivanortegaalba@gmail.com>
This commit is contained in:
Dominik Prokop
2025-07-16 12:22:50 +00:00
committed by GitHub
co-authored by Ivan Ortega
parent 2fcb86f031
commit b4738c57e4
33 changed files with 12818 additions and 157 deletions
+8 -1
View File
@@ -1,4 +1,4 @@
APP_SDK_VERSION := v0.39.0
APP_SDK_VERSION := v0.39.2
APP_SDK_DIR := $(shell go env GOPATH)/bin/app-sdk-$(APP_SDK_VERSION)
APP_SDK_BIN := $(APP_SDK_DIR)/grafana-app-sdk
@@ -60,3 +60,10 @@ post-generate-cleanup: ## Clean up the generated code
@echo "// To sync changes, run: make generate in apps/dashboard" >> ./pkg/apis/dashboard/v2alpha1/dashboard_spec.cue
@echo "" >> ./pkg/apis/dashboard/v2alpha1/dashboard_spec.cue
@cat ./kinds/v2alpha1/dashboard_spec.cue >> ./pkg/apis/dashboard/v2alpha1/dashboard_spec.cue
# Copy dashboard/v2alpha2 spec so we can use it for schema validation
@echo "// This file is managed by grafana-app-sdk - DO NOT EDIT MANUALLY" > ./pkg/apis/dashboard/v2alpha2/dashboard_spec.cue
@echo "// Source: apps/dashboard/kinds/v2alpha2/dashboard_spec.cue" >> ./pkg/apis/dashboard/v2alpha2/dashboard_spec.cue
@echo "// To sync changes, run: make generate in apps/dashboard" >> ./pkg/apis/dashboard/v2alpha2/dashboard_spec.cue
@echo "" >> ./pkg/apis/dashboard/v2alpha2/dashboard_spec.cue
@cat ./kinds/v2alpha2/dashboard_spec.cue >> ./pkg/apis/dashboard/v2alpha2/dashboard_spec.cue
+9 -2
View File
@@ -3,7 +3,8 @@ package kinds
import (
v0 "github.com/grafana/grafana/sdkkinds/dashboard/v0alpha1"
v1 "github.com/grafana/grafana/sdkkinds/dashboard/v1beta1"
v2 "github.com/grafana/grafana/sdkkinds/dashboard/v2alpha1"
v2alpha1 "github.com/grafana/grafana/sdkkinds/dashboard/v2alpha1"
v2alpha2 "github.com/grafana/grafana/sdkkinds/dashboard/v2alpha2"
)
// Status is the shared status of all dashboard versions.
@@ -63,7 +64,13 @@ dashboard: {
}
"v2alpha1": {
schema: {
spec: v2.DashboardSpec
spec: v2alpha1.DashboardSpec
status: DashboardStatus
}
}
"v2alpha2": {
schema: {
spec: v2alpha2.DashboardSpec
status: DashboardStatus
}
}
@@ -0,0 +1,964 @@
package v2alpha2
DashboardSpec: {
annotations: [...AnnotationQueryKind] | *[]
// Configuration of dashboard cursor sync behavior.
// "Off" for no shared crosshair or tooltip (default).
// "Crosshair" for shared crosshair.
// "Tooltip" for shared crosshair AND shared tooltip.
cursorSync: DashboardCursorSync
// Description of dashboard.
description?: string
// Whether a dashboard is editable or not.
editable?: bool | *true
elements: [ElementReference.name]: Element | *{}
layout: GridLayoutKind | RowsLayoutKind | AutoGridLayoutKind | TabsLayoutKind
// Links with references to other dashboards or external websites.
links: [...DashboardLink] | *[]
// When set to true, the dashboard will redraw panels at an interval matching the pixel width.
// This will keep data "moving left" regardless of the query refresh rate. This setting helps
// avoid dashboards presenting stale live data.
liveNow?: bool
// When set to true, the dashboard will load all panels in the dashboard when it's loaded.
preload: bool | *false
// Plugins only. The version of the dashboard installed together with the plugin.
// This is used to determine if the dashboard should be updated when the plugin is updated.
revision?: uint16
// Tags associated with dashboard.
tags: [...string] | *[]
timeSettings: TimeSettingsSpec
// Title of dashboard.
title: string
// Configured template variables.
variables: [...VariableKind] | *[]
}
// Supported dashboard elements
Element: PanelKind | LibraryPanelKind // |* more element types in the future
LibraryPanelKind: {
kind: "LibraryPanel"
spec: LibraryPanelKindSpec
}
LibraryPanelKindSpec: {
// Panel ID for the library panel in the dashboard
id: number
// Title for the library panel in the dashboard
title: string
libraryPanel: LibraryPanelRef
}
// A library panel is a reusable panel that you can use in any dashboard.
// When you make a change to a library panel, that change propagates to all instances of where the panel is used.
// Library panels streamline reuse of panels across multiple dashboards.
LibraryPanelRef: {
// Library panel name
name: string
// Library panel uid
uid: string
}
AnnotationPanelFilter: {
// Should the specified panels be included or excluded
exclude?: bool | *false
// Panel IDs that should be included or excluded
ids: [...uint32]
}
// "Off" for no shared crosshair or tooltip (default).
// "Crosshair" for shared crosshair.
// "Tooltip" for shared crosshair AND shared tooltip.
DashboardCursorSync: "Crosshair" | "Tooltip" | *"Off"
// Links with references to other dashboards or external resources
DashboardLink: {
// Title to display with the link
title: string
// Link type. Accepted values are dashboards (to refer to another dashboard) and link (to refer to an external resource)
// FIXME: The type is generated as `type: DashboardLinkType | dashboardLinkType.Link;` but it should be `type: DashboardLinkType`
type: DashboardLinkType
// Icon name to be displayed with the link
icon: string
// Tooltip to display when the user hovers their mouse over it
tooltip: string
// Link URL. Only required/valid if the type is link
url?: string
// List of tags to limit the linked dashboards. If empty, all dashboards will be displayed. Only valid if the type is dashboards
tags: [...string] | *[]
// If true, all dashboards links will be displayed in a dropdown. If false, all dashboards links will be displayed side by side. Only valid if the type is dashboards
asDropdown: bool | *false
// If true, the link will be opened in a new tab
targetBlank: bool | *false
// If true, includes current template variables values in the link as query params
includeVars: bool | *false
// If true, includes current time range in the link as query params
keepTime: bool | *false
}
DataSourceRef: {
// The plugin type-id
type?: string
// Specific datasource instance
uid?: string
}
// A topic is attached to DataFrame metadata in query results.
// This specifies where the data should be used.
DataTopic: "series" | "annotations" | "alertStates" @cog(kind="enum",memberNames="Series|Annotations|AlertStates")
// Transformations allow to manipulate data returned by a query before the system applies a visualization.
// Using transformations you can: rename fields, join time series data, perform mathematical operations across queries,
// use the output of one transformation as the input to another transformation, etc.
DataTransformerConfig: {
// Unique identifier of transformer
id: string
// Disabled transformations are skipped
disabled?: bool
// Optional frame matcher. When missing it will be applied to all results
filter?: MatcherConfig
// Where to pull DataFrames from as input to transformation
topic?: DataTopic
// Options to be passed to the transformer
// Valid options depend on the transformer id
options: _
}
DataLink: {
title: string
url: string
targetBlank?: bool
}
// The data model used in Grafana, namely the data frame, is a columnar-oriented table structure that unifies both time series and table query results.
// Each column within this structure is called a field. A field can represent a single time series or table column.
// Field options allow you to change how the data is displayed in your visualizations.
FieldConfigSource: {
// Defaults are the options applied to all fields.
defaults: FieldConfig
// Overrides are the options applied to specific fields overriding the defaults.
overrides: [...{
matcher: MatcherConfig
properties: [...DynamicConfigValue]
}]
}
// The data model used in Grafana, namely the data frame, is a columnar-oriented table structure that unifies both time series and table query results.
// Each column within this structure is called a field. A field can represent a single time series or table column.
// Field options allow you to change how the data is displayed in your visualizations.
FieldConfig: {
// The display value for this field. This supports template variables blank is auto
displayName?: string
// This can be used by data sources that return and explicit naming structure for values and labels
// When this property is configured, this value is used rather than the default naming strategy.
displayNameFromDS?: string
// Human readable field metadata
description?: string
// An explicit path to the field in the datasource. When the frame meta includes a path,
// This will default to `${frame.meta.path}/${field.name}
//
// When defined, this value can be used as an identifier within the datasource scope, and
// may be used to update the results
path?: string
// True if data source can write a value to the path. Auth/authz are supported separately
writeable?: bool
// True if data source field supports ad-hoc filters
filterable?: bool
// Unit a field should use. The unit you select is applied to all fields except time.
// You can use the units ID availables in Grafana or a custom unit.
// Available units in Grafana: https://github.com/grafana/grafana/blob/main/packages/grafana-data/src/valueFormats/categories.ts
// As custom unit, you can use the following formats:
// `suffix:<suffix>` for custom unit that should go after value.
// `prefix:<prefix>` for custom unit that should go before value.
// `time:<format>` For custom date time formats type for example `time:YYYY-MM-DD`.
// `si:<base scale><unit characters>` for custom SI units. For example: `si: mF`. This one is a bit more advanced as you can specify both a unit and the source data scale. So if your source data is represented as milli (thousands of) something prefix the unit with that SI scale character.
// `count:<unit>` for a custom count unit.
// `currency:<unit>` for custom a currency unit.
unit?: string
// Specify the number of decimals Grafana includes in the rendered value.
// If you leave this field blank, Grafana automatically truncates the number of decimals based on the value.
// For example 1.1234 will display as 1.12 and 100.456 will display as 100.
// To display all decimals, set the unit to `String`.
decimals?: number
// The minimum value used in percentage threshold calculations. Leave blank for auto calculation based on all series and fields.
min?: number
// The maximum value used in percentage threshold calculations. Leave blank for auto calculation based on all series and fields.
max?: number
// Convert input values into a display string
mappings?: [...ValueMapping]
// Map numeric values to states
thresholds?: ThresholdsConfig
// Panel color configuration
color?: FieldColor
// The behavior when clicking on a result
links?: [...]
// Alternative to empty string
noValue?: string
// custom is specified by the FieldConfig field
// in panel plugin schemas.
custom?: {...}
}
DynamicConfigValue: {
id: string | *""
value?: _
}
// Matcher is a predicate configuration. Based on the config a set of field(s) or values is filtered in order to apply override / transformation.
// It comes with in id ( to resolve implementation from registry) and a configuration that’s specific to a particular matcher type.
MatcherConfig: {
// The matcher id. This is used to find the matcher implementation from registry.
id: string | *""
// The matcher options. This is specific to the matcher implementation.
options?: _
}
Threshold: {
value: number
color: string
}
ThresholdsMode: "absolute" | "percentage"
ThresholdsConfig: {
mode: ThresholdsMode
steps: [...Threshold]
}
ValueMapping: ValueMap | RangeMap | RegexMap | SpecialValueMap
// Supported value mapping types
// `value`: Maps text values to a color or different display text and color. For example, you can configure a value mapping so that all instances of the value 10 appear as Perfection! rather than the number.
// `range`: Maps numerical ranges to a display text and color. For example, if a value is within a certain range, you can configure a range value mapping to display Low or High rather than the number.
// `regex`: Maps regular expressions to replacement text and a color. For example, if a value is www.example.com, you can configure a regex value mapping so that Grafana displays www and truncates the domain.
// `special`: Maps special values like Null, NaN (not a number), and boolean values like true and false to a display text and color. See SpecialValueMatch to see the list of special values. For example, you can configure a special value mapping so that null values appear as N/A.
MappingType: "value" | "range" | "regex" | "special"
// Maps text values to a color or different display text and color.
// For example, you can configure a value mapping so that all instances of the value 10 appear as Perfection! rather than the number.
ValueMap: {
type: MappingType & "value"
// Map with <value_to_match>: ValueMappingResult. For example: { "10": { text: "Perfection!", color: "green" } }
options: [string]: ValueMappingResult
}
// Maps numerical ranges to a display text and color.
// For example, if a value is within a certain range, you can configure a range value mapping to display Low or High rather than the number.
RangeMap: {
type: MappingType & "range"
// Range to match against and the result to apply when the value is within the range
options: {
// Min value of the range. It can be null which means -Infinity
from: float64 | null
// Max value of the range. It can be null which means +Infinity
to: float64 | null
// Config to apply when the value is within the range
result: ValueMappingResult
}
}
// Maps regular expressions to replacement text and a color.
// For example, if a value is www.example.com, you can configure a regex value mapping so that Grafana displays www and truncates the domain.
RegexMap: {
type: MappingType & "regex"
// Regular expression to match against and the result to apply when the value matches the regex
options: {
// Regular expression to match against
pattern: string
// Config to apply when the value matches the regex
result: ValueMappingResult
}
}
// Maps special values like Null, NaN (not a number), and boolean values like true and false to a display text and color.
// See SpecialValueMatch to see the list of special values.
// For example, you can configure a special value mapping so that null values appear as N/A.
SpecialValueMap: {
type: MappingType & "special"
options: {
// Special value to match against
match: SpecialValueMatch
// Config to apply when the value matches the special value
result: ValueMappingResult
}
}
// Special value types supported by the `SpecialValueMap`
SpecialValueMatch: "true" | "false" | "null" | "nan" | "null+nan" | "empty" @cog(kind="enum",memberNames="True|False|Null|NaN|NullAndNaN|Empty")
// Result used as replacement with text and color when the value matches
ValueMappingResult: {
// Text to display when the value matches
text?: string
// Text to use when the value matches
color?: string
// Icon to display when the value matches. Only specific visualizations.
icon?: string
// Position in the mapping array. Only used internally.
index?: int32
}
// Color mode for a field. You can specify a single color, or select a continuous (gradient) color schemes, based on a value.
// Continuous color interpolates a color using the percentage of a value relative to min and max.
// Accepted values are:
// `thresholds`: From thresholds. Informs Grafana to take the color from the matching threshold
// `palette-classic`: Classic palette. Grafana will assign color by looking up a color in a palette by series index. Useful for Graphs and pie charts and other categorical data visualizations
// `palette-classic-by-name`: Classic palette (by name). Grafana will assign color by looking up a color in a palette by series name. Useful for Graphs and pie charts and other categorical data visualizations
// `continuous-GrYlRd`: ontinuous Green-Yellow-Red palette mode
// `continuous-RdYlGr`: Continuous Red-Yellow-Green palette mode
// `continuous-BlYlRd`: Continuous Blue-Yellow-Red palette mode
// `continuous-YlRd`: Continuous Yellow-Red palette mode
// `continuous-BlPu`: Continuous Blue-Purple palette mode
// `continuous-YlBl`: Continuous Yellow-Blue palette mode
// `continuous-blues`: Continuous Blue palette mode
// `continuous-reds`: Continuous Red palette mode
// `continuous-greens`: Continuous Green palette mode
// `continuous-purples`: Continuous Purple palette mode
// `shades`: Shades of a single color. Specify a single color, useful in an override rule.
// `fixed`: Fixed color mode. Specify a single color, useful in an override rule.
FieldColorModeId: "thresholds" | "palette-classic" | "palette-classic-by-name" | "continuous-GrYlRd" | "continuous-RdYlGr" | "continuous-BlYlRd" | "continuous-YlRd" | "continuous-BlPu" | "continuous-YlBl" | "continuous-blues" | "continuous-reds" | "continuous-greens" | "continuous-purples" | "fixed" | "shades"
// Defines how to assign a series color from "by value" color schemes. For example for an aggregated data points like a timeseries, the color can be assigned by the min, max or last value.
FieldColorSeriesByMode: "min" | "max" | "last"
// Map a field to a color.
FieldColor: {
// The main color scheme mode.
mode: FieldColorModeId
// The fixed color value for fixed or shades color modes.
fixedColor?: string
// Some visualizations need to know how to assign a series color from by value color schemes.
seriesBy?: FieldColorSeriesByMode
}
// Dashboard Link type. Accepted values are dashboards (to refer to another dashboard) and link (to refer to an external resource)
DashboardLinkType: "link" | "dashboards"
// --- Common types ---
Kind: {
kind: string
spec: _
metadata?: _
}
// --- Kinds ---
VizConfigSpec: {
pluginVersion: string
options: [string]: _
fieldConfig: FieldConfigSource
}
VizConfigKind: {
// The kind of a VizConfigKind is the plugin ID
kind: string
spec: VizConfigSpec
}
AnnotationQuerySpec: {
datasource?: DataSourceRef
query?: DataQueryKind
enable: bool
hide: bool
iconColor: string
name: string
builtIn?: bool | *false
filter?: AnnotationPanelFilter
legacyOptions?: [string]: _ //Catch-all field for datasource-specific properties
}
AnnotationQueryKind: {
kind: "AnnotationQuery"
spec: AnnotationQuerySpec
}
QueryOptionsSpec: {
timeFrom?: string
maxDataPoints?: int
timeShift?: string
queryCachingTTL?: int
interval?: string
cacheTimeout?: string
hideTimeOverride?: bool
}
DataQueryKind: {
// The kind of a DataQueryKind is the datasource type
kind: string
spec: [string]: _
}
PanelQuerySpec: {
query: DataQueryKind
datasource?: DataSourceRef
refId: string
hidden: bool
}
PanelQueryKind: {
kind: "PanelQuery"
spec: PanelQuerySpec
}
TransformationKind: {
// The kind of a TransformationKind is the transformation ID
kind: string
spec: DataTransformerConfig
}
QueryGroupSpec: {
queries: [...PanelQueryKind]
transformations: [...TransformationKind]
queryOptions: QueryOptionsSpec
}
QueryGroupKind: {
kind: "QueryGroup"
spec: QueryGroupSpec
}
TimeRangeOption: {
display: string | *"Last 6 hours"
from: string | *"now-6h"
to: string | *"now"
}
// Time configuration
// It defines the default time config for the time picker, the refresh picker for the specific dashboard.
TimeSettingsSpec: {
// Timezone of dashboard. Accepted values are IANA TZDB zone ID or "browser" or "utc".
timezone?: string | *"browser"
// Start time range for dashboard.
// Accepted values are relative time strings like "now-6h" or absolute time strings like "2020-07-10T08:00:00.000Z".
from: string | *"now-6h"
// End time range for dashboard.
// Accepted values are relative time strings like "now-6h" or absolute time strings like "2020-07-10T08:00:00.000Z".
to: string | *"now"
// Refresh rate of dashboard. Represented via interval string, e.g. "5s", "1m", "1h", "1d".
autoRefresh: string | *"" // v1: refresh
// Interval options available in the refresh picker dropdown.
autoRefreshIntervals: [...string] | *["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"] // v1: timepicker.refresh_intervals
// Selectable options available in the time picker dropdown. Has no effect on provisioned dashboard.
quickRanges?: [...TimeRangeOption] // v1: timepicker.quick_ranges , not exposed in the UI
// Whether timepicker is visible or not.
hideTimepicker: bool | *false // v1: timepicker.hidden
// Day when the week starts. Expressed by the name of the day in lowercase, e.g. "monday".
weekStart?: "saturday" | "monday" | "sunday"
// The month that the fiscal year starts on. 0 = January, 11 = December
fiscalYearStartMonth: int | *0
// Override the now time by entering a time delay. Use this option to accommodate known delays in data aggregation to avoid null values.
nowDelay?: string // v1: timepicker.nowDelay
}
RepeatMode: "variable" // other repeat modes will be added in the future: label, frame
RepeatOptions: {
mode: RepeatMode
value: string
direction?: "h" | "v"
maxPerRow?: int
}
RowRepeatOptions: {
mode: RepeatMode
value: string
}
TabRepeatOptions: {
mode: RepeatMode
value: string
}
AutoGridRepeatOptions: {
mode: RepeatMode
value: string
}
GridLayoutItemSpec: {
x: int
y: int
width: int
height: int
element: ElementReference // reference to a PanelKind from dashboard.spec.elements Expressed as JSON Schema reference
repeat?: RepeatOptions
}
GridLayoutItemKind: {
kind: "GridLayoutItem"
spec: GridLayoutItemSpec
}
GridLayoutSpec: {
items: [...GridLayoutItemKind]
}
GridLayoutKind: {
kind: "GridLayout"
spec: GridLayoutSpec
}
RowsLayoutKind: {
kind: "RowsLayout"
spec: RowsLayoutSpec
}
RowsLayoutSpec: {
rows: [...RowsLayoutRowKind]
}
RowsLayoutRowKind: {
kind: "RowsLayoutRow"
spec: RowsLayoutRowSpec
}
RowsLayoutRowSpec: {
title?: string
collapse?: bool
hideHeader?: bool
fillScreen?: bool
conditionalRendering?: ConditionalRenderingGroupKind
repeat?: RowRepeatOptions
layout: GridLayoutKind | AutoGridLayoutKind | TabsLayoutKind | RowsLayoutKind
}
AutoGridLayoutKind: {
kind: "AutoGridLayout"
spec: AutoGridLayoutSpec
}
AutoGridLayoutSpec: {
maxColumnCount?: number | *3
columnWidthMode: "narrow" | *"standard" | "wide" | "custom"
columnWidth?: number
rowHeightMode: "short" | *"standard" | "tall" | "custom"
rowHeight?: number
fillScreen?: bool | *false
items: [...AutoGridLayoutItemKind]
}
AutoGridLayoutItemKind: {
kind: "AutoGridLayoutItem"
spec: AutoGridLayoutItemSpec
}
AutoGridLayoutItemSpec: {
element: ElementReference
repeat?: AutoGridRepeatOptions
conditionalRendering?: ConditionalRenderingGroupKind
}
TabsLayoutKind: {
kind: "TabsLayout"
spec: TabsLayoutSpec
}
TabsLayoutSpec: {
tabs: [...TabsLayoutTabKind]
}
TabsLayoutTabKind: {
kind: "TabsLayoutTab"
spec: TabsLayoutTabSpec
}
TabsLayoutTabSpec: {
title?: string
layout: GridLayoutKind | RowsLayoutKind | AutoGridLayoutKind | TabsLayoutKind
conditionalRendering?: ConditionalRenderingGroupKind
repeat?: TabRepeatOptions
}
PanelSpec: {
id: number
title: string
description: string
links: [...DataLink]
data: QueryGroupKind
vizConfig: VizConfigKind
transparent?: bool
}
PanelKind: {
kind: "Panel"
spec: PanelSpec
}
ElementReference: {
kind: "ElementReference"
name: string
}
// Start FIXME: variables - in CUE PR - this are things that should be added into the cue schema
// TODO: properties such as `hide`, `skipUrlSync`, `multi` are type boolean, and in the old schema they are conditional,
// should we make them conditional in the new schema as well? or should we make them required but default to false?
// Variable types
VariableValue: VariableValueSingle | [...VariableValueSingle]
VariableValueSingle: string | bool | number | CustomVariableValue
// Custom formatter variable
CustomFormatterVariable: {
name: string
type: VariableType
multi: bool
includeAll: bool
}
// Custom variable value
CustomVariableValue: {
// The format name or function used in the expression
formatter: *null | string | VariableCustomFormatterFn
}
// Custom formatter function
VariableCustomFormatterFn: {
value: _
legacyVariableModel: {
name: string
type: VariableType
multi: bool
includeAll: bool
}
legacyDefaultFormatter?: VariableCustomFormatterFn
}
// Dashboard variable type
// `query`: Query-generated list of values such as metric names, server names, sensor IDs, data centers, and so on.
// `adhoc`: Key/value filters that are automatically added to all metric queries for a data source (Prometheus, Loki, InfluxDB, and Elasticsearch only).
// `constant`: Define a hidden constant.
// `datasource`: Quickly change the data source for an entire dashboard.
// `interval`: Interval variables represent time spans.
// `textbox`: Display a free text input field with an optional default value.
// `custom`: Define the variable options manually using a comma-separated list.
// `system`: Variables defined by Grafana. See: https://grafana.com/docs/grafana/latest/dashboards/variables/add-template-variables/#global-variables
VariableType: "query" | "adhoc" | "groupby" | "constant" | "datasource" | "interval" | "textbox" | "custom" |
"system" | "snapshot"
VariableKind: QueryVariableKind | TextVariableKind | ConstantVariableKind | DatasourceVariableKind | IntervalVariableKind | CustomVariableKind | GroupByVariableKind | AdhocVariableKind
// Sort variable options
// Accepted values are:
// `disabled`: No sorting
// `alphabeticalAsc`: Alphabetical ASC
// `alphabeticalDesc`: Alphabetical DESC
// `numericalAsc`: Numerical ASC
// `numericalDesc`: Numerical DESC
// `alphabeticalCaseInsensitiveAsc`: Alphabetical Case Insensitive ASC
// `alphabeticalCaseInsensitiveDesc`: Alphabetical Case Insensitive DESC
// `naturalAsc`: Natural ASC
// `naturalDesc`: Natural DESC
// VariableSort enum with default value
VariableSort: "disabled" | "alphabeticalAsc" | "alphabeticalDesc" | "numericalAsc" | "numericalDesc" | "alphabeticalCaseInsensitiveAsc" | "alphabeticalCaseInsensitiveDesc" | "naturalAsc" | "naturalDesc"
// Options to config when to refresh a variable
// `never`: Never refresh the variable
// `onDashboardLoad`: Queries the data source every time the dashboard loads.
// `onTimeRangeChanged`: Queries the data source when the dashboard time range changes.
VariableRefresh: *"never" | "onDashboardLoad" | "onTimeRangeChanged"
// Determine if the variable shows on dashboard
// Accepted values are `dontHide` (show label and value), `hideLabel` (show value only), `hideVariable` (show nothing).
VariableHide: *"dontHide" | "hideLabel" | "hideVariable"
// Determine the origin of the adhoc variable filter
FilterOrigin: "dashboard"
// FIXME: should we introduce this? --- Variable value option
VariableValueOption: {
label: string
value: VariableValueSingle
group?: string
}
// Variable option specification
VariableOption: {
// Whether the option is selected or not
selected?: bool
// Text to be displayed for the option
text: string | [...string]
// Value of the option
value: string | [...string]
}
// Query variable specification
QueryVariableSpec: {
name: string | *""
current: VariableOption | *{
text: ""
value: ""
}
label?: string
hide: VariableHide
refresh: VariableRefresh
skipUrlSync: bool | *false
description?: string
datasource?: DataSourceRef
query: DataQueryKind
regex: string | *""
sort: VariableSort
definition?: string
options: [...VariableOption] | *[]
multi: bool | *false
includeAll: bool | *false
allValue?: string
placeholder?: string
allowCustomValue: bool | *true
staticOptions?: [...VariableOption]
staticOptionsOrder?: "before" | "after" | "sorted"
}
// Query variable kind
QueryVariableKind: {
kind: "QueryVariable"
spec: QueryVariableSpec
}
// Text variable specification
TextVariableSpec: {
name: string | *""
current: VariableOption | *{
text: ""
value: ""
}
query: string | *""
label?: string
hide: VariableHide
skipUrlSync: bool | *false
description?: string
}
// Text variable kind
TextVariableKind: {
kind: "TextVariable"
spec: TextVariableSpec
}
// Constant variable specification
ConstantVariableSpec: {
name: string | *""
query: string | *""
current: VariableOption | *{
text: ""
value: ""
}
label?: string
hide: VariableHide
skipUrlSync: bool | *false
description?: string
}
// Constant variable kind
ConstantVariableKind: {
kind: "ConstantVariable"
spec: ConstantVariableSpec
}
// Datasource variable specification
DatasourceVariableSpec: {
name: string | *""
pluginId: string | *""
refresh: VariableRefresh
regex: string | *""
current: VariableOption | *{
text: ""
value: ""
}
options: [...VariableOption] | *[]
multi: bool | *false
includeAll: bool | *false
allValue?: string
label?: string
hide: VariableHide
skipUrlSync: bool | *false
description?: string
allowCustomValue: bool | *true
}
// Datasource variable kind
DatasourceVariableKind: {
kind: "DatasourceVariable"
spec: DatasourceVariableSpec
}
// Interval variable specification
IntervalVariableSpec: {
name: string | *""
query: string | *""
current: VariableOption | *{
text: ""
value: ""
}
options: [...VariableOption] | *[]
auto: bool | *false
auto_min: string | *""
auto_count: int | *0
refresh: VariableRefresh
label?: string
hide: VariableHide
skipUrlSync: bool | *false
description?: string
}
// Interval variable kind
IntervalVariableKind: {
kind: "IntervalVariable"
spec: IntervalVariableSpec
}
// Custom variable specification
CustomVariableSpec: {
name: string | *""
query: string | *""
current: VariableOption
options: [...VariableOption] | *[]
multi: bool | *false
includeAll: bool | *false
allValue?: string
label?: string
hide: VariableHide
skipUrlSync: bool | *false
description?: string
allowCustomValue: bool | *true
}
// Custom variable kind
CustomVariableKind: {
kind: "CustomVariable"
spec: CustomVariableSpec
}
// GroupBy variable specification
GroupByVariableSpec: {
name: string | *""
datasource?: DataSourceRef
defaultValue?: VariableOption
current: VariableOption | *{
text: ""
value: ""
}
options: [...VariableOption] | *[]
multi: bool | *false
label?: string
hide: VariableHide
skipUrlSync: bool | *false
description?: string
}
// Group variable kind
GroupByVariableKind: {
kind: "GroupByVariable"
spec: GroupByVariableSpec
}
// Adhoc variable specification
AdhocVariableSpec: {
name: string | *""
datasource?: DataSourceRef
baseFilters: [...AdHocFilterWithLabels] | *[]
filters: [...AdHocFilterWithLabels] | *[]
defaultKeys: [...MetricFindValue] | *[]
label?: string
hide: VariableHide
skipUrlSync: bool | *false
description?: string
allowCustomValue: bool | *true
}
// Define the MetricFindValue type
MetricFindValue: {
text: string
value?: string | number
group?: string
expandable?: bool
}
// Define the AdHocFilterWithLabels type
AdHocFilterWithLabels: {
key: string
operator: string
value: string
values?: [...string]
keyLabel?: string
valueLabels?: [...string]
forceEdit?: bool
origin?: FilterOrigin
// @deprecated
condition?: string
}
// Adhoc variable kind
AdhocVariableKind: {
kind: "AdhocVariable"
spec: AdhocVariableSpec
}
ConditionalRenderingGroupKind: {
kind: "ConditionalRenderingGroup"
spec: ConditionalRenderingGroupSpec
}
ConditionalRenderingGroupSpec: {
visibility: "show" | "hide"
condition: "and" | "or"
items: [...ConditionalRenderingVariableKind | ConditionalRenderingDataKind | ConditionalRenderingTimeRangeSizeKind]
}
ConditionalRenderingVariableKind: {
kind: "ConditionalRenderingVariable"
spec: ConditionalRenderingVariableSpec
}
ConditionalRenderingVariableSpec: {
variable: string
operator: "equals" | "notEquals"
value: string
}
ConditionalRenderingDataKind: {
kind: "ConditionalRenderingData"
spec: ConditionalRenderingDataSpec
}
ConditionalRenderingDataSpec: {
value: bool
}
ConditionalRenderingTimeRangeSizeKind: {
kind: "ConditionalRenderingTimeRangeSize"
spec: ConditionalRenderingTimeRangeSizeSpec
}
ConditionalRenderingTimeRangeSizeSpec: {
value: string
}
@@ -763,7 +763,9 @@ type DashboardRepeatOptions struct {
// NewDashboardRepeatOptions creates a new DashboardRepeatOptions object.
func NewDashboardRepeatOptions() *DashboardRepeatOptions {
return &DashboardRepeatOptions{}
return &DashboardRepeatOptions{
Mode: DashboardRepeatMode,
}
}
// other repeat modes will be added in the future: label, frame
@@ -938,7 +940,9 @@ type DashboardRowRepeatOptions struct {
// NewDashboardRowRepeatOptions creates a new DashboardRowRepeatOptions object.
func NewDashboardRowRepeatOptions() *DashboardRowRepeatOptions {
return &DashboardRowRepeatOptions{}
return &DashboardRowRepeatOptions{
Mode: DashboardRepeatMode,
}
}
// +k8s:openapi-gen=true
@@ -1011,7 +1015,9 @@ type DashboardAutoGridRepeatOptions struct {
// NewDashboardAutoGridRepeatOptions creates a new DashboardAutoGridRepeatOptions object.
func NewDashboardAutoGridRepeatOptions() *DashboardAutoGridRepeatOptions {
return &DashboardAutoGridRepeatOptions{}
return &DashboardAutoGridRepeatOptions{
Mode: DashboardRepeatMode,
}
}
// +k8s:openapi-gen=true
@@ -1077,7 +1083,9 @@ type DashboardTabRepeatOptions struct {
// NewDashboardTabRepeatOptions creates a new DashboardTabRepeatOptions object.
func NewDashboardTabRepeatOptions() *DashboardTabRepeatOptions {
return &DashboardTabRepeatOptions{}
return &DashboardTabRepeatOptions{
Mode: DashboardRepeatMode,
}
}
// Links with references to other dashboards or external resources
@@ -1689,7 +1697,9 @@ type DashboardAdHocFilterWithLabels struct {
// NewDashboardAdHocFilterWithLabels creates a new DashboardAdHocFilterWithLabels object.
func NewDashboardAdHocFilterWithLabels() *DashboardAdHocFilterWithLabels {
return &DashboardAdHocFilterWithLabels{}
return &DashboardAdHocFilterWithLabels{
Origin: DashboardFilterOrigin,
}
}
// Determine the origin of the adhoc variable filter
@@ -0,0 +1,18 @@
package v2alpha2
import "k8s.io/apimachinery/pkg/runtime/schema"
const (
// APIGroup is the API group used by all kinds in this package
APIGroup = "dashboard.grafana.app"
// APIVersion is the API version used by all kinds in this package
APIVersion = "v2alpha2"
)
var (
// GroupVersion is a schema.GroupVersion consisting of the Group and Version constants for this package
GroupVersion = schema.GroupVersion{
Group: APIGroup,
Version: APIVersion,
}
)
@@ -0,0 +1,28 @@
//
// Code generated by grafana-app-sdk. DO NOT EDIT.
//
package v2alpha2
import (
"encoding/json"
"io"
"github.com/grafana/grafana-app-sdk/resource"
)
// DashboardJSONCodec is an implementation of resource.Codec for kubernetes JSON encoding
type DashboardJSONCodec struct{}
// Read reads JSON-encoded bytes from `reader` and unmarshals them into `into`
func (*DashboardJSONCodec) Read(reader io.Reader, into resource.Object) error {
return json.NewDecoder(reader).Decode(into)
}
// Write writes JSON-encoded bytes into `writer` marshaled from `from`
func (*DashboardJSONCodec) Write(writer io.Writer, from resource.Object) error {
return json.NewEncoder(writer).Encode(from)
}
// Interface compliance checks
var _ resource.Codec = &DashboardJSONCodec{}
@@ -0,0 +1,31 @@
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
package v2alpha2
import (
time "time"
)
// metadata contains embedded CommonMetadata and can be extended with custom string fields
// TODO: use CommonMetadata instead of redefining here; currently needs to be defined here
// without external reference as using the CommonMetadata reference breaks thema codegen.
type DashboardMetadata struct {
UpdateTimestamp time.Time `json:"updateTimestamp"`
CreatedBy string `json:"createdBy"`
Uid string `json:"uid"`
CreationTimestamp time.Time `json:"creationTimestamp"`
DeletionTimestamp *time.Time `json:"deletionTimestamp,omitempty"`
Finalizers []string `json:"finalizers"`
ResourceVersion string `json:"resourceVersion"`
Generation int64 `json:"generation"`
UpdatedBy string `json:"updatedBy"`
Labels map[string]string `json:"labels"`
}
// NewDashboardMetadata creates a new DashboardMetadata object.
func NewDashboardMetadata() *DashboardMetadata {
return &DashboardMetadata{
Finalizers: []string{},
Labels: map[string]string{},
}
}
@@ -0,0 +1,319 @@
//
// Code generated by grafana-app-sdk. DO NOT EDIT.
//
package v2alpha2
import (
"fmt"
"github.com/grafana/grafana-app-sdk/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"time"
)
// +k8s:openapi-gen=true
type Dashboard struct {
metav1.TypeMeta `json:",inline" yaml:",inline"`
metav1.ObjectMeta `json:"metadata" yaml:"metadata"`
// Spec is the spec of the Dashboard
Spec DashboardSpec `json:"spec" yaml:"spec"`
Status DashboardStatus `json:"status" yaml:"status"`
}
func (o *Dashboard) GetSpec() any {
return o.Spec
}
func (o *Dashboard) SetSpec(spec any) error {
cast, ok := spec.(DashboardSpec)
if !ok {
return fmt.Errorf("cannot set spec type %#v, not of type Spec", spec)
}
o.Spec = cast
return nil
}
func (o *Dashboard) GetSubresources() map[string]any {
return map[string]any{
"status": o.Status,
}
}
func (o *Dashboard) GetSubresource(name string) (any, bool) {
switch name {
case "status":
return o.Status, true
default:
return nil, false
}
}
func (o *Dashboard) SetSubresource(name string, value any) error {
switch name {
case "status":
cast, ok := value.(DashboardStatus)
if !ok {
return fmt.Errorf("cannot set status type %#v, not of type DashboardStatus", value)
}
o.Status = cast
return nil
default:
return fmt.Errorf("subresource '%s' does not exist", name)
}
}
func (o *Dashboard) GetStaticMetadata() resource.StaticMetadata {
gvk := o.GroupVersionKind()
return resource.StaticMetadata{
Name: o.ObjectMeta.Name,
Namespace: o.ObjectMeta.Namespace,
Group: gvk.Group,
Version: gvk.Version,
Kind: gvk.Kind,
}
}
func (o *Dashboard) SetStaticMetadata(metadata resource.StaticMetadata) {
o.Name = metadata.Name
o.Namespace = metadata.Namespace
o.SetGroupVersionKind(schema.GroupVersionKind{
Group: metadata.Group,
Version: metadata.Version,
Kind: metadata.Kind,
})
}
func (o *Dashboard) GetCommonMetadata() resource.CommonMetadata {
dt := o.DeletionTimestamp
var deletionTimestamp *time.Time
if dt != nil {
deletionTimestamp = &dt.Time
}
// Legacy ExtraFields support
extraFields := make(map[string]any)
if o.Annotations != nil {
extraFields["annotations"] = o.Annotations
}
if o.ManagedFields != nil {
extraFields["managedFields"] = o.ManagedFields
}
if o.OwnerReferences != nil {
extraFields["ownerReferences"] = o.OwnerReferences
}
return resource.CommonMetadata{
UID: string(o.UID),
ResourceVersion: o.ResourceVersion,
Generation: o.Generation,
Labels: o.Labels,
CreationTimestamp: o.CreationTimestamp.Time,
DeletionTimestamp: deletionTimestamp,
Finalizers: o.Finalizers,
UpdateTimestamp: o.GetUpdateTimestamp(),
CreatedBy: o.GetCreatedBy(),
UpdatedBy: o.GetUpdatedBy(),
ExtraFields: extraFields,
}
}
func (o *Dashboard) SetCommonMetadata(metadata resource.CommonMetadata) {
o.UID = types.UID(metadata.UID)
o.ResourceVersion = metadata.ResourceVersion
o.Generation = metadata.Generation
o.Labels = metadata.Labels
o.CreationTimestamp = metav1.NewTime(metadata.CreationTimestamp)
if metadata.DeletionTimestamp != nil {
dt := metav1.NewTime(*metadata.DeletionTimestamp)
o.DeletionTimestamp = &dt
} else {
o.DeletionTimestamp = nil
}
o.Finalizers = metadata.Finalizers
if o.Annotations == nil {
o.Annotations = make(map[string]string)
}
if !metadata.UpdateTimestamp.IsZero() {
o.SetUpdateTimestamp(metadata.UpdateTimestamp)
}
if metadata.CreatedBy != "" {
o.SetCreatedBy(metadata.CreatedBy)
}
if metadata.UpdatedBy != "" {
o.SetUpdatedBy(metadata.UpdatedBy)
}
// Legacy support for setting Annotations, ManagedFields, and OwnerReferences via ExtraFields
if metadata.ExtraFields != nil {
if annotations, ok := metadata.ExtraFields["annotations"]; ok {
if cast, ok := annotations.(map[string]string); ok {
o.Annotations = cast
}
}
if managedFields, ok := metadata.ExtraFields["managedFields"]; ok {
if cast, ok := managedFields.([]metav1.ManagedFieldsEntry); ok {
o.ManagedFields = cast
}
}
if ownerReferences, ok := metadata.ExtraFields["ownerReferences"]; ok {
if cast, ok := ownerReferences.([]metav1.OwnerReference); ok {
o.OwnerReferences = cast
}
}
}
}
func (o *Dashboard) GetCreatedBy() string {
if o.ObjectMeta.Annotations == nil {
o.ObjectMeta.Annotations = make(map[string]string)
}
return o.ObjectMeta.Annotations["grafana.com/createdBy"]
}
func (o *Dashboard) SetCreatedBy(createdBy string) {
if o.ObjectMeta.Annotations == nil {
o.ObjectMeta.Annotations = make(map[string]string)
}
o.ObjectMeta.Annotations["grafana.com/createdBy"] = createdBy
}
func (o *Dashboard) GetUpdateTimestamp() time.Time {
if o.ObjectMeta.Annotations == nil {
o.ObjectMeta.Annotations = make(map[string]string)
}
parsed, _ := time.Parse(time.RFC3339, o.ObjectMeta.Annotations["grafana.com/updateTimestamp"])
return parsed
}
func (o *Dashboard) SetUpdateTimestamp(updateTimestamp time.Time) {
if o.ObjectMeta.Annotations == nil {
o.ObjectMeta.Annotations = make(map[string]string)
}
o.ObjectMeta.Annotations["grafana.com/updateTimestamp"] = updateTimestamp.Format(time.RFC3339)
}
func (o *Dashboard) GetUpdatedBy() string {
if o.ObjectMeta.Annotations == nil {
o.ObjectMeta.Annotations = make(map[string]string)
}
return o.ObjectMeta.Annotations["grafana.com/updatedBy"]
}
func (o *Dashboard) SetUpdatedBy(updatedBy string) {
if o.ObjectMeta.Annotations == nil {
o.ObjectMeta.Annotations = make(map[string]string)
}
o.ObjectMeta.Annotations["grafana.com/updatedBy"] = updatedBy
}
func (o *Dashboard) Copy() resource.Object {
return resource.CopyObject(o)
}
func (o *Dashboard) DeepCopyObject() runtime.Object {
return o.Copy()
}
func (o *Dashboard) DeepCopy() *Dashboard {
cpy := &Dashboard{}
o.DeepCopyInto(cpy)
return cpy
}
func (o *Dashboard) DeepCopyInto(dst *Dashboard) {
dst.TypeMeta.APIVersion = o.TypeMeta.APIVersion
dst.TypeMeta.Kind = o.TypeMeta.Kind
o.ObjectMeta.DeepCopyInto(&dst.ObjectMeta)
o.Spec.DeepCopyInto(&dst.Spec)
o.Status.DeepCopyInto(&dst.Status)
}
// Interface compliance compile-time check
var _ resource.Object = &Dashboard{}
// +k8s:openapi-gen=true
type DashboardList struct {
metav1.TypeMeta `json:",inline" yaml:",inline"`
metav1.ListMeta `json:"metadata" yaml:"metadata"`
Items []Dashboard `json:"items" yaml:"items"`
}
func (o *DashboardList) DeepCopyObject() runtime.Object {
return o.Copy()
}
func (o *DashboardList) Copy() resource.ListObject {
cpy := &DashboardList{
TypeMeta: o.TypeMeta,
Items: make([]Dashboard, len(o.Items)),
}
o.ListMeta.DeepCopyInto(&cpy.ListMeta)
for i := 0; i < len(o.Items); i++ {
if item, ok := o.Items[i].Copy().(*Dashboard); ok {
cpy.Items[i] = *item
}
}
return cpy
}
func (o *DashboardList) GetItems() []resource.Object {
items := make([]resource.Object, len(o.Items))
for i := 0; i < len(o.Items); i++ {
items[i] = &o.Items[i]
}
return items
}
func (o *DashboardList) SetItems(items []resource.Object) {
o.Items = make([]Dashboard, len(items))
for i := 0; i < len(items); i++ {
o.Items[i] = *items[i].(*Dashboard)
}
}
func (o *DashboardList) DeepCopy() *DashboardList {
cpy := &DashboardList{}
o.DeepCopyInto(cpy)
return cpy
}
func (o *DashboardList) DeepCopyInto(dst *DashboardList) {
resource.CopyObjectInto(dst, o)
}
// Interface compliance compile-time check
var _ resource.ListObject = &DashboardList{}
// Copy methods for all subresource types
// DeepCopy creates a full deep copy of Spec
func (s *DashboardSpec) DeepCopy() *DashboardSpec {
cpy := &DashboardSpec{}
s.DeepCopyInto(cpy)
return cpy
}
// DeepCopyInto deep copies Spec into another Spec object
func (s *DashboardSpec) DeepCopyInto(dst *DashboardSpec) {
resource.CopyObjectInto(dst, s)
}
// DeepCopy creates a full deep copy of DashboardStatus
func (s *DashboardStatus) DeepCopy() *DashboardStatus {
cpy := &DashboardStatus{}
s.DeepCopyInto(cpy)
return cpy
}
// DeepCopyInto deep copies DashboardStatus into another DashboardStatus object
func (s *DashboardStatus) DeepCopyInto(dst *DashboardStatus) {
resource.CopyObjectInto(dst, s)
}
@@ -0,0 +1,34 @@
//
// Code generated by grafana-app-sdk. DO NOT EDIT.
//
package v2alpha2
import (
"github.com/grafana/grafana-app-sdk/resource"
)
// schema is unexported to prevent accidental overwrites
var (
schemaDashboard = resource.NewSimpleSchema("dashboard.grafana.app", "v2alpha2", &Dashboard{}, &DashboardList{}, resource.WithKind("Dashboard"),
resource.WithPlural("dashboards"), resource.WithScope(resource.NamespacedScope))
kindDashboard = resource.Kind{
Schema: schemaDashboard,
Codecs: map[resource.KindEncoding]resource.Codec{
resource.KindEncodingJSON: &DashboardJSONCodec{},
},
}
)
// Kind returns a resource.Kind for this Schema with a JSON codec
func DashboardKind() resource.Kind {
return kindDashboard
}
// Schema returns a resource.SimpleSchema representation of Dashboard
func DashboardSchema() *resource.SimpleSchema {
return schemaDashboard
}
// Interface compliance checks
var _ resource.Schema = kindDashboard
@@ -0,0 +1,968 @@
// This file is managed by grafana-app-sdk - DO NOT EDIT MANUALLY
// Source: apps/dashboard/kinds/v2alpha2/dashboard_spec.cue
// To sync changes, run: make generate in apps/dashboard
package v2alpha2
DashboardSpec: {
annotations: [...AnnotationQueryKind] | *[]
// Configuration of dashboard cursor sync behavior.
// "Off" for no shared crosshair or tooltip (default).
// "Crosshair" for shared crosshair.
// "Tooltip" for shared crosshair AND shared tooltip.
cursorSync: DashboardCursorSync
// Description of dashboard.
description?: string
// Whether a dashboard is editable or not.
editable?: bool | *true
elements: [ElementReference.name]: Element | *{}
layout: GridLayoutKind | RowsLayoutKind | AutoGridLayoutKind | TabsLayoutKind
// Links with references to other dashboards or external websites.
links: [...DashboardLink] | *[]
// When set to true, the dashboard will redraw panels at an interval matching the pixel width.
// This will keep data "moving left" regardless of the query refresh rate. This setting helps
// avoid dashboards presenting stale live data.
liveNow?: bool
// When set to true, the dashboard will load all panels in the dashboard when it's loaded.
preload: bool | *false
// Plugins only. The version of the dashboard installed together with the plugin.
// This is used to determine if the dashboard should be updated when the plugin is updated.
revision?: uint16
// Tags associated with dashboard.
tags: [...string] | *[]
timeSettings: TimeSettingsSpec
// Title of dashboard.
title: string
// Configured template variables.
variables: [...VariableKind] | *[]
}
// Supported dashboard elements
Element: PanelKind | LibraryPanelKind // |* more element types in the future
LibraryPanelKind: {
kind: "LibraryPanel"
spec: LibraryPanelKindSpec
}
LibraryPanelKindSpec: {
// Panel ID for the library panel in the dashboard
id: number
// Title for the library panel in the dashboard
title: string
libraryPanel: LibraryPanelRef
}
// A library panel is a reusable panel that you can use in any dashboard.
// When you make a change to a library panel, that change propagates to all instances of where the panel is used.
// Library panels streamline reuse of panels across multiple dashboards.
LibraryPanelRef: {
// Library panel name
name: string
// Library panel uid
uid: string
}
AnnotationPanelFilter: {
// Should the specified panels be included or excluded
exclude?: bool | *false
// Panel IDs that should be included or excluded
ids: [...uint32]
}
// "Off" for no shared crosshair or tooltip (default).
// "Crosshair" for shared crosshair.
// "Tooltip" for shared crosshair AND shared tooltip.
DashboardCursorSync: "Crosshair" | "Tooltip" | *"Off"
// Links with references to other dashboards or external resources
DashboardLink: {
// Title to display with the link
title: string
// Link type. Accepted values are dashboards (to refer to another dashboard) and link (to refer to an external resource)
// FIXME: The type is generated as `type: DashboardLinkType | dashboardLinkType.Link;` but it should be `type: DashboardLinkType`
type: DashboardLinkType
// Icon name to be displayed with the link
icon: string
// Tooltip to display when the user hovers their mouse over it
tooltip: string
// Link URL. Only required/valid if the type is link
url?: string
// List of tags to limit the linked dashboards. If empty, all dashboards will be displayed. Only valid if the type is dashboards
tags: [...string] | *[]
// If true, all dashboards links will be displayed in a dropdown. If false, all dashboards links will be displayed side by side. Only valid if the type is dashboards
asDropdown: bool | *false
// If true, the link will be opened in a new tab
targetBlank: bool | *false
// If true, includes current template variables values in the link as query params
includeVars: bool | *false
// If true, includes current time range in the link as query params
keepTime: bool | *false
}
DataSourceRef: {
// The plugin type-id
type?: string
// Specific datasource instance
uid?: string
}
// A topic is attached to DataFrame metadata in query results.
// This specifies where the data should be used.
DataTopic: "series" | "annotations" | "alertStates" @cog(kind="enum",memberNames="Series|Annotations|AlertStates")
// Transformations allow to manipulate data returned by a query before the system applies a visualization.
// Using transformations you can: rename fields, join time series data, perform mathematical operations across queries,
// use the output of one transformation as the input to another transformation, etc.
DataTransformerConfig: {
// Unique identifier of transformer
id: string
// Disabled transformations are skipped
disabled?: bool
// Optional frame matcher. When missing it will be applied to all results
filter?: MatcherConfig
// Where to pull DataFrames from as input to transformation
topic?: DataTopic
// Options to be passed to the transformer
// Valid options depend on the transformer id
options: _
}
DataLink: {
title: string
url: string
targetBlank?: bool
}
// The data model used in Grafana, namely the data frame, is a columnar-oriented table structure that unifies both time series and table query results.
// Each column within this structure is called a field. A field can represent a single time series or table column.
// Field options allow you to change how the data is displayed in your visualizations.
FieldConfigSource: {
// Defaults are the options applied to all fields.
defaults: FieldConfig
// Overrides are the options applied to specific fields overriding the defaults.
overrides: [...{
matcher: MatcherConfig
properties: [...DynamicConfigValue]
}]
}
// The data model used in Grafana, namely the data frame, is a columnar-oriented table structure that unifies both time series and table query results.
// Each column within this structure is called a field. A field can represent a single time series or table column.
// Field options allow you to change how the data is displayed in your visualizations.
FieldConfig: {
// The display value for this field. This supports template variables blank is auto
displayName?: string
// This can be used by data sources that return and explicit naming structure for values and labels
// When this property is configured, this value is used rather than the default naming strategy.
displayNameFromDS?: string
// Human readable field metadata
description?: string
// An explicit path to the field in the datasource. When the frame meta includes a path,
// This will default to `${frame.meta.path}/${field.name}
//
// When defined, this value can be used as an identifier within the datasource scope, and
// may be used to update the results
path?: string
// True if data source can write a value to the path. Auth/authz are supported separately
writeable?: bool
// True if data source field supports ad-hoc filters
filterable?: bool
// Unit a field should use. The unit you select is applied to all fields except time.
// You can use the units ID availables in Grafana or a custom unit.
// Available units in Grafana: https://github.com/grafana/grafana/blob/main/packages/grafana-data/src/valueFormats/categories.ts
// As custom unit, you can use the following formats:
// `suffix:<suffix>` for custom unit that should go after value.
// `prefix:<prefix>` for custom unit that should go before value.
// `time:<format>` For custom date time formats type for example `time:YYYY-MM-DD`.
// `si:<base scale><unit characters>` for custom SI units. For example: `si: mF`. This one is a bit more advanced as you can specify both a unit and the source data scale. So if your source data is represented as milli (thousands of) something prefix the unit with that SI scale character.
// `count:<unit>` for a custom count unit.
// `currency:<unit>` for custom a currency unit.
unit?: string
// Specify the number of decimals Grafana includes in the rendered value.
// If you leave this field blank, Grafana automatically truncates the number of decimals based on the value.
// For example 1.1234 will display as 1.12 and 100.456 will display as 100.
// To display all decimals, set the unit to `String`.
decimals?: number
// The minimum value used in percentage threshold calculations. Leave blank for auto calculation based on all series and fields.
min?: number
// The maximum value used in percentage threshold calculations. Leave blank for auto calculation based on all series and fields.
max?: number
// Convert input values into a display string
mappings?: [...ValueMapping]
// Map numeric values to states
thresholds?: ThresholdsConfig
// Panel color configuration
color?: FieldColor
// The behavior when clicking on a result
links?: [...]
// Alternative to empty string
noValue?: string
// custom is specified by the FieldConfig field
// in panel plugin schemas.
custom?: {...}
}
DynamicConfigValue: {
id: string | *""
value?: _
}
// Matcher is a predicate configuration. Based on the config a set of field(s) or values is filtered in order to apply override / transformation.
// It comes with in id ( to resolve implementation from registry) and a configuration that’s specific to a particular matcher type.
MatcherConfig: {
// The matcher id. This is used to find the matcher implementation from registry.
id: string | *""
// The matcher options. This is specific to the matcher implementation.
options?: _
}
Threshold: {
value: number
color: string
}
ThresholdsMode: "absolute" | "percentage"
ThresholdsConfig: {
mode: ThresholdsMode
steps: [...Threshold]
}
ValueMapping: ValueMap | RangeMap | RegexMap | SpecialValueMap
// Supported value mapping types
// `value`: Maps text values to a color or different display text and color. For example, you can configure a value mapping so that all instances of the value 10 appear as Perfection! rather than the number.
// `range`: Maps numerical ranges to a display text and color. For example, if a value is within a certain range, you can configure a range value mapping to display Low or High rather than the number.
// `regex`: Maps regular expressions to replacement text and a color. For example, if a value is www.example.com, you can configure a regex value mapping so that Grafana displays www and truncates the domain.
// `special`: Maps special values like Null, NaN (not a number), and boolean values like true and false to a display text and color. See SpecialValueMatch to see the list of special values. For example, you can configure a special value mapping so that null values appear as N/A.
MappingType: "value" | "range" | "regex" | "special"
// Maps text values to a color or different display text and color.
// For example, you can configure a value mapping so that all instances of the value 10 appear as Perfection! rather than the number.
ValueMap: {
type: MappingType & "value"
// Map with <value_to_match>: ValueMappingResult. For example: { "10": { text: "Perfection!", color: "green" } }
options: [string]: ValueMappingResult
}
// Maps numerical ranges to a display text and color.
// For example, if a value is within a certain range, you can configure a range value mapping to display Low or High rather than the number.
RangeMap: {
type: MappingType & "range"
// Range to match against and the result to apply when the value is within the range
options: {
// Min value of the range. It can be null which means -Infinity
from: float64 | null
// Max value of the range. It can be null which means +Infinity
to: float64 | null
// Config to apply when the value is within the range
result: ValueMappingResult
}
}
// Maps regular expressions to replacement text and a color.
// For example, if a value is www.example.com, you can configure a regex value mapping so that Grafana displays www and truncates the domain.
RegexMap: {
type: MappingType & "regex"
// Regular expression to match against and the result to apply when the value matches the regex
options: {
// Regular expression to match against
pattern: string
// Config to apply when the value matches the regex
result: ValueMappingResult
}
}
// Maps special values like Null, NaN (not a number), and boolean values like true and false to a display text and color.
// See SpecialValueMatch to see the list of special values.
// For example, you can configure a special value mapping so that null values appear as N/A.
SpecialValueMap: {
type: MappingType & "special"
options: {
// Special value to match against
match: SpecialValueMatch
// Config to apply when the value matches the special value
result: ValueMappingResult
}
}
// Special value types supported by the `SpecialValueMap`
SpecialValueMatch: "true" | "false" | "null" | "nan" | "null+nan" | "empty" @cog(kind="enum",memberNames="True|False|Null|NaN|NullAndNaN|Empty")
// Result used as replacement with text and color when the value matches
ValueMappingResult: {
// Text to display when the value matches
text?: string
// Text to use when the value matches
color?: string
// Icon to display when the value matches. Only specific visualizations.
icon?: string
// Position in the mapping array. Only used internally.
index?: int32
}
// Color mode for a field. You can specify a single color, or select a continuous (gradient) color schemes, based on a value.
// Continuous color interpolates a color using the percentage of a value relative to min and max.
// Accepted values are:
// `thresholds`: From thresholds. Informs Grafana to take the color from the matching threshold
// `palette-classic`: Classic palette. Grafana will assign color by looking up a color in a palette by series index. Useful for Graphs and pie charts and other categorical data visualizations
// `palette-classic-by-name`: Classic palette (by name). Grafana will assign color by looking up a color in a palette by series name. Useful for Graphs and pie charts and other categorical data visualizations
// `continuous-GrYlRd`: ontinuous Green-Yellow-Red palette mode
// `continuous-RdYlGr`: Continuous Red-Yellow-Green palette mode
// `continuous-BlYlRd`: Continuous Blue-Yellow-Red palette mode
// `continuous-YlRd`: Continuous Yellow-Red palette mode
// `continuous-BlPu`: Continuous Blue-Purple palette mode
// `continuous-YlBl`: Continuous Yellow-Blue palette mode
// `continuous-blues`: Continuous Blue palette mode
// `continuous-reds`: Continuous Red palette mode
// `continuous-greens`: Continuous Green palette mode
// `continuous-purples`: Continuous Purple palette mode
// `shades`: Shades of a single color. Specify a single color, useful in an override rule.
// `fixed`: Fixed color mode. Specify a single color, useful in an override rule.
FieldColorModeId: "thresholds" | "palette-classic" | "palette-classic-by-name" | "continuous-GrYlRd" | "continuous-RdYlGr" | "continuous-BlYlRd" | "continuous-YlRd" | "continuous-BlPu" | "continuous-YlBl" | "continuous-blues" | "continuous-reds" | "continuous-greens" | "continuous-purples" | "fixed" | "shades"
// Defines how to assign a series color from "by value" color schemes. For example for an aggregated data points like a timeseries, the color can be assigned by the min, max or last value.
FieldColorSeriesByMode: "min" | "max" | "last"
// Map a field to a color.
FieldColor: {
// The main color scheme mode.
mode: FieldColorModeId
// The fixed color value for fixed or shades color modes.
fixedColor?: string
// Some visualizations need to know how to assign a series color from by value color schemes.
seriesBy?: FieldColorSeriesByMode
}
// Dashboard Link type. Accepted values are dashboards (to refer to another dashboard) and link (to refer to an external resource)
DashboardLinkType: "link" | "dashboards"
// --- Common types ---
Kind: {
kind: string
spec: _
metadata?: _
}
// --- Kinds ---
VizConfigSpec: {
pluginVersion: string
options: [string]: _
fieldConfig: FieldConfigSource
}
VizConfigKind: {
// The kind of a VizConfigKind is the plugin ID
kind: string
spec: VizConfigSpec
}
AnnotationQuerySpec: {
datasource?: DataSourceRef
query?: DataQueryKind
enable: bool
hide: bool
iconColor: string
name: string
builtIn?: bool | *false
filter?: AnnotationPanelFilter
legacyOptions?: [string]: _ //Catch-all field for datasource-specific properties
}
AnnotationQueryKind: {
kind: "AnnotationQuery"
spec: AnnotationQuerySpec
}
QueryOptionsSpec: {
timeFrom?: string
maxDataPoints?: int
timeShift?: string
queryCachingTTL?: int
interval?: string
cacheTimeout?: string
hideTimeOverride?: bool
}
DataQueryKind: {
// The kind of a DataQueryKind is the datasource type
kind: string
spec: [string]: _
}
PanelQuerySpec: {
query: DataQueryKind
datasource?: DataSourceRef
refId: string
hidden: bool
}
PanelQueryKind: {
kind: "PanelQuery"
spec: PanelQuerySpec
}
TransformationKind: {
// The kind of a TransformationKind is the transformation ID
kind: string
spec: DataTransformerConfig
}
QueryGroupSpec: {
queries: [...PanelQueryKind]
transformations: [...TransformationKind]
queryOptions: QueryOptionsSpec
}
QueryGroupKind: {
kind: "QueryGroup"
spec: QueryGroupSpec
}
TimeRangeOption: {
display: string | *"Last 6 hours"
from: string | *"now-6h"
to: string | *"now"
}
// Time configuration
// It defines the default time config for the time picker, the refresh picker for the specific dashboard.
TimeSettingsSpec: {
// Timezone of dashboard. Accepted values are IANA TZDB zone ID or "browser" or "utc".
timezone?: string | *"browser"
// Start time range for dashboard.
// Accepted values are relative time strings like "now-6h" or absolute time strings like "2020-07-10T08:00:00.000Z".
from: string | *"now-6h"
// End time range for dashboard.
// Accepted values are relative time strings like "now-6h" or absolute time strings like "2020-07-10T08:00:00.000Z".
to: string | *"now"
// Refresh rate of dashboard. Represented via interval string, e.g. "5s", "1m", "1h", "1d".
autoRefresh: string | *"" // v1: refresh
// Interval options available in the refresh picker dropdown.
autoRefreshIntervals: [...string] | *["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"] // v1: timepicker.refresh_intervals
// Selectable options available in the time picker dropdown. Has no effect on provisioned dashboard.
quickRanges?: [...TimeRangeOption] // v1: timepicker.quick_ranges , not exposed in the UI
// Whether timepicker is visible or not.
hideTimepicker: bool | *false // v1: timepicker.hidden
// Day when the week starts. Expressed by the name of the day in lowercase, e.g. "monday".
weekStart?: "saturday" | "monday" | "sunday"
// The month that the fiscal year starts on. 0 = January, 11 = December
fiscalYearStartMonth: int | *0
// Override the now time by entering a time delay. Use this option to accommodate known delays in data aggregation to avoid null values.
nowDelay?: string // v1: timepicker.nowDelay
}
RepeatMode: "variable" // other repeat modes will be added in the future: label, frame
RepeatOptions: {
mode: RepeatMode
value: string
direction?: "h" | "v"
maxPerRow?: int
}
RowRepeatOptions: {
mode: RepeatMode
value: string
}
TabRepeatOptions: {
mode: RepeatMode
value: string
}
AutoGridRepeatOptions: {
mode: RepeatMode
value: string
}
GridLayoutItemSpec: {
x: int
y: int
width: int
height: int
element: ElementReference // reference to a PanelKind from dashboard.spec.elements Expressed as JSON Schema reference
repeat?: RepeatOptions
}
GridLayoutItemKind: {
kind: "GridLayoutItem"
spec: GridLayoutItemSpec
}
GridLayoutSpec: {
items: [...GridLayoutItemKind]
}
GridLayoutKind: {
kind: "GridLayout"
spec: GridLayoutSpec
}
RowsLayoutKind: {
kind: "RowsLayout"
spec: RowsLayoutSpec
}
RowsLayoutSpec: {
rows: [...RowsLayoutRowKind]
}
RowsLayoutRowKind: {
kind: "RowsLayoutRow"
spec: RowsLayoutRowSpec
}
RowsLayoutRowSpec: {
title?: string
collapse?: bool
hideHeader?: bool
fillScreen?: bool
conditionalRendering?: ConditionalRenderingGroupKind
repeat?: RowRepeatOptions
layout: GridLayoutKind | AutoGridLayoutKind | TabsLayoutKind | RowsLayoutKind
}
AutoGridLayoutKind: {
kind: "AutoGridLayout"
spec: AutoGridLayoutSpec
}
AutoGridLayoutSpec: {
maxColumnCount?: number | *3
columnWidthMode: "narrow" | *"standard" | "wide" | "custom"
columnWidth?: number
rowHeightMode: "short" | *"standard" | "tall" | "custom"
rowHeight?: number
fillScreen?: bool | *false
items: [...AutoGridLayoutItemKind]
}
AutoGridLayoutItemKind: {
kind: "AutoGridLayoutItem"
spec: AutoGridLayoutItemSpec
}
AutoGridLayoutItemSpec: {
element: ElementReference
repeat?: AutoGridRepeatOptions
conditionalRendering?: ConditionalRenderingGroupKind
}
TabsLayoutKind: {
kind: "TabsLayout"
spec: TabsLayoutSpec
}
TabsLayoutSpec: {
tabs: [...TabsLayoutTabKind]
}
TabsLayoutTabKind: {
kind: "TabsLayoutTab"
spec: TabsLayoutTabSpec
}
TabsLayoutTabSpec: {
title?: string
layout: GridLayoutKind | RowsLayoutKind | AutoGridLayoutKind | TabsLayoutKind
conditionalRendering?: ConditionalRenderingGroupKind
repeat?: TabRepeatOptions
}
PanelSpec: {
id: number
title: string
description: string
links: [...DataLink]
data: QueryGroupKind
vizConfig: VizConfigKind
transparent?: bool
}
PanelKind: {
kind: "Panel"
spec: PanelSpec
}
ElementReference: {
kind: "ElementReference"
name: string
}
// Start FIXME: variables - in CUE PR - this are things that should be added into the cue schema
// TODO: properties such as `hide`, `skipUrlSync`, `multi` are type boolean, and in the old schema they are conditional,
// should we make them conditional in the new schema as well? or should we make them required but default to false?
// Variable types
VariableValue: VariableValueSingle | [...VariableValueSingle]
VariableValueSingle: string | bool | number | CustomVariableValue
// Custom formatter variable
CustomFormatterVariable: {
name: string
type: VariableType
multi: bool
includeAll: bool
}
// Custom variable value
CustomVariableValue: {
// The format name or function used in the expression
formatter: *null | string | VariableCustomFormatterFn
}
// Custom formatter function
VariableCustomFormatterFn: {
value: _
legacyVariableModel: {
name: string
type: VariableType
multi: bool
includeAll: bool
}
legacyDefaultFormatter?: VariableCustomFormatterFn
}
// Dashboard variable type
// `query`: Query-generated list of values such as metric names, server names, sensor IDs, data centers, and so on.
// `adhoc`: Key/value filters that are automatically added to all metric queries for a data source (Prometheus, Loki, InfluxDB, and Elasticsearch only).
// `constant`: Define a hidden constant.
// `datasource`: Quickly change the data source for an entire dashboard.
// `interval`: Interval variables represent time spans.
// `textbox`: Display a free text input field with an optional default value.
// `custom`: Define the variable options manually using a comma-separated list.
// `system`: Variables defined by Grafana. See: https://grafana.com/docs/grafana/latest/dashboards/variables/add-template-variables/#global-variables
VariableType: "query" | "adhoc" | "groupby" | "constant" | "datasource" | "interval" | "textbox" | "custom" |
"system" | "snapshot"
VariableKind: QueryVariableKind | TextVariableKind | ConstantVariableKind | DatasourceVariableKind | IntervalVariableKind | CustomVariableKind | GroupByVariableKind | AdhocVariableKind
// Sort variable options
// Accepted values are:
// `disabled`: No sorting
// `alphabeticalAsc`: Alphabetical ASC
// `alphabeticalDesc`: Alphabetical DESC
// `numericalAsc`: Numerical ASC
// `numericalDesc`: Numerical DESC
// `alphabeticalCaseInsensitiveAsc`: Alphabetical Case Insensitive ASC
// `alphabeticalCaseInsensitiveDesc`: Alphabetical Case Insensitive DESC
// `naturalAsc`: Natural ASC
// `naturalDesc`: Natural DESC
// VariableSort enum with default value
VariableSort: "disabled" | "alphabeticalAsc" | "alphabeticalDesc" | "numericalAsc" | "numericalDesc" | "alphabeticalCaseInsensitiveAsc" | "alphabeticalCaseInsensitiveDesc" | "naturalAsc" | "naturalDesc"
// Options to config when to refresh a variable
// `never`: Never refresh the variable
// `onDashboardLoad`: Queries the data source every time the dashboard loads.
// `onTimeRangeChanged`: Queries the data source when the dashboard time range changes.
VariableRefresh: *"never" | "onDashboardLoad" | "onTimeRangeChanged"
// Determine if the variable shows on dashboard
// Accepted values are `dontHide` (show label and value), `hideLabel` (show value only), `hideVariable` (show nothing).
VariableHide: *"dontHide" | "hideLabel" | "hideVariable"
// Determine the origin of the adhoc variable filter
FilterOrigin: "dashboard"
// FIXME: should we introduce this? --- Variable value option
VariableValueOption: {
label: string
value: VariableValueSingle
group?: string
}
// Variable option specification
VariableOption: {
// Whether the option is selected or not
selected?: bool
// Text to be displayed for the option
text: string | [...string]
// Value of the option
value: string | [...string]
}
// Query variable specification
QueryVariableSpec: {
name: string | *""
current: VariableOption | *{
text: ""
value: ""
}
label?: string
hide: VariableHide
refresh: VariableRefresh
skipUrlSync: bool | *false
description?: string
datasource?: DataSourceRef
query: DataQueryKind
regex: string | *""
sort: VariableSort
definition?: string
options: [...VariableOption] | *[]
multi: bool | *false
includeAll: bool | *false
allValue?: string
placeholder?: string
allowCustomValue: bool | *true
staticOptions?: [...VariableOption]
staticOptionsOrder?: "before" | "after" | "sorted"
}
// Query variable kind
QueryVariableKind: {
kind: "QueryVariable"
spec: QueryVariableSpec
}
// Text variable specification
TextVariableSpec: {
name: string | *""
current: VariableOption | *{
text: ""
value: ""
}
query: string | *""
label?: string
hide: VariableHide
skipUrlSync: bool | *false
description?: string
}
// Text variable kind
TextVariableKind: {
kind: "TextVariable"
spec: TextVariableSpec
}
// Constant variable specification
ConstantVariableSpec: {
name: string | *""
query: string | *""
current: VariableOption | *{
text: ""
value: ""
}
label?: string
hide: VariableHide
skipUrlSync: bool | *false
description?: string
}
// Constant variable kind
ConstantVariableKind: {
kind: "ConstantVariable"
spec: ConstantVariableSpec
}
// Datasource variable specification
DatasourceVariableSpec: {
name: string | *""
pluginId: string | *""
refresh: VariableRefresh
regex: string | *""
current: VariableOption | *{
text: ""
value: ""
}
options: [...VariableOption] | *[]
multi: bool | *false
includeAll: bool | *false
allValue?: string
label?: string
hide: VariableHide
skipUrlSync: bool | *false
description?: string
allowCustomValue: bool | *true
}
// Datasource variable kind
DatasourceVariableKind: {
kind: "DatasourceVariable"
spec: DatasourceVariableSpec
}
// Interval variable specification
IntervalVariableSpec: {
name: string | *""
query: string | *""
current: VariableOption | *{
text: ""
value: ""
}
options: [...VariableOption] | *[]
auto: bool | *false
auto_min: string | *""
auto_count: int | *0
refresh: VariableRefresh
label?: string
hide: VariableHide
skipUrlSync: bool | *false
description?: string
}
// Interval variable kind
IntervalVariableKind: {
kind: "IntervalVariable"
spec: IntervalVariableSpec
}
// Custom variable specification
CustomVariableSpec: {
name: string | *""
query: string | *""
current: VariableOption
options: [...VariableOption] | *[]
multi: bool | *false
includeAll: bool | *false
allValue?: string
label?: string
hide: VariableHide
skipUrlSync: bool | *false
description?: string
allowCustomValue: bool | *true
}
// Custom variable kind
CustomVariableKind: {
kind: "CustomVariable"
spec: CustomVariableSpec
}
// GroupBy variable specification
GroupByVariableSpec: {
name: string | *""
datasource?: DataSourceRef
defaultValue?: VariableOption
current: VariableOption | *{
text: ""
value: ""
}
options: [...VariableOption] | *[]
multi: bool | *false
label?: string
hide: VariableHide
skipUrlSync: bool | *false
description?: string
}
// Group variable kind
GroupByVariableKind: {
kind: "GroupByVariable"
spec: GroupByVariableSpec
}
// Adhoc variable specification
AdhocVariableSpec: {
name: string | *""
datasource?: DataSourceRef
baseFilters: [...AdHocFilterWithLabels] | *[]
filters: [...AdHocFilterWithLabels] | *[]
defaultKeys: [...MetricFindValue] | *[]
label?: string
hide: VariableHide
skipUrlSync: bool | *false
description?: string
allowCustomValue: bool | *true
}
// Define the MetricFindValue type
MetricFindValue: {
text: string
value?: string | number
group?: string
expandable?: bool
}
// Define the AdHocFilterWithLabels type
AdHocFilterWithLabels: {
key: string
operator: string
value: string
values?: [...string]
keyLabel?: string
valueLabels?: [...string]
forceEdit?: bool
origin?: FilterOrigin
// @deprecated
condition?: string
}
// Adhoc variable kind
AdhocVariableKind: {
kind: "AdhocVariable"
spec: AdhocVariableSpec
}
ConditionalRenderingGroupKind: {
kind: "ConditionalRenderingGroup"
spec: ConditionalRenderingGroupSpec
}
ConditionalRenderingGroupSpec: {
visibility: "show" | "hide"
condition: "and" | "or"
items: [...ConditionalRenderingVariableKind | ConditionalRenderingDataKind | ConditionalRenderingTimeRangeSizeKind]
}
ConditionalRenderingVariableKind: {
kind: "ConditionalRenderingVariable"
spec: ConditionalRenderingVariableSpec
}
ConditionalRenderingVariableSpec: {
variable: string
operator: "equals" | "notEquals"
value: string
}
ConditionalRenderingDataKind: {
kind: "ConditionalRenderingData"
spec: ConditionalRenderingDataSpec
}
ConditionalRenderingDataSpec: {
value: bool
}
ConditionalRenderingTimeRangeSizeKind: {
kind: "ConditionalRenderingTimeRangeSize"
spec: ConditionalRenderingTimeRangeSizeSpec
}
ConditionalRenderingTimeRangeSizeSpec: {
value: string
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,34 @@
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
package v2alpha2
// ConversionStatus is the status of the conversion of the dashboard.
// +k8s:openapi-gen=true
type DashboardConversionStatus struct {
// Whether from another version has failed.
// If true, means that the dashboard is not valid,
// and the caller should instead fetch the stored version.
Failed bool `json:"failed"`
// The version which was stored when the dashboard was created / updated.
// Fetching this version should always succeed.
StoredVersion string `json:"storedVersion"`
// The error message from the conversion.
// Empty if the conversion has not failed.
Error string `json:"error"`
}
// NewDashboardConversionStatus creates a new DashboardConversionStatus object.
func NewDashboardConversionStatus() *DashboardConversionStatus {
return &DashboardConversionStatus{}
}
// +k8s:openapi-gen=true
type DashboardStatus struct {
// Optional conversion status.
Conversion *DashboardConversionStatus `json:"conversion,omitempty"`
}
// NewDashboardStatus creates a new DashboardStatus object.
func NewDashboardStatus() *DashboardStatus {
return &DashboardStatus{}
}
@@ -0,0 +1,10 @@
// +k8s:openapi-gen=true
// +k8s:defaulter-gen=TypeMeta
// +k8s:conversion-gen=github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard
// +groupName=dashboard.grafana.app
// NOTE (@radiohead): we do not use package-wide deepcopy generation
// because grafana-app-sdk already provides deepcopy functions.
// Kinds which are not generated by the SDK are explicitly opted in to deepcopy generation.
package v2alpha2 // import "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1"
@@ -0,0 +1,103 @@
package v2alpha2
import (
"fmt"
"time"
"github.com/grafana/grafana/pkg/apimachinery/utils"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
const (
GROUP = "dashboard.grafana.app"
VERSION = "v2alpha2"
APIVERSION = GROUP + "/" + VERSION
)
var DashboardResourceInfo = utils.NewResourceInfo(GROUP, VERSION,
"dashboards", "dashboard", "Dashboard",
func() runtime.Object { return &Dashboard{} },
func() runtime.Object { return &DashboardList{} },
utils.TableColumns{
Definition: []metav1.TableColumnDefinition{
{Name: "Name", Type: "string", Format: "name"},
{Name: "Title", Type: "string", Format: "string", Description: "The dashboard name"},
{Name: "Created At", Type: "date"},
},
Reader: func(obj any) ([]interface{}, error) {
dash, ok := obj.(*Dashboard)
if ok {
if dash != nil {
return []interface{}{
dash.Name,
dash.Spec.Title,
dash.CreationTimestamp.UTC().Format(time.RFC3339),
}, nil
}
}
return nil, fmt.Errorf("expected dashboard")
},
},
)
var LibraryPanelResourceInfo = utils.NewResourceInfo(GROUP, VERSION,
"librarypanels", "librarypanel", "LibraryPanel",
func() runtime.Object { return &LibraryPanel{} },
func() runtime.Object { return &LibraryPanelList{} },
utils.TableColumns{
Definition: []metav1.TableColumnDefinition{
{Name: "Name", Type: "string", Format: "name"},
{Name: "Title", Type: "string", Description: "The dashboard name"},
{Name: "Type", Type: "string", Description: "the panel type"},
{Name: "Created At", Type: "date"},
},
Reader: func(obj any) ([]interface{}, error) {
panel, ok := obj.(*LibraryPanel)
if ok {
if panel != nil {
return []interface{}{
panel.Name,
panel.Spec.Title,
panel.Spec.Type,
panel.CreationTimestamp.UTC().Format(time.RFC3339),
}, nil
}
}
return nil, fmt.Errorf("expected library panel")
},
},
)
var (
SchemeBuilder runtime.SchemeBuilder
localSchemeBuilder = &SchemeBuilder
AddToScheme = localSchemeBuilder.AddToScheme
schemeGroupVersion = schema.GroupVersion{Group: GROUP, Version: VERSION}
)
func init() {
localSchemeBuilder.Register(addKnownTypes, addDefaultingFuncs)
}
// Adds the list of known types to the given scheme.
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(schemeGroupVersion,
&Dashboard{},
&DashboardList{},
&DashboardWithAccessInfo{},
&DashboardVersionList{},
&VersionsQueryOptions{},
&LibraryPanel{},
&LibraryPanelList{},
&metav1.PartialObjectMetadata{},
&metav1.PartialObjectMetadataList{},
)
metav1.AddToGroupVersion(scheme, schemeGroupVersion)
return nil
}
func addDefaultingFuncs(scheme *runtime.Scheme) error {
return RegisterDefaults(scheme)
}
@@ -0,0 +1,149 @@
package v2alpha2
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
data "github.com/grafana/grafana-plugin-sdk-go/experimental/apis/data/v0alpha1"
common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1"
)
// +k8s:deepcopy-gen=true
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type DashboardVersionList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []DashboardVersionInfo `json:"items"`
}
// +k8s:deepcopy-gen=true
type DashboardVersionInfo struct {
// The internal ID for this version (will be replaced with resourceVersion)
Version int `json:"version"`
// If the dashboard came from a previous version, it is set here
ParentVersion int `json:"parentVersion,omitempty"`
// The creation timestamp for this version
Created int64 `json:"created"`
// The user who created this version
CreatedBy string `json:"createdBy,omitempty"`
// Message passed while saving the version
Message string `json:"message,omitempty"`
}
// +k8s:deepcopy-gen=true
// +k8s:conversion-gen:explicit-from=net/url.Values
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type VersionsQueryOptions struct {
metav1.TypeMeta `json:",inline"`
// Path is the URL path
// +optional
Path string `json:"path,omitempty"`
// +optional
Version int64 `json:"version,omitempty"`
}
// +k8s:deepcopy-gen=true
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type LibraryPanel struct {
metav1.TypeMeta `json:",inline"`
// Standard object's metadata
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
// +optional
metav1.ObjectMeta `json:"metadata,omitempty"`
// Panel properties
Spec LibraryPanelSpec `json:"spec"`
// Status will show errors
Status *LibraryPanelStatus `json:"status,omitempty"`
}
// +k8s:deepcopy-gen=true
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type LibraryPanelList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []LibraryPanel `json:"items"`
}
// +k8s:deepcopy-gen=true
type LibraryPanelSpec struct {
// The panel type
Type string `json:"type"`
// The panel type
PluginVersion string `json:"pluginVersion,omitempty"`
// The panel title
Title string `json:"title,omitempty"`
// Library panel description
Description string `json:"description,omitempty"`
// The options schema depends on the panel type
Options common.Unstructured `json:"options"`
// The fieldConfig schema depends on the panel type
FieldConfig common.Unstructured `json:"fieldConfig"`
// The default datasource type
Datasource *data.DataSourceRef `json:"datasource,omitempty"`
// The datasource queries
// +listType=set
Targets []data.DataQuery `json:"targets,omitempty"`
}
// +k8s:deepcopy-gen=true
type LibraryPanelStatus struct {
// Translation warnings (mostly things that were in SQL columns but not found in the saved body)
Warnings []string `json:"warnings,omitempty"`
// The properties previously stored in SQL that are not included in this model
Missing common.Unstructured `json:"missing,omitempty"`
}
// This is like the legacy DTO where access and metadata are all returned in a single call
// +k8s:deepcopy-gen=true
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type DashboardWithAccessInfo struct {
Dashboard `json:",inline"`
Access DashboardAccess `json:"access"`
}
// Information about how the requesting user can use a given dashboard
// +k8s:deepcopy-gen=true
type DashboardAccess struct {
// Metadata fields
Slug string `json:"slug,omitempty"`
Url string `json:"url,omitempty"`
// The permissions part
CanSave bool `json:"canSave"`
CanEdit bool `json:"canEdit"`
CanAdmin bool `json:"canAdmin"`
CanStar bool `json:"canStar"`
CanDelete bool `json:"canDelete"`
AnnotationsPermissions *AnnotationPermission `json:"annotationsPermissions"`
}
// +k8s:deepcopy-gen=true
type AnnotationPermission struct {
Dashboard AnnotationActions `json:"dashboard"`
Organization AnnotationActions `json:"organization"`
}
// +k8s:deepcopy-gen=true
type AnnotationActions struct {
CanAdd bool `json:"canAdd"`
CanEdit bool `json:"canEdit"`
CanDelete bool `json:"canDelete"`
}
@@ -0,0 +1,84 @@
package v2alpha2
import (
_ "embed"
json "encoding/json"
fmt "fmt"
"strings"
"sync"
"k8s.io/apimachinery/pkg/util/validation/field"
"cuelang.org/go/cue"
"cuelang.org/go/cue/cuecontext"
"cuelang.org/go/cue/errors"
cuejson "cuelang.org/go/encoding/json"
)
func ValidateDashboardSpec(obj *Dashboard) field.ErrorList {
data, err := json.Marshal(obj.Spec)
if err != nil {
return field.ErrorList{
field.Invalid(field.NewPath("spec"), field.OmitValueType{}, err.Error()),
}
}
if err := cuejson.Validate(data, getCueSchema()); err != nil {
errs := field.ErrorList{}
for _, e := range errors.Errors(err) {
if
// We don't want to return confusing "empty disjunction" errors,
// because the users don't necessarily understand what to do with them.
// For empty disjunctions, CUE will also return more specific errors,
// so we can safely ignore the generic ones.
strings.Contains(e.Error(), "disjunction") ||
// We don't want to return errors about unknown fields either.
strings.Contains(e.Error(), "field not allowed") {
continue
}
if strings.Contains(e.Error(), "mismatched types null and list") {
// Go populates empty slices as nil, which the cue validator does not like
continue
}
// We want to manually format the error message,
// because e.Error() contains the full CUE path.
format, args := e.Msg()
errs = append(errs, field.Invalid(
field.NewPath(formatErrorPath(e.Path())),
field.OmitValueType{},
fmt.Sprintf(format, args...),
))
}
return errs
}
return nil
}
func formatErrorPath(path []string) string {
return strings.Join(path, ".")
}
var (
compiledSchema cue.Value
getSchemaOnce sync.Once
)
//go:embed dashboard_spec.cue
var schemaSource string
func getCueSchema() cue.Value {
getSchemaOnce.Do(func() {
cueCtx := cuecontext.New()
compiledSchema = cueCtx.CompileString(schemaSource).LookupPath(
cue.ParsePath("DashboardSpec"),
)
})
return compiledSchema
}
@@ -0,0 +1,175 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
// SPDX-License-Identifier: AGPL-3.0-only
// Code generated by conversion-gen. DO NOT EDIT.
package v2alpha2
import (
url "net/url"
unsafe "unsafe"
dashboard "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard"
conversion "k8s.io/apimachinery/pkg/conversion"
runtime "k8s.io/apimachinery/pkg/runtime"
)
func init() {
localSchemeBuilder.Register(RegisterConversions)
}
// RegisterConversions adds conversion functions to the given scheme.
// Public to allow building arbitrary schemes.
func RegisterConversions(s *runtime.Scheme) error {
if err := s.AddGeneratedConversionFunc((*AnnotationActions)(nil), (*dashboard.AnnotationActions)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v2alpha2_AnnotationActions_To_dashboard_AnnotationActions(a.(*AnnotationActions), b.(*dashboard.AnnotationActions), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*dashboard.AnnotationActions)(nil), (*AnnotationActions)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_dashboard_AnnotationActions_To_v2alpha2_AnnotationActions(a.(*dashboard.AnnotationActions), b.(*AnnotationActions), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*AnnotationPermission)(nil), (*dashboard.AnnotationPermission)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v2alpha2_AnnotationPermission_To_dashboard_AnnotationPermission(a.(*AnnotationPermission), b.(*dashboard.AnnotationPermission), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*dashboard.AnnotationPermission)(nil), (*AnnotationPermission)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_dashboard_AnnotationPermission_To_v2alpha2_AnnotationPermission(a.(*dashboard.AnnotationPermission), b.(*AnnotationPermission), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*DashboardAccess)(nil), (*dashboard.DashboardAccess)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v2alpha2_DashboardAccess_To_dashboard_DashboardAccess(a.(*DashboardAccess), b.(*dashboard.DashboardAccess), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*dashboard.DashboardAccess)(nil), (*DashboardAccess)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_dashboard_DashboardAccess_To_v2alpha2_DashboardAccess(a.(*dashboard.DashboardAccess), b.(*DashboardAccess), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*url.Values)(nil), (*VersionsQueryOptions)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_url_Values_To_v2alpha2_VersionsQueryOptions(a.(*url.Values), b.(*VersionsQueryOptions), scope)
}); err != nil {
return err
}
return nil
}
func autoConvert_v2alpha2_AnnotationActions_To_dashboard_AnnotationActions(in *AnnotationActions, out *dashboard.AnnotationActions, s conversion.Scope) error {
out.CanAdd = in.CanAdd
out.CanEdit = in.CanEdit
out.CanDelete = in.CanDelete
return nil
}
// Convert_v2alpha2_AnnotationActions_To_dashboard_AnnotationActions is an autogenerated conversion function.
func Convert_v2alpha2_AnnotationActions_To_dashboard_AnnotationActions(in *AnnotationActions, out *dashboard.AnnotationActions, s conversion.Scope) error {
return autoConvert_v2alpha2_AnnotationActions_To_dashboard_AnnotationActions(in, out, s)
}
func autoConvert_dashboard_AnnotationActions_To_v2alpha2_AnnotationActions(in *dashboard.AnnotationActions, out *AnnotationActions, s conversion.Scope) error {
out.CanAdd = in.CanAdd
out.CanEdit = in.CanEdit
out.CanDelete = in.CanDelete
return nil
}
// Convert_dashboard_AnnotationActions_To_v2alpha2_AnnotationActions is an autogenerated conversion function.
func Convert_dashboard_AnnotationActions_To_v2alpha2_AnnotationActions(in *dashboard.AnnotationActions, out *AnnotationActions, s conversion.Scope) error {
return autoConvert_dashboard_AnnotationActions_To_v2alpha2_AnnotationActions(in, out, s)
}
func autoConvert_v2alpha2_AnnotationPermission_To_dashboard_AnnotationPermission(in *AnnotationPermission, out *dashboard.AnnotationPermission, s conversion.Scope) error {
if err := Convert_v2alpha2_AnnotationActions_To_dashboard_AnnotationActions(&in.Dashboard, &out.Dashboard, s); err != nil {
return err
}
if err := Convert_v2alpha2_AnnotationActions_To_dashboard_AnnotationActions(&in.Organization, &out.Organization, s); err != nil {
return err
}
return nil
}
// Convert_v2alpha2_AnnotationPermission_To_dashboard_AnnotationPermission is an autogenerated conversion function.
func Convert_v2alpha2_AnnotationPermission_To_dashboard_AnnotationPermission(in *AnnotationPermission, out *dashboard.AnnotationPermission, s conversion.Scope) error {
return autoConvert_v2alpha2_AnnotationPermission_To_dashboard_AnnotationPermission(in, out, s)
}
func autoConvert_dashboard_AnnotationPermission_To_v2alpha2_AnnotationPermission(in *dashboard.AnnotationPermission, out *AnnotationPermission, s conversion.Scope) error {
if err := Convert_dashboard_AnnotationActions_To_v2alpha2_AnnotationActions(&in.Dashboard, &out.Dashboard, s); err != nil {
return err
}
if err := Convert_dashboard_AnnotationActions_To_v2alpha2_AnnotationActions(&in.Organization, &out.Organization, s); err != nil {
return err
}
return nil
}
// Convert_dashboard_AnnotationPermission_To_v2alpha2_AnnotationPermission is an autogenerated conversion function.
func Convert_dashboard_AnnotationPermission_To_v2alpha2_AnnotationPermission(in *dashboard.AnnotationPermission, out *AnnotationPermission, s conversion.Scope) error {
return autoConvert_dashboard_AnnotationPermission_To_v2alpha2_AnnotationPermission(in, out, s)
}
func autoConvert_v2alpha2_DashboardAccess_To_dashboard_DashboardAccess(in *DashboardAccess, out *dashboard.DashboardAccess, s conversion.Scope) error {
out.Slug = in.Slug
out.Url = in.Url
out.CanSave = in.CanSave
out.CanEdit = in.CanEdit
out.CanAdmin = in.CanAdmin
out.CanStar = in.CanStar
out.CanDelete = in.CanDelete
out.AnnotationsPermissions = (*dashboard.AnnotationPermission)(unsafe.Pointer(in.AnnotationsPermissions))
return nil
}
// Convert_v2alpha2_DashboardAccess_To_dashboard_DashboardAccess is an autogenerated conversion function.
func Convert_v2alpha2_DashboardAccess_To_dashboard_DashboardAccess(in *DashboardAccess, out *dashboard.DashboardAccess, s conversion.Scope) error {
return autoConvert_v2alpha2_DashboardAccess_To_dashboard_DashboardAccess(in, out, s)
}
func autoConvert_dashboard_DashboardAccess_To_v2alpha2_DashboardAccess(in *dashboard.DashboardAccess, out *DashboardAccess, s conversion.Scope) error {
out.Slug = in.Slug
out.Url = in.Url
out.CanSave = in.CanSave
out.CanEdit = in.CanEdit
out.CanAdmin = in.CanAdmin
out.CanStar = in.CanStar
out.CanDelete = in.CanDelete
out.AnnotationsPermissions = (*AnnotationPermission)(unsafe.Pointer(in.AnnotationsPermissions))
return nil
}
// Convert_dashboard_DashboardAccess_To_v2alpha2_DashboardAccess is an autogenerated conversion function.
func Convert_dashboard_DashboardAccess_To_v2alpha2_DashboardAccess(in *dashboard.DashboardAccess, out *DashboardAccess, s conversion.Scope) error {
return autoConvert_dashboard_DashboardAccess_To_v2alpha2_DashboardAccess(in, out, s)
}
func autoConvert_url_Values_To_v2alpha2_VersionsQueryOptions(in *url.Values, out *VersionsQueryOptions, s conversion.Scope) error {
// WARNING: Field TypeMeta does not have json tag, skipping.
if values, ok := map[string][]string(*in)["path"]; ok && len(values) > 0 {
if err := runtime.Convert_Slice_string_To_string(&values, &out.Path, s); err != nil {
return err
}
} else {
out.Path = ""
}
if values, ok := map[string][]string(*in)["version"]; ok && len(values) > 0 {
if err := runtime.Convert_Slice_string_To_int64(&values, &out.Version, s); err != nil {
return err
}
} else {
out.Version = 0
}
return nil
}
// Convert_url_Values_To_v2alpha2_VersionsQueryOptions is an autogenerated conversion function.
func Convert_url_Values_To_v2alpha2_VersionsQueryOptions(in *url.Values, out *VersionsQueryOptions, s conversion.Scope) error {
return autoConvert_url_Values_To_v2alpha2_VersionsQueryOptions(in, out, s)
}
@@ -0,0 +1,283 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
// SPDX-License-Identifier: AGPL-3.0-only
// Code generated by deepcopy-gen. DO NOT EDIT.
package v2alpha2
import (
v0alpha1 "github.com/grafana/grafana-plugin-sdk-go/experimental/apis/data/v0alpha1"
runtime "k8s.io/apimachinery/pkg/runtime"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *AnnotationActions) DeepCopyInto(out *AnnotationActions) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AnnotationActions.
func (in *AnnotationActions) DeepCopy() *AnnotationActions {
if in == nil {
return nil
}
out := new(AnnotationActions)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *AnnotationPermission) DeepCopyInto(out *AnnotationPermission) {
*out = *in
out.Dashboard = in.Dashboard
out.Organization = in.Organization
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AnnotationPermission.
func (in *AnnotationPermission) DeepCopy() *AnnotationPermission {
if in == nil {
return nil
}
out := new(AnnotationPermission)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DashboardAccess) DeepCopyInto(out *DashboardAccess) {
*out = *in
if in.AnnotationsPermissions != nil {
in, out := &in.AnnotationsPermissions, &out.AnnotationsPermissions
*out = new(AnnotationPermission)
**out = **in
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DashboardAccess.
func (in *DashboardAccess) DeepCopy() *DashboardAccess {
if in == nil {
return nil
}
out := new(DashboardAccess)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DashboardVersionInfo) DeepCopyInto(out *DashboardVersionInfo) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DashboardVersionInfo.
func (in *DashboardVersionInfo) DeepCopy() *DashboardVersionInfo {
if in == nil {
return nil
}
out := new(DashboardVersionInfo)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DashboardVersionList) DeepCopyInto(out *DashboardVersionList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]DashboardVersionInfo, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DashboardVersionList.
func (in *DashboardVersionList) DeepCopy() *DashboardVersionList {
if in == nil {
return nil
}
out := new(DashboardVersionList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *DashboardVersionList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DashboardWithAccessInfo) DeepCopyInto(out *DashboardWithAccessInfo) {
*out = *in
in.Dashboard.DeepCopyInto(&out.Dashboard)
in.Access.DeepCopyInto(&out.Access)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DashboardWithAccessInfo.
func (in *DashboardWithAccessInfo) DeepCopy() *DashboardWithAccessInfo {
if in == nil {
return nil
}
out := new(DashboardWithAccessInfo)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *DashboardWithAccessInfo) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *LibraryPanel) DeepCopyInto(out *LibraryPanel) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
if in.Status != nil {
in, out := &in.Status, &out.Status
*out = new(LibraryPanelStatus)
(*in).DeepCopyInto(*out)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LibraryPanel.
func (in *LibraryPanel) DeepCopy() *LibraryPanel {
if in == nil {
return nil
}
out := new(LibraryPanel)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *LibraryPanel) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *LibraryPanelList) DeepCopyInto(out *LibraryPanelList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]LibraryPanel, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LibraryPanelList.
func (in *LibraryPanelList) DeepCopy() *LibraryPanelList {
if in == nil {
return nil
}
out := new(LibraryPanelList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *LibraryPanelList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *LibraryPanelSpec) DeepCopyInto(out *LibraryPanelSpec) {
*out = *in
in.Options.DeepCopyInto(&out.Options)
in.FieldConfig.DeepCopyInto(&out.FieldConfig)
if in.Datasource != nil {
in, out := &in.Datasource, &out.Datasource
*out = new(v0alpha1.DataSourceRef)
**out = **in
}
if in.Targets != nil {
in, out := &in.Targets, &out.Targets
*out = make([]v0alpha1.DataQuery, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LibraryPanelSpec.
func (in *LibraryPanelSpec) DeepCopy() *LibraryPanelSpec {
if in == nil {
return nil
}
out := new(LibraryPanelSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *LibraryPanelStatus) DeepCopyInto(out *LibraryPanelStatus) {
*out = *in
if in.Warnings != nil {
in, out := &in.Warnings, &out.Warnings
*out = make([]string, len(*in))
copy(*out, *in)
}
in.Missing.DeepCopyInto(&out.Missing)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LibraryPanelStatus.
func (in *LibraryPanelStatus) DeepCopy() *LibraryPanelStatus {
if in == nil {
return nil
}
out := new(LibraryPanelStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *VersionsQueryOptions) DeepCopyInto(out *VersionsQueryOptions) {
*out = *in
out.TypeMeta = in.TypeMeta
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VersionsQueryOptions.
func (in *VersionsQueryOptions) DeepCopy() *VersionsQueryOptions {
if in == nil {
return nil
}
out := new(VersionsQueryOptions)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *VersionsQueryOptions) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
@@ -0,0 +1,19 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
// SPDX-License-Identifier: AGPL-3.0-only
// Code generated by defaulter-gen. DO NOT EDIT.
package v2alpha2
import (
runtime "k8s.io/apimachinery/pkg/runtime"
)
// RegisterDefaults adds defaulters functions to the given scheme.
// Public to allow building arbitrary schemes.
// All generated defaulters are covering - they call all nested defaulters.
func RegisterDefaults(scheme *runtime.Scheme) error {
return nil
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,67 @@
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardAdHocFilterWithLabels,ValueLabels
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardAdHocFilterWithLabels,Values
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardAdhocVariableSpec,BaseFilters
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardAdhocVariableSpec,DefaultKeys
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardAdhocVariableSpec,Filters
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardAnnotationPanelFilter,Ids
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardAutoGridLayoutSpec,Items
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardConditionalRenderingGroupSpec,Items
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardCustomVariableSpec,Options
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardDashboardLink,Tags
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardDatasourceVariableSpec,Options
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardFieldConfig,Links
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardFieldConfig,Mappings
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardFieldConfigSource,Overrides
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardGridLayoutSpec,Items
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardGroupByVariableSpec,Options
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardIntervalVariableSpec,Options
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardMetadata,Finalizers
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardPanelSpec,Links
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardQueryGroupSpec,Queries
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardQueryGroupSpec,Transformations
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardQueryVariableSpec,Options
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardQueryVariableSpec,StaticOptions
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardRowsLayoutSpec,Rows
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardSpec,Annotations
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardSpec,Links
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardSpec,Tags
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardSpec,Variables
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardStringOrArrayOfString,ArrayOfString
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardTabsLayoutSpec,Tabs
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardThresholdsConfig,Steps
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardTimeSettingsSpec,AutoRefreshIntervals
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardTimeSettingsSpec,QuickRanges
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardV2alpha2FieldConfigSourceOverrides,Properties
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,LibraryPanelStatus,Warnings
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardConditionalRenderingVariableKindOrConditionalRenderingDataKindOrConditionalRenderingTimeRangeSizeKind,ConditionalRenderingDataKind
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardConditionalRenderingVariableKindOrConditionalRenderingDataKindOrConditionalRenderingTimeRangeSizeKind,ConditionalRenderingTimeRangeSizeKind
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardConditionalRenderingVariableKindOrConditionalRenderingDataKindOrConditionalRenderingTimeRangeSizeKind,ConditionalRenderingVariableKind
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardGridLayoutKindOrAutoGridLayoutKindOrTabsLayoutKindOrRowsLayoutKind,AutoGridLayoutKind
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardGridLayoutKindOrAutoGridLayoutKindOrTabsLayoutKindOrRowsLayoutKind,GridLayoutKind
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardGridLayoutKindOrAutoGridLayoutKindOrTabsLayoutKindOrRowsLayoutKind,RowsLayoutKind
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardGridLayoutKindOrAutoGridLayoutKindOrTabsLayoutKindOrRowsLayoutKind,TabsLayoutKind
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardGridLayoutKindOrRowsLayoutKindOrAutoGridLayoutKindOrTabsLayoutKind,AutoGridLayoutKind
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardGridLayoutKindOrRowsLayoutKindOrAutoGridLayoutKindOrTabsLayoutKind,GridLayoutKind
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardGridLayoutKindOrRowsLayoutKindOrAutoGridLayoutKindOrTabsLayoutKind,RowsLayoutKind
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardGridLayoutKindOrRowsLayoutKindOrAutoGridLayoutKindOrTabsLayoutKind,TabsLayoutKind
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardIntervalVariableSpec,AutoCount
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardIntervalVariableSpec,AutoMin
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardPanelKindOrLibraryPanelKind,LibraryPanelKind
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardPanelKindOrLibraryPanelKind,PanelKind
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardQueryVariableKindOrTextVariableKindOrConstantVariableKindOrDatasourceVariableKindOrIntervalVariableKindOrCustomVariableKindOrGroupByVariableKindOrAdhocVariableKind,AdhocVariableKind
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardQueryVariableKindOrTextVariableKindOrConstantVariableKindOrDatasourceVariableKindOrIntervalVariableKindOrCustomVariableKindOrGroupByVariableKindOrAdhocVariableKind,ConstantVariableKind
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardQueryVariableKindOrTextVariableKindOrConstantVariableKindOrDatasourceVariableKindOrIntervalVariableKindOrCustomVariableKindOrGroupByVariableKindOrAdhocVariableKind,CustomVariableKind
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardQueryVariableKindOrTextVariableKindOrConstantVariableKindOrDatasourceVariableKindOrIntervalVariableKindOrCustomVariableKindOrGroupByVariableKindOrAdhocVariableKind,DatasourceVariableKind
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardQueryVariableKindOrTextVariableKindOrConstantVariableKindOrDatasourceVariableKindOrIntervalVariableKindOrCustomVariableKindOrGroupByVariableKindOrAdhocVariableKind,GroupByVariableKind
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardQueryVariableKindOrTextVariableKindOrConstantVariableKindOrDatasourceVariableKindOrIntervalVariableKindOrCustomVariableKindOrGroupByVariableKindOrAdhocVariableKind,IntervalVariableKind
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardQueryVariableKindOrTextVariableKindOrConstantVariableKindOrDatasourceVariableKindOrIntervalVariableKindOrCustomVariableKindOrGroupByVariableKindOrAdhocVariableKind,QueryVariableKind
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardQueryVariableKindOrTextVariableKindOrConstantVariableKindOrDatasourceVariableKindOrIntervalVariableKindOrCustomVariableKindOrGroupByVariableKindOrAdhocVariableKind,TextVariableKind
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardStringOrArrayOfString,ArrayOfString
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardStringOrArrayOfString,String
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardStringOrFloat64,Float64
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardStringOrFloat64,String
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardValueMapOrRangeMapOrRegexMapOrSpecialValueMap,RangeMap
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardValueMapOrRangeMapOrRegexMapOrSpecialValueMap,RegexMap
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardValueMapOrRangeMapOrRegexMapOrSpecialValueMap,SpecialValueMap
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardValueMapOrRangeMapOrRegexMapOrSpecialValueMap,ValueMap
API rule violation: streaming_list_type_json_tags,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2,DashboardList,ListMeta
@@ -14,6 +14,7 @@ import (
v0alpha1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1"
v1beta1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v1beta1"
v2alpha1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1"
v2alpha2 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2"
)
var appManifestData = app.ManifestData{
@@ -36,6 +37,10 @@ var appManifestData = app.ManifestData{
{
Name: "v2alpha1",
},
{
Name: "v2alpha2",
},
},
},
},
@@ -53,6 +58,7 @@ var kindVersionToGoType = map[string]resource.Kind{
"Dashboard/v0alpha1": v0alpha1.DashboardKind(),
"Dashboard/v1beta1": v1beta1.DashboardKind(),
"Dashboard/v2alpha1": v2alpha1.DashboardKind(),
"Dashboard/v2alpha2": v2alpha2.DashboardKind(),
}
// ManifestGoTypeAssociator returns the associated resource.Kind instance for a given Kind and Version, if one exists.
@@ -6,167 +6,77 @@ import (
dashv0 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1"
dashv1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v1beta1"
dashv2 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1"
"github.com/grafana/grafana/apps/dashboard/pkg/migration"
"github.com/grafana/grafana/apps/dashboard/pkg/migration/schemaversion"
dashv2alpha1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1"
dashv2alpha2 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2"
)
func RegisterConversions(s *runtime.Scheme) error {
// v0 conversions
if err := s.AddConversionFunc((*dashv0.Dashboard)(nil), (*dashv1.Dashboard)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_V0_to_V1(a.(*dashv0.Dashboard), b.(*dashv1.Dashboard), scope)
}); err != nil {
return err
}
if err := s.AddConversionFunc((*dashv0.Dashboard)(nil), (*dashv2.Dashboard)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_V0_to_V2(a.(*dashv0.Dashboard), b.(*dashv2.Dashboard), scope)
if err := s.AddConversionFunc((*dashv0.Dashboard)(nil), (*dashv2alpha1.Dashboard)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_V0_to_V2alpha1(a.(*dashv0.Dashboard), b.(*dashv2alpha1.Dashboard), scope)
}); err != nil {
return err
}
if err := s.AddConversionFunc((*dashv0.Dashboard)(nil), (*dashv2alpha2.Dashboard)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_V0_to_V2alpha2(a.(*dashv0.Dashboard), b.(*dashv2alpha2.Dashboard), scope)
}); err != nil {
return err
}
// v1 conversions
if err := s.AddConversionFunc((*dashv1.Dashboard)(nil), (*dashv0.Dashboard)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_V1_to_V0(a.(*dashv1.Dashboard), b.(*dashv0.Dashboard), scope)
}); err != nil {
return err
}
if err := s.AddConversionFunc((*dashv1.Dashboard)(nil), (*dashv2.Dashboard)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_V1_to_V2(a.(*dashv1.Dashboard), b.(*dashv2.Dashboard), scope)
if err := s.AddConversionFunc((*dashv1.Dashboard)(nil), (*dashv2alpha1.Dashboard)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_V1_to_V2alpha1(a.(*dashv1.Dashboard), b.(*dashv2alpha1.Dashboard), scope)
}); err != nil {
return err
}
if err := s.AddConversionFunc((*dashv2.Dashboard)(nil), (*dashv0.Dashboard)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_V2_to_V0(a.(*dashv2.Dashboard), b.(*dashv0.Dashboard), scope)
if err := s.AddConversionFunc((*dashv1.Dashboard)(nil), (*dashv2alpha2.Dashboard)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_V1_to_V2alpha2(a.(*dashv1.Dashboard), b.(*dashv2alpha2.Dashboard), scope)
}); err != nil {
return err
}
if err := s.AddConversionFunc((*dashv2.Dashboard)(nil), (*dashv1.Dashboard)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_V2_to_V1(a.(*dashv2.Dashboard), b.(*dashv1.Dashboard), scope)
// v2alpha1 conversions
if err := s.AddConversionFunc((*dashv2alpha1.Dashboard)(nil), (*dashv0.Dashboard)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_V2alpha1_to_V0(a.(*dashv2alpha1.Dashboard), b.(*dashv0.Dashboard), scope)
}); err != nil {
return err
}
return nil
}
func Convert_V0_to_V1(in *dashv0.Dashboard, out *dashv1.Dashboard, scope conversion.Scope) error {
out.ObjectMeta = in.ObjectMeta
out.Spec.Object = in.Spec.Object
out.Status = dashv1.DashboardStatus{
Conversion: &dashv1.DashboardConversionStatus{
StoredVersion: dashv0.VERSION,
},
if err := s.AddConversionFunc((*dashv2alpha1.Dashboard)(nil), (*dashv1.Dashboard)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_V2alpha1_to_V1(a.(*dashv2alpha1.Dashboard), b.(*dashv1.Dashboard), scope)
}); err != nil {
return err
}
if err := s.AddConversionFunc((*dashv2alpha1.Dashboard)(nil), (*dashv2alpha2.Dashboard)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_V2alpha1_to_V2alpha2(a.(*dashv2alpha1.Dashboard), b.(*dashv2alpha2.Dashboard), scope)
}); err != nil {
return err
}
if err := migration.Migrate(out.Spec.Object, schemaversion.LATEST_VERSION); err != nil {
out.Status.Conversion.Failed = true
out.Status.Conversion.Error = err.Error()
}
return nil
}
func Convert_V0_to_V2(in *dashv0.Dashboard, out *dashv2.Dashboard, scope conversion.Scope) error {
out.ObjectMeta = in.ObjectMeta
// TODO (@radiohead): implement V0 to V2 conversion
// This is the bare minimum conversion that is needed to make the dashboard servable.
if v, ok := in.Spec.Object["title"]; ok {
if title, ok := v.(string); ok {
out.Spec.Title = title
}
}
// We need to make sure the layout is set to some value, otherwise the JSON marshaling will fail.
out.Spec.Layout = dashv2.DashboardGridLayoutKindOrRowsLayoutKindOrAutoGridLayoutKindOrTabsLayoutKind{
GridLayoutKind: &dashv2.DashboardGridLayoutKind{
Kind: "GridLayout",
Spec: dashv2.DashboardGridLayoutSpec{},
},
}
out.Status = dashv2.DashboardStatus{
Conversion: &dashv2.DashboardConversionStatus{
StoredVersion: dashv0.VERSION,
Failed: true,
Error: "backend conversion not yet implemented",
},
}
return nil
}
func Convert_V1_to_V0(in *dashv1.Dashboard, out *dashv0.Dashboard, scope conversion.Scope) error {
out.ObjectMeta = in.ObjectMeta
out.Spec.Object = in.Spec.Object
out.Status = dashv0.DashboardStatus{
Conversion: &dashv0.DashboardConversionStatus{
StoredVersion: dashv1.VERSION,
},
}
return nil
}
func Convert_V1_to_V2(in *dashv1.Dashboard, out *dashv2.Dashboard, scope conversion.Scope) error {
out.ObjectMeta = in.ObjectMeta
// TODO (@radiohead): implement V1 to V2 conversion
// This is the bare minimum conversion that is needed to make the dashboard servable.
if v, ok := in.Spec.Object["title"]; ok {
if title, ok := v.(string); ok {
out.Spec.Title = title
}
}
// We need to make sure the layout is set to some value, otherwise the JSON marshaling will fail.
out.Spec.Layout = dashv2.DashboardGridLayoutKindOrRowsLayoutKindOrAutoGridLayoutKindOrTabsLayoutKind{
GridLayoutKind: &dashv2.DashboardGridLayoutKind{
Kind: "GridLayout",
Spec: dashv2.DashboardGridLayoutSpec{},
},
}
out.Status = dashv2.DashboardStatus{
Conversion: &dashv2.DashboardConversionStatus{
StoredVersion: dashv1.VERSION,
Failed: true,
Error: "backend conversion not yet implemented",
},
}
return nil
}
func Convert_V2_to_V0(in *dashv2.Dashboard, out *dashv0.Dashboard, scope conversion.Scope) error {
out.ObjectMeta = in.ObjectMeta
// TODO: implement V2 to V0 conversion
out.Status = dashv0.DashboardStatus{
Conversion: &dashv0.DashboardConversionStatus{
StoredVersion: dashv2.VERSION,
Failed: true,
Error: "backend conversion not yet implemented",
},
}
return nil
}
func Convert_V2_to_V1(in *dashv2.Dashboard, out *dashv1.Dashboard, scope conversion.Scope) error {
out.ObjectMeta = in.ObjectMeta
// TODO: implement V2 to V1 conversion
out.Status = dashv1.DashboardStatus{
Conversion: &dashv1.DashboardConversionStatus{
StoredVersion: dashv2.VERSION,
Failed: true,
Error: "backend conversion not yet implemented",
},
// v2alpha2 conversions
if err := s.AddConversionFunc((*dashv2alpha2.Dashboard)(nil), (*dashv0.Dashboard)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_V2alpha2_to_V0(a.(*dashv2alpha2.Dashboard), b.(*dashv0.Dashboard), scope)
}); err != nil {
return err
}
if err := s.AddConversionFunc((*dashv2alpha2.Dashboard)(nil), (*dashv1.Dashboard)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_V2alpha2_to_V1(a.(*dashv2alpha2.Dashboard), b.(*dashv1.Dashboard), scope)
}); err != nil {
return err
}
if err := s.AddConversionFunc((*dashv2alpha2.Dashboard)(nil), (*dashv2alpha1.Dashboard)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_V2alpha2_to_V2alpha1(a.(*dashv2alpha2.Dashboard), b.(*dashv2alpha1.Dashboard), scope)
}); err != nil {
return err
}
return nil
@@ -11,7 +11,8 @@ import (
dashv0 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1"
dashv1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v1beta1"
dashv2 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1"
dashv2alpha1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1"
dashv2alpha2 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2"
"github.com/grafana/grafana/apps/dashboard/pkg/migration"
"github.com/grafana/grafana/apps/dashboard/pkg/migration/testutil"
common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1"
@@ -25,7 +26,8 @@ func TestConversionMatrixExist(t *testing.T) {
versions := []v1.Object{
&dashv0.Dashboard{Spec: common.Unstructured{Object: map[string]any{"title": "dashboardV0"}}},
&dashv1.Dashboard{Spec: common.Unstructured{Object: map[string]any{"title": "dashboardV1"}}},
&dashv2.Dashboard{Spec: dashv2.DashboardSpec{Title: "dashboardV2"}},
&dashv2alpha1.Dashboard{Spec: dashv2alpha1.DashboardSpec{Title: "dashboardV2alpha1"}},
&dashv2alpha2.Dashboard{Spec: dashv2alpha2.DashboardSpec{Title: "dashboardV2alpha2"}},
}
scheme := runtime.NewScheme()
@@ -0,0 +1,78 @@
package conversion
import (
"k8s.io/apimachinery/pkg/conversion"
dashv0 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1"
dashv1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v1beta1"
dashv2alpha1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1"
dashv2alpha2 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2"
"github.com/grafana/grafana/apps/dashboard/pkg/migration"
"github.com/grafana/grafana/apps/dashboard/pkg/migration/schemaversion"
)
func Convert_V0_to_V1(in *dashv0.Dashboard, out *dashv1.Dashboard, scope conversion.Scope) error {
out.ObjectMeta = in.ObjectMeta
out.Spec.Object = in.Spec.Object
out.Status = dashv1.DashboardStatus{
Conversion: &dashv1.DashboardConversionStatus{
StoredVersion: dashv0.VERSION,
},
}
if err := migration.Migrate(out.Spec.Object, schemaversion.LATEST_VERSION); err != nil {
out.Status.Conversion.Failed = true
out.Status.Conversion.Error = err.Error()
}
return nil
}
func Convert_V0_to_V2alpha1(in *dashv0.Dashboard, out *dashv2alpha1.Dashboard, scope conversion.Scope) error {
out.ObjectMeta = in.ObjectMeta
// TODO (@radiohead): implement V0 to V2 conversion
// This is the bare minimum conversion that is needed to make the dashboard servable.
if v, ok := in.Spec.Object["title"]; ok {
if title, ok := v.(string); ok {
out.Spec.Title = title
}
}
// We need to make sure the layout is set to some value, otherwise the JSON marshaling will fail.
out.Spec.Layout = dashv2alpha1.DashboardGridLayoutKindOrRowsLayoutKindOrAutoGridLayoutKindOrTabsLayoutKind{
GridLayoutKind: &dashv2alpha1.DashboardGridLayoutKind{
Kind: "GridLayout",
Spec: dashv2alpha1.DashboardGridLayoutSpec{},
},
}
out.Status = dashv2alpha1.DashboardStatus{
Conversion: &dashv2alpha1.DashboardConversionStatus{
StoredVersion: dashv0.VERSION,
Failed: true,
Error: "backend conversion not yet implemented",
},
}
return nil
}
func Convert_V0_to_V2alpha2(in *dashv0.Dashboard, out *dashv2alpha2.Dashboard, scope conversion.Scope) error {
out.ObjectMeta = in.ObjectMeta
// TODO: implement V0 to V2alpha2 conversion
out.Status = dashv2alpha2.DashboardStatus{
Conversion: &dashv2alpha2.DashboardConversionStatus{
StoredVersion: dashv0.VERSION,
Failed: true,
Error: "backend conversion not yet implemented",
},
}
return nil
}
@@ -0,0 +1,71 @@
package conversion
import (
"k8s.io/apimachinery/pkg/conversion"
dashv0 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1"
dashv1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v1beta1"
dashv2alpha1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1"
dashv2alpha2 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2"
)
func Convert_V1_to_V0(in *dashv1.Dashboard, out *dashv0.Dashboard, scope conversion.Scope) error {
out.ObjectMeta = in.ObjectMeta
out.Spec.Object = in.Spec.Object
out.Status = dashv0.DashboardStatus{
Conversion: &dashv0.DashboardConversionStatus{
StoredVersion: dashv1.VERSION,
},
}
return nil
}
func Convert_V1_to_V2alpha1(in *dashv1.Dashboard, out *dashv2alpha1.Dashboard, scope conversion.Scope) error {
out.ObjectMeta = in.ObjectMeta
// TODO (@radiohead): implement V1 to V2 conversion
// This is the bare minimum conversion that is needed to make the dashboard servable.
if v, ok := in.Spec.Object["title"]; ok {
if title, ok := v.(string); ok {
out.Spec.Title = title
}
}
// We need to make sure the layout is set to some value, otherwise the JSON marshaling will fail.
out.Spec.Layout = dashv2alpha1.DashboardGridLayoutKindOrRowsLayoutKindOrAutoGridLayoutKindOrTabsLayoutKind{
GridLayoutKind: &dashv2alpha1.DashboardGridLayoutKind{
Kind: "GridLayout",
Spec: dashv2alpha1.DashboardGridLayoutSpec{},
},
}
out.Status = dashv2alpha1.DashboardStatus{
Conversion: &dashv2alpha1.DashboardConversionStatus{
StoredVersion: dashv1.VERSION,
Failed: true,
Error: "backend conversion not yet implemented",
},
}
return nil
}
func Convert_V1_to_V2alpha2(in *dashv1.Dashboard, out *dashv2alpha2.Dashboard, scope conversion.Scope) error {
out.ObjectMeta = in.ObjectMeta
// TODO: implement V1 to V2alpha2 conversion
out.Status = dashv2alpha2.DashboardStatus{
Conversion: &dashv2alpha2.DashboardConversionStatus{
StoredVersion: dashv1.VERSION,
Failed: true,
Error: "backend conversion not yet implemented",
},
}
return nil
}
@@ -0,0 +1,105 @@
package conversion
import (
"k8s.io/apimachinery/pkg/conversion"
dashv0 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1"
dashv1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v1beta1"
dashv2alpha1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1"
dashv2alpha2 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2"
)
func Convert_V2alpha1_to_V0(in *dashv2alpha1.Dashboard, out *dashv0.Dashboard, scope conversion.Scope) error {
out.ObjectMeta = in.ObjectMeta
// TODO: implement V2 to V0 conversion
out.Status = dashv0.DashboardStatus{
Conversion: &dashv0.DashboardConversionStatus{
StoredVersion: dashv2alpha1.VERSION,
Failed: true,
Error: "backend conversion not yet implemented",
},
}
return nil
}
func Convert_V2alpha1_to_V1(in *dashv2alpha1.Dashboard, out *dashv1.Dashboard, scope conversion.Scope) error {
out.ObjectMeta = in.ObjectMeta
// TODO: implement V2 to V1 conversion
out.Status = dashv1.DashboardStatus{
Conversion: &dashv1.DashboardConversionStatus{
StoredVersion: dashv2alpha1.VERSION,
Failed: true,
Error: "backend conversion not yet implemented",
},
}
return nil
}
func Convert_V2alpha1_to_V2alpha2(in *dashv2alpha1.Dashboard, out *dashv2alpha2.Dashboard, scope conversion.Scope) error {
out.ObjectMeta = in.ObjectMeta
// TODO: implement V2alpha1 to V2alpha2 conversion
out.Status = dashv2alpha2.DashboardStatus{
Conversion: &dashv2alpha2.DashboardConversionStatus{
StoredVersion: dashv2alpha1.VERSION,
Failed: true,
Error: "backend conversion not yet implemented",
},
}
return nil
}
func Convert_V2alpha2_to_V0(in *dashv2alpha2.Dashboard, out *dashv0.Dashboard, scope conversion.Scope) error {
out.ObjectMeta = in.ObjectMeta
// TODO: implement V2alpha2 to V0 conversion
out.Status = dashv0.DashboardStatus{
Conversion: &dashv0.DashboardConversionStatus{
StoredVersion: dashv2alpha2.VERSION,
Failed: true,
Error: "backend conversion not yet implemented",
},
}
return nil
}
func Convert_V2alpha2_to_V1(in *dashv2alpha2.Dashboard, out *dashv1.Dashboard, scope conversion.Scope) error {
out.ObjectMeta = in.ObjectMeta
// TODO: implement V2alpha2 to V1 conversion
out.Status = dashv1.DashboardStatus{
Conversion: &dashv1.DashboardConversionStatus{
StoredVersion: dashv2alpha2.VERSION,
Failed: true,
Error: "backend conversion not yet implemented",
},
}
return nil
}
func Convert_V2alpha2_to_V2alpha1(in *dashv2alpha2.Dashboard, out *dashv2alpha1.Dashboard, scope conversion.Scope) error {
out.ObjectMeta = in.ObjectMeta
// TODO: implement V2alpha2 to V2alpha1 conversion
out.Status = dashv2alpha1.DashboardStatus{
Conversion: &dashv2alpha1.DashboardConversionStatus{
StoredVersion: dashv2alpha2.VERSION,
Failed: true,
Error: "backend conversion not yet implemented",
},
}
return nil
}
@@ -0,0 +1,49 @@
/*
* This file was generated by grafana-app-sdk. DO NOT EDIT.
*/
import { Spec } from './types.spec.gen';
import { Status } from './types.status.gen';
export interface Metadata {
name: string;
namespace: string;
generateName?: string;
selfLink?: string;
uid?: string;
resourceVersion?: string;
generation?: number;
creationTimestamp?: string;
deletionTimestamp?: string;
deletionGracePeriodSeconds?: number;
labels?: Record<string, string>;
annotations?: Record<string, string>;
ownerReferences?: OwnerReference[];
finalizers?: string[];
managedFields?: ManagedFieldsEntry[];
}
export interface OwnerReference {
apiVersion: string;
kind: string;
name: string;
uid: string;
controller?: boolean;
blockOwnerDeletion?: boolean;
}
export interface ManagedFieldsEntry {
manager?: string;
operation?: string;
apiVersion?: string;
time?: string;
fieldsType?: string;
subresource?: string;
}
export interface Dashboard {
kind: string;
apiVersion: string;
metadata: Metadata;
spec: Spec;
status: Status;
}
@@ -0,0 +1,30 @@
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
// metadata contains embedded CommonMetadata and can be extended with custom string fields
// TODO: use CommonMetadata instead of redefining here; currently needs to be defined here
// without external reference as using the CommonMetadata reference breaks thema codegen.
export interface Metadata {
updateTimestamp: string;
createdBy: string;
uid: string;
creationTimestamp: string;
deletionTimestamp?: string;
finalizers: string[];
resourceVersion: string;
generation: number;
updatedBy: string;
labels: Record<string, string>;
}
export const defaultMetadata = (): Metadata => ({
updateTimestamp: "",
createdBy: "",
uid: "",
creationTimestamp: "",
finalizers: [],
resourceVersion: "",
generation: 0,
updatedBy: "",
labels: {},
});
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,30 @@
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
// ConversionStatus is the status of the conversion of the dashboard.
export interface ConversionStatus {
// Whether from another version has failed.
// If true, means that the dashboard is not valid,
// and the caller should instead fetch the stored version.
failed: boolean;
// The version which was stored when the dashboard was created / updated.
// Fetching this version should always succeed.
storedVersion: string;
// The error message from the conversion.
// Empty if the conversion has not failed.
error: string;
}
export const defaultConversionStatus = (): ConversionStatus => ({
failed: false,
storedVersion: "",
error: "",
});
export interface Status {
// Optional conversion status.
conversion?: ConversionStatus;
}
export const defaultStatus = (): Status => ({
});
+37 -9
View File
@@ -23,7 +23,8 @@ import (
internal "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard"
dashv0 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1"
dashv1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v1beta1"
dashv2 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1"
dashv2alpha1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1"
dashv2alpha2 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2"
"github.com/grafana/grafana/apps/dashboard/pkg/migration"
"github.com/grafana/grafana/apps/dashboard/pkg/migration/conversion"
"github.com/grafana/grafana/pkg/apimachinery/identity"
@@ -158,16 +159,18 @@ func (b *DashboardsAPIBuilder) GetGroupVersions() []schema.GroupVersion {
if featuremgmt.AnyEnabled(b.features, featuremgmt.FlagDashboardNewLayouts) {
// If dashboards v2 is enabled, we want to use v2alpha1 as the default API version.
return []schema.GroupVersion{
dashv2.DashboardResourceInfo.GroupVersion(),
dashv2alpha1.DashboardResourceInfo.GroupVersion(),
dashv0.DashboardResourceInfo.GroupVersion(),
dashv1.DashboardResourceInfo.GroupVersion(),
dashv2alpha2.DashboardResourceInfo.GroupVersion(),
}
}
return []schema.GroupVersion{
dashv1.DashboardResourceInfo.GroupVersion(),
dashv0.DashboardResourceInfo.GroupVersion(),
dashv2.DashboardResourceInfo.GroupVersion(),
dashv2alpha1.DashboardResourceInfo.GroupVersion(),
dashv2alpha2.DashboardResourceInfo.GroupVersion(),
}
}
@@ -179,7 +182,11 @@ func (b *DashboardsAPIBuilder) InstallSchema(scheme *runtime.Scheme) error {
if err := dashv1.AddToScheme(scheme); err != nil {
return err
}
if err := dashv2.AddToScheme(scheme); err != nil {
if err := dashv2alpha1.AddToScheme(scheme); err != nil {
return err
}
if err := dashv2alpha2.AddToScheme(scheme); err != nil {
return err
}
@@ -391,7 +398,10 @@ func getDashboardProperties(obj runtime.Object) (string, string, error) {
case *dashv1.Dashboard:
title = d.Spec.GetNestedString(dashboardSpecTitle)
refresh = d.Spec.GetNestedString(dashboardSpecRefreshInterval)
case *dashv2.Dashboard:
case *dashv2alpha1.Dashboard:
title = d.Spec.Title
refresh = d.Spec.TimeSettings.AutoRefresh
case *dashv2alpha2.Dashboard:
title = d.Spec.Title
refresh = d.Spec.TimeSettings.AutoRefresh
default:
@@ -456,11 +466,28 @@ func (b *DashboardsAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver
// v2alpha1
if err := b.storageForVersion(apiGroupInfo, opts, largeObjects,
dashv2.DashboardResourceInfo,
dashv2alpha1.DashboardResourceInfo,
nil, // do not register library panel
func(obj runtime.Object, access *internal.DashboardAccess) (v runtime.Object, err error) {
dto := &dashv2.DashboardWithAccessInfo{}
dash, ok := obj.(*dashv2.Dashboard)
dto := &dashv2alpha1.DashboardWithAccessInfo{}
dash, ok := obj.(*dashv2alpha1.Dashboard)
if ok {
dto.Dashboard = *dash
}
if access != nil {
err = b.scheme.Convert(access, &dto.Access, nil)
}
return dto, err
}); err != nil {
return err
}
if err := b.storageForVersion(apiGroupInfo, opts, largeObjects,
dashv2alpha2.DashboardResourceInfo,
nil, // do not register library panel
func(obj runtime.Object, access *internal.DashboardAccess) (v runtime.Object, err error) {
dto := &dashv2alpha2.DashboardWithAccessInfo{}
dash, ok := obj.(*dashv2alpha2.Dashboard)
if ok {
dto.Dashboard = *dash
}
@@ -544,7 +571,8 @@ func (b *DashboardsAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefiniti
return func(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition {
defs := dashv0.GetOpenAPIDefinitions(ref)
maps.Copy(defs, dashv1.GetOpenAPIDefinitions(ref))
maps.Copy(defs, dashv2.GetOpenAPIDefinitions(ref))
maps.Copy(defs, dashv2alpha1.GetOpenAPIDefinitions(ref))
maps.Copy(defs, dashv2alpha2.GetOpenAPIDefinitions(ref))
return defs
}
}
+8 -4
View File
@@ -13,7 +13,8 @@ import (
dashv0 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1"
dashv1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v1beta1"
dashv2 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1"
dashv2alpha1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1"
dashv2alpha2 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha2"
common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/featuremgmt"
@@ -176,7 +177,8 @@ func TestDashboardAPIBuilder_GetGroupVersions(t *testing.T) {
expected: []schema.GroupVersion{
dashv1.DashboardResourceInfo.GroupVersion(),
dashv0.DashboardResourceInfo.GroupVersion(),
dashv2.DashboardResourceInfo.GroupVersion(),
dashv2alpha1.DashboardResourceInfo.GroupVersion(),
dashv2alpha2.DashboardResourceInfo.GroupVersion(),
},
},
{
@@ -187,7 +189,8 @@ func TestDashboardAPIBuilder_GetGroupVersions(t *testing.T) {
expected: []schema.GroupVersion{
dashv1.DashboardResourceInfo.GroupVersion(),
dashv0.DashboardResourceInfo.GroupVersion(),
dashv2.DashboardResourceInfo.GroupVersion(),
dashv2alpha1.DashboardResourceInfo.GroupVersion(),
dashv2alpha2.DashboardResourceInfo.GroupVersion(),
},
},
{
@@ -196,9 +199,10 @@ func TestDashboardAPIBuilder_GetGroupVersions(t *testing.T) {
featuremgmt.FlagDashboardNewLayouts,
},
expected: []schema.GroupVersion{
dashv2.DashboardResourceInfo.GroupVersion(),
dashv2alpha1.DashboardResourceInfo.GroupVersion(),
dashv0.DashboardResourceInfo.GroupVersion(),
dashv1.DashboardResourceInfo.GroupVersion(),
dashv2alpha2.DashboardResourceInfo.GroupVersion(),
},
},
}