module.tsx 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. import React from 'react';
  2. import { PanelPlugin } from '@grafana/data';
  3. import { config, DataSourcePicker } from '@grafana/runtime';
  4. import { TagsInput } from '@grafana/ui';
  5. import { FolderPicker } from 'app/core/components/Select/FolderPicker';
  6. import {
  7. ALL_FOLDER,
  8. GENERAL_FOLDER,
  9. ReadonlyFolderPicker,
  10. } from 'app/core/components/Select/ReadonlyFolderPicker/ReadonlyFolderPicker';
  11. import { PermissionLevelString } from 'app/types';
  12. import { AlertList } from './AlertList';
  13. import { alertListPanelMigrationHandler } from './AlertListMigrationHandler';
  14. import { GroupBy } from './GroupByWithLoading';
  15. import { UnifiedAlertList } from './UnifiedAlertList';
  16. import { AlertListSuggestionsSupplier } from './suggestions';
  17. import { AlertListOptions, GroupMode, ShowOption, SortOrder, UnifiedAlertListOptions } from './types';
  18. function showIfCurrentState(options: AlertListOptions) {
  19. return options.showOptions === ShowOption.Current;
  20. }
  21. const alertList = new PanelPlugin<AlertListOptions>(AlertList)
  22. .setPanelOptions((builder) => {
  23. builder
  24. .addSelect({
  25. name: 'Show',
  26. path: 'showOptions',
  27. settings: {
  28. options: [
  29. { label: 'Current state', value: ShowOption.Current },
  30. { label: 'Recent state changes', value: ShowOption.RecentChanges },
  31. ],
  32. },
  33. defaultValue: ShowOption.Current,
  34. category: ['Options'],
  35. })
  36. .addNumberInput({
  37. name: 'Max items',
  38. path: 'maxItems',
  39. defaultValue: 10,
  40. category: ['Options'],
  41. })
  42. .addSelect({
  43. name: 'Sort order',
  44. path: 'sortOrder',
  45. settings: {
  46. options: [
  47. { label: 'Alphabetical (asc)', value: SortOrder.AlphaAsc },
  48. { label: 'Alphabetical (desc)', value: SortOrder.AlphaDesc },
  49. { label: 'Importance', value: SortOrder.Importance },
  50. { label: 'Time (asc)', value: SortOrder.TimeAsc },
  51. { label: 'Time (desc)', value: SortOrder.TimeDesc },
  52. ],
  53. },
  54. defaultValue: SortOrder.AlphaAsc,
  55. category: ['Options'],
  56. })
  57. .addBooleanSwitch({
  58. path: 'dashboardAlerts',
  59. name: 'Alerts from this dashboard',
  60. defaultValue: false,
  61. category: ['Options'],
  62. })
  63. .addTextInput({
  64. path: 'alertName',
  65. name: 'Alert name',
  66. defaultValue: '',
  67. category: ['Filter'],
  68. showIf: showIfCurrentState,
  69. })
  70. .addTextInput({
  71. path: 'dashboardTitle',
  72. name: 'Dashboard title',
  73. defaultValue: '',
  74. category: ['Filter'],
  75. showIf: showIfCurrentState,
  76. })
  77. .addCustomEditor({
  78. path: 'folderId',
  79. name: 'Folder',
  80. id: 'folderId',
  81. defaultValue: null,
  82. editor: function RenderFolderPicker({ value, onChange }) {
  83. return (
  84. <ReadonlyFolderPicker
  85. initialFolderId={value}
  86. onChange={(folder) => onChange(folder?.id)}
  87. extraFolders={[ALL_FOLDER, GENERAL_FOLDER]}
  88. />
  89. );
  90. },
  91. category: ['Filter'],
  92. showIf: showIfCurrentState,
  93. })
  94. .addCustomEditor({
  95. id: 'tags',
  96. path: 'tags',
  97. name: 'Tags',
  98. description: '',
  99. defaultValue: [],
  100. editor(props) {
  101. return <TagsInput tags={props.value} onChange={props.onChange} />;
  102. },
  103. category: ['Filter'],
  104. showIf: showIfCurrentState,
  105. })
  106. .addBooleanSwitch({
  107. path: 'stateFilter.ok',
  108. name: 'Ok',
  109. defaultValue: false,
  110. category: ['State filter'],
  111. showIf: showIfCurrentState,
  112. })
  113. .addBooleanSwitch({
  114. path: 'stateFilter.paused',
  115. name: 'Paused',
  116. defaultValue: false,
  117. category: ['State filter'],
  118. showIf: showIfCurrentState,
  119. })
  120. .addBooleanSwitch({
  121. path: 'stateFilter.no_data',
  122. name: 'No data',
  123. defaultValue: false,
  124. category: ['State filter'],
  125. showIf: showIfCurrentState,
  126. })
  127. .addBooleanSwitch({
  128. path: 'stateFilter.execution_error',
  129. name: 'Execution error',
  130. defaultValue: false,
  131. category: ['State filter'],
  132. showIf: showIfCurrentState,
  133. })
  134. .addBooleanSwitch({
  135. path: 'stateFilter.alerting',
  136. name: 'Alerting',
  137. defaultValue: false,
  138. category: ['State filter'],
  139. showIf: showIfCurrentState,
  140. })
  141. .addBooleanSwitch({
  142. path: 'stateFilter.pending',
  143. name: 'Pending',
  144. defaultValue: false,
  145. category: ['State filter'],
  146. showIf: showIfCurrentState,
  147. });
  148. })
  149. .setMigrationHandler(alertListPanelMigrationHandler)
  150. .setSuggestionsSupplier(new AlertListSuggestionsSupplier());
  151. const unifiedAlertList = new PanelPlugin<UnifiedAlertListOptions>(UnifiedAlertList).setPanelOptions((builder) => {
  152. builder
  153. .addRadio({
  154. path: 'groupMode',
  155. name: 'Group mode',
  156. description: 'How alert instances should be grouped',
  157. defaultValue: GroupMode.Default,
  158. settings: {
  159. options: [
  160. { value: GroupMode.Default, label: 'Default grouping' },
  161. { value: GroupMode.Custom, label: 'Custom grouping' },
  162. ],
  163. },
  164. category: ['Options'],
  165. })
  166. .addCustomEditor({
  167. path: 'groupBy',
  168. name: 'Group by',
  169. description: 'Filter alerts using label querying',
  170. id: 'groupBy',
  171. defaultValue: [],
  172. showIf: (options) => options.groupMode === GroupMode.Custom,
  173. category: ['Options'],
  174. editor: (props) => {
  175. return (
  176. <GroupBy
  177. id={props.id ?? 'groupBy'}
  178. defaultValue={props.value.map((value: string) => ({ label: value, value }))}
  179. onChange={props.onChange}
  180. />
  181. );
  182. },
  183. })
  184. .addNumberInput({
  185. name: 'Max items',
  186. path: 'maxItems',
  187. description: 'Maximum alerts to display',
  188. defaultValue: 20,
  189. category: ['Options'],
  190. })
  191. .addSelect({
  192. name: 'Sort order',
  193. path: 'sortOrder',
  194. description: 'Sort order of alerts and alert instances',
  195. settings: {
  196. options: [
  197. { label: 'Alphabetical (asc)', value: SortOrder.AlphaAsc },
  198. { label: 'Alphabetical (desc)', value: SortOrder.AlphaDesc },
  199. { label: 'Importance', value: SortOrder.Importance },
  200. { label: 'Time (asc)', value: SortOrder.TimeAsc },
  201. { label: 'Time (desc)', value: SortOrder.TimeDesc },
  202. ],
  203. },
  204. defaultValue: SortOrder.AlphaAsc,
  205. category: ['Options'],
  206. })
  207. .addBooleanSwitch({
  208. path: 'dashboardAlerts',
  209. name: 'Alerts from this dashboard',
  210. description: 'Show alerts from this dashboard',
  211. defaultValue: false,
  212. category: ['Options'],
  213. })
  214. .addTextInput({
  215. path: 'alertName',
  216. name: 'Alert name',
  217. description: 'Filter for alerts containing this text',
  218. defaultValue: '',
  219. category: ['Filter'],
  220. })
  221. .addTextInput({
  222. path: 'alertInstanceLabelFilter',
  223. name: 'Alert instance label',
  224. description: 'Filter alert instances using label querying, ex: {severity="critical", instance=~"cluster-us-.+"}',
  225. defaultValue: '',
  226. category: ['Filter'],
  227. })
  228. .addCustomEditor({
  229. path: 'folder',
  230. name: 'Folder',
  231. description: 'Filter for alerts in the selected folder',
  232. id: 'folder',
  233. defaultValue: null,
  234. editor: function RenderFolderPicker(props) {
  235. return (
  236. <FolderPicker
  237. enableReset={true}
  238. showRoot={false}
  239. allowEmpty={true}
  240. initialTitle={props.value?.title}
  241. initialFolderId={props.value?.id}
  242. permissionLevel={PermissionLevelString.View}
  243. onClear={() => props.onChange('')}
  244. {...props}
  245. />
  246. );
  247. },
  248. category: ['Filter'],
  249. })
  250. .addCustomEditor({
  251. path: 'datasource',
  252. name: 'Datasource',
  253. description: 'Filter alerts from selected datasource',
  254. id: 'datasource',
  255. defaultValue: null,
  256. editor: function RenderDatasourcePicker(props) {
  257. return (
  258. <DataSourcePicker
  259. {...props}
  260. type={['prometheus', 'loki', 'grafana']}
  261. noDefault
  262. current={props.value}
  263. onChange={(ds) => props.onChange(ds.name)}
  264. onClear={() => props.onChange('')}
  265. />
  266. );
  267. },
  268. category: ['Filter'],
  269. })
  270. .addBooleanSwitch({
  271. path: 'stateFilter.firing',
  272. name: 'Alerting / Firing',
  273. defaultValue: true,
  274. category: ['Alert state filter'],
  275. })
  276. .addBooleanSwitch({
  277. path: 'stateFilter.pending',
  278. name: 'Pending',
  279. defaultValue: true,
  280. category: ['Alert state filter'],
  281. })
  282. .addBooleanSwitch({
  283. path: 'stateFilter.noData',
  284. name: 'No Data',
  285. defaultValue: false,
  286. category: ['Alert state filter'],
  287. })
  288. .addBooleanSwitch({
  289. path: 'stateFilter.normal',
  290. name: 'Normal',
  291. defaultValue: false,
  292. category: ['Alert state filter'],
  293. })
  294. .addBooleanSwitch({
  295. path: 'stateFilter.error',
  296. name: 'Error',
  297. defaultValue: true,
  298. category: ['Alert state filter'],
  299. });
  300. });
  301. export const plugin = config.unifiedAlertingEnabled ? unifiedAlertList : alertList;