@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.
Files changed (532) hide show
  1. package/README.md +24 -8
  2. package/dist/actions/grafana.d.ts +24 -0
  3. package/dist/actions/grafana.d.ts.map +1 -0
  4. package/dist/actions/index.d.ts +2 -0
  5. package/dist/actions/index.d.ts.map +1 -0
  6. package/dist/alerting-build.d.ts +128 -0
  7. package/dist/alerting-build.d.ts.map +1 -0
  8. package/dist/alerting.d.ts +273 -0
  9. package/dist/alerting.d.ts.map +1 -0
  10. package/dist/annotations.d.ts +61 -0
  11. package/dist/annotations.d.ts.map +1 -0
  12. package/dist/api/apply.d.ts +160 -0
  13. package/dist/api/apply.d.ts.map +1 -0
  14. package/dist/api/bind.d.ts +32 -0
  15. package/dist/api/bind.d.ts.map +1 -0
  16. package/dist/api/client.d.ts +76 -0
  17. package/dist/api/client.d.ts.map +1 -0
  18. package/dist/api/converge.d.ts +33 -0
  19. package/dist/api/converge.d.ts.map +1 -0
  20. package/dist/api/dashboards.d.ts +102 -0
  21. package/dist/api/dashboards.d.ts.map +1 -0
  22. package/dist/api/datasources.d.ts +26 -0
  23. package/dist/api/datasources.d.ts.map +1 -0
  24. package/dist/api/fake-grafana-writes.d.ts +41 -0
  25. package/dist/api/fake-grafana-writes.d.ts.map +1 -0
  26. package/dist/api/fake-grafana.d.ts +63 -0
  27. package/dist/api/fake-grafana.d.ts.map +1 -0
  28. package/dist/api/folders.d.ts +146 -0
  29. package/dist/api/folders.d.ts.map +1 -0
  30. package/dist/api/library-panels.d.ts +52 -0
  31. package/dist/api/library-panels.d.ts.map +1 -0
  32. package/dist/build.d.ts +55 -6
  33. package/dist/build.d.ts.map +1 -1
  34. package/dist/catalog.d.ts +1 -1
  35. package/dist/catalog.d.ts.map +1 -1
  36. package/dist/codegen/docs.d.ts.map +1 -1
  37. package/dist/codegen/generate.d.ts +7 -1
  38. package/dist/codegen/generate.d.ts.map +1 -1
  39. package/dist/codegen/schema-types.d.ts +3 -3
  40. package/dist/codegen/schema-types.d.ts.map +1 -1
  41. package/dist/composites/agent-dashboard.d.ts.map +1 -1
  42. package/dist/composites/catalog.d.ts.map +1 -1
  43. package/dist/composites/index.d.ts +4 -2
  44. package/dist/composites/index.d.ts.map +1 -1
  45. package/dist/composites/red-dashboard.d.ts +21 -2
  46. package/dist/composites/red-dashboard.d.ts.map +1 -1
  47. package/dist/composites/shared.d.ts +11 -3
  48. package/dist/composites/shared.d.ts.map +1 -1
  49. package/dist/composites/slo-alert-rules.d.ts +92 -0
  50. package/dist/composites/slo-alert-rules.d.ts.map +1 -0
  51. package/dist/config.d.ts +111 -0
  52. package/dist/config.d.ts.map +1 -0
  53. package/dist/contact-point-secrets.d.ts +17 -0
  54. package/dist/contact-point-secrets.d.ts.map +1 -0
  55. package/dist/dashboard.d.ts +51 -9
  56. package/dist/dashboard.d.ts.map +1 -1
  57. package/dist/datasource-refs.d.ts +99 -0
  58. package/dist/datasource-refs.d.ts.map +1 -0
  59. package/dist/datasource-settings.d.ts +834 -0
  60. package/dist/datasource-settings.d.ts.map +1 -0
  61. package/dist/datasource.d.ts +82 -11
  62. package/dist/datasource.d.ts.map +1 -1
  63. package/dist/deep-observe-hooks.d.ts +64 -0
  64. package/dist/deep-observe-hooks.d.ts.map +1 -0
  65. package/dist/deep-observe.d.ts +47 -0
  66. package/dist/deep-observe.d.ts.map +1 -0
  67. package/dist/describe-resources.d.ts +50 -0
  68. package/dist/describe-resources.d.ts.map +1 -0
  69. package/dist/detect.d.ts +32 -3
  70. package/dist/detect.d.ts.map +1 -1
  71. package/dist/export-resources.d.ts +38 -0
  72. package/dist/export-resources.d.ts.map +1 -0
  73. package/dist/folder.d.ts +68 -0
  74. package/dist/folder.d.ts.map +1 -0
  75. package/dist/import/alerting.d.ts +40 -0
  76. package/dist/import/alerting.d.ts.map +1 -0
  77. package/dist/import/edits.d.ts +47 -0
  78. package/dist/import/edits.d.ts.map +1 -0
  79. package/dist/import/embedded.d.ts +14 -0
  80. package/dist/import/embedded.d.ts.map +1 -0
  81. package/dist/import/generator.d.ts +60 -0
  82. package/dist/import/generator.d.ts.map +1 -0
  83. package/dist/import/live-export.d.ts +108 -0
  84. package/dist/import/live-export.d.ts.map +1 -0
  85. package/dist/import/mappings.d.ts +89 -0
  86. package/dist/import/mappings.d.ts.map +1 -0
  87. package/dist/import/model.d.ts +105 -0
  88. package/dist/import/model.d.ts.map +1 -0
  89. package/dist/import/normalize-alerting.d.ts +26 -0
  90. package/dist/import/normalize-alerting.d.ts.map +1 -0
  91. package/dist/import/normalize.d.ts +74 -0
  92. package/dist/import/normalize.d.ts.map +1 -0
  93. package/dist/import/parser.d.ts +125 -0
  94. package/dist/import/parser.d.ts.map +1 -0
  95. package/dist/import/report.d.ts +26 -0
  96. package/dist/import/report.d.ts.map +1 -0
  97. package/dist/import/testdata/fixtures.d.ts +41 -0
  98. package/dist/import/testdata/fixtures.d.ts.map +1 -0
  99. package/dist/import/v2.d.ts +73 -0
  100. package/dist/import/v2.d.ts.map +1 -0
  101. package/dist/index.d.ts +31 -12
  102. package/dist/index.d.ts.map +1 -1
  103. package/dist/init-templates.d.ts +27 -0
  104. package/dist/init-templates.d.ts.map +1 -0
  105. package/dist/integrity.json +22 -12
  106. package/dist/k8s.d.ts +107 -0
  107. package/dist/k8s.d.ts.map +1 -0
  108. package/dist/lint/audit-catalog.d.ts +2 -1
  109. package/dist/lint/audit-catalog.d.ts.map +1 -1
  110. package/dist/lint/post-synth/graf101.d.ts +2 -2
  111. package/dist/lint/post-synth/graf102.d.ts +1 -1
  112. package/dist/lint/post-synth/graf104.d.ts +2 -2
  113. package/dist/lint/post-synth/graf106.d.ts +2 -2
  114. package/dist/lint/post-synth/graf107.d.ts +1 -1
  115. package/dist/lint/post-synth/graf108.d.ts +8 -0
  116. package/dist/lint/post-synth/graf108.d.ts.map +1 -0
  117. package/dist/lint/post-synth/graf109.d.ts +8 -0
  118. package/dist/lint/post-synth/graf109.d.ts.map +1 -0
  119. package/dist/lint/post-synth/graf110.d.ts +8 -0
  120. package/dist/lint/post-synth/graf110.d.ts.map +1 -0
  121. package/dist/lint/post-synth/graf111.d.ts +8 -0
  122. package/dist/lint/post-synth/graf111.d.ts.map +1 -0
  123. package/dist/lint/post-synth/graf112.d.ts +8 -0
  124. package/dist/lint/post-synth/graf112.d.ts.map +1 -0
  125. package/dist/lint/post-synth/graf113.d.ts +8 -0
  126. package/dist/lint/post-synth/graf113.d.ts.map +1 -0
  127. package/dist/lint/post-synth/graf114.d.ts +8 -0
  128. package/dist/lint/post-synth/graf114.d.ts.map +1 -0
  129. package/dist/lint/post-synth/graf115.d.ts +8 -0
  130. package/dist/lint/post-synth/graf115.d.ts.map +1 -0
  131. package/dist/lint/post-synth/grafana-helpers.d.ts +7 -5
  132. package/dist/lint/post-synth/grafana-helpers.d.ts.map +1 -1
  133. package/dist/lint/post-synth/index.d.ts.map +1 -1
  134. package/dist/lint/rules/literal-secret.d.ts +7 -3
  135. package/dist/lint/rules/literal-secret.d.ts.map +1 -1
  136. package/dist/lsp/hover.d.ts.map +1 -1
  137. package/dist/manifest.json +1 -1
  138. package/dist/members.d.ts +27 -0
  139. package/dist/members.d.ts.map +1 -0
  140. package/dist/meta.json +205 -0
  141. package/dist/okf/index.md +53 -4
  142. package/dist/okf/rules/GRAF002.md +3 -2
  143. package/dist/okf/rules/GRAF101.md +3 -2
  144. package/dist/okf/rules/GRAF102.md +1 -0
  145. package/dist/okf/rules/GRAF104.md +2 -2
  146. package/dist/okf/rules/GRAF106.md +2 -2
  147. package/dist/okf/rules/GRAF108.md +11 -0
  148. package/dist/okf/rules/GRAF109.md +15 -0
  149. package/dist/okf/rules/GRAF110.md +11 -0
  150. package/dist/okf/rules/GRAF111.md +11 -0
  151. package/dist/okf/rules/GRAF112.md +16 -0
  152. package/dist/okf/rules/GRAF113.md +16 -0
  153. package/dist/okf/rules/GRAF114.md +11 -0
  154. package/dist/okf/rules/GRAF115.md +11 -0
  155. package/dist/okf/types/AdhocVariable.md +9 -0
  156. package/dist/okf/types/AlertListPanel.md +9 -0
  157. package/dist/okf/types/AlertQuery.md +9 -0
  158. package/dist/okf/types/AlertRule.md +9 -0
  159. package/dist/okf/types/AlertRuleGroup.md +9 -0
  160. package/dist/okf/types/AzureMonitorQuery.md +9 -0
  161. package/dist/okf/types/BarChartPanel.md +9 -0
  162. package/dist/okf/types/BarGaugePanel.md +9 -0
  163. package/dist/okf/types/BigQueryQuery.md +9 -0
  164. package/dist/okf/types/CanvasPanel.md +9 -0
  165. package/dist/okf/types/ClassicConditionsExpression.md +9 -0
  166. package/dist/okf/types/CloudMonitoringQuery.md +9 -0
  167. package/dist/okf/types/CloudWatchQuery.md +9 -0
  168. package/dist/okf/types/ContactPoint.md +14 -0
  169. package/dist/okf/types/Dashboard.md +2 -1
  170. package/dist/okf/types/Datasource.md +3 -2
  171. package/dist/okf/types/DatasourceProvisioning.md +9 -0
  172. package/dist/okf/types/ElasticsearchQuery.md +9 -0
  173. package/dist/okf/types/ExternalDatasource.md +15 -0
  174. package/dist/okf/types/FlameGraphPanel.md +9 -0
  175. package/dist/okf/types/Folder.md +9 -0
  176. package/dist/okf/types/GeomapPanel.md +9 -0
  177. package/dist/okf/types/GroupByVariable.md +9 -0
  178. package/dist/okf/types/HistogramPanel.md +9 -0
  179. package/dist/okf/types/MSSQLQuery.md +9 -0
  180. package/dist/okf/types/MathExpression.md +9 -0
  181. package/dist/okf/types/MuteTiming.md +13 -0
  182. package/dist/okf/types/MySQLQuery.md +9 -0
  183. package/dist/okf/types/NodeGraphPanel.md +9 -0
  184. package/dist/okf/types/NotificationPolicy.md +9 -0
  185. package/dist/okf/types/NotificationTemplate.md +9 -0
  186. package/dist/okf/types/PieChartPanel.md +9 -0
  187. package/dist/okf/types/PostgresQuery.md +9 -0
  188. package/dist/okf/types/PyroscopeQuery.md +9 -0
  189. package/dist/okf/types/ReduceExpression.md +9 -0
  190. package/dist/okf/types/ResampleExpression.md +9 -0
  191. package/dist/okf/types/SqlExpression.md +9 -0
  192. package/dist/okf/types/StateTimelinePanel.md +9 -0
  193. package/dist/okf/types/StatusHistoryPanel.md +9 -0
  194. package/dist/okf/types/SwitchVariable.md +9 -0
  195. package/dist/okf/types/ThresholdExpression.md +9 -0
  196. package/dist/okf/types/TrendPanel.md +9 -0
  197. package/dist/okf/types/XYChartPanel.md +9 -0
  198. package/dist/op/activities/grafana-apply.d.ts +86 -0
  199. package/dist/op/activities/grafana-apply.d.ts.map +1 -0
  200. package/dist/op/activities/index.d.ts +9 -0
  201. package/dist/op/activities/index.d.ts.map +1 -0
  202. package/dist/op/builders.d.ts +24 -0
  203. package/dist/op/builders.d.ts.map +1 -0
  204. package/dist/ownership.d.ts +78 -0
  205. package/dist/ownership.d.ts.map +1 -0
  206. package/dist/panel-options.d.ts +65 -0
  207. package/dist/panel-options.d.ts.map +1 -0
  208. package/dist/panels.d.ts +46 -9
  209. package/dist/panels.d.ts.map +1 -1
  210. package/dist/pin.d.ts +29 -7
  211. package/dist/pin.d.ts.map +1 -1
  212. package/dist/plugin.d.ts.map +1 -1
  213. package/dist/promql-check.d.ts +51 -0
  214. package/dist/promql-check.d.ts.map +1 -0
  215. package/dist/query-models.d.ts +95 -0
  216. package/dist/query-models.d.ts.map +1 -0
  217. package/dist/query.d.ts +116 -18
  218. package/dist/query.d.ts.map +1 -1
  219. package/dist/rules/graf101.ts +3 -3
  220. package/dist/rules/graf102.ts +1 -1
  221. package/dist/rules/graf104.ts +3 -3
  222. package/dist/rules/graf106.ts +3 -3
  223. package/dist/rules/graf107.ts +1 -1
  224. package/dist/rules/graf108.ts +17 -0
  225. package/dist/rules/graf109.ts +17 -0
  226. package/dist/rules/graf110.ts +17 -0
  227. package/dist/rules/graf111.ts +17 -0
  228. package/dist/rules/graf112.ts +17 -0
  229. package/dist/rules/graf113.ts +17 -0
  230. package/dist/rules/graf114.ts +17 -0
  231. package/dist/rules/graf115.ts +17 -0
  232. package/dist/rules/grafana-helpers.ts +27 -10
  233. package/dist/rules/literal-secret.ts +60 -6
  234. package/dist/schema/azuremonitor.gen.d.ts +354 -0
  235. package/dist/schema/azuremonitor.gen.d.ts.map +1 -0
  236. package/dist/schema/barchart.gen.d.ts +198 -0
  237. package/dist/schema/barchart.gen.d.ts.map +1 -0
  238. package/dist/schema/bargauge.gen.d.ts +97 -0
  239. package/dist/schema/bargauge.gen.d.ts.map +1 -0
  240. package/dist/schema/bigquery.gen.d.ts +93 -0
  241. package/dist/schema/bigquery.gen.d.ts.map +1 -0
  242. package/dist/schema/canvas.gen.d.ts +152 -0
  243. package/dist/schema/canvas.gen.d.ts.map +1 -0
  244. package/dist/schema/cloudwatch.gen.d.ts +394 -0
  245. package/dist/schema/cloudwatch.gen.d.ts.map +1 -0
  246. package/dist/schema/dashboard.gen.d.ts +196 -21
  247. package/dist/schema/dashboard.gen.d.ts.map +1 -1
  248. package/dist/schema/elasticsearch.gen.d.ts +444 -0
  249. package/dist/schema/elasticsearch.gen.d.ts.map +1 -0
  250. package/dist/schema/expr.gen.d.ts +606 -0
  251. package/dist/schema/expr.gen.d.ts.map +1 -0
  252. package/dist/schema/gauge.gen.d.ts.map +1 -1
  253. package/dist/schema/geomap.gen.d.ts +100 -0
  254. package/dist/schema/geomap.gen.d.ts.map +1 -0
  255. package/dist/schema/googlecloudmonitoring.gen.d.ts +312 -0
  256. package/dist/schema/googlecloudmonitoring.gen.d.ts.map +1 -0
  257. package/dist/schema/grafanapyroscope.gen.d.ts +60 -0
  258. package/dist/schema/grafanapyroscope.gen.d.ts.map +1 -0
  259. package/dist/schema/heatmap.gen.d.ts.map +1 -1
  260. package/dist/schema/histogram.gen.d.ts +132 -0
  261. package/dist/schema/histogram.gen.d.ts.map +1 -0
  262. package/dist/schema/index.d.ts +18 -0
  263. package/dist/schema/index.d.ts.map +1 -1
  264. package/dist/schema/logs.gen.d.ts +1 -0
  265. package/dist/schema/logs.gen.d.ts.map +1 -1
  266. package/dist/schema/loki.gen.d.ts.map +1 -1
  267. package/dist/schema/nodegraph.gen.d.ts +49 -0
  268. package/dist/schema/nodegraph.gen.d.ts.map +1 -0
  269. package/dist/schema/piechart.gen.d.ts +127 -0
  270. package/dist/schema/piechart.gen.d.ts.map +1 -0
  271. package/dist/schema/prometheus.gen.d.ts.map +1 -1
  272. package/dist/schema/stat.gen.d.ts.map +1 -1
  273. package/dist/schema/statetimeline.gen.d.ts +124 -0
  274. package/dist/schema/statetimeline.gen.d.ts.map +1 -0
  275. package/dist/schema/statushistory.gen.d.ts +114 -0
  276. package/dist/schema/statushistory.gen.d.ts.map +1 -0
  277. package/dist/schema/table.gen.d.ts +35 -3
  278. package/dist/schema/table.gen.d.ts.map +1 -1
  279. package/dist/schema/tempo.gen.d.ts.map +1 -1
  280. package/dist/schema/text.gen.d.ts.map +1 -1
  281. package/dist/schema/timeseries.gen.d.ts +5 -1
  282. package/dist/schema/timeseries.gen.d.ts.map +1 -1
  283. package/dist/schema/trend.gen.d.ts +180 -0
  284. package/dist/schema/trend.gen.d.ts.map +1 -0
  285. package/dist/schema/xychart.gen.d.ts +145 -0
  286. package/dist/schema/xychart.gen.d.ts.map +1 -0
  287. package/dist/schema-validate.d.ts +39 -4
  288. package/dist/schema-validate.d.ts.map +1 -1
  289. package/dist/serializer.d.ts +11 -3
  290. package/dist/serializer.d.ts.map +1 -1
  291. package/dist/skill-defs.d.ts.map +1 -1
  292. package/dist/skills/chant-grafana-alerting.md +49 -0
  293. package/dist/skills/chant-grafana-operations.md +108 -0
  294. package/dist/skills/chant-grafana-provisioning.md +3 -3
  295. package/dist/skills/chant-grafana.md +15 -8
  296. package/dist/spec/fetch-units-cli.d.ts +3 -0
  297. package/dist/spec/fetch-units-cli.d.ts.map +1 -0
  298. package/dist/spec/overlay.d.ts +43 -0
  299. package/dist/spec/overlay.d.ts.map +1 -0
  300. package/dist/spec/schemas.d.ts +21 -13
  301. package/dist/spec/schemas.d.ts.map +1 -1
  302. package/dist/spec/schemas.gen.d.ts +3 -0
  303. package/dist/spec/schemas.gen.d.ts.map +1 -0
  304. package/dist/spec/units.d.ts +35 -0
  305. package/dist/spec/units.d.ts.map +1 -0
  306. package/dist/spec/units.gen.d.ts +2 -0
  307. package/dist/spec/units.gen.d.ts.map +1 -0
  308. package/dist/transformations.d.ts +459 -0
  309. package/dist/transformations.d.ts.map +1 -0
  310. package/dist/util.d.ts +6 -0
  311. package/dist/util.d.ts.map +1 -1
  312. package/dist/validate-alerting.d.ts +65 -0
  313. package/dist/validate-alerting.d.ts.map +1 -0
  314. package/dist/validate-output.d.ts +62 -9
  315. package/dist/validate-output.d.ts.map +1 -1
  316. package/dist/validate.d.ts.map +1 -1
  317. package/dist/validation.d.ts +14 -0
  318. package/dist/validation.d.ts.map +1 -0
  319. package/dist/variables.d.ts +109 -7
  320. package/dist/variables.d.ts.map +1 -1
  321. package/package.json +12 -4
  322. package/src/actions/actions.test.ts +24 -0
  323. package/src/actions/grafana.ts +40 -0
  324. package/src/actions/index.ts +1 -0
  325. package/src/alerting-build.ts +376 -0
  326. package/src/alerting.e2e.test.ts +212 -0
  327. package/src/alerting.test.ts +272 -0
  328. package/src/alerting.ts +435 -0
  329. package/src/annotations.ts +84 -0
  330. package/src/api/apply.test.ts +256 -0
  331. package/src/api/apply.ts +394 -0
  332. package/src/api/bind.ts +58 -0
  333. package/src/api/client.ts +148 -0
  334. package/src/api/converge.ts +63 -0
  335. package/src/api/dashboards.ts +247 -0
  336. package/src/api/datasources.ts +33 -0
  337. package/src/api/fake-grafana-writes.ts +201 -0
  338. package/src/api/fake-grafana.ts +190 -0
  339. package/src/api/folders.ts +339 -0
  340. package/src/api/library-panels.ts +101 -0
  341. package/src/build.test.ts +351 -10
  342. package/src/build.ts +294 -55
  343. package/src/catalog.ts +104 -2
  344. package/src/codegen/docs.ts +50 -10
  345. package/src/codegen/generate.ts +27 -1
  346. package/src/codegen/schema-types.ts +16 -6
  347. package/src/composites/agent-dashboard.ts +6 -3
  348. package/src/composites/catalog.test.ts +2 -2
  349. package/src/composites/catalog.ts +82 -0
  350. package/src/composites/composites.test.ts +73 -9
  351. package/src/composites/index.ts +4 -2
  352. package/src/composites/queries.e2e.test.ts +374 -0
  353. package/src/composites/red-dashboard.ts +83 -12
  354. package/src/composites/shared.ts +14 -2
  355. package/src/composites/slo-alert-rules.ts +149 -0
  356. package/src/config.test.ts +61 -0
  357. package/src/config.ts +138 -0
  358. package/src/contact-point-secrets.ts +63 -0
  359. package/src/dashboard.ts +68 -9
  360. package/src/datasource-refs.test.ts +56 -0
  361. package/src/datasource-refs.ts +213 -0
  362. package/src/datasource-settings.test.ts +106 -0
  363. package/src/datasource-settings.ts +941 -0
  364. package/src/datasource.ts +123 -11
  365. package/src/deep-observe-hooks.ts +267 -0
  366. package/src/deep-observe.test.ts +311 -0
  367. package/src/deep-observe.ts +187 -0
  368. package/src/describe-resources.test.ts +271 -0
  369. package/src/describe-resources.ts +244 -0
  370. package/src/detect.ts +82 -5
  371. package/src/export-resources.test.ts +129 -0
  372. package/src/export-resources.ts +84 -0
  373. package/src/folder.ts +118 -0
  374. package/src/generated/lexicon-grafana.json +205 -0
  375. package/src/import/alerting-roundtrip.test.ts +161 -0
  376. package/src/import/alerting.ts +500 -0
  377. package/src/import/edits.ts +95 -0
  378. package/src/import/embedded.test.ts +45 -0
  379. package/src/import/embedded.ts +47 -0
  380. package/src/import/generated-types.e2e.test.ts +130 -0
  381. package/src/import/generator.test.ts +210 -0
  382. package/src/import/generator.ts +463 -0
  383. package/src/import/live-export.ts +264 -0
  384. package/src/import/mappings.ts +336 -0
  385. package/src/import/model.ts +117 -0
  386. package/src/import/normalize-alerting.ts +101 -0
  387. package/src/import/normalize.test.ts +117 -0
  388. package/src/import/normalize.ts +393 -0
  389. package/src/import/parser.test.ts +516 -0
  390. package/src/import/parser.ts +1387 -0
  391. package/src/import/report.ts +62 -0
  392. package/src/import/roundtrip.test.ts +563 -0
  393. package/src/import/testdata/fixtures.ts +137 -0
  394. package/src/import/v2.test.ts +292 -0
  395. package/src/import/v2.ts +804 -0
  396. package/src/import.e2e.test.ts +31 -84
  397. package/src/import.test.ts +9 -3
  398. package/src/index.ts +308 -14
  399. package/src/init-templates.test.ts +74 -0
  400. package/src/init-templates.ts +349 -0
  401. package/src/k8s.test.ts +98 -0
  402. package/src/k8s.ts +197 -0
  403. package/src/lint/audit-catalog.ts +68 -3
  404. package/src/lint/core-lint.test.ts +43 -0
  405. package/src/lint/post-synth/graf101.ts +3 -3
  406. package/src/lint/post-synth/graf102.ts +1 -1
  407. package/src/lint/post-synth/graf104.ts +3 -3
  408. package/src/lint/post-synth/graf106.ts +3 -3
  409. package/src/lint/post-synth/graf107.ts +1 -1
  410. package/src/lint/post-synth/graf108.ts +17 -0
  411. package/src/lint/post-synth/graf109.ts +17 -0
  412. package/src/lint/post-synth/graf110.ts +17 -0
  413. package/src/lint/post-synth/graf111.ts +17 -0
  414. package/src/lint/post-synth/graf112.ts +17 -0
  415. package/src/lint/post-synth/graf113.ts +17 -0
  416. package/src/lint/post-synth/graf114.ts +17 -0
  417. package/src/lint/post-synth/graf115.ts +17 -0
  418. package/src/lint/post-synth/grafana-helpers.ts +27 -10
  419. package/src/lint/post-synth/index.ts +16 -0
  420. package/src/lint/post-synth/post-synth.test.ts +333 -12
  421. package/src/lint/rules/literal-secret.ts +60 -6
  422. package/src/lint/rules/rules.test.ts +27 -0
  423. package/src/load-cost.test.ts +35 -0
  424. package/src/lsp/completions.test.ts +5 -0
  425. package/src/lsp/hover.test.ts +7 -0
  426. package/src/lsp/hover.ts +8 -1
  427. package/src/members.ts +68 -0
  428. package/src/observe.e2e.test.ts +255 -0
  429. package/src/op/activities/grafana-apply.e2e.test.ts +184 -0
  430. package/src/op/activities/grafana-apply.test.ts +243 -0
  431. package/src/op/activities/grafana-apply.ts +197 -0
  432. package/src/op/activities/index.ts +8 -0
  433. package/src/op/builders.test.ts +40 -0
  434. package/src/op/builders.ts +34 -0
  435. package/src/ownership.ts +122 -0
  436. package/src/panel-options.ts +66 -0
  437. package/src/panels.test.ts +53 -0
  438. package/src/panels.ts +148 -10
  439. package/src/pin.ts +69 -6
  440. package/src/plugin.test.ts +12 -2
  441. package/src/plugin.ts +75 -0
  442. package/src/promql-check.test.ts +108 -0
  443. package/src/promql-check.ts +193 -0
  444. package/src/query-models.ts +94 -0
  445. package/src/query.test.ts +166 -0
  446. package/src/query.ts +190 -20
  447. package/src/schema/azuremonitor.gen.ts +381 -0
  448. package/src/schema/barchart.gen.ts +221 -0
  449. package/src/schema/bargauge.gen.ts +111 -0
  450. package/src/schema/bigquery.gen.ts +110 -0
  451. package/src/schema/canvas.gen.ts +176 -0
  452. package/src/schema/cloudwatch.gen.ts +423 -0
  453. package/src/schema/dashboard.gen.ts +206 -22
  454. package/src/schema/elasticsearch.gen.ts +508 -0
  455. package/src/schema/expr.gen.ts +618 -0
  456. package/src/schema/gauge.gen.ts +2 -1
  457. package/src/schema/geomap.gen.ts +112 -0
  458. package/src/schema/googlecloudmonitoring.gen.ts +330 -0
  459. package/src/schema/grafanapyroscope.gen.ts +66 -0
  460. package/src/schema/heatmap.gen.ts +2 -1
  461. package/src/schema/histogram.gen.ts +151 -0
  462. package/src/schema/index.ts +18 -0
  463. package/src/schema/logs.gen.ts +3 -1
  464. package/src/schema/loki.gen.ts +2 -1
  465. package/src/schema/nodegraph.gen.ts +58 -0
  466. package/src/schema/piechart.gen.ts +146 -0
  467. package/src/schema/prometheus.gen.ts +2 -1
  468. package/src/schema/stat.gen.ts +2 -1
  469. package/src/schema/statetimeline.gen.ts +143 -0
  470. package/src/schema/statushistory.gen.ts +132 -0
  471. package/src/schema/table.gen.ts +41 -4
  472. package/src/schema/tempo.gen.ts +2 -1
  473. package/src/schema/text.gen.ts +2 -1
  474. package/src/schema/timeseries.gen.ts +7 -2
  475. package/src/schema/trend.gen.ts +208 -0
  476. package/src/schema/xychart.gen.ts +167 -0
  477. package/src/schema-overlay.test.ts +282 -0
  478. package/src/schema-validate.ts +199 -57
  479. package/src/schema.test.ts +4 -2
  480. package/src/serializer.test.ts +13 -1
  481. package/src/serializer.ts +11 -3
  482. package/src/skill-defs.ts +34 -0
  483. package/src/skills/chant-grafana-alerting.md +49 -0
  484. package/src/skills/chant-grafana-operations.md +108 -0
  485. package/src/skills/chant-grafana-provisioning.md +3 -3
  486. package/src/skills/chant-grafana.md +15 -8
  487. package/src/spec/fetch-cli.ts +3 -3
  488. package/src/spec/fetch-units-cli.ts +37 -0
  489. package/src/spec/overlay/canvas.overlay.json +142 -0
  490. package/src/spec/overlay/dashboard.overlay.json +378 -0
  491. package/src/spec/overlay/expr.overlay.json +14 -0
  492. package/src/spec/overlay/geomap.overlay.json +35 -0
  493. package/src/spec/overlay/logs.overlay.json +14 -0
  494. package/src/spec/overlay/nodegraph.overlay.json +31 -0
  495. package/src/spec/overlay/piechart.overlay.json +17 -0
  496. package/src/spec/overlay/table.overlay.json +103 -0
  497. package/src/spec/overlay/timeseries.overlay.json +21 -0
  498. package/src/spec/overlay/trend.overlay.json +17 -0
  499. package/src/spec/overlay/xychart.overlay.json +16 -0
  500. package/src/spec/overlay.ts +105 -0
  501. package/src/spec/schemas/azuremonitor.jsonschema.json +679 -0
  502. package/src/spec/schemas/barchart.jsonschema.json +419 -0
  503. package/src/spec/schemas/bargauge.jsonschema.json +224 -0
  504. package/src/spec/schemas/bigquery.jsonschema.json +290 -0
  505. package/src/spec/schemas/canvas.jsonschema.json +356 -0
  506. package/src/spec/schemas/cloudwatch.jsonschema.json +721 -0
  507. package/src/spec/schemas/dashboardv2.jsonschema.json +3387 -0
  508. package/src/spec/schemas/elasticsearch.jsonschema.json +1695 -0
  509. package/src/spec/schemas/expr.jsonschema.json +987 -0
  510. package/src/spec/schemas/geomap.jsonschema.json +220 -0
  511. package/src/spec/schemas/googlecloudmonitoring.jsonschema.json +488 -0
  512. package/src/spec/schemas/grafanapyroscope.jsonschema.json +93 -0
  513. package/src/spec/schemas/histogram.jsonschema.json +308 -0
  514. package/src/spec/schemas/nodegraph.jsonschema.json +77 -0
  515. package/src/spec/schemas/piechart.jsonschema.json +275 -0
  516. package/src/spec/schemas/statetimeline.jsonschema.json +324 -0
  517. package/src/spec/schemas/statushistory.jsonschema.json +292 -0
  518. package/src/spec/schemas/trend.jsonschema.json +449 -0
  519. package/src/spec/schemas/xychart.jsonschema.json +428 -0
  520. package/src/spec/schemas.gen.ts +40 -0
  521. package/src/spec/schemas.ts +30 -16
  522. package/src/spec/units.gen.ts +281 -0
  523. package/src/spec/units.ts +77 -0
  524. package/src/transformations.test.ts +65 -0
  525. package/src/transformations.ts +574 -0
  526. package/src/util.ts +8 -0
  527. package/src/validate-alerting.test.ts +255 -0
  528. package/src/validate-alerting.ts +430 -0
  529. package/src/validate-output.ts +427 -104
  530. package/src/validate.ts +28 -0
  531. package/src/validation.ts +27 -0
  532. package/src/variables.ts +120 -8
package/src/build.test.ts CHANGED
@@ -1,23 +1,29 @@
1
1
  import { describe, expect, test } from "vitest";
2
- import { Datasource } from "./datasource";
3
- import { Dashboard } from "./dashboard";
2
+ import { Datasource, DatasourceProvisioning, ExternalDatasource } from "./datasource";
3
+ import { Dashboard, DashboardProvider } from "./dashboard";
4
+ import { Folder } from "./folder";
5
+ import { load } from "js-yaml";
4
6
  import { Row, StatPanel, TextPanel, TimeSeriesPanel, TablePanel, definePanel } from "./panels";
5
7
  import { PromQuery, TempoQuery, LokiQuery, defineQuery } from "./query";
6
8
  import {
9
+ AdhocVariable,
7
10
  CustomVariable,
8
11
  ConstantVariable,
9
12
  DatasourceVariable,
13
+ GroupByVariable,
10
14
  IntervalVariable,
11
15
  QueryVariable,
16
+ SwitchVariable,
12
17
  TextboxVariable,
13
18
  } from "./variables";
14
- import { panelsJson, renderDashboard, variableModel, dashboardJson, grafanaFiles, type PanelJson } from "./build";
19
+ import { panelsJson, renderDashboard, variableModel, dashboardJson, grafanaFiles, buildGrafana, customVariableOptions, type PanelJson } from "./build";
15
20
 
16
21
  /** The panels array, read as plain panels (the tests below build no rows unless they say so). */
17
22
  function panelsOnly(items: Parameters<typeof panelsJson>[0]): PanelJson[] {
18
23
  return panelsJson(items) as PanelJson[];
19
24
  }
20
25
  import { validateDashboardSchema } from "./schema-validate";
26
+ import { checkGrid } from "./validate-output";
21
27
 
22
28
  const prometheus = new Datasource({ name: "Prometheus", type: "prometheus" });
23
29
  const tempo = new Datasource({ name: "Tempo", type: "tempo" });
@@ -77,6 +83,138 @@ describe("layout", () => {
77
83
  expect((panels[1] as unknown as { panels: unknown[] }).panels).toEqual([]);
78
84
  });
79
85
 
86
+ test("a row with a y keeps that line, even over an empty band or on a line a panel takes (#2992)", () => {
87
+ const panels = panelsJson([
88
+ new StatPanel({ title: "a", gridPos: { x: 0, y: 0, w: 24, h: 4 } }),
89
+ new Row({ title: "late", gridPos: { y: 6 }, panels: [new StatPanel({ title: "b", gridPos: { x: 0, y: 7, w: 24, h: 4 } })] }),
90
+ new Row({ title: "auto", panels: [new StatPanel({ title: "c" })] }),
91
+ new Row({ title: "early", gridPos: { y: 8 } }),
92
+ ]);
93
+ expect(panels.map((p) => [p.title, p.gridPos])).toEqual([
94
+ ["a", { h: 4, w: 24, x: 0, y: 0 }],
95
+ ["late", { h: 1, w: 24, x: 0, y: 6 }],
96
+ ["b", { h: 4, w: 24, x: 0, y: 7 }],
97
+ // An auto-placed row skips the line the "early" row reserved.
98
+ ["auto", { h: 1, w: 24, x: 0, y: 11 }],
99
+ ["c", { h: 4, w: 6, x: 0, y: 12 }],
100
+ ["early", { h: 1, w: 24, x: 0, y: 8 }],
101
+ ]);
102
+ });
103
+
104
+ test("an auto-placed panel flows around an explicit one declared before it (#2941)", () => {
105
+ const panels = panelsJson([
106
+ new TimeSeriesPanel({ title: "a", gridPos: { x: 0, y: 0, w: 12 } }),
107
+ new TimeSeriesPanel({ title: "b", gridPos: { w: 12 } }),
108
+ ]);
109
+ expect(panels.map((p) => p.gridPos)).toEqual([
110
+ { h: 8, w: 12, x: 0, y: 0 },
111
+ { h: 8, w: 12, x: 12, y: 0 },
112
+ ]);
113
+ });
114
+
115
+ test("an explicit panel reserves its cells even when declared after auto-placed ones", () => {
116
+ const panels = panelsJson([
117
+ new StatPanel({ title: "s1" }),
118
+ new StatPanel({ title: "s2" }),
119
+ new StatPanel({ title: "s3" }),
120
+ new StatPanel({ title: "s4" }),
121
+ new StatPanel({ title: "pinned", gridPos: { x: 6, y: 0, w: 6, h: 4 } }),
122
+ new TextPanel({ title: "wide" }),
123
+ ]);
124
+ expect(panels.map((p) => [p.title, p.gridPos])).toEqual([
125
+ ["s1", { h: 4, w: 6, x: 0, y: 0 }],
126
+ ["s2", { h: 4, w: 6, x: 12, y: 0 }],
127
+ ["s3", { h: 4, w: 6, x: 18, y: 0 }],
128
+ ["s4", { h: 4, w: 6, x: 0, y: 4 }],
129
+ ["pinned", { h: 4, w: 6, x: 6, y: 0 }],
130
+ ["wide", { h: 3, w: 24, x: 0, y: 8 }],
131
+ ]);
132
+ });
133
+
134
+ test("a line blocked by an explicit panel is skipped", () => {
135
+ const panels = panelsJson([
136
+ new StatPanel({ title: "band", gridPos: { x: 0, y: 0, w: 24, h: 2 } }),
137
+ new StatPanel({ title: "hole", gridPos: { x: 0, y: 6, w: 6, h: 2 } }),
138
+ new StatPanel({ title: "s1" }),
139
+ new TextPanel({ title: "wide" }),
140
+ ]);
141
+ expect(panels.map((p) => [p.title, p.gridPos])).toEqual([
142
+ ["band", { h: 2, w: 24, x: 0, y: 0 }],
143
+ ["hole", { h: 2, w: 6, x: 0, y: 6 }],
144
+ ["s1", { h: 4, w: 6, x: 0, y: 2 }],
145
+ ["wide", { h: 3, w: 24, x: 0, y: 8 }],
146
+ ]);
147
+ });
148
+
149
+ test("a partial gridPos is honoured: x only keeps its column, y only its line", () => {
150
+ const panels = panelsJson([
151
+ new StatPanel({ title: "right", gridPos: { x: 18 } }),
152
+ new StatPanel({ title: "left", gridPos: { x: 0 } }),
153
+ new StatPanel({ title: "next" }),
154
+ new StatPanel({ title: "low", gridPos: { y: 20, w: 12 } }),
155
+ new StatPanel({ title: "low2", gridPos: { y: 20, w: 12 } }),
156
+ new StatPanel({ title: "low3", gridPos: { y: 20, w: 12 } }),
157
+ ]);
158
+ expect(panels.map((p) => [p.title, p.gridPos])).toEqual([
159
+ ["right", { h: 4, w: 6, x: 18, y: 0 }],
160
+ ["left", { h: 4, w: 6, x: 0, y: 4 }],
161
+ ["next", { h: 4, w: 6, x: 6, y: 4 }],
162
+ ["low", { h: 4, w: 12, x: 0, y: 20 }],
163
+ ["low2", { h: 4, w: 12, x: 12, y: 20 }],
164
+ ["low3", { h: 4, w: 12, x: 0, y: 24 }],
165
+ ]);
166
+ });
167
+
168
+ test("a full-width row header skips lines taken by explicit panels", () => {
169
+ const panels = panelsJson([
170
+ new TimeSeriesPanel({ title: "top" }),
171
+ new Row({
172
+ title: "open",
173
+ panels: [new StatPanel({ title: "pinned", gridPos: { x: 0, y: 8, w: 24, h: 2 } }), new StatPanel({ title: "a" })],
174
+ }),
175
+ new Row({ title: "next" }),
176
+ ]);
177
+ expect(panels.map((p) => [p.type, p.title, p.gridPos])).toEqual([
178
+ ["timeseries", "top", { h: 8, w: 12, x: 0, y: 0 }],
179
+ ["row", "open", { h: 1, w: 24, x: 0, y: 10 }],
180
+ ["stat", "pinned", { h: 2, w: 24, x: 0, y: 8 }],
181
+ ["stat", "a", { h: 4, w: 6, x: 0, y: 11 }],
182
+ ["row", "next", { h: 1, w: 24, x: 0, y: 15 }],
183
+ ]);
184
+ });
185
+
186
+ test("a collapsed row's panels flow around its own explicit panels and don't block the dashboard", () => {
187
+ const panels = panelsJson([
188
+ new Row({
189
+ title: "shut",
190
+ collapsed: true,
191
+ panels: [new StatPanel({ title: "pinned", gridPos: { x: 0, y: 1, w: 6, h: 4 } }), new StatPanel({ title: "a" })],
192
+ }),
193
+ new StatPanel({ title: "after" }),
194
+ ]);
195
+ const shut = panels[0] as unknown as { panels: PanelJson[] };
196
+ expect(shut.panels.map((p) => [p.title, p.gridPos])).toEqual([
197
+ ["pinned", { h: 4, w: 6, x: 0, y: 1 }],
198
+ ["a", { h: 4, w: 6, x: 6, y: 1 }],
199
+ ]);
200
+ expect(panels[1].gridPos).toEqual({ h: 4, w: 6, x: 0, y: 1 });
201
+ });
202
+
203
+ test("a mixed layout built by the dashboard passes GRAF105", () => {
204
+ const dash = new Dashboard({
205
+ title: "Mixed",
206
+ panels: [
207
+ new TimeSeriesPanel({ title: "a", gridPos: { x: 0, y: 0, w: 12 } }),
208
+ new TimeSeriesPanel({ title: "b", gridPos: { w: 12 } }),
209
+ new StatPanel({ title: "c", gridPos: { x: 6 } }),
210
+ new StatPanel({ title: "d", gridPos: { x: 12, y: 8, w: 12, h: 4 } }),
211
+ new StatPanel({ title: "e" }),
212
+ new Row({ title: "r", panels: [new StatPanel({ title: "f", gridPos: { x: 18, y: 12 } }), new StatPanel({ title: "g" })] }),
213
+ ],
214
+ });
215
+ expect(checkGrid({ dashboards: [{ json: JSON.parse(dashboardJson(dash)) }], datasources: [] })).toEqual([]);
216
+ });
217
+
80
218
  test("auto ids skip ids set explicitly", () => {
81
219
  const panels = panelsJson([new StatPanel(), new StatPanel({ id: 1 }), new StatPanel()]);
82
220
  expect(panels.map((p) => p.id)).toEqual([2, 1, 3]);
@@ -102,6 +240,17 @@ describe("datasources and targets", () => {
102
240
  ]);
103
241
  });
104
242
 
243
+ test("a panel declared Mixed stays Mixed, and a query naming no datasource is not sent to Mixed (#2992)", () => {
244
+ const mixed = { type: "datasource", uid: "-- Mixed --" };
245
+ const [bare, panel] = panelsOnly([
246
+ new TextPanel({ datasource: mixed }),
247
+ new StatPanel({ datasource: mixed, targets: [new PromQuery({ expr: "up", datasource: prometheus }), new PromQuery({ expr: "down" })] }),
248
+ ]);
249
+ expect(bare.datasource).toEqual(mixed);
250
+ expect(panel.datasource).toEqual(mixed);
251
+ expect(panel.targets!.map((t) => (t as { datasource?: unknown }).datasource)).toEqual([{ type: "prometheus", uid: "prometheus" }, undefined]);
252
+ });
253
+
105
254
  test("a panel takes its queries' shared datasource, and a row passes its own down", () => {
106
255
  const [shared] = panelsOnly([new StatPanel({ targets: [new PromQuery({ expr: "up", datasource: prometheus })] })]);
107
256
  expect(shared.datasource).toEqual({ type: "prometheus", uid: "prometheus" });
@@ -158,6 +307,98 @@ describe("variables", () => {
158
307
  expect(variableModel(new TextboxVariable({ name: "q" }))).toMatchObject({ type: "textbox", query: "" });
159
308
  });
160
309
 
310
+ test("an object query is written as it is, its text as the definition", () => {
311
+ const query = { qryType: 1 as const, query: "label_values(up, job)", refId: "PrometheusVariableQueryEditor-VariableQuery" };
312
+ expect(variableModel(new QueryVariable({ name: "job", datasource: prometheus, query }))).toMatchObject({ query, definition: "label_values(up, job)" });
313
+ expect(variableModel(new QueryVariable({ name: "ns", datasource: prometheus, query: { namespace: "AWS/EC2" }, definition: "Namespaces" }))).toMatchObject({
314
+ query: { namespace: "AWS/EC2" },
315
+ definition: "Namespaces",
316
+ });
317
+ });
318
+
319
+ test("ad hoc, group by and switch variables as Grafana writes them", () => {
320
+ const ds = new DatasourceVariable({ name: "ds", pluginType: "prometheus" });
321
+ expect(variableModel(new AdhocVariable({ name: "f", datasource: ds, filters: [{ key: "ns", operator: "=", value: "shop" }] }))).toEqual({
322
+ type: "adhoc",
323
+ name: "f",
324
+ datasource: { type: "prometheus", uid: "${ds}" },
325
+ filters: [{ key: "ns", operator: "=", value: "shop" }],
326
+ baseFilters: [],
327
+ });
328
+ expect(variableModel(new GroupByVariable({ name: "by", datasource: prometheus, options: ["pod", { text: "Node", value: "node" }], defaultValue: ["pod"] }))).toEqual({
329
+ type: "groupby",
330
+ name: "by",
331
+ datasource: { type: "prometheus", uid: prometheus.uid },
332
+ options: [
333
+ { text: "pod", value: "pod" },
334
+ { text: "Node", value: "node" },
335
+ ],
336
+ current: { text: ["pod"], value: ["pod"] },
337
+ defaultValue: { text: ["pod"], value: ["pod"] },
338
+ });
339
+ expect(variableModel(new SwitchVariable({ name: "on" }))).toEqual({
340
+ type: "switch",
341
+ name: "on",
342
+ current: { text: "false", value: "false" },
343
+ options: [
344
+ { text: "true", value: "true" },
345
+ { text: "false", value: "false" },
346
+ ],
347
+ });
348
+ expect(variableModel(new SwitchVariable({ name: "q", enabled: true, enabledValue: "0.99", disabledValue: "0.5" }))).toMatchObject({
349
+ current: { text: "0.99", value: "0.99" },
350
+ options: [
351
+ { text: "0.99", value: "0.99" },
352
+ { text: "0.5", value: "0.5" },
353
+ ],
354
+ });
355
+ });
356
+
357
+ test("a custom value in Grafana's `text : value` syntax shows the text and sets the value (#2944)", () => {
358
+ const v = variableModel(new CustomVariable({ name: "env", values: ["Production : prod", "Staging : stg", "dev"] }));
359
+ expect(v).toMatchObject({
360
+ query: "Production : prod,Staging : stg,dev",
361
+ current: { text: "Production", value: "prod" },
362
+ options: [
363
+ { selected: true, text: "Production", value: "prod" },
364
+ { selected: false, text: "Staging", value: "stg" },
365
+ { selected: false, text: "dev", value: "dev" },
366
+ ],
367
+ });
368
+ });
369
+
370
+ test("a custom value's selected option follows current by value, and multi-value current selects several", () => {
371
+ const v = variableModel(
372
+ new CustomVariable({ name: "env", multi: true, values: ["Production : prod", "Staging : stg"], current: { text: ["Staging"], value: ["stg"] } }),
373
+ );
374
+ expect((v as { options: Array<{ selected: boolean }> }).options.map((o) => o.selected)).toEqual([false, true]);
375
+ });
376
+
377
+ test("a comma already escaped as \\, is not escaped again (#2944)", () => {
378
+ const v = variableModel(new CustomVariable({ name: "pair", values: ["a\\,b", "c,d", "Label, with comma : x\\,y"] }));
379
+ expect(v).toMatchObject({
380
+ query: "a\\,b,c\\,d,Label\\, with comma : x\\,y",
381
+ options: [
382
+ { text: "a,b", value: "a,b" },
383
+ { text: "c,d", value: "c,d" },
384
+ { text: "Label, with comma", value: "x,y" },
385
+ ],
386
+ });
387
+ });
388
+
389
+ test("customVariableOptions parses a query the way Grafana does", () => {
390
+ expect(customVariableOptions("a : 1, b,c\\,d , ,x:y, k : v : w")).toEqual([
391
+ { text: "a", value: "1" },
392
+ { text: "b", value: "b" },
393
+ { text: "c,d", value: "c,d" },
394
+ { text: "", value: "" },
395
+ // No spaces around the colon: one plain value.
396
+ { text: "x:y", value: "x:y" },
397
+ // Grafana's first group is greedy: the last ` : ` splits.
398
+ { text: "k : v", value: "w" },
399
+ ]);
400
+ });
401
+
161
402
  test("a dashboard with every variable kind matches the dashboard schema", () => {
162
403
  const dash = new Dashboard({
163
404
  title: "Vars",
@@ -168,6 +409,10 @@ describe("variables", () => {
168
409
  new DatasourceVariable({ name: "ds", pluginType: "prometheus" }),
169
410
  new ConstantVariable({ name: "cluster", value: "x" }),
170
411
  new TextboxVariable({ name: "q", value: "y" }),
412
+ new QueryVariable({ name: "pods", datasource: prometheus, query: { qryType: 1, query: "label_values(kube_pod_info, pod)" } }),
413
+ new AdhocVariable({ name: "f", datasource: prometheus, baseFilters: [{ key: "cluster", operator: "=", value: "prod" }], defaultKeys: [{ text: "pod" }] }),
414
+ new GroupByVariable({ name: "by", datasource: prometheus, options: ["pod"] }),
415
+ new SwitchVariable({ name: "on", enabled: true }),
171
416
  ],
172
417
  });
173
418
  expect(validateDashboardSchema(renderDashboard(dash) as unknown as Record<string, unknown>)).toEqual([]);
@@ -176,17 +421,17 @@ describe("variables", () => {
176
421
 
177
422
  describe("extension points", () => {
178
423
  test("definePanel and defineQuery produce classes that render and lay out like built-ins", () => {
179
- const PieChartPanel = definePanel<{ pieType?: "pie" | "donut" }>()({ type: "piechart", className: "PieChartPanel", defaultSize: { w: 8, h: 8 } });
180
- const ElasticQuery = defineQuery<{ query: string; refId?: string }>()({ datasourceType: "elasticsearch", className: "ElasticQuery" });
181
- const es = new Datasource({ name: "Logs ES", type: "elasticsearch" });
424
+ const ClockPanel = definePanel<{ mode?: "time" | "countdown" }>()({ type: "grafana-clock-panel", className: "ClockPanel", defaultSize: { w: 8, h: 8 } });
425
+ const OpenSearchQuery = defineQuery<{ query: string; refId?: string }>()({ datasourceType: "grafana-opensearch-datasource", className: "OpenSearchQuery" });
426
+ const os = new Datasource({ name: "Logs OS", type: "grafana-opensearch-datasource" });
182
427
  const json = renderDashboard(
183
- new Dashboard({ title: "Custom", panels: [new PieChartPanel({ options: { pieType: "donut" }, datasource: es, targets: [new ElasticQuery({ query: "*" })] })] }),
428
+ new Dashboard({ title: "Custom", panels: [new ClockPanel({ options: { mode: "countdown" }, datasource: os, targets: [new OpenSearchQuery({ query: "*" })] })] }),
184
429
  );
185
430
  expect(json.panels![0]).toMatchObject({
186
- type: "piechart",
431
+ type: "grafana-clock-panel",
187
432
  gridPos: { w: 8, h: 8, x: 0, y: 0 },
188
- options: { pieType: "donut" },
189
- datasource: { type: "elasticsearch", uid: "logs-es" },
433
+ options: { mode: "countdown" },
434
+ datasource: { type: "grafana-opensearch-datasource", uid: "logs-os" },
190
435
  targets: [{ refId: "A", query: "*" }],
191
436
  });
192
437
  expect(validateDashboardSchema(json as unknown as Record<string, unknown>)).toEqual([]);
@@ -208,3 +453,99 @@ describe("extension points", () => {
208
453
  ]);
209
454
  });
210
455
  });
456
+
457
+ describe("folders (#2944)", () => {
458
+ test("a nested folder is written as nested directories under dashboards/", () => {
459
+ const built = buildGrafana([new Dashboard({ title: "Pods", uid: "pods", folder: "Platform/Kubernetes" })]);
460
+ expect(built.dashboards[0].file).toBe("dashboards/Platform/Kubernetes/pods.json");
461
+ expect(built.index.dashboards[0].folder).toBe("Platform/Kubernetes");
462
+ });
463
+
464
+ test("blank levels, dot-led levels and backslashes can't leave dashboards/", () => {
465
+ const file = (folder: string) => buildGrafana([new Dashboard({ title: "D", uid: "d", folder })]).dashboards[0].file;
466
+ expect(file("/Platform//Kubernetes/")).toBe("dashboards/Platform/Kubernetes/d.json");
467
+ expect(file("../../etc")).toBe("dashboards/etc/d.json");
468
+ expect(file("a\\b")).toBe("dashboards/a-b/d.json");
469
+ expect(file(" / ")).toBe("dashboards/d.json");
470
+ });
471
+ });
472
+
473
+ describe("folder uids and nesting (#2953)", () => {
474
+ const platform = new Folder({ title: "Platform", uid: "plat" });
475
+ const k8s = new Folder({ title: "Kubernetes", parent: platform });
476
+
477
+ test("a Folder is written where its path is, and the index lists every level with its uid and parent", () => {
478
+ const built = buildGrafana(
479
+ new Map<string, never>([
480
+ ["pods", new Dashboard({ title: "Pods", uid: "pods", folder: k8s }) as never],
481
+ ["nodes", new Dashboard({ title: "Nodes", uid: "nodes", folder: "Platform/Kubernetes/Nodes" }) as never],
482
+ ["spare", new Folder({ title: "Spare" }) as never],
483
+ ]),
484
+ );
485
+ expect(built.dashboards.map((d) => [d.file, d.folder, d.folderUid])).toEqual([
486
+ ["dashboards/Platform/Kubernetes/pods.json", "Platform/Kubernetes", "platform-kubernetes"],
487
+ ["dashboards/Platform/Kubernetes/Nodes/nodes.json", "Platform/Kubernetes/Nodes", "platform-kubernetes-nodes"],
488
+ ]);
489
+ expect(built.index.folders).toEqual([
490
+ { uid: "plat", title: "Platform", path: "Platform" },
491
+ { uid: "platform-kubernetes", title: "Kubernetes", parentUid: "plat", path: "Platform/Kubernetes" },
492
+ { uid: "platform-kubernetes-nodes", title: "Nodes", parentUid: "platform-kubernetes", path: "Platform/Kubernetes/Nodes" },
493
+ { uid: "spare", title: "Spare", path: "Spare" },
494
+ ]);
495
+ });
496
+
497
+ test("a path and a Folder at the same path are one folder; the Folder's uid wins", () => {
498
+ const built = buildGrafana([new Dashboard({ title: "A", uid: "a", folder: "Platform" }), new Dashboard({ title: "B", uid: "b", folder: platform })]);
499
+ expect(built.dashboards.map((d) => d.folderUid)).toEqual(["plat", "plat"]);
500
+ expect(built.folders).toEqual([{ uid: "plat", title: "Platform", path: "Platform" }]);
501
+ });
502
+
503
+ test("a Folder title is one level, and two uids at one path are refused", () => {
504
+ expect(() => new Folder({ title: "Platform/Kubernetes" })).toThrow(/not one folder level/);
505
+ expect(() => buildGrafana([new Folder({ title: "X", uid: "one" }), new Folder({ title: "X", uid: "two" })])).toThrow(/declared with the uids "one" and "two"/);
506
+ });
507
+
508
+ test("a root-level Folder on a DashboardProvider is written as folder and folderUid; a nested one is refused", () => {
509
+ const built = buildGrafana([new DashboardProvider({ name: "ops", folder: platform, path: "/d" })]);
510
+ expect(built.providers[0]).toMatchObject({ folder: "Platform", folderUid: "plat", options: { foldersFromFilesStructure: false } });
511
+ expect(() => new DashboardProvider({ name: "ops", folder: k8s })).toThrow(/nested; Grafana creates a provider's folder at the root/);
512
+ });
513
+ });
514
+
515
+ describe("annotations (#2953)", () => {
516
+ test("an annotation is written with its datasource resolved and Grafana's defaults filled in", () => {
517
+ const json = renderDashboard(
518
+ new Dashboard({
519
+ title: "D",
520
+ annotations: [
521
+ { name: "Deploys", datasource: prometheus, target: new PromQuery({ expr: "changes(up[5m]) > 0" }), titleFormat: "deploy" },
522
+ { name: "Incidents", datasource: { type: "grafana", uid: "-- Grafana --" }, enable: false, iconColor: "blue", target: { type: "tags", tags: ["incident"], limit: 100, matchAny: false } },
523
+ ],
524
+ }),
525
+ );
526
+ expect(json.annotations).toEqual({
527
+ list: [
528
+ { datasource: { type: "prometheus", uid: "prometheus" }, enable: true, iconColor: "red", name: "Deploys", titleFormat: "deploy", target: expect.objectContaining({ refId: "Anno", expr: "changes(up[5m]) > 0" }) },
529
+ { datasource: { type: "grafana", uid: "-- Grafana --" }, enable: false, iconColor: "blue", name: "Incidents", target: { type: "tags", tags: ["incident"], limit: 100, matchAny: false } },
530
+ ],
531
+ });
532
+ expect(validateDashboardSchema(json as never).filter((p) => p.severity === "error")).toEqual([]);
533
+ expect(renderDashboard(new Dashboard({ title: "E" })).annotations).toEqual({ list: [] });
534
+ });
535
+ });
536
+
537
+ describe("datasource prune (#2953)", () => {
538
+ const files = (entities: unknown[]) => load(buildGrafana(entities as never).files["provisioning/datasources/chant.yaml"] ?? "null") as Record<string, unknown> | null;
539
+
540
+ test("the datasource file prunes by default, so a removed Datasource leaves Grafana", () => {
541
+ expect(files([prometheus])).toMatchObject({ apiVersion: 1, prune: true });
542
+ });
543
+
544
+ test("DatasourceProvisioning turns pruning off and lists datasources to delete", () => {
545
+ const out = files([prometheus, new DatasourceProvisioning({ prune: false, deleteDatasources: [{ name: "Old" }, { name: "Other", orgId: 2 }] })]);
546
+ expect(out).toEqual({ apiVersion: 1, deleteDatasources: [{ name: "Old" }, { name: "Other", orgId: 2 }], datasources: [expect.objectContaining({ name: "Prometheus" })] });
547
+ expect(files([new DatasourceProvisioning({ deleteDatasources: [{ name: "Old" }] })])).toEqual({ apiVersion: 1, prune: true, deleteDatasources: [{ name: "Old" }], datasources: [] });
548
+ expect(files([new ExternalDatasource({ type: "prometheus", uid: "p" })])).toBeNull();
549
+ expect(() => buildGrafana([new DatasourceProvisioning({}), new DatasourceProvisioning({})])).toThrow(/at most one DatasourceProvisioning/);
550
+ });
551
+ });