diff --git a/x-pack/platform/plugins/private/translations/translations/fr-FR.json b/x-pack/platform/plugins/private/translations/translations/fr-FR.json index 031904320bf99..3a94d0a039966 100644 --- a/x-pack/platform/plugins/private/translations/translations/fr-FR.json +++ b/x-pack/platform/plugins/private/translations/translations/fr-FR.json @@ -39080,43 +39080,26 @@ "xpack.securitySolution.detectionEngine.rules.upgradeRules.comparisonSide.title": "Affichage différé", "xpack.securitySolution.detectionEngine.rules.upgradeRules.currentVersionDescriptionLabel": "Affiche la règle actuellement installée", "xpack.securitySolution.detectionEngine.rules.upgradeRules.currentVersionLabel": "Règle actuelle", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.diffTab.fieldsWithUpdates": "La mise à niveau contient {count} {count, plural, one {champ} other {champs}}", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.diffTab.numOfConflicts": "{count} {count, plural, one {conflit} other {conflits}}", "xpack.securitySolution.detectionEngine.rules.upgradeRules.editButtonLabel": "Modifier", "xpack.securitySolution.detectionEngine.rules.upgradeRules.elasticUpdateVersionLabel": "Mise à jour Elastic", "xpack.securitySolution.detectionEngine.rules.upgradeRules.expandHiddenDiffLinesLabel": "Développer {linesCount}{linesCount, plural, one {ligne} other {lignes}}", "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldReadOnly.noteLabel": "Guide d'investigation", "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.nonSolvableConflict": "Conflit résolu", "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.nonSolvableConflictDescription": "Nous avons suggéré une mise à jour pour ce champ modifié, veuillez la consulter avant d'accepter.", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.ruleHasNonSolvableConflicts": "{count} des champs {count, plural, one {a} other {ont}} un conflit non résolu. Veuillez en prendre connaissance et apporter les modifications appropriées.", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.ruleHasNonSolvableConflictsDescription": "Veuillez apporter une contribution au conflit non résolu. Vous pouvez également conserver la version actuelle sans les mises à jour, ou accepter la mise à jour Elastic tout en perdant vos modifications.", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.ruleHasSolvableConflicts": "{count} des champs {count, plural, one {a} other {ont}} un conflit de mise à jour. Veuillez examiner la mise à jour en cours suggérée.", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.ruleHasSolvableConflictsDescription": "Veuillez consulter la version mise à jour recommandée avant de l'accepter. Vous pouvez modifier le champ, puis l'enregistrer, si nécessaire.", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.ruleIsReadyForUpgrade": "La mise à jour est prête à être appliquée.", "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.ruleIsReadyForUpgradeDescription": "Tous les conflits ont maintenant été examinés et résolus, veuillez mettre à jour la règle.", "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.separator": "-", "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.solvableConflict": "Conflit résolu", "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.solvableConflictDescription": "Nous avons suggéré une mise à jour pour ce champ modifié, veuillez la consulter avant d'accepter.", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.updateAccepted": "Mise à jour acceptée", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.updateAcceptedDescription": "Vous pouvez toujours apporter des modifications, veuillez consulter/accepter tous les autres conflits avant de mettre à jour la règle.", "xpack.securitySolution.detectionEngine.rules.upgradeRules.finalUpdate": "Mise à jour finale", "xpack.securitySolution.detectionEngine.rules.upgradeRules.noRulesBodyTitle": "Il n’y a actuellement aucune mise à jour disponible pour vos règles Elastic installées.", "xpack.securitySolution.detectionEngine.rules.upgradeRules.noRulesTitle": "Toutes les règles Elastic sont à jour", "xpack.securitySolution.detectionEngine.rules.upgradeRules.ruleUpgradeHelper": "Découvrez comment {docsLink}.", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.saveButtonLabel": "Enregistrer", "xpack.securitySolution.detectionEngine.rules.upgradeRules.searchBarPlaceholder": "Rechercher par nom de règle", "xpack.securitySolution.detectionEngine.rules.upgradeRules.updatedVersionDescriptionLabel": "Affiche la règle qui sera installée", "xpack.securitySolution.detectionEngine.rules.upgradeRules.updateYourRulesDocsLink": "mettre à jour vos règles", "xpack.securitySolution.detectionEngine.rules.upgradeRules.upgradeAll": "Tout mettre à jour", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.upgradeHelpText": "Choisissez les valeurs de champ utilisées dans la règle mise à niveau.", "xpack.securitySolution.detectionEngine.rules.upgradeRules.upgradeSelected": "Mettre à jour {numberOfSelectedRules} règle(s) sélectionnée(s)", "xpack.securitySolution.detectionEngine.rules.upgradeRules.versionsPicker.ariaLabel": "Sélectionnez les versions à comparer", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.versionsPicker.baseVsCurrentLabel": "Base - Actuel", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.versionsPicker.baseVsFinalLabel": "Base - Final", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.versionsPicker.baseVsTargetLabel": "Base - Cible", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.versionsPicker.currentVsFinalLabel": "Actuel - Final", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.versionsPicker.currentVsTargetLabel": "Actuel - Cible", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.versionsPicker.targetVsFinalLabel": "Actuel - Final", "xpack.securitySolution.detectionEngine.rulesSnoozeBadge.error.unableToFetch": "Impossible de récupérer les paramètres de répétition", "xpack.securitySolution.detectionEngine.ruleStatus.askAssistant": "Demander à l'assistant", "xpack.securitySolution.detectionEngine.ruleStatus.askAssistantDesc": "Message d'erreur de l'exécution de la règle", diff --git a/x-pack/platform/plugins/private/translations/translations/ja-JP.json b/x-pack/platform/plugins/private/translations/translations/ja-JP.json index 90eeb4cc57b12..91ea24cbcd7e4 100644 --- a/x-pack/platform/plugins/private/translations/translations/ja-JP.json +++ b/x-pack/platform/plugins/private/translations/translations/ja-JP.json @@ -38937,43 +38937,26 @@ "xpack.securitySolution.detectionEngine.rules.upgradeRules.comparisonSide.title": "差異ビュー", "xpack.securitySolution.detectionEngine.rules.upgradeRules.currentVersionDescriptionLabel": "現在インストールされているルールを表示します", "xpack.securitySolution.detectionEngine.rules.upgradeRules.currentVersionLabel": "現在のルール", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.diffTab.fieldsWithUpdates": "アップグレードには{count} {count, plural, other {個のフィールド}}があります", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.diffTab.numOfConflicts": "{count} {count, plural, other {件の競合}}", "xpack.securitySolution.detectionEngine.rules.upgradeRules.editButtonLabel": "編集", "xpack.securitySolution.detectionEngine.rules.upgradeRules.elasticUpdateVersionLabel": "Elastic更新", "xpack.securitySolution.detectionEngine.rules.upgradeRules.expandHiddenDiffLinesLabel": "変更されていない{linesCount} {linesCount, plural, other {行}}を展開", "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldReadOnly.noteLabel": "調査ガイド", "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.nonSolvableConflict": "解決された競合", "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.nonSolvableConflictDescription": "この修正されたフィールドの更新を提案しました。承認する前に確認してください。", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.ruleHasNonSolvableConflicts": "{count}個のフィールド{count, plural, other {には}}未解決の競合があります。確認し、必要に応じて修正してください。", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.ruleHasNonSolvableConflictsDescription": "未解決の競合の情報を入力してください。更新を適用せずに現在の状態を維持することもできます。Elasticの更新を承認すると、修正内容は失われます。", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.ruleHasSolvableConflicts": "{count}個のフィールド{count, plural, other {には}}更新の競合があります。更新中の候補の更新を確認してください。", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.ruleHasSolvableConflictsDescription": "更新を承認する前に、提案された更新バージョンを確認してください。変更する場合は、編集してフィールドを保存できます。", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.ruleIsReadyForUpgrade": "更新を適用できます。", "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.ruleIsReadyForUpgradeDescription": "すべての競合が確認され、解決されました。ルールを更新してください。", "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.separator": "-", "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.solvableConflict": "解決された競合", "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.solvableConflictDescription": "この修正されたフィールドの更新を提案しました。承認する前に確認してください。", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.updateAccepted": "更新が承認されました", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.updateAcceptedDescription": "変更を行うことができます。ルールを更新する前に、他のすべての競合を確認/承認してください。", "xpack.securitySolution.detectionEngine.rules.upgradeRules.finalUpdate": "最終更新", "xpack.securitySolution.detectionEngine.rules.upgradeRules.noRulesBodyTitle": "現在、インストールされているElasticルールに利用可能な更新はありません。", "xpack.securitySolution.detectionEngine.rules.upgradeRules.noRulesTitle": "すべてのElasticルールが最新です", "xpack.securitySolution.detectionEngine.rules.upgradeRules.ruleUpgradeHelper": "{docsLink}方法を確認してください。", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.saveButtonLabel": "保存", "xpack.securitySolution.detectionEngine.rules.upgradeRules.searchBarPlaceholder": "ルール名で検索", "xpack.securitySolution.detectionEngine.rules.upgradeRules.updatedVersionDescriptionLabel": "インストールされるルールを表示します", "xpack.securitySolution.detectionEngine.rules.upgradeRules.updateYourRulesDocsLink": "ルールを更新", "xpack.securitySolution.detectionEngine.rules.upgradeRules.upgradeAll": "すべて更新", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.upgradeHelpText": "アップグレードされたルールで使用されるフィールド値を選択してください。", "xpack.securitySolution.detectionEngine.rules.upgradeRules.upgradeSelected": "{numberOfSelectedRules}個の選択したルールを更新", "xpack.securitySolution.detectionEngine.rules.upgradeRules.versionsPicker.ariaLabel": "比較するバージョンを選択", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.versionsPicker.baseVsCurrentLabel": "基本と現在", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.versionsPicker.baseVsFinalLabel": "基本と最終", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.versionsPicker.baseVsTargetLabel": "基本とターゲット", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.versionsPicker.currentVsFinalLabel": "現在と最終", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.versionsPicker.currentVsTargetLabel": "現在とターゲット", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.versionsPicker.targetVsFinalLabel": "ターゲットと最終", "xpack.securitySolution.detectionEngine.rulesSnoozeBadge.error.unableToFetch": "スヌーズ設定を取得できません", "xpack.securitySolution.detectionEngine.ruleStatus.askAssistant": "アシスタントに聞く", "xpack.securitySolution.detectionEngine.ruleStatus.askAssistantDesc": "ルールの実行失敗メッセージ", diff --git a/x-pack/platform/plugins/private/translations/translations/zh-CN.json b/x-pack/platform/plugins/private/translations/translations/zh-CN.json index a4a6f117857e1..c7fbc414a3379 100644 --- a/x-pack/platform/plugins/private/translations/translations/zh-CN.json +++ b/x-pack/platform/plugins/private/translations/translations/zh-CN.json @@ -38361,43 +38361,26 @@ "xpack.securitySolution.detectionEngine.rules.upgradeRules.comparisonSide.title": "差异视图", "xpack.securitySolution.detectionEngine.rules.upgradeRules.currentVersionDescriptionLabel": "显示当前安装的规则", "xpack.securitySolution.detectionEngine.rules.upgradeRules.currentVersionLabel": "当前规则", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.diffTab.fieldsWithUpdates": "升级包含 {count} 个{count, plural, other {字段}}", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.diffTab.numOfConflicts": "{count} 个{count, plural, other {冲突}}", "xpack.securitySolution.detectionEngine.rules.upgradeRules.editButtonLabel": "编辑", "xpack.securitySolution.detectionEngine.rules.upgradeRules.elasticUpdateVersionLabel": "Elastic 更新", "xpack.securitySolution.detectionEngine.rules.upgradeRules.expandHiddenDiffLinesLabel": "展开 {linesCount} 个未更改的{linesCount, plural, other {行}}", "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldReadOnly.noteLabel": "调查指南", "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.nonSolvableConflict": "已解决冲突", "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.nonSolvableConflictDescription": "我们已为这个已修改字段推荐了更新,请在接受前进行复查。", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.ruleHasNonSolvableConflicts": "{count} 个字段{count, plural, other {存在}}未解决的冲突。请复查并做出相应更改。", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.ruleHasNonSolvableConflictsDescription": "请为未解决的冲突提供输入。您还可以保持现状而不进行更新,也可以接受 Elastic 更新但丢失修改。", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.ruleHasSolvableConflicts": "{count} 个字段{count, plural, other {存在}}更新冲突,请复查正在更新的建议更新。", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.ruleHasSolvableConflictsDescription": "在接受更新之前,请复查建议的已更新版本。如果希望更改字段,您可以编辑然后保存字段。", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.ruleIsReadyForUpgrade": "更新已准备就绪,可以应用。", "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.ruleIsReadyForUpgradeDescription": "现已复查并解决所有冲突,请更新规则。", "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.separator": "-", "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.solvableConflict": "已解决冲突", "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.solvableConflictDescription": "我们已为这个已修改字段推荐了更新,请在接受前进行复查。", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.updateAccepted": "已接受更新", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.updateAcceptedDescription": "您仍然可以做出更改,在更新规则之前,请复查/接受所有其他冲突。", "xpack.securitySolution.detectionEngine.rules.upgradeRules.finalUpdate": "最后更新", "xpack.securitySolution.detectionEngine.rules.upgradeRules.noRulesBodyTitle": "您已安装的 Elastic 规则当前没有可用更新。", "xpack.securitySolution.detectionEngine.rules.upgradeRules.noRulesTitle": "所有 Elastic 规则均保持最新", "xpack.securitySolution.detectionEngine.rules.upgradeRules.ruleUpgradeHelper": "了解如何 {docsLink}。", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.saveButtonLabel": "保存", "xpack.securitySolution.detectionEngine.rules.upgradeRules.searchBarPlaceholder": "按规则名称搜索", "xpack.securitySolution.detectionEngine.rules.upgradeRules.updatedVersionDescriptionLabel": "显示将安装的规则", "xpack.securitySolution.detectionEngine.rules.upgradeRules.updateYourRulesDocsLink": "更新您的规则", "xpack.securitySolution.detectionEngine.rules.upgradeRules.upgradeAll": "全部更新", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.upgradeHelpText": "选择用在已升级规则中的字段值。", "xpack.securitySolution.detectionEngine.rules.upgradeRules.upgradeSelected": "更新 {numberOfSelectedRules} 个选定规则", "xpack.securitySolution.detectionEngine.rules.upgradeRules.versionsPicker.ariaLabel": "选择要比较的版本", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.versionsPicker.baseVsCurrentLabel": "基础与当前", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.versionsPicker.baseVsFinalLabel": "基础与最终", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.versionsPicker.baseVsTargetLabel": "基础与目标", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.versionsPicker.currentVsFinalLabel": "当前与最终", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.versionsPicker.currentVsTargetLabel": "当前与目标", - "xpack.securitySolution.detectionEngine.rules.upgradeRules.versionsPicker.targetVsFinalLabel": "目标与最终", "xpack.securitySolution.detectionEngine.rulesSnoozeBadge.error.unableToFetch": "无法提取暂停设置", "xpack.securitySolution.detectionEngine.ruleStatus.askAssistant": "询问助手", "xpack.securitySolution.detectionEngine.ruleStatus.askAssistantDesc": "规则的执行失败消息", diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/perform_rule_upgrade/perform_rule_upgrade_route.ts b/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/perform_rule_upgrade/perform_rule_upgrade_route.ts index 0021aece67455..3ef53e7b7c67a 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/perform_rule_upgrade/perform_rule_upgrade_route.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/perform_rule_upgrade/perform_rule_upgrade_route.ts @@ -115,7 +115,7 @@ export const RuleUpgradeSpecifier = z.object({ export type UpgradeSpecificRulesRequest = z.infer; export const UpgradeSpecificRulesRequest = z.object({ mode: z.literal('SPECIFIC_RULES'), - rules: z.array(RuleUpgradeSpecifier), + rules: z.array(RuleUpgradeSpecifier).min(1), pick_version: PickVersionValues.optional(), }); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_details_flyout.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_details_flyout.tsx index 7c7125a36dc5d..3425779926f7d 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_details_flyout.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_details_flyout.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import type { FC, PropsWithChildren } from 'react'; +import type { FC, PropsWithChildren, ReactNode } from 'react'; import React, { useMemo, useState, useEffect } from 'react'; import styled from 'styled-components'; import { css } from '@emotion/css'; @@ -107,6 +107,7 @@ export const TabContentPadding: FC> = ({ children }) interface RuleDetailsFlyoutProps { rule: RuleResponse; + subHeader?: ReactNode; ruleActions?: React.ReactNode; size?: EuiFlyoutProps['size']; extraTabs?: EuiTabbedContentTab[]; @@ -115,15 +116,16 @@ interface RuleDetailsFlyoutProps { closeFlyout: () => void; } -export const RuleDetailsFlyout = ({ +export function RuleDetailsFlyout({ rule, ruleActions, + subHeader, size = 'm', extraTabs = [], dataTestSubj, id, closeFlyout, -}: RuleDetailsFlyoutProps) => { +}: RuleDetailsFlyoutProps): JSX.Element { const { expandedOverviewSections, toggleOverviewSection } = useOverviewTabSections(); const overviewTab: EuiTabbedContentTab = useMemo( @@ -202,7 +204,13 @@ export const RuleDetailsFlyout = ({

{rule.name}

- + + {subHeader && ( + <> + {subHeader} + + + )} ); -}; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/badges/action_required.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/badges/action_required.tsx new file mode 100644 index 0000000000000..d21136531fd07 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/badges/action_required.tsx @@ -0,0 +1,14 @@ +/* + * 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 React from 'react'; +import { EuiBadge } from '@elastic/eui'; +import * as i18n from './translations'; + +export function ActionRequiredBadge(): JSX.Element { + return {i18n.ACTION_REQUIRED}; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/badges/modified_badge.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/badges/modified_badge.tsx new file mode 100644 index 0000000000000..bfe70af031835 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/badges/modified_badge.tsx @@ -0,0 +1,25 @@ +/* + * 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 type { ReactNode } from 'react'; +import React from 'react'; +import { EuiBadge, EuiToolTip } from '@elastic/eui'; +import * as i18n from './translations'; + +interface ModifiedBadgeProps { + tooltip?: ReactNode; +} + +export function ModifiedBadge({ tooltip }: ModifiedBadgeProps): JSX.Element { + return ( + + + {i18n.MODIFIED} + + + ); +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/badges/ready_for_upgrade_badge.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/badges/ready_for_upgrade_badge.tsx new file mode 100644 index 0000000000000..c5498fe04dcfe --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/badges/ready_for_upgrade_badge.tsx @@ -0,0 +1,21 @@ +/* + * 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 React from 'react'; +import type { EuiBadgeProps } from '@elastic/eui'; +import { EuiBadge } from '@elastic/eui'; +import * as i18n from './translations'; + +interface ReadyForUpgradeBadgeProps { + color?: EuiBadgeProps['color']; +} + +export function ReadyForUpgradeBadge({ + color = 'success', +}: ReadyForUpgradeBadgeProps): JSX.Element { + return {i18n.READY_FOR_UPDATE}; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/badges/review_required_badge.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/badges/review_required_badge.tsx new file mode 100644 index 0000000000000..db02ce9a3615e --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/badges/review_required_badge.tsx @@ -0,0 +1,14 @@ +/* + * 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 React from 'react'; +import { EuiBadge } from '@elastic/eui'; +import * as i18n from './translations'; + +export function ReviewRequiredBadge(): JSX.Element { + return {i18n.REVIEW_REQUIRED}; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/badges/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/badges/translations.ts new file mode 100644 index 0000000000000..f55b9ad2eef73 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/badges/translations.ts @@ -0,0 +1,36 @@ +/* + * 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 { i18n } from '@kbn/i18n'; + +export const READY_FOR_UPDATE = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.badge.readyForUpdate', + { + defaultMessage: 'Ready for update', + } +); + +export const REVIEW_REQUIRED = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.badge.reviewRequired', + { + defaultMessage: 'Review required', + } +); + +export const ACTION_REQUIRED = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.badge.actionRequired', + { + defaultMessage: 'Action required', + } +); + +export const MODIFIED = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.badge.modified', + { + defaultMessage: 'Modified', + } +); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/comparison_side.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/comparison_side.tsx deleted file mode 100644 index e5ec6a8dfc540..0000000000000 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/comparison_side.tsx +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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 React, { useState } from 'react'; -import { EuiFlexGroup, EuiTitle } from '@elastic/eui'; -import { VersionsPicker } from '../versions_picker/versions_picker'; -import type { Version } from '../versions_picker/constants'; -import { SelectedVersions } from '../versions_picker/constants'; -import { pickFieldValueForVersion } from './utils'; -import type { - DiffableAllFields, - ThreeWayDiff, -} from '../../../../../../../common/api/detection_engine'; -import { getSubfieldChanges } from './get_subfield_changes'; -import { SubfieldChanges } from './subfield_changes'; -import { SideHeader } from '../components/side_header'; -import { ComparisonSideHelpInfo } from './comparison_side_help_info'; -import * as i18n from './translations'; - -interface ComparisonSideProps { - fieldName: FieldName; - fieldThreeWayDiff: ThreeWayDiff; - resolvedValue: DiffableAllFields[FieldName]; -} - -export function ComparisonSide({ - fieldName, - fieldThreeWayDiff, - resolvedValue, -}: ComparisonSideProps) { - const [selectedVersions, setSelectedVersions] = useState( - SelectedVersions.CurrentFinal - ); - - const [oldVersionType, newVersionType] = selectedVersions.split('_') as [Version, Version]; - - const oldFieldValue = pickFieldValueForVersion(oldVersionType, fieldThreeWayDiff, resolvedValue); - - const newFieldValue = pickFieldValueForVersion(newVersionType, fieldThreeWayDiff, resolvedValue); - - const subfieldChanges = getSubfieldChanges(fieldName, oldFieldValue, newFieldValue); - - return ( - <> - - - -

- {i18n.TITLE} - -

-
- -
-
- - - ); -} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/comparison_side_help_info.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/comparison_side_help_info.tsx index e1eaa9b1e96cd..47e5e537f3ab0 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/comparison_side_help_info.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/comparison_side_help_info.tsx @@ -9,6 +9,14 @@ import React from 'react'; import useToggle from 'react-use/lib/useToggle'; import { EuiPopover, EuiText, EuiButtonIcon } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; +import { i18n } from '@kbn/i18n'; +import { TITLE } from './translations'; +import { + BASE_VERSION, + CURRENT_VERSION, + FINAL_VERSION, + TARGET_VERSION, +} from './versions_picker/translations'; /** * Theme doesn't expose width variables. Using provided size variables will require @@ -34,10 +42,64 @@ export function ComparisonSideHelpInfo(): JSX.Element { {TITLE}, + versions: ( + <> +
+
    +
  • + {BASE_VERSION} {'-'} {BASE_VERSION_EXPLANATION} +
  • +
  • + {CURRENT_VERSION} {'-'} {CURRENT_VERSION_EXPLANATION} +
  • +
  • + {TARGET_VERSION} {'-'} {TARGET_VERSION_EXPLANATION} +
  • +
  • + {FINAL_VERSION} {'-'} {FINAL_VERSION_EXPLANATION} +
  • +
+ + ), + }} />
); } + +const BASE_VERSION_EXPLANATION = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.versions.baseVersionExplanation', + { + defaultMessage: 'version originally installed from Elastic prebuilt rules package', + } +); + +const CURRENT_VERSION_EXPLANATION = ( + {BASE_VERSION}, + }} + /> +); + +const TARGET_VERSION_EXPLANATION = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.versions.targetVersionExplanation', + { + defaultMessage: 'version coming from a new version of Elastic prebuilt rules package', + } +); + +const FINAL_VERSION_EXPLANATION = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.versions.finalVersionExplanation', + { + defaultMessage: + 'version used to the update the rule. Initial value is suggested by the diff algorithm.', + } +); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/comparison_side.stories.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/field_comparison_side.stories.tsx similarity index 98% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/comparison_side.stories.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/field_comparison_side.stories.tsx index 37ddb71dce9f7..004b7ff25670b 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/comparison_side.stories.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/field_comparison_side.stories.tsx @@ -7,7 +7,7 @@ import React from 'react'; import type { Story } from '@storybook/react'; -import { ComparisonSide } from './comparison_side'; +import { FieldComparisonSide } from './field_comparison_side'; import type { ThreeWayDiff, DiffableAllFields, @@ -20,7 +20,7 @@ import { KqlQueryType, } from '../../../../../../../common/api/detection_engine'; export default { - component: ComparisonSide, + component: FieldComparisonSide, title: 'Rule Management/Prebuilt Rules/Upgrade Flyout/ThreeWayDiff/ComparisonSide', argTypes: { fieldName: { @@ -44,14 +44,8 @@ interface TemplateProps { resolvedValue?: DiffableAllFields[FieldName]; } -const Template: Story> = (args) => { - return ( - - ); +const Template: Story> = () => { + return ; }; export const NoBaseVersion = Template.bind({}); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/field_comparison_side.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/field_comparison_side.tsx new file mode 100644 index 0000000000000..0b9b37c91e226 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/field_comparison_side.tsx @@ -0,0 +1,61 @@ +/* + * 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 React, { useState } from 'react'; +import { EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui'; +import { VersionsPicker } from './versions_picker/versions_picker'; +import type { Version } from './versions_picker/constants'; +import { SelectedVersions } from './versions_picker/constants'; +import { FieldUpgradeSideHeader } from '../field_upgrade_side_header'; +import { useFieldUpgradeContext } from '../rule_upgrade/field_upgrade_context'; +import { pickFieldValueForVersion } from './utils'; +import { getSubfieldChanges } from './get_subfield_changes'; +import { SubfieldChanges } from './subfield_changes'; +import { ComparisonSideHelpInfo } from './comparison_side_help_info'; +import * as i18n from './translations'; + +export function FieldComparisonSide(): JSX.Element { + const { fieldName, fieldDiff, finalDiffableRule } = useFieldUpgradeContext(); + const resolvedValue = finalDiffableRule[fieldName]; + + const [selectedVersions, setSelectedVersions] = useState( + SelectedVersions.CurrentFinal + ); + + const [oldVersionType, newVersionType] = selectedVersions.split('_') as [Version, Version]; + + const oldFieldValue = pickFieldValueForVersion(oldVersionType, fieldDiff, resolvedValue); + + const newFieldValue = pickFieldValueForVersion(newVersionType, fieldDiff, resolvedValue); + + const subfieldChanges = getSubfieldChanges(fieldName, oldFieldValue, newFieldValue); + + return ( + <> + + + + +

+ {i18n.TITLE} + +

+
+
+ + + +
+
+ + + ); +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/get_subfield_changes/index.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/get_subfield_changes/index.ts index c3628d74176c3..0ac093b895a73 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/get_subfield_changes/index.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/get_subfield_changes/index.ts @@ -28,10 +28,10 @@ import type { SubfieldChanges } from '../types'; * @param newFieldValue - The new value of the field. * @returns - An array of subfield changes. */ -export const getSubfieldChanges = ( - fieldName: FieldName, - oldFieldValue?: DiffableAllFields[FieldName], - newFieldValue?: DiffableAllFields[FieldName] +export const getSubfieldChanges = ( + fieldName: keyof DiffableAllFields, + oldFieldValue: unknown, + newFieldValue: unknown ): SubfieldChanges => { switch (fieldName) { /* diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/subfield_changes.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/subfield_changes.tsx index af10edbe1c599..a5d44438f161c 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/subfield_changes.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/subfield_changes.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React from 'react'; +import React, { Fragment } from 'react'; import { EuiHorizontalRule } from '@elastic/eui'; import type { SubfieldChanges } from './types'; import { Subfield } from './subfield'; @@ -28,16 +28,15 @@ export function SubfieldChanges({ fieldName, subfieldChanges }: SubfieldChangesP const shouldShowSeparator = index !== subfieldChanges.length - 1; return ( - <> + {shouldShowSeparator ? : null} - + ); })} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/utils.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/utils.ts index d0673c460a1d5..8f97d3462d358 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/utils.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/utils.ts @@ -6,11 +6,8 @@ */ import stringify from 'json-stable-stringify'; -import { Version } from '../versions_picker/constants'; -import type { - DiffableAllFields, - ThreeWayDiff, -} from '../../../../../../../common/api/detection_engine'; +import { Version } from './versions_picker/constants'; +import type { ThreeWayDiff } from '../../../../../../../common/api/detection_engine'; /** * Picks the field value for a given version either from a three-way diff object or from a user-set resolved value. @@ -20,11 +17,11 @@ import type { * @param resolvedValue - A value field will be upgraded to. * @returns - The field value for the specified version */ -export function pickFieldValueForVersion( +export function pickFieldValueForVersion( version: Version, - fieldThreeWayDiff: ThreeWayDiff, - resolvedValue: DiffableAllFields[FieldName] -): DiffableAllFields[FieldName] | undefined { + fieldThreeWayDiff: ThreeWayDiff, + resolvedValue: unknown +): unknown { if (version === Version.Final) { return resolvedValue; } diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/versions_picker/constants.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/versions_picker/constants.ts similarity index 70% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/versions_picker/constants.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/versions_picker/constants.ts index 73a7e89a200a3..04d38ed10dce2 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/versions_picker/constants.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/versions_picker/constants.ts @@ -27,32 +27,32 @@ export enum SelectedVersions { export const CURRENT_OPTIONS: EuiSelectOption[] = [ { value: SelectedVersions.CurrentFinal, - text: i18n.CURRENT_VS_FINAL, + text: i18n.VERSION1_VS_VERSION2(i18n.CURRENT_VERSION, i18n.FINAL_VERSION), }, { value: SelectedVersions.CurrentTarget, - text: i18n.CURRENT_VS_TARGET, + text: i18n.VERSION1_VS_VERSION2(i18n.CURRENT_VERSION, i18n.TARGET_VERSION), }, ]; export const TARGET_OPTIONS: EuiSelectOption[] = [ { value: SelectedVersions.TargetFinal, - text: i18n.TARGET_VS_FINAL, + text: i18n.VERSION1_VS_VERSION2(i18n.TARGET_VERSION, i18n.FINAL_VERSION), }, ]; export const BASE_OPTIONS: EuiSelectOption[] = [ { value: SelectedVersions.BaseFinal, - text: i18n.BASE_VS_FINAL, + text: i18n.VERSION1_VS_VERSION2(i18n.BASE_VERSION, i18n.FINAL_VERSION), }, { value: SelectedVersions.BaseTarget, - text: i18n.BASE_VS_TARGET, + text: i18n.VERSION1_VS_VERSION2(i18n.BASE_VERSION, i18n.TARGET_VERSION), }, { value: SelectedVersions.BaseCurrent, - text: i18n.BASE_VS_CURRENT, + text: i18n.VERSION1_VS_VERSION2(i18n.BASE_VERSION, i18n.CURRENT_VERSION), }, ]; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/versions_picker/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/versions_picker/translations.ts new file mode 100644 index 0000000000000..0f63b8be2aa92 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/versions_picker/translations.ts @@ -0,0 +1,56 @@ +/* + * 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 { i18n } from '@kbn/i18n'; + +export const BASE_VERSION = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.versions.baseVersionLabel', + { + defaultMessage: 'Original', + } +); + +export const CURRENT_VERSION = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.versions.currentVersionLabel', + { + defaultMessage: 'Current', + } +); + +export const TARGET_VERSION = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.versions.targetVersionLabel', + { + defaultMessage: 'Elastic update', + } +); + +export const FINAL_VERSION = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.versions.finalVersionLabel', + { + defaultMessage: 'Final', + } +); + +export const VERSION1_VS_VERSION2 = (version1: string, version2: string): string => { + return i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.versionsPicker.version1VsVersion2', + { + defaultMessage: '{version1} vs {version2}', + values: { + version1, + version2, + }, + } + ); +}; + +export const VERSION_PICKER_ARIA_LABEL = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.versionsPicker.ariaLabel', + { + defaultMessage: 'Select versions to compare', + } +); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/versions_picker/versions_picker.stories.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/versions_picker/versions_picker.stories.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/versions_picker/versions_picker.stories.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/versions_picker/versions_picker.stories.tsx diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/versions_picker/versions_picker.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/versions_picker/versions_picker.tsx similarity index 85% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/versions_picker/versions_picker.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/versions_picker/versions_picker.tsx index 572e281ff3ae4..4710667e0b315 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/versions_picker/versions_picker.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/versions_picker/versions_picker.tsx @@ -6,6 +6,7 @@ */ import React, { useCallback, useMemo } from 'react'; +import { css } from '@emotion/css'; import { EuiSelect } from '@elastic/eui'; import type { EuiSelectOption } from '@elastic/eui'; import { BASE_OPTIONS, CURRENT_OPTIONS, TARGET_OPTIONS, SelectedVersions } from './constants'; @@ -36,6 +37,7 @@ export function VersionsPicker({ return ( ); } + +const VERSIONS_PICKER_STYLES = css` + // Set min-width a bit wider than default + // to make English text in narrow screens readable + min-width: 220px; +`; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/field_upgrade_conflicts_resolver.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/field_upgrade_conflicts_resolver.tsx deleted file mode 100644 index 6a2ad17f45f26..0000000000000 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/field_upgrade_conflicts_resolver.tsx +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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 React from 'react'; -import { EuiFlexGroup, EuiFlexItem, EuiSpacer, useEuiTheme } from '@elastic/eui'; -import { css } from '@emotion/css'; -import { SplitAccordion } from '../../../../../../common/components/split_accordion'; -import type { - DiffableAllFields, - RuleFieldsDiff, - ThreeWayDiff, -} from '../../../../../../../common/api/detection_engine'; -import { ThreeWayDiffConflict } from '../../../../../../../common/api/detection_engine'; -import type { FieldUpgradeState } from '../../../../model/prebuilt_rule_upgrade'; -import { ComparisonSide } from '../comparison_side/comparison_side'; -import { FinalSide } from '../final_side/final_side'; -import { FieldUpgradeConflictsResolverHeader } from './field_upgrade_conflicts_resolver_header'; -import { useDiffableRuleContext } from '../diffable_rule_context'; -import type { UpgradeableDiffableFields } from '../../../../model/prebuilt_rule_upgrade/fields'; - -interface FieldUpgradeConflictsResolverProps { - fieldName: FieldName; - fieldUpgradeState: FieldUpgradeState; - fieldThreeWayDiff: RuleFieldsDiff[FieldName]; -} - -export function FieldUpgradeConflictsResolver({ - fieldName, - fieldUpgradeState, - fieldThreeWayDiff, -}: FieldUpgradeConflictsResolverProps): JSX.Element { - const { euiTheme } = useEuiTheme(); - const hasConflict = fieldThreeWayDiff.conflict !== ThreeWayDiffConflict.NONE; - - const { finalDiffableRule } = useDiffableRuleContext(); - - return ( - <> - - } - initialIsOpen={hasConflict} - data-test-subj="ruleUpgradePerFieldDiff" - > - - - } - resolvedValue={finalDiffableRule[fieldName] as DiffableAllFields[FieldName]} - /> - - - - - - - - - - ); -} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/field_upgrade_state_info/field_upgrade_state_info.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/field_upgrade_state_info/field_upgrade_state_info.tsx deleted file mode 100644 index c49fc18e2c6ba..0000000000000 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/field_upgrade_state_info/field_upgrade_state_info.tsx +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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 React from 'react'; -import { EuiIcon, EuiText } from '@elastic/eui'; -import { FieldUpgradeState } from '../../../../../model/prebuilt_rule_upgrade'; -import * as i18n from './translations'; - -interface FieldUpgradeStateInfoProps { - state: FieldUpgradeState; -} - -export function FieldUpgradeStateInfo({ state }: FieldUpgradeStateInfoProps): JSX.Element { - switch (state) { - case FieldUpgradeState.Accepted: - return ( - <> - - -  {i18n.UPDATE_ACCEPTED} - {i18n.SEPARATOR} - {i18n.UPDATE_ACCEPTED_DESCRIPTION} - - - ); - - case FieldUpgradeState.SolvableConflict: - return ( - <> - - -  {i18n.SOLVABLE_CONFLICT} - {i18n.SEPARATOR} - {i18n.SOLVABLE_CONFLICT_DESCRIPTION} - - - ); - - case FieldUpgradeState.NonSolvableConflict: - return ( - <> - - -  {i18n.NON_SOLVABLE_CONFLICT} - {i18n.SEPARATOR} - {i18n.NON_SOLVABLE_CONFLICT_DESCRIPTION} - - - ); - } -} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/rule_upgrade_callout/rule_upgrade_callout.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/rule_upgrade_callout/rule_upgrade_callout.tsx deleted file mode 100644 index 8ab2674524952..0000000000000 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/rule_upgrade_callout/rule_upgrade_callout.tsx +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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 React, { useMemo } from 'react'; -import { EuiCallOut } from '@elastic/eui'; -import type { RuleUpgradeState } from '../../../../../model/prebuilt_rule_upgrade'; -import { FieldUpgradeState } from '../../../../../model/prebuilt_rule_upgrade'; -import * as i18n from './translations'; - -interface RuleUpgradeCalloutProps { - ruleUpgradeState: RuleUpgradeState; -} - -export function RuleUpgradeCallout({ ruleUpgradeState }: RuleUpgradeCalloutProps): JSX.Element { - const fieldsUpgradeState = ruleUpgradeState.fieldsUpgradeState; - const { numOfNonSolvableConflicts, numOfSolvableConflicts } = useMemo(() => { - let numOfFieldsWithNonSolvableConflicts = 0; - let numOfFieldsWithSolvableConflicts = 0; - - for (const fieldName of Object.keys(fieldsUpgradeState)) { - if (fieldsUpgradeState[fieldName] === FieldUpgradeState.NonSolvableConflict) { - numOfFieldsWithNonSolvableConflicts++; - } - - if (fieldsUpgradeState[fieldName] === FieldUpgradeState.SolvableConflict) { - numOfFieldsWithSolvableConflicts++; - } - } - - return { - numOfNonSolvableConflicts: numOfFieldsWithNonSolvableConflicts, - numOfSolvableConflicts: numOfFieldsWithSolvableConflicts, - }; - }, [fieldsUpgradeState]); - - if (numOfNonSolvableConflicts > 0) { - return ( - -

{i18n.RULE_HAS_NON_SOLVABLE_CONFLICTS_DESCRIPTION}

-
- ); - } - - if (numOfSolvableConflicts > 0) { - return ( - -

{i18n.RULE_HAS_SOLVABLE_CONFLICTS_DESCRIPTION}

-
- ); - } - - return ( - -

{i18n.RULE_IS_READY_FOR_UPGRADE_DESCRIPTION}

-
- ); -} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/rule_upgrade_callout/translations.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/rule_upgrade_callout/translations.tsx deleted file mode 100644 index 319884746dbc2..0000000000000 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/rule_upgrade_callout/translations.tsx +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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 { i18n } from '@kbn/i18n'; - -export const RULE_HAS_NON_SOLVABLE_CONFLICTS = (count: number) => - i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.ruleHasNonSolvableConflicts', - { - values: { count }, - defaultMessage: - '{count} of the fields {count, plural, one {has} other {have}} an unsolved conflict. Please review and modify accordingly.', - } - ); - -export const RULE_HAS_NON_SOLVABLE_CONFLICTS_DESCRIPTION = i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.ruleHasNonSolvableConflictsDescription', - { - defaultMessage: - 'Please provide an input for the unsolved conflict. You can also keep the current without the updates, or accept the Elastic update but lose your modifications.', - } -); - -export const RULE_HAS_SOLVABLE_CONFLICTS = (count: number) => - i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.ruleHasSolvableConflicts', - { - values: { count }, - defaultMessage: - '{count} of the fields {count, plural, one {has} other {have}} an update conflict, please review the suggested update being updating.', - } - ); - -export const RULE_HAS_SOLVABLE_CONFLICTS_DESCRIPTION = i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.ruleHasSolvableConflictsDescription', - { - defaultMessage: - 'Please review the suggested updated version before accepting the update. You can edit and then save the field if you wish to change it.', - } -); - -export const RULE_IS_READY_FOR_UPGRADE = i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.ruleIsReadyForUpgrade', - { - defaultMessage: 'The update is ready to be applied.', - } -); - -export const RULE_IS_READY_FOR_UPGRADE_DESCRIPTION = i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.ruleIsReadyForUpgradeDescription', - { - defaultMessage: 'All conflicts have now been reviewed and solved please update the rule.', - } -); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/rule_upgrade_conflicts_resolver.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/rule_upgrade_conflicts_resolver.tsx deleted file mode 100644 index 3379cf2ab3e96..0000000000000 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/rule_upgrade_conflicts_resolver.tsx +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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 React from 'react'; -import type { RuleUpgradeState } from '../../../../model/prebuilt_rule_upgrade'; -import { FieldUpgradeConflictsResolver } from './field_upgrade_conflicts_resolver'; -import type { NonUpgradeableDiffableFields } from '../../../../model/prebuilt_rule_upgrade/fields'; -import { isNonUpgradeableFieldName } from '../../../../model/prebuilt_rule_upgrade/fields'; - -type FieldDiffEntries = Array< - [ - Exclude, - Required[Exclude] - ] ->; - -interface RuleUpgradeConflictsResolverProps { - ruleUpgradeState: RuleUpgradeState; -} - -export function RuleUpgradeConflictsResolver({ - ruleUpgradeState, -}: RuleUpgradeConflictsResolverProps): React.ReactNode { - const fieldDiffEntries = Object.entries(ruleUpgradeState.diff.fields) as FieldDiffEntries< - typeof ruleUpgradeState.diff.fields - >; - - const fields = fieldDiffEntries.filter(([fieldName]) => { - return isNonUpgradeableFieldName(fieldName) === false; - }) as FieldDiffEntries; - - return fields.map(([fieldName, fieldDiff]) => ( - - )); -} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/translations.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/translations.tsx deleted file mode 100644 index 27172cb98755c..0000000000000 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/translations.tsx +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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 React from 'react'; -import { EuiLink } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { useKibana } from '../../../../../../common/lib/kibana/kibana_react'; - -export const NUM_OF_FIELDS_WITH_UPDATES = (count: number) => ( - {count} }} - /> -); - -export const NUM_OF_CONFLICTS = (count: number) => ( - {count} }} - /> -); - -const UPGRADE_RULES_DOCS_LINK = i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.upgradeRules.updateYourRulesDocsLink', - { - defaultMessage: 'update your rules', - } -); - -export function RuleUpgradeHelper(): JSX.Element { - const { - docLinks: { - links: { - securitySolution: { manageDetectionRules }, - }, - }, - } = useKibana().services; - const manageDetectionRulesSnoozeSection = `${manageDetectionRules}#edit-rules-settings`; - - return ( - - {UPGRADE_RULES_DOCS_LINK} - - ), - }} - /> - ); -} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/diffable_rule_context.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/diffable_rule_context.tsx deleted file mode 100644 index 4210b394c7618..0000000000000 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/diffable_rule_context.tsx +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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 React, { createContext, useContext } from 'react'; -import type { DiffableRule } from '../../../../../../common/api/detection_engine'; -import { invariant } from '../../../../../../common/utils/invariant'; -import type { SetRuleFieldResolvedValueFn } from '../../../model/prebuilt_rule_upgrade/set_rule_field_resolved_value'; - -interface DiffableRuleContextType { - finalDiffableRule: DiffableRule; - setRuleFieldResolvedValue: SetRuleFieldResolvedValueFn; -} - -const DiffableRuleContext = createContext(null); - -interface DiffableRuleContextProviderProps { - finalDiffableRule: DiffableRule; - setRuleFieldResolvedValue: SetRuleFieldResolvedValueFn; - children: React.ReactNode; -} - -export function DiffableRuleContextProvider({ - finalDiffableRule, - setRuleFieldResolvedValue, - children, -}: DiffableRuleContextProviderProps) { - const contextValue = { - finalDiffableRule, - setRuleFieldResolvedValue, - }; - - return ( - {children} - ); -} - -export function useDiffableRuleContext() { - const context = useContext(DiffableRuleContext); - - invariant( - context !== null, - 'useDiffableRuleContext must be used inside a DiffableRuleContextProvider' - ); - - return context; -} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/field_final_side/components/field_final_side.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/field_final_side/components/field_final_side.tsx new file mode 100644 index 0000000000000..8a6c312d74db0 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/field_final_side/components/field_final_side.tsx @@ -0,0 +1,20 @@ +/* + * 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 React from 'react'; +import { FieldEditFormContextProvider } from '../context/field_edit_form_context'; +import { FieldFinalSideContent } from './field_final_side_content'; +import { FieldFinalSideHeader } from './field_final_side_header'; + +export function FieldFinalSide(): JSX.Element { + return ( + + + + + ); +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/field_final_side/components/field_final_side_content.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/field_final_side/components/field_final_side_content.tsx new file mode 100644 index 0000000000000..66fcee8547d7f --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/field_final_side/components/field_final_side_content.tsx @@ -0,0 +1,48 @@ +/* + * 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 React from 'react'; +import { EuiButtonEmpty, EuiFlexGroup } from '@elastic/eui'; +import { FieldFinalReadOnly } from '../../final_readonly'; +import { FieldFinalEdit } from '../../final_edit'; +import { assertUnreachable } from '../../../../../../../../common/utility_types'; +import { + FieldFinalSideMode, + useFieldUpgradeContext, +} from '../../rule_upgrade/field_upgrade_context'; +import * as i18n from './translations'; + +export function FieldFinalSideContent(): JSX.Element { + const { rightSideMode, setEditMode, setReadOnlyMode } = useFieldUpgradeContext(); + + switch (rightSideMode) { + case FieldFinalSideMode.Readonly: + return ( + <> + + + {i18n.EDIT} + + + + + ); + case FieldFinalSideMode.Edit: + return ( + <> + + + {i18n.CANCEL} + + + + + ); + default: + return assertUnreachable(rightSideMode); + } +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/field_final_side/components/field_final_side_header.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/field_final_side/components/field_final_side_header.tsx new file mode 100644 index 0000000000000..0e70689b7c9db --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/field_final_side/components/field_final_side_header.tsx @@ -0,0 +1,87 @@ +/* + * 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 type { PropsWithChildren } from 'react'; +import React, { useCallback } from 'react'; +import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui'; +import type { DiffableAllFields } from '../../../../../../../../common/api/detection_engine'; +import { FieldUpgradeSideHeader } from '../../field_upgrade_side_header'; +import { assertUnreachable } from '../../../../../../../../common/utility_types'; +import { + FieldFinalSideMode, + useFieldUpgradeContext, +} from '../../rule_upgrade/field_upgrade_context'; +import { useFieldEditFormContext } from '../context/field_edit_form_context'; +import { FieldFinalSideHelpInfo } from './field_final_side_help_info'; +import * as i18n from './translations'; + +export function FieldFinalSideHeader(): JSX.Element { + const { fieldName, hasConflict, rightSideMode, finalDiffableRule, setRuleFieldResolvedValue } = + useFieldUpgradeContext(); + const { form } = useFieldEditFormContext(); + + const handleAccept = useCallback( + () => + setRuleFieldResolvedValue({ + ruleId: finalDiffableRule.rule_id, + fieldName: fieldName as keyof DiffableAllFields, + resolvedValue: finalDiffableRule[fieldName] as DiffableAllFields[typeof fieldName], + }), + [finalDiffableRule, fieldName, setRuleFieldResolvedValue] + ); + const handleSave = useCallback(() => form?.submit(), [form]); + + switch (rightSideMode) { + case FieldFinalSideMode.Readonly: + return ( + + + {hasConflict && ( + + {i18n.ACCEPT} + + )} + + + ); + case FieldFinalSideMode.Edit: + return ( + + + + {hasConflict ? i18n.SAVE_AND_ACCEPT : i18n.SAVE} + + + + ); + default: + return assertUnreachable(rightSideMode); + } +} + +function StaticHeaderContent({ children }: PropsWithChildren<{}>): JSX.Element { + return ( + + + + +

+ {i18n.FINAL_UPDATE} + +

+
+
+
+ {children} +
+ ); +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_side/final_side_help_info.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/field_final_side/components/field_final_side_help_info.tsx similarity index 93% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_side/final_side_help_info.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/field_final_side/components/field_final_side_help_info.tsx index 51e0c5097b97d..e3e0b38da7d63 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_side/final_side_help_info.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/field_final_side/components/field_final_side_help_info.tsx @@ -19,7 +19,7 @@ import { FormattedMessage } from '@kbn/i18n-react'; */ const POPOVER_WIDTH = 320; -export function FinalSideHelpInfo(): JSX.Element { +export function FieldFinalSideHelpInfo(): JSX.Element { const [isPopoverOpen, togglePopover] = useToggle(false); const button = ( @@ -34,7 +34,7 @@ export function FinalSideHelpInfo(): JSX.Element { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/rule_field_edit_component_props.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/field_final_side/components/rule_field_edit_component_props.ts similarity index 100% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/rule_field_edit_component_props.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/field_final_side/components/rule_field_edit_component_props.ts diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/rule_field_edit_form_wrapper.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/field_final_side/components/rule_field_edit_form_wrapper.tsx similarity index 81% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/rule_field_edit_form_wrapper.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/field_final_side/components/rule_field_edit_form_wrapper.tsx index a5f7eedc6114c..ab12f62cfa27b 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/rule_field_edit_form_wrapper.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/field_final_side/components/rule_field_edit_form_wrapper.tsx @@ -6,7 +6,6 @@ */ import React, { useCallback, useEffect } from 'react'; -import { EuiButtonEmpty, EuiFlexGroup } from '@elastic/eui'; import { extractValidationMessages } from '../../../../../../rule_creation/logic/extract_validation_messages'; import type { FormWithWarningsSubmitHandler } from '../../../../../../../common/hooks/use_form_with_warnings'; import { useFormWithWarnings } from '../../../../../../../common/hooks/use_form_with_warnings'; @@ -16,9 +15,8 @@ import type { DiffableAllFields, DiffableRule, } from '../../../../../../../../common/api/detection_engine'; -import { useFinalSideContext } from '../../final_side/final_side_context'; -import { useDiffableRuleContext } from '../../diffable_rule_context'; -import * as i18n from '../../translations'; +import { useFieldUpgradeContext } from '../../rule_upgrade/field_upgrade_context'; +import { useFieldEditFormContext } from '../context/field_edit_form_context'; import type { RuleFieldEditComponentProps } from './rule_field_edit_component_props'; import { useConfirmValidationErrorsModal } from '../../../../../../../common/hooks/use_confirm_validation_errors_modal'; import { @@ -55,8 +53,9 @@ export function RuleFieldEditFormWrapper({ deserializer, serializer, }: RuleFieldEditFormWrapperProps) { - const { fieldName, setReadOnlyMode } = useFinalSideContext(); - const { finalDiffableRule, setRuleFieldResolvedValue } = useDiffableRuleContext(); + const { registerForm } = useFieldEditFormContext(); + const { fieldName, finalDiffableRule, setReadOnlyMode, setRuleFieldResolvedValue } = + useFieldUpgradeContext(); const deserialize = useCallback( (defaultValue: FormData): FormData => @@ -104,6 +103,8 @@ export function RuleFieldEditFormWrapper({ }, }); + useEffect(() => registerForm(form), [registerForm, form]); + // form.isValid has `undefined` value until all fields are dirty. // Run the validation upfront to visualize form validity state. useEffect(() => { @@ -111,24 +112,14 @@ export function RuleFieldEditFormWrapper({ }, [form]); return ( - <> - - - {i18n.CANCEL_BUTTON_LABEL} - - - {i18n.SAVE_BUTTON_LABEL} - - +
{modal} - - - - + + ); } diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/field_final_side/components/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/field_final_side/components/translations.ts new file mode 100644 index 0000000000000..4c44629bf4268 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/field_final_side/components/translations.ts @@ -0,0 +1,50 @@ +/* + * 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 { i18n } from '@kbn/i18n'; + +export const FINAL_UPDATE = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.finalUpdate', + { + defaultMessage: 'Final update', + } +); + +export const SAVE = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.field.save', + { + defaultMessage: 'Save', + } +); + +export const ACCEPT = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.field.accept', + { + defaultMessage: 'Accept', + } +); + +export const SAVE_AND_ACCEPT = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.field.saveAndAccept', + { + defaultMessage: 'Save and accept', + } +); + +export const CANCEL = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.cancelButtonLabel', + { + defaultMessage: 'Cancel', + } +); + +export const EDIT = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.editButtonLabel', + { + defaultMessage: 'Edit', + } +); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/field_final_side/context/field_edit_form_context.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/field_final_side/context/field_edit_form_context.tsx new file mode 100644 index 0000000000000..ba722107e8b9e --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/field_final_side/context/field_edit_form_context.tsx @@ -0,0 +1,75 @@ +/* + * 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 React, { + createContext, + useContext, + type PropsWithChildren, + useState, + useCallback, + useRef, +} from 'react'; +import type { FormHook } from '../../../../../../../shared_imports'; +import { invariant } from '../../../../../../../../common/utils/invariant'; + +type FieldEditFormCleanUp = () => void; + +interface FieldEditFormContextType { + form: FormHook | undefined; + registerForm: (form: FormHook) => FieldEditFormCleanUp; +} + +const FieldEditFormContext = createContext(null); + +/** + * FieldEditFormContext helps to encapsulate form related logic in `field_final_side` folder. + * + * The only purpose is to obtain the recent form handler and provide it for consumers in + * in the `field_final_side` folder. + */ +export function FieldEditFormContextProvider({ children }: PropsWithChildren<{}>) { + // Using reference reduces unnecessary re-renders though we need to re-render children + // whenever something in the form changes like validity state to be able to reflect that changes. + const formRef = useRef(); + // Setting the state re-renders the component and its children. The state value is ignored since + // we use a ref here. In that case it doesn't re-render components upon form cleanup. In that case + // the edit component disappears and we aren't interested in the form's state anymore. + const [, setForm] = useState(); + const registerForm = useCallback( + (formToRegister: FormHook) => { + // Guard against subtle bugs. In attempt of using two forms throw an exception. + if (formRef.current) { + throw new Error( + 'Unexpected new form registration while the old one was not cleaned. Do you properly cleanup form by returning registerForm result from useEffect.' + ); + } + + formRef.current = formToRegister; + setForm(formToRegister); + + return () => (formRef.current = undefined); + }, + [formRef, setForm] + ); + + return ( + + {children} + + ); +} + +export function useFieldEditFormContext() { + const context = useContext(FieldEditFormContext); + + invariant( + context !== null, + 'useFieldEditFormContext must be used inside a FieldEditFormProvider' + ); + + return context; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_side/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/field_final_side/index.ts similarity index 55% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_side/translations.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/field_final_side/index.ts index 8f6a10b5681be..bcab35a1c27b1 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_side/translations.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/field_final_side/index.ts @@ -5,11 +5,6 @@ * 2.0. */ -import { i18n } from '@kbn/i18n'; - -export const FINAL_UPDATE = i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.upgradeRules.finalUpdate', - { - defaultMessage: 'Final update', - } -); +export * from './components/field_final_side'; +export type * from './components/rule_field_edit_component_props'; +export * from './components/rule_field_edit_form_wrapper'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/side_header.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/field_upgrade_side_header.tsx similarity index 90% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/side_header.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/field_upgrade_side_header.tsx index 574e3f526f856..3e0e60d3c4edf 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/side_header.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/field_upgrade_side_header.tsx @@ -10,7 +10,7 @@ import React from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiHorizontalRule, useEuiTheme } from '@elastic/eui'; import { css } from '@emotion/css'; -export function SideHeader({ children }: PropsWithChildren<{}>) { +export function FieldUpgradeSideHeader({ children }: PropsWithChildren<{}>) { const { euiTheme } = useEuiTheme(); return ( diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/common_rule_field_edit.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/common_rule_field_edit.tsx index 3f10ce014d82e..0b8668e90a903 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/common_rule_field_edit.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/common_rule_field_edit.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { RuleFieldEditFormWrapper } from './fields/rule_field_edit_form_wrapper'; +import { RuleFieldEditFormWrapper } from '../field_final_side'; import type { UpgradeableCommonFields } from '../../../../model/prebuilt_rule_upgrade/fields'; import { BuildingBlockEdit, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/final_edit.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/field_final_edit.tsx similarity index 86% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/final_edit.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/field_final_edit.tsx index 13bc3daa56037..542e9aabcddd2 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/final_edit.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/field_final_edit.tsx @@ -7,13 +7,6 @@ import React from 'react'; import { assertUnreachable } from '../../../../../../../common/utility_types'; -import { useDiffableRuleContext } from '../diffable_rule_context'; -import { CommonRuleFieldEdit } from './common_rule_field_edit'; -import { CustomQueryRuleFieldEdit } from './custom_query_rule_field_edit'; -import { SavedQueryRuleFieldEdit } from './saved_query_rule_field_edit'; -import { ThreatMatchRuleFieldEdit } from './threat_match_rule_field_edit'; -import { ThresholdRuleFieldEdit } from './threshold_rule_field_edit'; -import { NewTermsRuleFieldEdit } from './new_terms_rule_field_edit'; import type { UpgradeableCustomQueryFields, UpgradeableSavedQueryFields, @@ -25,22 +18,28 @@ import type { UpgradeableMachineLearningFields, } from '../../../../model/prebuilt_rule_upgrade/fields'; import { isCommonFieldName } from '../../../../model/prebuilt_rule_upgrade/fields'; -import { useFinalSideContext } from '../final_side/final_side_context'; +import { useFieldUpgradeContext } from '../rule_upgrade/field_upgrade_context'; +import { CommonRuleFieldEdit } from './common_rule_field_edit'; +import { CustomQueryRuleFieldEdit } from './custom_query_rule_field_edit'; +import { SavedQueryRuleFieldEdit } from './saved_query_rule_field_edit'; +import { ThreatMatchRuleFieldEdit } from './threat_match_rule_field_edit'; +import { ThresholdRuleFieldEdit } from './threshold_rule_field_edit'; +import { NewTermsRuleFieldEdit } from './new_terms_rule_field_edit'; import { EqlRuleFieldEdit } from './eql_rule_field_edit'; import { EsqlRuleFieldEdit } from './esql_rule_field_edit'; import { MachineLearningRuleFieldEdit } from './machine_learning_rule_field_edit'; -export function FinalEdit() { - const { finalDiffableRule } = useDiffableRuleContext(); - const { type } = finalDiffableRule; - - const { fieldName } = useFinalSideContext(); +export function FieldFinalEdit(): JSX.Element { + const { + fieldName, + finalDiffableRule: { type: ruleType }, + } = useFieldUpgradeContext(); if (isCommonFieldName(fieldName)) { return ; } - switch (type) { + switch (ruleType) { case 'query': return ; case 'saved_query': @@ -60,6 +59,6 @@ export function FinalEdit() { case 'new_terms': return ; default: - return assertUnreachable(type); + return assertUnreachable(ruleType); } } diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/alert_suppression/suppression_edit_adapter.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/alert_suppression/suppression_edit_adapter.tsx index 6dfd38d5676d3..3100e5c21f8bb 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/alert_suppression/suppression_edit_adapter.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/alert_suppression/suppression_edit_adapter.tsx @@ -11,7 +11,7 @@ import { getTermsAggregationFields } from '../../../../../../../rule_creation_ui import { isEsqlRule, isMlRule } from '../../../../../../../../../common/detection_engine/utils'; import { useAllEsqlRuleFields } from '../../../../../../../rule_creation_ui/hooks'; import { useMLRuleConfig } from '../../../../../../../../common/components/ml/hooks/use_ml_rule_config'; -import type { RuleFieldEditComponentProps } from '../rule_field_edit_component_props'; +import type { RuleFieldEditComponentProps } from '../../../field_final_side'; import { useDiffableRuleDataView } from '../hooks/use_diffable_rule_data_view'; import * as i18n from './translations'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/alert_suppression/suppression_edit_form.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/alert_suppression/suppression_edit_form.tsx index f6ed2e5c657c7..e01db6f428887 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/alert_suppression/suppression_edit_form.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/alert_suppression/suppression_edit_form.tsx @@ -17,7 +17,7 @@ import { AlertSuppressionDurationType } from '../../../../../../../../detections import { type FormData } from '../../../../../../../../shared_imports'; import { DEFAULT_SUPPRESSION_MISSING_FIELDS_STRATEGY } from '../../../../../../../../../common/detection_engine/constants'; import { type AlertSuppression } from '../../../../../../../../../common/api/detection_engine'; -import { RuleFieldEditFormWrapper } from '../rule_field_edit_form_wrapper'; +import { RuleFieldEditFormWrapper } from '../../../field_final_side'; import { AlertSuppressionEditAdapter } from './suppression_edit_adapter'; import { alertSuppressionFormSchema, type AlertSuppressionFormData } from './form_schema'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/data_source_edit.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/data_source_edit.tsx index 2f697288221cf..7ff2b7fdbd6fd 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/data_source_edit.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/data_source_edit.tsx @@ -11,7 +11,7 @@ import { css } from '@emotion/css'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { DataSourceType } from '../../../../../../../../../common/api/detection_engine/prebuilt_rules'; import { UseMultiFields } from '../../../../../../../../shared_imports'; -import type { RuleFieldEditComponentProps } from '../rule_field_edit_component_props'; +import type { RuleFieldEditComponentProps } from '../../../field_final_side'; import { IndexPatternField } from './index_pattern_edit'; import { DataSourceInfoText } from './data_source_info_text'; import { DataViewField } from './data_view_field'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/data_source_edit_form.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/data_source_edit_form.tsx index e30b713908a02..ec9e49bb7ab17 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/data_source_edit_form.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/data_source_edit_form.tsx @@ -16,7 +16,7 @@ import { FIELD_TYPES, } from '../../../../../../../../shared_imports'; import { DataSourceType } from '../../../../../../../../../common/api/detection_engine/prebuilt_rules'; -import { RuleFieldEditFormWrapper } from '../rule_field_edit_form_wrapper'; +import { RuleFieldEditFormWrapper } from '../../../field_final_side'; import { DataSourceEdit } from './data_source_edit'; import { INDEX_HELPER_TEXT } from '../../../../../../../rule_creation_ui/components/step_define_rule/translations'; import * as i18n from './translations'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/data_source_type_selector_field.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/data_source_type_selector_field.tsx index 9e24fd6c56c77..3562e7de82d66 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/data_source_type_selector_field.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/data_source/data_source_type_selector_field.tsx @@ -10,7 +10,7 @@ import type { EuiButtonGroupOptionProps } from '@elastic/eui'; import { EuiButtonGroup } from '@elastic/eui'; import { DataSourceType } from '../../../../../../../../../common/api/detection_engine/prebuilt_rules'; import type { FieldHook } from '../../../../../../../../shared_imports'; -import type { ResetFormFn } from '../rule_field_edit_component_props'; +import type { ResetFormFn } from '../../../field_final_side'; import * as i18n from './translations'; interface DataSourceTypeSelectorFieldProps { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/eql_query/eql_query_edit_adapter.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/eql_query/eql_query_edit_adapter.tsx index cea9b9308c0df..73e7c553c9127 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/eql_query/eql_query_edit_adapter.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/eql_query/eql_query_edit_adapter.tsx @@ -8,7 +8,7 @@ import React from 'react'; import type { DataViewBase } from '@kbn/es-query'; import { EqlQueryEdit } from '../../../../../../../rule_creation/components/eql_query_edit'; -import type { RuleFieldEditComponentProps } from '../rule_field_edit_component_props'; +import type { RuleFieldEditComponentProps } from '../../../field_final_side'; import { useDiffableRuleDataView } from '../hooks/use_diffable_rule_data_view'; export function EqlQueryEditAdapter({ diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/eql_query/eql_query_edit_form.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/eql_query/eql_query_edit_form.tsx index 4dd953006d39c..f357504af76f0 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/eql_query/eql_query_edit_form.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/eql_query/eql_query_edit_form.tsx @@ -10,7 +10,7 @@ import type { Filter } from '@kbn/es-query'; import type { EqlOptions } from '@kbn/timelines-plugin/common'; import type { FieldValueQueryBar } from '../../../../../../../rule_creation_ui/components/query_bar_field'; import type { FormData, FormSchema } from '../../../../../../../../shared_imports'; -import { RuleFieldEditFormWrapper } from '../rule_field_edit_form_wrapper'; +import { RuleFieldEditFormWrapper } from '../../../field_final_side'; import { type DiffableRule, RuleEqlQuery, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/esql_query/esql_query_edit_adapter.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/esql_query/esql_query_edit_adapter.tsx index faf43d5b88b22..a3b1faf667d99 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/esql_query/esql_query_edit_adapter.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/esql_query/esql_query_edit_adapter.tsx @@ -7,8 +7,8 @@ import React from 'react'; import type { DataViewBase } from '@kbn/es-query'; +import type { RuleFieldEditComponentProps } from '../../../field_final_side'; import { EsqlQueryEdit } from '../../../../../../../rule_creation/components/esql_query_edit'; -import type { RuleFieldEditComponentProps } from '../rule_field_edit_component_props'; import { useDiffableRuleDataView } from '../hooks/use_diffable_rule_data_view'; export function EsqlQueryEditAdapter({ diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/esql_query/esql_query_edit_form.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/esql_query/esql_query_edit_form.tsx index a156ef747aedc..dd482b6962d8a 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/esql_query/esql_query_edit_form.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/esql_query/esql_query_edit_form.tsx @@ -7,7 +7,7 @@ import React from 'react'; import type { FormData, FormSchema } from '../../../../../../../../shared_imports'; -import { RuleFieldEditFormWrapper } from '../rule_field_edit_form_wrapper'; +import { RuleFieldEditFormWrapper } from '../../../field_final_side'; import type { FieldValueQueryBar } from '../../../../../../../rule_creation_ui/components/query_bar_field'; import { type DiffableRule, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/kql_query/kql_query_edit.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/kql_query/kql_query_edit.tsx index 27415855adfbe..f377e17d8e23b 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/kql_query/kql_query_edit.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/kql_query/kql_query_edit.tsx @@ -18,7 +18,7 @@ import type { DiffableRule } from '../../../../../../../../../common/api/detecti import type { SetRuleQuery } from '../../../../../../../../detections/containers/detection_engine/rules/use_rule_from_timeline'; import { useRuleFromTimeline } from '../../../../../../../../detections/containers/detection_engine/rules/use_rule_from_timeline'; import { useGetSavedQuery } from '../../../../../../../../detections/pages/detection_engine/rules/use_get_saved_query'; -import type { RuleFieldEditComponentProps } from '../rule_field_edit_component_props'; +import type { RuleFieldEditComponentProps } from '../../../field_final_side'; import { useDiffableRuleDataView } from '../hooks/use_diffable_rule_data_view'; export function KqlQueryEdit({ diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/kql_query/kql_query_edit_form.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/kql_query/kql_query_edit_form.tsx index 98ffc4b6bfdf0..a02fa9b9fd9d4 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/kql_query/kql_query_edit_form.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/kql_query/kql_query_edit_form.tsx @@ -9,8 +9,8 @@ import React from 'react'; import type { Type } from '@kbn/securitysolution-io-ts-alerting-types'; import type { FormData, FormSchema } from '../../../../../../../../shared_imports'; import { schema } from '../../../../../../../rule_creation_ui/components/step_define_rule/schema'; -import { RuleFieldEditFormWrapper } from '../rule_field_edit_form_wrapper'; import type { FieldValueQueryBar } from '../../../../../../../rule_creation_ui/components/query_bar_field'; +import { RuleFieldEditFormWrapper } from '../../../field_final_side'; import { KqlQueryLanguage, KqlQueryType, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/threshold_alert_suppression/suppression_edit_form.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/threshold_alert_suppression/suppression_edit_form.tsx index af9f9db00cff2..0d4be2e421a5c 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/threshold_alert_suppression/suppression_edit_form.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/threshold_alert_suppression/suppression_edit_form.tsx @@ -13,12 +13,12 @@ import { import { ALERT_SUPPRESSION_DURATION_FIELD_NAME } from '../../../../../../../rule_creation/components/alert_suppression_edit'; import { type FormData } from '../../../../../../../../shared_imports'; import type { ThresholdAlertSuppression } from '../../../../../../../../../common/api/detection_engine'; -import { RuleFieldEditFormWrapper } from '../rule_field_edit_form_wrapper'; +import { RuleFieldEditFormWrapper } from '../../../field_final_side'; import { thresholdAlertSuppressionFormSchema, type ThresholdAlertSuppressionFormData, } from './form_schema'; -import type { RuleFieldEditComponentProps } from '../rule_field_edit_component_props'; +import type { RuleFieldEditComponentProps } from '../../../field_final_side'; export function ThresholdAlertSuppressionEditForm(): JSX.Element { return ( diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/rule_upgrade_callout/index.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/index.ts similarity index 86% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/rule_upgrade_callout/index.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/index.ts index 75ff48ff541a1..cc252595beee6 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/rule_upgrade_callout/index.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/index.ts @@ -5,4 +5,4 @@ * 2.0. */ -export * from './rule_upgrade_callout'; +export * from './field_final_edit'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/field_readonly.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/field_final_readonly.tsx similarity index 93% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/field_readonly.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/field_final_readonly.tsx index ecaec5af0f54a..33abbb4792946 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/field_readonly.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/field_final_readonly.tsx @@ -18,6 +18,7 @@ import type { DiffableMachineLearningFields, } from '../../../../../../../common/api/detection_engine'; import { assertUnreachable } from '../../../../../../../common/utility_types'; +import { useFieldUpgradeContext } from '../rule_upgrade/field_upgrade_context'; import { CustomQueryRuleFieldReadOnly } from './custom_query_rule_field_readonly'; import { SavedQueryRuleFieldReadOnly } from './saved_query_rule_field_readonly'; import { EqlRuleFieldReadOnly } from './eql_rule_field_readonly'; @@ -27,14 +28,9 @@ import { ThresholdRuleFieldReadOnly } from './threshold_rule_field_readonly'; import { MachineLearningRuleFieldReadOnly } from './machine_learning_rule_field_readonly'; import { NewTermsRuleFieldReadOnly } from './new_terms_rule_field_readonly'; import { CommonRuleFieldReadOnly } from './common_rule_field_readonly'; -import { useDiffableRuleContext } from '../diffable_rule_context'; -interface FieldReadOnlyProps { - fieldName: string; -} - -export function FieldReadOnly({ fieldName }: FieldReadOnlyProps) { - const { finalDiffableRule } = useDiffableRuleContext(); +export function FieldFinalReadOnly(): JSX.Element { + const { fieldName, finalDiffableRule } = useFieldUpgradeContext(); const { data: commonField } = useMemo( () => DiffableCommonFields.keyof().safeParse(fieldName), diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/alert_suppression/alert_suppression.stories.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/alert_suppression/alert_suppression.stories.tsx index 9aeeee25983d3..9cebd044dad63 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/alert_suppression/alert_suppression.stories.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/alert_suppression/alert_suppression.stories.tsx @@ -8,7 +8,7 @@ import React from 'react'; import type { Story } from '@storybook/react'; import { AlertSuppressionReadOnly } from './alert_suppression'; -import { FieldReadOnly } from '../../field_readonly'; +import { FieldFinalReadOnly } from '../../field_final_readonly'; import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine'; import { mockCustomQueryRule } from '../../storybook/mocks'; import { ThreeWayDiffStorybookProviders } from '../../storybook/three_way_diff_storybook_providers'; @@ -25,8 +25,11 @@ interface TemplateProps { const Template: Story = (args) => { return ( - - + + ); }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/anomaly_threshold/anomaly_threshold.stories.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/anomaly_threshold/anomaly_threshold.stories.tsx index 392187941046c..0f7ce369a117d 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/anomaly_threshold/anomaly_threshold.stories.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/anomaly_threshold/anomaly_threshold.stories.tsx @@ -8,7 +8,7 @@ import React from 'react'; import type { Story } from '@storybook/react'; import { AnomalyThresholdReadOnly } from './anomaly_threshold'; -import { FieldReadOnly } from '../../field_readonly'; +import { FieldFinalReadOnly } from '../../field_final_readonly'; import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine'; import { mockMachineLearningRule } from '../../storybook/mocks'; import { ThreeWayDiffStorybookProviders } from '../../storybook/three_way_diff_storybook_providers'; @@ -25,8 +25,11 @@ interface TemplateProps { const Template: Story = (args) => { return ( - - + + ); }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/building_block/building_block.stories.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/building_block/building_block.stories.tsx index 6bace209f283b..7112e63a313d8 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/building_block/building_block.stories.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/building_block/building_block.stories.tsx @@ -8,7 +8,7 @@ import React from 'react'; import type { Story } from '@storybook/react'; import { BuildingBlockReadOnly } from './building_block'; -import { FieldReadOnly } from '../../field_readonly'; +import { FieldFinalReadOnly } from '../../field_final_readonly'; import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine'; import { mockCustomQueryRule } from '../../storybook/mocks'; import { ThreeWayDiffStorybookProviders } from '../../storybook/three_way_diff_storybook_providers'; @@ -24,8 +24,11 @@ interface TemplateProps { const Template: Story = (args) => { return ( - - + + ); }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/data_source/data_source.stories.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/data_source/data_source.stories.tsx index d7bf26bc7d9ba..93f71afefb902 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/data_source/data_source.stories.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/data_source/data_source.stories.tsx @@ -7,7 +7,7 @@ import React from 'react'; import type { Story } from '@storybook/react'; -import { FieldReadOnly } from '../../field_readonly'; +import { FieldFinalReadOnly } from '../../field_final_readonly'; import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine'; import { ThreeWayDiffStorybookProviders } from '../../storybook/three_way_diff_storybook_providers'; import { @@ -18,7 +18,7 @@ import { } from '../../storybook/mocks'; export default { - component: FieldReadOnly, + component: FieldFinalReadOnly, title: 'Rule Management/Prebuilt Rules/Upgrade Flyout/ThreeWayDiff/FieldReadOnly/data_source', }; @@ -32,8 +32,9 @@ const Template: Story = (args) => { - + ); }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/description/description.stories.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/description/description.stories.tsx index 079c327fb29ef..de7df1f7fbfbf 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/description/description.stories.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/description/description.stories.tsx @@ -8,7 +8,7 @@ import React from 'react'; import type { Story } from '@storybook/react'; import { DescriptionReadOnly } from './description'; -import { FieldReadOnly } from '../../field_readonly'; +import { FieldFinalReadOnly } from '../../field_final_readonly'; import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine'; import { mockCustomQueryRule } from '../../storybook/mocks'; import { ThreeWayDiffStorybookProviders } from '../../storybook/three_way_diff_storybook_providers'; @@ -24,8 +24,11 @@ interface TemplateProps { const Template: Story = (args) => { return ( - - + + ); }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/eql_query/eql_query.stories.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/eql_query/eql_query.stories.tsx index 8ee0ac1511784..bad23cba21e2e 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/eql_query/eql_query.stories.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/eql_query/eql_query.stories.tsx @@ -7,7 +7,7 @@ import React from 'react'; import type { Story } from '@storybook/react'; -import { FieldReadOnly } from '../../field_readonly'; +import { FieldFinalReadOnly } from '../../field_final_readonly'; import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine'; import { ThreeWayDiffStorybookProviders } from '../../storybook/three_way_diff_storybook_providers'; import { EqlQueryReadOnly } from './eql_query'; @@ -34,8 +34,9 @@ const Template: Story = (args) => { - + ); }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/esql_query/esql_query.stories.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/esql_query/esql_query.stories.tsx index 70f37106842e1..81b692bfc4e9b 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/esql_query/esql_query.stories.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/esql_query/esql_query.stories.tsx @@ -7,13 +7,13 @@ import React from 'react'; import type { Story } from '@storybook/react'; -import { FieldReadOnly } from '../../field_readonly'; +import { FieldFinalReadOnly } from '../../field_final_readonly'; import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine'; import { mockEsqlRule } from '../../storybook/mocks'; import { ThreeWayDiffStorybookProviders } from '../../storybook/three_way_diff_storybook_providers'; export default { - component: FieldReadOnly, + component: FieldFinalReadOnly, title: 'Rule Management/Prebuilt Rules/Upgrade Flyout/ThreeWayDiff/FieldReadOnly/esql_query', }; @@ -23,8 +23,11 @@ interface TemplateProps { const Template: Story = (args) => { return ( - - + + ); }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/false_positives/false_positives.stories.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/false_positives/false_positives.stories.tsx index a5884b340e32b..a3f2defba2ec9 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/false_positives/false_positives.stories.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/false_positives/false_positives.stories.tsx @@ -8,7 +8,7 @@ import React from 'react'; import type { Story } from '@storybook/react'; import { FalsePositivesReadOnly } from './false_positives'; -import { FieldReadOnly } from '../../field_readonly'; +import { FieldFinalReadOnly } from '../../field_final_readonly'; import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine'; import { mockCustomQueryRule } from '../../storybook/mocks'; import { ThreeWayDiffStorybookProviders } from '../../storybook/three_way_diff_storybook_providers'; @@ -24,8 +24,11 @@ interface TemplateProps { const Template: Story = (args) => { return ( - - + + ); }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/history_window_start/history_window_start.stories.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/history_window_start/history_window_start.stories.tsx index 12e0f086ecec9..da87cf2c04eb0 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/history_window_start/history_window_start.stories.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/history_window_start/history_window_start.stories.tsx @@ -8,7 +8,7 @@ import React from 'react'; import type { Story } from '@storybook/react'; import { HistoryWindowStartReadOnly } from './history_window_start'; -import { FieldReadOnly } from '../../field_readonly'; +import { FieldFinalReadOnly } from '../../field_final_readonly'; import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine'; import { mockNewTermsRule } from '../../storybook/mocks'; import { ThreeWayDiffStorybookProviders } from '../../storybook/three_way_diff_storybook_providers'; @@ -25,8 +25,11 @@ interface TemplateProps { const Template: Story = (args) => { return ( - - + + ); }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/investigation_fields/investigation_fields.stories.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/investigation_fields/investigation_fields.stories.tsx index a32c79076a03d..400e7fd5ccba9 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/investigation_fields/investigation_fields.stories.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/investigation_fields/investigation_fields.stories.tsx @@ -8,7 +8,7 @@ import React from 'react'; import type { Story } from '@storybook/react'; import { InvestigationFieldsReadOnly } from './investigation_fields'; -import { FieldReadOnly } from '../../field_readonly'; +import { FieldFinalReadOnly } from '../../field_final_readonly'; import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine'; import { mockCustomQueryRule } from '../../storybook/mocks'; import { ThreeWayDiffStorybookProviders } from '../../storybook/three_way_diff_storybook_providers'; @@ -25,8 +25,11 @@ interface TemplateProps { const Template: Story = (args) => { return ( - - + + ); }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/kql_query/kql_query.stories.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/kql_query/kql_query.stories.tsx index 16731ec498162..500999fea6c4f 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/kql_query/kql_query.stories.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/kql_query/kql_query.stories.tsx @@ -7,7 +7,7 @@ import React from 'react'; import type { Story } from '@storybook/react'; -import { FieldReadOnly } from '../../field_readonly'; +import { FieldFinalReadOnly } from '../../field_final_readonly'; import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine'; import { ThreeWayDiffStorybookProviders } from '../../storybook/three_way_diff_storybook_providers'; import { @@ -22,7 +22,7 @@ import { } from '../../storybook/mocks'; export default { - component: FieldReadOnly, + component: FieldFinalReadOnly, title: 'Rule Management/Prebuilt Rules/Upgrade Flyout/ThreeWayDiff/FieldReadOnly/kql_query', }; @@ -36,8 +36,9 @@ const Template: Story = (args) => { - + ); }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/machine_learning_job_id/machine_learning_job_id.stories.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/machine_learning_job_id/machine_learning_job_id.stories.tsx index ea23aa5984106..35d90a26fdfde 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/machine_learning_job_id/machine_learning_job_id.stories.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/machine_learning_job_id/machine_learning_job_id.stories.tsx @@ -10,7 +10,7 @@ import { useQueryClient } from '@tanstack/react-query'; import type { Story } from '@storybook/react'; import { MachineLearningJobIdReadOnly } from './machine_learning_job_id'; import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine'; -import { FieldReadOnly } from '../../field_readonly'; +import { FieldFinalReadOnly } from '../../field_final_readonly'; import { ThreeWayDiffStorybookProviders } from '../../storybook/three_way_diff_storybook_providers'; import { GET_MODULES_QUERY_KEY } from '../../../../../../../../common/components/ml_popover/hooks/use_fetch_modules_query'; import { GET_RECOGNIZER_QUERY_KEY } from '../../../../../../../../common/components/ml_popover/hooks/use_fetch_recognizer_query'; @@ -64,9 +64,12 @@ interface TemplateProps { const Template: Story = (args) => { return ( - + - + ); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/max_signals/max_signals.stories.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/max_signals/max_signals.stories.tsx index 3c7945366a174..6959a5c391649 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/max_signals/max_signals.stories.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/max_signals/max_signals.stories.tsx @@ -8,7 +8,7 @@ import React from 'react'; import type { Story } from '@storybook/react'; import { MaxSignalsReadOnly } from './max_signals'; -import { FieldReadOnly } from '../../field_readonly'; +import { FieldFinalReadOnly } from '../../field_final_readonly'; import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine'; import { mockCustomQueryRule } from '../../storybook/mocks'; import { ThreeWayDiffStorybookProviders } from '../../storybook/three_way_diff_storybook_providers'; @@ -24,8 +24,11 @@ interface TemplateProps { const Template: Story = (args) => { return ( - - + + ); }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/name/name.stories.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/name/name.stories.tsx index d97f71b4df0ac..137b34f851a27 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/name/name.stories.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/name/name.stories.tsx @@ -8,7 +8,7 @@ import React from 'react'; import type { Story } from '@storybook/react'; import { NameReadOnly } from './name'; -import { FieldReadOnly } from '../../field_readonly'; +import { FieldFinalReadOnly } from '../../field_final_readonly'; import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine'; import { mockCustomQueryRule } from '../../storybook/mocks'; import { ThreeWayDiffStorybookProviders } from '../../storybook/three_way_diff_storybook_providers'; @@ -24,8 +24,8 @@ interface TemplateProps { const Template: Story = (args) => { return ( - - + + ); }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/new_terms_fields/new_terms_fields.stories.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/new_terms_fields/new_terms_fields.stories.tsx index f3dc5a1e3da9b..0f870562f2a8b 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/new_terms_fields/new_terms_fields.stories.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/new_terms_fields/new_terms_fields.stories.tsx @@ -8,7 +8,7 @@ import React from 'react'; import type { Story } from '@storybook/react'; import { NewTermsFieldsReadOnly } from './new_terms_fields'; -import { FieldReadOnly } from '../../field_readonly'; +import { FieldFinalReadOnly } from '../../field_final_readonly'; import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine'; import { mockNewTermsRule } from '../../storybook/mocks'; import { ThreeWayDiffStorybookProviders } from '../../storybook/three_way_diff_storybook_providers'; @@ -25,8 +25,11 @@ interface TemplateProps { const Template: Story = (args) => { return ( - - + + ); }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/note/note.stories.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/note/note.stories.tsx index 4a62c5e58dc28..9492b797689c7 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/note/note.stories.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/note/note.stories.tsx @@ -8,7 +8,7 @@ import React from 'react'; import type { Story } from '@storybook/react'; import { NoteReadOnly } from './note'; -import { FieldReadOnly } from '../../field_readonly'; +import { FieldFinalReadOnly } from '../../field_final_readonly'; import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine'; import { mockCustomQueryRule } from '../../storybook/mocks'; import { ThreeWayDiffStorybookProviders } from '../../storybook/three_way_diff_storybook_providers'; @@ -24,8 +24,8 @@ interface TemplateProps { const Template: Story = (args) => { return ( - - + + ); }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/references/references.stories.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/references/references.stories.tsx index ea8ee856099dd..d4d0d3241a6bf 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/references/references.stories.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/references/references.stories.tsx @@ -8,7 +8,7 @@ import React from 'react'; import type { Story } from '@storybook/react'; import { ReferencesReadOnly } from './references'; -import { FieldReadOnly } from '../../field_readonly'; +import { FieldFinalReadOnly } from '../../field_final_readonly'; import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine'; import { mockCustomQueryRule } from '../../storybook/mocks'; import { ThreeWayDiffStorybookProviders } from '../../storybook/three_way_diff_storybook_providers'; @@ -24,8 +24,11 @@ interface TemplateProps { const Template: Story = (args) => { return ( - - + + ); }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/related_integrations/related_integrations.stories.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/related_integrations/related_integrations.stories.tsx index b810eaa1fbb8f..65f4f50dbfb87 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/related_integrations/related_integrations.stories.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/related_integrations/related_integrations.stories.tsx @@ -10,7 +10,7 @@ import { useQueryClient } from '@tanstack/react-query'; import type { Story } from '@storybook/react'; import { RelatedIntegrationsReadOnly } from './related_integrations'; import { ThreeWayDiffStorybookProviders } from '../../storybook/three_way_diff_storybook_providers'; -import { FieldReadOnly } from '../../field_readonly'; +import { FieldFinalReadOnly } from '../../field_final_readonly'; import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine'; import { mockCustomQueryRule } from '../../storybook/mocks'; @@ -45,9 +45,12 @@ interface TemplateProps { const Template: Story = (args) => { return ( - + - + ); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/required_fields/required_fields.stories.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/required_fields/required_fields.stories.tsx index ee926fc7ed561..b3839c9535612 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/required_fields/required_fields.stories.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/required_fields/required_fields.stories.tsx @@ -7,7 +7,7 @@ import React from 'react'; import type { Story } from '@storybook/react'; import { RequiredFieldsReadOnly } from './required_fields'; -import { FieldReadOnly } from '../../field_readonly'; +import { FieldFinalReadOnly } from '../../field_final_readonly'; import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine'; import { mockCustomQueryRule } from '../../storybook/mocks'; import { ThreeWayDiffStorybookProviders } from '../../storybook/three_way_diff_storybook_providers'; @@ -23,8 +23,11 @@ interface TemplateProps { const Template: Story = (args) => { return ( - - + + ); }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/risk_score/risk_score.stories.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/risk_score/risk_score.stories.tsx index cb640e31090cc..c045000018d07 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/risk_score/risk_score.stories.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/risk_score/risk_score.stories.tsx @@ -8,7 +8,7 @@ import React from 'react'; import type { Story } from '@storybook/react'; import { RiskScoreReadOnly } from './risk_score'; -import { FieldReadOnly } from '../../field_readonly'; +import { FieldFinalReadOnly } from '../../field_final_readonly'; import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine'; import { mockCustomQueryRule } from '../../storybook/mocks'; import { ThreeWayDiffStorybookProviders } from '../../storybook/three_way_diff_storybook_providers'; @@ -24,8 +24,11 @@ interface TemplateProps { const Template: Story = (args) => { return ( - - + + ); }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/risk_score_mapping/risk_score_mapping.stories.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/risk_score_mapping/risk_score_mapping.stories.tsx index 90dbe7f981f64..4c7bd4cbba9ef 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/risk_score_mapping/risk_score_mapping.stories.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/risk_score_mapping/risk_score_mapping.stories.tsx @@ -7,7 +7,7 @@ import React from 'react'; import type { Story } from '@storybook/react'; -import { FieldReadOnly } from '../../field_readonly'; +import { FieldFinalReadOnly } from '../../field_final_readonly'; import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine'; import { RiskScoreMappingReadOnly } from './risk_score_mapping'; import { mockCustomQueryRule } from '../../storybook/mocks'; @@ -25,8 +25,11 @@ interface TemplateProps { const Template: Story = (args) => { return ( - - + + ); }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/rule_name_override/rule_name_override.stories.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/rule_name_override/rule_name_override.stories.tsx index d0d596f15af42..0552b9e4f6b4f 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/rule_name_override/rule_name_override.stories.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/rule_name_override/rule_name_override.stories.tsx @@ -8,7 +8,7 @@ import React from 'react'; import type { Story } from '@storybook/react'; import { RuleNameOverrideReadOnly } from './rule_name_override'; -import { FieldReadOnly } from '../../field_readonly'; +import { FieldFinalReadOnly } from '../../field_final_readonly'; import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine'; import { mockCustomQueryRule } from '../../storybook/mocks'; import { ThreeWayDiffStorybookProviders } from '../../storybook/three_way_diff_storybook_providers'; @@ -25,8 +25,11 @@ interface TemplateProps { const Template: Story = (args) => { return ( - - + + ); }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/rule_schedule/rule_schedule.stories.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/rule_schedule/rule_schedule.stories.tsx index 30f2170a30f31..cca1dcb9bc21f 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/rule_schedule/rule_schedule.stories.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/rule_schedule/rule_schedule.stories.tsx @@ -8,7 +8,7 @@ import React from 'react'; import type { Story } from '@storybook/react'; import { RuleScheduleReadOnly } from './rule_schedule'; -import { FieldReadOnly } from '../../field_readonly'; +import { FieldFinalReadOnly } from '../../field_final_readonly'; import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine'; import { mockCustomQueryRule } from '../../storybook/mocks'; import { ThreeWayDiffStorybookProviders } from '../../storybook/three_way_diff_storybook_providers'; @@ -24,8 +24,11 @@ interface TemplateProps { const Template: Story = (args) => { return ( - - + + ); }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/setup/setup.stories.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/setup/setup.stories.tsx index 34410c7c6f638..14ba62913053e 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/setup/setup.stories.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/setup/setup.stories.tsx @@ -8,7 +8,7 @@ import React from 'react'; import type { Story } from '@storybook/react'; import { SetupReadOnly } from './setup'; -import { FieldReadOnly } from '../../field_readonly'; +import { FieldFinalReadOnly } from '../../field_final_readonly'; import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine'; import { mockCustomQueryRule } from '../../storybook/mocks'; import { ThreeWayDiffStorybookProviders } from '../../storybook/three_way_diff_storybook_providers'; @@ -24,8 +24,8 @@ interface TemplateProps { const Template: Story = (args) => { return ( - - + + ); }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/severity/severity.stories.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/severity/severity.stories.tsx index b51547d1655e0..3d6836295aa94 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/severity/severity.stories.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/severity/severity.stories.tsx @@ -8,7 +8,7 @@ import React from 'react'; import type { Story } from '@storybook/react'; import { SeverityReadOnly } from './severity'; -import { FieldReadOnly } from '../../field_readonly'; +import { FieldFinalReadOnly } from '../../field_final_readonly'; import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine'; import { mockCustomQueryRule } from '../../storybook/mocks'; import { ThreeWayDiffStorybookProviders } from '../../storybook/three_way_diff_storybook_providers'; @@ -24,8 +24,8 @@ interface TemplateProps { const Template: Story = (args) => { return ( - - + + ); }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/severity_mapping/severity_mapping.stories.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/severity_mapping/severity_mapping.stories.tsx index b4ecb70ce66cd..4d3825cc7e4dc 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/severity_mapping/severity_mapping.stories.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/severity_mapping/severity_mapping.stories.tsx @@ -7,7 +7,7 @@ import React from 'react'; import type { Story } from '@storybook/react'; -import { FieldReadOnly } from '../../field_readonly'; +import { FieldFinalReadOnly } from '../../field_final_readonly'; import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine'; import { SeverityMappingReadOnly } from './severity_mapping'; import { mockCustomQueryRule } from '../../storybook/mocks'; @@ -25,8 +25,11 @@ interface TemplateProps { const Template: Story = (args) => { return ( - - + + ); }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/tags/tags.stories.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/tags/tags.stories.tsx index c8129dd989d24..f93f5ffd2dad0 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/tags/tags.stories.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/tags/tags.stories.tsx @@ -8,7 +8,7 @@ import React from 'react'; import type { Story } from '@storybook/react'; import { TagsReadOnly } from './tags'; -import { FieldReadOnly } from '../../field_readonly'; +import { FieldFinalReadOnly } from '../../field_final_readonly'; import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine'; import { mockCustomQueryRule } from '../../storybook/mocks'; import { ThreeWayDiffStorybookProviders } from '../../storybook/three_way_diff_storybook_providers'; @@ -24,8 +24,8 @@ interface TemplateProps { const Template: Story = (args) => { return ( - - + + ); }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/threat/threat.stories.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/threat/threat.stories.tsx index de8c15f29e0cc..671dc68e1054f 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/threat/threat.stories.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/threat/threat.stories.tsx @@ -7,7 +7,7 @@ import React from 'react'; import type { Story } from '@storybook/react'; -import { FieldReadOnly } from '../../field_readonly'; +import { FieldFinalReadOnly } from '../../field_final_readonly'; import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine'; import { ThreatReadOnly } from './threat'; import { mockCustomQueryRule } from '../../storybook/mocks'; @@ -24,8 +24,8 @@ interface TemplateProps { const Template: Story = (args) => { return ( - - + + ); }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/threat_index/threat_index.stories.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/threat_index/threat_index.stories.tsx index aeb1b6491bba6..6ab55ca01e335 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/threat_index/threat_index.stories.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/threat_index/threat_index.stories.tsx @@ -7,7 +7,7 @@ import React from 'react'; import type { Story } from '@storybook/react'; -import { FieldReadOnly } from '../../field_readonly'; +import { FieldFinalReadOnly } from '../../field_final_readonly'; import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine'; import { ThreatIndexReadOnly } from './threat_index'; import { mockThreatMatchRule } from '../../storybook/mocks'; @@ -24,8 +24,11 @@ interface TemplateProps { const Template: Story = (args) => { return ( - - + + ); }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/threat_indicator_path/threat_indicator_path.stories.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/threat_indicator_path/threat_indicator_path.stories.tsx index bb91b29fffe11..15c547001a27d 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/threat_indicator_path/threat_indicator_path.stories.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/threat_indicator_path/threat_indicator_path.stories.tsx @@ -7,7 +7,7 @@ import React from 'react'; import type { Story } from '@storybook/react'; -import { FieldReadOnly } from '../../field_readonly'; +import { FieldFinalReadOnly } from '../../field_final_readonly'; import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine'; import { ThreatIndicatorPathReadOnly } from './threat_indicator_path'; import { mockThreatMatchRule } from '../../storybook/mocks'; @@ -25,8 +25,11 @@ interface TemplateProps { const Template: Story = (args) => { return ( - - + + ); }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/threat_mapping/threat_mapping.stories.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/threat_mapping/threat_mapping.stories.tsx index 35c4bba4544a7..587be1b02cba0 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/threat_mapping/threat_mapping.stories.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/threat_mapping/threat_mapping.stories.tsx @@ -7,7 +7,7 @@ import React from 'react'; import type { Story } from '@storybook/react'; -import { FieldReadOnly } from '../../field_readonly'; +import { FieldFinalReadOnly } from '../../field_final_readonly'; import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine'; import { ThreatMappingReadOnly } from './threat_mapping'; import { mockThreatMatchRule } from '../../storybook/mocks'; @@ -24,8 +24,11 @@ interface TemplateProps { const Template: Story = (args) => { return ( - - + + ); }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/threat_query/threat_query.stories.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/threat_query/threat_query.stories.tsx index 625226ab4f9f5..46e98bbaa798d 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/threat_query/threat_query.stories.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/threat_query/threat_query.stories.tsx @@ -7,7 +7,7 @@ import React from 'react'; import type { Story } from '@storybook/react'; -import { FieldReadOnly } from '../../field_readonly'; +import { FieldFinalReadOnly } from '../../field_final_readonly'; import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine'; import { ThreatQueryReadOnly } from './threat_query'; import { @@ -34,8 +34,9 @@ const Template: Story = (args) => { - + ); }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/threshold/threshold.stories.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/threshold/threshold.stories.tsx index 0541d5f9a9b47..5270a2af8a635 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/threshold/threshold.stories.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/threshold/threshold.stories.tsx @@ -8,7 +8,7 @@ import React from 'react'; import type { Story } from '@storybook/react'; import { ThresholdReadOnly } from './threshold'; -import { FieldReadOnly } from '../../field_readonly'; +import { FieldFinalReadOnly } from '../../field_final_readonly'; import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine'; import { mockThresholdRule } from '../../storybook/mocks'; import { ThreeWayDiffStorybookProviders } from '../../storybook/three_way_diff_storybook_providers'; @@ -24,8 +24,11 @@ interface TemplateProps { const Template: Story = (args) => { return ( - - + + ); }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/timeline_template/timeline_template.stories.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/timeline_template/timeline_template.stories.tsx index e4c3a2043ff24..582affc9d192e 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/timeline_template/timeline_template.stories.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/timeline_template/timeline_template.stories.tsx @@ -8,7 +8,7 @@ import React from 'react'; import type { Story } from '@storybook/react'; import { TimelineTemplateReadOnly } from './timeline_template'; -import { FieldReadOnly } from '../../field_readonly'; +import { FieldFinalReadOnly } from '../../field_final_readonly'; import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine'; import { mockCustomQueryRule } from '../../storybook/mocks'; import { ThreeWayDiffStorybookProviders } from '../../storybook/three_way_diff_storybook_providers'; @@ -25,8 +25,11 @@ interface TemplateProps { const Template: Story = (args) => { return ( - - + + ); }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/timestamp_override/timestamp_override.stories.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/timestamp_override/timestamp_override.stories.tsx index 5828ba156d9d2..3d4c5b00005ad 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/timestamp_override/timestamp_override.stories.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/timestamp_override/timestamp_override.stories.tsx @@ -8,7 +8,7 @@ import React from 'react'; import type { Story } from '@storybook/react'; import { TimestampOverrideReadOnly } from './timestamp_override'; -import { FieldReadOnly } from '../../field_readonly'; +import { FieldFinalReadOnly } from '../../field_final_readonly'; import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine'; import { mockCustomQueryRule } from '../../storybook/mocks'; import { ThreeWayDiffStorybookProviders } from '../../storybook/three_way_diff_storybook_providers'; @@ -25,8 +25,11 @@ interface TemplateProps { const Template: Story = (args) => { return ( - - + + ); }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/type/type.stories.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/type/type.stories.tsx index ba252a8a80b88..c57bdf36ce3a0 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/type/type.stories.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/type/type.stories.tsx @@ -8,7 +8,7 @@ import React from 'react'; import type { Story } from '@storybook/react'; import { TypeReadOnly } from './type'; -import { FieldReadOnly } from '../../field_readonly'; +import { FieldFinalReadOnly } from '../../field_final_readonly'; import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine'; import { mockCustomQueryRule } from '../../storybook/mocks'; import { ThreeWayDiffStorybookProviders } from '../../storybook/three_way_diff_storybook_providers'; @@ -24,8 +24,8 @@ interface TemplateProps { const Template: Story = (args) => { return ( - - + + ); }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/final_readonly.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/final_readonly.tsx deleted file mode 100644 index 21b8475fe3002..0000000000000 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/final_readonly.tsx +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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 { EuiButtonEmpty } from '@elastic/eui'; -import React from 'react'; -import { FieldReadOnly } from './field_readonly'; -import * as i18n from '../translations'; -import { useFinalSideContext } from '../final_side/final_side_context'; - -export function FinalReadOnly() { - const { setEditMode, fieldName } = useFinalSideContext(); - - return ( - <> - - {i18n.EDIT_BUTTON_LABEL} - - - - ); -} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_side/constants.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/index.ts similarity index 77% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_side/constants.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/index.ts index 6316abcae48a3..4abd3b839ae2f 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_side/constants.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/index.ts @@ -5,7 +5,4 @@ * 2.0. */ -export enum FinalSideMode { - READONLY = 'readonly', - EDIT = 'edit', -} +export * from './field_final_readonly'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/storybook/three_way_diff_storybook_providers.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/storybook/three_way_diff_storybook_providers.tsx index 722f5ac9f6ada..d961f3d23befb 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/storybook/three_way_diff_storybook_providers.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/storybook/three_way_diff_storybook_providers.tsx @@ -13,10 +13,14 @@ import { Provider as ReduxStoreProvider } from 'react-redux'; import type { CoreStart } from '@kbn/core/public'; import type { UpsellingService } from '@kbn/security-solution-upselling/service'; import { createKibanaReactContext } from '@kbn/kibana-react-plugin/public'; +import type { UpgradeableDiffableFields } from '../../../../../model/prebuilt_rule_upgrade/fields'; import { ReactQueryClientProvider } from '../../../../../../../common/containers/query_client/query_client_provider'; import { UpsellingProvider } from '../../../../../../../common/components/upselling_provider'; -import { DiffableRuleContextProvider } from '../../diffable_rule_context'; -import type { DiffableRule } from '../../../../../../../../common/api/detection_engine'; +import { FieldUpgradeContextProvider } from '../../rule_upgrade/field_upgrade_context'; +import type { + DiffableRule, + RuleResponse, +} from '../../../../../../../../common/api/detection_engine'; import { mockCustomQueryRule } from './mocks'; function createKibanaServicesMock(overrides?: Partial) { @@ -78,29 +82,49 @@ interface StorybookProvidersProps { children: React.ReactNode; kibanaServicesOverrides?: Record; finalDiffableRule?: DiffableRule; + fieldName: string; } export function ThreeWayDiffStorybookProviders({ children, kibanaServicesOverrides, finalDiffableRule = mockCustomQueryRule(), + fieldName, }: StorybookProvidersProps) { const kibanaServicesMock = createKibanaServicesMock(kibanaServicesOverrides); const KibanaReactContext = createKibanaReactContext(kibanaServicesMock); const store = createMockStore(); + const ruleUpgradeStateMock = { + id: 'test-id', + rule_id: 'test-id', + current_rule: {} as RuleResponse, + target_rule: {} as RuleResponse, + diff: { + fields: {}, + num_fields_with_updates: 0, + num_fields_with_conflicts: 0, + num_fields_with_non_solvable_conflicts: 0, + }, + revision: 1, + finalRule: finalDiffableRule, + hasUnresolvedConflicts: false, + fieldsUpgradeState: {}, + }; + return ( - {children} - + diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_side/final_side.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_side/final_side.tsx deleted file mode 100644 index 30e3f4461195a..0000000000000 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_side/final_side.tsx +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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 React from 'react'; -import { EuiTitle } from '@elastic/eui'; -import { SideHeader } from '../components/side_header'; -import { FinalSideHelpInfo } from './final_side_help_info'; -import * as i18n from './translations'; -import { FinalReadOnly } from '../final_readonly/final_readonly'; -import { FinalEdit } from '../final_edit/final_edit'; -import { FinalSideMode } from './constants'; -import type { UpgradeableDiffableFields } from '../../../../model/prebuilt_rule_upgrade/fields'; -import { assertUnreachable } from '../../../../../../../common/utility_types'; -import { FinalSideContextProvider, useFinalSideContext } from './final_side_context'; - -interface FinalSideProps { - fieldName: UpgradeableDiffableFields; -} - -export function FinalSide({ fieldName }: FinalSideProps): JSX.Element { - return ( - <> - - -

- {i18n.FINAL_UPDATE} - -

-
-
- - - - - ); -} - -function FinalSideContent(): JSX.Element { - const { mode } = useFinalSideContext(); - - switch (mode) { - case FinalSideMode.READONLY: - return ; - case FinalSideMode.EDIT: - return ; - default: - return assertUnreachable(mode); - } -} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_side/final_side_context.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_side/final_side_context.tsx deleted file mode 100644 index 6beb0535e5e27..0000000000000 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_side/final_side_context.tsx +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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 React, { createContext, useContext, type PropsWithChildren, useCallback } from 'react'; -import { invariant } from '../../../../../../../common/utils/invariant'; -import { FinalSideMode } from './constants'; -import type { UpgradeableDiffableFields } from '../../../../model/prebuilt_rule_upgrade/fields'; - -interface FinalSideContextType { - fieldName: UpgradeableDiffableFields; - mode: FinalSideMode; - setReadOnlyMode: () => void; - setEditMode: () => void; -} - -const FinalSideContext = createContext(null); - -interface FinalSideContextProviderProps { - fieldName: UpgradeableDiffableFields; -} - -export function FinalSideContextProvider({ - children, - fieldName, -}: PropsWithChildren) { - const [mode, setMode] = React.useState(FinalSideMode.READONLY); - const setReadOnlyMode = useCallback(() => setMode(FinalSideMode.READONLY), []); - const setEditMode = useCallback(() => setMode(FinalSideMode.EDIT), []); - - const contextValue = { - fieldName, - setReadOnlyMode, - setEditMode, - mode, - }; - - return {children}; -} - -export function useFinalSideContext() { - const context = useContext(FinalSideContext); - - invariant(context !== null, 'useFinalSideContext must be used inside a FinalSideContextProvider'); - - return context; -} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/index.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/index.ts new file mode 100644 index 0000000000000..95e6836ca8f09 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/index.ts @@ -0,0 +1,8 @@ +/* + * 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. + */ + +export { RuleUpgrade as RuleUpgradeTab } from './rule_upgrade'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/field_upgrade.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/field_upgrade.tsx new file mode 100644 index 0000000000000..d7e3e33fcb5f8 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/field_upgrade.tsx @@ -0,0 +1,47 @@ +/* + * 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 React from 'react'; +import { EuiFlexGroup, EuiFlexItem, EuiSpacer, useEuiTheme } from '@elastic/eui'; +import { css } from '@emotion/css'; +import { SplitAccordion } from '../../../../../../common/components/split_accordion'; +import { FieldComparisonSide } from '../comparison_side/field_comparison_side'; +import { FieldFinalSide } from '../field_final_side'; +import { FieldUpgradeHeader } from './field_upgrade_header'; +import { useFieldUpgradeContext } from './field_upgrade_context'; + +export function FieldUpgrade(): JSX.Element { + const { euiTheme } = useEuiTheme(); + const { fieldName, fieldUpgradeState, hasConflict } = useFieldUpgradeContext(); + + return ( + <> + } + initialIsOpen={hasConflict} + data-test-subj="ruleUpgradePerFieldDiff" + > + + + + + + + + + + + + + ); +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/field_upgrade_context.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/field_upgrade_context.tsx new file mode 100644 index 0000000000000..f88c9fb3e0760 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/field_upgrade_context.tsx @@ -0,0 +1,167 @@ +/* + * 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 React, { createContext, useContext, useMemo } from 'react'; +import { useBoolean } from '@kbn/react-hooks'; +import type { + DiffableRule, + FieldsDiff, + 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'; +import type { SetRuleFieldResolvedValueFn } from '../../../../model/prebuilt_rule_upgrade/set_rule_field_resolved_value'; +import type { UpgradeableDiffableFields } from '../../../../model/prebuilt_rule_upgrade/fields'; +import type { RuleUpgradeState } from '../../../../model/prebuilt_rule_upgrade'; +import { FieldUpgradeStateEnum } from '../../../../model/prebuilt_rule_upgrade'; + +export enum FieldFinalSideMode { + Readonly = 'readonly', + Edit = 'edit', +} + +interface FieldUpgradeContextType { + /** + * Field name of an upgradable field from DiffableRule + */ + fieldName: UpgradeableDiffableFields; + /** + * Field's upgrade state + */ + fieldUpgradeState: FieldUpgradeStateEnum; + /** + * Whether rule has an unresolved conflict. This state is derived from `fieldUpgradeState`. + */ + hasConflict: boolean; + /** + * Field's three way diff + */ + fieldDiff: ThreeWayDiff; + /** + * Current final diffable rule including resolved values + */ + finalDiffableRule: DiffableRule; + /** + * Field final side view mode `Readonly` or `Editing` + */ + rightSideMode: FieldFinalSideMode; + /** + * Sets field's resolved value + */ + setRuleFieldResolvedValue: SetRuleFieldResolvedValueFn; + /** + * Sets field's right side `readonly` mode + */ + setReadOnlyMode: () => void; + /** + * Sets field's right side `edit` mode + */ + setEditMode: () => void; +} + +const FieldUpgradeContext = createContext(null); + +interface FieldUpgradeContextProviderProps { + ruleUpgradeState: RuleUpgradeState; + fieldName: UpgradeableDiffableFields; + setRuleFieldResolvedValue: SetRuleFieldResolvedValueFn; + children: React.ReactNode; +} + +export function FieldUpgradeContextProvider({ + ruleUpgradeState, + fieldName, + setRuleFieldResolvedValue, + children, +}: FieldUpgradeContextProviderProps) { + const { state: fieldUpgradeState } = ruleUpgradeState.fieldsUpgradeState[fieldName]; + const fieldDiff = ruleUpgradeState.diff.fields[fieldName]; + const initialRightSideMode = + fieldUpgradeState === FieldUpgradeStateEnum.NonSolvableConflict + ? FieldFinalSideMode.Edit + : FieldFinalSideMode.Readonly; + + const [editing, { on: setEditMode, off: setReadOnlyMode }] = useBoolean( + initialRightSideMode === FieldFinalSideMode.Edit + ); + + invariant(fieldDiff, `Field diff is not found for ${fieldName}.`); + + const contextValue: FieldUpgradeContextType = useMemo( + () => ({ + fieldName, + fieldUpgradeState, + hasConflict: + fieldUpgradeState === FieldUpgradeStateEnum.SolvableConflict || + fieldUpgradeState === FieldUpgradeStateEnum.NonSolvableConflict, + fieldDiff, + finalDiffableRule: calcFinalDiffableRule(ruleUpgradeState), + rightSideMode: editing ? FieldFinalSideMode.Edit : FieldFinalSideMode.Readonly, + setRuleFieldResolvedValue, + setReadOnlyMode, + setEditMode, + }), + [ + fieldName, + fieldUpgradeState, + fieldDiff, + ruleUpgradeState, + editing, + setRuleFieldResolvedValue, + setReadOnlyMode, + setEditMode, + ] + ); + + return ( + {children} + ); +} + +export function useFieldUpgradeContext() { + const context = useContext(FieldUpgradeContext); + + invariant( + context !== null, + 'useFieldUpgradeContext must be used inside a FieldUpgradeContextProvider' + ); + + return context; +} + +function calcFinalDiffableRule(ruleUpgradeState: RuleUpgradeState): DiffableRule { + const fieldsResolvedValues = Object.entries(ruleUpgradeState.fieldsUpgradeState).reduce< + Record + >((result, [fieldName, fieldState]) => { + if (fieldState.state === FieldUpgradeStateEnum.Accepted) { + result[fieldName] = fieldState.resolvedValue; + } + + return result; + }, {}); + + return { + ...convertRuleToDiffable(ruleUpgradeState.target_rule), + ...convertRuleFieldsDiffToDiffable(ruleUpgradeState.diff.fields), + ...fieldsResolvedValues, + } as DiffableRule; +} + +/** + * Assembles a `DiffableRule` from rule fields diff `merged_version`s. + */ +function convertRuleFieldsDiffToDiffable( + ruleFieldsDiff: FieldsDiff> +): Partial { + const mergeVersionRule: Record = {}; + + for (const fieldName of Object.keys(ruleFieldsDiff)) { + mergeVersionRule[fieldName] = ruleFieldsDiff[fieldName].merged_version; + } + + return mergeVersionRule; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/field_upgrade_conflicts_resolver_header.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/field_upgrade_header.tsx similarity index 65% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/field_upgrade_conflicts_resolver_header.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/field_upgrade_header.tsx index a096f025873a5..b401f702bd036 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/field_upgrade_conflicts_resolver_header.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/field_upgrade_header.tsx @@ -9,25 +9,27 @@ import React from 'react'; import { camelCase, startCase } from 'lodash'; import { EuiFlexGroup, EuiTitle } from '@elastic/eui'; import { fieldToDisplayNameMap } from '../../diff_components/translations'; -import type { FieldUpgradeState } from '../../../../model/prebuilt_rule_upgrade'; +import type { FieldUpgradeStateEnum } from '../../../../model/prebuilt_rule_upgrade'; import { FieldUpgradeStateInfo } from './field_upgrade_state_info'; -interface FieldUpgradeConflictsResolverHeaderProps { +interface FieldUpgradeHeaderProps { fieldName: string; - fieldUpgradeState: FieldUpgradeState; + fieldUpgradeState: FieldUpgradeStateEnum; } -export function FieldUpgradeConflictsResolverHeader({ +export function FieldUpgradeHeader({ fieldName, fieldUpgradeState, -}: FieldUpgradeConflictsResolverHeaderProps): JSX.Element { +}: FieldUpgradeHeaderProps): JSX.Element { return ( - +
{fieldToDisplayNameMap[fieldName] ?? startCase(camelCase(fieldName))}
- + + +
); } diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/field_upgrade_state_info/field_upgrade_state_info.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/field_upgrade_state_info/field_upgrade_state_info.tsx new file mode 100644 index 0000000000000..a85cf96cc50d2 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/field_upgrade_state_info/field_upgrade_state_info.tsx @@ -0,0 +1,83 @@ +/* + * 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 React, { useMemo } from 'react'; +import { EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; +import { assertUnreachable } from '../../../../../../../../common/utility_types'; +import { FieldUpgradeStateEnum } from '../../../../../model/prebuilt_rule_upgrade'; +import { ReadyForUpgradeBadge } from '../../badges/ready_for_upgrade_badge'; +import { ReviewRequiredBadge } from '../../badges/review_required_badge'; +import { ActionRequiredBadge } from '../../badges/action_required'; +import * as i18n from './translations'; + +interface FieldUpgradeStateInfoProps { + state: FieldUpgradeStateEnum; +} + +export function FieldUpgradeStateInfo({ state }: FieldUpgradeStateInfoProps): JSX.Element { + const { color, badge, title, description } = useMemo(() => { + switch (state) { + case FieldUpgradeStateEnum.NoUpdate: + return { + color: 'success', + title: i18n.NO_UPDATE, + description: i18n.NO_UPDATE_DESCRIPTION, + }; + + case FieldUpgradeStateEnum.NoConflict: + return { + color: 'success', + badge: , + title: i18n.NO_CONFLICT, + description: i18n.NO_CONFLICT_DESCRIPTION, + }; + + case FieldUpgradeStateEnum.Accepted: + return { + color: 'success', + badge: , + title: i18n.REVIEWED_AND_ACCEPTED, + }; + + case FieldUpgradeStateEnum.SolvableConflict: + return { + color: 'warning', + badge: , + title: i18n.SOLVABLE_CONFLICT, + description: i18n.SOLVABLE_CONFLICT_DESCRIPTION, + }; + + case FieldUpgradeStateEnum.NonSolvableConflict: + return { + color: 'danger', + badge: , + title: i18n.NON_SOLVABLE_CONFLICT, + description: i18n.NON_SOLVABLE_CONFLICT_DESCRIPTION, + }; + + default: + return assertUnreachable(state); + } + }, [state]); + + return ( + + + {badge} + + {title} + + + {description && ( + + {i18n.SEPARATOR} {description} + + )} + + + ); +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/field_upgrade_state_info/index.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/field_upgrade_state_info/index.ts similarity index 100% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/field_upgrade_state_info/index.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/field_upgrade_state_info/index.ts diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/field_upgrade_state_info/translations.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/field_upgrade_state_info/translations.tsx similarity index 58% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/field_upgrade_state_info/translations.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/field_upgrade_state_info/translations.tsx index 36349b5029a87..c3115c6ce0925 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/field_upgrade_state_info/translations.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/field_upgrade_state_info/translations.tsx @@ -7,18 +7,39 @@ import { i18n } from '@kbn/i18n'; -export const UPDATE_ACCEPTED = i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.updateAccepted', +export const NO_UPDATE = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.noUpdate', { - defaultMessage: 'Update accepted', + defaultMessage: 'No update', } ); -export const UPDATE_ACCEPTED_DESCRIPTION = i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.updateAcceptedDescription', +export const NO_UPDATE_DESCRIPTION = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.noUpdateDescription', { defaultMessage: - 'You can still make changes, please review/accept all other conflicts before updating the rule.', + 'The field was modified after rule installation but does not have Elastic update.', + } +); + +export const NO_CONFLICT = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.noConflict', + { + defaultMessage: 'No conflicts', + } +); + +export const NO_CONFLICT_DESCRIPTION = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.noConflictDescription', + { + defaultMessage: 'The update has no conflicts and has been applied to the final update.', + } +); + +export const REVIEWED_AND_ACCEPTED = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.reviewedAndAccepted', + { + defaultMessage: 'Reviewed and accepted', } ); @@ -40,7 +61,7 @@ export const SOLVABLE_CONFLICT_DESCRIPTION = i18n.translate( export const NON_SOLVABLE_CONFLICT = i18n.translate( 'xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.nonSolvableConflict', { - defaultMessage: 'Solved conflict', + defaultMessage: 'Unsolved conflict', } ); @@ -48,7 +69,7 @@ export const NON_SOLVABLE_CONFLICT_DESCRIPTION = i18n.translate( 'xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.nonSolvableConflictDescription', { defaultMessage: - 'We have suggested an update for this modified field, please review before accepting.', + 'Unable to suggest a merged version for the update. Current version is provided for you to edit.', } ); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/index.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/index.ts new file mode 100644 index 0000000000000..af2bd34a7b6e8 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/index.ts @@ -0,0 +1,8 @@ +/* + * 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. + */ + +export * from './rule_upgrade'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/rule_upgrade.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/rule_upgrade.tsx new file mode 100644 index 0000000000000..73746f3c48211 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/rule_upgrade.tsx @@ -0,0 +1,86 @@ +/* + * 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 React, { memo } from 'react'; +import { EuiSpacer } from '@elastic/eui'; +import { + FieldUpgradeStateEnum, + type RuleUpgradeState, + type SetRuleFieldResolvedValueFn, +} from '../../../../model/prebuilt_rule_upgrade'; +import type { UpgradeableDiffableFields } from '../../../../model/prebuilt_rule_upgrade/fields'; +import { RuleUpgradeInfoBar } from './rule_upgrade_info_bar'; +import { RuleUpgradeCallout } from './rule_upgrade_callout'; +import { FieldUpgrade } from './field_upgrade'; +import { FieldUpgradeContextProvider } from './field_upgrade_context'; + +interface RuleUpgradeProps { + ruleUpgradeState: RuleUpgradeState; + setRuleFieldResolvedValue: SetRuleFieldResolvedValueFn; +} + +export const RuleUpgrade = memo(function RuleUpgrade({ + ruleUpgradeState, + setRuleFieldResolvedValue, +}: RuleUpgradeProps): JSX.Element { + const totalNumOfFields = calcTotalNumOfFields(ruleUpgradeState); + const numOfFieldsWithUpdates = calcNumOfFieldsWithUpdates(ruleUpgradeState); + const numOfSolvableConflicts = calcNumOfSolvableConflicts(ruleUpgradeState); + const numOfNonSolvableConflicts = calcNumOfNonSolvableConflicts(ruleUpgradeState); + const fieldNames = Object.keys( + ruleUpgradeState.fieldsUpgradeState + ) as UpgradeableDiffableFields[]; + + return ( + <> + + + + + + {fieldNames.map((fieldName) => ( + + + + ))} + + ); +}); + +function calcTotalNumOfFields(ruleUpgradeState: RuleUpgradeState): number { + return Object.keys(ruleUpgradeState.fieldsUpgradeState).length; +} + +function calcNumOfFieldsWithUpdates(ruleUpgradeState: RuleUpgradeState): number { + return Object.values(ruleUpgradeState.fieldsUpgradeState).filter( + ({ state }) => state !== FieldUpgradeStateEnum.NoUpdate + ).length; +} + +function calcNumOfSolvableConflicts(ruleUpgradeState: RuleUpgradeState): number { + return Object.values(ruleUpgradeState.fieldsUpgradeState).filter( + ({ state }) => state === FieldUpgradeStateEnum.SolvableConflict + ).length; +} + +function calcNumOfNonSolvableConflicts(ruleUpgradeState: RuleUpgradeState): number { + return Object.values(ruleUpgradeState.fieldsUpgradeState).filter( + ({ state }) => state === FieldUpgradeStateEnum.NonSolvableConflict + ).length; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/rule_upgrade_callout.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/rule_upgrade_callout.tsx new file mode 100644 index 0000000000000..3b3c0c7e49e51 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/rule_upgrade_callout.tsx @@ -0,0 +1,79 @@ +/* + * 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 React from 'react'; +import { EuiCallOut } from '@elastic/eui'; +import { ActionRequiredBadge } from '../badges/action_required'; +import { ReviewRequiredBadge } from '../badges/review_required_badge'; +import { ReadyForUpgradeBadge } from '../badges/ready_for_upgrade_badge'; +import * as i18n from './translations'; + +interface RuleUpgradeCalloutProps { + numOfSolvableConflicts: number; + numOfNonSolvableConflicts: number; +} + +export function RuleUpgradeCallout({ + numOfSolvableConflicts, + numOfNonSolvableConflicts, +}: RuleUpgradeCalloutProps): JSX.Element { + if (numOfNonSolvableConflicts > 0) { + return ( + + {i18n.UPGRADE_STATUS} +   + +   + {i18n.RULE_HAS_CONFLICTS(numOfNonSolvableConflicts + numOfSolvableConflicts)} + + } + color="danger" + size="s" + > +

{i18n.RULE_HAS_HARD_CONFLICTS_DESCRIPTION}

+
+ ); + } + + if (numOfSolvableConflicts > 0) { + return ( + + {i18n.UPGRADE_STATUS} +   + +   + {i18n.RULE_HAS_CONFLICTS(numOfSolvableConflicts)} + + } + color="warning" + size="s" + > +

{i18n.RULE_HAS_SOFT_CONFLICTS_DESCRIPTION}

+
+ ); + } + + return ( + + {i18n.UPGRADE_STATUS} +   + + + } + color="success" + size="s" + > +

{i18n.RULE_IS_READY_FOR_UPGRADE_DESCRIPTION}

+
+ ); +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/rule_upgrade_info_bar.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/rule_upgrade_info_bar.tsx similarity index 70% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/rule_upgrade_info_bar.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/rule_upgrade_info_bar.tsx index 970f04f383274..3520734b2b257 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/rule_upgrade_info_bar.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/rule_upgrade_info_bar.tsx @@ -6,7 +6,6 @@ */ import React from 'react'; -import type { RuleUpgradeState } from '../../../../model/prebuilt_rule_upgrade'; import { UtilityBar, UtilityBarGroup, @@ -15,17 +14,25 @@ import { } from '../../../../../../common/components/utility_bar'; import * as i18n from './translations'; -interface UpgradeInfoBarProps { - ruleUpgradeState: RuleUpgradeState; +interface RuleUpgradeInfoBarProps { + totalNumOfFields: number; + numOfFieldsWithUpdates: number; + numOfConflicts: number; } -export function RuleUpgradeInfoBar({ ruleUpgradeState }: UpgradeInfoBarProps): JSX.Element { - const numOfFieldsWithUpdates = ruleUpgradeState.diff.num_fields_with_updates; - const numOfConflicts = ruleUpgradeState.diff.num_fields_with_conflicts; - +export function RuleUpgradeInfoBar({ + totalNumOfFields, + numOfFieldsWithUpdates, + numOfConflicts, +}: RuleUpgradeInfoBarProps): JSX.Element { return ( + + + {i18n.TOTAL_NUM_OF_FIELDS(totalNumOfFields)} + + {i18n.NUM_OF_FIELDS_WITH_UPDATES(numOfFieldsWithUpdates)} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/translations.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/translations.tsx new file mode 100644 index 0000000000000..4a73f096a271c --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/translations.tsx @@ -0,0 +1,115 @@ +/* + * 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 React from 'react'; +import { EuiLink } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { useKibana } from '../../../../../../common/lib/kibana/kibana_react'; + +export const TOTAL_NUM_OF_FIELDS = (count: number) => ( + {count}, count }} + /> +); + +export const NUM_OF_FIELDS_WITH_UPDATES = (count: number) => ( + {count}, count }} + /> +); + +export const NUM_OF_CONFLICTS = (count: number) => ( + {count}, count }} + /> +); + +const UPGRADE_RULES_DOCS_LINK = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.updateYourRulesDocsLink', + { + defaultMessage: 'update your rules', + } +); + +export function RuleUpgradeHelper(): JSX.Element { + const { + docLinks: { + links: { + securitySolution: { manageDetectionRules }, + }, + }, + } = useKibana().services; + const manageDetectionRulesUpdateRulesSection = `${manageDetectionRules}#edit-rules-settings`; + + return ( + + {UPGRADE_RULES_DOCS_LINK} + + ), + }} + /> + ); +} + +export const UPGRADE_STATUS = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.upgradeStatusTitle', + { + defaultMessage: 'Update status:', + } +); + +export const RULE_HAS_CONFLICTS = (count: number) => + i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.ruleHasConflicts', + { + values: { count }, + defaultMessage: + '{count} {count, plural, one {field has a conflict} other {fields have conflicts}}. Please review and provide a final update.', + } + ); + +export const RULE_HAS_SOFT_CONFLICTS_DESCRIPTION = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.ruleHasSoftConflictsDescription', + { + defaultMessage: + 'Please review and accept conflicts. You can also keep the current version without the updates, or accept the Elastic update but lose your modifications.', + } +); + +export const RULE_HAS_HARD_CONFLICTS_DESCRIPTION = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.ruleHasHardConflictsDescription', + { + defaultMessage: + 'Please provide an input for the conflicts. You can also keep the current version without the updates, or accept the Elastic update but lose your modifications.', + } +); + +export const RULE_IS_READY_FOR_UPGRADE_DESCRIPTION = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.fieldUpgradeState.ruleIsReadyForUpgradeDescription', + { + defaultMessage: 'There are no conflicts and the update is ready to be applied.', + } +); + +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', + } +); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade_conflicts_resolver_tab.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade_conflicts_resolver_tab.tsx deleted file mode 100644 index 95fa407fb7ca2..0000000000000 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade_conflicts_resolver_tab.tsx +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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 React from 'react'; -import { EuiSpacer } from '@elastic/eui'; -import type { - RuleUpgradeState, - SetRuleFieldResolvedValueFn, -} from '../../../model/prebuilt_rule_upgrade'; -import { RuleUpgradeInfoBar } from './components/rule_upgrade_info_bar'; -import { RuleUpgradeConflictsResolver } from './components/rule_upgrade_conflicts_resolver'; -import { DiffableRuleContextProvider } from './diffable_rule_context'; -import { RuleUpgradeCallout } from './components/rule_upgrade_callout'; - -interface RuleUpgradeConflictsResolverTabProps { - ruleUpgradeState: RuleUpgradeState; - setRuleFieldResolvedValue: SetRuleFieldResolvedValueFn; -} - -export function RuleUpgradeConflictsResolverTab({ - ruleUpgradeState, - setRuleFieldResolvedValue, -}: RuleUpgradeConflictsResolverTabProps): JSX.Element { - return ( - - - - - - - - - ); -} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/translations.ts deleted file mode 100644 index ced733d87ff6e..0000000000000 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/translations.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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 { i18n } from '@kbn/i18n'; - -export const CANCEL_BUTTON_LABEL = i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.upgradeRules.cancelButtonLabel', - { - defaultMessage: 'Cancel', - } -); - -export const SAVE_BUTTON_LABEL = i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.upgradeRules.saveButtonLabel', - { - defaultMessage: 'Save', - } -); - -export const EDIT_BUTTON_LABEL = i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.upgradeRules.editButtonLabel', - { - defaultMessage: 'Edit', - } -); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/versions_picker/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/versions_picker/translations.ts deleted file mode 100644 index 15699edc206e7..0000000000000 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/versions_picker/translations.ts +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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 { i18n } from '@kbn/i18n'; - -export const BASE_VS_TARGET = i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.upgradeRules.versionsPicker.baseVsTargetLabel', - { - defaultMessage: 'Base vs Target', - } -); - -export const BASE_VS_CURRENT = i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.upgradeRules.versionsPicker.baseVsCurrentLabel', - { - defaultMessage: 'Base vs Current', - } -); - -export const BASE_VS_FINAL = i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.upgradeRules.versionsPicker.baseVsFinalLabel', - { - defaultMessage: 'Base vs Final', - } -); - -export const CURRENT_VS_TARGET = i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.upgradeRules.versionsPicker.currentVsTargetLabel', - { - defaultMessage: 'Current vs Target', - } -); - -export const CURRENT_VS_FINAL = i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.upgradeRules.versionsPicker.currentVsFinalLabel', - { - defaultMessage: 'Current vs Final', - } -); - -export const TARGET_VS_FINAL = i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.upgradeRules.versionsPicker.targetVsFinalLabel', - { - defaultMessage: 'Target vs Final', - } -); - -export const VERSION_PICKER_ARIA_LABEL = i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.upgradeRules.versionsPicker.ariaLabel', - { - defaultMessage: 'Select versions to compare', - } -); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/model/prebuilt_rule_upgrade/field_upgrade_state.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/model/prebuilt_rule_upgrade/field_upgrade_state_enum.ts similarity index 80% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management/model/prebuilt_rule_upgrade/field_upgrade_state.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/model/prebuilt_rule_upgrade/field_upgrade_state_enum.ts index ae2d8799c0bd4..0fd522403edc6 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/model/prebuilt_rule_upgrade/field_upgrade_state.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/model/prebuilt_rule_upgrade/field_upgrade_state_enum.ts @@ -5,7 +5,9 @@ * 2.0. */ -export enum FieldUpgradeState { +export enum FieldUpgradeStateEnum { + NoUpdate = 'NO_UPDATE', + NoConflict = 'NO_CONFLICT', Accepted = 'ACCEPTED', SolvableConflict = 'SOLVABLE_CONFLICT', NonSolvableConflict = 'NON_SOLVABLE_CONFLICT', diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/model/prebuilt_rule_upgrade/fields_upgrade_state.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/model/prebuilt_rule_upgrade/fields_upgrade_state.ts index fb18061067ff8..88522bf559050 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/model/prebuilt_rule_upgrade/fields_upgrade_state.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/model/prebuilt_rule_upgrade/fields_upgrade_state.ts @@ -5,6 +5,16 @@ * 2.0. */ -import type { FieldUpgradeState } from './field_upgrade_state'; +import type { DiffableAllFields } from '../../../../../common/api/detection_engine'; +import type { FieldUpgradeStateEnum } from './field_upgrade_state_enum'; -export type FieldsUpgradeState = Record; +export type FieldsUpgradeState = Record< + string, + | { + state: Exclude; + } + | { + state: FieldUpgradeStateEnum.Accepted; + resolvedValue: DiffableAllFields[keyof DiffableAllFields]; + } +>; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/model/prebuilt_rule_upgrade/index.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/model/prebuilt_rule_upgrade/index.ts index 57ee30f308f08..0e5a631fde2e2 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/model/prebuilt_rule_upgrade/index.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/model/prebuilt_rule_upgrade/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -export * from './field_upgrade_state'; +export * from './field_upgrade_state_enum'; export * from './fields_upgrade_state'; export * from './rule_upgrade_state'; export * from './rules_upgrade_state'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/model/prebuilt_rule_upgrade/rule_upgrade_state.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/model/prebuilt_rule_upgrade/rule_upgrade_state.ts index 0c72361bb29dc..7cd1f9c9ef843 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/model/prebuilt_rule_upgrade/rule_upgrade_state.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/model/prebuilt_rule_upgrade/rule_upgrade_state.ts @@ -5,23 +5,16 @@ * 2.0. */ -import { - type DiffableRule, - type RuleUpgradeInfoForReview, -} from '../../../../../common/api/detection_engine'; +import { type RuleUpgradeInfoForReview } from '../../../../../common/api/detection_engine'; import type { FieldsUpgradeState } from './fields_upgrade_state'; export interface RuleUpgradeState extends RuleUpgradeInfoForReview { /** - * Rule containing desired values users expect to see in the upgraded rule. + * Stores a record of customizable field names mapped to field upgrade state. */ - finalRule: DiffableRule; + fieldsUpgradeState: FieldsUpgradeState; /** * Indicates whether there are conflicts blocking rule upgrading. */ hasUnresolvedConflicts: boolean; - /** - * Stores a record of field names mapped to field upgrade state. - */ - fieldsUpgradeState: FieldsUpgradeState; } diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/use_add_prebuilt_rules_table_columns.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/use_add_prebuilt_rules_table_columns.tsx index a0a317e72b4c2..4e15de4011fab 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/use_add_prebuilt_rules_table_columns.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/use_add_prebuilt_rules_table_columns.tsx @@ -55,7 +55,7 @@ export const RULE_NAME_COLUMN: TableColumn = { field: 'name', name: i18n.COLUMN_RULE, render: (value: RuleResponse['name'], rule: RuleResponse) => ( - + ), sortable: true, truncateText: true, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/rule_type_change_callout.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/rule_type_change_callout.tsx index f66fd92a685fe..0111ceb40d38f 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/rule_type_change_callout.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/rule_type_change_callout.tsx @@ -5,17 +5,28 @@ * 2.0. */ -import { EuiCallOut } from '@elastic/eui'; import React from 'react'; +import { EuiCallOut } from '@elastic/eui'; import { RULE_TYPE_CHANGE_CALLOUT_DESCRIPTION, RULE_TYPE_CHANGE_CALLOUT_TITLE, + RULE_TYPE_CHANGE_WITH_CUSTOMIZATIONS_CALLOUT_DESCRIPTION, } from './translations'; -export const RuleTypeChangeCallout = () => { +interface RuleTypeChangeCalloutProps { + hasCustomizations: boolean; +} + +export function RuleTypeChangeCallout({ + hasCustomizations, +}: RuleTypeChangeCalloutProps): JSX.Element { return ( -

{RULE_TYPE_CHANGE_CALLOUT_DESCRIPTION}

+

+ {hasCustomizations + ? RULE_TYPE_CHANGE_WITH_CUSTOMIZATIONS_CALLOUT_DESCRIPTION + : RULE_TYPE_CHANGE_CALLOUT_DESCRIPTION} +

); -}; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/translations.tsx similarity index 68% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/translations.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/translations.tsx index 9a07c1bb6908a..4b9f79e061ce9 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/translations.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/translations.tsx @@ -5,7 +5,10 @@ * 2.0. */ +import React from 'react'; import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; +import type { ReactNode } from 'react'; export const UPDATE_ALL = i18n.translate( 'xpack.securitySolution.detectionEngine.rules.upgradeRules.upgradeAll', @@ -88,8 +91,51 @@ export const RULE_TYPE_CHANGE_CALLOUT_TITLE = i18n.translate( export const RULE_TYPE_CHANGE_CALLOUT_DESCRIPTION = i18n.translate( 'xpack.securitySolution.detectionEngine.upgradeRules.ruleTypeChangeCalloutDescription', + { + defaultMessage: 'Elastic update has rule type changed.', + } +); + +export const RULE_TYPE_CHANGE_WITH_CUSTOMIZATIONS_CALLOUT_DESCRIPTION = i18n.translate( + 'xpack.securitySolution.detectionEngine.upgradeRules.ruleTypeChangeWithCustomizationCalloutDescription', { defaultMessage: 'Your customization will be lost at update. Please take note of your customization or clone this rule before updating.', } ); + +export const LAST_UPDATE = i18n.translate( + 'xpack.securitySolution.detectionEngine.upgradeFlyout.header.lastUpdate', + { + defaultMessage: 'Last update', + } +); + +export const UPDATED_BY_AND_WHEN = (updatedBy: ReactNode, updatedAt: ReactNode) => ( + +); + +export const SEVERITY = i18n.translate( + 'xpack.securitySolution.detectionEngine.upgradeFlyout.header.severity', + { + defaultMessage: 'Severity', + } +); + +export const FIELD_UPDATES = i18n.translate( + 'xpack.securitySolution.detectionEngine.upgradeFlyout.header.fieldUpdates', + { + defaultMessage: 'Field updates', + } +); + +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', + } +); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_flyout_subheader.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_flyout_subheader.tsx new file mode 100644 index 0000000000000..bab43e55c2e00 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_flyout_subheader.tsx @@ -0,0 +1,85 @@ +/* + * 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 React, { memo } from 'react'; +import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiText } from '@elastic/eui'; +import { camelCase, startCase } from 'lodash'; +import type { FieldsDiff } from '../../../../../../common/api/detection_engine'; +import { FormattedDate } from '../../../../../common/components/formatted_date'; +import { SeverityBadge } from '../../../../../common/components/severity_badge'; +import { ModifiedBadge } from '../../../../rule_management/components/rule_details/three_way_diff/badges/modified_badge'; +import type { RuleUpgradeState } from '../../../../rule_management/model/prebuilt_rule_upgrade'; +import { fieldToDisplayNameMap } from '../../../../rule_management/components/rule_details/diff_components/translations'; +import * as i18n from './translations'; + +interface UpgradeFlyoutSubHeaderProps { + ruleUpgradeState: RuleUpgradeState; +} + +export const UpgradeFlyoutSubHeader = memo(function UpgradeFlyoutSubHeader({ + ruleUpgradeState, +}: UpgradeFlyoutSubHeaderProps): JSX.Element { + const lastUpdate = ( + + + {i18n.LAST_UPDATE} + {':'} + {' '} + {i18n.UPDATED_BY_AND_WHEN( + ruleUpgradeState.current_rule.updated_by, + + )} + + ); + + const severity = ( + + + + {i18n.SEVERITY} + {':'} + + + + + ); + + const customized = ruleUpgradeState.current_rule.rule_source.type === 'external' && + ruleUpgradeState.current_rule.rule_source.is_customized && ( + + ); + + const fieldsDiff: FieldsDiff> = ruleUpgradeState.diff.fields; + const fieldsNamesWithUpdates = Object.keys(ruleUpgradeState.fieldsUpgradeState).filter( + (fieldName) => fieldsDiff[fieldName].has_update + ); + const fieldUpdates = !fieldsDiff.type && fieldsNamesWithUpdates.length > 0 && ( + + + {i18n.FIELD_UPDATES} + {':'} + {' '} + {fieldsNamesWithUpdates + .map((fieldName) => fieldToDisplayNameMap[fieldName] ?? startCase(camelCase(fieldName))) + .join(', ')} + + ); + + return ( + <> + + {lastUpdate} + {severity} + + + + {customized && {customized}} + {fieldUpdates} + + + ); +}); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table.tsx index 2437a5e87866d..623f36c5ebb1d 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table.tsx @@ -15,7 +15,7 @@ import { EuiSkeletonText, EuiSkeletonTitle, } from '@elastic/eui'; -import React, { useMemo, useState } from 'react'; +import React, { useState } from 'react'; import type { RuleUpgradeState } from '../../../../rule_management/model/prebuilt_rule_upgrade'; import * as i18n from '../../../../../detections/pages/detection_engine/rules/translations'; import { RULES_TABLE_INITIAL_PAGE_SIZE, RULES_TABLE_PAGE_SIZE_OPTIONS } from '../constants'; @@ -38,22 +38,17 @@ const NO_ITEMS_MESSAGE = ( * Table Component for displaying rules that have available updates */ export const UpgradePrebuiltRulesTable = React.memo(() => { - const upgradeRulesTableContext = useUpgradePrebuiltRulesTableContext(); - const [selected, setSelected] = useState([]); - const { state: { - rulesUpgradeState, + ruleUpgradeStates, hasRulesToUpgrade, isLoading, isRefetching, isUpgradingSecurityPackages, }, - } = upgradeRulesTableContext; - const ruleUpgradeStatesArray = useMemo( - () => Object.values(rulesUpgradeState), - [rulesUpgradeState] - ); + } = useUpgradePrebuiltRulesTableContext(); + const [selected, setSelected] = useState([]); + const rulesColumns = useUpgradePrebuiltRulesTableColumns(); const shouldShowProgress = isUpgradingSecurityPackages || isRefetching; @@ -102,7 +97,7 @@ export const UpgradePrebuiltRulesTable = React.memo(() => {
{ const { state: { - ruleUpgradeInfos, + ruleUpgradeStates, hasRulesToUpgrade, loadingRules, isRefetching, isUpgradingSecurityPackages, isPrebuiltRulesCustomizationEnabled, }, - actions: { upgradeRules }, + actions: { upgradeRules, upgradeAllRules }, } = useUpgradePrebuiltRulesTableContext(); const [{ loading: isUserDataLoading, canUserCRUD }] = useUserData(); const canUserEditRules = canUserCRUD && !isUserDataLoading; @@ -38,10 +38,13 @@ export const UpgradePrebuiltRulesTableButtons = ({ const isRuleUpgrading = loadingRules.length > 0; const isRequestInProgress = isRuleUpgrading || isRefetching || isUpgradingSecurityPackages; + const doAllSelectedRulesHaveConflicts = - isPrebuiltRulesCustomizationEnabled && isAllRuleHaveConflicts(selectedRules); + isPrebuiltRulesCustomizationEnabled && + selectedRules.every(({ hasUnresolvedConflicts }) => hasUnresolvedConflicts); const doAllRulesHaveConflicts = - isPrebuiltRulesCustomizationEnabled && isAllRuleHaveConflicts(ruleUpgradeInfos); + isPrebuiltRulesCustomizationEnabled && + ruleUpgradeStates.every(({ hasUnresolvedConflicts }) => hasUnresolvedConflicts); const { selectedRulesButtonTooltip, allRulesButtonTooltip } = useBulkUpdateButtonsTooltipContent({ canUserEditRules, @@ -55,12 +58,6 @@ export const UpgradePrebuiltRulesTableButtons = ({ [selectedRules, upgradeRules] ); - const upgradeAllRules = useCallback( - // Upgrade all rules, ignoring filter and selection - () => upgradeRules(ruleUpgradeInfos.map((rule) => rule.rule_id)), - [ruleUpgradeInfos, upgradeRules] - ); - return ( {shouldDisplayUpgradeSelectedRulesButton ? ( @@ -146,7 +143,3 @@ const useBulkUpdateButtonsTooltipContent = ({ allRulesButtonTooltip: undefined, }; }; - -function isAllRuleHaveConflicts(rules: Array<{ diff: { num_fields_with_conflicts: number } }>) { - return rules.every((rule) => rule.diff.num_fields_with_conflicts > 0); -} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table_context.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table_context.tsx index 6aad29f8b5792..751b24f865e61 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table_context.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table_context.tsx @@ -10,49 +10,40 @@ import type { Dispatch, SetStateAction } from 'react'; import React, { createContext, useCallback, useContext, useMemo, useState } from 'react'; import type { RuleFieldsToUpgrade, - RuleUpgradeInfoForReview, RuleUpgradeSpecifier, } from '../../../../../../common/api/detection_engine'; +import { useIsPrebuiltRulesCustomizationEnabled } from '../../../../rule_management/hooks/use_is_prebuilt_rules_customization_enabled'; +import { useAppToasts } from '../../../../../common/hooks/use_app_toasts'; +import type { RuleUpgradeState } from '../../../../rule_management/model/prebuilt_rule_upgrade'; +import { RuleUpgradeTab } from '../../../../rule_management/components/rule_details/three_way_diff'; +import { PerFieldRuleDiffTab } from '../../../../rule_management/components/rule_details/per_field_rule_diff_tab'; +import { useIsUpgradingSecurityPackages } from '../../../../rule_management/logic/use_upgrade_security_packages'; import type { RuleResponse, RuleSignatureId, } from '../../../../../../common/api/detection_engine/model/rule_schema'; import { invariant } from '../../../../../../common/utils/invariant'; -import { useAppToasts } from '../../../../../common/hooks/use_app_toasts'; -import { PerFieldRuleDiffTab } from '../../../../rule_management/components/rule_details/per_field_rule_diff_tab'; import { TabContentPadding } from '../../../../rule_management/components/rule_details/rule_details_flyout'; -import { RuleDiffTab } from '../../../../rule_management/components/rule_details/rule_diff_tab'; -import { RuleUpgradeConflictsResolverTab } from '../../../../rule_management/components/rule_details/three_way_diff/rule_upgrade_conflicts_resolver_tab'; -import * as ruleDetailsI18n from '../../../../rule_management/components/rule_details/translations'; -import { useIsPrebuiltRulesCustomizationEnabled } from '../../../../rule_management/hooks/use_is_prebuilt_rules_customization_enabled'; import { usePerformUpgradeSpecificRules } from '../../../../rule_management/logic/prebuilt_rules/use_perform_rule_upgrade'; import { usePrebuiltRulesUpgradeReview } from '../../../../rule_management/logic/prebuilt_rules/use_prebuilt_rules_upgrade_review'; -import { useIsUpgradingSecurityPackages } from '../../../../rule_management/logic/use_upgrade_security_packages'; -import type { - RuleUpgradeState, - RulesUpgradeState, -} from '../../../../rule_management/model/prebuilt_rule_upgrade'; -import { FieldUpgradeState } from '../../../../rule_management/model/prebuilt_rule_upgrade/field_upgrade_state'; -import { isNonUpgradeableFieldName } from '../../../../rule_management/model/prebuilt_rule_upgrade/fields'; +import { RuleDiffTab } from '../../../../rule_management/components/rule_details/rule_diff_tab'; +import { FieldUpgradeStateEnum } from '../../../../rule_management/model/prebuilt_rule_upgrade/field_upgrade_state_enum'; import { useRulePreviewFlyout } from '../use_rule_preview_flyout'; -import { MlJobUpgradeModal } from './modals/ml_job_upgrade_modal'; -import { UpgradeConflictsModal } from './modals/upgrade_conflicts_modal'; -import * as i18n from './translations'; import type { UpgradePrebuiltRulesTableFilterOptions } from './use_filter_prebuilt_rules_to_upgrade'; import { useFilterPrebuiltRulesToUpgrade } from './use_filter_prebuilt_rules_to_upgrade'; import { usePrebuiltRulesUpgradeState } from './use_prebuilt_rules_upgrade_state'; -import { useMlJobUpgradeModal, useUpgradeConflictsModal } from './use_upgrade_modals'; +import { useOutdatedMlJobsUpgradeModal } from './use_ml_jobs_upgrade_modal'; +import { useUpgradeWithConflictsModal } from './use_upgrade_with_conflicts_modal'; import { RuleTypeChangeCallout } from './rule_type_change_callout'; +import { UpgradeFlyoutSubHeader } from './upgrade_flyout_subheader'; +import * as ruleDetailsI18n from '../../../../rule_management/components/rule_details/translations'; +import * as i18n from './translations'; export interface UpgradePrebuiltRulesTableState { - /** - * Rule upgrade state (all rules available for upgrade) - */ - ruleUpgradeInfos: RuleUpgradeInfoForReview[]; /** * Rule upgrade state after applying `filterOptions` */ - rulesUpgradeState: RulesUpgradeState; + ruleUpgradeStates: RuleUpgradeState[]; /** * Currently selected table filter */ @@ -101,6 +92,7 @@ export const PREBUILT_RULE_UPDATE_FLYOUT_ANCHOR = 'updatePrebuiltRulePreview'; export interface UpgradePrebuiltRulesTableActions { reFetchRules: () => void; upgradeRules: (ruleIds: RuleSignatureId[]) => void; + upgradeAllRules: () => void; setFilterOptions: Dispatch>; openRulePreview: (ruleId: string) => void; } @@ -146,28 +138,20 @@ export const UpgradePrebuiltRulesTableContextProvider = ({ refetchInterval: false, // Disable automatic refetching since request is expensive keepPreviousData: true, // Use this option so that the state doesn't jump between "success" and "loading" on page change }); - const filteredRuleUpgradeInfos = useFilterPrebuiltRulesToUpgrade({ + const { rulesUpgradeState, setRuleFieldResolvedValue } = + usePrebuiltRulesUpgradeState(ruleUpgradeInfos); + const ruleUpgradeStates = useMemo(() => Object.values(rulesUpgradeState), [rulesUpgradeState]); + const filteredRuleUpgradeStates = useFilterPrebuiltRulesToUpgrade({ filterOptions, - rules: ruleUpgradeInfos, + data: ruleUpgradeStates, }); - const { rulesUpgradeState, setRuleFieldResolvedValue } = - usePrebuiltRulesUpgradeState(filteredRuleUpgradeInfos); const { - isVisible: isLegacyMLJobsModalVisible, - legacyJobsInstalled, + modal: confirmLegacyMlJobsUpgradeModal, confirmLegacyMLJobs, - handleConfirm: handleLegacyMLJobsConfirm, - handleCancel: handleLegacyMLJobsCancel, - loadingJobs, - } = useMlJobUpgradeModal(); - - const { - isVisible: isConflictsModalVisible, - confirmConflictsUpgrade, - handleConfirm: handleConflictsConfirm, - handleCancel: handleConflictsCancel, - } = useUpgradeConflictsModal(); + isLoading: areMlJobsLoading, + } = useOutdatedMlJobsUpgradeModal(); + const { modal: upgradeConflictsModal, confirmConflictsUpgrade } = useUpgradeWithConflictsModal(); const { mutateAsync: upgradeSpecificRulesRequest } = usePerformUpgradeSpecificRules(); @@ -263,6 +247,19 @@ export const UpgradePrebuiltRulesTableContextProvider = ({ [isPrebuiltRulesCustomizationEnabled, upgradeRulesToResolved, upgradeRulesToTarget] ); + const upgradeAllRules = useCallback( + // Upgrade all rules, ignoring filter and selection + () => upgradeRules(ruleUpgradeInfos.map((rule) => rule.rule_id)), + [ruleUpgradeInfos, upgradeRules] + ); + + const subHeaderFactory = useCallback( + (rule: RuleResponse) => + rulesUpgradeState[rule.rule_id] ? ( + + ) : null, + [rulesUpgradeState] + ); const ruleActionsFactory = useCallback( (rule: RuleResponse, closeRulePreview: () => void) => { const ruleUpgradeState = rulesUpgradeState[rule.rule_id]; @@ -313,11 +310,19 @@ export const UpgradePrebuiltRulesTableContextProvider = ({ } const hasRuleTypeChange = ruleUpgradeState.diff.fields.type?.has_update ?? false; + const hasCustomizations = + ruleUpgradeState.current_rule.rule_source.type === 'external' && + ruleUpgradeState.current_rule.rule_source.is_customized; const shouldShowRuleTypeChangeCallout = hasRuleTypeChange && isPrebuiltRulesCustomizationEnabled; + let updateTabContent = ( : null} + header={ + shouldShowRuleTypeChangeCallout && ( + + ) + } ruleDiff={ruleUpgradeState.diff} /> ); @@ -327,7 +332,7 @@ export const UpgradePrebuiltRulesTableContextProvider = ({ // conflicts, only accept the target rule. if (isPrebuiltRulesCustomizationEnabled && !hasRuleTypeChange) { updateTabContent = ( - @@ -352,12 +357,12 @@ export const UpgradePrebuiltRulesTableContextProvider = ({ ), content: ( - +
- +
), }; @@ -366,11 +371,12 @@ export const UpgradePrebuiltRulesTableContextProvider = ({ [rulesUpgradeState, setRuleFieldResolvedValue, isPrebuiltRulesCustomizationEnabled] ); const filteredRules = useMemo( - () => filteredRuleUpgradeInfos.map((rule) => rule.target_rule), - [filteredRuleUpgradeInfos] + () => filteredRuleUpgradeStates.map(({ target_rule: targetRule }) => targetRule), + [filteredRuleUpgradeStates] ); const { rulePreviewFlyout, openRulePreview } = useRulePreviewFlyout({ rules: filteredRules, + subHeaderFactory, ruleActionsFactory, extraTabsFactory, flyoutProps: { @@ -383,22 +389,22 @@ export const UpgradePrebuiltRulesTableContextProvider = ({ () => ({ reFetchRules: refetch, upgradeRules, + upgradeAllRules, setFilterOptions, openRulePreview, }), - [refetch, upgradeRules, openRulePreview] + [refetch, upgradeRules, upgradeAllRules, openRulePreview] ); - const providerValue = useMemo(() => { - return { + const providerValue = useMemo( + () => ({ state: { - ruleUpgradeInfos, - rulesUpgradeState, + ruleUpgradeStates: filteredRuleUpgradeStates, hasRulesToUpgrade: isFetched && ruleUpgradeInfos.length > 0, filterOptions, tags, isFetched, - isLoading: isLoading || loadingJobs, + isLoading: isLoading || areMlJobsLoading, isRefetching, isUpgradingSecurityPackages, loadingRules, @@ -406,39 +412,29 @@ export const UpgradePrebuiltRulesTableContextProvider = ({ isPrebuiltRulesCustomizationEnabled, }, actions, - }; - }, [ - ruleUpgradeInfos, - rulesUpgradeState, - filterOptions, - tags, - isFetched, - isLoading, - loadingJobs, - isRefetching, - isUpgradingSecurityPackages, - loadingRules, - dataUpdatedAt, - actions, - isPrebuiltRulesCustomizationEnabled, - ]); + }), + [ + ruleUpgradeInfos.length, + filteredRuleUpgradeStates, + filterOptions, + tags, + isFetched, + isLoading, + areMlJobsLoading, + isRefetching, + isUpgradingSecurityPackages, + loadingRules, + dataUpdatedAt, + actions, + isPrebuiltRulesCustomizationEnabled, + ] + ); return ( <> - {isLegacyMLJobsModalVisible && ( - - )} - {isConflictsModalVisible && ( - - )} + {confirmLegacyMlJobsUpgradeModal} + {upgradeConflictsModal} {children} {rulePreviewFlyout} @@ -457,21 +453,15 @@ export const useUpgradePrebuiltRulesTableContext = (): UpgradePrebuiltRulesConte }; function constructRuleFieldsToUpgrade(ruleUpgradeState: RuleUpgradeState): RuleFieldsToUpgrade { - const finalRule = ruleUpgradeState.finalRule as Record; const ruleFieldsToUpgrade: Record = {}; - for (const fieldName of Object.keys(ruleUpgradeState.fieldsUpgradeState)) { - const fieldUpgradeState = ruleUpgradeState.fieldsUpgradeState[fieldName]; - - if (!isNonUpgradeableFieldName(fieldName) && fieldUpgradeState === FieldUpgradeState.Accepted) { - invariant( - fieldName in finalRule, - `Ready to upgrade field "${fieldName}" is not found in final rule` - ); - + for (const [fieldName, fieldUpgradeState] of Object.entries( + ruleUpgradeState.fieldsUpgradeState + )) { + if (fieldUpgradeState.state === FieldUpgradeStateEnum.Accepted) { ruleFieldsToUpgrade[fieldName] = { pick_version: 'RESOLVED', - resolved_value: finalRule[fieldName], + resolved_value: fieldUpgradeState.resolvedValue, }; } } diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_filter_prebuilt_rules_to_upgrade.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_filter_prebuilt_rules_to_upgrade.ts index b5a0e123d7510..a3dd45f8fabc0 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_filter_prebuilt_rules_to_upgrade.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_filter_prebuilt_rules_to_upgrade.ts @@ -6,7 +6,7 @@ */ import { useMemo } from 'react'; -import type { RuleUpgradeInfoForReview } from '../../../../../../common/api/detection_engine/prebuilt_rules'; +import type { RuleUpgradeState } from '../../../../rule_management/model/prebuilt_rule_upgrade'; import { RuleCustomizationEnum, type FilterOptions } from '../../../../rule_management/logic/types'; export type UpgradePrebuiltRulesTableFilterOptions = Pick< @@ -14,16 +14,19 @@ export type UpgradePrebuiltRulesTableFilterOptions = Pick< 'filter' | 'tags' | 'ruleSource' >; +interface UseFilterPrebuiltRulesToUpgradeParams { + data: RuleUpgradeState[]; + filterOptions: UpgradePrebuiltRulesTableFilterOptions; +} + export const useFilterPrebuiltRulesToUpgrade = ({ - rules, + data, filterOptions, -}: { - rules: RuleUpgradeInfoForReview[]; - filterOptions: UpgradePrebuiltRulesTableFilterOptions; -}) => { - const filteredRules = useMemo(() => { +}: UseFilterPrebuiltRulesToUpgradeParams): RuleUpgradeState[] => { + return useMemo(() => { const { filter, tags, ruleSource } = filterOptions; - return rules.filter((ruleInfo) => { + + return data.filter((ruleInfo) => { if (filter && !ruleInfo.current_rule.name.toLowerCase().includes(filter.toLowerCase())) { return false; } @@ -53,7 +56,5 @@ export const useFilterPrebuiltRulesToUpgrade = ({ return true; }); - }, [filterOptions, rules]); - - return filteredRules; + }, [filterOptions, data]); }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_ml_jobs_upgrade_modal/index.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_ml_jobs_upgrade_modal/index.ts new file mode 100644 index 0000000000000..470224e90a547 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_ml_jobs_upgrade_modal/index.ts @@ -0,0 +1,8 @@ +/* + * 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. + */ + +export * from './use_ml_jobs_upgrade_modal'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/modals/ml_job_upgrade_modal/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_ml_jobs_upgrade_modal/ml_jobs_upgrade_modal.tsx similarity index 80% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/modals/ml_job_upgrade_modal/index.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_ml_jobs_upgrade_modal/ml_jobs_upgrade_modal.tsx index 84c0a5a579ba6..37d6a84728aea 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/modals/ml_job_upgrade_modal/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_ml_jobs_upgrade_modal/ml_jobs_upgrade_modal.tsx @@ -5,9 +5,9 @@ * 2.0. */ +import React, { memo } from 'react'; import { EuiConfirmModal } from '@elastic/eui'; import type { MlSummaryJob } from '@kbn/ml-plugin/common'; -import React, { memo } from 'react'; import styled from 'styled-components'; import { rgba } from 'polished'; import * as i18n from './translations'; @@ -33,15 +33,17 @@ const JobsUL = styled.ul` } `; -export interface MlJobUpgradeModalProps { +interface OutdatedMlJobsUpgradeModalProps { jobs: MlSummaryJob[]; - onCancel: ( - event?: React.KeyboardEvent | React.MouseEvent - ) => void; - onConfirm?: (event: React.MouseEvent) => void; + onCancel: () => void; + onConfirm: () => void; } -const MlJobUpgradeModalComponent = ({ jobs, onCancel, onConfirm }: MlJobUpgradeModalProps) => { +export const OutdatedMlJobsUpgradeModal = memo(function LegacyMlJobsUpgradeModal({ + jobs, + onCancel, + onConfirm, +}: OutdatedMlJobsUpgradeModalProps): JSX.Element { return ( ); -}; - -export const MlJobUpgradeModal = memo(MlJobUpgradeModalComponent); +}); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/modals/ml_job_upgrade_modal/translations.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_ml_jobs_upgrade_modal/translations.tsx similarity index 95% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/modals/ml_job_upgrade_modal/translations.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_ml_jobs_upgrade_modal/translations.tsx index caf94e5c1a261..8250591de71cc 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/modals/ml_job_upgrade_modal/translations.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_ml_jobs_upgrade_modal/translations.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import { MlJobCompatibilityLink } from '../../../../../../../common/components/links_to_docs'; +import { MlJobCompatibilityLink } from '../../../../../../common/components/links_to_docs'; export const ML_JOB_UPGRADE_MODAL_TITLE = i18n.translate( 'xpack.securitySolution.detectionEngine.mlJobUpgradeModal.messageTitle', diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_ml_jobs_upgrade_modal/use_ml_jobs_upgrade_modal.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_ml_jobs_upgrade_modal/use_ml_jobs_upgrade_modal.tsx new file mode 100644 index 0000000000000..cb4682f49a603 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_ml_jobs_upgrade_modal/use_ml_jobs_upgrade_modal.tsx @@ -0,0 +1,46 @@ +/* + * 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 type { ReactNode } from 'react'; +import React, { useCallback } from 'react'; +import { useBoolean } from '@kbn/react-hooks'; +import { useInstalledSecurityJobs } from '../../../../../../common/components/ml/hooks/use_installed_security_jobs'; +import { affectedJobIds } from '../../../../../../../common/machine_learning/affected_job_ids'; +import { useAsyncConfirmation } from '../../rules_table/use_async_confirmation'; +import { OutdatedMlJobsUpgradeModal } from './ml_jobs_upgrade_modal'; + +interface UseOutdatedMlJobsUpgradeModalResult { + modal: ReactNode; + isLoading: boolean; + confirmLegacyMLJobs: () => Promise; +} + +export function useOutdatedMlJobsUpgradeModal(): UseOutdatedMlJobsUpgradeModalResult { + const [isVisible, { on: showModal, off: hideModal }] = useBoolean(false); + const { loading, jobs } = useInstalledSecurityJobs(); + const legacyJobsInstalled = jobs.filter((job) => affectedJobIds.includes(job.id)); + const [confirmLegacyMLJobs, confirm, cancel] = useAsyncConfirmation({ + onInit: showModal, + onFinish: hideModal, + }); + + const handleLegacyMLJobsConfirm = useCallback(async () => { + if (legacyJobsInstalled.length > 0) { + return confirmLegacyMLJobs(); + } + + return true; + }, [confirmLegacyMLJobs, legacyJobsInstalled]); + + return { + modal: isVisible && ( + + ), + confirmLegacyMLJobs: handleLegacyMLJobsConfirm, + isLoading: loading, + }; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_prebuilt_rules_upgrade_state.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_prebuilt_rules_upgrade_state.ts index b50ca7da1849d..81d64b1b39945 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_prebuilt_rules_upgrade_state.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_prebuilt_rules_upgrade_state.ts @@ -12,16 +12,16 @@ import type { FieldsUpgradeState, SetRuleFieldResolvedValueFn, } from '../../../../rule_management/model/prebuilt_rule_upgrade'; -import { FieldUpgradeState } from '../../../../rule_management/model/prebuilt_rule_upgrade'; +import { FieldUpgradeStateEnum } from '../../../../rule_management/model/prebuilt_rule_upgrade'; import { type FieldsDiff, type DiffableAllFields, - type DiffableRule, type RuleUpgradeInfoForReview, ThreeWayDiffConflict, type RuleSignatureId, + NON_UPGRADEABLE_DIFFABLE_FIELDS, } from '../../../../../../common/api/detection_engine'; -import { convertRuleToDiffable } from '../../../../../../common/detection_engine/prebuilt_rules/diff/convert_rule_to_diffable'; +import { assertUnreachable } from '../../../../../../common/utility_types'; type RuleResolvedConflicts = Partial; type RulesResolvedConflicts = Record; @@ -54,21 +54,23 @@ export function usePrebuiltRulesUpgradeState( const state: RulesUpgradeState = {}; for (const ruleUpgradeInfo of ruleUpgradeInfos) { + const fieldsUpgradeState = calcFieldsState( + ruleUpgradeInfo.diff.fields, + rulesResolvedConflicts[ruleUpgradeInfo.rule_id] ?? {} + ); + + const hasRuleTypeChange = Boolean(ruleUpgradeInfo.diff.fields.type); + const hasFieldConflicts = Object.values(fieldsUpgradeState).some( + ({ state: fieldState }) => + fieldState === FieldUpgradeStateEnum.SolvableConflict || + fieldState === FieldUpgradeStateEnum.NonSolvableConflict + ); + state[ruleUpgradeInfo.rule_id] = { ...ruleUpgradeInfo, - finalRule: calcFinalDiffableRule( - ruleUpgradeInfo, - rulesResolvedConflicts[ruleUpgradeInfo.rule_id] ?? {} - ), - fieldsUpgradeState: calcFieldsState( - ruleUpgradeInfo.diff.fields, - rulesResolvedConflicts[ruleUpgradeInfo.rule_id] ?? {} - ), + fieldsUpgradeState, hasUnresolvedConflicts: isPrebuiltRulesCustomizationEnabled - ? getUnacceptedConflictsCount( - ruleUpgradeInfo.diff.fields, - rulesResolvedConflicts[ruleUpgradeInfo.rule_id] ?? {} - ) > 0 + ? hasRuleTypeChange || hasFieldConflicts : false, }; } @@ -82,76 +84,49 @@ export function usePrebuiltRulesUpgradeState( }; } -function calcFinalDiffableRule( - ruleUpgradeInfo: RuleUpgradeInfoForReview, - ruleResolvedConflicts: RuleResolvedConflicts -): DiffableRule { - return { - ...convertRuleToDiffable(ruleUpgradeInfo.target_rule), - ...convertRuleFieldsDiffToDiffable(ruleUpgradeInfo.diff.fields), - ...ruleResolvedConflicts, - } as DiffableRule; -} - -/** - * Assembles a `DiffableRule` from rule fields diff `merged_version`s. - */ -function convertRuleFieldsDiffToDiffable( - ruleFieldsDiff: FieldsDiff> -): Partial { - const mergeVersionRule: Record = {}; - - for (const fieldName of Object.keys(ruleFieldsDiff)) { - mergeVersionRule[fieldName] = ruleFieldsDiff[fieldName].merged_version; - } - - return mergeVersionRule; -} +const NON_UPGRADEABLE_DIFFABLE_FIELDS_SET: Readonly> = new Set( + NON_UPGRADEABLE_DIFFABLE_FIELDS +); function calcFieldsState( - ruleFieldsDiff: FieldsDiff>, + fieldsDiff: FieldsDiff>, ruleResolvedConflicts: RuleResolvedConflicts ): FieldsUpgradeState { const fieldsState: FieldsUpgradeState = {}; - for (const fieldName of Object.keys(ruleFieldsDiff)) { - switch (ruleFieldsDiff[fieldName].conflict) { + for (const fieldName of Object.keys(fieldsDiff)) { + if (NON_UPGRADEABLE_DIFFABLE_FIELDS_SET.has(fieldName)) { + // eslint-disable-next-line no-continue + continue; + } + + const fieldDiff = fieldsDiff[fieldName]; + + switch (fieldDiff.conflict) { case ThreeWayDiffConflict.NONE: - fieldsState[fieldName] = FieldUpgradeState.Accepted; + fieldsState[fieldName] = { + state: fieldDiff.has_update + ? FieldUpgradeStateEnum.NoConflict + : FieldUpgradeStateEnum.NoUpdate, + }; break; case ThreeWayDiffConflict.SOLVABLE: - fieldsState[fieldName] = FieldUpgradeState.SolvableConflict; + fieldsState[fieldName] = { state: FieldUpgradeStateEnum.SolvableConflict }; break; case ThreeWayDiffConflict.NON_SOLVABLE: - fieldsState[fieldName] = FieldUpgradeState.NonSolvableConflict; + fieldsState[fieldName] = { state: FieldUpgradeStateEnum.NonSolvableConflict }; break; + + default: + assertUnreachable(fieldDiff.conflict); } } - for (const fieldName of Object.keys(ruleResolvedConflicts)) { - fieldsState[fieldName] = FieldUpgradeState.Accepted; + for (const [fieldName, resolvedValue] of Object.entries(ruleResolvedConflicts)) { + fieldsState[fieldName] = { state: FieldUpgradeStateEnum.Accepted, resolvedValue }; } return fieldsState; } - -function getUnacceptedConflictsCount( - ruleFieldsDiff: FieldsDiff>, - ruleResolvedConflicts: RuleResolvedConflicts -): number { - const fieldNames = Object.keys(ruleFieldsDiff); - const fieldNamesWithConflict = fieldNames.filter( - (fieldName) => ruleFieldsDiff[fieldName].conflict !== ThreeWayDiffConflict.NONE - ); - const fieldNamesWithConflictSet = new Set(fieldNamesWithConflict); - - for (const resolvedConflictField of Object.keys(ruleResolvedConflicts)) { - if (fieldNamesWithConflictSet.has(resolvedConflictField)) { - fieldNamesWithConflictSet.delete(resolvedConflictField); - } - } - - return fieldNamesWithConflictSet.size; -} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_modals.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_modals.tsx deleted file mode 100644 index 256ccf47c194f..0000000000000 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_modals.tsx +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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 { useCallback } from 'react'; -import { useInstalledSecurityJobs } from '../../../../../common/components/ml/hooks/use_installed_security_jobs'; -import { useBoolState } from '../../../../../common/hooks/use_bool_state'; -import { affectedJobIds } from '../../../../../../common/machine_learning/affected_job_ids'; -import { useAsyncConfirmation } from '../rules_table/use_async_confirmation'; - -export const useMlJobUpgradeModal = () => { - const [isVisible, showModal, hideModal] = useBoolState(false); - const { loading: loadingJobs, jobs } = useInstalledSecurityJobs(); - const legacyJobsInstalled = jobs.filter((job) => affectedJobIds.includes(job.id)); - const [confirmLegacyMLJobs, handleConfirm, handleCancel] = useAsyncConfirmation({ - onInit: showModal, - onFinish: hideModal, - }); - - const handleLegacyMLJobsConfirm = useCallback(async () => { - if (legacyJobsInstalled.length > 0) { - return confirmLegacyMLJobs(); - } - return true; - }, [confirmLegacyMLJobs, legacyJobsInstalled]); - - return { - isVisible, - legacyJobsInstalled, - confirmLegacyMLJobs: handleLegacyMLJobsConfirm, - handleConfirm, - handleCancel, - loadingJobs, - }; -}; - -export const useUpgradeConflictsModal = () => { - const [isVisible, showModal, hideModal] = useBoolState(false); - const [confirmConflictsUpgrade, handleConfirm, handleCancel] = useAsyncConfirmation({ - onInit: showModal, - onFinish: hideModal, - }); - - return { - isVisible, - confirmConflictsUpgrade, - handleConfirm, - handleCancel, - }; -}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_prebuilt_rules_table_columns.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_prebuilt_rules_table_columns.tsx index c2b1f8e3dbe46..919664c100b2f 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_prebuilt_rules_table_columns.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_prebuilt_rules_table_columns.tsx @@ -59,7 +59,7 @@ const RULE_NAME_COLUMN: TableColumn = { field: 'current_rule.name', name: i18n.COLUMN_RULE, render: (value: RuleUpgradeState['current_rule']['name'], ruleUpgradeState: RuleUpgradeState) => ( - + ), sortable: true, truncateText: true, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_with_conflicts_modal/index.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_with_conflicts_modal/index.ts new file mode 100644 index 0000000000000..7a01864683869 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_with_conflicts_modal/index.ts @@ -0,0 +1,8 @@ +/* + * 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. + */ + +export * from './use_upgrade_modal'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/modals/upgrade_conflicts_modal/translations.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_with_conflicts_modal/translations.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/modals/upgrade_conflicts_modal/translations.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_with_conflicts_modal/translations.tsx diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/modals/upgrade_conflicts_modal/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_with_conflicts_modal/upgrade_modal.tsx similarity index 63% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/modals/upgrade_conflicts_modal/index.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_with_conflicts_modal/upgrade_modal.tsx index 0c664398c51f6..3374ae5c16b4d 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/modals/upgrade_conflicts_modal/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_with_conflicts_modal/upgrade_modal.tsx @@ -9,14 +9,15 @@ import { EuiConfirmModal, EuiText } from '@elastic/eui'; import React, { memo } from 'react'; import * as i18n from './translations'; -export interface UpgradeConflictsModalProps { - onCancel: ( - event?: React.KeyboardEvent | React.MouseEvent - ) => void; - onConfirm?: (event: React.MouseEvent) => void; +interface UpgradeWithConflictsModalProps { + onCancel: () => void; + onConfirm: () => void; } -const UpgradeConflictsModalComponent = ({ onCancel, onConfirm }: UpgradeConflictsModalProps) => { +export const UpgradeWithConflictsModal = memo(function ConfirmUpgradeWithConflictsModal({ + onCancel, + onConfirm, +}: UpgradeWithConflictsModalProps): JSX.Element { return ( {i18n.UPGRADE_CONFLICTS_MODAL_BODY} ); -}; - -export const UpgradeConflictsModal = memo(UpgradeConflictsModalComponent); +}); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_with_conflicts_modal/use_upgrade_modal.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_with_conflicts_modal/use_upgrade_modal.tsx new file mode 100644 index 0000000000000..0714ba458d34e --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_with_conflicts_modal/use_upgrade_modal.tsx @@ -0,0 +1,30 @@ +/* + * 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 type { ReactNode } from 'react'; +import React from 'react'; +import { useBoolean } from '@kbn/react-hooks'; +import { useAsyncConfirmation } from '../../rules_table/use_async_confirmation'; +import { UpgradeWithConflictsModal } from './upgrade_modal'; + +interface UseUpgradeWithConflictsModalResult { + modal: ReactNode; + confirmConflictsUpgrade: () => Promise; +} + +export function useUpgradeWithConflictsModal(): UseUpgradeWithConflictsModalResult { + const [isVisible, { on: showModal, off: hideModal }] = useBoolean(false); + const [confirmConflictsUpgrade, confirm, cancel] = useAsyncConfirmation({ + onInit: showModal, + onFinish: hideModal, + }); + + return { + modal: isVisible && , + confirmConflictsUpgrade, + }; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_rule_preview_flyout.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_rule_preview_flyout.tsx index d6dcdd0592b85..0c16a5c6ed165 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_rule_preview_flyout.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_rule_preview_flyout.tsx @@ -17,6 +17,7 @@ interface UseRulePreviewFlyoutParams { rules: RuleResponse[]; ruleActionsFactory: (rule: RuleResponse, closeRulePreview: () => void) => ReactNode; extraTabsFactory?: (rule: RuleResponse) => EuiTabbedContentTab[]; + subHeaderFactory?: (rule: RuleResponse) => ReactNode; flyoutProps: RulePreviewFlyoutProps; } @@ -38,10 +39,15 @@ export function useRulePreviewFlyout({ rules, extraTabsFactory, ruleActionsFactory, + subHeaderFactory, flyoutProps, }: UseRulePreviewFlyoutParams): UseRulePreviewFlyoutResult { const [rule, setRuleForPreview] = useState(); const closeRulePreview = useCallback(() => setRuleForPreview(undefined), []); + const subHeader = useMemo( + () => (rule ? subHeaderFactory?.(rule) : null), + [subHeaderFactory, rule] + ); const ruleActions = useMemo( () => rule && ruleActionsFactory(rule, closeRulePreview), [rule, ruleActionsFactory, closeRulePreview] @@ -61,13 +67,14 @@ export function useRulePreviewFlyout({ closeFlyout={closeRulePreview} ruleActions={ruleActions} extraTabs={extraTabs} + subHeader={subHeader} /> ), openRulePreview: useCallback( (ruleId: RuleSignatureId) => { - const ruleToShowInFlyout = rules.find((x) => x.id === ruleId); + const ruleToShowInFlyout = rules.find((x) => x.rule_id === ruleId); - invariant(ruleToShowInFlyout, `Rule with id ${ruleId} not found`); + invariant(ruleToShowInFlyout, `Rule with rule_id ${ruleId} not found`); setRuleForPreview(ruleToShowInFlyout); }, [rules, setRuleForPreview]