mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
schema: Finish converting dashboard schema datasource references to objects (#47806)
* coremodel: finish string -> object datasource ref Seems we missed updating a couple of the datasource references from strings to objects. * cue fmt * Also fix dashboard in scuemata dashboard schema * Update devenv/dev-dashboards/panel-graph/graph-ng-stacking2.json Co-authored-by: Ryan McKinley <ryantxu@gmail.com> Co-authored-by: Ryan McKinley <ryantxu@gmail.com>
This commit is contained in:
parent
031a8e140a
commit
5e11af0121
@ -68,7 +68,7 @@ func themaTestableDashboards() (map[string][]byte, error) {
|
||||
|
||||
jtree := make(map[string]interface{})
|
||||
json.Unmarshal(b, &jtree)
|
||||
if oldschemav, has := jtree["schemaVersion"]; !has || !(oldschemav.(float64) > 32) {
|
||||
if oldschemav, has := jtree["schemaVersion"]; !has || !(oldschemav.(float64) > dashboard.HandoffSchemaVersion-1) {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -71,8 +71,7 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@ -178,8 +177,7 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@ -266,8 +264,7 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@ -354,8 +351,7 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@ -485,8 +481,7 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@ -573,8 +568,7 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@ -661,8 +655,7 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@ -792,8 +785,7 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@ -893,8 +885,7 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@ -982,8 +973,7 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@ -1069,8 +1059,7 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@ -1155,8 +1144,7 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@ -1253,8 +1241,7 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@ -1354,8 +1341,7 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@ -1455,8 +1441,7 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@ -1555,8 +1540,7 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@ -1692,8 +1676,7 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@ -1800,8 +1783,7 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@ -1909,8 +1891,7 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@ -2040,8 +2021,7 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@ -2128,8 +2108,7 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@ -2240,8 +2219,7 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@ -2356,8 +2334,7 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@ -2460,8 +2437,7 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@ -2564,8 +2540,7 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@ -2701,8 +2676,7 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@ -2838,8 +2812,7 @@
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@ -2934,7 +2907,7 @@
|
||||
}
|
||||
],
|
||||
"refresh": false,
|
||||
"schemaVersion": 32,
|
||||
"schemaVersion": 36,
|
||||
"style": "dark",
|
||||
"tags": [
|
||||
"gdev",
|
||||
@ -2954,4 +2927,4 @@
|
||||
"uid": "1KxMUdE7k",
|
||||
"version": 1,
|
||||
"weekStart": ""
|
||||
}
|
||||
}
|
||||
|
@ -1,434 +1,441 @@
|
||||
package dashboard
|
||||
|
||||
import (
|
||||
"list"
|
||||
"list"
|
||||
|
||||
"github.com/grafana/grafana/cue/scuemata"
|
||||
"github.com/grafana/grafana/cue/scuemata"
|
||||
)
|
||||
|
||||
Family: scuemata.#Family & {
|
||||
lineages: [
|
||||
[
|
||||
{ // 0.0
|
||||
// Unique numeric identifier for the dashboard.
|
||||
// TODO must isolate or remove identifiers local to a Grafana instance...?
|
||||
id?: number
|
||||
// Unique dashboard identifier that can be generated by anyone. string (8-40)
|
||||
uid?: string
|
||||
// Title of dashboard.
|
||||
title?: string
|
||||
// Description of dashboard.
|
||||
description?: string
|
||||
{// 0.0
|
||||
// Unique numeric identifier for the dashboard.
|
||||
// TODO must isolate or remove identifiers local to a Grafana instance...?
|
||||
id?: number
|
||||
// Unique dashboard identifier that can be generated by anyone. string (8-40)
|
||||
uid?: string
|
||||
// Title of dashboard.
|
||||
title?: string
|
||||
// Description of dashboard.
|
||||
description?: string
|
||||
|
||||
gnetId?: string
|
||||
// Tags associated with dashboard.
|
||||
tags?: [...string]
|
||||
// Theme of dashboard.
|
||||
style: *"light" | "dark"
|
||||
// Timezone of dashboard,
|
||||
timezone?: *"browser" | "utc" | ""
|
||||
// Whether a dashboard is editable or not.
|
||||
editable: bool | *true
|
||||
// 0 for no shared crosshair or tooltip (default).
|
||||
// 1 for shared crosshair.
|
||||
// 2 for shared crosshair AND shared tooltip.
|
||||
graphTooltip: >=0 & <=2 | *0
|
||||
// Time range for dashboard, e.g. last 6 hours, last 7 days, etc
|
||||
time?: {
|
||||
from: string | *"now-6h"
|
||||
to: string | *"now"
|
||||
}
|
||||
// Timepicker metadata.
|
||||
timepicker?: {
|
||||
// Whether timepicker is collapsed or not.
|
||||
collapse: bool | *false
|
||||
// Whether timepicker is enabled or not.
|
||||
enable: bool | *true
|
||||
// Whether timepicker is visible or not.
|
||||
hidden: bool | *false
|
||||
// Selectable intervals for auto-refresh.
|
||||
refresh_intervals: [...string] | *["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"]
|
||||
}
|
||||
// Templating.
|
||||
templating?: list: [...{...}]
|
||||
// Annotations.
|
||||
annotations?: list: [...{
|
||||
builtIn: number | *0
|
||||
// Datasource to use for annotation.
|
||||
datasource: string
|
||||
// Whether annotation is enabled.
|
||||
enable: bool | *true
|
||||
// Whether to hide annotation.
|
||||
hide?: bool | *false
|
||||
// Annotation icon color.
|
||||
iconColor?: string
|
||||
// Name of annotation.
|
||||
name?: string
|
||||
type: string | *"dashboard"
|
||||
// Query for annotation data.
|
||||
rawQuery?: string
|
||||
showIn: number | *0
|
||||
}]
|
||||
// Auto-refresh interval.
|
||||
refresh?: string | false
|
||||
// Version of the JSON schema, incremented each time a Grafana update brings
|
||||
// changes to said schema.
|
||||
// FIXME this is the old schema numbering system, and will be replaced by scuemata
|
||||
schemaVersion: number | *30
|
||||
// Version of the dashboard, incremented each time the dashboard is updated.
|
||||
version?: number
|
||||
panels?: [...(#Panel | #GraphPanel | #RowPanel)]
|
||||
gnetId?: string
|
||||
// Tags associated with dashboard.
|
||||
tags?: [...string]
|
||||
// Theme of dashboard.
|
||||
style: *"light" | "dark"
|
||||
// Timezone of dashboard,
|
||||
timezone?: *"browser" | "utc" | ""
|
||||
// Whether a dashboard is editable or not.
|
||||
editable: bool | *true
|
||||
// 0 for no shared crosshair or tooltip (default).
|
||||
// 1 for shared crosshair.
|
||||
// 2 for shared crosshair AND shared tooltip.
|
||||
graphTooltip: >=0 & <=2 | *0
|
||||
// Time range for dashboard, e.g. last 6 hours, last 7 days, etc
|
||||
time?: {
|
||||
from: string | *"now-6h"
|
||||
to: string | *"now"
|
||||
}
|
||||
// Timepicker metadata.
|
||||
timepicker?: {
|
||||
// Whether timepicker is collapsed or not.
|
||||
collapse: bool | *false
|
||||
// Whether timepicker is enabled or not.
|
||||
enable: bool | *true
|
||||
// Whether timepicker is visible or not.
|
||||
hidden: bool | *false
|
||||
// Selectable intervals for auto-refresh.
|
||||
refresh_intervals: [...string] | *["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"]
|
||||
}
|
||||
// Templating.
|
||||
templating?: list: [...{...}]
|
||||
// Annotations.
|
||||
annotations?: list: [...{
|
||||
builtIn: number | *0
|
||||
// Datasource to use for annotation.
|
||||
datasource: {
|
||||
type?: string
|
||||
uid?: string
|
||||
}
|
||||
// Whether annotation is enabled.
|
||||
enable: bool | *true
|
||||
// Whether to hide annotation.
|
||||
hide?: bool | *false
|
||||
// Annotation icon color.
|
||||
iconColor?: string
|
||||
// Name of annotation.
|
||||
name?: string
|
||||
type: string | *"dashboard"
|
||||
// Query for annotation data.
|
||||
rawQuery?: string
|
||||
showIn: number | *0
|
||||
}]
|
||||
// Auto-refresh interval.
|
||||
refresh?: string | false
|
||||
// Version of the JSON schema, incremented each time a Grafana update brings
|
||||
// changes to said schema.
|
||||
// FIXME this is the old schema numbering system, and will be replaced by scuemata
|
||||
schemaVersion: number | *30
|
||||
// Version of the dashboard, incremented each time the dashboard is updated.
|
||||
version?: number
|
||||
panels?: [...(#Panel | #GraphPanel | #RowPanel)]
|
||||
|
||||
// TODO docs
|
||||
#FieldColorModeId: "thresholds" | "palette-classic" | "palette-saturated" | "continuous-GrYlRd" | "fixed" @cuetsy(kind="enum")
|
||||
// TODO docs
|
||||
#FieldColorModeId: "thresholds" | "palette-classic" | "palette-saturated" | "continuous-GrYlRd" | "fixed" @cuetsy(kind="enum")
|
||||
|
||||
// TODO docs
|
||||
#FieldColorSeriesByMode: "min" | "max" | "last" @cuetsy(kind="type")
|
||||
// TODO docs
|
||||
#FieldColorSeriesByMode: "min" | "max" | "last" @cuetsy(kind="type")
|
||||
|
||||
// TODO docs
|
||||
#FieldColor: {
|
||||
// The main color scheme mode
|
||||
mode: #FieldColorModeId | string
|
||||
// Stores the fixed color value if mode is fixed
|
||||
fixedColor?: string
|
||||
// Some visualizations need to know how to assign a series color from by value color schemes
|
||||
seriesBy?: #FieldColorSeriesByMode
|
||||
} @cuetsy(kind="interface")
|
||||
// TODO docs
|
||||
#FieldColor: {
|
||||
// The main color scheme mode
|
||||
mode: #FieldColorModeId | string
|
||||
// Stores the fixed color value if mode is fixed
|
||||
fixedColor?: string
|
||||
// Some visualizations need to know how to assign a series color from by value color schemes
|
||||
seriesBy?: #FieldColorSeriesByMode
|
||||
} @cuetsy(kind="interface")
|
||||
|
||||
// TODO docs
|
||||
#Threshold: {
|
||||
// TODO docs
|
||||
// FIXME the corresponding typescript field is required/non-optional, but nulls currently appear here when serializing -Infinity to JSON
|
||||
value?: number
|
||||
// TODO docs
|
||||
color: string
|
||||
// TODO docs
|
||||
// TODO are the values here enumerable into a disjunction?
|
||||
// Some seem to be listed in typescript comment
|
||||
state?: string
|
||||
} @cuetsy(kind="interface")
|
||||
// TODO docs
|
||||
#Threshold: {
|
||||
// TODO docs
|
||||
// FIXME the corresponding typescript field is required/non-optional, but nulls currently appear here when serializing -Infinity to JSON
|
||||
value?: number
|
||||
// TODO docs
|
||||
color: string
|
||||
// TODO docs
|
||||
// TODO are the values here enumerable into a disjunction?
|
||||
// Some seem to be listed in typescript comment
|
||||
state?: string
|
||||
} @cuetsy(kind="interface")
|
||||
|
||||
#ThresholdsMode: "absolute" | "percentage" @cuetsy(kind="enum")
|
||||
#ThresholdsMode: "absolute" | "percentage" @cuetsy(kind="enum")
|
||||
|
||||
#ThresholdsConfig: {
|
||||
mode: #ThresholdsMode
|
||||
#ThresholdsConfig: {
|
||||
mode: #ThresholdsMode
|
||||
|
||||
// Must be sorted by 'value', first value is always -Infinity
|
||||
steps: [...#Threshold]
|
||||
} @cuetsy(kind="interface")
|
||||
// Must be sorted by 'value', first value is always -Infinity
|
||||
steps: [...#Threshold]
|
||||
} @cuetsy(kind="interface")
|
||||
|
||||
// TODO docs
|
||||
// FIXME this is extremely underspecfied; wasn't obvious which typescript types corresponded to it
|
||||
#Transformation: {
|
||||
id: string
|
||||
options: {...}
|
||||
}
|
||||
// TODO docs
|
||||
// FIXME this is extremely underspecfied; wasn't obvious which typescript types corresponded to it
|
||||
#Transformation: {
|
||||
id: string
|
||||
options: {...}
|
||||
}
|
||||
|
||||
// Schema for panel targets is specified by datasource
|
||||
// plugins. We use a placeholder definition, which the Go
|
||||
// schema loader either left open/as-is with the Base
|
||||
// variant of the Dashboard and Panel families, or filled
|
||||
// with types derived from plugins in the Instance variant.
|
||||
// When working directly from CUE, importers can extend this
|
||||
// type directly to achieve the same effect.
|
||||
#Target: {...}
|
||||
// Schema for panel targets is specified by datasource
|
||||
// plugins. We use a placeholder definition, which the Go
|
||||
// schema loader either left open/as-is with the Base
|
||||
// variant of the Dashboard and Panel families, or filled
|
||||
// with types derived from plugins in the Instance variant.
|
||||
// When working directly from CUE, importers can extend this
|
||||
// type directly to achieve the same effect.
|
||||
#Target: {...}
|
||||
|
||||
// Dashboard panels. Panels are canonically defined inline
|
||||
// because they share a version timeline with the dashboard
|
||||
// schema; they do not evolve independently.
|
||||
#Panel: {
|
||||
// The panel plugin type id.
|
||||
type: !=""
|
||||
// Dashboard panels. Panels are canonically defined inline
|
||||
// because they share a version timeline with the dashboard
|
||||
// schema; they do not evolve independently.
|
||||
#Panel: {
|
||||
// The panel plugin type id.
|
||||
type: !=""
|
||||
|
||||
// TODO docs
|
||||
id?: number
|
||||
// TODO docs
|
||||
id?: number
|
||||
|
||||
// FIXME this almost certainly has to be changed in favor of scuemata versions
|
||||
pluginVersion?: string
|
||||
// FIXME this almost certainly has to be changed in favor of scuemata versions
|
||||
pluginVersion?: string
|
||||
|
||||
// TODO docs
|
||||
tags?: [...string]
|
||||
// TODO docs
|
||||
tags?: [...string]
|
||||
|
||||
// Internal - the exact major and minor versions of the panel plugin
|
||||
// schema. Hidden and therefore not a part of the data model, but
|
||||
// expected to be filled with panel plugin schema versions so that it's
|
||||
// possible to figure out which schema version matched on a successful
|
||||
// unification.
|
||||
// _pv: { maj: int, min: int }
|
||||
// The major and minor versions of the panel plugin for this schema.
|
||||
// TODO 2-tuple list instead of struct?
|
||||
// panelSchema?: { maj: number, min: number }
|
||||
panelSchema?: [number, number]
|
||||
// Internal - the exact major and minor versions of the panel plugin
|
||||
// schema. Hidden and therefore not a part of the data model, but
|
||||
// expected to be filled with panel plugin schema versions so that it's
|
||||
// possible to figure out which schema version matched on a successful
|
||||
// unification.
|
||||
// _pv: { maj: int, min: int }
|
||||
// The major and minor versions of the panel plugin for this schema.
|
||||
// TODO 2-tuple list instead of struct?
|
||||
// panelSchema?: { maj: number, min: number }
|
||||
panelSchema?: [number, number]
|
||||
|
||||
// TODO docs
|
||||
targets?: [...#Target]
|
||||
// TODO docs
|
||||
targets?: [...#Target]
|
||||
|
||||
// Panel title.
|
||||
title?: string
|
||||
// Description.
|
||||
description?: string
|
||||
// Whether to display the panel without a background.
|
||||
transparent: bool | *false
|
||||
// The datasource used in all targets.
|
||||
datasource?: {
|
||||
type?: string
|
||||
uid?: string
|
||||
}
|
||||
// Grid position.
|
||||
gridPos?: {
|
||||
// Panel
|
||||
h: number & >0 | *9
|
||||
// Panel
|
||||
w: number & >0 & <=24 | *12
|
||||
// Panel x
|
||||
x: number & >=0 & <24 | *0
|
||||
// Panel y
|
||||
y: number & >=0 | *0
|
||||
// true if fixed
|
||||
static?: bool
|
||||
}
|
||||
// Panel links.
|
||||
// FIXME this is temporarily specified as a closed list so
|
||||
// that validation will pass when no links are present, but
|
||||
// to force a failure as soon as it's checked against there
|
||||
// being anything in the list so it can be fixed in
|
||||
// accordance with that object
|
||||
links?: []
|
||||
// Panel title.
|
||||
title?: string
|
||||
// Description.
|
||||
description?: string
|
||||
// Whether to display the panel without a background.
|
||||
transparent: bool | *false
|
||||
// The datasource used in all targets.
|
||||
datasource?: {
|
||||
type?: string
|
||||
uid?: string
|
||||
}
|
||||
// Grid position.
|
||||
gridPos?: {
|
||||
// Panel
|
||||
h: number & >0 | *9
|
||||
// Panel
|
||||
w: number & >0 & <=24 | *12
|
||||
// Panel x
|
||||
x: number & >=0 & <24 | *0
|
||||
// Panel y
|
||||
y: number & >=0 | *0
|
||||
// true if fixed
|
||||
static?: bool
|
||||
}
|
||||
// Panel links.
|
||||
// FIXME this is temporarily specified as a closed list so
|
||||
// that validation will pass when no links are present, but
|
||||
// to force a failure as soon as it's checked against there
|
||||
// being anything in the list so it can be fixed in
|
||||
// accordance with that object
|
||||
links?: []
|
||||
|
||||
// Name of template variable to repeat for.
|
||||
repeat?: string
|
||||
// Direction to repeat in if 'repeat' is set.
|
||||
// "h" for horizontal, "v" for vertical.
|
||||
repeatDirection: *"h" | "v"
|
||||
// Name of template variable to repeat for.
|
||||
repeat?: string
|
||||
// Direction to repeat in if 'repeat' is set.
|
||||
// "h" for horizontal, "v" for vertical.
|
||||
repeatDirection: *"h" | "v"
|
||||
|
||||
// TODO docs
|
||||
maxDataPoints?: number
|
||||
// TODO docs
|
||||
maxDataPoints?: number
|
||||
|
||||
// TODO docs
|
||||
thresholds?: [...]
|
||||
// TODO docs
|
||||
thresholds?: [...]
|
||||
|
||||
// TODO docs
|
||||
timeRegions?: [...]
|
||||
// TODO docs
|
||||
timeRegions?: [...]
|
||||
|
||||
transformations: [...#Transformation]
|
||||
transformations: [...#Transformation]
|
||||
|
||||
// TODO docs
|
||||
// TODO tighter constraint
|
||||
interval?: string
|
||||
// TODO docs
|
||||
// TODO tighter constraint
|
||||
interval?: string
|
||||
|
||||
// TODO docs
|
||||
// TODO tighter constraint
|
||||
timeFrom?: string
|
||||
// TODO docs
|
||||
// TODO tighter constraint
|
||||
timeFrom?: string
|
||||
|
||||
// TODO docs
|
||||
// TODO tighter constraint
|
||||
timeShift?: string
|
||||
// TODO docs
|
||||
// TODO tighter constraint
|
||||
timeShift?: string
|
||||
|
||||
// options is specified by the PanelOptions field in panel
|
||||
// plugin schemas.
|
||||
options: {}
|
||||
// options is specified by the PanelOptions field in panel
|
||||
// plugin schemas.
|
||||
options: {}
|
||||
|
||||
fieldConfig: {
|
||||
defaults: {
|
||||
// The display value for this field. This supports template variables blank is auto
|
||||
displayName?: string
|
||||
fieldConfig: {
|
||||
defaults: {
|
||||
// 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
|
||||
// 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
|
||||
// Human readable field metadata
|
||||
description?: string
|
||||
|
||||
// An explict 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
|
||||
// An explict 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 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
|
||||
// True if data source field supports ad-hoc filters
|
||||
filterable?: bool
|
||||
|
||||
// Numeric Options
|
||||
unit?: string
|
||||
// Numeric Options
|
||||
unit?: string
|
||||
|
||||
// Significant digits (for display)
|
||||
decimals?: number
|
||||
// Significant digits (for display)
|
||||
decimals?: number
|
||||
|
||||
min?: number
|
||||
max?: number
|
||||
min?: number
|
||||
max?: number
|
||||
|
||||
// Convert input values into a display string
|
||||
//
|
||||
// TODO this one corresponds to a complex type with
|
||||
// generics on the typescript side. Ouch. Will
|
||||
// either need special care, or we'll just need to
|
||||
// accept a very loosely specified schema. It's very
|
||||
// unlikely we'll be able to translate cue to
|
||||
// typescript generics in the general case, though
|
||||
// this particular one *may* be able to work.
|
||||
mappings?: [...{...}]
|
||||
// Convert input values into a display string
|
||||
//
|
||||
// TODO this one corresponds to a complex type with
|
||||
// generics on the typescript side. Ouch. Will
|
||||
// either need special care, or we'll just need to
|
||||
// accept a very loosely specified schema. It's very
|
||||
// unlikely we'll be able to translate cue to
|
||||
// typescript generics in the general case, though
|
||||
// this particular one *may* be able to work.
|
||||
mappings?: [...{...}]
|
||||
|
||||
// Map numeric values to states
|
||||
thresholds?: #ThresholdsConfig
|
||||
// Map numeric values to states
|
||||
thresholds?: #ThresholdsConfig
|
||||
|
||||
// // Map values to a display color
|
||||
color?: #FieldColor
|
||||
// // Map values to a display color
|
||||
color?: #FieldColor
|
||||
|
||||
// // Used when reducing field values
|
||||
// nullValueMode?: NullValueMode
|
||||
// // Used when reducing field values
|
||||
// nullValueMode?: NullValueMode
|
||||
|
||||
// // The behavior when clicking on a result
|
||||
links?: [...]
|
||||
// // The behavior when clicking on a result
|
||||
links?: [...]
|
||||
|
||||
// Alternative to empty string
|
||||
noValue?: string
|
||||
// Alternative to empty string
|
||||
noValue?: string
|
||||
|
||||
// custom is specified by the PanelFieldConfig field
|
||||
// in panel plugin schemas.
|
||||
custom?: {}
|
||||
}
|
||||
overrides: [...{
|
||||
matcher: {
|
||||
id: string | *""
|
||||
options?: _
|
||||
}
|
||||
properties: [...{
|
||||
id: string | *""
|
||||
value?: _
|
||||
}]
|
||||
}]
|
||||
}
|
||||
// Embed the disjunction of all injected panel schema, if any were injected.
|
||||
if len(compose._panelSchemas) > 0 {
|
||||
or(compose._panelSchemas) // TODO try to stick graph in here
|
||||
}
|
||||
// custom is specified by the PanelFieldConfig field
|
||||
// in panel plugin schemas.
|
||||
custom?: {}
|
||||
}
|
||||
overrides: [...{
|
||||
matcher: {
|
||||
id: string | *""
|
||||
options?: _
|
||||
}
|
||||
properties: [...{
|
||||
id: string | *""
|
||||
value?: _
|
||||
}]
|
||||
}]
|
||||
}
|
||||
// Embed the disjunction of all injected panel schema, if any were injected.
|
||||
if len(compose._panelSchemas) > 0 {
|
||||
or(compose._panelSchemas)// TODO try to stick graph in here
|
||||
}
|
||||
|
||||
// Make the plugin-composed subtrees open if the panel is
|
||||
// of unknown types. This is important in every possible case:
|
||||
// - Base (this file only): no real dashboard json
|
||||
// containing any panels would ever validate
|
||||
// - Dist (this file + core plugin schema): dashboard json containing
|
||||
// panels with any third-party panel plugins would fail to validate,
|
||||
// as well as any core plugins lacking a models.cue. The latter case
|
||||
// is not normally expected, but this is not the appropriate place
|
||||
// to enforce the invariant, anyway.
|
||||
// - Instance (this file + core + third-party plugin schema): dashboard
|
||||
// json containing panels with a third-party plugin that exists but
|
||||
// is not currently installed would fail to validate.
|
||||
if !list.Contains(compose._panelTypes, type) {
|
||||
options: {...}
|
||||
fieldConfig: defaults: custom: {...}
|
||||
...
|
||||
}
|
||||
}
|
||||
// Make the plugin-composed subtrees open if the panel is
|
||||
// of unknown types. This is important in every possible case:
|
||||
// - Base (this file only): no real dashboard json
|
||||
// containing any panels would ever validate
|
||||
// - Dist (this file + core plugin schema): dashboard json containing
|
||||
// panels with any third-party panel plugins would fail to validate,
|
||||
// as well as any core plugins lacking a models.cue. The latter case
|
||||
// is not normally expected, but this is not the appropriate place
|
||||
// to enforce the invariant, anyway.
|
||||
// - Instance (this file + core + third-party plugin schema): dashboard
|
||||
// json containing panels with a third-party plugin that exists but
|
||||
// is not currently installed would fail to validate.
|
||||
if !list.Contains(compose._panelTypes, type) {
|
||||
options: {...}
|
||||
fieldConfig: defaults: custom: {...}
|
||||
...
|
||||
}
|
||||
}
|
||||
|
||||
// Row panel
|
||||
#RowPanel: {
|
||||
type: "row"
|
||||
collapsed: bool | *false
|
||||
title?: string
|
||||
// Row panel
|
||||
#RowPanel: {
|
||||
type: "row"
|
||||
collapsed: bool | *false
|
||||
title?: string
|
||||
|
||||
// Name of default datasource.
|
||||
datasource?: string
|
||||
// Name of default datasource.
|
||||
datasource: {
|
||||
type?: string
|
||||
uid?: string
|
||||
}
|
||||
|
||||
gridPos?: {
|
||||
// Panel
|
||||
h: number & >0 | *9
|
||||
// Panel
|
||||
w: number & >0 & <=24 | *12
|
||||
// Panel x
|
||||
x: number & >=0 & <24 | *0
|
||||
// Panel y
|
||||
y: number & >=0 | *0
|
||||
// true if fixed
|
||||
static?: bool
|
||||
}
|
||||
id: number
|
||||
panels: [...(#Panel | #GraphPanel)]
|
||||
// Name of template variable to repeat for.
|
||||
repeat?: string
|
||||
}
|
||||
// Support for legacy graph panels.
|
||||
#GraphPanel: {
|
||||
...
|
||||
type: "graph"
|
||||
thresholds: [...{...}]
|
||||
timeRegions?: [...{...}]
|
||||
seriesOverrides: [...{...}]
|
||||
aliasColors?: [string]: string
|
||||
bars: bool | *false
|
||||
dashes: bool | *false
|
||||
dashLength: number | *10
|
||||
fill?: number
|
||||
fillGradient?: number
|
||||
hiddenSeries: bool | *false
|
||||
legend: {...}
|
||||
lines: bool | *false
|
||||
linewidth?: number
|
||||
nullPointMode: *"null" | "connected" | "null as zero"
|
||||
percentage: bool | *false
|
||||
points: bool | *false
|
||||
pointradius?: number
|
||||
renderer: string
|
||||
spaceLength: number | *10
|
||||
stack: bool | *false
|
||||
steppedLine: bool | *false
|
||||
tooltip?: {
|
||||
shared?: bool
|
||||
sort: number | *0
|
||||
value_type: *"individual" | "cumulative"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
gridPos?: {
|
||||
// Panel
|
||||
h: number & >0 | *9
|
||||
// Panel
|
||||
w: number & >0 & <=24 | *12
|
||||
// Panel x
|
||||
x: number & >=0 & <24 | *0
|
||||
// Panel y
|
||||
y: number & >=0 | *0
|
||||
// true if fixed
|
||||
static?: bool
|
||||
}
|
||||
id: number
|
||||
panels: [...(#Panel | #GraphPanel)]
|
||||
// Name of template variable to repeat for.
|
||||
repeat?: string
|
||||
}
|
||||
|
||||
// Support for legacy graph panels.
|
||||
#GraphPanel: {
|
||||
...
|
||||
type: "graph"
|
||||
thresholds: [...{...}]
|
||||
timeRegions?: [...{...}]
|
||||
seriesOverrides: [...{...}]
|
||||
aliasColors?: [string]: string
|
||||
bars: bool | *false
|
||||
dashes: bool | *false
|
||||
dashLength: number | *10
|
||||
fill?: number
|
||||
fillGradient?: number
|
||||
hiddenSeries: bool | *false
|
||||
legend: {...}
|
||||
lines: bool | *false
|
||||
linewidth?: number
|
||||
nullPointMode: *"null" | "connected" | "null as zero"
|
||||
percentage: bool | *false
|
||||
points: bool | *false
|
||||
pointradius?: number
|
||||
renderer: string
|
||||
spaceLength: number | *10
|
||||
stack: bool | *false
|
||||
steppedLine: bool | *false
|
||||
tooltip?: {
|
||||
shared?: bool
|
||||
sort: number | *0
|
||||
value_type: *"individual" | "cumulative"
|
||||
}
|
||||
}
|
||||
},
|
||||
],
|
||||
]
|
||||
compose: {
|
||||
// Scuemata families for all panel types that should be composed into the
|
||||
// dashboard schema.
|
||||
Panel: [string]: scuemata.#PanelFamily
|
||||
compose: {
|
||||
// Scuemata families for all panel types that should be composed into the
|
||||
// dashboard schema.
|
||||
Panel: [string]: scuemata.#PanelFamily
|
||||
|
||||
// _panelTypes: [for typ, _ in Panel {typ}]
|
||||
_panelTypes: [for typ, _ in Panel {typ}, "graph", "row"]
|
||||
_panelSchemas: [for typ, scue in Panel {
|
||||
for lv, lin in scue.lineages {
|
||||
for sv, sch in lin {
|
||||
(_mapPanel & {arg: {
|
||||
type: typ
|
||||
v: [lv, sv] // TODO add optionality for exact, at least, at most, any
|
||||
model: sch // TODO Does this need to be close()d?
|
||||
}}).out
|
||||
}
|
||||
}
|
||||
}, { type: string }]
|
||||
_mapPanel: {
|
||||
arg: {
|
||||
type: string & !=""
|
||||
v: [number, number]
|
||||
model: {...}
|
||||
}
|
||||
// Until CUE introduces the must() constraint, we have to enforce
|
||||
// that the input model is as expected by checking for unification
|
||||
// in this hidden property (see https://github.com/cue-lang/cue/issues/575).
|
||||
// If we unified arg.model with the scuemata.#PanelSchema
|
||||
// meta-schema directly, the struct openness (PanelOptions: {...})
|
||||
// would be applied to the actual schema instance in the arg. Here,
|
||||
// where we're actually putting those in the dashboard schema, want
|
||||
// those to be closed, or at least preserve closed-ness.
|
||||
_checkSchema: scuemata.#PanelSchema & arg.model
|
||||
out: {
|
||||
type: arg.type
|
||||
panelSchema: arg.v // TODO add optionality for exact, at least, at most, any
|
||||
options: arg.model.PanelOptions
|
||||
fieldConfig: defaults: custom: {}
|
||||
if arg.model.PanelFieldConfig != _|_ {
|
||||
fieldConfig: defaults: custom: arg.model.PanelFieldConfig
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// _panelTypes: [for typ, _ in Panel {typ}]
|
||||
_panelTypes: [ for typ, _ in Panel {typ}, "graph", "row"]
|
||||
_panelSchemas: [ for typ, scue in Panel {
|
||||
for lv, lin in scue.lineages {
|
||||
for sv, sch in lin {
|
||||
(_mapPanel & {arg: {
|
||||
type: typ
|
||||
v: [lv, sv] // TODO add optionality for exact, at least, at most, any
|
||||
model: sch // TODO Does this need to be close()d?
|
||||
}}).out
|
||||
}
|
||||
}
|
||||
}, {type: string}]
|
||||
_mapPanel: {
|
||||
arg: {
|
||||
type: string & !=""
|
||||
v: [number, number]
|
||||
model: {...}
|
||||
}
|
||||
// Until CUE introduces the must() constraint, we have to enforce
|
||||
// that the input model is as expected by checking for unification
|
||||
// in this hidden property (see https://github.com/cue-lang/cue/issues/575).
|
||||
// If we unified arg.model with the scuemata.#PanelSchema
|
||||
// meta-schema directly, the struct openness (PanelOptions: {...})
|
||||
// would be applied to the actual schema instance in the arg. Here,
|
||||
// where we're actually putting those in the dashboard schema, want
|
||||
// those to be closed, or at least preserve closed-ness.
|
||||
_checkSchema: scuemata.#PanelSchema & arg.model
|
||||
out: {
|
||||
type: arg.type
|
||||
panelSchema: arg.v // TODO add optionality for exact, at least, at most, any
|
||||
options: arg.model.PanelOptions
|
||||
fieldConfig: defaults: custom: {}
|
||||
if arg.model.PanelFieldConfig != _|_ {
|
||||
fieldConfig: defaults: custom: arg.model.PanelFieldConfig
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,338 +7,345 @@ name: "dashboard"
|
||||
seqs: [
|
||||
{
|
||||
schemas: [
|
||||
{ // 0.0
|
||||
// Unique numeric identifier for the dashboard.
|
||||
// TODO must isolate or remove identifiers local to a Grafana instance...?
|
||||
id?: int64
|
||||
// Unique dashboard identifier that can be generated by anyone. string (8-40)
|
||||
uid?: string
|
||||
// Title of dashboard.
|
||||
title?: string
|
||||
// Description of dashboard.
|
||||
description?: string
|
||||
{// 0.0
|
||||
// Unique numeric identifier for the dashboard.
|
||||
// TODO must isolate or remove identifiers local to a Grafana instance...?
|
||||
id?: int64
|
||||
// Unique dashboard identifier that can be generated by anyone. string (8-40)
|
||||
uid?: string
|
||||
// Title of dashboard.
|
||||
title?: string
|
||||
// Description of dashboard.
|
||||
description?: string
|
||||
|
||||
gnetId?: string
|
||||
// Tags associated with dashboard.
|
||||
tags?: [...string]
|
||||
// Theme of dashboard.
|
||||
style: *"light" | "dark"
|
||||
// Timezone of dashboard,
|
||||
timezone?: *"browser" | "utc" | ""
|
||||
// Whether a dashboard is editable or not.
|
||||
editable: bool | *true
|
||||
// 0 for no shared crosshair or tooltip (default).
|
||||
// 1 for shared crosshair.
|
||||
// 2 for shared crosshair AND shared tooltip.
|
||||
graphTooltip: uint8 & >=0 & <=2 | *0
|
||||
// Time range for dashboard, e.g. last 6 hours, last 7 days, etc
|
||||
time?: {
|
||||
from: string | *"now-6h"
|
||||
to: string | *"now"
|
||||
}
|
||||
// Timepicker metadata.
|
||||
timepicker?: {
|
||||
// Whether timepicker is collapsed or not.
|
||||
collapse: bool | *false
|
||||
// Whether timepicker is enabled or not.
|
||||
enable: bool | *true
|
||||
// Whether timepicker is visible or not.
|
||||
hidden: bool | *false
|
||||
// Selectable intervals for auto-refresh.
|
||||
refresh_intervals: [...string] | *["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"]
|
||||
}
|
||||
// Templating.
|
||||
templating?: list: [...{...}]
|
||||
// Annotations.
|
||||
annotations?: list: [...{
|
||||
builtIn: uint8 | *0
|
||||
// Datasource to use for annotation.
|
||||
datasource: string
|
||||
// Whether annotation is enabled.
|
||||
enable: bool | *true
|
||||
// Whether to hide annotation.
|
||||
hide?: bool | *false
|
||||
// Annotation icon color.
|
||||
iconColor?: string
|
||||
// Name of annotation.
|
||||
name?: string
|
||||
type: string | *"dashboard"
|
||||
// Query for annotation data.
|
||||
rawQuery?: string
|
||||
showIn: uint8 | *0
|
||||
}]
|
||||
// Auto-refresh interval.
|
||||
refresh?: string | false
|
||||
// Version of the JSON schema, incremented each time a Grafana update brings
|
||||
// changes to said schema.
|
||||
// FIXME this is the old schema numbering system, and will be replaced by Thema's themaVersion
|
||||
schemaVersion: uint16 | *33
|
||||
// Version of the dashboard, incremented each time the dashboard is updated.
|
||||
version?: uint32
|
||||
panels?: [...(#Panel | #GraphPanel | #HeatmapPanel | #RowPanel)]
|
||||
gnetId?: string
|
||||
// Tags associated with dashboard.
|
||||
tags?: [...string]
|
||||
// Theme of dashboard.
|
||||
style: *"light" | "dark"
|
||||
// Timezone of dashboard,
|
||||
timezone?: *"browser" | "utc" | ""
|
||||
// Whether a dashboard is editable or not.
|
||||
editable: bool | *true
|
||||
// 0 for no shared crosshair or tooltip (default).
|
||||
// 1 for shared crosshair.
|
||||
// 2 for shared crosshair AND shared tooltip.
|
||||
graphTooltip: uint8 & >=0 & <=2 | *0
|
||||
// Time range for dashboard, e.g. last 6 hours, last 7 days, etc
|
||||
time?: {
|
||||
from: string | *"now-6h"
|
||||
to: string | *"now"
|
||||
}
|
||||
// Timepicker metadata.
|
||||
timepicker?: {
|
||||
// Whether timepicker is collapsed or not.
|
||||
collapse: bool | *false
|
||||
// Whether timepicker is enabled or not.
|
||||
enable: bool | *true
|
||||
// Whether timepicker is visible or not.
|
||||
hidden: bool | *false
|
||||
// Selectable intervals for auto-refresh.
|
||||
refresh_intervals: [...string] | *["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"]
|
||||
}
|
||||
// Templating.
|
||||
templating?: list: [...{...}]
|
||||
// Annotations.
|
||||
annotations?: list: [...{
|
||||
builtIn: uint8 | *0
|
||||
// Datasource to use for annotation.
|
||||
datasource: {
|
||||
type?: string
|
||||
uid?: string
|
||||
}
|
||||
// Whether annotation is enabled.
|
||||
enable: bool | *true
|
||||
// Whether to hide annotation.
|
||||
hide?: bool | *false
|
||||
// Annotation icon color.
|
||||
iconColor?: string
|
||||
// Name of annotation.
|
||||
name?: string
|
||||
type: string | *"dashboard"
|
||||
// Query for annotation data.
|
||||
rawQuery?: string
|
||||
showIn: uint8 | *0
|
||||
}]
|
||||
// Auto-refresh interval.
|
||||
refresh?: string | false
|
||||
// Version of the JSON schema, incremented each time a Grafana update brings
|
||||
// changes to said schema.
|
||||
// FIXME this is the old schema numbering system, and will be replaced by Thema's themaVersion
|
||||
schemaVersion: uint16 | *33
|
||||
// Version of the dashboard, incremented each time the dashboard is updated.
|
||||
version?: uint32
|
||||
panels?: [...(#Panel | #GraphPanel | #HeatmapPanel | #RowPanel)]
|
||||
|
||||
// TODO docs
|
||||
#FieldColorModeId: "thresholds" | "palette-classic" | "palette-saturated" | "continuous-GrYlRd" | "fixed" @cuetsy(kind="enum")
|
||||
// TODO docs
|
||||
#FieldColorModeId: "thresholds" | "palette-classic" | "palette-saturated" | "continuous-GrYlRd" | "fixed" @cuetsy(kind="enum")
|
||||
|
||||
// TODO docs
|
||||
#FieldColorSeriesByMode: "min" | "max" | "last" @cuetsy(kind="type")
|
||||
// TODO docs
|
||||
#FieldColorSeriesByMode: "min" | "max" | "last" @cuetsy(kind="type")
|
||||
|
||||
// TODO docs
|
||||
#FieldColor: {
|
||||
// The main color scheme mode
|
||||
mode: #FieldColorModeId | string
|
||||
// Stores the fixed color value if mode is fixed
|
||||
fixedColor?: string
|
||||
// Some visualizations need to know how to assign a series color from by value color schemes
|
||||
seriesBy?: #FieldColorSeriesByMode
|
||||
} @cuetsy(kind="interface")
|
||||
// TODO docs
|
||||
#FieldColor: {
|
||||
// The main color scheme mode
|
||||
mode: #FieldColorModeId | string
|
||||
// Stores the fixed color value if mode is fixed
|
||||
fixedColor?: string
|
||||
// Some visualizations need to know how to assign a series color from by value color schemes
|
||||
seriesBy?: #FieldColorSeriesByMode
|
||||
} @cuetsy(kind="interface")
|
||||
|
||||
// TODO docs
|
||||
#Threshold: {
|
||||
// TODO docs
|
||||
// FIXME the corresponding typescript field is required/non-optional, but nulls currently appear here when serializing -Infinity to JSON
|
||||
value?: number
|
||||
// TODO docs
|
||||
color: string
|
||||
// TODO docs
|
||||
// TODO are the values here enumerable into a disjunction?
|
||||
// Some seem to be listed in typescript comment
|
||||
state?: string
|
||||
} @cuetsy(kind="interface")
|
||||
// TODO docs
|
||||
#Threshold: {
|
||||
// TODO docs
|
||||
// FIXME the corresponding typescript field is required/non-optional, but nulls currently appear here when serializing -Infinity to JSON
|
||||
value?: number
|
||||
// TODO docs
|
||||
color: string
|
||||
// TODO docs
|
||||
// TODO are the values here enumerable into a disjunction?
|
||||
// Some seem to be listed in typescript comment
|
||||
state?: string
|
||||
} @cuetsy(kind="interface")
|
||||
|
||||
#ThresholdsMode: "absolute" | "percentage" @cuetsy(kind="enum")
|
||||
#ThresholdsMode: "absolute" | "percentage" @cuetsy(kind="enum")
|
||||
|
||||
#ThresholdsConfig: {
|
||||
mode: #ThresholdsMode
|
||||
#ThresholdsConfig: {
|
||||
mode: #ThresholdsMode
|
||||
|
||||
// Must be sorted by 'value', first value is always -Infinity
|
||||
steps: [...#Threshold]
|
||||
} @cuetsy(kind="interface")
|
||||
// Must be sorted by 'value', first value is always -Infinity
|
||||
steps: [...#Threshold]
|
||||
} @cuetsy(kind="interface")
|
||||
|
||||
// TODO docs
|
||||
// FIXME this is extremely underspecfied; wasn't obvious which typescript types corresponded to it
|
||||
#Transformation: {
|
||||
id: string
|
||||
options: {...}
|
||||
}
|
||||
// TODO docs
|
||||
// FIXME this is extremely underspecfied; wasn't obvious which typescript types corresponded to it
|
||||
#Transformation: {
|
||||
id: string
|
||||
options: {...}
|
||||
}
|
||||
|
||||
// Schema for panel targets is specified by datasource
|
||||
// plugins. We use a placeholder definition, which the Go
|
||||
// schema loader either left open/as-is with the Base
|
||||
// variant of the Dashboard and Panel families, or filled
|
||||
// with types derived from plugins in the Instance variant.
|
||||
// When working directly from CUE, importers can extend this
|
||||
// type directly to achieve the same effect.
|
||||
#Target: {...}
|
||||
// Schema for panel targets is specified by datasource
|
||||
// plugins. We use a placeholder definition, which the Go
|
||||
// schema loader either left open/as-is with the Base
|
||||
// variant of the Dashboard and Panel families, or filled
|
||||
// with types derived from plugins in the Instance variant.
|
||||
// When working directly from CUE, importers can extend this
|
||||
// type directly to achieve the same effect.
|
||||
#Target: {...}
|
||||
|
||||
// Dashboard panels. Panels are canonically defined inline
|
||||
// because they share a version timeline with the dashboard
|
||||
// schema; they do not evolve independently.
|
||||
#Panel: {
|
||||
// The panel plugin type id.
|
||||
type: !=""
|
||||
// Dashboard panels. Panels are canonically defined inline
|
||||
// because they share a version timeline with the dashboard
|
||||
// schema; they do not evolve independently.
|
||||
#Panel: {
|
||||
// The panel plugin type id.
|
||||
type: !=""
|
||||
|
||||
// TODO docs
|
||||
id?: uint32
|
||||
// TODO docs
|
||||
id?: uint32
|
||||
|
||||
// FIXME this almost certainly has to be changed in favor of scuemata versions
|
||||
pluginVersion?: string
|
||||
// FIXME this almost certainly has to be changed in favor of scuemata versions
|
||||
pluginVersion?: string
|
||||
|
||||
// TODO docs
|
||||
tags?: [...string]
|
||||
// TODO docs
|
||||
tags?: [...string]
|
||||
|
||||
// Internal - the exact major and minor versions of the panel plugin
|
||||
// schema. Hidden and therefore not a part of the data model, but
|
||||
// expected to be filled with panel plugin schema versions so that it's
|
||||
// possible to figure out which schema version matched on a successful
|
||||
// unification.
|
||||
// _pv: { maj: int, min: int }
|
||||
// The major and minor versions of the panel plugin for this schema.
|
||||
// TODO 2-tuple list instead of struct?
|
||||
// panelSchema?: { maj: number, min: number }
|
||||
panelSchema?: [number, number]
|
||||
// Internal - the exact major and minor versions of the panel plugin
|
||||
// schema. Hidden and therefore not a part of the data model, but
|
||||
// expected to be filled with panel plugin schema versions so that it's
|
||||
// possible to figure out which schema version matched on a successful
|
||||
// unification.
|
||||
// _pv: { maj: int, min: int }
|
||||
// The major and minor versions of the panel plugin for this schema.
|
||||
// TODO 2-tuple list instead of struct?
|
||||
// panelSchema?: { maj: number, min: number }
|
||||
panelSchema?: [number, number]
|
||||
|
||||
// TODO docs
|
||||
targets?: [...#Target]
|
||||
// TODO docs
|
||||
targets?: [...#Target]
|
||||
|
||||
// Panel title.
|
||||
title?: string
|
||||
// Description.
|
||||
description?: string
|
||||
// Whether to display the panel without a background.
|
||||
transparent: bool | *false
|
||||
// The datasource used in all targets.
|
||||
datasource?: {
|
||||
type?: string
|
||||
uid?: string
|
||||
}
|
||||
// Grid position.
|
||||
gridPos?: {
|
||||
// Panel
|
||||
h: uint32 & >0 | *9
|
||||
// Panel
|
||||
w: uint32 & >0 & <=24 | *12
|
||||
// Panel x
|
||||
x: uint32 & >=0 & <24 | *0
|
||||
// Panel y
|
||||
y: uint32 & >=0 | *0
|
||||
// true if fixed
|
||||
static?: bool
|
||||
}
|
||||
// Panel links.
|
||||
// FIXME this is temporarily specified as a closed list so
|
||||
// that validation will pass when no links are present, but
|
||||
// to force a failure as soon as it's checked against there
|
||||
// being anything in the list so it can be fixed in
|
||||
// accordance with that object
|
||||
links?: []
|
||||
// Panel title.
|
||||
title?: string
|
||||
// Description.
|
||||
description?: string
|
||||
// Whether to display the panel without a background.
|
||||
transparent: bool | *false
|
||||
// The datasource used in all targets.
|
||||
datasource?: {
|
||||
type?: string
|
||||
uid?: string
|
||||
}
|
||||
// Grid position.
|
||||
gridPos?: {
|
||||
// Panel
|
||||
h: uint32 & >0 | *9
|
||||
// Panel
|
||||
w: uint32 & >0 & <=24 | *12
|
||||
// Panel x
|
||||
x: uint32 & >=0 & <24 | *0
|
||||
// Panel y
|
||||
y: uint32 & >=0 | *0
|
||||
// true if fixed
|
||||
static?: bool
|
||||
}
|
||||
// Panel links.
|
||||
// FIXME this is temporarily specified as a closed list so
|
||||
// that validation will pass when no links are present, but
|
||||
// to force a failure as soon as it's checked against there
|
||||
// being anything in the list so it can be fixed in
|
||||
// accordance with that object
|
||||
links?: []
|
||||
|
||||
// Name of template variable to repeat for.
|
||||
repeat?: string
|
||||
// Direction to repeat in if 'repeat' is set.
|
||||
// "h" for horizontal, "v" for vertical.
|
||||
repeatDirection: *"h" | "v"
|
||||
// Name of template variable to repeat for.
|
||||
repeat?: string
|
||||
// Direction to repeat in if 'repeat' is set.
|
||||
// "h" for horizontal, "v" for vertical.
|
||||
repeatDirection: *"h" | "v"
|
||||
|
||||
// TODO docs
|
||||
maxDataPoints?: number
|
||||
// TODO docs
|
||||
maxDataPoints?: number
|
||||
|
||||
// TODO docs
|
||||
thresholds?: [...]
|
||||
// TODO docs
|
||||
thresholds?: [...]
|
||||
|
||||
// TODO docs
|
||||
timeRegions?: [...]
|
||||
// TODO docs
|
||||
timeRegions?: [...]
|
||||
|
||||
transformations: [...#Transformation]
|
||||
transformations: [...#Transformation]
|
||||
|
||||
// TODO docs
|
||||
// TODO tighter constraint
|
||||
interval?: string
|
||||
// TODO docs
|
||||
// TODO tighter constraint
|
||||
interval?: string
|
||||
|
||||
// TODO docs
|
||||
// TODO tighter constraint
|
||||
timeFrom?: string
|
||||
// TODO docs
|
||||
// TODO tighter constraint
|
||||
timeFrom?: string
|
||||
|
||||
// TODO docs
|
||||
// TODO tighter constraint
|
||||
timeShift?: string
|
||||
// TODO docs
|
||||
// TODO tighter constraint
|
||||
timeShift?: string
|
||||
|
||||
// options is specified by the PanelOptions field in panel
|
||||
// plugin schemas.
|
||||
options: {...}
|
||||
// options is specified by the PanelOptions field in panel
|
||||
// plugin schemas.
|
||||
options: {...}
|
||||
|
||||
fieldConfig: {
|
||||
defaults: {
|
||||
// The display value for this field. This supports template variables blank is auto
|
||||
displayName?: string
|
||||
fieldConfig: {
|
||||
defaults: {
|
||||
// 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
|
||||
// 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
|
||||
// Human readable field metadata
|
||||
description?: string
|
||||
|
||||
// An explict 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
|
||||
// An explict 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 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
|
||||
// True if data source field supports ad-hoc filters
|
||||
filterable?: bool
|
||||
|
||||
// Numeric Options
|
||||
unit?: string
|
||||
// Numeric Options
|
||||
unit?: string
|
||||
|
||||
// Significant digits (for display)
|
||||
decimals?: number
|
||||
// Significant digits (for display)
|
||||
decimals?: number
|
||||
|
||||
min?: number
|
||||
max?: number
|
||||
min?: number
|
||||
max?: number
|
||||
|
||||
// Convert input values into a display string
|
||||
//
|
||||
// TODO this one corresponds to a complex type with
|
||||
// generics on the typescript side. Ouch. Will
|
||||
// either need special care, or we'll just need to
|
||||
// accept a very loosely specified schema. It's very
|
||||
// unlikely we'll be able to translate cue to
|
||||
// typescript generics in the general case, though
|
||||
// this particular one *may* be able to work.
|
||||
mappings?: [...{...}]
|
||||
// Convert input values into a display string
|
||||
//
|
||||
// TODO this one corresponds to a complex type with
|
||||
// generics on the typescript side. Ouch. Will
|
||||
// either need special care, or we'll just need to
|
||||
// accept a very loosely specified schema. It's very
|
||||
// unlikely we'll be able to translate cue to
|
||||
// typescript generics in the general case, though
|
||||
// this particular one *may* be able to work.
|
||||
mappings?: [...{...}]
|
||||
|
||||
// Map numeric values to states
|
||||
thresholds?: #ThresholdsConfig
|
||||
// Map numeric values to states
|
||||
thresholds?: #ThresholdsConfig
|
||||
|
||||
// // Map values to a display color
|
||||
color?: #FieldColor
|
||||
// // Map values to a display color
|
||||
color?: #FieldColor
|
||||
|
||||
// // Used when reducing field values
|
||||
// nullValueMode?: NullValueMode
|
||||
// // Used when reducing field values
|
||||
// nullValueMode?: NullValueMode
|
||||
|
||||
// // The behavior when clicking on a result
|
||||
links?: [...]
|
||||
// // The behavior when clicking on a result
|
||||
links?: [...]
|
||||
|
||||
// Alternative to empty string
|
||||
noValue?: string
|
||||
// Alternative to empty string
|
||||
noValue?: string
|
||||
|
||||
// custom is specified by the PanelFieldConfig field
|
||||
// in panel plugin schemas.
|
||||
custom?: {...}
|
||||
}
|
||||
overrides: [...{
|
||||
matcher: {
|
||||
id: string | *""
|
||||
options?: _
|
||||
}
|
||||
properties: [...{
|
||||
id: string | *""
|
||||
value?: _
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}
|
||||
// custom is specified by the PanelFieldConfig field
|
||||
// in panel plugin schemas.
|
||||
custom?: {...}
|
||||
}
|
||||
overrides: [...{
|
||||
matcher: {
|
||||
id: string | *""
|
||||
options?: _
|
||||
}
|
||||
properties: [...{
|
||||
id: string | *""
|
||||
value?: _
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
// Row panel
|
||||
#RowPanel: {
|
||||
type: "row"
|
||||
collapsed: bool | *false
|
||||
title?: string
|
||||
// Row panel
|
||||
#RowPanel: {
|
||||
type: "row"
|
||||
collapsed: bool | *false
|
||||
title?: string
|
||||
|
||||
// Name of default datasource.
|
||||
datasource?: string
|
||||
// Name of default datasource.
|
||||
datasource?: {
|
||||
type?: string
|
||||
uid?: string
|
||||
}
|
||||
|
||||
gridPos?: {
|
||||
// Panel
|
||||
h: uint32 & >0 | *9
|
||||
// Panel
|
||||
w: uint32 & >0 & <=24 | *12
|
||||
// Panel x
|
||||
x: uint32 & >=0 & <24 | *0
|
||||
// Panel y
|
||||
y: uint32 & >=0 | *0
|
||||
// true if fixed
|
||||
static?: bool
|
||||
}
|
||||
id: uint32
|
||||
panels: [...(#Panel | #GraphPanel | #HeatmapPanel)]
|
||||
// Name of template variable to repeat for.
|
||||
repeat?: string
|
||||
}
|
||||
// Support for legacy graph and heatmap panels.
|
||||
#GraphPanel: {
|
||||
...
|
||||
type: "graph"
|
||||
}
|
||||
#HeatmapPanel: {
|
||||
...
|
||||
type: "heatmap"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
gridPos?: {
|
||||
// Panel
|
||||
h: uint32 & >0 | *9
|
||||
// Panel
|
||||
w: uint32 & >0 & <=24 | *12
|
||||
// Panel x
|
||||
x: uint32 & >=0 & <24 | *0
|
||||
// Panel y
|
||||
y: uint32 & >=0 | *0
|
||||
// true if fixed
|
||||
static?: bool
|
||||
}
|
||||
id: uint32
|
||||
panels: [...(#Panel | #GraphPanel | #HeatmapPanel)]
|
||||
// Name of template variable to repeat for.
|
||||
repeat?: string
|
||||
}
|
||||
|
||||
// Support for legacy graph and heatmap panels.
|
||||
#GraphPanel: {
|
||||
type: "graph"
|
||||
...
|
||||
}
|
||||
#HeatmapPanel: {
|
||||
type: "heatmap"
|
||||
...
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
]
|
||||
|
@ -17,6 +17,15 @@ var (
|
||||
currentVersion = thema.SV(0, 0)
|
||||
)
|
||||
|
||||
// HandoffSchemaVersion is the minimum schemaVersion for dashboards at which the
|
||||
// Thema-based dashboard schema is known to be valid.
|
||||
//
|
||||
// schemaVersion is the original version numbering system for dashboards. If a
|
||||
// dashboard is below this schemaVersion, it is necessary for the frontend
|
||||
// typescript dashboard migration logic to first run and get it past this
|
||||
// number, after which Thema can take over.
|
||||
const HandoffSchemaVersion = 36
|
||||
|
||||
// Lineage returns the Thema lineage representing Grafana dashboards. The
|
||||
// lineage is the canonical specification of the current datasource schema, all
|
||||
// prior schema versions, and the mappings that allow migration between schema
|
||||
@ -80,7 +89,7 @@ type model struct {
|
||||
SchemaVersion int `json:"schemaVersion"`
|
||||
Panels []interface{} `json:"panels"`
|
||||
|
||||
////
|
||||
// //
|
||||
|
||||
Uid string `json:"uid"`
|
||||
// OrgId int64 `json:"orgId"`
|
||||
|
@ -19,6 +19,7 @@ import (
|
||||
"cuelang.org/go/cue/errors"
|
||||
"cuelang.org/go/cue/load"
|
||||
cuejson "cuelang.org/go/pkg/encoding/json"
|
||||
"github.com/grafana/grafana/pkg/coremodel/dashboard"
|
||||
"github.com/grafana/grafana/pkg/schema"
|
||||
"github.com/laher/mergefs"
|
||||
"github.com/stretchr/testify/require"
|
||||
@ -48,7 +49,6 @@ var doTestAgainstDevenv = func(sch schema.VersionedCueSchema, validdir string, f
|
||||
b, err := os.Open(path)
|
||||
require.NoError(t, err, "failed to open dashboard file")
|
||||
|
||||
// Only try to validate dashboards with schemaVersion >= 30
|
||||
jtree := make(map[string]interface{})
|
||||
byt, err := io.ReadAll(b)
|
||||
if err != nil {
|
||||
@ -59,9 +59,9 @@ var doTestAgainstDevenv = func(sch schema.VersionedCueSchema, validdir string, f
|
||||
t.Logf("no schemaVersion in %s", path)
|
||||
return nil
|
||||
} else {
|
||||
if !(oldschemav.(float64) > 32) {
|
||||
if !(oldschemav.(float64) > dashboard.HandoffSchemaVersion-1) {
|
||||
if testing.Verbose() {
|
||||
t.Logf("schemaVersion is %v, older than 33, skipping %s", oldschemav, path)
|
||||
t.Logf("schemaVersion is %v, older than %v, skipping %s", oldschemav, dashboard.HandoffSchemaVersion-1, path)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
SED=$(command -v gsed)
|
||||
SED=${SED:-"sed"}
|
||||
|
||||
FILES=$(grep -rl '"schemaVersion": 3[34]' devenv)
|
||||
FILES=$(grep -rl '"schemaVersion": 3[3456]' devenv)
|
||||
set -e
|
||||
set -x
|
||||
for DASH in ${FILES}; do echo "${DASH}"; grep -v 'null,$' "${DASH}" > "${DASH}-nulless"; mv "${DASH}-nulless" "${DASH}"; done
|
||||
|
Loading…
Reference in New Issue
Block a user