Skip to content

Commit

Permalink
prepend warnings with a field name
Browse files Browse the repository at this point in the history
  • Loading branch information
maximpn committed Dec 2, 2024
1 parent 631bedc commit b0497b0
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,6 @@ export const CONFIRM = i18n.translate(
export const SAVE_WITH_ERRORS_MESSAGE = (errorsCount: number) =>
i18n.translate('xpack.securitySolution.detectionEngine.createRule.saveWithErrorsModalMessage', {
defaultMessage:
'There are {errorsCount} validation {errorsCount, plural, one {error} other {errors}} which can lead to failed rule executions, save anyway?',
'There {errorsCount, plural, one {is} other {are}} {errorsCount} validation {errorsCount, plural, one {error} other {errors}} which can lead to failed rule executions, save anyway?',
values: { errorsCount },
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
* 2.0.
*/

import type { FormHook, FormData } from '../../../shared_imports';
import type { FormHook, FormData, ValidationError } from '../../../shared_imports';

export interface FormHookWithWarn<T extends FormData = FormData, I extends FormData = T>
extends FormHook<T, I> {
getWarnings(): string[];
getValidationWarnings(): ValidationError[];
}
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ export function useFormWithWarn<T extends FormData = FormData, I extends FormDat
validate,
submit,
getErrors: () => errorsRef.current.map((x) => x.message),
getWarnings: () => warningsRef.current.map((x) => x.message),
getValidationWarnings: () => warningsRef.current,
},
}),
[form, validate, submit, isSubmitted, isSubmitting, isValid, errorsRef, warningsRef]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,34 @@
* 2.0.
*/

import { i18n } from '@kbn/i18n';
import { EQL_ERROR_CODES } from '../../../common/hooks/eql/api';
import { ESQL_ERROR_CODES } from '../components/esql_query_edit';

// const ESQL_FIELD_NAME = i18n.translate(
// 'xpack.securitySolution.detectionEngine.createRule.nonBlockingErrorCodes.esqlFieldName',
// {
// defaultMessage: 'ES|QL Query',
// }
// );
const ESQL_FIELD_NAME = i18n.translate(
'xpack.securitySolution.detectionEngine.createRule.nonBlockingErrorCodes.esqlFieldName',
{
defaultMessage: 'ES|QL Query',
}
);

// const EQL_FIELD_NAME = i18n.translate(
// 'xpack.securitySolution.detectionEngine.createRule.nonBlockingErrorCodes.eqlFieldName',
// {
// defaultMessage: 'EQL Query',
// }
// );
const EQL_FIELD_NAME = i18n.translate(
'xpack.securitySolution.detectionEngine.createRule.nonBlockingErrorCodes.eqlFieldName',
{
defaultMessage: 'EQL Query',
}
);

export const NON_BLOCKING_ERROR_CODES = [
ESQL_ERROR_CODES.INVALID_ESQL,
EQL_ERROR_CODES.FAILED_REQUEST,
EQL_ERROR_CODES.INVALID_EQL,
EQL_ERROR_CODES.MISSING_DATA_SOURCE,
] as const;

export const ERROR_CODE_FIELD_NAME_MAP: Readonly<Record<string, string>> = {
[ESQL_ERROR_CODES.INVALID_ESQL]: ESQL_FIELD_NAME,
[EQL_ERROR_CODES.FAILED_REQUEST]: EQL_FIELD_NAME,
[EQL_ERROR_CODES.INVALID_EQL]: EQL_FIELD_NAME,
[EQL_ERROR_CODES.MISSING_DATA_SOURCE]: EQL_FIELD_NAME,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* 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 { capitalize } from 'lodash';
import type { ValidationError } from '../../../shared_imports';

export function extractValidationMessages(
validationErrors: ValidationError[],
errorCodeFieldNameMap: Readonly<Record<string, string>>
): string[] {
return validationErrors.map(
(x) => `${errorCodeFieldNameMap[x.code ?? ''] ?? capitalize(x.path)}: ${x.message}`
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ import { useKibana, useUiSetting$ } from '../../../../common/lib/kibana';
import { RulePreview } from '../../components/rule_preview';
import { getIsRulePreviewDisabled } from '../../components/rule_preview/helpers';
import { useStartMlJobs } from '../../../rule_management/logic/use_start_ml_jobs';
import { ERROR_CODE_FIELD_NAME_MAP } from '../../../rule_creation/constants/non_blocking_error_codes';
import { extractValidationMessages } from '../../../rule_creation/logic/extract_validation_messages';
import { NextStep } from '../../components/next_step';
import { useRuleForms, useRuleIndexPattern } from '../form';
import { CustomHeaderPageMemo } from '..';
Expand Down Expand Up @@ -314,7 +316,7 @@ const CreateRulePageComponent: React.FC = () => {

return {
valid,
warnings: defineStepForm.getWarnings(),
warnings: defineStepForm.getValidationWarnings(),
};
}

Expand All @@ -323,23 +325,23 @@ const CreateRulePageComponent: React.FC = () => {

return {
valid,
warnings: aboutStepForm.getWarnings(),
warnings: aboutStepForm.getValidationWarnings(),
};
}
case RuleStep.scheduleRule: {
const valid = await scheduleStepForm.validate();

return {
valid,
warnings: scheduleStepForm.getWarnings(),
warnings: scheduleStepForm.getValidationWarnings(),
};
}
case RuleStep.ruleActions: {
const valid = await actionsStepForm.validate();

return {
valid,
warnings: actionsStepForm.getWarnings(),
warnings: actionsStepForm.getValidationWarnings(),
};
}
}
Expand Down Expand Up @@ -439,8 +441,9 @@ const CreateRulePageComponent: React.FC = () => {
const submitRule = useCallback(
async (enabled: boolean) => {
const { valid, warnings } = await validateAllSteps();
const warningMessages = extractValidationMessages(warnings, ERROR_CODE_FIELD_NAME_MAP);

if (!valid || !(await confirmValidationErrors(warnings))) {
if (!valid || !(await confirmValidationErrors(warningMessages))) {
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ import {
import { useStartTransaction } from '../../../../common/lib/apm/use_start_transaction';
import { SINGLE_RULE_ACTIONS } from '../../../../common/lib/apm/user_actions';
import { useGetSavedQuery } from '../../../../detections/pages/detection_engine/rules/use_get_saved_query';
import { extractValidationMessages } from '../../../rule_creation/logic/extract_validation_messages';
import { ERROR_CODE_FIELD_NAME_MAP } from '../../../rule_creation/constants/non_blocking_error_codes';
import { useRuleForms, useRuleIndexPattern } from '../form';
import { useEsqlIndex, useEsqlQueryForAboutStep } from '../../hooks';
import { CustomHeaderPageMemo } from '..';
Expand Down Expand Up @@ -423,19 +425,22 @@ const EditRulePageComponent: FC<{ rule: RuleResponse }> = ({ rule }) => {
return;
}

const defineRuleWarnings = defineStepForm.getWarnings();
const aboutRuleWarnings = aboutStepForm.getWarnings();
const scheduleRuleWarnings = scheduleStepForm.getWarnings();
const ruleActionsWarnings = actionsStepForm.getWarnings();
const defineRuleWarnings = defineStepForm.getValidationWarnings();
const aboutRuleWarnings = aboutStepForm.getValidationWarnings();
const scheduleRuleWarnings = scheduleStepForm.getValidationWarnings();
const ruleActionsWarnings = actionsStepForm.getValidationWarnings();

if (
!(await confirmValidationErrors([
const warnings = extractValidationMessages(
[
...defineRuleWarnings,
...aboutRuleWarnings,
...scheduleRuleWarnings,
...ruleActionsWarnings,
]))
) {
],
ERROR_CODE_FIELD_NAME_MAP
);

if (!(await confirmValidationErrors(warnings))) {
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
*/

import React, { useCallback, useEffect } from 'react';
import { capitalize } from 'lodash';
import { EuiButtonEmpty, EuiFlexGroup } from '@elastic/eui';
import { extractValidationMessages } from '../../../../../../rule_creation/logic/extract_validation_messages';
import type { FormWithWarnSubmitHandler } from '../../../../../../../common/hooks/use_form_with_warn';
import { useFormWithWarn } from '../../../../../../../common/hooks/use_form_with_warn';
import { Form } from '../../../../../../../shared_imports';
Expand All @@ -21,7 +21,10 @@ import { useDiffableRuleContext } from '../../diffable_rule_context';
import * as i18n from '../../translations';
import type { RuleFieldEditComponentProps } from './rule_field_edit_component_props';
import { useConfirmValidationErrorsModal } from '../../../../../../../common/hooks/use_confirm_validation_errors_modal';
import { NON_BLOCKING_ERROR_CODES } from '../../../../../../rule_creation/constants/non_blocking_error_codes';
import {
ERROR_CODE_FIELD_NAME_MAP,
NON_BLOCKING_ERROR_CODES,
} from '../../../../../../rule_creation/constants/non_blocking_error_codes';

type RuleFieldEditComponent = React.ComponentType<RuleFieldEditComponentProps>;

Expand Down Expand Up @@ -65,7 +68,7 @@ export function RuleFieldEditFormWrapper({

const handleSubmit = useCallback<FormWithWarnSubmitHandler>(
async (formData: FormData, isValid: boolean, { warnings }) => {
const warningMessages = warnings.map((x) => `${capitalize(x.path)}: ${x.message}`);
const warningMessages = extractValidationMessages(warnings, ERROR_CODE_FIELD_NAME_MAP);

if (!isValid || !(await confirmValidationErrors(warningMessages))) {
return;
Expand Down

0 comments on commit b0497b0

Please sign in to comment.