[8.16] [Security Solution] Repurpose attack discover tour into knowledge base tour (#196615) (#197535)

# Backport

This will backport the following commits from `main` to `8.16`:
- [[Security Solution] Repurpose attack discover tour into knowledge
base tour (#196615)](https://github.com/elastic/kibana/pull/196615)

<!--- Backport version: 9.4.3 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Steph
Milovic","email":"stephanie.milovic@elastic.co"},"sourceCommit":{"committedDate":"2024-10-23T21:02:35Z","message":"[Security
Solution] Repurpose attack discover tour into knowledge base tour
(#196615)","sha":"fa9bb19f14648bbe34493481df0b32838d0e5734","branchLabelMapping":{"^v9.0.0$":"main","^v8.17.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","Team:
SecuritySolution","backport:prev-minor","Team:Security Generative
AI","v8.16.0"],"title":"[Security Solution] Repurpose attack discover
tour into knowledge base
tour","number":196615,"url":"https://github.com/elastic/kibana/pull/196615","mergeCommit":{"message":"[Security
Solution] Repurpose attack discover tour into knowledge base tour
(#196615)","sha":"fa9bb19f14648bbe34493481df0b32838d0e5734"}},"sourceBranch":"main","suggestedTargetBranches":["8.16"],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/196615","number":196615,"mergeCommit":{"message":"[Security
Solution] Repurpose attack discover tour into knowledge base tour
(#196615)","sha":"fa9bb19f14648bbe34493481df0b32838d0e5734"}},{"branch":"8.16","label":"v8.16.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->

Co-authored-by: Steph Milovic <stephanie.milovic@elastic.co>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
Kibana Machine 2024-10-24 10:47:20 +11:00 committed by GitHub
parent 871137b456
commit a8d1c24dab
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 388 additions and 405 deletions

View file

@ -47,7 +47,7 @@ export const NEW_FEATURES_TOUR_STORAGE_KEYS = {
TIMELINES: 'securitySolution.security.timelineFlyoutHeader.saveTimelineTour',
TIMELINE: 'securitySolution.timeline.newFeaturesTour.v8.12',
FLYOUT: 'securitySolution.documentDetails.newFeaturesTour.v8.14',
ATTACK_DISCOVERY: 'securitySolution.attackDiscovery.newFeaturesTour.v8.14',
KNOWLEDGE_BASE: 'elasticAssistant.knowledgeBase.newFeaturesTour.v8.16',
};
/**

View file

@ -424,7 +424,6 @@ export const NEW_FEATURES_TOUR_STORAGE_KEYS = {
TIMELINES: 'securitySolution.security.timelineFlyoutHeader.saveTimelineTour',
TIMELINE: 'securitySolution.timeline.newFeaturesTour.v8.12',
FLYOUT: 'securitySolution.documentDetails.newFeaturesTour.v8.14',
ATTACK_DISCOVERY: 'securitySolution.attackDiscovery.newFeaturesTour.v8.14',
};
export const RULE_DETAILS_EXECUTION_LOG_TABLE_SHOW_METRIC_COLUMNS_STORAGE_KEY =

View file

@ -5,14 +5,13 @@
* 2.0.
*/
import React, { type ReactNode, useMemo, useState, useCallback } from 'react';
import React, { type ReactNode, useMemo } from 'react';
import styled from 'styled-components';
import { EuiThemeProvider, useEuiTheme, type EuiThemeComputed } from '@elastic/eui';
import { IS_DRAGGING_CLASS_NAME } from '@kbn/securitysolution-t-grid';
import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template';
import type { KibanaPageTemplateProps } from '@kbn/shared-ux-page-kibana-template';
import { ExpandableFlyoutProvider } from '@kbn/expandable-flyout';
import { AttackDiscoveryTour } from '../../../attack_discovery/tour';
import { URL_PARAM_KEY } from '../../../common/hooks/use_url_state';
import { SecuritySolutionFlyout, TimelineFlyout } from '../../../flyout';
import { useSecuritySolutionNavigation } from '../../../common/components/navigation/use_security_solution_navigation';
@ -56,11 +55,7 @@ export type SecuritySolutionTemplateWrapperProps = Omit<KibanaPageTemplateProps,
export const SecuritySolutionTemplateWrapper: React.FC<SecuritySolutionTemplateWrapperProps> =
React.memo(({ children, ...rest }) => {
const [didMount, setDidMount] = useState(false);
const onMount = useCallback(() => {
setDidMount(true);
}, []);
const solutionNavProps = useSecuritySolutionNavigation(onMount);
const solutionNavProps = useSecuritySolutionNavigation();
const [isTimelineBottomBarVisible] = useShowTimeline();
const getTimelineShowStatus = useMemo(() => getTimelineShowStatusByIdSelector(), []);
const { show: isShowingTimelineOverlay } = useDeepEqualSelector((state) =>
@ -107,8 +102,6 @@ export const SecuritySolutionTemplateWrapper: React.FC<SecuritySolutionTemplateW
{children}
<SecuritySolutionFlyout />
</ExpandableFlyoutProvider>
{didMount && <AttackDiscoveryTour />}
</KibanaPageTemplate.Section>
{isTimelineBottomBarVisible && (
<KibanaPageTemplate.BottomBar data-test-subj="timeline-bottom-bar-container">

View file

@ -1,137 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React from 'react';
import { useIsElementMounted } from '../../detection_engine/rule_management_ui/components/rules_table/rules_table/guided_onboarding/use_is_element_mounted';
import { render, screen } from '@testing-library/react';
import {
createMockStore,
createSecuritySolutionStorageMock,
TestProviders,
} from '../../common/mock';
import { useKibana as mockUseKibana } from '../../common/lib/kibana/__mocks__';
import { useKibana } from '../../common/lib/kibana';
import { AttackDiscoveryTour } from '.';
import { ATTACK_DISCOVERY_TOUR_CONFIG_ANCHORS } from './step_config';
import { NEW_FEATURES_TOUR_STORAGE_KEYS, SecurityPageName } from '../../../common/constants';
import type { RouteSpyState } from '../../common/utils/route/types';
import { useRouteSpy } from '../../common/utils/route/use_route_spy';
const mockRouteSpy: RouteSpyState = {
pageName: SecurityPageName.overview,
detailName: undefined,
tabName: undefined,
search: '',
pathName: '/',
};
jest.mock(
'../../detection_engine/rule_management_ui/components/rules_table/rules_table/guided_onboarding/use_is_element_mounted'
);
jest.mock('../../common/lib/kibana');
jest.mock('../../common/utils/route/use_route_spy');
jest.mock('@elastic/eui', () => {
const original = jest.requireActual('@elastic/eui');
return {
...original,
EuiTourStep: () => <div data-test-subj="attackDiscovery-tour-step-1" />,
};
});
const mockedUseKibana = mockUseKibana();
const { storage: storageMock } = createSecuritySolutionStorageMock();
const mockStore = createMockStore(undefined, undefined, undefined, storageMock);
const TestComponent = () => {
return (
<TestProviders store={mockStore}>
<div id={ATTACK_DISCOVERY_TOUR_CONFIG_ANCHORS.NAV_LINK} />
<AttackDiscoveryTour />
</TestProviders>
);
};
describe('Attack discovery tour', () => {
beforeAll(() => {
(useIsElementMounted as jest.Mock).mockReturnValue(true);
(useRouteSpy as jest.Mock).mockReturnValue([mockRouteSpy]);
});
beforeEach(() => {
(useKibana as jest.Mock).mockReturnValue({
...mockedUseKibana,
services: {
...mockedUseKibana.services,
storage: storageMock,
},
});
storageMock.clear();
});
afterEach(() => {
jest.clearAllMocks();
});
it('should not render tour step 1 when element is not mounted', () => {
(useIsElementMounted as jest.Mock).mockReturnValueOnce(false);
render(<TestComponent />);
expect(screen.queryByTestId('attackDiscovery-tour-step-1')).toBeNull();
});
it('should not render any tour steps when tour is not activated', () => {
storageMock.set(NEW_FEATURES_TOUR_STORAGE_KEYS.ATTACK_DISCOVERY, {
currentTourStep: 1,
isTourActive: false,
});
render(<TestComponent />);
expect(screen.queryByTestId('attackDiscovery-tour-step-1')).toBeNull();
expect(screen.queryByTestId('attackDiscovery-tour-step-2')).toBeNull();
});
it('should not render any tour steps when tour is on step 2 and page is not attack discovery', () => {
storageMock.set(NEW_FEATURES_TOUR_STORAGE_KEYS.ATTACK_DISCOVERY, {
currentTourStep: 2,
isTourActive: true,
});
const { debug } = render(<TestComponent />);
expect(screen.queryByTestId('attackDiscovery-tour-step-1')).toBeNull();
debug();
});
it('should render tour step 1 when element is mounted', async () => {
const { getByTestId } = render(<TestComponent />);
expect(getByTestId('attackDiscovery-tour-step-1')).toBeInTheDocument();
});
it('should render tour video when tour is on step 2 and page is attack discovery', () => {
(useRouteSpy as jest.Mock).mockReturnValue([
{ ...mockRouteSpy, pageName: SecurityPageName.attackDiscovery },
]);
storageMock.set(NEW_FEATURES_TOUR_STORAGE_KEYS.ATTACK_DISCOVERY, {
currentTourStep: 2,
isTourActive: true,
});
const { getByTestId } = render(<TestComponent />);
expect(screen.queryByTestId('attackDiscovery-tour-step-1')).toBeNull();
expect(getByTestId('attackDiscovery-tour-step-2')).toBeInTheDocument();
});
it('should advance to tour step 2 when page is attack discovery', () => {
(useRouteSpy as jest.Mock).mockReturnValue([
{ ...mockRouteSpy, pageName: SecurityPageName.attackDiscovery },
]);
storageMock.set(NEW_FEATURES_TOUR_STORAGE_KEYS.ATTACK_DISCOVERY, {
currentTourStep: 1,
isTourActive: true,
});
render(<TestComponent />);
expect(
storageMock.get(NEW_FEATURES_TOUR_STORAGE_KEYS.ATTACK_DISCOVERY).currentTourStep
).toEqual(2);
});
});

View file

@ -1,133 +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.
*/
/*
* The attack discovery tour for 8.14
*
* */
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { EuiButton, EuiButtonEmpty, EuiTourStep } from '@elastic/eui';
import { useRouteSpy } from '../../common/utils/route/use_route_spy';
import { VideoToast } from './video_toast';
import { useIsElementMounted } from '../../detection_engine/rule_management_ui/components/rules_table/rules_table/guided_onboarding/use_is_element_mounted';
import { NEW_FEATURES_TOUR_STORAGE_KEYS, SecurityPageName } from '../../../common/constants';
import { useKibana, useNavigation } from '../../common/lib/kibana';
import { attackDiscoveryTourStepOne, tourConfig } from './step_config';
import * as i18n from './translations';
interface TourState {
currentTourStep: number;
isTourActive: boolean;
}
const AttackDiscoveryTourComp = () => {
const {
services: { storage },
} = useKibana();
const { navigateTo } = useNavigation();
const [{ pageName }] = useRouteSpy();
const [tourState, setTourState] = useState<TourState>(
storage.get(NEW_FEATURES_TOUR_STORAGE_KEYS.ATTACK_DISCOVERY) ?? tourConfig
);
const advanceToVideoStep = useCallback(() => {
setTourState((prev) => {
storage.set(NEW_FEATURES_TOUR_STORAGE_KEYS.ATTACK_DISCOVERY, {
...prev,
currentTourStep: 2,
});
return {
...prev,
currentTourStep: 2,
};
});
}, [storage]);
useEffect(() => {
if (tourState.isTourActive && pageName === SecurityPageName.attackDiscovery) {
advanceToVideoStep();
}
}, [advanceToVideoStep, pageName, tourState.isTourActive]);
const finishTour = useCallback(() => {
setTourState((prev) => {
storage.set(NEW_FEATURES_TOUR_STORAGE_KEYS.ATTACK_DISCOVERY, {
...prev,
isTourActive: false,
});
return {
...prev,
isTourActive: false,
};
});
}, [storage]);
const navigateToAttackDiscovery = useCallback(() => {
navigateTo({
deepLinkId: SecurityPageName.attackDiscovery,
});
}, [navigateTo]);
const nextStep = useCallback(() => {
if (tourState.currentTourStep === 1) {
navigateToAttackDiscovery();
advanceToVideoStep();
}
}, [tourState.currentTourStep, navigateToAttackDiscovery, advanceToVideoStep]);
const footerAction = useMemo(
() => [
// if exit, set tour to the video step without navigating to the page
<EuiButtonEmpty size="s" color="text" onClick={advanceToVideoStep}>
{i18n.ATTACK_DISCOVERY_TOUR_EXIT}
</EuiButtonEmpty>,
// if next, set tour to the video step and navigate to the page
<EuiButton color="success" size="s" onClick={nextStep}>
{i18n.ATTACK_DISCOVERY_TRY_IT}
</EuiButton>,
],
[advanceToVideoStep, nextStep]
);
const isElementAtCurrentStepMounted = useIsElementMounted(attackDiscoveryTourStepOne?.anchor);
const isTestAutomation =
window.Cypress != null || // TODO: temporary workaround to disable the tour when running in Cypress, because the tour breaks other projects Cypress tests
navigator.webdriver === true; // TODO: temporary workaround to disable the tour when running in the FTR, because the tour breaks other projects FTR tests
if (
isTestAutomation ||
!tourState.isTourActive ||
(tourState.currentTourStep === 1 && !isElementAtCurrentStepMounted)
) {
return null;
}
return tourState.currentTourStep === 1 ? (
<EuiTourStep
anchor={`#${attackDiscoveryTourStepOne.anchor}`}
content={attackDiscoveryTourStepOne.content}
footerAction={footerAction}
isStepOpen
maxWidth={450}
onFinish={advanceToVideoStep}
panelProps={{
'data-test-subj': `attackDiscovery-tour-step-1`,
}}
repositionOnScroll
step={1}
stepsTotal={1}
title={attackDiscoveryTourStepOne.title}
/>
) : pageName === SecurityPageName.attackDiscovery ? (
<VideoToast onClose={finishTour} />
) : null;
};
export const AttackDiscoveryTour = React.memo(AttackDiscoveryTourComp);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 MiB

View file

@ -1,23 +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 * as i18n from './translations';
export const ATTACK_DISCOVERY_TOUR_CONFIG_ANCHORS = {
NAV_LINK: 'solutionSideNavItemLink-attack_discovery',
};
export const attackDiscoveryTourStepOne = {
title: i18n.ATTACK_DISCOVERY_TOUR_ATTACK_DISCOVERY_TITLE,
content: i18n.ATTACK_DISCOVERY_TOUR_ATTACK_DISCOVERY_DESC,
anchor: ATTACK_DISCOVERY_TOUR_CONFIG_ANCHORS.NAV_LINK,
};
export const tourConfig = {
currentTourStep: 1,
isTourActive: true,
};

View file

@ -1,59 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
export const ATTACK_DISCOVERY_TOUR_ATTACK_DISCOVERY_TITLE = i18n.translate(
'xpack.securitySolution.attackDiscovery.tour.navStep.title',
{
defaultMessage: 'Introducing attack discovery',
}
);
export const ATTACK_DISCOVERY_TOUR_ATTACK_DISCOVERY_DESC = i18n.translate(
'xpack.securitySolution.attackDiscovery.tour.navStep.desc',
{
defaultMessage:
'Leverage Generative AI to find relationships among your alerts and describe attack chains.',
}
);
export const ATTACK_DISCOVERY_TOUR_VIDEO_STEP_TITLE = i18n.translate(
'xpack.securitySolution.attackDiscovery.tour.videoStep.title',
{
defaultMessage: 'Start discovering attacks',
}
);
export const ATTACK_DISCOVERY_TOUR_VIDEO_STEP_DESC = i18n.translate(
'xpack.securitySolution.attackDiscovery.tour.videoStep.desc',
{
defaultMessage:
'Dive into data-driven attack discoveries and streamline your workflow with our intuitive AI technology, designed to elevate your productivity instantly.',
}
);
export const ATTACK_DISCOVERY_TOUR_EXIT = i18n.translate(
'xpack.securitySolution.attackDiscovery.tour.exit',
{
defaultMessage: 'Close',
}
);
export const ATTACK_DISCOVERY_TRY_IT = i18n.translate(
'xpack.securitySolution.attackDiscovery.tour.tryIt',
{
defaultMessage: 'Try it',
}
);
export const WATCH_OVERVIEW_VIDEO = i18n.translate(
'xpack.securitySolution.attackDiscovery.tour.video',
{
defaultMessage: 'Watch overview video',
}
);

View file

@ -1,55 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React from 'react';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { VideoToast } from './video_toast';
describe('VideoToast', () => {
const onCloseMock = jest.fn();
beforeEach(() => {
jest.spyOn(window, 'open').mockImplementation(() => null);
render(<VideoToast onClose={onCloseMock} />);
});
afterEach(() => {
jest.restoreAllMocks();
});
it('should render the video toast', () => {
const videoToast = screen.getByTestId('attackDiscovery-tour-step-2');
expect(videoToast).toBeInTheDocument();
});
it('should render the video gif', () => {
const videoGif = screen.getByTestId('video-gif');
expect(videoGif).toBeInTheDocument();
});
it('should open the video in a new tab when the gif is clicked', async () => {
const videoGif = screen.getByTestId('video-gif');
await userEvent.click(videoGif);
expect(window.open).toHaveBeenCalledWith(
'https://videos.elastic.co/watch/BrDaDBAAvdygvemFKNAkBW',
'_blank'
);
});
it('should open the video in a new tab when the "Watch overview video" button is clicked', async () => {
const watchVideoButton = screen.getByRole('button', { name: 'Watch overview video' });
await userEvent.click(watchVideoButton);
expect(window.open).toHaveBeenCalledWith(
'https://videos.elastic.co/watch/BrDaDBAAvdygvemFKNAkBW',
'_blank'
);
});
it('should call the onClose callback when the close button is clicked', async () => {
const closeButton = screen.getByTestId('toastCloseButton');
await userEvent.click(closeButton);
expect(onCloseMock).toHaveBeenCalled();
});
});

View file

@ -1,59 +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 {
EuiButton,
EuiIcon,
EuiImage,
EuiToast,
EuiPortal,
EuiText,
EuiSpacer,
} from '@elastic/eui';
import React, { useCallback } from 'react';
import * as i18n from './translations';
import theGif from './overview.gif';
const VIDEO_CONTENT_WIDTH = 250;
const VIDEO_PAGE = `https://videos.elastic.co/watch/BrDaDBAAvdygvemFKNAkBW`;
const VideoComponent: React.FC<{ onClose: () => void }> = ({ onClose }) => {
const openVideoInNewTab = useCallback(() => {
window.open(VIDEO_PAGE, '_blank');
}, []);
return (
<EuiPortal>
<div
data-test-subj="attackDiscovery-tour-step-2"
css={{ position: 'fixed', bottom: 16, right: 16, zIndex: 9999 }}
>
<EuiToast onClose={onClose} css={{ maxWidth: VIDEO_CONTENT_WIDTH }}>
<EuiImage
onClick={openVideoInNewTab}
css={{ marginTop: 20, '&:hover': { cursor: 'pointer' } }}
src={theGif}
data-test-subj="video-gif"
alt={i18n.WATCH_OVERVIEW_VIDEO}
/>
<EuiText size="s" grow={false} css={{ marginTop: 20 }}>
<h4>
<EuiIcon type="cheer" color="success" /> {i18n.ATTACK_DISCOVERY_TOUR_VIDEO_STEP_TITLE}
</h4>
<p>{i18n.ATTACK_DISCOVERY_TOUR_VIDEO_STEP_DESC}</p>
</EuiText>
<EuiSpacer size="m" />
<EuiButton color="success" onClick={openVideoInNewTab} fullWidth>
{i18n.WATCH_OVERVIEW_VIDEO}
</EuiButton>
</EuiToast>
</div>
</EuiPortal>
);
};
export const VideoToast = React.memo(VideoComponent);

View file

@ -137,7 +137,7 @@ const usePanelBottomOffset = (): string | undefined => {
* Main security navigation component.
* It takes the links to render from the generic application `links` configs.
*/
export const SecuritySideNav: React.FC<{ onMount?: () => void }> = ({ onMount }) => {
export const SecuritySideNav: React.FC = () => {
const items = useSolutionSideNavItems();
const selectedId = useSelectedId();
const panelTopOffset = usePanelTopOffset();
@ -151,7 +151,6 @@ export const SecuritySideNav: React.FC<{ onMount?: () => void }> = ({ onMount })
<SolutionSideNav
items={items}
categories={CATEGORIES}
onMount={onMount}
selectedId={selectedId}
panelTopOffset={panelTopOffset}
panelBottomOffset={panelBottomOffset}

View file

@ -23,9 +23,7 @@ const translatedNavTitle = i18n.translate('xpack.securitySolution.navigation.mai
defaultMessage: 'Security',
});
export const useSecuritySolutionNavigation = (
onMount: () => void
): KibanaPageTemplateProps['solutionNav'] => {
export const useSecuritySolutionNavigation = (): KibanaPageTemplateProps['solutionNav'] => {
const { chrome } = useKibana().services;
const chromeStyle$ = useMemo(() => chrome.getChromeStyle$(), [chrome]);
const chromeStyle = useObservable(chromeStyle$, 'classic');
@ -41,7 +39,7 @@ export const useSecuritySolutionNavigation = (
canBeCollapsed: true,
name: translatedNavTitle,
icon: 'logoSecurity',
children: <SecuritySideNav onMount={onMount} />,
children: <SecuritySideNav />,
closeFlyoutButtonPosition: 'inside',
};
};

View file

@ -35336,13 +35336,6 @@
"xpack.securitySolution.attackDiscovery.summaryCount.alertsLabel": "{alertsCount} {alertsCount, plural, =1 {alerte} other {alertes}}",
"xpack.securitySolution.attackDiscovery.summaryCount.discoveriesLabel": "{attackDiscoveriesCount} {attackDiscoveriesCount, plural, =1 {découverte} other {découvertes}}",
"xpack.securitySolution.attackDiscovery.summaryCount.lastGeneratedLabel": "Généré",
"xpack.securitySolution.attackDiscovery.tour.exit": "Fermer",
"xpack.securitySolution.attackDiscovery.tour.navStep.desc": "Tirez parti de lIA générative pour trouver des relations entre vos alertes et détailler les chaînes dattaque.",
"xpack.securitySolution.attackDiscovery.tour.navStep.title": "Présentation dAttack Discovery",
"xpack.securitySolution.attackDiscovery.tour.tryIt": "Essayer",
"xpack.securitySolution.attackDiscovery.tour.video": "Regardez la vidéo de présentation",
"xpack.securitySolution.attackDiscovery.tour.videoStep.desc": "Plongez dans les découvertes d'attaques axées sur les données et rationalisez votre flux de travail grâce à notre technologie d'IA intuitive, conçue pour accroître instantanément votre productivité.",
"xpack.securitySolution.attackDiscovery.tour.videoStep.title": "Démarrez la découverte des attaques",
"xpack.securitySolution.auditd.abortedAuditStartupDescription": "démarrage de l'audit abandonné",
"xpack.securitySolution.auditd.accessErrorDescription": "erreur d'accès",
"xpack.securitySolution.auditd.accessPermissionDescription": "autorisation d'accès",

View file

@ -35081,13 +35081,6 @@
"xpack.securitySolution.attackDiscovery.summaryCount.alertsLabel": "{alertsCount} {alertsCount, plural, other {件のアラート}}",
"xpack.securitySolution.attackDiscovery.summaryCount.discoveriesLabel": "{attackDiscoveriesCount} {attackDiscoveriesCount, plural, other {件の検出}}",
"xpack.securitySolution.attackDiscovery.summaryCount.lastGeneratedLabel": "生成済み",
"xpack.securitySolution.attackDiscovery.tour.exit": "閉じる",
"xpack.securitySolution.attackDiscovery.tour.navStep.desc": "生成AIを活用して、アラート全体の関係を特定し、攻撃チェーンを解析します。",
"xpack.securitySolution.attackDiscovery.tour.navStep.title": "Attack Discoveryの概要",
"xpack.securitySolution.attackDiscovery.tour.tryIt": "お試しください",
"xpack.securitySolution.attackDiscovery.tour.video": "概要動画を視聴",
"xpack.securitySolution.attackDiscovery.tour.videoStep.desc": "データ主導のAttack Discoveryを導入し、生産性を即時に高めるために設計されたElasticの直感的なAI技術でワークフローを合理化しましょう。",
"xpack.securitySolution.attackDiscovery.tour.videoStep.title": "攻撃の検出を開始",
"xpack.securitySolution.auditd.abortedAuditStartupDescription": "中断された監査のスタートアップ",
"xpack.securitySolution.auditd.accessErrorDescription": "アクセスエラー",
"xpack.securitySolution.auditd.accessPermissionDescription": "アクセス権限",

View file

@ -35124,13 +35124,6 @@
"xpack.securitySolution.attackDiscovery.summaryCount.alertsLabel": "{alertsCount} 个{alertsCount, plural, other {告警}}",
"xpack.securitySolution.attackDiscovery.summaryCount.discoveriesLabel": "{attackDiscoveriesCount} 个{attackDiscoveriesCount, plural, other {发现}}",
"xpack.securitySolution.attackDiscovery.summaryCount.lastGeneratedLabel": "已生成",
"xpack.securitySolution.attackDiscovery.tour.exit": "关闭",
"xpack.securitySolution.attackDiscovery.tour.navStep.desc": "利用生成式 AI 找出您的告警之间的关系并描述攻击链。",
"xpack.securitySolution.attackDiscovery.tour.navStep.title": "Attack Discovery 简介",
"xpack.securitySolution.attackDiscovery.tour.tryIt": "试用",
"xpack.securitySolution.attackDiscovery.tour.video": "观看概述视频",
"xpack.securitySolution.attackDiscovery.tour.videoStep.desc": "深入了解数据驱动式 Attack Discovery并利用旨在即时提高生产力的直观式 AI 技术精简您的工作流。",
"xpack.securitySolution.attackDiscovery.tour.videoStep.title": "开始发现攻击",
"xpack.securitySolution.auditd.abortedAuditStartupDescription": "已中止审计启动",
"xpack.securitySolution.auditd.accessErrorDescription": "访问错误",
"xpack.securitySolution.auditd.accessPermissionDescription": "访问权限",