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 aad31d0c92b67..0274f9260b917 100644 --- a/x-pack/platform/plugins/private/translations/translations/fr-FR.json +++ b/x-pack/platform/plugins/private/translations/translations/fr-FR.json @@ -170,14 +170,6 @@ "avcBanner.body": "Elastic Security passe avec brio le test de protection contre les malwares réalisé par AV-Comparatives", "avcBanner.readTheBlog.link": "Lire le blog", "avcBanner.title": "Protection à 100 % sans aucun faux positif.", - "bfetch.advancedSettings.disableBfetchCompressionDeprecation": "Ce paramètre est déclassé et sera supprimé dans la version 9.0 de Kibana.", - "bfetch.advancedSettings.disableBfetchDeprecation": "Ce paramètre est déclassé et sera supprimé dans la version 9.0 de Kibana.", - "bfetch.disableBfetch": "Désactiver la mise en lots de requêtes", - "bfetch.disableBfetchCompression": "Désactiver la compression par lots", - "bfetch.disableBfetchCompressionDesc": "Vous pouvez désactiver la compression par lots. Cela permet de déboguer des requêtes individuelles, mais augmente la taille des réponses.", - "bfetch.disableBfetchDesc": "Désactive la mise en lot des requêtes. Cette option augmente le nombre de requêtes HTTP depuis Kibana, mais permet de les déboguer individuellement.", - "bfetchError.networkError": "Vérifiez votre connexion réseau et réessayez.", - "bfetchError.networkErrorWithStatus": "Vérifiez votre connexion réseau et réessayez. Code {code}", "cases.components.status.closed": "Fermé", "cases.components.status.inProgress": "En cours", "cases.components.status.open": "Ouvrir", 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 707b2b610fd64..19513093d5517 100644 --- a/x-pack/platform/plugins/private/translations/translations/ja-JP.json +++ b/x-pack/platform/plugins/private/translations/translations/ja-JP.json @@ -170,14 +170,6 @@ "avcBanner.body": "AV-Comparativesのマルウェア保護テストで高い評価を受けたElastic Security", "avcBanner.readTheBlog.link": "ブログを読む", "avcBanner.title": "誤検知がゼロの100%保護。", - "bfetch.advancedSettings.disableBfetchCompressionDeprecation": "この設定はサポートが終了し、Kibana 9.0では削除されます。", - "bfetch.advancedSettings.disableBfetchDeprecation": "この設定はサポートが終了し、Kibana 9.0では削除されます。", - "bfetch.disableBfetch": "リクエストバッチを無効にする", - "bfetch.disableBfetchCompression": "バッチ圧縮を無効にする", - "bfetch.disableBfetchCompressionDesc": "バッチ圧縮を無効にします。個別の要求をデバッグできますが、応答サイズが大きくなります。", - "bfetch.disableBfetchDesc": "リクエストバッチを無効にします。これにより、KibanaからのHTTPリクエスト数は減りますが、個別にリクエストをデバッグできます。", - "bfetchError.networkError": "ネットワーク接続を確認して再試行してください。", - "bfetchError.networkErrorWithStatus": "ネットワーク接続を確認して再試行してください。コード{code}", "cases.components.status.closed": "終了", "cases.components.status.inProgress": "進行中", "cases.components.status.open": "オープン", 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 4a3ddd8ad1856..41bb4953fc45b 100644 --- a/x-pack/platform/plugins/private/translations/translations/zh-CN.json +++ b/x-pack/platform/plugins/private/translations/translations/zh-CN.json @@ -196,14 +196,6 @@ "avcBanner.body": "在 AV-Comparatives 进行的恶意软件防护测试中,Elastic Security 表现突出", "avcBanner.readTheBlog.link": "阅读博客", "avcBanner.title": "提供全面保护,误报率为零。", - "bfetch.advancedSettings.disableBfetchCompressionDeprecation": "此设置已过时,将在 Kibana 9.0 中移除。", - "bfetch.advancedSettings.disableBfetchDeprecation": "此设置已过时,将在 Kibana 9.0 中移除。", - "bfetch.disableBfetch": "禁用请求批处理", - "bfetch.disableBfetchCompression": "禁用批量压缩", - "bfetch.disableBfetchCompressionDesc": "禁用批量压缩。这允许您对单个请求进行故障排查,但会增加响应大小。", - "bfetch.disableBfetchDesc": "禁用请求批处理。这会增加来自 Kibana 的 HTTP 请求数,但允许对单个请求进行故障排查。", - "bfetchError.networkError": "检查您的网络连接,然后重试。", - "bfetchError.networkErrorWithStatus": "检查您的网络连接,然后重试。代码 {code}", "cases.components.status.closed": "已关闭", "cases.components.status.inProgress": "进行中", "cases.components.status.open": "打开", diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/ml_job_select/ml_job_select.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/ml_job_select/ml_job_select.test.tsx index ddbb6c8b70708..1580cc961c7c5 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/ml_job_select/ml_job_select.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/ml_job_select/ml_job_select.test.tsx @@ -21,7 +21,7 @@ describe('MlJobSelect', () => { it('renders correctly', () => { const Component = () => { - const field = useFormFieldMock(); + const field = useFormFieldMock({ value: [] }); return ; }; diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/ml_job_select/ml_job_select.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/ml_job_select/ml_job_select.tsx index 160178a5b782d..8e715b6fe0e7e 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/ml_job_select/ml_job_select.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/ml_job_select/ml_job_select.tsx @@ -57,6 +57,21 @@ export const MlJobSelect: React.FC = ({ label: `${job.customSettings?.security_app_display_name} ${job.id}`, })); + // If rule's ML job is no longer available or has not yet become available, we still want it to appear in the dropdown. + selectedJobIds.forEach((selectedJobId) => { + const isSelectedJobAvailable = jobOptions.some((job) => job.value.id === selectedJobId); + if (!isSelectedJobAvailable) { + jobOptions.push({ + value: { + id: selectedJobId, + description: '', + name: selectedJobId, + }, + label: selectedJobId, + }); + } + }); + const selectedJobOptions = jobOptions .filter((option) => selectedJobIds.includes(option.value.id)) // 'label' defines what is rendered inside the selected ComboBoxPill diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/ml_jobs_description/ml_job_item.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/ml_jobs_description/ml_job_item.tsx index b706ed4135f49..e32b8cb98270c 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/ml_jobs_description/ml_job_item.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/ml_jobs_description/ml_job_item.tsx @@ -9,6 +9,7 @@ import type { FC, ReactNode } from 'react'; import React, { memo } from 'react'; import styled from 'styled-components'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { euiThemeVars } from '@kbn/ui-theme'; import type { MlSummaryJob } from '@kbn/ml-plugin/public'; import * as i18n from './translations'; @@ -21,6 +22,7 @@ import { MlJobStatusBadge } from '../ml_job_status_badge'; const Wrapper = styled.div` overflow: hidden; + margin-bottom: ${euiThemeVars.euiSizeS}; `; const MlJobItemComponent: FC<{ 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 de4fce3da3686..047e9e5bf1977 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 @@ -14,6 +14,8 @@ import { EuiFlexItem, EuiFlexGroup, EuiLoadingSpinner, + EuiButtonIcon, + EuiPopover, } from '@elastic/eui'; import type { EuiDescriptionListProps } from '@elastic/eui'; import type { @@ -24,6 +26,7 @@ import type { Filter } from '@kbn/es-query'; import type { SavedQuery } from '@kbn/data-plugin/public'; import { mapAndFlattenFilters } from '@kbn/data-plugin/public'; import { FilterItems } from '@kbn/unified-search-plugin/public'; +import useToggle from 'react-use/lib/useToggle'; import { isDataView } from '../../../../common/components/query_bar'; import type { AlertSuppressionMissingFieldsStrategy, @@ -237,7 +240,7 @@ interface MachineLearningJobListProps { } export const MachineLearningJobList = ({ jobIds, isInteractive }: MachineLearningJobListProps) => { - const { jobs } = useSecurityJobs(); + const { jobs: availableJobs } = useSecurityJobs(); if (!jobIds) { return null; @@ -245,11 +248,20 @@ export const MachineLearningJobList = ({ jobIds, isInteractive }: MachineLearnin const jobIdsArray = Array.isArray(jobIds) ? jobIds : [jobIds]; + const unavailableJobIds = jobIdsArray.filter( + (jobId) => !availableJobs.some((job) => job.id === jobId) + ); + if (isInteractive) { - return ; + return ( + <> + + + + ); } - const relevantJobs = jobs.filter((job) => jobIdsArray.includes(job.id)); + const relevantJobs = availableJobs.filter((job) => jobIdsArray.includes(job.id)); return ( <> @@ -260,10 +272,48 @@ export const MachineLearningJobList = ({ jobIds, isInteractive }: MachineLearnin jobName={job.customSettings?.security_app_display_name} /> ))} + ); }; +interface UnavailableMlJobsProps { + unavailableJobIds: string[]; +} + +const UnavailableMlJobs = ({ unavailableJobIds }: UnavailableMlJobsProps) => { + return unavailableJobIds.map((jobId) => ( +
+ +
+ )); +}; + +interface UnavailableMlJobLinkProps { + jobId: string; +} + +const UnavailableMlJobLink: React.FC = ({ jobId }) => { + const [isPopoverOpen, togglePopover] = useToggle(false); + + const button = ( + + ); + + return ( + + {jobId} + + {i18n.MACHINE_LEARNING_JOB_NOT_AVAILABLE} + + + ); +}; + const getRuleTypeDescription = (ruleType: Type) => { switch (ruleType) { case 'machine_learning': diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/translations.ts b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/translations.ts index c5183626a63a7..7ea98fbb6a067 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/translations.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/translations.ts @@ -273,6 +273,21 @@ export const MACHINE_LEARNING_JOB_ID_FIELD_LABEL = i18n.translate( } ); +export const MACHINE_LEARNING_JOB_NOT_AVAILABLE = i18n.translate( + 'xpack.securitySolution.detectionEngine.ruleDetails.machineLearning.mlJobNotAvailable', + { + defaultMessage: + 'This job is currently unavailable. Please ensure that all related ML integrations are installed and configured.', + } +); + +export const OPEN_HELP_POPOVER_ARIA_LABEL = i18n.translate( + 'xpack.securitySolution.detectionEngine.ruleDetails.machineLearning.mlJobNotAvailable.openHelpPopoverAriaLabel', + { + defaultMessage: 'Open help popover', + } +); + export const ANOMALY_THRESHOLD_FIELD_LABEL = i18n.translate( 'xpack.securitySolution.detectionEngine.ruleDetails.anomalyThresholdFieldLabel', {