diff --git a/x-pack/plugins/security_solution/public/common/components/links_to_docs/doc_link.tsx b/x-pack/plugins/security_solution/public/common/components/links_to_docs/doc_link.tsx new file mode 100644 index 0000000000000..f02e4390db02f --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/links_to_docs/doc_link.tsx @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { FC, memo } from 'react'; +import { useKibana } from '../../lib/kibana'; +import { ExternalLink } from './external_link'; +import { COMMON_ARIA_LABEL_ENDING } from './links_translations'; + +interface DocLinkProps { + guidePath?: string; + docPath: string; + linkText: string; +} + +const DocLink: FC = ({ guidePath = 'security', docPath, linkText }) => { + const { services } = useKibana(); + const { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } = services.docLinks; + + const url = `${ELASTIC_WEBSITE_URL}guide/en/${guidePath}/${DOC_LINK_VERSION}/${docPath}`; + const ariaLabel = `${linkText} - ${COMMON_ARIA_LABEL_ENDING}`; + + return ; +}; + +/** + * A simple text link to documentation. + */ +const DocLinkWrapper = memo(DocLink); + +export { DocLinkWrapper as DocLink }; diff --git a/x-pack/plugins/security_solution/public/common/components/links_to_docs/external_link.tsx b/x-pack/plugins/security_solution/public/common/components/links_to_docs/external_link.tsx new file mode 100644 index 0000000000000..f83c6f8fe31e4 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/links_to_docs/external_link.tsx @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { FC } from 'react'; +import { EuiLink } from '@elastic/eui'; + +interface ExternalLinkProps { + url: string; + text: string; + ariaLabel?: string; +} + +/** + * A simplistic text link for opening external urls in a new browser tab. + */ +export const ExternalLink: FC = ({ url, text, ariaLabel }) => { + return ( + + {text} + + ); +}; diff --git a/x-pack/plugins/security_solution/public/common/components/links_to_docs/index.tsx b/x-pack/plugins/security_solution/public/common/components/links_to_docs/index.tsx new file mode 100644 index 0000000000000..f681783cb78fa --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/links_to_docs/index.tsx @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export * from './links_components'; diff --git a/x-pack/plugins/security_solution/public/common/components/links_to_docs/links_components.tsx b/x-pack/plugins/security_solution/public/common/components/links_to_docs/links_components.tsx new file mode 100644 index 0000000000000..362f6b25c1103 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/links_to_docs/links_components.tsx @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { DocLink } from './doc_link'; +import * as i18n from './links_translations'; + +export const SecuritySolutionRequirementsLink = () => ( + +); + +export const DetectionsRequirementsLink = () => ( + +); diff --git a/x-pack/plugins/security_solution/public/common/components/links_to_docs/links_translations.ts b/x-pack/plugins/security_solution/public/common/components/links_to_docs/links_translations.ts new file mode 100644 index 0000000000000..5ab0032b9b9a7 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/links_to_docs/links_translations.ts @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; + +/** + * If a link's text is "Docs", its aria-label will be set to + * "Docs - ${COMMON_ARIA_LABEL_ENDING}". + */ +export const COMMON_ARIA_LABEL_ENDING = i18n.translate( + 'xpack.securitySolution.documentationLinks.ariaLabelEnding', + { + defaultMessage: 'click to open documentation in a new tab', + } +); + +export const SOLUTION_REQUIREMENTS_LINK_PATH = 'sec-requirements.html'; +export const SOLUTION_REQUIREMENTS_LINK_TEXT = i18n.translate( + 'xpack.securitySolution.documentationLinks.solutionRequirements.text', + { + defaultMessage: 'Elastic Security system requirements', + } +); + +export const DETECTIONS_REQUIREMENTS_LINK_PATH = 'detections-permissions-section.html'; +export const DETECTIONS_REQUIREMENTS_LINK_TEXT = i18n.translate( + 'xpack.securitySolution.documentationLinks.detectionsRequirements.text', + { + defaultMessage: 'Detections prerequisites and requirements', + } +); diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.tsx index ccdc2b5022070..614b39d280ae4 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.tsx @@ -98,7 +98,7 @@ const AlertContextMenuComponent: React.FC = ({ setPopover(false); }, []); const [exceptionModalType, setOpenAddExceptionModal] = useState(null); - const [{ canUserCRUD, hasIndexWrite }] = useUserData(); + const [{ canUserCRUD, hasIndexWrite, hasIndexUpdateDelete }] = useUserData(); const isEndpointAlert = useMemo((): boolean => { if (ecsRowData == null) { @@ -218,7 +218,7 @@ const AlertContextMenuComponent: React.FC = ({ data-test-subj="open-alert-status" id={FILTER_OPEN} onClick={openAlertActionOnClick} - disabled={!canUserCRUD || !hasIndexWrite} + disabled={!canUserCRUD || !hasIndexUpdateDelete} > {i18n.ACTION_OPEN_ALERT} @@ -251,7 +251,7 @@ const AlertContextMenuComponent: React.FC = ({ data-test-subj="close-alert-status" id={FILTER_CLOSED} onClick={closeAlertActionClick} - disabled={!canUserCRUD || !hasIndexWrite} + disabled={!canUserCRUD || !hasIndexUpdateDelete} > {i18n.ACTION_CLOSE_ALERT} @@ -284,7 +284,7 @@ const AlertContextMenuComponent: React.FC = ({ data-test-subj="in-progress-alert-status" id={FILTER_IN_PROGRESS} onClick={inProgressAlertActionClick} - disabled={!canUserCRUD || !hasIndexWrite} + disabled={!canUserCRUD || !hasIndexUpdateDelete} > {i18n.ACTION_IN_PROGRESS_ALERT} diff --git a/x-pack/plugins/security_solution/public/detections/components/callouts/read_only_alerts_callout/index.tsx b/x-pack/plugins/security_solution/public/detections/components/callouts/read_only_alerts_callout/index.tsx index 8ba04e5fdd7de..a2bc18c1aa3f2 100644 --- a/x-pack/plugins/security_solution/public/detections/components/callouts/read_only_alerts_callout/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/callouts/read_only_alerts_callout/index.tsx @@ -14,16 +14,16 @@ const readOnlyAccessToAlertsMessage: CallOutMessage = { type: 'primary', id: 'read-only-access-to-alerts', title: i18n.READ_ONLY_ALERTS_CALLOUT_TITLE, - description:

{i18n.READ_ONLY_ALERTS_CALLOUT_MSG}

, + description: i18n.readOnlyAlertsCallOutBody(), }; const ReadOnlyAlertsCallOutComponent = () => { - const [{ hasIndexWrite }] = useUserData(); + const [{ hasIndexUpdateDelete }] = useUserData(); return ( ); diff --git a/x-pack/plugins/security_solution/public/detections/components/callouts/read_only_alerts_callout/translations.ts b/x-pack/plugins/security_solution/public/detections/components/callouts/read_only_alerts_callout/translations.ts deleted file mode 100644 index aabd9e44dfff8..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/components/callouts/read_only_alerts_callout/translations.ts +++ /dev/null @@ -1,22 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { i18n } from '@kbn/i18n'; - -export const READ_ONLY_ALERTS_CALLOUT_TITLE = i18n.translate( - 'xpack.securitySolution.detectionEngine.readOnlyAlertsCallOutTitle', - { - defaultMessage: 'You cannot change alert states', - } -); - -export const READ_ONLY_ALERTS_CALLOUT_MSG = i18n.translate( - 'xpack.securitySolution.detectionEngine.readOnlyAlertsCallOutMsg', - { - defaultMessage: - 'You only have permissions to view alerts. If you need to update alert states (open or close alerts), contact your Kibana administrator.', - } -); diff --git a/x-pack/plugins/security_solution/public/detections/components/callouts/read_only_alerts_callout/translations.tsx b/x-pack/plugins/security_solution/public/detections/components/callouts/read_only_alerts_callout/translations.tsx new file mode 100644 index 0000000000000..451748ff7be68 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/components/callouts/read_only_alerts_callout/translations.tsx @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { + SecuritySolutionRequirementsLink, + DetectionsRequirementsLink, +} from '../../../../common/components/links_to_docs'; + +export const READ_ONLY_ALERTS_CALLOUT_TITLE = i18n.translate( + 'xpack.securitySolution.detectionEngine.readOnlyAlertsCallOut.messageTitle', + { + defaultMessage: 'You cannot change alert states', + } +); + +export const readOnlyAlertsCallOutBody = () => ( + + +

+ ), + docs: ( +
    +
  • + +
  • +
  • + +
  • +
+ ), + }} + /> +); diff --git a/x-pack/plugins/security_solution/public/detections/components/callouts/read_only_rules_callout/index.tsx b/x-pack/plugins/security_solution/public/detections/components/callouts/read_only_rules_callout/index.tsx index e25812acbea92..d593b5f696970 100644 --- a/x-pack/plugins/security_solution/public/detections/components/callouts/read_only_rules_callout/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/callouts/read_only_rules_callout/index.tsx @@ -14,7 +14,7 @@ const readOnlyAccessToRulesMessage: CallOutMessage = { type: 'primary', id: 'read-only-access-to-rules', title: i18n.READ_ONLY_RULES_CALLOUT_TITLE, - description:

{i18n.READ_ONLY_RULES_CALLOUT_MSG}

, + description: i18n.readOnlyRulesCallOutBody(), }; const ReadOnlyRulesCallOutComponent = () => { diff --git a/x-pack/plugins/security_solution/public/detections/components/callouts/read_only_rules_callout/translations.ts b/x-pack/plugins/security_solution/public/detections/components/callouts/read_only_rules_callout/translations.ts deleted file mode 100644 index a0c971df37a2e..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/components/callouts/read_only_rules_callout/translations.ts +++ /dev/null @@ -1,22 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { i18n } from '@kbn/i18n'; - -export const READ_ONLY_RULES_CALLOUT_TITLE = i18n.translate( - 'xpack.securitySolution.detectionEngine.readOnlyRulesCallOutTitle', - { - defaultMessage: 'Rule permissions required', - } -); - -export const READ_ONLY_RULES_CALLOUT_MSG = i18n.translate( - 'xpack.securitySolution.detectionEngine.readOnlyRulesCallOutMsg', - { - defaultMessage: - 'You are currently missing the required permissions to create/edit detection engine rule. Please contact your administrator for further assistance.', - } -); diff --git a/x-pack/plugins/security_solution/public/detections/components/callouts/read_only_rules_callout/translations.tsx b/x-pack/plugins/security_solution/public/detections/components/callouts/read_only_rules_callout/translations.tsx new file mode 100644 index 0000000000000..93ac43173935d --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/components/callouts/read_only_rules_callout/translations.tsx @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { + SecuritySolutionRequirementsLink, + DetectionsRequirementsLink, +} from '../../../../common/components/links_to_docs'; + +export const READ_ONLY_RULES_CALLOUT_TITLE = i18n.translate( + 'xpack.securitySolution.detectionEngine.readOnlyRulesCallOut.messageTitle', + { + defaultMessage: 'Rule permissions required', + } +); + +export const readOnlyRulesCallOutBody = () => ( + + +

+ ), + docs: ( +
    +
  • + +
  • +
  • + +
  • +
+ ), + }} + /> +); diff --git a/x-pack/plugins/security_solution/public/detections/components/user_info/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/user_info/index.test.tsx index e87303efbe526..ffbdd74f0485c 100644 --- a/x-pack/plugins/security_solution/public/detections/components/user_info/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/user_info/index.test.tsx @@ -38,6 +38,7 @@ describe('useUserInfo', () => { hasEncryptionKey: null, hasIndexManage: null, hasIndexWrite: null, + hasIndexUpdateDelete: null, isAuthenticated: null, isSignalIndexExists: null, loading: true, diff --git a/x-pack/plugins/security_solution/public/detections/components/user_info/index.tsx b/x-pack/plugins/security_solution/public/detections/components/user_info/index.tsx index 3b0976f459324..8592de826a200 100644 --- a/x-pack/plugins/security_solution/public/detections/components/user_info/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/user_info/index.tsx @@ -15,6 +15,7 @@ export interface State { canUserCRUD: boolean | null; hasIndexManage: boolean | null; hasIndexWrite: boolean | null; + hasIndexUpdateDelete: boolean | null; isSignalIndexExists: boolean | null; isAuthenticated: boolean | null; hasEncryptionKey: boolean | null; @@ -27,6 +28,7 @@ export const initialState: State = { canUserCRUD: null, hasIndexManage: null, hasIndexWrite: null, + hasIndexUpdateDelete: null, isSignalIndexExists: null, isAuthenticated: null, hasEncryptionKey: null, @@ -45,6 +47,10 @@ export type Action = type: 'updateHasIndexWrite'; hasIndexWrite: boolean | null; } + | { + type: 'updateHasIndexUpdateDelete'; + hasIndexUpdateDelete: boolean | null; + } | { type: 'updateIsSignalIndexExists'; isSignalIndexExists: boolean | null; @@ -90,6 +96,12 @@ export const userInfoReducer = (state: State, action: Action): State => { hasIndexWrite: action.hasIndexWrite, }; } + case 'updateHasIndexUpdateDelete': { + return { + ...state, + hasIndexUpdateDelete: action.hasIndexUpdateDelete, + }; + } case 'updateIsSignalIndexExists': { return { ...state, @@ -151,6 +163,7 @@ export const useUserInfo = (): State => { canUserCRUD, hasIndexManage, hasIndexWrite, + hasIndexUpdateDelete, isSignalIndexExists, isAuthenticated, hasEncryptionKey, @@ -166,6 +179,7 @@ export const useUserInfo = (): State => { hasEncryptionKey: isApiEncryptionKey, hasIndexManage: hasApiIndexManage, hasIndexWrite: hasApiIndexWrite, + hasIndexUpdateDelete: hasApiIndexUpdateDelete, } = usePrivilegeUser(); const { loading: indexNameLoading, @@ -197,6 +211,19 @@ export const useUserInfo = (): State => { } }, [dispatch, loading, hasIndexWrite, hasApiIndexWrite]); + useEffect(() => { + if ( + !loading && + hasIndexUpdateDelete !== hasApiIndexUpdateDelete && + hasApiIndexUpdateDelete != null + ) { + dispatch({ + type: 'updateHasIndexUpdateDelete', + hasIndexUpdateDelete: hasApiIndexUpdateDelete, + }); + } + }, [dispatch, loading, hasIndexUpdateDelete, hasApiIndexUpdateDelete]); + useEffect(() => { if ( !loading && @@ -272,6 +299,7 @@ export const useUserInfo = (): State => { canUserCRUD, hasIndexManage, hasIndexWrite, + hasIndexUpdateDelete, signalIndexName, signalIndexMappingOutdated, }; diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_privilege_user.test.tsx b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_privilege_user.test.tsx index c248223c6b81b..fca4714b922f7 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_privilege_user.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_privilege_user.test.tsx @@ -21,6 +21,7 @@ describe('usePrivilegeUser', () => { hasEncryptionKey: null, hasIndexManage: null, hasIndexWrite: null, + hasIndexUpdateDelete: null, isAuthenticated: null, loading: true, }); @@ -38,6 +39,7 @@ describe('usePrivilegeUser', () => { hasEncryptionKey: true, hasIndexManage: true, hasIndexWrite: true, + hasIndexUpdateDelete: true, isAuthenticated: true, loading: false, }); @@ -59,6 +61,7 @@ describe('usePrivilegeUser', () => { hasEncryptionKey: false, hasIndexManage: false, hasIndexWrite: false, + hasIndexUpdateDelete: false, isAuthenticated: false, loading: false, }); diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_privilege_user.tsx b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_privilege_user.tsx index dda9b50239cde..f8a61faee2914 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_privilege_user.tsx +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_privilege_user.tsx @@ -16,6 +16,7 @@ export interface ReturnPrivilegeUser { hasEncryptionKey: boolean | null; hasIndexManage: boolean | null; hasIndexWrite: boolean | null; + hasIndexUpdateDelete: boolean | null; } /** * Hook to get user privilege from @@ -23,16 +24,12 @@ export interface ReturnPrivilegeUser { */ export const usePrivilegeUser = (): ReturnPrivilegeUser => { const [loading, setLoading] = useState(true); - const [privilegeUser, setPrivilegeUser] = useState< - Pick< - ReturnPrivilegeUser, - 'isAuthenticated' | 'hasEncryptionKey' | 'hasIndexManage' | 'hasIndexWrite' - > - >({ + const [privilegeUser, setPrivilegeUser] = useState>({ isAuthenticated: null, hasEncryptionKey: null, hasIndexManage: null, hasIndexWrite: null, + hasIndexUpdateDelete: null, }); const [, dispatchToaster] = useStateToaster(); @@ -59,6 +56,7 @@ export const usePrivilegeUser = (): ReturnPrivilegeUser => { privilege.index[indexName].create_doc || privilege.index[indexName].index || privilege.index[indexName].write, + hasIndexUpdateDelete: privilege.index[indexName].write, }); } } @@ -69,6 +67,7 @@ export const usePrivilegeUser = (): ReturnPrivilegeUser => { hasEncryptionKey: false, hasIndexManage: false, hasIndexWrite: false, + hasIndexUpdateDelete: false, }); errorToToaster({ title: i18n.PRIVILEGE_FETCH_FAILURE, error, dispatchToaster }); } diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 116a81361699f..068515b652486 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -16826,8 +16826,7 @@ "xpack.securitySolution.detectionEngine.noApiIntegrationKeyCallOutMsg": "Kibanaを起動するごとに保存されたオブジェクトの新しい暗号化キーを作成します。永続キーがないと、Kibanaの再起動後にルールを削除または修正することができません。永続キーを設定するには、kibana.ymlファイルに32文字以上のテキスト値を付けてxpack.encryptedSavedObjects.encryptionKey設定を追加してください。", "xpack.securitySolution.detectionEngine.noApiIntegrationKeyCallOutTitle": "API統合キーが必要です", "xpack.securitySolution.detectionEngine.noIndexTitle": "検出エンジンを設定しましょう", - "xpack.securitySolution.detectionEngine.readOnlyAlertsCallOutMsg": "アラートを表示する権限のみが付与されています。アラート状態を更新(アラートを開く、アラートを閉じる)必要がある場合は、Kibana管理者に連絡してください。", - "xpack.securitySolution.detectionEngine.readOnlyAlertsCallOutTitle": "アラート状態を変更することはできません", + "xpack.securitySolution.detectionEngine.readOnlyAlertsCallOut.messageTitle": "アラート状態を変更することはできません", "xpack.securitySolution.detectionEngine.pageTitle": "検出エンジン", "xpack.securitySolution.detectionEngine.panelSubtitleShowing": "表示中", "xpack.securitySolution.detectionEngine.queryPreview.queryGraphCountLabel": "カウント", @@ -16842,8 +16841,7 @@ "xpack.securitySolution.detectionEngine.queryPreview.queryPreviewGraphTitle": "{hits} {hits, plural, =1 {ヒット} other {ヒット}}", "xpack.securitySolution.detectionEngine.queryPreview.queryPreviewHelpText": "クエリ結果をプレビューするデータのタイムフレームを選択します", "xpack.securitySolution.detectionEngine.queryPreview.queryPreviewLabel": "クイッククエリプレビュー", - "xpack.securitySolution.detectionEngine.readOnlyRulesCallOutMsg": "現在、検出エンジンルールを作成/編集するための必要な権限がありません。サポートについては、管理者にお問い合わせください。", - "xpack.securitySolution.detectionEngine.readOnlyRulesCallOutTitle": "ルールアクセス権が必要です", + "xpack.securitySolution.detectionEngine.readOnlyRulesCallOut.messageTitle": "ルールアクセス権が必要です", "xpack.securitySolution.detectionEngine.rule.editRule.errorMsgDescription": "{countError, plural, one {このタブ} other {これらのタブ}}に無効な入力があります: {tabHasError}", "xpack.securitySolution.detectionEngine.ruleDescription.mlJobStartedDescription": "開始", "xpack.securitySolution.detectionEngine.ruleDescription.mlJobStoppedDescription": "停止", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index f03b720c8a77f..e5b03ee1d5d41 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -16843,8 +16843,7 @@ "xpack.securitySolution.detectionEngine.noApiIntegrationKeyCallOutMsg": "每次启动 Kibana,都会为已保存对象生成新的加密密钥。没有持久性密钥,在 Kibana 重新启动后,将无法删除或修改规则。要设置持久性密钥,请将文本值为 32 个或更多任意字符的 xpack.encryptedSavedObjects.encryptionKey 设置添加到 kibana.yml 文件。", "xpack.securitySolution.detectionEngine.noApiIntegrationKeyCallOutTitle": "需要 API 集成密钥", "xpack.securitySolution.detectionEngine.noIndexTitle": "让我们来设置您的检测引擎", - "xpack.securitySolution.detectionEngine.readOnlyAlertsCallOutMsg": "您仅有权查看告警。如果您需要更新告警状态(打开或关闭告警),请联系您的 Kibana 管理员。", - "xpack.securitySolution.detectionEngine.readOnlyAlertsCallOutTitle": "您无法更改告警状态", + "xpack.securitySolution.detectionEngine.readOnlyAlertsCallOut.messageTitle": "您无法更改告警状态", "xpack.securitySolution.detectionEngine.pageTitle": "检测引擎", "xpack.securitySolution.detectionEngine.panelSubtitleShowing": "正在显示", "xpack.securitySolution.detectionEngine.queryPreview.queryGraphCountLabel": "计数", @@ -16859,8 +16858,7 @@ "xpack.securitySolution.detectionEngine.queryPreview.queryPreviewGraphTitle": "{hits} 个{hits, plural, =1 {命中} other {命中}}", "xpack.securitySolution.detectionEngine.queryPreview.queryPreviewHelpText": "选择数据的时间范围以预览查询结果", "xpack.securitySolution.detectionEngine.queryPreview.queryPreviewLabel": "快速查询预览", - "xpack.securitySolution.detectionEngine.readOnlyRulesCallOutMsg": "您当前缺少所需的权限,无法创建/编辑检测引擎规则。有关进一步帮助,请联系您的管理员。", - "xpack.securitySolution.detectionEngine.readOnlyRulesCallOutTitle": "需要规则权限", + "xpack.securitySolution.detectionEngine.readOnlyRulesCallOut.messageTitle": "需要规则权限", "xpack.securitySolution.detectionEngine.rule.editRule.errorMsgDescription": "您在{countError, plural, one {以下选项卡} other {以下选项卡}}中的输入无效:{tabHasError}", "xpack.securitySolution.detectionEngine.ruleDescription.mlJobStartedDescription": "已启动", "xpack.securitySolution.detectionEngine.ruleDescription.mlJobStoppedDescription": "已停止",