[Security Solution] UI copy for Upgrade rules confirmation modal (#213981)

## Summary

Updates texts according to the suggested UI copy ([source doc](https://docs.google.com/document/d/1qjSxs1aDHJ8AKj5xR4erPdNumLy9Jqu3AlL9oGXnfxo/edit?tab=t.0)).

## Screenshots

Update All rules:
<img width="1722" alt="image" src="https://github.com/user-attachments/assets/424d4812-6a29-4205-ab5d-df2b2024507a" />

Single rule with solvable conflicts:
<img width="1714" alt="image" src="https://github.com/user-attachments/assets/916a264f-44ba-45de-99cb-15e337ead2bd" />

Multiple rules with solvable conflicts:
<img width="1718" alt="image" src="https://github.com/user-attachments/assets/6b7684f6-978b-4511-9b8a-ccde049730b9" />

Mix of conflict-free rules and rules with solvable conflicts:
<img width="1716" alt="image" src="https://github.com/user-attachments/assets/cd2325a6-0dec-48b1-a2af-6185acf16b10" />
<img width="1714" alt="image" src="https://github.com/user-attachments/assets/ecb74497-ddbb-4407-8dfd-6902642dd9c3" />

Mix of conflict-free rules and rules with non-solvable conflicts:
<img width="1723" alt="image" src="https://github.com/user-attachments/assets/0b980dd4-4109-4b63-859f-c95cc31dd7b4" />

Only rules with conflicts:
<img width="1720" alt="image" src="https://github.com/user-attachments/assets/f66cee4e-e648-4eb5-902a-db0a4bd3a423" />
<img width="1718" alt="image" src="https://github.com/user-attachments/assets/9d42e5d9-6a62-4c60-8aea-bb5376b2d2c5" />

Mix of rules selected to update:
<img width="1717" alt="image" src="https://github.com/user-attachments/assets/e882cbd1-203d-499f-b51f-37691405a3a5" />
This commit is contained in:
Maxim Palenov 2025-03-13 19:36:35 +01:00 committed by GitHub
parent 482ac1ee76
commit aa3d5eb373
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 153 additions and 66 deletions

View file

@ -12,7 +12,7 @@ import { FormattedMessage } from '@kbn/i18n-react';
export const UPGRADE_CONFLICTS_MODAL_TITLE = i18n.translate(
'xpack.securitySolution.detectionEngine.upgradeConflictsModal.messageTitle',
{
defaultMessage: 'There are rules with conflicts',
defaultMessage: 'Exclude rules with conflicts?',
}
);
@ -23,32 +23,87 @@ export const UPGRADE_CONFLICTS_MODAL_CANCEL = i18n.translate(
}
);
export const UPGRADE_RULES_WITHOUT_CONFLICTS = i18n.translate(
'xpack.securitySolution.detectionEngine.upgradeConflictsModal.upgradeRulesWithoutConflicts',
{
defaultMessage: 'Update rules without conflicts',
}
export const UPGRADE_RULES_WITHOUT_CONFLICTS = (rulesCount: number) =>
i18n.translate(
'xpack.securitySolution.detectionEngine.upgradeConflictsModal.upgradeRulesWithoutConflicts',
{
defaultMessage: 'Update {rulesCount, plural, =1 {rule} other {rules}} without conflicts',
values: { rulesCount },
}
);
export const UPGRADE_RULES_WITH_CONFLICTS = (numOfRules: number) =>
i18n.translate(
'xpack.securitySolution.detectionEngine.upgradeConflictsModal.upgradeRulesWithConflicts',
{
defaultMessage: 'Update {numOfRules, plural, =1 {rule} other {rules}}',
values: { numOfRules },
}
);
const PROCEED_WITH_NO_CONCERNS = (numOfRules: number) => (
<FormattedMessage
id="xpack.securitySolution.detectionEngine.upgradeConflictsModal.proceedWhenNoConcerns"
defaultMessage="If you have no concerns and want to continue with the update, click {updateRules}."
values={{ updateRules: <strong>{UPGRADE_RULES_WITH_CONFLICTS(numOfRules)}</strong> }}
/>
);
export const UPGRADE_RULES_WITH_CONFLICTS = i18n.translate(
'xpack.securitySolution.detectionEngine.upgradeConflictsModal.upgradeRulesWithConflicts',
{
defaultMessage: 'Update rules',
}
const PROCEED_WITH_CONFLICT_FREE_RULES = (numOfRules: number) => (
<FormattedMessage
id="xpack.securitySolution.detectionEngine.upgradeConflictsModal.proceedWithConflictFreeRules"
defaultMessage="Click {updateRulesWithoutConflicts} to update the {numOfRulesStrong} conflict-free {numOfRules, plural, =1 {rule} other {rules}}."
values={{
numOfRules,
numOfRulesStrong: <strong>{numOfRules}</strong>,
updateRulesWithoutConflicts: <strong>{UPGRADE_RULES_WITHOUT_CONFLICTS(numOfRules)}</strong>,
}}
/>
);
const PROCEED_WITH_CONFLICT_FREE_AND_SOLVABLE_CONFLICT_RULES = ({
numOfRulesWithoutConflicts,
numOfRulesWithSolvableConflicts,
}: {
numOfRulesWithoutConflicts: number;
numOfRulesWithSolvableConflicts: number;
}) => (
<FormattedMessage
id="xpack.securitySolution.detectionEngine.upgradeConflictsModal.proceedWithConflictFreeRules"
defaultMessage="Click {updateRules} to update the {numOfRulesWithoutConflictsStrong} conflict-free {numOfRulesWithoutConflicts, plural, =1 {rule} other {rules}} and {numOfRulesWithSolvableConflictsStrong} {numOfRulesWithSolvableConflicts, plural, =1 {rule} other {rules}} with auto-resolved conflicts."
values={{
numOfRulesWithoutConflicts,
numOfRulesWithoutConflictsStrong: <strong>{numOfRulesWithoutConflicts}</strong>,
numOfRulesWithSolvableConflicts,
numOfRulesWithSolvableConflictsStrong: <strong>{numOfRulesWithSolvableConflicts}</strong>,
updateRules: (
<strong>
{UPGRADE_RULES_WITH_CONFLICTS(
numOfRulesWithoutConflicts + numOfRulesWithSolvableConflicts
)}
</strong>
),
}}
/>
);
export const ONLY_RULES_WITH_SOLVABLE_CONFLICTS = (numOfRules: number) => (
<FormattedMessage
id="xpack.securitySolution.detectionEngine.upgradeConflictsModal.onlySolvableConflicts"
defaultMessage="{numOfRulesStrong} selected {numOfRules, plural, =1 {rule has} other {rules have}} auto-resolved conflicts. You may proceed updating without reviewing conflicts but this operation is potentially dangerous and may result in broken rules."
values={{ numOfRules, numOfRulesStrong: <strong>{numOfRules}</strong> }}
/>
<>
<FormattedMessage
id="xpack.securitySolution.detectionEngine.upgradeConflictsModal.onlySolvableConflicts"
defaultMessage="The selected {numOfRules, plural, =1 {rule has} other {rules have}} auto-resolved conflicts. To safely update the {numOfRules, plural, =1 {rule} other {rules}}, we recommend addressing the conflicts from the rule's update flyout."
values={{ numOfRules }}
/>
<br />
<br />
{PROCEED_WITH_NO_CONCERNS(numOfRules)}
</>
);
export const ONLY_RULES_WITH_NON_SOLVABLE_CONFLICTS = (numOfRules: number) => (
<FormattedMessage
id="xpack.securitySolution.detectionEngine.upgradeConflictsModal.onlyNonSolvableConflicts"
defaultMessage="{numOfRulesStrong} selected {numOfRules, plural, =1 {rule has} other {rules have}} unresolved conflicts. Please review and update them individually via the flyout."
defaultMessage="{numOfRulesStrong} selected {numOfRules, plural, =1 {rule has} other {rules have}} unresolved conflicts. Rules with unresolved conflicts cant be bulk-updated. You must manually fix their conflicts before updating them."
values={{ numOfRules, numOfRulesStrong: <strong>{numOfRules}</strong> }}
/>
);
@ -60,18 +115,30 @@ export const ONLY_RULES_WITH_CONFLICTS = ({
numOfRulesWithSolvableConflicts: number;
numOfRulesWithNonSolvableConflicts: number;
}) => (
<FormattedMessage
id="xpack.securitySolution.detectionEngine.upgradeConflictsModal.rulesWithoutConflictsAndRulesWithNonSolvableConflicts"
defaultMessage="{numOfRulesStrong} selected {numOfRules, plural, =1 {rule has} other {rules have}} conflicts. You may proceed updating {numOfRulesWithSolvableConflictsStrong} {numOfRulesWithSolvableConflicts, plural, =1 {rule} other {rules}} with auto-resolved conflicts but this operation is potentially dangerous and may result in broken rules. Rules with unresolved conflicts may be updated only via the flyout."
values={{
numOfRules: numOfRulesWithSolvableConflicts + numOfRulesWithNonSolvableConflicts,
numOfRulesStrong: (
<strong>{numOfRulesWithSolvableConflicts + numOfRulesWithNonSolvableConflicts}</strong>
),
numOfRulesWithSolvableConflicts,
numOfRulesWithSolvableConflictsStrong: <strong>{numOfRulesWithSolvableConflicts}</strong>,
}}
/>
<>
<FormattedMessage
id="xpack.securitySolution.detectionEngine.upgradeConflictsModal.onlyRulesWithConflicts"
defaultMessage="Selected rules have conflicts. To safely update the rules, we recommend addressing the conflicts from the rule's update flyout."
/>
<br />
<br />
<FormattedMessage
id="xpack.securitySolution.detectionEngine.upgradeConflictsModal.unresolvedConflictsCanNotBeBulkUpdated"
defaultMessage="{numOfRulesWithNonSolvableConflictsStrong} out of the selected {numOfRulesStrong} {numOfRules, plural, =1 {rule} other {rules}} with unresolved conflicts cant be bulk-updated. You must manually fix their conflicts before updating them."
values={{
numOfRules: numOfRulesWithSolvableConflicts + numOfRulesWithNonSolvableConflicts,
numOfRulesStrong: (
<strong>{numOfRulesWithSolvableConflicts + numOfRulesWithNonSolvableConflicts}</strong>
),
numOfRulesWithNonSolvableConflictsStrong: (
<strong>{numOfRulesWithNonSolvableConflicts}</strong>
),
}}
/>
<br />
<br />
{PROCEED_WITH_NO_CONCERNS(numOfRulesWithSolvableConflicts)}
</>
);
export const RULES_WITHOUT_CONFLICTS_AND_RULES_WITH_NON_SOLVABLE_CONFLICTS = ({
@ -81,19 +148,24 @@ export const RULES_WITHOUT_CONFLICTS_AND_RULES_WITH_NON_SOLVABLE_CONFLICTS = ({
numOfRulesWithoutConflicts: number;
numOfRulesWithNonSolvableConflicts: number;
}) => (
<FormattedMessage
id="xpack.securitySolution.detectionEngine.upgradeConflictsModal.rulesWithoutConflictsAndRulesWithNonSolvableConflicts"
defaultMessage="{numOfRulesWithNonSolvableConflicts} of {numOfRulesStrong} selected {numOfRules, plural, =1 {rule has} other {rules have}} unresolved conflicts. You may proceed updating only {numOfRulesWithoutConflictsStrong} {numOfRulesWithoutConflicts, plural, =1 {rule} other {rules}} without conflicts. Rules with unresolved conflicts may be updated only via the flyout."
values={{
numOfRules: numOfRulesWithoutConflicts + numOfRulesWithNonSolvableConflicts,
numOfRulesStrong: (
<strong>{numOfRulesWithoutConflicts + numOfRulesWithNonSolvableConflicts}</strong>
),
numOfRulesWithoutConflicts,
numOfRulesWithoutConflictsStrong: <strong>{numOfRulesWithoutConflicts}</strong>,
numOfRulesWithNonSolvableConflicts: <strong>{numOfRulesWithNonSolvableConflicts}</strong>,
}}
/>
<>
<FormattedMessage
id="xpack.securitySolution.detectionEngine.upgradeConflictsModal.rulesWithoutConflictsAndRulesWithNonSolvableConflicts"
defaultMessage="{numOfRulesWithNonSolvableConflictsStrong} of the {numOfRulesStrong} selected rules {numOfRulesWithNonSolvableConflicts, plural, =1 {has} other {have}} unresolved conflicts, which cannot be bulk-updated until you manually fix them."
values={{
numOfRulesStrong: (
<strong>{numOfRulesWithoutConflicts + numOfRulesWithNonSolvableConflicts}</strong>
),
numOfRulesWithNonSolvableConflicts,
numOfRulesWithNonSolvableConflictsStrong: (
<strong>{numOfRulesWithNonSolvableConflicts}</strong>
),
}}
/>
<br />
<br />
{PROCEED_WITH_CONFLICT_FREE_RULES(numOfRulesWithoutConflicts)}
</>
);
export const RULES_WITHOUT_CONFLICTS_AND_RULES_WITH_SOLVABLE_CONFLICTS = ({
@ -103,18 +175,27 @@ export const RULES_WITHOUT_CONFLICTS_AND_RULES_WITH_SOLVABLE_CONFLICTS = ({
numOfRulesWithoutConflicts: number;
numOfRulesWithSolvableConflicts: number;
}) => (
<FormattedMessage
id="xpack.securitySolution.detectionEngine.upgradeConflictsModal.rulesWithoutConflictsAndRulesWithSolvableConflicts"
defaultMessage="{numOfRulesWithSolvableConflictsStrong} of {numOfRulesStrong} selected rules have auto-resolved conflicts. You may proceed and update only {numOfRulesWithoutConflictsStrong} {numOfRulesWithoutConflicts, plural, =1 {rule} other {rules}} without conflicts or update all rules which is potentially dangerous and may result in broken rules."
values={{
numOfRulesStrong: (
<strong>{numOfRulesWithoutConflicts + numOfRulesWithSolvableConflicts}</strong>
),
<>
<FormattedMessage
id="xpack.securitySolution.detectionEngine.upgradeConflictsModal.rulesWithoutConflictsAndRulesWithSolvableConflicts"
defaultMessage="{numOfRulesWithSolvableConflictsStrong} of the {numOfRulesStrong} selected {numOfRules, plural, =1 {rule has} other {rules have}} auto-resolved conflicts. To safely update them, we recommend addressing the conflicts from the rule update flyout."
values={{
numOfRules: numOfRulesWithoutConflicts + numOfRulesWithSolvableConflicts,
numOfRulesStrong: (
<strong>{numOfRulesWithoutConflicts + numOfRulesWithSolvableConflicts}</strong>
),
numOfRulesWithSolvableConflictsStrong: <strong>{numOfRulesWithSolvableConflicts}</strong>,
}}
/>
<br />
<br />
{PROCEED_WITH_CONFLICT_FREE_RULES(numOfRulesWithoutConflicts)}
<br />
{PROCEED_WITH_CONFLICT_FREE_AND_SOLVABLE_CONFLICT_RULES({
numOfRulesWithoutConflicts,
numOfRulesWithoutConflictsStrong: <strong>{numOfRulesWithoutConflicts}</strong>,
numOfRulesWithSolvableConflictsStrong: <strong>{numOfRulesWithSolvableConflicts}</strong>,
}}
/>
numOfRulesWithSolvableConflicts,
})}
</>
);
export const ALL_KINDS_OF_RULES = ({
@ -129,7 +210,7 @@ export const ALL_KINDS_OF_RULES = ({
<>
<FormattedMessage
id="xpack.securitySolution.detectionEngine.upgradeConflictsModal.allKindsOfRules"
defaultMessage="{numOfRulesWithConflictsStrong} of {numOfRulesStrong} selected rules have conflicts. You may proceed and update only {numOfRulesWithoutConflictsStrong} {numOfRulesWithoutConflicts, plural, =1 {rule} other {rules}} without conflicts or update also {numOfRulesWithSolvableConflictsStrong} {numOfRulesWithSolvableConflicts, plural, =1 {rule} other {rules}} with auto-resolved conflicts which is potentially dangerous and may result in broken rules."
defaultMessage="{numOfRulesWithConflictsStrong} of the {numOfRulesStrong} selected rules have conflicts. To safely update the {numOfRulesWithSolvableConflictsStrong} {numOfRulesWithSolvableConflicts, plural, =1 {rule} other {rules}} with auto-resolved conflicts, we recommend addressing the conflicts from the rule update flyout. The {numOfRulesWithNonSolvableConflictsStrong} {numOfRulesWithNonSolvableConflicts, plural, =1 {rule} other {rules}} with unresolved conflicts cannot be bulk-updated until you manually fix them."
values={{
numOfRulesStrong: (
<strong>
@ -141,17 +222,21 @@ export const ALL_KINDS_OF_RULES = ({
numOfRulesWithConflictsStrong: (
<strong>{numOfRulesWithSolvableConflicts + numOfRulesWithNonSolvableConflicts}</strong>
),
numOfRulesWithoutConflicts,
numOfRulesWithoutConflictsStrong: <strong>{numOfRulesWithoutConflicts}</strong>,
numOfRulesWithSolvableConflicts,
numOfRulesWithSolvableConflictsStrong: <strong>{numOfRulesWithSolvableConflicts}</strong>,
numOfRulesWithNonSolvableConflicts,
numOfRulesWithNonSolvableConflictsStrong: (
<strong>{numOfRulesWithNonSolvableConflicts}</strong>
),
}}
/>
{numOfRulesWithNonSolvableConflicts > 0 && (
<FormattedMessage
id="xpack.securitySolution.detectionEngine.upgradeConflictsModal.unresolvedConflicts"
defaultMessage="Rules with unresolved conflicts may be updated only via the flyout."
/>
)}
<br />
<br />
{PROCEED_WITH_CONFLICT_FREE_RULES(numOfRulesWithoutConflicts)}
<br />
{PROCEED_WITH_CONFLICT_FREE_AND_SOLVABLE_CONFLICT_RULES({
numOfRulesWithoutConflicts,
numOfRulesWithSolvableConflicts,
})}
</>
);

View file

@ -65,12 +65,14 @@ export const UpgradeWithConflictsModal = memo(function ConfirmUpgradeWithConflic
<EuiModalFooter>
{numOfRulesWithoutConflicts > 0 && (
<EuiButton onClick={confirmUpgradingRulesWithoutConflicts}>
{i18n.UPGRADE_RULES_WITHOUT_CONFLICTS}
{i18n.UPGRADE_RULES_WITHOUT_CONFLICTS(numOfRulesWithoutConflicts)}
</EuiButton>
)}
{numOfRulesWithSolvableConflicts > 0 && (
<EuiButton onClick={confirmUpgradingRulesWithSolvableConflicts} color="warning">
{i18n.UPGRADE_RULES_WITH_CONFLICTS}
{i18n.UPGRADE_RULES_WITH_CONFLICTS(
numOfRulesWithoutConflicts + numOfRulesWithSolvableConflicts
)}
</EuiButton>
)}
<EuiButtonEmpty onClick={onCancel}>{i18n.UPGRADE_CONFLICTS_MODAL_CANCEL}</EuiButtonEmpty>

View file

@ -881,7 +881,7 @@ export const SOLVABLE_CONFLICT_TOOLTIP = i18n.translate(
'xpack.securitySolution.detectionEngine.upgradeRules.solvableConflictTooltipDescription',
{
defaultMessage:
'This Elastic rule has auto-resolved conflicts that require review before upgrade.',
'This Elastic rule has auto-resolved conflicts to review before updating the rule. ',
}
);
@ -896,7 +896,7 @@ export const NON_SOLVABLE_CONFLICT_TOOLTIP = i18n.translate(
'xpack.securitySolution.detectionEngine.upgradeRules.nonSolvableConflictTooltipDescription',
{
defaultMessage:
'This Elastic rule has unresolved conflicts that require editing before upgrade.',
'This Elastic rule has unresolved conflicts that you must fix before updating the rule.',
}
);