@intentius/chant-lexicon-grafana 0.98.0 → 0.100.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 +24 -8
- 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/annotations.d.ts +61 -0
- package/dist/annotations.d.ts.map +1 -0
- package/dist/api/apply.d.ts +160 -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 +63 -0
- package/dist/api/fake-grafana.d.ts.map +1 -0
- package/dist/api/folders.d.ts +146 -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 +55 -6
- 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/generate.d.ts +7 -1
- package/dist/codegen/generate.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 +11 -3
- 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 +51 -9
- package/dist/dashboard.d.ts.map +1 -1
- package/dist/datasource-refs.d.ts +99 -0
- package/dist/datasource-refs.d.ts.map +1 -0
- package/dist/datasource-settings.d.ts +834 -0
- package/dist/datasource-settings.d.ts.map +1 -0
- package/dist/datasource.d.ts +82 -11
- 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 +47 -0
- package/dist/deep-observe.d.ts.map +1 -0
- package/dist/describe-resources.d.ts +50 -0
- package/dist/describe-resources.d.ts.map +1 -0
- package/dist/detect.d.ts +32 -3
- 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/folder.d.ts +68 -0
- package/dist/folder.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 +89 -0
- package/dist/import/mappings.d.ts.map +1 -0
- package/dist/import/model.d.ts +105 -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 +125 -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 +41 -0
- package/dist/import/testdata/fixtures.d.ts.map +1 -0
- package/dist/import/v2.d.ts +73 -0
- package/dist/import/v2.d.ts.map +1 -0
- package/dist/index.d.ts +31 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/init-templates.d.ts +27 -0
- package/dist/init-templates.d.ts.map +1 -0
- package/dist/integrity.json +22 -12
- 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/graf104.d.ts +2 -2
- package/dist/lint/post-synth/graf106.d.ts +2 -2
- 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/graf110.d.ts +8 -0
- package/dist/lint/post-synth/graf110.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 +205 -0
- package/dist/okf/index.md +53 -4
- 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/GRAF104.md +2 -2
- package/dist/okf/rules/GRAF106.md +2 -2
- package/dist/okf/rules/GRAF108.md +11 -0
- package/dist/okf/rules/GRAF109.md +15 -0
- package/dist/okf/rules/GRAF110.md +11 -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/AdhocVariable.md +9 -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/AzureMonitorQuery.md +9 -0
- package/dist/okf/types/BarChartPanel.md +9 -0
- package/dist/okf/types/BarGaugePanel.md +9 -0
- package/dist/okf/types/BigQueryQuery.md +9 -0
- package/dist/okf/types/CanvasPanel.md +9 -0
- package/dist/okf/types/ClassicConditionsExpression.md +9 -0
- package/dist/okf/types/CloudMonitoringQuery.md +9 -0
- package/dist/okf/types/CloudWatchQuery.md +9 -0
- package/dist/okf/types/ContactPoint.md +14 -0
- package/dist/okf/types/Dashboard.md +2 -1
- package/dist/okf/types/Datasource.md +3 -2
- package/dist/okf/types/DatasourceProvisioning.md +9 -0
- package/dist/okf/types/ElasticsearchQuery.md +9 -0
- package/dist/okf/types/ExternalDatasource.md +15 -0
- package/dist/okf/types/FlameGraphPanel.md +9 -0
- package/dist/okf/types/Folder.md +9 -0
- package/dist/okf/types/GeomapPanel.md +9 -0
- package/dist/okf/types/GroupByVariable.md +9 -0
- package/dist/okf/types/HistogramPanel.md +9 -0
- package/dist/okf/types/MSSQLQuery.md +9 -0
- package/dist/okf/types/MathExpression.md +9 -0
- package/dist/okf/types/MuteTiming.md +13 -0
- package/dist/okf/types/MySQLQuery.md +9 -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/PostgresQuery.md +9 -0
- package/dist/okf/types/PyroscopeQuery.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/SwitchVariable.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 +86 -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 +78 -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-models.d.ts +95 -0
- package/dist/query-models.d.ts.map +1 -0
- package/dist/query.d.ts +116 -18
- 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/graf104.ts +3 -3
- package/dist/rules/graf106.ts +3 -3
- package/dist/rules/graf107.ts +1 -1
- package/dist/rules/graf108.ts +17 -0
- package/dist/rules/graf109.ts +17 -0
- package/dist/rules/graf110.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 +27 -10
- package/dist/rules/literal-secret.ts +60 -6
- package/dist/schema/azuremonitor.gen.d.ts +354 -0
- package/dist/schema/azuremonitor.gen.d.ts.map +1 -0
- 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/bigquery.gen.d.ts +93 -0
- package/dist/schema/bigquery.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/cloudwatch.gen.d.ts +394 -0
- package/dist/schema/cloudwatch.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/elasticsearch.gen.d.ts +444 -0
- package/dist/schema/elasticsearch.gen.d.ts.map +1 -0
- 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/googlecloudmonitoring.gen.d.ts +312 -0
- package/dist/schema/googlecloudmonitoring.gen.d.ts.map +1 -0
- package/dist/schema/grafanapyroscope.gen.d.ts +60 -0
- package/dist/schema/grafanapyroscope.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 +18 -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 +35 -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 +39 -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-operations.md +108 -0
- package/dist/skills/chant-grafana-provisioning.md +3 -3
- package/dist/skills/chant-grafana.md +15 -8
- 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 +21 -13
- package/dist/spec/schemas.d.ts.map +1 -1
- package/dist/spec/schemas.gen.d.ts +3 -0
- package/dist/spec/schemas.gen.d.ts.map +1 -0
- 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 +62 -9
- package/dist/validate-output.d.ts.map +1 -1
- package/dist/validate.d.ts.map +1 -1
- package/dist/validation.d.ts +14 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/variables.d.ts +109 -7
- 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/annotations.ts +84 -0
- package/src/api/apply.test.ts +256 -0
- package/src/api/apply.ts +394 -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 +190 -0
- package/src/api/folders.ts +339 -0
- package/src/api/library-panels.ts +101 -0
- package/src/build.test.ts +351 -10
- package/src/build.ts +294 -55
- package/src/catalog.ts +104 -2
- package/src/codegen/docs.ts +50 -10
- package/src/codegen/generate.ts +27 -1
- 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 +14 -2
- 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 +68 -9
- package/src/datasource-refs.test.ts +56 -0
- package/src/datasource-refs.ts +213 -0
- package/src/datasource-settings.test.ts +106 -0
- package/src/datasource-settings.ts +941 -0
- package/src/datasource.ts +123 -11
- package/src/deep-observe-hooks.ts +267 -0
- package/src/deep-observe.test.ts +311 -0
- package/src/deep-observe.ts +187 -0
- package/src/describe-resources.test.ts +271 -0
- package/src/describe-resources.ts +244 -0
- package/src/detect.ts +82 -5
- package/src/export-resources.test.ts +129 -0
- package/src/export-resources.ts +84 -0
- package/src/folder.ts +118 -0
- package/src/generated/lexicon-grafana.json +205 -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 +130 -0
- package/src/import/generator.test.ts +210 -0
- package/src/import/generator.ts +463 -0
- package/src/import/live-export.ts +264 -0
- package/src/import/mappings.ts +336 -0
- package/src/import/model.ts +117 -0
- package/src/import/normalize-alerting.ts +101 -0
- package/src/import/normalize.test.ts +117 -0
- package/src/import/normalize.ts +393 -0
- package/src/import/parser.test.ts +516 -0
- package/src/import/parser.ts +1387 -0
- package/src/import/report.ts +62 -0
- package/src/import/roundtrip.test.ts +563 -0
- package/src/import/testdata/fixtures.ts +137 -0
- package/src/import/v2.test.ts +292 -0
- package/src/import/v2.ts +804 -0
- package/src/import.e2e.test.ts +31 -84
- package/src/import.test.ts +9 -3
- package/src/index.ts +308 -14
- package/src/init-templates.test.ts +74 -0
- package/src/init-templates.ts +349 -0
- package/src/k8s.test.ts +98 -0
- package/src/k8s.ts +197 -0
- package/src/lint/audit-catalog.ts +68 -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/graf104.ts +3 -3
- package/src/lint/post-synth/graf106.ts +3 -3
- 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/graf110.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 +27 -10
- package/src/lint/post-synth/index.ts +16 -0
- package/src/lint/post-synth/post-synth.test.ts +333 -12
- package/src/lint/rules/literal-secret.ts +60 -6
- package/src/lint/rules/rules.test.ts +27 -0
- package/src/load-cost.test.ts +35 -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 +184 -0
- package/src/op/activities/grafana-apply.test.ts +243 -0
- package/src/op/activities/grafana-apply.ts +197 -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 +122 -0
- package/src/panel-options.ts +66 -0
- package/src/panels.test.ts +53 -0
- package/src/panels.ts +148 -10
- package/src/pin.ts +69 -6
- package/src/plugin.test.ts +12 -2
- package/src/plugin.ts +75 -0
- package/src/promql-check.test.ts +108 -0
- package/src/promql-check.ts +193 -0
- package/src/query-models.ts +94 -0
- package/src/query.test.ts +166 -0
- package/src/query.ts +190 -20
- package/src/schema/azuremonitor.gen.ts +381 -0
- package/src/schema/barchart.gen.ts +221 -0
- package/src/schema/bargauge.gen.ts +111 -0
- package/src/schema/bigquery.gen.ts +110 -0
- package/src/schema/canvas.gen.ts +176 -0
- package/src/schema/cloudwatch.gen.ts +423 -0
- package/src/schema/dashboard.gen.ts +206 -22
- package/src/schema/elasticsearch.gen.ts +508 -0
- 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/googlecloudmonitoring.gen.ts +330 -0
- package/src/schema/grafanapyroscope.gen.ts +66 -0
- package/src/schema/heatmap.gen.ts +2 -1
- package/src/schema/histogram.gen.ts +151 -0
- package/src/schema/index.ts +18 -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 +41 -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 +199 -57
- 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 +34 -0
- package/src/skills/chant-grafana-alerting.md +49 -0
- package/src/skills/chant-grafana-operations.md +108 -0
- package/src/skills/chant-grafana-provisioning.md +3 -3
- package/src/skills/chant-grafana.md +15 -8
- 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 +103 -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/azuremonitor.jsonschema.json +679 -0
- package/src/spec/schemas/barchart.jsonschema.json +419 -0
- package/src/spec/schemas/bargauge.jsonschema.json +224 -0
- package/src/spec/schemas/bigquery.jsonschema.json +290 -0
- package/src/spec/schemas/canvas.jsonschema.json +356 -0
- package/src/spec/schemas/cloudwatch.jsonschema.json +721 -0
- package/src/spec/schemas/dashboardv2.jsonschema.json +3387 -0
- package/src/spec/schemas/elasticsearch.jsonschema.json +1695 -0
- package/src/spec/schemas/expr.jsonschema.json +987 -0
- package/src/spec/schemas/geomap.jsonschema.json +220 -0
- package/src/spec/schemas/googlecloudmonitoring.jsonschema.json +488 -0
- package/src/spec/schemas/grafanapyroscope.jsonschema.json +93 -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.gen.ts +40 -0
- package/src/spec/schemas.ts +30 -16
- 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 +430 -0
- package/src/validate-output.ts +427 -104
- package/src/validate.ts +28 -0
- package/src/validation.ts +27 -0
- package/src/variables.ts +120 -8
package/src/build.ts
CHANGED
|
@@ -10,15 +10,28 @@
|
|
|
10
10
|
|
|
11
11
|
import { dump } from "js-yaml";
|
|
12
12
|
import type { Declarable } from "@intentius/chant/declarable";
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
isDatasourceDeclaration,
|
|
15
|
+
isDatasourceEntity,
|
|
16
|
+
isDatasourceProvisioningEntity,
|
|
17
|
+
isExternalDatasource,
|
|
18
|
+
type DatasourceEntity,
|
|
19
|
+
type DatasourceProvisioningProps,
|
|
20
|
+
type DatasourceRef,
|
|
21
|
+
type DeletedDatasource,
|
|
22
|
+
type ExternalDatasourceEntity,
|
|
23
|
+
} from "./datasource";
|
|
14
24
|
import {
|
|
15
25
|
isDashboardEntity,
|
|
16
26
|
isDashboardProviderEntity,
|
|
17
27
|
DEFAULT_DASHBOARDS_PATH,
|
|
18
28
|
type DashboardEntity,
|
|
19
29
|
type DashboardLinkInput,
|
|
20
|
-
type
|
|
30
|
+
type DashboardProviderEntityProps,
|
|
21
31
|
} from "./dashboard";
|
|
32
|
+
import { annotationJson } from "./annotations";
|
|
33
|
+
import { folderLevels, isFolderEntity, type FolderEntity } from "./folder";
|
|
34
|
+
import { resolveFolders, type FolderPlan } from "./api/folders";
|
|
22
35
|
import { isPanelEntity, isRowEntity, type PanelEntity, type RowEntity, type PanelLink } from "./panels";
|
|
23
36
|
import { isQueryEntity, type QueryEntity, type DatasourceInput } from "./query";
|
|
24
37
|
import { isDatasourceVariable, isVariableEntity, type VariableEntity, type VariableHide } from "./variables";
|
|
@@ -34,6 +47,8 @@ import type {
|
|
|
34
47
|
import { DASHBOARD_SCHEMA_VERSION } from "./schema/dashboard.gen";
|
|
35
48
|
import { GRAFANA_SCHEMA_PIN } from "./pin";
|
|
36
49
|
import { compact, slugUid } from "./util";
|
|
50
|
+
import { ALERTING_FILE, alertingYaml, buildAlerting, type AlertingFile, type AlertingIndex } from "./alerting-build";
|
|
51
|
+
import { DEFAULT_PROVIDER_NAME } from "./ownership";
|
|
37
52
|
|
|
38
53
|
export type { DashboardJson, PanelJson, RowPanelJson, VariableModel, DataSourceRef };
|
|
39
54
|
|
|
@@ -65,6 +80,12 @@ export interface ProvisionedDatasource {
|
|
|
65
80
|
version?: number;
|
|
66
81
|
}
|
|
67
82
|
|
|
83
|
+
/** The settings of the datasource provisioning file besides its datasources. */
|
|
84
|
+
export interface DatasourceFileSettings {
|
|
85
|
+
prune: boolean;
|
|
86
|
+
deleteDatasources: DeletedDatasource[];
|
|
87
|
+
}
|
|
88
|
+
|
|
68
89
|
/** One entry of `providers:` in a dashboard provisioning file. */
|
|
69
90
|
export interface ProvisionedProvider {
|
|
70
91
|
name: string;
|
|
@@ -82,6 +103,8 @@ export interface BuiltDashboard {
|
|
|
82
103
|
uid: string;
|
|
83
104
|
title: string;
|
|
84
105
|
folder?: string;
|
|
106
|
+
/** The uid of its folder, when it is in one. */
|
|
107
|
+
folderUid?: string;
|
|
85
108
|
/** Path of its JSON file, relative to the output directory. */
|
|
86
109
|
file: string;
|
|
87
110
|
json: DashboardJson;
|
|
@@ -90,7 +113,15 @@ export interface BuiltDashboard {
|
|
|
90
113
|
export interface BuiltGrafana {
|
|
91
114
|
dashboards: BuiltDashboard[];
|
|
92
115
|
datasources: ProvisionedDatasource[];
|
|
116
|
+
/** `ExternalDatasource` declarations: the checks count them, the provisioning file leaves them out. */
|
|
117
|
+
externalDatasources: ExternalDatasourceRecord[];
|
|
93
118
|
providers: ProvisionedProvider[];
|
|
119
|
+
/** Every folder the dashboards and `Folder`s name, each level of a path its own, sorted by path. */
|
|
120
|
+
folders: FolderPlan[];
|
|
121
|
+
/** `prune` and `deleteDatasources` of the datasource provisioning file. */
|
|
122
|
+
datasourceFile: DatasourceFileSettings;
|
|
123
|
+
/** The alerting provisioning file, when the build declares any alerting. */
|
|
124
|
+
alerting?: AlertingFile;
|
|
94
125
|
/** Every output file by path, ready to write. */
|
|
95
126
|
files: Record<string, string>;
|
|
96
127
|
/** A short summary of what was built: the serializer's primary output. */
|
|
@@ -99,11 +130,24 @@ export interface BuiltGrafana {
|
|
|
99
130
|
|
|
100
131
|
export interface GrafanaIndex {
|
|
101
132
|
grafanaSchema: string;
|
|
102
|
-
dashboards: Array<{ uid: string; title: string; folder?: string; file: string }>;
|
|
133
|
+
dashboards: Array<{ uid: string; title: string; folder?: string; folderUid?: string; file: string }>;
|
|
134
|
+
/** The folders the dashboards are in, and any `Folder` declared: what the API applier creates, parents first. */
|
|
135
|
+
folders?: FolderPlan[];
|
|
103
136
|
datasources: Array<{ name: string; type: string; uid: string }>;
|
|
137
|
+
/** Datasources declared with `ExternalDatasource`: referenced, never provisioned. */
|
|
138
|
+
externalDatasources?: ExternalDatasourceRecord[];
|
|
139
|
+
/** Rule groups, contact points, policies, mute timings and templates, when the build declares any. */
|
|
140
|
+
alerting?: AlertingIndex;
|
|
104
141
|
files: string[];
|
|
105
142
|
}
|
|
106
143
|
|
|
144
|
+
/** An `ExternalDatasource` as the checks and the index see it. */
|
|
145
|
+
export interface ExternalDatasourceRecord {
|
|
146
|
+
type: string;
|
|
147
|
+
uid: string;
|
|
148
|
+
name?: string;
|
|
149
|
+
}
|
|
150
|
+
|
|
107
151
|
// ── References ──────────────────────────────────────────────────
|
|
108
152
|
|
|
109
153
|
function isRef(value: unknown): value is DatasourceRef {
|
|
@@ -116,13 +160,13 @@ function isRef(value: unknown): value is DatasourceRef {
|
|
|
116
160
|
);
|
|
117
161
|
}
|
|
118
162
|
|
|
119
|
-
/** The `{ type, uid }` Grafana stores for a datasource, a datasource variable, or a ref. */
|
|
163
|
+
/** The `{ type, uid }` Grafana stores for a datasource (declared or external), a datasource variable, or a ref. */
|
|
120
164
|
export function datasourceRef(input: DatasourceInput | undefined): DataSourceRef | undefined {
|
|
121
165
|
if (input === undefined || input === null) return undefined;
|
|
122
|
-
if (
|
|
166
|
+
if (isDatasourceDeclaration(input)) return { type: input.datasourceType, uid: input.uid };
|
|
123
167
|
if (isDatasourceVariable(input)) return { type: input.pluginType, uid: `\${${input.variableName}}` };
|
|
124
168
|
if (isRef(input)) return { type: input.type, uid: input.uid };
|
|
125
|
-
throw new Error("grafana: a datasource must be a Datasource, a DatasourceVariable or a { type, uid } ref");
|
|
169
|
+
throw new Error("grafana: a datasource must be a Datasource, an ExternalDatasource, a DatasourceVariable or a { type, uid } ref");
|
|
126
170
|
}
|
|
127
171
|
|
|
128
172
|
function sameRef(a: DataSourceRef | undefined, b: DataSourceRef | undefined): boolean {
|
|
@@ -154,8 +198,24 @@ function dashboardLink(link: DashboardLinkInput | PanelLink): DashboardLink {
|
|
|
154
198
|
const HIDE: Record<VariableHide, 0 | 1 | 2> = { label: 0, valueOnly: 1, hidden: 2 };
|
|
155
199
|
const REFRESH = { never: 0, onLoad: 1, onTimeRangeChange: 2 } as const;
|
|
156
200
|
|
|
201
|
+
/** A custom variable value in its `query`: a comma is escaped as `\\,`, and one already escaped is left alone. */
|
|
157
202
|
function escapeCustom(v: string): string {
|
|
158
|
-
return v.replace(
|
|
203
|
+
return v.replace(/\\?,/g, "\\,");
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* The options Grafana makes of a custom variable's `query`: split on commas
|
|
208
|
+
* not escaped as `\\,`, and `text : value` (spaces around the colon) read as
|
|
209
|
+
* an option showing `text` that sets `value`. The same parse as Grafana's
|
|
210
|
+
* custom variable (public/app/features/variables/custom/reducer.ts, and
|
|
211
|
+
* CustomVariable in @grafana/scenes).
|
|
212
|
+
*/
|
|
213
|
+
export function customVariableOptions(query: string): Array<{ text: string; value: string }> {
|
|
214
|
+
return (query.match(/(?:\\,|[^,])+/g) ?? []).map((item) => {
|
|
215
|
+
const text = item.replace(/\\,/g, ",");
|
|
216
|
+
const kv = /^\s*(.+)\s:\s(.+)$/.exec(text);
|
|
217
|
+
return kv ? { text: kv[1].trim(), value: kv[2].trim() } : { text: text.trim(), value: text.trim() };
|
|
218
|
+
});
|
|
159
219
|
}
|
|
160
220
|
|
|
161
221
|
function optionsOf(values: string[], current?: { text: string | string[]; value: string | string[] }) {
|
|
@@ -182,7 +242,7 @@ export function variableModel(variable: VariableEntity): VariableModel {
|
|
|
182
242
|
...common,
|
|
183
243
|
datasource: datasourceRef(p.datasource),
|
|
184
244
|
query: p.query,
|
|
185
|
-
definition: p.query,
|
|
245
|
+
definition: p.definition ?? queryText(p.query),
|
|
186
246
|
regex: p.regex,
|
|
187
247
|
refresh: REFRESH[(p.refresh ?? "onLoad") as keyof typeof REFRESH],
|
|
188
248
|
sort: p.sort,
|
|
@@ -192,13 +252,16 @@ export function variableModel(variable: VariableEntity): VariableModel {
|
|
|
192
252
|
}) as VariableModel;
|
|
193
253
|
case "custom": {
|
|
194
254
|
const values: string[] = p.values;
|
|
195
|
-
const
|
|
255
|
+
const query = values.map(escapeCustom).join(",");
|
|
256
|
+
const options = customVariableOptions(query);
|
|
257
|
+
const current = p.current ?? (options[0] !== undefined ? { text: options[0].text, value: options[0].value } : undefined);
|
|
258
|
+
const selected = current ? (Array.isArray(current.value) ? current.value : [current.value]) : [];
|
|
196
259
|
return compact({
|
|
197
260
|
...common,
|
|
198
|
-
query
|
|
261
|
+
query,
|
|
199
262
|
...multi,
|
|
200
263
|
current,
|
|
201
|
-
options:
|
|
264
|
+
options: options.map((o) => ({ selected: selected.includes(o.value), ...o })),
|
|
202
265
|
}) as VariableModel;
|
|
203
266
|
}
|
|
204
267
|
case "interval": {
|
|
@@ -238,9 +301,51 @@ export function variableModel(variable: VariableEntity): VariableModel {
|
|
|
238
301
|
query: p.value ?? "",
|
|
239
302
|
current: { text: p.value ?? "", value: p.value ?? "" },
|
|
240
303
|
}) as VariableModel;
|
|
304
|
+
case "adhoc":
|
|
305
|
+
return compact({
|
|
306
|
+
...common,
|
|
307
|
+
datasource: datasourceRef(p.datasource),
|
|
308
|
+
filters: p.filters ?? [],
|
|
309
|
+
baseFilters: p.baseFilters ?? [],
|
|
310
|
+
defaultKeys: p.defaultKeys,
|
|
311
|
+
allowCustomValue: p.allowCustomValue,
|
|
312
|
+
enableGroupBy: p.enableGroupBy,
|
|
313
|
+
}) as VariableModel;
|
|
314
|
+
case "groupby": {
|
|
315
|
+
const options = p.options?.map((o: string | { text: string; value: string }) => (typeof o === "string" ? { text: o, value: o } : o));
|
|
316
|
+
const defaultValue = Array.isArray(p.defaultValue) ? { text: p.defaultValue, value: p.defaultValue } : p.defaultValue;
|
|
317
|
+
return compact({
|
|
318
|
+
...common,
|
|
319
|
+
datasource: datasourceRef(p.datasource),
|
|
320
|
+
options,
|
|
321
|
+
current: p.current ?? defaultValue,
|
|
322
|
+
defaultValue,
|
|
323
|
+
allowCustomValue: p.allowCustomValue,
|
|
324
|
+
}) as VariableModel;
|
|
325
|
+
}
|
|
326
|
+
case "switch": {
|
|
327
|
+
const on: string = p.enabledValue ?? "true";
|
|
328
|
+
const off: string = p.disabledValue ?? "false";
|
|
329
|
+
const value = p.enabled ? on : off;
|
|
330
|
+
return compact({
|
|
331
|
+
...common,
|
|
332
|
+
current: { text: value, value },
|
|
333
|
+
options: [
|
|
334
|
+
{ text: on, value: on },
|
|
335
|
+
{ text: off, value: off },
|
|
336
|
+
],
|
|
337
|
+
}) as VariableModel;
|
|
338
|
+
}
|
|
241
339
|
}
|
|
242
340
|
}
|
|
243
341
|
|
|
342
|
+
/** The text of a variable query: the string, or an object query's `query`. */
|
|
343
|
+
function queryText(query: unknown): string | undefined {
|
|
344
|
+
if (typeof query === "string") return query;
|
|
345
|
+
if (query && typeof query === "object" && typeof (query as { query?: unknown }).query === "string") return (query as { query: string }).query;
|
|
346
|
+
return undefined;
|
|
347
|
+
}
|
|
348
|
+
|
|
244
349
|
// ── Panels and layout ───────────────────────────────────────────
|
|
245
350
|
|
|
246
351
|
function repeatName(repeat: VariableEntity | string | undefined): string | undefined {
|
|
@@ -266,47 +371,110 @@ export function targetJson(query: QueryEntity, index: number, panelDatasource?:
|
|
|
266
371
|
});
|
|
267
372
|
}
|
|
268
373
|
|
|
374
|
+
/** A bitmask of grid columns [x, x + w), clipped to the grid. */
|
|
375
|
+
function columns(x: number, w: number): number {
|
|
376
|
+
const from = Math.max(0, x);
|
|
377
|
+
const to = Math.min(GRID_COLUMNS, x + w);
|
|
378
|
+
return to > from ? ((1 << (to - from)) - 1) << from : 0;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Places panels on Grafana's grid. It keeps an occupancy grid, so a panel
|
|
383
|
+
* placed automatically never lands on one placed explicitly (reserved up
|
|
384
|
+
* front) or on one placed before it.
|
|
385
|
+
*/
|
|
269
386
|
class Layout {
|
|
270
387
|
private x = 0;
|
|
271
|
-
private y
|
|
388
|
+
private y: number;
|
|
272
389
|
private lineH = 0;
|
|
273
|
-
private bottom
|
|
390
|
+
private bottom: number;
|
|
391
|
+
/** Taken cells: one column bitmask per grid line. */
|
|
392
|
+
private readonly taken: number[] = [];
|
|
393
|
+
|
|
394
|
+
constructor(top = 0) {
|
|
395
|
+
this.y = top;
|
|
396
|
+
this.bottom = top;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/** Marks the cells of a panel with both `x` and `y` as taken, before anything is placed. */
|
|
400
|
+
reserve(gp: Partial<GridPos> | undefined, size: { w: number; h: number }): void {
|
|
401
|
+
if (gp?.x === undefined || gp?.y === undefined) return;
|
|
402
|
+
this.take(gp.x, gp.y, gp.w ?? size.w, gp.h ?? size.h);
|
|
403
|
+
}
|
|
274
404
|
|
|
275
405
|
place(gp: Partial<GridPos> | undefined, size: { w: number; h: number }): GridPos {
|
|
276
406
|
const w = gp?.w ?? size.w;
|
|
277
407
|
const h = gp?.h ?? size.h;
|
|
278
408
|
if (gp?.x !== undefined && gp?.y !== undefined) {
|
|
409
|
+
this.take(gp.x, gp.y, w, h);
|
|
279
410
|
this.bottom = Math.max(this.bottom, gp.y + h);
|
|
280
411
|
return { h, w, x: gp.x, y: gp.y };
|
|
281
412
|
}
|
|
282
|
-
if (
|
|
283
|
-
|
|
413
|
+
if (gp?.y !== undefined) {
|
|
414
|
+
// Only `y`: the first free column on that line, else on the first line below with room.
|
|
415
|
+
for (let y = Math.max(0, gp.y); ; y++) {
|
|
416
|
+
const x = this.freeColumn(0, y, w, h);
|
|
417
|
+
if (x === undefined) continue;
|
|
418
|
+
this.take(x, y, w, h);
|
|
419
|
+
this.bottom = Math.max(this.bottom, y + h);
|
|
420
|
+
return { h, w, x, y };
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
// Flow: the first free spot on the current line after the previous panel, else the next line.
|
|
424
|
+
// Only `x`: that column, on the first line where it is free.
|
|
425
|
+
for (;;) {
|
|
426
|
+
const x =
|
|
427
|
+
gp?.x === undefined
|
|
428
|
+
? this.freeColumn(this.x, this.y, w, h)
|
|
429
|
+
: gp.x >= this.x && this.free(gp.x, this.y, w, h)
|
|
430
|
+
? gp.x
|
|
431
|
+
: undefined;
|
|
432
|
+
if (x !== undefined) {
|
|
433
|
+
const pos = { h, w, x, y: this.y };
|
|
434
|
+
this.take(x, this.y, w, h);
|
|
435
|
+
this.x = x + w;
|
|
436
|
+
this.lineH = Math.max(this.lineH, h);
|
|
437
|
+
this.bottom = Math.max(this.bottom, this.y + h);
|
|
438
|
+
return pos;
|
|
439
|
+
}
|
|
440
|
+
this.y += this.lineH || 1;
|
|
284
441
|
this.x = 0;
|
|
285
442
|
this.lineH = 0;
|
|
286
443
|
}
|
|
287
|
-
const pos = { h, w, x: this.x, y: this.y };
|
|
288
|
-
this.x += w;
|
|
289
|
-
this.lineH = Math.max(this.lineH, h);
|
|
290
|
-
this.bottom = Math.max(this.bottom, this.y + h);
|
|
291
|
-
return pos;
|
|
292
444
|
}
|
|
293
445
|
|
|
294
|
-
/**
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
446
|
+
/** Marks the line of a row header with an explicit `y` as taken, before anything is placed. */
|
|
447
|
+
reserveRow(y: number | undefined): void {
|
|
448
|
+
if (y !== undefined) this.take(0, y, GRID_COLUMNS, 1);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/** A full-width row header on line `explicitY`, else on the first free line below everything placed so far. */
|
|
452
|
+
row(explicitY?: number): GridPos {
|
|
453
|
+
let y = explicitY ?? Math.max(this.bottom, this.y + this.lineH);
|
|
454
|
+
if (explicitY === undefined) while (!this.free(0, y, GRID_COLUMNS, 1)) y++;
|
|
455
|
+
this.take(0, y, GRID_COLUMNS, 1);
|
|
298
456
|
this.x = 0;
|
|
299
457
|
this.y = y + 1;
|
|
300
458
|
this.lineH = 0;
|
|
301
459
|
this.bottom = y + 1;
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
460
|
+
return { h: 1, w: GRID_COLUMNS, x: 0, y };
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/** The first column at or after `from` where a w×h panel fits on line `y`. A panel wider than the grid fits only at 0. */
|
|
464
|
+
private freeColumn(from: number, y: number, w: number, h: number): number | undefined {
|
|
465
|
+
for (let x = from; x === 0 || x + w <= GRID_COLUMNS; x++) if (this.free(x, y, w, h)) return x;
|
|
466
|
+
return undefined;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
private free(x: number, y: number, w: number, h: number): boolean {
|
|
470
|
+
const mask = columns(x, w);
|
|
471
|
+
for (let line = Math.max(0, y); line < y + h; line++) if ((this.taken[line] ?? 0) & mask) return false;
|
|
472
|
+
return true;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
private take(x: number, y: number, w: number, h: number): void {
|
|
476
|
+
const mask = columns(x, w);
|
|
477
|
+
for (let line = Math.max(0, y); line < y + h; line++) this.taken[line] = (this.taken[line] ?? 0) | mask;
|
|
310
478
|
}
|
|
311
479
|
}
|
|
312
480
|
|
|
@@ -334,7 +502,8 @@ function panelJson(panel: PanelEntity, gridPos: GridPos, id: number, inherited?:
|
|
|
334
502
|
const def = panel.panelDefinition;
|
|
335
503
|
const own = datasourceRef(p.datasource) ?? inherited;
|
|
336
504
|
const queries = (p.targets ?? []).filter(isQueryEntity);
|
|
337
|
-
|
|
505
|
+
// A query under a Mixed panel names its own datasource; one that names none goes to the default, not to Mixed.
|
|
506
|
+
const targets = queries.map((q, i) => targetJson(q, i, sameRef(own, MIXED) ? undefined : own));
|
|
338
507
|
const refs = targets.map((t) => t.datasource as DataSourceRef | undefined);
|
|
339
508
|
let datasource = own;
|
|
340
509
|
if (!datasource && refs.length > 0) {
|
|
@@ -374,19 +543,29 @@ function panelJson(panel: PanelEntity, gridPos: GridPos, id: number, inherited?:
|
|
|
374
543
|
/** A dashboard's `panels` array: rows and panels, laid out, with ids. */
|
|
375
544
|
export function panelsJson(items: Array<PanelEntity | RowEntity>): Array<PanelJson | RowPanelJson> {
|
|
376
545
|
const layout = new Layout();
|
|
546
|
+
// Panels on the dashboard's grid with both x and y, and rows with a y, take their cells first; a collapsed row's panels are laid out on their own.
|
|
547
|
+
for (const item of items) {
|
|
548
|
+
if (isRowEntity(item)) layout.reserveRow(item.props.gridPos?.y);
|
|
549
|
+
const onGrid = isRowEntity(item) ? (item.props.collapsed ? [] : (item.props.panels ?? [])) : [item];
|
|
550
|
+
for (const p of onGrid.filter(isPanelEntity)) layout.reserve(p.props.gridPos, p.panelDefinition.defaultSize);
|
|
551
|
+
}
|
|
377
552
|
const ids = new Ids(explicitIds(items));
|
|
378
553
|
const out: Array<PanelJson | RowPanelJson> = [];
|
|
379
554
|
for (const item of items) {
|
|
380
555
|
if (isRowEntity(item)) {
|
|
381
556
|
const r = item.props;
|
|
382
|
-
const
|
|
557
|
+
const pos = layout.row(r.gridPos?.y);
|
|
383
558
|
const rowId = ids.take(r.id);
|
|
384
559
|
const rowRef = datasourceRef(r.datasource);
|
|
385
|
-
const
|
|
386
|
-
|
|
560
|
+
const collapsed = r.collapsed ?? false;
|
|
561
|
+
// A collapsed row's panels sit under its header on a grid of their own; the next item starts right under the header.
|
|
562
|
+
const rowLayout = collapsed ? new Layout(pos.y + 1) : layout;
|
|
563
|
+
const panels = (r.panels ?? []).filter(isPanelEntity);
|
|
564
|
+
if (collapsed) for (const p of panels) rowLayout.reserve(p.props.gridPos, p.panelDefinition.defaultSize);
|
|
565
|
+
const children = panels.map((p) => {
|
|
566
|
+
const gp = rowLayout.place(p.props.gridPos, p.panelDefinition.defaultSize);
|
|
387
567
|
return panelJson(p, gp, ids.take(p.props.id), rowRef);
|
|
388
568
|
});
|
|
389
|
-
const collapsed = r.collapsed ?? false;
|
|
390
569
|
out.push(
|
|
391
570
|
compact({
|
|
392
571
|
type: "row" as const,
|
|
@@ -399,8 +578,7 @@ export function panelsJson(items: Array<PanelEntity | RowEntity>): Array<PanelJs
|
|
|
399
578
|
repeat: repeatName(r.repeat),
|
|
400
579
|
}),
|
|
401
580
|
);
|
|
402
|
-
if (collapsed)
|
|
403
|
-
else out.push(...children);
|
|
581
|
+
if (!collapsed) out.push(...children);
|
|
404
582
|
} else if (isPanelEntity(item)) {
|
|
405
583
|
const gp = layout.place(item.props.gridPos, item.panelDefinition.defaultSize);
|
|
406
584
|
out.push(panelJson(item, gp, ids.take(item.props.id)));
|
|
@@ -422,7 +600,7 @@ export function dashboardUid(dashboard: DashboardEntity, exportName?: string): s
|
|
|
422
600
|
export function renderDashboard(dashboard: DashboardEntity, exportName?: string): DashboardJson {
|
|
423
601
|
const p = dashboard.props;
|
|
424
602
|
return compact({
|
|
425
|
-
annotations: { list: [] },
|
|
603
|
+
annotations: { list: (p.annotations ?? []).map((a) => annotationJson(a, datasourceRef)) },
|
|
426
604
|
description: p.description,
|
|
427
605
|
editable: p.editable ?? true,
|
|
428
606
|
fiscalYearStartMonth: p.fiscalYearStartMonth ?? 0,
|
|
@@ -431,7 +609,7 @@ export function renderDashboard(dashboard: DashboardEntity, exportName?: string)
|
|
|
431
609
|
liveNow: p.liveNow,
|
|
432
610
|
panels: panelsJson(p.panels ?? []),
|
|
433
611
|
refresh: p.refresh,
|
|
434
|
-
schemaVersion: DASHBOARD_SCHEMA_VERSION,
|
|
612
|
+
schemaVersion: p.schemaVersion ?? DASHBOARD_SCHEMA_VERSION,
|
|
435
613
|
tags: p.tags ?? [],
|
|
436
614
|
templating: { list: (p.variables ?? []).filter(isVariableEntity).map(variableModel) },
|
|
437
615
|
time: p.time ?? { from: "now-6h", to: "now" },
|
|
@@ -450,9 +628,9 @@ export function dashboardJson(dashboard: DashboardEntity, exportName?: string):
|
|
|
450
628
|
|
|
451
629
|
// ── Datasources and providers ───────────────────────────────────
|
|
452
630
|
|
|
453
|
-
/** Replace every declared
|
|
631
|
+
/** Replace every declared or external datasource inside plugin settings with its uid. */
|
|
454
632
|
function resolveNested(value: unknown): unknown {
|
|
455
|
-
if (
|
|
633
|
+
if (isDatasourceDeclaration(value)) return value.uid;
|
|
456
634
|
if (Array.isArray(value)) return value.map(resolveNested);
|
|
457
635
|
if (value && typeof value === "object" && Object.getPrototypeOf(value) === Object.prototype) {
|
|
458
636
|
return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, resolveNested(v)]));
|
|
@@ -483,8 +661,13 @@ export function provisionedDatasource(ds: DatasourceEntity): ProvisionedDatasour
|
|
|
483
661
|
});
|
|
484
662
|
}
|
|
485
663
|
|
|
664
|
+
/** One `ExternalDatasource` as the checks and the index see it. */
|
|
665
|
+
export function externalDatasourceRecord(ds: ExternalDatasourceEntity): ExternalDatasourceRecord {
|
|
666
|
+
return compact({ type: ds.datasourceType, uid: ds.uid, name: ds.props.name });
|
|
667
|
+
}
|
|
668
|
+
|
|
486
669
|
/** One dashboard provider as a provisioning entry. */
|
|
487
|
-
export function provisionedProvider(p:
|
|
670
|
+
export function provisionedProvider(p: DashboardProviderEntityProps): ProvisionedProvider {
|
|
488
671
|
const pinnedFolder = p.folder !== undefined || p.folderUid !== undefined;
|
|
489
672
|
return compact({
|
|
490
673
|
name: p.name,
|
|
@@ -506,9 +689,26 @@ function yamlFile(header: string, body: Record<string, unknown>): string {
|
|
|
506
689
|
return `# ${header}\n${dump(body, { lineWidth: -1, noRefs: true, quotingType: '"' })}`;
|
|
507
690
|
}
|
|
508
691
|
|
|
509
|
-
/**
|
|
510
|
-
export function
|
|
511
|
-
return
|
|
692
|
+
/** `prune` and `deleteDatasources` as a build writes them: pruning on unless a `DatasourceProvisioning` turns it off. */
|
|
693
|
+
export function datasourceFileSettings(props: DatasourceProvisioningProps | undefined): DatasourceFileSettings {
|
|
694
|
+
return {
|
|
695
|
+
prune: props?.prune ?? true,
|
|
696
|
+
deleteDatasources: (props?.deleteDatasources ?? []).map((d) => ({ name: d.name, ...(d.orgId !== undefined ? { orgId: d.orgId } : {}) })),
|
|
697
|
+
};
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
/**
|
|
701
|
+
* The datasource provisioning file for these datasources. It prunes by
|
|
702
|
+
* default (`prune: true`), so a datasource removed from the build is removed
|
|
703
|
+
* from Grafana; `deleteDatasources` comes first, as Grafana runs it first.
|
|
704
|
+
*/
|
|
705
|
+
export function datasourcesYaml(datasources: ProvisionedDatasource[], settings: DatasourceFileSettings = datasourceFileSettings(undefined)): string {
|
|
706
|
+
return yamlFile("Grafana datasource provisioning, generated by chant.", {
|
|
707
|
+
apiVersion: 1,
|
|
708
|
+
...(settings.prune ? { prune: true } : {}),
|
|
709
|
+
...(settings.deleteDatasources.length > 0 ? { deleteDatasources: settings.deleteDatasources } : {}),
|
|
710
|
+
datasources,
|
|
711
|
+
});
|
|
512
712
|
}
|
|
513
713
|
|
|
514
714
|
/** The dashboard provisioning file for these providers. */
|
|
@@ -516,8 +716,20 @@ export function dashboardProvidersYaml(providers: ProvisionedProvider[]): string
|
|
|
516
716
|
return yamlFile("Grafana dashboard provisioning, generated by chant.", { apiVersion: 1, providers });
|
|
517
717
|
}
|
|
518
718
|
|
|
719
|
+
/**
|
|
720
|
+
* A dashboard's `folder` as its directory under `dashboards/`: one
|
|
721
|
+
* subdirectory per level (`folderLevels`), which a provider with
|
|
722
|
+
* `foldersFromFilesStructure` turns into nested folders on Grafana 13.1 and
|
|
723
|
+
* later (GRAF109 says what earlier versions do). Empty for the General
|
|
724
|
+
* folder.
|
|
725
|
+
*/
|
|
519
726
|
function folderDir(folder: string): string {
|
|
520
|
-
return folder
|
|
727
|
+
return folderLevels(folder).join("/");
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
/** A `Folder` and every folder above it. */
|
|
731
|
+
function withAncestors(folder: FolderEntity, into: Set<FolderEntity>): void {
|
|
732
|
+
for (let f: FolderEntity | undefined = folder; f; f = f.props.parent) into.add(f);
|
|
521
733
|
}
|
|
522
734
|
|
|
523
735
|
// ── The whole build ─────────────────────────────────────────────
|
|
@@ -534,37 +746,64 @@ export function buildGrafana(entities: Map<string, Declarable> | Iterable<Declar
|
|
|
534
746
|
.map(([, e]) => provisionedDatasource(e as DatasourceEntity))
|
|
535
747
|
.sort((a, b) => a.name.localeCompare(b.name));
|
|
536
748
|
|
|
749
|
+
const externalDatasources: ExternalDatasourceRecord[] = named
|
|
750
|
+
.filter(([, e]) => isExternalDatasource(e))
|
|
751
|
+
.map(([, e]) => externalDatasourceRecord(e as ExternalDatasourceEntity))
|
|
752
|
+
.sort((a, b) => a.uid.localeCompare(b.uid));
|
|
753
|
+
|
|
754
|
+
// Folders: every declared `Folder` and every one a dashboard holds, with their parents, pin uids; every path a dashboard names is a folder per level.
|
|
755
|
+
const declaredFolders = new Set<FolderEntity>();
|
|
756
|
+
for (const [, e] of named) {
|
|
757
|
+
if (isFolderEntity(e)) withAncestors(e, declaredFolders);
|
|
758
|
+
else if (isDashboardEntity(e) && e.folderEntity) withAncestors(e.folderEntity, declaredFolders);
|
|
759
|
+
}
|
|
760
|
+
const resolved = resolveFolders({
|
|
761
|
+
declared: [...declaredFolders].map((f) => ({ uid: f.uid, path: f.path })),
|
|
762
|
+
paths: named.flatMap(([, e]) => (isDashboardEntity(e) && e.props.folder ? [e.props.folder] : [])),
|
|
763
|
+
}, { duplicateUids: "keep" });
|
|
764
|
+
|
|
537
765
|
const dashboards: BuiltDashboard[] = [];
|
|
538
766
|
for (const [name, e] of named) {
|
|
539
767
|
if (!isDashboardEntity(e)) continue;
|
|
540
768
|
const json = renderDashboard(e, name);
|
|
541
769
|
const uid = json.uid as string;
|
|
542
770
|
const folder = e.props.folder;
|
|
543
|
-
const
|
|
771
|
+
const sub = folder ? folderDir(folder) : "";
|
|
772
|
+
const dir = sub ? `${DASHBOARDS_DIR}/${sub}` : DASHBOARDS_DIR;
|
|
544
773
|
let file = `${dir}/${uid}.json`;
|
|
545
774
|
for (let n = 2; file in files; n++) file = `${dir}/${uid}-${n}.json`;
|
|
546
775
|
files[file] = `${JSON.stringify(json, null, 2)}\n`;
|
|
547
|
-
|
|
776
|
+
const folderUid = sub ? resolved.uidOf(sub) : undefined;
|
|
777
|
+
dashboards.push({ uid, title: e.props.title, ...(folder ? { folder } : {}), ...(folderUid ? { folderUid } : {}), file, json });
|
|
548
778
|
}
|
|
549
779
|
|
|
550
|
-
const
|
|
780
|
+
const settings = named.map(([, e]) => e).filter(isDatasourceProvisioningEntity);
|
|
781
|
+
if (settings.length > 1) throw new Error("grafana: declare at most one DatasourceProvisioning; the build writes one datasource provisioning file");
|
|
782
|
+
const datasourceFile = datasourceFileSettings(settings[0]?.props);
|
|
783
|
+
|
|
784
|
+
const declaredProviders = named.filter(([, e]) => isDashboardProviderEntity(e)).map(([, e]) => (e as unknown as { props: DashboardProviderEntityProps }).props);
|
|
551
785
|
const providers =
|
|
552
786
|
declaredProviders.length > 0
|
|
553
787
|
? declaredProviders.map(provisionedProvider)
|
|
554
788
|
: dashboards.length > 0
|
|
555
|
-
? [provisionedProvider({ name:
|
|
789
|
+
? [provisionedProvider({ name: DEFAULT_PROVIDER_NAME })]
|
|
556
790
|
: [];
|
|
557
791
|
|
|
558
|
-
if (datasources.length > 0) files[DATASOURCES_FILE] = datasourcesYaml(datasources);
|
|
792
|
+
if (datasources.length > 0 || datasourceFile.deleteDatasources.length > 0) files[DATASOURCES_FILE] = datasourcesYaml(datasources, datasourceFile);
|
|
559
793
|
if (providers.length > 0) files[DASHBOARD_PROVIDERS_FILE] = dashboardProvidersYaml(providers);
|
|
794
|
+
const alerting = buildAlerting(named.map(([, e]) => e));
|
|
795
|
+
if (alerting) files[ALERTING_FILE] = alertingYaml(alerting.file);
|
|
560
796
|
|
|
561
797
|
const index: GrafanaIndex = {
|
|
562
798
|
grafanaSchema: `${GRAFANA_SCHEMA_PIN.source}@${GRAFANA_SCHEMA_PIN.ref}`,
|
|
563
|
-
dashboards: dashboards.map(({ uid, title, folder, file }) => ({ uid, title, ...(folder ? { folder } : {}), file })),
|
|
799
|
+
dashboards: dashboards.map(({ uid, title, folder, folderUid, file }) => ({ uid, title, ...(folder ? { folder } : {}), ...(folderUid ? { folderUid } : {}), file })),
|
|
800
|
+
...(resolved.folders.length > 0 ? { folders: resolved.folders } : {}),
|
|
564
801
|
datasources: datasources.map(({ name, type, uid }) => ({ name, type, uid })),
|
|
802
|
+
...(externalDatasources.length > 0 ? { externalDatasources } : {}),
|
|
803
|
+
...(alerting ? { alerting: alerting.index } : {}),
|
|
565
804
|
files: Object.keys(files).sort(),
|
|
566
805
|
};
|
|
567
|
-
return { dashboards, datasources, providers, files, index };
|
|
806
|
+
return { dashboards, datasources, externalDatasources, providers, folders: resolved.folders, datasourceFile, ...(alerting ? { alerting: alerting.file } : {}), files, index };
|
|
568
807
|
}
|
|
569
808
|
|
|
570
809
|
/** Every file the grafana entities render to, by path relative to the output directory. */
|