@intentius/chant-lexicon-grafana 0.102.0 → 0.104.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -54,13 +54,13 @@ With `grafana.profiles.<env>` in `chant.config.ts` (a URL, and a service account
54
54
 
55
55
  ## Checks
56
56
 
57
- GRAF001 and GRAF002 run on source (uid and variable-name syntax, literal secrets). The GRAF1xx checks run after a build: undeclared or mistyped datasources, undeclared variables, duplicate uids and ids, panels off the grid or overlapping, uids Grafana rejects, validation against the pinned dashboard, panel and query schemas (an unknown key is a warning), a PromQL syntax check on every query sent to a Prometheus (GRAF108), LogQL and TraceQL syntax checks on queries sent to a Loki (GRAF116) or a Tempo (GRAF117), dashboard providers that load a dashboard twice or not into its declared folder (GRAF109), a panel or row repeated over a variable that only ever holds one value (GRAF110), and a check that every panel unit is one Grafana knows or a custom `suffix:`/`prefix:`-style unit (GRAF115). For alerting: rules whose condition or expressions name no query (GRAF111), queries to undeclared datasources (GRAF112), routes to undeclared contact points or mute timings (GRAF113), and uids, intervals and duplicates Grafana refuses (GRAF114).
57
+ GRAF001 and GRAF002 run on source (uid and variable-name syntax, literal secrets). The GRAF1xx checks run after a build: undeclared or mistyped datasources, undeclared variables, duplicate uids and ids, panels off the grid or overlapping, uids Grafana rejects, validation against the pinned dashboard, panel and query schemas (an unknown key is a warning), a PromQL syntax check on every query sent to a Prometheus (GRAF108), LogQL and TraceQL syntax checks on queries sent to a Loki (GRAF116) or a Tempo (GRAF117), dashboard providers that load a dashboard twice or not into its declared folder (GRAF109), a panel or row repeated over a variable that only ever holds one value (GRAF110), and a check that every panel unit is one Grafana knows or a custom `suffix:`/`prefix:`-style unit (GRAF115), and a panel that reads a spanmetrics, servicegraph or GenAI metric no collector config in the build emits (GRAF118). For alerting: rules whose condition or expressions name no query (GRAF111), queries to undeclared datasources (GRAF112), routes to undeclared contact points or mute timings (GRAF113), and uids, intervals and duplicates Grafana refuses (GRAF114).
58
58
 
59
59
  GRAF101 and GRAF102 compare dashboards with the datasources declared in the same build root (chant #1939); keep them together, and declare a datasource that already exists in Grafana with `ExternalDatasource`, which the checks count and the build never provisions.
60
60
 
61
61
  ## Plain-data API
62
62
 
63
63
  - `buildGrafana(entities)` and `grafanaFiles(entities)` render every file by path, for embedding in another lexicon's output (a ConfigMap, a volume).
64
- - `GrafanaConfigMaps` and `grafanaVolumes` from `@intentius/chant-lexicon-grafana/k8s` deliver dashboards and provisioning to Kubernetes as ConfigMaps labelled for the Grafana Helm chart's sidecar (`grafana_dashboard`, `grafana_datasource`), or mounted into a plain Grafana Deployment. `GrafanaOperatorResources` from the same subpath writes `GrafanaDashboard`, `GrafanaDatasource` and `GrafanaFolder` resources for a Grafana the Grafana Operator runs.
64
+ - `GrafanaConfigMaps` and `grafanaVolumes` from `@intentius/chant-lexicon-grafana/k8s` deliver dashboards and provisioning to Kubernetes as ConfigMaps labelled for the Grafana Helm chart's sidecar (`grafana_dashboard`, `grafana_datasource`), or mounted into a plain Grafana Deployment. `GrafanaOperatorResources` from the same subpath writes `GrafanaDashboard`, `GrafanaDatasource`, `GrafanaFolder` and `GrafanaLibraryPanel` resources for a Grafana the Grafana Operator runs.
65
65
  - `renderDashboard(dashboard)` and `dashboardJson(dashboard)` render one dashboard.
66
66
  - `validateGrafanaOutput({ dashboards, datasources })` and `validateDashboardSchema(json)`, from `@intentius/chant-lexicon-grafana/validation`, run the checks without a build. They are not on the package root, so declaring dashboards does not load them; ajv loads the first time a schema is checked.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "algorithm": "sha256",
3
3
  "artifacts": {
4
- "manifest.json": "6d6d901701efc94bf97c32eda41e2046586ae7a9a064a868358c22aeaf9f7e65",
4
+ "manifest.json": "a50cbf71f667cfe6c17c2ed94c815c8be8a98c376877efc8337f0d16989ed63a",
5
5
  "meta.json": "330a1598c3b35ae62267e886a3416a494b0ebe9f1d2e2379253787d0a0bcb32e",
6
6
  "types/index.d.ts": "ad385264290f2486f7a54be205684de8415a25b74eee5b809ca625ae19fb08da",
7
7
  "rules/grafana-ast.ts": "51f4fac423f7a5c6d6f577074e95b4a70d4ab0a05883a86e04970a50c63d92e8",
@@ -24,11 +24,12 @@
24
24
  "rules/graf115.ts": "eb6b5cb7b275ab27f9602eb5bdc3e2bc8e698ae6d0ffcd984d71e2315e4d6315",
25
25
  "rules/graf116.ts": "5413964ec389c35cc008d68fc82438fbd44544b85c22722c7268f1daeb243b51",
26
26
  "rules/graf117.ts": "9de2e565219d73e320e381559389efaa6b91f373de939cfcf9637d94b5f97cb1",
27
+ "rules/graf118.ts": "e4ad3c5b944185139331a1f30488c6107a87f37872a0d52b7afc03d9a2ed6125",
27
28
  "rules/grafana-helpers.ts": "0a538daafb10f32077dd6cda4c03b541f703b0a10abc51bfd241eae9365c9be6",
28
29
  "skills/chant-grafana.md": "6a7f4ba6d8a40d339fad892c612131370ef0c2595547860ee718801bfa893163",
29
- "skills/chant-grafana-provisioning.md": "12c0f00ba767c833c1a20ed212c637d638c63386eea0a310cce44112bab19145",
30
+ "skills/chant-grafana-provisioning.md": "b861a848761c4db9c8c07f248650af14b254c19277b35839ff23033e484089aa",
30
31
  "skills/chant-grafana-alerting.md": "d9648dc14c848851bdccbe069dac54ad06115066f9466c90c4137d07dde6d4ad",
31
32
  "skills/chant-grafana-operations.md": "4e665f80292ab32bde6d77940cc3f3923678c58e6db0b80613489050d2cb665b"
32
33
  },
33
- "composite": "8978638d5a5e8bea98231146fc60b2ae1ffa751e86f94ec5cc72238bbf4ccd00"
34
+ "composite": "34effea118fac5a57812130bc284f0140c0524aadedc8bdfae0283bfc523fa90"
34
35
  }
package/dist/k8s.d.ts CHANGED
@@ -22,16 +22,17 @@
22
22
  *
23
23
  * A Grafana run by the Grafana Operator reads custom resources instead
24
24
  * (#3015): `GrafanaOperatorResources` writes a `GrafanaDashboard` per
25
- * dashboard, a `GrafanaDatasource` per datasource and a `GrafanaFolder` per
26
- * folder, all `grafana.integreatly.org/v1beta1` as the k8s lexicon types
27
- * them from the operator's CRDs (pinned in its `crd-sources.ts`).
25
+ * dashboard, a `GrafanaDatasource` per datasource, a `GrafanaFolder` per
26
+ * folder and a `GrafanaLibraryPanel` per library panel (#3186), all
27
+ * `grafana.integreatly.org/v1beta1` as the k8s lexicon types them from the
28
+ * operator's CRDs (pinned in its `crd-sources.ts`).
28
29
  *
29
30
  * This module is the only part of the grafana lexicon that loads the k8s
30
31
  * lexicon; nothing else imports it.
31
32
  */
32
33
  import { type CompositeInstance } from "@intentius/chant/composite";
33
34
  import type { Declarable } from "@intentius/chant/declarable";
34
- import { ConfigMap, GrafanaDashboard, GrafanaDatasource, GrafanaFolder } from "@intentius/chant-lexicon-k8s/generated/index";
35
+ import { ConfigMap, GrafanaDashboard, GrafanaDatasource, GrafanaFolder, GrafanaLibraryPanel } from "@intentius/chant-lexicon-k8s/generated/index";
35
36
  import { type ProvisionedDatasource } from "./build.js";
36
37
  /** The label the Grafana Helm chart's sidecar looks for on dashboard ConfigMaps (`sidecar.dashboards.label`). */
37
38
  export declare const SIDECAR_DASHBOARD_LABEL = "grafana_dashboard";
@@ -120,7 +121,7 @@ export interface GrafanaInstanceSelector {
120
121
  }>;
121
122
  }
122
123
  export interface GrafanaOperatorResourcesProps {
123
- /** The grafana declarations to deliver: dashboards, datasources and `Folder`s. Anything else is ignored. */
124
+ /** The grafana declarations to deliver: dashboards (with the library panels they place), datasources and `Folder`s. Anything else is ignored. */
124
125
  entities: Iterable<Declarable>;
125
126
  /**
126
127
  * Which `Grafana` resources pick these up, usually the labels on your
@@ -155,7 +156,7 @@ export interface GrafanaOperatorResourcesProps {
155
156
  */
156
157
  secretName?: string;
157
158
  }
158
- type OperatorEntity = (InstanceType<typeof GrafanaDashboard> | InstanceType<typeof GrafanaDatasource> | InstanceType<typeof GrafanaFolder>) & Declarable;
159
+ type OperatorEntity = (InstanceType<typeof GrafanaDashboard> | InstanceType<typeof GrafanaDatasource> | InstanceType<typeof GrafanaFolder> | InstanceType<typeof GrafanaLibraryPanel>) & Declarable;
159
160
  export type GrafanaOperatorResourcesMembers = Record<string, OperatorEntity>;
160
161
  export type GrafanaOperatorResourcesInstance = CompositeInstance<GrafanaOperatorResourcesMembers> & GrafanaOperatorResourcesMembers;
161
162
  /**
@@ -175,6 +176,11 @@ export declare function operatorDatasource(ds: ProvisionedDatasource, secretName
175
176
  *
176
177
  * - a `GrafanaFolder` per folder, `<name>-folder-<uid>`, with the folder's uid,
177
178
  * its title, and its parent as `parentFolderRef`;
179
+ * - a `GrafanaLibraryPanel` per library panel the dashboards place,
180
+ * `<name>-library-panel-<uid>`, holding its model with its `name` and `uid`
181
+ * in `spec.json` and naming its folder with `folderRef`. File provisioning
182
+ * and a `GrafanaDashboard`'s `__elements` do not create library panels, so
183
+ * without these a dashboard's library panel references stay empty;
178
184
  * - a `GrafanaDashboard` per dashboard, `<name>-dashboard-<uid>`, holding
179
185
  * `dashboardJson(dashboard)` in `spec.json` and naming its folder with
180
186
  * `folderRef`;
package/dist/k8s.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"k8s.d.ts","sourceRoot":"","sources":["../src/k8s.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"k8s.d.ts","sourceRoot":"","sources":["../src/k8s.ts"],"names":[],"mappings":"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"}
@@ -2,7 +2,7 @@
2
2
  * The grafana lexicon's chant audit catalog, contributed via
3
3
  * `grafanaPlugin.auditCatalog()` (#687, #1346).
4
4
  *
5
- * GRAF101-GRAF110, GRAF111-GRAF114 and GRAF115-GRAF117 read the emitted dashboard
5
+ * GRAF101-GRAF110, GRAF111-GRAF114 and GRAF115-GRAF118 read the emitted dashboard
6
6
  * JSON and provisioning files (alerting included), so
7
7
  * they fire on an audit of files chant didn't build too, and are
8
8
  * `yamlBased`. GRAF001 and GRAF002 read TypeScript source, so they are
@@ -1 +1 @@
1
- {"version":3,"file":"audit-catalog.d.ts","sourceRoot":"","sources":["../../src/lint/audit-catalog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAA2B,KAAK,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAOxF,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAqJxD,CAAC"}
1
+ {"version":3,"file":"audit-catalog.d.ts","sourceRoot":"","sources":["../../src/lint/audit-catalog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAA2B,KAAK,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAOxF,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CA6JxD,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * GRAF118: A panel reads a connector metric no collector in the build emits
3
+ *
4
+ * The prometheus lexicon's PROM301, over dashboards: each panel query and query variable whose datasource resolves to a prometheus datasource, with its template variables replaced as GRAF108 replaces them, goes through `collectorMetricIssues` (prometheus `collector-metrics.ts`). A name under a namespace the build's spanmetrics, servicegraph or GenAI connectors own that no collector config emits is reported, and a by (...) label that is not a declared dimension. Silent for names outside those namespaces, and when the build has no collector config.
5
+ */
6
+ import type { PostSynthCheck } from "@intentius/chant/lint/post-synth";
7
+ export declare const graf118: PostSynthCheck;
8
+ //# sourceMappingURL=graf118.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graf118.d.ts","sourceRoot":"","sources":["../../../src/lint/post-synth/graf118.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAyC,MAAM,kCAAkC,CAAC;AAM9G,eAAO,MAAM,OAAO,EAAE,cA0BrB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lint/post-synth/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAmBvE,eAAO,MAAM,eAAe,EAAE,cAAc,EAkB3C,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lint/post-synth/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAoBvE,eAAO,MAAM,eAAe,EAAE,cAAc,EAmB3C,CAAC"}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "grafana",
3
- "version": "0.102.0",
3
+ "version": "0.104.0",
4
4
  "chantVersion": ">=0.1.0",
5
5
  "namespace": "Grafana",
6
6
  "intrinsics": [],
package/dist/okf/index.md CHANGED
@@ -96,3 +96,4 @@ okf_version: '0.2'
96
96
  * [GRAF115](/rules/GRAF115.md) - A panel unit Grafana doesn't know, which it shows as a literal suffix
97
97
  * [GRAF116](/rules/GRAF116.md) - A query sent to Loki is not valid LogQL
98
98
  * [GRAF117](/rules/GRAF117.md) - A query sent to Tempo is not valid TraceQL
99
+ * [GRAF118](/rules/GRAF118.md) - A panel reads a connector metric no collector in the build emits
@@ -0,0 +1,15 @@
1
+ ---
2
+ type: post-synth-check
3
+ title: GRAF118
4
+ description: A panel reads a connector metric no collector in the build emits
5
+ id: GRAF118
6
+ severity: error
7
+ category: post-synth
8
+ lexicon: grafana
9
+ docs: https://intentius.io/chant/lexicons/grafana/rules/
10
+ ---
11
+ A panel reads a connector metric no collector in the build emits
12
+
13
+ ## Applies to
14
+
15
+ - [Dashboard](/types/Dashboard.md)
@@ -13,3 +13,4 @@ resource_type: Grafana::Dashboard
13
13
  - [GRAF001](/rules/GRAF001.md): a uid Grafana rejects, or a variable name queries cannot reference.
14
14
  - [GRAF104](/rules/GRAF104.md): Two dashboards, datasources, folders, panels, variables or queries share an id
15
15
  - [GRAF109](/rules/GRAF109.md): Dashboard provisioning puts a dashboard somewhere other than its declared folder, or loads it twice
16
+ - [GRAF118](/rules/GRAF118.md): A panel reads a connector metric no collector in the build emits
@@ -0,0 +1,39 @@
1
+ /**
2
+ * GRAF118: A panel reads a connector metric no collector in the build emits
3
+ *
4
+ * The prometheus lexicon's PROM301, over dashboards: each panel query and query variable whose datasource resolves to a prometheus datasource, with its template variables replaced as GRAF108 replaces them, goes through `collectorMetricIssues` (prometheus `collector-metrics.ts`). A name under a namespace the build's spanmetrics, servicegraph or GenAI connectors own that no collector config emits is reported, and a by (...) label that is not a declared dimension. Silent for names outside those namespaces, and when the build has no collector config.
5
+ */
6
+
7
+ import type { PostSynthCheck, PostSynthContext, PostSynthDiagnostic } from "@intentius/chant/lint/post-synth";
8
+ import { buildCollectorConfigs, collectorMetricIssues, collectorMetrics } from "@intentius/chant-lexicon-prometheus/collector-metrics";
9
+ import { grafanaArtifacts } from "./grafana-helpers";
10
+ import { knownDatasourcesOf } from "../../validate-output";
11
+ import { prometheusQueries, substituteTemplateVariables } from "../../promql-check";
12
+
13
+ export const graf118: PostSynthCheck = {
14
+ id: "GRAF118",
15
+ description: "A panel reads a connector metric no collector in the build emits",
16
+
17
+ check(ctx: PostSynthContext): PostSynthDiagnostic[] {
18
+ const artifacts = grafanaArtifacts(ctx);
19
+ if (artifacts.dashboards.length === 0) return [];
20
+ const emitted = collectorMetrics(buildCollectorConfigs(ctx));
21
+ if (!emitted) return [];
22
+ const known = knownDatasourcesOf(artifacts);
23
+ const out: PostSynthDiagnostic[] = [];
24
+ for (const { json: d } of artifacts.dashboards) {
25
+ for (const { where, expr } of prometheusQueries(d, known)) {
26
+ for (const issue of collectorMetricIssues(substituteTemplateVariables(expr).text, emitted)) {
27
+ out.push({
28
+ checkId: "GRAF118",
29
+ severity: "warning",
30
+ message: `Dashboard "${String(d.title ?? d.uid ?? "?")}" ${where} ${issue.message}.`,
31
+ entity: String(d.uid ?? ""),
32
+ lexicon: "grafana",
33
+ });
34
+ }
35
+ }
36
+ }
37
+ return out;
38
+ },
39
+ };
@@ -3,6 +3,7 @@ export interface Options {
3
3
  legend: VizLegendOptions;
4
4
  tooltip: VizTooltipOptions;
5
5
  orientation?: VizOrientation;
6
+ annotations?: VizAnnotations;
6
7
  }
7
8
  export type FieldConfig = GraphFieldConfig;
8
9
  /**
@@ -180,4 +181,20 @@ export type ScaleDistribution = "linear" | "log" | "ordinal" | "symlog";
180
181
  * TODO docs
181
182
  */
182
183
  export type StackingMode = "none" | "normal" | "percent";
184
+ export interface VizAnnotations {
185
+ /**
186
+ * Breaks out each annotation frame into multiple lanes on the x-axis
187
+ */
188
+ multiLane?: boolean;
189
+ /**
190
+ * Sets whether clustering is enabled. Any value > 0 will enable clustering.
191
+ */
192
+ clustering?: number;
193
+ lines?: {
194
+ width?: number;
195
+ };
196
+ regions?: {
197
+ opacity?: number;
198
+ };
199
+ }
183
200
  //# sourceMappingURL=timeseries.gen.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"timeseries.gen.d.ts","sourceRoot":"","sources":["../../src/schema/timeseries.gen.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"timeseries.gen.d.ts","sourceRoot":"","sources":["../../src/schema/timeseries.gen.ts"],"names":[],"mappings":"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"}
@@ -25,7 +25,7 @@ docker run -p 3000:3000 \
25
25
 
26
26
  ## Kubernetes
27
27
 
28
- Use `GrafanaConfigMaps({ entities, namespace })` from `@intentius/chant-lexicon-grafana/k8s` in a k8s build root. It writes one ConfigMap per dashboard labelled `grafana_dashboard: "1"`, with the folder in the `k8s-sidecar-target-directory` annotation. The datasource file goes in a ConfigMap labelled `grafana_datasource: "1"`, and the provider file in a third. The Grafana Helm chart's sidecar picks these up as they are. For a Grafana without the sidecar, spread `grafanaVolumes({ entities })`'s `volumes` and `volumeMounts` into the Deployment: provisioning goes under `/etc/grafana/provisioning`, and each dashboard folder gets a projected volume of its own. For a Grafana the Grafana Operator runs, use `GrafanaOperatorResources({ entities, namespace, instanceSelector })` instead: a `GrafanaFolder` per folder, a `GrafanaDashboard` per dashboard (JSON in `spec.json`, folder by `folderRef`) and a `GrafanaDatasource` per datasource. `instanceSelector` is required and must match the labels on your `Grafana` resource. A datasource secret written `${NAME}` or `$__env{NAME}` needs `secretName`, the Secret holding key `NAME`. `grafanaFiles(entities)` still returns every file by path for any other layout.
28
+ Use `GrafanaConfigMaps({ entities, namespace })` from `@intentius/chant-lexicon-grafana/k8s` in a k8s build root. It writes one ConfigMap per dashboard labelled `grafana_dashboard: "1"`, with the folder in the `k8s-sidecar-target-directory` annotation. The datasource file goes in a ConfigMap labelled `grafana_datasource: "1"`, and the provider file in a third. The Grafana Helm chart's sidecar picks these up as they are. For a Grafana without the sidecar, spread `grafanaVolumes({ entities })`'s `volumes` and `volumeMounts` into the Deployment: provisioning goes under `/etc/grafana/provisioning`, and each dashboard folder gets a projected volume of its own. For a Grafana the Grafana Operator runs, use `GrafanaOperatorResources({ entities, namespace, instanceSelector })` instead: a `GrafanaFolder` per folder, a `GrafanaLibraryPanel` per library panel the dashboards place, a `GrafanaDashboard` per dashboard (JSON in `spec.json`, folder by `folderRef`) and a `GrafanaDatasource` per datasource. `instanceSelector` is required and must match the labels on your `Grafana` resource. A datasource secret written `${NAME}` or `$__env{NAME}` needs `secretName`, the Secret holding key `NAME`. `grafanaFiles(entities)` still returns every file by path for any other layout.
29
29
 
30
30
  ## Changing where dashboards live
31
31
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentius/chant-lexicon-grafana",
3
- "version": "0.102.0",
3
+ "version": "0.104.0",
4
4
  "description": "Grafana lexicon for chant — typed dashboards, panels, queries and datasources, serialized to dashboard JSON and Grafana provisioning files",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://intentius.io/chant",
@@ -83,7 +83,7 @@
83
83
  "zod": "^4.3.6"
84
84
  },
85
85
  "peerDependencies": {
86
- "@intentius/chant": "^0.102.0",
86
+ "@intentius/chant": "^0.104.0",
87
87
  "typescript": "^5.9.3",
88
88
  "zod": "^4.3.6"
89
89
  }
@@ -35,7 +35,10 @@ describe("init templates", () => {
35
35
  expect(runPostSynthChecks(postSynthChecks, result)).toEqual([]);
36
36
  const other = name === "k8s-pods" ? k8sPlugin : name === "slo" ? prometheusPlugin : undefined;
37
37
  if (other) {
38
- expect(runPostSynthChecks(other.postSynthChecks!(), result)).toEqual([]);
38
+ // Through the lexicon's default preset, as `chant build` reports them (prometheus leaves PROM212 out).
39
+ const recommended = other.lintPresets?.().recommended;
40
+ const reported = runPostSynthChecks(other.postSynthChecks!(), result).filter((d) => !recommended || recommended.includes(d.checkId));
41
+ expect(reported).toEqual([]);
39
42
  }
40
43
 
41
44
  const lint = await lintCommand({ path: join(dir, "src"), format: "stylish", fix: false });
package/src/k8s.test.ts CHANGED
@@ -5,6 +5,7 @@ import { loadAll } from "js-yaml";
5
5
  import { Dashboard } from "./dashboard";
6
6
  import { Datasource } from "./datasource";
7
7
  import { StatPanel } from "./panels";
8
+ import { LibraryPanel, LibraryPanelRef } from "./library-panel";
8
9
  import { PromQuery } from "./query";
9
10
  import { dashboardJson } from "./build";
10
11
  import { Folder } from "./folder";
@@ -147,6 +148,35 @@ describe("GrafanaOperatorResources (#3015)", () => {
147
148
  expect(docs[1].spec).toEqual({ instanceSelector: selector, configMapRef: { name: sidecar.configMap, key: sidecar.key }, folderRef: "grafana-folder-services" });
148
149
  });
149
150
 
151
+ test("a GrafanaLibraryPanel per library panel the dashboards place, once each, in its folder (#3186)", () => {
152
+ const burn = new LibraryPanel({ name: "Burn rate", folder: "SLOs", panel: stat() });
153
+ const owners = new LibraryPanel({ name: "Owners", uid: "owners", panel: stat() });
154
+ const team = new Dashboard({
155
+ title: "Team",
156
+ uid: "team",
157
+ folder: "Team A",
158
+ panels: [burn, owners, new LibraryPanelRef({ libraryPanel: { uid: "in-grafana", name: "Already there" } })],
159
+ });
160
+ const other = new Dashboard({ title: "Other", uid: "other", panels: [burn] });
161
+ const docs = ops({ entities: [prometheus, team, other] });
162
+ expect(docs.map((d) => [d.kind, d.metadata.name])).toEqual([
163
+ ["GrafanaFolder", "grafana-folder-slos"],
164
+ ["GrafanaFolder", "grafana-folder-team-a"],
165
+ ["GrafanaLibraryPanel", "grafana-library-panel-burn-rate"],
166
+ ["GrafanaLibraryPanel", "grafana-library-panel-owners"],
167
+ ["GrafanaDashboard", "grafana-dashboard-team"],
168
+ ["GrafanaDashboard", "grafana-dashboard-other"],
169
+ ["GrafanaDatasource", `grafana-datasource-${prometheus.uid}`],
170
+ ]);
171
+ const [, , burnDoc, ownersDoc] = docs;
172
+ // The LibraryPanel's own folder; one without a folder goes in the first dashboard's, as the API applier puts it.
173
+ expect(burnDoc.spec).toMatchObject({ instanceSelector: selector, uid: "burn-rate", folderRef: "grafana-folder-slos" });
174
+ expect(ownersDoc.spec).toMatchObject({ instanceSelector: selector, uid: "owners", folderRef: "grafana-folder-team-a" });
175
+ // The operator reads the element's name and uid from the model; the model is the panel as __elements carries it.
176
+ const element = (JSON.parse(dashboardJson(team)) as { __elements: Record<string, { model: Record<string, unknown> }> }).__elements["burn-rate"];
177
+ expect(JSON.parse(burnDoc.spec.json as string)).toEqual({ ...element.model, name: "Burn rate", uid: "burn-rate" });
178
+ });
179
+
150
180
  test("datasource secrets become valuesFrom entries reading the Secret", () => {
151
181
  const loki = new Datasource({
152
182
  name: "Loki",
package/src/k8s.ts CHANGED
@@ -22,9 +22,10 @@
22
22
  *
23
23
  * A Grafana run by the Grafana Operator reads custom resources instead
24
24
  * (#3015): `GrafanaOperatorResources` writes a `GrafanaDashboard` per
25
- * dashboard, a `GrafanaDatasource` per datasource and a `GrafanaFolder` per
26
- * folder, all `grafana.integreatly.org/v1beta1` as the k8s lexicon types
27
- * them from the operator's CRDs (pinned in its `crd-sources.ts`).
25
+ * dashboard, a `GrafanaDatasource` per datasource, a `GrafanaFolder` per
26
+ * folder and a `GrafanaLibraryPanel` per library panel (#3186), all
27
+ * `grafana.integreatly.org/v1beta1` as the k8s lexicon types them from the
28
+ * operator's CRDs (pinned in its `crd-sources.ts`).
28
29
  *
29
30
  * This module is the only part of the grafana lexicon that loads the k8s
30
31
  * lexicon; nothing else imports it.
@@ -32,8 +33,9 @@
32
33
 
33
34
  import { Composite, type CompositeInstance } from "@intentius/chant/composite";
34
35
  import type { Declarable } from "@intentius/chant/declarable";
35
- import { ConfigMap, GrafanaDashboard, GrafanaDatasource, GrafanaFolder } from "@intentius/chant-lexicon-k8s/generated/index";
36
+ import { ConfigMap, GrafanaDashboard, GrafanaDatasource, GrafanaFolder, GrafanaLibraryPanel } from "@intentius/chant-lexicon-k8s/generated/index";
36
37
  import { buildGrafana, DASHBOARD_PROVIDERS_FILE, DASHBOARDS_DIR, DATASOURCES_FILE, type ProvisionedDatasource } from "./build";
38
+ import { libraryPanelsOf, type LibraryPanelPlan } from "./api/library-panels";
37
39
  import { DEFAULT_DASHBOARDS_PATH } from "./dashboard";
38
40
 
39
41
  /** The label the Grafana Helm chart's sidecar looks for on dashboard ConfigMaps (`sidecar.dashboards.label`). */
@@ -211,7 +213,7 @@ export interface GrafanaInstanceSelector {
211
213
  }
212
214
 
213
215
  export interface GrafanaOperatorResourcesProps {
214
- /** The grafana declarations to deliver: dashboards, datasources and `Folder`s. Anything else is ignored. */
216
+ /** The grafana declarations to deliver: dashboards (with the library panels they place), datasources and `Folder`s. Anything else is ignored. */
215
217
  entities: Iterable<Declarable>;
216
218
  /**
217
219
  * Which `Grafana` resources pick these up, usually the labels on your
@@ -247,7 +249,13 @@ export interface GrafanaOperatorResourcesProps {
247
249
  secretName?: string;
248
250
  }
249
251
 
250
- type OperatorEntity = (InstanceType<typeof GrafanaDashboard> | InstanceType<typeof GrafanaDatasource> | InstanceType<typeof GrafanaFolder>) & Declarable;
252
+ type OperatorEntity = (
253
+ | InstanceType<typeof GrafanaDashboard>
254
+ | InstanceType<typeof GrafanaDatasource>
255
+ | InstanceType<typeof GrafanaFolder>
256
+ | InstanceType<typeof GrafanaLibraryPanel>
257
+ ) &
258
+ Declarable;
251
259
 
252
260
  export type GrafanaOperatorResourcesMembers = Record<string, OperatorEntity>;
253
261
  export type GrafanaOperatorResourcesInstance = CompositeInstance<GrafanaOperatorResourcesMembers> & GrafanaOperatorResourcesMembers;
@@ -313,6 +321,11 @@ export function operatorDatasource(
313
321
  *
314
322
  * - a `GrafanaFolder` per folder, `<name>-folder-<uid>`, with the folder's uid,
315
323
  * its title, and its parent as `parentFolderRef`;
324
+ * - a `GrafanaLibraryPanel` per library panel the dashboards place,
325
+ * `<name>-library-panel-<uid>`, holding its model with its `name` and `uid`
326
+ * in `spec.json` and naming its folder with `folderRef`. File provisioning
327
+ * and a `GrafanaDashboard`'s `__elements` do not create library panels, so
328
+ * without these a dashboard's library panel references stay empty;
316
329
  * - a `GrafanaDashboard` per dashboard, `<name>-dashboard-<uid>`, holding
317
330
  * `dashboardJson(dashboard)` in `spec.json` and naming its folder with
318
331
  * `folderRef`;
@@ -356,6 +369,25 @@ export const GrafanaOperatorResources = Composite<GrafanaOperatorResourcesProps,
356
369
  }) as OperatorEntity;
357
370
  }
358
371
 
372
+ // Library panels next, each once. Its folder is the one its `LibraryPanel`
373
+ // names, else that of the first dashboard placing it, as the API applier does.
374
+ const libraryPanels = new Map<string, LibraryPanelPlan>();
375
+ for (const d of built.dashboards) {
376
+ for (const lp of libraryPanelsOf(d.json as unknown as Record<string, unknown>, d.folderUid).panels) {
377
+ if (!libraryPanels.has(lp.uid)) libraryPanels.set(lp.uid, lp);
378
+ }
379
+ }
380
+ for (const lp of libraryPanels.values()) {
381
+ const name = unique(`${prefix}-library-panel-${lp.uid}`);
382
+ const folder = lp.folderUid !== undefined ? folderRef.get(lp.folderUid) : undefined;
383
+ const placement = folder ? { folderRef: folder } : lp.folderUid !== undefined ? { folderUID: lp.folderUid } : {};
384
+ members[memberName(name, prefix)] = new GrafanaLibraryPanel({
385
+ metadata: metadata(name),
386
+ // The operator takes the element's name from the model's `name`, and its uid from `spec.uid` (else the model's).
387
+ spec: { ...common, uid: lp.uid, json: JSON.stringify({ ...lp.model, name: lp.name, uid: lp.uid }, null, 2), ...placement },
388
+ }) as OperatorEntity;
389
+ }
390
+
359
391
  const configMaps = props.dashboardSource === "configMap" ? grafanaConfigMapLayout({ entities: props.entities, name: prefix }).dashboards : undefined;
360
392
  built.dashboards.forEach((d, i) => {
361
393
  const name = unique(`${prefix}-dashboard-${d.uid}`);
@@ -2,7 +2,7 @@
2
2
  * The grafana lexicon's chant audit catalog, contributed via
3
3
  * `grafanaPlugin.auditCatalog()` (#687, #1346).
4
4
  *
5
- * GRAF101-GRAF110, GRAF111-GRAF114 and GRAF115-GRAF117 read the emitted dashboard
5
+ * GRAF101-GRAF110, GRAF111-GRAF114 and GRAF115-GRAF118 read the emitted dashboard
6
6
  * JSON and provisioning files (alerting included), so
7
7
  * they fire on an audit of files chant didn't build too, and are
8
8
  * `yamlBased`. GRAF001 and GRAF002 read TypeScript source, so they are
@@ -166,6 +166,14 @@ export const grafanaAuditCatalog: Record<string, RuleMeta> = {
166
166
  "Fix the query at the offset the message names: an unclosed { } spanset or quote, an operator with no value, an unknown intrinsic. Grafana's TraceQL grammar can trail Tempo's, so check newer syntax against Tempo itself before changing a query that runs.",
167
167
  { category: "correctness" },
168
168
  ),
169
+ GRAF118: auditRule(
170
+ "GRAF118",
171
+ "merge-worthy",
172
+ "guidance",
173
+ "Panel reads a connector metric no collector in the build emits",
174
+ "Read the name spanMetricsNames(), serviceGraphNames() or genAiMetrics() gives for the declared connector, and group by its declared dimensions, or add the dimension to the connector.",
175
+ { category: "correctness" },
176
+ ),
169
177
  };
170
178
 
171
179
  // Prior art credits live beside the rules in ./audit-lineage.ts (see core audit/prior-art.ts).
@@ -0,0 +1,70 @@
1
+ /**
2
+ * GRAF118 (#3364): panel queries under a connector namespace against what the
3
+ * build's collector configs emit, through the prometheus lexicon's helper.
4
+ */
5
+ import { describe, expect, test } from "vitest";
6
+ import { makePostSynthCtxFromFiles } from "@intentius/chant-test-utils";
7
+ import type { Declarable } from "@intentius/chant/declarable";
8
+ import { PrometheusExporter, SpanMetricsConnector } from "@intentius/chant-lexicon-otel/components/index";
9
+ import { genAiComponents, genAiPipeline, type GenAiMetricsOptions } from "@intentius/chant-lexicon-otel/genai";
10
+ import { GenAiRules } from "@intentius/chant-lexicon-prometheus/composites/genai";
11
+ import { grafanaSerializer } from "../../serializer";
12
+ import { Datasource } from "../../datasource";
13
+ import { Dashboard } from "../../dashboard";
14
+ import { TimeSeriesPanel } from "../../panels";
15
+ import { PromQuery } from "../../query";
16
+ import { AgentDashboard, RedDashboard } from "../../composites/index";
17
+ import { graf118 } from "./graf118";
18
+
19
+ const prometheus = new Datasource({ name: "Prometheus", type: "prometheus", url: "http://prometheus:9090" });
20
+
21
+ /** Serialize the grafana entities the way a build does; every entity, the collector's included, is in the context. */
22
+ function check(...list: Declarable[]): string[] {
23
+ const entities = new Map(list.map((e, i) => [`e${i}`, e] as [string, Declarable]));
24
+ const out = grafanaSerializer.serialize(entities);
25
+ if (typeof out === "string") throw new Error("expected files");
26
+ return graf118.check(makePostSynthCtxFromFiles("grafana", out.files!, out.primary, entities)).map((d) => d.message);
27
+ }
28
+
29
+ const panel = (expr: string) =>
30
+ new Dashboard({ title: "D", panels: [new TimeSeriesPanel({ title: "p", datasource: prometheus, targets: [new PromQuery({ expr })] })] });
31
+
32
+ describe("GRAF118", () => {
33
+ test("a panel reading a spanmetrics name no connector emits, or grouping by an undeclared label", () => {
34
+ const spans = new SpanMetricsConnector({ namespace: "shop" });
35
+ expect(check(prometheus, spans, panel("sum(rate(traces_span_metrics_calls_total[$__rate_interval]))"))).toEqual([
36
+ 'Dashboard "D" panel "p" (id 1) query A reads traces_span_metrics_calls_total, which no collector config in the build emits under traces_span_metrics.',
37
+ ]);
38
+ expect(check(prometheus, spans, panel("sum by (http_route) (rate(shop_calls_total[$__rate_interval]))"))).toHaveLength(1);
39
+ expect(check(prometheus, spans, panel('sum by (service_name) (rate(shop_calls_total{service_name=~"$service"}[$__rate_interval]))'))).toEqual([]);
40
+ });
41
+
42
+ test("silent without a collector config, and for names outside the namespaces", () => {
43
+ expect(check(prometheus, panel("sum(rate(traces_span_metrics_calls_total[5m]))"))).toEqual([]);
44
+ expect(check(prometheus, new SpanMetricsConnector({}), panel("sum(rate(http_requests_total[5m]))"))).toEqual([]);
45
+ });
46
+ });
47
+
48
+ describe("GRAF118 on the lexicon's own dashboards", () => {
49
+ const exporter = () => new PrometheusExporter({ endpoint: "0.0.0.0:8889" });
50
+
51
+ test("RedDashboard over its connector, with and without an exporter namespace", () => {
52
+ const spans = new SpanMetricsConnector({ namespace: "shop", histogram: { unit: "s" } });
53
+ expect(check(prometheus, spans, RedDashboard({ spanMetrics: spans, datasource: prometheus }).dashboard)).toEqual([]);
54
+ const plain = new SpanMetricsConnector({});
55
+ const named = new PrometheusExporter({ endpoint: "0.0.0.0:8889", namespace: "otel" });
56
+ expect(check(prometheus, plain, named, RedDashboard({ spanMetrics: plain, exporter: named, datasource: prometheus }).dashboard)).toEqual([]);
57
+ });
58
+
59
+ test.each([
60
+ ["spans", {}],
61
+ ["derived client metrics", { clientMetrics: "derive" }],
62
+ ["provider dimensions and a namespace", { providerDimensions: true, namespace: "ai" }],
63
+ ] as Array<[string, GenAiMetricsOptions]>)("AgentDashboard over genAiPipeline with %s, from the metrics and from GenAiRules", (_label, options) => {
64
+ const collector = genAiPipeline({ ...options, metricExporters: [exporter()] });
65
+ const genAi = genAiComponents(options);
66
+ expect(check(prometheus, ...collector, AgentDashboard({ genAi, datasource: prometheus }).dashboard)).toEqual([]);
67
+ const rules = GenAiRules({ genAi, alerts: { errorRatio: true } });
68
+ expect(check(prometheus, ...collector, AgentDashboard({ rules, datasource: prometheus }).dashboard)).toEqual([]);
69
+ });
70
+ });
@@ -0,0 +1,39 @@
1
+ /**
2
+ * GRAF118: A panel reads a connector metric no collector in the build emits
3
+ *
4
+ * The prometheus lexicon's PROM301, over dashboards: each panel query and query variable whose datasource resolves to a prometheus datasource, with its template variables replaced as GRAF108 replaces them, goes through `collectorMetricIssues` (prometheus `collector-metrics.ts`). A name under a namespace the build's spanmetrics, servicegraph or GenAI connectors own that no collector config emits is reported, and a by (...) label that is not a declared dimension. Silent for names outside those namespaces, and when the build has no collector config.
5
+ */
6
+
7
+ import type { PostSynthCheck, PostSynthContext, PostSynthDiagnostic } from "@intentius/chant/lint/post-synth";
8
+ import { buildCollectorConfigs, collectorMetricIssues, collectorMetrics } from "@intentius/chant-lexicon-prometheus/collector-metrics";
9
+ import { grafanaArtifacts } from "./grafana-helpers";
10
+ import { knownDatasourcesOf } from "../../validate-output";
11
+ import { prometheusQueries, substituteTemplateVariables } from "../../promql-check";
12
+
13
+ export const graf118: PostSynthCheck = {
14
+ id: "GRAF118",
15
+ description: "A panel reads a connector metric no collector in the build emits",
16
+
17
+ check(ctx: PostSynthContext): PostSynthDiagnostic[] {
18
+ const artifacts = grafanaArtifacts(ctx);
19
+ if (artifacts.dashboards.length === 0) return [];
20
+ const emitted = collectorMetrics(buildCollectorConfigs(ctx));
21
+ if (!emitted) return [];
22
+ const known = knownDatasourcesOf(artifacts);
23
+ const out: PostSynthDiagnostic[] = [];
24
+ for (const { json: d } of artifacts.dashboards) {
25
+ for (const { where, expr } of prometheusQueries(d, known)) {
26
+ for (const issue of collectorMetricIssues(substituteTemplateVariables(expr).text, emitted)) {
27
+ out.push({
28
+ checkId: "GRAF118",
29
+ severity: "warning",
30
+ message: `Dashboard "${String(d.title ?? d.uid ?? "?")}" ${where} ${issue.message}.`,
31
+ entity: String(d.uid ?? ""),
32
+ lexicon: "grafana",
33
+ });
34
+ }
35
+ }
36
+ }
37
+ return out;
38
+ },
39
+ };
@@ -17,6 +17,7 @@ import { graf114 } from "./graf114";
17
17
  import { graf115 } from "./graf115";
18
18
  import { graf116 } from "./graf116";
19
19
  import { graf117 } from "./graf117";
20
+ import { graf118 } from "./graf118";
20
21
 
21
22
  export const postSynthChecks: PostSynthCheck[] = [
22
23
  graf101,
@@ -36,4 +37,5 @@ export const postSynthChecks: PostSynthCheck[] = [
36
37
  graf115,
37
38
  graf116,
38
39
  graf117,
40
+ graf118,
39
41
  ];
@@ -29,7 +29,7 @@ describe("grafana plugin", () => {
29
29
 
30
30
  it("ships lint rules and post-synth checks, all under the GRAF prefix", () => {
31
31
  const ids = [...grafanaPlugin.lintRules!().map((r) => r.id), ...grafanaPlugin.postSynthChecks!().map((c) => c.id)];
32
- expect(ids).toEqual(["GRAF001", "GRAF002", "GRAF101", "GRAF102", "GRAF103", "GRAF104", "GRAF105", "GRAF106", "GRAF107", "GRAF108", "GRAF109", "GRAF110", "GRAF111", "GRAF112", "GRAF113", "GRAF114", "GRAF115", "GRAF116", "GRAF117"]);
32
+ expect(ids).toEqual(["GRAF001", "GRAF002", "GRAF101", "GRAF102", "GRAF103", "GRAF104", "GRAF105", "GRAF106", "GRAF107", "GRAF108", "GRAF109", "GRAF110", "GRAF111", "GRAF112", "GRAF113", "GRAF114", "GRAF115", "GRAF116", "GRAF117", "GRAF118"]);
33
33
  });
34
34
 
35
35
  it("catalogues every rule and check for chant audit, and nothing else", () => {
@@ -8,6 +8,7 @@ export interface Options {
8
8
  legend: VizLegendOptions;
9
9
  tooltip: VizTooltipOptions;
10
10
  orientation?: VizOrientation;
11
+ annotations?: VizAnnotations;
11
12
  }
12
13
 
13
14
  export type FieldConfig = GraphFieldConfig;
@@ -211,3 +212,20 @@ export type ScaleDistribution = "linear" | "log" | "ordinal" | "symlog";
211
212
  * TODO docs
212
213
  */
213
214
  export type StackingMode = "none" | "normal" | "percent";
215
+
216
+ export interface VizAnnotations {
217
+ /**
218
+ * Breaks out each annotation frame into multiple lanes on the x-axis
219
+ */
220
+ multiLane?: boolean;
221
+ /**
222
+ * Sets whether clustering is enabled. Any value > 0 will enable clustering.
223
+ */
224
+ clustering?: number;
225
+ lines?: {
226
+ width?: number;
227
+ };
228
+ regions?: {
229
+ opacity?: number;
230
+ };
231
+ }
@@ -244,6 +244,30 @@ describe("the issue's reproductions", () => {
244
244
  ]);
245
245
  });
246
246
 
247
+ test("options.annotations on a time series panel is typed and validates; trend and barchart leave it unknown (#3138)", () => {
248
+ const annotations = { multiLane: true, clustering: 1, lines: { width: 2 }, regions: { opacity: 0.2 } };
249
+ expect((((loadVendoredSchema("timeseries").definitions as Json).Options as Json).properties as Json).annotations).toBeUndefined();
250
+ const panel = new TimeSeriesPanel({ title: "Requests", datasource: prometheus, targets: [rate], options: { annotations } });
251
+ const json = renderDashboard(new Dashboard({ title: "Annotated", uid: "annotated", panels: [panel] })) as unknown as Json;
252
+ expect(validateDashboardSchema(json)).toEqual([]);
253
+ expect(((json.panels as Json[])[0].options as Json).annotations).toEqual(annotations);
254
+
255
+ const bad = structuredClone(json);
256
+ (((bad.panels as Json[])[0].options as Json).annotations as Json).clustering = "on";
257
+ expect(validateDashboardSchema(bad).map((p) => [p.severity, p.path])).toContainEqual(["error", "/panels/0/options/annotations/clustering"]);
258
+
259
+ // Grafana's CUE at the pin gives neither panel the field (trend/panelcfg.cue, barchart/panelcfg.cue).
260
+ for (const type of ["trend", "barchart"]) {
261
+ const other = structuredClone(json);
262
+ Object.assign((other.panels as Json[])[0], { type, options: { annotations } });
263
+ expect(validateDashboardSchema(other)).toContainEqual({
264
+ path: "/panels/0/options",
265
+ message: 'unknown key "annotations" (not in the pinned schema)',
266
+ severity: "warning",
267
+ });
268
+ }
269
+ });
270
+
247
271
  test("a table cellOptions matching several variants is accepted", () => {
248
272
  const panel = new TablePanel({ title: "T", fieldConfig: { defaults: { custom: { cellOptions: { type: "auto" } } } } });
249
273
  const json = renderDashboard(new Dashboard({ title: "Table", uid: "table", panels: [panel] })) as unknown as Json;
@@ -25,7 +25,7 @@ docker run -p 3000:3000 \
25
25
 
26
26
  ## Kubernetes
27
27
 
28
- Use `GrafanaConfigMaps({ entities, namespace })` from `@intentius/chant-lexicon-grafana/k8s` in a k8s build root. It writes one ConfigMap per dashboard labelled `grafana_dashboard: "1"`, with the folder in the `k8s-sidecar-target-directory` annotation. The datasource file goes in a ConfigMap labelled `grafana_datasource: "1"`, and the provider file in a third. The Grafana Helm chart's sidecar picks these up as they are. For a Grafana without the sidecar, spread `grafanaVolumes({ entities })`'s `volumes` and `volumeMounts` into the Deployment: provisioning goes under `/etc/grafana/provisioning`, and each dashboard folder gets a projected volume of its own. For a Grafana the Grafana Operator runs, use `GrafanaOperatorResources({ entities, namespace, instanceSelector })` instead: a `GrafanaFolder` per folder, a `GrafanaDashboard` per dashboard (JSON in `spec.json`, folder by `folderRef`) and a `GrafanaDatasource` per datasource. `instanceSelector` is required and must match the labels on your `Grafana` resource. A datasource secret written `${NAME}` or `$__env{NAME}` needs `secretName`, the Secret holding key `NAME`. `grafanaFiles(entities)` still returns every file by path for any other layout.
28
+ Use `GrafanaConfigMaps({ entities, namespace })` from `@intentius/chant-lexicon-grafana/k8s` in a k8s build root. It writes one ConfigMap per dashboard labelled `grafana_dashboard: "1"`, with the folder in the `k8s-sidecar-target-directory` annotation. The datasource file goes in a ConfigMap labelled `grafana_datasource: "1"`, and the provider file in a third. The Grafana Helm chart's sidecar picks these up as they are. For a Grafana without the sidecar, spread `grafanaVolumes({ entities })`'s `volumes` and `volumeMounts` into the Deployment: provisioning goes under `/etc/grafana/provisioning`, and each dashboard folder gets a projected volume of its own. For a Grafana the Grafana Operator runs, use `GrafanaOperatorResources({ entities, namespace, instanceSelector })` instead: a `GrafanaFolder` per folder, a `GrafanaLibraryPanel` per library panel the dashboards place, a `GrafanaDashboard` per dashboard (JSON in `spec.json`, folder by `folderRef`) and a `GrafanaDatasource` per datasource. `instanceSelector` is required and must match the labels on your `Grafana` resource. A datasource secret written `${NAME}` or `$__env{NAME}` needs `secretName`, the Secret holding key `NAME`. `grafanaFiles(entities)` still returns every file by path for any other layout.
29
29
 
30
30
  ## Changing where dashboards live
31
31
 
@@ -3,6 +3,29 @@
3
3
  "schema": "timeseries",
4
4
  "grafana": "v13.2.2",
5
5
  "patches": [
6
+ {
7
+ "op": "add",
8
+ "path": "/definitions/VizAnnotations",
9
+ "value": {
10
+ "type": "object",
11
+ "additionalProperties": false,
12
+ "properties": {
13
+ "multiLane": { "type": "boolean", "description": "Breaks out each annotation frame into multiple lanes on the x-axis" },
14
+ "clustering": { "type": "number", "description": "Sets whether clustering is enabled. Any value > 0 will enable clustering." },
15
+ "lines": { "type": "object", "additionalProperties": false, "properties": { "width": { "type": "number" } } },
16
+ "regions": { "type": "object", "additionalProperties": false, "properties": { "opacity": { "type": "number" } } }
17
+ }
18
+ },
19
+ "source": "packages/grafana-schema/src/common/mudball.cue:161 (VizAnnotations, with AnnotationDisplayOptions at :170)",
20
+ "why": "The time series CUE embeds common.OptionsWithAnnotations and declares annotations (public/app/plugins/panel/timeseries/panelcfg.cue:32 and :38); the vendored schema has no such type."
21
+ },
22
+ {
23
+ "op": "add",
24
+ "path": "/definitions/Options/properties/annotations",
25
+ "value": { "$ref": "#/definitions/VizAnnotations" },
26
+ "source": "packages/grafana-schema/src/common/mudball.cue:180 (OptionsWithAnnotations)",
27
+ "why": "Same: the vendored Options has timezone, legend, tooltip and orientation but not annotations."
28
+ },
6
29
  {
7
30
  "op": "add",
8
31
  "path": "/definitions/GraphFieldConfig/properties/showValues",
@@ -9,7 +9,7 @@ import type { SchemaName } from "../pin";
9
9
 
10
10
  export const SCHEMA_JSON: Readonly<Record<SchemaName, string>> = {
11
11
  "dashboard": "{\"$schema\":\"http://json-schema.org/draft-07/schema#\",\"$ref\":\"#/definitions/Dashboard\",\"definitions\":{\"AnnotationActions\":{\"type\":\"object\",\"additionalProperties\":false,\"properties\":{\"canAdd\":{\"type\":\"boolean\"},\"canDelete\":{\"type\":\"boolean\"},\"canEdit\":{\"type\":\"boolean\"}}},\"AnnotationPermission\":{\"type\":\"object\",\"additionalProperties\":false,\"properties\":{\"dashboard\":{\"$ref\":\"#/definitions/AnnotationActions\"},\"organization\":{\"$ref\":\"#/definitions/AnnotationActions\"}}},\"DashboardMeta\":{\"type\":\"object\",\"additionalProperties\":false,\"properties\":{\"annotationsPermissions\":{\"$ref\":\"#/definitions/AnnotationPermission\"},\"apiVersion\":{\"type\":\"string\"},\"canAdmin\":{\"type\":\"boolean\"},\"canDelete\":{\"type\":\"boolean\"},\"canEdit\":{\"type\":\"boolean\"},\"canSave\":{\"type\":\"boolean\"},\"canStar\":{\"type\":\"boolean\"},\"created\":{\"type\":\"string\",\"format\":\"date-time\"},\"createdBy\":{\"type\":\"string\"},\"expires\":{\"type\":\"string\",\"format\":\"date-time\"},\"folderId\":{\"type\":\"integer\",\"description\":\"Deprecated: use FolderUID instead\"},\"folderTitle\":{\"type\":\"string\"},\"folderUid\":{\"type\":\"string\"},\"folderUrl\":{\"type\":\"string\"},\"hasAcl\":{\"type\":\"boolean\"},\"isFolder\":{\"type\":\"boolean\"},\"isSnapshot\":{\"type\":\"boolean\"},\"isStarred\":{\"type\":\"boolean\"},\"provisioned\":{\"type\":\"boolean\"},\"provisionedExternalId\":{\"type\":\"string\"},\"publicDashboardEnabled\":{\"type\":\"boolean\"},\"slug\":{\"type\":\"string\"},\"type\":{\"type\":\"string\"},\"updated\":{\"type\":\"string\",\"format\":\"date-time\"},\"updatedBy\":{\"type\":\"string\"},\"url\":{\"type\":\"string\"},\"version\":{\"type\":\"integer\"}}},\"Dashboard\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"schemaVersion\"],\"properties\":{\"id\":{\"anyOf\":[{\"type\":\"integer\"},{\"type\":\"null\"}],\"description\":\"Unique numeric identifier for the dashboard.\\n`id` is internal to a specific Grafana instance. `uid` should be used to identify a dashboard across Grafana instances.\\nTODO eliminate this null option\"},\"uid\":{\"type\":\"string\",\"description\":\"Unique dashboard identifier that can be generated by anyone. string (8-40)\"},\"title\":{\"type\":\"string\",\"description\":\"Title of dashboard.\"},\"description\":{\"type\":\"string\",\"description\":\"Description of dashboard.\"},\"revision\":{\"type\":\"integer\",\"description\":\"This property should only be used in dashboards defined by plugins. It is a quick check\\nto see if the version has changed since the last time.\"},\"gnetId\":{\"anyOf\":[{\"type\":\"string\"},{\"type\":\"integer\"},{\"type\":\"null\"}],\"description\":\"ID of a dashboard imported from the https://grafana.com/grafana/dashboards/ portal. A string in Grafana 12.4, an integer in 13.x; grafana.com downloads carry null.\"},\"tags\":{\"type\":\"array\",\"items\":{\"type\":\"string\"},\"description\":\"Tags associated with dashboard.\"},\"timezone\":{\"type\":\"string\",\"description\":\"Timezone of dashboard. Accepted values are IANA TZDB zone ID or \\\"browser\\\" or \\\"utc\\\".\",\"default\":\"browser\"},\"editable\":{\"type\":\"boolean\",\"description\":\"Whether a dashboard is editable or not.\",\"default\":true},\"graphTooltip\":{\"$ref\":\"#/definitions/DashboardCursorSync\",\"description\":\"Configuration of dashboard cursor sync behavior.\\nAccepted values are 0 (sync turned off), 1 (shared crosshair), 2 (shared crosshair and tooltip).\",\"default\":0},\"time\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"from\",\"to\"],\"properties\":{\"from\":{\"type\":\"string\",\"default\":\"now-6h\"},\"to\":{\"type\":\"string\",\"default\":\"now\"}},\"description\":\"Time range for dashboard.\\nAccepted values are relative time strings like {from: 'now-6h', to: 'now'} or absolute time strings like {from: '2020-07-10T08:00:00.000Z', to: '2020-07-10T14:00:00.000Z'}.\"},\"timepicker\":{\"$ref\":\"#/definitions/TimePickerConfig\",\"description\":\"Configuration of the time picker shown at the top of a dashboard.\"},\"fiscalYearStartMonth\":{\"type\":\"integer\",\"exclusiveMaximum\":12,\"description\":\"The month that the fiscal year starts on. 0 = January, 11 = December\",\"default\":0},\"liveNow\":{\"type\":\"boolean\",\"description\":\"When set to true, the dashboard will redraw panels at an interval matching the pixel width.\\nThis will keep data \\\"moving left\\\" regardless of the query refresh rate. This setting helps\\navoid dashboards presenting stale live data\"},\"weekStart\":{\"type\":\"string\",\"description\":\"Day when the week starts. Expressed by the name of the day in lowercase, e.g. \\\"monday\\\".\"},\"refresh\":{\"type\":\"string\",\"description\":\"Refresh rate of dashboard. Represented via interval string, e.g. \\\"5s\\\", \\\"1m\\\", \\\"1h\\\", \\\"1d\\\".\"},\"schemaVersion\":{\"type\":\"integer\",\"description\":\"Version of the JSON schema, incremented each time a Grafana update brings\\nchanges to said schema.\",\"default\":42},\"version\":{\"type\":\"integer\",\"description\":\"Version of the dashboard, incremented each time the dashboard is updated.\"},\"panels\":{\"type\":\"array\",\"items\":{\"oneOf\":[{\"$ref\":\"#/definitions/Panel\"},{\"$ref\":\"#/definitions/RowPanel\"}]},\"description\":\"List of dashboard panels\"},\"templating\":{\"type\":\"object\",\"additionalProperties\":false,\"properties\":{\"list\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/definitions/VariableModel\"},\"description\":\"List of configured template variables with their saved values along with some other metadata\"}},\"description\":\"Configured template variables\"},\"annotations\":{\"$ref\":\"#/definitions/AnnotationContainer\",\"description\":\"Contains the list of annotations that are associated with the dashboard.\\nAnnotations are used to overlay event markers and overlay event tags on graphs.\\nGrafana comes with a native annotation store and the ability to add annotation events directly from the graph panel or via the HTTP API.\\nSee https://grafana.com/docs/grafana/latest/dashboards/build-dashboards/annotate-visualizations/\"},\"links\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/definitions/DashboardLink\"},\"description\":\"Links with references to other dashboards or external websites.\"},\"snapshot\":{\"$ref\":\"#/definitions/Snapshot\",\"description\":\"Snapshot options. They are present only if the dashboard is a snapshot.\"},\"preload\":{\"type\":\"boolean\",\"description\":\"When set to true, the dashboard will load all panels in the dashboard when it's loaded.\"},\"__inputs\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/definitions/ExportInput\"},\"description\":\"Inputs the importer asks for (datasources, constants). Written by \\\"Export for sharing externally\\\".\"},\"__requires\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/definitions/ExportRequirement\"},\"description\":\"Plugins and the Grafana version the export needs. Written by \\\"Export for sharing externally\\\".\"},\"__elements\":{\"type\":\"object\",\"additionalProperties\":{\"$ref\":\"#/definitions/LibraryElementExport\"},\"description\":\"Library panels the export embeds, keyed by uid. Written by \\\"Export for sharing externally\\\".\"}},\"deprecated\":true,\"x-deprecation-message\":\"Prefer using dashboardv2.Dashboard instead.\"},\"DashboardCursorSync\":{\"enum\":[0,1,2],\"type\":\"integer\",\"description\":\"0 for no shared crosshair or tooltip (default).\\n1 for shared crosshair.\\n2 for shared crosshair AND shared tooltip.\"},\"TimePickerConfig\":{\"type\":\"object\",\"additionalProperties\":false,\"properties\":{\"hidden\":{\"type\":\"boolean\",\"description\":\"Whether timepicker is visible or not.\",\"default\":false},\"refresh_intervals\":{\"type\":\"array\",\"items\":{\"type\":\"string\"},\"description\":\"Interval options available in the refresh picker dropdown.\",\"default\":[\"5s\",\"10s\",\"30s\",\"1m\",\"5m\",\"15m\",\"30m\",\"1h\",\"2h\",\"1d\"]},\"quick_ranges\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/definitions/TimeOption\"},\"description\":\"Quick ranges for time picker.\"},\"nowDelay\":{\"type\":\"string\",\"description\":\"Override the now time by entering a time delay. Use this option to accommodate known delays in data aggregation to avoid null values.\"}},\"description\":\"Time picker configuration\\nIt defines the default config for the time picker and the refresh picker for the specific dashboard.\"},\"TimeOption\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"display\",\"from\",\"to\"],\"properties\":{\"display\":{\"type\":\"string\"},\"from\":{\"type\":\"string\"},\"to\":{\"type\":\"string\"}},\"description\":\"Counterpart for TypeScript's TimeOption type.\"},\"Panel\":{\"type\":\"object\",\"additionalProperties\":false,\"properties\":{\"type\":{\"type\":\"string\",\"minLength\":1,\"description\":\"The panel plugin type id. This is used to find the plugin to display the panel.\"},\"id\":{\"type\":\"integer\",\"description\":\"Unique identifier of the panel. Generated by Grafana when creating a new panel. It must be unique within a dashboard, but not globally.\"},\"pluginVersion\":{\"type\":\"string\",\"description\":\"The version of the plugin that is used for this panel. This is used to find the plugin to display the panel and to migrate old panel configs.\"},\"targets\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"additionalProperties\":{}},\"description\":\"Depends on the panel plugin. See the plugin documentation for details.\"},\"title\":{\"type\":\"string\",\"description\":\"Panel title.\"},\"description\":{\"type\":\"string\",\"description\":\"Panel description.\"},\"transparent\":{\"type\":\"boolean\",\"description\":\"Whether to display the panel without a background.\",\"default\":false},\"datasource\":{\"$ref\":\"#/definitions/DataSourceRef\",\"description\":\"The datasource used in all targets.\"},\"gridPos\":{\"$ref\":\"#/definitions/GridPos\",\"description\":\"Grid position.\"},\"links\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/definitions/PanelLink\"},\"description\":\"Panel links.\"},\"repeat\":{\"type\":\"string\",\"description\":\"Name of template variable to repeat for.\"},\"repeatDirection\":{\"enum\":[\"h\",\"v\"],\"type\":\"string\",\"description\":\"Direction to repeat in if 'repeat' is set.\\n`h` for horizontal, `v` for vertical.\",\"default\":\"h\"},\"maxPerRow\":{\"type\":\"number\",\"description\":\"Option for repeated panels that controls max items per row\\nOnly relevant for horizontally repeated panels\"},\"maxDataPoints\":{\"type\":\"number\",\"description\":\"The maximum number of data points that the panel queries are retrieving.\"},\"transformations\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/definitions/DataTransformerConfig\"},\"description\":\"List of transformations that are applied to the panel data before rendering.\\nWhen there are multiple transformations, Grafana applies them in the order they are listed.\\nEach transformation creates a result set that then passes on to the next transformation in the processing pipeline.\"},\"interval\":{\"type\":\"string\",\"description\":\"The min time interval setting defines a lower limit for the $__interval and $__interval_ms variables.\\nThis value must be formatted as a number followed by a valid time\\nidentifier like: \\\"40s\\\", \\\"3d\\\", etc.\\nSee: https://grafana.com/docs/grafana/latest/panels-visualizations/query-transform-data/#query-options\"},\"timeFrom\":{\"type\":\"string\",\"description\":\"Overrides the relative time range for individual panels,\\nwhich causes them to be different than what is selected in\\nthe dashboard time picker in the top-right corner of the dashboard. You can use this to show metrics from different\\ntime periods or days on the same dashboard.\\nThe value is formatted as time operation like: `now-5m` (Last 5 minutes), `now/d` (the day so far),\\n`now-5d/d`(Last 5 days), `now/w` (This week so far), `now-2y/y` (Last 2 years).\\nNote: Panel time overrides have no effect when the dashboard’s time range is absolute.\\nSee: https://grafana.com/docs/grafana/latest/panels-visualizations/query-transform-data/#query-options\"},\"timeShift\":{\"type\":\"string\",\"description\":\"Overrides the time range for individual panels by shifting its start and end relative to the time picker.\\nFor example, you can shift the time range for the panel to be two hours earlier than the dashboard time picker setting `2h`.\\nNote: Panel time overrides have no effect when the dashboard’s time range is absolute.\\nSee: https://grafana.com/docs/grafana/latest/panels-visualizations/query-transform-data/#query-options\"},\"hideTimeOverride\":{\"type\":\"boolean\",\"description\":\"Controls if the timeFrom or timeShift overrides are shown in the panel header\"},\"timeCompare\":{\"type\":\"string\",\"description\":\"Compare the current time range with a previous period\\nFor example \\\"1d\\\" to compare current period but shifted back 1 day\"},\"libraryPanel\":{\"$ref\":\"#/definitions/LibraryPanelRef\",\"description\":\"Dynamically load the panel\"},\"cacheTimeout\":{\"type\":\"string\",\"description\":\"Sets panel queries cache timeout.\"},\"queryCachingTTL\":{\"type\":\"number\",\"description\":\"Overrides the data source configured time-to-live for a query cache item in milliseconds\"},\"options\":{\"type\":\"object\",\"additionalProperties\":{},\"description\":\"It depends on the panel plugin. They are specified by the Options field in panel plugin schemas.\"},\"fieldConfig\":{\"$ref\":\"#/definitions/FieldConfigSource\",\"description\":\"Field options allow you to change how the data is displayed in your visualizations.\"}},\"description\":\"Dashboard panels are the basic visualization building blocks.\",\"anyOf\":[{\"required\":[\"type\"]},{\"required\":[\"libraryPanel\"]}]},\"DataSourceRef\":{\"type\":\"object\",\"additionalProperties\":false,\"properties\":{\"type\":{\"type\":\"string\",\"description\":\"The plugin type-id\"},\"uid\":{\"type\":\"string\",\"description\":\"Specific datasource instance\"}}},\"GridPos\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"h\",\"w\",\"x\",\"y\"],\"properties\":{\"h\":{\"type\":\"integer\",\"exclusiveMinimum\":0,\"description\":\"Panel height. The height is the number of rows from the top edge of the panel.\",\"default\":9},\"w\":{\"type\":\"integer\",\"exclusiveMinimum\":0,\"maximum\":24,\"description\":\"Panel width. The width is the number of columns from the left edge of the panel.\",\"default\":12},\"x\":{\"type\":\"integer\",\"minimum\":0,\"exclusiveMaximum\":24,\"description\":\"Panel x. The x coordinate is the number of columns from the left edge of the grid\",\"default\":0},\"y\":{\"type\":\"integer\",\"minimum\":0,\"description\":\"Panel y. The y coordinate is the number of rows from the top edge of the grid\",\"default\":0},\"static\":{\"type\":\"boolean\",\"description\":\"Whether the panel is fixed within the grid. If true, the panel will not be affected by other panels' interactions\"}},\"description\":\"Position and dimensions of a panel in the grid\"},\"DashboardLink\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"title\",\"type\",\"icon\",\"tooltip\",\"tags\"],\"properties\":{\"title\":{\"type\":\"string\",\"description\":\"Title to display with the link\"},\"type\":{\"$ref\":\"#/definitions/DashboardLinkType\",\"description\":\"Link type. Accepted values are dashboards (to refer to another dashboard) and link (to refer to an external resource)\"},\"icon\":{\"type\":\"string\",\"description\":\"Icon name to be displayed with the link\"},\"tooltip\":{\"type\":\"string\",\"description\":\"Tooltip to display when the user hovers their mouse over it\"},\"url\":{\"type\":\"string\",\"description\":\"Link URL. Only required/valid if the type is link\"},\"tags\":{\"type\":\"array\",\"items\":{\"type\":\"string\"},\"description\":\"List of tags to limit the linked dashboards. If empty, all dashboards will be displayed. Only valid if the type is dashboards\"},\"asDropdown\":{\"type\":\"boolean\",\"description\":\"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\",\"default\":false},\"placement\":{\"allOf\":[{\"$ref\":\"#/definitions/DashboardLinkPlacement\"}],\"default\":\"inControlsMenu\",\"description\":\"Placement can be used to display the link somewhere else on the dashboard other than above the visualisations.\"},\"targetBlank\":{\"type\":\"boolean\",\"description\":\"If true, the link will be opened in a new tab\",\"default\":false},\"includeVars\":{\"type\":\"boolean\",\"description\":\"If true, includes current template variables values in the link as query params\",\"default\":false},\"keepTime\":{\"type\":\"boolean\",\"description\":\"If true, includes current time range in the link as query params\",\"default\":false},\"origin\":{\"$ref\":\"#/definitions/ControlSourceRef\",\"description\":\"The source that registered the link (if any)\"}},\"description\":\"Links with references to other dashboards or external resources\"},\"DashboardLinkType\":{\"enum\":[\"link\",\"dashboards\"],\"type\":\"string\",\"description\":\"Dashboard Link type. Accepted values are dashboards (to refer to another dashboard) and link (to refer to an external resource)\"},\"DashboardLinkPlacement\":{\"enum\":[\"inControlsMenu\"],\"type\":\"string\",\"description\":\"Dashboard Link placement. Defines where the link should be displayed.\\n- \\\"inControlsMenu\\\" renders the link in bottom part of the dashboard controls dropdown menu\"},\"DataTransformerConfig\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"id\",\"options\"],\"properties\":{\"id\":{\"type\":\"string\",\"description\":\"Unique identifier of transformer\"},\"disabled\":{\"type\":\"boolean\",\"description\":\"Disabled transformations are skipped\"},\"filter\":{\"$ref\":\"#/definitions/MatcherConfig\",\"description\":\"Optional frame matcher. When missing it will be applied to all results\"},\"topic\":{\"enum\":[\"series\",\"annotations\",\"alertStates\"],\"type\":\"string\",\"description\":\"Where to pull DataFrames from as input to transformation\\nreplaced with common.DataTopic\"},\"options\":{\"description\":\"Options to be passed to the transformer\\nValid options depend on the transformer id\"}},\"description\":\"Transformations allow to manipulate data returned by a query before the system applies a visualization.\\nUsing transformations you can: rename fields, join time series data, perform mathematical operations across queries,\\nuse the output of one transformation as the input to another transformation, etc.\"},\"MatcherConfig\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"id\"],\"properties\":{\"id\":{\"type\":\"string\",\"description\":\"The matcher id. This is used to find the matcher implementation from registry.\",\"default\":\"\"},\"options\":{\"description\":\"The matcher options. This is specific to the matcher implementation: a field name for byName, a pattern for byRegexp, an object for byNames or byValue.\"},\"scope\":{\"$ref\":\"#/definitions/MatcherScope\",\"description\":\"If set, limits this matcher to fields of that type. If not set, \\\"series\\\" mode is used.\"}},\"description\":\"Matcher is a predicate configuration. Based on the config a set of field(s) or values is filtered in order to apply override / transformation.\\nIt comes with in id ( to resolve implementation from registry) and a configuration that’s specific to a particular matcher type.\"},\"LibraryPanelRef\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"name\",\"uid\"],\"properties\":{\"name\":{\"type\":\"string\",\"description\":\"Library panel name\"},\"uid\":{\"type\":\"string\",\"description\":\"Library panel uid\"}},\"description\":\"A library panel is a reusable panel that you can use in any dashboard.\\nWhen you make a change to a library panel, that change propagates to all instances of where the panel is used.\\nLibrary panels streamline reuse of panels across multiple dashboards.\"},\"FieldConfigSource\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"defaults\",\"overrides\"],\"properties\":{\"defaults\":{\"$ref\":\"#/definitions/FieldConfig\",\"description\":\"Defaults are the options applied to all fields.\"},\"overrides\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"matcher\",\"properties\"],\"properties\":{\"__systemRef\":{\"type\":\"string\"},\"matcher\":{\"$ref\":\"#/definitions/MatcherConfig\"},\"properties\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/definitions/DynamicConfigValue\"}}}},\"description\":\"Overrides are the options applied to specific fields overriding the defaults.\"}},\"description\":\"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.\\nEach column within this structure is called a field. A field can represent a single time series or table column.\\nField options allow you to change how the data is displayed in your visualizations.\"},\"FieldConfig\":{\"type\":\"object\",\"additionalProperties\":false,\"properties\":{\"displayName\":{\"type\":\"string\",\"description\":\"The display value for this field. This supports template variables blank is auto\"},\"displayNameFromDS\":{\"type\":\"string\",\"description\":\"This can be used by data sources that return and explicit naming structure for values and labels\\nWhen this property is configured, this value is used rather than the default naming strategy.\"},\"description\":{\"type\":\"string\",\"description\":\"Human readable field metadata\"},\"path\":{\"type\":\"string\",\"description\":\"An explicit path to the field in the datasource. When the frame meta includes a path,\\nThis will default to `${frame.meta.path}/${field.name}\\n\\nWhen defined, this value can be used as an identifier within the datasource scope, and\\nmay be used to update the results\"},\"writeable\":{\"type\":\"boolean\",\"description\":\"True if data source can write a value to the path. Auth/authz are supported separately\"},\"filterable\":{\"type\":\"boolean\",\"description\":\"True if data source field supports ad-hoc filters\"},\"unit\":{\"type\":\"string\",\"description\":\"Unit a field should use. The unit you select is applied to all fields except time.\\nYou can use the units ID availables in Grafana or a custom unit.\\nAvailable units in Grafana: https://github.com/grafana/grafana/blob/main/packages/grafana-data/src/valueFormats/categories.ts\\nAs custom unit, you can use the following formats:\\n`suffix:<suffix>` for custom unit that should go after value.\\n`prefix:<prefix>` for custom unit that should go before value.\\n`time:<format>` For custom date time formats type for example `time:YYYY-MM-DD`.\\n`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.\\n`count:<unit>` for a custom count unit.\\n`currency:<unit>` for custom a currency unit.\"},\"decimals\":{\"type\":\"number\",\"description\":\"Specify the number of decimals Grafana includes in the rendered value.\\nIf you leave this field blank, Grafana automatically truncates the number of decimals based on the value.\\nFor example 1.1234 will display as 1.12 and 100.456 will display as 100.\\nTo display all decimals, set the unit to `String`.\"},\"min\":{\"type\":\"number\",\"description\":\"The minimum value used in percentage threshold calculations. Leave blank for auto calculation based on all series and fields.\"},\"max\":{\"type\":\"number\",\"description\":\"The maximum value used in percentage threshold calculations. Leave blank for auto calculation based on all series and fields.\"},\"mappings\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/definitions/ValueMapping\"},\"description\":\"Convert input values into a display string\"},\"thresholds\":{\"$ref\":\"#/definitions/ThresholdsConfig\",\"description\":\"Map numeric values to states\"},\"color\":{\"$ref\":\"#/definitions/FieldColor\",\"description\":\"Panel color configuration\"},\"links\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/definitions/DataLink\"},\"description\":\"The behavior when clicking on a result\"},\"actions\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/definitions/Action\"},\"description\":\"Define interactive HTTP requests that can be triggered from data visualizations.\"},\"noValue\":{\"type\":\"string\",\"description\":\"Alternative to empty string\"},\"custom\":{\"type\":\"object\",\"additionalProperties\":{},\"description\":\"custom is specified by the FieldConfig field\\nin panel plugin schemas.\"},\"fieldMinMax\":{\"type\":\"boolean\"}},\"description\":\"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.\\nEach column within this structure is called a field. A field can represent a single time series or table column.\\nField options allow you to change how the data is displayed in your visualizations.\"},\"ValueMapping\":{\"oneOf\":[{\"$ref\":\"#/definitions/ValueMap\"},{\"$ref\":\"#/definitions/RangeMap\"},{\"$ref\":\"#/definitions/RegexMap\"},{\"$ref\":\"#/definitions/SpecialValueMap\"}],\"description\":\"Allow to transform the visual representation of specific data values in a visualization, irrespective of their original units\"},\"ValueMap\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"type\",\"options\"],\"properties\":{\"type\":{\"allOf\":[{\"$ref\":\"#/definitions/MappingType\"}],\"default\":\"value\"},\"options\":{\"type\":\"object\",\"additionalProperties\":{\"$ref\":\"#/definitions/ValueMappingResult\"},\"description\":\"Map with <value_to_match>: ValueMappingResult. For example: { \\\"10\\\": { text: \\\"Perfection!\\\", color: \\\"green\\\" } }\"}},\"description\":\"Maps text values to a color or different display text and color.\\nFor example, you can configure a value mapping so that all instances of the value 10 appear as Perfection! rather than the number.\"},\"MappingType\":{\"enum\":[\"value\",\"range\",\"regex\",\"special\"],\"type\":\"string\",\"description\":\"Supported value mapping types\\n`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.\\n`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.\\n`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.\\n`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.\"},\"ValueMappingResult\":{\"type\":\"object\",\"additionalProperties\":false,\"properties\":{\"text\":{\"type\":\"string\",\"description\":\"Text to display when the value matches\"},\"color\":{\"type\":\"string\",\"description\":\"Text to use when the value matches\"},\"icon\":{\"type\":\"string\",\"description\":\"Icon to display when the value matches. Only specific visualizations.\"},\"index\":{\"type\":\"integer\",\"description\":\"Position in the mapping array. Only used internally.\"}},\"description\":\"Result used as replacement with text and color when the value matches\"},\"RangeMap\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"type\",\"options\"],\"properties\":{\"type\":{\"allOf\":[{\"$ref\":\"#/definitions/MappingType\"}],\"default\":\"range\"},\"options\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"from\",\"to\",\"result\"],\"properties\":{\"from\":{\"anyOf\":[{\"type\":\"number\"},{\"type\":\"null\"}],\"description\":\"Min value of the range. It can be null which means -Infinity\"},\"to\":{\"anyOf\":[{\"type\":\"number\"},{\"type\":\"null\"}],\"description\":\"Max value of the range. It can be null which means +Infinity\"},\"result\":{\"$ref\":\"#/definitions/ValueMappingResult\",\"description\":\"Config to apply when the value is within the range\"}},\"description\":\"Range to match against and the result to apply when the value is within the range\"}},\"description\":\"Maps numerical ranges to a display text and color.\\nFor 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.\"},\"RegexMap\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"type\",\"options\"],\"properties\":{\"type\":{\"allOf\":[{\"$ref\":\"#/definitions/MappingType\"}],\"default\":\"regex\"},\"options\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"pattern\",\"result\"],\"properties\":{\"pattern\":{\"type\":\"string\",\"description\":\"Regular expression to match against\"},\"result\":{\"$ref\":\"#/definitions/ValueMappingResult\",\"description\":\"Config to apply when the value matches the regex\"}},\"description\":\"Regular expression to match against and the result to apply when the value matches the regex\"}},\"description\":\"Maps regular expressions to replacement text and a color.\\nFor example, if a value is www.example.com, you can configure a regex value mapping so that Grafana displays www and truncates the domain.\"},\"SpecialValueMap\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"type\",\"options\"],\"properties\":{\"type\":{\"allOf\":[{\"$ref\":\"#/definitions/MappingType\"}],\"default\":\"special\"},\"options\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"match\",\"result\"],\"properties\":{\"match\":{\"$ref\":\"#/definitions/SpecialValueMatch\",\"description\":\"Special value to match against\"},\"result\":{\"$ref\":\"#/definitions/ValueMappingResult\",\"description\":\"Config to apply when the value matches the special value\"}}}},\"description\":\"Maps special values like Null, NaN (not a number), and boolean values like true and false to a display text and color.\\nSee SpecialValueMatch to see the list of special values.\\nFor example, you can configure a special value mapping so that null values appear as N/A.\"},\"SpecialValueMatch\":{\"enum\":[\"true\",\"false\",\"null\",\"nan\",\"null+nan\",\"empty\"],\"type\":\"string\",\"description\":\"Special value types supported by the `SpecialValueMap`\"},\"ThresholdsConfig\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"mode\",\"steps\"],\"properties\":{\"mode\":{\"$ref\":\"#/definitions/ThresholdsMode\",\"description\":\"Thresholds mode.\"},\"steps\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/definitions/Threshold\"},\"description\":\"Must be sorted by 'value', first value is always -Infinity\"}},\"description\":\"Thresholds configuration for the panel\"},\"ThresholdsMode\":{\"enum\":[\"absolute\",\"percentage\"],\"type\":\"string\",\"description\":\"Thresholds can either be `absolute` (specific number) or `percentage` (relative to min or max, it will be values between 0 and 1).\"},\"Threshold\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"color\"],\"properties\":{\"value\":{\"anyOf\":[{\"type\":\"number\"},{\"type\":\"null\"}],\"description\":\"Value represents a specified metric for the threshold, which triggers a visual change in the dashboard when this value is met or exceeded.\\nNulls currently appear here when serializing -Infinity to JSON.\"},\"color\":{\"type\":\"string\",\"description\":\"Color represents the color of the visual change that will occur in the dashboard when the threshold value is met or exceeded.\"},\"valueExpr\":{\"type\":\"string\",\"description\":\"Optional dashboard-variable expression (e.g. `$myVar`) resolved at render time; `value` is the numeric fallback when the expression cannot be resolved to a single finite number.\"}},\"description\":\"User-defined value for a metric that triggers visual changes in a panel when this value is met or exceeded\\nThey are used to conditionally style and color visualizations based on query results , and can be applied to most visualizations.\"},\"FieldColor\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"mode\"],\"properties\":{\"mode\":{\"$ref\":\"#/definitions/FieldColorModeId\",\"description\":\"The main color scheme mode.\"},\"fixedColor\":{\"type\":\"string\",\"description\":\"The fixed color value for fixed or shades color modes.\"},\"seriesBy\":{\"$ref\":\"#/definitions/FieldColorSeriesByMode\",\"description\":\"Some visualizations need to know how to assign a series color from by value color schemes.\"}},\"description\":\"Map a field to a color.\"},\"FieldColorModeId\":{\"enum\":[\"thresholds\",\"palette-classic\",\"palette-classic-by-name\",\"continuous-viridis\",\"continuous-magma\",\"continuous-plasma\",\"continuous-inferno\",\"continuous-cividis\",\"continuous-GrYlRd\",\"continuous-RdYlGr\",\"continuous-BlYlRd\",\"continuous-YlRd\",\"continuous-BlPu\",\"continuous-YlBl\",\"continuous-blues\",\"continuous-reds\",\"continuous-greens\",\"continuous-purples\",\"fixed\",\"shades\"],\"type\":\"string\",\"description\":\"Color mode for a field. You can specify a single color, or select a continuous (gradient) color schemes, based on a value.\\nContinuous color interpolates a color using the percentage of a value relative to min and max.\\nAccepted values are:\\n`thresholds`: From thresholds. Informs Grafana to take the color from the matching threshold\\n`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\\n`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\\n`continuous-GrYlRd`: ontinuous Green-Yellow-Red palette mode\\n`continuous-RdYlGr`: Continuous Red-Yellow-Green palette mode\\n`continuous-BlYlRd`: Continuous Blue-Yellow-Red palette mode\\n`continuous-YlRd`: Continuous Yellow-Red palette mode\\n`continuous-BlPu`: Continuous Blue-Purple palette mode\\n`continuous-YlBl`: Continuous Yellow-Blue palette mode\\n`continuous-blues`: Continuous Blue palette mode\\n`continuous-reds`: Continuous Red palette mode\\n`continuous-greens`: Continuous Green palette mode\\n`continuous-purples`: Continuous Purple palette mode\\n`shades`: Shades of a single color. Specify a single color, useful in an override rule.\\n`fixed`: Fixed color mode. Specify a single color, useful in an override rule.\"},\"FieldColorSeriesByMode\":{\"enum\":[\"min\",\"max\",\"last\"],\"type\":\"string\",\"description\":\"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.\"},\"Action\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"type\",\"title\"],\"properties\":{\"type\":{\"$ref\":\"#/definitions/ActionType\"},\"title\":{\"type\":\"string\"},\"fetch\":{\"$ref\":\"#/definitions/FetchOptions\"},\"infinity\":{\"$ref\":\"#/definitions/InfinityOptions\"},\"confirmation\":{\"type\":\"string\"},\"oneClick\":{\"type\":\"boolean\"},\"variables\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/definitions/ActionVariable\"}},\"style\":{\"type\":\"object\",\"additionalProperties\":false,\"properties\":{\"backgroundColor\":{\"type\":\"string\"}}}},\"description\":\"Dashboard action\"},\"ActionType\":{\"enum\":[\"fetch\",\"infinity\"],\"type\":\"string\",\"description\":\"Dashboard action type\"},\"FetchOptions\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"method\",\"url\"],\"properties\":{\"method\":{\"$ref\":\"#/definitions/HttpRequestMethod\"},\"url\":{\"type\":\"string\"},\"body\":{\"type\":\"string\"},\"queryParams\":{\"type\":\"array\",\"items\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"description\":\"These are 2D arrays of strings, each representing a key-value pair\\nWe are defining this way because we can't generate a go struct that\\nthat would have exactly two strings in each sub-array\"},\"headers\":{\"type\":\"array\",\"items\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}}}},\"description\":\"Fetch options\"},\"HttpRequestMethod\":{\"enum\":[\"GET\",\"PUT\",\"POST\",\"DELETE\",\"PATCH\"],\"type\":\"string\"},\"InfinityOptions\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"method\",\"url\",\"datasourceUid\"],\"properties\":{\"method\":{\"$ref\":\"#/definitions/HttpRequestMethod\"},\"url\":{\"type\":\"string\"},\"body\":{\"type\":\"string\"},\"queryParams\":{\"type\":\"array\",\"items\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"description\":\"These are 2D arrays of strings, each representing a key-value pair\\nWe are defining them this way because we can't generate a go struct that\\nthat would have exactly two strings in each sub-array\"},\"headers\":{\"type\":\"array\",\"items\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}}},\"datasourceUid\":{\"type\":\"string\"}},\"description\":\"Infinity options\"},\"ActionVariable\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"key\",\"name\",\"type\"],\"properties\":{\"key\":{\"type\":\"string\"},\"name\":{\"type\":\"string\"},\"type\":{\"allOf\":[{\"$ref\":\"#/definitions/ActionVariableType\"}],\"default\":\"string\"}}},\"ActionVariableType\":{\"enum\":[\"string\"],\"type\":\"string\",\"description\":\"Action variable type\"},\"DynamicConfigValue\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"id\"],\"properties\":{\"id\":{\"type\":\"string\",\"default\":\"\"},\"value\":{}}},\"RowPanel\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"type\",\"collapsed\",\"id\",\"panels\"],\"properties\":{\"type\":{\"type\":\"string\",\"const\":\"row\",\"description\":\"The panel type\"},\"collapsed\":{\"type\":\"boolean\",\"description\":\"Whether this row should be collapsed or not.\",\"default\":false},\"title\":{\"type\":\"string\",\"description\":\"Row title\"},\"datasource\":{\"$ref\":\"#/definitions/DataSourceRef\",\"description\":\"Name of default datasource for the row\"},\"gridPos\":{\"$ref\":\"#/definitions/GridPos\",\"description\":\"Row grid position\"},\"id\":{\"type\":\"integer\",\"description\":\"Unique identifier of the panel. Generated by Grafana when creating a new panel. It must be unique within a dashboard, but not globally.\"},\"panels\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/definitions/Panel\"},\"description\":\"List of panels in the row\"},\"repeat\":{\"type\":\"string\",\"description\":\"Name of template variable to repeat for.\"}},\"description\":\"Row panel\"},\"VariableModel\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"type\",\"name\"],\"properties\":{\"type\":{\"$ref\":\"#/definitions/VariableType\",\"description\":\"Type of variable\"},\"name\":{\"type\":\"string\",\"description\":\"Name of variable\"},\"label\":{\"type\":\"string\",\"description\":\"Optional display name\"},\"hide\":{\"$ref\":\"#/definitions/VariableHide\",\"description\":\"Visibility configuration for the variable\"},\"skipUrlSync\":{\"type\":\"boolean\",\"description\":\"Whether the variable value should be managed by URL query params or not\",\"default\":false},\"description\":{\"type\":\"string\",\"description\":\"Description of variable. It can be defined but `null`.\"},\"query\":{\"anyOf\":[{\"type\":\"string\"},{\"type\":\"object\",\"additionalProperties\":{}}],\"description\":\"Query used to fetch values for a variable: a string, or the datasource's own query object (Prometheus writes { query, qryType, refId }).\"},\"datasource\":{\"$ref\":\"#/definitions/DataSourceRef\",\"description\":\"Data source used to fetch values for a variable. It can be defined but `null`.\"},\"current\":{\"anyOf\":[{\"$ref\":\"#/definitions/VariableOption\"},{\"type\":\"object\",\"additionalProperties\":false,\"maxProperties\":0}],\"description\":\"Shows current selected variable text/value on the dashboard. `{}` before the variable has been resolved.\"},\"multi\":{\"type\":\"boolean\",\"description\":\"Whether multiple values can be selected or not from variable value list\",\"default\":false},\"allowCustomValue\":{\"type\":\"boolean\",\"description\":\"Allow custom values to be entered in the variable\",\"default\":true},\"options\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/definitions/VariableOption\"},\"description\":\"Options that can be selected for a variable.\"},\"refresh\":{\"$ref\":\"#/definitions/VariableRefresh\",\"description\":\"Options to config when to refresh a variable\"},\"sort\":{\"$ref\":\"#/definitions/VariableSort\",\"description\":\"Options sort order\"},\"includeAll\":{\"type\":\"boolean\",\"description\":\"Whether all value option is available or not\",\"default\":false},\"allValue\":{\"type\":\"string\",\"description\":\"Custom all value\"},\"regex\":{\"type\":\"string\",\"description\":\"Optional field, if you want to extract part of a series name or metric node segment.\\nNamed capture groups can be used to separate the display text and value.\"},\"staticOptions\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/definitions/VariableOption\"},\"description\":\"Additional static options for query variable\"},\"staticOptionsOrder\":{\"enum\":[\"before\",\"after\",\"sorted\"],\"type\":\"string\",\"description\":\"Ordering of static options in relation to options returned from data source for query variable\"},\"auto\":{\"type\":\"boolean\",\"description\":\"Dynamically calculates interval by dividing time range by the count specified.\",\"default\":false},\"auto_min\":{\"type\":\"string\",\"description\":\"The minimum threshold below which the step count intervals will not divide the time.\",\"default\":\"10s\"},\"auto_count\":{\"type\":\"integer\",\"exclusiveMinimum\":0,\"description\":\"How many times the current time range should be divided to calculate the value, similar to the Max data points query option.\\nFor example, if the current visible time range is 30 minutes, then the auto interval groups the data into 30 one-minute increments.\",\"default\":30},\"definition\":{\"type\":\"string\"},\"enableGroupBy\":{\"type\":\"boolean\",\"default\":false,\"description\":\"Whether the group-by operator is enabled in the ad hoc filter combobox.\"},\"valuesFormat\":{\"type\":\"string\",\"enum\":[\"csv\",\"json\"],\"default\":\"csv\",\"description\":\"Whether a custom variable defines its values as CSV or JSON.\"},\"regexApplyTo\":{\"type\":\"string\",\"enum\":[\"value\",\"text\"],\"description\":\"Whether regex applies to the variable value or its display text.\"},\"filters\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/definitions/AdHocFilter\"},\"description\":\"Ad hoc variable: the filters currently applied.\"},\"baseFilters\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/definitions/AdHocFilter\"},\"description\":\"Ad hoc variable: filters always applied to the key lookup, not shown in the UI.\"},\"defaultKeys\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"additionalProperties\":{}},\"description\":\"Ad hoc variable: static keys that override the datasource's.\"},\"defaultValue\":{\"$ref\":\"#/definitions/VariableOption\",\"description\":\"Group-by variable: the default selection.\"}},\"description\":\"A variable is a placeholder for a value. You can use variables in metric queries and in panel titles.\"},\"VariableType\":{\"enum\":[\"query\",\"adhoc\",\"groupby\",\"constant\",\"datasource\",\"interval\",\"textbox\",\"custom\",\"system\",\"snapshot\",\"switch\"],\"type\":\"string\",\"description\":\"Dashboard variable type\\n`query`: Query-generated list of values such as metric names, server names, sensor IDs, data centers, and so on.\\n`adhoc`: Key/value filters that are automatically added to all metric queries for a data source (Prometheus, Loki, InfluxDB, and Elasticsearch only).\\n`constant`: \\tDefine a hidden constant.\\n`datasource`: Quickly change the data source for an entire dashboard.\\n`interval`: Interval variables represent time spans.\\n`textbox`: Display a free text input field with an optional default value.\\n`custom`: Define the variable options manually using a comma-separated list.\\n`system`: Variables defined by Grafana. See: https://grafana.com/docs/grafana/latest/dashboards/variables/add-template-variables/#global-variables\\n`switch`: Boolean variables rendered as a switch\"},\"VariableHide\":{\"enum\":[0,1,2,3],\"type\":\"integer\",\"description\":\"Determine if the variable shows on dashboard\\nAccepted values are 0 (show label and value), 1 (show value only), 2 (show nothing), 3 (show under the controls dropdown menu).\"},\"VariableOption\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"text\",\"value\"],\"properties\":{\"selected\":{\"type\":\"boolean\",\"description\":\"Whether the option is selected or not\"},\"text\":{\"oneOf\":[{\"type\":\"string\"},{\"type\":\"array\",\"items\":{\"type\":\"string\"}}],\"description\":\"Text to be displayed for the option\"},\"value\":{\"oneOf\":[{\"type\":\"string\"},{\"type\":\"array\",\"items\":{\"type\":\"string\"}}],\"description\":\"Value of the option\"},\"properties\":{\"type\":\"object\",\"additionalProperties\":{\"type\":\"string\"},\"description\":\"Additional properties for multi-props variables\"}},\"description\":\"Option to be selected in a variable.\"},\"VariableRefresh\":{\"enum\":[0,1,2],\"type\":\"integer\",\"description\":\"Options to config when to refresh a variable\\n`0`: Never refresh the variable\\n`1`: Queries the data source every time the dashboard loads.\\n`2`: Queries the data source when the dashboard time range changes.\"},\"VariableSort\":{\"enum\":[0,1,2,3,4,5,6,7,8],\"type\":\"integer\",\"description\":\"Sort variable options\\nAccepted values are:\\n`0`: No sorting\\n`1`: Alphabetical ASC\\n`2`: Alphabetical DESC\\n`3`: Numerical ASC\\n`4`: Numerical DESC\\n`5`: Alphabetical Case Insensitive ASC\\n`6`: Alphabetical Case Insensitive DESC\\n`7`: Natural ASC\\n`8`: Natural DESC\"},\"AnnotationContainer\":{\"type\":\"object\",\"additionalProperties\":false,\"properties\":{\"list\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/definitions/AnnotationQuery\"},\"description\":\"List of annotations\"}},\"description\":\"Contains the list of annotations that are associated with the dashboard.\\nAnnotations are used to overlay event markers and overlay event tags on graphs.\\nGrafana comes with a native annotation store and the ability to add annotation events directly from the graph panel or via the HTTP API.\\nSee https://grafana.com/docs/grafana/latest/dashboards/build-dashboards/annotate-visualizations/\"},\"AnnotationQuery\":{\"type\":\"object\",\"additionalProperties\":{},\"required\":[\"name\",\"enable\",\"iconColor\"],\"properties\":{\"name\":{\"type\":\"string\",\"description\":\"Name of annotation.\"},\"datasource\":{\"$ref\":\"#/definitions/DataSourceRef\",\"description\":\"Datasource where the annotations data is\"},\"enable\":{\"type\":\"boolean\",\"description\":\"When enabled the annotation query is issued with every dashboard refresh\",\"default\":true},\"hide\":{\"type\":\"boolean\",\"description\":\"Annotation queries can be toggled on or off at the top of the dashboard.\\nWhen hide is true, the toggle is not shown in the dashboard.\",\"default\":false},\"iconColor\":{\"type\":\"string\",\"description\":\"Color to use for the annotation event markers\"},\"filter\":{\"$ref\":\"#/definitions/AnnotationPanelFilter\",\"description\":\"Filters to apply when fetching annotations\"},\"target\":{\"type\":\"object\",\"additionalProperties\":{},\"description\":\"TODO.. this should just be a normal query target\"},\"type\":{\"type\":\"string\",\"description\":\"TODO -- this should not exist here, it is based on the --grafana-- datasource\"},\"builtIn\":{\"type\":\"number\",\"description\":\"Set to 1 for the standard annotation query all dashboards have by default.\",\"default\":0},\"placement\":{\"allOf\":[{\"$ref\":\"#/definitions/AnnotationQueryPlacement\"}],\"default\":\"inControlsMenu\",\"description\":\"Placement can be used to display the annotation query somewhere else on the dashboard other than the default location.\"},\"expr\":{\"type\":\"string\"},\"textFormat\":{\"type\":\"string\",\"description\":\"Format for Prometheus annotation text. Label values can be interpolated with templates like {{instance}}.\"},\"titleFormat\":{\"type\":\"string\",\"description\":\"Format for Prometheus and Loki annotation titles. Label values can be interpolated with templates like {{instance}}.\"},\"tagKeys\":{\"type\":\"string\",\"description\":\"Comma-separated label keys used as annotation tags.\"},\"step\":{\"type\":\"string\",\"description\":\"Legacy Prometheus annotation query step interval.\"},\"useValueForTime\":{\"type\":\"boolean\",\"description\":\"Use the Prometheus series value as the annotation timestamp.\"},\"mappings\":{\"type\":\"object\",\"additionalProperties\":{\"$ref\":\"#/definitions/AnnotationEventFieldMapping\"},\"description\":\"Mappings define how to convert data frame fields to annotation event fields.\"}},\"description\":\"TODO docs\\nFROM: AnnotationQuery in grafana-data/src/types/annotations.ts\"},\"AnnotationPanelFilter\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"ids\"],\"properties\":{\"exclude\":{\"type\":\"boolean\",\"description\":\"Should the specified panels be included or excluded\",\"default\":false},\"ids\":{\"type\":\"array\",\"items\":{\"type\":\"integer\"},\"description\":\"Panel IDs that should be included or excluded\"}}},\"AnnotationTarget\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"limit\",\"matchAny\",\"tags\",\"type\"],\"properties\":{\"limit\":{\"type\":\"integer\",\"description\":\"Only required/valid for the grafana datasource...\\nbut code+tests is already depending on it so hard to change\"},\"matchAny\":{\"type\":\"boolean\",\"description\":\"Only required/valid for the grafana datasource...\\nbut code+tests is already depending on it so hard to change\"},\"tags\":{\"type\":\"array\",\"items\":{\"type\":\"string\"},\"description\":\"Only required/valid for the grafana datasource...\\nbut code+tests is already depending on it so hard to change\"},\"type\":{\"type\":\"string\",\"description\":\"Only required/valid for the grafana datasource...\\nbut code+tests is already depending on it so hard to change\"}},\"description\":\"TODO: this should be a regular DataQuery that depends on the selected dashboard\\nthese match the properties of the \\\"grafana\\\" datasouce that is default in most dashboards\"},\"AnnotationQueryPlacement\":{\"enum\":[\"inControlsMenu\"],\"type\":\"string\",\"description\":\"Annotation Query placement. Defines where the annotation query should be displayed.\\n- \\\"inControlsMenu\\\" renders the annotation query in the dashboard controls dropdown menu\"},\"Snapshot\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"created\",\"expires\",\"external\",\"externalUrl\",\"originalUrl\",\"id\",\"key\",\"name\",\"orgId\",\"updated\",\"userId\"],\"properties\":{\"created\":{\"type\":\"string\",\"format\":\"date-time\",\"description\":\"Time when the snapshot was created\"},\"expires\":{\"type\":\"string\",\"description\":\"Time when the snapshot expires, default is never to expire\"},\"external\":{\"type\":\"boolean\",\"description\":\"Is the snapshot saved in an external grafana instance\"},\"externalUrl\":{\"type\":\"string\",\"description\":\"external url, if snapshot was shared in external grafana instance\"},\"originalUrl\":{\"type\":\"string\",\"description\":\"original url, url of the dashboard that was snapshotted\"},\"id\":{\"type\":\"integer\",\"description\":\"Unique identifier of the snapshot\"},\"key\":{\"type\":\"string\",\"description\":\"Optional, defined the unique key of the snapshot, required if external is true\"},\"name\":{\"type\":\"string\",\"description\":\"Optional, name of the snapshot\"},\"orgId\":{\"type\":\"integer\",\"description\":\"org id of the snapshot\"},\"updated\":{\"type\":\"string\",\"format\":\"date-time\",\"description\":\"last time when the snapshot was updated\"},\"url\":{\"type\":\"string\",\"description\":\"url of the snapshot, if snapshot was shared internally\"},\"userId\":{\"type\":\"integer\",\"description\":\"user id of the snapshot creator\"},\"dashboard\":{\"$ref\":\"#/definitions/Dashboard\"}},\"description\":\"A dashboard snapshot shares an interactive dashboard publicly.\\nIt is a read-only version of a dashboard, and is not editable.\\nIt is possible to create a snapshot of a snapshot.\\nGrafana strips away all sensitive information from the dashboard.\\nSensitive information stripped: queries (metric, template,annotation) and panel links.\"},\"AnnotationEventFieldSource\":{\"enum\":[\"field\",\"text\",\"skip\"],\"type\":\"string\",\"description\":\"Annotation event field source. Defines how to obtain the value for an annotation event field.\\n- \\\"field\\\": Find the value with a matching key (default)\\n- \\\"text\\\": Write a constant string into the value\\n- \\\"skip\\\": Do not include the field\"},\"AnnotationEventFieldMapping\":{\"type\":\"object\",\"additionalProperties\":false,\"properties\":{\"source\":{\"$ref\":\"#/definitions/AnnotationEventFieldSource\",\"description\":\"Source type for the field value.\"},\"value\":{\"type\":\"string\",\"description\":\"Constant value to use when source is \\\"text\\\".\"},\"regex\":{\"type\":\"string\",\"description\":\"Regular expression to apply to the field value.\"}},\"description\":\"Annotation event field mapping. Defines how to map a data frame field to an annotation event field.\"},\"ExportInput\":{\"type\":\"object\",\"additionalProperties\":{},\"required\":[\"name\",\"type\"],\"properties\":{\"name\":{\"type\":\"string\",\"description\":\"Placeholder name, used as `${name}` in the dashboard.\"},\"label\":{\"type\":\"string\"},\"description\":{\"type\":\"string\"},\"type\":{\"type\":\"string\",\"description\":\"`datasource` or `constant`.\"},\"pluginId\":{\"type\":\"string\"},\"pluginName\":{\"type\":\"string\"},\"value\":{\"description\":\"The value a constant input carries.\"}},\"description\":\"One entry of an export's `__inputs`.\"},\"ExportRequirement\":{\"type\":\"object\",\"additionalProperties\":{},\"required\":[\"type\",\"id\"],\"properties\":{\"type\":{\"type\":\"string\",\"description\":\"`grafana`, `panel` or `datasource`.\"},\"id\":{\"type\":\"string\"},\"name\":{\"type\":\"string\"},\"version\":{\"type\":\"string\"}},\"description\":\"One entry of an export's `__requires`.\"},\"LibraryElementExport\":{\"type\":\"object\",\"additionalProperties\":{},\"required\":[\"uid\",\"name\",\"model\"],\"properties\":{\"uid\":{\"type\":\"string\"},\"name\":{\"type\":\"string\"},\"kind\":{\"type\":\"integer\"},\"model\":{\"type\":\"object\",\"additionalProperties\":{},\"description\":\"The library panel's own panel JSON. GRAF107 checks it as a panel (src/schema-validate.ts), not here.\"}},\"description\":\"One library panel embedded in an export's `__elements`.\"},\"PanelLink\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"title\"],\"properties\":{\"title\":{\"type\":\"string\",\"description\":\"Title to display with the link\"},\"url\":{\"type\":\"string\",\"description\":\"Link URL. Supports variables, e.g. ${__url_time_range}.\"},\"targetBlank\":{\"type\":\"boolean\",\"description\":\"If true, the link will be opened in a new tab\"},\"type\":{\"$ref\":\"#/definitions/DashboardLinkType\"},\"icon\":{\"type\":\"string\"},\"tooltip\":{\"type\":\"string\"},\"tags\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"asDropdown\":{\"type\":\"boolean\"},\"includeVars\":{\"type\":\"boolean\"},\"keepTime\":{\"type\":\"boolean\"},\"placement\":{\"$ref\":\"#/definitions/DashboardLinkPlacement\"},\"oneClick\":{\"type\":\"boolean\"}},\"description\":\"A panel link: the fields Grafana's panel link editor writes, plus DashboardLink's.\"},\"DataLink\":{\"type\":\"object\",\"additionalProperties\":{},\"properties\":{\"title\":{\"type\":\"string\"},\"url\":{\"type\":\"string\",\"description\":\"Link URL. Supports data variables, e.g. ${__field.labels.pod}.\"},\"targetBlank\":{\"type\":\"boolean\"},\"oneClick\":{\"type\":\"boolean\"},\"internal\":{\"type\":\"object\",\"additionalProperties\":{},\"description\":\"A query in another datasource (Explore link).\"},\"origin\":{}},\"description\":\"A data link on a field. Open: the CUE leaves these items unconstrained.\"},\"ControlSourceRef\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"type\",\"group\"],\"properties\":{\"type\":{\"type\":\"string\",\"const\":\"datasource\"},\"group\":{\"type\":\"string\",\"description\":\"The plugin type-id\"}}},\"MatcherScope\":{\"type\":\"string\",\"enum\":[\"series\",\"nested\",\"annotation\",\"exemplar\"]},\"AdHocFilter\":{\"type\":\"object\",\"additionalProperties\":{},\"required\":[\"key\",\"operator\"],\"properties\":{\"key\":{\"type\":\"string\"},\"operator\":{\"type\":\"string\",\"description\":\"=, !=, =~, !~, <, >, =| or !=|\"},\"value\":{\"type\":\"string\"},\"values\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"origin\":{\"type\":\"string\"},\"condition\":{\"type\":\"string\",\"deprecated\":true}},\"description\":\"One ad hoc filter.\"}}}",
12
- "timeseries": "{\"$schema\":\"http://json-schema.org/draft-07/schema#\",\"definitions\":{\"Options\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"legend\",\"tooltip\"],\"properties\":{\"timezone\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/definitions/TimeZone\"}},\"legend\":{\"$ref\":\"#/definitions/VizLegendOptions\",\"default\":{\"calcs\":[],\"displayMode\":\"list\",\"placement\":\"bottom\"}},\"tooltip\":{\"$ref\":\"#/definitions/VizTooltipOptions\"},\"orientation\":{\"$ref\":\"#/definitions/VizOrientation\"}}},\"FieldConfig\":{\"$ref\":\"#/definitions/GraphFieldConfig\"},\"TimeZone\":{\"type\":\"string\",\"description\":\"A specific timezone from https://en.wikipedia.org/wiki/Tz_database\"},\"VizLegendOptions\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"displayMode\",\"placement\",\"showLegend\",\"calcs\"],\"properties\":{\"displayMode\":{\"$ref\":\"#/definitions/LegendDisplayMode\",\"default\":\"list\"},\"placement\":{\"$ref\":\"#/definitions/LegendPlacement\",\"default\":\"bottom\"},\"showLegend\":{\"type\":\"boolean\"},\"asTable\":{\"type\":\"boolean\"},\"isVisible\":{\"type\":\"boolean\"},\"sortBy\":{\"type\":\"string\"},\"sortDesc\":{\"type\":\"boolean\"},\"width\":{\"type\":\"number\"},\"calcs\":{\"type\":\"array\",\"items\":{\"type\":\"string\"},\"default\":[]}},\"description\":\"TODO docs\"},\"VizTooltipOptions\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"mode\",\"sort\"],\"properties\":{\"mode\":{\"$ref\":\"#/definitions/TooltipDisplayMode\"},\"sort\":{\"$ref\":\"#/definitions/SortOrder\"},\"maxWidth\":{\"type\":\"number\"},\"maxHeight\":{\"type\":\"number\"},\"hideZeros\":{\"type\":\"boolean\"}},\"description\":\"TODO docs\"},\"VizOrientation\":{\"enum\":[\"auto\",\"vertical\",\"horizontal\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"GraphFieldConfig\":{\"type\":\"object\",\"additionalProperties\":false,\"properties\":{\"drawStyle\":{\"$ref\":\"#/definitions/GraphDrawStyle\"},\"gradientMode\":{\"$ref\":\"#/definitions/GraphGradientMode\"},\"thresholdsStyle\":{\"$ref\":\"#/definitions/GraphThresholdsStyleConfig\"},\"transform\":{\"$ref\":\"#/definitions/GraphTransform\"},\"lineColor\":{\"type\":\"string\"},\"lineWidth\":{\"type\":\"number\"},\"lineInterpolation\":{\"$ref\":\"#/definitions/LineInterpolation\"},\"lineStyle\":{\"$ref\":\"#/definitions/LineStyle\"},\"fillColor\":{\"type\":\"string\"},\"fillOpacity\":{\"type\":\"number\"},\"showPoints\":{\"$ref\":\"#/definitions/VisibilityMode\"},\"pointSize\":{\"type\":\"number\"},\"pointColor\":{\"type\":\"string\"},\"axisPlacement\":{\"$ref\":\"#/definitions/AxisPlacement\"},\"axisColorMode\":{\"$ref\":\"#/definitions/AxisColorMode\"},\"axisLabel\":{\"type\":\"string\"},\"axisWidth\":{\"type\":\"number\"},\"axisSoftMin\":{\"type\":\"number\"},\"axisSoftMax\":{\"type\":\"number\"},\"axisGridShow\":{\"type\":\"boolean\"},\"scaleDistribution\":{\"$ref\":\"#/definitions/ScaleDistributionConfig\"},\"axisCenteredZero\":{\"type\":\"boolean\"},\"barAlignment\":{\"$ref\":\"#/definitions/BarAlignment\"},\"barWidthFactor\":{\"type\":\"number\"},\"stacking\":{\"$ref\":\"#/definitions/StackingConfig\"},\"hideFrom\":{\"$ref\":\"#/definitions/HideSeriesConfig\"},\"insertNulls\":{\"oneOf\":[{\"type\":\"boolean\"},{\"type\":\"number\"}]},\"spanNulls\":{\"oneOf\":[{\"type\":\"boolean\"},{\"type\":\"number\"}],\"description\":\"Indicate if null values should be treated as gaps or connected.\\nWhen the value is a number, it represents the maximum delta in the\\nX axis that should be considered connected. For timeseries, this is milliseconds\"},\"fillBelowTo\":{\"type\":\"string\"},\"pointSymbol\":{\"type\":\"string\"},\"axisBorderShow\":{\"type\":\"boolean\"},\"barMaxWidth\":{\"type\":\"number\"},\"showValues\":{\"type\":\"boolean\",\"description\":\"Show point values on the graph.\"}},\"description\":\"TODO docs\"},\"LegendDisplayMode\":{\"enum\":[\"list\",\"table\",\"hidden\"],\"type\":\"string\",\"description\":\"TODO docs\\nNote: \\\"hidden\\\" needs to remain as an option for plugins compatibility\"},\"LegendPlacement\":{\"enum\":[\"bottom\",\"right\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"TooltipDisplayMode\":{\"enum\":[\"single\",\"multi\",\"none\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"SortOrder\":{\"enum\":[\"asc\",\"desc\",\"none\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"GraphDrawStyle\":{\"enum\":[\"line\",\"bars\",\"points\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"GraphGradientMode\":{\"enum\":[\"none\",\"opacity\",\"hue\",\"scheme\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"GraphThresholdsStyleConfig\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"mode\"],\"properties\":{\"mode\":{\"$ref\":\"#/definitions/GraphThresholdsStyleMode\"}},\"description\":\"TODO docs\"},\"GraphTransform\":{\"enum\":[\"constant\",\"negative-Y\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"LineInterpolation\":{\"enum\":[\"linear\",\"smooth\",\"stepBefore\",\"stepAfter\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"LineStyle\":{\"type\":\"object\",\"additionalProperties\":false,\"properties\":{\"fill\":{\"enum\":[\"solid\",\"dash\",\"dot\",\"square\",\"accessible\"],\"type\":\"string\"},\"dash\":{\"type\":\"array\",\"items\":{\"type\":\"number\"}}},\"description\":\"TODO docs\"},\"VisibilityMode\":{\"enum\":[\"auto\",\"never\",\"always\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"AxisPlacement\":{\"enum\":[\"auto\",\"top\",\"right\",\"bottom\",\"left\",\"hidden\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"AxisColorMode\":{\"enum\":[\"text\",\"series\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"ScaleDistributionConfig\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"type\"],\"properties\":{\"type\":{\"$ref\":\"#/definitions/ScaleDistribution\"},\"log\":{\"type\":\"number\"},\"linearThreshold\":{\"type\":\"number\"}},\"description\":\"TODO docs\"},\"BarAlignment\":{\"enum\":[-1,0,1],\"type\":\"integer\",\"description\":\"TODO docs\"},\"StackingConfig\":{\"type\":\"object\",\"additionalProperties\":false,\"properties\":{\"mode\":{\"$ref\":\"#/definitions/StackingMode\"},\"group\":{\"type\":\"string\"}},\"description\":\"TODO docs\"},\"HideSeriesConfig\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"tooltip\",\"legend\",\"viz\"],\"properties\":{\"tooltip\":{\"type\":\"boolean\"},\"legend\":{\"type\":\"boolean\"},\"viz\":{\"type\":\"boolean\"}},\"description\":\"TODO docs\"},\"GraphThresholdsStyleMode\":{\"enum\":[\"off\",\"line\",\"dashed\",\"area\",\"line+area\",\"dashed+area\",\"series\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"ScaleDistribution\":{\"enum\":[\"linear\",\"log\",\"ordinal\",\"symlog\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"StackingMode\":{\"enum\":[\"none\",\"normal\",\"percent\"],\"type\":\"string\",\"description\":\"TODO docs\"}}}",
12
+ "timeseries": "{\"$schema\":\"http://json-schema.org/draft-07/schema#\",\"definitions\":{\"Options\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"legend\",\"tooltip\"],\"properties\":{\"timezone\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/definitions/TimeZone\"}},\"legend\":{\"$ref\":\"#/definitions/VizLegendOptions\",\"default\":{\"calcs\":[],\"displayMode\":\"list\",\"placement\":\"bottom\"}},\"tooltip\":{\"$ref\":\"#/definitions/VizTooltipOptions\"},\"orientation\":{\"$ref\":\"#/definitions/VizOrientation\"},\"annotations\":{\"$ref\":\"#/definitions/VizAnnotations\"}}},\"FieldConfig\":{\"$ref\":\"#/definitions/GraphFieldConfig\"},\"TimeZone\":{\"type\":\"string\",\"description\":\"A specific timezone from https://en.wikipedia.org/wiki/Tz_database\"},\"VizLegendOptions\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"displayMode\",\"placement\",\"showLegend\",\"calcs\"],\"properties\":{\"displayMode\":{\"$ref\":\"#/definitions/LegendDisplayMode\",\"default\":\"list\"},\"placement\":{\"$ref\":\"#/definitions/LegendPlacement\",\"default\":\"bottom\"},\"showLegend\":{\"type\":\"boolean\"},\"asTable\":{\"type\":\"boolean\"},\"isVisible\":{\"type\":\"boolean\"},\"sortBy\":{\"type\":\"string\"},\"sortDesc\":{\"type\":\"boolean\"},\"width\":{\"type\":\"number\"},\"calcs\":{\"type\":\"array\",\"items\":{\"type\":\"string\"},\"default\":[]}},\"description\":\"TODO docs\"},\"VizTooltipOptions\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"mode\",\"sort\"],\"properties\":{\"mode\":{\"$ref\":\"#/definitions/TooltipDisplayMode\"},\"sort\":{\"$ref\":\"#/definitions/SortOrder\"},\"maxWidth\":{\"type\":\"number\"},\"maxHeight\":{\"type\":\"number\"},\"hideZeros\":{\"type\":\"boolean\"}},\"description\":\"TODO docs\"},\"VizOrientation\":{\"enum\":[\"auto\",\"vertical\",\"horizontal\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"GraphFieldConfig\":{\"type\":\"object\",\"additionalProperties\":false,\"properties\":{\"drawStyle\":{\"$ref\":\"#/definitions/GraphDrawStyle\"},\"gradientMode\":{\"$ref\":\"#/definitions/GraphGradientMode\"},\"thresholdsStyle\":{\"$ref\":\"#/definitions/GraphThresholdsStyleConfig\"},\"transform\":{\"$ref\":\"#/definitions/GraphTransform\"},\"lineColor\":{\"type\":\"string\"},\"lineWidth\":{\"type\":\"number\"},\"lineInterpolation\":{\"$ref\":\"#/definitions/LineInterpolation\"},\"lineStyle\":{\"$ref\":\"#/definitions/LineStyle\"},\"fillColor\":{\"type\":\"string\"},\"fillOpacity\":{\"type\":\"number\"},\"showPoints\":{\"$ref\":\"#/definitions/VisibilityMode\"},\"pointSize\":{\"type\":\"number\"},\"pointColor\":{\"type\":\"string\"},\"axisPlacement\":{\"$ref\":\"#/definitions/AxisPlacement\"},\"axisColorMode\":{\"$ref\":\"#/definitions/AxisColorMode\"},\"axisLabel\":{\"type\":\"string\"},\"axisWidth\":{\"type\":\"number\"},\"axisSoftMin\":{\"type\":\"number\"},\"axisSoftMax\":{\"type\":\"number\"},\"axisGridShow\":{\"type\":\"boolean\"},\"scaleDistribution\":{\"$ref\":\"#/definitions/ScaleDistributionConfig\"},\"axisCenteredZero\":{\"type\":\"boolean\"},\"barAlignment\":{\"$ref\":\"#/definitions/BarAlignment\"},\"barWidthFactor\":{\"type\":\"number\"},\"stacking\":{\"$ref\":\"#/definitions/StackingConfig\"},\"hideFrom\":{\"$ref\":\"#/definitions/HideSeriesConfig\"},\"insertNulls\":{\"oneOf\":[{\"type\":\"boolean\"},{\"type\":\"number\"}]},\"spanNulls\":{\"oneOf\":[{\"type\":\"boolean\"},{\"type\":\"number\"}],\"description\":\"Indicate if null values should be treated as gaps or connected.\\nWhen the value is a number, it represents the maximum delta in the\\nX axis that should be considered connected. For timeseries, this is milliseconds\"},\"fillBelowTo\":{\"type\":\"string\"},\"pointSymbol\":{\"type\":\"string\"},\"axisBorderShow\":{\"type\":\"boolean\"},\"barMaxWidth\":{\"type\":\"number\"},\"showValues\":{\"type\":\"boolean\",\"description\":\"Show point values on the graph.\"}},\"description\":\"TODO docs\"},\"LegendDisplayMode\":{\"enum\":[\"list\",\"table\",\"hidden\"],\"type\":\"string\",\"description\":\"TODO docs\\nNote: \\\"hidden\\\" needs to remain as an option for plugins compatibility\"},\"LegendPlacement\":{\"enum\":[\"bottom\",\"right\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"TooltipDisplayMode\":{\"enum\":[\"single\",\"multi\",\"none\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"SortOrder\":{\"enum\":[\"asc\",\"desc\",\"none\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"GraphDrawStyle\":{\"enum\":[\"line\",\"bars\",\"points\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"GraphGradientMode\":{\"enum\":[\"none\",\"opacity\",\"hue\",\"scheme\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"GraphThresholdsStyleConfig\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"mode\"],\"properties\":{\"mode\":{\"$ref\":\"#/definitions/GraphThresholdsStyleMode\"}},\"description\":\"TODO docs\"},\"GraphTransform\":{\"enum\":[\"constant\",\"negative-Y\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"LineInterpolation\":{\"enum\":[\"linear\",\"smooth\",\"stepBefore\",\"stepAfter\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"LineStyle\":{\"type\":\"object\",\"additionalProperties\":false,\"properties\":{\"fill\":{\"enum\":[\"solid\",\"dash\",\"dot\",\"square\",\"accessible\"],\"type\":\"string\"},\"dash\":{\"type\":\"array\",\"items\":{\"type\":\"number\"}}},\"description\":\"TODO docs\"},\"VisibilityMode\":{\"enum\":[\"auto\",\"never\",\"always\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"AxisPlacement\":{\"enum\":[\"auto\",\"top\",\"right\",\"bottom\",\"left\",\"hidden\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"AxisColorMode\":{\"enum\":[\"text\",\"series\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"ScaleDistributionConfig\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"type\"],\"properties\":{\"type\":{\"$ref\":\"#/definitions/ScaleDistribution\"},\"log\":{\"type\":\"number\"},\"linearThreshold\":{\"type\":\"number\"}},\"description\":\"TODO docs\"},\"BarAlignment\":{\"enum\":[-1,0,1],\"type\":\"integer\",\"description\":\"TODO docs\"},\"StackingConfig\":{\"type\":\"object\",\"additionalProperties\":false,\"properties\":{\"mode\":{\"$ref\":\"#/definitions/StackingMode\"},\"group\":{\"type\":\"string\"}},\"description\":\"TODO docs\"},\"HideSeriesConfig\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"tooltip\",\"legend\",\"viz\"],\"properties\":{\"tooltip\":{\"type\":\"boolean\"},\"legend\":{\"type\":\"boolean\"},\"viz\":{\"type\":\"boolean\"}},\"description\":\"TODO docs\"},\"GraphThresholdsStyleMode\":{\"enum\":[\"off\",\"line\",\"dashed\",\"area\",\"line+area\",\"dashed+area\",\"series\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"ScaleDistribution\":{\"enum\":[\"linear\",\"log\",\"ordinal\",\"symlog\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"StackingMode\":{\"enum\":[\"none\",\"normal\",\"percent\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"VizAnnotations\":{\"type\":\"object\",\"additionalProperties\":false,\"properties\":{\"multiLane\":{\"type\":\"boolean\",\"description\":\"Breaks out each annotation frame into multiple lanes on the x-axis\"},\"clustering\":{\"type\":\"number\",\"description\":\"Sets whether clustering is enabled. Any value > 0 will enable clustering.\"},\"lines\":{\"type\":\"object\",\"additionalProperties\":false,\"properties\":{\"width\":{\"type\":\"number\"}}},\"regions\":{\"type\":\"object\",\"additionalProperties\":false,\"properties\":{\"opacity\":{\"type\":\"number\"}}}}}}}",
13
13
  "stat": "{\"$schema\":\"http://json-schema.org/draft-07/schema#\",\"definitions\":{\"Options\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"graphMode\",\"colorMode\",\"justifyMode\",\"textMode\",\"wideLayout\",\"showPercentChange\",\"reduceOptions\",\"percentChangeColorMode\",\"orientation\"],\"properties\":{\"graphMode\":{\"$ref\":\"#/definitions/BigValueGraphMode\",\"default\":\"area\"},\"colorMode\":{\"$ref\":\"#/definitions/BigValueColorMode\",\"default\":\"value\"},\"justifyMode\":{\"$ref\":\"#/definitions/BigValueJustifyMode\",\"default\":\"auto\"},\"textMode\":{\"$ref\":\"#/definitions/BigValueTextMode\",\"default\":\"auto\"},\"wideLayout\":{\"type\":\"boolean\",\"default\":true},\"showPercentChange\":{\"type\":\"boolean\",\"default\":false},\"reduceOptions\":{\"$ref\":\"#/definitions/ReduceDataOptions\"},\"text\":{\"$ref\":\"#/definitions/VizTextDisplayOptions\"},\"percentChangeColorMode\":{\"$ref\":\"#/definitions/PercentChangeColorMode\",\"default\":\"standard\"},\"orientation\":{\"$ref\":\"#/definitions/VizOrientation\"}}},\"BigValueGraphMode\":{\"enum\":[\"none\",\"line\",\"area\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"BigValueColorMode\":{\"enum\":[\"value\",\"background\",\"background_solid\",\"none\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"BigValueJustifyMode\":{\"enum\":[\"auto\",\"center\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"BigValueTextMode\":{\"enum\":[\"auto\",\"value\",\"value_and_name\",\"name\",\"none\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"ReduceDataOptions\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"calcs\"],\"properties\":{\"values\":{\"type\":\"boolean\",\"description\":\"If true show each row value\"},\"limit\":{\"type\":\"number\",\"description\":\"if showing all values limit\"},\"calcs\":{\"type\":\"array\",\"items\":{\"type\":\"string\"},\"description\":\"When !values, pick one value for the whole field\"},\"fields\":{\"type\":\"string\",\"description\":\"Which fields to show. By default this is only numeric fields\"}},\"description\":\"TODO docs\"},\"VizTextDisplayOptions\":{\"type\":\"object\",\"additionalProperties\":false,\"properties\":{\"titleSize\":{\"type\":\"number\",\"description\":\"Explicit title text size\"},\"valueSize\":{\"type\":\"number\",\"description\":\"Explicit value text size\"},\"percentSize\":{\"type\":\"number\",\"description\":\"Explicit percent text size\"}},\"description\":\"TODO docs\"},\"PercentChangeColorMode\":{\"enum\":[\"standard\",\"inverted\",\"same_as_value\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"VizOrientation\":{\"enum\":[\"auto\",\"vertical\",\"horizontal\"],\"type\":\"string\",\"description\":\"TODO docs\"}}}",
14
14
  "gauge": "{\"$schema\":\"http://json-schema.org/draft-07/schema#\",\"definitions\":{\"Options\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"showThresholdLabels\",\"showThresholdMarkers\",\"sizing\",\"minVizWidth\",\"reduceOptions\",\"minVizHeight\",\"orientation\"],\"properties\":{\"showThresholdLabels\":{\"type\":\"boolean\",\"default\":false},\"showThresholdMarkers\":{\"type\":\"boolean\",\"default\":true},\"sizing\":{\"$ref\":\"#/definitions/BarGaugeSizing\",\"default\":\"auto\"},\"minVizWidth\":{\"type\":\"integer\",\"default\":75},\"reduceOptions\":{\"$ref\":\"#/definitions/ReduceDataOptions\"},\"text\":{\"$ref\":\"#/definitions/VizTextDisplayOptions\"},\"minVizHeight\":{\"type\":\"integer\",\"default\":75},\"orientation\":{\"$ref\":\"#/definitions/VizOrientation\"}}},\"BarGaugeSizing\":{\"enum\":[\"auto\",\"manual\"],\"type\":\"string\",\"description\":\"Allows for the bar gauge size to be set explicitly\"},\"ReduceDataOptions\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"calcs\"],\"properties\":{\"values\":{\"type\":\"boolean\",\"description\":\"If true show each row value\"},\"limit\":{\"type\":\"number\",\"description\":\"if showing all values limit\"},\"calcs\":{\"type\":\"array\",\"items\":{\"type\":\"string\"},\"description\":\"When !values, pick one value for the whole field\"},\"fields\":{\"type\":\"string\",\"description\":\"Which fields to show. By default this is only numeric fields\"}},\"description\":\"TODO docs\"},\"VizTextDisplayOptions\":{\"type\":\"object\",\"additionalProperties\":false,\"properties\":{\"titleSize\":{\"type\":\"number\",\"description\":\"Explicit title text size\"},\"valueSize\":{\"type\":\"number\",\"description\":\"Explicit value text size\"},\"percentSize\":{\"type\":\"number\",\"description\":\"Explicit percent text size\"}},\"description\":\"TODO docs\"},\"VizOrientation\":{\"enum\":[\"auto\",\"vertical\",\"horizontal\"],\"type\":\"string\",\"description\":\"TODO docs\"}}}",
15
15
  "table": "{\"$schema\":\"http://json-schema.org/draft-07/schema#\",\"definitions\":{\"Options\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"frameIndex\",\"showHeader\"],\"properties\":{\"frameIndex\":{\"type\":\"number\",\"description\":\"Represents the index of the selected frame\",\"default\":0},\"showHeader\":{\"type\":\"boolean\",\"description\":\"Controls whether the panel should show the header\",\"default\":true},\"showTypeIcons\":{\"type\":\"boolean\",\"description\":\"Controls whether the header should show icons for the column types\",\"default\":false},\"sortBy\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/definitions/TableSortByFieldState\"},\"description\":\"Used to control row sorting\"},\"footer\":{\"$ref\":\"#/definitions/TableFooterOptions\",\"description\":\"Controls footer options\",\"default\":{\"countRows\":false,\"reducer\":null,\"show\":false}},\"cellHeight\":{\"$ref\":\"#/definitions/TableCellHeight\",\"description\":\"Controls the height of the rows\",\"default\":\"sm\"}}},\"FieldConfig\":{\"$ref\":\"#/definitions/TableFieldOptions\"},\"TableSortByFieldState\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"displayName\"],\"properties\":{\"displayName\":{\"type\":\"string\",\"description\":\"Sets the display name of the field to sort by\"},\"desc\":{\"type\":\"boolean\",\"description\":\"Flag used to indicate descending sort order\"}},\"description\":\"Sort by field state\"},\"TableFooterOptions\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"show\",\"reducer\"],\"properties\":{\"show\":{\"type\":\"boolean\"},\"reducer\":{\"type\":\"array\",\"items\":{\"type\":\"string\"},\"description\":\"actually 1 value\"},\"fields\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"enablePagination\":{\"type\":\"boolean\"},\"countRows\":{\"type\":\"boolean\"}},\"description\":\"Footer options\"},\"TableCellHeight\":{\"enum\":[\"sm\",\"md\",\"lg\",\"auto\"],\"type\":\"string\",\"description\":\"Height of a table cell\"},\"TableFieldOptions\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"align\",\"inspect\"],\"properties\":{\"width\":{\"type\":\"number\"},\"minWidth\":{\"type\":\"number\"},\"align\":{\"$ref\":\"#/definitions/FieldTextAlignment\",\"default\":\"auto\"},\"displayMode\":{\"$ref\":\"#/definitions/TableCellDisplayMode\",\"description\":\"This field is deprecated in favor of using cellOptions\"},\"cellOptions\":{\"anyOf\":[{\"$ref\":\"#/definitions/TableCellOptions\"},{\"type\":\"null\"}]},\"hidden\":{\"type\":\"boolean\",\"description\":\"?? default is missing or false ??\"},\"inspect\":{\"type\":\"boolean\",\"default\":false},\"filterable\":{\"type\":\"boolean\"},\"hideHeader\":{\"type\":\"boolean\",\"description\":\"Hides any header for a column, useful for columns that show some static content or buttons.\"},\"footer\":{\"$ref\":\"#/definitions/TableFieldFooterOptions\",\"description\":\"options for the footer for this field\"},\"sortable\":{\"type\":\"boolean\",\"description\":\"Controls whether the column can be sorted. Every column is sortable by default; set to false to disable sorting for this column.\"},\"wrapText\":{\"type\":\"boolean\",\"description\":\"if true, wrap the text content of the cell\"},\"wrapHeaderText\":{\"type\":\"boolean\",\"description\":\"Enables text wrapping for column headers\"},\"tooltip\":{\"$ref\":\"#/definitions/TableCellTooltipOptions\",\"description\":\"Selecting or hovering this field will show a tooltip containing the content within the target field\"},\"styleField\":{\"type\":\"string\",\"description\":\"The name of the field which contains styling overrides for this cell\"}},\"description\":\"Field options for each field within a table (e.g 10, \\\"The String\\\", 64.20, etc.)\\nGenerally defines alignment, filtering capabilties, display options, etc.\"},\"FieldTextAlignment\":{\"enum\":[\"auto\",\"left\",\"right\",\"center\"],\"type\":\"string\",\"description\":\"TODO -- should not be table specific!\\nTODO docs\"},\"TableCellDisplayMode\":{\"enum\":[\"auto\",\"color-text\",\"color-background\",\"color-background-solid\",\"gradient-gauge\",\"lcd-gauge\",\"json-view\",\"basic\",\"image\",\"gauge\",\"sparkline\",\"data-links\",\"custom\",\"actions\",\"pill\",\"markdown\",\"geo\"],\"type\":\"string\",\"description\":\"Internally, this is the \\\"type\\\" of cell that's being displayed\\nin the table such as colored text, JSON, gauge, etc.\\nThe color-background-solid, gradient-gauge, and lcd-gauge\\nmodes are deprecated in favor of new cell subOptions\"},\"TableCellOptions\":{\"oneOf\":[{\"$ref\":\"#/definitions/TableAutoCellOptions\"},{\"$ref\":\"#/definitions/TableSparklineCellOptions\"},{\"$ref\":\"#/definitions/TableBarGaugeCellOptions\"},{\"$ref\":\"#/definitions/TableColoredBackgroundCellOptions\"},{\"$ref\":\"#/definitions/TableColorTextCellOptions\"},{\"$ref\":\"#/definitions/TableImageCellOptions\"},{\"$ref\":\"#/definitions/TableDataLinksCellOptions\"},{\"$ref\":\"#/definitions/TableActionsCellOptions\"},{\"$ref\":\"#/definitions/TableJsonViewCellOptions\"},{\"$ref\":\"#/definitions/TablePillCellOptions\"},{\"$ref\":\"#/definitions/TableMarkdownCellOptions\"},{\"$ref\":\"#/definitions/TableGeoCellOptions\"}],\"description\":\"Table cell options. Each cell has a display mode\\nand other potential options for that display.\"},\"TableAutoCellOptions\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"type\"],\"properties\":{\"type\":{\"allOf\":[{\"$ref\":\"#/definitions/TableCellDisplayMode\"}],\"default\":\"auto\"},\"wrapText\":{\"type\":\"boolean\"}},\"description\":\"Auto mode table cell options\"},\"TableSparklineCellOptions\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"type\"],\"properties\":{\"type\":{\"allOf\":[{\"$ref\":\"#/definitions/TableCellDisplayMode\"}],\"default\":\"sparkline\"},\"drawStyle\":{\"$ref\":\"#/definitions/GraphDrawStyle\"},\"gradientMode\":{\"$ref\":\"#/definitions/GraphGradientMode\"},\"thresholdsStyle\":{\"$ref\":\"#/definitions/GraphThresholdsStyleConfig\"},\"transform\":{\"$ref\":\"#/definitions/GraphTransform\"},\"lineColor\":{\"type\":\"string\"},\"lineWidth\":{\"type\":\"number\"},\"lineInterpolation\":{\"$ref\":\"#/definitions/LineInterpolation\"},\"lineStyle\":{\"$ref\":\"#/definitions/LineStyle\"},\"fillColor\":{\"type\":\"string\"},\"fillOpacity\":{\"type\":\"number\"},\"showPoints\":{\"$ref\":\"#/definitions/VisibilityMode\"},\"pointSize\":{\"type\":\"number\"},\"pointColor\":{\"type\":\"string\"},\"axisPlacement\":{\"$ref\":\"#/definitions/AxisPlacement\"},\"axisColorMode\":{\"$ref\":\"#/definitions/AxisColorMode\"},\"axisLabel\":{\"type\":\"string\"},\"axisWidth\":{\"type\":\"number\"},\"axisSoftMin\":{\"type\":\"number\"},\"axisSoftMax\":{\"type\":\"number\"},\"axisGridShow\":{\"type\":\"boolean\"},\"scaleDistribution\":{\"$ref\":\"#/definitions/ScaleDistributionConfig\"},\"axisCenteredZero\":{\"type\":\"boolean\"},\"barAlignment\":{\"$ref\":\"#/definitions/BarAlignment\"},\"barWidthFactor\":{\"type\":\"number\"},\"stacking\":{\"$ref\":\"#/definitions/StackingConfig\"},\"hideFrom\":{\"$ref\":\"#/definitions/HideSeriesConfig\"},\"hideValue\":{\"type\":\"boolean\"},\"insertNulls\":{\"oneOf\":[{\"type\":\"boolean\"},{\"type\":\"number\"}]},\"spanNulls\":{\"oneOf\":[{\"type\":\"boolean\"},{\"type\":\"number\"}],\"description\":\"Indicate if null values should be treated as gaps or connected.\\nWhen the value is a number, it represents the maximum delta in the\\nX axis that should be considered connected. For timeseries, this is milliseconds\"},\"fillBelowTo\":{\"type\":\"string\"},\"pointSymbol\":{\"type\":\"string\"},\"axisBorderShow\":{\"type\":\"boolean\"},\"barMaxWidth\":{\"type\":\"number\"}},\"description\":\"Sparkline cell options\"},\"TableBarGaugeCellOptions\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"type\"],\"properties\":{\"type\":{\"allOf\":[{\"$ref\":\"#/definitions/TableCellDisplayMode\"}],\"default\":\"gauge\"},\"mode\":{\"$ref\":\"#/definitions/BarGaugeDisplayMode\"},\"valueDisplayMode\":{\"$ref\":\"#/definitions/BarGaugeValueMode\"}},\"description\":\"Gauge cell options\"},\"TableColoredBackgroundCellOptions\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"type\"],\"properties\":{\"type\":{\"allOf\":[{\"$ref\":\"#/definitions/TableCellDisplayMode\"}],\"default\":\"color-background\"},\"mode\":{\"$ref\":\"#/definitions/TableCellBackgroundDisplayMode\"},\"applyToRow\":{\"type\":\"boolean\"},\"wrapText\":{\"type\":\"boolean\"}},\"description\":\"Colored background cell options\"},\"TableColorTextCellOptions\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"type\"],\"properties\":{\"type\":{\"allOf\":[{\"$ref\":\"#/definitions/TableCellDisplayMode\"}],\"default\":\"color-text\"},\"wrapText\":{\"type\":\"boolean\"}},\"description\":\"Colored text cell options\"},\"TableImageCellOptions\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"type\"],\"properties\":{\"type\":{\"allOf\":[{\"$ref\":\"#/definitions/TableCellDisplayMode\"}],\"default\":\"image\"},\"alt\":{\"type\":\"string\"},\"title\":{\"type\":\"string\"}},\"description\":\"Json view cell options\"},\"TableDataLinksCellOptions\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"type\"],\"properties\":{\"type\":{\"allOf\":[{\"$ref\":\"#/definitions/TableCellDisplayMode\"}],\"default\":\"data-links\"}},\"description\":\"Show data links in the cell\"},\"TableActionsCellOptions\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"type\"],\"properties\":{\"type\":{\"allOf\":[{\"$ref\":\"#/definitions/TableCellDisplayMode\"}],\"default\":\"actions\"}},\"description\":\"Show actions in the cell\"},\"TableJsonViewCellOptions\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"type\"],\"properties\":{\"type\":{\"allOf\":[{\"$ref\":\"#/definitions/TableCellDisplayMode\"}],\"default\":\"json-view\"}},\"description\":\"Json view cell options\"},\"GraphDrawStyle\":{\"enum\":[\"line\",\"bars\",\"points\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"GraphGradientMode\":{\"enum\":[\"none\",\"opacity\",\"hue\",\"scheme\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"GraphThresholdsStyleConfig\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"mode\"],\"properties\":{\"mode\":{\"$ref\":\"#/definitions/GraphThresholdsStyleMode\"}},\"description\":\"TODO docs\"},\"GraphTransform\":{\"enum\":[\"constant\",\"negative-Y\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"LineInterpolation\":{\"enum\":[\"linear\",\"smooth\",\"stepBefore\",\"stepAfter\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"LineStyle\":{\"type\":\"object\",\"additionalProperties\":false,\"properties\":{\"fill\":{\"enum\":[\"solid\",\"dash\",\"dot\",\"square\",\"accessible\"],\"type\":\"string\"},\"dash\":{\"type\":\"array\",\"items\":{\"type\":\"number\"}}},\"description\":\"TODO docs\"},\"VisibilityMode\":{\"enum\":[\"auto\",\"never\",\"always\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"AxisPlacement\":{\"enum\":[\"auto\",\"top\",\"right\",\"bottom\",\"left\",\"hidden\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"AxisColorMode\":{\"enum\":[\"text\",\"series\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"ScaleDistributionConfig\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"type\"],\"properties\":{\"type\":{\"$ref\":\"#/definitions/ScaleDistribution\"},\"log\":{\"type\":\"number\"},\"linearThreshold\":{\"type\":\"number\"}},\"description\":\"TODO docs\"},\"BarAlignment\":{\"enum\":[-1,0,1],\"type\":\"integer\",\"description\":\"TODO docs\"},\"StackingConfig\":{\"type\":\"object\",\"additionalProperties\":false,\"properties\":{\"mode\":{\"$ref\":\"#/definitions/StackingMode\"},\"group\":{\"type\":\"string\"}},\"description\":\"TODO docs\"},\"HideSeriesConfig\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"tooltip\",\"legend\",\"viz\"],\"properties\":{\"tooltip\":{\"type\":\"boolean\"},\"legend\":{\"type\":\"boolean\"},\"viz\":{\"type\":\"boolean\"}},\"description\":\"TODO docs\"},\"BarGaugeDisplayMode\":{\"enum\":[\"basic\",\"lcd\",\"gradient\"],\"type\":\"string\",\"description\":\"Enum expressing the possible display modes\\nfor the bar gauge component of Grafana UI\"},\"BarGaugeValueMode\":{\"enum\":[\"color\",\"text\",\"hidden\"],\"type\":\"string\",\"description\":\"Allows for the table cell gauge display type to set the gauge mode.\"},\"TableCellBackgroundDisplayMode\":{\"enum\":[\"basic\",\"gradient\"],\"type\":\"string\",\"description\":\"Display mode to the \\\"Colored Background\\\" display\\nmode for table cells. Either displays a solid color (basic mode)\\nor a gradient.\"},\"GraphThresholdsStyleMode\":{\"enum\":[\"off\",\"line\",\"dashed\",\"area\",\"line+area\",\"dashed+area\",\"series\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"ScaleDistribution\":{\"enum\":[\"linear\",\"log\",\"ordinal\",\"symlog\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"StackingMode\":{\"enum\":[\"none\",\"normal\",\"percent\"],\"type\":\"string\",\"description\":\"TODO docs\"},\"TablePillCellOptions\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"type\"],\"properties\":{\"type\":{\"allOf\":[{\"$ref\":\"#/definitions/TableCellDisplayMode\"}],\"default\":\"pill\"}},\"description\":\"Pill cell options\"},\"TableMarkdownCellOptions\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"type\"],\"properties\":{\"type\":{\"allOf\":[{\"$ref\":\"#/definitions/TableCellDisplayMode\"}],\"default\":\"markdown\"},\"dynamicHeight\":{\"type\":\"boolean\"}},\"description\":\"Markdown cell options\"},\"TableGeoCellOptions\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"type\"],\"properties\":{\"type\":{\"allOf\":[{\"$ref\":\"#/definitions/TableCellDisplayMode\"}],\"default\":\"geo\"}},\"description\":\"Geo cell options\"},\"TableFieldFooterOptions\":{\"type\":\"object\",\"additionalProperties\":false,\"properties\":{\"reducers\":{\"type\":\"array\",\"items\":{\"type\":\"string\"},\"description\":\"footer reducers to apply to this field\"}},\"description\":\"The footer of one field (TableFooterOptions in the CUE; renamed here because the vendored schema already has a panel-level TableFooterOptions)\"},\"TableCellTooltipPlacement\":{\"type\":\"string\",\"enum\":[\"top\",\"bottom\",\"left\",\"right\",\"auto\"],\"description\":\"Where the cell tooltip is placed\"},\"TableCellTooltipOptions\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"field\"],\"properties\":{\"field\":{\"type\":\"string\",\"description\":\"The name of the field to get the tooltip content from\"},\"placement\":{\"$ref\":\"#/definitions/TableCellTooltipPlacement\",\"description\":\"placement of the tooltip\"}},\"description\":\"Tooltip shown when a cell of this field is selected or hovered\"}}}",