[OBS-UX-MNGMT] Move the Alerting comparators from TriggersActionsUI plugin to the alerting-types package (#181584)

## Summary
 It fixes #179633

Observability created a Comparator type/enum, when ResponseOps is
already exporting one and other rules using it.
The only difference is the wording of not in between [I put the two
types side by side to compare]
Currently, we import the one in triggers-actions-ui-plugin , and then
update the not in between to match our Comparator.

### Comparing the two enums:
![Screenshot 2024-04-23 at 18 17
23](16429ff9-e672-4c16-92ed-488a2f66007d)

## For reviewers 🧪 
- Everything should work as expected: Alert flyout, Alert reason
message, Rule creation flyout, etc.
- I kept the `outside` comparator (replaced by `NOT BETWEEN`) for
backward compatibility
This commit is contained in:
Faisal Kanout 2024-05-28 15:34:52 +02:00 committed by GitHub
parent 69b28f317b
commit 4396bf6e2e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
135 changed files with 1238 additions and 1079 deletions

1
.github/CODEOWNERS vendored
View file

@ -21,6 +21,7 @@ x-pack/plugins/aiops @elastic/ml-ui
x-pack/packages/ml/aiops_test_utils @elastic/ml-ui
x-pack/test/alerting_api_integration/packages/helpers @elastic/response-ops
x-pack/test/alerting_api_integration/common/plugins/alerts @elastic/response-ops
x-pack/packages/kbn-alerting-comparators @elastic/response-ops
x-pack/examples/alerting_example @elastic/response-ops
x-pack/test/functional_with_es_ssl/plugins/alerts @elastic/response-ops
x-pack/plugins/alerting @elastic/response-ops

View file

@ -149,6 +149,7 @@
"@kbn/aiops-plugin": "link:x-pack/plugins/aiops",
"@kbn/aiops-test-utils": "link:x-pack/packages/ml/aiops_test_utils",
"@kbn/alerting-api-integration-test-plugin": "link:x-pack/test/alerting_api_integration/common/plugins/alerts",
"@kbn/alerting-comparators": "link:x-pack/packages/kbn-alerting-comparators",
"@kbn/alerting-example-plugin": "link:x-pack/examples/alerting_example",
"@kbn/alerting-fixture-plugin": "link:x-pack/test/functional_with_es_ssl/plugins/alerts",
"@kbn/alerting-plugin": "link:x-pack/plugins/alerting",

View file

@ -36,6 +36,8 @@
"@kbn/alerting-api-integration-helpers/*": ["x-pack/test/alerting_api_integration/packages/helpers/*"],
"@kbn/alerting-api-integration-test-plugin": ["x-pack/test/alerting_api_integration/common/plugins/alerts"],
"@kbn/alerting-api-integration-test-plugin/*": ["x-pack/test/alerting_api_integration/common/plugins/alerts/*"],
"@kbn/alerting-comparators": ["x-pack/packages/kbn-alerting-comparators"],
"@kbn/alerting-comparators/*": ["x-pack/packages/kbn-alerting-comparators/*"],
"@kbn/alerting-example-plugin": ["x-pack/examples/alerting_example"],
"@kbn/alerting-example-plugin/*": ["x-pack/examples/alerting_example/*"],
"@kbn/alerting-fixture-plugin": ["x-pack/test/functional_with_es_ssl/plugins/alerts"],

View file

@ -0,0 +1,5 @@
# @kbn/alerting-comparators
Contains type information and enum for the alerting rule comparators. e.g. >, <
This comparators are used extensively in Observability UI and server side. Also, in the triggers-actions-ui in some related UI like ThresholdExpression.

View file

@ -0,0 +1,7 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
export * from './src/comparators';

View file

@ -0,0 +1,12 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
module.exports = {
preset: '@kbn/test/jest_node',
rootDir: '../../..',
roots: ['<rootDir>/x-pack/packages/kbn-alerting-comparators'],
};

View file

@ -0,0 +1,5 @@
{
"type": "shared-common",
"id": "@kbn/alerting-comparators",
"owner": "@elastic/response-ops"
}

View file

@ -0,0 +1,6 @@
{
"name": "@kbn/alerting-comparators",
"private": true,
"version": "1.0.0",
"license": "Elastic License 2.0"
}

View file

@ -0,0 +1,20 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
export interface Comparator {
text: string;
value: string;
requiredValues: number;
}
export enum COMPARATORS {
GREATER_THAN = '>',
GREATER_THAN_OR_EQUALS = '>=',
BETWEEN = 'between',
LESS_THAN = '<',
LESS_THAN_OR_EQUALS = '<=',
NOT_BETWEEN = 'notBetween',
}

View file

@ -0,0 +1,18 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "target/types",
"types": [
"jest",
"node"
]
},
"include": [
"**/*.ts",
],
"exclude": [
"target/**/*"
],
"kbn_references": [
]
}

View file

@ -5,10 +5,8 @@
* 2.0.
*/
import {
Aggregators,
Comparator,
} from '@kbn/observability-plugin/common/custom_threshold_rule/types';
import { Aggregators } from '@kbn/observability-plugin/common/custom_threshold_rule/types';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { OBSERVABILITY_THRESHOLD_RULE_TYPE_ID } from '@kbn/rule-data-utils';
import { FIRED_ACTIONS_ID } from './constants';
import { createRule } from './create_rule';
@ -38,7 +36,7 @@ export const createCustomThresholdRule = async (
params: {
criteria: ruleParams.params?.criteria || [
{
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [1],
timeSize: 1,
timeUnit: 'm',

View file

@ -5,10 +5,8 @@
* 2.0.
*/
import {
Aggregators,
Comparator,
} from '@kbn/observability-plugin/common/custom_threshold_rule/types';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { Aggregators } from '@kbn/observability-plugin/common/custom_threshold_rule/types';
export const scenario1 = {
dataView: {
@ -22,7 +20,7 @@ export const scenario1 = {
params: {
criteria: [
{
comparator: Comparator.LT,
comparator: COMPARATORS.LESS_THAN,
threshold: [100],
timeSize: 1,
timeUnit: 'm',

View file

@ -5,10 +5,8 @@
* 2.0.
*/
import {
Aggregators,
Comparator,
} from '@kbn/observability-plugin/common/custom_threshold_rule/types';
import { Aggregators } from '@kbn/observability-plugin/common/custom_threshold_rule/types';
import { COMPARATORS } from '@kbn/alerting-comparators';
export const scenario2 = {
dataView: {
@ -22,7 +20,7 @@ export const scenario2 = {
params: {
criteria: [
{
comparator: Comparator.LT,
comparator: COMPARATORS.LESS_THAN,
threshold: [40],
timeSize: 1,
timeUnit: 'm',

View file

@ -5,11 +5,8 @@
* 2.0.
*/
import {
Aggregators,
Comparator,
} from '@kbn/observability-plugin/common/custom_threshold_rule/types';
import { Aggregators } from '@kbn/observability-plugin/common/custom_threshold_rule/types';
import { COMPARATORS } from '@kbn/alerting-comparators';
export const scenario3 = {
dataView: {
indexPattern: 'high-cardinality-data-fake_hosts.fake_hosts-*',
@ -22,7 +19,7 @@ export const scenario3 = {
params: {
criteria: [
{
comparator: Comparator.LT,
comparator: COMPARATORS.LESS_THAN,
threshold: [5],
timeSize: 1,
timeUnit: 'm',

View file

@ -5,10 +5,8 @@
* 2.0.
*/
import {
Aggregators,
Comparator,
} from '@kbn/observability-plugin/common/custom_threshold_rule/types';
import { Aggregators } from '@kbn/observability-plugin/common/custom_threshold_rule/types';
import { COMPARATORS } from '@kbn/alerting-comparators';
export const scenario4 = {
dataView: {
@ -22,7 +20,7 @@ export const scenario4 = {
params: {
criteria: [
{
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [80],
timeSize: 1,
timeUnit: 'm',

View file

@ -5,10 +5,8 @@
* 2.0.
*/
import {
Aggregators,
Comparator,
} from '@kbn/observability-plugin/common/custom_threshold_rule/types';
import { Aggregators } from '@kbn/observability-plugin/common/custom_threshold_rule/types';
import { COMPARATORS } from '@kbn/alerting-comparators';
export const scenario5 = {
dataView: {
@ -22,7 +20,7 @@ export const scenario5 = {
params: {
criteria: [
{
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [80],
timeSize: 5,
timeUnit: 'm',

View file

@ -5,10 +5,8 @@
* 2.0.
*/
import {
Aggregators,
Comparator,
} from '@kbn/observability-plugin/common/custom_threshold_rule/types';
import { Aggregators } from '@kbn/observability-plugin/common/custom_threshold_rule/types';
import { COMPARATORS } from '@kbn/alerting-comparators';
export const scenario6 = {
dataView: {
@ -22,7 +20,7 @@ export const scenario6 = {
params: {
criteria: [
{
comparator: Comparator.LT,
comparator: COMPARATORS.LESS_THAN,
threshold: [1],
timeSize: 1,
timeUnit: 'm',

View file

@ -18,5 +18,6 @@
"kbn_references": [
"@kbn/observability-plugin",
"@kbn/rule-data-utils",
"@kbn/alerting-comparators",
]
}

View file

@ -39,7 +39,6 @@
"@kbn/data-views-plugin",
"@kbn/share-plugin",
"@kbn/safer-lodash-set",
"@kbn/alerting-state-types",
"@kbn/alerting-types",
"@kbn/alerts-as-data-utils",
"@kbn/core-elasticsearch-client-server-mocks",
@ -70,7 +69,8 @@
"@kbn/core-execution-context-server-mocks",
"@kbn/react-kibana-context-render",
"@kbn/search-types",
"@kbn/core-security-server",
"@kbn/alerting-state-types",
"@kbn/core-security-server"
],
"exclude": [
"target/**/*"

View file

@ -4,10 +4,10 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import * as rt from 'io-ts';
import { TimeUnitChar } from '@kbn/observability-plugin/common/utils/formatters/duration';
import { ML_ANOMALY_THRESHOLD } from '@kbn/ml-anomaly-utils/anomaly_threshold';
import { InventoryItemType, SnapshotMetricType } from '@kbn/metrics-data-access-plugin/common';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { LEGACY_COMPARATORS } from '@kbn/observability-plugin/common/utils/convert_legacy_outside_comparator';
import { SnapshotCustomMetricInput } from '../../http_api';
export const METRIC_THRESHOLD_ALERT_TYPE_ID = 'metrics.alert.threshold';
@ -18,20 +18,6 @@ export enum InfraRuleType {
InventoryThreshold = 'metrics.alert.inventory.threshold',
}
export interface InfraRuleTypeParams {
[InfraRuleType.MetricThreshold]: MetricThresholdParams;
[InfraRuleType.InventoryThreshold]: InventoryMetricConditions;
}
export enum Comparator {
GT = '>',
LT = '<',
GT_OR_EQ = '>=',
LT_OR_EQ = '<=',
BETWEEN = 'between',
OUTSIDE_RANGE = 'outside',
}
export enum Aggregators {
COUNT = 'count',
AVERAGE = 'avg',
@ -53,27 +39,6 @@ export enum AlertStates {
ERROR,
}
const metricAnomalyNodeTypeRT = rt.union([rt.literal('hosts'), rt.literal('k8s')]);
const metricAnomalyMetricRT = rt.union([
rt.literal('memory_usage'),
rt.literal('network_in'),
rt.literal('network_out'),
]);
const metricAnomalyInfluencerFilterRT = rt.type({
fieldName: rt.string,
fieldValue: rt.string,
});
export interface MetricAnomalyParams {
nodeType: rt.TypeOf<typeof metricAnomalyNodeTypeRT>;
metric: rt.TypeOf<typeof metricAnomalyMetricRT>;
alertInterval?: string;
sourceId?: string;
spaceId?: string;
threshold: Exclude<ML_ANOMALY_THRESHOLD, ML_ANOMALY_THRESHOLD.LOW>;
influencerFilter: rt.TypeOf<typeof metricAnomalyInfluencerFilterRT> | undefined;
}
// Types for the executor
export interface InventoryMetricConditions {
@ -82,10 +47,10 @@ export interface InventoryMetricConditions {
timeUnit: TimeUnitChar;
sourceId?: string;
threshold: number[];
comparator: Comparator;
comparator: COMPARATORS | LEGACY_COMPARATORS;
customMetric?: SnapshotCustomMetricInput;
warningThreshold?: number[];
warningComparator?: Comparator;
warningComparator?: COMPARATORS | LEGACY_COMPARATORS;
}
export interface InventoryMetricThresholdParams {
@ -111,8 +76,8 @@ interface BaseMetricExpressionParams {
timeUnit: TimeUnitChar;
sourceId?: string;
threshold: number[];
comparator: Comparator;
warningComparator?: Comparator;
comparator: COMPARATORS | LEGACY_COMPARATORS;
warningComparator?: COMPARATORS | LEGACY_COMPARATORS;
warningThreshold?: number[];
}

View file

@ -8,7 +8,7 @@
import React from 'react';
import { ComponentMeta } from '@storybook/react';
import { LIGHT_THEME } from '@elastic/charts';
import { Comparator } from '../../../../common/alerting/metrics';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { Props, Threshold as Component } from './threshold';
export default {
@ -30,7 +30,7 @@ export default {
const defaultProps: Props = {
chartProps: { baseTheme: LIGHT_THEME },
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
id: 'componentId',
threshold: 90,
title: 'Threshold breached',

View file

@ -6,7 +6,7 @@
*/
import { LIGHT_THEME } from '@elastic/charts';
import { Comparator } from '../../../../common/alerting/metrics';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { render } from '@testing-library/react';
import { Props, Threshold } from './threshold';
import React from 'react';
@ -15,7 +15,7 @@ describe('Threshold', () => {
const renderComponent = (props: Partial<Props> = {}) => {
const defaultProps: Props = {
chartProps: { baseTheme: LIGHT_THEME },
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
id: 'componentId',
threshold: 90,
title: 'Threshold breached',

View file

@ -10,8 +10,7 @@ import { Chart, Metric, Settings } from '@elastic/charts';
import { EuiIcon, EuiPanel, useEuiBackgroundColor } from '@elastic/eui';
import type { PartialTheme, Theme } from '@elastic/charts';
import { i18n } from '@kbn/i18n';
import { Comparator } from '../../../../common/alerting/metrics';
import { COMPARATORS } from '@kbn/alerting-comparators';
export interface ChartProps {
theme?: PartialTheme;
baseTheme: Theme;
@ -19,7 +18,7 @@ export interface ChartProps {
export interface Props {
chartProps: ChartProps;
comparator: Comparator | string;
comparator: COMPARATORS | string;
id: string;
threshold: number;
title: string;

View file

@ -6,7 +6,7 @@
*/
import { shallow } from 'enzyme';
import React from 'react';
import { Comparator } from '../../../../common/alerting/metrics';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { Color } from '../../../../common/color_palette';
import { ThresholdAnnotations } from './threshold_annotations';
@ -29,7 +29,7 @@ describe('ThresholdAnnotations', () => {
const defaultProps = {
threshold: [20, 30],
sortedThresholds: [20, 30],
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
color: Color.color0,
id: 'testId',
firstTimestamp: 123456789,
@ -53,7 +53,7 @@ describe('ThresholdAnnotations', () => {
});
it('should render a rectangular annotation for in between thresholds', async () => {
const wrapper = await setup({ comparator: Comparator.BETWEEN });
const wrapper = await setup({ comparator: COMPARATORS.BETWEEN });
const annotation = wrapper.find('[data-test-subj="between-rect"]');
const expectedValues = [
@ -72,7 +72,7 @@ describe('ThresholdAnnotations', () => {
});
it('should render an upper rectangular annotation for outside range thresholds', async () => {
const wrapper = await setup({ comparator: Comparator.OUTSIDE_RANGE });
const wrapper = await setup({ comparator: COMPARATORS.NOT_BETWEEN });
const annotation = wrapper.find('[data-test-subj="outside-range-lower-rect"]');
const expectedValues = [
@ -91,7 +91,7 @@ describe('ThresholdAnnotations', () => {
});
it('should render a lower rectangular annotation for outside range thresholds', async () => {
const wrapper = await setup({ comparator: Comparator.OUTSIDE_RANGE });
const wrapper = await setup({ comparator: COMPARATORS.NOT_BETWEEN });
const annotation = wrapper.find('[data-test-subj="outside-range-upper-rect"]');
const expectedValues = [
@ -110,7 +110,7 @@ describe('ThresholdAnnotations', () => {
});
it('should render a rectangular annotation for below thresholds', async () => {
const wrapper = await setup({ comparator: Comparator.LT });
const wrapper = await setup({ comparator: COMPARATORS.LESS_THAN });
const annotation = wrapper.find('[data-test-subj="below-rect"]');
const expectedValues = [
@ -129,7 +129,7 @@ describe('ThresholdAnnotations', () => {
});
it('should render a rectangular annotation for above thresholds', async () => {
const wrapper = await setup({ comparator: Comparator.GT });
const wrapper = await setup({ comparator: COMPARATORS.GREATER_THAN });
const annotation = wrapper.find('[data-test-subj="above-rect"]');
const expectedValues = [

View file

@ -7,13 +7,13 @@
import { AnnotationDomainType, LineAnnotation, RectAnnotation } from '@elastic/charts';
import { first, last } from 'lodash';
import React from 'react';
import { Comparator } from '../../../../common/alerting/metrics';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { Color, colorTransformer } from '../../../../common/color_palette';
interface ThresholdAnnotationsProps {
threshold: number[];
sortedThresholds: number[];
comparator: Comparator;
comparator: COMPARATORS;
color: Color;
id: string;
firstTimestamp: number;
@ -34,8 +34,10 @@ export const ThresholdAnnotations = ({
domain,
}: ThresholdAnnotationsProps) => {
if (!comparator || !threshold) return null;
const isAbove = [Comparator.GT, Comparator.GT_OR_EQ].includes(comparator);
const isBelow = [Comparator.LT, Comparator.LT_OR_EQ].includes(comparator);
const isAbove = [COMPARATORS.GREATER_THAN, COMPARATORS.GREATER_THAN_OR_EQUALS].includes(
comparator
);
const isBelow = [COMPARATORS.LESS_THAN, COMPARATORS.LESS_THAN_OR_EQUALS].includes(comparator);
return (
<>
<LineAnnotation
@ -53,7 +55,7 @@ export const ThresholdAnnotations = ({
},
}}
/>
{sortedThresholds.length === 2 && comparator === Comparator.BETWEEN ? (
{sortedThresholds.length === 2 && comparator === COMPARATORS.BETWEEN ? (
<>
<RectAnnotation
id={`${id}-lower-threshold`}
@ -75,7 +77,7 @@ export const ThresholdAnnotations = ({
/>
</>
) : null}
{sortedThresholds.length === 2 && comparator === Comparator.OUTSIDE_RANGE ? (
{sortedThresholds.length === 2 && comparator === COMPARATORS.NOT_BETWEEN ? (
<>
<RectAnnotation
id={`${id}-lower-threshold`}

View file

@ -11,7 +11,8 @@ import { act } from 'react-dom/test-utils';
import { DataView, type FieldSpec } from '@kbn/data-views-plugin/common';
// We are using this inside a `jest.mock` call. Jest requires dynamic dependencies to be prefixed with `mock`
import { coreMock as mockCoreMock } from '@kbn/core/public/mocks';
import { Comparator, InventoryMetricConditions } from '../../../../common/alerting/metrics';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { InventoryMetricConditions } from '../../../../common/alerting/metrics';
import { AlertContextMeta, defaultExpression, ExpressionRow, Expressions } from './expression';
import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks';
import { ResolvedDataView } from '../../../utils/data_view';
@ -111,7 +112,7 @@ describe('Expression', () => {
expect(ruleParams.criteria).toEqual([
{
metric: 'memory',
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [],
timeSize: 1,
timeUnit: 'm',
@ -131,7 +132,7 @@ describe('Expression', () => {
timeSize: 1,
timeUnit: 'm',
threshold: [10],
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
},
],
nodeType: undefined,
@ -173,7 +174,7 @@ describe('Expression', () => {
expect(ruleParams.criteria).toEqual([
{
metric: 'custom',
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [],
timeSize: 1,
timeUnit: 'm',
@ -217,7 +218,7 @@ describe('ExpressionRow', () => {
}
const expression = {
metric: 'custom',
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [],
timeSize: 1,
timeUnit: 'm',

View file

@ -52,16 +52,17 @@ import {
SnapshotMetricType,
SnapshotMetricTypeRT,
} from '@kbn/metrics-data-access-plugin/common';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { convertToBuiltInComparators } from '@kbn/observability-plugin/common';
import {
SnapshotCustomMetricInput,
SnapshotCustomMetricInputRT,
} from '../../../../common/http_api';
import {
Comparator,
FilterQuery,
InventoryMetricConditions,
QUERY_INVALID,
} from '../../../../common/alerting/metrics';
import {
SnapshotCustomMetricInput,
SnapshotCustomMetricInputRT,
} from '../../../../common/http_api/snapshot_api';
import { toMetricOpt } from '../../../../common/snapshot_metric_i18n';
import {
useMetricsDataViewContext,
@ -106,7 +107,7 @@ type Props = Omit<
export const defaultExpression = {
metric: 'cpu' as SnapshotMetricType,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [],
timeSize: 1,
timeUnit: 'm',
@ -447,7 +448,7 @@ export const ExpressionRow: FC<PropsWithChildren<ExpressionRowProps>> = (props)
const { children, setRuleParams, expression, errors, expressionId, remove, canDelete } = props;
const {
metric,
comparator = Comparator.GT,
comparator = COMPARATORS.GREATER_THAN,
threshold = [],
customMetric,
warningThreshold = [],
@ -478,14 +479,14 @@ export const ExpressionRow: FC<PropsWithChildren<ExpressionRowProps>> = (props)
const updateComparator = useCallback(
(c?: string) => {
setRuleParams(expressionId, { ...expression, comparator: c as Comparator | undefined });
setRuleParams(expressionId, { ...expression, comparator: c as COMPARATORS | undefined });
},
[expressionId, expression, setRuleParams]
);
const updateWarningComparator = useCallback(
(c?: string) => {
setRuleParams(expressionId, { ...expression, warningComparator: c as Comparator });
setRuleParams(expressionId, { ...expression, warningComparator: c as COMPARATORS });
},
[expressionId, expression, setRuleParams]
);
@ -713,7 +714,7 @@ const ThresholdElement: React.FC<{
<>
<div css={StyledExpressionCss}>
<ThresholdExpression
thresholdComparator={comparator || Comparator.GT}
thresholdComparator={convertToBuiltInComparators(comparator) || COMPARATORS.GREATER_THAN}
threshold={threshold}
onChangeSelectedThresholdComparator={updateComparator}
onChangeSelectedThreshold={updateThreshold}

View file

@ -12,6 +12,7 @@ import moment from 'moment';
import React, { useCallback, useMemo } from 'react';
import { i18n } from '@kbn/i18n';
import { InventoryItemType, SnapshotMetricType } from '@kbn/metrics-data-access-plugin/common';
import { convertToBuiltInComparators } from '@kbn/observability-plugin/common';
import { useTimelineChartTheme } from '../../../utils/use_timeline_chart_theme';
import { InventoryMetricConditions } from '../../../../common/alerting/metrics';
import { Color } from '../../../../common/color_palette';
@ -166,7 +167,7 @@ export const ExpressionChart: React.FC<Props> = ({
stack={false}
/>
<ThresholdAnnotations
comparator={expression.comparator}
comparator={convertToBuiltInComparators(expression.comparator)}
threshold={convertedThresholds}
sortedThresholds={criticalThresholds}
color={Color.color1}
@ -177,7 +178,7 @@ export const ExpressionChart: React.FC<Props> = ({
/>
{expression.warningComparator && expression.warningThreshold && (
<ThresholdAnnotations
comparator={expression.warningComparator}
comparator={convertToBuiltInComparators(expression.warningComparator)}
threshold={convertedWarningThresholds}
sortedThresholds={warningThresholds}
color={Color.color5}

View file

@ -7,8 +7,8 @@
import { i18n } from '@kbn/i18n';
import type { ValidationResult } from '@kbn/triggers-actions-ui-plugin/public';
import { COMPARATORS } from '@kbn/alerting-comparators';
import {
Comparator,
FilterQuery,
InventoryMetricConditions,
QUERY_INVALID,
@ -91,7 +91,7 @@ export function validateMetricThreshold({
// The Threshold component returns an empty array with a length ([empty]) because it's using delete newThreshold[i].
// We need to use [...c.threshold] to convert it to an array with an undefined value ([undefined]) so we can test each element.
const { comparator, threshold, type } = props as {
comparator?: Comparator;
comparator?: COMPARATORS;
threshold?: number[];
type: 'critical' | 'warning';
};
@ -108,7 +108,7 @@ export function validateMetricThreshold({
});
}
if (comparator === Comparator.BETWEEN && (!threshold || threshold.length < 2)) {
if (comparator === COMPARATORS.BETWEEN && (!threshold || threshold.length < 2)) {
errors[id][type].threshold1.push(
i18n.translate('xpack.infra.metrics.alertFlyout.error.thresholdRequired', {
defaultMessage: 'Threshold is required.',

View file

@ -9,11 +9,8 @@ import { Meta, Story } from '@storybook/react/types-6-0';
import React, { useCallback, useEffect, useState } from 'react';
import { TimeUnitChar } from '@kbn/observability-plugin/common';
import { IErrorObject } from '@kbn/triggers-actions-ui-plugin/public';
import {
Aggregators,
Comparator,
MetricExpressionParams,
} from '../../../../../common/alerting/metrics';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { Aggregators, MetricExpressionParams } from '../../../../../common/alerting/metrics';
import { decorateWithGlobalStorybookThemeProviders } from '../../../../test_utils/use_global_storybook_theme';
import { CustomEquationEditor, CustomEquationEditorProps } from './custom_equation_editor';
import { aggregationType } from '../expression_row';
@ -74,7 +71,7 @@ const BASE_ARGS = {
timeSize: 1,
timeUnit: 'm' as TimeUnitChar,
threshold: [1],
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
},
fields: [
{ name: 'system.cpu.user.pct', normalizedType: 'number' },

View file

@ -10,7 +10,7 @@ import React from 'react';
import { act } from 'react-dom/test-utils';
// We are using this inside a `jest.mock` call. Jest requires dynamic dependencies to be prefixed with `mock`
import { coreMock as mockCoreMock } from '@kbn/core/public/mocks';
import { Comparator } from '../../../../common/alerting/metrics';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { MetricsExplorerMetric } from '../../../../common/http_api/metrics_explorer';
import { Expressions } from './expression';
import type { DataView } from '@kbn/data-views-plugin/common';
@ -102,7 +102,7 @@ describe('Expression', () => {
expect(ruleParams.criteria).toEqual([
{
metric: 'system.load.1',
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [],
timeSize: 1,
timeUnit: 'm',
@ -110,7 +110,7 @@ describe('Expression', () => {
},
{
metric: 'system.cpu.user.pct',
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [],
timeSize: 1,
timeUnit: 'm',

View file

@ -28,12 +28,13 @@ import {
RuleTypeParamsExpressionProps,
} from '@kbn/triggers-actions-ui-plugin/public';
import { TimeUnitChar } from '@kbn/observability-plugin/common/utils/formatters/duration';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { Aggregators, QUERY_INVALID } from '../../../../common/alerting/metrics';
import {
useMetricsDataViewContext,
useSourceContext,
withSourceProvider,
} from '../../../containers/metrics_source';
import { Aggregators, Comparator, QUERY_INVALID } from '../../../../common/alerting/metrics';
import { useKibanaContextForPlugin } from '../../../hooks/use_kibana';
import { MetricsExplorerGroupBy } from '../../../pages/metrics/metrics_explorer/components/group_by';
import { MetricsExplorerKueryBar } from '../../../pages/metrics/metrics_explorer/components/kuery_bar';
@ -57,7 +58,7 @@ type Props = Omit<
const defaultExpression = {
aggType: Aggregators.AVERAGE,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [],
timeSize: 1,
timeUnit: 'm',
@ -182,7 +183,7 @@ export const Expressions: React.FC<Props> = (props) => {
'criteria',
md.currentOptions.metrics.map((metric) => ({
metric: metric.field,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [],
timeSize,
timeUnit,

View file

@ -11,7 +11,8 @@ import { LineAnnotation, RectAnnotation } from '@elastic/charts';
import { mountWithIntl, nextTick } from '@kbn/test-jest-helpers';
// We are using this inside a `jest.mock` call. Jest requires dynamic dependencies to be prefixed with `mock`
import { coreMock as mockCoreMock } from '@kbn/core/public/mocks';
import { Aggregators, Comparator } from '../../../../common/alerting/metrics';
import { Aggregators } from '../../../../common/alerting/metrics';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { MetricExpression } from '../types';
import type { DataView } from '@kbn/data-views-plugin/common';
import { ExpressionChart } from './expression_chart';
@ -105,7 +106,7 @@ describe('ExpressionChart', () => {
timeUnit: 'm',
sourceId: 'default',
threshold: [1],
comparator: Comparator.GT_OR_EQ,
comparator: COMPARATORS.GREATER_THAN_OR_EQUALS,
};
const { wrapper } = await setup(expression);
expect(wrapper.find('[data-test-subj~="noChartData"]').exists()).toBeTruthy();

View file

@ -22,6 +22,7 @@ import { useActiveCursor } from '@kbn/charts-plugin/public';
import { first, last } from 'lodash';
import { i18n } from '@kbn/i18n';
import { convertToBuiltInComparators } from '@kbn/observability-plugin/common';
import { useTimelineChartTheme } from '../../../utils/use_timeline_chart_theme';
import { Color } from '../../../../common/color_palette';
import { MetricsExplorerRow, MetricsExplorerAggregation } from '../../../../common/http_api';
@ -155,7 +156,7 @@ export const ExpressionChart: React.FC<Props> = ({
stack={false}
/>
<ThresholdAnnotations
comparator={expression.comparator}
comparator={convertToBuiltInComparators(expression.comparator)}
threshold={expression.threshold}
sortedThresholds={criticalThresholds}
color={Color.color1}
@ -166,7 +167,7 @@ export const ExpressionChart: React.FC<Props> = ({
/>
{expression.warningComparator && expression.warningThreshold && (
<ThresholdAnnotations
comparator={expression.warningComparator}
comparator={convertToBuiltInComparators(expression.comparator)}
threshold={expression.warningThreshold}
sortedThresholds={warningThresholds}
color={Color.color5}

View file

@ -9,7 +9,7 @@ import { ResolvedDataView } from '../../../utils/data_view';
import { mountWithIntl, nextTick } from '@kbn/test-jest-helpers';
import React from 'react';
import { act } from 'react-dom/test-utils';
import { Comparator } from '../../../../common/alerting/metrics';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { MetricExpression } from '../types';
import { ExpressionRow } from './expression_row';
import { TIMESTAMP_FIELD } from '../../../../common/constants';
@ -88,7 +88,7 @@ describe('ExpressionRow', () => {
it('should display thresholds as a percentage for pct metrics', async () => {
const expression = {
metric: 'system.cpu.user.pct',
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.5],
timeSize: 1,
timeUnit: 'm',
@ -107,7 +107,7 @@ describe('ExpressionRow', () => {
it('should display thresholds as a decimal for all other metrics', async () => {
const expression = {
metric: 'system.load.1',
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.5],
timeSize: 1,
timeUnit: 'm',
@ -125,7 +125,7 @@ describe('ExpressionRow', () => {
it('should render a helpText for the of expression', async () => {
const expression = {
metric: 'system.load.1',
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.5],
timeSize: 1,
timeUnit: 'm',

View file

@ -21,31 +21,21 @@ import React, { PropsWithChildren, useCallback, useMemo, useState } from 'react'
import { euiStyled } from '@kbn/kibana-react-plugin/common';
import {
AggregationType,
builtInComparators,
IErrorObject,
OfExpression,
ThresholdExpression,
WhenExpression,
} from '@kbn/triggers-actions-ui-plugin/public';
import useToggle from 'react-use/lib/useToggle';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { convertToBuiltInComparators } from '@kbn/observability-plugin/common';
import { Aggregators } from '../../../../common/alerting/metrics';
import { useMetricsDataViewContext } from '../../../containers/metrics_source';
import { Aggregators, Comparator } from '../../../../common/alerting/metrics';
import { decimalToPct, pctToDecimal } from '../../../../common/utils/corrected_percent_convert';
import { AGGREGATION_TYPES, MetricExpression } from '../types';
import { CustomEquationEditor } from './custom_equation';
import { CUSTOM_EQUATION } from '../i18n_strings';
const customComparators = {
...builtInComparators,
[Comparator.OUTSIDE_RANGE]: {
text: i18n.translate('xpack.infra.metrics.alertFlyout.outsideRangeLabel', {
defaultMessage: 'Is not between',
}),
value: Comparator.OUTSIDE_RANGE,
requiredValues: 2,
},
};
interface ExpressionRowProps {
expressionId: number;
expression: MetricExpression;
@ -81,7 +71,7 @@ export const ExpressionRow = ({
const {
aggType = AGGREGATION_TYPES.MAX,
metric,
comparator = Comparator.GT,
comparator = COMPARATORS.GREATER_THAN,
threshold = [],
warningThreshold = [],
warningComparator,
@ -115,14 +105,14 @@ export const ExpressionRow = ({
const updateComparator = useCallback(
(c?: string) => {
setRuleParams(expressionId, { ...expression, comparator: c as Comparator });
setRuleParams(expressionId, { ...expression, comparator: c as COMPARATORS });
},
[expressionId, expression, setRuleParams]
);
const updateWarningComparator = useCallback(
(c?: string) => {
setRuleParams(expressionId, { ...expression, warningComparator: c as Comparator });
setRuleParams(expressionId, { ...expression, warningComparator: c as COMPARATORS });
},
[expressionId, expression, setRuleParams]
);
@ -373,14 +363,18 @@ const ThresholdElement: React.FC<{
if (isMetricPct) return threshold.map((v) => decimalToPct(v));
return threshold;
}, [threshold, isMetricPct]);
const thresholdComparator = useCallback(() => {
if (!comparator) return COMPARATORS.GREATER_THAN;
// Check if the rule had the legacy OUTSIDE_RANGE inside its params.
// Then, change it on-the-fly to NOT_BETWEEN
return convertToBuiltInComparators(comparator);
}, [comparator]);
return (
<>
<StyledExpression>
<ThresholdExpression
thresholdComparator={comparator || Comparator.GT}
thresholdComparator={thresholdComparator()}
threshold={displayedThreshold}
customComparators={customComparators}
onChangeSelectedThresholdComparator={updateComparator}
onChangeSelectedThreshold={updateThreshold}
errors={errors}

View file

@ -9,15 +9,14 @@ import { fromKueryExpression } from '@kbn/es-query';
import { i18n } from '@kbn/i18n';
import { ValidationResult } from '@kbn/triggers-actions-ui-plugin/public';
import { isEmpty } from 'lodash';
import { COMPARATORS } from '@kbn/alerting-comparators';
import {
Aggregators,
Comparator,
CustomMetricExpressionParams,
FilterQuery,
MetricExpressionParams,
QUERY_INVALID,
} from '../../../../common/alerting/metrics';
export const EQUATION_REGEX = /[^A-Z|+|\-|\s|\d+|\.|\(|\)|\/|\*|>|<|=|\?|\:|&|\!|\|]+/g;
const isCustomMetricExpressionParams = (
@ -118,7 +117,7 @@ export function validateMetricThreshold({
// The Threshold component returns an empty array with a length ([empty]) because it's using delete newThreshold[i].
// We need to use [...c.threshold] to convert it to an array with an undefined value ([undefined]) so we can test each element.
const { comparator, threshold, type } = props as {
comparator?: Comparator;
comparator?: COMPARATORS;
threshold?: number[];
type: 'critical' | 'warning';
};
@ -135,7 +134,7 @@ export function validateMetricThreshold({
});
}
if (comparator === Comparator.BETWEEN && (!threshold || threshold.length < 2)) {
if (comparator === COMPARATORS.BETWEEN && (!threshold || threshold.length < 2)) {
errors[id][type].threshold1.push(
i18n.translate('xpack.infra.metrics.alertFlyout.error.thresholdRequired', {
defaultMessage: 'Threshold is required.',

View file

@ -4,8 +4,8 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { Aggregators, Comparator } from '../../../../common/alerting/metrics';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { Aggregators } from '../../../../common/alerting/metrics';
import { MetricExpression } from '../types';
import { generateUniqueKey } from './generate_unique_key';
@ -14,7 +14,7 @@ describe('generateUniqueKey', () => {
[
{
aggType: Aggregators.COUNT,
comparator: Comparator.LT,
comparator: COMPARATORS.LESS_THAN,
threshold: [2000, 5000],
timeSize: 15,
timeUnit: 'm',
@ -24,7 +24,7 @@ describe('generateUniqueKey', () => {
[
{
aggType: Aggregators.CUSTOM,
comparator: Comparator.GT_OR_EQ,
comparator: COMPARATORS.GREATER_THAN_OR_EQUALS,
threshold: [30],
timeSize: 15,
timeUnit: 'm',
@ -34,7 +34,7 @@ describe('generateUniqueKey', () => {
[
{
aggType: Aggregators.AVERAGE,
comparator: Comparator.LT_OR_EQ,
comparator: COMPARATORS.LESS_THAN_OR_EQUALS,
threshold: [500],
timeSize: 15,
timeUnit: 'm',

View file

@ -6,7 +6,8 @@
*/
import { v4 as uuidv4 } from 'uuid';
import { Aggregators, Comparator } from '../../../../common/alerting/metrics';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { Aggregators } from '../../../../common/alerting/metrics';
import { MetricThresholdAlert, MetricThresholdRule } from '../components/alert_details_app_section';
export const buildMetricThresholdRule = (
@ -59,24 +60,24 @@ export const buildMetricThresholdRule = (
criteria: [
{
aggType: Aggregators.COUNT,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [2000],
timeSize: 15,
timeUnit: 'm',
},
{
aggType: Aggregators.MAX,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [4],
timeSize: 15,
timeUnit: 'm',
metric: 'system.cpu.user.pct',
warningComparator: Comparator.GT,
warningComparator: COMPARATORS.GREATER_THAN,
warningThreshold: [2.2],
},
{
aggType: Aggregators.MIN,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.8],
timeSize: 15,
timeUnit: 'm',
@ -131,7 +132,7 @@ export const buildMetricThresholdAlert = (
criteria: [
{
aggType: Aggregators.AVERAGE,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [2000],
timeSize: 15,
timeUnit: 'm',
@ -139,12 +140,12 @@ export const buildMetricThresholdAlert = (
},
{
aggType: Aggregators.MAX,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [4],
timeSize: 15,
timeUnit: 'm',
metric: 'system.cpu.user.pct',
warningComparator: Comparator.GT,
warningComparator: COMPARATORS.GREATER_THAN,
warningThreshold: [2.2],
},
],

View file

@ -10,7 +10,8 @@ import {
formatDurationFromTimeUnitChar,
TimeUnitChar,
} from '@kbn/observability-plugin/common/utils/formatters/duration';
import { AlertStates, Comparator } from '../../../../common/alerting/metrics';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { AlertStates } from '../../../../common/alerting/metrics';
import { UNGROUPED_FACTORY_KEY } from './utils';
export const DOCUMENT_COUNT_I18N = i18n.translate(
@ -49,7 +50,7 @@ const toNumber = (value: number | string) =>
typeof value === 'string' ? parseFloat(value) : value;
const recoveredComparatorToI18n = (
comparator: Comparator,
comparator: COMPARATORS,
threshold: number[],
currentValue: number
) => {
@ -60,20 +61,49 @@ const recoveredComparatorToI18n = (
defaultMessage: 'above',
});
switch (comparator) {
case Comparator.BETWEEN:
case COMPARATORS.BETWEEN:
return currentValue < threshold[0] ? belowText : aboveText;
case Comparator.OUTSIDE_RANGE:
case COMPARATORS.NOT_BETWEEN:
return i18n.translate('xpack.infra.metrics.alerting.threshold.betweenRecovery', {
defaultMessage: 'between',
});
case Comparator.GT:
case Comparator.GT_OR_EQ:
case COMPARATORS.GREATER_THAN:
case COMPARATORS.GREATER_THAN_OR_EQUALS:
return belowText;
case Comparator.LT:
case Comparator.LT_OR_EQ:
case COMPARATORS.LESS_THAN:
case COMPARATORS.LESS_THAN_OR_EQUALS:
return aboveText;
}
};
const alertComparatorToI18n = (comparator: COMPARATORS) => {
switch (comparator) {
case COMPARATORS.BETWEEN:
return i18n.translate('xpack.infra.customThreshold.rule.threshold.between', {
defaultMessage: 'between',
});
case COMPARATORS.NOT_BETWEEN:
return i18n.translate('xpack.infra.customThreshold.rule.threshold.notBetween', {
defaultMessage: 'not between',
});
case COMPARATORS.GREATER_THAN:
return i18n.translate('xpack.infra.customThreshold.rule.threshold.above', {
defaultMessage: 'above',
});
case COMPARATORS.GREATER_THAN_OR_EQUALS:
return i18n.translate('xpack.infra.customThreshold.rule.threshold.aboveOrEqual', {
defaultMessage: 'above or equal',
});
case COMPARATORS.LESS_THAN:
return i18n.translate('xpack.infra.customThreshold.rule.threshold.below', {
defaultMessage: 'below',
});
case COMPARATORS.LESS_THAN_OR_EQUALS:
return i18n.translate('xpack.infra.customThreshold.rule.threshold.belowOrEqual', {
defaultMessage: 'below or equal',
});
}
};
const thresholdToI18n = ([a, b]: Array<number | string>) => {
if (typeof b === 'undefined') return a;
@ -88,7 +118,7 @@ const formatGroup = (group: string) => (group === UNGROUPED_FACTORY_KEY ? '' : `
export const buildFiredAlertReason: (alertResult: {
group: string;
metric: string;
comparator: Comparator;
comparator: COMPARATORS;
threshold: Array<number | string>;
currentValue: number | string;
timeSize: number;
@ -100,7 +130,7 @@ export const buildFiredAlertReason: (alertResult: {
values: {
group: formatGroup(group),
metric,
comparator,
comparator: alertComparatorToI18n(comparator),
threshold: thresholdToI18n(threshold),
currentValue,
duration: formatDurationFromTimeUnitChar(timeSize, timeUnit),
@ -111,7 +141,7 @@ export const buildFiredAlertReason: (alertResult: {
export const buildRecoveredAlertReason: (alertResult: {
group: string;
metric: string;
comparator: Comparator;
comparator: COMPARATORS;
threshold: Array<number | string>;
currentValue: number | string;
}) => string = ({ group, metric, comparator, threshold, currentValue }) =>

View file

@ -13,12 +13,8 @@ import { RuleExecutorServicesMock, alertsMock } from '@kbn/alerting-plugin/serve
import { LifecycleAlertServices } from '@kbn/rule-registry-plugin/server';
import { ruleRegistryMocks } from '@kbn/rule-registry-plugin/server/mocks';
import { createLifecycleRuleExecutorMock } from '@kbn/rule-registry-plugin/server/utils/create_lifecycle_rule_executor_mock';
import {
Aggregators,
Comparator,
InventoryMetricConditions,
} from '../../../../common/alerting/metrics';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { Aggregators, InventoryMetricConditions } from '../../../../common/alerting/metrics';
import type { LogMeta, Logger } from '@kbn/logging';
import { DEFAULT_FLAPPING_SETTINGS } from '@kbn/alerting-plugin/common';
import { createInventoryMetricThresholdExecutor } from './inventory_metric_threshold_executor';
@ -178,7 +174,7 @@ const baseCriterion = {
timeSize: 1,
timeUnit: 'm',
threshold: [0],
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
} as InventoryMetricConditions;
describe('The inventory threshold alert type', () => {
@ -187,7 +183,7 @@ describe('The inventory threshold alert type', () => {
setup();
const execute = (comparator: Comparator, threshold: number[], options?: any) =>
const execute = (comparator: COMPARATORS, threshold: number[], options?: any) =>
executor({
...mockOptions,
services,
@ -215,7 +211,7 @@ describe('The inventory threshold alert type', () => {
test('throws error when alertsClient is null', async () => {
try {
services.alertsClient = null;
await execute(Comparator.GT, [0.75]);
await execute(COMPARATORS.GREATER_THAN, [0.75]);
} catch (e) {
expect(e).toMatchInlineSnapshot(
'[Error: Expected alertsClient not to be null! There may have been an issue installing alert resources.]'
@ -232,7 +228,7 @@ describe('The inventory threshold alert type', () => {
timeSize: 1,
timeUnit: 'm',
threshold: [0.75],
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
shouldFire: true,
shouldWarn: false,
currentValue: 1.0,
@ -248,7 +244,7 @@ describe('The inventory threshold alert type', () => {
timeSize: 1,
timeUnit: 'm',
threshold: [0.75],
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
shouldFire: true,
shouldWarn: false,
currentValue: 1.0,
@ -259,7 +255,7 @@ describe('The inventory threshold alert type', () => {
},
},
});
await execute(Comparator.GT, [0.75]);
await execute(COMPARATORS.GREATER_THAN, [0.75]);
expect(mostRecentAction(instanceIdA).tags).toStrictEqual([
'host-01_tag1',
'host-01_tag2',
@ -282,7 +278,7 @@ describe('The inventory threshold alert type', () => {
timeSize: 1,
timeUnit: 'm',
threshold: [0.75],
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
shouldFire: true,
shouldWarn: false,
currentValue: 1.0,
@ -298,7 +294,7 @@ describe('The inventory threshold alert type', () => {
timeSize: 1,
timeUnit: 'm',
threshold: [0.75],
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
shouldFire: true,
shouldWarn: false,
currentValue: 1.0,
@ -309,7 +305,7 @@ describe('The inventory threshold alert type', () => {
},
},
});
await execute(Comparator.GT, [0.75]);
await execute(COMPARATORS.GREATER_THAN, [0.75]);
expect(mostRecentAction(instanceIdA).tags).toStrictEqual(['ruleTag1', 'ruleTag2']);
expect(mostRecentAction(instanceIdB).tags).toStrictEqual(['ruleTag1', 'ruleTag2']);
});
@ -329,7 +325,7 @@ describe('The inventory threshold alert type', () => {
timeSize: 1,
timeUnit: 'm',
threshold: [0.75],
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
shouldFire: true,
shouldWarn: false,
currentValue: 1.0,
@ -340,7 +336,7 @@ describe('The inventory threshold alert type', () => {
},
},
});
await execute(Comparator.GT, [0.75], options);
await execute(COMPARATORS.GREATER_THAN, [0.75], options);
expect(evaluateConditionFn).toHaveBeenCalledWith(
expect.objectContaining({
executionTimestamp: mockedEndDate,

View file

@ -19,7 +19,7 @@ import {
AlertInstanceState as AlertState,
} from '@kbn/alerting-plugin/common';
import { AlertsClientError, RuleExecutorOptions, RuleTypeState } from '@kbn/alerting-plugin/server';
import { getAlertUrl } from '@kbn/observability-plugin/common';
import { convertToBuiltInComparators, getAlertUrl } from '@kbn/observability-plugin/common';
import { SnapshotMetricType } from '@kbn/metrics-data-access-plugin/common';
import { ObservabilityMetricsAlert } from '@kbn/alerts-as-data-utils';
import { getOriginalActionGroup } from '../../../utils/get_original_action_group';
@ -128,7 +128,6 @@ export const createInventoryMetricThresholdExecutor =
});
const indexedStartedAt = start ?? startedAt.toISOString();
alertsClient.setAlertData({
id: UNGROUPED_FACTORY_KEY,
payload: {
@ -403,7 +402,9 @@ const buildReasonWithVerboseMetricName = (
: resultItem.metric),
currentValue: formatMetric(resultItem.metric, resultItem.currentValue),
threshold: formatThreshold(resultItem.metric, thresholdToFormat),
comparator: useWarningThreshold ? resultItem.warningComparator! : resultItem.comparator,
comparator: useWarningThreshold
? convertToBuiltInComparators(resultItem.warningComparator!)
: convertToBuiltInComparators(resultItem.comparator),
};
return buildReason(resultWithVerboseMetricName);
};

View file

@ -4,8 +4,8 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { Comparator, InventoryMetricConditions } from '../../../../../common/alerting/metrics';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { InventoryMetricConditions } from '../../../../../common/alerting/metrics';
import { createBucketSelector } from './create_bucket_selector';
describe('createBucketSelector', () => {
@ -15,9 +15,9 @@ describe('createBucketSelector', () => {
timeSize: 5,
timeUnit: 'm',
threshold: [8],
comparator: Comparator.GT_OR_EQ,
comparator: COMPARATORS.GREATER_THAN_OR_EQUALS,
warningThreshold: [16],
warningComparator: Comparator.LT_OR_EQ,
warningComparator: COMPARATORS.LESS_THAN_OR_EQUALS,
};
expect(createBucketSelector('tx', inventoryMetricConditions)).toEqual({
selectedBucket: {

View file

@ -6,7 +6,8 @@
*/
import { SnapshotMetricType } from '@kbn/metrics-data-access-plugin/common';
import { Comparator, InventoryMetricConditions } from '../../../../../common/alerting/metrics';
import { convertToBuiltInComparators } from '@kbn/observability-plugin/common';
import { InventoryMetricConditions } from '../../../../../common/alerting/metrics';
import { SnapshotCustomMetricInput } from '../../../../../common/http_api';
import { createConditionScript } from './create_condition_script';
@ -34,7 +35,7 @@ export const createBucketSelector = (
},
script: createConditionScript(
condition.warningThreshold as number[],
condition.warningComparator as Comparator,
convertToBuiltInComparators(condition.warningComparator!),
metric
),
},
@ -47,7 +48,11 @@ export const createBucketSelector = (
buckets_path: {
value: metricId,
},
script: createConditionScript(condition.threshold, condition.comparator, metric),
script: createConditionScript(
condition.threshold,
convertToBuiltInComparators(condition.comparator),
metric
),
},
}
: EMPTY_SHOULD_WARN;

View file

@ -4,13 +4,12 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { Comparator } from '../../../../../common/alerting/metrics';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { createConditionScript } from './create_condition_script';
describe('createConditionScript', () => {
it('should convert tx threshold from bits to byte', () => {
expect(createConditionScript([8], Comparator.GT_OR_EQ, 'tx')).toEqual({
expect(createConditionScript([8], COMPARATORS.GREATER_THAN_OR_EQUALS, 'tx')).toEqual({
params: {
// Threshold has been converted from 8 bits to 1 byte
threshold: 1,

View file

@ -5,16 +5,16 @@
* 2.0.
*/
import { SnapshotMetricType } from '@kbn/metrics-data-access-plugin/common';
import { Comparator } from '../../../../../common/alerting/metrics';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { convertMetricValue } from './convert_metric_value';
export const createConditionScript = (
conditionThresholds: number[],
comparator: Comparator,
comparator: COMPARATORS,
metric: SnapshotMetricType
) => {
const threshold = conditionThresholds.map((n) => convertMetricValue(metric, n));
if (comparator === Comparator.BETWEEN && threshold.length === 2) {
if (comparator === COMPARATORS.BETWEEN && threshold.length === 2) {
return {
source: `params.value > params.threshold0 && params.value < params.threshold1 ? 1 : 0`,
params: {
@ -23,9 +23,10 @@ export const createConditionScript = (
},
};
}
if (comparator === Comparator.OUTSIDE_RANGE && threshold.length === 2) {
if (comparator === COMPARATORS.NOT_BETWEEN && threshold.length === 2) {
return {
// OUTSIDE_RANGE/NOT BETWEEN is the opposite of BETWEEN. Use the BETWEEN condition and switch the 1 and 0
// NOT BETWEEN is the opposite of BETWEEN. Use the BETWEEN condition and switch the 1 and 0
source: `params.value > params.threshold0 && params.value < params.threshold1 ? 0 : 1`,
params: {
threshold0: threshold[0],

View file

@ -16,15 +16,14 @@ import {
SnapshotMetricType,
SnapshotMetricTypeKeys,
} from '@kbn/metrics-data-access-plugin/common';
import type { InfraConfig } from '../../../../common/plugin_config_types';
import {
Comparator,
METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID,
} from '../../../../common/alerting/metrics';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { LEGACY_COMPARATORS } from '@kbn/observability-plugin/common/utils/convert_legacy_outside_comparator';
import {
SnapshotCustomAggregation,
SNAPSHOT_CUSTOM_AGGREGATIONS,
} from '../../../../common/http_api/snapshot_api';
} from '../../../../common/http_api';
import type { InfraConfig } from '../../../../common/plugin_config_types';
import { METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID } from '../../../../common/alerting/metrics';
import { InfraBackendLibs } from '../../infra_types';
import {
alertDetailUrlActionVariableDescription,
@ -54,16 +53,15 @@ import {
import { MetricsRulesTypeAlertDefinition } from '../register_rule_types';
import { O11Y_AAD_FIELDS } from '../../../../common/constants';
const comparators = Object.values({ ...COMPARATORS, ...LEGACY_COMPARATORS });
const condition = schema.object({
threshold: schema.arrayOf(schema.number()),
comparator: oneOfLiterals(Object.values(Comparator)) as Type<Comparator>,
comparator: oneOfLiterals(comparators) as Type<COMPARATORS>,
timeUnit: schema.string() as Type<TimeUnitChar>,
timeSize: schema.number(),
metric: oneOfLiterals(Object.keys(SnapshotMetricTypeKeys)) as Type<SnapshotMetricType>,
warningThreshold: schema.maybe(schema.arrayOf(schema.number())),
warningComparator: schema.maybe(oneOfLiterals(Object.values(Comparator))) as Type<
Comparator | undefined
>,
warningComparator: schema.maybe(oneOfLiterals(comparators)) as Type<COMPARATORS | undefined>,
customMetric: schema.maybe(
schema.object({
type: schema.literal('custom'),

View file

@ -4,12 +4,8 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import {
Aggregators,
Comparator,
MetricExpressionParams,
} from '../../../../../common/alerting/metrics';
import { convertToBuiltInComparators } from '@kbn/observability-plugin/common';
import { Aggregators, MetricExpressionParams } from '../../../../../common/alerting/metrics';
import { createConditionScript } from './create_condition_script';
import { createLastPeriod } from './wrap_in_period';
@ -49,7 +45,7 @@ export const createBucketSelector = (
},
script: createConditionScript(
condition.warningThreshold as number[],
condition.warningComparator as Comparator
convertToBuiltInComparators(condition.warningComparator!)
),
},
}
@ -60,7 +56,10 @@ export const createBucketSelector = (
buckets_path: {
value: bucketPath,
},
script: createConditionScript(condition.threshold, condition.comparator),
script: createConditionScript(
condition.threshold,
convertToBuiltInComparators(condition.comparator)
),
},
};

View file

@ -4,10 +4,9 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { Comparator } from '../../../../../common/alerting/metrics';
export const createConditionScript = (threshold: number[], comparator: Comparator) => {
if (comparator === Comparator.BETWEEN && threshold.length === 2) {
import { COMPARATORS } from '@kbn/alerting-comparators';
export const createConditionScript = (threshold: number[], comparator: COMPARATORS) => {
if (comparator === COMPARATORS.BETWEEN && threshold.length === 2) {
return {
source: `params.value > params.threshold0 && params.value < params.threshold1 ? 1 : 0`,
params: {
@ -16,9 +15,9 @@ export const createConditionScript = (threshold: number[], comparator: Comparato
},
};
}
if (comparator === Comparator.OUTSIDE_RANGE && threshold.length === 2) {
if (comparator === COMPARATORS.NOT_BETWEEN && threshold.length === 2) {
return {
// OUTSIDE_RANGE/NOT BETWEEN is the opposite of BETWEEN. Use the BETWEEN condition and switch the 1 and 0
// NOT BETWEEN is the opposite of BETWEEN. Use the BETWEEN condition and switch the 1 and 0
source: `params.value > params.threshold0 && params.value < params.threshold1 ? 0 : 1`,
params: {
threshold0: threshold[0],

View file

@ -9,11 +9,9 @@ import { SearchResponse, AggregationsAggregate } from '@elastic/elasticsearch/li
import { ElasticsearchClient } from '@kbn/core/server';
import type { Logger } from '@kbn/logging';
import { EcsFieldsResponse } from '@kbn/rule-registry-plugin/common/search_strategy';
import {
Aggregators,
Comparator,
MetricExpressionParams,
} from '../../../../../common/alerting/metrics';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { convertToBuiltInComparators } from '@kbn/observability-plugin/common';
import { Aggregators, MetricExpressionParams } from '../../../../../common/alerting/metrics';
import {
AdditionalContext,
doFieldsExist,
@ -226,10 +224,16 @@ export const getData = async (
// the value will end up being ZERO, for other metrics it will be null. In this case
// we need to do the evaluation in Node.js
if (aggs.all && params.aggType === Aggregators.COUNT && value === 0) {
const trigger = comparatorMap[params.comparator](value, params.threshold);
const trigger = comparatorMap[convertToBuiltInComparators(params.comparator)](
value,
params.threshold
);
const warn =
params.warningThreshold && params.warningComparator
? comparatorMap[params.warningComparator](value, params.warningThreshold)
? comparatorMap[convertToBuiltInComparators(params.warningComparator)](
value,
params.warningThreshold
)
: false;
return {
[UNGROUPED_FACTORY_KEY]: {
@ -286,13 +290,13 @@ export const getData = async (
};
const comparatorMap = {
[Comparator.BETWEEN]: (value: number, [a, b]: number[]) =>
[COMPARATORS.BETWEEN]: (value: number, [a, b]: number[]) =>
value >= Math.min(a, b) && value <= Math.max(a, b),
// `threshold` is always an array of numbers in case the BETWEEN comparator is
// used; all other compartors will just destructure the first value in the array
[Comparator.GT]: (a: number, [b]: number[]) => a > b,
[Comparator.LT]: (a: number, [b]: number[]) => a < b,
[Comparator.OUTSIDE_RANGE]: (value: number, [a, b]: number[]) => value < a || value > b,
[Comparator.GT_OR_EQ]: (a: number, [b]: number[]) => a >= b,
[Comparator.LT_OR_EQ]: (a: number, [b]: number[]) => a <= b,
[COMPARATORS.GREATER_THAN]: (a: number, [b]: number[]) => a > b,
[COMPARATORS.LESS_THAN]: (a: number, [b]: number[]) => a < b,
[COMPARATORS.NOT_BETWEEN]: (value: number, [a, b]: number[]) => value < a || value > b,
[COMPARATORS.GREATER_THAN_OR_EQUALS]: (a: number, [b]: number[]) => a >= b,
[COMPARATORS.LESS_THAN_OR_EQUALS]: (a: number, [b]: number[]) => a <= b,
};

View file

@ -6,11 +6,8 @@
*/
import moment from 'moment';
import {
Aggregators,
Comparator,
MetricExpressionParams,
} from '../../../../../common/alerting/metrics';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { Aggregators, MetricExpressionParams } from '../../../../../common/alerting/metrics';
import { getElasticsearchMetricQuery } from './metric_query';
describe("The Metric Threshold Alert's getElasticsearchMetricQuery", () => {
@ -20,7 +17,7 @@ describe("The Metric Threshold Alert's getElasticsearchMetricQuery", () => {
timeUnit: 'm',
timeSize: 1,
threshold: [1],
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
};
const groupBy = 'host.doggoname';

View file

@ -20,11 +20,12 @@ import {
RecoveredActionGroup,
} from '@kbn/alerting-plugin/common';
import { AlertsClientError, RuleExecutorOptions, RuleTypeState } from '@kbn/alerting-plugin/server';
import type { TimeUnitChar } from '@kbn/observability-plugin/common';
import { getAlertUrl } from '@kbn/observability-plugin/common';
import { TimeUnitChar, getAlertUrl } from '@kbn/observability-plugin/common';
import { ObservabilityMetricsAlert } from '@kbn/alerts-as-data-utils';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { convertToBuiltInComparators } from '@kbn/observability-plugin/common/utils/convert_legacy_outside_comparator';
import { getOriginalActionGroup } from '../../../utils/get_original_action_group';
import { AlertStates, Comparator } from '../../../../common/alerting/metrics';
import { AlertStates } from '../../../../common/alerting/metrics';
import { createFormatter } from '../../../../common/formatters';
import { InfraBackendLibs } from '../../infra_types';
import {
@ -296,7 +297,16 @@ export const createMetricThresholdExecutor =
reason = alertResults
.map((result) =>
buildFiredAlertReason({
...formatAlertResult(result[group], nextState === AlertStates.WARNING),
...formatAlertResult(
{
...result[group],
comparator: convertToBuiltInComparators(result[group].comparator),
warningComparator: result[group].comparator
? convertToBuiltInComparators(result[group].comparator)
: undefined,
},
nextState === AlertStates.WARNING
),
group,
})
)
@ -367,21 +377,33 @@ export const createMetricThresholdExecutor =
}),
reason,
threshold: mapToConditionsLookup(alertResults, (result, index) => {
const evaluation = result[group];
const evaluation = result[group] as Evaluation;
if (!evaluation) {
return criteria[index].threshold;
}
return formatAlertResult(evaluation).threshold;
return formatAlertResult({
...evaluation,
comparator: convertToBuiltInComparators(evaluation.comparator),
warningComparator: evaluation.warningComparator
? convertToBuiltInComparators(evaluation.warningComparator)
: undefined,
}).threshold;
}),
timestamp,
value: mapToConditionsLookup(alertResults, (result, index) => {
const evaluation = result[group];
const evaluation = result[group] as Evaluation;
if (!evaluation && criteria[index].aggType === 'count') {
return 0;
} else if (!evaluation) {
return null;
}
return formatAlertResult(evaluation).currentValue;
return formatAlertResult({
...evaluation,
comparator: convertToBuiltInComparators(evaluation.comparator),
warningComparator: evaluation.warningComparator
? convertToBuiltInComparators(evaluation.warningComparator)
: undefined,
}).currentValue;
}),
viewInAppUrl: getMetricsViewInAppUrlWithSpaceId({
basePath: libs.basePath,
@ -518,9 +540,9 @@ const formatAlertResult = <AlertResult>(
metric: string;
currentValue: number | null;
threshold: number[];
comparator: Comparator;
comparator: COMPARATORS;
warningThreshold?: number[];
warningComparator?: Comparator;
warningComparator?: COMPARATORS;
timeSize: number;
timeUnit: TimeUnitChar;
} & AlertResult,
@ -544,7 +566,7 @@ const formatAlertResult = <AlertResult>(
threshold: Array.isArray(thresholdToFormat)
? thresholdToFormat.map((v: number) => formatter(v))
: formatter(thresholdToFormat),
comparator: comparatorToUse,
comparator: convertToBuiltInComparators(comparatorToUse),
};
}

View file

@ -8,15 +8,12 @@
import { DEFAULT_APP_CATEGORIES } from '@kbn/core/server';
import { schema } from '@kbn/config-schema';
import { i18n } from '@kbn/i18n';
import { ActionGroupIdsOf } from '@kbn/alerting-plugin/common';
import {
GetViewInAppRelativeUrlFnOpts,
PluginSetupContract,
RuleType,
} from '@kbn/alerting-plugin/server';
import { GetViewInAppRelativeUrlFnOpts, PluginSetupContract } from '@kbn/alerting-plugin/server';
import { observabilityPaths } from '@kbn/observability-plugin/common';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { LEGACY_COMPARATORS } from '@kbn/observability-plugin/common/utils/convert_legacy_outside_comparator';
import type { InfraConfig } from '../../../../common/plugin_config_types';
import { Comparator, METRIC_THRESHOLD_ALERT_TYPE_ID } from '../../../../common/alerting/metrics';
import { METRIC_THRESHOLD_ALERT_TYPE_ID } from '../../../../common/alerting/metrics';
import { METRIC_EXPLORER_AGGREGATIONS } from '../../../../common/http_api';
import { InfraBackendLibs } from '../../infra_types';
import {
@ -48,13 +45,6 @@ import {
import { MetricsRulesTypeAlertDefinition } from '../register_rule_types';
import { O11Y_AAD_FIELDS } from '../../../../common/constants';
type MetricThresholdAllowedActionGroups = ActionGroupIdsOf<
typeof FIRED_ACTIONS | typeof WARNING_ACTIONS | typeof NO_DATA_ACTIONS
>;
export type MetricThresholdAlertType = Omit<RuleType, 'ActionGroupIdsOf'> & {
ActionGroupIdsOf: MetricThresholdAllowedActionGroups;
};
export function registerMetricThresholdRuleType(
alertingPlugin: PluginSetupContract,
libs: InfraBackendLibs,
@ -63,14 +53,14 @@ export function registerMetricThresholdRuleType(
if (!featureFlags.metricThresholdAlertRuleEnabled) {
return;
}
const comparator = Object.values({ ...COMPARATORS, ...LEGACY_COMPARATORS });
const baseCriterion = {
threshold: schema.arrayOf(schema.number()),
comparator: oneOfLiterals(Object.values(Comparator)),
comparator: oneOfLiterals(comparator),
timeUnit: schema.string(),
timeSize: schema.number(),
warningThreshold: schema.maybe(schema.arrayOf(schema.number())),
warningComparator: schema.maybe(oneOfLiterals(Object.values(Comparator))),
warningComparator: schema.maybe(oneOfLiterals(comparator)),
};
const nonCountCriterion = schema.object({

View file

@ -97,6 +97,8 @@
"@kbn/dashboard-plugin",
"@kbn/shared-svg",
"@kbn/aiops-log-rate-analysis",
"@kbn/search-types",
"@kbn/alerting-comparators",
"@kbn/react-hooks",
"@kbn/search-types",
"@kbn/router-utils",

View file

@ -8,6 +8,8 @@
import * as rt from 'io-ts';
import { DataViewSpec, SerializedSearchSourceFields } from '@kbn/data-plugin/common';
import { Filter, Query } from '@kbn/es-query';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { LEGACY_COMPARATORS } from '../utils/convert_legacy_outside_comparator';
import { TimeUnitChar } from '../utils/formatters/duration';
export const ThresholdFormatterTypeRT = rt.keyof({
@ -20,15 +22,6 @@ export const ThresholdFormatterTypeRT = rt.keyof({
});
export type ThresholdFormatterType = rt.TypeOf<typeof ThresholdFormatterTypeRT>;
export enum Comparator {
GT = '>',
LT = '<',
GT_OR_EQ = '>=',
LT_OR_EQ = '<=',
BETWEEN = 'between',
OUTSIDE_RANGE = 'outside',
}
export enum Aggregators {
COUNT = 'count',
AVERAGE = 'avg',
@ -78,9 +71,7 @@ export interface BaseMetricExpressionParams {
timeUnit: TimeUnitChar;
sourceId?: string;
threshold: number[];
comparator: Comparator;
warningComparator?: Comparator;
warningThreshold?: number[];
comparator: COMPARATORS | LEGACY_COMPARATORS;
}
export interface CustomThresholdExpressionMetric {

View file

@ -10,3 +10,46 @@ import { i18n } from '@kbn/i18n';
export const NOT_AVAILABLE_LABEL = i18n.translate('xpack.observability.notAvailable', {
defaultMessage: 'N/A',
});
// Comparators
export const BELOW_TEXT = i18n.translate(
'xpack.observability.customThreshold.rule.threshold.below',
{
defaultMessage: 'below',
}
);
export const BELOW_OR_EQ_TEXT = i18n.translate(
'xpack.observability.customThreshold.rule.threshold.belowOrEqual',
{
defaultMessage: 'below or equal',
}
);
export const ABOVE_TEXT = i18n.translate(
'xpack.observability.customThreshold.rule.threshold.above',
{
defaultMessage: 'above',
}
);
export const ABOVE_OR_EQ_TEXT = i18n.translate(
'xpack.observability.customThreshold.rule.threshold.aboveOrEqual',
{
defaultMessage: 'above or equal',
}
);
export const BETWEEN_TEXT = i18n.translate(
'xpack.observability.customThreshold.rule.threshold.between',
{
defaultMessage: 'between',
}
);
export const NOT_BETWEEN_TEXT = i18n.translate(
'xpack.observability.customThreshold.rule.threshold.notBetween',
{
defaultMessage: 'not between',
}
);

View file

@ -18,7 +18,7 @@ export {
} from './utils/formatters';
export { getInspectResponse } from './utils/get_inspect_response';
export { getAlertDetailsUrl, getAlertUrl } from './utils/alerting/alert_url';
export { convertToBuiltInComparators } from './utils/convert_legacy_outside_comparator';
export { ProcessorEvent } from './processor_event';
export {

View file

@ -0,0 +1,24 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import {
convertToBuiltInComparators,
LEGACY_COMPARATORS,
} from './convert_legacy_outside_comparator';
import { COMPARATORS } from '@kbn/alerting-comparators';
describe('convertToBuiltInComparators', () => {
it('should return in between when passing the legacy outside', () => {
const comparator = convertToBuiltInComparators(LEGACY_COMPARATORS.OUTSIDE_RANGE);
expect(comparator).toBe(COMPARATORS.NOT_BETWEEN);
});
it('should return the same comparator when NOT passing the legacy outside', () => {
const comparator = convertToBuiltInComparators(COMPARATORS.GREATER_THAN);
expect(comparator).toBe(COMPARATORS.GREATER_THAN);
});
});

View file

@ -0,0 +1,17 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { COMPARATORS } from '@kbn/alerting-comparators';
export enum LEGACY_COMPARATORS {
OUTSIDE_RANGE = 'outside',
}
export type LegacyComparator = COMPARATORS | LEGACY_COMPARATORS;
export function convertToBuiltInComparators(comparator: LegacyComparator): COMPARATORS {
if (comparator === LEGACY_COMPARATORS.OUTSIDE_RANGE) return COMPARATORS.NOT_BETWEEN;
return comparator;
}

View file

@ -103,13 +103,13 @@ describe('Map rules params with flyout', () => {
excludeHitsFromPreviousRun: false,
},
'kibana.alert.evaluation.value': 100870655162.18182,
'kibana.alert.evaluation.threshold': 1,
'kibana.alert.evaluation.threshold': [1],
},
},
results: [
{
observedValue: [100870655162.18182],
threshold: [1],
threshold: '1',
comparator: '>',
pctAboveThreshold: ' (10087065516118.18% above the threshold)',
},
@ -149,7 +149,7 @@ describe('Map rules params with flyout', () => {
observedValue: [4577],
threshold: [100],
comparator: 'more than',
pctAboveThreshold: ' (4477% above the threshold)',
pctAboveThreshold: ' (4477% more than the threshold)',
},
],
},
@ -215,12 +215,50 @@ describe('Map rules params with flyout', () => {
results: [
{
observedValue: '10.4 Mbit',
threshold: ['3 Mbit'],
threshold: '3 Mbit',
comparator: '>',
pctAboveThreshold: ' (247.54% above the threshold)',
},
],
},
{
ruleType: 'metrics.alert.inventory.threshold',
alert: {
fields: {
'kibana.alert.rule.rule_type_id': 'metrics.alert.inventory.threshold',
'kibana.alert.rule.parameters': {
nodeType: 'host',
criteria: [
{
metric: 'rx',
comparator: '<',
threshold: [90],
timeSize: 1,
timeUnit: 'm',
customMetric: {
type: 'custom',
id: 'alert-custom-metric',
field: 'system.memory.used.pct',
aggregation: 'avg',
},
},
],
sourceId: 'default',
},
'kibana.alert.evaluation.value': [130.4],
'kibana.alert.evaluation.threshold': 3000000,
},
},
results: [
{
comparator: '<',
observedValue: '13,040%',
pctAboveThreshold: ' (14388.89% below the threshold)',
threshold: '9,000%',
},
],
},
{
ruleType: 'apm.error_rate',
alert: {

View file

@ -19,7 +19,15 @@ import {
} from '@kbn/rule-data-utils';
import { EsQueryRuleParams } from '@kbn/stack-alerts-plugin/public/rule_types/es_query/types';
import { i18n } from '@kbn/i18n';
import { asDuration, asPercent } from '../../../../common';
import { COMPARATORS } from '@kbn/alerting-comparators';
import {
ABOVE_OR_EQ_TEXT,
ABOVE_TEXT,
BELOW_OR_EQ_TEXT,
BELOW_TEXT,
} from '../../../../common/i18n';
import { asDuration, asPercent, convertToBuiltInComparators } from '../../../../common';
import { createFormatter } from '../../../../common/custom_threshold_rule/formatters';
import { metricValueFormatter } from '../../../../common/custom_threshold_rule/metric_value_formatter';
import { METRIC_FORMATTERS } from '../../../../common/custom_threshold_rule/formatters/snapshot_metric_formats';
@ -37,12 +45,34 @@ export interface FlyoutThresholdData {
pctAboveThreshold: string;
}
const getPctAboveThreshold = (observedValue?: number, threshold?: number[]): string => {
const getI18nComparator = (comparator?: COMPARATORS) => {
switch (comparator) {
case COMPARATORS.GREATER_THAN:
return ABOVE_TEXT;
case COMPARATORS.GREATER_THAN_OR_EQUALS:
return ABOVE_OR_EQ_TEXT;
case COMPARATORS.LESS_THAN:
return BELOW_TEXT;
case COMPARATORS.LESS_THAN_OR_EQUALS:
return BELOW_OR_EQ_TEXT;
default:
return comparator;
}
};
const getPctAboveThreshold = (
threshold: number[],
comparator: COMPARATORS,
observedValue?: number
): string => {
if (!observedValue || !threshold || threshold.length > 1 || threshold[0] <= 0) return '';
return i18n.translate('xpack.observability.alertFlyout.overview.aboveThresholdLabel', {
defaultMessage: ' ({pctValue}% above the threshold)',
defaultMessage: ' ({pctValue}% {comparator} the threshold)',
values: {
pctValue: parseFloat((((observedValue - threshold[0]) * 100) / threshold[0]).toFixed(2)),
pctValue: Math.abs(
parseFloat((((observedValue - threshold[0]) * 100) / threshold[0]).toFixed(2))
),
comparator: getI18nComparator(convertToBuiltInComparators(comparator)),
},
});
};
@ -78,7 +108,11 @@ export const mapRuleParamsWithFlyout = (alert: TopAlert): FlyoutThresholdData[]
observedValue: formattedValue,
threshold: thresholdFormattedAsString,
comparator,
pctAboveThreshold: getPctAboveThreshold(observedValue, threshold),
pctAboveThreshold: getPctAboveThreshold(
threshold,
convertToBuiltInComparators(comparator),
observedValue
),
} as unknown as FlyoutThresholdData;
});
@ -113,46 +147,82 @@ export const mapRuleParamsWithFlyout = (alert: TopAlert): FlyoutThresholdData[]
observedValue: formattedValue,
threshold: thresholdFormattedAsString,
comparator,
pctAboveThreshold: getPctAboveThreshold(observedValue, threshold),
pctAboveThreshold: getPctAboveThreshold(
threshold,
convertToBuiltInComparators(comparator),
observedValue
),
} as unknown as FlyoutThresholdData;
});
case METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID:
return observedValues.map((observedValue, metricIndex) => {
const criteria = ruleCriteria[metricIndex] as BaseMetricExpressionParams & {
const { threshold, customMetric, metric, comparator } = ruleCriteria[
metricIndex
] as BaseMetricExpressionParams & {
metric: string;
customMetric: {
field: string;
};
};
const infraType = METRIC_FORMATTERS[criteria.metric].formatter;
const formatter = createFormatter(infraType);
const comparator = criteria.comparator;
const threshold = criteria.threshold;
const formatThreshold = threshold.map((v: number) => {
if (infraType === 'percent') {
v = Number(v) / 100;
const metricField = customMetric?.field || metric;
const thresholdFormatted = threshold.map((thresholdToFormat) => {
if (
metricField.endsWith('.pct') ||
(METRIC_FORMATTERS[metric] && METRIC_FORMATTERS[metric].formatter === 'percent')
) {
thresholdToFormat = thresholdToFormat / 100;
} else if (
metricField.endsWith('.bytes') ||
(METRIC_FORMATTERS[metric] && METRIC_FORMATTERS[metric].formatter === 'bits')
) {
thresholdToFormat = thresholdToFormat / 8;
}
if (infraType === 'bits') {
v = Number(v) / 8;
}
return v;
return thresholdToFormat;
});
let observedValueFormatted: string;
let thresholdFormattedAsString: string;
if (customMetric.field) {
observedValueFormatted = metricValueFormatter(
observedValue as number,
customMetric.field
);
thresholdFormattedAsString = threshold
.map((thresholdToStringFormat) =>
metricValueFormatter(thresholdToStringFormat, metricField)
)
.join(' AND ');
} else {
const infraType = METRIC_FORMATTERS[metric].formatter;
const formatter = createFormatter(infraType);
observedValueFormatted = formatter(observedValue);
thresholdFormattedAsString = thresholdFormatted.map(formatter).join(' AND ');
}
return {
observedValue: formatter(observedValue),
threshold: formatThreshold.map(formatter),
observedValue: observedValueFormatted,
threshold: thresholdFormattedAsString,
comparator,
pctAboveThreshold: getPctAboveThreshold(observedValue, formatThreshold),
pctAboveThreshold: getPctAboveThreshold(
thresholdFormatted,
convertToBuiltInComparators(comparator),
observedValue
),
} as unknown as FlyoutThresholdData;
});
case LOG_THRESHOLD_ALERT_TYPE_ID:
const { comparator } = ruleParams?.count as { comparator: string };
const { comparator } = ruleParams?.count as { comparator: COMPARATORS };
const flyoutMap = {
observedValue: [alert.fields[ALERT_EVALUATION_VALUE]],
threshold: [alert.fields[ALERT_EVALUATION_THRESHOLD]],
comparator,
pctAboveThreshold: getPctAboveThreshold(alert.fields[ALERT_EVALUATION_VALUE], [
alert.fields[ALERT_EVALUATION_THRESHOLD]!,
]),
pctAboveThreshold: getPctAboveThreshold(
[alert.fields[ALERT_EVALUATION_THRESHOLD]!],
comparator,
alert.fields[ALERT_EVALUATION_VALUE]
),
} as unknown as FlyoutThresholdData;
return [flyoutMap];
@ -160,10 +230,12 @@ export const mapRuleParamsWithFlyout = (alert: TopAlert): FlyoutThresholdData[]
const APMFlyoutMapErrorCount = {
observedValue: [alert.fields[ALERT_EVALUATION_VALUE]],
threshold: [alert.fields[ALERT_EVALUATION_THRESHOLD]],
comparator: '>',
pctAboveThreshold: getPctAboveThreshold(alert.fields[ALERT_EVALUATION_VALUE], [
alert.fields[ALERT_EVALUATION_THRESHOLD]!,
]),
comparator: COMPARATORS.GREATER_THAN,
pctAboveThreshold: getPctAboveThreshold(
[alert.fields[ALERT_EVALUATION_THRESHOLD]!],
COMPARATORS.GREATER_THAN,
alert.fields[ALERT_EVALUATION_VALUE]
),
} as unknown as FlyoutThresholdData;
return [APMFlyoutMapErrorCount];
@ -171,10 +243,12 @@ export const mapRuleParamsWithFlyout = (alert: TopAlert): FlyoutThresholdData[]
const APMFlyoutMapTransactionErrorRate = {
observedValue: [asPercent(alert.fields[ALERT_EVALUATION_VALUE], 100)],
threshold: [asPercent(alert.fields[ALERT_EVALUATION_THRESHOLD], 100)],
comparator: '>',
pctAboveThreshold: getPctAboveThreshold(alert.fields[ALERT_EVALUATION_VALUE], [
alert.fields[ALERT_EVALUATION_THRESHOLD]!,
]),
comparator: COMPARATORS.GREATER_THAN,
pctAboveThreshold: getPctAboveThreshold(
[alert.fields[ALERT_EVALUATION_THRESHOLD]!],
COMPARATORS.GREATER_THAN,
alert.fields[ALERT_EVALUATION_VALUE]
),
} as unknown as FlyoutThresholdData;
return [APMFlyoutMapTransactionErrorRate];
@ -182,22 +256,26 @@ export const mapRuleParamsWithFlyout = (alert: TopAlert): FlyoutThresholdData[]
const APMFlyoutMapTransactionDuration = {
observedValue: [asDuration(alert.fields[ALERT_EVALUATION_VALUE])],
threshold: [asDuration(alert.fields[ALERT_EVALUATION_THRESHOLD])],
comparator: '>',
pctAboveThreshold: getPctAboveThreshold(alert.fields[ALERT_EVALUATION_VALUE], [
alert.fields[ALERT_EVALUATION_THRESHOLD]!,
]),
comparator: COMPARATORS.GREATER_THAN,
pctAboveThreshold: getPctAboveThreshold(
[alert.fields[ALERT_EVALUATION_THRESHOLD]!],
COMPARATORS.GREATER_THAN,
alert.fields[ALERT_EVALUATION_VALUE]
),
} as unknown as FlyoutThresholdData;
return [APMFlyoutMapTransactionDuration];
case '.es-query':
const { thresholdComparator } = ruleParams as EsQueryRuleParams;
const { thresholdComparator, threshold } = ruleParams as EsQueryRuleParams;
const ESQueryFlyoutMap = {
observedValue: [alert.fields[ALERT_EVALUATION_VALUE]],
threshold: [alert.fields[ALERT_EVALUATION_THRESHOLD]],
threshold: threshold.join(' AND '),
comparator: thresholdComparator,
pctAboveThreshold: getPctAboveThreshold(alert.fields[ALERT_EVALUATION_VALUE], [
alert.fields[ALERT_EVALUATION_THRESHOLD]!,
]),
pctAboveThreshold: getPctAboveThreshold(
threshold,
thresholdComparator as COMPARATORS,
alert.fields[ALERT_EVALUATION_VALUE]
),
} as unknown as FlyoutThresholdData;
return [ESQueryFlyoutMap];
@ -205,10 +283,12 @@ export const mapRuleParamsWithFlyout = (alert: TopAlert): FlyoutThresholdData[]
const SLOBurnRateFlyoutMap = {
observedValue: [alert.fields[ALERT_EVALUATION_VALUE]],
threshold: [alert.fields[ALERT_EVALUATION_THRESHOLD]],
comparator: '>',
pctAboveThreshold: getPctAboveThreshold(alert.fields[ALERT_EVALUATION_VALUE], [
alert.fields[ALERT_EVALUATION_THRESHOLD]!,
]),
comparator: COMPARATORS.GREATER_THAN,
pctAboveThreshold: getPctAboveThreshold(
[alert.fields[ALERT_EVALUATION_THRESHOLD]!],
COMPARATORS.GREATER_THAN,
alert.fields[ALERT_EVALUATION_VALUE]
),
} as unknown as FlyoutThresholdData;
return [SLOBurnRateFlyoutMap];
default:

View file

@ -13,6 +13,8 @@ import { AlertStatus } from '@kbn/rule-data-utils';
import moment from 'moment';
import React from 'react';
import { Tooltip as CaseTooltip } from '@kbn/cases-components';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { LEGACY_COMPARATORS } from '../../../common/utils/convert_legacy_outside_comparator';
import type { Group } from '../../../common/custom_threshold_rule/types';
import { NavigateToCaseView } from '../../hooks/use_case_view_navigation';
import { Groups } from '../custom_threshold/components/alert_details_app_section/groups';
@ -124,11 +126,18 @@ export const overviewColumns: Array<EuiBasicTableColumn<AlertOverviewField>> = [
return (
<div>
{ruleCriteria.map((criteria, criticalIndex) => {
const threshold = criteria.threshold;
const comparator = criteria.comparator;
const { threshold, comparator } = criteria;
let formattedComparator = comparator.toUpperCase();
if (
comparator === COMPARATORS.NOT_BETWEEN ||
comparator === LEGACY_COMPARATORS.OUTSIDE_RANGE
) {
// No need for i18n as we are using the enum value, we only need a space.
formattedComparator = 'NOT BETWEEN';
}
return (
<EuiText size="s" key={`${threshold}-${criticalIndex}`}>
<h4>{`${comparator.toUpperCase()} ${threshold}`}</h4>
<h4>{`${formattedComparator} ${threshold}`}</h4>
</EuiText>
);
})}

View file

@ -5,7 +5,8 @@
* 2.0.
*/
import { Aggregators, Comparator } from '../../../../../../common/custom_threshold_rule/types';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { Aggregators } from '../../../../../../common/custom_threshold_rule/types';
import { CustomThresholdRuleTypeParams } from '../../../types';
import { getLogRateAnalysisEQQuery } from './log_rate_analysis_query';
@ -29,7 +30,7 @@ describe('buildEsQuery', () => {
timeSize: 1,
timeUnit: 'm',
threshold: [90],
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
},
],
};
@ -85,7 +86,7 @@ describe('buildEsQuery', () => {
timeSize: 1,
timeUnit: 'm',
threshold: [90],
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
},
],
},
@ -108,7 +109,7 @@ describe('buildEsQuery', () => {
timeSize: 1,
timeUnit: 'm',
threshold: [90],
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
},
],
},

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { Color } from '../../../../../common/custom_threshold_rule/color_palette';
import { Comparator } from '../../../../../common/custom_threshold_rule/types';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { shallow } from 'enzyme';
import React from 'react';
@ -30,7 +30,7 @@ describe('ThresholdAnnotations', () => {
const defaultProps = {
threshold: [20, 30],
sortedThresholds: [20, 30],
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
color: Color.color0,
id: 'testId',
firstTimestamp: 123456789,
@ -54,7 +54,7 @@ describe('ThresholdAnnotations', () => {
});
it('should render a rectangular annotation for in between thresholds', async () => {
const wrapper = await setup({ comparator: Comparator.BETWEEN });
const wrapper = await setup({ comparator: COMPARATORS.BETWEEN });
const annotation = wrapper.find('[data-test-subj="between-rect"]');
const expectedValues = [
@ -73,7 +73,7 @@ describe('ThresholdAnnotations', () => {
});
it('should render an upper rectangular annotation for outside range thresholds', async () => {
const wrapper = await setup({ comparator: Comparator.OUTSIDE_RANGE });
const wrapper = await setup({ comparator: COMPARATORS.NOT_BETWEEN });
const annotation = wrapper.find('[data-test-subj="outside-range-lower-rect"]');
const expectedValues = [
@ -92,7 +92,7 @@ describe('ThresholdAnnotations', () => {
});
it('should render a lower rectangular annotation for outside range thresholds', async () => {
const wrapper = await setup({ comparator: Comparator.OUTSIDE_RANGE });
const wrapper = await setup({ comparator: COMPARATORS.NOT_BETWEEN });
const annotation = wrapper.find('[data-test-subj="outside-range-upper-rect"]');
const expectedValues = [
@ -111,7 +111,7 @@ describe('ThresholdAnnotations', () => {
});
it('should render a rectangular annotation for below thresholds', async () => {
const wrapper = await setup({ comparator: Comparator.LT });
const wrapper = await setup({ comparator: COMPARATORS.LESS_THAN });
const annotation = wrapper.find('[data-test-subj="below-rect"]');
const expectedValues = [
@ -130,7 +130,7 @@ describe('ThresholdAnnotations', () => {
});
it('should render a rectangular annotation for above thresholds', async () => {
const wrapper = await setup({ comparator: Comparator.GT });
const wrapper = await setup({ comparator: COMPARATORS.GREATER_THAN });
const annotation = wrapper.find('[data-test-subj="above-rect"]');
const expectedValues = [

View file

@ -7,13 +7,13 @@
import { AnnotationDomainType, LineAnnotation, RectAnnotation } from '@elastic/charts';
import { first, last } from 'lodash';
import React from 'react';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { Color, colorTransformer } from '../../../../../common/custom_threshold_rule/color_palette';
import { Comparator } from '../../../../../common/custom_threshold_rule/types';
interface ThresholdAnnotationsProps {
threshold: number[];
sortedThresholds: number[];
comparator: Comparator;
comparator: COMPARATORS;
color: Color;
id: string;
firstTimestamp: number;
@ -34,8 +34,10 @@ export function ThresholdAnnotations({
domain,
}: ThresholdAnnotationsProps) {
if (!comparator || !threshold) return null;
const isAbove = [Comparator.GT, Comparator.GT_OR_EQ].includes(comparator);
const isBelow = [Comparator.LT, Comparator.LT_OR_EQ].includes(comparator);
const isAbove = [COMPARATORS.GREATER_THAN, COMPARATORS.GREATER_THAN_OR_EQUALS].includes(
comparator
);
const isBelow = [COMPARATORS.LESS_THAN, COMPARATORS.LESS_THAN_OR_EQUALS].includes(comparator);
return (
<>
<LineAnnotation
@ -53,7 +55,7 @@ export function ThresholdAnnotations({
},
}}
/>
{sortedThresholds.length === 2 && comparator === Comparator.BETWEEN ? (
{sortedThresholds.length === 2 && comparator === COMPARATORS.BETWEEN ? (
<>
<RectAnnotation
id={`${id}-lower-threshold`}
@ -75,7 +77,7 @@ export function ThresholdAnnotations({
/>
</>
) : null}
{sortedThresholds.length === 2 && comparator === Comparator.OUTSIDE_RANGE ? (
{sortedThresholds.length === 2 && comparator === COMPARATORS.NOT_BETWEEN ? (
<>
<RectAnnotation
id={`${id}-lower-threshold`}

View file

@ -9,10 +9,10 @@ import { Meta, Story } from '@storybook/react/types-6-0';
import React, { useCallback, useEffect, useState } from 'react';
import { IErrorObject } from '@kbn/triggers-actions-ui-plugin/public';
import { IUiSettingsClient } from '@kbn/core-ui-settings-browser';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { decorateWithGlobalStorybookThemeProviders } from '../../../../test_utils/use_global_storybook_theme';
import {
Aggregators,
Comparator,
CustomMetricExpressionParams,
} from '../../../../../common/custom_threshold_rule/types';
import { TimeUnitChar } from '../../../../../common';
@ -102,7 +102,7 @@ const BASE_ARGS: Partial<CustomEquationEditorProps> = {
timeSize: 1,
timeUnit: 'm' as TimeUnitChar,
threshold: [1],
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
},
fields: [
{ name: 'system.cpu.user.pct', normalizedType: 'number' },
@ -128,7 +128,7 @@ CustomEquationEditorWithEquationErrors.args = {
timeSize: 1,
timeUnit: 'm' as TimeUnitChar,
threshold: [1],
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
},
errors: {
equation:

View file

@ -8,8 +8,7 @@
import React from 'react';
import { ComponentMeta } from '@storybook/react';
import { LIGHT_THEME } from '@elastic/charts';
import { Comparator } from '../../../../common/custom_threshold_rule/types';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { Props, Threshold as Component } from './custom_threshold';
export default {
@ -31,7 +30,7 @@ export default {
const defaultProps: Props = {
chartProps: { baseTheme: LIGHT_THEME },
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
id: 'componentId',
threshold: [90],
title: 'Threshold breached',

View file

@ -10,13 +10,13 @@ import { LIGHT_THEME } from '@elastic/charts';
import { render } from '@testing-library/react';
import { Props, Threshold } from './custom_threshold';
import React from 'react';
import { Comparator } from '../../../../common/custom_threshold_rule/types';
import { COMPARATORS } from '@kbn/alerting-comparators';
describe('Threshold', () => {
const renderComponent = (props: Partial<Props> = {}) => {
const defaultProps: Props = {
chartProps: { baseTheme: LIGHT_THEME },
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
id: 'componentId',
threshold: [90],
title: 'Threshold breached',
@ -43,7 +43,7 @@ describe('Threshold', () => {
it('shows component for between', () => {
const component = renderComponent({
comparator: Comparator.BETWEEN,
comparator: COMPARATORS.BETWEEN,
threshold: [90, 95],
});
expect(component.queryByTestId('thresholdRule-90-95-93')).toBeTruthy();

View file

@ -10,7 +10,7 @@ import { Chart, Metric, Settings } from '@elastic/charts';
import { EuiIcon, EuiPanel, useEuiBackgroundColor } from '@elastic/eui';
import type { PartialTheme, Theme } from '@elastic/charts';
import { i18n } from '@kbn/i18n';
import { Comparator } from '../../../../common/custom_threshold_rule/types';
import { COMPARATORS } from '@kbn/alerting-comparators';
export interface ChartProps {
theme?: PartialTheme;
@ -19,7 +19,7 @@ export interface ChartProps {
export interface Props {
chartProps: ChartProps;
comparator: Comparator | string;
comparator: COMPARATORS | string;
id: string;
threshold: number[];
title: string;

View file

@ -9,9 +9,10 @@ import { mountWithIntl, nextTick } from '@kbn/test-jest-helpers';
import React from 'react';
import { act } from 'react-dom/test-utils';
import { Aggregators, Comparator } from '../../../../common/custom_threshold_rule/types';
import { Aggregators } from '../../../../common/custom_threshold_rule/types';
import { MetricExpression } from '../types';
import { ExpressionRow } from './expression_row';
import { COMPARATORS } from '@kbn/alerting-comparators';
describe('ExpressionRow', () => {
async function setup(expression: MetricExpression) {
@ -57,7 +58,7 @@ describe('ExpressionRow', () => {
it('should display thresholds as a percentage for pct metrics', async () => {
const expression: MetricExpression = {
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
metrics: [
{
name: 'A',
@ -82,7 +83,7 @@ describe('ExpressionRow', () => {
it('should display thresholds as a decimal for all other metrics', async () => {
const expression = {
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
metrics: [
{
name: 'A',

View file

@ -18,35 +18,20 @@ import { i18n } from '@kbn/i18n';
import React, { useCallback, useMemo, useState, ReactElement } from 'react';
import {
AggregationType,
builtInComparators,
COMPARATORS,
IErrorObject,
ThresholdExpression,
} from '@kbn/triggers-actions-ui-plugin/public';
import { DataViewBase, DataViewFieldBase } from '@kbn/es-query';
import { debounce } from 'lodash';
import { Aggregators, Comparator } from '../../../../common/custom_threshold_rule/types';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { convertToBuiltInComparators } from '../../../../common/utils/convert_legacy_outside_comparator';
import { Aggregators } from '../../../../common/custom_threshold_rule/types';
import { MetricExpression } from '../types';
import { CustomEquationEditor } from './custom_equation';
import { CUSTOM_EQUATION, LABEL_HELP_MESSAGE, LABEL_LABEL } from '../i18n_strings';
import { decimalToPct, pctToDecimal } from '../helpers/corrected_percent_convert';
import { isPercent } from '../helpers/threshold_unit';
// Create a new object with COMPARATORS.NOT_BETWEEN removed as we use OUTSIDE_RANGE
const updatedBuiltInComparators = { ...builtInComparators };
delete updatedBuiltInComparators[COMPARATORS.NOT_BETWEEN];
const customComparators = {
...updatedBuiltInComparators,
[Comparator.OUTSIDE_RANGE]: {
text: i18n.translate('xpack.observability.customThreshold.rule.alertFlyout.outsideRangeLabel', {
defaultMessage: 'Is not between',
}),
value: Comparator.OUTSIDE_RANGE,
requiredValues: 2,
},
};
interface ExpressionRowProps {
title: ReactElement;
fields: DataViewFieldBase[];
@ -76,14 +61,13 @@ export const ExpressionRow: React.FC<ExpressionRowProps> = (props) => {
title,
} = props;
const { metrics, comparator = Comparator.GT, threshold = [] } = expression;
const { metrics, comparator = COMPARATORS.GREATER_THAN, threshold = [] } = expression;
const isMetricPct = useMemo(() => isPercent(metrics), [metrics]);
const [label, setLabel] = useState<string | undefined>(expression?.label || undefined);
const updateComparator = useCallback(
(c?: string) => {
setRuleParams(expressionId, { ...expression, comparator: c as Comparator });
setRuleParams(expressionId, { ...expression, comparator: c as COMPARATORS });
},
[expressionId, expression, setRuleParams]
);
@ -214,12 +198,17 @@ const ThresholdElement: React.FC<{
return threshold;
}, [threshold, isMetricPct]);
const thresholdComparator = useCallback(() => {
if (!comparator) return COMPARATORS.GREATER_THAN;
// Check if the rule had a legacy OUTSIDE_RANGE inside its params.
// Then, change it on-the-fly to NOT_BETWEEN
return convertToBuiltInComparators(comparator);
}, [comparator]);
return (
<>
<ThresholdExpression
thresholdComparator={comparator || Comparator.GT}
thresholdComparator={thresholdComparator()}
threshold={displayedThreshold}
customComparators={customComparators}
onChangeSelectedThresholdComparator={updateComparator}
onChangeSelectedThreshold={updateThreshold}
errors={errors}

View file

@ -9,8 +9,8 @@ import React from 'react';
import { act } from 'react-dom/test-utils';
import { DataView } from '@kbn/data-views-plugin/common';
import { mountWithIntl, nextTick } from '@kbn/test-jest-helpers';
import { COMPARATORS } from '@kbn/alerting-comparators';
import {
Comparator,
Aggregators,
CustomThresholdSearchSourceFields,
} from '../../../../../common/custom_threshold_rule/types';
@ -69,7 +69,7 @@ describe('Rule condition chart', () => {
timeUnit: 'm',
sourceId: 'default',
threshold: [1],
comparator: Comparator.GT_OR_EQ,
comparator: COMPARATORS.GREATER_THAN_OR_EQUALS,
};
const { wrapper } = await setup(expression);
expect(wrapper.find('[data-test-subj="thresholdRuleNoChartData"]').exists()).toBeTruthy();

View file

@ -25,11 +25,9 @@ import { IErrorObject } from '@kbn/triggers-actions-ui-plugin/public';
import { i18n } from '@kbn/i18n';
import { TimeRange } from '@kbn/es-query';
import { EventAnnotationConfig } from '@kbn/event-annotation-common';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { EventsAsUnit } from '../../../../../common/constants';
import {
Comparator,
CustomThresholdSearchSourceFields,
} from '../../../../../common/custom_threshold_rule/types';
import { CustomThresholdSearchSourceFields } from '../../../../../common/custom_threshold_rule/types';
import { useKibana } from '../../../../utils/kibana_react';
import { MetricExpression } from '../../types';
import { AggMap, PainlessTinyMathParser } from './painless_tinymath_parser';
@ -121,15 +119,15 @@ export function RuleConditionChart({
const refLayers = [];
if (
comparator === Comparator.OUTSIDE_RANGE ||
(comparator === Comparator.BETWEEN && threshold.length === 2)
comparator === COMPARATORS.NOT_BETWEEN ||
(comparator === COMPARATORS.BETWEEN && threshold.length === 2)
) {
const refLineStart = new XYReferenceLinesLayer({
data: [
{
value: (threshold[0] || 0).toString(),
color: euiTheme.colors.danger,
fill: comparator === Comparator.OUTSIDE_RANGE ? 'below' : 'none',
fill: comparator === COMPARATORS.NOT_BETWEEN ? 'below' : 'none',
},
],
});
@ -138,7 +136,7 @@ export function RuleConditionChart({
{
value: (threshold[1] || 0).toString(),
color: euiTheme.colors.danger,
fill: comparator === Comparator.OUTSIDE_RANGE ? 'above' : 'none',
fill: comparator === COMPARATORS.NOT_BETWEEN ? 'above' : 'none',
},
],
});
@ -146,7 +144,7 @@ export function RuleConditionChart({
refLayers.push(refLineStart, refLineEnd);
} else {
let fill: FillStyle = 'above';
if (comparator === Comparator.LT || comparator === Comparator.LT_OR_EQ) {
if (comparator === COMPARATORS.LESS_THAN || comparator === COMPARATORS.LESS_THAN_OR_EQUALS) {
fill = 'below';
}
const thresholdRefLine = new XYReferenceLinesLayer({

View file

@ -11,8 +11,8 @@ import { buildEsQuery, fromKueryExpression } from '@kbn/es-query';
import { i18n } from '@kbn/i18n';
import { ValidationResult } from '@kbn/triggers-actions-ui-plugin/public';
import { isEmpty } from 'lodash';
import { COMPARATORS } from '@kbn/alerting-comparators';
import {
Comparator,
CustomMetricExpressionParams,
CustomThresholdSearchSourceFields,
} from '../../../../common/custom_threshold_rule/types';
@ -111,7 +111,7 @@ export function validateCustomThreshold({
// The Threshold component returns an empty array with a length ([empty]) because it's using delete newThreshold[i].
// We need to use [...c.threshold] to convert it to an array with an undefined value ([undefined]) so we can test each element.
const { comparator, threshold } = { comparator: c.comparator, threshold: c.threshold } as {
comparator?: Comparator;
comparator?: COMPARATORS;
threshold?: number[];
};
if (threshold && threshold.length && ![...threshold].every(isNumber)) {
@ -130,7 +130,7 @@ export function validateCustomThreshold({
});
}
if (comparator === Comparator.BETWEEN && (!threshold || threshold.length < 2)) {
if (comparator === COMPARATORS.BETWEEN && (!threshold || threshold.length < 2)) {
errors[id].critical.threshold1.push(
i18n.translate(
'xpack.observability.customThreshold.rule.alertFlyout.error.thresholdRequired',

View file

@ -13,7 +13,8 @@ import { queryClient } from '@kbn/osquery-plugin/public/query_client';
import { mountWithIntl, nextTick } from '@kbn/test-jest-helpers';
import { QueryClientProvider } from '@tanstack/react-query';
import { act } from 'react-dom/test-utils';
import { Aggregators, Comparator } from '../../../common/custom_threshold_rule/types';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { Aggregators } from '../../../common/custom_threshold_rule/types';
import { useKibana } from '../../utils/kibana_react';
import { kibanaStartMock } from '../../utils/kibana_react.mock';
import Expressions from './custom_threshold_rule_expression';
@ -152,7 +153,7 @@ describe('Expression', () => {
aggType: Aggregators.COUNT,
},
],
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [100],
timeSize: 1,
timeUnit: 'm',
@ -178,7 +179,7 @@ describe('Expression', () => {
{ name: 'A', aggType: Aggregators.AVERAGE, field: 'system.load.1' },
{ name: 'B', aggType: Aggregators.CARDINALITY, field: 'system.cpu.user.pct' },
],
comparator: Comparator.LT_OR_EQ,
comparator: COMPARATORS.LESS_THAN_OR_EQUALS,
equation: 'A * B',
label: 'prefill label',
threshold: [500],
@ -200,7 +201,7 @@ describe('Expression', () => {
{ name: 'A', aggType: Aggregators.AVERAGE, field: 'system.load.1' },
{ name: 'B', aggType: Aggregators.CARDINALITY, field: 'system.cpu.user.pct' },
],
comparator: Comparator.LT_OR_EQ,
comparator: COMPARATORS.LESS_THAN_OR_EQUALS,
equation: 'A * B',
label: 'prefill label',
threshold: [500],

View file

@ -36,8 +36,9 @@ import {
RuleTypeParamsExpressionProps,
} from '@kbn/triggers-actions-ui-plugin/public';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { useKibana } from '../../utils/kibana_react';
import { Aggregators, Comparator } from '../../../common/custom_threshold_rule/types';
import { Aggregators } from '../../../common/custom_threshold_rule/types';
import { TimeUnitChar } from '../../../common/utils/formatters/duration';
import { AlertContextMeta, AlertParams, MetricExpression } from './types';
import { ExpressionRow } from './components/expression_row';
@ -53,7 +54,7 @@ type Props = Omit<
>;
export const defaultExpression: MetricExpression = {
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
metrics: [
{
name: 'A',

View file

@ -7,8 +7,9 @@
import { v4 as uuidv4 } from 'uuid';
import { ParsedTechnicalFields } from '@kbn/rule-registry-plugin/common';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { CustomThresholdAlertFields } from '../types';
import { Aggregators, Comparator } from '../../../../common/custom_threshold_rule/types';
import { Aggregators } from '../../../../common/custom_threshold_rule/types';
import { CustomThresholdAlert, CustomThresholdRule } from '../components/types';
@ -60,7 +61,7 @@ export const buildCustomThresholdRule = (
params: {
criteria: [
{
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
metrics: [
{
name: 'A',
@ -72,7 +73,7 @@ export const buildCustomThresholdRule = (
timeUnit: 'm',
},
{
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
metrics: [
{
name: 'B',
@ -83,11 +84,9 @@ export const buildCustomThresholdRule = (
threshold: [4],
timeSize: 15,
timeUnit: 'm',
warningComparator: Comparator.GT,
warningThreshold: [2.2],
},
{
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
metrics: [
{
name: 'C',
@ -100,7 +99,7 @@ export const buildCustomThresholdRule = (
timeUnit: 'm',
},
{
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
metrics: [
{
name: 'A',
@ -115,7 +114,7 @@ export const buildCustomThresholdRule = (
'A + A + A + A + A + A + A + A + A + A + A + A + A + A + A + A + A + A + A + A + A',
},
{
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
metrics: [
{
name: 'C',
@ -133,7 +132,7 @@ export const buildCustomThresholdRule = (
timeUnit: 'm',
},
{
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
metrics: [
{
name: 'CAD',
@ -209,7 +208,7 @@ export const buildCustomThresholdAlert = (
'kibana.alert.rule.parameters': {
criteria: [
{
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
metrics: [
{
name: 'A',
@ -222,7 +221,7 @@ export const buildCustomThresholdAlert = (
timeUnit: 'm',
},
{
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
metrics: [
{
name: 'B',
@ -233,7 +232,7 @@ export const buildCustomThresholdAlert = (
threshold: [4],
timeSize: 15,
timeUnit: 'm',
warningComparator: Comparator.GT,
warningComparator: COMPARATORS.GREATER_THAN,
warningThreshold: [2.2],
},
],

View file

@ -194,7 +194,6 @@ export function RuleDetailsPage() {
: '';
if (isLoading || isRuleDeleting) return <CenterJustifiedSpinner />;
if (!rule || isError) return <NoRuleFoundPanel />;
return (

View file

@ -13,9 +13,9 @@ import { FIRED_ACTION, NO_DATA_ACTION } from './constants';
import { Evaluation } from './lib/evaluate_rule';
import type { LogMeta, Logger } from '@kbn/logging';
import { DEFAULT_FLAPPING_SETTINGS } from '@kbn/alerting-plugin/common';
import { COMPARATORS } from '@kbn/alerting-comparators';
import {
Aggregators,
Comparator,
CustomMetricExpressionParams,
CustomThresholdExpressionMetric,
} from '../../../../common/custom_threshold_rule/types';
@ -234,7 +234,7 @@ describe('The custom threshold alert type', () => {
beforeEach(() => jest.clearAllMocks());
afterAll(() => clearInstances());
const instanceID = '*';
const execute = (comparator: Comparator, threshold: number[], sourceId: string = 'default') =>
const execute = (comparator: COMPARATORS, threshold: number[], sourceId: string = 'default') =>
executor({
...mockOptions,
services,
@ -251,7 +251,7 @@ describe('The custom threshold alert type', () => {
},
});
const setResults = (
comparator: Comparator,
comparator: COMPARATORS,
threshold: number[],
shouldFire: boolean = false,
isNoData: boolean = false
@ -271,62 +271,62 @@ describe('The custom threshold alert type', () => {
},
]);
test('alerts as expected with the > comparator', async () => {
setResults(Comparator.GT, [0.75], true);
await execute(Comparator.GT, [0.75]);
setResults(COMPARATORS.GREATER_THAN, [0.75], true);
await execute(COMPARATORS.GREATER_THAN, [0.75]);
expect(getLastReportedAlert(instanceID)).toHaveAlertAction();
setResults(Comparator.GT, [1.5], false);
await execute(Comparator.GT, [1.5]);
setResults(COMPARATORS.GREATER_THAN, [1.5], false);
await execute(COMPARATORS.GREATER_THAN, [1.5]);
expect(getLastReportedAlert(instanceID)).toBe(undefined);
});
test('alerts as expected with the < comparator', async () => {
setResults(Comparator.LT, [1.5], true);
await execute(Comparator.LT, [1.5]);
setResults(COMPARATORS.LESS_THAN, [1.5], true);
await execute(COMPARATORS.LESS_THAN, [1.5]);
expect(getLastReportedAlert(instanceID)).toHaveAlertAction();
setResults(Comparator.LT, [0.75], false);
await execute(Comparator.LT, [0.75]);
setResults(COMPARATORS.LESS_THAN, [0.75], false);
await execute(COMPARATORS.LESS_THAN, [0.75]);
expect(getLastReportedAlert(instanceID)).toBe(undefined);
});
test('alerts as expected with the >= comparator', async () => {
setResults(Comparator.GT_OR_EQ, [0.75], true);
await execute(Comparator.GT_OR_EQ, [0.75]);
setResults(COMPARATORS.GREATER_THAN_OR_EQUALS, [0.75], true);
await execute(COMPARATORS.GREATER_THAN_OR_EQUALS, [0.75]);
expect(getLastReportedAlert(instanceID)).toHaveAlertAction();
setResults(Comparator.GT_OR_EQ, [1.0], true);
await execute(Comparator.GT_OR_EQ, [1.0]);
setResults(COMPARATORS.GREATER_THAN_OR_EQUALS, [1.0], true);
await execute(COMPARATORS.GREATER_THAN_OR_EQUALS, [1.0]);
expect(getLastReportedAlert(instanceID)).toHaveAlertAction();
setResults(Comparator.GT_OR_EQ, [1.5], false);
await execute(Comparator.GT_OR_EQ, [1.5]);
setResults(COMPARATORS.GREATER_THAN_OR_EQUALS, [1.5], false);
await execute(COMPARATORS.GREATER_THAN_OR_EQUALS, [1.5]);
expect(getLastReportedAlert(instanceID)).toBe(undefined);
});
test('alerts as expected with the <= comparator', async () => {
setResults(Comparator.LT_OR_EQ, [1.5], true);
await execute(Comparator.LT_OR_EQ, [1.5]);
setResults(COMPARATORS.LESS_THAN_OR_EQUALS, [1.5], true);
await execute(COMPARATORS.LESS_THAN_OR_EQUALS, [1.5]);
expect(getLastReportedAlert(instanceID)).toHaveAlertAction();
setResults(Comparator.LT_OR_EQ, [1.0], true);
await execute(Comparator.LT_OR_EQ, [1.0]);
setResults(COMPARATORS.LESS_THAN_OR_EQUALS, [1.0], true);
await execute(COMPARATORS.LESS_THAN_OR_EQUALS, [1.0]);
expect(getLastReportedAlert(instanceID)).toHaveAlertAction();
setResults(Comparator.LT_OR_EQ, [0.75], false);
await execute(Comparator.LT_OR_EQ, [0.75]);
setResults(COMPARATORS.LESS_THAN_OR_EQUALS, [0.75], false);
await execute(COMPARATORS.LESS_THAN_OR_EQUALS, [0.75]);
expect(getLastReportedAlert(instanceID)).toBe(undefined);
});
test('alerts as expected with the between comparator', async () => {
setResults(Comparator.BETWEEN, [0, 1.5], true);
await execute(Comparator.BETWEEN, [0, 1.5]);
setResults(COMPARATORS.BETWEEN, [0, 1.5], true);
await execute(COMPARATORS.BETWEEN, [0, 1.5]);
expect(getLastReportedAlert(instanceID)).toHaveAlertAction();
setResults(Comparator.BETWEEN, [0, 0.75], false);
await execute(Comparator.BETWEEN, [0, 0.75]);
setResults(COMPARATORS.BETWEEN, [0, 0.75], false);
await execute(COMPARATORS.BETWEEN, [0, 0.75]);
expect(getLastReportedAlert(instanceID)).toBe(undefined);
});
test('alerts as expected with the outside range comparator', async () => {
setResults(Comparator.OUTSIDE_RANGE, [0, 0.75], true);
await execute(Comparator.OUTSIDE_RANGE, [0, 0.75]);
test('alerts as expected with the not between comparator', async () => {
setResults(COMPARATORS.NOT_BETWEEN, [0, 0.75], true);
await execute(COMPARATORS.NOT_BETWEEN, [0, 0.75]);
expect(getLastReportedAlert(instanceID)).toHaveAlertAction();
setResults(Comparator.OUTSIDE_RANGE, [0, 1.5], false);
await execute(Comparator.OUTSIDE_RANGE, [0, 1.5]);
setResults(COMPARATORS.NOT_BETWEEN, [0, 1.5], false);
await execute(COMPARATORS.NOT_BETWEEN, [0, 1.5]);
expect(getLastReportedAlert(instanceID)).toBe(undefined);
});
test('reports expected values to the action context', async () => {
setResults(Comparator.GT, [0.75], true);
await execute(Comparator.GT, [0.75]);
setResults(COMPARATORS.GREATER_THAN, [0.75], true);
await execute(COMPARATORS.GREATER_THAN, [0.75]);
const reportedAlert = getLastReportedAlert(instanceID);
expect(reportedAlert?.context?.group).toBeUndefined();
expect(reportedAlert?.context?.reason).toBe(
@ -339,7 +339,7 @@ describe('The custom threshold alert type', () => {
beforeEach(() => jest.clearAllMocks());
afterAll(() => clearInstances());
const execute = (
comparator: Comparator,
comparator: COMPARATORS,
threshold: number[],
groupBy: string[] = ['groupByField'],
metrics?: CustomThresholdExpressionMetric[],
@ -369,7 +369,7 @@ describe('The custom threshold alert type', () => {
{
a: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.75],
currentValue: 1.0,
timestamp: new Date().toISOString(),
@ -379,7 +379,7 @@ describe('The custom threshold alert type', () => {
},
b: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.75],
currentValue: 1.0,
timestamp: new Date().toISOString(),
@ -389,7 +389,7 @@ describe('The custom threshold alert type', () => {
},
},
]);
await execute(Comparator.GT, [0.75]);
await execute(COMPARATORS.GREATER_THAN, [0.75]);
expect(getLastReportedAlert(instanceIdA)).toHaveAlertAction();
expect(getLastReportedAlert(instanceIdB)).toHaveAlertAction();
});
@ -398,7 +398,7 @@ describe('The custom threshold alert type', () => {
{
a: {
...customThresholdNonCountCriterion,
comparator: Comparator.LT,
comparator: COMPARATORS.LESS_THAN,
threshold: [1.5],
currentValue: 1.0,
timestamp: new Date().toISOString(),
@ -408,7 +408,7 @@ describe('The custom threshold alert type', () => {
},
b: {
...customThresholdNonCountCriterion,
comparator: Comparator.LT,
comparator: COMPARATORS.LESS_THAN,
threshold: [1.5],
currentValue: 3,
timestamp: new Date().toISOString(),
@ -418,7 +418,7 @@ describe('The custom threshold alert type', () => {
},
},
]);
await execute(Comparator.LT, [1.5]);
await execute(COMPARATORS.LESS_THAN, [1.5]);
expect(getLastReportedAlert(instanceIdA)).toHaveAlertAction();
expect(getLastReportedAlert(instanceIdB)).toBe(undefined);
});
@ -427,7 +427,7 @@ describe('The custom threshold alert type', () => {
{
a: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [5],
currentValue: 1.0,
timestamp: new Date().toISOString(),
@ -437,7 +437,7 @@ describe('The custom threshold alert type', () => {
},
b: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [5],
currentValue: 3,
timestamp: new Date().toISOString(),
@ -447,7 +447,7 @@ describe('The custom threshold alert type', () => {
},
},
]);
await execute(Comparator.GT, [5]);
await execute(COMPARATORS.GREATER_THAN, [5]);
expect(getLastReportedAlert(instanceIdA)).toBe(undefined);
expect(getLastReportedAlert(instanceIdB)).toBe(undefined);
});
@ -456,7 +456,7 @@ describe('The custom threshold alert type', () => {
{
a: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.75],
currentValue: 1.0,
timestamp: new Date().toISOString(),
@ -466,7 +466,7 @@ describe('The custom threshold alert type', () => {
},
b: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.75],
currentValue: 3,
timestamp: new Date().toISOString(),
@ -476,7 +476,7 @@ describe('The custom threshold alert type', () => {
},
},
]);
await execute(Comparator.GT, [0.75]);
await execute(COMPARATORS.GREATER_THAN, [0.75]);
expect(getLastReportedAlert(instanceIdA)?.context?.group).toEqual([
{ field: 'groupByField', value: 'a' },
]);
@ -489,7 +489,7 @@ describe('The custom threshold alert type', () => {
{
a: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.75],
metrics: [
{
@ -506,7 +506,7 @@ describe('The custom threshold alert type', () => {
},
b: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.75],
metrics: [
{
@ -523,7 +523,7 @@ describe('The custom threshold alert type', () => {
},
c: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.75],
metrics: [
{
@ -541,7 +541,7 @@ describe('The custom threshold alert type', () => {
},
]);
const { state: stateResult1 } = await execute(
Comparator.GT,
COMPARATORS.GREATER_THAN,
[0.75],
['groupByField'],
[
@ -557,7 +557,7 @@ describe('The custom threshold alert type', () => {
{
a: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.75],
currentValue: 1.0,
timestamp: new Date().toISOString(),
@ -567,7 +567,7 @@ describe('The custom threshold alert type', () => {
},
b: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.75],
currentValue: 3,
timestamp: new Date().toISOString(),
@ -577,7 +577,7 @@ describe('The custom threshold alert type', () => {
},
c: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.75],
currentValue: null,
timestamp: new Date().toISOString(),
@ -588,7 +588,7 @@ describe('The custom threshold alert type', () => {
},
]);
const { state: stateResult2 } = await execute(
Comparator.GT,
COMPARATORS.GREATER_THAN,
[0.75],
['groupByField'],
[
@ -607,7 +607,7 @@ describe('The custom threshold alert type', () => {
{
a: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.75],
currentValue: 1.0,
timestamp: new Date().toISOString(),
@ -617,7 +617,7 @@ describe('The custom threshold alert type', () => {
},
b: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.75],
currentValue: 3,
timestamp: new Date().toISOString(),
@ -628,7 +628,7 @@ describe('The custom threshold alert type', () => {
},
]);
const { state: stateResult3 } = await execute(
Comparator.GT,
COMPARATORS.GREATER_THAN,
[0.75],
['groupByField', 'groupByField-else'],
[
@ -644,7 +644,7 @@ describe('The custom threshold alert type', () => {
});
const executeWithFilter = (
comparator: Comparator,
comparator: COMPARATORS,
threshold: number[],
filterQuery: string,
metrics?: any,
@ -679,7 +679,7 @@ describe('The custom threshold alert type', () => {
{
a: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.75],
metrics: [
{
@ -696,7 +696,7 @@ describe('The custom threshold alert type', () => {
},
b: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.75],
metrics: [
{
@ -713,7 +713,7 @@ describe('The custom threshold alert type', () => {
},
c: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.75],
metrics: [
{
@ -731,7 +731,7 @@ describe('The custom threshold alert type', () => {
},
]);
const { state: stateResult1 } = await executeWithFilter(
Comparator.GT,
COMPARATORS.GREATER_THAN,
[0.75],
JSON.stringify({ query: 'q' }),
'test.metric.2'
@ -741,7 +741,7 @@ describe('The custom threshold alert type', () => {
{
a: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.75],
currentValue: 1.0,
timestamp: new Date().toISOString(),
@ -751,7 +751,7 @@ describe('The custom threshold alert type', () => {
},
b: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.75],
currentValue: 3,
timestamp: new Date().toISOString(),
@ -761,7 +761,7 @@ describe('The custom threshold alert type', () => {
},
c: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.75],
currentValue: null,
timestamp: new Date().toISOString(),
@ -772,7 +772,7 @@ describe('The custom threshold alert type', () => {
},
]);
const { state: stateResult2 } = await executeWithFilter(
Comparator.GT,
COMPARATORS.GREATER_THAN,
[0.75],
JSON.stringify({ query: 'q' }),
'test.metric.1',
@ -785,7 +785,7 @@ describe('The custom threshold alert type', () => {
{
a: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.75],
currentValue: 1.0,
timestamp: new Date().toISOString(),
@ -795,7 +795,7 @@ describe('The custom threshold alert type', () => {
},
b: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.75],
currentValue: 3,
timestamp: new Date().toISOString(),
@ -806,7 +806,7 @@ describe('The custom threshold alert type', () => {
},
]);
const { state: stateResult3 } = await executeWithFilter(
Comparator.GT,
COMPARATORS.GREATER_THAN,
[0.75],
JSON.stringify({ query: 'different' }),
[
@ -825,7 +825,7 @@ describe('The custom threshold alert type', () => {
{
a: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.75],
metrics: [
{
@ -842,7 +842,7 @@ describe('The custom threshold alert type', () => {
},
b: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.75],
metrics: [
{
@ -859,7 +859,7 @@ describe('The custom threshold alert type', () => {
},
c: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.75],
metrics: [
{
@ -877,7 +877,7 @@ describe('The custom threshold alert type', () => {
},
]);
const { state: stateResult1 } = await executeWithFilter(
Comparator.GT,
COMPARATORS.GREATER_THAN,
[0.75],
JSON.stringify({ query: 'q' }),
'test.metric.2'
@ -887,7 +887,7 @@ describe('The custom threshold alert type', () => {
{
a: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.75],
currentValue: 1.0,
timestamp: new Date().toISOString(),
@ -897,7 +897,7 @@ describe('The custom threshold alert type', () => {
},
b: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.75],
currentValue: null,
timestamp: new Date().toISOString(),
@ -907,7 +907,7 @@ describe('The custom threshold alert type', () => {
},
c: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.75],
currentValue: null,
timestamp: new Date().toISOString(),
@ -918,7 +918,7 @@ describe('The custom threshold alert type', () => {
},
]);
const { state: stateResult2 } = await executeWithFilter(
Comparator.GT,
COMPARATORS.GREATER_THAN,
[0.75],
JSON.stringify({ query: 'q' }),
'test.metric.1',
@ -934,7 +934,7 @@ describe('The custom threshold alert type', () => {
{
a: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.75],
currentValue: 1.0,
timestamp: new Date().toISOString(),
@ -944,7 +944,7 @@ describe('The custom threshold alert type', () => {
},
b: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.75],
currentValue: null,
timestamp: new Date().toISOString(),
@ -957,7 +957,7 @@ describe('The custom threshold alert type', () => {
// Consider c as untracked
services.alertsClient.isTrackedAlert.mockImplementation((id: string) => id !== 'c');
const { state: stateResult3 } = await executeWithFilter(
Comparator.GT,
COMPARATORS.GREATER_THAN,
[0.75],
JSON.stringify({ query: 'q' }),
'test.metric.1',
@ -973,7 +973,7 @@ describe('The custom threshold alert type', () => {
describe('querying with a groupBy parameter host.name and rule tags', () => {
afterAll(() => clearInstances());
const execute = (
comparator: Comparator,
comparator: COMPARATORS,
threshold: number[],
groupBy: string[] = ['host.name'],
metrics?: any,
@ -1008,7 +1008,7 @@ describe('The custom threshold alert type', () => {
{
'host-01': {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.75],
currentValue: 1.0,
timestamp: new Date().toISOString(),
@ -1021,7 +1021,7 @@ describe('The custom threshold alert type', () => {
},
'host-02': {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.75],
currentValue: 3,
timestamp: new Date().toISOString(),
@ -1034,7 +1034,7 @@ describe('The custom threshold alert type', () => {
},
},
]);
await execute(Comparator.GT, [0.75]);
await execute(COMPARATORS.GREATER_THAN, [0.75]);
expect(getLastReportedAlert(instanceIdA)?.context?.tags).toStrictEqual([
'host-01_tag1',
'host-01_tag2',
@ -1053,7 +1053,7 @@ describe('The custom threshold alert type', () => {
describe('querying without a groupBy parameter and rule tags', () => {
afterAll(() => clearInstances());
const execute = (
comparator: Comparator,
comparator: COMPARATORS,
threshold: number[],
groupBy: string = '',
metrics?: any,
@ -1086,7 +1086,7 @@ describe('The custom threshold alert type', () => {
{
'*': {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.75],
currentValue: 1.0,
timestamp: new Date().toISOString(),
@ -1098,7 +1098,7 @@ describe('The custom threshold alert type', () => {
]);
const instanceID = '*';
await execute(Comparator.GT, [0.75]);
await execute(COMPARATORS.GREATER_THAN, [0.75]);
expect(getLastReportedAlert(instanceID)?.context?.tags).toStrictEqual([
'ruleTag1',
'ruleTag2',
@ -1109,7 +1109,7 @@ describe('The custom threshold alert type', () => {
describe('querying with multiple criteria', () => {
afterAll(() => clearInstances());
const execute = (
comparator: Comparator,
comparator: COMPARATORS,
thresholdA: number[],
thresholdB: number[],
groupBy: string = '',
@ -1148,7 +1148,7 @@ describe('The custom threshold alert type', () => {
{
'*': {
...customThresholdNonCountCriterion,
comparator: Comparator.GT_OR_EQ,
comparator: COMPARATORS.GREATER_THAN_OR_EQUALS,
threshold: [1.0],
currentValue: 1.0,
timestamp: new Date().toISOString(),
@ -1160,7 +1160,7 @@ describe('The custom threshold alert type', () => {
{
'*': {
...customThresholdNonCountCriterion,
comparator: Comparator.GT_OR_EQ,
comparator: COMPARATORS.GREATER_THAN_OR_EQUALS,
threshold: [3.0],
currentValue: 3.0,
timestamp: new Date().toISOString(),
@ -1171,7 +1171,7 @@ describe('The custom threshold alert type', () => {
},
]);
const instanceID = '*';
await execute(Comparator.GT_OR_EQ, [1.0], [3.0]);
await execute(COMPARATORS.GREATER_THAN_OR_EQUALS, [1.0], [3.0]);
expect(getLastReportedAlert(instanceID)).toHaveAlertAction();
});
test('sends no alert when some, but not all, criteria cross the threshold', async () => {
@ -1179,7 +1179,7 @@ describe('The custom threshold alert type', () => {
{
'*': {
...customThresholdNonCountCriterion,
comparator: Comparator.LT_OR_EQ,
comparator: COMPARATORS.LESS_THAN_OR_EQUALS,
threshold: [1.0],
currentValue: 1.0,
timestamp: new Date().toISOString(),
@ -1191,7 +1191,7 @@ describe('The custom threshold alert type', () => {
{},
]);
const instanceID = '*';
await execute(Comparator.LT_OR_EQ, [1.0], [2.5]);
await execute(COMPARATORS.LESS_THAN_OR_EQUALS, [1.0], [2.5]);
expect(getLastReportedAlert(instanceID)).toBe(undefined);
});
test('alerts only on groups that meet all criteria when querying with a groupBy parameter', async () => {
@ -1199,7 +1199,7 @@ describe('The custom threshold alert type', () => {
{
a: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT_OR_EQ,
comparator: COMPARATORS.GREATER_THAN_OR_EQUALS,
threshold: [1.0],
currentValue: 1.0,
timestamp: new Date().toISOString(),
@ -1209,7 +1209,7 @@ describe('The custom threshold alert type', () => {
},
b: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT_OR_EQ,
comparator: COMPARATORS.GREATER_THAN_OR_EQUALS,
threshold: [1.0],
currentValue: 3.0,
timestamp: new Date().toISOString(),
@ -1221,7 +1221,7 @@ describe('The custom threshold alert type', () => {
{
a: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT_OR_EQ,
comparator: COMPARATORS.GREATER_THAN_OR_EQUALS,
threshold: [3.0],
metrics: [
{
@ -1238,7 +1238,7 @@ describe('The custom threshold alert type', () => {
},
b: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT_OR_EQ,
comparator: COMPARATORS.GREATER_THAN_OR_EQUALS,
threshold: [3.0],
metrics: [
{
@ -1257,7 +1257,7 @@ describe('The custom threshold alert type', () => {
]);
const instanceIdA = 'a';
const instanceIdB = 'b';
await execute(Comparator.GT_OR_EQ, [1.0], [3.0], 'groupByField');
await execute(COMPARATORS.GREATER_THAN_OR_EQUALS, [1.0], [3.0], 'groupByField');
expect(getLastReportedAlert(instanceIdA)).toHaveAlertAction();
expect(getLastReportedAlert(instanceIdB)).toBe(undefined);
});
@ -1266,7 +1266,7 @@ describe('The custom threshold alert type', () => {
{
'*': {
...customThresholdNonCountCriterion,
comparator: Comparator.GT_OR_EQ,
comparator: COMPARATORS.GREATER_THAN_OR_EQUALS,
threshold: [1.0],
currentValue: 1.0,
timestamp: new Date().toISOString(),
@ -1278,7 +1278,7 @@ describe('The custom threshold alert type', () => {
{
'*': {
...customThresholdNonCountCriterion,
comparator: Comparator.GT_OR_EQ,
comparator: COMPARATORS.GREATER_THAN_OR_EQUALS,
threshold: [3.0],
metrics: [
{
@ -1296,7 +1296,7 @@ describe('The custom threshold alert type', () => {
},
]);
const instanceID = '*';
await execute(Comparator.GT_OR_EQ, [1.0], [3.0]);
await execute(COMPARATORS.GREATER_THAN_OR_EQUALS, [1.0], [3.0]);
const reportedAlert = getLastReportedAlert(instanceID);
const reasons = reportedAlert?.context?.reason;
expect(reasons).toBe(
@ -1308,7 +1308,7 @@ describe('The custom threshold alert type', () => {
describe('querying with the count aggregator', () => {
afterAll(() => clearInstances());
const instanceID = '*';
const execute = (comparator: Comparator, threshold: number[], sourceId: string = 'default') =>
const execute = (comparator: COMPARATORS, threshold: number[], sourceId: string = 'default') =>
executor({
...mockOptions,
services,
@ -1329,7 +1329,7 @@ describe('The custom threshold alert type', () => {
{
'*': {
...customThresholdCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.9],
currentValue: 1,
timestamp: new Date().toISOString(),
@ -1339,13 +1339,13 @@ describe('The custom threshold alert type', () => {
},
},
]);
await execute(Comparator.GT, [0.9]);
await execute(COMPARATORS.GREATER_THAN, [0.9]);
expect(getLastReportedAlert(instanceID)).toHaveAlertAction();
setEvaluationResults([
{
'*': {
...customThresholdCountCriterion,
comparator: Comparator.LT,
comparator: COMPARATORS.LESS_THAN,
threshold: [0.5],
currentValue: 1,
timestamp: new Date().toISOString(),
@ -1355,12 +1355,12 @@ describe('The custom threshold alert type', () => {
},
},
]);
await execute(Comparator.LT, [0.5]);
await execute(COMPARATORS.LESS_THAN, [0.5]);
expect(getLastReportedAlert(instanceID)).toBe(undefined);
});
describe('with a groupBy parameter', () => {
const executeGroupBy = (
comparator: Comparator,
comparator: COMPARATORS,
threshold: number[],
sourceId: string = 'default',
state?: any
@ -1390,7 +1390,7 @@ describe('The custom threshold alert type', () => {
{
a: {
...customThresholdCountCriterion,
comparator: Comparator.LT_OR_EQ,
comparator: COMPARATORS.LESS_THAN_OR_EQUALS,
threshold: [0],
currentValue: 1,
timestamp: new Date().toISOString(),
@ -1400,7 +1400,7 @@ describe('The custom threshold alert type', () => {
},
b: {
...customThresholdCountCriterion,
comparator: Comparator.LT_OR_EQ,
comparator: COMPARATORS.LESS_THAN_OR_EQUALS,
threshold: [0],
currentValue: 1,
timestamp: new Date().toISOString(),
@ -1410,14 +1410,14 @@ describe('The custom threshold alert type', () => {
},
},
]);
const resultState = await executeGroupBy(Comparator.LT_OR_EQ, [0]);
const resultState = await executeGroupBy(COMPARATORS.LESS_THAN_OR_EQUALS, [0]);
expect(getLastReportedAlert(instanceIdA)).toBe(undefined);
expect(getLastReportedAlert(instanceIdB)).toBe(undefined);
setEvaluationResults([
{
a: {
...customThresholdCountCriterion,
comparator: Comparator.LT_OR_EQ,
comparator: COMPARATORS.LESS_THAN_OR_EQUALS,
threshold: [0],
currentValue: 0,
timestamp: new Date().toISOString(),
@ -1427,7 +1427,7 @@ describe('The custom threshold alert type', () => {
},
b: {
...customThresholdCountCriterion,
comparator: Comparator.LT_OR_EQ,
comparator: COMPARATORS.LESS_THAN_OR_EQUALS,
threshold: [0],
currentValue: 0,
timestamp: new Date().toISOString(),
@ -1437,7 +1437,7 @@ describe('The custom threshold alert type', () => {
},
},
]);
await executeGroupBy(Comparator.LT_OR_EQ, [0], 'empty-response', resultState);
await executeGroupBy(COMPARATORS.LESS_THAN_OR_EQUALS, [0], 'empty-response', resultState);
expect(getLastReportedAlert(instanceIdA)).toHaveAlertAction();
expect(getLastReportedAlert(instanceIdB)).toHaveAlertAction();
});
@ -1446,7 +1446,7 @@ describe('The custom threshold alert type', () => {
describe('querying recovered alert with a count aggregator', () => {
afterAll(() => clearInstances());
const execute = (comparator: Comparator, threshold: number[], sourceId: string = 'default') =>
const execute = (comparator: COMPARATORS, threshold: number[], sourceId: string = 'default') =>
executor({
...mockOptions,
services,
@ -1467,7 +1467,7 @@ describe('The custom threshold alert type', () => {
{
'*': {
...customThresholdCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.9],
currentValue: 1,
timestamp: new Date().toISOString(),
@ -1488,7 +1488,7 @@ describe('The custom threshold alert type', () => {
]),
};
});
await execute(Comparator.GT, [0.9]);
await execute(COMPARATORS.GREATER_THAN, [0.9]);
const ISO_DATE_REGEX = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
expect(getViewInAppUrl).toBeCalledWith({
dataViewId: 'c34a7c79-a88b-4b4a-ad19-72f6d24104e4',
@ -1519,7 +1519,7 @@ describe('The custom threshold alert type', () => {
criteria: [
{
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [1],
metrics: [
{
@ -1538,7 +1538,7 @@ describe('The custom threshold alert type', () => {
{
'*': {
...customThresholdNonCountCriterion,
comparator: Comparator.LT,
comparator: COMPARATORS.LESS_THAN,
threshold: [1],
metrics: [
{
@ -1567,7 +1567,7 @@ describe('The custom threshold alert type', () => {
{
'*': {
...customThresholdNonCountCriterion,
comparator: Comparator.LT,
comparator: COMPARATORS.LESS_THAN,
threshold: [1],
metrics: [
{
@ -1602,7 +1602,7 @@ describe('The custom threshold alert type', () => {
criteria: [
{
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [1],
metrics: [
{
@ -1614,7 +1614,7 @@ describe('The custom threshold alert type', () => {
},
{
...customThresholdCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [30],
},
],
@ -1626,7 +1626,7 @@ describe('The custom threshold alert type', () => {
{
'*': {
...customThresholdNonCountCriterion,
comparator: Comparator.LT,
comparator: COMPARATORS.LESS_THAN,
threshold: [1],
metrics: [
{
@ -1675,7 +1675,7 @@ describe('The custom threshold alert type', () => {
criteria: [
{
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0],
metrics,
},
@ -1700,7 +1700,7 @@ describe('The custom threshold alert type', () => {
{
'*': {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0],
metrics: [
{
@ -1723,7 +1723,7 @@ describe('The custom threshold alert type', () => {
{
'*': {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0],
metrics: [
{
@ -1746,7 +1746,7 @@ describe('The custom threshold alert type', () => {
{
a: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0],
currentValue: 1.0,
timestamp: new Date().toISOString(),
@ -1756,7 +1756,7 @@ describe('The custom threshold alert type', () => {
},
b: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0],
currentValue: 3,
timestamp: new Date().toISOString(),
@ -1780,7 +1780,7 @@ describe('The custom threshold alert type', () => {
{
a: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0],
metrics: [
{
@ -1797,7 +1797,7 @@ describe('The custom threshold alert type', () => {
},
b: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0],
metrics: [
{
@ -1824,7 +1824,7 @@ describe('The custom threshold alert type', () => {
{
a: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0],
metrics: [
{
@ -1841,7 +1841,7 @@ describe('The custom threshold alert type', () => {
},
b: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0],
metrics: [
{
@ -1858,7 +1858,7 @@ describe('The custom threshold alert type', () => {
},
c: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0],
metrics: [
{
@ -1884,7 +1884,7 @@ describe('The custom threshold alert type', () => {
{
a: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0],
currentValue: 1,
timestamp: new Date().toISOString(),
@ -1894,7 +1894,7 @@ describe('The custom threshold alert type', () => {
},
b: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0],
currentValue: 3,
timestamp: new Date().toISOString(),
@ -1923,7 +1923,7 @@ describe('The custom threshold alert type', () => {
criteria: [
{
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0],
metrics,
},
@ -1944,7 +1944,7 @@ describe('The custom threshold alert type', () => {
{
'*': {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0],
metrics: [
{
@ -1967,7 +1967,7 @@ describe('The custom threshold alert type', () => {
{
'*': {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0],
metrics: [
{
@ -1990,7 +1990,7 @@ describe('The custom threshold alert type', () => {
{
a: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0],
currentValue: 1,
timestamp: new Date().toISOString(),
@ -2000,7 +2000,7 @@ describe('The custom threshold alert type', () => {
},
b: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0],
currentValue: 3,
timestamp: new Date().toISOString(),
@ -2022,7 +2022,7 @@ describe('The custom threshold alert type', () => {
{
a: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0],
metrics: [
{
@ -2039,7 +2039,7 @@ describe('The custom threshold alert type', () => {
},
b: {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0],
metrics: [
{
@ -2116,7 +2116,7 @@ declare global {
}
const customThresholdNonCountCriterion: CustomMetricExpressionParams = {
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
metrics: [
{
aggType: Aggregators.AVERAGE,
@ -2131,7 +2131,7 @@ const customThresholdNonCountCriterion: CustomMetricExpressionParams = {
const mockedCountFilter = 'mockedCountFilter';
const customThresholdCountCriterion: CustomMetricExpressionParams = {
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
metrics: [
{
aggType: Aggregators.COUNT,

View file

@ -33,11 +33,7 @@ import {
CustomThresholdActionGroup,
CustomThresholdAlert,
} from './types';
import {
buildFiredAlertReason,
buildNoDataAlertReason,
// buildRecoveredAlertReason,
} from './messages';
import { buildFiredAlertReason, buildNoDataAlertReason } from './messages';
import {
createScopedLogger,
hasAdditionalContext,
@ -91,6 +87,7 @@ export const createCustomThresholdExecutor = ({
} = options;
const { criteria } = params;
if (criteria.length === 0) throw new Error('Cannot execute an alert with 0 conditions');
const thresholdLogger = createScopedLogger(logger, 'thresholdRule', {
alertId: ruleId,

View file

@ -5,6 +5,7 @@
* 2.0.
*/
import { convertToBuiltInComparators } from '../../../../../common';
import { CustomMetricExpressionParams } from '../../../../../common/custom_threshold_rule/types';
import { createConditionScript } from './create_condition_script';
import { createLastPeriod } from './wrap_in_period';
@ -24,7 +25,10 @@ export const createBucketSelector = (
buckets_path: {
value: bucketPath,
},
script: createConditionScript(condition.threshold, condition.comparator),
script: createConditionScript(
condition.threshold,
convertToBuiltInComparators(condition.comparator)
),
},
};

View file

@ -5,10 +5,10 @@
* 2.0.
*/
import { Comparator } from '../../../../../common/custom_threshold_rule/types';
import { COMPARATORS } from '@kbn/alerting-comparators';
export const createConditionScript = (threshold: number[], comparator: Comparator) => {
if (comparator === Comparator.BETWEEN && threshold.length === 2) {
export const createConditionScript = (threshold: number[], comparator: COMPARATORS) => {
if (comparator === COMPARATORS.BETWEEN && threshold.length === 2) {
return {
source: `params.value > params.threshold0 && params.value < params.threshold1 ? 1 : 0`,
params: {
@ -17,9 +17,9 @@ export const createConditionScript = (threshold: number[], comparator: Comparato
},
};
}
if (comparator === Comparator.OUTSIDE_RANGE && threshold.length === 2) {
if (comparator === COMPARATORS.NOT_BETWEEN && threshold.length === 2) {
return {
// OUTSIDE_RANGE/NOT BETWEEN is the opposite of BETWEEN. Use the BETWEEN condition and switch the 1 and 0
// NOT BETWEEN is the opposite of BETWEEN. Use the BETWEEN condition and switch the 1 and 0
source: `params.value > params.threshold0 && params.value < params.threshold1 ? 0 : 1`,
params: {
threshold0: threshold[0],

View file

@ -194,7 +194,6 @@ export const getData = async (
const fieldsExisted = groupBy?.includes(KUBERNETES_POD_UID)
? await doFieldsExist(esClient, [CONTAINER_ID], index)
: null;
const request = {
index,
allow_no_indices: true,

View file

@ -7,12 +7,12 @@
import moment from 'moment';
import {
Comparator,
Aggregators,
CustomMetricExpressionParams,
SearchConfigurationType,
} from '../../../../../common/custom_threshold_rule/types';
import { getElasticsearchMetricQuery } from './metric_query';
import { COMPARATORS } from '@kbn/alerting-comparators';
describe("The Metric Threshold Alert's getElasticsearchMetricQuery", () => {
const expressionParams: CustomMetricExpressionParams = {
@ -26,7 +26,7 @@ describe("The Metric Threshold Alert's getElasticsearchMetricQuery", () => {
timeUnit: 'm',
timeSize: 1,
threshold: [1],
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
};
const searchConfiguration: SearchConfigurationType = {
index: {

View file

@ -6,58 +6,58 @@
*/
import { i18n } from '@kbn/i18n';
import { Comparator } from '../../../../common/custom_threshold_rule/types';
import { formatDurationFromTimeUnitChar } from '../../../../common';
import { Evaluation } from './lib/evaluate_rule';
import { formatAlertResult, FormattedEvaluation } from './lib/format_alert_result';
import { COMPARATORS } from '@kbn/alerting-comparators';
import {
BELOW_TEXT,
ABOVE_TEXT,
ABOVE_OR_EQ_TEXT,
BELOW_TEXT,
BELOW_OR_EQ_TEXT,
BETWEEN_TEXT,
NOT_BETWEEN_TEXT,
CUSTOM_EQUATION_I18N,
ABOVE_OR_EQ_TEXT,
BELOW_OR_EQ_TEXT,
} from './translations';
} from '../../../../common/i18n';
import { convertToBuiltInComparators, formatDurationFromTimeUnitChar } from '../../../../common';
import { Evaluation } from './lib/evaluate_rule';
import { formatAlertResult, FormattedEvaluation } from './lib/format_alert_result';
import { CUSTOM_EQUATION_I18N } from './translations';
import { UNGROUPED_FACTORY_KEY } from './constants';
const toNumber = (value: number | string) =>
typeof value === 'string' ? parseFloat(value) : value;
const recoveredComparatorToI18n = (
comparator: Comparator,
comparator: COMPARATORS,
threshold: number[],
currentValue: number
) => {
switch (comparator) {
case Comparator.BETWEEN:
case COMPARATORS.BETWEEN:
return currentValue < threshold[0] ? BELOW_TEXT : ABOVE_TEXT;
case Comparator.OUTSIDE_RANGE:
case COMPARATORS.NOT_BETWEEN:
return BETWEEN_TEXT;
case Comparator.GT:
case COMPARATORS.GREATER_THAN:
return ABOVE_TEXT;
case Comparator.GT_OR_EQ:
case COMPARATORS.GREATER_THAN_OR_EQUALS:
return ABOVE_OR_EQ_TEXT;
case Comparator.LT:
case COMPARATORS.LESS_THAN:
return BELOW_TEXT;
case Comparator.LT_OR_EQ:
case COMPARATORS.LESS_THAN_OR_EQUALS:
return BELOW_OR_EQ_TEXT;
}
};
const alertComparatorToI18n = (comparator: Comparator) => {
const alertComparatorToI18n = (comparator: COMPARATORS) => {
switch (comparator) {
case Comparator.BETWEEN:
case COMPARATORS.BETWEEN:
return BETWEEN_TEXT;
case Comparator.OUTSIDE_RANGE:
case COMPARATORS.NOT_BETWEEN:
return NOT_BETWEEN_TEXT;
case Comparator.GT:
case COMPARATORS.GREATER_THAN:
return ABOVE_TEXT;
case Comparator.GT_OR_EQ:
case COMPARATORS.GREATER_THAN_OR_EQUALS:
return ABOVE_OR_EQ_TEXT;
case Comparator.LT:
case COMPARATORS.LESS_THAN:
return BELOW_TEXT;
case Comparator.LT_OR_EQ:
case COMPARATORS.LESS_THAN_OR_EQUALS:
return BELOW_OR_EQ_TEXT;
}
};
@ -124,7 +124,7 @@ const buildAggregationReason: (evaluation: FormattedEvaluation) => string = ({
defaultMessage: '{label} is {currentValue}, {comparator} the threshold of {threshold}',
values: {
label,
comparator: alertComparatorToI18n(comparator),
comparator: alertComparatorToI18n(convertToBuiltInComparators(comparator)),
threshold: thresholdToI18n(threshold),
currentValue,
},
@ -134,7 +134,7 @@ const buildAggregationReason: (evaluation: FormattedEvaluation) => string = ({
export const buildRecoveredAlertReason: (alertResult: {
group: string;
label?: string;
comparator: Comparator;
comparator: COMPARATORS;
threshold: Array<number | string>;
currentValue: number | string;
}) => string = ({ group, label = CUSTOM_EQUATION_I18N, comparator, threshold, currentValue }) =>

View file

@ -5,15 +5,15 @@
* 2.0.
*/
import { COMPARATORS } from '@kbn/alerting-comparators';
import {
Aggregators,
Comparator,
CustomMetricExpressionParams,
} from '../../../../../common/custom_threshold_rule/types';
import { Evaluation } from '../lib/evaluate_rule';
const customThresholdNonCountCriterion: CustomMetricExpressionParams = {
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
metrics: [
{
aggType: Aggregators.AVERAGE,
@ -30,7 +30,7 @@ export const alertResultsMultipleConditions: Array<Record<string, Evaluation>> =
{
'*': {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.75],
currentValue: 1.0,
timestamp: new Date().toISOString(),
@ -42,7 +42,7 @@ export const alertResultsMultipleConditions: Array<Record<string, Evaluation>> =
{
'*': {
...customThresholdNonCountCriterion,
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.75],
currentValue: 3.0,
timestamp: new Date().toISOString(),

View file

@ -5,9 +5,9 @@
* 2.0.
*/
import { COMPARATORS } from '@kbn/alerting-comparators';
import {
Aggregators,
Comparator,
CustomMetricExpressionParams,
} from '../../../../../common/custom_threshold_rule/types';
@ -28,7 +28,7 @@ export const criteriaMultipleConditions: CustomMetricExpressionParams[] = [
timeUnit: 'm',
timeSize: 1,
threshold: [1],
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
},
{
metrics: [
@ -46,7 +46,7 @@ export const criteriaMultipleConditions: CustomMetricExpressionParams[] = [
timeUnit: 'm',
timeSize: 1,
threshold: [4],
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
},
];
@ -67,7 +67,7 @@ export const criteriaMultipleConditionsWithIsBetween: CustomMetricExpressionPara
timeUnit: 'm',
timeSize: 1,
threshold: [1, 2],
comparator: Comparator.BETWEEN,
comparator: COMPARATORS.BETWEEN,
},
{
metrics: [
@ -85,6 +85,6 @@ export const criteriaMultipleConditionsWithIsBetween: CustomMetricExpressionPara
timeUnit: 'm',
timeSize: 1,
threshold: [4],
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
},
];

View file

@ -15,9 +15,11 @@ import { IBasePath, Logger } from '@kbn/core/server';
import { legacyExperimentalFieldMap } from '@kbn/alerts-as-data-utils';
import { OBSERVABILITY_THRESHOLD_RULE_TYPE_ID } from '@kbn/rule-data-utils';
import { LicenseType } from '@kbn/licensing-plugin/server';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { EsQueryRuleParamsExtractedParams } from '@kbn/stack-alerts-plugin/server/rule_types/es_query/rule_type_params';
import { LEGACY_COMPARATORS } from '../../../../common/utils/convert_legacy_outside_comparator';
import { observabilityFeatureId, observabilityPaths } from '../../../../common';
import { Aggregators, Comparator } from '../../../../common/custom_threshold_rule/types';
import { Aggregators } from '../../../../common/custom_threshold_rule/types';
import { THRESHOLD_RULE_REGISTRATION_CONTEXT } from '../../../common/constants';
import {
@ -75,9 +77,10 @@ export function thresholdRuleType(
logger: Logger,
locators: CustomThresholdLocators
) {
const comparators = Object.values({ ...COMPARATORS, ...LEGACY_COMPARATORS });
const baseCriterion = {
threshold: schema.arrayOf(schema.number()),
comparator: oneOfLiterals(Object.values(Comparator)),
comparator: oneOfLiterals(comparators),
timeUnit: schema.string(),
timeSize: schema.number(),
};

View file

@ -85,50 +85,6 @@ export const CUSTOM_EQUATION_I18N = i18n.translate(
}
);
// Comparators
export const BELOW_TEXT = i18n.translate(
'xpack.observability.customThreshold.rule.threshold.below',
{
defaultMessage: 'below',
}
);
export const BELOW_OR_EQ_TEXT = i18n.translate(
'xpack.observability.customThreshold.rule.threshold.belowOrEqual',
{
defaultMessage: 'below or equal',
}
);
export const ABOVE_TEXT = i18n.translate(
'xpack.observability.customThreshold.rule.threshold.above',
{
defaultMessage: 'above',
}
);
export const ABOVE_OR_EQ_TEXT = i18n.translate(
'xpack.observability.customThreshold.rule.threshold.aboveOrEqual',
{
defaultMessage: 'above or equal',
}
);
export const BETWEEN_TEXT = i18n.translate(
'xpack.observability.customThreshold.rule.threshold.between',
{
defaultMessage: 'between',
}
);
export const NOT_BETWEEN_TEXT = i18n.translate(
'xpack.observability.customThreshold.rule.threshold.notBetween',
{
defaultMessage: 'not between',
}
);
// Action variable descriptions
export const groupByKeysActionVariableDescription = i18n.translate(

View file

@ -98,6 +98,7 @@
"@kbn/data-view-field-editor-plugin",
"@kbn/cases-components",
"@kbn/aiops-log-rate-analysis",
"@kbn/alerting-comparators",
"@kbn/react-kibana-context-render",
"@kbn/react-kibana-mount",
],

View file

@ -5,14 +5,7 @@
* 2.0.
*/
export enum Comparator {
GT = '>',
LT = '<',
GT_OR_EQ = '>=',
LT_OR_EQ = '<=',
BETWEEN = 'between',
OUTSIDE_RANGE = 'outside',
}
import { COMPARATORS } from '@kbn/alerting-comparators';
export enum Aggregators {
COUNT = 'count',
@ -49,7 +42,7 @@ export const customThresholdAIAssistantLogCount = {
params: {
criteria: [
{
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [10],
timeSize: 2,
timeUnit: 'h',
@ -82,7 +75,7 @@ export const customThresholdAIAssistantMetricAvg = {
params: {
criteria: [
{
comparator: Comparator.GT,
comparator: COMPARATORS.GREATER_THAN,
threshold: [0.5],
timeSize: 2,
timeUnit: 'h',

View file

@ -68,7 +68,8 @@
"@kbn/serverless",
"@kbn/task-manager-plugin",
"@kbn/cloud-plugin",
"@kbn/observability-plugin"
"@kbn/observability-plugin",
"@kbn/alerting-comparators"
],
"exclude": ["target/**/*"]
}

View file

@ -31,11 +31,11 @@
"@kbn/logging",
"@kbn/securitysolution-io-ts-utils",
"@kbn/share-plugin",
"@kbn/alerting-state-types",
"@kbn/alerts-as-data-utils",
"@kbn/core-http-router-server-mocks",
"@kbn/core-http-server",
"@kbn/search-types",
"@kbn/alerting-state-types"
],
"exclude": [
"target/**/*",

View file

@ -5,8 +5,7 @@
* 2.0.
*/
import { COMPARATORS } from '@kbn/triggers-actions-ui-plugin/public';
import { COMPARATORS } from '@kbn/alerting-comparators';
export const DEFAULT_VALUES = {
THRESHOLD_COMPARATOR: COMPARATORS.GREATER_THAN,
QUERY: `{

View file

@ -12,8 +12,8 @@ import {
builtInComparators,
builtInAggregationTypes,
builtInGroupByTypes,
COMPARATORS,
} from '@kbn/triggers-actions-ui-plugin/public';
import { COMPARATORS } from '@kbn/alerting-comparators';
import {
MAX_SELECTABLE_SOURCE_FIELDS,
MAX_SELECTABLE_GROUP_BY_TERMS,

View file

@ -20,7 +20,6 @@ import { HttpSetup } from '@kbn/core/public';
import { useKibana } from '@kbn/kibana-react-plugin/public';
import {
getFields,
COMPARATORS,
builtInComparators,
OfExpression,
ThresholdExpression,
@ -30,6 +29,7 @@ import {
builtInAggregationTypes,
RuleTypeParamsExpressionProps,
} from '@kbn/triggers-actions-ui-plugin/public';
import { COMPARATORS } from '@kbn/alerting-comparators';
import { ThresholdVisualization } from './visualization';
import { IndexThresholdRuleParams } from './types';
import './expression.scss';

View file

@ -33,7 +33,8 @@ import { FormattedMessage } from '@kbn/i18n-react';
import { ChartsPluginSetup } from '@kbn/charts-plugin/public';
import { FieldFormatsStart } from '@kbn/field-formats-plugin/public';
import { useKibana } from '@kbn/kibana-react-plugin/public';
import { AggregationType, Comparator } from '@kbn/triggers-actions-ui-plugin/public';
import { AggregationType } from '@kbn/triggers-actions-ui-plugin/public';
import type { Comparator } from '@kbn/alerting-comparators';
import { parseDuration } from '@kbn/alerting-plugin/common/parse_duration';
import { i18n } from '@kbn/i18n';
import {

View file

@ -51,6 +51,7 @@
"@kbn/esql-utils",
"@kbn/data-view-utils",
"@kbn/search-types",
"@kbn/alerting-comparators"
],
"exclude": [
"target/**/*",

View file

@ -10,7 +10,6 @@
"common/**/*"
],
"kbn_references": [
"@kbn/alerting-state-types",
"@kbn/core",
"@kbn/usage-collection-plugin",
"@kbn/config-schema",
@ -22,7 +21,8 @@
"@kbn/core-saved-objects-common",
"@kbn/core-saved-objects-utils-server",
"@kbn/core-test-helpers-kbn-server",
"@kbn/core-saved-objects-server"
"@kbn/core-saved-objects-server",
"@kbn/alerting-state-types"
],
"exclude": [
"target/**/*",

Some files were not shown because too many files have changed in this diff Show more