Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,7 @@ export const getDocLinks = ({ kibanaBranch, buildFlavor }: GetDocLinkOptions): D
? `${SERVERLESS_DOCS}security-prebuilt-rules-management.html#update-prebuilt-rules`
: `${SECURITY_SOLUTION_DOCS}prebuilt-rules-management.html#update-prebuilt-rules`,
prebuiltRuleCustomizationPromoBlog: `${ELASTIC_WEBSITE_URL}blog/security-prebuilt-rules-editing`,
resolvePrebuiltRuleConflicts: `${SECURITY_SOLUTION_DOCS}prebuilt-rules-update-modified-unmodified.html#resolve-reduce-rule-conflicts`,
createEsqlRuleType: `${SECURITY_SOLUTION_DOCS}rules-ui-create.html#create-esql-rule`,
ruleUiAdvancedParams: `${SECURITY_SOLUTION_DOCS}rules-ui-create.html#rule-ui-advanced-params`,
entityAnalytics: {
Expand Down
1 change: 1 addition & 0 deletions src/platform/packages/shared/kbn-doc-links/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,7 @@ export interface DocLinks {
readonly createDetectionRules: string;
readonly updatePrebuiltDetectionRules: string;
readonly prebuiltRuleCustomizationPromoBlog: string;
readonly resolvePrebuiltRuleConflicts: string;
readonly createEsqlRuleType: string;
readonly ruleUiAdvancedParams: string;
readonly entityAnalytics: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39759,6 +39759,9 @@
"xpack.securitySolution.detectionEngine.translationDetails.translationTab.statusTitle": "Statut de la traduction",
"xpack.securitySolution.detectionEngine.upgradeConflictsModal.cancelTitle": "Annuler",
"xpack.securitySolution.detectionEngine.upgradeConflictsModal.messageTitle": "Mettre à jour les règles sans conflits ?",
"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.",
"xpack.securitySolution.detectionEngine.upgradeFlyout.fieldModifiedBadgeDescription": "La valeur du champ a été modifiée après l'installation de la règle et diffère de la valeur de l'installation",
"xpack.securitySolution.detectionEngine.upgradeFlyout.header.fieldUpdates": "Mises à jour du champ",
"xpack.securitySolution.detectionEngine.upgradeFlyout.header.lastUpdate": "Dernière mise à jour",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39728,6 +39728,9 @@
"xpack.securitySolution.detectionEngine.translationDetails.translationTab.statusTitle": "変換ステータス",
"xpack.securitySolution.detectionEngine.upgradeConflictsModal.cancelTitle": "キャンセル",
"xpack.securitySolution.detectionEngine.upgradeConflictsModal.messageTitle": "競合がないルールを更新しますか?",
"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ルールの更新頻度を上げると、今後、この状況を回避できます。この更新を注意深くレビューし、変更が誤って上書きされていないことを確認することをお勧めします。",
"xpack.securitySolution.detectionEngine.upgradeFlyout.fieldModifiedBadgeDescription": "フィールド値はルールのインストール後に編集され、インストール時の値とは異なります",
"xpack.securitySolution.detectionEngine.upgradeFlyout.header.fieldUpdates": "フィールド更新",
"xpack.securitySolution.detectionEngine.upgradeFlyout.header.lastUpdate": "最終更新",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39798,6 +39798,9 @@
"xpack.securitySolution.detectionEngine.translationDetails.translationTab.statusTitle": "转换状态",
"xpack.securitySolution.detectionEngine.upgradeConflictsModal.cancelTitle": "取消",
"xpack.securitySolution.detectionEngine.upgradeConflictsModal.messageTitle": "更新没有冲突的规则?",
"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 规则可帮助您在未来避免这种情况。建议您仔细复查此更新,并确保不会无意中覆盖您的更改。",
"xpack.securitySolution.detectionEngine.upgradeFlyout.fieldModifiedBadgeDescription": "此字段值已在安装规则后经过编辑,且与安装时的值不同",
"xpack.securitySolution.detectionEngine.upgradeFlyout.header.fieldUpdates": "字段更新",
"xpack.securitySolution.detectionEngine.upgradeFlyout.header.lastUpdate": "上次更新",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
Original file line number Diff line number Diff line change
@@ -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(
<ConflictsDescription
numOfRulesWithoutConflicts={0}
numOfRulesWithSolvableConflicts={5}
numOfRulesWithNonSolvableConflicts={0}
/>,
{ 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(
<ConflictsDescription
numOfRulesWithoutConflicts={0}
numOfRulesWithSolvableConflicts={0}
numOfRulesWithNonSolvableConflicts={5}
/>,
{ 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(
<ConflictsDescription
numOfRulesWithoutConflicts={0}
numOfRulesWithSolvableConflicts={3}
numOfRulesWithNonSolvableConflicts={5}
/>,
{ 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(
<ConflictsDescription
numOfRulesWithoutConflicts={10}
numOfRulesWithSolvableConflicts={3}
numOfRulesWithNonSolvableConflicts={0}
/>,
{ 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(
<ConflictsDescription
numOfRulesWithoutConflicts={10}
numOfRulesWithSolvableConflicts={0}
numOfRulesWithNonSolvableConflicts={5}
/>,
{ 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(
<ConflictsDescription
numOfRulesWithoutConflicts={10}
numOfRulesWithSolvableConflicts={3}
numOfRulesWithNonSolvableConflicts={5}
/>,
{ 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));
});
});
Original file line number Diff line number Diff line change
@@ -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 (
<EuiText>
<p>
{numOfRulesWithNonSolvableConflicts > 0 && (
<>
{i18n.RULES_WITH_NON_SOLVABLE_CONFLICTS_TOTAL(numOfRulesWithNonSolvableConflicts)}
<br />
</>
)}
{numOfRulesWithSolvableConflicts > 0 && (
<>
{i18n.RULES_WITH_SOLVABLE_CONFLICTS_TOTAL(numOfRulesWithSolvableConflicts)}
<br />
</>
)}
{numOfRulesWithoutConflicts > 0 && (
<>
{i18n.RULES_WITHOUT_CONFLICTS_TOTAL(numOfRulesWithoutConflicts)}
<br />
</>
)}
</p>
{numOfRulesWithNonSolvableConflicts > 0 && (
<p>{i18n.RULES_WITH_NON_SOLVABLE_CONFLICTS_GUIDANCE(numOfRulesWithNonSolvableConflicts)}</p>
)}
{numOfRulesWithSolvableConflicts > 0 &&
i18n.RULES_WITH_AUTO_RESOLVED_CONFLICTS_GUIDANCE({
numOfRulesWithSolvableConflicts,
numOfRulesWithoutConflicts,
})}
{numOfRulesWithoutConflicts > 0 && (
<p>{i18n.RULES_WITHOUT_CONFLICTS_GUIDANCE(numOfRulesWithoutConflicts)}</p>
)}
</EuiText>
);
}
Loading