| 
									
										
										
										
											2021-05-18 22:16:26 +08:00
										 |  |  | import { css } from '@emotion/css'; | 
					
						
							| 
									
										
										
										
											2022-12-22 23:28:17 +08:00
										 |  |  | import { cloneDeep } from 'lodash'; | 
					
						
							| 
									
										
										
										
											2023-03-14 22:38:21 +08:00
										 |  |  | import React, { ChangeEvent, useState } from 'react'; | 
					
						
							| 
									
										
										
										
											2022-04-22 21:33:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-18 22:16:26 +08:00
										 |  |  | import { | 
					
						
							| 
									
										
										
										
											2021-11-12 19:49:06 +08:00
										 |  |  |   CoreApp, | 
					
						
							| 
									
										
										
										
											2021-05-18 22:16:26 +08:00
										 |  |  |   DataQuery, | 
					
						
							| 
									
										
										
										
											2023-04-27 22:38:22 +08:00
										 |  |  |   DataSourceApi, | 
					
						
							| 
									
										
										
										
											2021-05-18 22:16:26 +08:00
										 |  |  |   DataSourceInstanceSettings, | 
					
						
							| 
									
										
										
										
											2021-09-15 23:35:12 +08:00
										 |  |  |   getDefaultRelativeTimeRange, | 
					
						
							| 
									
										
										
										
											2021-05-18 22:16:26 +08:00
										 |  |  |   GrafanaTheme2, | 
					
						
							| 
									
										
										
										
											2021-10-12 18:49:30 +08:00
										 |  |  |   LoadingState, | 
					
						
							| 
									
										
										
										
											2021-05-18 22:16:26 +08:00
										 |  |  |   PanelData, | 
					
						
							|  |  |  |   RelativeTimeRange, | 
					
						
							| 
									
										
										
										
											2021-09-15 23:35:12 +08:00
										 |  |  |   ThresholdsConfig, | 
					
						
							| 
									
										
										
										
											2021-05-18 22:16:26 +08:00
										 |  |  | } from '@grafana/data'; | 
					
						
							| 
									
										
										
										
											2022-10-24 23:12:36 +08:00
										 |  |  | import { Stack } from '@grafana/experimental'; | 
					
						
							| 
									
										
										
										
											2023-01-24 16:16:21 +08:00
										 |  |  | import { | 
					
						
							|  |  |  |   GraphTresholdsStyleMode, | 
					
						
							|  |  |  |   Icon, | 
					
						
							|  |  |  |   InlineFormLabel, | 
					
						
							|  |  |  |   Input, | 
					
						
							|  |  |  |   RelativeTimeRangePicker, | 
					
						
							|  |  |  |   Tooltip, | 
					
						
							|  |  |  |   useStyles2, | 
					
						
							|  |  |  | } from '@grafana/ui'; | 
					
						
							| 
									
										
										
										
											2022-04-22 21:33:13 +08:00
										 |  |  | import { QueryEditorRow } from 'app/features/query/components/QueryEditorRow'; | 
					
						
							|  |  |  | import { AlertQuery } from 'app/types/unified-alerting-dto'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-05 20:35:15 +08:00
										 |  |  | import { AlertConditionIndicator } from '../expressions/AlertConditionIndicator'; | 
					
						
							| 
									
										
										
										
											2022-04-22 21:33:13 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import { VizWrapper } from './VizWrapper'; | 
					
						
							| 
									
										
										
										
											2021-05-18 22:16:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-24 16:16:21 +08:00
										 |  |  | export const DEFAULT_MAX_DATA_POINTS = 43200; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export interface AlertQueryOptions { | 
					
						
							|  |  |  |   maxDataPoints?: number | undefined; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-18 22:16:26 +08:00
										 |  |  | interface Props { | 
					
						
							|  |  |  |   data: PanelData; | 
					
						
							| 
									
										
										
										
											2022-10-05 20:35:15 +08:00
										 |  |  |   error?: Error; | 
					
						
							| 
									
										
										
										
											2021-05-27 18:29:10 +08:00
										 |  |  |   query: AlertQuery; | 
					
						
							|  |  |  |   queries: AlertQuery[]; | 
					
						
							| 
									
										
										
										
											2021-05-18 22:16:26 +08:00
										 |  |  |   dsSettings: DataSourceInstanceSettings; | 
					
						
							|  |  |  |   onChangeDataSource: (settings: DataSourceInstanceSettings, index: number) => void; | 
					
						
							|  |  |  |   onChangeQuery: (query: DataQuery, index: number) => void; | 
					
						
							|  |  |  |   onChangeTimeRange?: (timeRange: RelativeTimeRange, index: number) => void; | 
					
						
							|  |  |  |   onRemoveQuery: (query: DataQuery) => void; | 
					
						
							| 
									
										
										
										
											2021-05-27 18:29:10 +08:00
										 |  |  |   onDuplicateQuery: (query: AlertQuery) => void; | 
					
						
							| 
									
										
										
										
											2021-05-18 22:16:26 +08:00
										 |  |  |   onRunQueries: () => void; | 
					
						
							|  |  |  |   index: number; | 
					
						
							| 
									
										
										
										
											2021-09-15 23:35:12 +08:00
										 |  |  |   thresholds: ThresholdsConfig; | 
					
						
							| 
									
										
										
										
											2022-12-22 23:28:17 +08:00
										 |  |  |   thresholdsType?: GraphTresholdsStyleMode; | 
					
						
							| 
									
										
										
										
											2022-12-21 23:18:35 +08:00
										 |  |  |   onChangeThreshold?: (thresholds: ThresholdsConfig, index: number) => void; | 
					
						
							| 
									
										
										
										
											2022-10-05 20:35:15 +08:00
										 |  |  |   condition: string | null; | 
					
						
							|  |  |  |   onSetCondition: (refId: string) => void; | 
					
						
							| 
									
										
										
										
											2023-01-24 16:16:21 +08:00
										 |  |  |   onChangeQueryOptions: (options: AlertQueryOptions, index: number) => void; | 
					
						
							| 
									
										
										
										
											2021-05-18 22:16:26 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-14 22:38:21 +08:00
										 |  |  | export const QueryWrapper = ({ | 
					
						
							| 
									
										
										
										
											2021-05-18 22:16:26 +08:00
										 |  |  |   data, | 
					
						
							| 
									
										
										
										
											2022-10-05 20:35:15 +08:00
										 |  |  |   error, | 
					
						
							| 
									
										
										
										
											2021-05-18 22:16:26 +08:00
										 |  |  |   dsSettings, | 
					
						
							|  |  |  |   index, | 
					
						
							|  |  |  |   onChangeDataSource, | 
					
						
							|  |  |  |   onChangeQuery, | 
					
						
							|  |  |  |   onChangeTimeRange, | 
					
						
							|  |  |  |   onRunQueries, | 
					
						
							|  |  |  |   onRemoveQuery, | 
					
						
							|  |  |  |   onDuplicateQuery, | 
					
						
							|  |  |  |   query, | 
					
						
							|  |  |  |   queries, | 
					
						
							| 
									
										
										
										
											2021-09-15 23:35:12 +08:00
										 |  |  |   thresholds, | 
					
						
							| 
									
										
										
										
											2022-12-22 23:28:17 +08:00
										 |  |  |   thresholdsType, | 
					
						
							| 
									
										
										
										
											2021-09-15 23:35:12 +08:00
										 |  |  |   onChangeThreshold, | 
					
						
							| 
									
										
										
										
											2022-10-05 20:35:15 +08:00
										 |  |  |   condition, | 
					
						
							|  |  |  |   onSetCondition, | 
					
						
							| 
									
										
										
										
											2023-01-24 16:16:21 +08:00
										 |  |  |   onChangeQueryOptions, | 
					
						
							| 
									
										
										
										
											2023-03-14 22:38:21 +08:00
										 |  |  | }: Props) => { | 
					
						
							| 
									
										
										
										
											2021-05-18 22:16:26 +08:00
										 |  |  |   const styles = useStyles2(getStyles); | 
					
						
							| 
									
										
										
										
											2023-04-27 22:38:22 +08:00
										 |  |  |   const [dsInstance, setDsInstance] = useState<DataSourceApi>(); | 
					
						
							|  |  |  |   const defaults = dsInstance?.getDefaultQuery ? dsInstance.getDefaultQuery(CoreApp.UnifiedAlerting) : {}; | 
					
						
							| 
									
										
										
										
											2021-05-18 22:16:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-12 21:32:07 +08:00
										 |  |  |   function SelectingDataSourceTooltip() { | 
					
						
							|  |  |  |     const styles = useStyles2(getStyles); | 
					
						
							| 
									
										
										
										
											2021-05-18 22:16:26 +08:00
										 |  |  |     return ( | 
					
						
							| 
									
										
										
										
											2022-08-12 21:32:07 +08:00
										 |  |  |       <div className={styles.dsTooltip}> | 
					
						
							|  |  |  |         <Tooltip | 
					
						
							|  |  |  |           content={ | 
					
						
							|  |  |  |             <> | 
					
						
							|  |  |  |               Not finding the data source you want? Some data sources are not supported for alerting. Click on the icon | 
					
						
							|  |  |  |               for more information. | 
					
						
							|  |  |  |             </> | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         > | 
					
						
							|  |  |  |           <Icon | 
					
						
							|  |  |  |             name="info-circle" | 
					
						
							|  |  |  |             onClick={() => | 
					
						
							|  |  |  |               window.open( | 
					
						
							|  |  |  |                 ' https://grafana.com/docs/grafana/latest/alerting/fundamentals/data-source-alerting/', | 
					
						
							|  |  |  |                 '_blank' | 
					
						
							|  |  |  |               ) | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           /> | 
					
						
							|  |  |  |         </Tooltip> | 
					
						
							|  |  |  |       </div> | 
					
						
							| 
									
										
										
										
											2021-05-18 22:16:26 +08:00
										 |  |  |     ); | 
					
						
							| 
									
										
										
										
											2022-08-12 21:32:07 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-05 20:35:15 +08:00
										 |  |  |   // TODO add a warning label here too when the data looks like time series data and is used as an alert condition
 | 
					
						
							|  |  |  |   function HeaderExtras({ query, error, index }: { query: AlertQuery; error?: Error; index: number }) { | 
					
						
							| 
									
										
										
										
											2023-01-24 16:16:21 +08:00
										 |  |  |     const queryOptions: AlertQueryOptions = { maxDataPoints: query.model.maxDataPoints }; | 
					
						
							|  |  |  |     const alertQueryOptions: AlertQueryOptions = { | 
					
						
							|  |  |  |       maxDataPoints: queryOptions.maxDataPoints, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-27 22:38:22 +08:00
										 |  |  |     return ( | 
					
						
							|  |  |  |       <Stack direction="row" alignItems="baseline" gap={1}> | 
					
						
							|  |  |  |         <SelectingDataSourceTooltip /> | 
					
						
							|  |  |  |         {onChangeTimeRange && ( | 
					
						
							|  |  |  |           <RelativeTimeRangePicker | 
					
						
							|  |  |  |             timeRange={query.relativeTimeRange ?? getDefaultRelativeTimeRange()} | 
					
						
							|  |  |  |             onChange={(range) => onChangeTimeRange(range, index)} | 
					
						
							| 
									
										
										
										
											2022-10-05 20:35:15 +08:00
										 |  |  |           /> | 
					
						
							| 
									
										
										
										
											2023-04-27 22:38:22 +08:00
										 |  |  |         )} | 
					
						
							|  |  |  |         <div className={styles.queryOptions}> | 
					
						
							|  |  |  |           <MaxDataPointsOption | 
					
						
							|  |  |  |             options={alertQueryOptions} | 
					
						
							|  |  |  |             onChange={(options) => onChangeQueryOptions(options, index)} | 
					
						
							|  |  |  |           /> | 
					
						
							|  |  |  |         </div> | 
					
						
							|  |  |  |         <AlertConditionIndicator | 
					
						
							|  |  |  |           onSetCondition={() => onSetCondition(query.refId)} | 
					
						
							|  |  |  |           enabled={condition === query.refId} | 
					
						
							|  |  |  |           error={error} | 
					
						
							|  |  |  |         /> | 
					
						
							|  |  |  |       </Stack> | 
					
						
							|  |  |  |     ); | 
					
						
							| 
									
										
										
										
											2022-08-12 21:32:07 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2021-05-18 22:16:26 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return ( | 
					
						
							| 
									
										
										
										
											2023-04-27 22:38:22 +08:00
										 |  |  |     <Stack direction="column" gap={0.5}> | 
					
						
							|  |  |  |       <div className={styles.wrapper}> | 
					
						
							|  |  |  |         <QueryEditorRow<DataQuery> | 
					
						
							|  |  |  |           alerting | 
					
						
							|  |  |  |           dataSource={dsSettings} | 
					
						
							|  |  |  |           onDataSourceLoaded={setDsInstance} | 
					
						
							|  |  |  |           onChangeDataSource={(settings) => onChangeDataSource(settings, index)} | 
					
						
							|  |  |  |           id={query.refId} | 
					
						
							|  |  |  |           index={index} | 
					
						
							|  |  |  |           key={query.refId} | 
					
						
							|  |  |  |           data={data} | 
					
						
							|  |  |  |           query={{ | 
					
						
							|  |  |  |             ...defaults, | 
					
						
							|  |  |  |             ...cloneDeep(query.model), | 
					
						
							|  |  |  |           }} | 
					
						
							|  |  |  |           onChange={(query) => onChangeQuery(query, index)} | 
					
						
							|  |  |  |           onRemoveQuery={onRemoveQuery} | 
					
						
							|  |  |  |           onAddQuery={() => onDuplicateQuery(cloneDeep(query))} | 
					
						
							|  |  |  |           onRunQuery={onRunQueries} | 
					
						
							|  |  |  |           queries={queries} | 
					
						
							|  |  |  |           renderHeaderExtras={() => <HeaderExtras query={query} index={index} error={error} />} | 
					
						
							|  |  |  |           app={CoreApp.UnifiedAlerting} | 
					
						
							|  |  |  |           hideDisableQuery={true} | 
					
						
							|  |  |  |         /> | 
					
						
							|  |  |  |       </div> | 
					
						
							|  |  |  |       {data.state !== LoadingState.NotStarted && ( | 
					
						
							|  |  |  |         <VizWrapper | 
					
						
							|  |  |  |           data={data} | 
					
						
							|  |  |  |           thresholds={thresholds} | 
					
						
							|  |  |  |           thresholdsType={thresholdsType} | 
					
						
							|  |  |  |           onThresholdsChange={onChangeThreshold ? (thresholds) => onChangeThreshold(thresholds, index) : undefined} | 
					
						
							|  |  |  |         /> | 
					
						
							|  |  |  |       )} | 
					
						
							|  |  |  |     </Stack> | 
					
						
							| 
									
										
										
										
											2021-05-18 22:16:26 +08:00
										 |  |  |   ); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-14 17:24:32 +08:00
										 |  |  | export const EmptyQueryWrapper = ({ children }: React.PropsWithChildren<{}>) => { | 
					
						
							| 
									
										
										
										
											2022-01-17 21:30:00 +08:00
										 |  |  |   const styles = useStyles2(getStyles); | 
					
						
							|  |  |  |   return <div className={styles.wrapper}>{children}</div>; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-24 16:16:21 +08:00
										 |  |  | function MaxDataPointsOption({ | 
					
						
							|  |  |  |   options, | 
					
						
							|  |  |  |   onChange, | 
					
						
							|  |  |  | }: { | 
					
						
							|  |  |  |   options: AlertQueryOptions; | 
					
						
							|  |  |  |   onChange: (options: AlertQueryOptions) => void; | 
					
						
							|  |  |  | }) { | 
					
						
							|  |  |  |   const value = options.maxDataPoints ?? ''; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const onMaxDataPointsBlur = (event: ChangeEvent<HTMLInputElement>) => { | 
					
						
							|  |  |  |     const maxDataPointsNumber = parseInt(event.target.value, 10); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const maxDataPoints = isNaN(maxDataPointsNumber) || maxDataPointsNumber === 0 ? undefined : maxDataPointsNumber; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (maxDataPoints !== options.maxDataPoints) { | 
					
						
							|  |  |  |       onChange({ | 
					
						
							|  |  |  |         ...options, | 
					
						
							|  |  |  |         maxDataPoints, | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return ( | 
					
						
							|  |  |  |     <Stack direction="row" alignItems="baseline" gap={1}> | 
					
						
							|  |  |  |       <InlineFormLabel | 
					
						
							|  |  |  |         width={8} | 
					
						
							|  |  |  |         tooltip={ | 
					
						
							|  |  |  |           <> | 
					
						
							|  |  |  |             The maximum data points per series. Used directly by some data sources and used in calculation of auto | 
					
						
							|  |  |  |             interval. With streaming data this value is used for the rolling buffer. | 
					
						
							|  |  |  |           </> | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       > | 
					
						
							|  |  |  |         Max data points | 
					
						
							|  |  |  |       </InlineFormLabel> | 
					
						
							|  |  |  |       <Input | 
					
						
							|  |  |  |         type="number" | 
					
						
							|  |  |  |         className="width-6" | 
					
						
							|  |  |  |         placeholder={DEFAULT_MAX_DATA_POINTS.toLocaleString()} | 
					
						
							|  |  |  |         spellCheck={false} | 
					
						
							|  |  |  |         onBlur={onMaxDataPointsBlur} | 
					
						
							|  |  |  |         defaultValue={value} | 
					
						
							|  |  |  |       /> | 
					
						
							|  |  |  |     </Stack> | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-18 22:16:26 +08:00
										 |  |  | const getStyles = (theme: GrafanaTheme2) => ({ | 
					
						
							|  |  |  |   wrapper: css`
 | 
					
						
							| 
									
										
										
										
											2021-05-27 16:46:06 +08:00
										 |  |  |     label: AlertingQueryWrapper; | 
					
						
							| 
									
										
										
										
											2021-05-18 22:16:26 +08:00
										 |  |  |     margin-bottom: ${theme.spacing(1)}; | 
					
						
							|  |  |  |     border: 1px solid ${theme.colors.border.medium}; | 
					
						
							|  |  |  |     border-radius: ${theme.shape.borderRadius(1)}; | 
					
						
							|  |  |  |   `,
 | 
					
						
							| 
									
										
										
										
											2023-01-24 16:16:21 +08:00
										 |  |  |   queryOptions: css`
 | 
					
						
							|  |  |  |     margin-bottom: -${theme.spacing(2)}; | 
					
						
							|  |  |  |   `,
 | 
					
						
							| 
									
										
										
										
											2022-08-12 21:32:07 +08:00
										 |  |  |   dsTooltip: css`
 | 
					
						
							|  |  |  |     display: flex; | 
					
						
							|  |  |  |     align-items: center; | 
					
						
							|  |  |  |     &:hover { | 
					
						
							|  |  |  |       opacity: 0.85; | 
					
						
							|  |  |  |       cursor: pointer; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   `,
 | 
					
						
							| 
									
										
										
										
											2021-05-18 22:16:26 +08:00
										 |  |  | }); |