From 2dcbc5d5b8b5e539f09268cad9f86646042e5bfd Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Wed, 11 Dec 2024 12:02:25 +0100 Subject: [PATCH] [Security Solution] Finalize Prebuilt Rule Customization workflow layout (#201501) **Addresses:** https://github.com/elastic/kibana/issues/171520 ## Summary This PR updates Prebuilt Rules Customization UI to match the [design](https://www.figma.com/design/gLHm8LpTtSkAUQHrkG3RHU/%5B8.7%5D-%5BRules%5D-Rule-Immutability%2FCustomization?node-id=5146-77820). On top of that it renames and toss files to organize them in a much more clear way. ## Details A number of changes required to match the [design](https://www.figma.com/design/gLHm8LpTtSkAUQHrkG3RHU/%5B8.7%5D-%5BRules%5D-Rule-Immutability%2FCustomization?node-id=5146-77820) - move save/accept button to the field's right side header - expose additional field upgrade state `NoConflicts` to distinguish between `Accepted` and `NoConflicts` states - consume `ruleUpgradeState` in different components to display proper badges and texts Additional refactoring was done to facilitate the changes - `FinalRuleContext` and `FieldFinalEditContext` were merged together into `FieldUpgradeContext` - files and some folders were renamed and tossed to make the structure simpler and transparent There is still space for improvement. Current PR tries to minimize the changes to avoid too many conflicts since development is still in progress. And an additional limit of 200 path characters is imposed in Kibana preventing too deep foldering. Some functionality could be moved to a package later on to mitigate that obstacle. ## How to test locally - Ensure the `prebuiltRulesCustomizationEnabled` feature flag is enabled - Allow internal APIs via adding `server.restrictInternalApis: false` to `kibana.dev.yaml` - Clear Elasticsearch data - Run Elasticsearch and Kibana locally (do not open Kibana in a web browser) - Install an outdated version of the `security_detection_engine` Fleet package ```bash curl -X POST --user elastic:changeme -H 'Content-Type: application/json' -H 'kbn-xsrf: 123' -H "elastic-api-version: 2023-10-31" -d '{"force":true}' http://localhost:5601/kbn/api/fleet/epm/packages/security_detection_engine/8.14.1 ``` - Install prebuilt rules ```bash curl -X POST --user elastic:changeme -H 'Content-Type: application/json' -H 'kbn-xsrf: 123' -H "elastic-api-version: 1" -d '{"mode":"ALL_RULES"}' http://localhost:5601/kbn/internal/detection_engine/prebuilt_rules/installation/_perform ``` - Open `Detection Rules (SIEM)` Page -> `Rule Updates` - Modify one or more prebuilt rules with updates to see unresolved conflicts (don't forget to refresh the page after rule's modification, it's required to clear the cache) ## Screenshots and screen recordings ![Screenshot 2024-11-26 at 13 42 16](https://github.com/user-attachments/assets/126bdc64-b810-424a-b81e-7674480a66cf) ![Screenshot 2024-11-26 at 13 42 27](https://github.com/user-attachments/assets/af5d9c2c-055d-423d-880a-b69e95ba129c) ![Screenshot 2024-11-26 at 13 42 40](https://github.com/user-attachments/assets/b0f87a95-df23-42a8-883b-29665f3db325) https://github.com/user-attachments/assets/7befe77a-3af7-48ea-a23f-aa0017d94be5 https://github.com/user-attachments/assets/2837b405-3889-44a0-b1cb-d6c51cd9d051 https://github.com/user-attachments/assets/7cbc411d-a927-45e9-8607-7ef515337ab5 --- .../translations/translations/fr-FR.json | 17 -- .../translations/translations/ja-JP.json | 17 -- .../translations/translations/zh-CN.json | 17 -- .../perform_rule_upgrade_route.ts | 2 +- .../rule_details/rule_details_flyout.tsx | 18 +- .../three_way_diff/badges/action_required.tsx | 14 ++ .../three_way_diff/badges/modified_badge.tsx | 25 +++ .../badges/ready_for_upgrade_badge.tsx | 21 +++ .../badges/review_required_badge.tsx | 14 ++ .../three_way_diff/badges/translations.ts | 36 ++++ .../comparison_side/comparison_side.tsx | 67 ------- .../comparison_side_help_info.tsx | 66 ++++++- ....tsx => field_comparison_side.stories.tsx} | 14 +- .../comparison_side/field_comparison_side.tsx | 61 ++++++ .../get_subfield_changes/index.ts | 8 +- .../comparison_side/subfield_changes.tsx | 7 +- .../three_way_diff/comparison_side/utils.ts | 15 +- .../versions_picker/constants.ts | 12 +- .../versions_picker/translations.ts | 56 ++++++ .../versions_picker.stories.tsx | 0 .../versions_picker/versions_picker.tsx | 8 + .../field_upgrade_conflicts_resolver.tsx | 76 -------- .../field_upgrade_state_info.tsx | 55 ------ .../rule_upgrade_callout.tsx | 76 -------- .../rule_upgrade_callout/translations.tsx | 58 ------ .../rule_upgrade_conflicts_resolver.tsx | 44 ----- .../components/translations.tsx | 60 ------ .../three_way_diff/diffable_rule_context.tsx | 50 ----- .../components/field_final_side.tsx | 20 ++ .../components/field_final_side_content.tsx | 48 +++++ .../components/field_final_side_header.tsx | 87 +++++++++ .../field_final_side_help_info.tsx} | 4 +- .../rule_field_edit_component_props.ts | 0 .../rule_field_edit_form_wrapper.tsx | 37 ++-- .../components/translations.ts | 50 +++++ .../context/field_edit_form_context.tsx | 75 ++++++++ .../index.ts} | 11 +- ...ader.tsx => field_upgrade_side_header.tsx} | 2 +- .../final_edit/common_rule_field_edit.tsx | 2 +- .../{final_edit.tsx => field_final_edit.tsx} | 29 ++- .../suppression_edit_adapter.tsx | 2 +- .../suppression_edit_form.tsx | 2 +- .../fields/data_source/data_source_edit.tsx | 2 +- .../data_source/data_source_edit_form.tsx | 2 +- .../data_source_type_selector_field.tsx | 2 +- .../eql_query/eql_query_edit_adapter.tsx | 2 +- .../fields/eql_query/eql_query_edit_form.tsx | 2 +- .../esql_query/esql_query_edit_adapter.tsx | 2 +- .../esql_query/esql_query_edit_form.tsx | 2 +- .../fields/kql_query/kql_query_edit.tsx | 2 +- .../fields/kql_query/kql_query_edit_form.tsx | 2 +- .../suppression_edit_form.tsx | 4 +- .../index.ts | 2 +- ..._readonly.tsx => field_final_readonly.tsx} | 10 +- .../alert_suppression.stories.tsx | 9 +- .../anomaly_threshold.stories.tsx | 9 +- .../building_block/building_block.stories.tsx | 9 +- .../data_source/data_source.stories.tsx | 7 +- .../description/description.stories.tsx | 9 +- .../fields/eql_query/eql_query.stories.tsx | 5 +- .../fields/esql_query/esql_query.stories.tsx | 11 +- .../false_positives.stories.tsx | 9 +- .../history_window_start.stories.tsx | 9 +- .../investigation_fields.stories.tsx | 9 +- .../fields/kql_query/kql_query.stories.tsx | 7 +- .../machine_learning_job_id.stories.tsx | 9 +- .../max_signals/max_signals.stories.tsx | 9 +- .../fields/name/name.stories.tsx | 6 +- .../new_terms_fields.stories.tsx | 9 +- .../fields/note/note.stories.tsx | 6 +- .../fields/references/references.stories.tsx | 9 +- .../related_integrations.stories.tsx | 9 +- .../required_fields.stories.tsx | 9 +- .../fields/risk_score/risk_score.stories.tsx | 9 +- .../risk_score_mapping.stories.tsx | 9 +- .../rule_name_override.stories.tsx | 9 +- .../rule_schedule/rule_schedule.stories.tsx | 9 +- .../fields/setup/setup.stories.tsx | 6 +- .../fields/severity/severity.stories.tsx | 6 +- .../severity_mapping.stories.tsx | 9 +- .../fields/tags/tags.stories.tsx | 6 +- .../fields/threat/threat.stories.tsx | 6 +- .../threat_index/threat_index.stories.tsx | 9 +- .../threat_indicator_path.stories.tsx | 9 +- .../threat_mapping/threat_mapping.stories.tsx | 9 +- .../threat_query/threat_query.stories.tsx | 5 +- .../fields/threshold/threshold.stories.tsx | 9 +- .../timeline_template.stories.tsx | 9 +- .../timestamp_override.stories.tsx | 9 +- .../fields/type/type.stories.tsx | 6 +- .../final_readonly/final_readonly.tsx | 25 --- .../constants.ts => final_readonly/index.ts} | 5 +- .../three_way_diff_storybook_providers.tsx | 34 +++- .../three_way_diff/final_side/final_side.tsx | 53 ------ .../final_side/final_side_context.tsx | 50 ----- .../rule_details/three_way_diff/index.ts | 8 + .../rule_upgrade/field_upgrade.tsx | 47 +++++ .../rule_upgrade/field_upgrade_context.tsx | 167 +++++++++++++++++ .../field_upgrade_header.tsx} | 16 +- .../field_upgrade_state_info.tsx | 83 +++++++++ .../field_upgrade_state_info/index.ts | 0 .../field_upgrade_state_info/translations.tsx | 37 +++- .../three_way_diff/rule_upgrade/index.ts | 8 + .../rule_upgrade/rule_upgrade.tsx | 86 +++++++++ .../rule_upgrade/rule_upgrade_callout.tsx | 79 ++++++++ .../rule_upgrade_info_bar.tsx | 21 ++- .../rule_upgrade/translations.tsx | 115 ++++++++++++ .../rule_upgrade_conflicts_resolver_tab.tsx | 41 ----- .../three_way_diff/translations.ts | 29 --- .../versions_picker/translations.ts | 57 ------ ...e_state.ts => field_upgrade_state_enum.ts} | 4 +- .../fields_upgrade_state.ts | 14 +- .../model/prebuilt_rule_upgrade/index.ts | 2 +- .../rule_upgrade_state.ts | 13 +- .../use_add_prebuilt_rules_table_columns.tsx | 2 +- .../rule_type_change_callout.tsx | 19 +- .../{translations.ts => translations.tsx} | 46 +++++ .../upgrade_flyout_subheader.tsx | 85 +++++++++ .../upgrade_prebuilt_rules_table.tsx | 17 +- .../upgrade_prebuilt_rules_table_buttons.tsx | 21 +-- .../upgrade_prebuilt_rules_table_context.tsx | 174 +++++++++--------- .../use_filter_prebuilt_rules_to_upgrade.ts | 23 +-- .../use_ml_jobs_upgrade_modal/index.ts | 8 + .../ml_jobs_upgrade_modal.tsx} | 20 +- .../translations.tsx | 2 +- .../use_ml_jobs_upgrade_modal.tsx | 46 +++++ .../use_prebuilt_rules_upgrade_state.ts | 109 +++++------ .../use_upgrade_modals.tsx | 53 ------ ...e_upgrade_prebuilt_rules_table_columns.tsx | 2 +- .../use_upgrade_with_conflicts_modal/index.ts | 8 + .../translations.tsx | 0 .../upgrade_modal.tsx} | 19 +- .../use_upgrade_modal.tsx | 30 +++ .../rules_table/use_rule_preview_flyout.tsx | 11 +- 134 files changed, 1966 insertions(+), 1333 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/badges/action_required.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/badges/modified_badge.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/badges/ready_for_upgrade_badge.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/badges/review_required_badge.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/badges/translations.ts delete mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/comparison_side.tsx rename x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/{comparison_side.stories.tsx => field_comparison_side.stories.tsx} (98%) create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/field_comparison_side.tsx rename x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/{ => comparison_side}/versions_picker/constants.ts (70%) create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/comparison_side/versions_picker/translations.ts rename x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/{ => comparison_side}/versions_picker/versions_picker.stories.tsx (100%) rename x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/{ => comparison_side}/versions_picker/versions_picker.tsx (85%) delete mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/field_upgrade_conflicts_resolver.tsx delete mode 100644 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 delete mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/rule_upgrade_callout/rule_upgrade_callout.tsx delete mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/rule_upgrade_callout/translations.tsx delete mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/rule_upgrade_conflicts_resolver.tsx delete mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/components/translations.tsx delete mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/diffable_rule_context.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/field_final_side/components/field_final_side.tsx create mode 100644 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 create mode 100644 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 rename x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/{final_side/final_side_help_info.tsx => field_final_side/components/field_final_side_help_info.tsx} (93%) rename x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/{final_edit/fields => field_final_side/components}/rule_field_edit_component_props.ts (100%) rename x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/{final_edit/fields => field_final_side/components}/rule_field_edit_form_wrapper.tsx (81%) create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/field_final_side/components/translations.ts create mode 100644 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 rename x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/{final_side/translations.ts => field_final_side/index.ts} (55%) rename x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/{components/side_header.tsx => field_upgrade_side_header.tsx} (90%) rename x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/{final_edit.tsx => field_final_edit.tsx} (86%) rename x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/{components/rule_upgrade_callout => final_edit}/index.ts (86%) rename x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/{field_readonly.tsx => field_final_readonly.tsx} (93%) delete mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/final_readonly.tsx rename x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/{final_side/constants.ts => final_readonly/index.ts} (77%) delete mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_side/final_side.tsx delete mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_side/final_side_context.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/index.ts create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/field_upgrade.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/field_upgrade_context.tsx rename x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/{components/field_upgrade_conflicts_resolver_header.tsx => rule_upgrade/field_upgrade_header.tsx} (65%) create mode 100644 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 rename x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/{components => rule_upgrade}/field_upgrade_state_info/index.ts (100%) rename x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/{components => rule_upgrade}/field_upgrade_state_info/translations.tsx (58%) create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/index.ts create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/rule_upgrade.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/rule_upgrade_callout.tsx rename x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/{components => rule_upgrade}/rule_upgrade_info_bar.tsx (70%) create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/translations.tsx delete mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade_conflicts_resolver_tab.tsx delete mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/translations.ts delete mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/versions_picker/translations.ts rename x-pack/plugins/security_solution/public/detection_engine/rule_management/model/prebuilt_rule_upgrade/{field_upgrade_state.ts => field_upgrade_state_enum.ts} (80%) rename x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/{translations.ts => translations.tsx} (68%) create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_flyout_subheader.tsx create mode 100644 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 rename 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 => use_ml_jobs_upgrade_modal/ml_jobs_upgrade_modal.tsx} (80%) rename x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/{modals/ml_job_upgrade_modal => use_ml_jobs_upgrade_modal}/translations.tsx (95%) create mode 100644 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 delete mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_modals.tsx create mode 100644 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 rename x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/{modals/upgrade_conflicts_modal => use_upgrade_with_conflicts_modal}/translations.tsx (100%) rename x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/{modals/upgrade_conflicts_modal/index.tsx => use_upgrade_with_conflicts_modal/upgrade_modal.tsx} (63%) create mode 100644 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 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]