From c8938d708018af0bf612392291675eb757fa84fa Mon Sep 17 00:00:00 2001 From: Angela Chuang Date: Mon, 24 Nov 2025 15:41:58 +0000 Subject: [PATCH 01/23] qradar UI --- .../migration_name_input.tsx | 1 - .../migration_source_step/index.tsx | 20 +++ .../migration_source_dropdown.tsx | 71 ++++++++ .../migration_source_options.tsx | 170 ++++++++++++++++++ .../migration_source_step/translations.ts | 23 +++ .../components/migration_source_step/types.ts | 44 +++++ .../public/siem_migrations/common/types.ts | 5 + .../public/siem_migrations/rules/api/index.ts | 14 +- .../data_input_flyout/data_input_flyout.tsx | 114 +++++------- .../data_input_flyout/flyout_description.tsx | 46 +++++ .../data_input_flyout/steps/constants.ts | 7 + .../steps/rules/rules_data_input.tsx | 41 ++++- .../copy_exported_qradar_query.tsx | 41 +++++ ...ery.tsx => copy_exported_splunk_query.tsx} | 6 +- .../sub_steps/copy_export_query/index.tsx | 19 +- .../copy_export_query/translations.ts | 2 +- .../sub_steps/rules_file_upload/index.tsx | 4 + .../rules_file_upload/rules_file_upload.tsx | 48 ++++- .../rules_file_upload/translations.ts | 9 +- .../service/hooks/use_create_migration.ts | 26 ++- .../rules/service/rule_migrations_service.ts | 16 +- 21 files changed, 623 insertions(+), 104 deletions(-) create mode 100644 x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/index.tsx create mode 100644 x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_dropdown.tsx create mode 100644 x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_options.tsx create mode 100644 x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/translations.ts create mode 100644 x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/types.ts create mode 100644 x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/flyout_description.tsx create mode 100644 x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/copy_exported_qradar_query.tsx rename x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/{copy_export_query.tsx => copy_exported_splunk_query.tsx} (92%) diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_name_step/migration_name_input.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_name_step/migration_name_input.tsx index 27fda2f7dfdcf..072b4e974dbc5 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_name_step/migration_name_input.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_name_step/migration_name_input.tsx @@ -62,7 +62,6 @@ export const MigrationNameInput = React.memo( onBlur={onBlur} onKeyDown={onEnter} fullWidth - autoFocus data-test-subj="migrationNameInput" /> diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/index.tsx new file mode 100644 index 0000000000000..f6d24f423e8a8 --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/index.tsx @@ -0,0 +1,20 @@ +/* + * 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 { useState } from 'react'; +import type { MigrationSource } from '../../types'; +import { MIGRATIONSOURCE_OPTIONS } from './migration_source_options'; + +export const useMigrationSourceStep = () => { + const [migrationSource, setMigrationSource] = useState( + MIGRATIONSOURCE_OPTIONS[0].value + ); + return { + migrationSource, + setMigrationSource, + }; +}; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_dropdown.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_dropdown.tsx new file mode 100644 index 0000000000000..11fade15c8a5c --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_dropdown.tsx @@ -0,0 +1,71 @@ +/* + * 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, useState } from 'react'; +import { EuiFlexGroup, EuiFlexItem, EuiForm, EuiFormRow, EuiSuperSelect } from '@elastic/eui'; +import * as i18n from './translations'; +import type { MigrationSource } from '../../types'; +import { MIGRATIONSOURCE_OPTIONS } from './migration_source_options'; + +export interface MigrationSourceDropdownProps { + migrationSource: MigrationSource; + setMigrationSource: (migrationSource: MigrationSource) => void; +} + +export const MigrationSourceDropdown = React.memo( + ({ migrationSource, setMigrationSource }) => { + const [value, setValue] = useState(migrationSource); + const [isTouched, setIsTouched] = useState(false); + + const checkAndSetMigrationSource = useCallback( + (selected: MigrationSource) => { + if (selected.length > 0) { + setMigrationSource(selected); + } + }, + [setMigrationSource] + ); + + const handleMigrationSourceChange = useCallback( + (selected: MigrationSource) => { + setValue(selected); + checkAndSetMigrationSource(selected); + }, + [checkAndSetMigrationSource] + ); + + const onBlur = useCallback(() => { + setMigrationSource(value); + }, [setMigrationSource, value]); + return ( + + + + { + setIsTouched(true); + }} + label={i18n.MIGRATION_SOURCE_DROPDOWN_TITLE} + fullWidth + > + + + + + + ); + } +); + +MigrationSourceDropdown.displayName = 'MigrationSourceDropdown'; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_options.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_options.tsx new file mode 100644 index 0000000000000..a29969efa8bc6 --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_options.tsx @@ -0,0 +1,170 @@ +/* + * 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, useMemo, useState } from 'react'; +import type { EuiSuperSelectOption } from '@elastic/eui'; +import { EuiIcon } from '@elastic/eui'; +import { MigrationSource } from '../../types'; +import * as i18n from './translations'; +import { + DataInputStep, + DataInputStepId, +} from '../../../rules/components/data_input_flyout/steps/constants'; +import { RulesDataInput } from '../../../rules/components/data_input_flyout/steps/rules/rules_data_input'; +import type { SiemMigrationResourceBase } from '../../../../../common/siem_migrations/model/common.gen'; +import type { RuleMigrationStats } from '../../../rules/types'; +import { MacrosDataInput } from '../../../rules/components/data_input_flyout/steps/macros/macros_data_input'; +import { LookupsDataInput } from '../../../rules/components/data_input_flyout/steps/lookups/lookups_data_input'; +import type { QradarMigrationSteps, SplunkMigrationSteps } from './types'; + +export const MIGRATIONSOURCE_OPTIONS: Array> = [ + { + value: MigrationSource.SPLUNK, + inputDisplay: {i18n.MIGRATION_SOURCE_DROPDOWN_OPTION_SPLUNK}, + }, + { + value: MigrationSource.QRADAR, + inputDisplay: ( + + {i18n.MIGRATION_SOURCE_DROPDOWN_OPTION_QRADAR} + + + ), + }, +]; + +interface MissingResourcesIndexed { + macros: string[]; + lookups: string[]; +} + +export const useSplunkMigrationSteps = ({ + setDataInputStep, + dataInputStep, + migrationSource, + migrationStats, + onMigrationCreated, +}: { + setDataInputStep: (step: DataInputStep) => void; + dataInputStep: DataInputStep; + migrationSource: MigrationSource; + migrationStats?: RuleMigrationStats; + onMigrationCreated: (createdMigrationStats: RuleMigrationStats) => void; +}): SplunkMigrationSteps | null => { + const [missingResourcesIndexed, setMissingResourcesIndexed] = useState< + MissingResourcesIndexed | undefined + >(); + + const onMissingResourcesFetched = useCallback( + (missingResources: SiemMigrationResourceBase[]) => { + const newMissingResourcesIndexed = missingResources.reduce( + (acc, { type, name }) => { + if (type === 'macro') { + acc.macros.push(name); + } else if (type === 'lookup') { + acc.lookups.push(name); + } + return acc; + }, + { macros: [], lookups: [] } + ); + setMissingResourcesIndexed(newMissingResourcesIndexed); + if (newMissingResourcesIndexed.macros.length) { + setDataInputStep(DataInputStep.Macros); + return; + } + if (newMissingResourcesIndexed.lookups.length) { + setDataInputStep(DataInputStep.Lookups); + return; + } + setDataInputStep(DataInputStep.End); + }, + [setDataInputStep] + ); + + const onAllLookupsCreated = useCallback(() => { + setDataInputStep(DataInputStep.End); + }, [setDataInputStep]); + + const SPLUNK_MIGRATION_STEPS: SplunkMigrationSteps = useMemo( + () => [ + { + id: DataInputStepId.SplunkRules, + Component: RulesDataInput, + extraProps: { + dataInputStep, + migrationSource, + migrationStats, + onMigrationCreated, + onMissingResourcesFetched, + }, + }, + { + id: DataInputStepId.SplunkMacros, + Component: MacrosDataInput, + extraProps: { + dataInputStep, + onMissingResourcesFetched, + missingMacros: missingResourcesIndexed?.macros, + migrationStats, + }, + }, + { + id: DataInputStepId.SplunkLookups, + Component: LookupsDataInput, + extraProps: { + dataInputStep, + onAllLookupsCreated, + missingLookups: missingResourcesIndexed?.lookups, + migrationStats, + }, + }, + ], + [ + dataInputStep, + migrationSource, + migrationStats, + onMigrationCreated, + onMissingResourcesFetched, + missingResourcesIndexed, + onAllLookupsCreated, + ] + ); + + return migrationSource === MigrationSource.SPLUNK ? SPLUNK_MIGRATION_STEPS : null; +}; + +export const useQradarMigrationSteps = ({ + onMigrationCreated, + dataInputStep, + migrationSource, + migrationStats, +}: { + onMigrationCreated: (createdMigrationStats: RuleMigrationStats) => void; + dataInputStep: DataInputStep; + migrationSource: MigrationSource; + migrationStats?: RuleMigrationStats; +}): QradarMigrationSteps | null => { + const onMissingResourcesFetched = useCallback(() => {}, []); + const QRADAR_MIGRATION_STEPS: QradarMigrationSteps = useMemo( + () => [ + { + id: DataInputStepId.QradarRules, + Component: RulesDataInput, + extraProps: { + dataInputStep, + migrationSource, + migrationStats, + onMigrationCreated, + onMissingResourcesFetched, + }, + }, + ], + [dataInputStep, migrationSource, migrationStats, onMigrationCreated, onMissingResourcesFetched] + ); + + return migrationSource === MigrationSource.QRADAR ? QRADAR_MIGRATION_STEPS : null; +}; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/translations.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/translations.ts new file mode 100644 index 0000000000000..7f307855d70bc --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/translations.ts @@ -0,0 +1,23 @@ +/* + * 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 MIGRATION_SOURCE_DROPDOWN_TITLE = i18n.translate( + 'xpack.securitySolution.siemMigrations.common.dataInputFlyout.migrationSource.title', + { defaultMessage: 'Select migration source' } +); + +export const MIGRATION_SOURCE_DROPDOWN_OPTION_SPLUNK = i18n.translate( + 'xpack.securitySolution.siemMigrations.common.dataInputFlyout.migrationSource.option.splunk', + { defaultMessage: 'Splunk' } +); + +export const MIGRATION_SOURCE_DROPDOWN_OPTION_QRADAR = i18n.translate( + 'xpack.securitySolution.siemMigrations.common.dataInputFlyout.migrationSource.option.qradar', + { defaultMessage: 'QRadar' } +); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/types.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/types.ts new file mode 100644 index 0000000000000..c5550a9933b4a --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/types.ts @@ -0,0 +1,44 @@ +/* + * 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 type { DataInputStepId } from '../../../rules/components/data_input_flyout/steps/constants'; +import type { LookupsDataInput } from '../../../rules/components/data_input_flyout/steps/lookups/lookups_data_input'; +import type { MacrosDataInput } from '../../../rules/components/data_input_flyout/steps/macros/macros_data_input'; +import type { RulesDataInput } from '../../../rules/components/data_input_flyout/steps/rules/rules_data_input'; + +interface RulesStep { + id: T; + Component: typeof RulesDataInput; + extraProps: React.ComponentProps; +} +interface MacrosStep { + id: DataInputStepId.SplunkMacros; + Component: typeof MacrosDataInput; + extraProps: React.ComponentProps; +} +interface LookupsStep { + id: DataInputStepId.SplunkLookups; + Component: typeof LookupsDataInput; + extraProps: React.ComponentProps; +} + +export type Step = + T extends DataInputStepId.SplunkRules + ? RulesStep + : T extends DataInputStepId.QradarRules + ? RulesStep + : T extends DataInputStepId.SplunkMacros + ? MacrosStep + : LookupsStep; + +export type SplunkMigrationSteps = [ + Step, + Step, + Step +]; + +export type QradarMigrationSteps = [Step]; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/types.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/types.ts index 29b8b5335ff89..e8b904f3fe942 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/types.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/types.ts @@ -39,3 +39,8 @@ export interface FilterOptionsBase { export interface MigrationStats extends MigrationTaskStats { status: SiemMigrationTaskStatus; // use the native enum instead of the zod enum from the model } + +export enum MigrationSource { + SPLUNK = 'splunk', + QRADAR = 'qradar', +} diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/api/index.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/api/index.ts index fa5187a76e8a2..d773495744538 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/api/index.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/api/index.ts @@ -25,11 +25,12 @@ import { SIEM_RULE_MIGRATIONS_PREBUILT_RULES_PATH, SIEM_RULE_MIGRATIONS_INTEGRATIONS_PATH, SIEM_RULE_MIGRATION_MISSING_PRIVILEGES_PATH, - SIEM_RULE_MIGRATION_RULES_PATH, SIEM_RULE_MIGRATIONS_INTEGRATIONS_STATS_PATH, SIEM_RULE_MIGRATION_PATH, SIEM_RULE_MIGRATION_STOP_PATH, SIEM_RULE_MIGRATION_UPDATE_INDEX_PATTERN_PATH, + SIEM_RULE_MIGRATION_RULES_PATH, + SIEM_RULE_MIGRATION_QRADAR_RULES_PATH, } from '../../../../common/siem_migrations/constants'; import type { CreateRuleMigrationResponse, @@ -53,6 +54,7 @@ import type { } from '../../../../common/siem_migrations/model/api/rules/rule_migration.gen'; import type { RuleMigrationStats } from '../types'; import type { GetMigrationStatsParams, GetMigrationsStatsAllParams } from '../../common/types'; +import { MigrationSource } from '../../common/types'; /** Retrieves the stats for the specific migration. */ export const getRuleMigrationStats = async ({ @@ -102,6 +104,8 @@ export interface AddRulesToMigrationParams { body: CreateRuleMigrationRulesRequestBody; /** Optional AbortSignal for cancelling request */ signal?: AbortSignal; + /** The source of the migration */ + migrationSource: MigrationSource; } /** Adds provided rules to an existing migration */ @@ -109,9 +113,15 @@ export const addRulesToMigration = async ({ migrationId, body, signal, + migrationSource, }: AddRulesToMigrationParams) => { return KibanaServices.get().http.post( - replaceParams(SIEM_RULE_MIGRATION_RULES_PATH, { migration_id: migrationId }), + replaceParams( + migrationSource === MigrationSource.QRADAR + ? SIEM_RULE_MIGRATION_QRADAR_RULES_PATH + : SIEM_RULE_MIGRATION_RULES_PATH, + { migration_id: migrationId } + ), { body: JSON.stringify(body), version: '1', signal } ); }; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx index 9cddaaaf0afac..1572ecb1d075e 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx @@ -19,29 +19,38 @@ import { useGeneratedHtmlId, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import type { SiemMigrationResourceBase } from '../../../../../common/siem_migrations/model/common.gen'; import { SiemMigrationRetryFilter, SiemMigrationTaskStatus, } from '../../../../../common/siem_migrations/constants'; -import { RulesDataInput } from './steps/rules/rules_data_input'; +import type { DataInputStepId } from './steps/constants'; import { DataInputStep } from './steps/constants'; -import { MacrosDataInput } from './steps/macros/macros_data_input'; -import { LookupsDataInput } from './steps/lookups/lookups_data_input'; import { useStartRulesMigrationModal } from '../../hooks/use_start_rules_migration_modal'; import type { RuleMigrationSettings, RuleMigrationStats } from '../../types'; import { useStartMigration } from '../../logic/use_start_migration'; - -interface MissingResourcesIndexed { - macros: string[]; - lookups: string[]; -} +import { useMigrationSourceStep } from '../../../common/components/migration_source_step'; +import { MigrationSourceDropdown } from '../../../common/components/migration_source_step/migration_source_dropdown'; +import { CenteredLoadingSpinner } from '../../../../common/components/centered_loading_spinner'; +import { + useQradarMigrationSteps, + useSplunkMigrationSteps, +} from '../../../common/components/migration_source_step/migration_source_options'; +import type { + QradarMigrationSteps, + SplunkMigrationSteps, + Step, +} from '../../../common/components/migration_source_step/types'; export interface MigrationDataInputFlyoutProps { onClose: () => void; migrationStats?: RuleMigrationStats; } +function StepRenderer({ step }: { step: Step }) { + const Component = step.Component as React.ComponentType; + return ; +} + const RULES_MIGRATION_DATA_INPUT_FLYOUT_TITLE = 'rulesMigrationDataInputFlyoutTitle'; export const MigrationDataInputFlyout = React.memo( @@ -53,9 +62,7 @@ export const MigrationDataInputFlyout = React.memo( initialMigrationSats ); - const [missingResourcesIndexed, setMissingResourcesIndexed] = useState< - MissingResourcesIndexed | undefined - >(); + const isRetry = migrationStats?.status === SiemMigrationTaskStatus.FINISHED; const [dataInputStep, setDataInputStep] = useState(DataInputStep.Rules); @@ -64,37 +71,6 @@ export const MigrationDataInputFlyout = React.memo { - const newMissingResourcesIndexed = missingResources.reduce( - (acc, { type, name }) => { - if (type === 'macro') { - acc.macros.push(name); - } else if (type === 'lookup') { - acc.lookups.push(name); - } - return acc; - }, - { macros: [], lookups: [] } - ); - setMissingResourcesIndexed(newMissingResourcesIndexed); - if (newMissingResourcesIndexed.macros.length) { - setDataInputStep(DataInputStep.Macros); - return; - } - if (newMissingResourcesIndexed.lookups.length) { - setDataInputStep(DataInputStep.Lookups); - return; - } - setDataInputStep(DataInputStep.End); - }, - [] - ); - - const onAllLookupsCreated = useCallback(() => { - setDataInputStep(DataInputStep.End); - }, []); - const { startMigration, isLoading: isStartLoading } = useStartMigration(onClose); const onStartMigrationWithSettings = useCallback( (settings: RuleMigrationSettings) => { @@ -120,6 +96,25 @@ export const MigrationDataInputFlyout = React.memo {startMigrationModal} @@ -136,7 +131,7 @@ export const MigrationDataInputFlyout = React.memo @@ -144,29 +139,18 @@ export const MigrationDataInputFlyout = React.memo - - - - - - - + <> + {steps?.map((step) => ( + + + + )) ?? } + diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/flyout_description.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/flyout_description.tsx new file mode 100644 index 0000000000000..7b8c56924b037 --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/flyout_description.tsx @@ -0,0 +1,46 @@ +/* + * 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 { FormattedMessage } from '@kbn/i18n-react'; +import { EuiText, EuiLink } from '@elastic/eui'; +import { useNavigation } from '../../../../common/lib/kibana'; + +export const FlyoutDescription = React.memo(() => { + const { navigateTo } = useNavigation(); + return ( + + { + navigateTo({ + appId: 'management', + path: '/kibana/dataViews', + }); + }} + target="_blank" + rel="noopener" + external + data-test-subj="siemMigrationsAdvancedSettingsLink" + > + + + ), + }} + /> + + ); +}); + +FlyoutDescription.displayName = 'FlyoutDescription'; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/constants.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/constants.ts index c0586108b0a19..a8707f95ea54d 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/constants.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/constants.ts @@ -11,3 +11,10 @@ export enum DataInputStep { Lookups = 3, End = 10, } + +export enum DataInputStepId { + SplunkRules = 'splunk_rules', + SplunkMacros = 'splunk_macros', + SplunkLookups = 'splunk_lookups', + QradarRules = 'qradar_rules', +} diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx index b10ed3a6df334..f044b0d1baa2f 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx @@ -18,17 +18,25 @@ import { useCopyExportQueryStep } from './sub_steps/copy_export_query'; import { useRulesFileUploadStep } from './sub_steps/rules_file_upload'; import { useCheckResourcesStep } from './sub_steps/check_resources'; import type { RuleMigrationStats } from '../../../../types'; +import { MigrationSource } from '../../../../../common/types'; interface RulesDataInputSubStepsProps { migrationStats?: RuleMigrationStats; onMigrationCreated: OnMigrationCreated; onMissingResourcesFetched: OnMissingResourcesFetched; + migrationSource: MigrationSource; } interface RulesDataInputProps extends RulesDataInputSubStepsProps { dataInputStep: DataInputStep; } export const RulesDataInput = React.memo( - ({ dataInputStep, migrationStats, onMigrationCreated, onMissingResourcesFetched }) => { + ({ + dataInputStep, + migrationStats, + migrationSource, + onMigrationCreated, + onMissingResourcesFetched, + }) => { const dataInputStatus = useMemo( () => getEuiStepStatus(DataInputStep.Rules, dataInputStep), [dataInputStep] @@ -57,6 +65,7 @@ export const RulesDataInput = React.memo( {dataInputStatus === 'current' && ( ( - ({ migrationStats, onMigrationCreated, onMissingResourcesFetched }) => { + ({ migrationStats, onMigrationCreated, onMissingResourcesFetched, migrationSource }) => { const { telemetry } = useKibana().services.siemMigrations.rules; const [subStep, setSubStep] = useState(migrationStats ? 4 : 1); @@ -103,16 +112,27 @@ export const RulesDataInputSubSteps = React.memo( setSubStep((currentSubStep) => (currentSubStep !== 1 ? 3 : currentSubStep)); // Move to the next step only if step 1 was completed telemetry.reportSetupQueryCopied({ migrationId: migrationStats?.id }); }, [telemetry, migrationStats?.id]); - const copyStep = useCopyExportQueryStep({ status: getEuiStepStatus(2, subStep), onCopied }); + const copyStep = useCopyExportQueryStep({ + status: getEuiStepStatus(2, subStep), + onCopied, + migrationSource, + }); // Upload rules step - const onMigrationCreatedStep = useCallback( + const onSplunkMigrationCreatedStep = useCallback( (stats) => { onMigrationCreated(stats); setSubStep(4); }, [onMigrationCreated] ); + const onQradarMigrationCreatedStep = useCallback( + (stats) => { + onMigrationCreated(stats); + setSubStep(END); + }, + [onMigrationCreated] + ); const onRulesFileChanged = useCallback((files: FileList | null) => { setIsRuleFileReady(!!files?.length); setSubStep(3); @@ -121,8 +141,12 @@ export const RulesDataInputSubSteps = React.memo( status: getEuiStepStatus(3, subStep), migrationStats, onRulesFileChanged, - onMigrationCreated: onMigrationCreatedStep, + onMigrationCreated: + migrationSource === MigrationSource.SPLUNK + ? onSplunkMigrationCreatedStep + : onQradarMigrationCreatedStep, migrationName, + migrationSource, }); // Check missing resources step @@ -140,8 +164,11 @@ export const RulesDataInputSubSteps = React.memo( }); const steps = useMemo( - () => [nameStep, copyStep, uploadStep, resourcesStep], - [nameStep, copyStep, uploadStep, resourcesStep] + () => + migrationSource === MigrationSource.SPLUNK + ? [nameStep, copyStep, uploadStep, resourcesStep] + : [nameStep, copyStep, uploadStep], + [migrationSource, nameStep, copyStep, uploadStep, resourcesStep] ); return ; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/copy_exported_qradar_query.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/copy_exported_qradar_query.tsx new file mode 100644 index 0000000000000..85e3e2948fede --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/copy_exported_qradar_query.tsx @@ -0,0 +1,41 @@ +/* + * 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 { EuiText } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; + +export const CopyExportedQradarQuery = React.memo(() => { + return ( + + + + + ), + xmlFileOption: ( + + + + ), + }} + defaultMessage="On the Use Case Explorer page, after clicking on the {download} button, select the second option in the Export window. Only the {xmlFileOption} is supported for export rules and dependencies. Leave the default options for the selected checkboxes regarding MITRE mappings and for custom rule attribute mappings." + /> + + ); +}); + +CopyExportedQradarQuery.displayName = 'CopyExportedQradarQuery'; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/copy_export_query.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/copy_exported_splunk_query.tsx similarity index 92% rename from x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/copy_export_query.tsx rename to x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/copy_exported_splunk_query.tsx index 0dad40571ebf8..8b3ac411cce9d 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/copy_export_query.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/copy_exported_splunk_query.tsx @@ -14,7 +14,7 @@ import * as i18n from './translations'; interface CopyExportQueryProps { onCopied: () => void; } -export const CopyExportQuery = React.memo(({ onCopied }) => { +export const CopyExportedSplunkQuery = React.memo(({ onCopied }) => { const onClick: React.MouseEventHandler = useCallback( (ev) => { // The only button inside the element is the "copy" button. @@ -40,7 +40,7 @@ export const CopyExportQuery = React.memo(({ onCopied }) = - {/* The click event is also dispatched when using the keyboard actions (space or enter) for "copy" button. + {/* The click event is also dispatched when using the keyboard actions (space or enter) for "copy" button. No need to use keyboard specific events, disabling the a11y lint rule:*/} {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events */}
@@ -62,4 +62,4 @@ export const CopyExportQuery = React.memo(({ onCopied }) = ); }); -CopyExportQuery.displayName = 'CopyExportQuery'; +CopyExportedSplunkQuery.displayName = 'CopyExportedSplunkQuery'; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/index.tsx index 3d2adcc78857b..91c821c99425c 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/index.tsx @@ -5,22 +5,35 @@ * 2.0. */ -import React from 'react'; +import React, { useMemo } from 'react'; import type { EuiStepProps, EuiStepStatus } from '@elastic/eui'; -import { CopyExportQuery } from './copy_export_query'; +import { CopyExportedSplunkQuery } from './copy_exported_splunk_query'; import * as i18n from './translations'; +import { MigrationSource } from '../../../../../../../common/types'; +import { CopyExportedQradarQuery } from './copy_exported_qradar_query'; export interface CopyExportQueryStepProps { status: EuiStepStatus; + migrationSource: MigrationSource; onCopied: () => void; } + export const useCopyExportQueryStep = ({ + migrationSource, status, onCopied, }: CopyExportQueryStepProps): EuiStepProps => { + const COPY_EXPORT_QUERY_SUPPORTED_SOURCES: Record = useMemo( + () => ({ + [MigrationSource.SPLUNK]: , + [MigrationSource.QRADAR]: , + }), + [onCopied] + ); + return { title: i18n.RULES_DATA_INPUT_COPY_TITLE, status, - children: , + children: COPY_EXPORT_QUERY_SUPPORTED_SOURCES[migrationSource], }; }; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/translations.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/translations.ts index 274cd3cda2b61..df5045e0e27ad 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/translations.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/translations.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; export const RULES_DATA_INPUT_COPY_TITLE = i18n.translate( 'xpack.securitySolution.siemMigrations.rules.dataInputFlyout.rules.copyExportQuery.title', - { defaultMessage: 'Export Splunk rules' } + { defaultMessage: 'Copy rule query' } ); export const RULES_DATA_INPUT_COPY_DESCRIPTION_SECTION = i18n.translate( diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/index.tsx index 09b5f136eb6db..fda03c35dba66 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/index.tsx @@ -15,11 +15,13 @@ import { type OnSuccess, } from '../../../../../../service/hooks/use_create_migration'; import * as i18n from './translations'; +import type { MigrationSource } from '../../../../../../../common/types'; export interface RulesFileUploadStepProps { status: EuiStepStatus; migrationStats: RuleMigrationStats | undefined; migrationName: string | undefined; + migrationSource: MigrationSource; onMigrationCreated: OnMigrationCreated; onRulesFileChanged: (files: FileList | null) => void; } @@ -27,6 +29,7 @@ export const useRulesFileUploadStep = ({ status, migrationStats, migrationName, + migrationSource, onMigrationCreated, onRulesFileChanged, }: RulesFileUploadStepProps): EuiStepProps => { @@ -57,6 +60,7 @@ export const useRulesFileUploadStep = ({ >; @@ -32,19 +34,33 @@ export interface RulesFileUploadProps { isCreated: boolean; onRulesFileChanged: (files: FileList | null) => void; migrationName: string | undefined; + migrationSource: MigrationSource; apiError: string | undefined; } + +const RULES_DATA_INPUT_FILE_UPLOAD_PROMPT: Record = { + [MigrationSource.SPLUNK]: i18n.RULES_DATA_INPUT_FILE_UPLOAD_PROMPT_SPLUNK, + [MigrationSource.QRADAR]: i18n.RULES_DATA_INPUT_FILE_UPLOAD_PROMPT_QRADAR, +}; export const RulesFileUpload = React.memo( - ({ createMigration, migrationName, apiError, isLoading, isCreated, onRulesFileChanged }) => { + ({ + createMigration, + migrationName, + migrationSource, + apiError, + isLoading, + isCreated, + onRulesFileChanged, + }) => { const [rulesToUpload, setRulesToUpload] = useState([]); const filePickerRef = useRef(null); const createRules = useCallback(() => { if (migrationName) { filePickerRef.current?.removeFiles(); - createMigration(migrationName, rulesToUpload); + createMigration({ migrationName, rules: rulesToUpload, migrationSource }); } - }, [createMigration, migrationName, rulesToUpload]); + }, [createMigration, migrationName, migrationSource, rulesToUpload]); const onFileParsed = useCallback((content: Array>) => { const rules = content.map(formatRuleRow); @@ -53,13 +69,22 @@ export const RulesFileUpload = React.memo( const { parseFile, isParsing, error: fileError } = useParseFileInput(onFileParsed); + // const onFileChange = useCallback( + // (files: FileList | null) => { + // setRulesToUpload([]); + // onRulesFileChanged(files); + // parseFile(files); + // }, + // [parseFile, onRulesFileChanged] + // ); + const onFileChange = useCallback( (files: FileList | null) => { - setRulesToUpload([]); + console.log('Files changed:', files); + setRulesToUpload(files?.length ? Array.from(files) : []); onRulesFileChanged(files); - parseFile(files); }, - [parseFile, onRulesFileChanged] + [setRulesToUpload, onRulesFileChanged] ); const error = useMemo(() => { @@ -75,6 +100,9 @@ export const RulesFileUpload = React.memo( return ( + + {RULES_DATA_INPUT_CHECK_RESOURCES_DESCRIPTION} + ( fullWidth initialPromptText={ - {i18n.RULES_DATA_INPUT_FILE_UPLOAD_PROMPT} + {RULES_DATA_INPUT_FILE_UPLOAD_PROMPT[migrationSource]} } - accept="application/json, application/x-ndjson" + accept={ + migrationSource === MigrationSource.SPLUNK + ? 'application/json, application/x-ndjson' + : '.xml' + } onChange={onFileChange} display="large" aria-label="Upload rules file" diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/translations.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/translations.ts index 01e5fd8dc35b3..9251914e99db5 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/translations.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/translations.ts @@ -12,7 +12,12 @@ export const RULES_DATA_INPUT_FILE_UPLOAD_TITLE = i18n.translate( { defaultMessage: 'Update exported rules' } ); -export const RULES_DATA_INPUT_FILE_UPLOAD_PROMPT = i18n.translate( - 'xpack.securitySolution.siemMigrations.rules.dataInputFlyout.rules.rulesFileUpload.prompt', +export const RULES_DATA_INPUT_FILE_UPLOAD_PROMPT_SPLUNK = i18n.translate( + 'xpack.securitySolution.siemMigrations.rules.dataInputFlyout.rules.rulesFileUpload.promptSplunk', { defaultMessage: 'Select or drag and drop the exported JSON file' } ); + +export const RULES_DATA_INPUT_FILE_UPLOAD_PROMPT_QRADAR = i18n.translate( + 'xpack.securitySolution.siemMigrations.rules.dataInputFlyout.rules.rulesFileUpload.promptQradar', + { defaultMessage: 'Select or drag and drop the exported XML file' } +); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.ts index 07a449dd891a7..6015db9b75fa6 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.ts @@ -11,6 +11,7 @@ import type { CreateRuleMigrationRulesRequestBody } from '../../../../../common/ import { useKibana } from '../../../../common/lib/kibana/kibana_react'; import { reducer, initialState } from '../../../common/service'; import type { RuleMigrationStats } from '../../types'; +import type { MigrationSource } from '../../../common/types'; export const RULES_DATA_INPUT_CREATE_MIGRATION_SUCCESS_TITLE = i18n.translate( 'xpack.securitySolution.siemMigrations.rules.service.createRuleSuccess.title', @@ -26,10 +27,15 @@ export const RULES_DATA_INPUT_CREATE_MIGRATION_ERROR = i18n.translate( { defaultMessage: 'Failed to upload rules file' } ); -export type CreateMigration = ( - migrationName: string, - rules: CreateRuleMigrationRulesRequestBody -) => void; +export type CreateMigration = ({ + rules, + migrationName, + migrationSource, +}: { + migrationName: string; + migrationSource: MigrationSource; + rules: CreateRuleMigrationRulesRequestBody; +}) => void; export type OnSuccess = (migrationStats: RuleMigrationStats) => void; export const useCreateMigration = (onSuccess: OnSuccess) => { @@ -37,12 +43,18 @@ export const useCreateMigration = (onSuccess: OnSuccess) => { const [state, dispatch] = useReducer(reducer, initialState); const createMigration = useCallback( - (migrationName, rules) => { + ({ migrationName, migrationSource, rules }) => { (async () => { try { dispatch({ type: 'start' }); - const migrationId = await siemMigrations.rules.createRuleMigration(rules, migrationName); - const stats = await siemMigrations.rules.api.getRuleMigrationStats({ migrationId }); + const migrationId = await siemMigrations.rules.createRuleMigration( + rules, + migrationName, + migrationSource + ); + const stats = await siemMigrations.rules.api.getRuleMigrationStats({ + migrationId, + }); notifications.toasts.addSuccess({ title: RULES_DATA_INPUT_CREATE_MIGRATION_SUCCESS_TITLE, diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/rule_migrations_service.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/rule_migrations_service.ts index 1de46051cd29c..6bae1d6453aa1 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/rule_migrations_service.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/rule_migrations_service.ts @@ -25,7 +25,11 @@ import { getMissingCapabilitiesToast, getNoConnectorToast, } from '../../common/service'; -import type { GetMigrationStatsParams, GetMigrationsStatsAllParams } from '../../common/types'; +import type { + GetMigrationStatsParams, + GetMigrationsStatsAllParams, + MigrationSource, +} from '../../common/types'; import { raiseSuccessToast } from './notification/success_notification'; import { START_STOP_POLLING_SLEEP_SECONDS } from '../../common/constants'; @@ -51,7 +55,8 @@ export class SiemRulesMigrationsService extends SiemMigrationsServiceBase { const rulesCount = data.length; if (rulesCount === 0) { @@ -81,7 +87,7 @@ export class SiemRulesMigrationsService extends SiemMigrationsServiceBase Date: Thu, 27 Nov 2025 16:00:01 +0000 Subject: [PATCH 02/23] qradar UI --- .../migration_source_step/index.tsx | 10 +- .../migration_source_dropdown.tsx | 5 +- .../migration_source_options.tsx | 55 ++++-- .../migration_source_step/translations.ts | 5 + .../public/siem_migrations/rules/api/index.ts | 31 ++- .../data_input_flyout/data_input_flyout.tsx | 76 ++++---- .../data_input_flyout/steps/constants.ts | 14 +- .../steps/lookups/lookups_data_input.test.tsx | 6 +- .../steps/lookups/lookups_data_input.tsx | 8 +- .../steps/macros/macros_data_input.test.tsx | 6 +- .../steps/macros/macros_data_input.tsx | 8 +- .../steps/rules/rules_data_input.test.tsx | 27 ++- .../steps/rules/rules_data_input.tsx | 109 ++++++++--- .../sub_steps/rules_file_upload/index.tsx | 29 ++- .../rules_file_upload.test.tsx | 2 + .../rules_file_upload/rules_file_upload.tsx | 19 +- .../rules_xml_file_upload.tsx | 183 ++++++++++++++++++ .../service/hooks/use_create_migration.ts | 10 +- .../rules/service/rule_migrations_service.ts | 31 +-- 19 files changed, 484 insertions(+), 150 deletions(-) create mode 100644 x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_xml_file_upload.tsx diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/index.tsx index f6d24f423e8a8..70a0d12eee2e4 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/index.tsx @@ -7,14 +7,14 @@ import { useState } from 'react'; import type { MigrationSource } from '../../types'; -import { MIGRATIONSOURCE_OPTIONS } from './migration_source_options'; -export const useMigrationSourceStep = () => { - const [migrationSource, setMigrationSource] = useState( - MIGRATIONSOURCE_OPTIONS[0].value - ); +export const useMigrationSourceStep = (initialMigrationSource: MigrationSource) => { + const [migrationSource, setMigrationSource] = useState(initialMigrationSource); + const [migrationSourceDisabled, setMigrationSourceDisabled] = useState(false); return { migrationSource, setMigrationSource, + migrationSourceDisabled, + setMigrationSourceDisabled, }; }; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_dropdown.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_dropdown.tsx index 11fade15c8a5c..c06b94364ee2a 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_dropdown.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_dropdown.tsx @@ -13,10 +13,11 @@ import { MIGRATIONSOURCE_OPTIONS } from './migration_source_options'; export interface MigrationSourceDropdownProps { migrationSource: MigrationSource; setMigrationSource: (migrationSource: MigrationSource) => void; + disabled: boolean; } export const MigrationSourceDropdown = React.memo( - ({ migrationSource, setMigrationSource }) => { + ({ migrationSource, setMigrationSource, disabled }) => { const [value, setValue] = useState(migrationSource); const [isTouched, setIsTouched] = useState(false); @@ -50,6 +51,7 @@ export const MigrationSourceDropdown = React.memo( }} label={i18n.MIGRATION_SOURCE_DROPDOWN_TITLE} fullWidth + helpText={disabled ? i18n.MIGRATION_SOURCE_DROPDOWN_HELPER_TEXT : undefined} > ( onBlur={onBlur} autoFocus data-test-subj="migrationSourceDropdown" + disabled={disabled} /> diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_options.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_options.tsx index a29969efa8bc6..c9b35b26d8758 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_options.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_options.tsx @@ -9,8 +9,12 @@ import type { EuiSuperSelectOption } from '@elastic/eui'; import { EuiIcon } from '@elastic/eui'; import { MigrationSource } from '../../types'; import * as i18n from './translations'; -import { +import type { DataInputStep, + QradarDataInputStep, +} from '../../../rules/components/data_input_flyout/steps/constants'; +import { + SplunkDataInputStep, DataInputStepId, } from '../../../rules/components/data_input_flyout/steps/constants'; import { RulesDataInput } from '../../../rules/components/data_input_flyout/steps/rules/rules_data_input'; @@ -48,8 +52,8 @@ export const useSplunkMigrationSteps = ({ migrationStats, onMigrationCreated, }: { - setDataInputStep: (step: DataInputStep) => void; - dataInputStep: DataInputStep; + setDataInputStep: (step: SplunkDataInputStep) => void; + dataInputStep: SplunkDataInputStep; migrationSource: MigrationSource; migrationStats?: RuleMigrationStats; onMigrationCreated: (createdMigrationStats: RuleMigrationStats) => void; @@ -73,20 +77,20 @@ export const useSplunkMigrationSteps = ({ ); setMissingResourcesIndexed(newMissingResourcesIndexed); if (newMissingResourcesIndexed.macros.length) { - setDataInputStep(DataInputStep.Macros); + setDataInputStep(SplunkDataInputStep.Macros); return; } if (newMissingResourcesIndexed.lookups.length) { - setDataInputStep(DataInputStep.Lookups); + setDataInputStep(SplunkDataInputStep.Lookups); return; } - setDataInputStep(DataInputStep.End); + setDataInputStep(SplunkDataInputStep.End); }, [setDataInputStep] ); const onAllLookupsCreated = useCallback(() => { - setDataInputStep(DataInputStep.End); + setDataInputStep(SplunkDataInputStep.End); }, [setDataInputStep]); const SPLUNK_MIGRATION_STEPS: SplunkMigrationSteps = useMemo( @@ -144,11 +148,10 @@ export const useQradarMigrationSteps = ({ migrationStats, }: { onMigrationCreated: (createdMigrationStats: RuleMigrationStats) => void; - dataInputStep: DataInputStep; + dataInputStep: QradarDataInputStep; migrationSource: MigrationSource; migrationStats?: RuleMigrationStats; }): QradarMigrationSteps | null => { - const onMissingResourcesFetched = useCallback(() => {}, []); const QRADAR_MIGRATION_STEPS: QradarMigrationSteps = useMemo( () => [ { @@ -159,12 +162,42 @@ export const useQradarMigrationSteps = ({ migrationSource, migrationStats, onMigrationCreated, - onMissingResourcesFetched, }, }, ], - [dataInputStep, migrationSource, migrationStats, onMigrationCreated, onMissingResourcesFetched] + [dataInputStep, migrationSource, migrationStats, onMigrationCreated] ); return migrationSource === MigrationSource.QRADAR ? QRADAR_MIGRATION_STEPS : null; }; + +export const useMigrationSteps = ({ + onMigrationCreated, + dataInputStep, + migrationSource, + migrationStats, + setMigrationDataInputStep, +}: { + onMigrationCreated: (createdMigrationStats: RuleMigrationStats) => void; + dataInputStep: DataInputStep; + migrationSource: MigrationSource; + migrationStats?: RuleMigrationStats; + setMigrationDataInputStep: (step: SplunkDataInputStep | QradarDataInputStep) => void; +}): SplunkMigrationSteps | QradarMigrationSteps | null => { + const splunkMigrationSteps: SplunkMigrationSteps | null = useSplunkMigrationSteps({ + setDataInputStep: setMigrationDataInputStep, + dataInputStep: dataInputStep[MigrationSource.SPLUNK], + migrationSource, + migrationStats, + onMigrationCreated, + }); + + const qradarMigrationSteps: QradarMigrationSteps | null = useQradarMigrationSteps({ + dataInputStep: dataInputStep[MigrationSource.QRADAR], + migrationSource, + migrationStats, + onMigrationCreated, + }); + + return splunkMigrationSteps ?? qradarMigrationSteps; +}; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/translations.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/translations.ts index 7f307855d70bc..d5a59900371ef 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/translations.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/translations.ts @@ -21,3 +21,8 @@ export const MIGRATION_SOURCE_DROPDOWN_OPTION_QRADAR = i18n.translate( 'xpack.securitySolution.siemMigrations.common.dataInputFlyout.migrationSource.option.qradar', { defaultMessage: 'QRadar' } ); + +export const MIGRATION_SOURCE_DROPDOWN_HELPER_TEXT = i18n.translate( + 'xpack.securitySolution.siemMigrations.common.dataInputFlyout.migrationSource.helperText', + { defaultMessage: 'You cannot change the migration source after creating a migration.' } +); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/api/index.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/api/index.ts index d773495744538..28f090d487020 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/api/index.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/api/index.ts @@ -54,7 +54,6 @@ import type { } from '../../../../common/siem_migrations/model/api/rules/rule_migration.gen'; import type { RuleMigrationStats } from '../types'; import type { GetMigrationStatsParams, GetMigrationsStatsAllParams } from '../../common/types'; -import { MigrationSource } from '../../common/types'; /** Retrieves the stats for the specific migration. */ export const getRuleMigrationStats = async ({ @@ -97,6 +96,26 @@ export const createRuleMigration = async ({ }); }; +export interface AddRulesToQradarMigrationParams { + /** `id` of the migration to add the rules to */ + migrationId: string; + /** The body containing the list of rules to be added to the migration */ + body: { xml: string }; + /** Optional AbortSignal for cancelling request */ + signal?: AbortSignal; +} + +export const addRulesToQRadarMigration = async ({ + migrationId, + body, + signal, +}: AddRulesToQradarMigrationParams) => { + return KibanaServices.get().http.post( + replaceParams(SIEM_RULE_MIGRATION_QRADAR_RULES_PATH, { migration_id: migrationId }), + { body: JSON.stringify(body), version: '1', signal } + ); +}; + export interface AddRulesToMigrationParams { /** `id` of the migration to add the rules to */ migrationId: string; @@ -104,8 +123,6 @@ export interface AddRulesToMigrationParams { body: CreateRuleMigrationRulesRequestBody; /** Optional AbortSignal for cancelling request */ signal?: AbortSignal; - /** The source of the migration */ - migrationSource: MigrationSource; } /** Adds provided rules to an existing migration */ @@ -113,15 +130,9 @@ export const addRulesToMigration = async ({ migrationId, body, signal, - migrationSource, }: AddRulesToMigrationParams) => { return KibanaServices.get().http.post( - replaceParams( - migrationSource === MigrationSource.QRADAR - ? SIEM_RULE_MIGRATION_QRADAR_RULES_PATH - : SIEM_RULE_MIGRATION_RULES_PATH, - { migration_id: migrationId } - ), + replaceParams(SIEM_RULE_MIGRATION_RULES_PATH, { migration_id: migrationId }), { body: JSON.stringify(body), version: '1', signal } ); }; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx index 1572ecb1d075e..bfa9b1d6ea1ab 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx @@ -23,27 +23,22 @@ import { SiemMigrationRetryFilter, SiemMigrationTaskStatus, } from '../../../../../common/siem_migrations/constants'; -import type { DataInputStepId } from './steps/constants'; -import { DataInputStep } from './steps/constants'; +import type { DataInputStep, DataInputStepId } from './steps/constants'; +import { QradarDataInputStep, SplunkDataInputStep } from './steps/constants'; import { useStartRulesMigrationModal } from '../../hooks/use_start_rules_migration_modal'; import type { RuleMigrationSettings, RuleMigrationStats } from '../../types'; import { useStartMigration } from '../../logic/use_start_migration'; import { useMigrationSourceStep } from '../../../common/components/migration_source_step'; import { MigrationSourceDropdown } from '../../../common/components/migration_source_step/migration_source_dropdown'; import { CenteredLoadingSpinner } from '../../../../common/components/centered_loading_spinner'; -import { - useQradarMigrationSteps, - useSplunkMigrationSteps, -} from '../../../common/components/migration_source_step/migration_source_options'; -import type { - QradarMigrationSteps, - SplunkMigrationSteps, - Step, -} from '../../../common/components/migration_source_step/types'; +import { useMigrationSteps } from '../../../common/components/migration_source_step/migration_source_options'; +import type { Step } from '../../../common/components/migration_source_step/types'; +import { MigrationSource } from '../../../common/types'; export interface MigrationDataInputFlyoutProps { onClose: () => void; migrationStats?: RuleMigrationStats; + migrationSource?: MigrationSource; } function StepRenderer({ step }: { step: Step }) { @@ -54,35 +49,60 @@ function StepRenderer({ step }: { step: Step }) { const RULES_MIGRATION_DATA_INPUT_FLYOUT_TITLE = 'rulesMigrationDataInputFlyoutTitle'; export const MigrationDataInputFlyout = React.memo( - ({ onClose, migrationStats: initialMigrationSats }) => { + ({ + onClose, + migrationStats: initialMigrationSats, + migrationSource: initialMigrationSource = MigrationSource.SPLUNK, + }) => { const modalTitleId = useGeneratedHtmlId({ prefix: RULES_MIGRATION_DATA_INPUT_FLYOUT_TITLE, }); + const { + migrationSource, + setMigrationSource, + migrationSourceDisabled, + setMigrationSourceDisabled, + } = useMigrationSourceStep(initialMigrationSource); + const [migrationStats, setMigrationStats] = useState( initialMigrationSats ); const isRetry = migrationStats?.status === SiemMigrationTaskStatus.FINISHED; - const [dataInputStep, setDataInputStep] = useState(DataInputStep.Rules); + const [dataInputStep, setDataInputStep] = useState({ + [MigrationSource.SPLUNK]: SplunkDataInputStep.Rules, + [MigrationSource.QRADAR]: QradarDataInputStep.Rules, + }); - const onMigrationCreated = useCallback((createdMigrationStats: RuleMigrationStats) => { - setMigrationStats(createdMigrationStats); - }, []); + const setMigrationDataInputStep = useCallback( + (step: DataInputStep[MigrationSource]) => { + setDataInputStep((prev) => ({ ...prev, ...{ [migrationSource]: step } })); + }, + [migrationSource] + ); + + const onMigrationCreated = useCallback( + (createdMigrationStats: RuleMigrationStats) => { + setMigrationStats(createdMigrationStats); + setMigrationSourceDisabled(true); + }, + [setMigrationStats, setMigrationSourceDisabled] + ); const { startMigration, isLoading: isStartLoading } = useStartMigration(onClose); const onStartMigrationWithSettings = useCallback( (settings: RuleMigrationSettings) => { - if (migrationStats?.id) { + if (typeof migrationStats?.id === 'string') { startMigration( - migrationStats.id, + migrationStats?.id as string, isRetry ? SiemMigrationRetryFilter.NOT_FULLY_TRANSLATED : undefined, settings ); } }, - [isRetry, migrationStats?.id, startMigration] + [isRetry, migrationStats, startMigration] ); const { modal: startMigrationModal, showModal: showStartMigrationModal } = useStartRulesMigrationModal({ @@ -94,27 +114,16 @@ export const MigrationDataInputFlyout = React.memo {startMigrationModal} @@ -142,6 +151,7 @@ export const MigrationDataInputFlyout = React.memo <> diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/constants.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/constants.ts index a8707f95ea54d..77684ea464f4c 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/constants.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/constants.ts @@ -5,13 +5,25 @@ * 2.0. */ -export enum DataInputStep { +import type { MigrationSource } from '../../../../common/types'; + +export enum SplunkDataInputStep { Rules = 1, Macros = 2, Lookups = 3, End = 10, } +export enum QradarDataInputStep { + Rules = 1, + End = 10, +} + +export interface DataInputStep { + [MigrationSource.SPLUNK]: SplunkDataInputStep; + [MigrationSource.QRADAR]: QradarDataInputStep; +} + export enum DataInputStepId { SplunkRules = 'splunk_rules', SplunkMacros = 'splunk_macros', diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.test.tsx index 5f0278be2f450..73a5748a84e68 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.test.tsx @@ -8,7 +8,7 @@ import { render } from '@testing-library/react'; import React from 'react'; import { LookupsDataInput } from './lookups_data_input'; -import { DataInputStep } from '../constants'; +import { SplunkDataInputStep } from '../constants'; import { getRuleMigrationStatsMock } from '../../../../__mocks__'; import { SiemMigrationTaskStatus } from '../../../../../../../common/siem_migrations/constants'; import { TestProviders } from '../../../../../../common/mock'; @@ -40,7 +40,7 @@ jest.mock('../../../../../../common/lib/kibana/kibana_react', () => ({ describe('LookupsDataInput', () => { const defaultProps = { onAllLookupsCreated: jest.fn(), - dataInputStep: DataInputStep.Lookups, + dataInputStep: SplunkDataInputStep.Lookups, migrationStats: getRuleMigrationStatsMock({ status: SiemMigrationTaskStatus.READY }), missingLookups: ['lookup1', 'lookup2'], }; @@ -84,7 +84,7 @@ describe('LookupsDataInput', () => { it('does not render description when dataInputStep is not LookupsUpload', () => { const { queryByTestId } = render( - + ); expect(queryByTestId('lookupsUploadDescription')).not.toBeInTheDocument(); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.tsx index 7e85980fd5329..dcab90085c33a 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.tsx @@ -25,7 +25,7 @@ import { useKibana } from '../../../../../../common/lib/kibana/kibana_react'; import type { RuleMigrationTaskStats } from '../../../../../../../common/siem_migrations/model/rule_migration.gen'; import type { OnResourcesCreated } from '../../types'; import * as i18n from './translations'; -import { DataInputStep } from '../constants'; +import { SplunkDataInputStep } from '../constants'; import { useMissingLookupsListStep } from './sub_steps/missing_lookups_list'; import { useLookupsFileUploadStep } from './sub_steps/lookups_file_upload'; @@ -36,14 +36,14 @@ interface LookupsDataInputSubStepsProps { } interface LookupsDataInputProps extends Omit { - dataInputStep: DataInputStep; + dataInputStep: SplunkDataInputStep; migrationStats?: RuleMigrationTaskStats; missingLookups?: string[]; } export const LookupsDataInput = React.memo( ({ dataInputStep, migrationStats, missingLookups, onAllLookupsCreated }) => { const dataInputStatus = useMemo( - () => getEuiStepStatus(DataInputStep.Lookups, dataInputStep), + () => getEuiStepStatus(SplunkDataInputStep.Lookups, dataInputStep), [dataInputStep] ); @@ -56,7 +56,7 @@ export const LookupsDataInput = React.memo( diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.test.tsx index af1622f9e8e1f..454548ebad41e 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.test.tsx @@ -8,7 +8,7 @@ import { act, fireEvent, render } from '@testing-library/react'; import React from 'react'; import { MacrosDataInput } from './macros_data_input'; -import { DataInputStep } from '../constants'; +import { SplunkDataInputStep } from '../constants'; import { getRuleMigrationStatsMock } from '../../../../__mocks__'; import { SiemMigrationTaskStatus } from '../../../../../../../common/siem_migrations/constants'; import { TestProviders } from '../../../../../../common/mock'; @@ -46,7 +46,7 @@ describe('MacrosDataInput', () => { const defaultProps = { onMissingResourcesFetched: jest.fn(), - dataInputStep: DataInputStep.Macros, + dataInputStep: SplunkDataInputStep.Macros, migrationStats: getRuleMigrationStatsMock({ status: SiemMigrationTaskStatus.READY }), missingMacros: ['macro1', 'macro2'], }; @@ -83,7 +83,7 @@ describe('MacrosDataInput', () => { it('does not render sub-steps when dataInputStep is not MacrosUpload', () => { const { queryByTestId } = render( - + ); expect(queryByTestId('migrationsSubSteps')).not.toBeInTheDocument(); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.tsx index 7915e63642ba7..9579cd6ee3681 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.tsx @@ -14,7 +14,7 @@ import { useKibana } from '../../../../../../common/lib/kibana/kibana_react'; import type { RuleMigrationTaskStats } from '../../../../../../../common/siem_migrations/model/rule_migration.gen'; import type { OnResourcesCreated, OnMissingResourcesFetched } from '../../types'; import * as i18n from './translations'; -import { DataInputStep } from '../constants'; +import { SplunkDataInputStep } from '../constants'; import { useCopyExportQueryStep } from './sub_steps/copy_export_query'; import { useMacrosFileUploadStep } from './sub_steps/macros_file_upload'; import { useCheckResourcesStep } from './sub_steps/check_resources'; @@ -26,14 +26,14 @@ interface MacrosDataInputSubStepsProps { } interface MacrosDataInputProps extends Omit { - dataInputStep: DataInputStep; + dataInputStep: SplunkDataInputStep; migrationStats?: RuleMigrationTaskStats; missingMacros?: string[]; } export const MacrosDataInput = React.memo( ({ dataInputStep, migrationStats, missingMacros, onMissingResourcesFetched }) => { const dataInputStatus = useMemo( - () => getEuiStepStatus(DataInputStep.Macros, dataInputStep), + () => getEuiStepStatus(SplunkDataInputStep.Macros, dataInputStep), [dataInputStep] ); @@ -46,7 +46,7 @@ export const MacrosDataInput = React.memo( diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.test.tsx index 492f2ef32f750..e48b680120647 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.test.tsx @@ -8,8 +8,9 @@ import React from 'react'; import { render } from '@testing-library/react'; import { RulesDataInput } from './rules_data_input'; -import { DataInputStep } from '../constants'; +import { SplunkDataInputStep } from '../constants'; import { TestProviders } from '../../../../../../common/mock/test_providers'; +import { MigrationSource } from '../../../../../common/types'; describe('RulesDataInput', () => { const defaultProps = { @@ -21,7 +22,11 @@ describe('RulesDataInput', () => { it('renders the step number', () => { const { getByTestId } = render( - + ); @@ -32,7 +37,11 @@ describe('RulesDataInput', () => { it('renders the title', () => { const { getByTestId } = render( - + ); @@ -43,7 +52,11 @@ describe('RulesDataInput', () => { it('renders sub-steps when the step is current', () => { const { getByTestId } = render( - + ); @@ -53,7 +66,11 @@ describe('RulesDataInput', () => { it('does not render sub-steps when the step is not current', () => { const { queryByTestId } = render( - + ); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx index f044b0d1baa2f..ff6fc442823ee 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx @@ -13,7 +13,7 @@ import { getEuiStepStatus } from '../../../../../common/utils/get_eui_step_statu import { useKibana } from '../../../../../../common/lib/kibana'; import type { OnMigrationCreated, OnMissingResourcesFetched } from '../../types'; import * as i18n from './translations'; -import { DataInputStep } from '../constants'; +import { QradarDataInputStep, SplunkDataInputStep } from '../constants'; import { useCopyExportQueryStep } from './sub_steps/copy_export_query'; import { useRulesFileUploadStep } from './sub_steps/rules_file_upload'; import { useCheckResourcesStep } from './sub_steps/check_resources'; @@ -23,11 +23,11 @@ import { MigrationSource } from '../../../../../common/types'; interface RulesDataInputSubStepsProps { migrationStats?: RuleMigrationStats; onMigrationCreated: OnMigrationCreated; - onMissingResourcesFetched: OnMissingResourcesFetched; + onMissingResourcesFetched?: OnMissingResourcesFetched; migrationSource: MigrationSource; } interface RulesDataInputProps extends RulesDataInputSubStepsProps { - dataInputStep: DataInputStep; + dataInputStep: SplunkDataInputStep | QradarDataInputStep; } export const RulesDataInput = React.memo( ({ @@ -37,9 +37,22 @@ export const RulesDataInput = React.memo( onMigrationCreated, onMissingResourcesFetched, }) => { + const dataInputNumber = useMemo( + () => + migrationSource === MigrationSource.QRADAR + ? QradarDataInputStep.Rules + : SplunkDataInputStep.Rules, + [migrationSource] + ); const dataInputStatus = useMemo( - () => getEuiStepStatus(DataInputStep.Rules, dataInputStep), - [dataInputStep] + () => + getEuiStepStatus( + migrationSource === MigrationSource.QRADAR + ? QradarDataInputStep.Rules + : SplunkDataInputStep.Rules, + dataInputStep + ), + [dataInputStep, migrationSource] ); return ( @@ -50,7 +63,7 @@ export const RulesDataInput = React.memo( @@ -84,36 +97,67 @@ type SubStep = 1 | 2 | 3 | 4 | typeof END; export const RulesDataInputSubSteps = React.memo( ({ migrationStats, onMigrationCreated, onMissingResourcesFetched, migrationSource }) => { const { telemetry } = useKibana().services.siemMigrations.rules; - const [subStep, setSubStep] = useState(migrationStats ? 4 : 1); + const [subStep, setSubStep] = useState<{ + [MigrationSource.SPLUNK]: SubStep; + [MigrationSource.QRADAR]: SubStep; + }>({ + [MigrationSource.QRADAR]: migrationStats ? 4 : 1, + [MigrationSource.SPLUNK]: migrationStats ? 4 : 1, + }); - const [migrationName, setMigrationName] = useState(migrationStats?.name); + const setMigrationSubStep = useCallback( + (step: SubStep) => { + setSubStep((prev) => ({ ...prev, ...{ [migrationSource]: step } })); + }, + [migrationSource] + ); + + const [migrationName, setMigrationName] = useState<{ + [MigrationSource.SPLUNK]: string | undefined; + [MigrationSource.QRADAR]: string | undefined; + }>({ + [MigrationSource.SPLUNK]: migrationStats?.name, + [MigrationSource.QRADAR]: migrationStats?.name, + }); + + const setRulesMigrationName = useCallback( + (name: string) => { + setMigrationName((prev) => ({ ...prev, ...{ [migrationSource]: name } })); + }, + [migrationSource] + ); const [isRulesFileReady, setIsRuleFileReady] = useState(false); // Migration name step const setName = useCallback( (name: string) => { - setMigrationName(name); + setRulesMigrationName(name); if (name) { - setSubStep(isRulesFileReady ? 3 : 2); + setMigrationSubStep(isRulesFileReady ? 3 : 2); } else { - setSubStep(1); + setMigrationSubStep(1); } }, - [isRulesFileReady] + [isRulesFileReady, setMigrationSubStep, setRulesMigrationName] ); const nameStep = useMigrationNameStep({ - status: getEuiStepStatus(1, subStep), + status: getEuiStepStatus(1, subStep[migrationSource]), setMigrationName: setName, - migrationName, + migrationName: migrationName[migrationSource], }); // Copy query step const onCopied = useCallback(() => { - setSubStep((currentSubStep) => (currentSubStep !== 1 ? 3 : currentSubStep)); // Move to the next step only if step 1 was completed + setSubStep((currentSubStep) => + currentSubStep[migrationSource] !== 1 + ? { ...currentSubStep, [migrationSource]: 3 } + : currentSubStep + ); // Move to the next step only if step 1 was completed + telemetry.reportSetupQueryCopied({ migrationId: migrationStats?.id }); - }, [telemetry, migrationStats?.id]); + }, [telemetry, migrationStats?.id, migrationSource]); const copyStep = useCopyExportQueryStep({ - status: getEuiStepStatus(2, subStep), + status: getEuiStepStatus(2, subStep[migrationSource]), onCopied, migrationSource, }); @@ -122,43 +166,46 @@ export const RulesDataInputSubSteps = React.memo( const onSplunkMigrationCreatedStep = useCallback( (stats) => { onMigrationCreated(stats); - setSubStep(4); + setMigrationSubStep(4); }, - [onMigrationCreated] + [onMigrationCreated, setMigrationSubStep] ); const onQradarMigrationCreatedStep = useCallback( (stats) => { onMigrationCreated(stats); - setSubStep(END); + setMigrationSubStep(END); + }, + [onMigrationCreated, setMigrationSubStep] + ); + const onRulesFileChanged = useCallback( + (files: FileList | null) => { + setIsRuleFileReady(!!files?.length); + setMigrationSubStep(3); }, - [onMigrationCreated] + [setMigrationSubStep] ); - const onRulesFileChanged = useCallback((files: FileList | null) => { - setIsRuleFileReady(!!files?.length); - setSubStep(3); - }, []); const uploadStep = useRulesFileUploadStep({ - status: getEuiStepStatus(3, subStep), + status: getEuiStepStatus(3, subStep[migrationSource]), migrationStats, onRulesFileChanged, onMigrationCreated: migrationSource === MigrationSource.SPLUNK ? onSplunkMigrationCreatedStep : onQradarMigrationCreatedStep, - migrationName, + migrationName: migrationName[migrationSource], migrationSource, }); // Check missing resources step const onMissingResourcesFetchedStep = useCallback( (missingResources) => { - onMissingResourcesFetched(missingResources); - setSubStep(END); + onMissingResourcesFetched?.(missingResources); + setMigrationSubStep(END); }, - [onMissingResourcesFetched] + [onMissingResourcesFetched, setMigrationSubStep] ); const resourcesStep = useCheckResourcesStep({ - status: getEuiStepStatus(4, subStep), + status: getEuiStepStatus(4, subStep[migrationSource]), migrationStats, onMissingResourcesFetched: onMissingResourcesFetchedStep, }); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/index.tsx index fda03c35dba66..04e80c0760d07 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/index.tsx @@ -15,7 +15,8 @@ import { type OnSuccess, } from '../../../../../../service/hooks/use_create_migration'; import * as i18n from './translations'; -import type { MigrationSource } from '../../../../../../../common/types'; +import { MigrationSource } from '../../../../../../../common/types'; +import { RulesXMLFileUpload } from './rules_xml_file_upload'; export interface RulesFileUploadStepProps { status: EuiStepStatus; @@ -33,13 +34,26 @@ export const useRulesFileUploadStep = ({ onMigrationCreated, onRulesFileChanged, }: RulesFileUploadStepProps): EuiStepProps => { - const [isCreated, setIsCreated] = useState(!!migrationStats); + const [isCreated, setIsCreated] = useState<{ + [MigrationSource.SPLUNK]: boolean; + [MigrationSource.QRADAR]: boolean; + }>({ + [MigrationSource.SPLUNK]: !!migrationStats, + [MigrationSource.QRADAR]: !!migrationStats, + }); + const setMigrationCreated = useCallback( + (created: boolean) => { + setIsCreated((prev) => ({ ...prev, ...{ [migrationSource]: created } })); + }, + [migrationSource] + ); + const onSuccess = useCallback( (stats) => { - setIsCreated(true); + setMigrationCreated(true); onMigrationCreated(stats); }, - [onMigrationCreated] + [onMigrationCreated, setMigrationCreated] ); const { createMigration, isLoading, error } = useCreateMigration(onSuccess); @@ -53,16 +67,19 @@ export const useRulesFileUploadStep = ({ return status; }, [isLoading, error, status]); + const Component = + migrationSource === MigrationSource.QRADAR ? RulesXMLFileUpload : RulesFileUpload; + return { title: i18n.RULES_DATA_INPUT_FILE_UPLOAD_TITLE, status: uploadStepStatus, children: ( - diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_file_upload.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_file_upload.test.tsx index 3049c602340fa..f4b34d48b0159 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_file_upload.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_file_upload.test.tsx @@ -17,6 +17,7 @@ import path from 'path'; import os from 'os'; import { splunkTestRules } from './splunk_rules.test.data'; import type { OriginalRule } from '../../../../../../../../../common/siem_migrations/model/rule_migration.gen'; +import { MigrationSource } from '../../../../../../../common/types'; const mockCreateMigration: CreateMigration = jest.fn(); const mockOnRulesFileChanged = jest.fn(); @@ -30,6 +31,7 @@ const defaultProps: RulesFileUploadProps = { isLoading: false, isCreated: false, migrationName, + migrationSource: MigrationSource.SPLUNK, }; const renderTestComponent = (props: Partial = {}) => { diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_file_upload.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_file_upload.tsx index e44590017edeb..a200948b83222 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_file_upload.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_file_upload.tsx @@ -15,16 +15,16 @@ import type { import { UploadFileButton } from '../../../../../../../common/components'; import { FILE_UPLOAD_ERROR } from '../../../../../../../common/translations/file_upload_error'; import { - useParseFileInput, type SplunkRow, + useParseFileInput, } from '../../../../../../../common/hooks/use_parse_file_input'; import type { CreateMigration } from '../../../../../../service/hooks/use_create_migration'; import type { CreateRuleMigrationRulesRequestBody } from '../../../../../../../../../common/siem_migrations/model/api/rules/rule_migration.gen'; import type { OriginalRule } from '../../../../../../../../../common/siem_migrations/model/rule_migration.gen'; -import type { SPLUNK_RULES_COLUMNS } from '../../../../constants'; import * as i18n from './translations'; import { MigrationSource } from '../../../../../../../common/types'; import { RULES_DATA_INPUT_CHECK_RESOURCES_DESCRIPTION } from '../check_resources/translations'; +import type { SPLUNK_RULES_COLUMNS } from '../../../../constants'; type SplunkRulesResult = Partial>; @@ -69,22 +69,13 @@ export const RulesFileUpload = React.memo( const { parseFile, isParsing, error: fileError } = useParseFileInput(onFileParsed); - // const onFileChange = useCallback( - // (files: FileList | null) => { - // setRulesToUpload([]); - // onRulesFileChanged(files); - // parseFile(files); - // }, - // [parseFile, onRulesFileChanged] - // ); - const onFileChange = useCallback( (files: FileList | null) => { - console.log('Files changed:', files); - setRulesToUpload(files?.length ? Array.from(files) : []); + setRulesToUpload([]); onRulesFileChanged(files); + parseFile(files); }, - [setRulesToUpload, onRulesFileChanged] + [parseFile, onRulesFileChanged] ); const error = useMemo(() => { diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_xml_file_upload.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_xml_file_upload.tsx new file mode 100644 index 0000000000000..a737c28dfa14f --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_xml_file_upload.tsx @@ -0,0 +1,183 @@ +/* + * 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, useMemo, useRef, useState } from 'react'; +import { EuiFilePicker, EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiText } from '@elastic/eui'; +import type { + EuiFilePickerClass, + EuiFilePickerProps, +} from '@elastic/eui/src/components/form/file_picker/file_picker'; +import { UploadFileButton } from '../../../../../../../common/components'; +import type { CreateMigration } from '../../../../../../service/hooks/use_create_migration'; +import * as i18n from './translations'; +import { MigrationSource } from '../../../../../../../common/types'; +import { RULES_DATA_INPUT_CHECK_RESOURCES_DESCRIPTION } from '../check_resources/translations'; +import { FILE_UPLOAD_ERROR } from '../../../../../../../common/translations/file_upload_error'; + +export interface RulesXMLFileUploadProps { + createMigration: CreateMigration; + isLoading: boolean; + isCreated: boolean; + onRulesFileChanged: (files: FileList | null) => void; + migrationName: string | undefined; + migrationSource: MigrationSource; + apiError: string | undefined; +} + +const RULES_DATA_INPUT_FILE_UPLOAD_PROMPT: Record = { + [MigrationSource.SPLUNK]: i18n.RULES_DATA_INPUT_FILE_UPLOAD_PROMPT_SPLUNK, + [MigrationSource.QRADAR]: i18n.RULES_DATA_INPUT_FILE_UPLOAD_PROMPT_QRADAR, +}; + +export const RulesXMLFileUpload = React.memo( + ({ + createMigration, + migrationName, + migrationSource, + apiError, + isLoading, + isCreated, + onRulesFileChanged, + }) => { + const [rulesToUpload, setRulesToUpload] = useState(); + const filePickerRef = useRef(null); + + const createRules = useCallback(() => { + if (migrationName && rulesToUpload) { + filePickerRef.current?.removeFiles(); + createMigration({ migrationName, rules: rulesToUpload, migrationSource }); + } + }, [createMigration, migrationName, migrationSource, rulesToUpload]); + + const onXMLFileParsed = useCallback((content: string) => { + setRulesToUpload(content); + }, []); + + const [isParsing, setIsParsing] = useState(false); + const [error, setError] = useState(); + + const parseFile = useCallback( + (files: FileList | null) => { + setError(undefined); + + if (!files || files.length === 0) { + return; + } + + const file = files[0]; + const reader = new FileReader(); + + reader.onloadstart = () => setIsParsing(true); + reader.onloadend = () => setIsParsing(false); + + reader.onload = function (e) { + // We can safely cast to string since we call `readAsText` to load the file. + const fileContent = e.target?.result as string | undefined; + + if (fileContent == null) { + setError(FILE_UPLOAD_ERROR.CAN_NOT_READ); + return; + } + + if (fileContent === '' && e.loaded > 100000) { + // V8-based browsers can't handle large files and return an empty string + // instead of an error; see https://stackoverflow.com/a/61316641 + setError(FILE_UPLOAD_ERROR.TOO_LARGE_TO_PARSE); + return; + } + + try { + onXMLFileParsed(fileContent); + } catch (err) { + setError(err.message); + } + }; + + const handleReaderError = function () { + const message = reader.error?.message; + if (message) { + setError(FILE_UPLOAD_ERROR.CAN_NOT_READ_WITH_REASON(message)); + } else { + setError(FILE_UPLOAD_ERROR.CAN_NOT_READ); + } + }; + + reader.onerror = handleReaderError; + reader.onabort = handleReaderError; + + reader.readAsText(file); + }, + [onXMLFileParsed] + ); + + const validationError = useMemo(() => { + if (apiError) { + return apiError; + } + return error; + }, [apiError, error]); + + const onFileChange = useCallback( + (files: FileList | null) => { + onRulesFileChanged(files); + parseFile(files); + }, + [parseFile, onRulesFileChanged] + ); + + const showLoader = isParsing || isLoading; + const isDisabled = !migrationName || showLoader || isCreated; + const isButtonDisabled = isDisabled || rulesToUpload == null; + + return ( + + + {RULES_DATA_INPUT_CHECK_RESOURCES_DESCRIPTION} + + + + >} + fullWidth + initialPromptText={ + + {RULES_DATA_INPUT_FILE_UPLOAD_PROMPT[migrationSource]} + + } + accept={ + migrationSource === MigrationSource.SPLUNK + ? 'application/json, application/x-ndjson' + : '.xml' + } + onChange={onFileChange} + display="large" + aria-label="Upload rules file" + isLoading={showLoader} + disabled={isDisabled} + data-test-subj="rulesFilePicker" + data-loading={isParsing} + /> + + + + + + + + + + + ); + } +); +RulesXMLFileUpload.displayName = 'RulesXMLFileUpload'; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.ts index 6015db9b75fa6..4e78a3f0bf0f4 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.ts @@ -34,7 +34,7 @@ export type CreateMigration = ({ }: { migrationName: string; migrationSource: MigrationSource; - rules: CreateRuleMigrationRulesRequestBody; + rules: CreateRuleMigrationRulesRequestBody | string; }) => void; export type OnSuccess = (migrationStats: RuleMigrationStats) => void; @@ -43,15 +43,11 @@ export const useCreateMigration = (onSuccess: OnSuccess) => { const [state, dispatch] = useReducer(reducer, initialState); const createMigration = useCallback( - ({ migrationName, migrationSource, rules }) => { + ({ migrationName, rules }) => { (async () => { try { dispatch({ type: 'start' }); - const migrationId = await siemMigrations.rules.createRuleMigration( - rules, - migrationName, - migrationSource - ); + const migrationId = await siemMigrations.rules.createRuleMigration(rules, migrationName); const stats = await siemMigrations.rules.api.getRuleMigrationStats({ migrationId, }); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/rule_migrations_service.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/rule_migrations_service.ts index 6bae1d6453aa1..a6410db364458 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/rule_migrations_service.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/rule_migrations_service.ts @@ -25,11 +25,7 @@ import { getMissingCapabilitiesToast, getNoConnectorToast, } from '../../common/service'; -import type { - GetMigrationStatsParams, - GetMigrationsStatsAllParams, - MigrationSource, -} from '../../common/types'; +import type { GetMigrationStatsParams, GetMigrationsStatsAllParams } from '../../common/types'; import { raiseSuccessToast } from './notification/success_notification'; import { START_STOP_POLLING_SLEEP_SECONDS } from '../../common/constants'; @@ -52,11 +48,19 @@ export class SiemRulesMigrationsService extends SiemMigrationsServiceBase { const rulesCount = data.length; if (rulesCount === 0) { @@ -87,7 +90,11 @@ export class SiemRulesMigrationsService extends SiemMigrationsServiceBase Date: Tue, 2 Dec 2025 14:46:56 +0000 Subject: [PATCH 03/23] clean up rules uploader component --- .../common/hooks/use_parse_file_input.ts | 7 +- .../macros_file_upload/macros_file_upload.tsx | 5 +- .../dashboards_file_upload.tsx | 11 ++- .../macros_file_upload/macros_file_upload.tsx | 5 +- .../rules_file_upload/rules_file_upload.tsx | 21 ++--- .../rules_xml_file_upload.tsx | 87 +++---------------- .../service/hooks/use_create_migration.ts | 2 +- 7 files changed, 37 insertions(+), 101 deletions(-) diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/hooks/use_parse_file_input.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/hooks/use_parse_file_input.ts index fcc87ed8584c7..553a9338696d2 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/hooks/use_parse_file_input.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/hooks/use_parse_file_input.ts @@ -12,7 +12,7 @@ export interface SplunkRow { result: T; } -export type OnFileParsed = (content: SplunkRow[]) => void; +export type OnFileParsed = (content: string) => void; export const useParseFileInput = (onFileParsed: OnFileParsed) => { const [isParsing, setIsParsing] = useState(false); @@ -49,8 +49,7 @@ export const useParseFileInput = (onFileParsed: OnFileParsed) => { } try { - const parsedData = parseContent(fileContent); - onFileParsed(parsedData); + onFileParsed(fileContent); } catch (err) { setError(err.message); } @@ -76,7 +75,7 @@ export const useParseFileInput = (onFileParsed: OnFileParsed) => { return { parseFile, isParsing, error }; }; -const parseContent = (fileContent: string): SplunkRow[] => { +export const parseContent = (fileContent: string): SplunkRow[] => { const trimmedContent = fileContent.trim(); let arrayContent: SplunkRow[]; if (trimmedContent.startsWith('[')) { diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/macros/sub_steps/macros_file_upload/macros_file_upload.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/macros/sub_steps/macros_file_upload/macros_file_upload.tsx index bf1b9e9d4d7fe..5ea1a3f623ce1 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/macros/sub_steps/macros_file_upload/macros_file_upload.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/macros/sub_steps/macros_file_upload/macros_file_upload.tsx @@ -15,6 +15,7 @@ import type { import { UploadFileButton } from '../../../../../../../common/components/migration_steps'; import { FILE_UPLOAD_ERROR } from '../../../../../../../common/translations/file_upload_error'; import { + parseContent, useParseFileInput, type SplunkRow, } from '../../../../../../../common/hooks/use_parse_file_input'; @@ -39,8 +40,8 @@ export const MacrosFileUpload = React.memo( createResources(macrosToUpload); }, [createResources, macrosToUpload]); - const onFileParsed = useCallback((content: Array>) => { - const macros = content.map(formatMacroRow); + const onFileParsed = useCallback((content: string) => { + const macros = parseContent(content).map(formatMacroRow); setMacrosToUpload(macros); }, []); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/upload_dashboards/sub_steps/dashboards_file_upload/dashboards_file_upload.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/upload_dashboards/sub_steps/dashboards_file_upload/dashboards_file_upload.tsx index fbae6842f093a..25557072e92b1 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/upload_dashboards/sub_steps/dashboards_file_upload/dashboards_file_upload.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/upload_dashboards/sub_steps/dashboards_file_upload/dashboards_file_upload.tsx @@ -15,7 +15,10 @@ import type { import { UploadFileButton } from '../../../../../../../common/components/migration_steps'; import { FILE_UPLOAD_ERROR } from '../../../../../../../common/translations/file_upload_error'; import type { SplunkRow } from '../../../../../../../common/hooks/use_parse_file_input'; -import { useParseFileInput } from '../../../../../../../common/hooks/use_parse_file_input'; +import { + parseContent, + useParseFileInput, +} from '../../../../../../../common/hooks/use_parse_file_input'; import * as i18n from './translations'; import type { SplunkDashboardsResult, OnMigrationCreated } from '../../../../types'; import type { CreateMigration } from '../../../../../../service/hooks/use_create_migration'; @@ -46,8 +49,10 @@ export const DashboardsFileUpload = React.memo( const filePickerRef = useRef(null); const onFileParsed = useCallback( - (content: Array>) => { - const dashboards = content.map(formatDashboardRow) as SplunkDashboardsResult[]; + (content: string) => { + const dashboards = parseContent(content).map( + formatDashboardRow + ) as SplunkDashboardsResult[]; setUploadedDashboards(dashboards); onFileUpload?.(dashboards); }, diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/sub_steps/macros_file_upload/macros_file_upload.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/sub_steps/macros_file_upload/macros_file_upload.tsx index d11b8f0c0d057..f93eab54801fe 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/sub_steps/macros_file_upload/macros_file_upload.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/sub_steps/macros_file_upload/macros_file_upload.tsx @@ -15,6 +15,7 @@ import type { import { UploadFileButton } from '../../../../../../../common/components'; import { FILE_UPLOAD_ERROR } from '../../../../../../../common/translations/file_upload_error'; import { + parseContent, useParseFileInput, type SplunkRow, } from '../../../../../../../common/hooks/use_parse_file_input'; @@ -39,8 +40,8 @@ export const MacrosFileUpload = React.memo( createResources(macrosToUpload); }, [createResources, macrosToUpload]); - const onFileParsed = useCallback((content: Array>) => { - const macros = content.map(formatMacroRow); + const onFileParsed = useCallback((content: string) => { + const macros = parseContent(content).map(formatMacroRow); setMacrosToUpload(macros); }, []); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_file_upload.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_file_upload.tsx index a200948b83222..087383d6895c4 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_file_upload.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_file_upload.tsx @@ -17,12 +17,13 @@ import { FILE_UPLOAD_ERROR } from '../../../../../../../common/translations/file import { type SplunkRow, useParseFileInput, + parseContent, } from '../../../../../../../common/hooks/use_parse_file_input'; import type { CreateMigration } from '../../../../../../service/hooks/use_create_migration'; import type { CreateRuleMigrationRulesRequestBody } from '../../../../../../../../../common/siem_migrations/model/api/rules/rule_migration.gen'; import type { OriginalRule } from '../../../../../../../../../common/siem_migrations/model/rule_migration.gen'; import * as i18n from './translations'; -import { MigrationSource } from '../../../../../../../common/types'; +import type { MigrationSource } from '../../../../../../../common/types'; import { RULES_DATA_INPUT_CHECK_RESOURCES_DESCRIPTION } from '../check_resources/translations'; import type { SPLUNK_RULES_COLUMNS } from '../../../../constants'; @@ -38,10 +39,6 @@ export interface RulesFileUploadProps { apiError: string | undefined; } -const RULES_DATA_INPUT_FILE_UPLOAD_PROMPT: Record = { - [MigrationSource.SPLUNK]: i18n.RULES_DATA_INPUT_FILE_UPLOAD_PROMPT_SPLUNK, - [MigrationSource.QRADAR]: i18n.RULES_DATA_INPUT_FILE_UPLOAD_PROMPT_QRADAR, -}; export const RulesFileUpload = React.memo( ({ createMigration, @@ -62,8 +59,8 @@ export const RulesFileUpload = React.memo( } }, [createMigration, migrationName, migrationSource, rulesToUpload]); - const onFileParsed = useCallback((content: Array>) => { - const rules = content.map(formatRuleRow); + const onFileParsed = useCallback((content: string) => { + const rules = parseContent(content).map(formatRuleRow); setRulesToUpload(rules); }, []); @@ -103,14 +100,10 @@ export const RulesFileUpload = React.memo( fullWidth initialPromptText={ - {RULES_DATA_INPUT_FILE_UPLOAD_PROMPT[migrationSource]} + {i18n.RULES_DATA_INPUT_FILE_UPLOAD_PROMPT_SPLUNK} } - accept={ - migrationSource === MigrationSource.SPLUNK - ? 'application/json, application/x-ndjson' - : '.xml' - } + accept={'application/json, application/x-ndjson'} onChange={onFileChange} display="large" aria-label="Upload rules file" @@ -138,7 +131,7 @@ export const RulesFileUpload = React.memo( ); RulesFileUpload.displayName = 'RulesFileUpload'; -const formatRuleRow = (row: SplunkRow): OriginalRule => { +export const formatRuleRow = (row: SplunkRow): OriginalRule => { if (!isPlainObject(row.result)) { throw new Error(FILE_UPLOAD_ERROR.NOT_OBJECT); } diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_xml_file_upload.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_xml_file_upload.tsx index a737c28dfa14f..dfa146fb5d4d5 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_xml_file_upload.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_xml_file_upload.tsx @@ -14,9 +14,9 @@ import type { import { UploadFileButton } from '../../../../../../../common/components'; import type { CreateMigration } from '../../../../../../service/hooks/use_create_migration'; import * as i18n from './translations'; -import { MigrationSource } from '../../../../../../../common/types'; +import type { MigrationSource } from '../../../../../../../common/types'; import { RULES_DATA_INPUT_CHECK_RESOURCES_DESCRIPTION } from '../check_resources/translations'; -import { FILE_UPLOAD_ERROR } from '../../../../../../../common/translations/file_upload_error'; +import { useParseFileInput } from '../../../../../../../common/hooks/use_parse_file_input'; export interface RulesXMLFileUploadProps { createMigration: CreateMigration; @@ -28,11 +28,6 @@ export interface RulesXMLFileUploadProps { apiError: string | undefined; } -const RULES_DATA_INPUT_FILE_UPLOAD_PROMPT: Record = { - [MigrationSource.SPLUNK]: i18n.RULES_DATA_INPUT_FILE_UPLOAD_PROMPT_SPLUNK, - [MigrationSource.QRADAR]: i18n.RULES_DATA_INPUT_FILE_UPLOAD_PROMPT_QRADAR, -}; - export const RulesXMLFileUpload = React.memo( ({ createMigration, @@ -57,77 +52,23 @@ export const RulesXMLFileUpload = React.memo( setRulesToUpload(content); }, []); - const [isParsing, setIsParsing] = useState(false); - const [error, setError] = useState(); + const { parseFile, isParsing, error: fileError } = useParseFileInput(onXMLFileParsed); - const parseFile = useCallback( + const onFileChange = useCallback( (files: FileList | null) => { - setError(undefined); - - if (!files || files.length === 0) { - return; - } - - const file = files[0]; - const reader = new FileReader(); - - reader.onloadstart = () => setIsParsing(true); - reader.onloadend = () => setIsParsing(false); - - reader.onload = function (e) { - // We can safely cast to string since we call `readAsText` to load the file. - const fileContent = e.target?.result as string | undefined; - - if (fileContent == null) { - setError(FILE_UPLOAD_ERROR.CAN_NOT_READ); - return; - } - - if (fileContent === '' && e.loaded > 100000) { - // V8-based browsers can't handle large files and return an empty string - // instead of an error; see https://stackoverflow.com/a/61316641 - setError(FILE_UPLOAD_ERROR.TOO_LARGE_TO_PARSE); - return; - } - - try { - onXMLFileParsed(fileContent); - } catch (err) { - setError(err.message); - } - }; - - const handleReaderError = function () { - const message = reader.error?.message; - if (message) { - setError(FILE_UPLOAD_ERROR.CAN_NOT_READ_WITH_REASON(message)); - } else { - setError(FILE_UPLOAD_ERROR.CAN_NOT_READ); - } - }; - - reader.onerror = handleReaderError; - reader.onabort = handleReaderError; - - reader.readAsText(file); + setRulesToUpload(undefined); + onRulesFileChanged(files); + parseFile(files); }, - [onXMLFileParsed] + [parseFile, onRulesFileChanged] ); const validationError = useMemo(() => { if (apiError) { return apiError; } - return error; - }, [apiError, error]); - - const onFileChange = useCallback( - (files: FileList | null) => { - onRulesFileChanged(files); - parseFile(files); - }, - [parseFile, onRulesFileChanged] - ); + return fileError; + }, [apiError, fileError]); const showLoader = isParsing || isLoading; const isDisabled = !migrationName || showLoader || isCreated; @@ -147,14 +88,10 @@ export const RulesXMLFileUpload = React.memo( fullWidth initialPromptText={ - {RULES_DATA_INPUT_FILE_UPLOAD_PROMPT[migrationSource]} + {i18n.RULES_DATA_INPUT_FILE_UPLOAD_PROMPT_QRADAR} } - accept={ - migrationSource === MigrationSource.SPLUNK - ? 'application/json, application/x-ndjson' - : '.xml' - } + accept={'.xml'} onChange={onFileChange} display="large" aria-label="Upload rules file" diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.ts index 4e78a3f0bf0f4..480e061c824a1 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.ts @@ -54,7 +54,7 @@ export const useCreateMigration = (onSuccess: OnSuccess) => { notifications.toasts.addSuccess({ title: RULES_DATA_INPUT_CREATE_MIGRATION_SUCCESS_TITLE, - text: RULES_DATA_INPUT_CREATE_MIGRATION_SUCCESS_DESCRIPTION(rules.length), + text: RULES_DATA_INPUT_CREATE_MIGRATION_SUCCESS_DESCRIPTION(stats.items.total), }); onSuccess(stats); dispatch({ type: 'success' }); From 8d081e42939bc5b9f0d04e6b478deb588ffc93a6 Mon Sep 17 00:00:00 2001 From: Angela Chuang Date: Tue, 2 Dec 2025 17:20:53 +0000 Subject: [PATCH 04/23] add component config --- .../migration_source_options.tsx | 76 +++++++----------- .../components/migration_source_step/types.ts | 16 ++-- .../components/migration_steps/configs.tsx | 31 +++++++ .../data_input_flyout/data_input_flyout.tsx | 5 +- .../steps/rules/rules_data_input.tsx | 80 ++++++------------- 5 files changed, 92 insertions(+), 116 deletions(-) create mode 100644 x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/configs.tsx diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_options.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_options.tsx index c9b35b26d8758..4e1c71b9d8499 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_options.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_options.tsx @@ -13,16 +13,11 @@ import type { DataInputStep, QradarDataInputStep, } from '../../../rules/components/data_input_flyout/steps/constants'; -import { - SplunkDataInputStep, - DataInputStepId, -} from '../../../rules/components/data_input_flyout/steps/constants'; -import { RulesDataInput } from '../../../rules/components/data_input_flyout/steps/rules/rules_data_input'; +import { SplunkDataInputStep } from '../../../rules/components/data_input_flyout/steps/constants'; import type { SiemMigrationResourceBase } from '../../../../../common/siem_migrations/model/common.gen'; import type { RuleMigrationStats } from '../../../rules/types'; -import { MacrosDataInput } from '../../../rules/components/data_input_flyout/steps/macros/macros_data_input'; -import { LookupsDataInput } from '../../../rules/components/data_input_flyout/steps/lookups/lookups_data_input'; import type { QradarMigrationSteps, SplunkMigrationSteps } from './types'; +import { STEP_COMPONENTS } from '../migration_steps/configs'; export const MIGRATIONSOURCE_OPTIONS: Array> = [ { @@ -94,47 +89,29 @@ export const useSplunkMigrationSteps = ({ }, [setDataInputStep]); const SPLUNK_MIGRATION_STEPS: SplunkMigrationSteps = useMemo( - () => [ - { - id: DataInputStepId.SplunkRules, - Component: RulesDataInput, + () => + STEP_COMPONENTS[MigrationSource.SPLUNK].map(({ id, Component }) => ({ + id, + Component, extraProps: { dataInputStep, migrationSource, migrationStats, - onMigrationCreated, - onMissingResourcesFetched, - }, - }, - { - id: DataInputStepId.SplunkMacros, - Component: MacrosDataInput, - extraProps: { - dataInputStep, - onMissingResourcesFetched, + missingLookups: missingResourcesIndexed?.lookups, missingMacros: missingResourcesIndexed?.macros, - migrationStats, - }, - }, - { - id: DataInputStepId.SplunkLookups, - Component: LookupsDataInput, - extraProps: { - dataInputStep, onAllLookupsCreated, - missingLookups: missingResourcesIndexed?.lookups, - migrationStats, + onMissingResourcesFetched, + onMigrationCreated, }, - }, - ], + })) as SplunkMigrationSteps, [ dataInputStep, migrationSource, migrationStats, onMigrationCreated, - onMissingResourcesFetched, missingResourcesIndexed, onAllLookupsCreated, + onMissingResourcesFetched, ] ); @@ -153,39 +130,40 @@ export const useQradarMigrationSteps = ({ migrationStats?: RuleMigrationStats; }): QradarMigrationSteps | null => { const QRADAR_MIGRATION_STEPS: QradarMigrationSteps = useMemo( - () => [ - { - id: DataInputStepId.QradarRules, - Component: RulesDataInput, + () => + STEP_COMPONENTS[MigrationSource.QRADAR].map(({ id, Component }) => ({ + id, + Component, extraProps: { dataInputStep, migrationSource, migrationStats, onMigrationCreated, }, - }, - ], + })), [dataInputStep, migrationSource, migrationStats, onMigrationCreated] ); return migrationSource === MigrationSource.QRADAR ? QRADAR_MIGRATION_STEPS : null; }; -export const useMigrationSteps = ({ - onMigrationCreated, - dataInputStep, - migrationSource, - migrationStats, - setMigrationDataInputStep, -}: { +interface UseMigrationStepsParams { onMigrationCreated: (createdMigrationStats: RuleMigrationStats) => void; dataInputStep: DataInputStep; migrationSource: MigrationSource; migrationStats?: RuleMigrationStats; setMigrationDataInputStep: (step: SplunkDataInputStep | QradarDataInputStep) => void; -}): SplunkMigrationSteps | QradarMigrationSteps | null => { +} + +export const useMigrationSteps = ({ + onMigrationCreated, + dataInputStep, + migrationSource, + migrationStats, + setMigrationDataInputStep: setDataInputStep, +}: UseMigrationStepsParams): SplunkMigrationSteps | QradarMigrationSteps | null => { const splunkMigrationSteps: SplunkMigrationSteps | null = useSplunkMigrationSteps({ - setDataInputStep: setMigrationDataInputStep, + setDataInputStep, dataInputStep: dataInputStep[MigrationSource.SPLUNK], migrationSource, migrationStats, diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/types.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/types.ts index c5550a9933b4a..150ceaadc9eb7 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/types.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/types.ts @@ -13,17 +13,17 @@ import type { RulesDataInput } from '../../../rules/components/data_input_flyout interface RulesStep { id: T; Component: typeof RulesDataInput; - extraProps: React.ComponentProps; + extraProps?: React.ComponentProps; } interface MacrosStep { id: DataInputStepId.SplunkMacros; Component: typeof MacrosDataInput; - extraProps: React.ComponentProps; + extraProps?: React.ComponentProps; } interface LookupsStep { id: DataInputStepId.SplunkLookups; Component: typeof LookupsDataInput; - extraProps: React.ComponentProps; + extraProps?: React.ComponentProps; } export type Step = @@ -35,10 +35,8 @@ export type Step = ? MacrosStep : LookupsStep; -export type SplunkMigrationSteps = [ - Step, - Step, - Step -]; +export type SplunkStep = RulesStep | MacrosStep | LookupsStep; -export type QradarMigrationSteps = [Step]; +export type SplunkMigrationSteps = SplunkStep[]; + +export type QradarMigrationSteps = Array>; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/configs.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/configs.tsx new file mode 100644 index 0000000000000..e295f8fee1364 --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/configs.tsx @@ -0,0 +1,31 @@ +/* + * 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 { MigrationSource } from '../../types'; +import { DataInputStepId } from '../../../rules/components/data_input_flyout/steps/constants'; +import { RulesDataInput } from '../../../rules/components/data_input_flyout/steps/rules/rules_data_input'; +import { MacrosDataInput } from '../../../rules/components/data_input_flyout/steps/macros/macros_data_input'; +import { LookupsDataInput } from '../../../rules/components/data_input_flyout/steps/lookups/lookups_data_input'; +import type { QradarMigrationSteps, SplunkMigrationSteps } from '../migration_source_step/types'; + +const SPLUNK_MIGRATION_STEPS: SplunkMigrationSteps = [ + { id: DataInputStepId.SplunkRules, Component: RulesDataInput }, + { id: DataInputStepId.SplunkMacros, Component: MacrosDataInput }, + { id: DataInputStepId.SplunkLookups, Component: LookupsDataInput }, +] as const; + +const QRADAR_MIGRATION_STEPS: QradarMigrationSteps = [ + { id: DataInputStepId.QradarRules, Component: RulesDataInput }, +] as const; + +export const STEP_COMPONENTS: { + [MigrationSource.SPLUNK]: SplunkMigrationSteps; + [MigrationSource.QRADAR]: QradarMigrationSteps; +} = { + [MigrationSource.SPLUNK]: SPLUNK_MIGRATION_STEPS, + [MigrationSource.QRADAR]: QRADAR_MIGRATION_STEPS, +}; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx index bfa9b1d6ea1ab..07e1874033bbd 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx @@ -42,8 +42,9 @@ export interface MigrationDataInputFlyoutProps { } function StepRenderer({ step }: { step: Step }) { - const Component = step.Component as React.ComponentType; - return ; + const Component = step.Component as React.ComponentType; + + return step.extraProps ? : ; } const RULES_MIGRATION_DATA_INPUT_FLYOUT_TITLE = 'rulesMigrationDataInputFlyoutTitle'; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx index ff6fc442823ee..4e026a5ec8074 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx @@ -97,67 +97,38 @@ type SubStep = 1 | 2 | 3 | 4 | typeof END; export const RulesDataInputSubSteps = React.memo( ({ migrationStats, onMigrationCreated, onMissingResourcesFetched, migrationSource }) => { const { telemetry } = useKibana().services.siemMigrations.rules; - const [subStep, setSubStep] = useState<{ - [MigrationSource.SPLUNK]: SubStep; - [MigrationSource.QRADAR]: SubStep; - }>({ - [MigrationSource.QRADAR]: migrationStats ? 4 : 1, - [MigrationSource.SPLUNK]: migrationStats ? 4 : 1, - }); - - const setMigrationSubStep = useCallback( - (step: SubStep) => { - setSubStep((prev) => ({ ...prev, ...{ [migrationSource]: step } })); - }, - [migrationSource] - ); + const [subStep, setSubStep] = useState(migrationStats ? 4 : 1); - const [migrationName, setMigrationName] = useState<{ - [MigrationSource.SPLUNK]: string | undefined; - [MigrationSource.QRADAR]: string | undefined; - }>({ - [MigrationSource.SPLUNK]: migrationStats?.name, - [MigrationSource.QRADAR]: migrationStats?.name, - }); + const [migrationName, setMigrationName] = useState(migrationStats?.name); - const setRulesMigrationName = useCallback( - (name: string) => { - setMigrationName((prev) => ({ ...prev, ...{ [migrationSource]: name } })); - }, - [migrationSource] - ); const [isRulesFileReady, setIsRuleFileReady] = useState(false); // Migration name step const setName = useCallback( (name: string) => { - setRulesMigrationName(name); + setMigrationName(name); if (name) { - setMigrationSubStep(isRulesFileReady ? 3 : 2); + setSubStep(isRulesFileReady ? 3 : 2); } else { - setMigrationSubStep(1); + setSubStep(1); } }, - [isRulesFileReady, setMigrationSubStep, setRulesMigrationName] + [isRulesFileReady] ); const nameStep = useMigrationNameStep({ - status: getEuiStepStatus(1, subStep[migrationSource]), + status: getEuiStepStatus(1, subStep), setMigrationName: setName, - migrationName: migrationName[migrationSource], + migrationName, }); // Copy query step const onCopied = useCallback(() => { - setSubStep((currentSubStep) => - currentSubStep[migrationSource] !== 1 - ? { ...currentSubStep, [migrationSource]: 3 } - : currentSubStep - ); // Move to the next step only if step 1 was completed + setSubStep((currentSubStep) => (currentSubStep !== 1 ? 3 : currentSubStep)); // Move to the next step only if step 1 was completed telemetry.reportSetupQueryCopied({ migrationId: migrationStats?.id }); - }, [telemetry, migrationStats?.id, migrationSource]); + }, [telemetry, migrationStats?.id]); const copyStep = useCopyExportQueryStep({ - status: getEuiStepStatus(2, subStep[migrationSource]), + status: getEuiStepStatus(2, subStep), onCopied, migrationSource, }); @@ -166,33 +137,30 @@ export const RulesDataInputSubSteps = React.memo( const onSplunkMigrationCreatedStep = useCallback( (stats) => { onMigrationCreated(stats); - setMigrationSubStep(4); + setSubStep(4); }, - [onMigrationCreated, setMigrationSubStep] + [onMigrationCreated] ); const onQradarMigrationCreatedStep = useCallback( (stats) => { onMigrationCreated(stats); - setMigrationSubStep(END); - }, - [onMigrationCreated, setMigrationSubStep] - ); - const onRulesFileChanged = useCallback( - (files: FileList | null) => { - setIsRuleFileReady(!!files?.length); - setMigrationSubStep(3); + setSubStep(END); }, - [setMigrationSubStep] + [onMigrationCreated] ); + const onRulesFileChanged = useCallback((files: FileList | null) => { + setIsRuleFileReady(!!files?.length); + setSubStep(3); + }, []); const uploadStep = useRulesFileUploadStep({ - status: getEuiStepStatus(3, subStep[migrationSource]), + status: getEuiStepStatus(3, subStep), migrationStats, onRulesFileChanged, onMigrationCreated: migrationSource === MigrationSource.SPLUNK ? onSplunkMigrationCreatedStep : onQradarMigrationCreatedStep, - migrationName: migrationName[migrationSource], + migrationName, migrationSource, }); @@ -200,12 +168,12 @@ export const RulesDataInputSubSteps = React.memo( const onMissingResourcesFetchedStep = useCallback( (missingResources) => { onMissingResourcesFetched?.(missingResources); - setMigrationSubStep(END); + setSubStep(END); }, - [onMissingResourcesFetched, setMigrationSubStep] + [onMissingResourcesFetched] ); const resourcesStep = useCheckResourcesStep({ - status: getEuiStepStatus(4, subStep[migrationSource]), + status: getEuiStepStatus(4, subStep), migrationStats, onMissingResourcesFetched: onMissingResourcesFetchedStep, }); From 2382d1992aab29b1c96fbdeda1fb335117f50d16 Mon Sep 17 00:00:00 2001 From: Angela Chuang Date: Wed, 3 Dec 2025 11:48:10 +0000 Subject: [PATCH 05/23] types --- .../migration_source_options.tsx | 90 ++++++++----------- .../components/migration_source_step/types.ts | 17 +++- .../steps/rules/rules_data_input.tsx | 11 +-- 3 files changed, 58 insertions(+), 60 deletions(-) diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_options.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_options.tsx index 4e1c71b9d8499..9dc4cb76c26b9 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_options.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_options.tsx @@ -15,10 +15,31 @@ import type { } from '../../../rules/components/data_input_flyout/steps/constants'; import { SplunkDataInputStep } from '../../../rules/components/data_input_flyout/steps/constants'; import type { SiemMigrationResourceBase } from '../../../../../common/siem_migrations/model/common.gen'; -import type { RuleMigrationStats } from '../../../rules/types'; -import type { QradarMigrationSteps, SplunkMigrationSteps } from './types'; +import type { + QradarMigrationSteps, + RulesDataInputSubStepsProps, + SplunkMigrationSteps, +} from './types'; import { STEP_COMPONENTS } from '../migration_steps/configs'; +interface MissingResourcesIndexed { + macros: string[]; + lookups: string[]; +} + +type UseMigrationStepsProps = Omit & { + dataInputStep: DataInputStep; + setMigrationDataInputStep: (step: SplunkDataInputStep | QradarDataInputStep) => void; +}; + +interface UseSplunkMigrationSteps extends Omit { + dataInputStep: SplunkDataInputStep; +} + +interface UseQradarMigrationSteps extends Omit { + dataInputStep: QradarDataInputStep; +} + export const MIGRATIONSOURCE_OPTIONS: Array> = [ { value: MigrationSource.SPLUNK, @@ -35,24 +56,13 @@ export const MIGRATIONSOURCE_OPTIONS: Array void; - dataInputStep: SplunkDataInputStep; - migrationSource: MigrationSource; - migrationStats?: RuleMigrationStats; - onMigrationCreated: (createdMigrationStats: RuleMigrationStats) => void; -}): SplunkMigrationSteps | null => { +}: UseSplunkMigrationSteps): SplunkMigrationSteps | null => { const [missingResourcesIndexed, setMissingResourcesIndexed] = useState< MissingResourcesIndexed | undefined >(); @@ -72,21 +82,21 @@ export const useSplunkMigrationSteps = ({ ); setMissingResourcesIndexed(newMissingResourcesIndexed); if (newMissingResourcesIndexed.macros.length) { - setDataInputStep(SplunkDataInputStep.Macros); + setMigrationDataInputStep(SplunkDataInputStep.Macros); return; } if (newMissingResourcesIndexed.lookups.length) { - setDataInputStep(SplunkDataInputStep.Lookups); + setMigrationDataInputStep(SplunkDataInputStep.Lookups); return; } - setDataInputStep(SplunkDataInputStep.End); + setMigrationDataInputStep(SplunkDataInputStep.End); }, - [setDataInputStep] + [setMigrationDataInputStep] ); const onAllLookupsCreated = useCallback(() => { - setDataInputStep(SplunkDataInputStep.End); - }, [setDataInputStep]); + setMigrationDataInputStep(SplunkDataInputStep.End); + }, [setMigrationDataInputStep]); const SPLUNK_MIGRATION_STEPS: SplunkMigrationSteps = useMemo( () => @@ -123,12 +133,7 @@ export const useQradarMigrationSteps = ({ dataInputStep, migrationSource, migrationStats, -}: { - onMigrationCreated: (createdMigrationStats: RuleMigrationStats) => void; - dataInputStep: QradarDataInputStep; - migrationSource: MigrationSource; - migrationStats?: RuleMigrationStats; -}): QradarMigrationSteps | null => { +}: UseQradarMigrationSteps): QradarMigrationSteps | null => { const QRADAR_MIGRATION_STEPS: QradarMigrationSteps = useMemo( () => STEP_COMPONENTS[MigrationSource.QRADAR].map(({ id, Component }) => ({ @@ -147,34 +152,17 @@ export const useQradarMigrationSteps = ({ return migrationSource === MigrationSource.QRADAR ? QRADAR_MIGRATION_STEPS : null; }; -interface UseMigrationStepsParams { - onMigrationCreated: (createdMigrationStats: RuleMigrationStats) => void; - dataInputStep: DataInputStep; - migrationSource: MigrationSource; - migrationStats?: RuleMigrationStats; - setMigrationDataInputStep: (step: SplunkDataInputStep | QradarDataInputStep) => void; -} - -export const useMigrationSteps = ({ - onMigrationCreated, - dataInputStep, - migrationSource, - migrationStats, - setMigrationDataInputStep: setDataInputStep, -}: UseMigrationStepsParams): SplunkMigrationSteps | QradarMigrationSteps | null => { +export const useMigrationSteps = ( + props: UseMigrationStepsProps +): SplunkMigrationSteps | QradarMigrationSteps | null => { const splunkMigrationSteps: SplunkMigrationSteps | null = useSplunkMigrationSteps({ - setDataInputStep, - dataInputStep: dataInputStep[MigrationSource.SPLUNK], - migrationSource, - migrationStats, - onMigrationCreated, + ...props, + dataInputStep: props.dataInputStep[MigrationSource.SPLUNK], }); const qradarMigrationSteps: QradarMigrationSteps | null = useQradarMigrationSteps({ - dataInputStep: dataInputStep[MigrationSource.QRADAR], - migrationSource, - migrationStats, - onMigrationCreated, + ...props, + dataInputStep: props.dataInputStep[MigrationSource.QRADAR], }); return splunkMigrationSteps ?? qradarMigrationSteps; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/types.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/types.ts index 150ceaadc9eb7..ec9c5fa9f45ae 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/types.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/types.ts @@ -5,10 +5,17 @@ * 2.0. */ -import type { DataInputStepId } from '../../../rules/components/data_input_flyout/steps/constants'; +import type { + DataInputStepId, + QradarDataInputStep, + SplunkDataInputStep, +} from '../../../rules/components/data_input_flyout/steps/constants'; import type { LookupsDataInput } from '../../../rules/components/data_input_flyout/steps/lookups/lookups_data_input'; import type { MacrosDataInput } from '../../../rules/components/data_input_flyout/steps/macros/macros_data_input'; import type { RulesDataInput } from '../../../rules/components/data_input_flyout/steps/rules/rules_data_input'; +import type { OnMissingResourcesFetched } from '../../../rules/components/data_input_flyout/types'; +import type { RuleMigrationStats } from '../../../rules/types'; +import type { MigrationSource } from '../../types'; interface RulesStep { id: T; @@ -40,3 +47,11 @@ export type SplunkStep = RulesStep | MacrosStep | LookupsStep; export type SplunkMigrationSteps = SplunkStep[]; export type QradarMigrationSteps = Array>; + +export interface RulesDataInputSubStepsProps { + dataInputStep: SplunkDataInputStep | QradarDataInputStep; + migrationSource: MigrationSource; + migrationStats?: RuleMigrationStats; + onMigrationCreated: (createdMigrationStats: RuleMigrationStats) => void; + onMissingResourcesFetched?: OnMissingResourcesFetched; +} diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx index 4e026a5ec8074..7d959436933c3 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx @@ -17,16 +17,10 @@ import { QradarDataInputStep, SplunkDataInputStep } from '../constants'; import { useCopyExportQueryStep } from './sub_steps/copy_export_query'; import { useRulesFileUploadStep } from './sub_steps/rules_file_upload'; import { useCheckResourcesStep } from './sub_steps/check_resources'; -import type { RuleMigrationStats } from '../../../../types'; import { MigrationSource } from '../../../../../common/types'; +import type { RulesDataInputSubStepsProps } from '../../../../../common/components/migration_source_step/types'; -interface RulesDataInputSubStepsProps { - migrationStats?: RuleMigrationStats; - onMigrationCreated: OnMigrationCreated; - onMissingResourcesFetched?: OnMissingResourcesFetched; - migrationSource: MigrationSource; -} -interface RulesDataInputProps extends RulesDataInputSubStepsProps { +interface RulesDataInputProps extends Omit { dataInputStep: SplunkDataInputStep | QradarDataInputStep; } export const RulesDataInput = React.memo( @@ -78,6 +72,7 @@ export const RulesDataInput = React.memo( {dataInputStatus === 'current' && ( Date: Wed, 3 Dec 2025 23:46:58 +0000 Subject: [PATCH 06/23] unit tests --- .../migration_source_dropdown.test.tsx | 55 +++++++++++++++++ .../migration_source_dropdown.tsx | 30 ++------- .../components/migration_source_step/types.ts | 6 +- .../use_migration_source_options.test.tsx | 35 +++++++++++ .../use_migration_source_options.tsx | 36 +++++++++++ ...ndex.tsx => use_migration_source_step.tsx} | 15 ++++- .../use_migration_steps.test.tsx | 61 +++++++++++++++++++ .../use_migration_steps.tsx} | 52 ++++++---------- .../data_input_flyout/data_input_flyout.tsx | 10 +-- 9 files changed, 233 insertions(+), 67 deletions(-) create mode 100644 x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_dropdown.test.tsx create mode 100644 x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/use_migration_source_options.test.tsx create mode 100644 x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/use_migration_source_options.tsx rename x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/{index.tsx => use_migration_source_step.tsx} (57%) create mode 100644 x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/use_migration_steps.test.tsx rename x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/{migration_source_step/migration_source_options.tsx => migration_steps/use_migration_steps.tsx} (83%) diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_dropdown.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_dropdown.test.tsx new file mode 100644 index 0000000000000..712138ad9c672 --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_dropdown.test.tsx @@ -0,0 +1,55 @@ +/* + * 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 { MigrationSource } from '../../types'; +import { MigrationSourceDropdown } from './migration_source_dropdown'; +import * as i18n from './translations'; + +describe('MigrationSourceDropdown', () => { + const mockSetMigrationSource = jest.fn(); + + const defaultProps = { + migrationSource: MigrationSource.SPLUNK, + setMigrationSource: mockSetMigrationSource, + disabled: false, + migrationSourceOptions: [ + { + value: MigrationSource.SPLUNK, + inputDisplay: {i18n.MIGRATION_SOURCE_DROPDOWN_OPTION_SPLUNK}, + }, + { + value: MigrationSource.QRADAR, + inputDisplay: {i18n.MIGRATION_SOURCE_DROPDOWN_OPTION_QRADAR}, + }, + ], + }; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('renders with initial value', () => { + render(); + + const select = screen.getByTestId('migrationSourceDropdown'); + expect(select.textContent).toContain(i18n.MIGRATION_SOURCE_DROPDOWN_OPTION_SPLUNK); + }); + + it('disables the dropdown when disabled equals true', () => { + render(); + + const select = screen.getByTestId('migrationSourceDropdown'); + expect(select).toBeDisabled(); + }); + + it('shows helper text when disabled', () => { + render(); + + expect(screen.getByText(i18n.MIGRATION_SOURCE_DROPDOWN_HELPER_TEXT)).toBeInTheDocument(); + }); +}); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_dropdown.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_dropdown.tsx index c06b94364ee2a..7d72d1ea6f5c2 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_dropdown.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_dropdown.tsx @@ -8,34 +8,18 @@ import React, { useCallback, useState } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiForm, EuiFormRow, EuiSuperSelect } from '@elastic/eui'; import * as i18n from './translations'; import type { MigrationSource } from '../../types'; -import { MIGRATIONSOURCE_OPTIONS } from './migration_source_options'; - -export interface MigrationSourceDropdownProps { - migrationSource: MigrationSource; - setMigrationSource: (migrationSource: MigrationSource) => void; - disabled: boolean; -} +import type { MigrationSourceDropdownProps } from './use_migration_source_step'; export const MigrationSourceDropdown = React.memo( - ({ migrationSource, setMigrationSource, disabled }) => { + ({ migrationSource, setMigrationSource, disabled, migrationSourceOptions }) => { const [value, setValue] = useState(migrationSource); - const [isTouched, setIsTouched] = useState(false); - - const checkAndSetMigrationSource = useCallback( - (selected: MigrationSource) => { - if (selected.length > 0) { - setMigrationSource(selected); - } - }, - [setMigrationSource] - ); const handleMigrationSourceChange = useCallback( (selected: MigrationSource) => { setValue(selected); - checkAndSetMigrationSource(selected); + setMigrationSource(selected); }, - [checkAndSetMigrationSource] + [setMigrationSource] ); const onBlur = useCallback(() => { @@ -46,16 +30,12 @@ export const MigrationSourceDropdown = React.memo( { - setIsTouched(true); - }} label={i18n.MIGRATION_SOURCE_DROPDOWN_TITLE} fullWidth helpText={disabled ? i18n.MIGRATION_SOURCE_DROPDOWN_HELPER_TEXT : undefined} > { id: T; Component: typeof RulesDataInput; - extraProps?: React.ComponentProps; + props?: React.ComponentProps; } interface MacrosStep { id: DataInputStepId.SplunkMacros; Component: typeof MacrosDataInput; - extraProps?: React.ComponentProps; + props?: React.ComponentProps; } interface LookupsStep { id: DataInputStepId.SplunkLookups; Component: typeof LookupsDataInput; - extraProps?: React.ComponentProps; + props?: React.ComponentProps; } export type Step = diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/use_migration_source_options.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/use_migration_source_options.test.tsx new file mode 100644 index 0000000000000..5676cc77a1bd3 --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/use_migration_source_options.test.tsx @@ -0,0 +1,35 @@ +/* + * 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 { renderHook } from '@testing-library/react'; +import { useMigrationSourceOptions } from './use_migration_source_options'; +import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; +import { MigrationSource } from '../../types'; + +jest.mock('../../../../common/hooks/use_experimental_features', () => ({ + useIsExperimentalFeatureEnabled: jest.fn(), +})); + +describe('useMigrationSourceOptions', () => { + it('returns only Splunk option when QRadar feature is disabled', () => { + const { result } = renderHook(() => { + (useIsExperimentalFeatureEnabled as jest.Mock).mockReturnValue(false); + return useMigrationSourceOptions(); + }); + expect(result.current.length).toEqual(1); + expect(result.current[0].value).toEqual(MigrationSource.SPLUNK); + }); + it('returns Splunk and QRadar options when QRadar feature is enabled', () => { + const { result } = renderHook(() => { + (useIsExperimentalFeatureEnabled as jest.Mock).mockReturnValue(true); + return useMigrationSourceOptions(); + }); + expect(result.current.length).toEqual(2); + expect(result.current[0].value).toEqual(MigrationSource.SPLUNK); + expect(result.current[1].value).toEqual(MigrationSource.QRADAR); + }); +}); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/use_migration_source_options.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/use_migration_source_options.tsx new file mode 100644 index 0000000000000..b4f79e0ee68bc --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/use_migration_source_options.tsx @@ -0,0 +1,36 @@ +/* + * 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 { EuiSuperSelectOption } from '@elastic/eui'; +import { EuiIcon } from '@elastic/eui'; +import { MigrationSource } from '../../types'; +import * as i18n from './translations'; +import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; + +export const useMigrationSourceOptions = () => { + const isQradarEnabled = useIsExperimentalFeatureEnabled('qradarRulesMigration'); + + const options: Array> = [ + { + value: MigrationSource.SPLUNK, + inputDisplay: {i18n.MIGRATION_SOURCE_DROPDOWN_OPTION_SPLUNK}, + }, + ]; + + if (isQradarEnabled) { + options.push({ + value: MigrationSource.QRADAR, + inputDisplay: ( + + {i18n.MIGRATION_SOURCE_DROPDOWN_OPTION_QRADAR} + + + ), + }); + } + return options; +}; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/use_migration_source_step.tsx similarity index 57% rename from x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/index.tsx rename to x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/use_migration_source_step.tsx index 70a0d12eee2e4..311d60979eceb 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/use_migration_source_step.tsx @@ -6,15 +6,28 @@ */ import { useState } from 'react'; +import type { EuiSuperSelectOption } from '@elastic/eui'; import type { MigrationSource } from '../../types'; +import { useMigrationSourceOptions } from './use_migration_source_options'; + +export interface MigrationSourceDropdownProps { + migrationSource: MigrationSource; + setMigrationSource: (migrationSource: MigrationSource) => void; + disabled: boolean; + migrationSourceOptions: Array>; +} export const useMigrationSourceStep = (initialMigrationSource: MigrationSource) => { + const migrationSourceOptions = useMigrationSourceOptions(); const [migrationSource, setMigrationSource] = useState(initialMigrationSource); - const [migrationSourceDisabled, setMigrationSourceDisabled] = useState(false); + const [migrationSourceDisabled, setMigrationSourceDisabled] = useState( + migrationSourceOptions.length <= 1 + ); return { migrationSource, setMigrationSource, migrationSourceDisabled, setMigrationSourceDisabled, + migrationSourceOptions, }; }; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/use_migration_steps.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/use_migration_steps.test.tsx new file mode 100644 index 0000000000000..3760d13154fe2 --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/use_migration_steps.test.tsx @@ -0,0 +1,61 @@ +/* + * 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 { + DataInputStepId, + QradarDataInputStep, + SplunkDataInputStep, +} from '../../../rules/components/data_input_flyout/steps/constants'; +import { MigrationSource } from '../../types'; +import type { UseMigrationStepsProps } from './use_migration_steps'; +import { useMigrationSteps } from './use_migration_steps'; +import { renderHook } from '@testing-library/react'; +import { SiemMigrationTaskStatus } from '../../../../../common/siem_migrations/constants'; + +describe('useMigrationSteps', () => { + const props: UseMigrationStepsProps = { + dataInputStep: { + [MigrationSource.SPLUNK]: SplunkDataInputStep.Rules, + [MigrationSource.QRADAR]: QradarDataInputStep.Rules, + }, + migrationSource: MigrationSource.SPLUNK, + setMigrationDataInputStep: jest.fn(), + migrationStats: { + id: 'test-id', + name: 'test-name', + status: SiemMigrationTaskStatus.FINISHED, + items: { + total: 1, + pending: 0, + failed: 0, + completed: 1, + processing: 0, + }, + created_at: '2024-01-01T00:00:00Z', + last_updated_at: '2024-01-01T00:00:00Z', + }, + onMigrationCreated: jest.fn(), + onMissingResourcesFetched: jest.fn(), + }; + + it('should return Splunk migration steps when migration source is Splunk', () => { + const { result } = renderHook(() => + useMigrationSteps({ ...props, migrationSource: MigrationSource.SPLUNK }) + ); + expect(result.current?.length).toEqual(3); + expect(result.current?.[0].id).toBe(DataInputStepId.SplunkRules); + expect(result.current?.[1].id).toBe(DataInputStepId.SplunkMacros); + expect(result.current?.[2].id).toBe(DataInputStepId.SplunkLookups); + }); + it('should return Qradar migration steps when migration source is Qradar', () => { + const { result } = renderHook(() => + useMigrationSteps({ ...props, migrationSource: MigrationSource.QRADAR }) + ); + expect(result.current?.length).toEqual(1); + expect(result.current?.[0].id).toBe(DataInputStepId.QradarRules); + }); +}); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_options.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/use_migration_steps.tsx similarity index 83% rename from x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_options.tsx rename to x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/use_migration_steps.tsx index 9dc4cb76c26b9..caf707643172f 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_options.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/use_migration_steps.tsx @@ -4,30 +4,25 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React, { useCallback, useMemo, useState } from 'react'; -import type { EuiSuperSelectOption } from '@elastic/eui'; -import { EuiIcon } from '@elastic/eui'; -import { MigrationSource } from '../../types'; -import * as i18n from './translations'; +import { useCallback, useMemo, useState } from 'react'; + +import type { SiemMigrationResourceBase } from '../../../../../common/siem_migrations/model/common.gen'; + import type { DataInputStep, QradarDataInputStep, } from '../../../rules/components/data_input_flyout/steps/constants'; import { SplunkDataInputStep } from '../../../rules/components/data_input_flyout/steps/constants'; -import type { SiemMigrationResourceBase } from '../../../../../common/siem_migrations/model/common.gen'; + +import { STEP_COMPONENTS } from './configs'; import type { QradarMigrationSteps, RulesDataInputSubStepsProps, SplunkMigrationSteps, -} from './types'; -import { STEP_COMPONENTS } from '../migration_steps/configs'; - -interface MissingResourcesIndexed { - macros: string[]; - lookups: string[]; -} +} from '../migration_source_step/types'; +import { MigrationSource } from '../../types'; -type UseMigrationStepsProps = Omit & { +export type UseMigrationStepsProps = Omit & { dataInputStep: DataInputStep; setMigrationDataInputStep: (step: SplunkDataInputStep | QradarDataInputStep) => void; }; @@ -40,23 +35,12 @@ interface UseQradarMigrationSteps extends Omit> = [ - { - value: MigrationSource.SPLUNK, - inputDisplay: {i18n.MIGRATION_SOURCE_DROPDOWN_OPTION_SPLUNK}, - }, - { - value: MigrationSource.QRADAR, - inputDisplay: ( - - {i18n.MIGRATION_SOURCE_DROPDOWN_OPTION_QRADAR} - - - ), - }, -]; - -export const useSplunkMigrationSteps = ({ +interface MissingResourcesIndexed { + macros: string[]; + lookups: string[]; +} + +const useSplunkMigrationSteps = ({ setMigrationDataInputStep, dataInputStep, migrationSource, @@ -103,7 +87,7 @@ export const useSplunkMigrationSteps = ({ STEP_COMPONENTS[MigrationSource.SPLUNK].map(({ id, Component }) => ({ id, Component, - extraProps: { + props: { dataInputStep, migrationSource, migrationStats, @@ -128,7 +112,7 @@ export const useSplunkMigrationSteps = ({ return migrationSource === MigrationSource.SPLUNK ? SPLUNK_MIGRATION_STEPS : null; }; -export const useQradarMigrationSteps = ({ +const useQradarMigrationSteps = ({ onMigrationCreated, dataInputStep, migrationSource, @@ -139,7 +123,7 @@ export const useQradarMigrationSteps = ({ STEP_COMPONENTS[MigrationSource.QRADAR].map(({ id, Component }) => ({ id, Component, - extraProps: { + props: { dataInputStep, migrationSource, migrationStats, diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx index 07e1874033bbd..749ec43276183 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx @@ -28,12 +28,12 @@ import { QradarDataInputStep, SplunkDataInputStep } from './steps/constants'; import { useStartRulesMigrationModal } from '../../hooks/use_start_rules_migration_modal'; import type { RuleMigrationSettings, RuleMigrationStats } from '../../types'; import { useStartMigration } from '../../logic/use_start_migration'; -import { useMigrationSourceStep } from '../../../common/components/migration_source_step'; +import { useMigrationSourceStep } from '../../../common/components/migration_source_step/use_migration_source_step'; import { MigrationSourceDropdown } from '../../../common/components/migration_source_step/migration_source_dropdown'; import { CenteredLoadingSpinner } from '../../../../common/components/centered_loading_spinner'; -import { useMigrationSteps } from '../../../common/components/migration_source_step/migration_source_options'; import type { Step } from '../../../common/components/migration_source_step/types'; import { MigrationSource } from '../../../common/types'; +import { useMigrationSteps } from '../../../common/components/migration_steps/use_migration_steps'; export interface MigrationDataInputFlyoutProps { onClose: () => void; @@ -42,9 +42,9 @@ export interface MigrationDataInputFlyoutProps { } function StepRenderer({ step }: { step: Step }) { - const Component = step.Component as React.ComponentType; + const Component = step.Component as React.ComponentType; - return step.extraProps ? : ; + return step.props ? : ; } const RULES_MIGRATION_DATA_INPUT_FLYOUT_TITLE = 'rulesMigrationDataInputFlyoutTitle'; @@ -64,6 +64,7 @@ export const MigrationDataInputFlyout = React.memo( @@ -153,6 +154,7 @@ export const MigrationDataInputFlyout = React.memo <> From ce06e6cbaf3e4e5a418a0786ef7d5727b928a7e1 Mon Sep 17 00:00:00 2001 From: Angela Chuang Date: Thu, 4 Dec 2025 00:50:41 +0000 Subject: [PATCH 07/23] lint --- .../private/translations/translations/de-DE.json | 1 - .../private/translations/translations/fr-FR.json | 1 - .../private/translations/translations/ja-JP.json | 1 - .../private/translations/translations/zh-CN.json | 1 - .../sub_steps/copy_export_query/index.test.tsx | 8 ++++++++ .../sub_steps/rules_file_upload/index.test.tsx | 4 ++++ .../service/hooks/use_create_migration.test.ts | 13 +++++++++++-- 7 files changed, 23 insertions(+), 6 deletions(-) diff --git a/x-pack/platform/plugins/private/translations/translations/de-DE.json b/x-pack/platform/plugins/private/translations/translations/de-DE.json index 26fe986605709..ffb90edda02a3 100644 --- a/x-pack/platform/plugins/private/translations/translations/de-DE.json +++ b/x-pack/platform/plugins/private/translations/translations/de-DE.json @@ -38566,7 +38566,6 @@ "xpack.securitySolution.siemMigrations.rules.dataInputFlyout.rules.copyExportQuery.description": "Loggen Sie sich in Ihr Splunk-Administratorkonto ein, gehen Sie zur {section} App und führen Sie die folgende Abfrage aus. Exportieren Sie Ihre Ergebnisse als {format}.", "xpack.securitySolution.siemMigrations.rules.dataInputFlyout.rules.copyExportQuery.description.section": "Search und Berichterstattung", "xpack.securitySolution.siemMigrations.rules.dataInputFlyout.rules.copyExportQuery.title": "Splunk-Regeln exportieren", - "xpack.securitySolution.siemMigrations.rules.dataInputFlyout.rules.rulesFileUpload.prompt": "Wählen Sie die exportierte JSON-Datei aus oder ziehen Sie sie per Drag-and-Drop.", "xpack.securitySolution.siemMigrations.rules.dataInputFlyout.rules.rulesFileUpload.title": "Exportierte Regeln aktualisieren", "xpack.securitySolution.siemMigrations.rules.dataInputFlyout.rules.title": "Regeln hochladen", "xpack.securitySolution.siemMigrations.rules.dataInputFlyout.title": "Splunk SIEM-Regeln hochladen", diff --git a/x-pack/platform/plugins/private/translations/translations/fr-FR.json b/x-pack/platform/plugins/private/translations/translations/fr-FR.json index d86df06fed5ea..5e050aa70ea9f 100644 --- a/x-pack/platform/plugins/private/translations/translations/fr-FR.json +++ b/x-pack/platform/plugins/private/translations/translations/fr-FR.json @@ -38822,7 +38822,6 @@ "xpack.securitySolution.siemMigrations.rules.dataInputFlyout.rules.copyExportQuery.description": "Connectez-vous à votre compte administrateur Splunk, rendez-vous dans l'application {section} et exécutez la recherche suivante. Exportez vos résultats au format {format}.", "xpack.securitySolution.siemMigrations.rules.dataInputFlyout.rules.copyExportQuery.description.section": "Recherche et Rapports", "xpack.securitySolution.siemMigrations.rules.dataInputFlyout.rules.copyExportQuery.title": "Exporter les règles Splunk", - "xpack.securitySolution.siemMigrations.rules.dataInputFlyout.rules.rulesFileUpload.prompt": "Sélectionnez ou faites un cliquer-glisser sur le fichier JSON exporté", "xpack.securitySolution.siemMigrations.rules.dataInputFlyout.rules.rulesFileUpload.title": "Mettre à jour les règles exportées", "xpack.securitySolution.siemMigrations.rules.dataInputFlyout.rules.title": "Charger les règles", "xpack.securitySolution.siemMigrations.rules.dataInputFlyout.title": "Charger les règles SIEM Splunk", diff --git a/x-pack/platform/plugins/private/translations/translations/ja-JP.json b/x-pack/platform/plugins/private/translations/translations/ja-JP.json index 044c97ba7631c..13e9aa73ef627 100644 --- a/x-pack/platform/plugins/private/translations/translations/ja-JP.json +++ b/x-pack/platform/plugins/private/translations/translations/ja-JP.json @@ -38864,7 +38864,6 @@ "xpack.securitySolution.siemMigrations.rules.dataInputFlyout.rules.copyExportQuery.description": "Splunk管理者アカウントにログインし、{section}アプリを開き、次のクエリを実行します。結果を{format}でエクスポートします。", "xpack.securitySolution.siemMigrations.rules.dataInputFlyout.rules.copyExportQuery.description.section": "検索とレポート", "xpack.securitySolution.siemMigrations.rules.dataInputFlyout.rules.copyExportQuery.title": "Splunkをエクスポート", - "xpack.securitySolution.siemMigrations.rules.dataInputFlyout.rules.rulesFileUpload.prompt": "エクスポートされたJSONファイルを選択するか、ドラッグしてドロップします", "xpack.securitySolution.siemMigrations.rules.dataInputFlyout.rules.rulesFileUpload.title": "エクスポートしたルールを更新", "xpack.securitySolution.siemMigrations.rules.dataInputFlyout.rules.title": "ルールのアップロード", "xpack.securitySolution.siemMigrations.rules.dataInputFlyout.title": "Splunk SIEMルールをアップロード", diff --git a/x-pack/platform/plugins/private/translations/translations/zh-CN.json b/x-pack/platform/plugins/private/translations/translations/zh-CN.json index 4376245c5e257..96042d3926191 100644 --- a/x-pack/platform/plugins/private/translations/translations/zh-CN.json +++ b/x-pack/platform/plugins/private/translations/translations/zh-CN.json @@ -38850,7 +38850,6 @@ "xpack.securitySolution.siemMigrations.rules.dataInputFlyout.rules.copyExportQuery.description": "登录到您的 Splunk 管理员帐户,前往 {section} 应用,然后运行以下查询。以 {format} 格式导出结果。", "xpack.securitySolution.siemMigrations.rules.dataInputFlyout.rules.copyExportQuery.description.section": "搜索和报告", "xpack.securitySolution.siemMigrations.rules.dataInputFlyout.rules.copyExportQuery.title": "导出 Splunk 规则", - "xpack.securitySolution.siemMigrations.rules.dataInputFlyout.rules.rulesFileUpload.prompt": "选择或拖放导出的 JSON 文件", "xpack.securitySolution.siemMigrations.rules.dataInputFlyout.rules.rulesFileUpload.title": "更新导出的规则", "xpack.securitySolution.siemMigrations.rules.dataInputFlyout.rules.title": "上传规则", "xpack.securitySolution.siemMigrations.rules.dataInputFlyout.title": "上传 Splunk SIEM 规则", diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/index.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/index.test.tsx index 79776dba609ac..09147a44f18a8 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/index.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/index.test.tsx @@ -9,6 +9,7 @@ import { renderHook } from '@testing-library/react'; import { useCopyExportQueryStep } from '.'; import type { CopyExportQueryStepProps } from '.'; import { TestProviders } from '../../../../../../../../common/mock'; +import { MigrationSource } from '../../../../../../../common/types'; const renderCopyExportQueryStep = (props: CopyExportQueryStepProps) => { const { result } = renderHook(() => useCopyExportQueryStep(props), { @@ -20,6 +21,7 @@ const renderCopyExportQueryStep = (props: CopyExportQueryStepProps) => { describe('useCopyExportQueryStep', () => { it('returns step props with "incomplete" status', () => { const result = renderCopyExportQueryStep({ + migrationSource: MigrationSource.SPLUNK, status: 'incomplete', onCopied: jest.fn(), }); @@ -32,6 +34,7 @@ describe('useCopyExportQueryStep', () => { it('returns step props with "complete" status', () => { const result = renderCopyExportQueryStep({ + migrationSource: MigrationSource.SPLUNK, status: 'complete', onCopied: jest.fn(), }); @@ -44,6 +47,7 @@ describe('useCopyExportQueryStep', () => { it('returns step props with "disabled" status', () => { const result = renderCopyExportQueryStep({ + migrationSource: MigrationSource.SPLUNK, status: 'disabled', onCopied: jest.fn(), }); @@ -56,6 +60,7 @@ describe('useCopyExportQueryStep', () => { it('returns step props with "loading" status', () => { const result = renderCopyExportQueryStep({ + migrationSource: MigrationSource.SPLUNK, status: 'loading', onCopied: jest.fn(), }); @@ -68,6 +73,7 @@ describe('useCopyExportQueryStep', () => { it('returns step props with "warning" status', () => { const result = renderCopyExportQueryStep({ + migrationSource: MigrationSource.SPLUNK, status: 'warning', onCopied: jest.fn(), }); @@ -80,6 +86,7 @@ describe('useCopyExportQueryStep', () => { it('returns step props with "danger" status', () => { const result = renderCopyExportQueryStep({ + migrationSource: MigrationSource.SPLUNK, status: 'danger', onCopied: jest.fn(), }); @@ -92,6 +99,7 @@ describe('useCopyExportQueryStep', () => { it('returns step props with "current" status', () => { const result = renderCopyExportQueryStep({ + migrationSource: MigrationSource.SPLUNK, status: 'current', onCopied: jest.fn(), }); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/index.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/index.test.tsx index 97361038d45f3..030ee563d7693 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/index.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/index.test.tsx @@ -9,6 +9,7 @@ import { renderHook } from '@testing-library/react'; import { useRulesFileUploadStep } from '.'; import { TestProviders } from '../../../../../../../../common/mock'; import { useCreateMigration } from '../../../../../../service/hooks/use_create_migration'; +import { MigrationSource } from '../../../../../../../common/types'; jest.mock('../../../../../../service/hooks/use_create_migration', () => ({ useCreateMigration: jest.fn(), @@ -36,6 +37,7 @@ describe('useRulesFileUploadStep', () => { migrationName: 'test', onMigrationCreated: jest.fn(), onRulesFileChanged: jest.fn(), + migrationSource: MigrationSource.SPLUNK, }), { wrapper: TestProviders } ); @@ -62,6 +64,7 @@ describe('useRulesFileUploadStep', () => { migrationName: 'test', onMigrationCreated: jest.fn(), onRulesFileChanged: jest.fn(), + migrationSource: MigrationSource.SPLUNK, }), { wrapper: TestProviders } ); @@ -88,6 +91,7 @@ describe('useRulesFileUploadStep', () => { migrationName: 'test', onMigrationCreated: jest.fn(), onRulesFileChanged: jest.fn(), + migrationSource: MigrationSource.SPLUNK, }), { wrapper: TestProviders } ); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.test.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.test.ts index 921e86b5f0777..fa649633d6acd 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.test.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.test.ts @@ -8,6 +8,7 @@ import { renderHook, act } from '@testing-library/react'; import { useCreateMigration } from './use_create_migration'; import { useKibana } from '../../../../common/lib/kibana/kibana_react'; +import { MigrationSource } from '../../../common/types'; jest.mock('../../../../common/lib/kibana/kibana_react', () => ({ useKibana: jest.fn(), @@ -51,7 +52,11 @@ describe('useCreateMigration', () => { const { result } = renderHook(() => useCreateMigration(onSuccess)); await act(async () => { - await result.current.createMigration('test-migration', []); + await result.current.createMigration({ + rules: [], + migrationName: 'test-migration', + migrationSource: MigrationSource.SPLUNK, + }); }); expect(createRuleMigration).toHaveBeenCalledWith([], 'test-migration'); @@ -68,7 +73,11 @@ describe('useCreateMigration', () => { const { result } = renderHook(() => useCreateMigration(onSuccess)); await act(async () => { - await result.current.createMigration('test-migration', []); + await result.current.createMigration({ + migrationName: 'test-migration', + rules: [], + migrationSource: MigrationSource.SPLUNK, + }); }); expect(addError).toHaveBeenCalledWith(error, { From 2105d14aa46fd05222f95c2a5b7f24086d3e7818 Mon Sep 17 00:00:00 2001 From: Angela Chuang Date: Thu, 4 Dec 2025 09:11:24 +0000 Subject: [PATCH 08/23] unit tests --- .../migration_name_step/migration_name_input.tsx | 1 + .../macros_file_upload.test.tsx | 16 +++++++++++----- .../dashboards_file_upload.test.tsx | 16 +++++++++++----- .../sub_steps/copy_export_query/index.test.tsx | 15 ++++++++------- .../rules_file_upload/rules_file_upload.test.tsx | 6 +++++- .../service/hooks/use_create_migration.test.ts | 14 +++++++++----- .../rules/service/hooks/use_create_migration.ts | 1 - 7 files changed, 45 insertions(+), 24 deletions(-) diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_name_step/migration_name_input.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_name_step/migration_name_input.tsx index 072b4e974dbc5..27fda2f7dfdcf 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_name_step/migration_name_input.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_name_step/migration_name_input.tsx @@ -62,6 +62,7 @@ export const MigrationNameInput = React.memo( onBlur={onBlur} onKeyDown={onEnter} fullWidth + autoFocus data-test-subj="migrationNameInput" /> diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/macros/sub_steps/macros_file_upload/macros_file_upload.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/macros/sub_steps/macros_file_upload/macros_file_upload.test.tsx index 578943d1cc1f6..55d3b2098ff48 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/macros/sub_steps/macros_file_upload/macros_file_upload.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/macros/sub_steps/macros_file_upload/macros_file_upload.test.tsx @@ -11,9 +11,15 @@ import { MacrosFileUpload } from './macros_file_upload'; import { TestProviders } from '../../../../../../../../common/mock'; import { useParseFileInput } from '../../../../../../../common/hooks/use_parse_file_input'; -jest.mock('../../../../../../../common/hooks/use_parse_file_input', () => ({ - useParseFileInput: jest.fn(), -})); +jest.mock('../../../../../../../common/hooks/use_parse_file_input', () => { + const { parseContent } = jest.requireActual( + '../../../../../../../common/hooks/use_parse_file_input' + ); + return { + parseContent, + useParseFileInput: jest.fn(), + }; +}); jest.mock('../../../../../../../common/components/migration_steps', () => ({ UploadFileButton: ({ @@ -34,7 +40,7 @@ jest.mock('../../../../../../../common/components/migration_steps', () => ({ describe('MacrosFileUpload', () => { const mockUseParseFileInput = useParseFileInput as jest.Mock; const mockParseFile = jest.fn(); - let onFileParsedCallback: (content: Array<{ result: Record }>) => void; + let onFileParsedCallback: (content: string) => void; beforeEach(() => { mockUseParseFileInput.mockImplementation((onFileParsed: typeof onFileParsedCallback) => { @@ -77,7 +83,7 @@ describe('MacrosFileUpload', () => { expect(mockParseFile).toHaveBeenCalledWith([file]); await act(async () => { - onFileParsedCallback([{ result: { title: 'test', definition: 'test' } }]); + onFileParsedCallback('[{ "result": { "title": "test", "definition": "test" } }]'); }); const uploadButton = getByText('Upload'); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/upload_dashboards/sub_steps/dashboards_file_upload/dashboards_file_upload.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/upload_dashboards/sub_steps/dashboards_file_upload/dashboards_file_upload.test.tsx index 7ef6cfcfdab7e..7b7994132a113 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/upload_dashboards/sub_steps/dashboards_file_upload/dashboards_file_upload.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/upload_dashboards/sub_steps/dashboards_file_upload/dashboards_file_upload.test.tsx @@ -11,9 +11,15 @@ import { DashboardsFileUpload } from './dashboards_file_upload'; import { TestProviders } from '../../../../../../../../common/mock'; import { useParseFileInput } from '../../../../../../../common/hooks/use_parse_file_input'; -jest.mock('../../../../../../../common/hooks/use_parse_file_input', () => ({ - useParseFileInput: jest.fn(), -})); +jest.mock('../../../../../../../common/hooks/use_parse_file_input', () => { + const { parseContent } = jest.requireActual( + '../../../../../../../common/hooks/use_parse_file_input' + ); + return { + parseContent, + useParseFileInput: jest.fn(), + }; +}); jest.mock('../../../../../../../common/components/migration_steps', () => ({ UploadFileButton: ({ @@ -34,7 +40,7 @@ jest.mock('../../../../../../../common/components/migration_steps', () => ({ describe('DashboardsFileUpload', () => { const mockUseParseFileInput = useParseFileInput as jest.Mock; const mockParseFile = jest.fn(); - let onFileParsedCallback: (content: Array<{ result: Record }>) => void; + let onFileParsedCallback: (content: string) => void; beforeEach(() => { mockUseParseFileInput.mockImplementation((onFileParsed: typeof onFileParsedCallback) => { @@ -90,7 +96,7 @@ describe('DashboardsFileUpload', () => { expect(mockParseFile).toHaveBeenCalledWith([file]); await act(async () => { - onFileParsedCallback([{ result: {} }]); + onFileParsedCallback('[{ "result": {} }]'); }); const uploadButton = getByText('Upload'); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/index.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/index.test.tsx index 09147a44f18a8..fa29151ce60eb 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/index.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/index.test.tsx @@ -19,6 +19,7 @@ const renderCopyExportQueryStep = (props: CopyExportQueryStepProps) => { }; describe('useCopyExportQueryStep', () => { + const title = 'Copy rule query'; it('returns step props with "incomplete" status', () => { const result = renderCopyExportQueryStep({ migrationSource: MigrationSource.SPLUNK, @@ -28,7 +29,7 @@ describe('useCopyExportQueryStep', () => { expect(result.current).toEqual({ children: expect.anything(), status: 'incomplete', - title: 'Export Splunk rules', + title, }); }); @@ -41,7 +42,7 @@ describe('useCopyExportQueryStep', () => { expect(result.current).toEqual({ children: expect.anything(), status: 'complete', - title: 'Export Splunk rules', + title, }); }); @@ -54,7 +55,7 @@ describe('useCopyExportQueryStep', () => { expect(result.current).toEqual({ children: expect.anything(), status: 'disabled', - title: 'Export Splunk rules', + title, }); }); @@ -67,7 +68,7 @@ describe('useCopyExportQueryStep', () => { expect(result.current).toEqual({ children: expect.anything(), status: 'loading', - title: 'Export Splunk rules', + title, }); }); @@ -80,7 +81,7 @@ describe('useCopyExportQueryStep', () => { expect(result.current).toEqual({ children: expect.anything(), status: 'warning', - title: 'Export Splunk rules', + title, }); }); @@ -93,7 +94,7 @@ describe('useCopyExportQueryStep', () => { expect(result.current).toEqual({ children: expect.anything(), status: 'danger', - title: 'Export Splunk rules', + title, }); }); @@ -106,7 +107,7 @@ describe('useCopyExportQueryStep', () => { expect(result.current).toEqual({ children: expect.anything(), status: 'current', - title: 'Export Splunk rules', + title, }); }); }); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_file_upload.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_file_upload.test.tsx index f4b34d48b0159..482e2e955462a 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_file_upload.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_file_upload.test.tsx @@ -117,7 +117,11 @@ describe('RulesFileUpload', () => { severity: rule['alert.severity'] as OriginalRule['severity'], })); - expect(mockCreateMigration).toHaveBeenNthCalledWith(1, migrationName, rulesToExpect); + expect(mockCreateMigration).toHaveBeenNthCalledWith(1, { + migrationName, + rules: rulesToExpect, + migrationSource: MigrationSource.SPLUNK, + }); }); describe('Error Handling', () => { diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.test.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.test.ts index fa649633d6acd..401a2ea609f8b 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.test.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.test.ts @@ -8,6 +8,7 @@ import { renderHook, act } from '@testing-library/react'; import { useCreateMigration } from './use_create_migration'; import { useKibana } from '../../../../common/lib/kibana/kibana_react'; +import type { CreateRuleMigrationRulesRequestBody } from '../../../../../common/siem_migrations/model/api/rules/rule_migration.gen'; import { MigrationSource } from '../../../common/types'; jest.mock('../../../../common/lib/kibana/kibana_react', () => ({ @@ -22,6 +23,9 @@ describe('useCreateMigration', () => { const addSuccess = jest.fn(); const addError = jest.fn(); const onSuccess = jest.fn(); + const rules: CreateRuleMigrationRulesRequestBody = [ + { id: 'test-rule' }, + ] as CreateRuleMigrationRulesRequestBody; beforeEach(() => { jest.clearAllMocks(); @@ -47,22 +51,22 @@ describe('useCreateMigration', () => { it('should call createRuleMigration and onSuccess on success', async () => { createRuleMigration.mockResolvedValue('migration-id'); - getRuleMigrationStats.mockResolvedValue({ id: 'migration-id' }); + getRuleMigrationStats.mockResolvedValue({ id: 'migration-id', items: { total: 1 } }); const { result } = renderHook(() => useCreateMigration(onSuccess)); await act(async () => { await result.current.createMigration({ - rules: [], + rules, migrationName: 'test-migration', migrationSource: MigrationSource.SPLUNK, }); }); - expect(createRuleMigration).toHaveBeenCalledWith([], 'test-migration'); + expect(createRuleMigration).toHaveBeenCalledWith(rules, 'test-migration'); expect(getRuleMigrationStats).toHaveBeenCalledWith({ migrationId: 'migration-id' }); expect(addSuccess).toHaveBeenCalled(); - expect(onSuccess).toHaveBeenCalledWith({ id: 'migration-id' }); + expect(onSuccess).toHaveBeenCalledWith({ id: 'migration-id', items: { total: 1 } }); expect(result.current.isLoading).toBe(false); }); @@ -75,7 +79,7 @@ describe('useCreateMigration', () => { await act(async () => { await result.current.createMigration({ migrationName: 'test-migration', - rules: [], + rules, migrationSource: MigrationSource.SPLUNK, }); }); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.ts index 480e061c824a1..581368699ca16 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.ts @@ -51,7 +51,6 @@ export const useCreateMigration = (onSuccess: OnSuccess) => { const stats = await siemMigrations.rules.api.getRuleMigrationStats({ migrationId, }); - notifications.toasts.addSuccess({ title: RULES_DATA_INPUT_CREATE_MIGRATION_SUCCESS_TITLE, text: RULES_DATA_INPUT_CREATE_MIGRATION_SUCCESS_DESCRIPTION(stats.items.total), From 682e4d469393d8d5068ac40f7480745f12332a61 Mon Sep 17 00:00:00 2001 From: Angela Chuang Date: Thu, 4 Dec 2025 14:14:50 +0000 Subject: [PATCH 09/23] unit tests --- .../macros_file_upload.test.tsx | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/sub_steps/macros_file_upload/macros_file_upload.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/sub_steps/macros_file_upload/macros_file_upload.test.tsx index 95d406e15cf7d..a7d2e1da34529 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/sub_steps/macros_file_upload/macros_file_upload.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/sub_steps/macros_file_upload/macros_file_upload.test.tsx @@ -11,9 +11,15 @@ import { MacrosFileUpload } from './macros_file_upload'; import { TestProviders } from '../../../../../../../../common/mock'; import { useParseFileInput } from '../../../../../../../common/hooks/use_parse_file_input'; -jest.mock('../../../../../../../common/hooks/use_parse_file_input', () => ({ - useParseFileInput: jest.fn(), -})); +jest.mock('../../../../../../../common/hooks/use_parse_file_input', () => { + const { parseContent } = jest.requireActual( + '../../../../../../../common/hooks/use_parse_file_input' + ); + return { + parseContent, + useParseFileInput: jest.fn(), + }; +}); jest.mock('../../../../../../../common/components', () => ({ UploadFileButton: ({ @@ -34,7 +40,7 @@ jest.mock('../../../../../../../common/components', () => ({ describe('MacrosFileUpload', () => { const mockUseParseFileInput = useParseFileInput as jest.Mock; const mockParseFile = jest.fn(); - let onFileParsedCallback: (content: Array<{ result: Record }>) => void; + let onFileParsedCallback: (content: string) => void; beforeEach(() => { mockUseParseFileInput.mockImplementation((onFileParsed: typeof onFileParsedCallback) => { @@ -77,7 +83,7 @@ describe('MacrosFileUpload', () => { expect(mockParseFile).toHaveBeenCalledWith([file]); await act(async () => { - onFileParsedCallback([{ result: { title: 'test', definition: 'test' } }]); + onFileParsedCallback('[{ "result": { "title": "test", "definition": "test" } }]'); }); const uploadButton = getByText('Upload'); From a908d77880d724a8b572368e16258dfecc78fd07 Mon Sep 17 00:00:00 2001 From: Angela Chuang Date: Fri, 5 Dec 2025 16:01:24 +0000 Subject: [PATCH 10/23] types --- .../migration_source_dropdown.test.tsx | 2 +- .../migration_source_dropdown.tsx | 13 +---- .../components/migration_source_step/types.ts | 57 ------------------- .../use_migration_source_options.test.tsx | 2 +- .../use_migration_source_options.tsx | 2 +- .../use_migration_source_step.tsx | 2 +- .../components/migration_steps/configs.tsx | 17 +++--- .../components/migration_steps/types.ts | 28 ++++++++- .../use_migration_steps.test.tsx | 11 ++-- .../migration_steps/use_migration_steps.tsx | 23 +++++--- .../public/siem_migrations/common/types.ts | 5 -- .../data_input_flyout/data_input_flyout.tsx | 11 ++-- .../data_input_flyout/steps/constants.ts | 15 +++-- .../steps/rules/rules_data_input.test.tsx | 2 +- .../steps/rules/rules_data_input.tsx | 4 +- .../sub_steps/copy_export_query/index.tsx | 2 +- .../rules_file_upload/index.test.tsx | 2 +- .../sub_steps/rules_file_upload/index.tsx | 22 ++----- .../rules_file_upload.test.tsx | 2 +- .../rules_file_upload/rules_file_upload.tsx | 2 +- .../rules_xml_file_upload.tsx | 2 +- .../hooks/use_create_migration.test.ts | 2 +- .../service/hooks/use_create_migration.ts | 3 +- .../public/siem_migrations/rules/types.ts | 5 ++ 24 files changed, 99 insertions(+), 137 deletions(-) delete mode 100644 x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/types.ts diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_dropdown.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_dropdown.test.tsx index 712138ad9c672..0481d2ffeb6df 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_dropdown.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_dropdown.test.tsx @@ -6,9 +6,9 @@ */ import React from 'react'; import { render, screen } from '@testing-library/react'; -import { MigrationSource } from '../../types'; import { MigrationSourceDropdown } from './migration_source_dropdown'; import * as i18n from './translations'; +import { MigrationSource } from '../../../rules/types'; describe('MigrationSourceDropdown', () => { const mockSetMigrationSource = jest.fn(); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_dropdown.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_dropdown.tsx index 7d72d1ea6f5c2..e121cdb495324 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_dropdown.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_dropdown.tsx @@ -4,27 +4,21 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React, { useCallback, useState } from 'react'; +import React, { useCallback } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiForm, EuiFormRow, EuiSuperSelect } from '@elastic/eui'; import * as i18n from './translations'; -import type { MigrationSource } from '../../types'; import type { MigrationSourceDropdownProps } from './use_migration_source_step'; +import type { MigrationSource } from '../../../rules/types'; export const MigrationSourceDropdown = React.memo( ({ migrationSource, setMigrationSource, disabled, migrationSourceOptions }) => { - const [value, setValue] = useState(migrationSource); - const handleMigrationSourceChange = useCallback( (selected: MigrationSource) => { - setValue(selected); setMigrationSource(selected); }, [setMigrationSource] ); - const onBlur = useCallback(() => { - setMigrationSource(value); - }, [setMigrationSource, value]); return ( @@ -36,9 +30,8 @@ export const MigrationSourceDropdown = React.memo( > { - id: T; - Component: typeof RulesDataInput; - props?: React.ComponentProps; -} -interface MacrosStep { - id: DataInputStepId.SplunkMacros; - Component: typeof MacrosDataInput; - props?: React.ComponentProps; -} -interface LookupsStep { - id: DataInputStepId.SplunkLookups; - Component: typeof LookupsDataInput; - props?: React.ComponentProps; -} - -export type Step = - T extends DataInputStepId.SplunkRules - ? RulesStep - : T extends DataInputStepId.QradarRules - ? RulesStep - : T extends DataInputStepId.SplunkMacros - ? MacrosStep - : LookupsStep; - -export type SplunkStep = RulesStep | MacrosStep | LookupsStep; - -export type SplunkMigrationSteps = SplunkStep[]; - -export type QradarMigrationSteps = Array>; - -export interface RulesDataInputSubStepsProps { - dataInputStep: SplunkDataInputStep | QradarDataInputStep; - migrationSource: MigrationSource; - migrationStats?: RuleMigrationStats; - onMigrationCreated: (createdMigrationStats: RuleMigrationStats) => void; - onMissingResourcesFetched?: OnMissingResourcesFetched; -} diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/use_migration_source_options.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/use_migration_source_options.test.tsx index 5676cc77a1bd3..3f6810caa91dd 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/use_migration_source_options.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/use_migration_source_options.test.tsx @@ -8,7 +8,7 @@ import { renderHook } from '@testing-library/react'; import { useMigrationSourceOptions } from './use_migration_source_options'; import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; -import { MigrationSource } from '../../types'; +import { MigrationSource } from '../../../rules/types'; jest.mock('../../../../common/hooks/use_experimental_features', () => ({ useIsExperimentalFeatureEnabled: jest.fn(), diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/use_migration_source_options.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/use_migration_source_options.tsx index b4f79e0ee68bc..a37cfbc9555fc 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/use_migration_source_options.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/use_migration_source_options.tsx @@ -7,9 +7,9 @@ import React from 'react'; import type { EuiSuperSelectOption } from '@elastic/eui'; import { EuiIcon } from '@elastic/eui'; -import { MigrationSource } from '../../types'; import * as i18n from './translations'; import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; +import { MigrationSource } from '../../../rules/types'; export const useMigrationSourceOptions = () => { const isQradarEnabled = useIsExperimentalFeatureEnabled('qradarRulesMigration'); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/use_migration_source_step.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/use_migration_source_step.tsx index 311d60979eceb..4553faa38754e 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/use_migration_source_step.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/use_migration_source_step.tsx @@ -7,8 +7,8 @@ import { useState } from 'react'; import type { EuiSuperSelectOption } from '@elastic/eui'; -import type { MigrationSource } from '../../types'; import { useMigrationSourceOptions } from './use_migration_source_options'; +import type { MigrationSource } from '../../../rules/types'; export interface MigrationSourceDropdownProps { migrationSource: MigrationSource; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/configs.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/configs.tsx index e295f8fee1364..3d8be1c4db7c2 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/configs.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/configs.tsx @@ -5,21 +5,24 @@ * 2.0. */ -import { MigrationSource } from '../../types'; -import { DataInputStepId } from '../../../rules/components/data_input_flyout/steps/constants'; import { RulesDataInput } from '../../../rules/components/data_input_flyout/steps/rules/rules_data_input'; import { MacrosDataInput } from '../../../rules/components/data_input_flyout/steps/macros/macros_data_input'; import { LookupsDataInput } from '../../../rules/components/data_input_flyout/steps/lookups/lookups_data_input'; -import type { QradarMigrationSteps, SplunkMigrationSteps } from '../migration_source_step/types'; +import { MigrationSource } from '../../../rules/types'; +import { + QradarDataInputStepId, + SplunkDataInputStepId, +} from '../../../rules/components/data_input_flyout/steps/constants'; +import type { SplunkMigrationSteps, QradarMigrationSteps } from './types'; const SPLUNK_MIGRATION_STEPS: SplunkMigrationSteps = [ - { id: DataInputStepId.SplunkRules, Component: RulesDataInput }, - { id: DataInputStepId.SplunkMacros, Component: MacrosDataInput }, - { id: DataInputStepId.SplunkLookups, Component: LookupsDataInput }, + { id: SplunkDataInputStepId.Rules, Component: RulesDataInput }, + { id: SplunkDataInputStepId.Macros, Component: MacrosDataInput }, + { id: SplunkDataInputStepId.Lookups, Component: LookupsDataInput }, ] as const; const QRADAR_MIGRATION_STEPS: QradarMigrationSteps = [ - { id: DataInputStepId.QradarRules, Component: RulesDataInput }, + { id: QradarDataInputStepId.Rules, Component: RulesDataInput }, ] as const; export const STEP_COMPONENTS: { diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/types.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/types.ts index 328c9a0781a63..72ca4133c0bd0 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/types.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/types.ts @@ -4,8 +4,34 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - +import type { MacrosDataInput } from '../../../rules/components/data_input_flyout/steps/macros/macros_data_input'; +import type { LookupsDataInput } from '../../../rules/components/data_input_flyout/steps/lookups/lookups_data_input'; import type { SiemMigrationResourceData } from '../../../../../common/siem_migrations/model/common.gen'; +import type { RulesDataInput } from '../../../rules/components/data_input_flyout/steps/rules/rules_data_input'; +import type { + QradarDataInputStepId, + SplunkDataInputStepId, +} from '../../../rules/components/data_input_flyout/steps/constants'; export type UploadedLookups = Record; export type AddUploadedLookups = (lookups: SiemMigrationResourceData[]) => void; + +export type DataInputStepId = SplunkDataInputStepId | QradarDataInputStepId; + +export interface Step> { + id: DataInputStepId; + Component: C; + props?: Props; +} + +type RulesStep = Step, typeof RulesDataInput>; + +type MacrosStep = Step, typeof MacrosDataInput>; + +type LookupsStep = Step, typeof LookupsDataInput>; + +export type SplunkStep = RulesStep | MacrosStep | LookupsStep; +export type QradarStep = RulesStep; + +export type SplunkMigrationSteps = Array; +export type QradarMigrationSteps = Array; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/use_migration_steps.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/use_migration_steps.test.tsx index 3760d13154fe2..ccf2fc7c14bc1 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/use_migration_steps.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/use_migration_steps.test.tsx @@ -6,15 +6,14 @@ */ import { - DataInputStepId, QradarDataInputStep, SplunkDataInputStep, } from '../../../rules/components/data_input_flyout/steps/constants'; -import { MigrationSource } from '../../types'; import type { UseMigrationStepsProps } from './use_migration_steps'; import { useMigrationSteps } from './use_migration_steps'; import { renderHook } from '@testing-library/react'; import { SiemMigrationTaskStatus } from '../../../../../common/siem_migrations/constants'; +import { MigrationSource } from '../../../rules/types'; describe('useMigrationSteps', () => { const props: UseMigrationStepsProps = { @@ -47,15 +46,15 @@ describe('useMigrationSteps', () => { useMigrationSteps({ ...props, migrationSource: MigrationSource.SPLUNK }) ); expect(result.current?.length).toEqual(3); - expect(result.current?.[0].id).toBe(DataInputStepId.SplunkRules); - expect(result.current?.[1].id).toBe(DataInputStepId.SplunkMacros); - expect(result.current?.[2].id).toBe(DataInputStepId.SplunkLookups); + expect(result.current?.[0].id).toBe(SplunkDataInputStep.Rules); + expect(result.current?.[1].id).toBe(SplunkDataInputStep.Macros); + expect(result.current?.[2].id).toBe(SplunkDataInputStep.Lookups); }); it('should return Qradar migration steps when migration source is Qradar', () => { const { result } = renderHook(() => useMigrationSteps({ ...props, migrationSource: MigrationSource.QRADAR }) ); expect(result.current?.length).toEqual(1); - expect(result.current?.[0].id).toBe(DataInputStepId.QradarRules); + expect(result.current?.[0].id).toBe(QradarDataInputStep.Rules); }); }); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/use_migration_steps.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/use_migration_steps.tsx index caf707643172f..b6036779c9210 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/use_migration_steps.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/use_migration_steps.tsx @@ -15,12 +15,19 @@ import type { import { SplunkDataInputStep } from '../../../rules/components/data_input_flyout/steps/constants'; import { STEP_COMPONENTS } from './configs'; -import type { - QradarMigrationSteps, - RulesDataInputSubStepsProps, - SplunkMigrationSteps, -} from '../migration_source_step/types'; -import { MigrationSource } from '../../types'; + +import type { RuleMigrationStats } from '../../../rules/types'; +import { MigrationSource } from '../../../rules/types'; +import type { OnMissingResourcesFetched } from '../../../rules/components/data_input_flyout/types'; +import type { QradarMigrationSteps, QradarStep, SplunkMigrationSteps, SplunkStep } from './types'; + +export interface RulesDataInputSubStepsProps { + dataInputStep: SplunkDataInputStep | QradarDataInputStep; + migrationSource: MigrationSource; + migrationStats?: RuleMigrationStats; + onMigrationCreated: (createdMigrationStats: RuleMigrationStats) => void; + onMissingResourcesFetched?: OnMissingResourcesFetched; +} export type UseMigrationStepsProps = Omit & { dataInputStep: DataInputStep; @@ -84,7 +91,7 @@ const useSplunkMigrationSteps = ({ const SPLUNK_MIGRATION_STEPS: SplunkMigrationSteps = useMemo( () => - STEP_COMPONENTS[MigrationSource.SPLUNK].map(({ id, Component }) => ({ + STEP_COMPONENTS[MigrationSource.SPLUNK].map(({ id, Component }: SplunkStep) => ({ id, Component, props: { @@ -120,7 +127,7 @@ const useQradarMigrationSteps = ({ }: UseQradarMigrationSteps): QradarMigrationSteps | null => { const QRADAR_MIGRATION_STEPS: QradarMigrationSteps = useMemo( () => - STEP_COMPONENTS[MigrationSource.QRADAR].map(({ id, Component }) => ({ + STEP_COMPONENTS[MigrationSource.QRADAR].map(({ id, Component }: QradarStep) => ({ id, Component, props: { diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/types.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/types.ts index e8b904f3fe942..29b8b5335ff89 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/types.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/types.ts @@ -39,8 +39,3 @@ export interface FilterOptionsBase { export interface MigrationStats extends MigrationTaskStats { status: SiemMigrationTaskStatus; // use the native enum instead of the zod enum from the model } - -export enum MigrationSource { - SPLUNK = 'splunk', - QRADAR = 'qradar', -} diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx index 749ec43276183..994408a95597d 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx @@ -23,17 +23,16 @@ import { SiemMigrationRetryFilter, SiemMigrationTaskStatus, } from '../../../../../common/siem_migrations/constants'; -import type { DataInputStep, DataInputStepId } from './steps/constants'; +import type { DataInputStep } from './steps/constants'; import { QradarDataInputStep, SplunkDataInputStep } from './steps/constants'; import { useStartRulesMigrationModal } from '../../hooks/use_start_rules_migration_modal'; -import type { RuleMigrationSettings, RuleMigrationStats } from '../../types'; +import { MigrationSource, type RuleMigrationSettings, type RuleMigrationStats } from '../../types'; import { useStartMigration } from '../../logic/use_start_migration'; import { useMigrationSourceStep } from '../../../common/components/migration_source_step/use_migration_source_step'; import { MigrationSourceDropdown } from '../../../common/components/migration_source_step/migration_source_dropdown'; import { CenteredLoadingSpinner } from '../../../../common/components/centered_loading_spinner'; -import type { Step } from '../../../common/components/migration_source_step/types'; -import { MigrationSource } from '../../../common/types'; import { useMigrationSteps } from '../../../common/components/migration_steps/use_migration_steps'; +import type { QradarStep, SplunkStep } from '../../../common/components/migration_steps/types'; export interface MigrationDataInputFlyoutProps { onClose: () => void; @@ -41,7 +40,9 @@ export interface MigrationDataInputFlyoutProps { migrationSource?: MigrationSource; } -function StepRenderer({ step }: { step: Step }) { +type Step = SplunkStep | QradarStep; + +function StepRenderer({ step }: { step: Step }) { const Component = step.Component as React.ComponentType; return step.props ? : ; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/constants.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/constants.ts index 77684ea464f4c..8894cfcb2c2c0 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/constants.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/constants.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { MigrationSource } from '../../../../common/types'; +import type { MigrationSource } from '../../../types'; export enum SplunkDataInputStep { Rules = 1, @@ -24,9 +24,12 @@ export interface DataInputStep { [MigrationSource.QRADAR]: QradarDataInputStep; } -export enum DataInputStepId { - SplunkRules = 'splunk_rules', - SplunkMacros = 'splunk_macros', - SplunkLookups = 'splunk_lookups', - QradarRules = 'qradar_rules', +export enum SplunkDataInputStepId { + Rules = 'splunk_rules', + Macros = 'splunk_macros', + Lookups = 'splunk_lookups', +} + +export enum QradarDataInputStepId { + Rules = 'qradar_rules', } diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.test.tsx index e48b680120647..754353a368cd8 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.test.tsx @@ -10,7 +10,7 @@ import { render } from '@testing-library/react'; import { RulesDataInput } from './rules_data_input'; import { SplunkDataInputStep } from '../constants'; import { TestProviders } from '../../../../../../common/mock/test_providers'; -import { MigrationSource } from '../../../../../common/types'; +import { MigrationSource } from '../../../../types'; describe('RulesDataInput', () => { const defaultProps = { diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx index 7d959436933c3..196b582f67332 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx @@ -17,8 +17,8 @@ import { QradarDataInputStep, SplunkDataInputStep } from '../constants'; import { useCopyExportQueryStep } from './sub_steps/copy_export_query'; import { useRulesFileUploadStep } from './sub_steps/rules_file_upload'; import { useCheckResourcesStep } from './sub_steps/check_resources'; -import { MigrationSource } from '../../../../../common/types'; -import type { RulesDataInputSubStepsProps } from '../../../../../common/components/migration_source_step/types'; +import type { RulesDataInputSubStepsProps } from '../../../../../common/components/migration_steps/use_migration_steps'; +import { MigrationSource } from '../../../../types'; interface RulesDataInputProps extends Omit { dataInputStep: SplunkDataInputStep | QradarDataInputStep; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/index.tsx index 91c821c99425c..753da7b867643 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/index.tsx @@ -9,8 +9,8 @@ import React, { useMemo } from 'react'; import type { EuiStepProps, EuiStepStatus } from '@elastic/eui'; import { CopyExportedSplunkQuery } from './copy_exported_splunk_query'; import * as i18n from './translations'; -import { MigrationSource } from '../../../../../../../common/types'; import { CopyExportedQradarQuery } from './copy_exported_qradar_query'; +import { MigrationSource } from '../../../../../../types'; export interface CopyExportQueryStepProps { status: EuiStepStatus; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/index.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/index.test.tsx index 030ee563d7693..9b48a64cde354 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/index.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/index.test.tsx @@ -9,7 +9,7 @@ import { renderHook } from '@testing-library/react'; import { useRulesFileUploadStep } from '.'; import { TestProviders } from '../../../../../../../../common/mock'; import { useCreateMigration } from '../../../../../../service/hooks/use_create_migration'; -import { MigrationSource } from '../../../../../../../common/types'; +import { MigrationSource } from '../../../../../../types'; jest.mock('../../../../../../service/hooks/use_create_migration', () => ({ useCreateMigration: jest.fn(), diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/index.tsx index 04e80c0760d07..98e190bb587d5 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/index.tsx @@ -8,6 +8,7 @@ import React, { useCallback, useMemo, useState } from 'react'; import type { EuiStepProps, EuiStepStatus } from '@elastic/eui'; import type { RuleMigrationStats } from '../../../../../../types'; +import { MigrationSource } from '../../../../../../types'; import type { OnMigrationCreated } from '../../../../types'; import { RulesFileUpload } from './rules_file_upload'; import { @@ -15,7 +16,6 @@ import { type OnSuccess, } from '../../../../../../service/hooks/use_create_migration'; import * as i18n from './translations'; -import { MigrationSource } from '../../../../../../../common/types'; import { RulesXMLFileUpload } from './rules_xml_file_upload'; export interface RulesFileUploadStepProps { @@ -34,26 +34,14 @@ export const useRulesFileUploadStep = ({ onMigrationCreated, onRulesFileChanged, }: RulesFileUploadStepProps): EuiStepProps => { - const [isCreated, setIsCreated] = useState<{ - [MigrationSource.SPLUNK]: boolean; - [MigrationSource.QRADAR]: boolean; - }>({ - [MigrationSource.SPLUNK]: !!migrationStats, - [MigrationSource.QRADAR]: !!migrationStats, - }); - const setMigrationCreated = useCallback( - (created: boolean) => { - setIsCreated((prev) => ({ ...prev, ...{ [migrationSource]: created } })); - }, - [migrationSource] - ); + const [isCreated, setIsCreated] = useState(!!migrationStats); const onSuccess = useCallback( (stats) => { - setMigrationCreated(true); + setIsCreated(true); onMigrationCreated(stats); }, - [onMigrationCreated, setMigrationCreated] + [onMigrationCreated] ); const { createMigration, isLoading, error } = useCreateMigration(onSuccess); @@ -79,7 +67,7 @@ export const useRulesFileUploadStep = ({ migrationName={migrationName} migrationSource={migrationSource} isLoading={isLoading} - isCreated={isCreated[migrationSource]} + isCreated={isCreated} apiError={error?.message} onRulesFileChanged={onRulesFileChanged} /> diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_file_upload.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_file_upload.test.tsx index 482e2e955462a..0f8b146f32a64 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_file_upload.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_file_upload.test.tsx @@ -17,7 +17,7 @@ import path from 'path'; import os from 'os'; import { splunkTestRules } from './splunk_rules.test.data'; import type { OriginalRule } from '../../../../../../../../../common/siem_migrations/model/rule_migration.gen'; -import { MigrationSource } from '../../../../../../../common/types'; +import { MigrationSource } from '../../../../../../types'; const mockCreateMigration: CreateMigration = jest.fn(); const mockOnRulesFileChanged = jest.fn(); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_file_upload.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_file_upload.tsx index 087383d6895c4..4f20a73373b30 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_file_upload.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_file_upload.tsx @@ -23,9 +23,9 @@ import type { CreateMigration } from '../../../../../../service/hooks/use_create import type { CreateRuleMigrationRulesRequestBody } from '../../../../../../../../../common/siem_migrations/model/api/rules/rule_migration.gen'; import type { OriginalRule } from '../../../../../../../../../common/siem_migrations/model/rule_migration.gen'; import * as i18n from './translations'; -import type { MigrationSource } from '../../../../../../../common/types'; import { RULES_DATA_INPUT_CHECK_RESOURCES_DESCRIPTION } from '../check_resources/translations'; import type { SPLUNK_RULES_COLUMNS } from '../../../../constants'; +import type { MigrationSource } from '../../../../../../types'; type SplunkRulesResult = Partial>; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_xml_file_upload.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_xml_file_upload.tsx index dfa146fb5d4d5..71e8c3e3155a0 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_xml_file_upload.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_xml_file_upload.tsx @@ -14,9 +14,9 @@ import type { import { UploadFileButton } from '../../../../../../../common/components'; import type { CreateMigration } from '../../../../../../service/hooks/use_create_migration'; import * as i18n from './translations'; -import type { MigrationSource } from '../../../../../../../common/types'; import { RULES_DATA_INPUT_CHECK_RESOURCES_DESCRIPTION } from '../check_resources/translations'; import { useParseFileInput } from '../../../../../../../common/hooks/use_parse_file_input'; +import type { MigrationSource } from '../../../../../../types'; export interface RulesXMLFileUploadProps { createMigration: CreateMigration; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.test.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.test.ts index 401a2ea609f8b..ec0f9ccd030cb 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.test.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.test.ts @@ -9,7 +9,7 @@ import { renderHook, act } from '@testing-library/react'; import { useCreateMigration } from './use_create_migration'; import { useKibana } from '../../../../common/lib/kibana/kibana_react'; import type { CreateRuleMigrationRulesRequestBody } from '../../../../../common/siem_migrations/model/api/rules/rule_migration.gen'; -import { MigrationSource } from '../../../common/types'; +import { MigrationSource } from '../../types'; jest.mock('../../../../common/lib/kibana/kibana_react', () => ({ useKibana: jest.fn(), diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.ts index 581368699ca16..48bfd5329a978 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.ts @@ -10,8 +10,7 @@ import { i18n } from '@kbn/i18n'; import type { CreateRuleMigrationRulesRequestBody } from '../../../../../common/siem_migrations/model/api/rules/rule_migration.gen'; import { useKibana } from '../../../../common/lib/kibana/kibana_react'; import { reducer, initialState } from '../../../common/service'; -import type { RuleMigrationStats } from '../../types'; -import type { MigrationSource } from '../../../common/types'; +import type { MigrationSource, RuleMigrationStats } from '../../types'; export const RULES_DATA_INPUT_CREATE_MIGRATION_SUCCESS_TITLE = i18n.translate( 'xpack.securitySolution.siemMigrations.rules.service.createRuleSuccess.title', diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/types.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/types.ts index 6b6c963b163e6..fe684dc614f13 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/types.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/types.ts @@ -18,6 +18,11 @@ export enum AuthorFilter { CUSTOM = 'custom', } +export enum MigrationSource { + SPLUNK = 'splunk', + QRADAR = 'qradar', +} + export enum RulesSpecificStatusFilter { INDEX_PATTERN_MISSING = 'index_pattern_missing', } From 72432b3ccd5e56052a800f33fc160ad879e164e7 Mon Sep 17 00:00:00 2001 From: Angela Chuang Date: Fri, 5 Dec 2025 16:50:24 +0000 Subject: [PATCH 11/23] path --- .../components/migration_steps/types.ts | 27 ------------- .../data_input_flyout/data_input_flyout.tsx | 12 +++--- .../steps/rules/rules_data_input.tsx | 7 +++- .../components/data_input_flyout/types.ts | 39 ++++++++++++++++++- .../migration_source_dropdown.test.tsx | 2 +- .../migration_source_dropdown.tsx | 2 +- .../migration_source_step/translations.ts | 0 .../use_migration_source_options.test.tsx | 2 +- .../use_migration_source_options.tsx | 2 +- .../use_migration_source_step.tsx | 2 +- .../hooks}/configs.tsx | 15 ++++--- .../hooks}/use_migration_steps.test.tsx | 6 +-- .../hooks}/use_migration_steps.tsx | 26 ++++++------- 13 files changed, 77 insertions(+), 65 deletions(-) rename x-pack/solutions/security/plugins/security_solution/public/siem_migrations/{common => rules}/components/migration_source_step/migration_source_dropdown.test.tsx (96%) rename x-pack/solutions/security/plugins/security_solution/public/siem_migrations/{common => rules}/components/migration_source_step/migration_source_dropdown.tsx (96%) rename x-pack/solutions/security/plugins/security_solution/public/siem_migrations/{common => rules}/components/migration_source_step/translations.ts (100%) rename x-pack/solutions/security/plugins/security_solution/public/siem_migrations/{common => rules}/components/migration_source_step/use_migration_source_options.test.tsx (96%) rename x-pack/solutions/security/plugins/security_solution/public/siem_migrations/{common => rules}/components/migration_source_step/use_migration_source_options.tsx (95%) rename x-pack/solutions/security/plugins/security_solution/public/siem_migrations/{common => rules}/components/migration_source_step/use_migration_source_step.tsx (95%) rename x-pack/solutions/security/plugins/security_solution/public/siem_migrations/{common/components/migration_steps => rules/hooks}/configs.tsx (64%) rename x-pack/solutions/security/plugins/security_solution/public/siem_migrations/{common/components/migration_steps => rules/hooks}/use_migration_steps.test.tsx (90%) rename x-pack/solutions/security/plugins/security_solution/public/siem_migrations/{common/components/migration_steps => rules/hooks}/use_migration_steps.tsx (82%) diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/types.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/types.ts index 72ca4133c0bd0..f17009646ece2 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/types.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/types.ts @@ -4,34 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { MacrosDataInput } from '../../../rules/components/data_input_flyout/steps/macros/macros_data_input'; -import type { LookupsDataInput } from '../../../rules/components/data_input_flyout/steps/lookups/lookups_data_input'; import type { SiemMigrationResourceData } from '../../../../../common/siem_migrations/model/common.gen'; -import type { RulesDataInput } from '../../../rules/components/data_input_flyout/steps/rules/rules_data_input'; -import type { - QradarDataInputStepId, - SplunkDataInputStepId, -} from '../../../rules/components/data_input_flyout/steps/constants'; export type UploadedLookups = Record; export type AddUploadedLookups = (lookups: SiemMigrationResourceData[]) => void; - -export type DataInputStepId = SplunkDataInputStepId | QradarDataInputStepId; - -export interface Step> { - id: DataInputStepId; - Component: C; - props?: Props; -} - -type RulesStep = Step, typeof RulesDataInput>; - -type MacrosStep = Step, typeof MacrosDataInput>; - -type LookupsStep = Step, typeof LookupsDataInput>; - -export type SplunkStep = RulesStep | MacrosStep | LookupsStep; -export type QradarStep = RulesStep; - -export type SplunkMigrationSteps = Array; -export type QradarMigrationSteps = Array; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx index 994408a95597d..81e26d99744f6 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx @@ -28,11 +28,11 @@ import { QradarDataInputStep, SplunkDataInputStep } from './steps/constants'; import { useStartRulesMigrationModal } from '../../hooks/use_start_rules_migration_modal'; import { MigrationSource, type RuleMigrationSettings, type RuleMigrationStats } from '../../types'; import { useStartMigration } from '../../logic/use_start_migration'; -import { useMigrationSourceStep } from '../../../common/components/migration_source_step/use_migration_source_step'; -import { MigrationSourceDropdown } from '../../../common/components/migration_source_step/migration_source_dropdown'; +import { useMigrationSourceStep } from '../migration_source_step/use_migration_source_step'; +import { MigrationSourceDropdown } from '../migration_source_step/migration_source_dropdown'; import { CenteredLoadingSpinner } from '../../../../common/components/centered_loading_spinner'; -import { useMigrationSteps } from '../../../common/components/migration_steps/use_migration_steps'; -import type { QradarStep, SplunkStep } from '../../../common/components/migration_steps/types'; +import { useMigrationSteps } from '../../hooks/use_migration_steps'; +import type { QradarStep, SplunkStep } from './types'; export interface MigrationDataInputFlyoutProps { onClose: () => void; @@ -40,9 +40,9 @@ export interface MigrationDataInputFlyoutProps { migrationSource?: MigrationSource; } -type Step = SplunkStep | QradarStep; +type StepToRender = SplunkStep | QradarStep; -function StepRenderer({ step }: { step: Step }) { +function StepRenderer({ step }: { step: StepToRender }) { const Component = step.Component as React.ComponentType; return step.props ? : ; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx index 196b582f67332..84cf910fef76f 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx @@ -11,13 +11,16 @@ import React, { useCallback, useMemo, useState } from 'react'; import { SubSteps, useMigrationNameStep } from '../../../../../common/components'; import { getEuiStepStatus } from '../../../../../common/utils/get_eui_step_status'; import { useKibana } from '../../../../../../common/lib/kibana'; -import type { OnMigrationCreated, OnMissingResourcesFetched } from '../../types'; +import type { + OnMigrationCreated, + OnMissingResourcesFetched, + RulesDataInputSubStepsProps, +} from '../../types'; import * as i18n from './translations'; import { QradarDataInputStep, SplunkDataInputStep } from '../constants'; import { useCopyExportQueryStep } from './sub_steps/copy_export_query'; import { useRulesFileUploadStep } from './sub_steps/rules_file_upload'; import { useCheckResourcesStep } from './sub_steps/check_resources'; -import type { RulesDataInputSubStepsProps } from '../../../../../common/components/migration_steps/use_migration_steps'; import { MigrationSource } from '../../../../types'; interface RulesDataInputProps extends Omit { diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/types.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/types.ts index 95cdc85fabb0c..2fc00feac230d 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/types.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/types.ts @@ -6,8 +6,45 @@ */ import type { SiemMigrationResourceBase } from '../../../../../common/siem_migrations/model/common.gen'; -import type { RuleMigrationStats } from '../../types'; +import type { MigrationSource, RuleMigrationStats } from '../../types'; +import type { + QradarDataInputStep, + QradarDataInputStepId, + SplunkDataInputStep, + SplunkDataInputStepId, +} from './steps/constants'; +import type { LookupsDataInput } from './steps/lookups/lookups_data_input'; +import type { MacrosDataInput } from './steps/macros/macros_data_input'; +import type { RulesDataInput } from './steps/rules/rules_data_input'; export type OnMigrationCreated = (migrationStats: RuleMigrationStats) => void; export type OnResourcesCreated = () => void; export type OnMissingResourcesFetched = (missingResources: SiemMigrationResourceBase[]) => void; + +type DataInputStepId = SplunkDataInputStepId | QradarDataInputStepId; + +export interface Step> { + id: DataInputStepId; + Component: C; + props?: Props; +} + +type RulesStep = Step, typeof RulesDataInput>; + +type MacrosStep = Step, typeof MacrosDataInput>; + +type LookupsStep = Step, typeof LookupsDataInput>; + +export type SplunkStep = RulesStep | MacrosStep | LookupsStep; +export type QradarStep = RulesStep; + +export type SplunkMigrationSteps = Array; +export type QradarMigrationSteps = Array; + +export interface RulesDataInputSubStepsProps { + dataInputStep: SplunkDataInputStep | QradarDataInputStep; + migrationSource: MigrationSource; + migrationStats?: RuleMigrationStats; + onMigrationCreated: (createdMigrationStats: RuleMigrationStats) => void; + onMissingResourcesFetched?: OnMissingResourcesFetched; +} diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_dropdown.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/migration_source_step/migration_source_dropdown.test.tsx similarity index 96% rename from x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_dropdown.test.tsx rename to x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/migration_source_step/migration_source_dropdown.test.tsx index 0481d2ffeb6df..2aa2e6de02833 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_dropdown.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/migration_source_step/migration_source_dropdown.test.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; import { MigrationSourceDropdown } from './migration_source_dropdown'; import * as i18n from './translations'; -import { MigrationSource } from '../../../rules/types'; +import { MigrationSource } from '../../types'; describe('MigrationSourceDropdown', () => { const mockSetMigrationSource = jest.fn(); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_dropdown.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/migration_source_step/migration_source_dropdown.tsx similarity index 96% rename from x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_dropdown.tsx rename to x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/migration_source_step/migration_source_dropdown.tsx index e121cdb495324..40b62d2ec55e7 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/migration_source_dropdown.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/migration_source_step/migration_source_dropdown.tsx @@ -8,7 +8,7 @@ import React, { useCallback } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiForm, EuiFormRow, EuiSuperSelect } from '@elastic/eui'; import * as i18n from './translations'; import type { MigrationSourceDropdownProps } from './use_migration_source_step'; -import type { MigrationSource } from '../../../rules/types'; +import type { MigrationSource } from '../../types'; export const MigrationSourceDropdown = React.memo( ({ migrationSource, setMigrationSource, disabled, migrationSourceOptions }) => { diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/translations.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/migration_source_step/translations.ts similarity index 100% rename from x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/translations.ts rename to x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/migration_source_step/translations.ts diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/use_migration_source_options.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/migration_source_step/use_migration_source_options.test.tsx similarity index 96% rename from x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/use_migration_source_options.test.tsx rename to x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/migration_source_step/use_migration_source_options.test.tsx index 3f6810caa91dd..5676cc77a1bd3 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/use_migration_source_options.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/migration_source_step/use_migration_source_options.test.tsx @@ -8,7 +8,7 @@ import { renderHook } from '@testing-library/react'; import { useMigrationSourceOptions } from './use_migration_source_options'; import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; -import { MigrationSource } from '../../../rules/types'; +import { MigrationSource } from '../../types'; jest.mock('../../../../common/hooks/use_experimental_features', () => ({ useIsExperimentalFeatureEnabled: jest.fn(), diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/use_migration_source_options.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/migration_source_step/use_migration_source_options.tsx similarity index 95% rename from x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/use_migration_source_options.tsx rename to x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/migration_source_step/use_migration_source_options.tsx index a37cfbc9555fc..a867d183192de 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/use_migration_source_options.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/migration_source_step/use_migration_source_options.tsx @@ -9,7 +9,7 @@ import type { EuiSuperSelectOption } from '@elastic/eui'; import { EuiIcon } from '@elastic/eui'; import * as i18n from './translations'; import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; -import { MigrationSource } from '../../../rules/types'; +import { MigrationSource } from '../../types'; export const useMigrationSourceOptions = () => { const isQradarEnabled = useIsExperimentalFeatureEnabled('qradarRulesMigration'); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/use_migration_source_step.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/migration_source_step/use_migration_source_step.tsx similarity index 95% rename from x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/use_migration_source_step.tsx rename to x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/migration_source_step/use_migration_source_step.tsx index 4553faa38754e..a4fb756c62a24 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_source_step/use_migration_source_step.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/migration_source_step/use_migration_source_step.tsx @@ -8,7 +8,7 @@ import { useState } from 'react'; import type { EuiSuperSelectOption } from '@elastic/eui'; import { useMigrationSourceOptions } from './use_migration_source_options'; -import type { MigrationSource } from '../../../rules/types'; +import type { MigrationSource } from '../../types'; export interface MigrationSourceDropdownProps { migrationSource: MigrationSource; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/configs.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/hooks/configs.tsx similarity index 64% rename from x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/configs.tsx rename to x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/hooks/configs.tsx index 3d8be1c4db7c2..deb18e31156cd 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/configs.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/hooks/configs.tsx @@ -5,15 +5,18 @@ * 2.0. */ -import { RulesDataInput } from '../../../rules/components/data_input_flyout/steps/rules/rules_data_input'; -import { MacrosDataInput } from '../../../rules/components/data_input_flyout/steps/macros/macros_data_input'; -import { LookupsDataInput } from '../../../rules/components/data_input_flyout/steps/lookups/lookups_data_input'; -import { MigrationSource } from '../../../rules/types'; +import { RulesDataInput } from '../components/data_input_flyout/steps/rules/rules_data_input'; +import { MacrosDataInput } from '../components/data_input_flyout/steps/macros/macros_data_input'; +import { LookupsDataInput } from '../components/data_input_flyout/steps/lookups/lookups_data_input'; +import { MigrationSource } from '../types'; import { QradarDataInputStepId, SplunkDataInputStepId, -} from '../../../rules/components/data_input_flyout/steps/constants'; -import type { SplunkMigrationSteps, QradarMigrationSteps } from './types'; +} from '../components/data_input_flyout/steps/constants'; +import type { + QradarMigrationSteps, + SplunkMigrationSteps, +} from '../components/data_input_flyout/types'; const SPLUNK_MIGRATION_STEPS: SplunkMigrationSteps = [ { id: SplunkDataInputStepId.Rules, Component: RulesDataInput }, diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/use_migration_steps.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/hooks/use_migration_steps.test.tsx similarity index 90% rename from x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/use_migration_steps.test.tsx rename to x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/hooks/use_migration_steps.test.tsx index ccf2fc7c14bc1..06702938594b2 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/use_migration_steps.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/hooks/use_migration_steps.test.tsx @@ -8,12 +8,12 @@ import { QradarDataInputStep, SplunkDataInputStep, -} from '../../../rules/components/data_input_flyout/steps/constants'; +} from '../components/data_input_flyout/steps/constants'; import type { UseMigrationStepsProps } from './use_migration_steps'; import { useMigrationSteps } from './use_migration_steps'; import { renderHook } from '@testing-library/react'; -import { SiemMigrationTaskStatus } from '../../../../../common/siem_migrations/constants'; -import { MigrationSource } from '../../../rules/types'; +import { SiemMigrationTaskStatus } from '../../../../common/siem_migrations/constants'; +import { MigrationSource } from '../types'; describe('useMigrationSteps', () => { const props: UseMigrationStepsProps = { diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/use_migration_steps.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/hooks/use_migration_steps.tsx similarity index 82% rename from x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/use_migration_steps.tsx rename to x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/hooks/use_migration_steps.tsx index b6036779c9210..8798c215565af 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/use_migration_steps.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/hooks/use_migration_steps.tsx @@ -6,28 +6,24 @@ */ import { useCallback, useMemo, useState } from 'react'; -import type { SiemMigrationResourceBase } from '../../../../../common/siem_migrations/model/common.gen'; +import type { SiemMigrationResourceBase } from '../../../../common/siem_migrations/model/common.gen'; import type { DataInputStep, QradarDataInputStep, -} from '../../../rules/components/data_input_flyout/steps/constants'; -import { SplunkDataInputStep } from '../../../rules/components/data_input_flyout/steps/constants'; +} from '../components/data_input_flyout/steps/constants'; +import { SplunkDataInputStep } from '../components/data_input_flyout/steps/constants'; import { STEP_COMPONENTS } from './configs'; -import type { RuleMigrationStats } from '../../../rules/types'; -import { MigrationSource } from '../../../rules/types'; -import type { OnMissingResourcesFetched } from '../../../rules/components/data_input_flyout/types'; -import type { QradarMigrationSteps, QradarStep, SplunkMigrationSteps, SplunkStep } from './types'; - -export interface RulesDataInputSubStepsProps { - dataInputStep: SplunkDataInputStep | QradarDataInputStep; - migrationSource: MigrationSource; - migrationStats?: RuleMigrationStats; - onMigrationCreated: (createdMigrationStats: RuleMigrationStats) => void; - onMissingResourcesFetched?: OnMissingResourcesFetched; -} +import { MigrationSource } from '../types'; +import type { + QradarMigrationSteps, + QradarStep, + RulesDataInputSubStepsProps, + SplunkMigrationSteps, + SplunkStep, +} from '../components/data_input_flyout/types'; export type UseMigrationStepsProps = Omit & { dataInputStep: DataInputStep; From 403212ea4fa9111e117b66584dad87c5bcc44fde Mon Sep 17 00:00:00 2001 From: Angela Chuang Date: Fri, 5 Dec 2025 16:57:10 +0000 Subject: [PATCH 12/23] configs --- .../siem_migrations/rules/configs/index.ts | 23 +++++++++++++++ .../siem_migrations/rules/configs/qradar.ts | 14 +++++++++ .../{hooks/configs.tsx => configs/splunk.ts} | 29 ++++--------------- .../rules/hooks/use_migration_steps.tsx | 2 +- 4 files changed, 43 insertions(+), 25 deletions(-) create mode 100644 x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/index.ts create mode 100644 x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/qradar.ts rename x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/{hooks/configs.tsx => configs/splunk.ts} (52%) diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/index.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/index.ts new file mode 100644 index 0000000000000..3891c362c7288 --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/index.ts @@ -0,0 +1,23 @@ +/* + * 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 { MigrationSource } from '../types'; + +import type { + QradarMigrationSteps, + SplunkMigrationSteps, +} from '../components/data_input_flyout/types'; +import { SPLUNK_MIGRATION_STEPS } from './splunk'; +import { QRADAR_MIGRATION_STEPS } from './qradar'; + +export const STEP_COMPONENTS: { + [MigrationSource.SPLUNK]: SplunkMigrationSteps; + [MigrationSource.QRADAR]: QradarMigrationSteps; +} = { + [MigrationSource.SPLUNK]: SPLUNK_MIGRATION_STEPS, + [MigrationSource.QRADAR]: QRADAR_MIGRATION_STEPS, +}; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/qradar.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/qradar.ts new file mode 100644 index 0000000000000..2abcf252dd49f --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/qradar.ts @@ -0,0 +1,14 @@ +/* + * 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 { QradarDataInputStepId } from '../components/data_input_flyout/steps/constants'; +import { RulesDataInput } from '../components/data_input_flyout/steps/rules/rules_data_input'; +import type { QradarMigrationSteps } from '../components/data_input_flyout/types'; + +export const QRADAR_MIGRATION_STEPS: QradarMigrationSteps = [ + { id: QradarDataInputStepId.Rules, Component: RulesDataInput }, +] as const; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/hooks/configs.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/splunk.ts similarity index 52% rename from x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/hooks/configs.tsx rename to x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/splunk.ts index deb18e31156cd..ed4bbe5d075e4 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/hooks/configs.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/splunk.ts @@ -5,33 +5,14 @@ * 2.0. */ -import { RulesDataInput } from '../components/data_input_flyout/steps/rules/rules_data_input'; -import { MacrosDataInput } from '../components/data_input_flyout/steps/macros/macros_data_input'; +import { SplunkDataInputStepId } from '../components/data_input_flyout/steps/constants'; import { LookupsDataInput } from '../components/data_input_flyout/steps/lookups/lookups_data_input'; -import { MigrationSource } from '../types'; -import { - QradarDataInputStepId, - SplunkDataInputStepId, -} from '../components/data_input_flyout/steps/constants'; -import type { - QradarMigrationSteps, - SplunkMigrationSteps, -} from '../components/data_input_flyout/types'; +import { MacrosDataInput } from '../components/data_input_flyout/steps/macros/macros_data_input'; +import { RulesDataInput } from '../components/data_input_flyout/steps/rules/rules_data_input'; +import type { SplunkMigrationSteps } from '../components/data_input_flyout/types'; -const SPLUNK_MIGRATION_STEPS: SplunkMigrationSteps = [ +export const SPLUNK_MIGRATION_STEPS: SplunkMigrationSteps = [ { id: SplunkDataInputStepId.Rules, Component: RulesDataInput }, { id: SplunkDataInputStepId.Macros, Component: MacrosDataInput }, { id: SplunkDataInputStepId.Lookups, Component: LookupsDataInput }, ] as const; - -const QRADAR_MIGRATION_STEPS: QradarMigrationSteps = [ - { id: QradarDataInputStepId.Rules, Component: RulesDataInput }, -] as const; - -export const STEP_COMPONENTS: { - [MigrationSource.SPLUNK]: SplunkMigrationSteps; - [MigrationSource.QRADAR]: QradarMigrationSteps; -} = { - [MigrationSource.SPLUNK]: SPLUNK_MIGRATION_STEPS, - [MigrationSource.QRADAR]: QRADAR_MIGRATION_STEPS, -}; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/hooks/use_migration_steps.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/hooks/use_migration_steps.tsx index 8798c215565af..e6ecd61b52bb1 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/hooks/use_migration_steps.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/hooks/use_migration_steps.tsx @@ -14,7 +14,7 @@ import type { } from '../components/data_input_flyout/steps/constants'; import { SplunkDataInputStep } from '../components/data_input_flyout/steps/constants'; -import { STEP_COMPONENTS } from './configs'; +import { STEP_COMPONENTS } from '../configs'; import { MigrationSource } from '../types'; import type { From 792bc25d35e8372c0be8f9777e5f590c325e7d90 Mon Sep 17 00:00:00 2001 From: Angela Chuang Date: Fri, 5 Dec 2025 17:32:33 +0000 Subject: [PATCH 13/23] configs --- .../steps/rules/sub_steps/copy_export_query/index.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/index.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/index.test.tsx index fa29151ce60eb..9f668be180f22 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/index.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/index.test.tsx @@ -9,7 +9,7 @@ import { renderHook } from '@testing-library/react'; import { useCopyExportQueryStep } from '.'; import type { CopyExportQueryStepProps } from '.'; import { TestProviders } from '../../../../../../../../common/mock'; -import { MigrationSource } from '../../../../../../../common/types'; +import { MigrationSource } from '../../../../../../types'; const renderCopyExportQueryStep = (props: CopyExportQueryStepProps) => { const { result } = renderHook(() => useCopyExportQueryStep(props), { From dc9724cc5029a696076d34aa333ccb2835b0f816 Mon Sep 17 00:00:00 2001 From: Angela Chuang Date: Mon, 8 Dec 2025 09:40:17 +0000 Subject: [PATCH 14/23] unit tests --- .../rules/hooks/use_migration_steps.test.tsx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/hooks/use_migration_steps.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/hooks/use_migration_steps.test.tsx index 06702938594b2..66986b8f52102 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/hooks/use_migration_steps.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/hooks/use_migration_steps.test.tsx @@ -7,7 +7,9 @@ import { QradarDataInputStep, + QradarDataInputStepId, SplunkDataInputStep, + SplunkDataInputStepId, } from '../components/data_input_flyout/steps/constants'; import type { UseMigrationStepsProps } from './use_migration_steps'; import { useMigrationSteps } from './use_migration_steps'; @@ -46,15 +48,15 @@ describe('useMigrationSteps', () => { useMigrationSteps({ ...props, migrationSource: MigrationSource.SPLUNK }) ); expect(result.current?.length).toEqual(3); - expect(result.current?.[0].id).toBe(SplunkDataInputStep.Rules); - expect(result.current?.[1].id).toBe(SplunkDataInputStep.Macros); - expect(result.current?.[2].id).toBe(SplunkDataInputStep.Lookups); + expect(result.current?.[0].id).toBe(SplunkDataInputStepId.Rules); + expect(result.current?.[1].id).toBe(SplunkDataInputStepId.Macros); + expect(result.current?.[2].id).toBe(SplunkDataInputStepId.Lookups); }); it('should return Qradar migration steps when migration source is Qradar', () => { const { result } = renderHook(() => useMigrationSteps({ ...props, migrationSource: MigrationSource.QRADAR }) ); expect(result.current?.length).toEqual(1); - expect(result.current?.[0].id).toBe(QradarDataInputStep.Rules); + expect(result.current?.[0].id).toBe(QradarDataInputStepId.Rules); }); }); From b08206faa9b9548ed71d3fa6f326628b6794ddc9 Mon Sep 17 00:00:00 2001 From: Angela Chuang Date: Mon, 8 Dec 2025 11:30:08 +0000 Subject: [PATCH 15/23] remove unused --- .../components/migration_steps/types.ts | 1 + .../data_input_flyout/flyout_description.tsx | 46 ------------------- 2 files changed, 1 insertion(+), 46 deletions(-) delete mode 100644 x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/flyout_description.tsx diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/types.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/types.ts index f17009646ece2..328c9a0781a63 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/types.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/types.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ + import type { SiemMigrationResourceData } from '../../../../../common/siem_migrations/model/common.gen'; export type UploadedLookups = Record; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/flyout_description.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/flyout_description.tsx deleted file mode 100644 index 7b8c56924b037..0000000000000 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/flyout_description.tsx +++ /dev/null @@ -1,46 +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 { FormattedMessage } from '@kbn/i18n-react'; -import { EuiText, EuiLink } from '@elastic/eui'; -import { useNavigation } from '../../../../common/lib/kibana'; - -export const FlyoutDescription = React.memo(() => { - const { navigateTo } = useNavigation(); - return ( - - { - navigateTo({ - appId: 'management', - path: '/kibana/dataViews', - }); - }} - target="_blank" - rel="noopener" - external - data-test-subj="siemMigrationsAdvancedSettingsLink" - > - - - ), - }} - /> - - ); -}); - -FlyoutDescription.displayName = 'FlyoutDescription'; From ec729d3951cf2724310d80eae9609f892b492078 Mon Sep 17 00:00:00 2001 From: Angela Chuang Date: Mon, 8 Dec 2025 17:56:30 +0000 Subject: [PATCH 16/23] types --- .../data_input_flyout/data_input_flyout.tsx | 28 +--- .../steps/hooks/use_missing_resources.ts | 55 ++++++ .../steps/lookups/lookups_data_input.test.tsx | 38 ++++- .../steps/lookups/lookups_data_input.tsx | 27 +-- .../steps/macros/macros_data_input.test.tsx | 37 ++++- .../steps/macros/macros_data_input.tsx | 26 +-- .../steps/rules/rules_data_input.test.tsx | 32 ++-- .../steps/rules/rules_data_input.tsx | 12 +- .../components/data_input_flyout/types.ts | 33 ++-- .../siem_migrations/rules/configs/index.ts | 9 +- .../siem_migrations/rules/configs/qradar.ts | 4 +- .../siem_migrations/rules/configs/splunk.ts | 4 +- .../rules/hooks/use_migration_steps.test.tsx | 62 ------- .../rules/hooks/use_migration_steps.tsx | 156 ------------------ 14 files changed, 201 insertions(+), 322 deletions(-) create mode 100644 x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/hooks/use_missing_resources.ts delete mode 100644 x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/hooks/use_migration_steps.test.tsx delete mode 100644 x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/hooks/use_migration_steps.tsx diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx index 81e26d99744f6..33795d3dd908e 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx @@ -31,8 +31,7 @@ import { useStartMigration } from '../../logic/use_start_migration'; import { useMigrationSourceStep } from '../migration_source_step/use_migration_source_step'; import { MigrationSourceDropdown } from '../migration_source_step/migration_source_dropdown'; import { CenteredLoadingSpinner } from '../../../../common/components/centered_loading_spinner'; -import { useMigrationSteps } from '../../hooks/use_migration_steps'; -import type { QradarStep, SplunkStep } from './types'; +import { STEP_COMPONENTS } from '../../configs'; export interface MigrationDataInputFlyoutProps { onClose: () => void; @@ -40,14 +39,6 @@ export interface MigrationDataInputFlyoutProps { migrationSource?: MigrationSource; } -type StepToRender = SplunkStep | QradarStep; - -function StepRenderer({ step }: { step: StepToRender }) { - const Component = step.Component as React.ComponentType; - - return step.props ? : ; -} - const RULES_MIGRATION_DATA_INPUT_FLYOUT_TITLE = 'rulesMigrationDataInputFlyoutTitle'; export const MigrationDataInputFlyout = React.memo( @@ -119,14 +110,6 @@ export const MigrationDataInputFlyout = React.memo {startMigrationModal} @@ -159,9 +142,14 @@ export const MigrationDataInputFlyout = React.memo <> - {steps?.map((step) => ( + {STEP_COMPONENTS[migrationSource]?.map((step) => ( - + )) ?? } diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/hooks/use_missing_resources.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/hooks/use_missing_resources.ts new file mode 100644 index 0000000000000..95c106d3af425 --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/hooks/use_missing_resources.ts @@ -0,0 +1,55 @@ +/* + * 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, useState } from 'react'; +import type { SiemMigrationResourceBase } from '../../../../../../../common/siem_migrations/model/common.gen'; +import type { QradarDataInputStep } from '../constants'; +import { SplunkDataInputStep } from '../constants'; + +interface MissingResourcesIndexed { + macros: string[]; + lookups: string[]; +} + +export const useMissingResources = ({ + setMigrationDataInputStep, +}: { + setMigrationDataInputStep: (step: SplunkDataInputStep | QradarDataInputStep) => void; +}) => { + const [missingResourcesIndexed, setMissingResourcesIndexed] = useState< + MissingResourcesIndexed | undefined + >(); + + const onMissingResourcesFetched = useCallback( + (missingResources: SiemMigrationResourceBase[]) => { + const newMissingResourcesIndexed = missingResources.reduce( + (acc, { type, name }) => { + if (type === 'macro') { + acc.macros.push(name); + } else if (type === 'lookup') { + acc.lookups.push(name); + } + return acc; + }, + { macros: [], lookups: [] } + ); + setMissingResourcesIndexed(newMissingResourcesIndexed); + if (newMissingResourcesIndexed.macros.length) { + setMigrationDataInputStep(SplunkDataInputStep.Macros); + return; + } + if (newMissingResourcesIndexed.lookups.length) { + setMigrationDataInputStep(SplunkDataInputStep.Lookups); + return; + } + setMigrationDataInputStep(SplunkDataInputStep.End); + }, + [setMigrationDataInputStep] + ); + + return { missingResourcesIndexed, onMissingResourcesFetched }; +}; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.test.tsx index 73a5748a84e68..42e8547f35325 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.test.tsx @@ -8,13 +8,16 @@ import { render } from '@testing-library/react'; import React from 'react'; import { LookupsDataInput } from './lookups_data_input'; -import { SplunkDataInputStep } from '../constants'; +import { QradarDataInputStep, SplunkDataInputStep } from '../constants'; import { getRuleMigrationStatsMock } from '../../../../__mocks__'; import { SiemMigrationTaskStatus } from '../../../../../../../common/siem_migrations/constants'; import { TestProviders } from '../../../../../../common/mock'; +import { MigrationSource } from '../../../../types'; +import { useMissingResources } from '../hooks/use_missing_resources'; const mockAddError = jest.fn(); const mockAddSuccess = jest.fn(); +const mockUseMissingResources = useMissingResources as jest.Mock; jest.mock('../../../../../../common/lib/kibana/kibana_react', () => ({ useKibana: () => ({ @@ -37,12 +40,24 @@ jest.mock('../../../../../../common/lib/kibana/kibana_react', () => ({ }), })); +jest.mock('../hooks/use_missing_resources', () => ({ + useMissingResources: jest.fn().mockReturnValue({ + missingResourcesIndexed: { + lookups: ['lookup1', 'lookup2'], + }, + }), +})); + describe('LookupsDataInput', () => { const defaultProps = { - onAllLookupsCreated: jest.fn(), - dataInputStep: SplunkDataInputStep.Lookups, + dataInputStep: { + [MigrationSource.SPLUNK]: SplunkDataInputStep.Lookups, + [MigrationSource.QRADAR]: QradarDataInputStep.Rules, + }, + migrationSource: MigrationSource.SPLUNK, migrationStats: getRuleMigrationStatsMock({ status: SiemMigrationTaskStatus.READY }), - missingLookups: ['lookup1', 'lookup2'], + setMigrationDataInputStep: jest.fn(), + onMigrationCreated: jest.fn(), }; afterEach(() => { @@ -84,7 +99,13 @@ describe('LookupsDataInput', () => { it('does not render description when dataInputStep is not LookupsUpload', () => { const { queryByTestId } = render( - + ); expect(queryByTestId('lookupsUploadDescription')).not.toBeInTheDocument(); @@ -100,9 +121,14 @@ describe('LookupsDataInput', () => { }); it('does not render description when missingLookups is missing', () => { + mockUseMissingResources.mockReturnValue({ + missingResourcesIndexed: { + lookups: undefined, + }, + }); const { queryByTestId } = render( - + ); expect(queryByTestId('lookupsUploadDescription')).not.toBeInTheDocument(); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.tsx index dcab90085c33a..02cea8a31091d 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.tsx @@ -23,28 +23,33 @@ import { SubSteps } from '../../../../../common/components'; import { getEuiStepStatus } from '../../../../../common/utils/get_eui_step_status'; import { useKibana } from '../../../../../../common/lib/kibana/kibana_react'; import type { RuleMigrationTaskStats } from '../../../../../../../common/siem_migrations/model/rule_migration.gen'; -import type { OnResourcesCreated } from '../../types'; +import type { OnResourcesCreated, UseMigrationStepsProps } from '../../types'; import * as i18n from './translations'; import { SplunkDataInputStep } from '../constants'; import { useMissingLookupsListStep } from './sub_steps/missing_lookups_list'; import { useLookupsFileUploadStep } from './sub_steps/lookups_file_upload'; +import { useMissingResources } from '../hooks/use_missing_resources'; interface LookupsDataInputSubStepsProps { migrationStats: RuleMigrationTaskStats; missingLookups: string[]; onAllLookupsCreated: OnResourcesCreated; } -interface LookupsDataInputProps - extends Omit { - dataInputStep: SplunkDataInputStep; - migrationStats?: RuleMigrationTaskStats; - missingLookups?: string[]; -} -export const LookupsDataInput = React.memo( - ({ dataInputStep, migrationStats, missingLookups, onAllLookupsCreated }) => { + +export const LookupsDataInput = React.memo( + ({ dataInputStep, migrationSource, migrationStats, setMigrationDataInputStep }) => { + const { missingResourcesIndexed } = useMissingResources({ setMigrationDataInputStep }); + const missingLookups = useMemo( + () => missingResourcesIndexed?.lookups, + [missingResourcesIndexed] + ); + const onAllLookupsCreated = useCallback(() => { + setMigrationDataInputStep(SplunkDataInputStep.End); + }, [setMigrationDataInputStep]); + const dataInputStatus = useMemo( - () => getEuiStepStatus(SplunkDataInputStep.Lookups, dataInputStep), - [dataInputStep] + () => getEuiStepStatus(SplunkDataInputStep.Lookups, dataInputStep[migrationSource]), + [dataInputStep, migrationSource] ); return ( diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.test.tsx index 454548ebad41e..b6a5218f0201a 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.test.tsx @@ -8,16 +8,19 @@ import { act, fireEvent, render } from '@testing-library/react'; import React from 'react'; import { MacrosDataInput } from './macros_data_input'; -import { SplunkDataInputStep } from '../constants'; +import { QradarDataInputStep, SplunkDataInputStep } from '../constants'; import { getRuleMigrationStatsMock } from '../../../../__mocks__'; import { SiemMigrationTaskStatus } from '../../../../../../../common/siem_migrations/constants'; import { TestProviders } from '../../../../../../common/mock'; import { useAppToasts } from '../../../../../../common/hooks/use_app_toasts'; import { useAppToastsMock } from '../../../../../../common/hooks/use_app_toasts.mock'; +import { MigrationSource } from '../../../../types'; +import { useMissingResources } from '../hooks/use_missing_resources'; const mockAddError = jest.fn(); const mockAddSuccess = jest.fn(); const mockReportSetupMacrosQueryCopied = jest.fn(); +const mockUseMissingResources = useMissingResources as jest.Mock; jest.mock('../../../../../../common/lib/kibana/kibana_react', () => ({ useKibana: () => ({ @@ -41,14 +44,27 @@ jest.mock('../../../../../../common/lib/kibana/kibana_react', () => ({ })); jest.mock('../../../../../../common/hooks/use_app_toasts'); +jest.mock('../hooks/use_missing_resources', () => ({ + useMissingResources: jest.fn().mockReturnValue({ + missingResourcesIndexed: { + macros: ['macro1', 'macro2'], + }, + }), +})); + describe('MacrosDataInput', () => { let appToastsMock: jest.Mocked>; const defaultProps = { onMissingResourcesFetched: jest.fn(), - dataInputStep: SplunkDataInputStep.Macros, + dataInputStep: { + [MigrationSource.SPLUNK]: SplunkDataInputStep.Macros, + [MigrationSource.QRADAR]: QradarDataInputStep.Rules, + }, migrationStats: getRuleMigrationStatsMock({ status: SiemMigrationTaskStatus.READY }), - missingMacros: ['macro1', 'macro2'], + migrationSource: MigrationSource.SPLUNK, + setMigrationDataInputStep: jest.fn(), + onMigrationCreated: jest.fn(), }; beforeEach(() => { @@ -83,7 +99,13 @@ describe('MacrosDataInput', () => { it('does not render sub-steps when dataInputStep is not MacrosUpload', () => { const { queryByTestId } = render( - + ); expect(queryByTestId('migrationsSubSteps')).not.toBeInTheDocument(); @@ -99,9 +121,14 @@ describe('MacrosDataInput', () => { }); it('does not render sub-steps when missingMacros is missing', () => { + mockUseMissingResources.mockReturnValue({ + missingResourcesIndexed: { + macros: undefined, + }, + }); const { queryByTestId } = render( - + ); expect(queryByTestId('migrationsSubSteps')).not.toBeInTheDocument(); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.tsx index 9579cd6ee3681..5126e650aa581 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.tsx @@ -12,29 +12,33 @@ import { SubSteps } from '../../../../../common/components'; import { getEuiStepStatus } from '../../../../../common/utils/get_eui_step_status'; import { useKibana } from '../../../../../../common/lib/kibana/kibana_react'; import type { RuleMigrationTaskStats } from '../../../../../../../common/siem_migrations/model/rule_migration.gen'; -import type { OnResourcesCreated, OnMissingResourcesFetched } from '../../types'; +import type { + OnResourcesCreated, + OnMissingResourcesFetched, + UseMigrationStepsProps, +} from '../../types'; import * as i18n from './translations'; import { SplunkDataInputStep } from '../constants'; import { useCopyExportQueryStep } from './sub_steps/copy_export_query'; import { useMacrosFileUploadStep } from './sub_steps/macros_file_upload'; import { useCheckResourcesStep } from './sub_steps/check_resources'; +import { useMissingResources } from '../hooks/use_missing_resources'; interface MacrosDataInputSubStepsProps { migrationStats: RuleMigrationTaskStats; missingMacros: string[]; onMissingResourcesFetched: OnMissingResourcesFetched; } -interface MacrosDataInputProps - extends Omit { - dataInputStep: SplunkDataInputStep; - migrationStats?: RuleMigrationTaskStats; - missingMacros?: string[]; -} -export const MacrosDataInput = React.memo( - ({ dataInputStep, migrationStats, missingMacros, onMissingResourcesFetched }) => { + +export const MacrosDataInput = React.memo( + ({ dataInputStep, migrationStats, migrationSource, setMigrationDataInputStep }) => { + const { missingResourcesIndexed, onMissingResourcesFetched } = useMissingResources({ + setMigrationDataInputStep, + }); + const missingMacros = useMemo(() => missingResourcesIndexed?.macros, [missingResourcesIndexed]); const dataInputStatus = useMemo( - () => getEuiStepStatus(SplunkDataInputStep.Macros, dataInputStep), - [dataInputStep] + () => getEuiStepStatus(SplunkDataInputStep.Macros, dataInputStep[migrationSource]), + [dataInputStep, migrationSource] ); return ( diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.test.tsx index 754353a368cd8..38ce0dbec3272 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.test.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { render } from '@testing-library/react'; import { RulesDataInput } from './rules_data_input'; -import { SplunkDataInputStep } from '../constants'; +import { QradarDataInputStep, SplunkDataInputStep } from '../constants'; import { TestProviders } from '../../../../../../common/mock/test_providers'; import { MigrationSource } from '../../../../types'; @@ -16,17 +16,18 @@ describe('RulesDataInput', () => { const defaultProps = { migrationStats: undefined, onMigrationCreated: jest.fn(), - onMissingResourcesFetched: jest.fn(), + dataInputStep: { + [MigrationSource.SPLUNK]: SplunkDataInputStep.Rules, + [MigrationSource.QRADAR]: QradarDataInputStep.Rules, + }, + migrationSource: MigrationSource.SPLUNK, + setMigrationDataInputStep: jest.fn(), }; it('renders the step number', () => { const { getByTestId } = render( - + ); @@ -37,11 +38,7 @@ describe('RulesDataInput', () => { it('renders the title', () => { const { getByTestId } = render( - + ); @@ -52,11 +49,7 @@ describe('RulesDataInput', () => { it('renders sub-steps when the step is current', () => { const { getByTestId } = render( - + ); @@ -68,7 +61,10 @@ describe('RulesDataInput', () => { diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx index 84cf910fef76f..24f6880f09cf1 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx @@ -15,6 +15,7 @@ import type { OnMigrationCreated, OnMissingResourcesFetched, RulesDataInputSubStepsProps, + UseMigrationStepsProps, } from '../../types'; import * as i18n from './translations'; import { QradarDataInputStep, SplunkDataInputStep } from '../constants'; @@ -22,18 +23,17 @@ import { useCopyExportQueryStep } from './sub_steps/copy_export_query'; import { useRulesFileUploadStep } from './sub_steps/rules_file_upload'; import { useCheckResourcesStep } from './sub_steps/check_resources'; import { MigrationSource } from '../../../../types'; +import { useMissingResources } from '../hooks/use_missing_resources'; -interface RulesDataInputProps extends Omit { - dataInputStep: SplunkDataInputStep | QradarDataInputStep; -} -export const RulesDataInput = React.memo( +export const RulesDataInput = React.memo( ({ dataInputStep, migrationStats, migrationSource, onMigrationCreated, - onMissingResourcesFetched, + setMigrationDataInputStep, }) => { + const { onMissingResourcesFetched } = useMissingResources({ setMigrationDataInputStep }); const dataInputNumber = useMemo( () => migrationSource === MigrationSource.QRADAR @@ -47,7 +47,7 @@ export const RulesDataInput = React.memo( migrationSource === MigrationSource.QRADAR ? QradarDataInputStep.Rules : SplunkDataInputStep.Rules, - dataInputStep + dataInputStep[migrationSource] ), [dataInputStep, migrationSource] ); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/types.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/types.ts index 2fc00feac230d..687a6cbeb5c19 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/types.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/types.ts @@ -8,14 +8,12 @@ import type { SiemMigrationResourceBase } from '../../../../../common/siem_migrations/model/common.gen'; import type { MigrationSource, RuleMigrationStats } from '../../types'; import type { + DataInputStep, QradarDataInputStep, QradarDataInputStepId, SplunkDataInputStep, SplunkDataInputStepId, } from './steps/constants'; -import type { LookupsDataInput } from './steps/lookups/lookups_data_input'; -import type { MacrosDataInput } from './steps/macros/macros_data_input'; -import type { RulesDataInput } from './steps/rules/rules_data_input'; export type OnMigrationCreated = (migrationStats: RuleMigrationStats) => void; export type OnResourcesCreated = () => void; @@ -23,26 +21,27 @@ export type OnMissingResourcesFetched = (missingResources: SiemMigrationResource type DataInputStepId = SplunkDataInputStepId | QradarDataInputStepId; -export interface Step> { +export interface UseMigrationStepsProps { + dataInputStep: DataInputStep; + migrationSource: MigrationSource; + migrationStats?: RuleMigrationStats; + onMigrationCreated: (createdMigrationStats: RuleMigrationStats) => void; + onMissingResourcesFetched?: OnMissingResourcesFetched; + setMigrationDataInputStep: (step: SplunkDataInputStep | QradarDataInputStep) => void; +} + +export interface Step< + Props = UseMigrationStepsProps, + C extends React.ComponentType = React.ComponentType +> { id: DataInputStepId; Component: C; - props?: Props; } -type RulesStep = Step, typeof RulesDataInput>; - -type MacrosStep = Step, typeof MacrosDataInput>; - -type LookupsStep = Step, typeof LookupsDataInput>; - -export type SplunkStep = RulesStep | MacrosStep | LookupsStep; -export type QradarStep = RulesStep; - -export type SplunkMigrationSteps = Array; -export type QradarMigrationSteps = Array; +export type Steps = Array; export interface RulesDataInputSubStepsProps { - dataInputStep: SplunkDataInputStep | QradarDataInputStep; + dataInputStep: DataInputStep; migrationSource: MigrationSource; migrationStats?: RuleMigrationStats; onMigrationCreated: (createdMigrationStats: RuleMigrationStats) => void; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/index.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/index.ts index 3891c362c7288..c427f449df5f2 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/index.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/index.ts @@ -7,16 +7,13 @@ import { MigrationSource } from '../types'; -import type { - QradarMigrationSteps, - SplunkMigrationSteps, -} from '../components/data_input_flyout/types'; +import type { Steps } from '../components/data_input_flyout/types'; import { SPLUNK_MIGRATION_STEPS } from './splunk'; import { QRADAR_MIGRATION_STEPS } from './qradar'; export const STEP_COMPONENTS: { - [MigrationSource.SPLUNK]: SplunkMigrationSteps; - [MigrationSource.QRADAR]: QradarMigrationSteps; + [MigrationSource.SPLUNK]: Steps; + [MigrationSource.QRADAR]: Steps; } = { [MigrationSource.SPLUNK]: SPLUNK_MIGRATION_STEPS, [MigrationSource.QRADAR]: QRADAR_MIGRATION_STEPS, diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/qradar.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/qradar.ts index 2abcf252dd49f..af43703c8ce80 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/qradar.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/qradar.ts @@ -7,8 +7,8 @@ import { QradarDataInputStepId } from '../components/data_input_flyout/steps/constants'; import { RulesDataInput } from '../components/data_input_flyout/steps/rules/rules_data_input'; -import type { QradarMigrationSteps } from '../components/data_input_flyout/types'; +import type { Steps } from '../components/data_input_flyout/types'; -export const QRADAR_MIGRATION_STEPS: QradarMigrationSteps = [ +export const QRADAR_MIGRATION_STEPS: Steps = [ { id: QradarDataInputStepId.Rules, Component: RulesDataInput }, ] as const; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/splunk.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/splunk.ts index ed4bbe5d075e4..b27b6d3cad622 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/splunk.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/splunk.ts @@ -9,9 +9,9 @@ import { SplunkDataInputStepId } from '../components/data_input_flyout/steps/con import { LookupsDataInput } from '../components/data_input_flyout/steps/lookups/lookups_data_input'; import { MacrosDataInput } from '../components/data_input_flyout/steps/macros/macros_data_input'; import { RulesDataInput } from '../components/data_input_flyout/steps/rules/rules_data_input'; -import type { SplunkMigrationSteps } from '../components/data_input_flyout/types'; +import type { Steps } from '../components/data_input_flyout/types'; -export const SPLUNK_MIGRATION_STEPS: SplunkMigrationSteps = [ +export const SPLUNK_MIGRATION_STEPS: Steps = [ { id: SplunkDataInputStepId.Rules, Component: RulesDataInput }, { id: SplunkDataInputStepId.Macros, Component: MacrosDataInput }, { id: SplunkDataInputStepId.Lookups, Component: LookupsDataInput }, diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/hooks/use_migration_steps.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/hooks/use_migration_steps.test.tsx deleted file mode 100644 index 66986b8f52102..0000000000000 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/hooks/use_migration_steps.test.tsx +++ /dev/null @@ -1,62 +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 { - QradarDataInputStep, - QradarDataInputStepId, - SplunkDataInputStep, - SplunkDataInputStepId, -} from '../components/data_input_flyout/steps/constants'; -import type { UseMigrationStepsProps } from './use_migration_steps'; -import { useMigrationSteps } from './use_migration_steps'; -import { renderHook } from '@testing-library/react'; -import { SiemMigrationTaskStatus } from '../../../../common/siem_migrations/constants'; -import { MigrationSource } from '../types'; - -describe('useMigrationSteps', () => { - const props: UseMigrationStepsProps = { - dataInputStep: { - [MigrationSource.SPLUNK]: SplunkDataInputStep.Rules, - [MigrationSource.QRADAR]: QradarDataInputStep.Rules, - }, - migrationSource: MigrationSource.SPLUNK, - setMigrationDataInputStep: jest.fn(), - migrationStats: { - id: 'test-id', - name: 'test-name', - status: SiemMigrationTaskStatus.FINISHED, - items: { - total: 1, - pending: 0, - failed: 0, - completed: 1, - processing: 0, - }, - created_at: '2024-01-01T00:00:00Z', - last_updated_at: '2024-01-01T00:00:00Z', - }, - onMigrationCreated: jest.fn(), - onMissingResourcesFetched: jest.fn(), - }; - - it('should return Splunk migration steps when migration source is Splunk', () => { - const { result } = renderHook(() => - useMigrationSteps({ ...props, migrationSource: MigrationSource.SPLUNK }) - ); - expect(result.current?.length).toEqual(3); - expect(result.current?.[0].id).toBe(SplunkDataInputStepId.Rules); - expect(result.current?.[1].id).toBe(SplunkDataInputStepId.Macros); - expect(result.current?.[2].id).toBe(SplunkDataInputStepId.Lookups); - }); - it('should return Qradar migration steps when migration source is Qradar', () => { - const { result } = renderHook(() => - useMigrationSteps({ ...props, migrationSource: MigrationSource.QRADAR }) - ); - expect(result.current?.length).toEqual(1); - expect(result.current?.[0].id).toBe(QradarDataInputStepId.Rules); - }); -}); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/hooks/use_migration_steps.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/hooks/use_migration_steps.tsx deleted file mode 100644 index e6ecd61b52bb1..0000000000000 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/hooks/use_migration_steps.tsx +++ /dev/null @@ -1,156 +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 { useCallback, useMemo, useState } from 'react'; - -import type { SiemMigrationResourceBase } from '../../../../common/siem_migrations/model/common.gen'; - -import type { - DataInputStep, - QradarDataInputStep, -} from '../components/data_input_flyout/steps/constants'; -import { SplunkDataInputStep } from '../components/data_input_flyout/steps/constants'; - -import { STEP_COMPONENTS } from '../configs'; - -import { MigrationSource } from '../types'; -import type { - QradarMigrationSteps, - QradarStep, - RulesDataInputSubStepsProps, - SplunkMigrationSteps, - SplunkStep, -} from '../components/data_input_flyout/types'; - -export type UseMigrationStepsProps = Omit & { - dataInputStep: DataInputStep; - setMigrationDataInputStep: (step: SplunkDataInputStep | QradarDataInputStep) => void; -}; - -interface UseSplunkMigrationSteps extends Omit { - dataInputStep: SplunkDataInputStep; -} - -interface UseQradarMigrationSteps extends Omit { - dataInputStep: QradarDataInputStep; -} - -interface MissingResourcesIndexed { - macros: string[]; - lookups: string[]; -} - -const useSplunkMigrationSteps = ({ - setMigrationDataInputStep, - dataInputStep, - migrationSource, - migrationStats, - onMigrationCreated, -}: UseSplunkMigrationSteps): SplunkMigrationSteps | null => { - const [missingResourcesIndexed, setMissingResourcesIndexed] = useState< - MissingResourcesIndexed | undefined - >(); - - const onMissingResourcesFetched = useCallback( - (missingResources: SiemMigrationResourceBase[]) => { - const newMissingResourcesIndexed = missingResources.reduce( - (acc, { type, name }) => { - if (type === 'macro') { - acc.macros.push(name); - } else if (type === 'lookup') { - acc.lookups.push(name); - } - return acc; - }, - { macros: [], lookups: [] } - ); - setMissingResourcesIndexed(newMissingResourcesIndexed); - if (newMissingResourcesIndexed.macros.length) { - setMigrationDataInputStep(SplunkDataInputStep.Macros); - return; - } - if (newMissingResourcesIndexed.lookups.length) { - setMigrationDataInputStep(SplunkDataInputStep.Lookups); - return; - } - setMigrationDataInputStep(SplunkDataInputStep.End); - }, - [setMigrationDataInputStep] - ); - - const onAllLookupsCreated = useCallback(() => { - setMigrationDataInputStep(SplunkDataInputStep.End); - }, [setMigrationDataInputStep]); - - const SPLUNK_MIGRATION_STEPS: SplunkMigrationSteps = useMemo( - () => - STEP_COMPONENTS[MigrationSource.SPLUNK].map(({ id, Component }: SplunkStep) => ({ - id, - Component, - props: { - dataInputStep, - migrationSource, - migrationStats, - missingLookups: missingResourcesIndexed?.lookups, - missingMacros: missingResourcesIndexed?.macros, - onAllLookupsCreated, - onMissingResourcesFetched, - onMigrationCreated, - }, - })) as SplunkMigrationSteps, - [ - dataInputStep, - migrationSource, - migrationStats, - onMigrationCreated, - missingResourcesIndexed, - onAllLookupsCreated, - onMissingResourcesFetched, - ] - ); - - return migrationSource === MigrationSource.SPLUNK ? SPLUNK_MIGRATION_STEPS : null; -}; - -const useQradarMigrationSteps = ({ - onMigrationCreated, - dataInputStep, - migrationSource, - migrationStats, -}: UseQradarMigrationSteps): QradarMigrationSteps | null => { - const QRADAR_MIGRATION_STEPS: QradarMigrationSteps = useMemo( - () => - STEP_COMPONENTS[MigrationSource.QRADAR].map(({ id, Component }: QradarStep) => ({ - id, - Component, - props: { - dataInputStep, - migrationSource, - migrationStats, - onMigrationCreated, - }, - })), - [dataInputStep, migrationSource, migrationStats, onMigrationCreated] - ); - - return migrationSource === MigrationSource.QRADAR ? QRADAR_MIGRATION_STEPS : null; -}; - -export const useMigrationSteps = ( - props: UseMigrationStepsProps -): SplunkMigrationSteps | QradarMigrationSteps | null => { - const splunkMigrationSteps: SplunkMigrationSteps | null = useSplunkMigrationSteps({ - ...props, - dataInputStep: props.dataInputStep[MigrationSource.SPLUNK], - }); - - const qradarMigrationSteps: QradarMigrationSteps | null = useQradarMigrationSteps({ - ...props, - dataInputStep: props.dataInputStep[MigrationSource.QRADAR], - }); - - return splunkMigrationSteps ?? qradarMigrationSteps; -}; From 37cf04ad11fc317371e7f955f9c6602b4eb8574a Mon Sep 17 00:00:00 2001 From: Angela Chuang Date: Tue, 9 Dec 2025 13:59:05 +0000 Subject: [PATCH 17/23] code review --- .../public/siem_migrations/common/types.ts | 7 ++ .../data_input_flyout/data_input_flyout.tsx | 68 ++++++------------- .../data_input_flyout/steps/constants.ts | 13 ---- .../steps/lookups/lookups_data_input.test.tsx | 16 +++-- .../steps/lookups/lookups_data_input.tsx | 27 ++++---- .../steps/macros/macros_data_input.test.tsx | 19 ++++-- .../steps/macros/macros_data_input.tsx | 20 +++--- .../steps/upload_dashboards/index.test.tsx | 17 +++-- .../steps/upload_dashboards/index.tsx | 16 ++--- .../data_input_flyout/data_input_flyout.tsx | 23 +++---- .../data_input_flyout/steps/constants.ts | 14 ---- .../steps/hooks/use_missing_resources.ts | 16 ++--- .../steps/lookups/lookups_data_input.test.tsx | 36 ++-------- .../steps/lookups/lookups_data_input.tsx | 14 ++-- .../steps/macros/macros_data_input.test.tsx | 39 ++++++----- .../steps/macros/macros_data_input.tsx | 12 ++-- .../steps/rules/rules_data_input.test.tsx | 16 ++--- .../steps/rules/rules_data_input.tsx | 13 ++-- .../components/data_input_flyout/types.ts | 22 +++--- 19 files changed, 164 insertions(+), 244 deletions(-) delete mode 100644 x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/constants.ts diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/types.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/types.ts index 29b8b5335ff89..801c3f40b8432 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/types.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/types.ts @@ -39,3 +39,10 @@ export interface FilterOptionsBase { export interface MigrationStats extends MigrationTaskStats { status: SiemMigrationTaskStatus; // use the native enum instead of the zod enum from the model } + +export enum SplunkDataInputStep { + Upload = 1, + Macros = 2, + Lookups = 3, + End = 10, +} diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/data_input_flyout.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/data_input_flyout.tsx index 15baf0bacbde1..6901680587695 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/data_input_flyout.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/data_input_flyout.tsx @@ -19,7 +19,6 @@ import { } from '@elastic/eui'; import React, { useState, useCallback } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; -import type { SiemMigrationResourceBase } from '../../../../../common/siem_migrations/model/common.gen'; import { SiemMigrationRetryFilter, SiemMigrationTaskStatus, @@ -29,11 +28,13 @@ import { useMigrationDataInputContext } from '../../../common/components/migrati import { DashboardsUploadStep } from './steps/upload_dashboards'; import { MacrosDataInput } from './steps/macros/macros_data_input'; import { LookupsDataInput } from './steps/lookups/lookups_data_input'; -import { DashboardUploadSteps } from './steps/constants'; import { useStartDashboardsMigrationModal } from '../../hooks/use_start_dashboard_migration_modal'; import type { DashboardMigrationStats } from '../../types'; import { useStartMigration } from '../../logic/use_start_migration'; import type { MigrationSettingsBase } from '../../../common/types'; +import { SplunkDataInputStep } from '../../../common/types'; +import { MigrationSource } from '../../../rules/types'; +import { useMissingResources } from '../../../rules/components/data_input_flyout/steps/hooks/use_missing_resources'; interface DashboardMigrationDataInputFlyoutProps { onClose: () => void; @@ -41,11 +42,6 @@ interface DashboardMigrationDataInputFlyoutProps { setFlyoutMigrationStats: (migrationStats: DashboardMigrationStats | undefined) => void; } -interface MissingResourcesIndexed { - macros: string[]; - lookups: string[]; -} - const DASHBOARDS_MIGRATION_DATA_INPUT_FLYOUT_TITLE = 'dashboardsMigrationDataInputFlyoutTitle'; export const DashboardMigrationDataInputFlyout = React.memo( @@ -59,15 +55,17 @@ export const DashboardMigrationDataInputFlyout = React.memo( }); const { closeFlyout } = useMigrationDataInputContext(); - const [missingResourcesIndexed, setMissingResourcesIndexed] = useState< - MissingResourcesIndexed | undefined - >(); + const isRetry = migrationStats?.status === SiemMigrationTaskStatus.FINISHED; - const [dataInputStep, setDataInputStep] = useState( - DashboardUploadSteps.DashboardsUpload + const [dataInputStep, setDataInputStep] = useState( + SplunkDataInputStep.Upload ); + const { missingResourcesIndexed, onMissingResourcesFetched } = useMissingResources({ + setDataInputStep, + }); + const onMigrationCreated = useCallback( (createdMigrationStats: DashboardMigrationStats) => { setFlyoutMigrationStats(createdMigrationStats); @@ -75,37 +73,6 @@ export const DashboardMigrationDataInputFlyout = React.memo( [setFlyoutMigrationStats] ); - const onMissingResourcesFetched = useCallback( - (missingResources: SiemMigrationResourceBase[]) => { - const newMissingResourcesIndexed = missingResources.reduce( - (acc, { type, name }) => { - if (type === 'macro') { - acc.macros.push(name); - } else if (type === 'lookup') { - acc.lookups.push(name); - } - return acc; - }, - { macros: [], lookups: [] } - ); - setMissingResourcesIndexed(newMissingResourcesIndexed); - if (newMissingResourcesIndexed.macros.length) { - setDataInputStep(DashboardUploadSteps.MacrosUpload); - return; - } - if (newMissingResourcesIndexed.lookups.length) { - setDataInputStep(DashboardUploadSteps.LookupsUpload); - return; - } - setDataInputStep(DashboardUploadSteps.End); - }, - [] - ); - - const onAllLookupsCreated = useCallback(() => { - setDataInputStep(DashboardUploadSteps.End); - }, []); - const { startMigration, isLoading: isStartLoading } = useStartMigration(onClose); const onStartMigrationWithSettings = useCallback( (settings: MigrationSettingsBase) => { @@ -156,25 +123,34 @@ export const DashboardMigrationDataInputFlyout = React.memo( diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/constants.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/constants.ts deleted file mode 100644 index a1c1504409661..0000000000000 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/constants.ts +++ /dev/null @@ -1,13 +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. - */ - -export enum DashboardUploadSteps { - DashboardsUpload = 1, - MacrosUpload = 2, - LookupsUpload = 3, - End = 10, -} diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/lookups/lookups_data_input.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/lookups/lookups_data_input.test.tsx index 017b17c4e0f1d..40588df6fd995 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/lookups/lookups_data_input.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/lookups/lookups_data_input.test.tsx @@ -8,11 +8,12 @@ import { render } from '@testing-library/react'; import React from 'react'; import { LookupsDataInput } from './lookups_data_input'; -import { DashboardUploadSteps } from '../constants'; import * as i18n from './translations'; import { getDashboardMigrationStatsMock } from '../../../../__mocks__'; import { SiemMigrationTaskStatus } from '../../../../../../../common/siem_migrations/constants'; import { TestProviders } from '../../../../../../common/mock'; +import { MigrationSource } from '../../../../../rules/types'; +import { SplunkDataInputStep } from '../../../../../common/types'; const mockAddError = jest.fn(); const mockAddSuccess = jest.fn(); @@ -37,10 +38,13 @@ jest.mock('../../../../../../common/lib/kibana/kibana_react', () => ({ describe('LookupsDataInput', () => { const defaultProps = { - onAllLookupsCreated: jest.fn(), - dataInputStep: DashboardUploadSteps.LookupsUpload, + dataInputStep: SplunkDataInputStep.Lookups, migrationStats: getDashboardMigrationStatsMock({ status: SiemMigrationTaskStatus.READY }), - missingLookups: ['lookup1', 'lookup2'], + missingResourcesIndexed: { lookups: ['lookup1', 'lookup2'], macros: [] }, + setDataInputStep: jest.fn(), + migrationSource: MigrationSource.SPLUNK, + onMigrationCreated: jest.fn(), + onMissingResourcesFetched: jest.fn(), }; afterEach(() => { @@ -82,7 +86,7 @@ describe('LookupsDataInput', () => { it('does not render description when dataInputStep is not LookupsUpload', () => { const { queryByText } = render( - + ); expect(queryByText(i18n.LOOKUPS_DATA_INPUT_DESCRIPTION)).not.toBeInTheDocument(); @@ -100,7 +104,7 @@ describe('LookupsDataInput', () => { it('does not render description when missingLookups is missing', () => { const { queryByText } = render( - + ); expect(queryByText(i18n.LOOKUPS_DATA_INPUT_DESCRIPTION)).not.toBeInTheDocument(); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/lookups/lookups_data_input.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/lookups/lookups_data_input.tsx index 117ae33f4c7c7..028f71438eaa5 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/lookups/lookups_data_input.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/lookups/lookups_data_input.tsx @@ -25,25 +25,28 @@ import { getEuiStepStatus } from '../../../../../common/utils/get_eui_step_statu import type { DashboardMigrationTaskStats } from '../../../../../../../common/siem_migrations/model/dashboard_migration.gen'; import type { OnResourcesCreated } from '../../types'; import * as i18n from './translations'; -import { DashboardUploadSteps } from '../constants'; import { useMissingLookupsListStep } from './sub_steps/missing_lookups_list'; import { useLookupsFileUploadStep } from './sub_steps/lookups_file_upload'; - +import type { UseMigrationStepsProps } from '../../../../../rules/components/data_input_flyout/types'; +import { SplunkDataInputStep } from '../../../../../common/types'; interface LookupsDataInputSubStepsProps { migrationStats: DashboardMigrationTaskStats; missingLookups: string[]; onAllLookupsCreated: OnResourcesCreated; } -interface LookupsDataInputProps - extends Omit { - dataInputStep: DashboardUploadSteps; - migrationStats?: DashboardMigrationTaskStats; - missingLookups?: string[]; -} -export const LookupsDataInput = React.memo( - ({ dataInputStep, migrationStats, missingLookups, onAllLookupsCreated }) => { + +export const LookupsDataInput = React.memo( + ({ dataInputStep, migrationStats, setDataInputStep, missingResourcesIndexed }) => { + const missingLookups = useMemo( + () => missingResourcesIndexed?.lookups, + [missingResourcesIndexed] + ); + const onAllLookupsCreated = useCallback(() => { + setDataInputStep(SplunkDataInputStep.End); + }, [setDataInputStep]); + const dataInputStatus = useMemo( - () => getEuiStepStatus(DashboardUploadSteps.LookupsUpload, dataInputStep), + () => getEuiStepStatus(SplunkDataInputStep.Lookups, dataInputStep), [dataInputStep] ); @@ -56,7 +59,7 @@ export const LookupsDataInput = React.memo( diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/macros/macros_data_input.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/macros/macros_data_input.test.tsx index 206610bd193c9..33c50937607a3 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/macros/macros_data_input.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/macros/macros_data_input.test.tsx @@ -8,12 +8,14 @@ import { act, fireEvent, render } from '@testing-library/react'; import React from 'react'; import { MacrosDataInput } from './macros_data_input'; -import { DashboardUploadSteps } from '../constants'; import { getDashboardMigrationStatsMock } from '../../../../__mocks__'; import { SiemMigrationTaskStatus } from '../../../../../../../common/siem_migrations/constants'; import { TestProviders } from '../../../../../../common/mock'; import { useAppToasts } from '../../../../../../common/hooks/use_app_toasts'; import { useAppToastsMock } from '../../../../../../common/hooks/use_app_toasts.mock'; +import type { UseMigrationStepsProps } from '../../../../../rules/components/data_input_flyout/types'; +import { MigrationSource } from '../../../../../rules/types'; +import { SplunkDataInputStep } from '../../../../../common/types'; const mockAddError = jest.fn(); const mockAddSuccess = jest.fn(); @@ -44,16 +46,19 @@ jest.mock('../../../../../../common/hooks/use_app_toasts'); describe('MacrosDataInput', () => { let appToastsMock: jest.Mocked>; - const defaultProps = { + const defaultProps: UseMigrationStepsProps = { onMissingResourcesFetched: jest.fn(), - dataInputStep: DashboardUploadSteps.MacrosUpload, + dataInputStep: SplunkDataInputStep.Macros, migrationStats: getDashboardMigrationStatsMock({ status: SiemMigrationTaskStatus.READY }), - missingMacros: ['macro1', 'macro2'], + migrationSource: MigrationSource.SPLUNK, + onMigrationCreated: jest.fn(), + setDataInputStep: jest.fn(), + missingResourcesIndexed: { macros: ['macro1', 'macro2'], lookups: [] }, }; beforeEach(() => { appToastsMock = useAppToastsMock.create(); - (useAppToasts as jest.Mock).mockReturnValue(appToastsMock); + jest.mocked(useAppToasts).mockReturnValue(appToastsMock); }); afterEach(() => { @@ -83,7 +88,7 @@ describe('MacrosDataInput', () => { it('does not render sub-steps when dataInputStep is not MacrosUpload', () => { const { queryByTestId } = render( - + ); expect(queryByTestId('migrationsSubSteps')).not.toBeInTheDocument(); @@ -101,7 +106,7 @@ describe('MacrosDataInput', () => { it('does not render sub-steps when missingMacros is missing', () => { const { queryByTestId } = render( - + ); expect(queryByTestId('migrationsSubSteps')).not.toBeInTheDocument(); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/macros/macros_data_input.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/macros/macros_data_input.tsx index 40c3d8d0b8f14..a72ae4c37d006 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/macros/macros_data_input.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/macros/macros_data_input.tsx @@ -14,26 +14,24 @@ import { useKibana } from '../../../../../../common/lib/kibana/kibana_react'; import type { DashboardMigrationTaskStats } from '../../../../../../../common/siem_migrations/model/dashboard_migration.gen'; import type { OnResourcesCreated, OnMissingResourcesFetched } from '../../types'; import * as i18n from './translations'; -import { DashboardUploadSteps } from '../constants'; import { useCopyExportQueryStep } from './sub_steps/copy_export_query'; import { useMacrosFileUploadStep } from './sub_steps/macros_file_upload'; import { useCheckResourcesStep } from '../common/check_resources'; +import type { UseMigrationStepsProps } from '../../../../../rules/components/data_input_flyout/types'; +import { SplunkDataInputStep } from '../../../../../common/types'; interface MacrosDataInputSubStepsProps { migrationStats: DashboardMigrationTaskStats; missingMacros: string[]; onMissingResourcesFetched: OnMissingResourcesFetched; } -interface MacrosDataInputProps - extends Omit { - dataInputStep: DashboardUploadSteps; - migrationStats?: DashboardMigrationTaskStats; - missingMacros?: string[]; -} -export const MacrosDataInput = React.memo( - ({ dataInputStep, migrationStats, missingMacros, onMissingResourcesFetched }) => { + +export const MacrosDataInput = React.memo( + ({ dataInputStep, migrationStats, missingResourcesIndexed, onMissingResourcesFetched }) => { + const missingMacros = useMemo(() => missingResourcesIndexed?.macros, [missingResourcesIndexed]); + const dataInputStatus = useMemo( - () => getEuiStepStatus(DashboardUploadSteps.MacrosUpload, dataInputStep), + () => getEuiStepStatus(SplunkDataInputStep.Macros, dataInputStep), [dataInputStep] ); @@ -46,7 +44,7 @@ export const MacrosDataInput = React.memo( diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/upload_dashboards/index.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/upload_dashboards/index.test.tsx index 30db5abd0f37a..794e670c9c038 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/upload_dashboards/index.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/upload_dashboards/index.test.tsx @@ -9,13 +9,18 @@ import React from 'react'; import { render } from '@testing-library/react'; import { DashboardsUploadStep } from '.'; import { TestProviders } from '../../../../../../common/mock/test_providers'; -import { DashboardUploadSteps } from '../constants'; +import { MigrationSource } from '../../../../../rules/types'; +import { SplunkDataInputStep } from '../../../../../common/types'; describe('DashboardsUploadStep', () => { const defaultProps = { migrationStats: undefined, onMigrationCreated: jest.fn(), onMissingResourcesFetched: jest.fn(), + dataInputStep: SplunkDataInputStep.Upload, + migrationSource: MigrationSource.SPLUNK, + setDataInputStep: jest.fn(), + missingResourcesIndexed: { lookups: [], macros: [] }, }; it('renders the step number', () => { @@ -43,10 +48,7 @@ describe('DashboardsUploadStep', () => { it('renders sub-steps when the step is current', () => { const { getByTestId } = render( - + ); @@ -56,10 +58,7 @@ describe('DashboardsUploadStep', () => { it('does not render sub-steps when the step is not current', () => { const { queryByTestId } = render( - + ); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/upload_dashboards/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/upload_dashboards/index.tsx index fb6f6d01484fe..9f45579b50627 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/upload_dashboards/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/upload_dashboards/index.tsx @@ -8,27 +8,19 @@ import React, { useMemo } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiStepNumber, EuiTitle } from '@elastic/eui'; import { getEuiStepStatus } from '../../../../../common/utils/get_eui_step_status'; -import { DashboardUploadSteps } from '../constants'; import * as i18n from '../translations'; import { DashboardsUploadSubSteps } from './sub_steps'; -import type { OnMigrationCreated, OnMissingResourcesFetched } from '../../types'; -import type { DashboardMigrationStats } from '../../../../types'; - -interface DashboardsUploadStepProps { - dataInputStep?: number; - migrationStats?: DashboardMigrationStats; - onMigrationCreated: OnMigrationCreated; - onMissingResourcesFetched: OnMissingResourcesFetched; -} +import type { UseMigrationStepsProps } from '../../../../../rules/components/data_input_flyout/types'; +import { SplunkDataInputStep } from '../../../../../common/types'; export const DashboardsUploadStep = ({ dataInputStep = 1, // Default value if not provided migrationStats, onMigrationCreated, onMissingResourcesFetched, -}: DashboardsUploadStepProps) => { +}: UseMigrationStepsProps) => { const dataInputStatus = useMemo( - () => getEuiStepStatus(DashboardUploadSteps.DashboardsUpload, dataInputStep), + () => getEuiStepStatus(SplunkDataInputStep.Upload, dataInputStep), [dataInputStep] ); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx index 33795d3dd908e..ee40faf737e86 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx @@ -23,8 +23,6 @@ import { SiemMigrationRetryFilter, SiemMigrationTaskStatus, } from '../../../../../common/siem_migrations/constants'; -import type { DataInputStep } from './steps/constants'; -import { QradarDataInputStep, SplunkDataInputStep } from './steps/constants'; import { useStartRulesMigrationModal } from '../../hooks/use_start_rules_migration_modal'; import { MigrationSource, type RuleMigrationSettings, type RuleMigrationStats } from '../../types'; import { useStartMigration } from '../../logic/use_start_migration'; @@ -32,6 +30,8 @@ import { useMigrationSourceStep } from '../migration_source_step/use_migration_s import { MigrationSourceDropdown } from '../migration_source_step/migration_source_dropdown'; import { CenteredLoadingSpinner } from '../../../../common/components/centered_loading_spinner'; import { STEP_COMPONENTS } from '../../configs'; +import { useMissingResources } from './steps/hooks/use_missing_resources'; +import { SplunkDataInputStep } from '../../../common/types'; export interface MigrationDataInputFlyoutProps { onClose: () => void; @@ -65,17 +65,11 @@ export const MigrationDataInputFlyout = React.memo({ - [MigrationSource.SPLUNK]: SplunkDataInputStep.Rules, - [MigrationSource.QRADAR]: QradarDataInputStep.Rules, - }); + const [dataInputStep, setDataInputStep] = useState(SplunkDataInputStep.Upload); - const setMigrationDataInputStep = useCallback( - (step: DataInputStep[MigrationSource]) => { - setDataInputStep((prev) => ({ ...prev, ...{ [migrationSource]: step } })); - }, - [migrationSource] - ); + const { missingResourcesIndexed, onMissingResourcesFetched } = useMissingResources({ + setDataInputStep, + }); const onMigrationCreated = useCallback( (createdMigrationStats: RuleMigrationStats) => { @@ -147,8 +141,11 @@ export const MigrationDataInputFlyout = React.memo )) ?? } diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/constants.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/constants.ts index 8894cfcb2c2c0..396e30bb0f48c 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/constants.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/constants.ts @@ -5,25 +5,11 @@ * 2.0. */ -import type { MigrationSource } from '../../../types'; - -export enum SplunkDataInputStep { - Rules = 1, - Macros = 2, - Lookups = 3, - End = 10, -} - export enum QradarDataInputStep { Rules = 1, End = 10, } -export interface DataInputStep { - [MigrationSource.SPLUNK]: SplunkDataInputStep; - [MigrationSource.QRADAR]: QradarDataInputStep; -} - export enum SplunkDataInputStepId { Rules = 'splunk_rules', Macros = 'splunk_macros', diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/hooks/use_missing_resources.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/hooks/use_missing_resources.ts index 95c106d3af425..97120ec700fd0 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/hooks/use_missing_resources.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/hooks/use_missing_resources.ts @@ -7,8 +7,8 @@ import { useCallback, useState } from 'react'; import type { SiemMigrationResourceBase } from '../../../../../../../common/siem_migrations/model/common.gen'; -import type { QradarDataInputStep } from '../constants'; -import { SplunkDataInputStep } from '../constants'; +import type { UseMigrationStepsProps } from '../../types'; +import { SplunkDataInputStep } from '../../../../../common/types'; interface MissingResourcesIndexed { macros: string[]; @@ -16,9 +16,9 @@ interface MissingResourcesIndexed { } export const useMissingResources = ({ - setMigrationDataInputStep, + setDataInputStep, }: { - setMigrationDataInputStep: (step: SplunkDataInputStep | QradarDataInputStep) => void; + setDataInputStep: UseMigrationStepsProps['setDataInputStep']; }) => { const [missingResourcesIndexed, setMissingResourcesIndexed] = useState< MissingResourcesIndexed | undefined @@ -39,16 +39,16 @@ export const useMissingResources = ({ ); setMissingResourcesIndexed(newMissingResourcesIndexed); if (newMissingResourcesIndexed.macros.length) { - setMigrationDataInputStep(SplunkDataInputStep.Macros); + setDataInputStep(SplunkDataInputStep.Macros); return; } if (newMissingResourcesIndexed.lookups.length) { - setMigrationDataInputStep(SplunkDataInputStep.Lookups); + setDataInputStep(SplunkDataInputStep.Lookups); return; } - setMigrationDataInputStep(SplunkDataInputStep.End); + setDataInputStep(SplunkDataInputStep.End); }, - [setMigrationDataInputStep] + [setDataInputStep] ); return { missingResourcesIndexed, onMissingResourcesFetched }; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.test.tsx index 42e8547f35325..1148dbc2f5b6f 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.test.tsx @@ -8,16 +8,14 @@ import { render } from '@testing-library/react'; import React from 'react'; import { LookupsDataInput } from './lookups_data_input'; -import { QradarDataInputStep, SplunkDataInputStep } from '../constants'; import { getRuleMigrationStatsMock } from '../../../../__mocks__'; import { SiemMigrationTaskStatus } from '../../../../../../../common/siem_migrations/constants'; import { TestProviders } from '../../../../../../common/mock'; import { MigrationSource } from '../../../../types'; -import { useMissingResources } from '../hooks/use_missing_resources'; +import { SplunkDataInputStep } from '../../../../../common/types'; const mockAddError = jest.fn(); const mockAddSuccess = jest.fn(); -const mockUseMissingResources = useMissingResources as jest.Mock; jest.mock('../../../../../../common/lib/kibana/kibana_react', () => ({ useKibana: () => ({ @@ -40,24 +38,15 @@ jest.mock('../../../../../../common/lib/kibana/kibana_react', () => ({ }), })); -jest.mock('../hooks/use_missing_resources', () => ({ - useMissingResources: jest.fn().mockReturnValue({ - missingResourcesIndexed: { - lookups: ['lookup1', 'lookup2'], - }, - }), -})); - describe('LookupsDataInput', () => { const defaultProps = { - dataInputStep: { - [MigrationSource.SPLUNK]: SplunkDataInputStep.Lookups, - [MigrationSource.QRADAR]: QradarDataInputStep.Rules, - }, + dataInputStep: SplunkDataInputStep.Lookups, migrationSource: MigrationSource.SPLUNK, migrationStats: getRuleMigrationStatsMock({ status: SiemMigrationTaskStatus.READY }), - setMigrationDataInputStep: jest.fn(), + setDataInputStep: jest.fn(), onMigrationCreated: jest.fn(), + onMissingResourcesFetched: jest.fn(), + missingResourcesIndexed: { lookups: ['lookup1', 'lookup2'], macros: [] }, }; afterEach(() => { @@ -99,13 +88,7 @@ describe('LookupsDataInput', () => { it('does not render description when dataInputStep is not LookupsUpload', () => { const { queryByTestId } = render( - + ); expect(queryByTestId('lookupsUploadDescription')).not.toBeInTheDocument(); @@ -121,14 +104,9 @@ describe('LookupsDataInput', () => { }); it('does not render description when missingLookups is missing', () => { - mockUseMissingResources.mockReturnValue({ - missingResourcesIndexed: { - lookups: undefined, - }, - }); const { queryByTestId } = render( - + ); expect(queryByTestId('lookupsUploadDescription')).not.toBeInTheDocument(); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.tsx index 02cea8a31091d..87ec830bdbbb8 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.tsx @@ -25,10 +25,9 @@ import { useKibana } from '../../../../../../common/lib/kibana/kibana_react'; import type { RuleMigrationTaskStats } from '../../../../../../../common/siem_migrations/model/rule_migration.gen'; import type { OnResourcesCreated, UseMigrationStepsProps } from '../../types'; import * as i18n from './translations'; -import { SplunkDataInputStep } from '../constants'; import { useMissingLookupsListStep } from './sub_steps/missing_lookups_list'; import { useLookupsFileUploadStep } from './sub_steps/lookups_file_upload'; -import { useMissingResources } from '../hooks/use_missing_resources'; +import { SplunkDataInputStep } from '../../../../../common/types'; interface LookupsDataInputSubStepsProps { migrationStats: RuleMigrationTaskStats; @@ -37,19 +36,18 @@ interface LookupsDataInputSubStepsProps { } export const LookupsDataInput = React.memo( - ({ dataInputStep, migrationSource, migrationStats, setMigrationDataInputStep }) => { - const { missingResourcesIndexed } = useMissingResources({ setMigrationDataInputStep }); + ({ dataInputStep, migrationStats, missingResourcesIndexed, setDataInputStep }) => { const missingLookups = useMemo( () => missingResourcesIndexed?.lookups, [missingResourcesIndexed] ); const onAllLookupsCreated = useCallback(() => { - setMigrationDataInputStep(SplunkDataInputStep.End); - }, [setMigrationDataInputStep]); + setDataInputStep(SplunkDataInputStep.End); + }, [setDataInputStep]); const dataInputStatus = useMemo( - () => getEuiStepStatus(SplunkDataInputStep.Lookups, dataInputStep[migrationSource]), - [dataInputStep, migrationSource] + () => getEuiStepStatus(SplunkDataInputStep.Lookups, dataInputStep), + [dataInputStep] ); return ( diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.test.tsx index b6a5218f0201a..d45d08debd32b 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.test.tsx @@ -8,7 +8,6 @@ import { act, fireEvent, render } from '@testing-library/react'; import React from 'react'; import { MacrosDataInput } from './macros_data_input'; -import { QradarDataInputStep, SplunkDataInputStep } from '../constants'; import { getRuleMigrationStatsMock } from '../../../../__mocks__'; import { SiemMigrationTaskStatus } from '../../../../../../../common/siem_migrations/constants'; import { TestProviders } from '../../../../../../common/mock'; @@ -16,11 +15,12 @@ import { useAppToasts } from '../../../../../../common/hooks/use_app_toasts'; import { useAppToastsMock } from '../../../../../../common/hooks/use_app_toasts.mock'; import { MigrationSource } from '../../../../types'; import { useMissingResources } from '../hooks/use_missing_resources'; +import type { UseMigrationStepsProps } from '../../types'; +import { SplunkDataInputStep } from '../../../../../common/types'; const mockAddError = jest.fn(); const mockAddSuccess = jest.fn(); const mockReportSetupMacrosQueryCopied = jest.fn(); -const mockUseMissingResources = useMissingResources as jest.Mock; jest.mock('../../../../../../common/lib/kibana/kibana_react', () => ({ useKibana: () => ({ @@ -48,28 +48,34 @@ jest.mock('../hooks/use_missing_resources', () => ({ useMissingResources: jest.fn().mockReturnValue({ missingResourcesIndexed: { macros: ['macro1', 'macro2'], + lookups: [], }, + onMissingResourcesFetched: jest.fn(), }), })); describe('MacrosDataInput', () => { let appToastsMock: jest.Mocked>; - const defaultProps = { + const defaultProps: UseMigrationStepsProps = { onMissingResourcesFetched: jest.fn(), - dataInputStep: { - [MigrationSource.SPLUNK]: SplunkDataInputStep.Macros, - [MigrationSource.QRADAR]: QradarDataInputStep.Rules, - }, + dataInputStep: SplunkDataInputStep.Macros, migrationStats: getRuleMigrationStatsMock({ status: SiemMigrationTaskStatus.READY }), migrationSource: MigrationSource.SPLUNK, - setMigrationDataInputStep: jest.fn(), + setDataInputStep: jest.fn(), onMigrationCreated: jest.fn(), }; beforeEach(() => { appToastsMock = useAppToastsMock.create(); - (useAppToasts as jest.Mock).mockReturnValue(appToastsMock); + jest.mocked(useAppToasts).mockReturnValue(appToastsMock); + jest.mocked(useMissingResources).mockReturnValue({ + missingResourcesIndexed: { + macros: ['macro1', 'macro2'], + lookups: [], + }, + onMissingResourcesFetched: jest.fn(), + }); }); afterEach(() => { @@ -99,13 +105,7 @@ describe('MacrosDataInput', () => { it('does not render sub-steps when dataInputStep is not MacrosUpload', () => { const { queryByTestId } = render( - + ); expect(queryByTestId('migrationsSubSteps')).not.toBeInTheDocument(); @@ -121,10 +121,9 @@ describe('MacrosDataInput', () => { }); it('does not render sub-steps when missingMacros is missing', () => { - mockUseMissingResources.mockReturnValue({ - missingResourcesIndexed: { - macros: undefined, - }, + jest.mocked(useMissingResources).mockReturnValue({ + missingResourcesIndexed: undefined, + onMissingResourcesFetched: jest.fn(), }); const { queryByTestId } = render( diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.tsx index 5126e650aa581..64b6450da8ae8 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.tsx @@ -18,11 +18,10 @@ import type { UseMigrationStepsProps, } from '../../types'; import * as i18n from './translations'; -import { SplunkDataInputStep } from '../constants'; import { useCopyExportQueryStep } from './sub_steps/copy_export_query'; import { useMacrosFileUploadStep } from './sub_steps/macros_file_upload'; import { useCheckResourcesStep } from './sub_steps/check_resources'; -import { useMissingResources } from '../hooks/use_missing_resources'; +import { SplunkDataInputStep } from '../../../../../common/types'; interface MacrosDataInputSubStepsProps { migrationStats: RuleMigrationTaskStats; @@ -31,14 +30,11 @@ interface MacrosDataInputSubStepsProps { } export const MacrosDataInput = React.memo( - ({ dataInputStep, migrationStats, migrationSource, setMigrationDataInputStep }) => { - const { missingResourcesIndexed, onMissingResourcesFetched } = useMissingResources({ - setMigrationDataInputStep, - }); + ({ dataInputStep, migrationStats, missingResourcesIndexed, onMissingResourcesFetched }) => { const missingMacros = useMemo(() => missingResourcesIndexed?.macros, [missingResourcesIndexed]); const dataInputStatus = useMemo( - () => getEuiStepStatus(SplunkDataInputStep.Macros, dataInputStep[migrationSource]), - [dataInputStep, migrationSource] + () => getEuiStepStatus(SplunkDataInputStep.Macros, dataInputStep), + [dataInputStep] ); return ( diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.test.tsx index 38ce0dbec3272..f5516e368aed1 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.test.tsx @@ -8,20 +8,19 @@ import React from 'react'; import { render } from '@testing-library/react'; import { RulesDataInput } from './rules_data_input'; -import { QradarDataInputStep, SplunkDataInputStep } from '../constants'; import { TestProviders } from '../../../../../../common/mock/test_providers'; import { MigrationSource } from '../../../../types'; +import { SplunkDataInputStep } from '../../../../../common/types'; describe('RulesDataInput', () => { const defaultProps = { migrationStats: undefined, onMigrationCreated: jest.fn(), - dataInputStep: { - [MigrationSource.SPLUNK]: SplunkDataInputStep.Rules, - [MigrationSource.QRADAR]: QradarDataInputStep.Rules, - }, + dataInputStep: SplunkDataInputStep.Upload, migrationSource: MigrationSource.SPLUNK, - setMigrationDataInputStep: jest.fn(), + setDataInputStep: jest.fn(), + onMissingResourcesFetched: jest.fn(), + missingResourcesIndexed: { lookups: [], macros: [] }, }; it('renders the step number', () => { @@ -61,10 +60,7 @@ describe('RulesDataInput', () => { diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx index 24f6880f09cf1..3bb0450c09934 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx @@ -18,12 +18,12 @@ import type { UseMigrationStepsProps, } from '../../types'; import * as i18n from './translations'; -import { QradarDataInputStep, SplunkDataInputStep } from '../constants'; +import { QradarDataInputStep } from '../constants'; import { useCopyExportQueryStep } from './sub_steps/copy_export_query'; import { useRulesFileUploadStep } from './sub_steps/rules_file_upload'; import { useCheckResourcesStep } from './sub_steps/check_resources'; import { MigrationSource } from '../../../../types'; -import { useMissingResources } from '../hooks/use_missing_resources'; +import { SplunkDataInputStep } from '../../../../../common/types'; export const RulesDataInput = React.memo( ({ @@ -31,14 +31,13 @@ export const RulesDataInput = React.memo( migrationStats, migrationSource, onMigrationCreated, - setMigrationDataInputStep, + onMissingResourcesFetched, }) => { - const { onMissingResourcesFetched } = useMissingResources({ setMigrationDataInputStep }); const dataInputNumber = useMemo( () => migrationSource === MigrationSource.QRADAR ? QradarDataInputStep.Rules - : SplunkDataInputStep.Rules, + : SplunkDataInputStep.Upload, [migrationSource] ); const dataInputStatus = useMemo( @@ -46,8 +45,8 @@ export const RulesDataInput = React.memo( getEuiStepStatus( migrationSource === MigrationSource.QRADAR ? QradarDataInputStep.Rules - : SplunkDataInputStep.Rules, - dataInputStep[migrationSource] + : SplunkDataInputStep.Upload, + dataInputStep ), [dataInputStep, migrationSource] ); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/types.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/types.ts index 687a6cbeb5c19..f15c01e0131d1 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/types.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/types.ts @@ -7,13 +7,7 @@ import type { SiemMigrationResourceBase } from '../../../../../common/siem_migrations/model/common.gen'; import type { MigrationSource, RuleMigrationStats } from '../../types'; -import type { - DataInputStep, - QradarDataInputStep, - QradarDataInputStepId, - SplunkDataInputStep, - SplunkDataInputStepId, -} from './steps/constants'; +import type { QradarDataInputStepId, SplunkDataInputStepId } from './steps/constants'; export type OnMigrationCreated = (migrationStats: RuleMigrationStats) => void; export type OnResourcesCreated = () => void; @@ -21,13 +15,19 @@ export type OnMissingResourcesFetched = (missingResources: SiemMigrationResource type DataInputStepId = SplunkDataInputStepId | QradarDataInputStepId; +interface MissingResourcesIndexed { + macros: string[]; + lookups: string[]; +} + export interface UseMigrationStepsProps { - dataInputStep: DataInputStep; + dataInputStep: number; migrationSource: MigrationSource; migrationStats?: RuleMigrationStats; onMigrationCreated: (createdMigrationStats: RuleMigrationStats) => void; - onMissingResourcesFetched?: OnMissingResourcesFetched; - setMigrationDataInputStep: (step: SplunkDataInputStep | QradarDataInputStep) => void; + onMissingResourcesFetched: OnMissingResourcesFetched; + setDataInputStep: (step: number) => void; + missingResourcesIndexed?: MissingResourcesIndexed; } export interface Step< @@ -41,7 +41,7 @@ export interface Step< export type Steps = Array; export interface RulesDataInputSubStepsProps { - dataInputStep: DataInputStep; + dataInputStep: number; migrationSource: MigrationSource; migrationStats?: RuleMigrationStats; onMigrationCreated: (createdMigrationStats: RuleMigrationStats) => void; From ae607d2a584789a71d8152a58b57ab4512b252b4 Mon Sep 17 00:00:00 2001 From: Angela Chuang Date: Tue, 9 Dec 2025 15:48:36 +0000 Subject: [PATCH 18/23] clean up --- .../public/siem_migrations/common/types.ts | 31 +++++++++- .../data_input_flyout/data_input_flyout.tsx | 59 +++++++------------ .../data_input_flyout/steps/constants.ts | 12 ++++ .../steps/lookups/lookups_data_input.test.tsx | 3 +- .../steps/lookups/lookups_data_input.tsx | 8 +-- .../steps/macros/macros_data_input.test.tsx | 8 +-- .../steps/macros/macros_data_input.tsx | 5 +- .../steps/upload_dashboards/index.test.tsx | 3 +- .../steps/upload_dashboards/index.tsx | 5 +- .../dashboards/configs/index.ts | 15 +++++ .../dashboards/configs/splunk.ts | 17 ++++++ .../siem_migrations/dashboards/types.ts | 3 + .../data_input_flyout/data_input_flyout.tsx | 36 +++++------ .../steps/hooks/use_missing_resources.ts | 8 ++- .../steps/lookups/lookups_data_input.test.tsx | 3 +- .../steps/lookups/lookups_data_input.tsx | 6 +- .../steps/macros/macros_data_input.test.tsx | 8 +-- .../steps/macros/macros_data_input.tsx | 13 ++-- .../steps/rules/rules_data_input.test.tsx | 3 +- .../steps/rules/rules_data_input.tsx | 17 +++--- .../rules/sub_steps/check_resources/index.tsx | 2 +- .../sub_steps/copy_export_query/index.tsx | 2 +- .../rules_file_upload/index.test.tsx | 2 +- .../sub_steps/rules_file_upload/index.tsx | 2 +- .../components/data_input_flyout/types.ts | 33 +---------- .../use_migration_source_options.test.tsx | 2 +- .../use_migration_source_options.tsx | 2 +- .../use_migration_source_step.tsx | 2 +- .../siem_migrations/rules/configs/index.ts | 10 +--- .../siem_migrations/rules/configs/qradar.ts | 2 +- .../siem_migrations/rules/configs/splunk.ts | 2 +- .../public/siem_migrations/rules/types.ts | 14 +++-- 32 files changed, 185 insertions(+), 153 deletions(-) create mode 100644 x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/constants.ts create mode 100644 x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/configs/index.ts create mode 100644 x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/configs/splunk.ts diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/types.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/types.ts index 801c3f40b8432..51622d9674529 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/types.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/types.ts @@ -6,7 +6,10 @@ */ import type { SiemMigrationTaskStatus } from '../../../common/siem_migrations/constants'; -import type { MigrationTaskStats } from '../../../common/siem_migrations/model/common.gen'; +import type { + MigrationTaskStats, + SiemMigrationResourceBase, +} from '../../../common/siem_migrations/model/common.gen'; export interface GetMigrationsStatsAllParams { /** Optional AbortSignal for cancelling request */ @@ -46,3 +49,29 @@ export enum SplunkDataInputStep { Lookups = 3, End = 10, } + +export interface Step = React.ComponentType> { + id: string; + Component: C; +} + +interface MissingResourcesIndexed { + macros: string[]; + lookups: string[]; +} + +export type OnMissingResourcesFetched = (missingResources: SiemMigrationResourceBase[]) => void; + +export enum MigrationSource { + SPLUNK = 'splunk', + QRADAR = 'qradar', +} +export interface UseMigrationStepsProps { + dataInputStep: number; + migrationSource: MigrationSource; + migrationStats?: T; + onMigrationCreated: (createdMigrationStats: T) => void; + onMissingResourcesFetched: OnMissingResourcesFetched; + setDataInputStep: (step: number) => void; + missingResourcesIndexed?: MissingResourcesIndexed; +} diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/data_input_flyout.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/data_input_flyout.tsx index 6901680587695..e721bfa55e060 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/data_input_flyout.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/data_input_flyout.tsx @@ -25,16 +25,13 @@ import { } from '../../../../../common/siem_migrations/constants'; import * as i18n from './translations'; import { useMigrationDataInputContext } from '../../../common/components/migration_data_input_flyout_context'; -import { DashboardsUploadStep } from './steps/upload_dashboards'; -import { MacrosDataInput } from './steps/macros/macros_data_input'; -import { LookupsDataInput } from './steps/lookups/lookups_data_input'; import { useStartDashboardsMigrationModal } from '../../hooks/use_start_dashboard_migration_modal'; import type { DashboardMigrationStats } from '../../types'; import { useStartMigration } from '../../logic/use_start_migration'; -import type { MigrationSettingsBase } from '../../../common/types'; -import { SplunkDataInputStep } from '../../../common/types'; -import { MigrationSource } from '../../../rules/types'; +import type { MigrationSettingsBase, Step, UseMigrationStepsProps } from '../../../common/types'; +import { MigrationSource, SplunkDataInputStep } from '../../../common/types'; import { useMissingResources } from '../../../rules/components/data_input_flyout/steps/hooks/use_missing_resources'; +import { STEP_COMPONENTS } from '../../configs'; interface DashboardMigrationDataInputFlyoutProps { onClose: () => void; @@ -120,39 +117,23 @@ export const DashboardMigrationDataInputFlyout = React.memo( - - - - - - - - - + <> + {STEP_COMPONENTS[MigrationSource.SPLUNK].map( + (step: Step>) => ( + + + + ) + )} + diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/constants.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/constants.ts new file mode 100644 index 0000000000000..baa5f36524229 --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/constants.ts @@ -0,0 +1,12 @@ +/* + * 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. + */ + +export enum SplunkDashboardDataInputStepId { + Rules = 'splunk_dashboard_rules', + Macros = 'splunk_dashboard_macros', + Lookups = 'splunk_dashboard_lookups', +} diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/lookups/lookups_data_input.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/lookups/lookups_data_input.test.tsx index 40588df6fd995..9f62dbd8026a4 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/lookups/lookups_data_input.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/lookups/lookups_data_input.test.tsx @@ -12,8 +12,7 @@ import * as i18n from './translations'; import { getDashboardMigrationStatsMock } from '../../../../__mocks__'; import { SiemMigrationTaskStatus } from '../../../../../../../common/siem_migrations/constants'; import { TestProviders } from '../../../../../../common/mock'; -import { MigrationSource } from '../../../../../rules/types'; -import { SplunkDataInputStep } from '../../../../../common/types'; +import { MigrationSource, SplunkDataInputStep } from '../../../../../common/types'; const mockAddError = jest.fn(); const mockAddSuccess = jest.fn(); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/lookups/lookups_data_input.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/lookups/lookups_data_input.tsx index 028f71438eaa5..c5405ed4f49e6 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/lookups/lookups_data_input.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/lookups/lookups_data_input.tsx @@ -22,20 +22,20 @@ import type { import { SubSteps } from '../../../../../common/components/migration_steps'; import { useKibana } from '../../../../../../common/lib/kibana/kibana_react'; import { getEuiStepStatus } from '../../../../../common/utils/get_eui_step_status'; -import type { DashboardMigrationTaskStats } from '../../../../../../../common/siem_migrations/model/dashboard_migration.gen'; import type { OnResourcesCreated } from '../../types'; import * as i18n from './translations'; import { useMissingLookupsListStep } from './sub_steps/missing_lookups_list'; import { useLookupsFileUploadStep } from './sub_steps/lookups_file_upload'; -import type { UseMigrationStepsProps } from '../../../../../rules/components/data_input_flyout/types'; +import type { UseMigrationStepsProps } from '../../../../../common/types'; import { SplunkDataInputStep } from '../../../../../common/types'; +import type { DashboardMigrationStats } from '../../../../types'; interface LookupsDataInputSubStepsProps { - migrationStats: DashboardMigrationTaskStats; + migrationStats: DashboardMigrationStats; missingLookups: string[]; onAllLookupsCreated: OnResourcesCreated; } -export const LookupsDataInput = React.memo( +export const LookupsDataInput = React.memo>( ({ dataInputStep, migrationStats, setDataInputStep, missingResourcesIndexed }) => { const missingLookups = useMemo( () => missingResourcesIndexed?.lookups, diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/macros/macros_data_input.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/macros/macros_data_input.test.tsx index 33c50937607a3..8047658baa174 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/macros/macros_data_input.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/macros/macros_data_input.test.tsx @@ -13,9 +13,9 @@ import { SiemMigrationTaskStatus } from '../../../../../../../common/siem_migrat import { TestProviders } from '../../../../../../common/mock'; import { useAppToasts } from '../../../../../../common/hooks/use_app_toasts'; import { useAppToastsMock } from '../../../../../../common/hooks/use_app_toasts.mock'; -import type { UseMigrationStepsProps } from '../../../../../rules/components/data_input_flyout/types'; -import { MigrationSource } from '../../../../../rules/types'; -import { SplunkDataInputStep } from '../../../../../common/types'; +import type { UseMigrationStepsProps } from '../../../../../common/types'; +import { MigrationSource, SplunkDataInputStep } from '../../../../../common/types'; +import type { DashboardMigrationStats } from '../../../../types'; const mockAddError = jest.fn(); const mockAddSuccess = jest.fn(); @@ -46,7 +46,7 @@ jest.mock('../../../../../../common/hooks/use_app_toasts'); describe('MacrosDataInput', () => { let appToastsMock: jest.Mocked>; - const defaultProps: UseMigrationStepsProps = { + const defaultProps: UseMigrationStepsProps = { onMissingResourcesFetched: jest.fn(), dataInputStep: SplunkDataInputStep.Macros, migrationStats: getDashboardMigrationStatsMock({ status: SiemMigrationTaskStatus.READY }), diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/macros/macros_data_input.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/macros/macros_data_input.tsx index a72ae4c37d006..c84aa30f2e3d8 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/macros/macros_data_input.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/macros/macros_data_input.tsx @@ -17,8 +17,9 @@ import * as i18n from './translations'; import { useCopyExportQueryStep } from './sub_steps/copy_export_query'; import { useMacrosFileUploadStep } from './sub_steps/macros_file_upload'; import { useCheckResourcesStep } from '../common/check_resources'; -import type { UseMigrationStepsProps } from '../../../../../rules/components/data_input_flyout/types'; +import type { UseMigrationStepsProps } from '../../../../../common/types'; import { SplunkDataInputStep } from '../../../../../common/types'; +import type { DashboardMigrationStats } from '../../../../types'; interface MacrosDataInputSubStepsProps { migrationStats: DashboardMigrationTaskStats; @@ -26,7 +27,7 @@ interface MacrosDataInputSubStepsProps { onMissingResourcesFetched: OnMissingResourcesFetched; } -export const MacrosDataInput = React.memo( +export const MacrosDataInput = React.memo>( ({ dataInputStep, migrationStats, missingResourcesIndexed, onMissingResourcesFetched }) => { const missingMacros = useMemo(() => missingResourcesIndexed?.macros, [missingResourcesIndexed]); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/upload_dashboards/index.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/upload_dashboards/index.test.tsx index 794e670c9c038..fe3d8fa4f6821 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/upload_dashboards/index.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/upload_dashboards/index.test.tsx @@ -9,8 +9,7 @@ import React from 'react'; import { render } from '@testing-library/react'; import { DashboardsUploadStep } from '.'; import { TestProviders } from '../../../../../../common/mock/test_providers'; -import { MigrationSource } from '../../../../../rules/types'; -import { SplunkDataInputStep } from '../../../../../common/types'; +import { MigrationSource, SplunkDataInputStep } from '../../../../../common/types'; describe('DashboardsUploadStep', () => { const defaultProps = { diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/upload_dashboards/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/upload_dashboards/index.tsx index 9f45579b50627..3b4b58b6ad982 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/upload_dashboards/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/upload_dashboards/index.tsx @@ -10,15 +10,16 @@ import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiStepNumber, EuiTitle } from '@e import { getEuiStepStatus } from '../../../../../common/utils/get_eui_step_status'; import * as i18n from '../translations'; import { DashboardsUploadSubSteps } from './sub_steps'; -import type { UseMigrationStepsProps } from '../../../../../rules/components/data_input_flyout/types'; +import type { UseMigrationStepsProps } from '../../../../../common/types'; import { SplunkDataInputStep } from '../../../../../common/types'; +import type { DashboardMigrationStats } from '../../../../types'; export const DashboardsUploadStep = ({ dataInputStep = 1, // Default value if not provided migrationStats, onMigrationCreated, onMissingResourcesFetched, -}: UseMigrationStepsProps) => { +}: UseMigrationStepsProps) => { const dataInputStatus = useMemo( () => getEuiStepStatus(SplunkDataInputStep.Upload, dataInputStep), [dataInputStep] diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/configs/index.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/configs/index.ts new file mode 100644 index 0000000000000..173babd93d5a9 --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/configs/index.ts @@ -0,0 +1,15 @@ +/* + * 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 { MigrationSource } from '../../common/types'; +import type { Steps } from '../types'; +import { SPLUNK_MIGRATION_STEPS } from './splunk'; + +export const STEP_COMPONENTS: { + [MigrationSource.SPLUNK]: Steps; +} = { + [MigrationSource.SPLUNK]: SPLUNK_MIGRATION_STEPS, +}; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/configs/splunk.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/configs/splunk.ts new file mode 100644 index 0000000000000..ce130dfa95743 --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/configs/splunk.ts @@ -0,0 +1,17 @@ +/* + * 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 { SplunkDashboardDataInputStepId } from '../components/data_input_flyout/steps/constants'; +import { LookupsDataInput } from '../components/data_input_flyout/steps/lookups/lookups_data_input'; +import { MacrosDataInput } from '../components/data_input_flyout/steps/macros/macros_data_input'; +import { DashboardsUploadStep } from '../components/data_input_flyout/steps/upload_dashboards'; +import type { Steps } from '../types'; + +export const SPLUNK_MIGRATION_STEPS: Steps = [ + { id: SplunkDashboardDataInputStepId.Rules, Component: DashboardsUploadStep }, + { id: SplunkDashboardDataInputStepId.Macros, Component: MacrosDataInput }, + { id: SplunkDashboardDataInputStepId.Lookups, Component: LookupsDataInput }, +] as const; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/types.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/types.ts index b3fe10eddbb24..b2d33229e0e98 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/types.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/types.ts @@ -7,7 +7,10 @@ import type { DashboardMigrationTaskStats } from '../../../common/siem_migrations/model/dashboard_migration.gen'; import type { SiemMigrationTaskStatus } from '../../../common/siem_migrations/constants'; +import type { Step, UseMigrationStepsProps } from '../common/types'; export interface DashboardMigrationStats extends DashboardMigrationTaskStats { status: SiemMigrationTaskStatus; // use the native enum instead of the zod enum from the model } + +export type Steps = Array>>; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx index ee40faf737e86..caf08a355bad7 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx @@ -24,14 +24,14 @@ import { SiemMigrationTaskStatus, } from '../../../../../common/siem_migrations/constants'; import { useStartRulesMigrationModal } from '../../hooks/use_start_rules_migration_modal'; -import { MigrationSource, type RuleMigrationSettings, type RuleMigrationStats } from '../../types'; +import { type RuleMigrationSettings, type RuleMigrationStats } from '../../types'; import { useStartMigration } from '../../logic/use_start_migration'; import { useMigrationSourceStep } from '../migration_source_step/use_migration_source_step'; import { MigrationSourceDropdown } from '../migration_source_step/migration_source_dropdown'; -import { CenteredLoadingSpinner } from '../../../../common/components/centered_loading_spinner'; -import { STEP_COMPONENTS } from '../../configs'; import { useMissingResources } from './steps/hooks/use_missing_resources'; -import { SplunkDataInputStep } from '../../../common/types'; +import type { Step, UseMigrationStepsProps } from '../../../common/types'; +import { MigrationSource, SplunkDataInputStep } from '../../../common/types'; +import { STEP_COMPONENTS } from '../../configs'; export interface MigrationDataInputFlyoutProps { onClose: () => void; @@ -136,19 +136,21 @@ export const MigrationDataInputFlyout = React.memo <> - {STEP_COMPONENTS[migrationSource]?.map((step) => ( - - - - )) ?? } + {STEP_COMPONENTS[migrationSource].map( + (step: Step>) => ( + + + + ) + )} diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/hooks/use_missing_resources.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/hooks/use_missing_resources.ts index 97120ec700fd0..7082a5b395de9 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/hooks/use_missing_resources.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/hooks/use_missing_resources.ts @@ -7,8 +7,10 @@ import { useCallback, useState } from 'react'; import type { SiemMigrationResourceBase } from '../../../../../../../common/siem_migrations/model/common.gen'; -import type { UseMigrationStepsProps } from '../../types'; +import type { UseMigrationStepsProps } from '../../../../../common/types'; import { SplunkDataInputStep } from '../../../../../common/types'; +import type { RuleMigrationStats } from '../../../../types'; +import type { DashboardMigrationStats } from '../../../../../dashboards/types'; interface MissingResourcesIndexed { macros: string[]; @@ -18,7 +20,9 @@ interface MissingResourcesIndexed { export const useMissingResources = ({ setDataInputStep, }: { - setDataInputStep: UseMigrationStepsProps['setDataInputStep']; + setDataInputStep: UseMigrationStepsProps< + RuleMigrationStats | DashboardMigrationStats + >['setDataInputStep']; }) => { const [missingResourcesIndexed, setMissingResourcesIndexed] = useState< MissingResourcesIndexed | undefined diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.test.tsx index 1148dbc2f5b6f..774d3a35c182e 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.test.tsx @@ -11,8 +11,7 @@ import { LookupsDataInput } from './lookups_data_input'; import { getRuleMigrationStatsMock } from '../../../../__mocks__'; import { SiemMigrationTaskStatus } from '../../../../../../../common/siem_migrations/constants'; import { TestProviders } from '../../../../../../common/mock'; -import { MigrationSource } from '../../../../types'; -import { SplunkDataInputStep } from '../../../../../common/types'; +import { MigrationSource, SplunkDataInputStep } from '../../../../../common/types'; const mockAddError = jest.fn(); const mockAddSuccess = jest.fn(); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.tsx index 87ec830bdbbb8..ef30aef1a1749 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.tsx @@ -23,11 +23,13 @@ import { SubSteps } from '../../../../../common/components'; import { getEuiStepStatus } from '../../../../../common/utils/get_eui_step_status'; import { useKibana } from '../../../../../../common/lib/kibana/kibana_react'; import type { RuleMigrationTaskStats } from '../../../../../../../common/siem_migrations/model/rule_migration.gen'; -import type { OnResourcesCreated, UseMigrationStepsProps } from '../../types'; +import type { OnResourcesCreated } from '../../types'; import * as i18n from './translations'; import { useMissingLookupsListStep } from './sub_steps/missing_lookups_list'; import { useLookupsFileUploadStep } from './sub_steps/lookups_file_upload'; +import type { UseMigrationStepsProps } from '../../../../../common/types'; import { SplunkDataInputStep } from '../../../../../common/types'; +import type { RuleMigrationStats } from '../../../../types'; interface LookupsDataInputSubStepsProps { migrationStats: RuleMigrationTaskStats; @@ -35,7 +37,7 @@ interface LookupsDataInputSubStepsProps { onAllLookupsCreated: OnResourcesCreated; } -export const LookupsDataInput = React.memo( +export const LookupsDataInput = React.memo>( ({ dataInputStep, migrationStats, missingResourcesIndexed, setDataInputStep }) => { const missingLookups = useMemo( () => missingResourcesIndexed?.lookups, diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.test.tsx index d45d08debd32b..b2cac67310a70 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.test.tsx @@ -13,10 +13,10 @@ import { SiemMigrationTaskStatus } from '../../../../../../../common/siem_migrat import { TestProviders } from '../../../../../../common/mock'; import { useAppToasts } from '../../../../../../common/hooks/use_app_toasts'; import { useAppToastsMock } from '../../../../../../common/hooks/use_app_toasts.mock'; -import { MigrationSource } from '../../../../types'; import { useMissingResources } from '../hooks/use_missing_resources'; -import type { UseMigrationStepsProps } from '../../types'; -import { SplunkDataInputStep } from '../../../../../common/types'; +import type { UseMigrationStepsProps } from '../../../../../common/types'; +import { MigrationSource, SplunkDataInputStep } from '../../../../../common/types'; +import type { RuleMigrationStats } from '../../../../types'; const mockAddError = jest.fn(); const mockAddSuccess = jest.fn(); @@ -57,7 +57,7 @@ jest.mock('../hooks/use_missing_resources', () => ({ describe('MacrosDataInput', () => { let appToastsMock: jest.Mocked>; - const defaultProps: UseMigrationStepsProps = { + const defaultProps: UseMigrationStepsProps = { onMissingResourcesFetched: jest.fn(), dataInputStep: SplunkDataInputStep.Macros, migrationStats: getRuleMigrationStatsMock({ status: SiemMigrationTaskStatus.READY }), diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.tsx index 64b6450da8ae8..6ff0220af8dba 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.tsx @@ -12,16 +12,17 @@ import { SubSteps } from '../../../../../common/components'; import { getEuiStepStatus } from '../../../../../common/utils/get_eui_step_status'; import { useKibana } from '../../../../../../common/lib/kibana/kibana_react'; import type { RuleMigrationTaskStats } from '../../../../../../../common/siem_migrations/model/rule_migration.gen'; -import type { - OnResourcesCreated, - OnMissingResourcesFetched, - UseMigrationStepsProps, -} from '../../types'; +import type { OnResourcesCreated } from '../../types'; import * as i18n from './translations'; import { useCopyExportQueryStep } from './sub_steps/copy_export_query'; import { useMacrosFileUploadStep } from './sub_steps/macros_file_upload'; import { useCheckResourcesStep } from './sub_steps/check_resources'; +import type { + OnMissingResourcesFetched, + UseMigrationStepsProps, +} from '../../../../../common/types'; import { SplunkDataInputStep } from '../../../../../common/types'; +import type { RuleMigrationStats } from '../../../../types'; interface MacrosDataInputSubStepsProps { migrationStats: RuleMigrationTaskStats; @@ -29,7 +30,7 @@ interface MacrosDataInputSubStepsProps { onMissingResourcesFetched: OnMissingResourcesFetched; } -export const MacrosDataInput = React.memo( +export const MacrosDataInput = React.memo>( ({ dataInputStep, migrationStats, missingResourcesIndexed, onMissingResourcesFetched }) => { const missingMacros = useMemo(() => missingResourcesIndexed?.macros, [missingResourcesIndexed]); const dataInputStatus = useMemo( diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.test.tsx index f5516e368aed1..e05117f1c7954 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.test.tsx @@ -9,8 +9,7 @@ import React from 'react'; import { render } from '@testing-library/react'; import { RulesDataInput } from './rules_data_input'; import { TestProviders } from '../../../../../../common/mock/test_providers'; -import { MigrationSource } from '../../../../types'; -import { SplunkDataInputStep } from '../../../../../common/types'; +import { MigrationSource, SplunkDataInputStep } from '../../../../../common/types'; describe('RulesDataInput', () => { const defaultProps = { diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx index 3bb0450c09934..5a178dd09b665 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx @@ -11,21 +11,20 @@ import React, { useCallback, useMemo, useState } from 'react'; import { SubSteps, useMigrationNameStep } from '../../../../../common/components'; import { getEuiStepStatus } from '../../../../../common/utils/get_eui_step_status'; import { useKibana } from '../../../../../../common/lib/kibana'; -import type { - OnMigrationCreated, - OnMissingResourcesFetched, - RulesDataInputSubStepsProps, - UseMigrationStepsProps, -} from '../../types'; +import type { OnMigrationCreated, RulesDataInputSubStepsProps } from '../../types'; import * as i18n from './translations'; import { QradarDataInputStep } from '../constants'; import { useCopyExportQueryStep } from './sub_steps/copy_export_query'; import { useRulesFileUploadStep } from './sub_steps/rules_file_upload'; import { useCheckResourcesStep } from './sub_steps/check_resources'; -import { MigrationSource } from '../../../../types'; -import { SplunkDataInputStep } from '../../../../../common/types'; +import type { + OnMissingResourcesFetched, + UseMigrationStepsProps, +} from '../../../../../common/types'; +import { MigrationSource, SplunkDataInputStep } from '../../../../../common/types'; +import type { RuleMigrationStats } from '../../../../types'; -export const RulesDataInput = React.memo( +export const RulesDataInput = React.memo>( ({ dataInputStep, migrationStats, diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/check_resources/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/check_resources/index.tsx index b40c188fc7487..e977841d6ebd5 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/check_resources/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/check_resources/index.tsx @@ -9,8 +9,8 @@ import React, { useEffect, useMemo } from 'react'; import { EuiText, type EuiStepProps, type EuiStepStatus } from '@elastic/eui'; import { useGetMissingResources } from '../../../../../../../common/hooks/use_get_missing_resources'; import type { RuleMigrationTaskStats } from '../../../../../../../../../common/siem_migrations/model/rule_migration.gen'; -import type { OnMissingResourcesFetched } from '../../../../types'; import * as i18n from './translations'; +import type { OnMissingResourcesFetched } from '../../../../../../../common/types'; export interface CheckResourcesStepProps { status: EuiStepStatus; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/index.tsx index 753da7b867643..1458703bc21b7 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/index.tsx @@ -10,7 +10,7 @@ import type { EuiStepProps, EuiStepStatus } from '@elastic/eui'; import { CopyExportedSplunkQuery } from './copy_exported_splunk_query'; import * as i18n from './translations'; import { CopyExportedQradarQuery } from './copy_exported_qradar_query'; -import { MigrationSource } from '../../../../../../types'; +import { MigrationSource } from '../../../../../../../common/types'; export interface CopyExportQueryStepProps { status: EuiStepStatus; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/index.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/index.test.tsx index 9b48a64cde354..030ee563d7693 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/index.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/index.test.tsx @@ -9,7 +9,7 @@ import { renderHook } from '@testing-library/react'; import { useRulesFileUploadStep } from '.'; import { TestProviders } from '../../../../../../../../common/mock'; import { useCreateMigration } from '../../../../../../service/hooks/use_create_migration'; -import { MigrationSource } from '../../../../../../types'; +import { MigrationSource } from '../../../../../../../common/types'; jest.mock('../../../../../../service/hooks/use_create_migration', () => ({ useCreateMigration: jest.fn(), diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/index.tsx index 98e190bb587d5..24847fdfe5c8b 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/index.tsx @@ -8,7 +8,6 @@ import React, { useCallback, useMemo, useState } from 'react'; import type { EuiStepProps, EuiStepStatus } from '@elastic/eui'; import type { RuleMigrationStats } from '../../../../../../types'; -import { MigrationSource } from '../../../../../../types'; import type { OnMigrationCreated } from '../../../../types'; import { RulesFileUpload } from './rules_file_upload'; import { @@ -17,6 +16,7 @@ import { } from '../../../../../../service/hooks/use_create_migration'; import * as i18n from './translations'; import { RulesXMLFileUpload } from './rules_xml_file_upload'; +import { MigrationSource } from '../../../../../../../common/types'; export interface RulesFileUploadStepProps { status: EuiStepStatus; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/types.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/types.ts index f15c01e0131d1..c8af6482589a9 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/types.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/types.ts @@ -5,40 +5,11 @@ * 2.0. */ -import type { SiemMigrationResourceBase } from '../../../../../common/siem_migrations/model/common.gen'; -import type { MigrationSource, RuleMigrationStats } from '../../types'; -import type { QradarDataInputStepId, SplunkDataInputStepId } from './steps/constants'; +import type { MigrationSource, OnMissingResourcesFetched } from '../../../common/types'; +import type { RuleMigrationStats } from '../../types'; export type OnMigrationCreated = (migrationStats: RuleMigrationStats) => void; export type OnResourcesCreated = () => void; -export type OnMissingResourcesFetched = (missingResources: SiemMigrationResourceBase[]) => void; - -type DataInputStepId = SplunkDataInputStepId | QradarDataInputStepId; - -interface MissingResourcesIndexed { - macros: string[]; - lookups: string[]; -} - -export interface UseMigrationStepsProps { - dataInputStep: number; - migrationSource: MigrationSource; - migrationStats?: RuleMigrationStats; - onMigrationCreated: (createdMigrationStats: RuleMigrationStats) => void; - onMissingResourcesFetched: OnMissingResourcesFetched; - setDataInputStep: (step: number) => void; - missingResourcesIndexed?: MissingResourcesIndexed; -} - -export interface Step< - Props = UseMigrationStepsProps, - C extends React.ComponentType = React.ComponentType -> { - id: DataInputStepId; - Component: C; -} - -export type Steps = Array; export interface RulesDataInputSubStepsProps { dataInputStep: number; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/migration_source_step/use_migration_source_options.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/migration_source_step/use_migration_source_options.test.tsx index 5676cc77a1bd3..adfd02942de62 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/migration_source_step/use_migration_source_options.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/migration_source_step/use_migration_source_options.test.tsx @@ -8,7 +8,7 @@ import { renderHook } from '@testing-library/react'; import { useMigrationSourceOptions } from './use_migration_source_options'; import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; -import { MigrationSource } from '../../types'; +import { MigrationSource } from '../../../common/types'; jest.mock('../../../../common/hooks/use_experimental_features', () => ({ useIsExperimentalFeatureEnabled: jest.fn(), diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/migration_source_step/use_migration_source_options.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/migration_source_step/use_migration_source_options.tsx index a867d183192de..a2b4dfb2e8295 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/migration_source_step/use_migration_source_options.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/migration_source_step/use_migration_source_options.tsx @@ -9,7 +9,7 @@ import type { EuiSuperSelectOption } from '@elastic/eui'; import { EuiIcon } from '@elastic/eui'; import * as i18n from './translations'; import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; -import { MigrationSource } from '../../types'; +import { MigrationSource } from '../../../common/types'; export const useMigrationSourceOptions = () => { const isQradarEnabled = useIsExperimentalFeatureEnabled('qradarRulesMigration'); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/migration_source_step/use_migration_source_step.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/migration_source_step/use_migration_source_step.tsx index a4fb756c62a24..00306b0baf5e6 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/migration_source_step/use_migration_source_step.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/migration_source_step/use_migration_source_step.tsx @@ -8,7 +8,7 @@ import { useState } from 'react'; import type { EuiSuperSelectOption } from '@elastic/eui'; import { useMigrationSourceOptions } from './use_migration_source_options'; -import type { MigrationSource } from '../../types'; +import type { MigrationSource } from '../../../common/types'; export interface MigrationSourceDropdownProps { migrationSource: MigrationSource; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/index.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/index.ts index c427f449df5f2..4e53ab8694865 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/index.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/index.ts @@ -5,16 +5,12 @@ * 2.0. */ -import { MigrationSource } from '../types'; - -import type { Steps } from '../components/data_input_flyout/types'; import { SPLUNK_MIGRATION_STEPS } from './splunk'; import { QRADAR_MIGRATION_STEPS } from './qradar'; +import type { Steps } from '../types'; +import { MigrationSource } from '../../common/types'; -export const STEP_COMPONENTS: { - [MigrationSource.SPLUNK]: Steps; - [MigrationSource.QRADAR]: Steps; -} = { +export const STEP_COMPONENTS: Record = { [MigrationSource.SPLUNK]: SPLUNK_MIGRATION_STEPS, [MigrationSource.QRADAR]: QRADAR_MIGRATION_STEPS, }; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/qradar.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/qradar.ts index af43703c8ce80..93ce800e0921d 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/qradar.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/qradar.ts @@ -7,7 +7,7 @@ import { QradarDataInputStepId } from '../components/data_input_flyout/steps/constants'; import { RulesDataInput } from '../components/data_input_flyout/steps/rules/rules_data_input'; -import type { Steps } from '../components/data_input_flyout/types'; +import type { Steps } from '../types'; export const QRADAR_MIGRATION_STEPS: Steps = [ { id: QradarDataInputStepId.Rules, Component: RulesDataInput }, diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/splunk.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/splunk.ts index b27b6d3cad622..18f7e4acce966 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/splunk.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/splunk.ts @@ -9,7 +9,7 @@ import { SplunkDataInputStepId } from '../components/data_input_flyout/steps/con import { LookupsDataInput } from '../components/data_input_flyout/steps/lookups/lookups_data_input'; import { MacrosDataInput } from '../components/data_input_flyout/steps/macros/macros_data_input'; import { RulesDataInput } from '../components/data_input_flyout/steps/rules/rules_data_input'; -import type { Steps } from '../components/data_input_flyout/types'; +import type { Steps } from '../types'; export const SPLUNK_MIGRATION_STEPS: Steps = [ { id: SplunkDataInputStepId.Rules, Component: RulesDataInput }, diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/types.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/types.ts index fe684dc614f13..4d13c1ef1aae3 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/types.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/types.ts @@ -7,7 +7,12 @@ import type { SiemMigrationTaskStatus } from '../../../common/siem_migrations/constants'; import type { RuleMigrationTaskStats } from '../../../common/siem_migrations/model/rule_migration.gen'; -import type { MigrationSettingsBase, StatusFilterBase } from '../common/types'; +import type { + MigrationSettingsBase, + StatusFilterBase, + Step, + UseMigrationStepsProps, +} from '../common/types'; export interface RuleMigrationStats extends RuleMigrationTaskStats { status: SiemMigrationTaskStatus; // use the native enum instead of the zod enum from the model @@ -18,11 +23,6 @@ export enum AuthorFilter { CUSTOM = 'custom', } -export enum MigrationSource { - SPLUNK = 'splunk', - QRADAR = 'qradar', -} - export enum RulesSpecificStatusFilter { INDEX_PATTERN_MISSING = 'index_pattern_missing', } @@ -37,3 +37,5 @@ export interface RulesFilterOptions { export interface RuleMigrationSettings extends MigrationSettingsBase { skipPrebuiltRulesMatching: boolean; } + +export type Steps = Array>>; From 639ef8ef6de8a1d47a6fffdf564284bab6879ffe Mon Sep 17 00:00:00 2001 From: Angela Chuang <6295984+angorayc@users.noreply.github.com> Date: Wed, 10 Dec 2025 09:07:29 +0000 Subject: [PATCH 19/23] Update x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx Co-authored-by: Jatin Kathuria --- .../rules/components/data_input_flyout/data_input_flyout.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx index caf08a355bad7..bfa0d12a0d587 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx @@ -65,7 +65,7 @@ export const MigrationDataInputFlyout = React.memo(SplunkDataInputStep.Upload); + const [dataInputStep, setDataInputStep] = useState(SplunkDataInputStep.Upload); const { missingResourcesIndexed, onMissingResourcesFetched } = useMissingResources({ setDataInputStep, From 36e1e5a17d1d13b601089b3cb4f7836f3fe69883 Mon Sep 17 00:00:00 2001 From: Angela Chuang Date: Wed, 10 Dec 2025 14:33:43 +0000 Subject: [PATCH 20/23] code review --- .../public/siem_migrations/common/types.ts | 23 +++--- .../data_input_flyout}/configs/index.ts | 4 +- .../data_input_flyout}/configs/splunk.ts | 10 +-- .../data_input_flyout/data_input_flyout.tsx | 32 ++++---- .../steps/common/check_resources/index.tsx | 2 +- .../steps/lookups/lookups_data_input.tsx | 4 +- .../steps/macros/macros_data_input.test.tsx | 5 +- .../steps/macros/macros_data_input.tsx | 7 +- .../steps/upload_dashboards/index.tsx | 5 +- .../upload_dashboards/sub_steps/index.tsx | 3 +- .../components/data_input_flyout/types.ts | 2 - .../siem_migrations/dashboards/types.ts | 3 - .../public/siem_migrations/rules/api/index.ts | 6 +- .../data_input_flyout}/configs/index.ts | 4 +- .../data_input_flyout}/configs/qradar.ts | 9 ++- .../data_input_flyout}/configs/splunk.ts | 15 ++-- .../data_input_flyout/data_input_flyout.tsx | 48 ++++++------ .../data_input_flyout/steps/constants.ts | 21 ------ .../steps/hooks/use_missing_resources.ts | 13 +--- .../steps/lookups/lookups_data_input.tsx | 5 +- .../steps/macros/macros_data_input.test.tsx | 5 +- .../steps/macros/macros_data_input.tsx | 8 +- .../sub_steps/check_resources/index.tsx | 2 +- .../steps/rules/rules_data_input.tsx | 24 ++++-- .../copy_export_query/translations.ts | 2 +- .../sub_steps/rules_file_upload/index.tsx | 1 - .../rules_file_upload.test.tsx | 3 +- .../rules_file_upload/rules_file_upload.tsx | 21 ++---- .../rules_xml_file_upload.tsx | 21 ++---- .../components/data_input_flyout/types.ts | 9 --- .../migration_source_dropdown.test.tsx | 2 +- .../migration_source_dropdown.tsx | 2 +- .../hooks/use_create_migration.test.ts | 2 +- .../service/hooks/use_create_migration.ts | 28 ++++--- .../service/rule_migrations_service.test.ts | 21 +++++- .../rules/service/rule_migrations_service.ts | 75 +++++++++++++------ .../public/siem_migrations/rules/types.ts | 9 +-- .../rules/api/rules/qradar/create.ts | 1 + 38 files changed, 235 insertions(+), 222 deletions(-) rename x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/{ => components/data_input_flyout}/configs/index.ts (79%) rename x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/{ => components/data_input_flyout}/configs/splunk.ts (56%) rename x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/{ => components/data_input_flyout}/configs/index.ts (82%) rename x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/{ => components/data_input_flyout}/configs/qradar.ts (63%) rename x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/{ => components/data_input_flyout}/configs/splunk.ts (55%) delete mode 100644 x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/constants.ts diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/types.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/types.ts index 51622d9674529..5cbb6893e7ab4 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/types.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/types.ts @@ -50,12 +50,7 @@ export enum SplunkDataInputStep { End = 10, } -export interface Step = React.ComponentType> { - id: string; - Component: C; -} - -interface MissingResourcesIndexed { +export interface MissingResourcesIndexed { macros: string[]; lookups: string[]; } @@ -66,12 +61,22 @@ export enum MigrationSource { SPLUNK = 'splunk', QRADAR = 'qradar', } -export interface UseMigrationStepsProps { +export interface MigrationStepProps { dataInputStep: number; migrationSource: MigrationSource; - migrationStats?: T; - onMigrationCreated: (createdMigrationStats: T) => void; + migrationStats?: MigrationStats; + onMigrationCreated: (createdMigrationStats: MigrationStats) => void; onMissingResourcesFetched: OnMissingResourcesFetched; setDataInputStep: (step: number) => void; missingResourcesIndexed?: MissingResourcesIndexed; } + +export interface Step< + Props = MigrationStepProps, + C extends React.ComponentType = React.ComponentType +> { + id: string; + Component: C; +} + +export type Steps = Array>; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/configs/index.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/configs/index.ts similarity index 79% rename from x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/configs/index.ts rename to x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/configs/index.ts index 173babd93d5a9..ac42cdc9097f4 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/configs/index.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/configs/index.ts @@ -4,8 +4,8 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { MigrationSource } from '../../common/types'; -import type { Steps } from '../types'; +import type { Steps } from '../../../../common/types'; +import { MigrationSource } from '../../../../common/types'; import { SPLUNK_MIGRATION_STEPS } from './splunk'; export const STEP_COMPONENTS: { diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/configs/splunk.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/configs/splunk.ts similarity index 56% rename from x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/configs/splunk.ts rename to x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/configs/splunk.ts index ce130dfa95743..27675adaf92a4 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/configs/splunk.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/configs/splunk.ts @@ -4,11 +4,11 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { SplunkDashboardDataInputStepId } from '../components/data_input_flyout/steps/constants'; -import { LookupsDataInput } from '../components/data_input_flyout/steps/lookups/lookups_data_input'; -import { MacrosDataInput } from '../components/data_input_flyout/steps/macros/macros_data_input'; -import { DashboardsUploadStep } from '../components/data_input_flyout/steps/upload_dashboards'; -import type { Steps } from '../types'; +import type { Steps } from '../../../../common/types'; +import { SplunkDashboardDataInputStepId } from '../steps/constants'; +import { LookupsDataInput } from '../steps/lookups/lookups_data_input'; +import { MacrosDataInput } from '../steps/macros/macros_data_input'; +import { DashboardsUploadStep } from '../steps/upload_dashboards'; export const SPLUNK_MIGRATION_STEPS: Steps = [ { id: SplunkDashboardDataInputStepId.Rules, Component: DashboardsUploadStep }, diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/data_input_flyout.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/data_input_flyout.tsx index e721bfa55e060..26e00441a45b2 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/data_input_flyout.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/data_input_flyout.tsx @@ -28,10 +28,10 @@ import { useMigrationDataInputContext } from '../../../common/components/migrati import { useStartDashboardsMigrationModal } from '../../hooks/use_start_dashboard_migration_modal'; import type { DashboardMigrationStats } from '../../types'; import { useStartMigration } from '../../logic/use_start_migration'; -import type { MigrationSettingsBase, Step, UseMigrationStepsProps } from '../../../common/types'; +import type { MigrationSettingsBase } from '../../../common/types'; import { MigrationSource, SplunkDataInputStep } from '../../../common/types'; import { useMissingResources } from '../../../rules/components/data_input_flyout/steps/hooks/use_missing_resources'; -import { STEP_COMPONENTS } from '../../configs'; +import { STEP_COMPONENTS } from './configs'; interface DashboardMigrationDataInputFlyoutProps { onClose: () => void; @@ -118,21 +118,19 @@ export const DashboardMigrationDataInputFlyout = React.memo( <> - {STEP_COMPONENTS[MigrationSource.SPLUNK].map( - (step: Step>) => ( - - - - ) - )} + {STEP_COMPONENTS[MigrationSource.SPLUNK].map((step) => ( + + + + ))} diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/common/check_resources/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/common/check_resources/index.tsx index b99250f4e146e..750a3a930e315 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/common/check_resources/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/common/check_resources/index.tsx @@ -9,8 +9,8 @@ import React, { useEffect, useMemo } from 'react'; import { EuiText, type EuiStepProps, type EuiStepStatus } from '@elastic/eui'; import { useGetMissingResources } from '../../../../../../common/hooks/use_get_missing_resources'; import type { DashboardMigrationTaskStats } from '../../../../../../../../common/siem_migrations/model/dashboard_migration.gen'; -import type { OnMissingResourcesFetched } from '../../../types'; import * as i18n from './translations'; +import type { OnMissingResourcesFetched } from '../../../../../../common/types'; export interface CheckResourcesStepProps { status: EuiStepStatus; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/lookups/lookups_data_input.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/lookups/lookups_data_input.tsx index c5405ed4f49e6..79c013f7c240e 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/lookups/lookups_data_input.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/lookups/lookups_data_input.tsx @@ -26,7 +26,7 @@ import type { OnResourcesCreated } from '../../types'; import * as i18n from './translations'; import { useMissingLookupsListStep } from './sub_steps/missing_lookups_list'; import { useLookupsFileUploadStep } from './sub_steps/lookups_file_upload'; -import type { UseMigrationStepsProps } from '../../../../../common/types'; +import type { MigrationStepProps } from '../../../../../common/types'; import { SplunkDataInputStep } from '../../../../../common/types'; import type { DashboardMigrationStats } from '../../../../types'; interface LookupsDataInputSubStepsProps { @@ -35,7 +35,7 @@ interface LookupsDataInputSubStepsProps { onAllLookupsCreated: OnResourcesCreated; } -export const LookupsDataInput = React.memo>( +export const LookupsDataInput = React.memo( ({ dataInputStep, migrationStats, setDataInputStep, missingResourcesIndexed }) => { const missingLookups = useMemo( () => missingResourcesIndexed?.lookups, diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/macros/macros_data_input.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/macros/macros_data_input.test.tsx index 8047658baa174..a39dcfc1454ed 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/macros/macros_data_input.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/macros/macros_data_input.test.tsx @@ -13,9 +13,8 @@ import { SiemMigrationTaskStatus } from '../../../../../../../common/siem_migrat import { TestProviders } from '../../../../../../common/mock'; import { useAppToasts } from '../../../../../../common/hooks/use_app_toasts'; import { useAppToastsMock } from '../../../../../../common/hooks/use_app_toasts.mock'; -import type { UseMigrationStepsProps } from '../../../../../common/types'; +import type { MigrationStepProps } from '../../../../../common/types'; import { MigrationSource, SplunkDataInputStep } from '../../../../../common/types'; -import type { DashboardMigrationStats } from '../../../../types'; const mockAddError = jest.fn(); const mockAddSuccess = jest.fn(); @@ -46,7 +45,7 @@ jest.mock('../../../../../../common/hooks/use_app_toasts'); describe('MacrosDataInput', () => { let appToastsMock: jest.Mocked>; - const defaultProps: UseMigrationStepsProps = { + const defaultProps: MigrationStepProps = { onMissingResourcesFetched: jest.fn(), dataInputStep: SplunkDataInputStep.Macros, migrationStats: getDashboardMigrationStatsMock({ status: SiemMigrationTaskStatus.READY }), diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/macros/macros_data_input.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/macros/macros_data_input.tsx index c84aa30f2e3d8..af8d123cae85b 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/macros/macros_data_input.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/macros/macros_data_input.tsx @@ -12,14 +12,13 @@ import { SubSteps } from '../../../../../common/components/migration_steps'; import { getEuiStepStatus } from '../../../../../common/utils/get_eui_step_status'; import { useKibana } from '../../../../../../common/lib/kibana/kibana_react'; import type { DashboardMigrationTaskStats } from '../../../../../../../common/siem_migrations/model/dashboard_migration.gen'; -import type { OnResourcesCreated, OnMissingResourcesFetched } from '../../types'; +import type { OnResourcesCreated } from '../../types'; import * as i18n from './translations'; import { useCopyExportQueryStep } from './sub_steps/copy_export_query'; import { useMacrosFileUploadStep } from './sub_steps/macros_file_upload'; import { useCheckResourcesStep } from '../common/check_resources'; -import type { UseMigrationStepsProps } from '../../../../../common/types'; +import type { MigrationStepProps, OnMissingResourcesFetched } from '../../../../../common/types'; import { SplunkDataInputStep } from '../../../../../common/types'; -import type { DashboardMigrationStats } from '../../../../types'; interface MacrosDataInputSubStepsProps { migrationStats: DashboardMigrationTaskStats; @@ -27,7 +26,7 @@ interface MacrosDataInputSubStepsProps { onMissingResourcesFetched: OnMissingResourcesFetched; } -export const MacrosDataInput = React.memo>( +export const MacrosDataInput = React.memo( ({ dataInputStep, migrationStats, missingResourcesIndexed, onMissingResourcesFetched }) => { const missingMacros = useMemo(() => missingResourcesIndexed?.macros, [missingResourcesIndexed]); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/upload_dashboards/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/upload_dashboards/index.tsx index 3b4b58b6ad982..38f1adfd2764e 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/upload_dashboards/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/upload_dashboards/index.tsx @@ -10,16 +10,15 @@ import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiStepNumber, EuiTitle } from '@e import { getEuiStepStatus } from '../../../../../common/utils/get_eui_step_status'; import * as i18n from '../translations'; import { DashboardsUploadSubSteps } from './sub_steps'; -import type { UseMigrationStepsProps } from '../../../../../common/types'; +import type { MigrationStepProps } from '../../../../../common/types'; import { SplunkDataInputStep } from '../../../../../common/types'; -import type { DashboardMigrationStats } from '../../../../types'; export const DashboardsUploadStep = ({ dataInputStep = 1, // Default value if not provided migrationStats, onMigrationCreated, onMissingResourcesFetched, -}: UseMigrationStepsProps) => { +}: MigrationStepProps) => { const dataInputStatus = useMemo( () => getEuiStepStatus(SplunkDataInputStep.Upload, dataInputStep), [dataInputStep] diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/upload_dashboards/sub_steps/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/upload_dashboards/sub_steps/index.tsx index d4e0e4890076e..6bde02fd376da 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/upload_dashboards/sub_steps/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/steps/upload_dashboards/sub_steps/index.tsx @@ -11,10 +11,11 @@ import type { DashboardMigrationStats } from '../../../../../types'; import { getEuiStepStatus } from '../../../../../../common/utils/get_eui_step_status'; import { SubSteps, useMigrationNameStep } from '../../../../../../common/components'; import { useCopyExportQueryStep } from './copy_export_query'; -import type { OnMigrationCreated, OnMissingResourcesFetched } from '../../../types'; +import type { OnMigrationCreated } from '../../../types'; import { useDashboardsFileUploadStep } from './dashboards_file_upload'; import { useKibana } from '../../../../../../../common/lib/kibana/kibana_react'; import { useCheckResourcesStep } from '../../common/check_resources'; +import type { OnMissingResourcesFetched } from '../../../../../../common/types'; interface DashboardsUploadSubStepsProps { migrationStats?: DashboardMigrationStats; onMissingResourcesFetched: OnMissingResourcesFetched; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/types.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/types.ts index f33187fa312b3..494f4bcd33158 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/types.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/components/data_input_flyout/types.ts @@ -6,12 +6,10 @@ */ import type { SPLUNK_DASHBOARD_COLUMNS } from './constants'; -import type { SiemMigrationResourceBase } from '../../../../../common/siem_migrations/model/common.gen'; import type { DashboardMigrationStats } from '../../types'; export type OnMigrationCreated = (migrationStats: DashboardMigrationStats) => void; export type OnResourcesCreated = () => void; -export type OnMissingResourcesFetched = (missingResources: SiemMigrationResourceBase[]) => void; export type SplunkDashboardsResult = Partial<{ preview: boolean; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/types.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/types.ts index b2d33229e0e98..b3fe10eddbb24 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/types.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/dashboards/types.ts @@ -7,10 +7,7 @@ import type { DashboardMigrationTaskStats } from '../../../common/siem_migrations/model/dashboard_migration.gen'; import type { SiemMigrationTaskStatus } from '../../../common/siem_migrations/constants'; -import type { Step, UseMigrationStepsProps } from '../common/types'; export interface DashboardMigrationStats extends DashboardMigrationTaskStats { status: SiemMigrationTaskStatus; // use the native enum instead of the zod enum from the model } - -export type Steps = Array>>; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/api/index.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/api/index.ts index 28f090d487020..bd5096ee994f9 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/api/index.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/api/index.ts @@ -105,12 +105,16 @@ export interface AddRulesToQradarMigrationParams { signal?: AbortSignal; } +interface AddRulesToQradarMigrationResponse { + count: number; +} + export const addRulesToQRadarMigration = async ({ migrationId, body, signal, }: AddRulesToQradarMigrationParams) => { - return KibanaServices.get().http.post( + return KibanaServices.get().http.post( replaceParams(SIEM_RULE_MIGRATION_QRADAR_RULES_PATH, { migration_id: migrationId }), { body: JSON.stringify(body), version: '1', signal } ); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/index.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/configs/index.ts similarity index 82% rename from x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/index.ts rename to x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/configs/index.ts index 4e53ab8694865..2296e6b52f1eb 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/index.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/configs/index.ts @@ -7,8 +7,8 @@ import { SPLUNK_MIGRATION_STEPS } from './splunk'; import { QRADAR_MIGRATION_STEPS } from './qradar'; -import type { Steps } from '../types'; -import { MigrationSource } from '../../common/types'; +import type { Steps } from '../../../../common/types'; +import { MigrationSource } from '../../../../common/types'; export const STEP_COMPONENTS: Record = { [MigrationSource.SPLUNK]: SPLUNK_MIGRATION_STEPS, diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/qradar.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/configs/qradar.ts similarity index 63% rename from x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/qradar.ts rename to x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/configs/qradar.ts index 93ce800e0921d..8b8a30dffdcc9 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/qradar.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/configs/qradar.ts @@ -5,9 +5,12 @@ * 2.0. */ -import { QradarDataInputStepId } from '../components/data_input_flyout/steps/constants'; -import { RulesDataInput } from '../components/data_input_flyout/steps/rules/rules_data_input'; -import type { Steps } from '../types'; +import type { Steps } from '../../../../common/types'; +import { RulesDataInput } from '../steps/rules/rules_data_input'; + +enum QradarDataInputStepId { + Rules = 'qradar_rules', +} export const QRADAR_MIGRATION_STEPS: Steps = [ { id: QradarDataInputStepId.Rules, Component: RulesDataInput }, diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/splunk.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/configs/splunk.ts similarity index 55% rename from x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/splunk.ts rename to x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/configs/splunk.ts index 18f7e4acce966..f41fcd8312fdd 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/configs/splunk.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/configs/splunk.ts @@ -5,11 +5,16 @@ * 2.0. */ -import { SplunkDataInputStepId } from '../components/data_input_flyout/steps/constants'; -import { LookupsDataInput } from '../components/data_input_flyout/steps/lookups/lookups_data_input'; -import { MacrosDataInput } from '../components/data_input_flyout/steps/macros/macros_data_input'; -import { RulesDataInput } from '../components/data_input_flyout/steps/rules/rules_data_input'; -import type { Steps } from '../types'; +import type { Steps } from '../../../../common/types'; +import { LookupsDataInput } from '../steps/lookups/lookups_data_input'; +import { MacrosDataInput } from '../steps/macros/macros_data_input'; +import { RulesDataInput } from '../steps/rules/rules_data_input'; + +enum SplunkDataInputStepId { + Rules = 'splunk_rules', + Macros = 'splunk_macros', + Lookups = 'splunk_lookups', +} export const SPLUNK_MIGRATION_STEPS: Steps = [ { id: SplunkDataInputStepId.Rules, Component: RulesDataInput }, diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx index bfa0d12a0d587..a53c177a37579 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/data_input_flyout.tsx @@ -24,14 +24,14 @@ import { SiemMigrationTaskStatus, } from '../../../../../common/siem_migrations/constants'; import { useStartRulesMigrationModal } from '../../hooks/use_start_rules_migration_modal'; -import { type RuleMigrationSettings, type RuleMigrationStats } from '../../types'; +import type { RuleMigrationSettings, RuleMigrationStats } from '../../types'; import { useStartMigration } from '../../logic/use_start_migration'; import { useMigrationSourceStep } from '../migration_source_step/use_migration_source_step'; import { MigrationSourceDropdown } from '../migration_source_step/migration_source_dropdown'; import { useMissingResources } from './steps/hooks/use_missing_resources'; -import type { Step, UseMigrationStepsProps } from '../../../common/types'; +import type { MigrationStepProps, Step } from '../../../common/types'; import { MigrationSource, SplunkDataInputStep } from '../../../common/types'; -import { STEP_COMPONENTS } from '../../configs'; +import { STEP_COMPONENTS } from './configs'; export interface MigrationDataInputFlyoutProps { onClose: () => void; @@ -82,13 +82,15 @@ export const MigrationDataInputFlyout = React.memo { - if (typeof migrationStats?.id === 'string') { - startMigration( - migrationStats?.id as string, - isRetry ? SiemMigrationRetryFilter.NOT_FULLY_TRANSLATED : undefined, - settings - ); + if (!migrationStats?.id) { + return; } + + startMigration( + migrationStats?.id as string, + isRetry ? SiemMigrationRetryFilter.NOT_FULLY_TRANSLATED : undefined, + settings + ); }, [isRetry, migrationStats, startMigration] ); @@ -136,21 +138,19 @@ export const MigrationDataInputFlyout = React.memo <> - {STEP_COMPONENTS[migrationSource].map( - (step: Step>) => ( - - - - ) - )} + {STEP_COMPONENTS[migrationSource].map((step: Step) => ( + + + + ))} diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/constants.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/constants.ts deleted file mode 100644 index 396e30bb0f48c..0000000000000 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/constants.ts +++ /dev/null @@ -1,21 +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. - */ - -export enum QradarDataInputStep { - Rules = 1, - End = 10, -} - -export enum SplunkDataInputStepId { - Rules = 'splunk_rules', - Macros = 'splunk_macros', - Lookups = 'splunk_lookups', -} - -export enum QradarDataInputStepId { - Rules = 'qradar_rules', -} diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/hooks/use_missing_resources.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/hooks/use_missing_resources.ts index 7082a5b395de9..b924779b8188a 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/hooks/use_missing_resources.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/hooks/use_missing_resources.ts @@ -7,22 +7,13 @@ import { useCallback, useState } from 'react'; import type { SiemMigrationResourceBase } from '../../../../../../../common/siem_migrations/model/common.gen'; -import type { UseMigrationStepsProps } from '../../../../../common/types'; +import type { MigrationStepProps, MissingResourcesIndexed } from '../../../../../common/types'; import { SplunkDataInputStep } from '../../../../../common/types'; -import type { RuleMigrationStats } from '../../../../types'; -import type { DashboardMigrationStats } from '../../../../../dashboards/types'; - -interface MissingResourcesIndexed { - macros: string[]; - lookups: string[]; -} export const useMissingResources = ({ setDataInputStep, }: { - setDataInputStep: UseMigrationStepsProps< - RuleMigrationStats | DashboardMigrationStats - >['setDataInputStep']; + setDataInputStep: MigrationStepProps['setDataInputStep']; }) => { const [missingResourcesIndexed, setMissingResourcesIndexed] = useState< MissingResourcesIndexed | undefined diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.tsx index ef30aef1a1749..5591f3c749dc7 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/lookups/lookups_data_input.tsx @@ -27,9 +27,8 @@ import type { OnResourcesCreated } from '../../types'; import * as i18n from './translations'; import { useMissingLookupsListStep } from './sub_steps/missing_lookups_list'; import { useLookupsFileUploadStep } from './sub_steps/lookups_file_upload'; -import type { UseMigrationStepsProps } from '../../../../../common/types'; +import type { MigrationStepProps } from '../../../../../common/types'; import { SplunkDataInputStep } from '../../../../../common/types'; -import type { RuleMigrationStats } from '../../../../types'; interface LookupsDataInputSubStepsProps { migrationStats: RuleMigrationTaskStats; @@ -37,7 +36,7 @@ interface LookupsDataInputSubStepsProps { onAllLookupsCreated: OnResourcesCreated; } -export const LookupsDataInput = React.memo>( +export const LookupsDataInput = React.memo( ({ dataInputStep, migrationStats, missingResourcesIndexed, setDataInputStep }) => { const missingLookups = useMemo( () => missingResourcesIndexed?.lookups, diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.test.tsx index b2cac67310a70..54410ecaf29cc 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.test.tsx @@ -14,9 +14,8 @@ import { TestProviders } from '../../../../../../common/mock'; import { useAppToasts } from '../../../../../../common/hooks/use_app_toasts'; import { useAppToastsMock } from '../../../../../../common/hooks/use_app_toasts.mock'; import { useMissingResources } from '../hooks/use_missing_resources'; -import type { UseMigrationStepsProps } from '../../../../../common/types'; +import type { MigrationStepProps } from '../../../../../common/types'; import { MigrationSource, SplunkDataInputStep } from '../../../../../common/types'; -import type { RuleMigrationStats } from '../../../../types'; const mockAddError = jest.fn(); const mockAddSuccess = jest.fn(); @@ -57,7 +56,7 @@ jest.mock('../hooks/use_missing_resources', () => ({ describe('MacrosDataInput', () => { let appToastsMock: jest.Mocked>; - const defaultProps: UseMigrationStepsProps = { + const defaultProps: MigrationStepProps = { onMissingResourcesFetched: jest.fn(), dataInputStep: SplunkDataInputStep.Macros, migrationStats: getRuleMigrationStatsMock({ status: SiemMigrationTaskStatus.READY }), diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.tsx index 6ff0220af8dba..9be836b45cea5 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.tsx @@ -17,12 +17,8 @@ import * as i18n from './translations'; import { useCopyExportQueryStep } from './sub_steps/copy_export_query'; import { useMacrosFileUploadStep } from './sub_steps/macros_file_upload'; import { useCheckResourcesStep } from './sub_steps/check_resources'; -import type { - OnMissingResourcesFetched, - UseMigrationStepsProps, -} from '../../../../../common/types'; +import type { MigrationStepProps, OnMissingResourcesFetched } from '../../../../../common/types'; import { SplunkDataInputStep } from '../../../../../common/types'; -import type { RuleMigrationStats } from '../../../../types'; interface MacrosDataInputSubStepsProps { migrationStats: RuleMigrationTaskStats; @@ -30,7 +26,7 @@ interface MacrosDataInputSubStepsProps { onMissingResourcesFetched: OnMissingResourcesFetched; } -export const MacrosDataInput = React.memo>( +export const MacrosDataInput = React.memo( ({ dataInputStep, migrationStats, missingResourcesIndexed, onMissingResourcesFetched }) => { const missingMacros = useMemo(() => missingResourcesIndexed?.macros, [missingResourcesIndexed]); const dataInputStatus = useMemo( diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/sub_steps/check_resources/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/sub_steps/check_resources/index.tsx index a30dd16eab4cb..763c569de9b55 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/sub_steps/check_resources/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/sub_steps/check_resources/index.tsx @@ -9,8 +9,8 @@ import React, { useEffect, useMemo } from 'react'; import { EuiText, type EuiStepProps, type EuiStepStatus } from '@elastic/eui'; import { useGetMissingResources } from '../../../../../../../common/hooks/use_get_missing_resources'; import type { RuleMigrationTaskStats } from '../../../../../../../../../common/siem_migrations/model/rule_migration.gen'; -import type { OnMissingResourcesFetched } from '../../../../types'; import * as i18n from './translations'; +import type { OnMissingResourcesFetched } from '../../../../../../../common/types'; export interface CheckResourcesStepProps { status: EuiStepStatus; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx index 5a178dd09b665..17ba624b36004 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/rules_data_input.tsx @@ -11,20 +11,21 @@ import React, { useCallback, useMemo, useState } from 'react'; import { SubSteps, useMigrationNameStep } from '../../../../../common/components'; import { getEuiStepStatus } from '../../../../../common/utils/get_eui_step_status'; import { useKibana } from '../../../../../../common/lib/kibana'; -import type { OnMigrationCreated, RulesDataInputSubStepsProps } from '../../types'; +import type { OnMigrationCreated } from '../../types'; import * as i18n from './translations'; -import { QradarDataInputStep } from '../constants'; import { useCopyExportQueryStep } from './sub_steps/copy_export_query'; import { useRulesFileUploadStep } from './sub_steps/rules_file_upload'; import { useCheckResourcesStep } from './sub_steps/check_resources'; -import type { - OnMissingResourcesFetched, - UseMigrationStepsProps, -} from '../../../../../common/types'; +import type { MigrationStepProps, OnMissingResourcesFetched } from '../../../../../common/types'; import { MigrationSource, SplunkDataInputStep } from '../../../../../common/types'; import type { RuleMigrationStats } from '../../../../types'; -export const RulesDataInput = React.memo>( +enum QradarDataInputStep { + Rules = 1, + End = 10, +} + +export const RulesDataInput = React.memo( ({ dataInputStep, migrationStats, @@ -90,6 +91,15 @@ RulesDataInput.displayName = 'RulesDataInput'; const END = 10 as const; type SubStep = 1 | 2 | 3 | 4 | typeof END; + +interface RulesDataInputSubStepsProps { + dataInputStep: number; + migrationSource: MigrationSource; + migrationStats?: RuleMigrationStats; + onMigrationCreated: (createdMigrationStats: RuleMigrationStats) => void; + onMissingResourcesFetched?: OnMissingResourcesFetched; +} + export const RulesDataInputSubSteps = React.memo( ({ migrationStats, onMigrationCreated, onMissingResourcesFetched, migrationSource }) => { const { telemetry } = useKibana().services.siemMigrations.rules; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/translations.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/translations.ts index df5045e0e27ad..900ee3bd64dc2 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/translations.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/translations.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; export const RULES_DATA_INPUT_COPY_TITLE = i18n.translate( 'xpack.securitySolution.siemMigrations.rules.dataInputFlyout.rules.copyExportQuery.title', - { defaultMessage: 'Copy rule query' } + { defaultMessage: 'Export rules' } ); export const RULES_DATA_INPUT_COPY_DESCRIPTION_SECTION = i18n.translate( diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/index.tsx index 24847fdfe5c8b..7208b36471b13 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/index.tsx @@ -65,7 +65,6 @@ export const useRulesFileUploadStep = ({ = {}) => { diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_file_upload.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_file_upload.tsx index 4f20a73373b30..8a48b6aee01e3 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_file_upload.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_file_upload.tsx @@ -25,7 +25,7 @@ import type { OriginalRule } from '../../../../../../../../../common/siem_migrat import * as i18n from './translations'; import { RULES_DATA_INPUT_CHECK_RESOURCES_DESCRIPTION } from '../check_resources/translations'; import type { SPLUNK_RULES_COLUMNS } from '../../../../constants'; -import type { MigrationSource } from '../../../../../../types'; +import { MigrationSource } from '../../../../../../../common/types'; type SplunkRulesResult = Partial>; @@ -35,29 +35,24 @@ export interface RulesFileUploadProps { isCreated: boolean; onRulesFileChanged: (files: FileList | null) => void; migrationName: string | undefined; - migrationSource: MigrationSource; apiError: string | undefined; } export const RulesFileUpload = React.memo( - ({ - createMigration, - migrationName, - migrationSource, - apiError, - isLoading, - isCreated, - onRulesFileChanged, - }) => { + ({ createMigration, migrationName, apiError, isLoading, isCreated, onRulesFileChanged }) => { const [rulesToUpload, setRulesToUpload] = useState([]); const filePickerRef = useRef(null); const createRules = useCallback(() => { if (migrationName) { filePickerRef.current?.removeFiles(); - createMigration({ migrationName, rules: rulesToUpload, migrationSource }); + createMigration({ + migrationName, + rules: rulesToUpload, + migrationSource: MigrationSource.SPLUNK, + }); } - }, [createMigration, migrationName, migrationSource, rulesToUpload]); + }, [createMigration, migrationName, rulesToUpload]); const onFileParsed = useCallback((content: string) => { const rules = parseContent(content).map(formatRuleRow); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_xml_file_upload.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_xml_file_upload.tsx index 71e8c3e3155a0..f993ffce91b3f 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_xml_file_upload.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_xml_file_upload.tsx @@ -16,7 +16,7 @@ import type { CreateMigration } from '../../../../../../service/hooks/use_create import * as i18n from './translations'; import { RULES_DATA_INPUT_CHECK_RESOURCES_DESCRIPTION } from '../check_resources/translations'; import { useParseFileInput } from '../../../../../../../common/hooks/use_parse_file_input'; -import type { MigrationSource } from '../../../../../../types'; +import { MigrationSource } from '../../../../../../../common/types'; export interface RulesXMLFileUploadProps { createMigration: CreateMigration; @@ -24,29 +24,24 @@ export interface RulesXMLFileUploadProps { isCreated: boolean; onRulesFileChanged: (files: FileList | null) => void; migrationName: string | undefined; - migrationSource: MigrationSource; apiError: string | undefined; } export const RulesXMLFileUpload = React.memo( - ({ - createMigration, - migrationName, - migrationSource, - apiError, - isLoading, - isCreated, - onRulesFileChanged, - }) => { + ({ createMigration, migrationName, apiError, isLoading, isCreated, onRulesFileChanged }) => { const [rulesToUpload, setRulesToUpload] = useState(); const filePickerRef = useRef(null); const createRules = useCallback(() => { if (migrationName && rulesToUpload) { filePickerRef.current?.removeFiles(); - createMigration({ migrationName, rules: rulesToUpload, migrationSource }); + createMigration({ + migrationName, + rules: { xml: rulesToUpload }, + migrationSource: MigrationSource.QRADAR, + }); } - }, [createMigration, migrationName, migrationSource, rulesToUpload]); + }, [createMigration, migrationName, rulesToUpload]); const onXMLFileParsed = useCallback((content: string) => { setRulesToUpload(content); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/types.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/types.ts index c8af6482589a9..f4751f5e7a3c8 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/types.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/types.ts @@ -5,16 +5,7 @@ * 2.0. */ -import type { MigrationSource, OnMissingResourcesFetched } from '../../../common/types'; import type { RuleMigrationStats } from '../../types'; export type OnMigrationCreated = (migrationStats: RuleMigrationStats) => void; export type OnResourcesCreated = () => void; - -export interface RulesDataInputSubStepsProps { - dataInputStep: number; - migrationSource: MigrationSource; - migrationStats?: RuleMigrationStats; - onMigrationCreated: (createdMigrationStats: RuleMigrationStats) => void; - onMissingResourcesFetched?: OnMissingResourcesFetched; -} diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/migration_source_step/migration_source_dropdown.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/migration_source_step/migration_source_dropdown.test.tsx index 2aa2e6de02833..5abcc81719e61 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/migration_source_step/migration_source_dropdown.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/migration_source_step/migration_source_dropdown.test.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; import { MigrationSourceDropdown } from './migration_source_dropdown'; import * as i18n from './translations'; -import { MigrationSource } from '../../types'; +import { MigrationSource } from '../../../common/types'; describe('MigrationSourceDropdown', () => { const mockSetMigrationSource = jest.fn(); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/migration_source_step/migration_source_dropdown.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/migration_source_step/migration_source_dropdown.tsx index 40b62d2ec55e7..f902161327006 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/migration_source_step/migration_source_dropdown.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/migration_source_step/migration_source_dropdown.tsx @@ -8,7 +8,7 @@ import React, { useCallback } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiForm, EuiFormRow, EuiSuperSelect } from '@elastic/eui'; import * as i18n from './translations'; import type { MigrationSourceDropdownProps } from './use_migration_source_step'; -import type { MigrationSource } from '../../types'; +import type { MigrationSource } from '../../../common/types'; export const MigrationSourceDropdown = React.memo( ({ migrationSource, setMigrationSource, disabled, migrationSourceOptions }) => { diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.test.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.test.ts index ec0f9ccd030cb..401a2ea609f8b 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.test.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.test.ts @@ -9,7 +9,7 @@ import { renderHook, act } from '@testing-library/react'; import { useCreateMigration } from './use_create_migration'; import { useKibana } from '../../../../common/lib/kibana/kibana_react'; import type { CreateRuleMigrationRulesRequestBody } from '../../../../../common/siem_migrations/model/api/rules/rule_migration.gen'; -import { MigrationSource } from '../../types'; +import { MigrationSource } from '../../../common/types'; jest.mock('../../../../common/lib/kibana/kibana_react', () => ({ useKibana: jest.fn(), diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.ts index 48bfd5329a978..213cfb188f898 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.ts @@ -7,10 +7,11 @@ import { useCallback, useReducer } from 'react'; import { i18n } from '@kbn/i18n'; -import type { CreateRuleMigrationRulesRequestBody } from '../../../../../common/siem_migrations/model/api/rules/rule_migration.gen'; import { useKibana } from '../../../../common/lib/kibana/kibana_react'; import { reducer, initialState } from '../../../common/service'; -import type { MigrationSource, RuleMigrationStats } from '../../types'; +import type { RuleMigrationStats } from '../../types'; +import type { CreateRuleMigrationParams } from '../rule_migrations_service'; +import { MigrationSource } from '../../../common/types'; export const RULES_DATA_INPUT_CREATE_MIGRATION_SUCCESS_TITLE = i18n.translate( 'xpack.securitySolution.siemMigrations.rules.service.createRuleSuccess.title', @@ -30,11 +31,7 @@ export type CreateMigration = ({ rules, migrationName, migrationSource, -}: { - migrationName: string; - migrationSource: MigrationSource; - rules: CreateRuleMigrationRulesRequestBody | string; -}) => void; +}: CreateRuleMigrationParams) => void; export type OnSuccess = (migrationStats: RuleMigrationStats) => void; export const useCreateMigration = (onSuccess: OnSuccess) => { @@ -42,11 +39,24 @@ export const useCreateMigration = (onSuccess: OnSuccess) => { const [state, dispatch] = useReducer(reducer, initialState); const createMigration = useCallback( - ({ migrationName, rules }) => { + ({ migrationName, migrationSource, rules }) => { (async () => { try { dispatch({ type: 'start' }); - const migrationId = await siemMigrations.rules.createRuleMigration(rules, migrationName); + let migrationId: string; + if (migrationSource === MigrationSource.QRADAR) { + migrationId = await siemMigrations.rules.createRuleMigration({ + migrationName, + migrationSource: MigrationSource.QRADAR, + rules, + }); + } else { + migrationId = await siemMigrations.rules.createRuleMigration({ + migrationName, + migrationSource: MigrationSource.SPLUNK, + rules, + }); + } const stats = await siemMigrations.rules.api.getRuleMigrationStats({ migrationId, }); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/rule_migrations_service.test.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/rule_migrations_service.test.ts index 490df2464cf50..c08a14811bfa2 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/rule_migrations_service.test.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/rule_migrations_service.test.ts @@ -36,6 +36,7 @@ import type { CreateRuleMigrationRulesRequestBody } from '../../../../common/sie import { TASK_STATS_POLLING_SLEEP_SECONDS } from '../../common/constants'; import { getMissingCapabilitiesChecker } from '../../common/service'; import { raiseSuccessToast } from './notification/success_notification'; +import { MigrationSource } from '../../common/types'; // --- Mocks for external modules --- @@ -146,7 +147,13 @@ describe('SiemRulesMigrationsService', () => { describe('createRuleMigration', () => { it('should throw an error when body is empty', async () => { - await expect(service.createRuleMigration([], 'test')).rejects.toThrow(i18n.EMPTY_RULES_ERROR); + await expect( + service.createRuleMigration({ + rules: [], + migrationName: 'test', + migrationSource: MigrationSource.SPLUNK, + }) + ).rejects.toThrow(i18n.EMPTY_RULES_ERROR); }); it('should create migration with a single batch', async () => { @@ -155,7 +162,11 @@ describe('SiemRulesMigrationsService', () => { (createRuleMigration as jest.Mock).mockResolvedValue({ migration_id: 'mig-1' }); (addRulesToMigration as jest.Mock).mockResolvedValue(undefined); - const migrationId = await service.createRuleMigration(body, name); + const migrationId = await service.createRuleMigration({ + rules: body, + migrationName: name, + migrationSource: MigrationSource.SPLUNK, + }); expect(createRuleMigration).toHaveBeenCalledTimes(1); expect(createRuleMigration).toHaveBeenCalledWith({ name }); @@ -170,7 +181,11 @@ describe('SiemRulesMigrationsService', () => { (createRuleMigration as jest.Mock).mockResolvedValueOnce({ migration_id: 'mig-1' }); (addRulesToMigration as jest.Mock).mockResolvedValue(undefined); - const migrationId = await service.createRuleMigration(body, name); + const migrationId = await service.createRuleMigration({ + rules: body, + migrationName: name, + migrationSource: MigrationSource.SPLUNK, + }); expect(createRuleMigration).toHaveBeenCalledTimes(1); expect(addRulesToMigration).toHaveBeenCalledTimes(2); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/rule_migrations_service.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/rule_migrations_service.ts index 55758c80d53e2..fa4251893d2bf 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/rule_migrations_service.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/rule_migrations_service.ts @@ -8,6 +8,7 @@ import type { CoreStart } from '@kbn/core/public'; import type { TelemetryServiceStart } from '../../../common/lib/telemetry'; import type { + CreateQRadarRuleMigrationRulesRequestBody, CreateRuleMigrationRulesRequestBody, StartRuleMigrationResponse, StopRuleMigrationResponse, @@ -26,11 +27,24 @@ import { getNoConnectorToast, } from '../../common/service'; import type { GetMigrationStatsParams, GetMigrationsStatsAllParams } from '../../common/types'; +import { MigrationSource } from '../../common/types'; import { raiseSuccessToast } from './notification/success_notification'; import { START_STOP_POLLING_SLEEP_SECONDS } from '../../common/constants'; const CREATE_MIGRATION_BODY_BATCH_SIZE = 50; +export type CreateRuleMigrationParams = + | { + rules: CreateRuleMigrationRulesRequestBody; + migrationName: string; + migrationSource: MigrationSource.SPLUNK; + } + | { + rules: CreateQRadarRuleMigrationRulesRequestBody; + migrationName: string; + migrationSource: MigrationSource.QRADAR; + }; + export class SiemRulesMigrationsService extends SiemMigrationsServiceBase { public telemetry: SiemRulesMigrationsTelemetry; @@ -48,13 +62,18 @@ export class SiemRulesMigrationsService extends SiemMigrationsServiceBase { - const rulesCount = data.length; - if (rulesCount === 0) { + public async createRuleMigration({ + rules, + migrationName, + migrationSource, + }: CreateRuleMigrationParams): Promise { + if (!rules) { const emptyRulesError = new Error(i18n.EMPTY_RULES_ERROR); - this.telemetry.reportSetupMigrationCreated({ count: rulesCount, error: emptyRulesError }); + this.telemetry.reportSetupMigrationCreated({ count: 0, error: emptyRulesError }); throw emptyRulesError; } try { - // create the migration - const { migration_id: migrationId } = await api.createRuleMigration({ - name: migrationName, - }); + if (migrationSource === MigrationSource.QRADAR) { + if (!rules.xml) { + throw new Error(i18n.EMPTY_RULES_ERROR); + } + + // create the migration + const { migration_id: migrationId } = await api.createRuleMigration({ + name: migrationName, + }); + const { count } = await this.addQradarRulesToMigration(migrationId, rules); + this.telemetry.reportSetupMigrationCreated({ migrationId, count }); - if (typeof data === 'string') { - await this.addQradarRulesToMigration(migrationId, data); + return migrationId; } else { - await this.addRulesToMigration(migrationId, data); - } + if (rules.length === 0) { + throw new Error(i18n.EMPTY_RULES_ERROR); + } - this.telemetry.reportSetupMigrationCreated({ migrationId, count: rulesCount }); - return migrationId; + // create the migration + const { migration_id: migrationId } = await api.createRuleMigration({ + name: migrationName, + }); + await this.addRulesToMigration(migrationId, rules); + this.telemetry.reportSetupMigrationCreated({ migrationId, count: rules.length }); + + return migrationId; + } } catch (error) { - this.telemetry.reportSetupMigrationCreated({ count: rulesCount, error }); + this.telemetry.reportSetupMigrationCreated({ count: 0, error }); throw error; } } diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/types.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/types.ts index 4d13c1ef1aae3..6b6c963b163e6 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/types.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/types.ts @@ -7,12 +7,7 @@ import type { SiemMigrationTaskStatus } from '../../../common/siem_migrations/constants'; import type { RuleMigrationTaskStats } from '../../../common/siem_migrations/model/rule_migration.gen'; -import type { - MigrationSettingsBase, - StatusFilterBase, - Step, - UseMigrationStepsProps, -} from '../common/types'; +import type { MigrationSettingsBase, StatusFilterBase } from '../common/types'; export interface RuleMigrationStats extends RuleMigrationTaskStats { status: SiemMigrationTaskStatus; // use the native enum instead of the zod enum from the model @@ -37,5 +32,3 @@ export interface RulesFilterOptions { export interface RuleMigrationSettings extends MigrationSettingsBase { skipPrebuiltRulesMatching: boolean; } - -export type Steps = Array>>; diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/api/rules/qradar/create.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/api/rules/qradar/create.ts index d3855f7636620..486859d76b85b 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/api/rules/qradar/create.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/siem_migrations/rules/api/rules/qradar/create.ts @@ -119,6 +119,7 @@ export const registerSiemRuleMigrationsCreateQRadarRulesRoute = ( message: `Successfully imported ${rulesCount} QRadar rule${ rulesCount !== 1 ? 's' : '' }`, + count: rulesCount, }, }); } catch (error) { From 3bb2d09ffd27e18b55b4f4d0da52e0d2250d52e2 Mon Sep 17 00:00:00 2001 From: Angela Chuang Date: Wed, 10 Dec 2025 15:31:47 +0000 Subject: [PATCH 21/23] types --- .../steps/rules/sub_steps/copy_export_query/index.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/index.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/index.test.tsx index 9f668be180f22..fa29151ce60eb 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/index.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/index.test.tsx @@ -9,7 +9,7 @@ import { renderHook } from '@testing-library/react'; import { useCopyExportQueryStep } from '.'; import type { CopyExportQueryStepProps } from '.'; import { TestProviders } from '../../../../../../../../common/mock'; -import { MigrationSource } from '../../../../../../types'; +import { MigrationSource } from '../../../../../../../common/types'; const renderCopyExportQueryStep = (props: CopyExportQueryStepProps) => { const { result } = renderHook(() => useCopyExportQueryStep(props), { From 0f472c53120c4fb9fa9429c2914376a30ddd09b5 Mon Sep 17 00:00:00 2001 From: Angela Chuang Date: Thu, 11 Dec 2025 09:55:47 +0000 Subject: [PATCH 22/23] types --- .../steps/macros/macros_data_input.test.tsx | 23 +++++-------------- .../sub_steps/check_resources/index.tsx | 4 +++- .../sub_steps/check_resources/translations.ts | 2 +- .../rules/sub_steps/check_resources/index.tsx | 2 +- .../sub_steps/check_resources/translations.ts | 11 +++++++-- .../copy_export_query/index.test.tsx | 2 +- .../rules_file_upload/rules_file_upload.tsx | 4 ++-- .../rules_xml_file_upload.tsx | 4 ++-- .../service/hooks/use_create_migration.ts | 18 ++------------- 9 files changed, 27 insertions(+), 43 deletions(-) diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.test.tsx index 54410ecaf29cc..d10de4cc14c5d 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/macros_data_input.test.tsx @@ -13,7 +13,6 @@ import { SiemMigrationTaskStatus } from '../../../../../../../common/siem_migrat import { TestProviders } from '../../../../../../common/mock'; import { useAppToasts } from '../../../../../../common/hooks/use_app_toasts'; import { useAppToastsMock } from '../../../../../../common/hooks/use_app_toasts.mock'; -import { useMissingResources } from '../hooks/use_missing_resources'; import type { MigrationStepProps } from '../../../../../common/types'; import { MigrationSource, SplunkDataInputStep } from '../../../../../common/types'; @@ -57,24 +56,18 @@ describe('MacrosDataInput', () => { let appToastsMock: jest.Mocked>; const defaultProps: MigrationStepProps = { - onMissingResourcesFetched: jest.fn(), dataInputStep: SplunkDataInputStep.Macros, - migrationStats: getRuleMigrationStatsMock({ status: SiemMigrationTaskStatus.READY }), migrationSource: MigrationSource.SPLUNK, - setDataInputStep: jest.fn(), + migrationStats: getRuleMigrationStatsMock({ status: SiemMigrationTaskStatus.READY }), + missingResourcesIndexed: { macros: ['macro1', 'macro2'], lookups: [] }, onMigrationCreated: jest.fn(), + onMissingResourcesFetched: jest.fn(), + setDataInputStep: jest.fn(), }; beforeEach(() => { appToastsMock = useAppToastsMock.create(); jest.mocked(useAppToasts).mockReturnValue(appToastsMock); - jest.mocked(useMissingResources).mockReturnValue({ - missingResourcesIndexed: { - macros: ['macro1', 'macro2'], - lookups: [], - }, - onMissingResourcesFetched: jest.fn(), - }); }); afterEach(() => { @@ -104,7 +97,7 @@ describe('MacrosDataInput', () => { it('does not render sub-steps when dataInputStep is not MacrosUpload', () => { const { queryByTestId } = render( - + ); expect(queryByTestId('migrationsSubSteps')).not.toBeInTheDocument(); @@ -120,13 +113,9 @@ describe('MacrosDataInput', () => { }); it('does not render sub-steps when missingMacros is missing', () => { - jest.mocked(useMissingResources).mockReturnValue({ - missingResourcesIndexed: undefined, - onMissingResourcesFetched: jest.fn(), - }); const { queryByTestId } = render( - + ); expect(queryByTestId('migrationsSubSteps')).not.toBeInTheDocument(); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/sub_steps/check_resources/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/sub_steps/check_resources/index.tsx index 763c569de9b55..64750e0807d07 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/sub_steps/check_resources/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/sub_steps/check_resources/index.tsx @@ -46,6 +46,8 @@ export const useCheckResourcesStep = ({ return { title: i18n.RULES_DATA_INPUT_CHECK_RESOURCES_TITLE, status: uploadStepStatus, - children: {i18n.RULES_DATA_INPUT_CHECK_RESOURCES_DESCRIPTION}, + children: ( + {i18n.RULES_DATA_INPUT_CHECK_RESOURCES_SPLUNK_DESCRIPTION} + ), }; }; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/sub_steps/check_resources/translations.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/sub_steps/check_resources/translations.ts index 9793bf43e9e97..2eb292b410237 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/sub_steps/check_resources/translations.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/macros/sub_steps/check_resources/translations.ts @@ -12,7 +12,7 @@ export const RULES_DATA_INPUT_CHECK_RESOURCES_TITLE = i18n.translate( { defaultMessage: 'Check for macros and lookups' } ); -export const RULES_DATA_INPUT_CHECK_RESOURCES_DESCRIPTION = i18n.translate( +export const RULES_DATA_INPUT_CHECK_RESOURCES_SPLUNK_DESCRIPTION = i18n.translate( 'xpack.securitySolution.siemMigrations.rules.dataInputFlyout.rules.checkResources.description', { defaultMessage: `For best translation results, we will review the data for macros and lookups. If found, we will ask you to upload them next.`, diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/check_resources/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/check_resources/index.tsx index e977841d6ebd5..6e1a69e6ea6ac 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/check_resources/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/check_resources/index.tsx @@ -48,7 +48,7 @@ export const useCheckResourcesStep = ({ status: uploadStepStatus, children: ( - {i18n.RULES_DATA_INPUT_CHECK_RESOURCES_DESCRIPTION} + {i18n.RULES_DATA_INPUT_CHECK_RESOURCES_SPLUNK_DESCRIPTION} ), }; diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/check_resources/translations.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/check_resources/translations.ts index 9793bf43e9e97..3e1ea2a069703 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/check_resources/translations.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/check_resources/translations.ts @@ -12,9 +12,16 @@ export const RULES_DATA_INPUT_CHECK_RESOURCES_TITLE = i18n.translate( { defaultMessage: 'Check for macros and lookups' } ); -export const RULES_DATA_INPUT_CHECK_RESOURCES_DESCRIPTION = i18n.translate( - 'xpack.securitySolution.siemMigrations.rules.dataInputFlyout.rules.checkResources.description', +export const RULES_DATA_INPUT_CHECK_RESOURCES_SPLUNK_DESCRIPTION = i18n.translate( + 'xpack.securitySolution.siemMigrations.rules.dataInputFlyout.rules.checkResources.splunk.description', { defaultMessage: `For best translation results, we will review the data for macros and lookups. If found, we will ask you to upload them next.`, } ); + +export const RULES_DATA_INPUT_CHECK_RESOURCES_QRADAR_DESCRIPTION = i18n.translate( + 'xpack.securitySolution.siemMigrations.rules.dataInputFlyout.rules.checkResources.qradarDescription', + { + defaultMessage: `For best translation results, we will review the data for reference sets. If found, we will ask you to upload them next.`, + } +); diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/index.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/index.test.tsx index fa29151ce60eb..95502399b7f79 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/index.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/copy_export_query/index.test.tsx @@ -19,7 +19,7 @@ const renderCopyExportQueryStep = (props: CopyExportQueryStepProps) => { }; describe('useCopyExportQueryStep', () => { - const title = 'Copy rule query'; + const title = 'Export rules'; it('returns step props with "incomplete" status', () => { const result = renderCopyExportQueryStep({ migrationSource: MigrationSource.SPLUNK, diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_file_upload.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_file_upload.tsx index 8a48b6aee01e3..c74b4fbbd3d61 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_file_upload.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_file_upload.tsx @@ -23,7 +23,7 @@ import type { CreateMigration } from '../../../../../../service/hooks/use_create import type { CreateRuleMigrationRulesRequestBody } from '../../../../../../../../../common/siem_migrations/model/api/rules/rule_migration.gen'; import type { OriginalRule } from '../../../../../../../../../common/siem_migrations/model/rule_migration.gen'; import * as i18n from './translations'; -import { RULES_DATA_INPUT_CHECK_RESOURCES_DESCRIPTION } from '../check_resources/translations'; +import { RULES_DATA_INPUT_CHECK_RESOURCES_SPLUNK_DESCRIPTION } from '../check_resources/translations'; import type { SPLUNK_RULES_COLUMNS } from '../../../../constants'; import { MigrationSource } from '../../../../../../../common/types'; @@ -84,7 +84,7 @@ export const RulesFileUpload = React.memo( return ( - {RULES_DATA_INPUT_CHECK_RESOURCES_DESCRIPTION} + {RULES_DATA_INPUT_CHECK_RESOURCES_SPLUNK_DESCRIPTION} diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_xml_file_upload.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_xml_file_upload.tsx index f993ffce91b3f..6e5ef2c2ec71e 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_xml_file_upload.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/rules/sub_steps/rules_file_upload/rules_xml_file_upload.tsx @@ -14,7 +14,7 @@ import type { import { UploadFileButton } from '../../../../../../../common/components'; import type { CreateMigration } from '../../../../../../service/hooks/use_create_migration'; import * as i18n from './translations'; -import { RULES_DATA_INPUT_CHECK_RESOURCES_DESCRIPTION } from '../check_resources/translations'; +import { RULES_DATA_INPUT_CHECK_RESOURCES_QRADAR_DESCRIPTION } from '../check_resources/translations'; import { useParseFileInput } from '../../../../../../../common/hooks/use_parse_file_input'; import { MigrationSource } from '../../../../../../../common/types'; @@ -72,7 +72,7 @@ export const RulesXMLFileUpload = React.memo( return ( - {RULES_DATA_INPUT_CHECK_RESOURCES_DESCRIPTION} + {RULES_DATA_INPUT_CHECK_RESOURCES_QRADAR_DESCRIPTION} diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.ts index 213cfb188f898..1d43c608410e6 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.ts @@ -11,7 +11,6 @@ import { useKibana } from '../../../../common/lib/kibana/kibana_react'; import { reducer, initialState } from '../../../common/service'; import type { RuleMigrationStats } from '../../types'; import type { CreateRuleMigrationParams } from '../rule_migrations_service'; -import { MigrationSource } from '../../../common/types'; export const RULES_DATA_INPUT_CREATE_MIGRATION_SUCCESS_TITLE = i18n.translate( 'xpack.securitySolution.siemMigrations.rules.service.createRuleSuccess.title', @@ -39,24 +38,11 @@ export const useCreateMigration = (onSuccess: OnSuccess) => { const [state, dispatch] = useReducer(reducer, initialState); const createMigration = useCallback( - ({ migrationName, migrationSource, rules }) => { + (args) => { (async () => { try { dispatch({ type: 'start' }); - let migrationId: string; - if (migrationSource === MigrationSource.QRADAR) { - migrationId = await siemMigrations.rules.createRuleMigration({ - migrationName, - migrationSource: MigrationSource.QRADAR, - rules, - }); - } else { - migrationId = await siemMigrations.rules.createRuleMigration({ - migrationName, - migrationSource: MigrationSource.SPLUNK, - rules, - }); - } + const migrationId = await siemMigrations.rules.createRuleMigration(args); const stats = await siemMigrations.rules.api.getRuleMigrationStats({ migrationId, }); From 565d5ed44ca299c1d2661323efc5882181ca793e Mon Sep 17 00:00:00 2001 From: Angela Chuang Date: Thu, 11 Dec 2025 11:46:05 +0000 Subject: [PATCH 23/23] unit tests --- .../rules/service/hooks/use_create_migration.test.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.test.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.test.ts index 401a2ea609f8b..b3d4ce9284087 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.test.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/service/hooks/use_create_migration.test.ts @@ -63,7 +63,11 @@ describe('useCreateMigration', () => { }); }); - expect(createRuleMigration).toHaveBeenCalledWith(rules, 'test-migration'); + expect(createRuleMigration).toHaveBeenCalledWith({ + rules, + migrationName: 'test-migration', + migrationSource: MigrationSource.SPLUNK, + }); expect(getRuleMigrationStats).toHaveBeenCalledWith({ migrationId: 'migration-id' }); expect(addSuccess).toHaveBeenCalled(); expect(onSuccess).toHaveBeenCalledWith({ id: 'migration-id', items: { total: 1 } });