Skip to content

Commit 0174558

Browse files
committed
adds concurrency controls
1 parent 917c65c commit 0174558

4 files changed

Lines changed: 59 additions & 9 deletions

File tree

x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/base_version_diff/base_version_flyout.tsx

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,27 @@
55
* 2.0.
66
*/
77

8-
import React, { memo, useCallback, useMemo } from 'react';
8+
import React, { memo, useCallback, useMemo, useRef, useEffect } from 'react';
99
import { EuiButton, EuiCallOut, EuiSpacer, EuiToolTip } from '@elastic/eui';
10+
import { useAppToasts } from '../../../../../common/hooks/use_app_toasts';
1011
import type { PartialRuleDiff, RuleResponse } from '../../../../../../common/api/detection_engine';
1112
import { PerFieldRuleDiffTab } from '../per_field_rule_diff_tab';
1213
import { RuleDetailsFlyout, TabContentPadding } from '../rule_details_flyout';
1314
import * as ruleDetailsI18n from '../translations';
1415
import * as i18n from './translations';
1516
import { RuleDiffTab } from '../rule_diff_tab';
1617
import { BaseVersionDiffFlyoutSubheader } from './base_version_flyout_subheader';
17-
import { useRevertPrebuiltRule } from '../../../logic/prebuilt_rules/use_revert_prebuilt_rule';
18+
import {
19+
getRevertRuleErrorStatusCode,
20+
useRevertPrebuiltRule,
21+
} from '../../../logic/prebuilt_rules/use_revert_prebuilt_rule';
1822

1923
export const PREBUILT_RULE_BASE_VERSION_FLYOUT_ANCHOR = 'baseVersionPrebuiltRulePreview';
2024

25+
interface PrebuiltRuleConcurrencyControl {
26+
revision: number;
27+
}
28+
2129
interface PrebuiltRulesBaseVersionFlyoutComponentProps {
2230
currentRule: RuleResponse;
2331
baseRule: RuleResponse;
@@ -35,6 +43,7 @@ export const PrebuiltRulesBaseVersionFlyout = memo(function PrebuiltRulesBaseVer
3543
isReverting,
3644
onRevert,
3745
}: PrebuiltRulesBaseVersionFlyoutComponentProps): JSX.Element {
46+
useConcurrecyControl(currentRule);
3847
const { mutateAsync: revertPrebuiltRule, isLoading } = useRevertPrebuiltRule();
3948
const subHeader = useMemo(
4049
() => <BaseVersionDiffFlyoutSubheader currentRule={currentRule} diff={diff} />,
@@ -48,10 +57,14 @@ export const PrebuiltRulesBaseVersionFlyout = memo(function PrebuiltRulesBaseVer
4857
version: currentRule.version,
4958
revision: currentRule.revision,
5059
});
51-
} catch {
52-
// Error is handled by the mutation's onError callback, so no need to do anything here
53-
} finally {
5460
closeFlyout();
61+
} catch (error) {
62+
const statusCode = getRevertRuleErrorStatusCode(error);
63+
// Don't close flyout on concurrency errors
64+
if (statusCode !== 409) {
65+
closeFlyout();
66+
}
67+
} finally {
5568
if (onRevert) {
5669
onRevert();
5770
}
@@ -141,3 +154,23 @@ export const PrebuiltRulesBaseVersionFlyout = memo(function PrebuiltRulesBaseVer
141154
/>
142155
);
143156
});
157+
158+
const useConcurrecyControl = (currentRule: RuleResponse) => {
159+
const concurrencyControl = useRef<PrebuiltRuleConcurrencyControl>();
160+
const { addWarning } = useAppToasts();
161+
162+
useEffect(() => {
163+
const concurrency = concurrencyControl.current;
164+
165+
if (concurrency != null && concurrency.revision !== currentRule.revision) {
166+
addWarning({
167+
title: i18n.NEW_REVISION_DETECTED_WARNING,
168+
text: i18n.NEW_REVISION_DETECTED_WARNING_MESSAGE,
169+
});
170+
}
171+
172+
concurrencyControl.current = {
173+
revision: currentRule.revision,
174+
};
175+
}, [addWarning, currentRule.revision]);
176+
};

x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/base_version_diff/translations.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,18 @@ export const BASE_VERSION_LABEL = i18n.translate(
8787
defaultMessage: 'Original Elastic rule',
8888
}
8989
);
90+
91+
export const NEW_REVISION_DETECTED_WARNING = i18n.translate(
92+
'xpack.securitySolution.detectionEngine.baseVersionFlyout.ruleNewRevisionDetectedWarning',
93+
{
94+
defaultMessage: 'Installed rule changed',
95+
}
96+
);
97+
98+
export const NEW_REVISION_DETECTED_WARNING_MESSAGE = i18n.translate(
99+
'xpack.securitySolution.detectionEngine.baseVersionFlyout.ruleNewRevisionDetectedWarningMessage',
100+
{
101+
defaultMessage:
102+
'The installed rule was changed, the rule modifications diff flyout has been updated.',
103+
}
104+
);

x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/hooks/use_prebuilt_rules_view_base_diff.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,10 @@ export const usePrebuiltRulesViewBaseDiff = ({
2929
}: UsePrebuiltRulesViewBaseDiffProps) => {
3030
const [isFlyoutOpen, setIsFlyoutOpen] = useState(false);
3131
const [isReverting, setIsReverting] = useState(false);
32+
const enabled = useMemo(() => rule != null && isCustomizedPrebuiltRule(rule), [rule]);
3233
const { data, isLoading, error } = useFetchPrebuiltRuleBaseVersionQuery({
3334
id: rule?.id,
34-
enabled: rule != null && isCustomizedPrebuiltRule(rule),
35+
enabled,
3536
});
3637

3738
// Handle when we receive an error when the base_version doesn't exist

x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/logic/prebuilt_rules/use_revert_prebuilt_rule.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,16 @@ const populateErrorStack = (error: HTTPError): HTTPError => {
3737
};
3838

3939
const getErrorToastMessage = (error: HTTPError): string => {
40-
const statusCode = (error.body as RevertPrebuiltRulesResponseBody)?.attributes.errors?.at(
41-
0
42-
)?.status_code;
40+
const statusCode = getRevertRuleErrorStatusCode(error);
4341
if (statusCode === 409) {
4442
return i18n.RULE_REVERT_FAILED_CONCURRENCY_MESSAGE;
4543
}
4644
return (error.body as RevertPrebuiltRulesResponseBody)?.attributes.errors?.at(0)?.message ?? '';
4745
};
4846

47+
export const getRevertRuleErrorStatusCode = (error: HTTPError) =>
48+
(error.body as RevertPrebuiltRulesResponseBody)?.attributes.errors?.at(0)?.status_code;
49+
4950
const getSuccessToastMessage = (result: {
5051
summary: {
5152
total: number;

0 commit comments

Comments
 (0)