From 3be8acd964953dec975c62089cc14d108d38e193 Mon Sep 17 00:00:00 2001 From: Ievgen Sorokopud Date: Wed, 22 Jan 2025 14:01:49 +0100 Subject: [PATCH] [Rules migration] Implement workflow tour - Setup Guide (#11384) (#207242) ## Summary [Internal link](https://github.com/elastic/security-team/issues/10820) to the feature details This PR adds the SIEM Migration setup tour guide on the main landing page. [Figma link](https://www.figma.com/design/BD9GZZz6y8pfSbubAt5H2W/%5B8.18%5D-GenAI-Powered-SIEM-Migration%3A-Rule-translation?node-id=2652-244526&t=WmkBy29xrzl5mN7G-4) https://github.com/user-attachments/assets/680e3bb6-a0af-43dc-99f8-30e32badf367 Delete `securitySolution.siemMigrations.setupGuide.v8.18` in the local storage to reset the tour. > [!NOTE] > This feature needs `siemMigrationsEnabled` experimental flag enabled to work. --- .../security_solution/common/constants.ts | 1 + .../onboarding_header_topic_selector.tsx | 17 +++- .../components/tours/setup_guide/index.tsx | 79 +++++++++++++++++++ .../tours/setup_guide/translations.ts | 37 +++++++++ 4 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/tours/setup_guide/index.tsx create mode 100644 x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/tours/setup_guide/translations.ts diff --git a/x-pack/solutions/security/plugins/security_solution/common/constants.ts b/x-pack/solutions/security/plugins/security_solution/common/constants.ts index aa3f2d0d5c096..33e031dae8ac6 100644 --- a/x-pack/solutions/security/plugins/security_solution/common/constants.ts +++ b/x-pack/solutions/security/plugins/security_solution/common/constants.ts @@ -423,6 +423,7 @@ 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', + SIEM_MAIN_LANDING_PAGE: 'securitySolution.siemMigrations.setupGuide.v8.18', }; export const RULE_DETAILS_EXECUTION_LOG_TABLE_SHOW_METRIC_COLUMNS_STORAGE_KEY = diff --git a/x-pack/solutions/security/plugins/security_solution/public/onboarding/components/onboarding_header/onboarding_header_topic_selector.tsx b/x-pack/solutions/security/plugins/security_solution/public/onboarding/components/onboarding_header/onboarding_header_topic_selector.tsx index c949f51d23da1..00e2353b66e29 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/onboarding/components/onboarding_header/onboarding_header_topic_selector.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/onboarding/components/onboarding_header/onboarding_header_topic_selector.tsx @@ -7,9 +7,22 @@ import React, { useMemo } from 'react'; import { EuiButtonGroup } from '@elastic/eui'; -import type { OnboardingTopicId } from '../../constants'; +import { OnboardingTopicId } from '../../constants'; import { useOnboardingContext } from '../onboarding_context'; import { useTopic } from '../hooks/use_topic_id'; +import type { TopicConfig } from '../../types'; +import { SiemMigrationSetupTour } from '../../../siem_migrations/rules/components/tours/setup_guide'; + +const getLabel = (topicConfig: TopicConfig) => { + if (topicConfig.id === OnboardingTopicId.siemMigrations) { + return ( + + <>{topicConfig.title} + + ); + } + return topicConfig.title; +}; export const OnboardingHeaderTopicSelector = React.memo(() => { const { config } = useOnboardingContext(); @@ -19,7 +32,7 @@ export const OnboardingHeaderTopicSelector = React.memo(() => { () => [...config.values()].map((topicConfig) => ({ id: topicConfig.id, - label: topicConfig.title, + label: getLabel(topicConfig), })), [config] ); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/tours/setup_guide/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/tours/setup_guide/index.tsx new file mode 100644 index 0000000000000..00822b49f49a8 --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/tours/setup_guide/index.tsx @@ -0,0 +1,79 @@ +/* + * 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, { useCallback, useEffect, useMemo, useState } from 'react'; +import { EuiButtonEmpty, EuiTourStep } from '@elastic/eui'; +import { NEW_FEATURES_TOUR_STORAGE_KEYS } from '../../../../../../common/constants'; +import { useKibana } from '../../../../../common/lib/kibana'; +import * as i18n from './translations'; + +const tourConfig = { + currentTourStep: 1, + isTourActive: true, + tourPopoverWidth: 360, +}; + +export interface SetupTourProps { + children: React.ReactElement; +} + +export const SiemMigrationSetupTour: React.FC = React.memo(({ children }) => { + const { siemMigrations, storage } = useKibana().services; + + const [tourState, setTourState] = useState(() => { + const restoredTourState = storage.get(NEW_FEATURES_TOUR_STORAGE_KEYS.SIEM_MAIN_LANDING_PAGE); + if (restoredTourState != null) { + return restoredTourState; + } + return tourConfig; + }); + + const onTourFinished = useCallback(() => { + setTourState({ + ...tourState, + isTourActive: false, + }); + }, [tourState]); + + useEffect(() => { + storage.set(NEW_FEATURES_TOUR_STORAGE_KEYS.SIEM_MAIN_LANDING_PAGE, tourState); + }, [tourState, storage]); + + const [tourDelayElapsed, setTourDelayElapsed] = useState(false); + + useEffect(() => { + // visible EuiTourStep anchors don't follow the button when the layout changes + const timeout = setTimeout(() => setTourDelayElapsed(true), 1000); + return () => clearTimeout(timeout); + }, []); + + const showTour = useMemo(() => { + return siemMigrations.rules.isAvailable() && tourState.isTourActive && tourDelayElapsed; + }, [siemMigrations.rules, tourDelayElapsed, tourState.isTourActive]); + + return ( + + {i18n.FINISH_TOUR_BUTTON} + + } + > + {children} + + ); +}); +SiemMigrationSetupTour.displayName = 'SiemMigrationSetupTour'; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/tours/setup_guide/translations.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/tours/setup_guide/translations.ts new file mode 100644 index 0000000000000..e5a57eea15507 --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/tours/setup_guide/translations.ts @@ -0,0 +1,37 @@ +/* + * 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 SETUP_SIEM_MIGRATION_TOUR_TITLE = i18n.translate( + 'xpack.securitySolution.siemMigrations.rules.tour.setupSiemMigrationTourTitle', + { + defaultMessage: 'Streamlined SIEM migration', + } +); + +export const SETUP_SIEM_MIGRATION_TOUR_SUBTITLE = i18n.translate( + 'xpack.securitySolution.siemMigrations.rules.tour.setupSiemMigrationTourTitle', + { + defaultMessage: 'New onboarding guide!', + } +); + +export const SETUP_SIEM_MIGRATION_TOUR_CONTENT = i18n.translate( + 'xpack.securitySolution.siemMigrations.rules.tour.setupSiemMigrationTourContent', + { + defaultMessage: + 'This is a step-by-step guide to quickly import your SIEM rules, assets, and data to Elastic Security. Powered by AI.', + } +); + +export const FINISH_TOUR_BUTTON = i18n.translate( + 'xpack.securitySolution.siemMigrations.rules.tour.finishButton', + { + defaultMessage: 'OK', + } +);