The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/public/app/features/expressions/components/Condition.tsx

153 lines
4.7 KiB

import React, { FC, FormEvent } from 'react';
import { css, cx } from '@emotion/css';
import { GrafanaTheme, SelectableValue } from '@grafana/data';
import { Button, ButtonSelect, Icon, InlineFieldRow, Input, Select, useStyles } from '@grafana/ui';
import alertDef, { EvalFunction } from '../../alerting/state/alertDef';
import { ClassicCondition, ReducerType } from '../types';
interface Props {
condition: ClassicCondition;
onChange: (condition: ClassicCondition) => void;
onRemoveCondition: (id: number) => void;
index: number;
refIds: Array<SelectableValue<string>>;
}
const reducerFunctions = alertDef.reducerTypes.map((rt) => ({ label: rt.text, value: rt.value }));
const evalOperators = alertDef.evalOperators.map((eo) => ({ label: eo.text, value: eo.value }));
const evalFunctions = alertDef.evalFunctions.map((ef) => ({ label: ef.text, value: ef.value }));
export const Condition: FC<Props> = ({ condition, index, onChange, onRemoveCondition, refIds }) => {
const styles = useStyles(getStyles);
const onEvalOperatorChange = (evalOperator: SelectableValue<string>) => {
onChange({
...condition,
operator: { type: evalOperator.value! },
});
};
const onReducerFunctionChange = (conditionFunction: SelectableValue<string>) => {
onChange({
...condition,
reducer: { type: conditionFunction.value! as ReducerType, params: [] },
});
};
const onRefIdChange = (refId: SelectableValue<string>) => {
onChange({
...condition,
query: { params: [refId.value!] },
});
};
const onEvalFunctionChange = (evalFunction: SelectableValue<EvalFunction>) => {
onChange({
...condition,
evaluator: { params: [], type: evalFunction.value! },
});
};
const onEvaluateValueChange = (event: FormEvent<HTMLInputElement>, index: number) => {
const newValue = parseFloat(event.currentTarget.value);
const newParams = [...condition.evaluator.params];
newParams[index] = newValue;
onChange({
...condition,
evaluator: { ...condition.evaluator, params: newParams },
});
};
const buttonWidth = css`
width: 60px;
`;
const isRange =
condition.evaluator.type === EvalFunction.IsWithinRange || condition.evaluator.type === EvalFunction.IsOutsideRange;
return (
<InlineFieldRow>
{index === 0 ? (
<div className={cx(styles.button, buttonWidth)}>WHEN</div>
) : (
<ButtonSelect
className={cx(styles.buttonSelectText, buttonWidth)}
options={evalOperators}
onChange={onEvalOperatorChange}
value={evalOperators.find((ea) => ea.value === condition.operator!.type)}
/>
)}
<Select
options={reducerFunctions}
onChange={onReducerFunctionChange}
width={20}
value={reducerFunctions.find((rf) => rf.value === condition.reducer.type)}
/>
<div className={styles.button}>OF</div>
<Select
onChange={onRefIdChange}
options={refIds}
width={15}
value={refIds.find((r) => r.value === condition.query.params[0])}
/>
<ButtonSelect
className={styles.buttonSelectText}
options={evalFunctions}
onChange={onEvalFunctionChange}
value={evalFunctions.find((ef) => ef.value === condition.evaluator.type)}
/>
{isRange ? (
<>
<Input
type="number"
width={10}
onChange={(event) => onEvaluateValueChange(event, 0)}
value={condition.evaluator.params[0]}
/>
<div className={styles.button}>TO</div>
<Input
type="number"
width={10}
onChange={(event) => onEvaluateValueChange(event, 1)}
value={condition.evaluator.params[1]}
/>
</>
) : condition.evaluator.type !== EvalFunction.HasNoValue ? (
<Input
type="number"
width={10}
onChange={(event) => onEvaluateValueChange(event, 0)}
value={condition.evaluator.params[0]}
/>
) : null}
<Button variant="secondary" type="button" onClick={() => onRemoveCondition(index)}>
<Icon name="trash-alt" />
</Button>
</InlineFieldRow>
);
};
const getStyles = (theme: GrafanaTheme) => {
const buttonStyle = css`
color: ${theme.colors.textBlue};
font-size: ${theme.typography.size.sm};
`;
return {
buttonSelectText: buttonStyle,
button: cx(
css`
display: flex;
align-items: center;
border-radius: ${theme.border.radius.sm};
font-weight: ${theme.typography.weight.semibold};
border: 1px solid ${theme.colors.border1};
white-space: nowrap;
padding: 0 ${theme.spacing.sm};
background-color: ${theme.colors.bodyBg};
`,
buttonStyle
),
};
};