-
Notifications
You must be signed in to change notification settings - Fork 8.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Detections][Alerts] fixes saved_query rule validation issue #142602
Changes from 8 commits
d516e67
6ec20f5
63a2201
698d33a
386133e
a24362e
a5bb487
bdd051c
4fca1c3
45901f9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,7 @@ import { FormattedMessage } from '@kbn/i18n-react'; | |
import type { FC } from 'react'; | ||
import React, { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'; | ||
import { useParams } from 'react-router-dom'; | ||
import { noop } from 'lodash'; | ||
|
||
import type { DataViewListItem } from '@kbn/data-views-plugin/common'; | ||
import type { UpdateRulesSchema } from '../../../../../../common/detection_engine/schemas/request'; | ||
|
@@ -75,6 +76,7 @@ import { HeaderPage } from '../../../../../common/components/header_page'; | |
import { useStartTransaction } from '../../../../../common/lib/apm/use_start_transaction'; | ||
import { SINGLE_RULE_ACTIONS } from '../../../../../common/lib/apm/user_actions'; | ||
import { PreviewFlyout } from '../preview'; | ||
import { useGetSavedQuery } from '../use_get_saved_query'; | ||
|
||
const formHookNoop = async (): Promise<undefined> => undefined; | ||
|
||
|
@@ -98,6 +100,11 @@ const EditRulePageComponent: FC = () => { | |
const [ruleLoading, rule] = useRule(ruleId); | ||
const loading = ruleLoading || userInfoLoading || listsConfigLoading; | ||
|
||
const { isSavedQueryLoading, savedQueryBar, savedQuery } = useGetSavedQuery(rule?.saved_id, { | ||
ruleType: rule?.type, | ||
onError: noop, | ||
}); | ||
|
||
const formHooks = useRef<RuleStepsFormHooks>({ | ||
[RuleStep.defineRule]: formHookNoop, | ||
[RuleStep.aboutRule]: formHookNoop, | ||
|
@@ -195,6 +202,17 @@ const EditRulePageComponent: FC = () => { | |
const [indicesConfig] = useUiSetting$<string[]>(DEFAULT_INDEX_KEY); | ||
const [threatIndicesConfig] = useUiSetting$<string[]>(DEFAULT_THREAT_INDEX_KEY); | ||
|
||
const defineStepDataWithSavedQuery = useMemo( | ||
() => | ||
defineStep.data | ||
? { | ||
...defineStep.data, | ||
queryBar: savedQueryBar ?? defineStep.data.queryBar, | ||
} | ||
: defineStep.data, | ||
[defineStep.data, savedQueryBar] | ||
); | ||
|
||
const tabs = useMemo( | ||
() => [ | ||
{ | ||
|
@@ -205,19 +223,20 @@ const EditRulePageComponent: FC = () => { | |
content: ( | ||
<> | ||
<EuiSpacer /> | ||
<StepPanel loading={loading} title={ruleI18n.DEFINITION}> | ||
{defineStep.data != null && ( | ||
<StepPanel loading={loading || isSavedQueryLoading} title={ruleI18n.DEFINITION}> | ||
{defineStepDataWithSavedQuery != null && !isSavedQueryLoading && ( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. non strict check for Fairly common pattern across Kibana codebase (example from previous implementation): <StepPanel loading={loading} title={ruleI18n.DEFINITION}>
{defineStep.data != null && ( |
||
<StepDefineRule | ||
isReadOnlyView={false} | ||
isLoading={isLoading} | ||
isLoading={isLoading || isSavedQueryLoading} | ||
isUpdateView | ||
defaultValues={defineStep.data} | ||
defaultValues={defineStepDataWithSavedQuery} | ||
setForm={setFormHook} | ||
kibanaDataViews={dataViewOptions} | ||
indicesConfig={indicesConfig} | ||
threatIndicesConfig={threatIndicesConfig} | ||
onRuleDataChange={onDataChange} | ||
onPreviewDisabledStateChange={setIsPreviewDisabled} | ||
defaultSavedQuery={savedQuery} | ||
/> | ||
)} | ||
<EuiSpacer /> | ||
|
@@ -305,6 +324,8 @@ const EditRulePageComponent: FC = () => { | |
loading, | ||
defineStep.data, | ||
isLoading, | ||
isSavedQueryLoading, | ||
defineStepDataWithSavedQuery, | ||
setFormHook, | ||
dataViewOptions, | ||
indicesConfig, | ||
|
@@ -314,6 +335,7 @@ const EditRulePageComponent: FC = () => { | |
scheduleStep.data, | ||
actionsStep.data, | ||
actionMessageParams, | ||
savedQuery, | ||
] | ||
); | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
/* | ||
* 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 { useMemo } from 'react'; | ||
import { useQuery } from '@tanstack/react-query'; | ||
|
||
import type { Type } from '@kbn/securitysolution-io-ts-alerting-types'; | ||
|
||
import { useSavedQueryServices } from '../../../../common/utils/saved_query_services'; | ||
import type { DefineStepRule } from './types'; | ||
|
||
import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; | ||
|
||
import { SAVED_QUERY_LOAD_ERROR_TOAST } from './translations'; | ||
|
||
interface UseGetSavedQuerySettings { | ||
onError?: (e: unknown) => void; | ||
ruleType: Type | undefined; | ||
} | ||
|
||
export const useGetSavedQuery = ( | ||
savedQueryId: string | undefined, | ||
{ ruleType, onError }: UseGetSavedQuerySettings | ||
) => { | ||
const savedQueryServices = useSavedQueryServices(); | ||
const { addError } = useAppToasts(); | ||
|
||
const defaultErrorHandler = (e: unknown) => { | ||
addError(e, { title: SAVED_QUERY_LOAD_ERROR_TOAST }); | ||
}; | ||
|
||
const query = useQuery( | ||
['detectionEngine', 'rule', 'savedQuery', savedQueryId], | ||
async () => { | ||
if (!savedQueryId) { | ||
return null; | ||
} | ||
|
||
return savedQueryServices.getSavedQuery(savedQueryId); | ||
}, | ||
{ | ||
onError: onError ?? defaultErrorHandler, | ||
// load saved query only if rule type === 'saved_query', as other rule types still can have saved_id property that is not used | ||
// Rule schema allows to save any rule with saved_id property, but it only used for saved_query rule type | ||
// In future we might look in possibility to restrict rule schema (breaking change!) and remove saved_id from the rest of rules through migration | ||
enabled: Boolean(savedQueryId) && ruleType === 'saved_query', | ||
retry: false, | ||
} | ||
); | ||
|
||
const savedQueryBar = useMemo<DefineStepRule['queryBar'] | null>( | ||
() => | ||
query.data | ||
? { | ||
saved_id: query.data.id, | ||
filters: query.data.attributes.filters ?? [], | ||
query: query.data.attributes.query, | ||
title: query.data.attributes.title, | ||
} | ||
: null, | ||
[query.data] | ||
); | ||
|
||
return { | ||
isSavedQueryLoading: savedQueryId ? query.isLoading : false, | ||
savedQueryBar, | ||
savedQuery: query.data ?? undefined, | ||
}; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
onError: noop,
reduces straightness of the code since it requires knowledge what's going on under the hood and suppressing of that behaviour when necessary. I'd recommend to consider removing the default error handling functionality inside, exposing ofshowErrorToastHandler
and passing it directly when necessary. Though it usestoasts
then it makes sense to expose a hook likeuseShowErrorToastHandler()
which can be composable and reusable.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@maximpn
Toast is not displayed in this case because error is displayed on edit form when saved query is not loaded. Thus it's prevents showing duplicated notifications