diff --git a/x-pack/plugins/security_solution/public/common/components/guided_onboarding_tour/README.md b/x-pack/plugins/security_solution/public/common/components/guided_onboarding_tour/README.md
index eb30e20f1318e..483d9c30cb82c 100644
--- a/x-pack/plugins/security_solution/public/common/components/guided_onboarding_tour/README.md
+++ b/x-pack/plugins/security_solution/public/common/components/guided_onboarding_tour/README.md
@@ -105,7 +105,7 @@ It was important that the `EuiTourStep` **anchor** is in the DOM when the tour s
```
createCaseFlyout.open({
attachments: caseAttachments,
- ...(isTourShown(SecurityStepId.alertsCases) && activeStep === 4
+ ...(isTourShown(SecurityStepId.alertsCases) && activeStep === AlertsCasesTourSteps.addAlertToCase
? {
headerContent: (
// isTourAnchor=true no matter what in order to
@@ -132,7 +132,7 @@ It was important that the `EuiTourStep` **anchor** is in the DOM when the tour s
So we utilize the `useTourContext` to do the following check and increment the step in `handleAddToNewCaseClick`:
```
- if (isTourShown(SecurityStepId.alertsCases) && activeStep === 4) {
+ if (isTourShown(SecurityStepId.alertsCases) && activeStep === AlertsCasesTourSteps.addAlertToCase) {
incrementStep(SecurityStepId.alertsCases);
}
```
diff --git a/x-pack/plugins/security_solution/public/common/components/guided_onboarding_tour/tour.tsx b/x-pack/plugins/security_solution/public/common/components/guided_onboarding_tour/tour.tsx
index 43f6ca15b33cb..80cadec5d04be 100644
--- a/x-pack/plugins/security_solution/public/common/components/guided_onboarding_tour/tour.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/guided_onboarding_tour/tour.tsx
@@ -19,7 +19,7 @@ import { securityTourConfig, SecurityStepId } from './tour_config';
export interface TourContextValue {
activeStep: number;
endTourStep: (stepId: SecurityStepId) => void;
- incrementStep: (stepId: SecurityStepId, step?: number) => void;
+ incrementStep: (stepId: SecurityStepId) => void;
isTourShown: (stepId: SecurityStepId) => boolean;
}
diff --git a/x-pack/plugins/security_solution/public/common/components/guided_onboarding_tour/tour_config.ts b/x-pack/plugins/security_solution/public/common/components/guided_onboarding_tour/tour_config.ts
index f7ed05be4c418..0a00c25417f83 100644
--- a/x-pack/plugins/security_solution/public/common/components/guided_onboarding_tour/tour_config.ts
+++ b/x-pack/plugins/security_solution/public/common/components/guided_onboarding_tour/tour_config.ts
@@ -14,6 +14,15 @@ export const enum SecurityStepId {
alertsCases = 'alertsCases',
}
+export const enum AlertsCasesTourSteps {
+ none = 0,
+ pointToAlertName = 1,
+ expandEvent = 2,
+ reviewAlertDetailsFlyout = 3,
+ addAlertToCase = 4,
+ createCase = 5,
+}
+
export type StepConfig = Pick<
EuiTourStepProps,
'step' | 'content' | 'anchorPosition' | 'title' | 'initialFocus' | 'anchor'
@@ -40,7 +49,7 @@ export const getTourAnchor = (step: number, stepId: SecurityStepId) =>
const alertsCasesConfig: StepConfig[] = [
{
...defaultConfig,
- step: 1,
+ step: AlertsCasesTourSteps.pointToAlertName,
title: i18n.translate('xpack.securitySolution.guided_onboarding.tour.ruleNameStep.tourTitle', {
defaultMessage: 'Test alert for practice',
}),
@@ -52,12 +61,12 @@ const alertsCasesConfig: StepConfig[] = [
}
),
anchorPosition: 'downCenter',
- dataTestSubj: getTourAnchor(1, SecurityStepId.alertsCases),
+ dataTestSubj: getTourAnchor(AlertsCasesTourSteps.pointToAlertName, SecurityStepId.alertsCases),
initialFocus: `button[tour-step="nextButton"]`,
},
{
...defaultConfig,
- step: 2,
+ step: AlertsCasesTourSteps.expandEvent,
title: i18n.translate('xpack.securitySolution.guided_onboarding.tour.openFlyout.tourTitle', {
defaultMessage: 'Review the alert details',
}),
@@ -69,12 +78,12 @@ const alertsCasesConfig: StepConfig[] = [
}
),
anchorPosition: 'rightUp',
- dataTestSubj: getTourAnchor(2, SecurityStepId.alertsCases),
+ dataTestSubj: getTourAnchor(AlertsCasesTourSteps.expandEvent, SecurityStepId.alertsCases),
hideNextButton: true,
},
{
...defaultConfig,
- step: 3,
+ step: AlertsCasesTourSteps.reviewAlertDetailsFlyout,
title: i18n.translate(
'xpack.securitySolution.guided_onboarding.tour.flyoutOverview.tourTitle',
{
@@ -89,13 +98,19 @@ const alertsCasesConfig: StepConfig[] = [
}
),
// needs to use anchor to properly place tour step
- anchor: `[tour-step="${getTourAnchor(3, SecurityStepId.alertsCases)}"] .euiTabs`,
+ anchor: `[tour-step="${getTourAnchor(
+ AlertsCasesTourSteps.reviewAlertDetailsFlyout,
+ SecurityStepId.alertsCases
+ )}"] .euiTabs`,
anchorPosition: 'leftUp',
- dataTestSubj: getTourAnchor(3, SecurityStepId.alertsCases),
+ dataTestSubj: getTourAnchor(
+ AlertsCasesTourSteps.reviewAlertDetailsFlyout,
+ SecurityStepId.alertsCases
+ ),
},
{
...defaultConfig,
- step: 4,
+ step: AlertsCasesTourSteps.addAlertToCase,
title: i18n.translate('xpack.securitySolution.guided_onboarding.tour.addToCase.tourTitle', {
defaultMessage: 'Create a case',
}),
@@ -103,12 +118,12 @@ const alertsCasesConfig: StepConfig[] = [
defaultMessage: 'From the Take action menu, add the alert to a new case.',
}),
anchorPosition: 'upRight',
- dataTestSubj: getTourAnchor(4, SecurityStepId.alertsCases),
+ dataTestSubj: getTourAnchor(AlertsCasesTourSteps.addAlertToCase, SecurityStepId.alertsCases),
hideNextButton: true,
},
{
...defaultConfig,
- step: 5,
+ step: AlertsCasesTourSteps.createCase,
title: i18n.translate('xpack.securitySolution.guided_onboarding.tour.createCase.tourTitle', {
defaultMessage: `Add details`,
}),
@@ -120,7 +135,7 @@ const alertsCasesConfig: StepConfig[] = [
),
anchor: `[data-test-subj="create-case-flyout"]`,
anchorPosition: 'leftUp',
- dataTestSubj: getTourAnchor(5, SecurityStepId.alertsCases),
+ dataTestSubj: getTourAnchor(AlertsCasesTourSteps.createCase, SecurityStepId.alertsCases),
hideNextButton: true,
},
];
diff --git a/x-pack/plugins/security_solution/public/common/components/guided_onboarding_tour/tour_step.test.tsx b/x-pack/plugins/security_solution/public/common/components/guided_onboarding_tour/tour_step.test.tsx
index 04f2cfd6a4311..90f8b6de7c2f8 100644
--- a/x-pack/plugins/security_solution/public/common/components/guided_onboarding_tour/tour_step.test.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/guided_onboarding_tour/tour_step.test.tsx
@@ -9,6 +9,12 @@ import { render } from '@testing-library/react';
import { GuidedOnboardingTourStep, SecurityTourStep } from './tour_step';
import { SecurityStepId } from './tour_config';
import { useTourContext } from './tour';
+import { mockGlobalState, SUB_PLUGINS_REDUCER, TestProviders } from '../../mock';
+import { TimelineId } from '../../../../common/types';
+import { createStore } from '../../store';
+import { tGridReducer } from '@kbn/timelines-plugin/public';
+import { kibanaObservable } from '@kbn/timelines-plugin/public/mock';
+import { createSecuritySolutionStorageMock } from '@kbn/timelines-plugin/public/mock/mock_local_storage';
jest.mock('./tour');
const mockTourStep = jest
@@ -43,7 +49,8 @@ describe('GuidedOnboardingTourStep', () => {
});
it('renders as a tour step', () => {
const { getByTestId } = render(
- {mockChildren}
+ {mockChildren},
+ { wrapper: TestProviders }
);
const tourStep = getByTestId('tourStepMock');
const header = getByTestId('h1');
@@ -54,7 +61,8 @@ describe('GuidedOnboardingTourStep', () => {
const { getByTestId, queryByTestId } = render(
{mockChildren}
-
+ ,
+ { wrapper: TestProviders }
);
const tourStep = queryByTestId('tourStepMock');
const header = getByTestId('h1');
@@ -83,7 +91,8 @@ describe('SecurityTourStep', () => {
render(
{mockChildren}
-
+ ,
+ { wrapper: TestProviders }
);
expect(mockTourStep).not.toHaveBeenCalled();
});
@@ -92,7 +101,8 @@ describe('SecurityTourStep', () => {
render(
{mockChildren}
-
+ ,
+ { wrapper: TestProviders }
);
expect(mockTourStep).not.toHaveBeenCalled();
});
@@ -103,12 +113,16 @@ describe('SecurityTourStep', () => {
incrementStep: jest.fn(),
isTourShown: () => false,
});
- render({mockChildren});
+ render({mockChildren}, {
+ wrapper: TestProviders,
+ });
expect(mockTourStep).not.toHaveBeenCalled();
});
it('renders tour step with correct number of steppers', () => {
- render({mockChildren});
+ render({mockChildren}, {
+ wrapper: TestProviders,
+ });
const mockCall = { ...mockTourStep.mock.calls[0][0] };
expect(mockCall.step).toEqual(1);
expect(mockCall.stepsTotal).toEqual(5);
@@ -118,7 +132,8 @@ describe('SecurityTourStep', () => {
render(
{mockChildren}
-
+ ,
+ { wrapper: TestProviders }
);
const mockCall = { ...mockTourStep.mock.calls[0][0] };
expect(mockCall.step).toEqual(5);
@@ -134,7 +149,8 @@ describe('SecurityTourStep', () => {
render(
{mockChildren}
-
+ ,
+ { wrapper: TestProviders }
);
const mockCall = { ...mockTourStep.mock.calls[0][0] };
expect(mockCall.footerAction).toMatchInlineSnapshot(`
@@ -163,7 +179,8 @@ describe('SecurityTourStep', () => {
const { container } = render(
{mockChildren}
-
+ ,
+ { wrapper: TestProviders }
);
const selectParent = container.querySelector(
`[data-test-subj="tourStepMock"] [data-test-subj="h1"]`
@@ -184,7 +201,8 @@ describe('SecurityTourStep', () => {
const { container } = render(
{mockChildren}
-
+ ,
+ { wrapper: TestProviders }
);
const selectParent = container.querySelector(
`[data-test-subj="tourStepMock"] [data-test-subj="h1"]`
@@ -197,13 +215,17 @@ describe('SecurityTourStep', () => {
});
it('if a tour step does not have children and has anchor, only render tour step', () => {
- const { getByTestId } = render();
+ const { getByTestId } = render(
+ ,
+ { wrapper: TestProviders }
+ );
expect(getByTestId('tourStepMock')).toBeInTheDocument();
});
it('if a tour step does not have children and does not have anchor, render nothing', () => {
const { queryByTestId } = render(
-
+ ,
+ { wrapper: TestProviders }
);
expect(queryByTestId('tourStepMock')).not.toBeInTheDocument();
});
@@ -217,9 +239,40 @@ describe('SecurityTourStep', () => {
render(
{mockChildren}
-
+ ,
+ { wrapper: TestProviders }
);
const mockCall = { ...mockTourStep.mock.calls[0][0] };
expect(mockCall.footerAction).toMatchInlineSnapshot(``);
});
+
+ it('does not render step if timeline is open', () => {
+ const mockstate = {
+ ...mockGlobalState,
+ timeline: {
+ ...mockGlobalState.timeline,
+ timelineById: {
+ [TimelineId.active]: {
+ ...mockGlobalState.timeline.timelineById.test,
+ show: true,
+ },
+ },
+ },
+ };
+ const { storage } = createSecuritySolutionStorageMock();
+ const mockStore = createStore(
+ mockstate,
+ SUB_PLUGINS_REDUCER,
+ { dataTable: tGridReducer },
+ kibanaObservable,
+ storage
+ );
+
+ render(
+
+ {mockChildren}
+
+ );
+ expect(mockTourStep).not.toHaveBeenCalled();
+ });
});
diff --git a/x-pack/plugins/security_solution/public/common/components/guided_onboarding_tour/tour_step.tsx b/x-pack/plugins/security_solution/public/common/components/guided_onboarding_tour/tour_step.tsx
index ef07c5ce44a42..b7ade00021bad 100644
--- a/x-pack/plugins/security_solution/public/common/components/guided_onboarding_tour/tour_step.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/guided_onboarding_tour/tour_step.tsx
@@ -11,26 +11,54 @@ import type { EuiTourStepProps } from '@elastic/eui';
import { EuiButton, EuiImage, EuiSpacer, EuiText, EuiTourStep } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
+import styled from 'styled-components';
+import { useShallowEqualSelector } from '../../hooks/use_selector';
+import { TimelineId } from '../../../../common/types';
+import { timelineDefaults } from '../../../timelines/store/timeline/defaults';
+import { timelineSelectors } from '../../../timelines/store/timeline';
import { useTourContext } from './tour';
-import { securityTourConfig, SecurityStepId } from './tour_config';
+import { AlertsCasesTourSteps, SecurityStepId, securityTourConfig } from './tour_config';
+
interface SecurityTourStep {
children?: React.ReactElement;
step: number;
stepId: SecurityStepId;
}
+const isStepExternallyMounted = (stepId: SecurityStepId, step: number) =>
+ step === AlertsCasesTourSteps.createCase && stepId === SecurityStepId.alertsCases;
+
+const StyledTourStep = styled(EuiTourStep)`
+ &.euiPopover__panel[data-popover-open] {
+ z-index: ${({ step, stepId }) =>
+ isStepExternallyMounted(stepId, step) ? '9000 !important' : '1000 !important'};
+ }
+`;
+
export const SecurityTourStep = ({ children, step, stepId }: SecurityTourStep) => {
const { activeStep, incrementStep, isTourShown } = useTourContext();
const tourStep = useMemo(
() => securityTourConfig[stepId].find((config) => config.step === step),
[step, stepId]
);
+
+ const getTimeline = useMemo(() => timelineSelectors.getTimelineByIdSelector(), []);
+ const showTimeline = useShallowEqualSelector(
+ (state) => (getTimeline(state, TimelineId.active) ?? timelineDefaults).show
+ );
+
const onClick = useCallback(() => incrementStep(stepId), [incrementStep, stepId]);
- // step === 5 && stepId === SecurityStepId.alertsCases is in Cases app and out of context.
+
+ // step === AlertsCasesTourSteps.createCase && stepId === SecurityStepId.alertsCases is in Cases app and out of context.
// If we mount this step, we know we need to render it
// we are also managing the context on the siem end in the background
- const overrideContext = step === 5 && stepId === SecurityStepId.alertsCases;
- if (tourStep == null || ((step !== activeStep || !isTourShown(stepId)) && !overrideContext)) {
+ const overrideContext = isStepExternallyMounted(stepId, step);
+
+ if (
+ tourStep == null ||
+ ((step !== activeStep || !isTourShown(stepId)) && !overrideContext) ||
+ showTimeline
+ ) {
return children ? children : null;
}
@@ -89,11 +117,13 @@ export const SecurityTourStep = ({ children, step, stepId }: SecurityTourStep) =
// see type EuiTourStepAnchorProps
return anchor != null ? (
<>
-
+
<>{children}>
>
) : children != null ? (
- {children}
+
+ {children}
+
) : null;
};
diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_add_to_case_actions.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_add_to_case_actions.tsx
index 70455fa342ab5..9f6fd3dd56104 100644
--- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_add_to_case_actions.tsx
+++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_add_to_case_actions.tsx
@@ -10,7 +10,10 @@ import { EuiContextMenuItem } from '@elastic/eui';
import { CommentType } from '@kbn/cases-plugin/common';
import type { CaseAttachmentsWithoutOwner } from '@kbn/cases-plugin/public';
import { GuidedOnboardingTourStep } from '../../../../common/components/guided_onboarding_tour/tour_step';
-import { SecurityStepId } from '../../../../common/components/guided_onboarding_tour/tour_config';
+import {
+ AlertsCasesTourSteps,
+ SecurityStepId,
+} from '../../../../common/components/guided_onboarding_tour/tour_config';
import { useTourContext } from '../../../../common/components/guided_onboarding_tour';
import { useGetUserCasesPermissions, useKibana } from '../../../../common/lib/kibana';
import type { TimelineNonEcsData } from '../../../../../common/search_strategy';
@@ -80,7 +83,11 @@ export const useAddToCaseActions = ({
onMenuItemClick();
createCaseFlyout.open({
attachments: caseAttachments,
- ...(isTourShown(SecurityStepId.alertsCases) && activeStep === 4
+ // activeStep will be 4 on first render because not yet incremented
+ // if the user closes the flyout without completing the form and comes back, we will be at step 5
+ ...(isTourShown(SecurityStepId.alertsCases) &&
+ (activeStep === AlertsCasesTourSteps.addAlertToCase ||
+ activeStep === AlertsCasesTourSteps.createCase)
? {
headerContent: (
// isTourAnchor=true no matter what in order to
@@ -90,7 +97,10 @@ export const useAddToCaseActions = ({
}
: {}),
});
- if (isTourShown(SecurityStepId.alertsCases) && activeStep === 4) {
+ if (
+ isTourShown(SecurityStepId.alertsCases) &&
+ activeStep === AlertsCasesTourSteps.addAlertToCase
+ ) {
incrementStep(SecurityStepId.alertsCases);
}
}, [onMenuItemClick, createCaseFlyout, caseAttachments, isTourShown, activeStep, incrementStep]);
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/actions/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/actions/index.test.tsx
index 9e8ea89d9175b..e34227f0bfe8f 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/actions/index.test.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/actions/index.test.tsx
@@ -14,7 +14,14 @@ import { useIsExperimentalFeatureEnabled } from '../../../../../common/hooks/use
import { mockCasesContract } from '@kbn/cases-plugin/public/mocks';
import { useShallowEqualSelector } from '../../../../../common/hooks/use_selector';
import { licenseService } from '../../../../../common/hooks/use_license';
-
+import { useTourContext } from '../../../../../common/components/guided_onboarding_tour';
+import {
+ GuidedOnboardingTourStep,
+ SecurityTourStep,
+} from '../../../../../common/components/guided_onboarding_tour/tour_step';
+import { SecurityStepId } from '../../../../../common/components/guided_onboarding_tour/tour_config';
+
+jest.mock('../../../../../common/components/guided_onboarding_tour');
jest.mock('../../../../../detections/components/user_info', () => ({
useUserData: jest.fn().mockReturnValue([{ canUserCRUD: true, hasIndexWrite: true }]),
}));
@@ -106,6 +113,11 @@ const defaultProps = {
describe('Actions', () => {
beforeAll(() => {
+ (useTourContext as jest.Mock).mockReturnValue({
+ activeStep: 1,
+ incrementStep: () => null,
+ isTourShown: () => false,
+ });
(useShallowEqualSelector as jest.Mock).mockReturnValue(mockTimelineModel);
});
@@ -140,6 +152,121 @@ describe('Actions', () => {
expect(wrapper.find('[data-test-subj="select-event"]').exists()).toBe(false);
});
+ describe('Guided Onboarding Step', () => {
+ const incrementStepMock = jest.fn();
+ beforeEach(() => {
+ (useTourContext as jest.Mock).mockReturnValue({
+ activeStep: 2,
+ incrementStep: incrementStepMock,
+ isTourShown: () => true,
+ });
+ jest.clearAllMocks();
+ });
+
+ const ecsData = {
+ ...mockTimelineData[0].ecs,
+ kibana: { alert: { rule: { uuid: ['123'], parameters: {} } } },
+ };
+ const isTourAnchorConditions: { [key: string]: unknown } = {
+ ecsData,
+ timelineId: TableId.alertsOnAlertsPage,
+ ariaRowindex: 1,
+ };
+
+ test('if isTourShown is false [isTourAnchor=false], SecurityTourStep is not active', () => {
+ (useTourContext as jest.Mock).mockReturnValue({
+ activeStep: 2,
+ incrementStep: jest.fn(),
+ isTourShown: () => false,
+ });
+
+ const wrapper = mount(
+
+
+
+ );
+
+ expect(wrapper.find(GuidedOnboardingTourStep).exists()).toEqual(true);
+ expect(wrapper.find(SecurityTourStep).exists()).toEqual(false);
+ });
+
+ test('if all conditions make isTourAnchor=true, SecurityTourStep is active', () => {
+ const wrapper = mount(
+
+
+
+ );
+
+ expect(wrapper.find(GuidedOnboardingTourStep).exists()).toEqual(true);
+ expect(wrapper.find(SecurityTourStep).exists()).toEqual(true);
+ });
+
+ test('on expand event click and SecurityTourStep is active, incrementStep', () => {
+ const wrapper = mount(
+
+
+
+ );
+
+ wrapper.find('[data-test-subj="expand-event"]').first().simulate('click');
+
+ expect(incrementStepMock).toHaveBeenCalledWith(SecurityStepId.alertsCases);
+ });
+
+ test('on expand event click and SecurityTourStep is active, but step is not 2, do not incrementStep', () => {
+ (useTourContext as jest.Mock).mockReturnValue({
+ activeStep: 1,
+ incrementStep: incrementStepMock,
+ isTourShown: () => true,
+ });
+
+ const wrapper = mount(
+
+
+
+ );
+
+ wrapper.find('[data-test-subj="expand-event"]').first().simulate('click');
+
+ expect(incrementStepMock).not.toHaveBeenCalled();
+ });
+
+ test('on expand event click and SecurityTourStep is not active, do not incrementStep', () => {
+ const wrapper = mount(
+
+
+
+ );
+
+ wrapper.find('[data-test-subj="expand-event"]').first().simulate('click');
+
+ expect(incrementStepMock).not.toHaveBeenCalled();
+ });
+
+ test('if isTourAnchor=false, SecurityTourStep is not active', () => {
+ const wrapper = mount(
+
+
+
+ );
+
+ expect(wrapper.find(GuidedOnboardingTourStep).exists()).toEqual(true);
+ expect(wrapper.find(SecurityTourStep).exists()).toEqual(false);
+ });
+ describe.each(Object.keys(isTourAnchorConditions))('tour condition true: %s', (key: string) => {
+ it('Single condition does not make tour step exist', () => {
+ const wrapper = mount(
+
+
+
+ );
+
+ expect(wrapper.find(GuidedOnboardingTourStep).exists()).toEqual(true);
+ expect(wrapper.find(SecurityTourStep).exists()).toEqual(false);
+ });
+ });
+ });
+
describe('Alert context menu enabled?', () => {
test('it disables for eventType=raw', () => {
const wrapper = mount(
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/actions/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/actions/index.tsx
index 5454642ea5892..26ffd4ea8e28e 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/actions/index.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/actions/index.tsx
@@ -203,7 +203,7 @@ const ActionsComponent: React.FC = ({
scopedActions,
]);
- const { isTourShown, incrementStep } = useTourContext();
+ const { activeStep, isTourShown, incrementStep } = useTourContext();
const isTourAnchor = useMemo(
() =>
@@ -215,11 +215,12 @@ const ActionsComponent: React.FC = ({
);
const onExpandEvent = useCallback(() => {
- if (isTourAnchor) {
+ const isStep2Active = activeStep === 2 && isTourShown(SecurityStepId.alertsCases);
+ if (isTourAnchor && isStep2Active) {
incrementStep(SecurityStepId.alertsCases);
}
onEventDetailsPanelOpened();
- }, [incrementStep, isTourAnchor, onEventDetailsPanelOpened]);
+ }, [activeStep, incrementStep, isTourAnchor, isTourShown, onEventDetailsPanelOpened]);
return (