Skip to content

Commit

Permalink
[Security Solution] Display Modified badge for customized fields in R…
Browse files Browse the repository at this point in the history
…ule Upgrade flyout (elastic#203968)

**Resolves:** elastic#203718

## Summary

This PR adds `Modified` badge to customized fields in rules upgrade flyout.

## Details

`_review` API endpoint contains fields diff providing enough information on what field values were involved in the comparison. In particular `diff_outcome` is used to determine if a field was customized i.e. the rule was edited and field value has a different value than a stock value. `Modified` badge is show for fields `CustomizedValueCanUpdate`, `CustomizedValueSameUpdate` and `CustomizedValueNoUpdate`.

## Screenshot

![image](https://github.com/user-attachments/assets/8f773f45-7ab5-4883-9ef7-fee8f3bde768)
  • Loading branch information
maximpn authored Dec 13, 2024
1 parent 0147e74 commit 87079ff
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,18 @@ import { useFieldUpgradeContext } from './field_upgrade_context';

export function FieldUpgrade(): JSX.Element {
const { euiTheme } = useEuiTheme();
const { fieldName, fieldUpgradeState, hasConflict } = useFieldUpgradeContext();
const { fieldName, fieldUpgradeState, hasConflict, isCustomized } = useFieldUpgradeContext();

return (
<>
<SplitAccordion
header={<FieldUpgradeHeader fieldName={fieldName} fieldUpgradeState={fieldUpgradeState} />}
header={
<FieldUpgradeHeader
fieldName={fieldName}
fieldUpgradeState={fieldUpgradeState}
isCustomized={isCustomized}
/>
}
initialIsOpen={hasConflict}
data-test-subj="ruleUpgradePerFieldDiff"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@

import React, { createContext, useContext, useMemo } from 'react';
import { useBoolean } from '@kbn/react-hooks';
import type {
DiffableRule,
FieldsDiff,
ThreeWayDiff,
import { assertUnreachable } from '../../../../../../../common/utility_types';
import {
ThreeWayDiffOutcome,
type DiffableRule,
type FieldsDiff,
type ThreeWayDiff,
} from '../../../../../../../common/api/detection_engine';
import { invariant } from '../../../../../../../common/utils/invariant';
import { convertRuleToDiffable } from '../../../../../../../common/detection_engine/prebuilt_rules/diff/convert_rule_to_diffable';
Expand All @@ -34,9 +36,13 @@ interface FieldUpgradeContextType {
*/
fieldUpgradeState: FieldUpgradeStateEnum;
/**
* Whether rule has an unresolved conflict. This state is derived from `fieldUpgradeState`.
* Whether the field has an unresolved conflict. This state is derived from `fieldUpgradeState`.
*/
hasConflict: boolean;
/**
* Whether the field was changed after prebuilt rule installation, i.e. customized
*/
isCustomized: boolean;
/**
* Field's three way diff
*/
Expand Down Expand Up @@ -98,6 +104,7 @@ export function FieldUpgradeContextProvider({
hasConflict:
fieldUpgradeState === FieldUpgradeStateEnum.SolvableConflict ||
fieldUpgradeState === FieldUpgradeStateEnum.NonSolvableConflict,
isCustomized: calcIsCustomized(fieldDiff),
fieldDiff,
finalDiffableRule: calcFinalDiffableRule(ruleUpgradeState),
rightSideMode: editing ? FieldFinalSideMode.Edit : FieldFinalSideMode.Readonly,
Expand Down Expand Up @@ -133,6 +140,24 @@ export function useFieldUpgradeContext() {
return context;
}

function calcIsCustomized(fieldDiff: ThreeWayDiff<unknown>): boolean {
switch (fieldDiff.diff_outcome) {
case ThreeWayDiffOutcome.StockValueNoUpdate:
case ThreeWayDiffOutcome.StockValueCanUpdate:
case ThreeWayDiffOutcome.MissingBaseCanUpdate:
case ThreeWayDiffOutcome.MissingBaseNoUpdate:
return false;

case ThreeWayDiffOutcome.CustomizedValueCanUpdate:
case ThreeWayDiffOutcome.CustomizedValueSameUpdate:
case ThreeWayDiffOutcome.CustomizedValueNoUpdate:
return true;

default:
return assertUnreachable(fieldDiff.diff_outcome);
}
}

function calcFinalDiffableRule(ruleUpgradeState: RuleUpgradeState): DiffableRule {
const fieldsResolvedValues = Object.entries(ruleUpgradeState.fieldsUpgradeState).reduce<
Record<string, unknown>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,29 @@ import { EuiFlexGroup, EuiTitle } from '@elastic/eui';
import { fieldToDisplayNameMap } from '../../diff_components/translations';
import type { FieldUpgradeStateEnum } from '../../../../model/prebuilt_rule_upgrade';
import { FieldUpgradeStateInfo } from './field_upgrade_state_info';
import { ModifiedBadge } from '../badges/modified_badge';
import { FIELD_MODIFIED_BADGE_DESCRIPTION } from './translations';

interface FieldUpgradeHeaderProps {
fieldName: string;
fieldUpgradeState: FieldUpgradeStateEnum;
isCustomized: boolean;
}

export function FieldUpgradeHeader({
fieldName,
fieldUpgradeState,
isCustomized,
}: FieldUpgradeHeaderProps): JSX.Element {
return (
<EuiFlexGroup alignItems="center">
<EuiFlexGroup alignItems="center" gutterSize="m">
<EuiTitle data-test-subj="ruleUpgradeFieldDiffLabel" size="xs">
<h5>{fieldToDisplayNameMap[fieldName] ?? startCase(camelCase(fieldName))}</h5>
</EuiTitle>

<EuiFlexGroup alignItems="center" gutterSize="s">
<FieldUpgradeStateInfo state={fieldUpgradeState} />
</EuiFlexGroup>
{isCustomized && <ModifiedBadge tooltip={FIELD_MODIFIED_BADGE_DESCRIPTION} />}

<FieldUpgradeStateInfo state={fieldUpgradeState} />
</EuiFlexGroup>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ export const RULE_IS_READY_FOR_UPGRADE_DESCRIPTION = i18n.translate(
export const FIELD_MODIFIED_BADGE_DESCRIPTION = i18n.translate(
'xpack.securitySolution.detectionEngine.upgradeFlyout.fieldModifiedBadgeDescription',
{
defaultMessage: 'The field value was edited and differs from the stock value',
defaultMessage:
"The field value was edited after rule's installation and differs from the value upon installation",
}
);
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ export const FIELD_UPDATES = i18n.translate(
export const RULE_MODIFIED_BADGE_DESCRIPTION = i18n.translate(
'xpack.securitySolution.detectionEngine.upgradeFlyout.ruleModifiedBadgeDescription',
{
defaultMessage: 'The rule was edited and field values differs from the stock values',
defaultMessage:
'The rule was edited after installation and field values differs from the values upon installation',
}
);

0 comments on commit 87079ff

Please sign in to comment.