mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Security Solution][Alert Details] - remove flyout tour introduced in 8.14 (#198708)
## Summary We [added](https://github.com/elastic/kibana/pull/180318) a guided tour to the expandable flyout back in `8.14`. It is time to remove it as enough users have seen it. No UI changes other than the tour not showing up. ### How to test - clear local storage (more specifically remove the `securitySolution.documentDetails.newFeaturesTour.v8.14` key - open a alert or event details flyout and verify that the tour does not show up ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios Should help solve https://github.com/elastic/kibana/issues/197492
This commit is contained in:
parent
1a100a4f52
commit
0aec5a82db
22 changed files with 14 additions and 946 deletions
|
@ -67,7 +67,6 @@ export const internalRequest = <T = unknown>({
|
|||
const NEW_FEATURES_TOUR_STORAGE_KEYS = {
|
||||
RULE_MANAGEMENT_PAGE: 'securitySolution.rulesManagementPage.newFeaturesTour.v8.9',
|
||||
TIMELINES: 'securitySolution.security.timelineFlyoutHeader.saveTimelineTour',
|
||||
FLYOUT: 'securitySolution.documentDetails.newFeaturesTour.v8.14',
|
||||
};
|
||||
|
||||
const disableNewFeaturesTours = (window: Window) => {
|
||||
|
|
|
@ -45,8 +45,6 @@ export enum NAV_SEARCH_INPUT_OSQUERY_RESULTS {
|
|||
export const NEW_FEATURES_TOUR_STORAGE_KEYS = {
|
||||
RULE_MANAGEMENT_PAGE: 'securitySolution.rulesManagementPage.newFeaturesTour.v8.13',
|
||||
TIMELINES: 'securitySolution.security.timelineFlyoutHeader.saveTimelineTour',
|
||||
TIMELINE: 'securitySolution.timeline.newFeaturesTour.v8.12',
|
||||
FLYOUT: 'securitySolution.documentDetails.newFeaturesTour.v8.14',
|
||||
KNOWLEDGE_BASE: 'elasticAssistant.knowledgeBase.newFeaturesTour.v8.16',
|
||||
};
|
||||
|
||||
|
|
|
@ -424,7 +424,6 @@ export const RULES_TABLE_MAX_PAGE_SIZE = 100;
|
|||
export const NEW_FEATURES_TOUR_STORAGE_KEYS = {
|
||||
RULE_MANAGEMENT_PAGE: 'securitySolution.rulesManagementPage.newFeaturesTour.v8.13',
|
||||
TIMELINES: 'securitySolution.security.timelineFlyoutHeader.saveTimelineTour',
|
||||
FLYOUT: 'securitySolution.documentDetails.newFeaturesTour.v8.14',
|
||||
};
|
||||
|
||||
export const RULE_DETAILS_EXECUTION_LOG_TABLE_SHOW_METRIC_COLUMNS_STORAGE_KEY =
|
||||
|
|
|
@ -1,122 +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, waitFor, fireEvent } from '@testing-library/react';
|
||||
import { LeftPanelTour } from './tour';
|
||||
import { DocumentDetailsContext } from '../../shared/context';
|
||||
import { mockContextValue } from '../../shared/mocks/mock_context';
|
||||
import {
|
||||
createMockStore,
|
||||
createSecuritySolutionStorageMock,
|
||||
TestProviders,
|
||||
} from '../../../../common/mock';
|
||||
import { useKibana as mockUseKibana } from '../../../../common/lib/kibana/__mocks__';
|
||||
import { useKibana } from '../../../../common/lib/kibana';
|
||||
import { FLYOUT_TOUR_CONFIG_ANCHORS } from '../../shared/utils/tour_step_config';
|
||||
import { FLYOUT_TOUR_TEST_ID } from '../../shared/components/test_ids';
|
||||
import { useWhichFlyout } from '../../shared/hooks/use_which_flyout';
|
||||
import { Flyouts } from '../../shared/constants/flyouts';
|
||||
|
||||
jest.mock('../../../../common/lib/kibana');
|
||||
jest.mock('../../shared/hooks/use_which_flyout');
|
||||
|
||||
const mockedUseKibana = mockUseKibana();
|
||||
|
||||
const { storage: storageMock } = createSecuritySolutionStorageMock();
|
||||
const mockStore = createMockStore(undefined, undefined, undefined, {
|
||||
...storageMock,
|
||||
});
|
||||
|
||||
const renderLeftPanelTour = (context: DocumentDetailsContext = mockContextValue) =>
|
||||
render(
|
||||
<TestProviders store={mockStore}>
|
||||
<DocumentDetailsContext.Provider value={context}>
|
||||
<LeftPanelTour />
|
||||
{Object.values(FLYOUT_TOUR_CONFIG_ANCHORS).map((i, idx) => (
|
||||
<div key={idx} data-test-subj={i} />
|
||||
))}
|
||||
</DocumentDetailsContext.Provider>
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
describe('<LeftPanelTour />', () => {
|
||||
beforeEach(() => {
|
||||
(useKibana as jest.Mock).mockReturnValue({
|
||||
...mockedUseKibana,
|
||||
services: {
|
||||
...mockedUseKibana.services,
|
||||
storage: storageMock,
|
||||
},
|
||||
});
|
||||
(useWhichFlyout as jest.Mock).mockReturnValue(Flyouts.securitySolution);
|
||||
|
||||
storageMock.clear();
|
||||
});
|
||||
|
||||
it('should render left panel tour for alerts starting as step 4', async () => {
|
||||
storageMock.set('securitySolution.documentDetails.newFeaturesTour.v8.14', {
|
||||
currentTourStep: 4,
|
||||
isTourActive: true,
|
||||
});
|
||||
|
||||
const { getByText, getByTestId } = renderLeftPanelTour();
|
||||
await waitFor(() => {
|
||||
expect(getByTestId(`${FLYOUT_TOUR_TEST_ID}-4`)).toBeVisible();
|
||||
});
|
||||
fireEvent.click(getByText('Next'));
|
||||
await waitFor(() => {
|
||||
expect(getByTestId(`${FLYOUT_TOUR_TEST_ID}-5`)).toBeVisible();
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(getByText('Finish')).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
it('should not render left panel tour for preview', () => {
|
||||
storageMock.set('securitySolution.documentDetails.newFeaturesTour.v8.14', {
|
||||
currentTourStep: 3,
|
||||
isTourActive: true,
|
||||
});
|
||||
|
||||
const { queryByTestId, queryByText } = renderLeftPanelTour({
|
||||
...mockContextValue,
|
||||
isPreview: true,
|
||||
});
|
||||
expect(queryByTestId(`${FLYOUT_TOUR_TEST_ID}-4`)).not.toBeInTheDocument();
|
||||
expect(queryByText('Next')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should not render left panel tour for non-alerts', async () => {
|
||||
storageMock.set('securitySolution.documentDetails.newFeaturesTour.v8.14', {
|
||||
currentTourStep: 3,
|
||||
isTourActive: true,
|
||||
});
|
||||
|
||||
const { queryByTestId, queryByText } = renderLeftPanelTour({
|
||||
...mockContextValue,
|
||||
getFieldsData: () => '',
|
||||
});
|
||||
expect(queryByTestId(`${FLYOUT_TOUR_TEST_ID}-4`)).not.toBeInTheDocument();
|
||||
expect(queryByText('Next')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should not render left panel tour for flyout in timeline', () => {
|
||||
(useWhichFlyout as jest.Mock).mockReturnValue(Flyouts.timeline);
|
||||
storageMock.set('securitySolution.documentDetails.newFeaturesTour.v8.14', {
|
||||
currentTourStep: 3,
|
||||
isTourActive: true,
|
||||
});
|
||||
|
||||
const { queryByTestId, queryByText } = renderLeftPanelTour({
|
||||
...mockContextValue,
|
||||
isPreview: true,
|
||||
});
|
||||
expect(queryByTestId(`${FLYOUT_TOUR_TEST_ID}-4`)).not.toBeInTheDocument();
|
||||
expect(queryByText('Next')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
|
@ -1,32 +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, { memo, useMemo } from 'react';
|
||||
import { useWhichFlyout } from '../../shared/hooks/use_which_flyout';
|
||||
import { getField } from '../../shared/utils';
|
||||
import { EventKind } from '../../shared/constants/event_kinds';
|
||||
import { useDocumentDetailsContext } from '../../shared/context';
|
||||
import { getLeftSectionTourSteps } from '../../shared/utils/tour_step_config';
|
||||
import { Flyouts } from '../../shared/constants/flyouts';
|
||||
import { FlyoutTour } from '../../shared/components/flyout_tour';
|
||||
|
||||
/**
|
||||
* Guided tour for the left panel in details flyout
|
||||
*/
|
||||
export const LeftPanelTour = memo(() => {
|
||||
const { getFieldsData, isPreview } = useDocumentDetailsContext();
|
||||
const eventKind = getField(getFieldsData('event.kind'));
|
||||
const isAlert = eventKind === EventKind.signal;
|
||||
const isTimelineFlyoutOpen = useWhichFlyout() === Flyouts.timeline;
|
||||
const showTour = isAlert && !isPreview && !isTimelineFlyoutOpen;
|
||||
|
||||
const tourStepContent = useMemo(() => getLeftSectionTourSteps(), []);
|
||||
|
||||
return showTour ? <FlyoutTour tourStepContent={tourStepContent} totalSteps={5} /> : null;
|
||||
});
|
||||
|
||||
LeftPanelTour.displayName = 'LeftPanelTour';
|
|
@ -22,7 +22,6 @@ import { getField } from '../shared/utils';
|
|||
import { EventKind } from '../shared/constants/event_kinds';
|
||||
import { useDocumentDetailsContext } from '../shared/context';
|
||||
import type { DocumentDetailsProps } from '../shared/types';
|
||||
import { LeftPanelTour } from './components/tour';
|
||||
|
||||
export type LeftPanelPaths = 'visualize' | 'insights' | 'investigation' | 'response' | 'notes';
|
||||
export const LeftPanelVisualizeTab: LeftPanelPaths = 'visualize';
|
||||
|
@ -85,7 +84,6 @@ export const LeftPanel: FC<Partial<DocumentDetailsProps>> = memo(({ path }) => {
|
|||
|
||||
return (
|
||||
<>
|
||||
<LeftPanelTour />
|
||||
<PanelHeader
|
||||
selectedTabId={selectedTabId}
|
||||
setSelectedTabId={setSelectedTabId}
|
||||
|
|
|
@ -14,10 +14,8 @@ import { useExpandableFlyoutApi, useExpandableFlyoutState } from '@kbn/expandabl
|
|||
import { useKibana } from '../../../../common/lib/kibana';
|
||||
import {
|
||||
INSIGHTS_TAB_BUTTON_GROUP_TEST_ID,
|
||||
INSIGHTS_TAB_ENTITIES_BUTTON_LABEL_TEST_ID,
|
||||
INSIGHTS_TAB_ENTITIES_BUTTON_TEST_ID,
|
||||
INSIGHTS_TAB_THREAT_INTELLIGENCE_BUTTON_TEST_ID,
|
||||
INSIGHTS_TAB_PREVALENCE_BUTTON_LABEL_TEST_ID,
|
||||
INSIGHTS_TAB_PREVALENCE_BUTTON_TEST_ID,
|
||||
INSIGHTS_TAB_CORRELATIONS_BUTTON_TEST_ID,
|
||||
} from './test_ids';
|
||||
|
@ -40,12 +38,10 @@ const insightsButtons: EuiButtonGroupOptionProps[] = [
|
|||
{
|
||||
id: ENTITIES_TAB_ID,
|
||||
label: (
|
||||
<div data-test-subj={INSIGHTS_TAB_ENTITIES_BUTTON_LABEL_TEST_ID}>
|
||||
<FormattedMessage
|
||||
id="xpack.securitySolution.flyout.left.insights.entitiesButtonLabel"
|
||||
defaultMessage="Entities"
|
||||
/>
|
||||
</div>
|
||||
<FormattedMessage
|
||||
id="xpack.securitySolution.flyout.left.insights.entitiesButtonLabel"
|
||||
defaultMessage="Entities"
|
||||
/>
|
||||
),
|
||||
'data-test-subj': INSIGHTS_TAB_ENTITIES_BUTTON_TEST_ID,
|
||||
},
|
||||
|
@ -62,12 +58,10 @@ const insightsButtons: EuiButtonGroupOptionProps[] = [
|
|||
{
|
||||
id: PREVALENCE_TAB_ID,
|
||||
label: (
|
||||
<div data-test-subj={INSIGHTS_TAB_PREVALENCE_BUTTON_LABEL_TEST_ID}>
|
||||
<FormattedMessage
|
||||
id="xpack.securitySolution.flyout.left.insights.prevalenceButtonLabel"
|
||||
defaultMessage="Prevalence"
|
||||
/>
|
||||
</div>
|
||||
<FormattedMessage
|
||||
id="xpack.securitySolution.flyout.left.insights.prevalenceButtonLabel"
|
||||
defaultMessage="Prevalence"
|
||||
/>
|
||||
),
|
||||
'data-test-subj': INSIGHTS_TAB_PREVALENCE_BUTTON_TEST_ID,
|
||||
},
|
||||
|
|
|
@ -17,12 +17,8 @@ const INSIGHTS_TAB_TEST_ID = `${PREFIX}InsightsTab` as const;
|
|||
export const INSIGHTS_TAB_BUTTON_GROUP_TEST_ID = `${INSIGHTS_TAB_TEST_ID}ButtonGroup` as const;
|
||||
export const INSIGHTS_TAB_ENTITIES_BUTTON_TEST_ID =
|
||||
`${INSIGHTS_TAB_TEST_ID}EntitiesButton` as const;
|
||||
export const INSIGHTS_TAB_ENTITIES_BUTTON_LABEL_TEST_ID =
|
||||
`${INSIGHTS_TAB_TEST_ID}Entities` as const;
|
||||
export const INSIGHTS_TAB_THREAT_INTELLIGENCE_BUTTON_TEST_ID =
|
||||
`${INSIGHTS_TAB_TEST_ID}ThreatIntelligenceButton` as const;
|
||||
export const INSIGHTS_TAB_PREVALENCE_BUTTON_LABEL_TEST_ID =
|
||||
`${INSIGHTS_TAB_TEST_ID}Prevalence` as const;
|
||||
export const INSIGHTS_TAB_PREVALENCE_BUTTON_TEST_ID =
|
||||
`${INSIGHTS_TAB_TEST_ID}PrevalenceButton` as const;
|
||||
export const INSIGHTS_TAB_CORRELATIONS_BUTTON_TEST_ID =
|
||||
|
|
|
@ -1,125 +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, waitFor, fireEvent } from '@testing-library/react';
|
||||
import { RightPanelTour } from './tour';
|
||||
import { DocumentDetailsContext } from '../../shared/context';
|
||||
import { mockContextValue } from '../../shared/mocks/mock_context';
|
||||
import {
|
||||
createMockStore,
|
||||
createSecuritySolutionStorageMock,
|
||||
TestProviders,
|
||||
} from '../../../../common/mock';
|
||||
import { useKibana as mockUseKibana } from '../../../../common/lib/kibana/__mocks__';
|
||||
import { useKibana } from '../../../../common/lib/kibana';
|
||||
import { FLYOUT_TOUR_CONFIG_ANCHORS } from '../../shared/utils/tour_step_config';
|
||||
import { FLYOUT_TOUR_TEST_ID } from '../../shared/components/test_ids';
|
||||
import { useTourContext } from '../../../../common/components/guided_onboarding_tour/tour';
|
||||
import { casesPluginMock } from '@kbn/cases-plugin/public/mocks';
|
||||
import { useWhichFlyout } from '../../shared/hooks/use_which_flyout';
|
||||
import { Flyouts } from '../../shared/constants/flyouts';
|
||||
|
||||
jest.mock('../../../../common/lib/kibana');
|
||||
jest.mock('../../shared/hooks/use_which_flyout');
|
||||
jest.mock('../../../../common/components/guided_onboarding_tour/tour');
|
||||
|
||||
const mockedUseKibana = mockUseKibana();
|
||||
|
||||
const { storage: storageMock } = createSecuritySolutionStorageMock();
|
||||
const mockStore = createMockStore(undefined, undefined, undefined, {
|
||||
...storageMock,
|
||||
});
|
||||
const mockCasesContract = casesPluginMock.createStartContract();
|
||||
const mockUseIsAddToCaseOpen = mockCasesContract.hooks.useIsAddToCaseOpen as jest.Mock;
|
||||
mockUseIsAddToCaseOpen.mockReturnValue(false);
|
||||
|
||||
const renderRightPanelTour = (context: DocumentDetailsContext = mockContextValue) =>
|
||||
render(
|
||||
<TestProviders store={mockStore}>
|
||||
<DocumentDetailsContext.Provider value={context}>
|
||||
<RightPanelTour />
|
||||
{Object.values(FLYOUT_TOUR_CONFIG_ANCHORS).map((i, idx) => (
|
||||
<div key={idx} data-test-subj={i} />
|
||||
))}
|
||||
</DocumentDetailsContext.Provider>
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
describe('<RightPanelTour />', () => {
|
||||
beforeEach(() => {
|
||||
(useKibana as jest.Mock).mockReturnValue({
|
||||
...mockedUseKibana,
|
||||
services: {
|
||||
...mockedUseKibana.services,
|
||||
storage: storageMock,
|
||||
cases: mockCasesContract,
|
||||
},
|
||||
});
|
||||
(useWhichFlyout as jest.Mock).mockReturnValue(Flyouts.securitySolution);
|
||||
(useTourContext as jest.Mock).mockReturnValue({ isTourShown: jest.fn(() => false) });
|
||||
storageMock.clear();
|
||||
});
|
||||
|
||||
it('should render tour for alerts', async () => {
|
||||
const { getByText, getByTestId } = renderRightPanelTour();
|
||||
await waitFor(() => {
|
||||
expect(getByTestId(`${FLYOUT_TOUR_TEST_ID}-1`)).toBeVisible();
|
||||
});
|
||||
fireEvent.click(getByText('Next'));
|
||||
await waitFor(() => {
|
||||
expect(getByTestId(`${FLYOUT_TOUR_TEST_ID}-2`)).toBeVisible();
|
||||
});
|
||||
fireEvent.click(getByText('Next'));
|
||||
await waitFor(() => {
|
||||
expect(getByTestId(`${FLYOUT_TOUR_TEST_ID}-3`)).toBeVisible();
|
||||
});
|
||||
fireEvent.click(getByText('Next'));
|
||||
});
|
||||
|
||||
it('should not render tour for preview', () => {
|
||||
const { queryByTestId, queryByText } = renderRightPanelTour({
|
||||
...mockContextValue,
|
||||
isPreview: true,
|
||||
});
|
||||
expect(queryByTestId(`${FLYOUT_TOUR_TEST_ID}-1`)).not.toBeInTheDocument();
|
||||
expect(queryByText('Next')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should not render tour when guided onboarding tour is active', () => {
|
||||
(useTourContext as jest.Mock).mockReturnValue({ isTourShown: jest.fn(() => true) });
|
||||
const { queryByText, queryByTestId } = renderRightPanelTour({
|
||||
...mockContextValue,
|
||||
getFieldsData: () => '',
|
||||
});
|
||||
|
||||
expect(queryByTestId(`${FLYOUT_TOUR_TEST_ID}-1`)).not.toBeInTheDocument();
|
||||
expect(queryByText('Next')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should not render tour when case modal is open', () => {
|
||||
mockUseIsAddToCaseOpen.mockReturnValue(true);
|
||||
const { queryByText, queryByTestId } = renderRightPanelTour({
|
||||
...mockContextValue,
|
||||
getFieldsData: () => '',
|
||||
});
|
||||
|
||||
expect(queryByTestId(`${FLYOUT_TOUR_TEST_ID}-1`)).not.toBeInTheDocument();
|
||||
expect(queryByText('Next')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should not render tour for flyout in timeline', () => {
|
||||
(useWhichFlyout as jest.Mock).mockReturnValue(Flyouts.timeline);
|
||||
const { queryByText, queryByTestId } = renderRightPanelTour({
|
||||
...mockContextValue,
|
||||
getFieldsData: () => '',
|
||||
});
|
||||
|
||||
expect(queryByTestId(`${FLYOUT_TOUR_TEST_ID}-1`)).not.toBeInTheDocument();
|
||||
expect(queryByText('Next')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
|
@ -1,90 +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, { memo, useMemo, useCallback } from 'react';
|
||||
import { useExpandableFlyoutApi } from '@kbn/expandable-flyout';
|
||||
import { useWhichFlyout } from '../../shared/hooks/use_which_flyout';
|
||||
import { Flyouts } from '../../shared/constants/flyouts';
|
||||
import { useDocumentDetailsContext } from '../../shared/context';
|
||||
import {
|
||||
getRightSectionTourSteps,
|
||||
getLeftSectionTourSteps,
|
||||
} from '../../shared/utils/tour_step_config';
|
||||
import { getField } from '../../shared/utils';
|
||||
import {
|
||||
DocumentDetailsLeftPanelKey,
|
||||
DocumentDetailsRightPanelKey,
|
||||
} from '../../shared/constants/panel_keys';
|
||||
import { EventKind } from '../../shared/constants/event_kinds';
|
||||
import { useTourContext } from '../../../../common/components/guided_onboarding_tour/tour';
|
||||
import { SecurityStepId } from '../../../../common/components/guided_onboarding_tour/tour_config';
|
||||
import { useKibana } from '../../../../common/lib/kibana';
|
||||
import { FlyoutTour } from '../../shared/components/flyout_tour';
|
||||
|
||||
/**
|
||||
* Guided tour for the right panel in details flyout
|
||||
*/
|
||||
export const RightPanelTour = memo(() => {
|
||||
const { useIsAddToCaseOpen } = useKibana().services.cases.hooks;
|
||||
|
||||
const casesFlyoutExpanded = useIsAddToCaseOpen();
|
||||
|
||||
const { isTourShown: isGuidedOnboardingTourShown } = useTourContext();
|
||||
|
||||
const { openLeftPanel, openRightPanel } = useExpandableFlyoutApi();
|
||||
const { eventId, indexName, scopeId, isPreview, getFieldsData } = useDocumentDetailsContext();
|
||||
|
||||
const eventKind = getField(getFieldsData('event.kind'));
|
||||
const isAlert = eventKind === EventKind.signal;
|
||||
const isTimelineFlyoutOpen = useWhichFlyout() === Flyouts.timeline;
|
||||
const showTour =
|
||||
isAlert &&
|
||||
!isPreview &&
|
||||
!isTimelineFlyoutOpen &&
|
||||
!isGuidedOnboardingTourShown(SecurityStepId.alertsCases) &&
|
||||
!casesFlyoutExpanded;
|
||||
|
||||
const goToLeftPanel = useCallback(() => {
|
||||
openLeftPanel({
|
||||
id: DocumentDetailsLeftPanelKey,
|
||||
params: {
|
||||
id: eventId,
|
||||
indexName,
|
||||
scopeId,
|
||||
},
|
||||
});
|
||||
}, [eventId, indexName, scopeId, openLeftPanel]);
|
||||
|
||||
const goToOverviewTab = useCallback(() => {
|
||||
openRightPanel({
|
||||
id: DocumentDetailsRightPanelKey,
|
||||
path: { tab: 'overview' },
|
||||
params: {
|
||||
id: eventId,
|
||||
indexName,
|
||||
scopeId,
|
||||
},
|
||||
});
|
||||
}, [eventId, indexName, scopeId, openRightPanel]);
|
||||
|
||||
const tourStepContent = useMemo(
|
||||
// we append the left tour steps here to support the scenarios where the flyout left section is already expanded when starting the tour
|
||||
() => [...getRightSectionTourSteps(), ...getLeftSectionTourSteps()],
|
||||
[]
|
||||
);
|
||||
|
||||
return showTour ? (
|
||||
<FlyoutTour
|
||||
tourStepContent={tourStepContent}
|
||||
totalSteps={5}
|
||||
goToOverviewTab={goToOverviewTab}
|
||||
goToLeftPanel={goToLeftPanel}
|
||||
/>
|
||||
) : null;
|
||||
});
|
||||
|
||||
RightPanelTour.displayName = 'RightPanelTour';
|
|
@ -17,7 +17,6 @@ import type { DocumentDetailsProps } from '../shared/types';
|
|||
import { PanelNavigation } from './navigation';
|
||||
import { PanelHeader } from './header';
|
||||
import { PanelContent } from './content';
|
||||
import { RightPanelTour } from './components/tour';
|
||||
import type { RightPanelTabType } from './tabs';
|
||||
import { PanelFooter } from './footer';
|
||||
import { useFlyoutIsExpandable } from './hooks/use_flyout_is_expandable';
|
||||
|
@ -76,7 +75,6 @@ export const RightPanel: FC<Partial<DocumentDetailsProps>> = memo(({ path }) =>
|
|||
|
||||
return (
|
||||
<>
|
||||
{flyoutIsExpandable && <RightPanelTour />}
|
||||
<PanelNavigation flyoutIsExpandable={flyoutIsExpandable} />
|
||||
<PanelHeader
|
||||
tabs={tabsDisplayed}
|
||||
|
|
|
@ -8,12 +8,7 @@
|
|||
import type { ReactElement } from 'react';
|
||||
import React from 'react';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import {
|
||||
JSON_TAB_TEST_ID,
|
||||
OVERVIEW_TAB_LABEL_TEST_ID,
|
||||
OVERVIEW_TAB_TEST_ID,
|
||||
TABLE_TAB_TEST_ID,
|
||||
} from './test_ids';
|
||||
import { JSON_TAB_TEST_ID, OVERVIEW_TAB_TEST_ID, TABLE_TAB_TEST_ID } from './test_ids';
|
||||
import type { RightPanelPaths } from '.';
|
||||
import { JsonTab } from './tabs/json_tab';
|
||||
import { OverviewTab } from './tabs/overview_tab';
|
||||
|
@ -30,12 +25,10 @@ export const overviewTab: RightPanelTabType = {
|
|||
id: 'overview',
|
||||
'data-test-subj': OVERVIEW_TAB_TEST_ID,
|
||||
name: (
|
||||
<div data-test-subj={OVERVIEW_TAB_LABEL_TEST_ID}>
|
||||
<FormattedMessage
|
||||
id="xpack.securitySolution.flyout.right.header.overviewTabLabel"
|
||||
defaultMessage="Overview"
|
||||
/>
|
||||
</div>
|
||||
<FormattedMessage
|
||||
id="xpack.securitySolution.flyout.right.header.overviewTabLabel"
|
||||
defaultMessage="Overview"
|
||||
/>
|
||||
),
|
||||
content: <OverviewTab />,
|
||||
};
|
||||
|
|
|
@ -12,6 +12,5 @@ export const FLYOUT_FOOTER_TEST_ID = `${PREFIX}Footer` as const;
|
|||
export const FLYOUT_FOOTER_DEOPDOEN_BUTTON_TEST_ID =
|
||||
`${FLYOUT_FOOTER_TEST_ID}DropdownButton` as const;
|
||||
export const OVERVIEW_TAB_TEST_ID = `${PREFIX}OverviewTab` as const;
|
||||
export const OVERVIEW_TAB_LABEL_TEST_ID = `${PREFIX}OverviewTabLabel` as const;
|
||||
export const TABLE_TAB_TEST_ID = `${PREFIX}TableTab` as const;
|
||||
export const JSON_TAB_TEST_ID = `${PREFIX}JsonTab` as const;
|
||||
|
|
|
@ -1,117 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { type FlyoutTourProps, FlyoutTour } from './flyout_tour';
|
||||
import { render, waitFor, fireEvent } 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 { FLYOUT_TOUR_TEST_ID } from './test_ids';
|
||||
|
||||
jest.mock('../../../../common/lib/kibana');
|
||||
|
||||
const mockedUseKibana = mockUseKibana();
|
||||
|
||||
const { storage: storageMock } = createSecuritySolutionStorageMock();
|
||||
const mockStore = createMockStore(undefined, undefined, undefined, storageMock);
|
||||
|
||||
const content = [1, 2, 3, 4].map((i) => ({
|
||||
title: `step${i}`,
|
||||
content: <p>{`step${i}`}</p>,
|
||||
stepNumber: i,
|
||||
anchor: `step${i}`,
|
||||
}));
|
||||
|
||||
const tourProps = {
|
||||
tourStepContent: content,
|
||||
totalSteps: 4,
|
||||
};
|
||||
const goToLeftPanel = jest.fn();
|
||||
const goToOverviewTab = jest.fn();
|
||||
|
||||
const renderTour = (props: FlyoutTourProps) =>
|
||||
render(
|
||||
<TestProviders store={mockStore}>
|
||||
<FlyoutTour {...props} />
|
||||
<div data-test-subj="step1" />
|
||||
<div data-test-subj="step2" />
|
||||
<div data-test-subj="step3" />
|
||||
<div data-test-subj="step4" />
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
describe('Flyout Tour', () => {
|
||||
beforeEach(() => {
|
||||
(useKibana as jest.Mock).mockReturnValue({
|
||||
...mockedUseKibana,
|
||||
services: {
|
||||
...mockedUseKibana.services,
|
||||
storage: storageMock,
|
||||
},
|
||||
});
|
||||
|
||||
storageMock.clear();
|
||||
});
|
||||
|
||||
it('should render tour steps', async () => {
|
||||
const wrapper = renderTour(tourProps);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(wrapper.getByTestId(`${FLYOUT_TOUR_TEST_ID}-1`)).toBeVisible();
|
||||
});
|
||||
fireEvent.click(wrapper.getByText('Next'));
|
||||
await waitFor(() => {
|
||||
expect(wrapper.getByTestId(`${FLYOUT_TOUR_TEST_ID}-2`)).toBeVisible();
|
||||
});
|
||||
fireEvent.click(wrapper.getByText('Next'));
|
||||
await waitFor(() => {
|
||||
expect(wrapper.getByTestId(`${FLYOUT_TOUR_TEST_ID}-3`)).toBeVisible();
|
||||
});
|
||||
fireEvent.click(wrapper.getByText('Next'));
|
||||
await waitFor(() => {
|
||||
expect(wrapper.getByTestId(`${FLYOUT_TOUR_TEST_ID}-4`)).toBeVisible();
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(wrapper.getByText('Finish')).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
it('should call goToOverview at step 1', () => {
|
||||
renderTour({
|
||||
...tourProps,
|
||||
goToOverviewTab,
|
||||
});
|
||||
expect(goToOverviewTab).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call goToLeftPanel when after step 3', async () => {
|
||||
const wrapper = renderTour({
|
||||
...tourProps,
|
||||
goToLeftPanel,
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(wrapper.getByTestId(`${FLYOUT_TOUR_TEST_ID}-1`)).toBeVisible();
|
||||
});
|
||||
fireEvent.click(wrapper.getByText('Next'));
|
||||
await waitFor(() => {
|
||||
expect(wrapper.getByTestId(`${FLYOUT_TOUR_TEST_ID}-2`)).toBeVisible();
|
||||
});
|
||||
fireEvent.click(wrapper.getByText('Next'));
|
||||
await waitFor(() => {
|
||||
expect(wrapper.getByTestId(`${FLYOUT_TOUR_TEST_ID}-3`)).toBeVisible();
|
||||
});
|
||||
fireEvent.click(wrapper.getByText('Next'));
|
||||
|
||||
expect(goToLeftPanel).toHaveBeenCalled();
|
||||
});
|
||||
});
|
|
@ -1,160 +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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This timeline tour only valid for 8.12 release is not needed for 8.13
|
||||
*
|
||||
* */
|
||||
|
||||
import type { FC } from 'react';
|
||||
import React, { useCallback, useState, useEffect } from 'react';
|
||||
import { EuiButton, EuiButtonEmpty, EuiTourStep } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { tourConfig, type TourState } from '../utils/tour_step_config';
|
||||
import type { FlyoutTourStepsProps } from '../utils/tour_step_config';
|
||||
import { NEW_FEATURES_TOUR_STORAGE_KEYS } from '../../../../../common/constants';
|
||||
import { useKibana } from '../../../../common/lib/kibana';
|
||||
import { FLYOUT_TOUR_TEST_ID } from './test_ids';
|
||||
|
||||
export interface FlyoutTourProps {
|
||||
/**
|
||||
* Content to be displayed in each tour card
|
||||
*/
|
||||
tourStepContent: FlyoutTourStepsProps[];
|
||||
/**
|
||||
* Total number of tour steps
|
||||
*/
|
||||
totalSteps: number;
|
||||
/**
|
||||
* Callback to go to overview tab before tour
|
||||
*/
|
||||
goToOverviewTab?: () => void;
|
||||
/**
|
||||
* Callback to go to open left panel
|
||||
*/
|
||||
goToLeftPanel?: () => void;
|
||||
}
|
||||
|
||||
const MAX_POPOVER_WIDTH = 500;
|
||||
const TOUR_SUBTITLE = i18n.translate('xpack.securitySolution.flyout.tour.subtitle', {
|
||||
defaultMessage: 'A redesigned alert experience',
|
||||
});
|
||||
|
||||
/**
|
||||
* Shared component that generates tour steps based on supplied tour step content.
|
||||
* Supports tours being shown in different panels and manages state via local storage
|
||||
*/
|
||||
export const FlyoutTour: FC<FlyoutTourProps> = ({
|
||||
tourStepContent,
|
||||
totalSteps,
|
||||
goToOverviewTab,
|
||||
goToLeftPanel,
|
||||
}) => {
|
||||
const {
|
||||
services: { storage },
|
||||
} = useKibana();
|
||||
|
||||
const [tourState, setTourState] = useState<TourState>(() => {
|
||||
const restoredTourState = storage.get(NEW_FEATURES_TOUR_STORAGE_KEYS.FLYOUT);
|
||||
if (restoredTourState != null) {
|
||||
return restoredTourState;
|
||||
}
|
||||
return tourConfig;
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
storage.set(NEW_FEATURES_TOUR_STORAGE_KEYS.FLYOUT, tourState);
|
||||
if (tourState.isTourActive && tourState.currentTourStep === 1 && goToOverviewTab) {
|
||||
goToOverviewTab();
|
||||
}
|
||||
}, [storage, tourState, goToOverviewTab]);
|
||||
|
||||
const nextStep = useCallback(() => {
|
||||
setTourState((prev) => {
|
||||
if (prev.currentTourStep === 3 && goToLeftPanel) {
|
||||
goToLeftPanel();
|
||||
}
|
||||
return {
|
||||
...prev,
|
||||
currentTourStep: prev.currentTourStep + 1,
|
||||
};
|
||||
});
|
||||
}, [goToLeftPanel]);
|
||||
|
||||
const finishTour = useCallback(() => {
|
||||
setTourState((prev) => {
|
||||
return {
|
||||
...prev,
|
||||
isTourActive: false,
|
||||
};
|
||||
});
|
||||
}, []);
|
||||
|
||||
const getFooterAction = useCallback(
|
||||
(step: number) => {
|
||||
// if it's the last step, we don't want to show the next button
|
||||
return step === totalSteps ? (
|
||||
<EuiButton color="success" size="s" onClick={finishTour}>
|
||||
{i18n.translate('xpack.securitySolution.flyout.tour.finish.text', {
|
||||
defaultMessage: 'Finish',
|
||||
})}
|
||||
</EuiButton>
|
||||
) : (
|
||||
[
|
||||
<EuiButtonEmpty size="s" color="text" onClick={finishTour}>
|
||||
{i18n.translate('xpack.securitySolution.flyout.tour.exit.text', {
|
||||
defaultMessage: 'Exit',
|
||||
})}
|
||||
</EuiButtonEmpty>,
|
||||
<EuiButton color="success" size="s" onClick={nextStep}>
|
||||
{i18n.translate('xpack.securitySolution.flyout.tour.Next.text', {
|
||||
defaultMessage: 'Next',
|
||||
})}
|
||||
</EuiButton>,
|
||||
]
|
||||
);
|
||||
},
|
||||
[finishTour, nextStep, totalSteps]
|
||||
);
|
||||
|
||||
// Do not show tour if it is inactive
|
||||
if (!tourState.isTourActive) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{tourStepContent.map((steps) => {
|
||||
const stepCount = steps.stepNumber;
|
||||
if (tourState.currentTourStep !== stepCount) return null;
|
||||
const panelProps = {
|
||||
'data-test-subj': `${FLYOUT_TOUR_TEST_ID}-${stepCount}`,
|
||||
};
|
||||
|
||||
return (
|
||||
<EuiTourStep
|
||||
panelProps={panelProps}
|
||||
key={stepCount}
|
||||
step={stepCount}
|
||||
isStepOpen={tourState.isTourActive}
|
||||
maxWidth={MAX_POPOVER_WIDTH}
|
||||
stepsTotal={totalSteps}
|
||||
onFinish={finishTour}
|
||||
title={steps.title}
|
||||
content={steps.content}
|
||||
anchor={`[data-test-subj=${steps.anchor}]`}
|
||||
anchorPosition={steps.anchorPosition}
|
||||
footerAction={getFooterAction(stepCount)}
|
||||
subtitle={TOUR_SUBTITLE}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
FlyoutTour.displayName = 'FlyoutTour';
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
import { PREFIX } from '../../../shared/test_ids';
|
||||
|
||||
export const FLYOUT_TOUR_TEST_ID = `${PREFIX}Tour` as const;
|
||||
export const FLYOUT_PREVIEW_LINK_TEST_ID = `${PREFIX}PreviewLink` as const;
|
||||
|
||||
export const SESSION_VIEW_UPSELL_TEST_ID = `${PREFIX}SessionViewUpsell` as const;
|
||||
|
|
|
@ -1,199 +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 { EuiText, EuiCode, type EuiTourStepProps } from '@elastic/eui';
|
||||
import React from 'react';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { HEADER_NAVIGATION_BUTTON_TEST_ID } from '../../../shared/components/test_ids';
|
||||
import { OVERVIEW_TAB_LABEL_TEST_ID } from '../../right/test_ids';
|
||||
import { RULE_SUMMARY_BUTTON_TEST_ID } from '../../right/components/test_ids';
|
||||
import {
|
||||
INSIGHTS_TAB_PREVALENCE_BUTTON_LABEL_TEST_ID,
|
||||
INSIGHTS_TAB_ENTITIES_BUTTON_LABEL_TEST_ID,
|
||||
} from '../../left/tabs/test_ids';
|
||||
|
||||
export const FLYOUT_TOUR_CONFIG_ANCHORS = {
|
||||
OVERVIEW_TAB: OVERVIEW_TAB_LABEL_TEST_ID,
|
||||
RULE_PREVIEW: RULE_SUMMARY_BUTTON_TEST_ID,
|
||||
NAVIGATION_BUTTON: HEADER_NAVIGATION_BUTTON_TEST_ID,
|
||||
ENTITIES: INSIGHTS_TAB_ENTITIES_BUTTON_LABEL_TEST_ID,
|
||||
PREVALENCE: INSIGHTS_TAB_PREVALENCE_BUTTON_LABEL_TEST_ID,
|
||||
};
|
||||
|
||||
export interface TourState {
|
||||
/**
|
||||
* The current step number
|
||||
*/
|
||||
currentTourStep: number;
|
||||
/**
|
||||
* True if tour is active (user has not completed or exited the tour)
|
||||
*/
|
||||
isTourActive: boolean;
|
||||
}
|
||||
|
||||
export const tourConfig: TourState = {
|
||||
currentTourStep: 1,
|
||||
isTourActive: true,
|
||||
};
|
||||
|
||||
export interface FlyoutTourStepsProps {
|
||||
/**
|
||||
* Title of the tour step
|
||||
*/
|
||||
title: string;
|
||||
/**
|
||||
* Content of tour step
|
||||
*/
|
||||
content: JSX.Element;
|
||||
/**
|
||||
* Step number
|
||||
*/
|
||||
stepNumber: number;
|
||||
/**
|
||||
* Data test subject of the anchor component
|
||||
*/
|
||||
anchor: string;
|
||||
/**
|
||||
* Optional anchor position prop
|
||||
*/
|
||||
anchorPosition?: EuiTourStepProps['anchorPosition'];
|
||||
}
|
||||
|
||||
export const getRightSectionTourSteps = (): FlyoutTourStepsProps[] => {
|
||||
const rightSectionTourSteps: FlyoutTourStepsProps[] = [
|
||||
{
|
||||
title: i18n.translate('xpack.securitySolution.flyout.tour.overview.title', {
|
||||
defaultMessage: 'More ways to understand your alerts',
|
||||
}),
|
||||
content: (
|
||||
<EuiText>
|
||||
<FormattedMessage
|
||||
id="xpack.securitySolution.flyout.tour.overview.description"
|
||||
defaultMessage="Explore new insights in the {entities} and {prevalence} sections."
|
||||
values={{
|
||||
entities: (
|
||||
<EuiCode>
|
||||
{i18n.translate('xpack.securitySolution.flyout.tour.overview.entities.text', {
|
||||
defaultMessage: 'Entities',
|
||||
})}
|
||||
</EuiCode>
|
||||
),
|
||||
prevalence: (
|
||||
<EuiCode>
|
||||
{i18n.translate('xpack.securitySolution.flyout.tour.overview.prevalence.text', {
|
||||
defaultMessage: 'Prevalence',
|
||||
})}
|
||||
</EuiCode>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</EuiText>
|
||||
),
|
||||
stepNumber: 1,
|
||||
anchor: FLYOUT_TOUR_CONFIG_ANCHORS.OVERVIEW_TAB,
|
||||
anchorPosition: 'downCenter',
|
||||
},
|
||||
{
|
||||
title: i18n.translate('xpack.securitySolution.flyout.tour.preview.title', {
|
||||
defaultMessage: 'A quick way to access rule details',
|
||||
}),
|
||||
content: (
|
||||
<EuiText>
|
||||
<FormattedMessage
|
||||
id="xpack.securitySolution.flyout.tour.rulePreview.description"
|
||||
defaultMessage="Click {rulePreview} to learn more about the rule that generated the alert."
|
||||
values={{
|
||||
rulePreview: (
|
||||
<EuiCode>
|
||||
{i18n.translate('xpack.securitySolution.flyout.tour.rulePreview.text', {
|
||||
defaultMessage: 'Show rule summary',
|
||||
})}
|
||||
</EuiCode>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</EuiText>
|
||||
),
|
||||
stepNumber: 2,
|
||||
anchor: FLYOUT_TOUR_CONFIG_ANCHORS.RULE_PREVIEW,
|
||||
anchorPosition: 'rightUp',
|
||||
},
|
||||
{
|
||||
title: i18n.translate('xpack.securitySolution.flyout.tour.expandDetails.title', {
|
||||
defaultMessage: 'An expanded view of important alert details',
|
||||
}),
|
||||
content: (
|
||||
<EuiText>
|
||||
<FormattedMessage
|
||||
id="xpack.securitySolution.flyout.tour.expandDetails.description"
|
||||
defaultMessage="Click the linked text to open and close the flyout's left panel. The left panel is a detailed view of sections in the right panel."
|
||||
/>
|
||||
</EuiText>
|
||||
),
|
||||
stepNumber: 3,
|
||||
anchor: FLYOUT_TOUR_CONFIG_ANCHORS.NAVIGATION_BUTTON,
|
||||
anchorPosition: 'downCenter',
|
||||
},
|
||||
];
|
||||
return rightSectionTourSteps;
|
||||
};
|
||||
|
||||
export const getLeftSectionTourSteps = (): FlyoutTourStepsProps[] => {
|
||||
return [
|
||||
{
|
||||
title: i18n.translate('xpack.securitySolution.flyout.tour.entities.title', {
|
||||
defaultMessage: 'New host and user insights are available',
|
||||
}),
|
||||
content: (
|
||||
<EuiText>
|
||||
<FormattedMessage
|
||||
id="xpack.securitySolution.flyout.tour.entities.description"
|
||||
defaultMessage="Check out the expanded {entities} view to learn more about hosts and users that are related to the alert."
|
||||
values={{
|
||||
entities: (
|
||||
<EuiCode>
|
||||
{i18n.translate('xpack.securitySolution.flyout.tour.entities.text', {
|
||||
defaultMessage: 'Entities',
|
||||
})}
|
||||
</EuiCode>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</EuiText>
|
||||
),
|
||||
stepNumber: 4,
|
||||
anchor: FLYOUT_TOUR_CONFIG_ANCHORS.ENTITIES,
|
||||
anchorPosition: 'rightUp',
|
||||
},
|
||||
{
|
||||
title: i18n.translate('xpack.securitySolution.flyout.tour.prevalence.title', {
|
||||
defaultMessage: 'New host and user insights are available',
|
||||
}),
|
||||
content: (
|
||||
<EuiText>
|
||||
<FormattedMessage
|
||||
id="xpack.securitySolution.flyout.tour.prevalence.description"
|
||||
defaultMessage="Check out the expanded {prevalence} view to learn how the alert is related to other alerts, events, and entities."
|
||||
values={{
|
||||
prevalence: (
|
||||
<EuiCode>
|
||||
{i18n.translate('xpack.securitySolution.flyout.tour.prevalence.text', {
|
||||
defaultMessage: 'Prevalence',
|
||||
})}
|
||||
</EuiCode>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</EuiText>
|
||||
),
|
||||
stepNumber: 5,
|
||||
anchor: FLYOUT_TOUR_CONFIG_ANCHORS.PREVALENCE,
|
||||
anchorPosition: 'rightUp',
|
||||
},
|
||||
];
|
||||
};
|
|
@ -22,7 +22,6 @@ import {
|
|||
HEADER_ACTIONS_TEST_ID,
|
||||
COLLAPSE_DETAILS_BUTTON_TEST_ID,
|
||||
EXPAND_DETAILS_BUTTON_TEST_ID,
|
||||
HEADER_NAVIGATION_BUTTON_TEST_ID,
|
||||
} from './test_ids';
|
||||
|
||||
export interface FlyoutNavigationProps {
|
||||
|
@ -116,7 +115,7 @@ export const FlyoutNavigation: FC<FlyoutNavigationProps> = memo(
|
|||
height: ${euiTheme.size.xxl};
|
||||
`}
|
||||
>
|
||||
<EuiFlexItem grow={false} data-test-subj={HEADER_NAVIGATION_BUTTON_TEST_ID}>
|
||||
<EuiFlexItem grow={false}>
|
||||
{flyoutIsExpandable && expandDetails && (isExpanded ? collapseButton : expandButton)}
|
||||
</EuiFlexItem>
|
||||
{actions && (
|
||||
|
|
|
@ -27,7 +27,6 @@ export const EXPANDABLE_PANEL_CONTENT_TEST_ID = (dataTestSubj: string) => `${dat
|
|||
/* Header Navigation */
|
||||
|
||||
const FLYOUT_NAVIGATION_TEST_ID = `${PREFIX}Navigation` as const;
|
||||
export const HEADER_NAVIGATION_BUTTON_TEST_ID = `${PREFIX}NavigationButton` as const;
|
||||
export const EXPAND_DETAILS_BUTTON_TEST_ID =
|
||||
`${FLYOUT_NAVIGATION_TEST_ID}ExpandDetailButton` as const;
|
||||
export const COLLAPSE_DETAILS_BUTTON_TEST_ID =
|
||||
|
|
|
@ -38809,25 +38809,6 @@
|
|||
"xpack.securitySolution.flyout.shared.errorTitle": "Impossible d'afficher {title}.",
|
||||
"xpack.securitySolution.flyout.shared.ExpandablePanelButtonIconAriaLabel": "Activer/Désactiver le panneau extensible",
|
||||
"xpack.securitySolution.flyout.shared.expandablePanelLoadingAriaLabel": "panneau extensible",
|
||||
"xpack.securitySolution.flyout.tour.entities.description": "Consultez la vue {entities} étendue pour en savoir plus sur les hôtes et les utilisateurs liés à l'alerte.",
|
||||
"xpack.securitySolution.flyout.tour.entities.text": "Entités",
|
||||
"xpack.securitySolution.flyout.tour.entities.title": "De nouvelles informations sur les hôtes et les utilisateurs sont disponibles",
|
||||
"xpack.securitySolution.flyout.tour.exit.text": "Quitter",
|
||||
"xpack.securitySolution.flyout.tour.expandDetails.description": "Cliquez sur le texte lié pour ouvrir et fermer le panneau gauche du menu volant. Le panneau de gauche est une vue détaillée des sections du panneau de droite.",
|
||||
"xpack.securitySolution.flyout.tour.expandDetails.title": "Un affichage élargi des détails importants de l'alerte",
|
||||
"xpack.securitySolution.flyout.tour.finish.text": "Terminer",
|
||||
"xpack.securitySolution.flyout.tour.Next.text": "Suivant",
|
||||
"xpack.securitySolution.flyout.tour.overview.description": "Explorez de nouvelles informations exploitables dans les sections {entities} et {prevalence}.",
|
||||
"xpack.securitySolution.flyout.tour.overview.entities.text": "Entités",
|
||||
"xpack.securitySolution.flyout.tour.overview.prevalence.text": "Prévalence",
|
||||
"xpack.securitySolution.flyout.tour.overview.title": "Plus de moyens pour comprendre vos alertes",
|
||||
"xpack.securitySolution.flyout.tour.prevalence.description": "Consultez la vue {prevalence} étendue pour savoir comment l'alerte est liée à d'autres alertes, événements et entités.",
|
||||
"xpack.securitySolution.flyout.tour.prevalence.text": "Prévalence",
|
||||
"xpack.securitySolution.flyout.tour.prevalence.title": "De nouvelles informations sur les hôtes et les utilisateurs sont disponibles",
|
||||
"xpack.securitySolution.flyout.tour.preview.title": "Un moyen rapide d'accéder aux détails des règles",
|
||||
"xpack.securitySolution.flyout.tour.rulePreview.description": "Cliquez sur {rulePreview} pour en savoir plus sur la règle qui a généré l'alerte.",
|
||||
"xpack.securitySolution.flyout.tour.rulePreview.text": "Afficher le résumé de la règle",
|
||||
"xpack.securitySolution.flyout.tour.subtitle": "Une expérience d'alerte repensée",
|
||||
"xpack.securitySolution.flyout.user.preview.viewDetailsLabel": "Ouvrez le menu volant des détails de l'utilisateur",
|
||||
"xpack.securitySolution.footer.autoRefreshActiveDescription": "Actualisation automatique active",
|
||||
"xpack.securitySolution.footer.autoRefreshActiveTooltip": "Lorsque l'actualisation automatique est activée, la chronologie vous montrera les {numberOfItems} derniers événements correspondant à votre recherche.",
|
||||
|
|
|
@ -38552,25 +38552,6 @@
|
|||
"xpack.securitySolution.flyout.shared.errorTitle": "{title}を表示できません。",
|
||||
"xpack.securitySolution.flyout.shared.ExpandablePanelButtonIconAriaLabel": "展開可能なパネルトグル",
|
||||
"xpack.securitySolution.flyout.shared.expandablePanelLoadingAriaLabel": "展開可能なパネル",
|
||||
"xpack.securitySolution.flyout.tour.entities.description": "アラートに関連付けられたホストとユーザーの詳細については、展開された{entities}ビューを確認してください。",
|
||||
"xpack.securitySolution.flyout.tour.entities.text": "エンティティ",
|
||||
"xpack.securitySolution.flyout.tour.entities.title": "新しいホストとユーザーのインサイトがあります",
|
||||
"xpack.securitySolution.flyout.tour.exit.text": "終了",
|
||||
"xpack.securitySolution.flyout.tour.expandDetails.description": "リンクされたテキストをクリックすると、フライアウトの左パネルが開いて閉じます。左パネルは、右パネルのセクションの詳細表示です。",
|
||||
"xpack.securitySolution.flyout.tour.expandDetails.title": "重要なアラート詳細の展開表示",
|
||||
"xpack.securitySolution.flyout.tour.finish.text": "終了",
|
||||
"xpack.securitySolution.flyout.tour.Next.text": "次へ",
|
||||
"xpack.securitySolution.flyout.tour.overview.description": "{entities}および{prevalence}セクションで新しいインサイトを探索してください。",
|
||||
"xpack.securitySolution.flyout.tour.overview.entities.text": "エンティティ",
|
||||
"xpack.securitySolution.flyout.tour.overview.prevalence.text": "発生率",
|
||||
"xpack.securitySolution.flyout.tour.overview.title": "アラートを理解するためのその他の方法",
|
||||
"xpack.securitySolution.flyout.tour.prevalence.description": "アラートが他のアラート、イベント、エンティティに関連付けられる詳細な方法については、展開された{prevalence}ビューを確認してください。",
|
||||
"xpack.securitySolution.flyout.tour.prevalence.text": "発生率",
|
||||
"xpack.securitySolution.flyout.tour.prevalence.title": "新しいホストとユーザーのインサイトがあります",
|
||||
"xpack.securitySolution.flyout.tour.preview.title": "ルール詳細をすばやく表示する方法",
|
||||
"xpack.securitySolution.flyout.tour.rulePreview.description": "アラートを生成したルールの詳細については、{rulePreview}をクリックしてください。",
|
||||
"xpack.securitySolution.flyout.tour.rulePreview.text": "ルール概要を表示",
|
||||
"xpack.securitySolution.flyout.tour.subtitle": "再設計されたアラート体験",
|
||||
"xpack.securitySolution.flyout.user.preview.viewDetailsLabel": "ユーザー詳細フライアウトを開く",
|
||||
"xpack.securitySolution.footer.autoRefreshActiveDescription": "自動更新アクション",
|
||||
"xpack.securitySolution.footer.autoRefreshActiveTooltip": "自動更新が有効な間、タイムラインはクエリーに一致する最新の {numberOfItems} 件のイベントを表示します。",
|
||||
|
|
|
@ -6846,7 +6846,6 @@
|
|||
"securitySolutionPackages.features.featureRegistry.subFeatures.trustedApplications": "受信任的应用程序",
|
||||
"securitySolutionPackages.features.featureRegistry.subFeatures.trustedApplications.description": "帮助减少与其他软件(通常指其他防病毒或终端安全应用程序)的冲突。",
|
||||
"securitySolutionPackages.features.featureRegistry.subFeatures.trustedApplications.privilegesTooltip": "访问受信任的应用程序需要所有工作区。",
|
||||
"sgcuritySolutionPackages.flyout.shared.errorDescription": "显示 {message} 时出现错误。",
|
||||
"securitySolutionPackages.markdown.insight.upsell": "升级到{requiredLicense}以利用调查指南中的洞见",
|
||||
"securitySolutionPackages.markdown.investigationGuideInteractions.upsell": "升级到 {requiredLicense} 以利用调查指南交互",
|
||||
"securitySolutionPackages.navigation.landingLinks": "安全视图",
|
||||
|
@ -38598,25 +38597,6 @@
|
|||
"xpack.securitySolution.flyout.shared.errorTitle": "无法显示 {title}。",
|
||||
"xpack.securitySolution.flyout.shared.ExpandablePanelButtonIconAriaLabel": "可展开面板切换按钮",
|
||||
"xpack.securitySolution.flyout.shared.expandablePanelLoadingAriaLabel": "可展开面板",
|
||||
"xpack.securitySolution.flyout.tour.entities.description": "请查阅展开的 {entities} 视图以了解与该告警有关的主机和用户的更多信息。",
|
||||
"xpack.securitySolution.flyout.tour.entities.text": "实体",
|
||||
"xpack.securitySolution.flyout.tour.entities.title": "有新主机和用户洞见可用",
|
||||
"xpack.securitySolution.flyout.tour.exit.text": "退出",
|
||||
"xpack.securitySolution.flyout.tour.expandDetails.description": "单击链接文本可打开和关闭浮出控件的左面板。左面板提供了右面板中的各个部分的详细视图。",
|
||||
"xpack.securitySolution.flyout.tour.expandDetails.title": "重要告警详情的扩展视图",
|
||||
"xpack.securitySolution.flyout.tour.finish.text": "完成",
|
||||
"xpack.securitySolution.flyout.tour.Next.text": "下一步",
|
||||
"xpack.securitySolution.flyout.tour.overview.description": "浏览 {entities} 和 {prevalence} 部分中的新洞见。",
|
||||
"xpack.securitySolution.flyout.tour.overview.entities.text": "实体",
|
||||
"xpack.securitySolution.flyout.tour.overview.prevalence.text": "普及率",
|
||||
"xpack.securitySolution.flyout.tour.overview.title": "了解告警的更多方式",
|
||||
"xpack.securitySolution.flyout.tour.prevalence.description": "请查阅展开的 {prevalence} 视图以了解该告警与其他告警、事件和实体的关系。",
|
||||
"xpack.securitySolution.flyout.tour.prevalence.text": "普及率",
|
||||
"xpack.securitySolution.flyout.tour.prevalence.title": "有新主机和用户洞见可用",
|
||||
"xpack.securitySolution.flyout.tour.preview.title": "一种快速访问规则详情的方法",
|
||||
"xpack.securitySolution.flyout.tour.rulePreview.description": "单击 {rulePreview} 以了解与生成该告警的规则有关的详情。",
|
||||
"xpack.securitySolution.flyout.tour.rulePreview.text": "显示规则摘要",
|
||||
"xpack.securitySolution.flyout.tour.subtitle": "经过重新设计的告警体验",
|
||||
"xpack.securitySolution.flyout.user.preview.viewDetailsLabel": "打开用户详情浮出控件",
|
||||
"xpack.securitySolution.footer.autoRefreshActiveDescription": "自动刷新已启用",
|
||||
"xpack.securitySolution.footer.autoRefreshActiveTooltip": "自动刷新已启用时,时间线将显示匹配查询的最近 {numberOfItems} 个事件。",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue