Condition.tsx 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. import { css, cx } from '@emotion/css';
  2. import React, { FC, FormEvent } from 'react';
  3. import { GrafanaTheme, SelectableValue } from '@grafana/data';
  4. import { Button, ButtonSelect, Icon, InlineFieldRow, Input, Select, useStyles } from '@grafana/ui';
  5. import alertDef, { EvalFunction } from '../../alerting/state/alertDef';
  6. import { ClassicCondition, ReducerType } from '../types';
  7. interface Props {
  8. condition: ClassicCondition;
  9. onChange: (condition: ClassicCondition) => void;
  10. onRemoveCondition: (id: number) => void;
  11. index: number;
  12. refIds: Array<SelectableValue<string>>;
  13. }
  14. const reducerFunctions = alertDef.reducerTypes.map((rt) => ({ label: rt.text, value: rt.value }));
  15. const evalOperators = alertDef.evalOperators.map((eo) => ({ label: eo.text, value: eo.value }));
  16. const evalFunctions = alertDef.evalFunctions.map((ef) => ({ label: ef.text, value: ef.value }));
  17. export const Condition: FC<Props> = ({ condition, index, onChange, onRemoveCondition, refIds }) => {
  18. const styles = useStyles(getStyles);
  19. const onEvalOperatorChange = (evalOperator: SelectableValue<string>) => {
  20. onChange({
  21. ...condition,
  22. operator: { type: evalOperator.value! },
  23. });
  24. };
  25. const onReducerFunctionChange = (conditionFunction: SelectableValue<string>) => {
  26. onChange({
  27. ...condition,
  28. reducer: { type: conditionFunction.value! as ReducerType, params: [] },
  29. });
  30. };
  31. const onRefIdChange = (refId: SelectableValue<string>) => {
  32. onChange({
  33. ...condition,
  34. query: { params: [refId.value!] },
  35. });
  36. };
  37. const onEvalFunctionChange = (evalFunction: SelectableValue<EvalFunction>) => {
  38. onChange({
  39. ...condition,
  40. evaluator: { params: condition.evaluator.params, type: evalFunction.value! },
  41. });
  42. };
  43. const onEvaluateValueChange = (event: FormEvent<HTMLInputElement>, index: number) => {
  44. const newValue = parseFloat(event.currentTarget.value);
  45. const newParams = [...condition.evaluator.params];
  46. newParams[index] = newValue;
  47. onChange({
  48. ...condition,
  49. evaluator: { ...condition.evaluator, params: newParams },
  50. });
  51. };
  52. const buttonWidth = css`
  53. width: 60px;
  54. `;
  55. const isRange =
  56. condition.evaluator.type === EvalFunction.IsWithinRange || condition.evaluator.type === EvalFunction.IsOutsideRange;
  57. return (
  58. <InlineFieldRow>
  59. {index === 0 ? (
  60. <div className={cx(styles.button, buttonWidth)}>WHEN</div>
  61. ) : (
  62. <ButtonSelect
  63. className={cx(styles.buttonSelectText, buttonWidth)}
  64. options={evalOperators}
  65. onChange={onEvalOperatorChange}
  66. value={evalOperators.find((ea) => ea.value === condition.operator!.type)}
  67. />
  68. )}
  69. <Select
  70. options={reducerFunctions}
  71. onChange={onReducerFunctionChange}
  72. width={20}
  73. value={reducerFunctions.find((rf) => rf.value === condition.reducer.type)}
  74. />
  75. <div className={styles.button}>OF</div>
  76. <Select
  77. onChange={onRefIdChange}
  78. options={refIds}
  79. width={15}
  80. value={refIds.find((r) => r.value === condition.query.params[0])}
  81. />
  82. <ButtonSelect
  83. className={styles.buttonSelectText}
  84. options={evalFunctions}
  85. onChange={onEvalFunctionChange}
  86. value={evalFunctions.find((ef) => ef.value === condition.evaluator.type)}
  87. />
  88. {isRange ? (
  89. <>
  90. <Input
  91. type="number"
  92. width={10}
  93. onChange={(event) => onEvaluateValueChange(event, 0)}
  94. value={condition.evaluator.params[0]}
  95. />
  96. <div className={styles.button}>TO</div>
  97. <Input
  98. type="number"
  99. width={10}
  100. onChange={(event) => onEvaluateValueChange(event, 1)}
  101. value={condition.evaluator.params[1]}
  102. />
  103. </>
  104. ) : condition.evaluator.type !== EvalFunction.HasNoValue ? (
  105. <Input
  106. type="number"
  107. width={10}
  108. onChange={(event) => onEvaluateValueChange(event, 0)}
  109. value={condition.evaluator.params[0]}
  110. />
  111. ) : null}
  112. <Button variant="secondary" type="button" onClick={() => onRemoveCondition(index)}>
  113. <Icon name="trash-alt" />
  114. </Button>
  115. </InlineFieldRow>
  116. );
  117. };
  118. const getStyles = (theme: GrafanaTheme) => {
  119. const buttonStyle = css`
  120. color: ${theme.colors.textBlue};
  121. font-size: ${theme.typography.size.sm};
  122. `;
  123. return {
  124. buttonSelectText: buttonStyle,
  125. button: cx(
  126. css`
  127. display: flex;
  128. align-items: center;
  129. border-radius: ${theme.border.radius.sm};
  130. font-weight: ${theme.typography.weight.semibold};
  131. border: 1px solid ${theme.colors.border1};
  132. white-space: nowrap;
  133. padding: 0 ${theme.spacing.sm};
  134. background-color: ${theme.colors.bodyBg};
  135. `,
  136. buttonStyle
  137. ),
  138. };
  139. };