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 07bc02dbceec3..132e0cb4051c1 100644
--- a/x-pack/platform/plugins/private/translations/translations/fr-FR.json
+++ b/x-pack/platform/plugins/private/translations/translations/fr-FR.json
@@ -7261,6 +7261,14 @@
"securitySolutionPackages.alertSuppressionRuleDetails.upsell": "La suppression d'alertes est configurée mais elle ne sera pas appliquée en raison d'une licence insuffisante",
"securitySolutionPackages.alertSuppressionRuleForm.upsell": "La suppression d'alertes est activée avec la licence {requiredLicense} ou supérieure",
"securitySolutionPackages.beta.label": "Bêta",
+ "securitySolutionPackages.csp.cspEvaluationBadge.failLabel": "Échec",
+ "securitySolutionPackages.csp.cspEvaluationBadge.naLabel": "S. O.",
+ "securitySolutionPackages.csp.cspEvaluationBadge.passLabel": "Réussite",
+ "securitySolutionPackages.csp.findings.findingsErrorToast.searchFailedTitle": "Échec de la recherche",
+ "securitySolutionPackages.csp.navigation.dashboardNavItemLabel": "Niveau de sécurité du cloud",
+ "securitySolutionPackages.csp.navigation.findingsNavItemLabel": "Résultats",
+ "securitySolutionPackages.csp.navigation.rulesNavItemLabel": "Règles",
+ "securitySolutionPackages.csp.navigation.vulnerabilityDashboardNavItemLabel": "Gestion des vulnérabilités natives du cloud",
"securitySolutionPackages.dataTable.ariaLabel": "Alertes",
"securitySolutionPackages.dataTable.columnHeaders.flyout.pane.removeColumnButtonLabel": "Supprimer la colonne",
"securitySolutionPackages.dataTable.eventRenderedView.eventSummary.column": "Résumé des événements",
@@ -7590,6 +7598,7 @@
"share.urlService.redirect.RedirectManager.missingParamLocator": "ID du localisateur non spécifié. Spécifiez le paramètre de recherche \"l\" dans l'URL ; ce devrait être un ID de localisateur existant.",
"share.urlService.redirect.RedirectManager.missingParamParams": "Paramètres du localisateur non spécifiés. Spécifiez le paramètre de recherche \"p\" dans l'URL ; ce devrait être un objet sérialisé JSON des paramètres du localisateur.",
"share.urlService.redirect.RedirectManager.missingParamVersion": "Version des paramètres du localisateur non spécifiée. Spécifiez le paramètre de recherche \"v\" dans l'URL ; ce devrait être la version de Kibana au moment de la génération des paramètres du localisateur.",
+ "sharedPlatformPackages.csp.common.utils.helpers.unknownError": "Erreur inconnue",
"sharedUXPackages.buttonToolbar.buttons.addFromLibrary.libraryButtonLabel": "Ajouter depuis la bibliothèque",
"sharedUXPackages.buttonToolbar.toolbar.errorToolbarText": "Il y a plus de 120 boutons supplémentaires. Nous vous invitons à limiter le nombre de boutons.",
"sharedUXPackages.card.noData.description": "Utilisez Elastic Agent pour collecter de manière simple et unifiée les données de vos machines.",
@@ -14597,7 +14606,6 @@
"xpack.csp.cnvmDashboardTable.section.topVulnerableResources.column.vulnerabilities": "Vulnérabilités",
"xpack.csp.cnvmDashboardTable.section.topVulnerableResources.column.vulnerabilityCount": "Vulnérabilités",
"xpack.csp.common.component.multiSelectFilter.searchWord": "Recherche",
- "sharedPlatformPackages.csp.common.utils.helpers.unknownError": "Erreur inconnue",
"xpack.csp.compactFormattedNumber.naTitle": "S. O.",
"xpack.csp.complianceScoreBar.tooltipTitle": "{failed} échecs et {passed} réussites de résultats",
"xpack.csp.complianceScoreChart.counterButtonLink.failedFindingsTooltip": "Échec des résultats",
@@ -14612,9 +14620,6 @@
"xpack.csp.createPackagePolicy.customAssetsTab.rulesViewLabel": "Afficher les règles CSP",
"xpack.csp.createPackagePolicy.customAssetsTab.vulnerabilityDashboardViewLabel": "Afficher le tableau de bord CNVM",
"xpack.csp.createPackagePolicy.customAssetsTab.vulnerabilityFindingsViewLabel": "Afficher les résultats des vulnérabilités",
- "securitySolutionPackages.csp.cspEvaluationBadge.failLabel": "Échec",
- "securitySolutionPackages.csp.cspEvaluationBadge.naLabel": "S. O.",
- "securitySolutionPackages.csp.cspEvaluationBadge.passLabel": "Réussite",
"xpack.csp.cspIntegration.gcpCloudCredentials.cloudFormationSupportedMessage": "La fonctionnalité Lancer Cloud Shell pour obtenir les informations d'identification de façon automatisée n’est pas pris en charge dans la version d'intégration actuelle. Veuillez effectuer une mise à niveau vers la dernière version pour activer Lancer Cloud Shell pour les informations d'identification automatisées.",
"xpack.csp.cspmIntegration.awsOption.benchmarkTitle": "CIS AWS",
"xpack.csp.cspmIntegration.awsOption.nameTitle": "AWS",
@@ -14698,7 +14703,6 @@
"xpack.csp.findings.distributionBar.totalPassedLabel": "Réussite des résultats",
"xpack.csp.findings.errorCallout.pageSearchErrorTitle": "Une erreur s’est produite lors de la récupération des résultats de recherche.",
"xpack.csp.findings.errorCallout.showErrorButtonLabel": "Afficher le message d'erreur",
- "securitySolutionPackages.csp.findings.findingsErrorToast.searchFailedTitle": "Échec de la recherche",
"xpack.csp.findings.findingsFlyout.calloutTitle": "Certains champs ne sont pas fournis par {vendor}",
"xpack.csp.findings.findingsFlyout.flyoutDescriptionList.resourceId": "ID ressource",
"xpack.csp.findings.findingsFlyout.flyoutDescriptionList.resourceName": "Nom de ressource",
@@ -14868,10 +14872,6 @@
"xpack.csp.kspmIntegration.integration.shortNameTitle": "KSPM",
"xpack.csp.kspmIntegration.vanillaOption.benchmarkTitle": "CIS Kubernetes",
"xpack.csp.kspmIntegration.vanillaOption.nameTitle": "Autogéré",
- "securitySolutionPackages.csp.navigation.dashboardNavItemLabel": "Niveau de sécurité du cloud",
- "securitySolutionPackages.csp.navigation.findingsNavItemLabel": "Résultats",
- "securitySolutionPackages.csp.navigation.rulesNavItemLabel": "Règles",
- "securitySolutionPackages.csp.navigation.vulnerabilityDashboardNavItemLabel": "Gestion des vulnérabilités natives du cloud",
"xpack.csp.noFindingsStates.indexing.indexingButtonTitle": "Évaluation du niveau en cours",
"xpack.csp.noFindingsStates.indexing.indexingDescription": "En attente de la collecte et de l'indexation des données. Revenez plus tard pour voir vos résultats",
"xpack.csp.noFindingsStates.indexTimeout.indexTimeoutDescription": "La collecte des résultats prend plus de temps que prévu. {docs}.",
@@ -37703,7 +37703,6 @@
"xpack.securitySolution.detectionEngine.createRule.stepDefineRule.multiSelectFields.placeholderText": "Sélectionner un champ",
"xpack.securitySolution.detectionEngine.createRule.stepDefineRule.newTermsField.placeholderText": "Sélectionner un champ",
"xpack.securitySolution.detectionEngine.createRule.stepDefineRule.newTermsFieldsLabel": "Champs",
- "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.newTermsFieldsMin": "Au moins un champ est requis.",
"xpack.securitySolution.detectionEngine.createRule.stepDefineRule.referencesUrlInvalidError": "Le format de l’URL n’est pas valide.",
"xpack.securitySolution.detectionEngine.createRule.stepDefineRule.resetDefaultIndicesButton": "Réinitialiser sur les modèles d'indexation par défaut",
"xpack.securitySolution.detectionEngine.createRule.stepDefineRule.rulePreviewTitle": "Aperçu de la règle",
@@ -39008,7 +39007,6 @@
"xpack.securitySolution.detectionEngine.userUnauthenticatedMsgBody": "Vous ne disposez pas des autorisations requises pour visualiser le moteur de détection. Pour une aide supplémentaire, contactez votre administrateur.",
"xpack.securitySolution.detectionEngine.userUnauthenticatedTitle": "Autorisations de moteur de détection requises",
"xpack.securitySolution.detectionEngine.validations.stepDefineRule.historyWindowSize.errMin": "La taille de la fenêtre d'historique doit être supérieure à 0.",
- "xpack.securitySolution.detectionEngine.validations.stepDefineRule.newTermsFieldsMax": "Le nombre de champs doit être de 3 au maximum.",
"xpack.securitySolution.detectionEngine.validations.thresholdCardinalityFieldFieldData.thresholdCardinalityFieldNotSuppliedMessage": "Un champ Cardinalité est requis.",
"xpack.securitySolution.detectionEngine.validations.thresholdCardinalityValueFieldData.numberGreaterThanOrEqualOneErrorMessage": "La valeur doit être supérieure ou égale à un.",
"xpack.securitySolution.detectionEngine.validations.thresholdFieldFieldData.arrayLengthGreaterThanMaxErrorMessage": "Le nombre de champs doit être de 3 au maximum.",
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 8641da40c1e3c..ceafc1e58d002 100644
--- a/x-pack/platform/plugins/private/translations/translations/ja-JP.json
+++ b/x-pack/platform/plugins/private/translations/translations/ja-JP.json
@@ -7139,6 +7139,14 @@
"securitySolutionPackages.alertSuppressionRuleDetails.upsell": "アラート非表示が構成されていますが、ライセンス不足のため適用されません",
"securitySolutionPackages.alertSuppressionRuleForm.upsell": "アラートの非表示は、{requiredLicense}ライセンス以上で有効です",
"securitySolutionPackages.beta.label": "ベータ",
+ "securitySolutionPackages.csp.cspEvaluationBadge.failLabel": "失敗",
+ "securitySolutionPackages.csp.cspEvaluationBadge.naLabel": "N/A",
+ "securitySolutionPackages.csp.cspEvaluationBadge.passLabel": "合格",
+ "securitySolutionPackages.csp.findings.findingsErrorToast.searchFailedTitle": "検索失敗",
+ "securitySolutionPackages.csp.navigation.dashboardNavItemLabel": "クラウドセキュリティ態勢",
+ "securitySolutionPackages.csp.navigation.findingsNavItemLabel": "調査結果",
+ "securitySolutionPackages.csp.navigation.rulesNavItemLabel": "ルール",
+ "securitySolutionPackages.csp.navigation.vulnerabilityDashboardNavItemLabel": "Cloud Native Vulnerability Management",
"securitySolutionPackages.dataTable.ariaLabel": "アラート",
"securitySolutionPackages.dataTable.columnHeaders.flyout.pane.removeColumnButtonLabel": "列を削除",
"securitySolutionPackages.dataTable.eventRenderedView.eventSummary.column": "イベント概要",
@@ -7467,6 +7475,7 @@
"share.urlService.redirect.RedirectManager.missingParamLocator": "ロケーターIDが指定されていません。URLで「l」検索パラメーターを指定します。これは既存のロケーターIDにしてください。",
"share.urlService.redirect.RedirectManager.missingParamParams": "ロケーターパラメーターが指定されていません。URLで「p」検索パラメーターを指定します。これはロケーターパラメーターのJSONシリアル化オブジェクトにしてください。",
"share.urlService.redirect.RedirectManager.missingParamVersion": "ロケーターパラメーターバージョンが指定されていません。URLで「v」検索パラメーターを指定します。これはロケーターパラメーターが生成されたときのKibanaのリリースバージョンです。",
+ "sharedPlatformPackages.csp.common.utils.helpers.unknownError": "不明なエラー",
"sharedUXPackages.buttonToolbar.buttons.addFromLibrary.libraryButtonLabel": "ライブラリから追加",
"sharedUXPackages.buttonToolbar.toolbar.errorToolbarText": "120以上のボタンがあります。ボタンの数を制限することを検討してください。",
"sharedUXPackages.card.noData.description": "Elasticエージェントを使用すると、シンプルで統一された方法でコンピューターからデータを収集するできます。",
@@ -14464,7 +14473,6 @@
"xpack.csp.cnvmDashboardTable.section.topVulnerableResources.column.vulnerabilities": "脆弱性",
"xpack.csp.cnvmDashboardTable.section.topVulnerableResources.column.vulnerabilityCount": "脆弱性",
"xpack.csp.common.component.multiSelectFilter.searchWord": "検索",
- "sharedPlatformPackages.csp.common.utils.helpers.unknownError": "不明なエラー",
"xpack.csp.compactFormattedNumber.naTitle": "N/A",
"xpack.csp.complianceScoreBar.tooltipTitle": "{failed}が失敗し、{passed}が調査結果に合格しました",
"xpack.csp.complianceScoreChart.counterButtonLink.failedFindingsTooltip": "失敗した調査結果",
@@ -14479,9 +14487,6 @@
"xpack.csp.createPackagePolicy.customAssetsTab.rulesViewLabel": "CSPルールを表示",
"xpack.csp.createPackagePolicy.customAssetsTab.vulnerabilityDashboardViewLabel": "CNVMダッシュボードを表示",
"xpack.csp.createPackagePolicy.customAssetsTab.vulnerabilityFindingsViewLabel": "脆弱性の調査結果を表示",
- "securitySolutionPackages.csp.cspEvaluationBadge.failLabel": "失敗",
- "securitySolutionPackages.csp.cspEvaluationBadge.naLabel": "N/A",
- "securitySolutionPackages.csp.cspEvaluationBadge.passLabel": "合格",
"xpack.csp.cspIntegration.gcpCloudCredentials.cloudFormationSupportedMessage": "Launch Cloud ShellLaunch Cloud Formation for Automated Credentialsは、現在の統合バージョンではサポートされていません。Launch Cloud Shell for Automated Credentialsを有効化するには、最新バージョンにアップグレードしてください。",
"xpack.csp.cspmIntegration.awsOption.benchmarkTitle": "CIS AWS",
"xpack.csp.cspmIntegration.awsOption.nameTitle": "AWS",
@@ -14564,7 +14569,6 @@
"xpack.csp.findings.distributionBar.totalPassedLabel": "合格した調査結果",
"xpack.csp.findings.errorCallout.pageSearchErrorTitle": "検索結果の取得中にエラーが発生しました",
"xpack.csp.findings.errorCallout.showErrorButtonLabel": "エラーメッセージを表示",
- "securitySolutionPackages.csp.findings.findingsErrorToast.searchFailedTitle": "検索失敗",
"xpack.csp.findings.findingsFlyout.calloutTitle": "一部のフィールドは{vendor}によって提供されていません",
"xpack.csp.findings.findingsFlyout.flyoutDescriptionList.resourceId": "リソースID",
"xpack.csp.findings.findingsFlyout.flyoutDescriptionList.resourceName": "リソース名",
@@ -14733,10 +14737,6 @@
"xpack.csp.kspmIntegration.integration.shortNameTitle": "KSPM",
"xpack.csp.kspmIntegration.vanillaOption.benchmarkTitle": "CIS Kubernetes",
"xpack.csp.kspmIntegration.vanillaOption.nameTitle": "自己管理",
- "securitySolutionPackages.csp.navigation.dashboardNavItemLabel": "クラウドセキュリティ態勢",
- "securitySolutionPackages.csp.navigation.findingsNavItemLabel": "調査結果",
- "securitySolutionPackages.csp.navigation.rulesNavItemLabel": "ルール",
- "securitySolutionPackages.csp.navigation.vulnerabilityDashboardNavItemLabel": "Cloud Native Vulnerability Management",
"xpack.csp.noFindingsStates.indexing.indexingButtonTitle": "態勢評価中",
"xpack.csp.noFindingsStates.indexing.indexingDescription": "データの収集とインデックス作成を待機しています。結果を表示するには、しばらくたってから確認してください",
"xpack.csp.noFindingsStates.indexTimeout.indexTimeoutDescription": "調査結果の収集に想定よりも時間がかかっています。{docs}。",
@@ -37561,7 +37561,6 @@
"xpack.securitySolution.detectionEngine.createRule.stepDefineRule.multiSelectFields.placeholderText": "フィールドを選択",
"xpack.securitySolution.detectionEngine.createRule.stepDefineRule.newTermsField.placeholderText": "フィールドを選択",
"xpack.securitySolution.detectionEngine.createRule.stepDefineRule.newTermsFieldsLabel": "フィールド",
- "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.newTermsFieldsMin": "1つ以上のフィールドが必要です。",
"xpack.securitySolution.detectionEngine.createRule.stepDefineRule.referencesUrlInvalidError": "URLの形式が無効です",
"xpack.securitySolution.detectionEngine.createRule.stepDefineRule.resetDefaultIndicesButton": "デフォルトインデックスパターンにリセット",
"xpack.securitySolution.detectionEngine.createRule.stepDefineRule.rulePreviewTitle": "ルールプレビュー",
@@ -38865,7 +38864,6 @@
"xpack.securitySolution.detectionEngine.userUnauthenticatedMsgBody": "検出エンジンを表示するための必要なアクセス権がありません。ヘルプについては、管理者にお問い合わせください。",
"xpack.securitySolution.detectionEngine.userUnauthenticatedTitle": "検出エンジンアクセス権が必要です",
"xpack.securitySolution.detectionEngine.validations.stepDefineRule.historyWindowSize.errMin": "履歴ウィンドウサイズは0よりも大きい値でなければなりません。",
- "xpack.securitySolution.detectionEngine.validations.stepDefineRule.newTermsFieldsMax": "フィールド数は3以下でなければなりません。",
"xpack.securitySolution.detectionEngine.validations.thresholdCardinalityFieldFieldData.thresholdCardinalityFieldNotSuppliedMessage": "カーディナリティフィールドは必須です。",
"xpack.securitySolution.detectionEngine.validations.thresholdCardinalityValueFieldData.numberGreaterThanOrEqualOneErrorMessage": "値は 1 以上でなければなりません。",
"xpack.securitySolution.detectionEngine.validations.thresholdFieldFieldData.arrayLengthGreaterThanMaxErrorMessage": "フィールド数は3以下でなければなりません。",
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 d6bca0a79d647..6a3f3c2e483a2 100644
--- a/x-pack/platform/plugins/private/translations/translations/zh-CN.json
+++ b/x-pack/platform/plugins/private/translations/translations/zh-CN.json
@@ -7023,6 +7023,14 @@
"securitySolutionPackages.alertSuppressionRuleDetails.upsell": "已配置告警阻止,但由于许可不足而无法应用",
"securitySolutionPackages.alertSuppressionRuleForm.upsell": "告警阻止通过{requiredLicense}或更高级许可证启用",
"securitySolutionPackages.beta.label": "公测版",
+ "securitySolutionPackages.csp.cspEvaluationBadge.failLabel": "失败",
+ "securitySolutionPackages.csp.cspEvaluationBadge.naLabel": "不可用",
+ "securitySolutionPackages.csp.cspEvaluationBadge.passLabel": "通过",
+ "securitySolutionPackages.csp.findings.findingsErrorToast.searchFailedTitle": "搜索失败",
+ "securitySolutionPackages.csp.navigation.dashboardNavItemLabel": "云安全态势",
+ "securitySolutionPackages.csp.navigation.findingsNavItemLabel": "结果",
+ "securitySolutionPackages.csp.navigation.rulesNavItemLabel": "规则",
+ "securitySolutionPackages.csp.navigation.vulnerabilityDashboardNavItemLabel": "云原生漏洞管理",
"securitySolutionPackages.dataTable.ariaLabel": "告警",
"securitySolutionPackages.dataTable.columnHeaders.flyout.pane.removeColumnButtonLabel": "移除列",
"securitySolutionPackages.dataTable.eventRenderedView.eventSummary.column": "事件摘要",
@@ -7352,6 +7360,7 @@
"share.urlService.redirect.RedirectManager.missingParamLocator": "未指定定位器 ID。在 URL 中指定'l'搜索参数,其应为现有定位器 ID。",
"share.urlService.redirect.RedirectManager.missingParamParams": "定位器参数未指定。在 URL 中指定'p'搜索参数,其应为定位器参数的 JSON 序列化对象。",
"share.urlService.redirect.RedirectManager.missingParamVersion": "定位器参数版本未指定。在 URL 中指定'v'搜索参数,其应为生成定位器参数时 Kibana 的版本。",
+ "sharedPlatformPackages.csp.common.utils.helpers.unknownError": "未知错误",
"sharedUXPackages.buttonToolbar.buttons.addFromLibrary.libraryButtonLabel": "从库中添加",
"sharedUXPackages.buttonToolbar.toolbar.errorToolbarText": "有 120 多个附加按钮。请考虑限制按钮数量。",
"sharedUXPackages.card.noData.description": "使用 Elastic 代理以简单统一的方式从您的计算机中收集数据。",
@@ -14194,7 +14203,6 @@
"xpack.csp.cnvmDashboardTable.section.topVulnerableResources.column.vulnerabilities": "漏洞",
"xpack.csp.cnvmDashboardTable.section.topVulnerableResources.column.vulnerabilityCount": "漏洞",
"xpack.csp.common.component.multiSelectFilter.searchWord": "搜索",
- "sharedPlatformPackages.csp.common.utils.helpers.unknownError": "未知错误",
"xpack.csp.compactFormattedNumber.naTitle": "不可用",
"xpack.csp.complianceScoreBar.tooltipTitle": "{failed} 个失败和 {passed} 个通过的结果",
"xpack.csp.complianceScoreChart.counterButtonLink.failedFindingsTooltip": "失败的结果",
@@ -14209,9 +14217,6 @@
"xpack.csp.createPackagePolicy.customAssetsTab.rulesViewLabel": "查看 CSP 规则",
"xpack.csp.createPackagePolicy.customAssetsTab.vulnerabilityDashboardViewLabel": "查看 CNVM 仪表板",
"xpack.csp.createPackagePolicy.customAssetsTab.vulnerabilityFindingsViewLabel": "查看漏洞结果",
- "securitySolutionPackages.csp.cspEvaluationBadge.failLabel": "失败",
- "securitySolutionPackages.csp.cspEvaluationBadge.naLabel": "不可用",
- "securitySolutionPackages.csp.cspEvaluationBadge.passLabel": "通过",
"xpack.csp.cspIntegration.gcpCloudCredentials.cloudFormationSupportedMessage": "当前集成版本不支持为自动化凭据启动 Cloud Shell。请升级到最新版本以启用为自动化凭据启动 Cloud Shell。",
"xpack.csp.cspmIntegration.awsOption.benchmarkTitle": "CIS AWS",
"xpack.csp.cspmIntegration.awsOption.nameTitle": "AWS",
@@ -14295,7 +14300,6 @@
"xpack.csp.findings.distributionBar.totalPassedLabel": "通过的结果",
"xpack.csp.findings.errorCallout.pageSearchErrorTitle": "检索搜索结果时遇到问题",
"xpack.csp.findings.errorCallout.showErrorButtonLabel": "显示错误消息",
- "securitySolutionPackages.csp.findings.findingsErrorToast.searchFailedTitle": "搜索失败",
"xpack.csp.findings.findingsFlyout.calloutTitle": "{vendor} 未提供某些字段",
"xpack.csp.findings.findingsFlyout.flyoutDescriptionList.resourceId": "资源 ID",
"xpack.csp.findings.findingsFlyout.flyoutDescriptionList.resourceName": "资源名称",
@@ -14465,10 +14469,6 @@
"xpack.csp.kspmIntegration.integration.shortNameTitle": "KSPM",
"xpack.csp.kspmIntegration.vanillaOption.benchmarkTitle": "CIS Kubernetes",
"xpack.csp.kspmIntegration.vanillaOption.nameTitle": "自管型",
- "securitySolutionPackages.csp.navigation.dashboardNavItemLabel": "云安全态势",
- "securitySolutionPackages.csp.navigation.findingsNavItemLabel": "结果",
- "securitySolutionPackages.csp.navigation.rulesNavItemLabel": "规则",
- "securitySolutionPackages.csp.navigation.vulnerabilityDashboardNavItemLabel": "云原生漏洞管理",
"xpack.csp.noFindingsStates.indexing.indexingButtonTitle": "正进行态势评估",
"xpack.csp.noFindingsStates.indexing.indexingDescription": "正在等待要收集和索引的数据。请稍后返回检查以查看结果",
"xpack.csp.noFindingsStates.indexTimeout.indexTimeoutDescription": "收集结果所需的时间长于预期。{docs}。",
@@ -36993,7 +36993,6 @@
"xpack.securitySolution.detectionEngine.createRule.stepDefineRule.multiSelectFields.placeholderText": "选择字段",
"xpack.securitySolution.detectionEngine.createRule.stepDefineRule.newTermsField.placeholderText": "选择字段",
"xpack.securitySolution.detectionEngine.createRule.stepDefineRule.newTermsFieldsLabel": "字段",
- "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.newTermsFieldsMin": "至少需要一个字段。",
"xpack.securitySolution.detectionEngine.createRule.stepDefineRule.referencesUrlInvalidError": "URL 的格式无效",
"xpack.securitySolution.detectionEngine.createRule.stepDefineRule.resetDefaultIndicesButton": "重置为默认索引模式",
"xpack.securitySolution.detectionEngine.createRule.stepDefineRule.rulePreviewTitle": "规则预览",
@@ -38292,7 +38291,6 @@
"xpack.securitySolution.detectionEngine.userUnauthenticatedMsgBody": "您没有所需的权限,无法查看检测引擎。若需要更多帮助,请联系您的管理员。",
"xpack.securitySolution.detectionEngine.userUnauthenticatedTitle": "需要检测引擎权限",
"xpack.securitySolution.detectionEngine.validations.stepDefineRule.historyWindowSize.errMin": "历史记录窗口大小必须大于 0。",
- "xpack.securitySolution.detectionEngine.validations.stepDefineRule.newTermsFieldsMax": "字段数目不得超过 3 个。",
"xpack.securitySolution.detectionEngine.validations.thresholdCardinalityFieldFieldData.thresholdCardinalityFieldNotSuppliedMessage": "基数字段必填。",
"xpack.securitySolution.detectionEngine.validations.thresholdCardinalityValueFieldData.numberGreaterThanOrEqualOneErrorMessage": "值必须大于或等于 1。",
"xpack.securitySolution.detectionEngine.validations.thresholdFieldFieldData.arrayLengthGreaterThanMaxErrorMessage": "字段数目不得超过 3 个。",
diff --git a/x-pack/solutions/security/plugins/security_solution/public/common/components/ml/hooks/use_ml_rule_config.ts b/x-pack/solutions/security/plugins/security_solution/public/common/components/ml/hooks/use_ml_rule_config.ts
index 139acb0473c8b..9b60c15dc1354 100644
--- a/x-pack/solutions/security/plugins/security_solution/public/common/components/ml/hooks/use_ml_rule_config.ts
+++ b/x-pack/solutions/security/plugins/security_solution/public/common/components/ml/hooks/use_ml_rule_config.ts
@@ -5,16 +5,15 @@
* 2.0.
*/
-import { useMemo } from 'react';
import type { DataViewFieldBase } from '@kbn/es-query';
import type { FieldSpec } from '@kbn/data-plugin/common';
-import { getTermsAggregationFields } from '../../../../detection_engine/rule_creation_ui/components/step_define_rule/utils';
import { useRuleFields } from '../../../../detection_engine/rule_management/logic/use_rule_fields';
import { useMlCapabilities } from './use_ml_capabilities';
import { useMlRuleValidations } from './use_ml_rule_validations';
import { hasMlAdminPermissions } from '../../../../../common/machine_learning/has_ml_admin_permissions';
import { hasMlLicense } from '../../../../../common/machine_learning/has_ml_license';
+import { useTermsAggregationFields } from '../../../hooks/use_terms_aggregation_fields';
export interface UseMlRuleConfigReturn {
hasMlAdminPermissions: boolean;
@@ -45,10 +44,7 @@ export const useMLRuleConfig = ({
const { loading: mlFieldsLoading, fields: mlFields } = useRuleFields({
machineLearningJobId,
});
- const mlSuppressionFields = useMemo(
- () => getTermsAggregationFields(mlFields as FieldSpec[]),
- [mlFields]
- );
+ const mlSuppressionFields = useTermsAggregationFields(mlFields);
return {
hasMlAdminPermissions: hasMlAdminPermissions(mlCapabilities),
diff --git a/x-pack/solutions/security/plugins/security_solution/public/common/constants.ts b/x-pack/solutions/security/plugins/security_solution/public/common/constants.ts
index c114f70915a75..a9761e87c20e1 100644
--- a/x-pack/solutions/security/plugins/security_solution/public/common/constants.ts
+++ b/x-pack/solutions/security/plugins/security_solution/public/common/constants.ts
@@ -18,3 +18,5 @@ export const RISK_SCORE_HIGH = 73;
export const RISK_SCORE_CRITICAL = 99;
export const ONBOARDING_VIDEO_SOURCE = '//play.vidyard.com/K6kKDBbP9SpXife9s2tHNP.html?';
+
+export const DEFAULT_HISTORY_WINDOW_SIZE = '7d';
diff --git a/x-pack/solutions/security/plugins/security_solution/public/common/hooks/use_terms_aggregation_fields.ts b/x-pack/solutions/security/plugins/security_solution/public/common/hooks/use_terms_aggregation_fields.ts
new file mode 100644
index 0000000000000..e62b16e826766
--- /dev/null
+++ b/x-pack/solutions/security/plugins/security_solution/public/common/hooks/use_terms_aggregation_fields.ts
@@ -0,0 +1,29 @@
+/*
+ * 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 { useMemo } from 'react';
+import type { FieldSpec } from '@kbn/data-views-plugin/common';
+import type { DataViewFieldBase } from '@kbn/es-query';
+import { getTermsAggregationFields } from '../../detection_engine/rule_creation_ui/components/step_define_rule/utils';
+
+export function useTermsAggregationFields(fields?: DataViewFieldBase[]) {
+ const termsAggregationFields = useMemo(
+ /**
+ * Typecasting to FieldSpec because fields is
+ * typed as DataViewFieldBase[] which does not have
+ * the 'aggregatable' property, however the type is incorrect
+ *
+ * fields does contain elements with the aggregatable property.
+ * We will need to determine where these types are defined and
+ * figure out where the discrepancy is.
+ */
+ () => getTermsAggregationFields((fields as FieldSpec[]) ?? []),
+ [fields]
+ );
+
+ return termsAggregationFields;
+}
diff --git a/x-pack/solutions/security/plugins/security_solution/public/common/utils/date_math.ts b/x-pack/solutions/security/plugins/security_solution/public/common/utils/date_math.ts
new file mode 100644
index 0000000000000..28dbe15955a27
--- /dev/null
+++ b/x-pack/solutions/security/plugins/security_solution/public/common/utils/date_math.ts
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+/**
+ * Converts a date math string to a duration string by removing the 'now-' prefix.
+ *
+ * @param historyStart - Date math string to convert. For example, "now-30d".
+ * @returns Resulting duration string. For example, "30d".
+ */
+export const convertDateMathToDuration = (dateMathString: string): string => {
+ if (dateMathString.startsWith('now-')) {
+ return dateMathString.substring(4);
+ }
+
+ return dateMathString;
+};
+
+/**
+ * Converts a duration string to a dateMath string by adding the 'now-' prefix.
+ *
+ * @param durationString - Duration string to convert. For example, "30d".
+ * @returns Resulting date math string. For example, "now-30d".
+ */
+export const convertDurationToDateMath = (durationString: string): string =>
+ `now-${durationString}`;
diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/history_window_start_edit/history_window_start_edit.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/history_window_start_edit/history_window_start_edit.tsx
new file mode 100644
index 0000000000000..c876fe926ce4f
--- /dev/null
+++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/history_window_start_edit/history_window_start_edit.tsx
@@ -0,0 +1,44 @@
+/*
+ * 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 { ScheduleItemField } from '../schedule_item_field';
+import { type FieldConfig, UseField } from '../../../../shared_imports';
+import { type HistoryWindowStart } from '../../../../../common/api/detection_engine';
+import * as i18n from './translations';
+import { validateHistoryWindowStart } from './validate_history_window_start';
+
+const COMPONENT_PROPS = {
+ idAria: 'historyWindowSize',
+ dataTestSubj: 'historyWindowSize',
+ timeTypes: ['m', 'h', 'd'],
+};
+
+interface HistoryWindowStartEditProps {
+ path: string;
+}
+
+export function HistoryWindowStartEdit({ path }: HistoryWindowStartEditProps): JSX.Element {
+ return (
+
+ );
+}
+
+const HISTORY_WINDOW_START_FIELD_CONFIG: FieldConfig = {
+ label: i18n.HISTORY_WINDOW_START_LABEL,
+ helpText: i18n.HELP_TEXT,
+ validations: [
+ {
+ validator: validateHistoryWindowStart,
+ },
+ ],
+};
diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/components/new_terms_fields/translations.ts b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/history_window_start_edit/index.tsx
similarity index 51%
rename from x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/components/new_terms_fields/translations.ts
rename to x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/history_window_start_edit/index.tsx
index 1bf73b4a46b48..a904f5d427710 100644
--- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/components/new_terms_fields/translations.ts
+++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/history_window_start_edit/index.tsx
@@ -5,11 +5,4 @@
* 2.0.
*/
-import { i18n } from '@kbn/i18n';
-
-export const NEW_TERMS_FIELD_PLACEHOLDER = i18n.translate(
- 'xpack.securitySolution.detectionEngine.createRule.stepDefineRule.newTermsField.placeholderText',
- {
- defaultMessage: 'Select a field',
- }
-);
+export { HistoryWindowStartEdit } from './history_window_start_edit';
diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/history_window_start_edit/translations.ts b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/history_window_start_edit/translations.ts
new file mode 100644
index 0000000000000..75ff11fe5e1b6
--- /dev/null
+++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/history_window_start_edit/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 HISTORY_WINDOW_START_LABEL = i18n.translate(
+ 'xpack.securitySolution.detectionEngine.createRule.stepDefineRule.historyWindowSizeLabel',
+ {
+ defaultMessage: 'History Window Size',
+ }
+);
+
+export const HELP_TEXT = i18n.translate(
+ 'xpack.securitySolution.detectionEngine.createRule.stepScheduleRule.historyWindowSizeHelpText',
+ {
+ defaultMessage: "New terms rules only alert if terms don't appear in historical data.",
+ }
+);
+
+export const MUST_BE_POSITIVE_INTEGER_VALIDATION_ERROR = i18n.translate(
+ 'xpack.securitySolution.detectionEngine.validations.stepDefineRule.historyWindowSize.errNumber',
+ {
+ defaultMessage: 'History window size must be a positive number.',
+ }
+);
+
+export const MUST_BE_GREATER_THAN_ZERO_VALIDATION_ERROR = i18n.translate(
+ 'xpack.securitySolution.detectionEngine.validations.stepDefineRule.historyWindowSize.errMin',
+ {
+ defaultMessage: 'History window size must be greater than 0.',
+ }
+);
diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/history_window_start_edit/validate_history_window_start.ts b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/history_window_start_edit/validate_history_window_start.ts
new file mode 100644
index 0000000000000..4e274683ad08b
--- /dev/null
+++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/history_window_start_edit/validate_history_window_start.ts
@@ -0,0 +1,31 @@
+/*
+ * 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 ValidationFunc } from '../../../../shared_imports';
+import * as i18n from './translations';
+
+export function validateHistoryWindowStart(...args: Parameters) {
+ const [{ path, value }] = args;
+
+ const historyWindowSize = Number.parseInt(String(value), 10);
+
+ if (Number.isNaN(historyWindowSize)) {
+ return {
+ code: 'ERR_NOT_INT_NUMBER',
+ path,
+ message: i18n.MUST_BE_POSITIVE_INTEGER_VALIDATION_ERROR,
+ };
+ }
+
+ if (historyWindowSize <= 0) {
+ return {
+ code: 'ERR_MIN_LENGTH',
+ path,
+ message: i18n.MUST_BE_GREATER_THAN_ZERO_VALIDATION_ERROR,
+ };
+ }
+}
diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/new_terms_fields_edit/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/new_terms_fields_edit/index.tsx
new file mode 100644
index 0000000000000..22c3c9e9047c0
--- /dev/null
+++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/new_terms_fields_edit/index.tsx
@@ -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 { NewTermsFieldsEdit } from './new_terms_fields_edit';
diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/new_terms_fields_edit/new_terms_fields_edit.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/new_terms_fields_edit/new_terms_fields_edit.tsx
new file mode 100644
index 0000000000000..f50c62ed8f7a0
--- /dev/null
+++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/new_terms_fields_edit/new_terms_fields_edit.tsx
@@ -0,0 +1,43 @@
+/*
+ * 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 { UseField, fieldValidators } from '../../../../shared_imports';
+import { NewTermsFieldsField } from './new_terms_fields_field';
+import * as i18n from './translations';
+
+interface NewTermsFieldsEditProps {
+ path: string;
+ fieldNames: string[];
+}
+
+export const NewTermsFieldsEdit = memo(function NewTermsFieldsEdit({
+ path,
+ fieldNames,
+}: NewTermsFieldsEditProps): JSX.Element {
+ return (
+
+ );
+});
+
+const NEW_TERMS_FIELDS_CONFIG = {
+ label: i18n.NEW_TERMS_FIELDS_LABEL,
+ helpText: i18n.HELP_TEXT,
+ validations: [
+ {
+ validator: fieldValidators.emptyField(i18n.MIN_FIELDS_COUNT_VALIDATION_ERROR),
+ },
+ {
+ validator: fieldValidators.maxLengthField(i18n.MAX_FIELDS_COUNT_VALIDATION_ERROR),
+ },
+ ],
+};
diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/new_terms_fields_edit/new_terms_fields_field.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/new_terms_fields_edit/new_terms_fields_field.tsx
new file mode 100644
index 0000000000000..a9c1148402f12
--- /dev/null
+++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/new_terms_fields_edit/new_terms_fields_field.tsx
@@ -0,0 +1,40 @@
+/*
+ * 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 type { DataViewFieldBase } from '@kbn/es-query';
+import { ComboBoxField } from '@kbn/es-ui-shared-plugin/static/forms/components';
+import type { FieldHook } from '../../../../shared_imports';
+import { PLACEHOLDER } from './translations';
+
+interface NewTermsFieldsProps {
+ fieldNames: DataViewFieldBase[];
+ field: FieldHook;
+}
+
+const FIELD_COMBO_BOX_WIDTH = 410;
+
+const fieldDescribedByIds = 'newTermsFieldEdit';
+
+export const NewTermsFieldsField = memo(function NewTermsFieldsField({
+ fieldNames,
+ field,
+}: NewTermsFieldsProps): JSX.Element {
+ const fieldEuiFieldProps = {
+ fullWidth: true,
+ noSuggestions: false,
+ options: fieldNames.map((name) => ({ label: name })),
+ placeholder: PLACEHOLDER,
+ onCreateOption: undefined,
+ style: { width: `${FIELD_COMBO_BOX_WIDTH}px` },
+ };
+
+ return (
+
+ );
+});
diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/new_terms_fields_edit/translations.ts b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/new_terms_fields_edit/translations.ts
new file mode 100644
index 0000000000000..4eb18b9a318e0
--- /dev/null
+++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/new_terms_fields_edit/translations.ts
@@ -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 { i18n } from '@kbn/i18n';
+import { MAX_NUMBER_OF_NEW_TERMS_FIELDS } from '../../../../../common/constants';
+
+export const NEW_TERMS_FIELDS_LABEL = i18n.translate(
+ 'xpack.securitySolution.detectionEngine.createRule.stepDefineRule.newTermsFieldsLabel',
+ {
+ defaultMessage: 'Fields',
+ }
+);
+
+export const PLACEHOLDER = i18n.translate(
+ 'xpack.securitySolution.detectionEngine.createRule.stepDefineRule.newTermsField.placeholderText',
+ {
+ defaultMessage: 'Select a field',
+ }
+);
+
+export const HELP_TEXT = i18n.translate(
+ 'xpack.securitySolution.detectionEngine.createRule.stepAboutRule.fieldNewTermsFieldHelpText',
+ {
+ defaultMessage: 'Select a field to check for new terms.',
+ }
+);
+
+export const MIN_FIELDS_COUNT_VALIDATION_ERROR = i18n.translate(
+ 'xpack.securitySolution.detectionEngine.createRule.stepDefineRule.newTermsField.minFieldsCountError',
+ {
+ defaultMessage: 'A minimum of one field is required.',
+ }
+);
+
+export const MAX_FIELDS_COUNT_VALIDATION_ERROR = {
+ length: MAX_NUMBER_OF_NEW_TERMS_FIELDS,
+ message: i18n.translate(
+ 'xpack.securitySolution.detectionEngine.validations.stepDefineRule.newTermsField.maxFieldsCountError',
+ {
+ defaultMessage: 'Number of fields must be 3 or less.',
+ }
+ ),
+};
diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/schedule_item_field/index.ts b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/schedule_item_field/index.ts
new file mode 100644
index 0000000000000..f2458bbb5a4e1
--- /dev/null
+++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/schedule_item_field/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 { ScheduleItemField } from './schedule_item_field';
diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/schedule_item_field/schedule_item_field.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/schedule_item_field/schedule_item_field.test.tsx
new file mode 100644
index 0000000000000..bf019bd43f2fd
--- /dev/null
+++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/schedule_item_field/schedule_item_field.test.tsx
@@ -0,0 +1,96 @@
+/*
+ * 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 { mount, shallow } from 'enzyme';
+
+import { ScheduleItemField } from './schedule_item_field';
+import { TestProviders, useFormFieldMock } from '../../../../common/mock';
+
+describe('ScheduleItemField', () => {
+ it('renders correctly', () => {
+ const mockField = useFormFieldMock();
+ const wrapper = shallow(
+
+ );
+
+ expect(wrapper.find('[data-test-subj="schedule-item"]')).toHaveLength(1);
+ });
+
+ it('accepts a large number via user input', () => {
+ const mockField = useFormFieldMock();
+ const wrapper = mount(
+
+
+
+ );
+
+ wrapper
+ .find('[data-test-subj="interval"]')
+ .last()
+ .simulate('change', { target: { value: '5000000' } });
+
+ expect(mockField.setValue).toHaveBeenCalledWith('5000000s');
+ });
+
+ it('clamps a number value greater than MAX_SAFE_INTEGER to MAX_SAFE_INTEGER', () => {
+ const unsafeInput = '99999999999999999999999';
+
+ const mockField = useFormFieldMock();
+ const wrapper = mount(
+
+
+
+ );
+
+ wrapper
+ .find('[data-test-subj="interval"]')
+ .last()
+ .simulate('change', { target: { value: unsafeInput } });
+
+ const expectedValue = `${Number.MAX_SAFE_INTEGER}s`;
+ expect(mockField.setValue).toHaveBeenCalledWith(expectedValue);
+ });
+
+ it('converts a non-numeric value to 0', () => {
+ const unsafeInput = 'this is not a number';
+
+ const mockField = useFormFieldMock();
+ const wrapper = mount(
+
+
+
+ );
+
+ wrapper
+ .find('[data-test-subj="interval"]')
+ .last()
+ .simulate('change', { target: { value: unsafeInput } });
+
+ expect(mockField.setValue).toHaveBeenCalledWith('0s');
+ });
+});
diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/schedule_item_field/schedule_item_field.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/schedule_item_field/schedule_item_field.tsx
new file mode 100644
index 0000000000000..241e3869958a8
--- /dev/null
+++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/schedule_item_field/schedule_item_field.tsx
@@ -0,0 +1,181 @@
+/*
+ * 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 { EuiSelectProps, EuiFieldNumberProps } from '@elastic/eui';
+import {
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiFieldNumber,
+ EuiFormRow,
+ EuiSelect,
+ transparentize,
+} from '@elastic/eui';
+import { isEmpty } from 'lodash/fp';
+import React, { useCallback, useEffect, useMemo, useState } from 'react';
+import styled from 'styled-components';
+
+import type { FieldHook } from '../../../../shared_imports';
+import { getFieldValidityAndErrorMessage } from '../../../../shared_imports';
+
+import * as I18n from './translations';
+
+interface ScheduleItemProps {
+ field: FieldHook;
+ dataTestSubj: string;
+ idAria: string;
+ isDisabled: boolean;
+ minimumValue?: number;
+ timeTypes?: string[];
+ fullWidth?: boolean;
+}
+
+const timeTypeOptions = [
+ { value: 's', text: I18n.SECONDS },
+ { value: 'm', text: I18n.MINUTES },
+ { value: 'h', text: I18n.HOURS },
+ { value: 'd', text: I18n.DAYS },
+];
+
+// move optional label to the end of input
+const StyledLabelAppend = styled(EuiFlexItem)`
+ &.euiFlexItem {
+ margin-left: 31px;
+ }
+`;
+
+const StyledEuiFormRow = styled(EuiFormRow)`
+ max-width: none;
+
+ .euiFormControlLayout__append {
+ padding-inline: 0 !important;
+ }
+
+ .euiFormControlLayoutIcons {
+ color: ${({ theme }) => theme.eui.euiColorPrimary};
+ }
+`;
+
+const MyEuiSelect = styled(EuiSelect)`
+ min-width: 106px; // Preserve layout when disabled & dropdown arrow is not rendered
+ background: ${({ theme }) =>
+ transparentize(theme.eui.euiColorPrimary, 0.1)} !important; // Override focus states etc.
+ color: ${({ theme }) => theme.eui.euiColorPrimary};
+ box-shadow: none;
+`;
+
+const getNumberFromUserInput = (input: string, minimumValue = 0): number => {
+ const number = parseInt(input, 10);
+ if (Number.isNaN(number)) {
+ return minimumValue;
+ } else {
+ return Math.max(minimumValue, Math.min(number, Number.MAX_SAFE_INTEGER));
+ }
+};
+
+export const ScheduleItemField = ({
+ dataTestSubj,
+ field,
+ idAria,
+ isDisabled,
+ minimumValue = 0,
+ timeTypes = ['s', 'm', 'h'],
+ fullWidth = false,
+}: ScheduleItemProps) => {
+ const [timeType, setTimeType] = useState(timeTypes[0]);
+ const [timeVal, setTimeVal] = useState(0);
+ const { isInvalid, errorMessage } = getFieldValidityAndErrorMessage(field);
+ const { value, setValue } = field;
+
+ const onChangeTimeType = useCallback>(
+ (e) => {
+ setTimeType(e.target.value);
+ setValue(`${timeVal}${e.target.value}`);
+ },
+ [setValue, timeVal]
+ );
+
+ const onChangeTimeVal = useCallback>(
+ (e) => {
+ const sanitizedValue = getNumberFromUserInput(e.target.value, minimumValue);
+ setTimeVal(sanitizedValue);
+ setValue(`${sanitizedValue}${timeType}`);
+ },
+ [minimumValue, setValue, timeType]
+ );
+
+ useEffect(() => {
+ if (value !== `${timeVal}${timeType}`) {
+ const filterTimeVal = value.match(/\d+/g);
+ const filterTimeType = value.match(/[a-zA-Z]+/g);
+ if (
+ !isEmpty(filterTimeVal) &&
+ filterTimeVal != null &&
+ !isNaN(Number(filterTimeVal[0])) &&
+ Number(filterTimeVal[0]) !== Number(timeVal)
+ ) {
+ setTimeVal(Number(filterTimeVal[0]));
+ }
+ if (
+ !isEmpty(filterTimeType) &&
+ filterTimeType != null &&
+ timeTypes.includes(filterTimeType[0]) &&
+ filterTimeType[0] !== timeType
+ ) {
+ setTimeType(filterTimeType[0]);
+ }
+ }
+ }, [timeType, timeTypes, timeVal, value]);
+
+ // EUI missing some props
+ const rest = { disabled: isDisabled };
+ const label = useMemo(
+ () => (
+
+
+ {field.label}
+
+
+ {field.labelAppend}
+
+
+ ),
+ [field.label, field.labelAppend]
+ );
+
+ return (
+
+ timeTypes.includes(type.value))}
+ onChange={onChangeTimeType}
+ value={timeType}
+ aria-label={field.label}
+ data-test-subj="timeType"
+ {...rest}
+ />
+ }
+ fullWidth
+ min={minimumValue}
+ max={Number.MAX_SAFE_INTEGER}
+ onChange={onChangeTimeVal}
+ value={timeVal}
+ data-test-subj="interval"
+ {...rest}
+ />
+
+ );
+};
diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/schedule_item_field/translations.ts b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/schedule_item_field/translations.ts
new file mode 100644
index 0000000000000..c460d2f7198b3
--- /dev/null
+++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/schedule_item_field/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 SECONDS = i18n.translate(
+ 'xpack.securitySolution.detectionEngine.createRule.stepScheduleRuleForm.secondsOptionDescription',
+ {
+ defaultMessage: 'Seconds',
+ }
+);
+
+export const MINUTES = i18n.translate(
+ 'xpack.securitySolution.detectionEngine.createRule.stepScheduleRuleForm.minutesOptionDescription',
+ {
+ defaultMessage: 'Minutes',
+ }
+);
+
+export const HOURS = i18n.translate(
+ 'xpack.securitySolution.detectionEngine.createRule.stepScheduleRuleForm.hoursOptionDescription',
+ {
+ defaultMessage: 'Hours',
+ }
+);
+
+export const DAYS = i18n.translate(
+ 'xpack.securitySolution.detectionEngine.createRule.stepScheduleRuleForm.daysOptionDescription',
+ {
+ defaultMessage: 'Days',
+ }
+);
diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/components/description_step/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/components/description_step/index.tsx
index 26c81f325ea18..a91487afc4486 100644
--- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/components/description_step/index.tsx
+++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/components/description_step/index.tsx
@@ -72,6 +72,8 @@ import {
ALERT_SUPPRESSION_MISSING_FIELDS_FIELD_NAME,
} from '../../../rule_creation/components/alert_suppression_edit';
import { THRESHOLD_ALERT_SUPPRESSION_ENABLED } from '../../../rule_creation/components/threshold_alert_suppression_edit';
+import { NEW_TERMS_FIELDS_LABEL } from '../../../rule_creation/components/new_terms_fields_edit/translations';
+import { HISTORY_WINDOW_START_LABEL } from '../../../rule_creation/components/history_window_start_edit/translations';
import type { FieldValueQueryBar } from '../query_bar_field';
const DescriptionListContainer = styled(EuiDescriptionList)`
@@ -341,6 +343,9 @@ export const getDescriptionItem = (
} else if (field === 'threatMapping') {
const threatMap: ThreatMapping = get(field, data);
return buildThreatMappingDescription(label, threatMap);
+ } else if (field === 'newTermsFields') {
+ const values: string[] = get(field, data);
+ return buildStringArrayDescription(NEW_TERMS_FIELDS_LABEL, field, values);
} else if (Array.isArray(get(field, data)) && field !== 'threatMapping') {
const values: string[] = get(field, data);
return buildStringArrayDescription(label, field, values);
@@ -357,6 +362,9 @@ export const getDescriptionItem = (
} else if (field === 'maxSignals') {
const value: number | undefined = get(field, data);
return value ? [{ title: label, description: value }] : [];
+ } else if (field === 'historyWindowSize') {
+ const value: number = get(field, data);
+ return value ? [{ title: HISTORY_WINDOW_START_LABEL, description: value }] : [];
}
const description: string = get(field, data);
diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/components/new_terms_fields/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/components/new_terms_fields/index.tsx
deleted file mode 100644
index 7dfb24200e645..0000000000000
--- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/components/new_terms_fields/index.tsx
+++ /dev/null
@@ -1,42 +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 type { DataViewFieldBase } from '@kbn/es-query';
-import type { FieldHook } from '../../../../shared_imports';
-import { Field } from '../../../../shared_imports';
-import { NEW_TERMS_FIELD_PLACEHOLDER } from './translations';
-
-interface NewTermsFieldsProps {
- browserFields: DataViewFieldBase[];
- field: FieldHook;
-}
-
-const FIELD_COMBO_BOX_WIDTH = 410;
-
-const fieldDescribedByIds = 'detectionEngineStepDefineRuleNewTermsField';
-
-export const NewTermsFieldsComponent: React.FC = ({
- browserFields,
- field,
-}: NewTermsFieldsProps) => {
- const fieldEuiFieldProps = useMemo(
- () => ({
- fullWidth: true,
- noSuggestions: false,
- options: browserFields.map((browserField) => ({ label: browserField.name })),
- placeholder: NEW_TERMS_FIELD_PLACEHOLDER,
- onCreateOption: undefined,
- style: { width: `${FIELD_COMBO_BOX_WIDTH}px` },
- }),
- [browserFields]
- );
- return ;
-};
-
-export const NewTermsFields = React.memo(NewTermsFieldsComponent);
diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/components/rule_preview/helpers.ts b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/components/rule_preview/helpers.ts
index 045e957c4e129..fcbdfdf4f86b7 100644
--- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/components/rule_preview/helpers.ts
+++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/components/rule_preview/helpers.ts
@@ -107,7 +107,7 @@ export const getIsRulePreviewDisabled = ({
threatMapping,
machineLearningJobId,
queryBar,
- newTermsFields,
+ newTermsFields = [],
}: {
ruleType: Type;
isQueryBarValid: boolean;
diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/index.tsx
index 7b056b5969799..f7845c31378af 100644
--- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/index.tsx
+++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/index.tsx
@@ -55,7 +55,6 @@ import {
} from '../../../../shared_imports';
import type { FormHook, FieldHook } from '../../../../shared_imports';
import { schema } from './schema';
-import { getTermsAggregationFields } from './utils';
import { useExperimentalFeatureFieldsTransform } from './use_experimental_feature_fields_transform';
import * as i18n from './translations';
import {
@@ -72,8 +71,6 @@ import { EqlQueryEdit } from '../../../rule_creation/components/eql_query_edit';
import { DataViewSelectorField } from '../data_view_selector_field';
import { ThreatMatchInput } from '../threatmatch_input';
import { useFetchIndex } from '../../../../common/containers/source';
-import { NewTermsFields } from '../new_terms_fields';
-import { ScheduleItem } from '../../../rule_creation/components/schedule_item_form';
import { RequiredFields } from '../../../rule_creation/components/required_fields';
import { DocLink } from '../../../../common/components/links_to_docs/doc_link';
import { useLicense } from '../../../../common/hooks/use_license';
@@ -90,6 +87,10 @@ import {
} from '../../../rule_creation/components/alert_suppression_edit';
import { ThresholdAlertSuppressionEdit } from '../../../rule_creation/components/threshold_alert_suppression_edit';
import { usePersistentAlertSuppressionState } from './use_persistent_alert_suppression_state';
+import { useTermsAggregationFields } from '../../../../common/hooks/use_terms_aggregation_fields';
+import { HistoryWindowStartEdit } from '../../../rule_creation/components/history_window_start_edit';
+import { NewTermsFieldsEdit } from '../../../rule_creation/components/new_terms_fields_edit';
+import { usePersistentNewTermsState } from './use_persistent_new_terms_state';
import { EsqlQueryEdit } from '../../../rule_creation/components/esql_query_edit';
import { usePersistentQuery } from './use_persistent_query';
@@ -211,18 +212,11 @@ const StepDefineRuleComponent: FC = ({
() => (indexPattern.fields as FieldSpec[]).filter((field) => field.aggregatable === true),
[indexPattern.fields]
);
- const termsAggregationFields = useMemo(
- /**
- * Typecasting to FieldSpec because fields is
- * typed as DataViewFieldBase[] which does not have
- * the 'aggregatable' property, however the type is incorrect
- *
- * fields does contain elements with the aggregatable property.
- * We will need to determine where these types are defined and
- * figure out where the discrepency is.
- */
- () => getTermsAggregationFields(indexPattern.fields as FieldSpec[]),
- [indexPattern.fields]
+
+ const termsAggregationFields = useTermsAggregationFields(indexPattern.fields);
+ const termsAggregationFieldNames = useMemo(
+ () => termsAggregationFields.map((field) => field.name),
+ [termsAggregationFields]
);
const [threatIndexPatternsLoading, { indexPatterns: threatIndexPatterns }] =
@@ -245,6 +239,12 @@ const StepDefineRuleComponent: FC = ({
form,
});
usePersistentAlertSuppressionState({ form });
+ usePersistentNewTermsState({
+ form,
+ ruleTypePath: 'ruleType',
+ newTermsFieldsPath: 'newTermsFields',
+ historyWindowStartPath: 'historyWindowSize',
+ });
const handleSetRuleFromTimeline = useCallback(
({ index: timelineIndex, queryBar: timelineQueryBar, eqlOptions }) => {
@@ -730,30 +730,14 @@ const StepDefineRuleComponent: FC = ({
>
-
- <>
-
-
- >
-
+ {isNewTermsRule(ruleType) && (
+
+ <>
+
+
+ >
+
+ )}
diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/schema.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/schema.tsx
index 323e321eee8d9..4f168d94388d5 100644
--- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/schema.tsx
+++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/schema.tsx
@@ -17,12 +17,10 @@ import {
} from '../../../../common/components/threat_match/helpers';
import {
isEsqlRule,
- isNewTermsRule,
isThreatMatchRule,
isThresholdRule,
isSuppressionRuleConfiguredWithGroupBy,
} from '../../../../../common/detection_engine/utils';
-import { MAX_NUMBER_OF_NEW_TERMS_FIELDS } from '../../../../../common/constants';
import { isMlRule } from '../../../../../common/machine_learning/helpers';
import type { ERROR_CODE, FormSchema, ValidationFunc } from '../../../../shared_imports';
import { FIELD_TYPES, fieldValidators } from '../../../../shared_imports';
@@ -478,106 +476,8 @@ export const schema: FormSchema = {
},
],
},
- newTermsFields: {
- type: FIELD_TYPES.COMBO_BOX,
- label: i18n.translate(
- 'xpack.securitySolution.detectionEngine.createRule.stepDefineRule.newTermsFieldsLabel',
- {
- defaultMessage: 'Fields',
- }
- ),
- helpText: i18n.translate(
- 'xpack.securitySolution.detectionEngine.createRule.stepAboutRule.fieldNewTermsFieldHelpText',
- {
- defaultMessage: 'Select a field to check for new terms.',
- }
- ),
- validations: [
- {
- validator: (
- ...args: Parameters
- ): ReturnType> | undefined => {
- const [{ formData }] = args;
- const needsValidation = isNewTermsRule(formData.ruleType);
- if (!needsValidation) {
- return;
- }
-
- return fieldValidators.emptyField(
- i18n.translate(
- 'xpack.securitySolution.detectionEngine.createRule.stepDefineRule.newTermsFieldsMin',
- {
- defaultMessage: 'A minimum of one field is required.',
- }
- )
- )(...args);
- },
- },
- {
- validator: (
- ...args: Parameters
- ): ReturnType> | undefined => {
- const [{ formData }] = args;
- const needsValidation = isNewTermsRule(formData.ruleType);
- if (!needsValidation) {
- return;
- }
- return fieldValidators.maxLengthField({
- length: MAX_NUMBER_OF_NEW_TERMS_FIELDS,
- message: i18n.translate(
- 'xpack.securitySolution.detectionEngine.validations.stepDefineRule.newTermsFieldsMax',
- {
- defaultMessage: 'Number of fields must be 3 or less.',
- }
- ),
- })(...args);
- },
- },
- ],
- },
- historyWindowSize: {
- label: i18n.translate(
- 'xpack.securitySolution.detectionEngine.createRule.stepDefineRule.historyWindowSizeLabel',
- {
- defaultMessage: 'History Window Size',
- }
- ),
- helpText: i18n.translate(
- 'xpack.securitySolution.detectionEngine.createRule.stepScheduleRule.historyWindowSizeHelpText',
- {
- defaultMessage: "New terms rules only alert if terms don't appear in historical data.",
- }
- ),
- validations: [
- {
- validator: (
- ...args: Parameters
- ): ReturnType> | undefined => {
- const [{ path, formData }] = args;
- const needsValidation = isNewTermsRule(formData.ruleType);
-
- if (!needsValidation) {
- return;
- }
-
- const filterTimeVal = formData.historyWindowSize.match(/\d+/g);
-
- if (filterTimeVal <= 0) {
- return {
- code: 'ERR_MIN_LENGTH',
- path,
- message: i18n.translate(
- 'xpack.securitySolution.detectionEngine.validations.stepDefineRule.historyWindowSize.errMin',
- {
- defaultMessage: 'History window size must be greater than 0.',
- }
- ),
- };
- }
- },
- },
- ],
- },
+ newTermsFields: {},
+ historyWindowSize: {},
[ALERT_SUPPRESSION_FIELDS_FIELD_NAME]: {
validations: [
{
diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/use_persistent_new_terms_state.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/use_persistent_new_terms_state.tsx
new file mode 100644
index 0000000000000..61bfa45ba8a72
--- /dev/null
+++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/use_persistent_new_terms_state.tsx
@@ -0,0 +1,73 @@
+/*
+ * 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 { useEffect, useRef } from 'react';
+import usePrevious from 'react-use/lib/usePrevious';
+import { isNewTermsRule } from '../../../../../common/detection_engine/utils';
+import type { FormHook } from '../../../../shared_imports';
+import { useFormData } from '../../../../shared_imports';
+import { type DefineStepRule } from '../../../../detections/pages/detection_engine/rules/types';
+import {
+ type NewTermsFields,
+ type HistoryWindowStart,
+} from '../../../../../common/api/detection_engine';
+
+interface UsePersistentNewTermsStateParams {
+ form: FormHook;
+ ruleTypePath: string;
+ newTermsFieldsPath: string;
+ historyWindowStartPath: string;
+}
+
+interface LastNewTermsState {
+ newTermsFields: NewTermsFields;
+ historyWindowStart: HistoryWindowStart;
+}
+
+export function usePersistentNewTermsState({
+ form,
+ ruleTypePath,
+ newTermsFieldsPath,
+ historyWindowStartPath,
+}: UsePersistentNewTermsStateParams): void {
+ const lastNewTermsState = useRef();
+ const [formData] = useFormData({ form, watch: [newTermsFieldsPath, historyWindowStartPath] });
+
+ const {
+ [ruleTypePath]: ruleType,
+ [newTermsFieldsPath]: newTermsFields,
+ [historyWindowStartPath]: historyWindowStart,
+ } = formData;
+ const previousRuleType = usePrevious(ruleType);
+
+ useEffect(() => {
+ if (
+ isNewTermsRule(ruleType) &&
+ !isNewTermsRule(previousRuleType) &&
+ lastNewTermsState.current
+ ) {
+ form.updateFieldValues({
+ [newTermsFieldsPath]: lastNewTermsState.current.newTermsFields,
+ [historyWindowStartPath]: lastNewTermsState.current.historyWindowStart,
+ });
+
+ return;
+ }
+
+ if (isNewTermsRule(ruleType)) {
+ lastNewTermsState.current = { newTermsFields, historyWindowStart };
+ }
+ }, [
+ form,
+ ruleType,
+ previousRuleType,
+ newTermsFieldsPath,
+ historyWindowStartPath,
+ newTermsFields,
+ historyWindowStart,
+ ]);
+}
diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_schedule_rule/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_schedule_rule/index.tsx
index 2197b069de404..7c309ed32a68b 100644
--- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_schedule_rule/index.tsx
+++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_schedule_rule/index.tsx
@@ -13,11 +13,11 @@ import type {
ScheduleStepRule,
} from '../../../../detections/pages/detection_engine/rules/types';
import { StepRuleDescription } from '../description_step';
-import { ScheduleItem } from '../../../rule_creation/components/schedule_item_form';
import { Form, UseField } from '../../../../shared_imports';
import type { FormHook } from '../../../../shared_imports';
import { StepContentWrapper } from '../../../rule_creation/components/step_content_wrapper';
import { schema } from './schema';
+import { ScheduleItemField } from '../../../rule_creation/components/schedule_item_field';
const StyledForm = styled(Form)`
max-width: 235px !important;
@@ -43,7 +43,7 @@ const StepScheduleRuleComponent: FC = ({
= ({
/>
{
const timeObj: { unit: Unit; value: number } = {
@@ -530,7 +531,7 @@ export const formatDefineStepData = (defineStepData: DefineStepRule): DefineStep
query: ruleFields.queryBar?.query?.query as string,
required_fields: requiredFields,
new_terms_fields: ruleFields.newTermsFields,
- history_window_start: `now-${ruleFields.historyWindowSize}`,
+ history_window_start: convertDurationToDateMath(ruleFields.historyWindowSize),
...alertSuppressionFields,
}
: isEsqlFields(ruleFields) && !('index' in ruleFields)
diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_definition_section.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_definition_section.tsx
index 177ff4e18d426..de4fce3da3686 100644
--- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_definition_section.tsx
+++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_definition_section.tsx
@@ -41,7 +41,6 @@ import { useGetSavedQuery } from '../../../../detections/pages/detection_engine/
import * as threatMatchI18n from '../../../../common/components/threat_match/translations';
import * as timelinesI18n from '../../../../timelines/components/timeline/translations';
import type { Duration } from '../../../../detections/pages/detection_engine/rules/types';
-import { convertHistoryStartToSize } from '../../../../detections/pages/detection_engine/rules/helpers';
import { MlJobsDescription } from '../../../rule_creation/components/ml_jobs_description/ml_jobs_description';
import { MlJobLink } from '../../../rule_creation/components/ml_job_link/ml_job_link';
import { useSecurityJobs } from '../../../../common/components/ml_popover/hooks/use_security_jobs';
@@ -58,6 +57,8 @@ import {
} from './rule_definition_section.styles';
import { getQueryLanguageLabel } from './helpers';
import { useDefaultIndexPattern } from '../../hooks/use_default_index_pattern';
+import { convertDateMathToDuration } from '../../../../common/utils/date_math';
+import { DEFAULT_HISTORY_WINDOW_SIZE } from '../../../../common/constants';
import {
EQL_OPTIONS_EVENT_CATEGORY_FIELD_LABEL,
EQL_OPTIONS_EVENT_TIEBREAKER_FIELD_LABEL,
@@ -435,7 +436,9 @@ interface HistoryWindowSizeProps {
}
export const HistoryWindowSize = ({ historyWindowStart }: HistoryWindowSizeProps) => {
- const size = historyWindowStart ? convertHistoryStartToSize(historyWindowStart) : '7d';
+ const size = historyWindowStart
+ ? convertDateMathToDuration(historyWindowStart)
+ : DEFAULT_HISTORY_WINDOW_SIZE;
return (
diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/history_window_start/history_window_start_edit_adapter.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/history_window_start/history_window_start_edit_adapter.tsx
new file mode 100644
index 0000000000000..084a81e3b9599
--- /dev/null
+++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/history_window_start/history_window_start_edit_adapter.tsx
@@ -0,0 +1,13 @@
+/*
+ * 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 { HistoryWindowStartEdit } from '../../../../../../../rule_creation/components/history_window_start_edit';
+
+export function HistoryWindowStartEditAdapter(): JSX.Element {
+ return ;
+}
diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/history_window_start/history_window_start_edit_form.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/history_window_start/history_window_start_edit_form.tsx
new file mode 100644
index 0000000000000..87ac2fee64e7b
--- /dev/null
+++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/history_window_start/history_window_start_edit_form.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 { type FormData } from '../../../../../../../../shared_imports';
+import { HistoryWindowStartEditAdapter } from './history_window_start_edit_adapter';
+import type { HistoryWindowStart } from '../../../../../../../../../common/api/detection_engine';
+import {
+ convertDurationToDateMath,
+ convertDateMathToDuration,
+} from '../../../../../../../../common/utils/date_math';
+import { DEFAULT_HISTORY_WINDOW_SIZE } from '../../../../../../../../common/constants';
+import { RuleFieldEditFormWrapper } from '../../../field_final_side';
+
+export function HistoryWindowStartEditForm(): JSX.Element {
+ return (
+
+ );
+}
+
+interface HistoryWindowFormData {
+ historyWindowSize: HistoryWindowStart;
+}
+
+function deserializer(defaultValue: FormData): HistoryWindowFormData {
+ return {
+ historyWindowSize: defaultValue.history_window_start
+ ? convertDateMathToDuration(defaultValue.history_window_start)
+ : DEFAULT_HISTORY_WINDOW_SIZE,
+ };
+}
+
+function serializer(formData: FormData): { history_window_start: HistoryWindowStart } {
+ return {
+ history_window_start: convertDurationToDateMath(formData.historyWindowSize),
+ };
+}
+
+const schema = {};
diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/new_terms_fields/new_terms_fields_edit_adapter.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/new_terms_fields/new_terms_fields_edit_adapter.tsx
new file mode 100644
index 0000000000000..476bf9869bd96
--- /dev/null
+++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/new_terms_fields/new_terms_fields_edit_adapter.tsx
@@ -0,0 +1,26 @@
+/*
+ * 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 { NewTermsFieldsEdit } from '../../../../../../../rule_creation/components/new_terms_fields_edit';
+import { useDiffableRuleDataView } from '../hooks/use_diffable_rule_data_view';
+import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine';
+import { useTermsAggregationFields } from '../../../../../../../../common/hooks/use_terms_aggregation_fields';
+
+interface NewTermsFieldsEditAdapterProps {
+ finalDiffableRule: DiffableRule;
+}
+
+export function NewTermsFieldsEditAdapter({
+ finalDiffableRule,
+}: NewTermsFieldsEditAdapterProps): JSX.Element {
+ const { dataView } = useDiffableRuleDataView(finalDiffableRule);
+ const termsAggregationFields = useTermsAggregationFields(dataView?.fields ?? []);
+ const fieldNames = termsAggregationFields.map((field) => field.name);
+
+ return ;
+}
diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/new_terms_fields/new_terms_fields_edit_form.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/new_terms_fields/new_terms_fields_edit_form.tsx
new file mode 100644
index 0000000000000..9b8d709b27f06
--- /dev/null
+++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/new_terms_fields/new_terms_fields_edit_form.tsx
@@ -0,0 +1,18 @@
+/*
+ * 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 { RuleFieldEditFormWrapper } from '../../../field_final_side';
+import { NewTermsFieldsEditAdapter } from './new_terms_fields_edit_adapter';
+
+export function NewTermsFieldsEditForm(): JSX.Element {
+ return (
+
+ );
+}
+
+const schema = {};
diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/rule_schedule.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/rule_schedule.tsx
index 12e7bbea9a20a..3acd7c3050fbb 100644
--- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/rule_schedule.tsx
+++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/rule_schedule.tsx
@@ -10,8 +10,8 @@ import { parseDuration } from '@kbn/alerting-plugin/common';
import { type FormSchema, type FormData, UseField } from '../../../../../../../shared_imports';
import { schema } from '../../../../../../rule_creation_ui/components/step_schedule_rule/schema';
import type { RuleSchedule } from '../../../../../../../../common/api/detection_engine';
-import { ScheduleItem } from '../../../../../../rule_creation/components/schedule_item_form';
import { secondsToDurationString } from '../../../../../../../detections/pages/detection_engine/rules/helpers';
+import { ScheduleItemField } from '../../../../../../rule_creation/components/schedule_item_field';
export const ruleScheduleSchema = {
interval: schema.interval,
@@ -28,8 +28,8 @@ const componentProps = {
export function RuleScheduleEdit(): JSX.Element {
return (
<>
-
-
+
+
>
);
}
diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/new_terms_rule_field_edit.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/new_terms_rule_field_edit.tsx
index e2860d431affa..f47607abe3844 100644
--- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/new_terms_rule_field_edit.tsx
+++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/new_terms_rule_field_edit.tsx
@@ -7,9 +7,12 @@
import React from 'react';
import type { UpgradeableNewTermsFields } from '../../../../model/prebuilt_rule_upgrade/fields';
-import { KqlQueryEditForm } from './fields/kql_query';
-import { DataSourceEditForm } from './fields/data_source';
import { AlertSuppressionEditForm } from './fields/alert_suppression';
+import { DataSourceEditForm } from './fields/data_source';
+import { HistoryWindowStartEditForm } from './fields/history_window_start/history_window_start_edit_form';
+import { KqlQueryEditForm } from './fields/kql_query';
+import { NewTermsFieldsEditForm } from './fields/new_terms_fields/new_terms_fields_edit_form';
+import { assertUnreachable } from '../../../../../../../common/utility_types';
interface NewTermsRuleFieldEditProps {
fieldName: UpgradeableNewTermsFields;
@@ -17,13 +20,17 @@ interface NewTermsRuleFieldEditProps {
export function NewTermsRuleFieldEdit({ fieldName }: NewTermsRuleFieldEditProps) {
switch (fieldName) {
- case 'kql_query':
- return ;
- case 'data_source':
- return ;
case 'alert_suppression':
return ;
+ case 'data_source':
+ return ;
+ case 'history_window_start':
+ return ;
+ case 'kql_query':
+ return ;
+ case 'new_terms_fields':
+ return ;
default:
- return null; // Will be replaced with `assertUnreachable(fieldName)` once all fields are implemented
+ return assertUnreachable(fieldName);
}
}
diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/schedule_form.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/schedule_form.tsx
index 88e1411a5e0bc..518c18a59a413 100644
--- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/schedule_form.tsx
+++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/schedule_form.tsx
@@ -9,11 +9,11 @@ import { EuiCallOut } from '@elastic/eui';
import React, { useCallback } from 'react';
import type { BulkActionEditPayload } from '../../../../../../../common/api/detection_engine/rule_management';
import { BulkActionEditTypeEnum } from '../../../../../../../common/api/detection_engine/rule_management';
-import { ScheduleItem } from '../../../../../rule_creation/components/schedule_item_form';
import type { FormSchema } from '../../../../../../shared_imports';
import { UseField, useForm } from '../../../../../../shared_imports';
import { bulkSetSchedule as i18n } from '../translations';
import { BulkEditFormWrapper } from './bulk_edit_form_wrapper';
+import { ScheduleItemField } from '../../../../../rule_creation/components/schedule_item_field';
export interface ScheduleFormData {
interval: string;
@@ -79,7 +79,7 @@ export const ScheduleForm = ({ rulesCount, onClose, onConfirm }: ScheduleFormCom
>
({
newTermsFields: ('new_terms_fields' in rule && rule.new_terms_fields) || [],
historyWindowSize:
'history_window_start' in rule && rule.history_window_start
- ? convertHistoryStartToSize(rule.history_window_start)
- : '7d',
+ ? convertDateMathToDuration(rule.history_window_start)
+ : DEFAULT_HISTORY_WINDOW_SIZE,
shouldLoadQueryDynamically: Boolean(rule.type === 'saved_query' && rule.saved_id),
[ALERT_SUPPRESSION_FIELDS_FIELD_NAME]:
('alert_suppression' in rule &&
@@ -189,14 +191,6 @@ export const getDefineStepsData = (rule: RuleResponse): DefineStepRule => ({
),
});
-export const convertHistoryStartToSize = (relativeTime: string) => {
- if (relativeTime.startsWith('now-')) {
- return relativeTime.substring(4);
- } else {
- return relativeTime;
- }
-};
-
export const getScheduleStepsData = (rule: RuleResponse): ScheduleStepRule => {
const { interval, from } = rule;
const fromHumanizedValue = getHumanizedDuration(from, interval);
diff --git a/x-pack/test/security_solution_cypress/cypress/screens/create_new_rule.ts b/x-pack/test/security_solution_cypress/cypress/screens/create_new_rule.ts
index 903b463d6f585..483cbf06b6256 100644
--- a/x-pack/test/security_solution_cypress/cypress/screens/create_new_rule.ts
+++ b/x-pack/test/security_solution_cypress/cypress/screens/create_new_rule.ts
@@ -275,10 +275,10 @@ export const ESQL_QUERY_BAR = '[data-test-subj="ruleEsqlQueryBar"]';
export const NEW_TERMS_INPUT_AREA = '[data-test-subj="newTermsInput"]';
export const NEW_TERMS_HISTORY_SIZE =
- '[data-test-subj="detectionEngineStepDefineRuleHistoryWindowSize"] [data-test-subj="interval"]';
+ '[data-test-subj="historyWindowSize"] [data-test-subj="interval"]';
export const NEW_TERMS_HISTORY_TIME_TYPE =
- '[data-test-subj="detectionEngineStepDefineRuleHistoryWindowSize"] [data-test-subj="timeType"]';
+ '[data-test-subj="historyWindowSize"] [data-test-subj="timeType"]';
export const LOAD_QUERY_DYNAMICALLY_CHECKBOX =
'[data-test-subj="detectionEngineStepDefineRuleShouldLoadQueryDynamically"] input';