Alerting: Add multiple threshold operators (#99516)
The following operators are being added: - Equal - Not Equal - Greater or Equal - Less or Equal - Within Range Inclusive - Outside Range Inclusive
This commit is contained in:
+1
-6
@@ -4991,12 +4991,7 @@ exports[`better eslint`] = {
|
||||
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "4"]
|
||||
],
|
||||
"public/app/features/expressions/components/Threshold.tsx:5381": [
|
||||
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"],
|
||||
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "1"],
|
||||
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "2"],
|
||||
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "3"],
|
||||
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "4"],
|
||||
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "5"]
|
||||
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"]
|
||||
],
|
||||
"public/app/features/expressions/guards.ts:5381": [
|
||||
[0, 0, 0, "\'@grafana/runtime/src/utils/DataSourceWithBackend\' import is restricted from being used by a pattern. Import from the public export instead.", "0"],
|
||||
|
||||
@@ -48,9 +48,9 @@ func (rangedEvaluator) Kind() EvaluatorKind {
|
||||
// an AlertEvaluator depending on evaluation operator.
|
||||
func newAlertEvaluator(model ConditionEvalJSON) (evaluator, error) {
|
||||
switch model.Type {
|
||||
case "gt", "lt":
|
||||
case "gt", "lt", "eq", "ne", "gte", "lte":
|
||||
return newThresholdEvaluator(model)
|
||||
case "within_range", "outside_range":
|
||||
case "within_range", "outside_range", "within_range_included", "outside_range_included":
|
||||
return newRangedEvaluator(model)
|
||||
case "no_value":
|
||||
return &noValueEvaluator{}, nil
|
||||
@@ -70,6 +70,14 @@ func (e *thresholdEvaluator) Eval(reducedValue mathexp.Number) bool {
|
||||
return *fv > e.Threshold
|
||||
case "lt":
|
||||
return *fv < e.Threshold
|
||||
case "eq":
|
||||
return *fv == e.Threshold
|
||||
case "ne":
|
||||
return *fv != e.Threshold
|
||||
case "gte":
|
||||
return *fv >= e.Threshold
|
||||
case "lte":
|
||||
return *fv <= e.Threshold
|
||||
}
|
||||
|
||||
return false
|
||||
@@ -113,6 +121,10 @@ func (e *rangedEvaluator) Eval(reducedValue mathexp.Number) bool {
|
||||
return (e.Lower < *fv && e.Upper > *fv) || (e.Upper < *fv && e.Lower > *fv)
|
||||
case "outside_range":
|
||||
return (e.Upper < *fv && e.Lower < *fv) || (e.Upper > *fv && e.Lower > *fv)
|
||||
case "within_range_included":
|
||||
return (e.Lower <= *fv && e.Upper >= *fv) || (e.Upper <= *fv && e.Lower >= *fv)
|
||||
case "outside_range_included":
|
||||
return (e.Upper <= *fv && e.Lower <= *fv) || (e.Upper >= *fv && e.Lower >= *fv)
|
||||
}
|
||||
|
||||
return false
|
||||
|
||||
@@ -40,6 +40,48 @@ func TestThresholdEvaluator(t *testing.T) {
|
||||
inputNumber: newNumber(util.Pointer(1.0)),
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "value 1 is eq 1: false",
|
||||
evaluator: &thresholdEvaluator{"eq", 1},
|
||||
inputNumber: newNumber(util.Pointer(1.0)),
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "value 0 is eq 0: false",
|
||||
evaluator: &thresholdEvaluator{"eq", 0},
|
||||
inputNumber: newNumber(util.Pointer(0.0)),
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "value 1 is eq 0: false",
|
||||
evaluator: &thresholdEvaluator{"eq", 0},
|
||||
inputNumber: newNumber(util.Pointer(1.0)),
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "value 0 is eq 1: false",
|
||||
evaluator: &thresholdEvaluator{"eq", 1},
|
||||
inputNumber: newNumber(util.Pointer(0.0)),
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "value 1 is ne 1: false",
|
||||
evaluator: &thresholdEvaluator{"ne", 1},
|
||||
inputNumber: newNumber(util.Pointer(1.0)),
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "value 3 is gte 3: false",
|
||||
evaluator: &thresholdEvaluator{"gte", 3},
|
||||
inputNumber: newNumber(util.Pointer(3.0)),
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "value 5 is lte 4: false",
|
||||
evaluator: &thresholdEvaluator{"lte", 4},
|
||||
inputNumber: newNumber(util.Pointer(5.0)),
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
@@ -712,8 +712,14 @@
|
||||
"enum": [
|
||||
"gt",
|
||||
"lt",
|
||||
"eq",
|
||||
"ne",
|
||||
"gte",
|
||||
"lte",
|
||||
"within_range",
|
||||
"outside_range"
|
||||
"outside_range",
|
||||
"within_range_included",
|
||||
"outside_range_included"
|
||||
],
|
||||
"x-enum-description": {}
|
||||
}
|
||||
@@ -744,8 +750,14 @@
|
||||
"enum": [
|
||||
"gt",
|
||||
"lt",
|
||||
"eq",
|
||||
"ne",
|
||||
"gte",
|
||||
"lte",
|
||||
"within_range",
|
||||
"outside_range"
|
||||
"outside_range",
|
||||
"within_range_included",
|
||||
"outside_range_included"
|
||||
],
|
||||
"x-enum-description": {}
|
||||
}
|
||||
@@ -1013,4 +1025,4 @@
|
||||
},
|
||||
"additionalProperties": true,
|
||||
"$schema": "https://json-schema.org/draft-04/schema#"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -754,8 +754,14 @@
|
||||
"enum": [
|
||||
"gt",
|
||||
"lt",
|
||||
"eq",
|
||||
"ne",
|
||||
"gte",
|
||||
"lte",
|
||||
"within_range",
|
||||
"outside_range"
|
||||
"outside_range",
|
||||
"within_range_included",
|
||||
"outside_range_included"
|
||||
],
|
||||
"x-enum-description": {}
|
||||
}
|
||||
@@ -786,8 +792,14 @@
|
||||
"enum": [
|
||||
"gt",
|
||||
"lt",
|
||||
"eq",
|
||||
"ne",
|
||||
"gte",
|
||||
"lte",
|
||||
"within_range",
|
||||
"outside_range"
|
||||
"outside_range",
|
||||
"within_range_included",
|
||||
"outside_range_included"
|
||||
],
|
||||
"x-enum-description": {}
|
||||
}
|
||||
@@ -1071,4 +1083,4 @@
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"$schema": "https://json-schema.org/draft-04/schema#"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -395,8 +395,14 @@
|
||||
"enum": [
|
||||
"gt",
|
||||
"lt",
|
||||
"eq",
|
||||
"ne",
|
||||
"gte",
|
||||
"lte",
|
||||
"within_range",
|
||||
"outside_range"
|
||||
"outside_range",
|
||||
"within_range_included",
|
||||
"outside_range_included"
|
||||
],
|
||||
"type": "string",
|
||||
"x-enum-description": {}
|
||||
@@ -427,8 +433,14 @@
|
||||
"enum": [
|
||||
"gt",
|
||||
"lt",
|
||||
"eq",
|
||||
"ne",
|
||||
"gte",
|
||||
"lte",
|
||||
"within_range",
|
||||
"outside_range"
|
||||
"outside_range",
|
||||
"within_range_included",
|
||||
"outside_range_included"
|
||||
],
|
||||
"type": "string",
|
||||
"x-enum-description": {}
|
||||
@@ -579,4 +591,4 @@
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
+96
-4
@@ -32,18 +32,30 @@ type ThresholdCommand struct {
|
||||
type ThresholdType string
|
||||
|
||||
const (
|
||||
ThresholdIsAbove ThresholdType = "gt"
|
||||
ThresholdIsBelow ThresholdType = "lt"
|
||||
ThresholdIsWithinRange ThresholdType = "within_range"
|
||||
ThresholdIsOutsideRange ThresholdType = "outside_range"
|
||||
ThresholdIsAbove ThresholdType = "gt"
|
||||
ThresholdIsBelow ThresholdType = "lt"
|
||||
ThresholdIsEqual ThresholdType = "eq"
|
||||
ThresholdIsNotEqual ThresholdType = "ne"
|
||||
ThresholdIsGreaterThanEqual ThresholdType = "gte"
|
||||
ThresholdIsLessThanEqual ThresholdType = "lte"
|
||||
ThresholdIsWithinRange ThresholdType = "within_range"
|
||||
ThresholdIsOutsideRange ThresholdType = "outside_range"
|
||||
ThresholdIsWithinRangeIncluded ThresholdType = "within_range_included"
|
||||
ThresholdIsOutsideRangeIncluded ThresholdType = "outside_range_included"
|
||||
)
|
||||
|
||||
var (
|
||||
supportedThresholdFuncs = []string{
|
||||
string(ThresholdIsAbove),
|
||||
string(ThresholdIsBelow),
|
||||
string(ThresholdIsEqual),
|
||||
string(ThresholdIsNotEqual),
|
||||
string(ThresholdIsGreaterThanEqual),
|
||||
string(ThresholdIsLessThanEqual),
|
||||
string(ThresholdIsWithinRange),
|
||||
string(ThresholdIsOutsideRange),
|
||||
string(ThresholdIsWithinRangeIncluded),
|
||||
string(ThresholdIsOutsideRangeIncluded),
|
||||
}
|
||||
)
|
||||
|
||||
@@ -60,6 +72,16 @@ func NewThresholdCommand(refID, referenceVar string, thresholdFunc ThresholdType
|
||||
return nil, fmt.Errorf("incorrect number of arguments for threshold function '%s': got %d but need 2", thresholdFunc, len(conditions))
|
||||
}
|
||||
predicate = withinRangePredicate{left: conditions[0], right: conditions[1]}
|
||||
case ThresholdIsWithinRangeIncluded:
|
||||
if len(conditions) < 2 {
|
||||
return nil, fmt.Errorf("incorrect number of arguments for threshold function '%s': got %d but need 2", thresholdFunc, len(conditions))
|
||||
}
|
||||
predicate = withinRangeIncludedPredicate{left: conditions[0], right: conditions[1]}
|
||||
case ThresholdIsOutsideRangeIncluded:
|
||||
if len(conditions) < 2 {
|
||||
return nil, fmt.Errorf("incorrect number of arguments for threshold function '%s': got %d but need 2", thresholdFunc, len(conditions))
|
||||
}
|
||||
predicate = outsideRangeIncludedPredicate{left: conditions[0], right: conditions[1]}
|
||||
case ThresholdIsAbove:
|
||||
if len(conditions) < 1 {
|
||||
return nil, fmt.Errorf("incorrect number of arguments for threshold function '%s': got %d but need 1", thresholdFunc, len(conditions))
|
||||
@@ -70,6 +92,26 @@ func NewThresholdCommand(refID, referenceVar string, thresholdFunc ThresholdType
|
||||
return nil, fmt.Errorf("incorrect number of arguments for threshold function '%s': got %d but need 1", thresholdFunc, len(conditions))
|
||||
}
|
||||
predicate = lessThanPredicate{value: conditions[0]}
|
||||
case ThresholdIsEqual:
|
||||
if len(conditions) < 1 {
|
||||
return nil, fmt.Errorf("incorrect number of arguments for threshold function '%s': got %d but need 1", thresholdFunc, len(conditions))
|
||||
}
|
||||
predicate = equalPredicate{value: conditions[0]}
|
||||
case ThresholdIsNotEqual:
|
||||
if len(conditions) < 1 {
|
||||
return nil, fmt.Errorf("incorrect number of arguments for threshold function '%s': got %d but need 1", thresholdFunc, len(conditions))
|
||||
}
|
||||
predicate = notEqualPredicate{value: conditions[0]}
|
||||
case ThresholdIsGreaterThanEqual:
|
||||
if len(conditions) < 1 {
|
||||
return nil, fmt.Errorf("incorrect number of arguments for threshold function '%s': got %d but need 1", thresholdFunc, len(conditions))
|
||||
}
|
||||
predicate = greaterThanEqualPredicate{value: conditions[0]}
|
||||
case ThresholdIsLessThanEqual:
|
||||
if len(conditions) < 1 {
|
||||
return nil, fmt.Errorf("incorrect number of arguments for threshold function '%s': got %d but need 1", thresholdFunc, len(conditions))
|
||||
}
|
||||
predicate = lessThanEqualPredicate{value: conditions[0]}
|
||||
default:
|
||||
return nil, fmt.Errorf("expected threshold function to be one of [%s], got %s", strings.Join(supportedThresholdFuncs, ", "), thresholdFunc)
|
||||
}
|
||||
@@ -279,6 +321,24 @@ func (r outsideRangePredicate) Eval(f float64) bool {
|
||||
return f < r.left || f > r.right
|
||||
}
|
||||
|
||||
type withinRangeIncludedPredicate struct {
|
||||
left float64
|
||||
right float64
|
||||
}
|
||||
|
||||
func (r withinRangeIncludedPredicate) Eval(f float64) bool {
|
||||
return f >= r.left && f <= r.right
|
||||
}
|
||||
|
||||
type outsideRangeIncludedPredicate struct {
|
||||
left float64
|
||||
right float64
|
||||
}
|
||||
|
||||
func (r outsideRangeIncludedPredicate) Eval(f float64) bool {
|
||||
return f <= r.left || f >= r.right
|
||||
}
|
||||
|
||||
type lessThanPredicate struct {
|
||||
value float64
|
||||
}
|
||||
@@ -294,3 +354,35 @@ type greaterThanPredicate struct {
|
||||
func (r greaterThanPredicate) Eval(f float64) bool {
|
||||
return f > r.value
|
||||
}
|
||||
|
||||
type equalPredicate struct {
|
||||
value float64
|
||||
}
|
||||
|
||||
func (r equalPredicate) Eval(f float64) bool {
|
||||
return f == r.value
|
||||
}
|
||||
|
||||
type notEqualPredicate struct {
|
||||
value float64
|
||||
}
|
||||
|
||||
func (r notEqualPredicate) Eval(f float64) bool {
|
||||
return f != r.value
|
||||
}
|
||||
|
||||
type greaterThanEqualPredicate struct {
|
||||
value float64
|
||||
}
|
||||
|
||||
func (r greaterThanEqualPredicate) Eval(f float64) bool {
|
||||
return f >= r.value
|
||||
}
|
||||
|
||||
type lessThanEqualPredicate struct {
|
||||
value float64
|
||||
}
|
||||
|
||||
func (r lessThanEqualPredicate) Eval(f float64) bool {
|
||||
return f <= r.value
|
||||
}
|
||||
|
||||
@@ -38,6 +38,26 @@ func TestNewThresholdCommand(t *testing.T) {
|
||||
args: []float64{0},
|
||||
shouldError: false,
|
||||
},
|
||||
{
|
||||
fn: "eq",
|
||||
args: []float64{0},
|
||||
shouldError: false,
|
||||
},
|
||||
{
|
||||
fn: "ne",
|
||||
args: []float64{0},
|
||||
shouldError: false,
|
||||
},
|
||||
{
|
||||
fn: "gte",
|
||||
args: []float64{0},
|
||||
shouldError: false,
|
||||
},
|
||||
{
|
||||
fn: "lte",
|
||||
args: []float64{0},
|
||||
shouldError: false,
|
||||
},
|
||||
{
|
||||
fn: "within_range",
|
||||
args: []float64{0, 1},
|
||||
@@ -48,6 +68,16 @@ func TestNewThresholdCommand(t *testing.T) {
|
||||
args: []float64{0, 1},
|
||||
shouldError: false,
|
||||
},
|
||||
{
|
||||
fn: "within_range_included",
|
||||
args: []float64{0, 1},
|
||||
shouldError: false,
|
||||
},
|
||||
{
|
||||
fn: "outside_range_included",
|
||||
args: []float64{0, 1},
|
||||
shouldError: false,
|
||||
},
|
||||
{
|
||||
fn: "gt",
|
||||
args: []float64{},
|
||||
@@ -60,6 +90,30 @@ func TestNewThresholdCommand(t *testing.T) {
|
||||
shouldError: true,
|
||||
expectedError: "incorrect number of arguments",
|
||||
},
|
||||
{
|
||||
fn: "eq",
|
||||
args: []float64{},
|
||||
shouldError: true,
|
||||
expectedError: "incorrect number of arguments",
|
||||
},
|
||||
{
|
||||
fn: "ne",
|
||||
args: []float64{},
|
||||
shouldError: true,
|
||||
expectedError: "incorrect number of arguments",
|
||||
},
|
||||
{
|
||||
fn: "gte",
|
||||
args: []float64{},
|
||||
shouldError: true,
|
||||
expectedError: "incorrect number of arguments",
|
||||
},
|
||||
{
|
||||
fn: "lte",
|
||||
args: []float64{},
|
||||
shouldError: true,
|
||||
expectedError: "incorrect number of arguments",
|
||||
},
|
||||
{
|
||||
fn: "within_range",
|
||||
args: []float64{0},
|
||||
@@ -72,6 +126,18 @@ func TestNewThresholdCommand(t *testing.T) {
|
||||
shouldError: true,
|
||||
expectedError: "incorrect number of arguments",
|
||||
},
|
||||
{
|
||||
fn: "within_range_included",
|
||||
args: []float64{0},
|
||||
shouldError: true,
|
||||
expectedError: "incorrect number of arguments",
|
||||
},
|
||||
{
|
||||
fn: "outside_range_included",
|
||||
args: []float64{0},
|
||||
shouldError: true,
|
||||
expectedError: "incorrect number of arguments",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
@@ -249,6 +315,22 @@ func TestIsSupportedThresholdFunc(t *testing.T) {
|
||||
function: ThresholdIsBelow,
|
||||
supported: true,
|
||||
},
|
||||
{
|
||||
function: ThresholdIsEqual,
|
||||
supported: true,
|
||||
},
|
||||
{
|
||||
function: ThresholdIsNotEqual,
|
||||
supported: true,
|
||||
},
|
||||
{
|
||||
function: ThresholdIsGreaterThanEqual,
|
||||
supported: true,
|
||||
},
|
||||
{
|
||||
function: ThresholdIsLessThanEqual,
|
||||
supported: true,
|
||||
},
|
||||
{
|
||||
function: ThresholdIsWithinRange,
|
||||
supported: true,
|
||||
@@ -257,6 +339,14 @@ func TestIsSupportedThresholdFunc(t *testing.T) {
|
||||
function: ThresholdIsOutsideRange,
|
||||
supported: true,
|
||||
},
|
||||
{
|
||||
function: ThresholdIsWithinRangeIncluded,
|
||||
supported: true,
|
||||
},
|
||||
{
|
||||
function: ThresholdIsOutsideRangeIncluded,
|
||||
supported: true,
|
||||
},
|
||||
{
|
||||
function: "foo",
|
||||
supported: false,
|
||||
|
||||
@@ -29,6 +29,26 @@ export class ThresholdMapper {
|
||||
thresholds.push({ value: value, op: 'lt', visible });
|
||||
break;
|
||||
}
|
||||
case 'eq': {
|
||||
const value = evaluator.params[0];
|
||||
thresholds.push({ value: value, op: 'eq', visible });
|
||||
break;
|
||||
}
|
||||
case 'ne': {
|
||||
const value = evaluator.params[0];
|
||||
thresholds.push({ value: value, op: 'ne', visible });
|
||||
break;
|
||||
}
|
||||
case 'gte': {
|
||||
const value = evaluator.params[0];
|
||||
thresholds.push({ value: value, op: 'ge', visible });
|
||||
break;
|
||||
}
|
||||
case 'lte': {
|
||||
const value = evaluator.params[0];
|
||||
thresholds.push({ value: value, op: 'le', visible });
|
||||
break;
|
||||
}
|
||||
case 'outside_range': {
|
||||
const value1 = evaluator.params[0];
|
||||
const value2 = evaluator.params[1];
|
||||
@@ -56,6 +76,33 @@ export class ThresholdMapper {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'outside_range_included': {
|
||||
const value1 = evaluator.params[0];
|
||||
const value2 = evaluator.params[1];
|
||||
|
||||
if (value1 >= value2) {
|
||||
thresholds.push({ value: value1, op: 'ge', visible });
|
||||
thresholds.push({ value: value2, op: 'le', visible });
|
||||
} else {
|
||||
thresholds.push({ value: value1, op: 'le', visible });
|
||||
thresholds.push({ value: value2, op: 'ge', visible });
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 'within_range_included': {
|
||||
const value1 = evaluator.params[0];
|
||||
const value2 = evaluator.params[1];
|
||||
|
||||
if (value1 >= value2) {
|
||||
thresholds.push({ value: value1, op: 'le', visible });
|
||||
thresholds.push({ value: value2, op: 'ge', visible });
|
||||
} else {
|
||||
thresholds.push({ value: value1, op: 'ge', visible });
|
||||
thresholds.push({ value: value2, op: 'le', visible });
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -32,16 +32,28 @@ const alertStateSortScore = {
|
||||
export enum EvalFunction {
|
||||
'IsAbove' = 'gt',
|
||||
'IsBelow' = 'lt',
|
||||
'IsEqual' = 'eq',
|
||||
'IsNotEqual' = 'ne',
|
||||
'IsGreaterThanEqual' = 'gte',
|
||||
'IsLessThanEqual' = 'lte',
|
||||
'IsOutsideRange' = 'outside_range',
|
||||
'IsWithinRange' = 'within_range',
|
||||
'IsWithinRangeIncluded' = 'within_range_included',
|
||||
'IsOutsideRangeIncluded' = 'outside_range_included',
|
||||
'HasNoValue' = 'no_value',
|
||||
}
|
||||
|
||||
const evalFunctions = [
|
||||
{ value: EvalFunction.IsAbove, text: 'IS ABOVE' },
|
||||
{ value: EvalFunction.IsBelow, text: 'IS BELOW' },
|
||||
{ value: EvalFunction.IsEqual, text: 'IS EQUAL TO' },
|
||||
{ value: EvalFunction.IsNotEqual, text: 'IS NOT EQUAL TO' },
|
||||
{ value: EvalFunction.IsGreaterThanEqual, text: 'IS ABOVE OR EQUAL TO' },
|
||||
{ value: EvalFunction.IsLessThanEqual, text: 'IS BELOW OR EQUAL TO' },
|
||||
{ value: EvalFunction.IsOutsideRange, text: 'IS OUTSIDE RANGE' },
|
||||
{ value: EvalFunction.IsWithinRange, text: 'IS WITHIN RANGE' },
|
||||
{ value: EvalFunction.IsOutsideRangeIncluded, text: 'IS OUTSIDE RANGE INCLUDED' },
|
||||
{ value: EvalFunction.IsWithinRangeIncluded, text: 'IS WITHIN RANGE INCLUDED' },
|
||||
{ value: EvalFunction.HasNoValue, text: 'HAS NO VALUE' },
|
||||
];
|
||||
|
||||
|
||||
@@ -538,5 +538,10 @@ const getCommonQueryStyles = (theme: GrafanaTheme2) => ({
|
||||
});
|
||||
|
||||
function isRangeEvaluator(evaluator: { params: number[]; type: EvalFunction }) {
|
||||
return evaluator.type === EvalFunction.IsWithinRange || evaluator.type === EvalFunction.IsOutsideRange;
|
||||
return (
|
||||
evaluator.type === EvalFunction.IsWithinRange ||
|
||||
evaluator.type === EvalFunction.IsOutsideRange ||
|
||||
evaluator.type === EvalFunction.IsOutsideRangeIncluded ||
|
||||
evaluator.type === EvalFunction.IsWithinRangeIncluded
|
||||
);
|
||||
}
|
||||
|
||||
@@ -279,6 +279,53 @@ export function getThresholdsForQueries(queries: AlertQuery[], condition: string
|
||||
);
|
||||
}
|
||||
|
||||
if (type === EvalFunction.IsWithinRangeIncluded) {
|
||||
thresholds[refId].config.steps.push(
|
||||
...[
|
||||
{
|
||||
value: -Infinity,
|
||||
color: 'transparent',
|
||||
},
|
||||
{
|
||||
value: values[0],
|
||||
color: config.theme2.colors.error.main,
|
||||
},
|
||||
{
|
||||
value: values[1],
|
||||
color: config.theme2.colors.error.main,
|
||||
},
|
||||
{
|
||||
value: values[1],
|
||||
color: 'transparent',
|
||||
},
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
if (type === EvalFunction.IsOutsideRangeIncluded) {
|
||||
thresholds[refId].config.steps.push(
|
||||
...[
|
||||
{
|
||||
value: -Infinity,
|
||||
color: config.theme2.colors.error.main,
|
||||
},
|
||||
// we have to duplicate this value, or the graph will not display the handle in the right color
|
||||
{
|
||||
value: values[0],
|
||||
color: config.theme2.colors.error.main,
|
||||
},
|
||||
{
|
||||
value: values[0],
|
||||
color: 'transparent',
|
||||
},
|
||||
{
|
||||
value: values[1],
|
||||
color: config.theme2.colors.error.main,
|
||||
},
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
// now also sort the threshold values, if we don't then they will look weird in the time series panel
|
||||
// TODO this doesn't work for negative values for now, those need to be sorted inverse
|
||||
thresholds[refId].config.steps.sort((a, b) => a.value - b.value);
|
||||
@@ -292,7 +339,10 @@ export function getThresholdsForQueries(queries: AlertQuery[], condition: string
|
||||
|
||||
function isRangeCondition(condition: ClassicCondition) {
|
||||
return (
|
||||
condition.evaluator.type === EvalFunction.IsWithinRange || condition.evaluator.type === EvalFunction.IsOutsideRange
|
||||
condition.evaluator.type === EvalFunction.IsWithinRange ||
|
||||
condition.evaluator.type === EvalFunction.IsOutsideRange ||
|
||||
condition.evaluator.type === EvalFunction.IsOutsideRangeIncluded ||
|
||||
condition.evaluator.type === EvalFunction.IsWithinRangeIncluded
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -69,7 +69,10 @@ export const Condition = ({ condition, index, onChange, onRemoveCondition, refId
|
||||
});
|
||||
|
||||
const isRange =
|
||||
condition.evaluator.type === EvalFunction.IsWithinRange || condition.evaluator.type === EvalFunction.IsOutsideRange;
|
||||
condition.evaluator.type === EvalFunction.IsWithinRange ||
|
||||
condition.evaluator.type === EvalFunction.IsOutsideRange ||
|
||||
condition.evaluator.type === EvalFunction.IsOutsideRangeIncluded ||
|
||||
condition.evaluator.type === EvalFunction.IsWithinRangeIncluded;
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
|
||||
@@ -5,8 +5,9 @@ import * as React from 'react';
|
||||
import { FormEvent, useEffect, useReducer } from 'react';
|
||||
|
||||
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
|
||||
import { InlineField, InlineFieldRow, InlineSwitch, Input, Select, useStyles2, Stack } from '@grafana/ui';
|
||||
import { InlineField, InlineFieldRow, InlineSwitch, Input, Select, Stack, useStyles2 } from '@grafana/ui';
|
||||
import { config } from 'app/core/config';
|
||||
import { t } from 'app/core/internationalization';
|
||||
import { EvalFunction } from 'app/features/alerting/state/alertDef';
|
||||
|
||||
import { ClassicCondition, ExpressionQuery, thresholdFunctions } from '../types';
|
||||
@@ -81,7 +82,9 @@ export const Threshold = ({ labelWidth, onChange, refIds, query, onError, useHys
|
||||
|
||||
const isRange =
|
||||
conditionInState.evaluator.type === EvalFunction.IsWithinRange ||
|
||||
conditionInState.evaluator.type === EvalFunction.IsOutsideRange;
|
||||
conditionInState.evaluator.type === EvalFunction.IsOutsideRange ||
|
||||
conditionInState.evaluator.type === EvalFunction.IsOutsideRangeIncluded ||
|
||||
conditionInState.evaluator.type === EvalFunction.IsWithinRangeIncluded;
|
||||
|
||||
const hysteresisEnabled = Boolean(config.featureToggles?.recoveryThreshold) && useHysteresis;
|
||||
|
||||
@@ -155,7 +158,7 @@ export const Threshold = ({ labelWidth, onChange, refIds, query, onError, useHys
|
||||
<div onMouseDown={onHysteresisCheckDown}>
|
||||
<InlineSwitch
|
||||
showLabel={true}
|
||||
label="Custom recovery threshold"
|
||||
label={t('alerting.rule-form.threshold.recovery.title', 'Custom recovery threshold')}
|
||||
value={hasHysteresis}
|
||||
onChange={onHysteresisCheckChange}
|
||||
className={styles.switch}
|
||||
@@ -211,111 +214,286 @@ function RecoveryThresholdRow({ isRange, condition, onError, dispatch, allowOnbl
|
||||
}
|
||||
|
||||
function RecoveryForRange({ allowOnblur }: RecoveryProps) {
|
||||
if (condition.evaluator.type === EvalFunction.IsWithinRange) {
|
||||
return (
|
||||
<InlineFieldRow className={styles.hysteresis}>
|
||||
<InlineField label="Stop alerting when outside range" labelWidth={'auto'}>
|
||||
<Stack direction="row" gap={0}>
|
||||
<div className={styles.range}>
|
||||
<InlineField invalid={Boolean(errorMsgFrom)} error={errorMsgFrom} className={styles.noMargin}>
|
||||
<Input
|
||||
type="number"
|
||||
width={10}
|
||||
onBlur={(event) => allowOnblur.current && onUnloadValueChange(event, 0)}
|
||||
defaultValue={condition.unloadEvaluator?.params[0]}
|
||||
/>
|
||||
</InlineField>
|
||||
</div>
|
||||
<ToLabel />
|
||||
<div className={styles.range}>
|
||||
<InlineField invalid={Boolean(errorMsgTo)} error={errorMsgTo}>
|
||||
<Input
|
||||
type="number"
|
||||
width={10}
|
||||
onBlur={(event) => allowOnblur.current && onUnloadValueChange(event, 1)}
|
||||
defaultValue={condition.unloadEvaluator?.params[1]}
|
||||
/>
|
||||
</InlineField>
|
||||
</div>
|
||||
</Stack>
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<InlineFieldRow className={styles.hysteresis}>
|
||||
<InlineField label="Stop alerting when inside range" labelWidth={'auto'}>
|
||||
<Stack direction="row" gap={0}>
|
||||
<div className={styles.range}>
|
||||
<InlineField invalid={Boolean(errorMsgFrom)} error={errorMsgFrom}>
|
||||
<Input
|
||||
type="number"
|
||||
width={10}
|
||||
onBlur={(event) => allowOnblur.current && onUnloadValueChange(event, 0)}
|
||||
defaultValue={condition.unloadEvaluator?.params[0]}
|
||||
/>
|
||||
</InlineField>
|
||||
</div>
|
||||
switch (condition.evaluator.type) {
|
||||
case EvalFunction.IsWithinRange:
|
||||
if (condition.evaluator.type === EvalFunction.IsWithinRange) {
|
||||
return (
|
||||
<InlineFieldRow className={styles.hysteresis}>
|
||||
<InlineField
|
||||
label={t(
|
||||
'alerting.rule-form.threshold.recovery.stop-alerting-outside-range',
|
||||
'Stop alerting when outside range'
|
||||
)}
|
||||
labelWidth={'auto'}
|
||||
>
|
||||
<Stack direction="row" gap={0}>
|
||||
<div className={styles.range}>
|
||||
<InlineField invalid={Boolean(errorMsgFrom)} error={errorMsgFrom} className={styles.noMargin}>
|
||||
<Input
|
||||
type="number"
|
||||
width={10}
|
||||
onBlur={(event) => allowOnblur.current && onUnloadValueChange(event, 0)}
|
||||
defaultValue={condition.unloadEvaluator?.params[0]}
|
||||
/>
|
||||
</InlineField>
|
||||
</div>
|
||||
<ToLabel />
|
||||
<div className={styles.range}>
|
||||
<InlineField invalid={Boolean(errorMsgTo)} error={errorMsgTo}>
|
||||
<Input
|
||||
type="number"
|
||||
width={10}
|
||||
onBlur={(event) => allowOnblur.current && onUnloadValueChange(event, 1)}
|
||||
defaultValue={condition.unloadEvaluator?.params[1]}
|
||||
/>
|
||||
</InlineField>
|
||||
</div>
|
||||
</Stack>
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
);
|
||||
}
|
||||
case EvalFunction.IsOutsideRange:
|
||||
return (
|
||||
<InlineFieldRow className={styles.hysteresis}>
|
||||
<InlineField
|
||||
label={t(
|
||||
'alerting.rule-form.threshold.recovery.stop-alerting-inside-range',
|
||||
'Stop alerting when inside range'
|
||||
)}
|
||||
labelWidth={'auto'}
|
||||
>
|
||||
<Stack direction="row" gap={0}>
|
||||
<div className={styles.range}>
|
||||
<InlineField invalid={Boolean(errorMsgFrom)} error={errorMsgFrom}>
|
||||
<Input
|
||||
type="number"
|
||||
width={10}
|
||||
onBlur={(event) => allowOnblur.current && onUnloadValueChange(event, 0)}
|
||||
defaultValue={condition.unloadEvaluator?.params[0]}
|
||||
/>
|
||||
</InlineField>
|
||||
</div>
|
||||
|
||||
<ToLabel />
|
||||
<div className={styles.range}>
|
||||
<InlineField invalid={Boolean(errorMsgTo)} error={errorMsgTo}>
|
||||
<Input
|
||||
type="number"
|
||||
width={10}
|
||||
onBlur={(event) => allowOnblur.current && onUnloadValueChange(event, 1)}
|
||||
defaultValue={condition.unloadEvaluator?.params[1]}
|
||||
/>
|
||||
</InlineField>
|
||||
</div>
|
||||
</Stack>
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
);
|
||||
<ToLabel />
|
||||
<div className={styles.range}>
|
||||
<InlineField invalid={Boolean(errorMsgTo)} error={errorMsgTo}>
|
||||
<Input
|
||||
type="number"
|
||||
width={10}
|
||||
onBlur={(event) => allowOnblur.current && onUnloadValueChange(event, 1)}
|
||||
defaultValue={condition.unloadEvaluator?.params[1]}
|
||||
/>
|
||||
</InlineField>
|
||||
</div>
|
||||
</Stack>
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
);
|
||||
case EvalFunction.IsOutsideRangeIncluded:
|
||||
return (
|
||||
<InlineFieldRow className={styles.hysteresis}>
|
||||
<InlineField
|
||||
label={t(
|
||||
'alerting.rule-form.threshold.recovery.stop-alerting-inside-range',
|
||||
'Stop alerting when inside range'
|
||||
)}
|
||||
labelWidth={'auto'}
|
||||
>
|
||||
<Stack direction="row" gap={0}>
|
||||
<div className={styles.range}>
|
||||
<InlineField invalid={Boolean(errorMsgFrom)} error={errorMsgFrom}>
|
||||
<Input
|
||||
type="number"
|
||||
width={10}
|
||||
onBlur={(event) => allowOnblur.current && onUnloadValueChange(event, 0)}
|
||||
defaultValue={condition.unloadEvaluator?.params[0]}
|
||||
/>
|
||||
</InlineField>
|
||||
</div>
|
||||
<ToLabel />
|
||||
<div className={styles.range}>
|
||||
<InlineField invalid={Boolean(errorMsgTo)} error={errorMsgTo}>
|
||||
<Input
|
||||
type="number"
|
||||
width={10}
|
||||
onBlur={(event) => allowOnblur.current && onUnloadValueChange(event, 1)}
|
||||
defaultValue={condition.unloadEvaluator?.params[1]}
|
||||
/>
|
||||
</InlineField>
|
||||
</div>
|
||||
</Stack>
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
);
|
||||
case EvalFunction.IsWithinRangeIncluded:
|
||||
return (
|
||||
<InlineFieldRow className={styles.hysteresis}>
|
||||
<InlineField
|
||||
label={t(
|
||||
'alerting.rule-form.threshold.recovery.stop-alerting-outside-range',
|
||||
'Stop alerting when outside range'
|
||||
)}
|
||||
labelWidth={'auto'}
|
||||
>
|
||||
<Stack direction="row" gap={0}>
|
||||
<div className={styles.range}>
|
||||
<InlineField invalid={Boolean(errorMsgFrom)} error={errorMsgFrom}>
|
||||
<Input
|
||||
type="number"
|
||||
width={10}
|
||||
onBlur={(event) => allowOnblur.current && onUnloadValueChange(event, 0)}
|
||||
defaultValue={condition.unloadEvaluator?.params[0]}
|
||||
/>
|
||||
</InlineField>
|
||||
</div>
|
||||
<ToLabel />
|
||||
<div className={styles.range}>
|
||||
<InlineField invalid={Boolean(errorMsgTo)} error={errorMsgTo}>
|
||||
<Input
|
||||
type="number"
|
||||
width={10}
|
||||
onBlur={(event) => allowOnblur.current && onUnloadValueChange(event, 1)}
|
||||
defaultValue={condition.unloadEvaluator?.params[1]}
|
||||
/>
|
||||
</InlineField>
|
||||
</div>
|
||||
</Stack>
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function RecoveryForSingleValue({ allowOnblur }: RecoveryProps) {
|
||||
if (condition.evaluator.type === EvalFunction.IsAbove) {
|
||||
return (
|
||||
<InlineFieldRow className={styles.hysteresis}>
|
||||
<InlineField
|
||||
label="Stop alerting when below"
|
||||
labelWidth={'auto'}
|
||||
invalid={Boolean(invalidErrorMsg)}
|
||||
error={invalidErrorMsg}
|
||||
>
|
||||
<Input
|
||||
type="number"
|
||||
width={10}
|
||||
onBlur={(event) => {
|
||||
allowOnblur.current && onUnloadValueChange(event, 0);
|
||||
}}
|
||||
defaultValue={condition.unloadEvaluator?.params[0]}
|
||||
/>
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<InlineFieldRow className={styles.hysteresis}>
|
||||
<InlineField
|
||||
label="Stop alerting when above"
|
||||
labelWidth={'auto'}
|
||||
invalid={Boolean(invalidErrorMsg)}
|
||||
error={invalidErrorMsg}
|
||||
>
|
||||
<Input
|
||||
type="number"
|
||||
width={10}
|
||||
onBlur={(event) => {
|
||||
allowOnblur.current && onUnloadValueChange(event, 0);
|
||||
}}
|
||||
defaultValue={condition.unloadEvaluator?.params[0]}
|
||||
/>
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
);
|
||||
switch (condition.evaluator.type) {
|
||||
case EvalFunction.IsAbove:
|
||||
return (
|
||||
<InlineFieldRow className={styles.hysteresis}>
|
||||
<InlineField
|
||||
label={t('alerting.rule-form.threshold.recovery.stop-alerting-bellow', 'Stop alerting when below')}
|
||||
labelWidth={'auto'}
|
||||
invalid={Boolean(invalidErrorMsg)}
|
||||
error={invalidErrorMsg}
|
||||
>
|
||||
<Input
|
||||
type="number"
|
||||
width={10}
|
||||
onBlur={(event) => {
|
||||
allowOnblur.current && onUnloadValueChange(event, 0);
|
||||
}}
|
||||
defaultValue={condition.unloadEvaluator?.params[0]}
|
||||
/>
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
);
|
||||
case EvalFunction.IsBelow:
|
||||
return (
|
||||
<InlineFieldRow className={styles.hysteresis}>
|
||||
<InlineField
|
||||
label={t('alerting.rule-form.threshold.recovery.stop-alerting-above', 'Stop alerting when above')}
|
||||
labelWidth={'auto'}
|
||||
invalid={Boolean(invalidErrorMsg)}
|
||||
error={invalidErrorMsg}
|
||||
>
|
||||
<Input
|
||||
type="number"
|
||||
width={10}
|
||||
onBlur={(event) => {
|
||||
allowOnblur.current && onUnloadValueChange(event, 0);
|
||||
}}
|
||||
defaultValue={condition.unloadEvaluator?.params[0]}
|
||||
/>
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
);
|
||||
case EvalFunction.IsEqual:
|
||||
return (
|
||||
<InlineFieldRow className={styles.hysteresis}>
|
||||
<InlineField
|
||||
label={t('alerting.rule-form.threshold.recovery.stop-alerting-equal', 'Stop alerting when equal to')}
|
||||
labelWidth={'auto'}
|
||||
invalid={Boolean(invalidErrorMsg)}
|
||||
error={invalidErrorMsg}
|
||||
>
|
||||
<Input
|
||||
type="number"
|
||||
width={10}
|
||||
onBlur={(event) => {
|
||||
allowOnblur.current && onUnloadValueChange(event, 0);
|
||||
}}
|
||||
defaultValue={condition.unloadEvaluator?.params[0]}
|
||||
/>
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
);
|
||||
case EvalFunction.IsNotEqual:
|
||||
return (
|
||||
<InlineFieldRow className={styles.hysteresis}>
|
||||
<InlineField
|
||||
label={t(
|
||||
'alerting.rule-form.threshold.recovery.stop-alerting-not-equal',
|
||||
'Stop alerting when not equal to'
|
||||
)}
|
||||
labelWidth={'auto'}
|
||||
invalid={Boolean(invalidErrorMsg)}
|
||||
error={invalidErrorMsg}
|
||||
>
|
||||
<Input
|
||||
type="number"
|
||||
width={10}
|
||||
onBlur={(event) => {
|
||||
allowOnblur.current && onUnloadValueChange(event, 0);
|
||||
}}
|
||||
defaultValue={condition.unloadEvaluator?.params[0]}
|
||||
/>
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
);
|
||||
case EvalFunction.IsGreaterThanEqual:
|
||||
return (
|
||||
<InlineFieldRow className={styles.hysteresis}>
|
||||
<InlineField
|
||||
label={t('alerting.rule-form.threshold.recovery.stop-alerting-less', 'Stop alerting when less than')}
|
||||
labelWidth={'auto'}
|
||||
invalid={Boolean(invalidErrorMsg)}
|
||||
error={invalidErrorMsg}
|
||||
>
|
||||
<Input
|
||||
type="number"
|
||||
width={10}
|
||||
onBlur={(event) => {
|
||||
allowOnblur.current && onUnloadValueChange(event, 0);
|
||||
}}
|
||||
defaultValue={condition.unloadEvaluator?.params[0]}
|
||||
/>
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
);
|
||||
case EvalFunction.IsLessThanEqual:
|
||||
return (
|
||||
<InlineFieldRow className={styles.hysteresis}>
|
||||
<InlineField
|
||||
label={t('alerting.rule-form.threshold.recovery.stop-alerting-more', 'Stop alerting when more than')}
|
||||
labelWidth={'auto'}
|
||||
invalid={Boolean(invalidErrorMsg)}
|
||||
error={invalidErrorMsg}
|
||||
>
|
||||
<Input
|
||||
type="number"
|
||||
width={10}
|
||||
onBlur={(event) => {
|
||||
allowOnblur.current && onUnloadValueChange(event, 0);
|
||||
}}
|
||||
defaultValue={condition.unloadEvaluator?.params[0]}
|
||||
/>
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,12 +104,30 @@ function getUnloadEvaluatorTypeFromEvaluatorType(type: EvalFunction) {
|
||||
if (type === EvalFunction.IsBelow) {
|
||||
return EvalFunction.IsAbove;
|
||||
}
|
||||
if (type === EvalFunction.IsEqual) {
|
||||
return EvalFunction.IsNotEqual;
|
||||
}
|
||||
if (type === EvalFunction.IsNotEqual) {
|
||||
return EvalFunction.IsEqual;
|
||||
}
|
||||
if (type === EvalFunction.IsGreaterThanEqual) {
|
||||
return EvalFunction.IsLessThanEqual;
|
||||
}
|
||||
if (type === EvalFunction.IsLessThanEqual) {
|
||||
return EvalFunction.IsGreaterThanEqual;
|
||||
}
|
||||
if (type === EvalFunction.IsWithinRange) {
|
||||
return EvalFunction.IsOutsideRange;
|
||||
}
|
||||
if (type === EvalFunction.IsOutsideRange) {
|
||||
return EvalFunction.IsWithinRange;
|
||||
}
|
||||
if (type === EvalFunction.IsWithinRangeIncluded) {
|
||||
return EvalFunction.IsOutsideRangeIncluded;
|
||||
}
|
||||
if (type === EvalFunction.IsOutsideRangeIncluded) {
|
||||
return EvalFunction.IsWithinRangeIncluded;
|
||||
}
|
||||
return EvalFunction.IsBelow;
|
||||
}
|
||||
|
||||
@@ -126,7 +144,12 @@ export function isInvalid(condition: ClassicCondition) {
|
||||
const { type, params: loadParams } = evaluator;
|
||||
const { params: unloadParams } = unloadEvaluator;
|
||||
|
||||
if (type === EvalFunction.IsWithinRange || type === EvalFunction.IsOutsideRange) {
|
||||
if (
|
||||
type === EvalFunction.IsWithinRange ||
|
||||
type === EvalFunction.IsOutsideRange ||
|
||||
type === EvalFunction.IsWithinRangeIncluded ||
|
||||
type === EvalFunction.IsOutsideRangeIncluded
|
||||
) {
|
||||
if (unloadParams[0] === undefined || Number.isNaN(unloadParams[0])) {
|
||||
return { errorMsgFrom: 'This value cannot be empty' };
|
||||
}
|
||||
@@ -149,6 +172,26 @@ export function isInvalid(condition: ClassicCondition) {
|
||||
return { errorMsg: `Enter a number more than or equal to ${firstParamInEvaluator}` };
|
||||
}
|
||||
break;
|
||||
case EvalFunction.IsEqual:
|
||||
if (firstParamInUnloadEvaluator === firstParamInEvaluator) {
|
||||
return { errorMsg: `Enter a different number than ${firstParamInEvaluator}` };
|
||||
}
|
||||
break;
|
||||
case EvalFunction.IsNotEqual:
|
||||
if (firstParamInUnloadEvaluator !== firstParamInEvaluator) {
|
||||
return { errorMsg: `Enter the same number as ${firstParamInEvaluator}` };
|
||||
}
|
||||
break;
|
||||
case EvalFunction.IsGreaterThanEqual:
|
||||
if (firstParamInUnloadEvaluator >= firstParamInEvaluator) {
|
||||
return { errorMsg: `Enter a number less than ${firstParamInEvaluator}` };
|
||||
}
|
||||
break;
|
||||
case EvalFunction.IsLessThanEqual:
|
||||
if (firstParamInUnloadEvaluator <= firstParamInEvaluator) {
|
||||
return { errorMsg: `Enter a number more than ${firstParamInEvaluator}` };
|
||||
}
|
||||
break;
|
||||
case EvalFunction.IsOutsideRange:
|
||||
if (firstParamInUnloadEvaluator < firstParamInEvaluator) {
|
||||
return { errorMsgFrom: `Enter a number more than or equal to ${firstParamInEvaluator}` };
|
||||
@@ -165,6 +208,22 @@ export function isInvalid(condition: ClassicCondition) {
|
||||
return { errorMsgTo: `Enter a number be more than or equal to ${secondParamInEvaluator}` };
|
||||
}
|
||||
break;
|
||||
case EvalFunction.IsOutsideRangeIncluded:
|
||||
if (firstParamInUnloadEvaluator <= firstParamInEvaluator) {
|
||||
return { errorMsgFrom: `Enter a number more than ${firstParamInEvaluator}` };
|
||||
}
|
||||
if (secondParamInUnloadEvaluator >= secondParamInEvaluator) {
|
||||
return { errorMsgTo: `Enter a number less than ${secondParamInEvaluator}` };
|
||||
}
|
||||
break;
|
||||
case EvalFunction.IsWithinRangeIncluded:
|
||||
if (firstParamInUnloadEvaluator >= firstParamInEvaluator) {
|
||||
return { errorMsgFrom: `Enter a number less than ${firstParamInEvaluator}` };
|
||||
}
|
||||
if (secondParamInUnloadEvaluator <= secondParamInEvaluator) {
|
||||
return { errorMsgTo: `Enter a number be more than ${secondParamInEvaluator}` };
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new Error(`evaluator function type ${type} not supported.`);
|
||||
}
|
||||
|
||||
@@ -126,8 +126,14 @@ export const upsamplingTypes: Array<SelectableValue<string>> = [
|
||||
export const thresholdFunctions: Array<SelectableValue<EvalFunction>> = [
|
||||
{ value: EvalFunction.IsAbove, label: 'Is above' },
|
||||
{ value: EvalFunction.IsBelow, label: 'Is below' },
|
||||
{ value: EvalFunction.IsEqual, label: 'Is equal to' },
|
||||
{ value: EvalFunction.IsNotEqual, label: 'Is not equal to' },
|
||||
{ value: EvalFunction.IsGreaterThanEqual, label: 'Is above or equal to' },
|
||||
{ value: EvalFunction.IsLessThanEqual, label: 'Is below or equal to' },
|
||||
{ value: EvalFunction.IsWithinRange, label: 'Is within range' },
|
||||
{ value: EvalFunction.IsOutsideRange, label: 'Is outside range' },
|
||||
{ value: EvalFunction.IsWithinRangeIncluded, label: 'Is within range included' },
|
||||
{ value: EvalFunction.IsOutsideRangeIncluded, label: 'Is outside range included' },
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -528,6 +528,19 @@
|
||||
},
|
||||
"pause": {
|
||||
"label": "Pause evaluation"
|
||||
},
|
||||
"threshold": {
|
||||
"recovery": {
|
||||
"stop-alerting-above": "Stop alerting when above",
|
||||
"stop-alerting-bellow": "Stop alerting when below",
|
||||
"stop-alerting-equal": "Stop alerting when equal to",
|
||||
"stop-alerting-inside-range": "Stop alerting when inside range",
|
||||
"stop-alerting-less": "Stop alerting when less than",
|
||||
"stop-alerting-more": "Stop alerting when more than",
|
||||
"stop-alerting-not-equal": "Stop alerting when not equal to",
|
||||
"stop-alerting-outside-range": "Stop alerting when outside range",
|
||||
"title": "Custom recovery threshold"
|
||||
}
|
||||
}
|
||||
},
|
||||
"rule-groups": {
|
||||
|
||||
@@ -528,6 +528,19 @@
|
||||
},
|
||||
"pause": {
|
||||
"label": "Päūşę ęväľūäŧįőʼn"
|
||||
},
|
||||
"threshold": {
|
||||
"recovery": {
|
||||
"stop-alerting-above": "Ŝŧőp äľęřŧįʼnģ ŵĥęʼn äþővę",
|
||||
"stop-alerting-bellow": "Ŝŧőp äľęřŧįʼnģ ŵĥęʼn þęľőŵ",
|
||||
"stop-alerting-equal": "Ŝŧőp äľęřŧįʼnģ ŵĥęʼn ęqūäľ ŧő",
|
||||
"stop-alerting-inside-range": "Ŝŧőp äľęřŧįʼnģ ŵĥęʼn įʼnşįđę řäʼnģę",
|
||||
"stop-alerting-less": "Ŝŧőp äľęřŧįʼnģ ŵĥęʼn ľęşş ŧĥäʼn",
|
||||
"stop-alerting-more": "Ŝŧőp äľęřŧįʼnģ ŵĥęʼn mőřę ŧĥäʼn",
|
||||
"stop-alerting-not-equal": "Ŝŧőp äľęřŧįʼnģ ŵĥęʼn ʼnőŧ ęqūäľ ŧő",
|
||||
"stop-alerting-outside-range": "Ŝŧőp äľęřŧįʼnģ ŵĥęʼn őūŧşįđę řäʼnģę",
|
||||
"title": "Cūşŧőm řęčővęřy ŧĥřęşĥőľđ"
|
||||
}
|
||||
}
|
||||
},
|
||||
"rule-groups": {
|
||||
|
||||
Reference in New Issue
Block a user