@intentius/chant-lexicon-grafana 0.97.0 → 0.99.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 +15 -5
- package/dist/actions/grafana.d.ts +24 -0
- package/dist/actions/grafana.d.ts.map +1 -0
- package/dist/actions/index.d.ts +2 -0
- package/dist/actions/index.d.ts.map +1 -0
- package/dist/alerting-build.d.ts +128 -0
- package/dist/alerting-build.d.ts.map +1 -0
- package/dist/alerting.d.ts +273 -0
- package/dist/alerting.d.ts.map +1 -0
- package/dist/api/apply.d.ts +156 -0
- package/dist/api/apply.d.ts.map +1 -0
- package/dist/api/bind.d.ts +32 -0
- package/dist/api/bind.d.ts.map +1 -0
- package/dist/api/client.d.ts +76 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/converge.d.ts +33 -0
- package/dist/api/converge.d.ts.map +1 -0
- package/dist/api/dashboards.d.ts +102 -0
- package/dist/api/dashboards.d.ts.map +1 -0
- package/dist/api/datasources.d.ts +26 -0
- package/dist/api/datasources.d.ts.map +1 -0
- package/dist/api/fake-grafana-writes.d.ts +41 -0
- package/dist/api/fake-grafana-writes.d.ts.map +1 -0
- package/dist/api/fake-grafana.d.ts +61 -0
- package/dist/api/fake-grafana.d.ts.map +1 -0
- package/dist/api/folders.d.ts +110 -0
- package/dist/api/folders.d.ts.map +1 -0
- package/dist/api/library-panels.d.ts +52 -0
- package/dist/api/library-panels.d.ts.map +1 -0
- package/dist/build.d.ts +30 -2
- package/dist/build.d.ts.map +1 -1
- package/dist/catalog.d.ts +1 -1
- package/dist/catalog.d.ts.map +1 -1
- package/dist/codegen/docs.d.ts.map +1 -1
- package/dist/codegen/schema-types.d.ts +3 -3
- package/dist/codegen/schema-types.d.ts.map +1 -1
- package/dist/composites/agent-dashboard.d.ts.map +1 -1
- package/dist/composites/catalog.d.ts.map +1 -1
- package/dist/composites/index.d.ts +4 -2
- package/dist/composites/index.d.ts.map +1 -1
- package/dist/composites/red-dashboard.d.ts +21 -2
- package/dist/composites/red-dashboard.d.ts.map +1 -1
- package/dist/composites/shared.d.ts +7 -0
- package/dist/composites/shared.d.ts.map +1 -1
- package/dist/composites/slo-alert-rules.d.ts +92 -0
- package/dist/composites/slo-alert-rules.d.ts.map +1 -0
- package/dist/config.d.ts +111 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/contact-point-secrets.d.ts +17 -0
- package/dist/contact-point-secrets.d.ts.map +1 -0
- package/dist/dashboard.d.ts +16 -2
- package/dist/dashboard.d.ts.map +1 -1
- package/dist/datasource-refs.d.ts +95 -0
- package/dist/datasource-refs.d.ts.map +1 -0
- package/dist/datasource.d.ts +29 -0
- package/dist/datasource.d.ts.map +1 -1
- package/dist/deep-observe-hooks.d.ts +64 -0
- package/dist/deep-observe-hooks.d.ts.map +1 -0
- package/dist/deep-observe.d.ts +42 -0
- package/dist/deep-observe.d.ts.map +1 -0
- package/dist/describe-resources.d.ts +49 -0
- package/dist/describe-resources.d.ts.map +1 -0
- package/dist/detect.d.ts +28 -1
- package/dist/detect.d.ts.map +1 -1
- package/dist/export-resources.d.ts +38 -0
- package/dist/export-resources.d.ts.map +1 -0
- package/dist/import/alerting.d.ts +40 -0
- package/dist/import/alerting.d.ts.map +1 -0
- package/dist/import/edits.d.ts +47 -0
- package/dist/import/edits.d.ts.map +1 -0
- package/dist/import/embedded.d.ts +14 -0
- package/dist/import/embedded.d.ts.map +1 -0
- package/dist/import/generator.d.ts +60 -0
- package/dist/import/generator.d.ts.map +1 -0
- package/dist/import/live-export.d.ts +108 -0
- package/dist/import/live-export.d.ts.map +1 -0
- package/dist/import/mappings.d.ts +83 -0
- package/dist/import/mappings.d.ts.map +1 -0
- package/dist/import/model.d.ts +98 -0
- package/dist/import/model.d.ts.map +1 -0
- package/dist/import/normalize-alerting.d.ts +26 -0
- package/dist/import/normalize-alerting.d.ts.map +1 -0
- package/dist/import/normalize.d.ts +74 -0
- package/dist/import/normalize.d.ts.map +1 -0
- package/dist/import/parser.d.ts +110 -0
- package/dist/import/parser.d.ts.map +1 -0
- package/dist/import/report.d.ts +26 -0
- package/dist/import/report.d.ts.map +1 -0
- package/dist/import/testdata/fixtures.d.ts +35 -0
- package/dist/import/testdata/fixtures.d.ts.map +1 -0
- package/dist/import/v2.d.ts +72 -0
- package/dist/import/v2.d.ts.map +1 -0
- package/dist/index.d.ts +26 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/integrity.json +18 -10
- package/dist/k8s.d.ts +107 -0
- package/dist/k8s.d.ts.map +1 -0
- package/dist/lint/audit-catalog.d.ts +2 -1
- package/dist/lint/audit-catalog.d.ts.map +1 -1
- package/dist/lint/post-synth/graf101.d.ts +2 -2
- package/dist/lint/post-synth/graf102.d.ts +1 -1
- package/dist/lint/post-synth/graf107.d.ts +1 -1
- package/dist/lint/post-synth/graf108.d.ts +8 -0
- package/dist/lint/post-synth/graf108.d.ts.map +1 -0
- package/dist/lint/post-synth/graf109.d.ts +8 -0
- package/dist/lint/post-synth/graf109.d.ts.map +1 -0
- package/dist/lint/post-synth/graf111.d.ts +8 -0
- package/dist/lint/post-synth/graf111.d.ts.map +1 -0
- package/dist/lint/post-synth/graf112.d.ts +8 -0
- package/dist/lint/post-synth/graf112.d.ts.map +1 -0
- package/dist/lint/post-synth/graf113.d.ts +8 -0
- package/dist/lint/post-synth/graf113.d.ts.map +1 -0
- package/dist/lint/post-synth/graf114.d.ts +8 -0
- package/dist/lint/post-synth/graf114.d.ts.map +1 -0
- package/dist/lint/post-synth/graf115.d.ts +8 -0
- package/dist/lint/post-synth/graf115.d.ts.map +1 -0
- package/dist/lint/post-synth/grafana-helpers.d.ts +7 -5
- package/dist/lint/post-synth/grafana-helpers.d.ts.map +1 -1
- package/dist/lint/post-synth/index.d.ts.map +1 -1
- package/dist/lint/rules/literal-secret.d.ts +7 -3
- package/dist/lint/rules/literal-secret.d.ts.map +1 -1
- package/dist/lsp/hover.d.ts.map +1 -1
- package/dist/manifest.json +1 -1
- package/dist/members.d.ts +27 -0
- package/dist/members.d.ts.map +1 -0
- package/dist/meta.json +135 -0
- package/dist/okf/index.md +36 -2
- package/dist/okf/rules/GRAF002.md +3 -2
- package/dist/okf/rules/GRAF101.md +3 -2
- package/dist/okf/rules/GRAF102.md +1 -0
- package/dist/okf/rules/GRAF108.md +11 -0
- package/dist/okf/rules/GRAF109.md +15 -0
- package/dist/okf/rules/GRAF111.md +11 -0
- package/dist/okf/rules/GRAF112.md +16 -0
- package/dist/okf/rules/GRAF113.md +16 -0
- package/dist/okf/rules/GRAF114.md +11 -0
- package/dist/okf/rules/GRAF115.md +11 -0
- package/dist/okf/types/AlertListPanel.md +9 -0
- package/dist/okf/types/AlertQuery.md +9 -0
- package/dist/okf/types/AlertRule.md +9 -0
- package/dist/okf/types/AlertRuleGroup.md +9 -0
- package/dist/okf/types/BarChartPanel.md +9 -0
- package/dist/okf/types/BarGaugePanel.md +9 -0
- package/dist/okf/types/CanvasPanel.md +9 -0
- package/dist/okf/types/ClassicConditionsExpression.md +9 -0
- package/dist/okf/types/ContactPoint.md +14 -0
- package/dist/okf/types/Dashboard.md +1 -0
- package/dist/okf/types/Datasource.md +3 -2
- package/dist/okf/types/ExternalDatasource.md +15 -0
- package/dist/okf/types/FlameGraphPanel.md +9 -0
- package/dist/okf/types/GeomapPanel.md +9 -0
- package/dist/okf/types/HistogramPanel.md +9 -0
- package/dist/okf/types/MathExpression.md +9 -0
- package/dist/okf/types/MuteTiming.md +13 -0
- package/dist/okf/types/NodeGraphPanel.md +9 -0
- package/dist/okf/types/NotificationPolicy.md +9 -0
- package/dist/okf/types/NotificationTemplate.md +9 -0
- package/dist/okf/types/PieChartPanel.md +9 -0
- package/dist/okf/types/ReduceExpression.md +9 -0
- package/dist/okf/types/ResampleExpression.md +9 -0
- package/dist/okf/types/SqlExpression.md +9 -0
- package/dist/okf/types/StateTimelinePanel.md +9 -0
- package/dist/okf/types/StatusHistoryPanel.md +9 -0
- package/dist/okf/types/ThresholdExpression.md +9 -0
- package/dist/okf/types/TrendPanel.md +9 -0
- package/dist/okf/types/XYChartPanel.md +9 -0
- package/dist/op/activities/grafana-apply.d.ts +75 -0
- package/dist/op/activities/grafana-apply.d.ts.map +1 -0
- package/dist/op/activities/index.d.ts +9 -0
- package/dist/op/activities/index.d.ts.map +1 -0
- package/dist/op/builders.d.ts +24 -0
- package/dist/op/builders.d.ts.map +1 -0
- package/dist/ownership.d.ts +67 -0
- package/dist/ownership.d.ts.map +1 -0
- package/dist/panel-options.d.ts +65 -0
- package/dist/panel-options.d.ts.map +1 -0
- package/dist/panels.d.ts +46 -9
- package/dist/panels.d.ts.map +1 -1
- package/dist/pin.d.ts +29 -7
- package/dist/pin.d.ts.map +1 -1
- package/dist/plugin.d.ts.map +1 -1
- package/dist/promql-check.d.ts +51 -0
- package/dist/promql-check.d.ts.map +1 -0
- package/dist/query.d.ts +9 -8
- package/dist/query.d.ts.map +1 -1
- package/dist/rules/graf101.ts +3 -3
- package/dist/rules/graf102.ts +1 -1
- package/dist/rules/graf107.ts +1 -1
- package/dist/rules/graf108.ts +17 -0
- package/dist/rules/graf109.ts +17 -0
- package/dist/rules/graf111.ts +17 -0
- package/dist/rules/graf112.ts +17 -0
- package/dist/rules/graf113.ts +17 -0
- package/dist/rules/graf114.ts +17 -0
- package/dist/rules/graf115.ts +17 -0
- package/dist/rules/grafana-helpers.ts +15 -8
- package/dist/rules/literal-secret.ts +60 -6
- package/dist/schema/barchart.gen.d.ts +198 -0
- package/dist/schema/barchart.gen.d.ts.map +1 -0
- package/dist/schema/bargauge.gen.d.ts +97 -0
- package/dist/schema/bargauge.gen.d.ts.map +1 -0
- package/dist/schema/canvas.gen.d.ts +152 -0
- package/dist/schema/canvas.gen.d.ts.map +1 -0
- package/dist/schema/dashboard.gen.d.ts +196 -21
- package/dist/schema/dashboard.gen.d.ts.map +1 -1
- package/dist/schema/expr.gen.d.ts +606 -0
- package/dist/schema/expr.gen.d.ts.map +1 -0
- package/dist/schema/gauge.gen.d.ts.map +1 -1
- package/dist/schema/geomap.gen.d.ts +100 -0
- package/dist/schema/geomap.gen.d.ts.map +1 -0
- package/dist/schema/heatmap.gen.d.ts.map +1 -1
- package/dist/schema/histogram.gen.d.ts +132 -0
- package/dist/schema/histogram.gen.d.ts.map +1 -0
- package/dist/schema/index.d.ts +12 -0
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/logs.gen.d.ts +1 -0
- package/dist/schema/logs.gen.d.ts.map +1 -1
- package/dist/schema/loki.gen.d.ts.map +1 -1
- package/dist/schema/nodegraph.gen.d.ts +49 -0
- package/dist/schema/nodegraph.gen.d.ts.map +1 -0
- package/dist/schema/piechart.gen.d.ts +127 -0
- package/dist/schema/piechart.gen.d.ts.map +1 -0
- package/dist/schema/prometheus.gen.d.ts.map +1 -1
- package/dist/schema/stat.gen.d.ts.map +1 -1
- package/dist/schema/statetimeline.gen.d.ts +124 -0
- package/dist/schema/statetimeline.gen.d.ts.map +1 -0
- package/dist/schema/statushistory.gen.d.ts +114 -0
- package/dist/schema/statushistory.gen.d.ts.map +1 -0
- package/dist/schema/table.gen.d.ts +22 -3
- package/dist/schema/table.gen.d.ts.map +1 -1
- package/dist/schema/tempo.gen.d.ts.map +1 -1
- package/dist/schema/text.gen.d.ts.map +1 -1
- package/dist/schema/timeseries.gen.d.ts +5 -1
- package/dist/schema/timeseries.gen.d.ts.map +1 -1
- package/dist/schema/trend.gen.d.ts +180 -0
- package/dist/schema/trend.gen.d.ts.map +1 -0
- package/dist/schema/xychart.gen.d.ts +145 -0
- package/dist/schema/xychart.gen.d.ts.map +1 -0
- package/dist/schema-validate.d.ts +30 -4
- package/dist/schema-validate.d.ts.map +1 -1
- package/dist/serializer.d.ts +11 -3
- package/dist/serializer.d.ts.map +1 -1
- package/dist/skill-defs.d.ts.map +1 -1
- package/dist/skills/chant-grafana-alerting.md +49 -0
- package/dist/skills/chant-grafana-provisioning.md +3 -3
- package/dist/skills/chant-grafana.md +12 -6
- package/dist/spec/fetch-units-cli.d.ts +3 -0
- package/dist/spec/fetch-units-cli.d.ts.map +1 -0
- package/dist/spec/overlay.d.ts +43 -0
- package/dist/spec/overlay.d.ts.map +1 -0
- package/dist/spec/schemas.d.ts +13 -7
- package/dist/spec/schemas.d.ts.map +1 -1
- package/dist/spec/units.d.ts +35 -0
- package/dist/spec/units.d.ts.map +1 -0
- package/dist/spec/units.gen.d.ts +2 -0
- package/dist/spec/units.gen.d.ts.map +1 -0
- package/dist/transformations.d.ts +459 -0
- package/dist/transformations.d.ts.map +1 -0
- package/dist/util.d.ts +6 -0
- package/dist/util.d.ts.map +1 -1
- package/dist/validate-alerting.d.ts +65 -0
- package/dist/validate-alerting.d.ts.map +1 -0
- package/dist/validate-output.d.ts +49 -9
- package/dist/validate-output.d.ts.map +1 -1
- package/dist/validate.d.ts.map +1 -1
- package/dist/variables.d.ts +7 -2
- package/dist/variables.d.ts.map +1 -1
- package/package.json +12 -4
- package/src/actions/actions.test.ts +24 -0
- package/src/actions/grafana.ts +40 -0
- package/src/actions/index.ts +1 -0
- package/src/alerting-build.ts +376 -0
- package/src/alerting.e2e.test.ts +212 -0
- package/src/alerting.test.ts +272 -0
- package/src/alerting.ts +435 -0
- package/src/api/apply.test.ts +238 -0
- package/src/api/apply.ts +384 -0
- package/src/api/bind.ts +58 -0
- package/src/api/client.ts +148 -0
- package/src/api/converge.ts +63 -0
- package/src/api/dashboards.ts +247 -0
- package/src/api/datasources.ts +33 -0
- package/src/api/fake-grafana-writes.ts +201 -0
- package/src/api/fake-grafana.ts +186 -0
- package/src/api/folders.ts +265 -0
- package/src/api/library-panels.ts +101 -0
- package/src/build.test.ts +210 -5
- package/src/build.ts +180 -43
- package/src/catalog.ts +86 -2
- package/src/codegen/docs.ts +42 -9
- package/src/codegen/schema-types.ts +16 -6
- package/src/composites/agent-dashboard.ts +6 -3
- package/src/composites/catalog.test.ts +2 -2
- package/src/composites/catalog.ts +82 -0
- package/src/composites/composites.test.ts +73 -9
- package/src/composites/index.ts +4 -2
- package/src/composites/queries.e2e.test.ts +374 -0
- package/src/composites/red-dashboard.ts +83 -12
- package/src/composites/shared.ts +11 -0
- package/src/composites/slo-alert-rules.ts +149 -0
- package/src/config.test.ts +61 -0
- package/src/config.ts +138 -0
- package/src/contact-point-secrets.ts +63 -0
- package/src/dashboard.ts +16 -2
- package/src/datasource-refs.test.ts +56 -0
- package/src/datasource-refs.ts +189 -0
- package/src/datasource.ts +52 -0
- package/src/deep-observe-hooks.ts +252 -0
- package/src/deep-observe.test.ts +265 -0
- package/src/deep-observe.ts +164 -0
- package/src/describe-resources.test.ts +255 -0
- package/src/describe-resources.ts +209 -0
- package/src/detect.ts +79 -2
- package/src/export-resources.test.ts +129 -0
- package/src/export-resources.ts +84 -0
- package/src/generated/lexicon-grafana.json +135 -0
- package/src/import/alerting-roundtrip.test.ts +161 -0
- package/src/import/alerting.ts +500 -0
- package/src/import/edits.ts +95 -0
- package/src/import/embedded.test.ts +45 -0
- package/src/import/embedded.ts +47 -0
- package/src/import/generated-types.e2e.test.ts +118 -0
- package/src/import/generator.test.ts +210 -0
- package/src/import/generator.ts +462 -0
- package/src/import/live-export.ts +264 -0
- package/src/import/mappings.ts +264 -0
- package/src/import/model.ts +110 -0
- package/src/import/normalize-alerting.ts +101 -0
- package/src/import/normalize.test.ts +117 -0
- package/src/import/normalize.ts +364 -0
- package/src/import/parser.test.ts +440 -0
- package/src/import/parser.ts +1236 -0
- package/src/import/report.ts +62 -0
- package/src/import/roundtrip.test.ts +468 -0
- package/src/import/testdata/fixtures.ts +129 -0
- package/src/import/v2.test.ts +292 -0
- package/src/import/v2.ts +803 -0
- package/src/import.e2e.test.ts +31 -84
- package/src/import.test.ts +9 -3
- package/src/index.ts +190 -5
- package/src/k8s.test.ts +98 -0
- package/src/k8s.ts +197 -0
- package/src/lint/audit-catalog.ts +60 -3
- package/src/lint/core-lint.test.ts +43 -0
- package/src/lint/post-synth/graf101.ts +3 -3
- package/src/lint/post-synth/graf102.ts +1 -1
- package/src/lint/post-synth/graf107.ts +1 -1
- package/src/lint/post-synth/graf108.ts +17 -0
- package/src/lint/post-synth/graf109.ts +17 -0
- package/src/lint/post-synth/graf111.ts +17 -0
- package/src/lint/post-synth/graf112.ts +17 -0
- package/src/lint/post-synth/graf113.ts +17 -0
- package/src/lint/post-synth/graf114.ts +17 -0
- package/src/lint/post-synth/graf115.ts +17 -0
- package/src/lint/post-synth/grafana-helpers.ts +15 -8
- package/src/lint/post-synth/index.ts +14 -0
- package/src/lint/post-synth/post-synth.test.ts +235 -11
- package/src/lint/rules/literal-secret.ts +60 -6
- package/src/lint/rules/rules.test.ts +27 -0
- package/src/lsp/completions.test.ts +5 -0
- package/src/lsp/hover.test.ts +7 -0
- package/src/lsp/hover.ts +8 -1
- package/src/members.ts +68 -0
- package/src/observe.e2e.test.ts +255 -0
- package/src/op/activities/grafana-apply.e2e.test.ts +175 -0
- package/src/op/activities/grafana-apply.test.ts +229 -0
- package/src/op/activities/grafana-apply.ts +171 -0
- package/src/op/activities/index.ts +8 -0
- package/src/op/builders.test.ts +40 -0
- package/src/op/builders.ts +34 -0
- package/src/ownership.ts +103 -0
- package/src/panel-options.ts +66 -0
- package/src/panels.test.ts +51 -0
- package/src/panels.ts +148 -10
- package/src/pin.ts +57 -6
- package/src/plugin.test.ts +5 -2
- package/src/plugin.ts +66 -0
- package/src/promql-check.test.ts +108 -0
- package/src/promql-check.ts +189 -0
- package/src/query.ts +13 -8
- package/src/schema/barchart.gen.ts +221 -0
- package/src/schema/bargauge.gen.ts +111 -0
- package/src/schema/canvas.gen.ts +176 -0
- package/src/schema/dashboard.gen.ts +206 -22
- package/src/schema/expr.gen.ts +618 -0
- package/src/schema/gauge.gen.ts +2 -1
- package/src/schema/geomap.gen.ts +112 -0
- package/src/schema/heatmap.gen.ts +2 -1
- package/src/schema/histogram.gen.ts +151 -0
- package/src/schema/index.ts +12 -0
- package/src/schema/logs.gen.ts +3 -1
- package/src/schema/loki.gen.ts +2 -1
- package/src/schema/nodegraph.gen.ts +58 -0
- package/src/schema/piechart.gen.ts +146 -0
- package/src/schema/prometheus.gen.ts +2 -1
- package/src/schema/stat.gen.ts +2 -1
- package/src/schema/statetimeline.gen.ts +143 -0
- package/src/schema/statushistory.gen.ts +132 -0
- package/src/schema/table.gen.ts +27 -4
- package/src/schema/tempo.gen.ts +2 -1
- package/src/schema/text.gen.ts +2 -1
- package/src/schema/timeseries.gen.ts +7 -2
- package/src/schema/trend.gen.ts +208 -0
- package/src/schema/xychart.gen.ts +167 -0
- package/src/schema-overlay.test.ts +282 -0
- package/src/schema-validate.ts +141 -50
- package/src/schema.test.ts +4 -2
- package/src/serializer.test.ts +13 -1
- package/src/serializer.ts +11 -3
- package/src/skill-defs.ts +17 -0
- package/src/skills/chant-grafana-alerting.md +49 -0
- package/src/skills/chant-grafana-provisioning.md +3 -3
- package/src/skills/chant-grafana.md +12 -6
- package/src/spec/fetch-cli.ts +3 -3
- package/src/spec/fetch-units-cli.ts +37 -0
- package/src/spec/overlay/canvas.overlay.json +142 -0
- package/src/spec/overlay/dashboard.overlay.json +378 -0
- package/src/spec/overlay/expr.overlay.json +14 -0
- package/src/spec/overlay/geomap.overlay.json +35 -0
- package/src/spec/overlay/logs.overlay.json +14 -0
- package/src/spec/overlay/nodegraph.overlay.json +31 -0
- package/src/spec/overlay/piechart.overlay.json +17 -0
- package/src/spec/overlay/table.overlay.json +84 -0
- package/src/spec/overlay/timeseries.overlay.json +21 -0
- package/src/spec/overlay/trend.overlay.json +17 -0
- package/src/spec/overlay/xychart.overlay.json +16 -0
- package/src/spec/overlay.ts +105 -0
- package/src/spec/schemas/barchart.jsonschema.json +419 -0
- package/src/spec/schemas/bargauge.jsonschema.json +224 -0
- package/src/spec/schemas/canvas.jsonschema.json +356 -0
- package/src/spec/schemas/dashboardv2.jsonschema.json +3387 -0
- package/src/spec/schemas/expr.jsonschema.json +987 -0
- package/src/spec/schemas/geomap.jsonschema.json +220 -0
- package/src/spec/schemas/histogram.jsonschema.json +308 -0
- package/src/spec/schemas/nodegraph.jsonschema.json +77 -0
- package/src/spec/schemas/piechart.jsonschema.json +275 -0
- package/src/spec/schemas/statetimeline.jsonschema.json +324 -0
- package/src/spec/schemas/statushistory.jsonschema.json +292 -0
- package/src/spec/schemas/trend.jsonschema.json +449 -0
- package/src/spec/schemas/xychart.jsonschema.json +428 -0
- package/src/spec/schemas.ts +22 -10
- package/src/spec/units.gen.ts +281 -0
- package/src/spec/units.ts +77 -0
- package/src/transformations.test.ts +65 -0
- package/src/transformations.ts +574 -0
- package/src/util.ts +8 -0
- package/src/validate-alerting.test.ts +255 -0
- package/src/validate-alerting.ts +428 -0
- package/src/validate-output.ts +332 -101
- package/src/validate.ts +14 -0
- package/src/variables.ts +7 -2
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
import { describe, expect, test } from "vitest";
|
|
2
|
+
import { detectTemplate } from "../detect";
|
|
3
|
+
import { DASHBOARD_SCHEMA_VERSION } from "../schema/dashboard.gen";
|
|
4
|
+
import { GrafanaParser, planDashboard, type DashboardResourceMetadata, type PlanResourceProperties } from "./parser";
|
|
5
|
+
import { applyEdits } from "./edits";
|
|
6
|
+
import type { Declaration } from "./model";
|
|
7
|
+
import { read, V2_EXPORTS } from "./testdata/fixtures";
|
|
8
|
+
|
|
9
|
+
type Json = Record<string, unknown>;
|
|
10
|
+
|
|
11
|
+
const parse = (doc: unknown) => new GrafanaParser().parse(typeof doc === "string" ? doc : JSON.stringify(doc));
|
|
12
|
+
|
|
13
|
+
/** A minimal classic dashboard with the given parts. */
|
|
14
|
+
function dashboard(parts: Json = {}): Json {
|
|
15
|
+
return { title: "T", uid: "t", schemaVersion: DASHBOARD_SCHEMA_VERSION, panels: [], templating: { list: [] }, ...parts };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function decl(declarations: readonly Declaration[], id: string): Declaration {
|
|
19
|
+
const d = declarations.find((x) => x.id === id);
|
|
20
|
+
if (!d) throw new Error(`no declaration ${id} in ${declarations.map((x) => x.id).join(", ")}`);
|
|
21
|
+
return d;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const prom = { type: "prometheus", uid: "prom" };
|
|
25
|
+
|
|
26
|
+
describe("what the parser accepts", () => {
|
|
27
|
+
// v2 dashboards (#2947) are read into classic JSON; v2.test.ts covers them.
|
|
28
|
+
test("a v2 resource is read into a classic dashboard", () => {
|
|
29
|
+
const ir = parse(read(V2_EXPORTS[0]));
|
|
30
|
+
expect(ir.resources.map((r) => r.logicalId)).toEqual(["checkoutService"]);
|
|
31
|
+
expect(ir.warnings?.[0]).toMatch(/^This is a v2 dashboard \(dashboard\.grafana\.app\/v2\)\./);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test("a bare v2 spec is read too", () => {
|
|
35
|
+
const ir = parse({ title: "x", elements: {}, layout: { kind: "GridLayout", spec: { items: [] } } });
|
|
36
|
+
expect(ir.resources).toHaveLength(1);
|
|
37
|
+
expect(ir.warnings?.[0]).toMatch(/^This is a v2 dashboard\. /);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test("a dashboard from before Grafana 5.0 is reported, not imported", () => {
|
|
41
|
+
const ir = parse({ title: "old", schemaVersion: 12, rows: [{ panels: [] }] });
|
|
42
|
+
expect(ir.resources).toEqual([]);
|
|
43
|
+
expect(ir.warnings?.[0]).toMatch(/^This dashboard was saved before Grafana 5\.0 \(schemaVersion 12\)/);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("a dashboard.grafana.app v1 resource is unwrapped, its uid taken from metadata.name", () => {
|
|
47
|
+
const ir = parse({ apiVersion: "dashboard.grafana.app/v1beta1", kind: "Dashboard", metadata: { name: "abc" }, spec: { title: "T", schemaVersion: 42, panels: [] } });
|
|
48
|
+
const meta = ir.resources[0].metadata as unknown as DashboardResourceMetadata;
|
|
49
|
+
expect(meta.source.uid).toBe("abc");
|
|
50
|
+
expect(ir.warnings).toEqual([]);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test("an /api/dashboards/uid response is unwrapped", () => {
|
|
54
|
+
const ir = parse({ dashboard: dashboard({ id: 7, version: 3 }), meta: { slug: "t" } });
|
|
55
|
+
expect(ir.resources[0].logicalId).toBe("t");
|
|
56
|
+
// The stored copy's id and version are Grafana's bookkeeping: dropped without a word.
|
|
57
|
+
expect(ir.warnings).toEqual([]);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test("anything else is an error", () => {
|
|
61
|
+
expect(() => parse({ hello: "world" })).toThrow(/not Grafana dashboard JSON/);
|
|
62
|
+
expect(() => parse("[1, 2]")).toThrow(/expected Grafana dashboard JSON/);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test("detectTemplate claims every shape the parser reads", () => {
|
|
66
|
+
expect(detectTemplate(JSON.parse(read(V2_EXPORTS[0])))).toBe(true);
|
|
67
|
+
expect(detectTemplate({ title: "old", schemaVersion: 12, rows: [] })).toBe(true);
|
|
68
|
+
expect(detectTemplate({ dashboard: dashboard(), meta: {} })).toBe(true);
|
|
69
|
+
expect(detectTemplate({ apiVersion: "dashboard.grafana.app/v1beta1", kind: "Dashboard", spec: dashboard() })).toBe(true);
|
|
70
|
+
expect(detectTemplate({ apiVersion: "v1", kind: "ConfigMap", spec: {} })).toBe(false);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe("__inputs", () => {
|
|
75
|
+
const exported = dashboard({
|
|
76
|
+
__inputs: [
|
|
77
|
+
{ name: "DS_PROM", label: "Prometheus", type: "datasource", pluginId: "prometheus", pluginName: "Prometheus" },
|
|
78
|
+
{ name: "VAR_ENV", type: "constant", label: "env", value: "prod" },
|
|
79
|
+
],
|
|
80
|
+
__requires: [{ type: "grafana", id: "grafana", version: "12.4.11" }],
|
|
81
|
+
panels: [{ type: "stat", id: 1, title: "Up in ${VAR_ENV}", datasource: { type: "prometheus", uid: "${DS_PROM}" }, targets: [{ refId: "A", expr: "up" }] }],
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test("a datasource input becomes a DatasourceVariable of the same name, first in the list", () => {
|
|
85
|
+
const { plan, edits, warnings } = planDashboard(exported);
|
|
86
|
+
expect(decl(plan.declarations, "variable:DS_PROM")).toMatchObject({
|
|
87
|
+
className: "DatasourceVariable",
|
|
88
|
+
props: { name: "DS_PROM", label: "Prometheus", pluginType: "prometheus" },
|
|
89
|
+
});
|
|
90
|
+
expect(decl(plan.declarations, "panel:0").props!.datasource).toEqual({ $decl: "variable:DS_PROM" });
|
|
91
|
+
expect(decl(plan.declarations, "dashboard").props!.variables).toEqual([{ $decl: "variable:DS_PROM" }]);
|
|
92
|
+
expect(edits).toContainEqual({
|
|
93
|
+
op: "prependVariable",
|
|
94
|
+
value: { type: "datasource", name: "DS_PROM", label: "Prometheus", query: "prometheus", regex: "", refresh: 1, options: [] },
|
|
95
|
+
});
|
|
96
|
+
expect(warnings).toContainEqual(expect.stringMatching(/^__inputs: DS_PROM \(prometheus\) becomes a datasource variable/));
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test("a constant input is filled in with its value", () => {
|
|
100
|
+
const { plan, edits, warnings } = planDashboard(exported);
|
|
101
|
+
expect(decl(plan.declarations, "panel:0").props!.title).toBe("Up in prod");
|
|
102
|
+
expect(edits).toContainEqual({ op: "substitute", from: "${VAR_ENV}", to: "prod" });
|
|
103
|
+
expect(warnings).toContain('__inputs: the constant VAR_ENV is written as its value "prod", the value Grafana\'s import dialog fills in');
|
|
104
|
+
expect(applyEdits(exported, edits).panels).toEqual([expect.objectContaining({ title: "Up in prod" })]);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
test("an input the dashboard also declares as a variable is that variable", () => {
|
|
108
|
+
const d = dashboard({
|
|
109
|
+
__inputs: [{ name: "ds", type: "datasource", pluginId: "prometheus" }],
|
|
110
|
+
templating: { list: [{ type: "datasource", name: "ds", query: "prometheus" }] },
|
|
111
|
+
});
|
|
112
|
+
const { plan } = planDashboard(d);
|
|
113
|
+
expect(plan.declarations.filter((x) => x.className === "DatasourceVariable").map((x) => x.id)).toEqual(["variable:ds"]);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
describe("datasource references", () => {
|
|
118
|
+
function panelWith(datasource: unknown, targets: Json[] = [{ refId: "A", expr: "up" }]) {
|
|
119
|
+
return dashboard({
|
|
120
|
+
templating: { list: [{ type: "datasource", name: "ds", query: "prometheus" }] },
|
|
121
|
+
panels: [{ type: "timeseries", id: 1, title: "p", datasource, targets }],
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
test("a concrete uid becomes one ExternalDatasource, shared by everything that names it and exported", () => {
|
|
126
|
+
const { plan } = planDashboard(panelWith(prom, [{ refId: "A", expr: "up", datasource: prom }]));
|
|
127
|
+
expect(decl(plan.declarations, "datasource:prometheus:prom")).toMatchObject({ kind: "new", className: "ExternalDatasource", props: prom });
|
|
128
|
+
expect(plan.exports).toEqual(["datasource:prometheus:prom", "dashboard"]);
|
|
129
|
+
// The query's datasource is the panel's, so the build writes it from the panel.
|
|
130
|
+
expect(decl(plan.declarations, "query:0:0").props).toEqual({ refId: "A", expr: "up" });
|
|
131
|
+
expect(decl(plan.declarations, "query:0:0").className).toBe("PromQuery");
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test("$ds, ${ds} and [[ds]] are the datasource variable", () => {
|
|
135
|
+
for (const uid of ["$ds", "${ds}", "[[ds]]"]) {
|
|
136
|
+
const { plan, warnings } = planDashboard(panelWith({ type: "prometheus", uid }));
|
|
137
|
+
expect(decl(plan.declarations, "panel:0").props!.datasource).toEqual({ $decl: "variable:ds" });
|
|
138
|
+
expect(warnings).toEqual([]);
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
test("a name from before Grafana 8.3 that is a variable is the variable; any other name is reported", () => {
|
|
143
|
+
const byVariable = planDashboard(panelWith("$ds"));
|
|
144
|
+
expect(decl(byVariable.plan.declarations, "panel:0").props!.datasource).toEqual({ $decl: "variable:ds" });
|
|
145
|
+
expect(byVariable.edits).toContainEqual({ op: "replace", path: "/panels/0/datasource", value: { type: "prometheus", uid: "${ds}" } });
|
|
146
|
+
const byName = planDashboard(panelWith("Prometheus"));
|
|
147
|
+
expect(decl(byName.plan.declarations, "panel:0").props!.datasource).toBeUndefined();
|
|
148
|
+
expect(byName.warnings).toContain('panel "p" (id 1): datasource is not carried (it names the datasource "Prometheus" rather than its uid, from before Grafana 8.3)');
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
test("a panel's Mixed datasource is carried, and its queries keep their own", () => {
|
|
152
|
+
const { plan, warnings, edits } = planDashboard(
|
|
153
|
+
panelWith({ type: "datasource", uid: "-- Mixed --" }, [
|
|
154
|
+
{ refId: "A", expr: "up", datasource: prom },
|
|
155
|
+
{ refId: "B", query: "{}", datasource: { type: "tempo", uid: "tempo" } },
|
|
156
|
+
]),
|
|
157
|
+
);
|
|
158
|
+
expect(decl(plan.declarations, "panel:0").props!.datasource).toEqual({ $decl: "datasource:datasource:-- Mixed --" });
|
|
159
|
+
expect(decl(plan.declarations, "datasource:datasource:-- Mixed --")).toMatchObject({ kind: "value", value: { type: "datasource", uid: "-- Mixed --" } });
|
|
160
|
+
expect(decl(plan.declarations, "query:0:0").props!.datasource).toEqual({ $decl: "datasource:prometheus:prom" });
|
|
161
|
+
expect(decl(plan.declarations, "query:0:1").className).toBe("TempoQuery");
|
|
162
|
+
expect(warnings).toEqual([]);
|
|
163
|
+
expect(edits.filter((e) => "path" in e && e.path.endsWith("/datasource"))).toEqual([]);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
test("a panel with no queries keeps its Mixed datasource (kube-prometheus apiserver)", () => {
|
|
167
|
+
const { plan, warnings } = planDashboard(dashboard({ panels: [{ type: "text", id: 1, datasource: { type: "datasource", uid: "-- Mixed --" }, targets: [] }] }));
|
|
168
|
+
expect(decl(plan.declarations, "panel:0").props!.datasource).toEqual({ $decl: "datasource:datasource:-- Mixed --" });
|
|
169
|
+
expect(warnings).toEqual([]);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
test("Mixed on a query or a row is not carried, and is reported", () => {
|
|
173
|
+
const mixed = { type: "datasource", uid: "-- Mixed --" };
|
|
174
|
+
const { edits, warnings } = planDashboard(
|
|
175
|
+
dashboard({
|
|
176
|
+
panels: [
|
|
177
|
+
{ type: "row", id: 1, title: "R", collapsed: true, datasource: mixed, panels: [{ type: "stat", id: 2, title: "s", datasource: prom, targets: [{ refId: "A", expr: "up", datasource: mixed }] }] },
|
|
178
|
+
],
|
|
179
|
+
}),
|
|
180
|
+
);
|
|
181
|
+
expect(edits).toContainEqual({ op: "remove", path: "/panels/0/datasource" });
|
|
182
|
+
expect(edits).toContainEqual({ op: "remove", path: "/panels/0/panels/0/targets/0/datasource" });
|
|
183
|
+
expect(warnings).toContainEqual(expect.stringMatching(/^row "R": datasource is not carried \(it is "-- Mixed --", which only a panel can have/));
|
|
184
|
+
expect(warnings).toContainEqual(expect.stringMatching(/^panel "s" \(id 2\) query A: datasource is not carried \(it is "-- Mixed --"/));
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
test("a query with no datasource anywhere gets a class of its own", () => {
|
|
188
|
+
const { plan } = planDashboard(dashboard({ panels: [{ type: "stat", id: 1, targets: [{ refId: "A", expr: "up" }] }] }));
|
|
189
|
+
expect(decl(plan.declarations, "query:0:0")).toMatchObject({ className: "DefaultDatasourceQuery", customClass: "query-class:default" });
|
|
190
|
+
expect(plan.customClasses.map((c) => c.definition)).toEqual([{ datasourceType: "default", className: "DefaultDatasourceQuery" }]);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
test("Grafana's own pseudo-datasources stay DatasourceRef consts", () => {
|
|
194
|
+
const { plan } = planDashboard(panelWith({ type: "datasource", uid: "-- Dashboard --" }));
|
|
195
|
+
expect(decl(plan.declarations, "datasource:datasource:-- Dashboard --")).toMatchObject({
|
|
196
|
+
kind: "value",
|
|
197
|
+
value: { type: "datasource", uid: "-- Dashboard --" },
|
|
198
|
+
type: { text: 'DatasourceRef<"datasource">', imports: ["DatasourceRef"] },
|
|
199
|
+
});
|
|
200
|
+
expect(plan.exports).toEqual(["dashboard"]);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
test("a ref with no uid, or a concrete uid with no type, is reported", () => {
|
|
204
|
+
expect(planDashboard(panelWith({ type: "prometheus" })).warnings).toContain('panel "p" (id 1): datasource is not carried (it names no uid, only the type prometheus)');
|
|
205
|
+
expect(planDashboard(panelWith({ uid: "abc" })).warnings).toContain(`panel "p" (id 1): datasource is not carried (it names the uid "abc" but not the datasource's type)`);
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
describe("variables", () => {
|
|
210
|
+
const plan = (list: Json[]) => planDashboard(dashboard({ templating: { list } }));
|
|
211
|
+
|
|
212
|
+
test("each type the lexicon has a class for", () => {
|
|
213
|
+
const { plan: p, warnings } = plan([
|
|
214
|
+
{ type: "datasource", name: "ds", query: "prometheus", regex: "/prod/", current: { text: "P", value: "p" }, refresh: 1, options: [] },
|
|
215
|
+
{ type: "query", name: "job", datasource: { type: "prometheus", uid: "${ds}" }, query: "label_values(up, job)", definition: "label_values(up, job)", refresh: 2, sort: 1, multi: true, includeAll: true, options: [{ text: "a", value: "a" }] },
|
|
216
|
+
{ type: "custom", name: "env", query: "prod, staging,dev", current: { text: "prod", value: "prod" }, options: [] },
|
|
217
|
+
{ type: "interval", name: "w", query: "1m,5m", auto: true, auto_count: 10, auto_min: "10s", refresh: 2 },
|
|
218
|
+
{ type: "constant", name: "c", query: "v", hide: 2 },
|
|
219
|
+
{ type: "textbox", name: "t", query: "x", current: { text: "x", value: "x" } },
|
|
220
|
+
]);
|
|
221
|
+
expect(warnings).toEqual([]);
|
|
222
|
+
const props = (id: string) => [decl(p.declarations, id).className, decl(p.declarations, id).props];
|
|
223
|
+
expect(props("variable:ds")).toEqual(["DatasourceVariable", { name: "ds", pluginType: "prometheus", regex: "/prod/", current: { text: "P", value: "p" } }]);
|
|
224
|
+
expect(props("variable:job")).toEqual([
|
|
225
|
+
"QueryVariable",
|
|
226
|
+
{ name: "job", datasource: { $decl: "variable:ds" }, query: "label_values(up, job)", refresh: "onTimeRangeChange", sort: 1, multi: true, includeAll: true },
|
|
227
|
+
]);
|
|
228
|
+
expect(props("variable:env")).toEqual(["CustomVariable", { name: "env", values: ["prod", "staging", "dev"], current: { text: "prod", value: "prod" } }]);
|
|
229
|
+
expect(props("variable:w")).toEqual(["IntervalVariable", { name: "w", values: ["1m", "5m"], auto: true, autoCount: 10 }]);
|
|
230
|
+
expect(props("variable:c")).toEqual(["ConstantVariable", { name: "c", value: "v" }]);
|
|
231
|
+
expect(props("variable:t")).toEqual(["TextboxVariable", { name: "t", value: "x" }]);
|
|
232
|
+
// Datasource variables are declared first, so what refers to them comes after; the dashboard keeps the order.
|
|
233
|
+
expect(p.declarations.filter((d) => d.module === "variables").map((d) => d.id)[0]).toBe("variable:ds");
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
test("a type the lexicon has no class for is reported and left out (#2952)", () => {
|
|
237
|
+
const { plan: p, warnings, edits } = plan([{ type: "adhoc", name: "Filters", datasource: prom, filters: [] }]);
|
|
238
|
+
expect(p.declarations.filter((d) => d.module === "variables")).toEqual([]);
|
|
239
|
+
expect(warnings).toEqual(['variable "Filters" (adhoc) is not carried: chant has no adhoc variable yet (#2952), so it is left out']);
|
|
240
|
+
expect(edits).toContainEqual({ op: "remove", path: "/templating/list/0" });
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
test("an object query is written as its query string; keys besides refId are named", () => {
|
|
244
|
+
const { plan: p, warnings, edits } = plan([
|
|
245
|
+
{ type: "query", name: "job", datasource: prom, query: { qryType: 1, query: "label_values(job)", refId: "PrometheusVariableQueryEditor-VariableQuery" } },
|
|
246
|
+
]);
|
|
247
|
+
expect(decl(p.declarations, "variable:job").props!.query).toBe("label_values(job)");
|
|
248
|
+
expect(edits).toContainEqual({ op: "replace", path: "/templating/list/0/query", value: "label_values(job)" });
|
|
249
|
+
expect(warnings).toEqual(['variable "job": query is an object; it is written as its query string, and its qryType is not carried (#2952)']);
|
|
250
|
+
expect(plan([{ type: "query", name: "j", datasource: prom, query: { query: "x", refId: "r" } }]).warnings).toEqual([]);
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
test("an object query with no query string cannot be carried", () => {
|
|
254
|
+
const { warnings } = plan([{ type: "query", name: "ns", datasource: { type: "cloudwatch", uid: "cw" }, query: { namespace: "AWS/EC2" } }]);
|
|
255
|
+
expect(warnings).toEqual([expect.stringMatching(/^variable "ns" is not carried: its query is an object with no query string/)]);
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
test("keys at Grafana's default are dropped quietly; others are named", () => {
|
|
259
|
+
const { warnings, edits } = plan([
|
|
260
|
+
{ type: "custom", name: "env", query: "a", allowCustomValue: true, valuesFormat: "csv", useTags: false, tagsQuery: "" },
|
|
261
|
+
{ type: "custom", name: "e2", query: "a", allowCustomValue: false },
|
|
262
|
+
]);
|
|
263
|
+
expect(edits).toContainEqual({ op: "remove", path: "/templating/list/0/allowCustomValue" });
|
|
264
|
+
expect(warnings).toEqual(['variable "e2": allowCustomValue is not carried (no prop takes it)']);
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
test("a textbox's current value, and a visible constant, are named", () => {
|
|
268
|
+
const { warnings } = plan([
|
|
269
|
+
{ type: "textbox", name: "t", query: "x", current: { text: "y", value: "y" } },
|
|
270
|
+
{ type: "constant", name: "c", query: "v", hide: 0 },
|
|
271
|
+
]);
|
|
272
|
+
expect(warnings).toEqual([
|
|
273
|
+
'variable "t": current is not carried (the box\'s value "y"; TextboxVariable starts at its default, "x")',
|
|
274
|
+
'variable "c": hide is not 2: chant always writes a constant hidden, as Grafana shows it',
|
|
275
|
+
]);
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
describe("panels and rows", () => {
|
|
280
|
+
test("an expanded row owns the panels after it; a collapsed row the panels inside it", () => {
|
|
281
|
+
const { plan } = planDashboard(
|
|
282
|
+
dashboard({
|
|
283
|
+
panels: [
|
|
284
|
+
{ type: "text", id: 1, title: "intro", gridPos: { x: 0, y: 0, w: 24, h: 3 } },
|
|
285
|
+
{ type: "row", id: 2, title: "Open", collapsed: false, gridPos: { x: 0, y: 3, w: 24, h: 1 }, panels: [] },
|
|
286
|
+
{ type: "stat", id: 3, title: "a", gridPos: { x: 0, y: 4, w: 6, h: 4 } },
|
|
287
|
+
{ type: "row", id: 4, title: "Shut", collapsed: true, gridPos: { x: 0, y: 8, w: 24, h: 1 }, panels: [{ type: "stat", id: 5, title: "b" }] },
|
|
288
|
+
],
|
|
289
|
+
}),
|
|
290
|
+
);
|
|
291
|
+
expect(decl(plan.declarations, "dashboard").props!.panels).toEqual([{ $decl: "panel:0" }, { $decl: "row:0" }, { $decl: "row:1" }]);
|
|
292
|
+
expect(decl(plan.declarations, "row:0").props).toEqual({ title: "Open", id: 2, gridPos: { y: 3 }, panels: [{ $decl: "panel:1" }] });
|
|
293
|
+
expect(decl(plan.declarations, "row:1").props).toEqual({ title: "Shut", id: 4, collapsed: true, gridPos: { y: 8 }, panels: [{ $decl: "panel:2" }] });
|
|
294
|
+
expect(plan.modules.map((m) => m.file)).toEqual(["panels", "row-open", "row-shut", "dashboard"]);
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
test("a row keeps the line it is on, even with an empty band above it (kube-prometheus nodes)", () => {
|
|
298
|
+
const { plan, edits, warnings } = planDashboard(
|
|
299
|
+
dashboard({
|
|
300
|
+
panels: [
|
|
301
|
+
{ type: "stat", id: 1, title: "a", gridPos: { x: 0, y: 0, w: 24, h: 4 } },
|
|
302
|
+
{ type: "row", id: 2, title: "Late", collapsed: false, gridPos: { x: 0, y: 6, w: 24, h: 1 }, panels: [] },
|
|
303
|
+
{ type: "row", id: 3, title: "Bare", collapsed: false, gridPos: { y: 7 }, panels: [] },
|
|
304
|
+
],
|
|
305
|
+
}),
|
|
306
|
+
);
|
|
307
|
+
expect(decl(plan.declarations, "row:0").props!.gridPos).toEqual({ y: 6 });
|
|
308
|
+
expect(decl(plan.declarations, "row:1").props!.gridPos).toEqual({ y: 7 });
|
|
309
|
+
// A row header is full width and one line high to Grafana, so filling those in is no change, and needs no warning.
|
|
310
|
+
expect(edits).toContainEqual({ op: "replace", path: "/panels/2/gridPos", value: { h: 1, w: 24, x: 0, y: 7 } });
|
|
311
|
+
expect(warnings).toEqual([]);
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
test("a gridPos without x or y has them written as 0; without h or w, with the schema's size and a warning", () => {
|
|
315
|
+
const { plan, edits, warnings } = planDashboard(
|
|
316
|
+
dashboard({
|
|
317
|
+
panels: [
|
|
318
|
+
{ type: "stat", id: 1, title: "a", gridPos: { h: 7, w: 18, y: 0 } },
|
|
319
|
+
{ type: "stat", id: 2, title: "b", gridPos: { x: 18, y: 0 } },
|
|
320
|
+
],
|
|
321
|
+
}),
|
|
322
|
+
);
|
|
323
|
+
expect(decl(plan.declarations, "panel:0").props!.gridPos).toEqual({ h: 7, w: 18, x: 0, y: 0 });
|
|
324
|
+
expect(decl(plan.declarations, "panel:1").props!.gridPos).toEqual({ h: 9, w: 12, x: 18, y: 0 });
|
|
325
|
+
expect(edits).toContainEqual({ op: "replace", path: "/panels/0/gridPos", value: { h: 7, w: 18, x: 0, y: 0 } });
|
|
326
|
+
expect(warnings).toEqual(['panel "b" (id 2): gridPos.h and gridPos.w are missing, so the dashboard schema\'s default is written (h 9, w 12)']);
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
test("a panel with no datasource in a row with one is reported: the build gives it the row's", () => {
|
|
330
|
+
const { edits, warnings } = planDashboard(
|
|
331
|
+
dashboard({
|
|
332
|
+
panels: [
|
|
333
|
+
{ type: "row", id: 1, title: "R", collapsed: true, datasource: prom, panels: [{ type: "stat", id: 2, title: "s", targets: [{ refId: "A", expr: "up" }] }] },
|
|
334
|
+
],
|
|
335
|
+
}),
|
|
336
|
+
);
|
|
337
|
+
expect(edits).toContainEqual({ op: "replace", path: "/panels/0/panels/0/datasource", value: prom });
|
|
338
|
+
expect(warnings).toEqual([expect.stringMatching(/^panel "s" \(id 2\): datasource is missing, and a panel in a chant Row without a datasource takes the row's/)]);
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
test("a library panel is reported and left out", () => {
|
|
342
|
+
const { plan, warnings } = planDashboard(dashboard({ panels: [{ id: 4, gridPos: {}, libraryPanel: { uid: "lp", name: "Burn" } }] }));
|
|
343
|
+
expect(plan.declarations.map((d) => d.id)).toEqual(["dashboard"]);
|
|
344
|
+
expect(warnings).toEqual(['panel (untitled) (id 4) is a library panel ("Burn", uid lp); library panels are not carried yet, so it is left out']);
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
test("a panel type chant has no class for gets a definePanel", () => {
|
|
348
|
+
const { plan } = planDashboard(dashboard({ panels: [{ type: "grafana-clock-panel", id: 1, title: "clock" }, { type: "grafana-clock-panel", id: 2, title: "clock 2" }] }));
|
|
349
|
+
expect(plan.customClasses).toEqual([
|
|
350
|
+
expect.objectContaining({ id: "panel-class:grafana-clock-panel", className: "GrafanaClockPanelPanel", factory: "definePanel", definition: { type: "grafana-clock-panel", className: "GrafanaClockPanelPanel", defaultSize: { w: 12, h: 8 } } }),
|
|
351
|
+
]);
|
|
352
|
+
expect(decl(plan.declarations, "panel:1")).toMatchObject({ className: "GrafanaClockPanelPanel", customClass: "panel-class:grafana-clock-panel" });
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
test("a panel key no prop takes is named, unless it is at Grafana's default", () => {
|
|
356
|
+
const { warnings } = planDashboard(dashboard({ panels: [{ type: "stat", id: 1, title: "s", transparent: false, cacheTimeout: null, libraryPanelX: 1 }] }));
|
|
357
|
+
expect(warnings).toEqual(['panel "s" (id 1): libraryPanelX is not carried (no prop takes it)']);
|
|
358
|
+
});
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
describe("the dashboard", () => {
|
|
362
|
+
test("fields, the tooltip by name, and a timezone Grafana would read as the viewer's", () => {
|
|
363
|
+
const { plan, warnings } = planDashboard(
|
|
364
|
+
dashboard({ graphTooltip: 1, refresh: "30s", tags: ["a"], editable: true, id: 3, version: 9, iteration: 1, time: { from: "now-1h", to: "now" } }),
|
|
365
|
+
);
|
|
366
|
+
expect(decl(plan.declarations, "dashboard").props).toEqual({
|
|
367
|
+
title: "T",
|
|
368
|
+
uid: "t",
|
|
369
|
+
tags: ["a"],
|
|
370
|
+
time: { from: "now-1h", to: "now" },
|
|
371
|
+
refresh: "30s",
|
|
372
|
+
timezone: "",
|
|
373
|
+
graphTooltip: "sharedCrosshair",
|
|
374
|
+
});
|
|
375
|
+
expect(warnings).toEqual([]);
|
|
376
|
+
expect(plan.directory).toBe("t");
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
test("an older schemaVersion is carried, so Grafana still migrates it", () => {
|
|
380
|
+
const { plan } = planDashboard(dashboard({ schemaVersion: 39 }));
|
|
381
|
+
expect(decl(plan.declarations, "dashboard").props!.schemaVersion).toBe(39);
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
test("a dashboard with no uid is given one from its title", () => {
|
|
385
|
+
const { plan, warnings } = planDashboard({ title: "My Board", schemaVersion: 42, panels: [] });
|
|
386
|
+
expect(decl(plan.declarations, "dashboard").props!.uid).toBe("my-board");
|
|
387
|
+
expect(warnings).toContain('dashboard: uid is missing, so the dashboard is given the uid "my-board", from its title');
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
test("the built-in annotation is Grafana's default; any other is named (#2953)", () => {
|
|
391
|
+
const builtin = { builtIn: 1, datasource: { type: "datasource", uid: "grafana" }, enable: true, hide: true, iconColor: "rgba(0, 211, 255, 1)", name: "Annotations & Alerts", type: "dashboard" };
|
|
392
|
+
expect(planDashboard(dashboard({ annotations: { list: [builtin] } })).warnings).toEqual([]);
|
|
393
|
+
const other = planDashboard(dashboard({ annotations: { list: [builtin, { name: "Deploys", enable: true }] } }));
|
|
394
|
+
expect(other.warnings).toEqual(['dashboard has the annotation "Deploys", which is not carried: Dashboard has no annotations yet (#2953)']);
|
|
395
|
+
expect(other.edits).toContainEqual({ op: "remove", path: "/annotations" });
|
|
396
|
+
});
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
describe("provisioning files", () => {
|
|
400
|
+
test("a datasource provisioning file: one Datasource each, unknown keys named", () => {
|
|
401
|
+
const ir = parse("apiVersion: 1\nprune: true\ndatasources:\n - name: Prometheus\n type: prometheus\n url: http://prom:9090\n password: x\n");
|
|
402
|
+
const { plan } = ir.resources[0].properties as unknown as PlanResourceProperties;
|
|
403
|
+
expect(plan.declarations).toEqual([
|
|
404
|
+
expect.objectContaining({ className: "Datasource", props: { name: "Prometheus", type: "prometheus", url: "http://prom:9090" } }),
|
|
405
|
+
]);
|
|
406
|
+
expect(ir.warnings).toEqual([
|
|
407
|
+
'datasource "Prometheus": password is not carried (no prop takes it)',
|
|
408
|
+
"the provisioning file: prune is not carried (chant writes datasources only; prune and deleteDatasources are #2953)",
|
|
409
|
+
]);
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
test("a dashboard provisioning file: file providers only", () => {
|
|
413
|
+
const ir = parse({ apiVersion: 1, providers: [{ name: "a", type: "file", options: { path: "/d" } }, { name: "b", type: "sqlite" }] });
|
|
414
|
+
const { plan } = ir.resources[0].properties as unknown as PlanResourceProperties;
|
|
415
|
+
expect(plan.declarations.map((d) => d.props)).toEqual([{ name: "a", path: "/d" }]);
|
|
416
|
+
expect(ir.warnings).toEqual(['provider "b" is of type sqlite; chant writes file providers only, so it is left out']);
|
|
417
|
+
});
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
describe("transformations (#2954)", () => {
|
|
421
|
+
test("a transformation the types hold stays an object; any other is written with customTransformation()", () => {
|
|
422
|
+
const transformations = [
|
|
423
|
+
{ id: "organize", options: { renameByName: { Value: "Requests" } } },
|
|
424
|
+
{ id: "sortBy", options: { fields: {}, sort: [{ field: "Pod" }] } },
|
|
425
|
+
{ id: "grafana-plugin-x", options: { a: 1 }, disabled: true },
|
|
426
|
+
{ options: {} },
|
|
427
|
+
];
|
|
428
|
+
const { plan, warnings } = planDashboard(dashboard({ panels: [{ type: "table", id: 1, title: "t", gridPos: { x: 0, y: 0, w: 12, h: 8 }, transformations }] }));
|
|
429
|
+
expect(decl(plan.declarations, "panel:0").props!.transformations).toEqual([
|
|
430
|
+
{ id: "organize", options: { renameByName: { Value: "Requests" } } },
|
|
431
|
+
{ $call: "customTransformation", args: ["sortBy", { fields: {}, sort: [{ field: "Pod" }] }] },
|
|
432
|
+
{ $call: "customTransformation", args: ["grafana-plugin-x", { a: 1 }, { disabled: true }] },
|
|
433
|
+
]);
|
|
434
|
+
expect(warnings).toEqual([
|
|
435
|
+
'panel "t" (id 1): transformation 2 is written with customTransformation(), untyped: the sortBy transformer takes no option "fields".',
|
|
436
|
+
'panel "t" (id 1): transformation 3 is written with customTransformation(), untyped: "grafana-plugin-x" is not a transformer Grafana v13.2.2 registers.',
|
|
437
|
+
'panel "t" (id 1): transformation 4 has no id, so Grafana skips it; it is not carried.',
|
|
438
|
+
]);
|
|
439
|
+
});
|
|
440
|
+
});
|