diff --git a/src/platform/packages/shared/kbn-doc-links/src/get_doc_links.ts b/src/platform/packages/shared/kbn-doc-links/src/get_doc_links.ts index b6cccc6ff37e5..f44e37c29d385 100644 --- a/src/platform/packages/shared/kbn-doc-links/src/get_doc_links.ts +++ b/src/platform/packages/shared/kbn-doc-links/src/get_doc_links.ts @@ -468,9 +468,8 @@ export const getDocLinks = ({ kibanaBranch, buildFlavor }: GetDocLinkOptions): D manageDetectionRules: `${ELASTIC_DOCS}solutions/security/detect-and-alert/manage-detection-rules`, createDetectionRules: `${ELASTIC_DOCS}solutions/security/detect-and-alert/create-detection-rule`, updatePrebuiltDetectionRules: `${ELASTIC_DOCS}solutions/security/detect-and-alert/install-manage-elastic-prebuilt-rules#update-prebuilt-rules`, - prebuiltRuleCustomizationPromoBlog: isServerless - ? '' // URL for Serverless to be added later, once the blog post is published. Issue: https://github.com/elastic/kibana/issues/209000 - : `https://www.elastic.co/blog/security-prebuilt-rules-editing`, + prebuiltRuleCustomizationPromoBlog: `${ELASTIC_WEBSITE_URL}blog/security-prebuilt-rules-editing`, + resolvePrebuiltRuleConflicts: `${ELASTIC_DOCS}solutions/security/detect-and-alert/prebuilt-rules-update-modified-unmodified#resolve-reduce-rule-conflicts`, createEsqlRuleType: `${ELASTIC_DOCS}solutions/security/detect-and-alert/create-detection-rule#create-esql-rule`, ruleUiAdvancedParams: `${ELASTIC_DOCS}solutions/security/detect-and-alert/create-detection-rule#rule-ui-advanced-params`, thirdPartyLlmProviders: `${ELASTIC_DOCS}solutions/security/ai/set-up-connectors-for-large-language-models-llm`, diff --git a/src/platform/packages/shared/kbn-doc-links/src/types.ts b/src/platform/packages/shared/kbn-doc-links/src/types.ts index 12e8c0d96b00d..73aaee795ea50 100644 --- a/src/platform/packages/shared/kbn-doc-links/src/types.ts +++ b/src/platform/packages/shared/kbn-doc-links/src/types.ts @@ -331,6 +331,7 @@ export interface DocLinks { readonly createDetectionRules: string; readonly updatePrebuiltDetectionRules: string; readonly prebuiltRuleCustomizationPromoBlog: string; + readonly resolvePrebuiltRuleConflicts: string; readonly createEsqlRuleType: string; readonly ruleUiAdvancedParams: string; readonly entityAnalytics: { 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 0d36a376b57b6..f84e58971a81b 100644 --- a/x-pack/platform/plugins/private/translations/translations/fr-FR.json +++ b/x-pack/platform/plugins/private/translations/translations/fr-FR.json @@ -37358,13 +37358,6 @@ "xpack.securitySolution.detectionEngine.translationDetails.translationTab.statusTitle": "Statut de la traduction", "xpack.securitySolution.detectionEngine.upgradeConflictsModal.cancelTitle": "Annuler", "xpack.securitySolution.detectionEngine.upgradeConflictsModal.messageTitle": "Exclure les règles avec des conflits ?", - "xpack.securitySolution.detectionEngine.upgradeConflictsModal.onlyNonSolvableConflicts": "{numOfRulesStrong} {numOfRules, plural, =1 {règle sélectionnée contient} other {règles sélectionnées contiennent}} des conflits non résolus. Les règles présentant des conflits non résolus ne peuvent pas être mises à jour en bloc. Vous devez résoudre manuellement les conflits avant d'effectuer la mise à jour.", - "xpack.securitySolution.detectionEngine.upgradeConflictsModal.onlyRulesWithConflicts": "Les règles sélectionnées présentent des conflits. Pour mettre à jour les règles en toute sécurité, nous vous recommandons de résoudre les conflits depuis le menu volant de mise à jour des règles.", - "xpack.securitySolution.detectionEngine.upgradeConflictsModal.onlySolvableConflicts": "{numOfRules, plural, =1 {règle sélectionnée contient} other {règles sélectionnées contiennent}} des conflits résolus automatiquement. Pour mettre à jour en toute sécurité {numOfRules, plural, =1 {la règle} other {les règles}}, nous vous recommandons de résoudre les conflits depuis le menu volant de mise à jour de la règle.", - "xpack.securitySolution.detectionEngine.upgradeConflictsModal.proceedWhenNoConcerns": "Si vous êtes satisfait et souhaitez poursuivre la mise à jour, cliquez sur {updateRules}.", - "xpack.securitySolution.detectionEngine.upgradeConflictsModal.proceedWithConflictFreeRules": "Cliquez sur {updateRules} pour mettre à jour {numOfRulesWithoutConflictsStrong} {numOfRulesWithoutConflicts, plural, =1 {la règle sans conflit} other {les règles sans conflits}} et {numOfRulesWithSolvableConflictsStrong} {numOfRulesWithSolvableConflicts, plural, =1 {rule} other {règles}} avec des conflits résolus automatiquement.", - "xpack.securitySolution.detectionEngine.upgradeConflictsModal.rulesWithoutConflictsAndRulesWithNonSolvableConflicts": "{numOfRulesWithNonSolvableConflictsStrong} des {numOfRulesStrong} règles sélectionnées {numOfRulesWithNonSolvableConflicts, plural, =1 {has} other {contiennent}} des conflits non résolus, qui ne peuvent pas être mis à jour en bloc tant que vous ne les avez pas corrigés manuellement.", - "xpack.securitySolution.detectionEngine.upgradeConflictsModal.unresolvedConflictsCanNotBeBulkUpdated": "Il est impossible de mettre à jour en bloc {numOfRulesWithNonSolvableConflictsStrong} sur {numOfRulesStrong} {numOfRules, plural, =1 {règle sélectionnée} other {règles sélectionnées}} contenant des conflits non résolus.. Vous devez résoudre manuellement les conflits avant d'effectuer la mise à jour.", "xpack.securitySolution.detectionEngine.upgradeConflictsModal.upgradeRulesWithConflicts": "Mise à jour {numOfRules, plural, =1 {rule} other {règles}}", "xpack.securitySolution.detectionEngine.upgradeConflictsModal.upgradeRulesWithoutConflicts": "Mettre à jour {rulesCount, plural, =1 {rule} other {règles}} sans conflits", "xpack.securitySolution.detectionEngine.upgradeFlyout.baseVersionMissingDescription": "La version d'origine non modifiée de cette règle Elastic est introuvable. Cela arrive parfois lorsqu'une règle n'a pas été mise à jour depuis un certain temps. Vous pouvez toujours mettre à jour cette règle, mais vous n'aurez accès qu'à sa version actuelle et à la prochaine mise à jour Elastic. Une mise à jour plus fréquente des règles Elastic peut vous aider à éviter ce problème à l'avenir. Nous vous invitons à examiner attentivement cette mise à jour et à vous assurer que vos modifications ne sont pas accidentellement écrasées.", 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 c6136c351e5ad..f10ea2f91fe5f 100644 --- a/x-pack/platform/plugins/private/translations/translations/ja-JP.json +++ b/x-pack/platform/plugins/private/translations/translations/ja-JP.json @@ -37395,17 +37395,8 @@ "xpack.securitySolution.detectionEngine.stepDefineRule.dataViewNotFoundLabel": "選択したデータビューが見つかりません", "xpack.securitySolution.detectionEngine.stepDefineRule.pickDataView": "データビューを選択", "xpack.securitySolution.detectionEngine.translationDetails.translationTab.statusTitle": "変換ステータス", - "xpack.securitySolution.detectionEngine.upgradeConflictsModal.allKindsOfRules": "選択した{numOfRulesStrong}件のうち{numOfRulesWithConflictsStrong}件のルールに競合があります。自動解決された競合のある{numOfRulesWithSolvableConflictsStrong}件の {numOfRulesWithSolvableConflicts, plural, =1 {rule} other {ルール}}を安全に更新するには、ルール更新フライアウトから競合に対処することをお勧めします。未解決の競合がある{numOfRulesWithNonSolvableConflictsStrong} {numOfRulesWithNonSolvableConflicts, plural, =1 {rule} other {ルール}}は、手動で修正するまで一括更新できません。", "xpack.securitySolution.detectionEngine.upgradeConflictsModal.cancelTitle": "キャンセル", "xpack.securitySolution.detectionEngine.upgradeConflictsModal.messageTitle": "競合するルールを除外しますか?", - "xpack.securitySolution.detectionEngine.upgradeConflictsModal.onlyNonSolvableConflicts": "{numOfRulesStrong}件の選択した{numOfRules, plural, =1 {rule has} other {ルールに}}未解決の競合があります。未解決の競合があるルールは一括更新できません。更新する前に競合を手動で修正する必要があります。", - "xpack.securitySolution.detectionEngine.upgradeConflictsModal.onlyRulesWithConflicts": "選択したルールに競合があります。ルールを安全に更新するには、ルールの更新フライアウトから競合に対処することをお勧めします。", - "xpack.securitySolution.detectionEngine.upgradeConflictsModal.onlySolvableConflicts": "選択した{numOfRules, plural, =1 {rule has} other {件のルール}}で競合が自動的に解決されました。{numOfRules, plural, =1 {rule} other {ルール}}を安全に更新するには、ルールの更新フライアウトから競合に対処することをお勧めします。", - "xpack.securitySolution.detectionEngine.upgradeConflictsModal.proceedWhenNoConcerns": "問題がなく、更新を続行する場合は、[{updateRules}] をクリックします。", - "xpack.securitySolution.detectionEngine.upgradeConflictsModal.proceedWithConflictFreeRules": "{updateRules}をクリックして、競合のない{numOfRulesWithoutConflictsStrong}件の {numOfRulesWithoutConflicts, plural, =1 {rule} other {ルール}}と自動解決された競合がある {numOfRulesWithSolvableConflictsStrong}件の{numOfRulesWithSolvableConflicts, plural, =1 {rule} other {ルール}}を更新します。", - "xpack.securitySolution.detectionEngine.upgradeConflictsModal.rulesWithoutConflictsAndRulesWithNonSolvableConflicts": "選択した{numOfRulesStrong}件のルールのうち{numOfRulesWithNonSolvableConflictsStrong}件には{numOfRulesWithNonSolvableConflicts, plural, =1 {has} other {}}未解決の競合があり、手動で解決するまで一括更新できません。", - "xpack.securitySolution.detectionEngine.upgradeConflictsModal.rulesWithoutConflictsAndRulesWithSolvableConflicts": "選択した{numOfRulesStrong}件のルールのうち{numOfRulesWithSolvableConflictsStrong}件の{numOfRules, plural, =1 {rule has} other {ルールに}}自動解決された競合があります。安全に更新するには、ルール更新フライアウトから競合に対処することをお勧めします。", - "xpack.securitySolution.detectionEngine.upgradeConflictsModal.unresolvedConflictsCanNotBeBulkUpdated": "選択した{numOfRulesStrong}件の{numOfRules, plural, =1 {rule} other {ルール}}のうち未解決の競合がある{numOfRulesWithNonSolvableConflictsStrong}件は一括更新できません。更新する前に競合を手動で修正する必要があります。", "xpack.securitySolution.detectionEngine.upgradeConflictsModal.upgradeRulesWithConflicts": "{numOfRules, plural, =1 {rule} other {個のルール}}を更新", "xpack.securitySolution.detectionEngine.upgradeConflictsModal.upgradeRulesWithoutConflicts": "{rulesCount, plural, =1 {rule} other {個のルール}}を競合なしで更新", "xpack.securitySolution.detectionEngine.upgradeFlyout.baseVersionMissingDescription": "このElasticルールの元の未編集のバージョンが見つかりませんでした。この状況は、ルールがしばらく更新されていない場合に発生することがあります。このルールを更新することはできますが、アクセスできるのは現在のバージョンと受信するElastic更新のみです。Elasticルールの更新頻度を上げると、今後、この状況を回避できます。この更新を注意深くレビューし、変更が誤って上書きされていないことを確認することをお勧めします。", 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 b13c338b97763..6899b0da928a7 100644 --- a/x-pack/platform/plugins/private/translations/translations/zh-CN.json +++ b/x-pack/platform/plugins/private/translations/translations/zh-CN.json @@ -37385,9 +37385,6 @@ "xpack.securitySolution.detectionEngine.translationDetails.translationTab.statusTitle": "转换状态", "xpack.securitySolution.detectionEngine.upgradeConflictsModal.cancelTitle": "取消", "xpack.securitySolution.detectionEngine.upgradeConflictsModal.messageTitle": "排除有冲突的规则?", - "xpack.securitySolution.detectionEngine.upgradeConflictsModal.onlyRulesWithConflicts": "选定的规则存在冲突。为了安全地更新规则,我们建议从规则的更新浮出控件中解决冲突。", - "xpack.securitySolution.detectionEngine.upgradeConflictsModal.onlySolvableConflicts": "选定的{numOfRules, plural, =1 {规则已} other {规则已}}自动解决冲突。要安全地更新{numOfRules, plural, =1 {规则} other {规则}},我们建议从规则更新浮出控件中解决冲突。", - "xpack.securitySolution.detectionEngine.upgradeConflictsModal.proceedWhenNoConcerns": "如果您没有任何顾虑并想继续更新,请单击{updateRules}。", "xpack.securitySolution.detectionEngine.upgradeConflictsModal.upgradeRulesWithConflicts": "更新 {numOfRules, plural, =1 {rule} other {规则}}", "xpack.securitySolution.detectionEngine.upgradeConflictsModal.upgradeRulesWithoutConflicts": "更新无冲突的{rulesCount, plural, =1 {规则} other {规则}}", "xpack.securitySolution.detectionEngine.upgradeFlyout.baseVersionMissingDescription": "找不到此 Elastic 规则的未编辑原始版本。有时,一段时间未更新某个规则时,会出现这种情况。您仍然可以更新此规则,但只能访问其当前版本和传入的 Elastic 更新。经常更新 Elastic 规则可帮助您在未来避免这种情况。建议您仔细复查此更新,并确保不会无意中覆盖您的更改。", diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/hooks/use_prebuilt_rules_upgrade.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/hooks/use_prebuilt_rules_upgrade.tsx index d612dc2dac973..c38e345c21596 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/hooks/use_prebuilt_rules_upgrade.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/hooks/use_prebuilt_rules_upgrade.tsx @@ -42,7 +42,7 @@ import { RuleDiffTab } from '../components/rule_details/rule_diff_tab'; import { useRulePreviewFlyout } from '../../rule_management_ui/components/rules_table/use_rule_preview_flyout'; import type { UpgradePrebuiltRulesSortingOptions } from '../../rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table_context'; import { RULES_TABLE_INITIAL_PAGE_SIZE } from '../../rule_management_ui/components/rules_table/constants'; -import type { RulesConflictStats } from '../../rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_with_conflicts_modal/upgrade_modal'; +import type { RulesConflictStats } from '../../rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_with_conflicts_modal/conflicts_description'; const REVIEW_PREBUILT_RULES_UPGRADE_REFRESH_INTERVAL = 5 * 60 * 1000; diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_with_conflicts_modal/conflicts_description.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_with_conflicts_modal/conflicts_description.test.tsx new file mode 100644 index 0000000000000..1047bd3f3a435 --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_with_conflicts_modal/conflicts_description.test.tsx @@ -0,0 +1,148 @@ +/* + * 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 { render } from '@testing-library/react'; +import React from 'react'; +import { ConflictsDescription } from './conflicts_description'; +import { TestProviders } from '../../../../../../common/mock'; + +// Removes extra whitespace from the text content to make it easier to compare +function normalizeText(text: string | null): string { + return (text ?? '').replace(/\s+/g, ' ').trim(); +} + +describe('UpgradeConflictsDescription displays proper text when there are', () => { + it('only rules with solvable conflicts', () => { + const { container } = render( + , + { wrapper: TestProviders } + ); + + const expectedText = [ + 'Rules with auto-resolved conflicts: 5', + '5 rules with auto-resolved conflicts can still be updated. Choose one of the following options:', + 'Use the rule update flyout to address auto-resolved conflicts. This is the safest option and gives you more control over the final update. Learn more(external, opens in a new tab or window)', + 'Click Update rules to bulk-update rules with auto-resolved conflicts and rules without conflicts.', + 'Only choose this option if you’re comfortable accepting the fixes Elastic suggested.', + ].join(''); + + expect(normalizeText(container.textContent)).toBe(normalizeText(expectedText)); + }); + + it('only rules with non-solvable conflicts', () => { + const { container } = render( + , + { wrapper: TestProviders } + ); + + const expectedText = [ + 'Rules with unresolved conflicts: 5', + '5 rules with unresolved conflicts can’t be updated until you fix the conflicts.', + ].join(''); + + expect(normalizeText(container.textContent)).toBe(normalizeText(expectedText)); + }); + + it('rules with solvable conflicts and rules with non-solvable conflicts', () => { + const { container } = render( + , + { wrapper: TestProviders } + ); + + const expectedText = [ + 'Rules with unresolved conflicts: 5', + 'Rules with auto-resolved conflicts: 3', + '5 rules with unresolved conflicts can’t be updated until you fix the conflicts.', + '3 rules with auto-resolved conflicts can still be updated. Choose one of the following options:', + 'Use the rule update flyout to address auto-resolved conflicts. This is the safest option and gives you more control over the final update. Learn more(external, opens in a new tab or window)', + 'Click Update rules to bulk-update rules with auto-resolved conflicts and rules without conflicts.', + 'Only choose this option if you’re comfortable accepting the fixes Elastic suggested.', + ].join(''); + + expect(normalizeText(container.textContent)).toBe(normalizeText(expectedText)); + }); + + it('rules with solvable conflicts and conflict-free rules', () => { + const { container } = render( + , + { wrapper: TestProviders } + ); + + const expectedText = [ + 'Rules with auto-resolved conflicts: 3', + 'Rules without conflicts: 10', + '3 rules with auto-resolved conflicts can still be updated. Choose one of the following options:', + 'Use the rule update flyout to address auto-resolved conflicts. This is the safest option and gives you more control over the final update. Learn more(external, opens in a new tab or window)', + 'Click Update rules to bulk-update rules with auto-resolved conflicts and rules without conflicts.', + 'Only choose this option if you’re comfortable accepting the fixes Elastic suggested.', + '10 rules without conflicts can still be updated by clicking Update rules without conflicts. Choose this option if you only want to update rules without conflicts.', + ].join(''); + + expect(normalizeText(container.textContent)).toBe(normalizeText(expectedText)); + }); + + it('rules with non-solvable conflicts and conflict-free rules', () => { + const { container } = render( + , + { wrapper: TestProviders } + ); + + const expectedText = [ + 'Rules with unresolved conflicts: 5', + 'Rules without conflicts: 10', + '5 rules with unresolved conflicts can’t be updated until you fix the conflicts.', + '10 rules without conflicts can still be updated by clicking Update rules without conflicts. Choose this option if you only want to update rules without conflicts.', + ].join(''); + + expect(normalizeText(container.textContent)).toBe(normalizeText(expectedText)); + }); + + it('rules with non-solvable conflicts, rules with solvable conflicts and conflict-free rules', () => { + const { container } = render( + , + { wrapper: TestProviders } + ); + + const expectedText = [ + 'Rules with unresolved conflicts: 5', + 'Rules with auto-resolved conflicts: 3', + 'Rules without conflicts: 10', + '5 rules with unresolved conflicts can’t be updated until you fix the conflicts.', + '3 rules with auto-resolved conflicts can still be updated. Choose one of the following options:', + 'Use the rule update flyout to address auto-resolved conflicts. This is the safest option and gives you more control over the final update. Learn more(external, opens in a new tab or window)', + 'Click Update rules to bulk-update rules with auto-resolved conflicts and rules without conflicts.', + 'Only choose this option if you’re comfortable accepting the fixes Elastic suggested.', + '10 rules without conflicts can still be updated by clicking Update rules without conflicts. Choose this option if you only want to update rules without conflicts.', + ].join(''); + + expect(normalizeText(container.textContent)).toBe(normalizeText(expectedText)); + }); +}); diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_with_conflicts_modal/conflicts_description.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_with_conflicts_modal/conflicts_description.tsx new file mode 100644 index 0000000000000..66d3d8b484e86 --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_with_conflicts_modal/conflicts_description.tsx @@ -0,0 +1,58 @@ +/* + * 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 { EuiText } from '@elastic/eui'; +import React from 'react'; +import * as i18n from './translations'; + +export interface RulesConflictStats { + numOfRulesWithoutConflicts: number; + numOfRulesWithSolvableConflicts: number; + numOfRulesWithNonSolvableConflicts: number; +} + +export function ConflictsDescription({ + numOfRulesWithoutConflicts, + numOfRulesWithSolvableConflicts, + numOfRulesWithNonSolvableConflicts, +}: RulesConflictStats): JSX.Element { + return ( + +

+ {numOfRulesWithNonSolvableConflicts > 0 && ( + <> + {i18n.RULES_WITH_NON_SOLVABLE_CONFLICTS_TOTAL(numOfRulesWithNonSolvableConflicts)} +
+ + )} + {numOfRulesWithSolvableConflicts > 0 && ( + <> + {i18n.RULES_WITH_SOLVABLE_CONFLICTS_TOTAL(numOfRulesWithSolvableConflicts)} +
+ + )} + {numOfRulesWithoutConflicts > 0 && ( + <> + {i18n.RULES_WITHOUT_CONFLICTS_TOTAL(numOfRulesWithoutConflicts)} +
+ + )} +

+ {numOfRulesWithNonSolvableConflicts > 0 && ( +

{i18n.RULES_WITH_NON_SOLVABLE_CONFLICTS_GUIDANCE(numOfRulesWithNonSolvableConflicts)}

+ )} + {numOfRulesWithSolvableConflicts > 0 && + i18n.RULES_WITH_AUTO_RESOLVED_CONFLICTS_GUIDANCE({ + numOfRulesWithSolvableConflicts, + numOfRulesWithoutConflicts, + })} + {numOfRulesWithoutConflicts > 0 && ( +

{i18n.RULES_WITHOUT_CONFLICTS_GUIDANCE(numOfRulesWithoutConflicts)}

+ )} +
+ ); +} diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_with_conflicts_modal/translations.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_with_conflicts_modal/translations.tsx index e1df96e1d082e..fbf4a958939d6 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_with_conflicts_modal/translations.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_with_conflicts_modal/translations.tsx @@ -8,11 +8,13 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; +import { EuiCallOut, EuiLink } from '@elastic/eui'; +import { useKibana } from '../../../../../../common/lib/kibana'; export const UPGRADE_CONFLICTS_MODAL_TITLE = i18n.translate( 'xpack.securitySolution.detectionEngine.upgradeConflictsModal.messageTitle', { - defaultMessage: 'Exclude rules with conflicts?', + defaultMessage: 'Conflicts found', } ); @@ -41,202 +43,139 @@ export const UPGRADE_RULES_WITH_CONFLICTS = (numOfRules: number) => } ); -const PROCEED_WITH_NO_CONCERNS = (numOfRules: number) => ( +export const RULES_WITH_NON_SOLVABLE_CONFLICTS_TOTAL = ( + numOfRulesWithNonSolvableConflicts: number +) => ( {UPGRADE_RULES_WITH_CONFLICTS(numOfRules)} }} + id="xpack.securitySolution.detectionEngine.upgradeConflictsModal.rulesWithNonSolvableConflictsTotal" + defaultMessage="Rules with unresolved conflicts: {numOfRulesWithNonSolvableConflictsStrong}" + values={{ + numOfRulesWithNonSolvableConflictsStrong: ( + {numOfRulesWithNonSolvableConflicts} + ), + }} /> ); -const PROCEED_WITH_CONFLICT_FREE_RULES = (numOfRules: number) => ( +export const RULES_WITH_SOLVABLE_CONFLICTS_TOTAL = (numOfRulesWithSolvableConflicts: number) => ( {numOfRules}, - updateRulesWithoutConflicts: {UPGRADE_RULES_WITHOUT_CONFLICTS(numOfRules)}, + numOfRulesWithSolvableConflictsStrong: {numOfRulesWithSolvableConflicts}, }} /> ); -const PROCEED_WITH_CONFLICT_FREE_AND_SOLVABLE_CONFLICT_RULES = ({ - numOfRulesWithoutConflicts, - numOfRulesWithSolvableConflicts, -}: { - numOfRulesWithoutConflicts: number; - numOfRulesWithSolvableConflicts: number; -}) => ( +export const RULES_WITHOUT_CONFLICTS_TOTAL = (numOfRulesWithoutConflicts: number) => ( {numOfRulesWithoutConflicts}, - numOfRulesWithSolvableConflicts, - numOfRulesWithSolvableConflictsStrong: {numOfRulesWithSolvableConflicts}, - updateRules: ( - - {UPGRADE_RULES_WITH_CONFLICTS( - numOfRulesWithoutConflicts + numOfRulesWithSolvableConflicts - )} - - ), }} /> ); -export const ONLY_RULES_WITH_SOLVABLE_CONFLICTS = (numOfRules: number) => ( - <> - -
-
- {PROCEED_WITH_NO_CONCERNS(numOfRules)} - -); - -export const ONLY_RULES_WITH_NON_SOLVABLE_CONFLICTS = (numOfRules: number) => ( +export const RULES_WITH_NON_SOLVABLE_CONFLICTS_GUIDANCE = ( + numOfRulesWithNonSolvableConflicts: number +) => ( {numOfRules} }} + id="xpack.securitySolution.detectionEngine.upgradeConflictsModal.rulesWithNonSolvableConflictsGuidance" + defaultMessage="{numOfRulesWithNonSolvableConflictsStrong} {numOfRulesWithNonSolvableConflicts, plural, =1 {rule} other {rules}} with unresolved {numOfRulesWithNonSolvableConflicts, plural, =1 {conflict} other {conflicts}} can’t be updated until you fix the {numOfRulesWithNonSolvableConflicts, plural, =1 {conflict} other {conflicts}}." + values={{ + numOfRulesWithNonSolvableConflicts, + numOfRulesWithNonSolvableConflictsStrong: ( + {numOfRulesWithNonSolvableConflicts} + ), + }} /> ); -export const ONLY_RULES_WITH_CONFLICTS = ({ - numOfRulesWithSolvableConflicts, - numOfRulesWithNonSolvableConflicts, -}: { - numOfRulesWithSolvableConflicts: number; - numOfRulesWithNonSolvableConflicts: number; -}) => ( - <> - -
-
- {numOfRulesWithSolvableConflicts + numOfRulesWithNonSolvableConflicts} - ), - numOfRulesWithNonSolvableConflictsStrong: ( - {numOfRulesWithNonSolvableConflicts} - ), - }} - /> -
-
- {PROCEED_WITH_NO_CONCERNS(numOfRulesWithSolvableConflicts)} - +const ACCEPT_SOLVABLE_CONFLICTS_WARNING = i18n.translate( + 'xpack.securitySolution.detectionEngine.upgradeConflictsModal.acceptSolvableConflictsWarning', + { + defaultMessage: + 'Only choose this option if you’re comfortable accepting the fixes Elastic suggested.', + } ); -export const RULES_WITHOUT_CONFLICTS_AND_RULES_WITH_NON_SOLVABLE_CONFLICTS = ({ +export const RULES_WITH_AUTO_RESOLVED_CONFLICTS_GUIDANCE = ({ + numOfRulesWithSolvableConflicts, numOfRulesWithoutConflicts, - numOfRulesWithNonSolvableConflicts, }: { + numOfRulesWithSolvableConflicts: number; numOfRulesWithoutConflicts: number; - numOfRulesWithNonSolvableConflicts: number; -}) => ( - <> - {numOfRulesWithoutConflicts + numOfRulesWithNonSolvableConflicts} - ), - numOfRulesWithNonSolvableConflicts, - numOfRulesWithNonSolvableConflictsStrong: ( - {numOfRulesWithNonSolvableConflicts} - ), - }} - /> -
-
- {PROCEED_WITH_CONFLICT_FREE_RULES(numOfRulesWithoutConflicts)} - -); +}) => { + const docsUrl = useKibana().services.docLinks.links.securitySolution.resolvePrebuiltRuleConflicts; -export const RULES_WITHOUT_CONFLICTS_AND_RULES_WITH_SOLVABLE_CONFLICTS = ({ - numOfRulesWithoutConflicts, - numOfRulesWithSolvableConflicts, -}: { - numOfRulesWithoutConflicts: number; - numOfRulesWithSolvableConflicts: number; -}) => ( - <> - {numOfRulesWithoutConflicts + numOfRulesWithSolvableConflicts} - ), - numOfRulesWithSolvableConflictsStrong: {numOfRulesWithSolvableConflicts}, - }} - /> -
-
- {PROCEED_WITH_CONFLICT_FREE_RULES(numOfRulesWithoutConflicts)} -
- {PROCEED_WITH_CONFLICT_FREE_AND_SOLVABLE_CONFLICT_RULES({ - numOfRulesWithoutConflicts, - numOfRulesWithSolvableConflicts, - })} - -); + return ( + <> +
+ {numOfRulesWithSolvableConflicts} + ), + }} + /> +
    +
  • + + + + ), + }} + /> +
  • +
  • + + {UPGRADE_RULES_WITH_CONFLICTS( + numOfRulesWithSolvableConflicts + numOfRulesWithoutConflicts + )} + + ), + }} + /> +
  • + +
+
+
+ + ); +}; -export const ALL_KINDS_OF_RULES = ({ - numOfRulesWithoutConflicts, - numOfRulesWithSolvableConflicts, - numOfRulesWithNonSolvableConflicts, -}: { - numOfRulesWithoutConflicts: number; - numOfRulesWithSolvableConflicts: number; - numOfRulesWithNonSolvableConflicts: number; -}) => ( - <> - - {numOfRulesWithoutConflicts + - numOfRulesWithSolvableConflicts + - numOfRulesWithNonSolvableConflicts} - - ), - numOfRulesWithConflictsStrong: ( - {numOfRulesWithSolvableConflicts + numOfRulesWithNonSolvableConflicts} - ), - numOfRulesWithSolvableConflicts, - numOfRulesWithSolvableConflictsStrong: {numOfRulesWithSolvableConflicts}, - numOfRulesWithNonSolvableConflicts, - numOfRulesWithNonSolvableConflictsStrong: ( - {numOfRulesWithNonSolvableConflicts} - ), - }} - /> -
-
- {PROCEED_WITH_CONFLICT_FREE_RULES(numOfRulesWithoutConflicts)} -
- {PROCEED_WITH_CONFLICT_FREE_AND_SOLVABLE_CONFLICT_RULES({ +export const RULES_WITHOUT_CONFLICTS_GUIDANCE = (numOfRulesWithoutConflicts: number) => ( + + numOfRulesWithoutConflictsStrong: {numOfRulesWithoutConflicts}, + updateRulesWithoutConflicts: ( + {UPGRADE_RULES_WITHOUT_CONFLICTS(numOfRulesWithoutConflicts)} + ), + }} + /> ); diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_with_conflicts_modal/upgrade_modal.tsx b/x-pack/solutions/security/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 ddf1a06813db0..f10ee686c45b9 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_with_conflicts_modal/upgrade_modal.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_with_conflicts_modal/upgrade_modal.tsx @@ -13,19 +13,13 @@ import { EuiModalFooter, EuiButton, EuiButtonEmpty, - EuiText, } from '@elastic/eui'; import React, { memo, useCallback } from 'react'; import { ConfirmRulesUpgrade } from './use_upgrade_modal'; import * as i18n from './translations'; +import { ConflictsDescription, type RulesConflictStats } from './conflicts_description'; -export interface RulesConflictStats { - numOfRulesWithoutConflicts: number; - numOfRulesWithSolvableConflicts: number; - numOfRulesWithNonSolvableConflicts: number; -} - -interface UpgradeWithConflictsModalProps extends RulesConflictStats { +export interface UpgradeWithConflictsModalProps extends RulesConflictStats { onCancel: () => void; onConfirm: (result: ConfirmRulesUpgrade) => void; } @@ -53,13 +47,11 @@ export const UpgradeWithConflictsModal = memo(function ConfirmUpgradeWithConflic - - {getModalBodyText({ - numOfRulesWithoutConflicts, - numOfRulesWithSolvableConflicts, - numOfRulesWithNonSolvableConflicts, - })} - + @@ -80,49 +72,3 @@ export const UpgradeWithConflictsModal = memo(function ConfirmUpgradeWithConflic ); }); - -function getModalBodyText({ - numOfRulesWithoutConflicts, - numOfRulesWithSolvableConflicts, - numOfRulesWithNonSolvableConflicts, -}: RulesConflictStats): JSX.Element { - // Only solvable conflicts - if (numOfRulesWithoutConflicts === 0 && numOfRulesWithNonSolvableConflicts === 0) { - return i18n.ONLY_RULES_WITH_SOLVABLE_CONFLICTS(numOfRulesWithSolvableConflicts); - } - - // Only non-solvable conflicts - if (numOfRulesWithoutConflicts === 0 && numOfRulesWithSolvableConflicts === 0) { - return i18n.ONLY_RULES_WITH_NON_SOLVABLE_CONFLICTS(numOfRulesWithNonSolvableConflicts); - } - - // Only conflicts - if (numOfRulesWithoutConflicts === 0) { - return i18n.ONLY_RULES_WITH_CONFLICTS({ - numOfRulesWithSolvableConflicts, - numOfRulesWithNonSolvableConflicts, - }); - } - - // Rules without conflicts + rules with solvable conflicts - if (numOfRulesWithNonSolvableConflicts === 0) { - return i18n.RULES_WITHOUT_CONFLICTS_AND_RULES_WITH_SOLVABLE_CONFLICTS({ - numOfRulesWithoutConflicts, - numOfRulesWithSolvableConflicts, - }); - } - - // Rules without conflicts + rules with non-solvable conflicts - if (numOfRulesWithSolvableConflicts === 0) { - return i18n.RULES_WITHOUT_CONFLICTS_AND_RULES_WITH_NON_SOLVABLE_CONFLICTS({ - numOfRulesWithoutConflicts, - numOfRulesWithNonSolvableConflicts, - }); - } - - return i18n.ALL_KINDS_OF_RULES({ - numOfRulesWithoutConflicts, - numOfRulesWithSolvableConflicts, - numOfRulesWithNonSolvableConflicts, - }); -} diff --git a/x-pack/solutions/security/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/solutions/security/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 index 4fbb7879471c7..ee2438904f8ee 100644 --- a/x-pack/solutions/security/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/solutions/security/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 @@ -9,7 +9,7 @@ import type { ReactNode } from 'react'; import React, { useCallback, useState } from 'react'; import { useBoolean } from '@kbn/react-hooks'; import { useAsyncConfirmation } from '../../rules_table/use_async_confirmation'; -import type { RulesConflictStats } from './upgrade_modal'; +import type { RulesConflictStats } from './conflicts_description'; import { UpgradeWithConflictsModal } from './upgrade_modal'; export enum ConfirmRulesUpgrade {