Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@
"fieldsMetadata",
"esql",
"savedObjectsTagging",
"streams"
"streams",
"kql"
],
"optionalPlugins": [
"observabilityAgentBuilder",
Expand All @@ -66,7 +67,6 @@
"logsShared",
"kibanaReact",
"kibanaUtils",
"kql",
"stackAlerts",
"spaces",
"observabilityAgentBuilder"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ dependsOn:
- '@kbn/management-settings-ids'
- '@kbn/observability-agent-builder-plugin'
- '@kbn/kql'
- '@kbn/shared-ux-utility'
tags:
- plugin
- prod
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import type { IErrorObject } from '@kbn/triggers-actions-ui-plugin/public';
import { FormattedMessage } from '@kbn/i18n-react';
import type { DataViewBase } from '@kbn/es-query';
import { i18n } from '@kbn/i18n';
import type { KqlPluginStart } from '@kbn/kql/public';
import { convertToApiThreshold } from '../../helpers/threshold_unit';
import type { CustomThresholdExpressionMetric } from '../../../../../common/custom_threshold_rule/types';
import { Aggregators } from '../../../../../common/custom_threshold_rule/types';
Expand All @@ -39,6 +40,7 @@ export interface CustomEquationEditorProps {
aggregationTypes: AggregationTypes;
errors: IErrorObject;
dataView: DataViewBase;
kql: KqlPluginStart;
}

const NEW_METRIC = {
Expand All @@ -57,6 +59,7 @@ export function CustomEquationEditor({
aggregationTypes,
errors,
dataView,
kql,
}: CustomEquationEditorProps) {
const [customMetrics, setCustomMetrics] = useState<CustomMetrics>(
expression?.metrics ?? [NEW_METRIC]
Expand Down Expand Up @@ -145,6 +148,7 @@ export function CustomEquationEditor({
onChange={handleChange}
errors={errors}
dataView={dataView}
kql={kql}
/>
));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import type { ValidNormalizedTypes } from '@kbn/triggers-actions-ui-plugin/publi
import { get } from 'lodash';
import React, { useCallback, useMemo, useState } from 'react';
import { ES_FIELD_TYPES } from '@kbn/field-types';
import type { KqlPluginStart } from '@kbn/kql/public';
import { Aggregators } from '../../../../../common/custom_threshold_rule/types';
import { RuleFlyoutKueryBar } from '../../../rule_kql_filter/kuery_bar';
import { ClosablePopoverTitle } from '../closable_popover_title';
Expand All @@ -34,6 +35,7 @@ interface MetricRowWithAggProps extends MetricRowBaseProps {
dataView: DataViewBase;
filter?: string;
fields: NormalizedFields;
kql: KqlPluginStart;
}

const DEFAULT_COUNT_FILTER_TITLE = i18n.translate(
Expand All @@ -53,6 +55,7 @@ export function MetricRowWithAgg({
aggregationTypes,
onChange,
errors,
kql,
}: MetricRowWithAggProps) {
const handleDelete = useCallback(() => {
onDelete(name);
Expand Down Expand Up @@ -212,6 +215,7 @@ export function MetricRowWithAgg({
onChange={handleFilterChange}
onSubmit={handleFilterChange}
value={filter}
kql={kql}
/>
</EuiFormRow>
) : (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { Aggregators } from '../../../../common/custom_threshold_rule/types';
import type { MetricExpression } from '../types';
import { ExpressionRow } from './expression_row';
import { COMPARATORS } from '@kbn/alerting-comparators';
import type { KqlPluginStart } from '@kbn/kql/public';

describe('ExpressionRow', () => {
async function setup(expression: MetricExpression) {
Expand All @@ -32,6 +33,7 @@ describe('ExpressionRow', () => {
]}
remove={() => {}}
addExpression={() => {}}
kql={{} as KqlPluginStart}
key={1}
expressionId={1}
setRuleParams={() => {}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { ThresholdExpression } from '@kbn/triggers-actions-ui-plugin/public';
import type { DataViewBase, DataViewFieldBase } from '@kbn/es-query';
import { debounce } from 'lodash';
import { COMPARATORS } from '@kbn/alerting-comparators';
import type { KqlPluginStart } from '@kbn/kql/public';
import { convertToBuiltInComparators } from '../../../../common/utils/convert_legacy_outside_comparator';
import { Aggregators } from '../../../../common/custom_threshold_rule/types';
import type { MetricExpression } from '../types';
Expand All @@ -42,6 +43,7 @@ interface ExpressionRowProps {
setRuleParams(id: number, params: MetricExpression): void;
dataView: DataViewBase;
children?: React.ReactNode;
kql: KqlPluginStart;
}

// eslint-disable-next-line react/function-component-definition
Expand All @@ -57,6 +59,7 @@ export const ExpressionRow: React.FC<ExpressionRowProps> = (props) => {
fields,
canDelete,
title,
kql,
} = props;

const { metrics, comparator = COMPARATORS.GREATER_THAN, threshold = [] } = expression;
Expand Down Expand Up @@ -157,6 +160,7 @@ export const ExpressionRow: React.FC<ExpressionRowProps> = (props) => {
onChange={handleCustomMetricChange}
errors={errors}
dataView={dataView}
kql={kql}
/>
{criticalThresholdExpression}
<EuiSpacer size={'s'} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { useKibana } from '../../utils/kibana_react';
import { kibanaStartMock } from '../../utils/kibana_react.mock';
import Expressions from './custom_threshold_rule_expression';
import type { AlertParams, CustomThresholdPrefillOptions } from './types';
import type { KqlPluginStart } from '@kbn/kql/public';

jest.mock('../../utils/kibana_react');
jest.mock('../rule_condition_chart/rule_condition_chart', () => ({
Expand Down Expand Up @@ -75,6 +76,7 @@ describe('Expression', () => {
metadata={metadata}
dataViews={dataViewMock}
onChangeMetaData={jest.fn()}
kql={{} as KqlPluginStart}
/>
</QueryClientProvider>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import type { SearchBarProps } from '@kbn/unified-search-plugin/public';

import { COMPARATORS } from '@kbn/alerting-comparators';
import type { DataPublicPluginStart } from '@kbn/data-plugin/public';
import type { KqlPluginStart } from '@kbn/kql/public';
import { useKibana } from '../../utils/kibana_react';
import {
Aggregators,
Expand All @@ -58,10 +59,10 @@ const HIDDEN_FILTER_PANEL_OPTIONS: SearchBarProps['hiddenFilterPanelOptions'] =
'disableFilter',
];

type Props = Omit<
export type CustomThresholdRuleExpressionProps = Omit<
RuleTypeParamsExpressionProps<RuleTypeParams & AlertParams, AlertContextMeta>,
'defaultActionGroupId' | 'actionGroups' | 'charts' | 'data' | 'unifiedSearch'
>;
> & { kql: KqlPluginStart };

export const defaultExpression: MetricExpression = {
comparator: COMPARATORS.GREATER_THAN,
Expand Down Expand Up @@ -102,8 +103,8 @@ const RECOMMENDED_TIMESIZE_WARNING = i18n.translate(
);

// eslint-disable-next-line import/no-default-export
export default function Expressions(props: Props) {
const { setRuleParams, ruleParams, errors, metadata, onChangeMetaData } = props;
export default function Expressions(props: CustomThresholdRuleExpressionProps) {
const { setRuleParams, ruleParams, errors, metadata, onChangeMetaData, kql } = props;
const {
data,
dataViews,
Expand Down Expand Up @@ -633,6 +634,7 @@ export default function Expressions(props: Props) {
errors={(errors[idx] as IErrorObject) || emptyError}
expression={e || {}}
dataView={derivedIndexPattern}
kql={kql}
title={
ruleParams.criteria.length === 1 ? (
<FormattedMessage
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* 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 { dynamic } from '@kbn/shared-ux-utility';
import React from 'react';
import type { CoreStart } from '@kbn/core/public';
import type { ObservabilityPublicPluginsStart } from '../../plugin';
import type { CustomThresholdRuleExpressionProps } from './custom_threshold_rule_expression';

export type GetStartServices = () => Promise<[CoreStart, ObservabilityPublicPluginsStart, unknown]>;

export const createCustomThresholdRuleExpression = (getStartServices: GetStartServices) => {
// Use dynamic() to lazily load the component, allowing us to asynchronously
// fetch the KQL service from start dependencies before rendering.
// This is needed because rule types are registered during the setup phase,
// but KqlPluginStart is only available during the start phase.
return dynamic(async () => {
const kql = await getStartServices().then(([, pluginsStart]) => pluginsStart.kql);
const { default: Expressions } = await import('./custom_threshold_rule_expression');
return {
default: (props: Omit<CustomThresholdRuleExpressionProps, 'kql'>) => (
<Expressions {...props} kql={kql} />
),
};
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import { fromKueryExpression } from '@kbn/es-query';
import React, { useEffect, useState } from 'react';
import type { DataViewBase } from '@kbn/es-query';
import type { QuerySuggestion } from '@kbn/kql/public';
import type { KqlPluginStart, QuerySuggestion } from '@kbn/kql/public';

import { useEuiTheme } from '@elastic/eui';
import { WithKueryAutocompletion } from './with_kuery_autocompletion';
Expand All @@ -30,6 +30,7 @@ export interface RuleFlyoutKueryBarProps {
placeholder?: string;
curryLoadSuggestions?: CurryLoadSuggestionsType;
compressed?: boolean;
kql: KqlPluginStart;
}

function validateQuery(query: string) {
Expand All @@ -49,6 +50,7 @@ export function RuleFlyoutKueryBar({
placeholder,
curryLoadSuggestions = defaultCurryLoadSuggestions,
compressed,
kql,
}: RuleFlyoutKueryBarProps) {
const [draftQuery, setDraftQuery] = useState<string>(value || '');
const [isValid, setValidation] = useState<boolean>(true);
Expand Down Expand Up @@ -76,7 +78,7 @@ export function RuleFlyoutKueryBar({
};

return (
<WithKueryAutocompletion indexPattern={filteredDerivedIndexPattern}>
<WithKueryAutocompletion indexPattern={filteredDerivedIndexPattern} kql={kql}>
{({ isLoadingSuggestions, loadSuggestions, suggestions }) => (
<AutocompleteField
compressed={compressed}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,18 @@

import React from 'react';
import type { DataViewBase } from '@kbn/es-query';
import type { KibanaReactContextValue, KibanaServices } from '@kbn/kibana-react-plugin/public';
import { withKibana } from '@kbn/kibana-react-plugin/public';
import type { DataView } from '@kbn/data-views-plugin/public';
import type { QuerySuggestion } from '@kbn/kql/public';
import type { InfraClientStartDeps, RendererFunction } from '../custom_threshold/types';
import type { KqlPluginStart, QuerySuggestion } from '@kbn/kql/public';
import type { RendererFunction } from '../custom_threshold/types';

export interface WithKueryAutocompletionLifecycleProps {
kibana: KibanaReactContextValue<InfraClientStartDeps & KibanaServices>;
children: RendererFunction<{
isLoadingSuggestions: boolean;
loadSuggestions: (expression: string, cursorPosition: number, maxSuggestions?: number) => void;
suggestions: QuerySuggestion[];
}>;
indexPattern: DataViewBase;
kql: KqlPluginStart;
}

interface WithKueryAutocompletionLifecycleState {
Expand Down Expand Up @@ -58,10 +56,9 @@ class WithKueryAutocompletionComponent extends React.Component<
maxSuggestions?: number,
transformSuggestions?: (s: QuerySuggestion[]) => QuerySuggestion[]
) => {
const { indexPattern } = this.props;
const { indexPattern, kql } = this.props;
const language = 'kuery';
const hasQuerySuggestions =
this.props.kibana.services.kql.autocomplete.hasQuerySuggestions(language);
const hasQuerySuggestions = kql.autocomplete.hasQuerySuggestions(language);

if (!hasQuerySuggestions) {
return;
Expand All @@ -76,7 +73,7 @@ class WithKueryAutocompletionComponent extends React.Component<
});

const suggestions =
(await this.props.kibana.services.kql.autocomplete.getQuerySuggestions({
(await kql.autocomplete.getQuerySuggestions({
language,
query: expression,
selectionStart: cursorPosition,
Expand Down Expand Up @@ -105,9 +102,7 @@ class WithKueryAutocompletionComponent extends React.Component<
};
}

export const WithKueryAutocompletion = withKibana<WithKueryAutocompletionLifecycleProps>(
WithKueryAutocompletionComponent
);
export const WithKueryAutocompletion = WithKueryAutocompletionComponent;

// eslint-disable-next-line import/no-default-export
export default WithKueryAutocompletion;
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,7 @@ export class Plugin
registerObservabilityRuleTypes(
this.observabilityRuleTypeRegistry,
coreSetup.uiSettings,
coreSetup.getStartServices,
logsLocator
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import {
import type { LocatorPublic } from '@kbn/share-plugin/common';
import type { DiscoverAppLocatorParams } from '@kbn/discover-plugin/common';
import type { IUiSettingsClient } from '@kbn/core-ui-settings-browser';
import type { CoreStart } from '@kbn/core/public';
import type { ObservabilityPublicPluginsStart } from '../plugin';
import type {
CustomMetricExpressionParams,
CustomThresholdExpressionMetric,
Expand All @@ -30,6 +32,7 @@ import { getGroups } from '../../common/custom_threshold_rule/helpers/get_group'
import type { ObservabilityRuleTypeRegistry } from './create_observability_rule_type_registry';
import { validateCustomThreshold } from '../components/custom_threshold/components/validation';
import { getDescriptionFields } from './custom_threshold_description_fields';
import { createCustomThresholdRuleExpression } from '../components/custom_threshold/custom_threshold_rule_expression_factory';

const thresholdDefaultActionMessage = i18n.translate(
'xpack.observability.customThreshold.rule.alerting.threshold.defaultActionMessage',
Expand Down Expand Up @@ -62,6 +65,7 @@ const getDataViewId = (searchConfiguration?: SearchConfigurationWithExtractedRef
export const registerObservabilityRuleTypes = (
observabilityRuleTypeRegistry: ObservabilityRuleTypeRegistry,
uiSettings: IUiSettingsClient,
getStartServices: () => Promise<[CoreStart, ObservabilityPublicPluginsStart, unknown]>,
logsLocator?: LocatorPublic<DiscoverAppLocatorParams>
) => {
const validateCustomThresholdWithUiSettings = ({
Expand All @@ -84,9 +88,7 @@ export const registerObservabilityRuleTypes = (
documentationUrl(docLinks) {
return `${docLinks.links.observability.customThreshold}`;
},
ruleParamsExpression: lazy(
() => import('../components/custom_threshold/custom_threshold_rule_expression')
),
ruleParamsExpression: createCustomThresholdRuleExpression(getStartServices),
validate: validateCustomThresholdWithUiSettings,
defaultActionMessage: thresholdDefaultActionMessage,
defaultRecoveryMessage: thresholdDefaultRecoveryMessage,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,14 @@ export const CUSTOM_THRESHOLD_RULE_TEST_SUBJECTS = {
INDEX_PATTERN_INPUT: 'indexPattern-switcher--input',
EXPLORE_MATCHING_INDICES_BUTTON: 'explore-matching-indices-button',

// Metric Row / Custom Equation
AGGREGATION_NAME_A: 'aggregationNameA',
AGGREGATION_TYPE_SELECT: 'aggregationTypeSelect',

// KQL Filter
KQL_SEARCH_FIELD: 'o11ySearchField',
KQL_SUGGESTIONS_PANEL: 'o11ySuggestionsPanel',

// Rule Save
RULE_SAVE_BUTTON: 'rulePageFooterSaveButton',
CONFIRM_MODAL_BUTTON: 'confirmModalConfirmButton',
Expand Down
Loading
Loading