Skip to content

Commit

Permalink
[Security solution] Guided onboarding rules (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
stephmilovic authored and xcrzx committed Oct 31, 2022
1 parent b76263b commit 7fd258c
Show file tree
Hide file tree
Showing 9 changed files with 113 additions and 216 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,16 @@ 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;
setActiveStep: (stepId: SecurityStepId, step: number) => void;
isTourShown: (stepId: SecurityStepId) => boolean;
}

const initialState: TourContextValue = {
activeStep: 0,
endTourStep: () => {},
incrementStep: () => {},
setActiveStep: () => {},
isTourShown: () => false,
};

Expand Down Expand Up @@ -63,6 +65,12 @@ export const RealTourContextProvider = ({ children }: { children: ReactChild })
const isTourShown = useCallback((stepId: SecurityStepId) => tourStatus[stepId], [tourStatus]);
const [activeStep, _setActiveStep] = useState<number>(1);

const setActiveStep = useCallback((stepId: SecurityStepId, step: number) => {
if (step <= securityTourConfig[stepId].length) {
_setActiveStep(step);
}
}, []);

const incrementStep = useCallback((stepId: SecurityStepId) => {
_setActiveStep(
(prevState) => (prevState >= securityTourConfig[stepId].length ? 0 : prevState) + 1
Expand Down Expand Up @@ -105,6 +113,7 @@ export const RealTourContextProvider = ({ children }: { children: ReactChild })
endTourStep,
incrementStep,
isTourShown,
setActiveStep,
};

return <TourContext.Provider value={context}>{children}</TourContext.Provider>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,39 @@ const alertsCasesConfig: StepConfig[] = [
},
];

const rulesConfig: StepConfig[] = [
{
...defaultConfig,
title: i18n.translate(
'xpack.securitySolution.detectionEngine.rules.guidedOnboarding.installPrebuiltRules.title',
{ defaultMessage: 'Load the Elastic prebuilt rules' }
),
content: i18n.translate(
'xpack.securitySolution.detectionEngine.rules.guidedOnboarding.installPrebuiltRules.content',
{ defaultMessage: 'To get started you need to load the Elastic prebuilt rules.' }
),
step: 1,
anchorPosition: 'downCenter',
hideNextButton: true,
dataTestSubj: getTourAnchor(1, SecurityStepId.rules),
},
{
...defaultConfig,
title: i18n.translate(
'xpack.securitySolution.detectionEngine.rules.guidedOnboarding.searchFirstRule.title',
{ defaultMessage: 'Search for Elastic Defend rules' }
),
content: i18n.translate(
'xpack.securitySolution.detectionEngine.rules.guidedOnboarding.searchFirstRule.content',
{ defaultMessage: 'Find the rules you want and enable them.' }
),
step: 2,
anchorPosition: 'upCenter',
hideNextButton: true,
dataTestSubj: getTourAnchor(2, SecurityStepId.rules),
},
];

interface SecurityTourConfig {
[SecurityStepId.rules]: StepConfig[];
[SecurityStepId.alertsCases]: StepConfig[];
Expand All @@ -134,6 +167,6 @@ export const securityTourConfig: SecurityTourConfig = {
/**
* D&R team implement your tour config here
*/
[SecurityStepId.rules]: [],
[SecurityStepId.rules]: rulesConfig,
[SecurityStepId.alertsCases]: alertsCasesConfig,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* 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 { useCallback, useEffect } from 'react';
import { useTourContext } from './tour';
import type { RulesQueryResponse } from '../../../detection_engine/rule_management/api/hooks/use_find_rules_query';
import { useFindRulesQuery } from '../../../detection_engine/rule_management/api/hooks/use_find_rules_query';
import { SecurityStepId } from './tour_config';
const GUIDED_ONBOARDING_RULES_FILTER = {
filter: '',
showCustomRules: false,
showElasticRules: true,
tags: ['Guided Onboarding'],
};
export const useRulesTour = () => {
const { isTourShown, endTourStep, incrementStep, activeStep, setActiveStep } = useTourContext();
const { data: onboardingRules } = useFindRulesQuery(
{ filterOptions: GUIDED_ONBOARDING_RULES_FILTER },
{ retry: false, enabled: isTourShown(SecurityStepId.rules) }
);

const manageRulesTour = useCallback(
({ rules }: RulesQueryResponse) => {
if (rules && rules.length === 0 && isTourShown(SecurityStepId.rules) && activeStep === 2) {
// reset to 1 if they are on step 2 but have no onboarding rules
setActiveStep(SecurityStepId.rules, 1);
}
if (rules && rules.length > 0 && isTourShown(SecurityStepId.rules) && activeStep === 1) {
// There are onboarding rules now, advance to step 2 if on step 1
incrementStep(SecurityStepId.rules);
}
if (rules.some((rule) => rule.enabled)) {
// The onboarding rule is enabled, end the tour
endTourStep(SecurityStepId.rules);
}
},
[activeStep, endTourStep, incrementStep, isTourShown, setActiveStep]
);

useEffect(() => {
if (onboardingRules) {
manageRulesTour(onboardingRules);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [onboardingRules]);
};

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,15 @@ import {
import { isEqual } from 'lodash/fp';
import React, { useCallback } from 'react';
import styled from 'styled-components';
import { GuidedOnboardingTourStep } from '../../../../../common/components/guided_onboarding_tour/tour_step';
import { SecurityStepId } from '../../../../../common/components/guided_onboarding_tour/tour_config';
import { RULES_TABLE_ACTIONS } from '../../../../../common/lib/apm/user_actions';
import { useStartTransaction } from '../../../../../common/lib/apm/use_start_transaction';
import { usePrePackagedRulesStatus } from '../../../../rule_management/logic/use_pre_packaged_rules_status';
import * as i18n from '../../../../../detections/pages/detection_engine/rules/translations';
import { useRulesTableContext } from '../rules_table/rules_table_context';
import { TagsFilterPopover } from './tags_filter_popover';
import { useTags } from '../../../../rule_management/logic/use_tags';
import { SEARCH_FIRST_RULE_ANCHOR } from '../../guided_onboarding/rules_management_tour';

const FilterWrapper = styled(EuiFlexGroup)`
margin-bottom: ${({ theme }) => theme.eui.euiSizeXS};
Expand Down Expand Up @@ -85,14 +86,15 @@ const RulesTableFiltersComponent = () => {
return (
<FilterWrapper gutterSize="m" justifyContent="flexEnd">
<SearchBarWrapper grow>
<EuiFieldSearch
id={SEARCH_FIRST_RULE_ANCHOR}
aria-label={i18n.SEARCH_RULES}
fullWidth
incremental={false}
placeholder={i18n.SEARCH_PLACEHOLDER}
onSearch={handleOnSearch}
/>
<GuidedOnboardingTourStep step={2} stepId={SecurityStepId.rules}>
<EuiFieldSearch
aria-label={i18n.SEARCH_RULES}
fullWidth
incremental={false}
placeholder={i18n.SEARCH_PLACEHOLDER}
onSearch={handleOnSearch}
/>
</GuidedOnboardingTourStep>
</SearchBarWrapper>
<EuiFlexItem grow={false}>
<EuiFilterGroup>
Expand Down
Loading

0 comments on commit 7fd258c

Please sign in to comment.