[ResponseOps][Alerting] Update the size of the input labels for the ES query and index threshold rule (#174137)

Resolves https://github.com/elastic/kibana/issues/173857

## Summary

Updates the size of the input labels for the ES query and index
threshold rules.
It is helpful to hide whitespace when reviewing the code changes.

**KQL**
<img width="618" alt="Screen Shot 2024-01-03 at 10 03 36 AM"
src="0079f54e-d367-43cd-94e4-1004c8351d0a">

**Query DSL**
<img width="615" alt="Screen Shot 2024-01-03 at 10 04 06 AM"
src="60ac7148-7e4e-4be5-bc82-de99e91a5d9e">

**ES|QL**
<img width="616" alt="Screen Shot 2024-01-03 at 10 04 35 AM"
src="bddd3c2b-42eb-43ec-b4f4-76df0138834d">

**Index Threshold**
<img width="617" alt="Screen Shot 2024-01-03 at 10 02 29 AM"
src="afc20b9d-73c6-4f74-bb9d-a980f488cecd">
This commit is contained in:
Alexi Doak 2024-01-04 07:03:52 -08:00 committed by GitHub
parent effd9e7a19
commit e4cac3725f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 198 additions and 224 deletions

View file

@ -7,7 +7,7 @@
import React, { useEffect, useState } from 'react';
import { uniqBy } from 'lodash';
import { EuiComboBox, EuiFormRow, EuiSpacer, EuiTitle } from '@elastic/eui';
import { EuiComboBox, EuiFormRow } from '@elastic/eui';
import { FieldOption } from '@kbn/triggers-actions-ui-plugin/public/common';
import { IErrorObject } from '@kbn/triggers-actions-ui-plugin/public';
import { FormattedMessage } from '@kbn/i18n-react';
@ -77,44 +77,39 @@ export const SourceFields: React.FC<SourceFieldsProps> = ({
fullWidth
isInvalid={errors.length > 0 && sourceFields !== undefined}
error={errors}
>
<>
<EuiTitle size="xs">
<h5>
<FormattedMessage
id="xpack.stackAlerts.components.ui.sourceFieldsSelect.title"
defaultMessage="Add more fields to alert details"
/>
</h5>
</EuiTitle>
<EuiSpacer size="s" />
<EuiComboBox
fullWidth
placeholder={i18n.translate(
'xpack.stackAlerts.components.ui.sourceFieldsSelect.placeholder',
{
defaultMessage: 'Select fields',
}
)}
data-test-subj="sourceFields"
isInvalid={errors.length > 0 && sourceFields !== undefined}
selectedOptions={(sourceFields || []).map((f) => ({
label: f.label,
value: f.searchPath,
'data-test-subj': `option-${f.label}`,
}))}
onChange={(options) => {
const fields: SourceField[] = [];
options.forEach((f) => {
if (f.value) {
fields.push({ label: f.label, searchPath: f.value });
}
});
onChangeSourceFields(fields);
}}
options={sourceFieldsOptions}
label={
<FormattedMessage
id="xpack.stackAlerts.components.ui.sourceFieldsSelect.title"
defaultMessage="Add more fields to alert details"
/>
</>
}
>
<EuiComboBox
fullWidth
placeholder={i18n.translate(
'xpack.stackAlerts.components.ui.sourceFieldsSelect.placeholder',
{
defaultMessage: 'Select fields',
}
)}
data-test-subj="sourceFields"
isInvalid={errors.length > 0 && sourceFields !== undefined}
selectedOptions={(sourceFields || []).map((f) => ({
label: f.label,
value: f.searchPath,
'data-test-subj': `option-${f.label}`,
}))}
onChange={(options) => {
const fields: SourceField[] = [];
options.forEach((f) => {
if (f.value) {
fields.push({ label: f.label, searchPath: f.value });
}
});
onChangeSourceFields(fields);
}}
options={sourceFieldsOptions}
/>
</EuiFormRow>
) : null;
};

View file

@ -11,7 +11,7 @@ import { lastValueFrom } from 'rxjs';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import { EuiFormRow, EuiLink, EuiSpacer, EuiTitle } from '@elastic/eui';
import { EuiFormRow, EuiLink, EuiSpacer } from '@elastic/eui';
import { XJson } from '@kbn/es-ui-shared-plugin/public';
import { CodeEditor } from '@kbn/kibana-react-plugin/public';
@ -195,60 +195,49 @@ export const EsQueryExpression: React.FC<
return (
<Fragment>
<EuiTitle size="xs">
<h5>
<EuiFormRow
fullWidth
label={
<FormattedMessage
id="xpack.stackAlerts.esQuery.ui.selectIndexPrompt"
defaultMessage="Select indices"
/>
</h5>
</EuiTitle>
}
>
<IndexSelectPopover
index={index}
data-test-subj="indexSelectPopover"
esFields={esFields}
timeField={timeField}
errors={errors}
onIndexChange={async (indices: string[]) => {
setParam('index', indices);
<EuiSpacer size="s" />
<IndexSelectPopover
index={index}
data-test-subj="indexSelectPopover"
esFields={esFields}
timeField={timeField}
errors={errors}
onIndexChange={async (indices: string[]) => {
setParam('index', indices);
// reset expression fields if indices are deleted
if (indices.length === 0) {
setRuleProperty('params', {
timeField: ruleParams.timeField,
index: indices,
esQuery: DEFAULT_VALUES.QUERY,
size: DEFAULT_VALUES.SIZE,
thresholdComparator: DEFAULT_VALUES.THRESHOLD_COMPARATOR,
timeWindowSize: DEFAULT_VALUES.TIME_WINDOW_SIZE,
timeWindowUnit: DEFAULT_VALUES.TIME_WINDOW_UNIT,
threshold: DEFAULT_VALUES.THRESHOLD,
aggType: DEFAULT_VALUES.AGGREGATION_TYPE,
groupBy: DEFAULT_VALUES.GROUP_BY,
termSize: DEFAULT_VALUES.TERM_SIZE,
searchType: SearchType.esQuery,
excludeHitsFromPreviousRun: DEFAULT_VALUES.EXCLUDE_PREVIOUS_HITS,
sourceFields: undefined,
});
} else {
await refreshEsFields(indices);
}
}}
onTimeFieldChange={(updatedTimeField: string) => setParam('timeField', updatedTimeField)}
/>
<EuiSpacer size="s" />
<EuiTitle size="xs">
<h5>
<FormattedMessage
id="xpack.stackAlerts.esQuery.ui.defineQueryPrompt"
defaultMessage="Define your query using Query DSL"
/>
</h5>
</EuiTitle>
// reset expression fields if indices are deleted
if (indices.length === 0) {
setRuleProperty('params', {
timeField: ruleParams.timeField,
index: indices,
esQuery: DEFAULT_VALUES.QUERY,
size: DEFAULT_VALUES.SIZE,
thresholdComparator: DEFAULT_VALUES.THRESHOLD_COMPARATOR,
timeWindowSize: DEFAULT_VALUES.TIME_WINDOW_SIZE,
timeWindowUnit: DEFAULT_VALUES.TIME_WINDOW_UNIT,
threshold: DEFAULT_VALUES.THRESHOLD,
aggType: DEFAULT_VALUES.AGGREGATION_TYPE,
groupBy: DEFAULT_VALUES.GROUP_BY,
termSize: DEFAULT_VALUES.TERM_SIZE,
searchType: SearchType.esQuery,
excludeHitsFromPreviousRun: DEFAULT_VALUES.EXCLUDE_PREVIOUS_HITS,
sourceFields: undefined,
});
} else {
await refreshEsFields(indices);
}
}}
onTimeFieldChange={(updatedTimeField: string) => setParam('timeField', updatedTimeField)}
/>
</EuiFormRow>
<EuiSpacer size="s" />
<EuiFormRow
id="queryEditor"
@ -264,6 +253,12 @@ export const EsQueryExpression: React.FC<
/>
</EuiLink>
}
label={
<FormattedMessage
id="xpack.stackAlerts.esQuery.ui.defineQueryPrompt"
defaultMessage="Define your query using Query DSL"
/>
}
>
<CodeEditor
languageId="xjson"

View file

@ -15,7 +15,6 @@ import {
EuiFormRow,
EuiSelect,
EuiSpacer,
EuiTitle,
} from '@elastic/eui';
import { getFields, RuleTypeParamsExpressionProps } from '@kbn/triggers-actions-ui-plugin/public';
import { TextBasedLangEditor } from '@kbn/text-based-languages/public';
@ -180,16 +179,17 @@ export const EsqlQueryExpression: React.FC<
return (
<Fragment>
<EuiTitle size="xs">
<h5>
<EuiFormRow
id="queryEditor"
data-test-subj="queryEsqlEditor"
fullWidth
label={
<FormattedMessage
id="xpack.stackAlerts.esQuery.ui.defineEsqlQueryPrompt"
defaultMessage="Define your query using ES|QL"
/>
</h5>
</EuiTitle>
<EuiSpacer size="s" />
<EuiFormRow id="queryEditor" data-test-subj="queryEsqlEditor" fullWidth>
}
>
<TextBasedLangEditor
query={query}
onTextLangQueryChange={debounce((q: AggregateQuery) => {
@ -215,20 +215,17 @@ export const EsqlQueryExpression: React.FC<
errors={errors.sourceFields}
/>
<EuiSpacer />
<EuiTitle size="xs">
<h5>
<FormattedMessage
id="xpack.stackAlerts.esQuery.ui.selectEsqlQueryTimeFieldPrompt"
defaultMessage="Select a time field"
/>
</h5>
</EuiTitle>
<EuiSpacer size="s" />
<EuiFormRow
id="timeField"
fullWidth
isInvalid={errors.timeField.length > 0 && timeField !== undefined}
error={errors.timeField}
label={
<FormattedMessage
id="xpack.stackAlerts.esQuery.ui.selectEsqlQueryTimeFieldPrompt"
defaultMessage="Select a time field"
/>
}
>
<EuiSelect
options={timeFieldOptions}
@ -243,21 +240,18 @@ export const EsqlQueryExpression: React.FC<
/>
</EuiFormRow>
<EuiSpacer />
<EuiTitle size="xs">
<h5>
<FormattedMessage
id="xpack.stackAlerts.esQuery.ui.setEsqlQueryTimeWindowPrompt"
defaultMessage="Set the time window"
/>
</h5>
</EuiTitle>
<EuiSpacer size="s" />
<EuiFlexGroup>
<EuiFlexGroup alignItems="flexEnd">
<EuiFlexItem grow={false}>
<EuiFormRow
id="timeWindowSize"
isInvalid={errors.timeWindowSize.length > 0}
error={errors.timeWindowSize}
label={
<FormattedMessage
id="xpack.stackAlerts.esQuery.ui.setEsqlQueryTimeWindowPrompt"
defaultMessage="Set the time window"
/>
}
>
<EuiFieldNumber
name="timeWindowSize"

View file

@ -10,7 +10,7 @@ import deepEqual from 'fast-deep-equal';
import { lastValueFrom } from 'rxjs';
import type { Filter, Query } from '@kbn/es-query';
import { FormattedMessage } from '@kbn/i18n-react';
import { EuiSpacer, EuiTitle } from '@elastic/eui';
import { EuiFormRow, EuiSpacer, EuiTitle } from '@elastic/eui';
import { IErrorObject } from '@kbn/triggers-actions-ui-plugin/public';
import type { SearchBarProps } from '@kbn/unified-search-plugin/public';
import type { DataView } from '@kbn/data-views-plugin/public';
@ -300,22 +300,23 @@ export const SearchSourceExpressionForm = (props: SearchSourceExpressionFormProp
return (
<Fragment>
<EuiTitle size="xs">
<h5>
<EuiFormRow
fullWidth
label={
<FormattedMessage
id="xpack.stackAlerts.esQuery.ui.selectDataViewPrompt"
defaultMessage="Select a data view"
/>
</h5>
</EuiTitle>
<EuiSpacer size="s" />
<DataViewSelectPopover
dependencies={{ dataViews, dataViewEditor }}
dataView={dataView}
metadata={props.metadata}
onSelectDataView={onSelectDataView}
onChangeMetaData={props.onChangeMetaData}
/>
}
>
<DataViewSelectPopover
dependencies={{ dataViews, dataViewEditor }}
dataView={dataView}
metadata={props.metadata}
onSelectDataView={onSelectDataView}
onChangeMetaData={props.onChangeMetaData}
/>
</EuiFormRow>
{Boolean(dataView?.id) && (
<>
<EuiSpacer size="s" />

View file

@ -7,15 +7,7 @@
import React, { useEffect, useState } from 'react';
import { FormattedMessage } from '@kbn/i18n-react';
import {
EuiCheckbox,
EuiFlexGroup,
EuiFlexItem,
EuiFormRow,
EuiIconTip,
EuiSpacer,
EuiTitle,
} from '@elastic/eui';
import { EuiCheckbox, EuiFormRow, EuiIconTip, EuiSpacer } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import {
builtInAggregationTypes,
@ -98,22 +90,23 @@ export const RuleCommonExpressions: React.FC<RuleCommonExpressionsProps> = ({
}, [groupBy]);
return (
<>
<EuiTitle size="xs">
<h4>
<EuiFormRow
fullWidth
label={[
<FormattedMessage
id="xpack.stackAlerts.esQuery.ui.conditionsPrompt"
defaultMessage="Set the group, threshold, and time window"
/>{' '}
<QueryThresholdHelpPopover />
</h4>
</EuiTitle>
<EuiSpacer size="s" />
<WhenExpression
display="fullWidth"
data-test-subj="whenExpression"
aggType={aggType ?? DEFAULT_VALUES.AGGREGATION_TYPE}
onChangeSelectedAggType={onChangeSelectedAggType}
/>
/>,
<QueryThresholdHelpPopover />,
]}
>
<WhenExpression
display="fullWidth"
data-test-subj="whenExpression"
aggType={aggType ?? DEFAULT_VALUES.AGGREGATION_TYPE}
onChangeSelectedAggType={onChangeSelectedAggType}
/>
</EuiFormRow>
{aggType && builtInAggregationTypes[aggType].fieldRequired ? (
<OfExpression
aggField={aggField}
@ -159,18 +152,13 @@ export const RuleCommonExpressions: React.FC<RuleCommonExpressionsProps> = ({
onChangeWindowUnit={onChangeWindowUnit}
/>
<EuiSpacer size="s" />
<EuiFlexGroup alignItems="center" responsive={false} gutterSize="xs">
<EuiFlexItem grow={false}>
<EuiTitle size="xs">
<h5>
<FormattedMessage
id="xpack.stackAlerts.esQuery.ui.selectSizePrompt"
defaultMessage="Set the number of documents to send"
/>
</h5>
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFormRow
fullWidth
label={[
<FormattedMessage
id="xpack.stackAlerts.esQuery.ui.selectSizePrompt"
defaultMessage="Set the number of documents to send"
/>,
<EuiIconTip
position="right"
color="subdued"
@ -179,21 +167,21 @@ export const RuleCommonExpressions: React.FC<RuleCommonExpressionsProps> = ({
defaultMessage:
'Specify the number of documents to pass to the configured actions when the threshold condition is met.',
})}
/>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size="s" />
<ValueExpression
description={i18n.translate('xpack.stackAlerts.esQuery.ui.sizeExpression', {
defaultMessage: 'Size',
})}
data-test-subj="sizeValueExpression"
value={size}
errors={errors.size}
display="fullWidth"
popupPosition="upLeft"
onChangeSelectedValue={onChangeSizeValue}
/>
/>,
]}
>
<ValueExpression
description={i18n.translate('xpack.stackAlerts.esQuery.ui.sizeExpression', {
defaultMessage: 'Size',
})}
data-test-subj="sizeValueExpression"
value={size}
errors={errors.size}
display="fullWidth"
popupPosition="upLeft"
onChangeSelectedValue={onChangeSizeValue}
/>
</EuiFormRow>
<EuiSpacer size="m" />
<EuiFormRow>
<EuiCheckbox

View file

@ -13,7 +13,6 @@ import {
EuiCallOut,
EuiEmptyPrompt,
EuiText,
EuiTitle,
EuiFieldSearch,
EuiFormRow,
} from '@elastic/eui';
@ -163,64 +162,66 @@ export const IndexThresholdRuleTypeExpression: React.FunctionComponent<
<EuiSpacer />
</Fragment>
) : null}
<EuiTitle size="xs">
<h5>
<EuiFormRow
fullWidth
label={
<FormattedMessage
id="xpack.stackAlerts.threshold.ui.selectIndex"
defaultMessage="Select indices"
/>
</h5>
</EuiTitle>
<EuiSpacer size="s" />
<IndexSelectPopover
index={indexArray}
data-test-subj="indexSelectPopover"
esFields={esFields}
timeField={timeField}
errors={errors}
onIndexChange={async (indices: string[]) => {
setRuleParams('index', indices);
// reset expression fields if indices are deleted
if (indices.length === 0) {
setRuleProperty('params', {
...ruleParams,
index: indices,
aggType: DEFAULT_VALUES.AGGREGATION_TYPE,
termSize: DEFAULT_VALUES.TERM_SIZE,
thresholdComparator: DEFAULT_VALUES.THRESHOLD_COMPARATOR,
timeWindowSize: DEFAULT_VALUES.TIME_WINDOW_SIZE,
timeWindowUnit: DEFAULT_VALUES.TIME_WINDOW_UNIT,
groupBy: DEFAULT_VALUES.GROUP_BY,
threshold: DEFAULT_VALUES.THRESHOLD,
timeField: '',
});
} else {
await refreshEsFields(indices);
}
}}
onTimeFieldChange={(updatedTimeField: string) =>
setRuleParams('timeField', updatedTimeField)
}
/>
>
<IndexSelectPopover
index={indexArray}
data-test-subj="indexSelectPopover"
esFields={esFields}
timeField={timeField}
errors={errors}
onIndexChange={async (indices: string[]) => {
setRuleParams('index', indices);
// reset expression fields if indices are deleted
if (indices.length === 0) {
setRuleProperty('params', {
...ruleParams,
index: indices,
aggType: DEFAULT_VALUES.AGGREGATION_TYPE,
termSize: DEFAULT_VALUES.TERM_SIZE,
thresholdComparator: DEFAULT_VALUES.THRESHOLD_COMPARATOR,
timeWindowSize: DEFAULT_VALUES.TIME_WINDOW_SIZE,
timeWindowUnit: DEFAULT_VALUES.TIME_WINDOW_UNIT,
groupBy: DEFAULT_VALUES.GROUP_BY,
threshold: DEFAULT_VALUES.THRESHOLD,
timeField: '',
});
} else {
await refreshEsFields(indices);
}
}}
onTimeFieldChange={(updatedTimeField: string) =>
setRuleParams('timeField', updatedTimeField)
}
/>
</EuiFormRow>
<EuiSpacer />
<EuiTitle size="xs">
<h5>
<EuiFormRow
fullWidth
label={
<FormattedMessage
id="xpack.stackAlerts.threshold.ui.conditionPrompt"
defaultMessage="Define the condition"
/>
</h5>
</EuiTitle>
<EuiSpacer size="s" />
<WhenExpression
display="fullWidth"
data-test-subj="whenExpression"
aggType={aggType ?? DEFAULT_VALUES.AGGREGATION_TYPE}
onChangeSelectedAggType={(selectedAggType: string) =>
setRuleParams('aggType', selectedAggType)
}
/>
>
<WhenExpression
display="fullWidth"
data-test-subj="whenExpression"
aggType={aggType ?? DEFAULT_VALUES.AGGREGATION_TYPE}
onChangeSelectedAggType={(selectedAggType: string) =>
setRuleParams('aggType', selectedAggType)
}
/>
</EuiFormRow>
{aggType && builtInAggregationTypes[aggType].fieldRequired ? (
<OfExpression
aggField={aggField}