diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/lookups/lookups_file_upload/index.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/lookups/lookups_file_upload/index.test.tsx
index d19f28b441f3f..8940741c65887 100644
--- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/lookups/lookups_file_upload/index.test.tsx
+++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/lookups/lookups_file_upload/index.test.tsx
@@ -6,7 +6,7 @@
*/
import React from 'react';
-import { render } from '@testing-library/react';
+import { fireEvent, render } from '@testing-library/react';
import { LookupsFileUpload } from '.';
import { MigrationSource } from '../../../../types';
@@ -22,4 +22,22 @@ describe('LookupsFileUpload', () => {
const { getByTestId } = render();
expect(getByTestId('uploadFileButton')).toBeInTheDocument();
});
+
+ it('does not render skip button when onSkip is not provided', () => {
+ const { queryByTestId } = render();
+ expect(queryByTestId('lookupsUploadSkipButton')).not.toBeInTheDocument();
+ });
+
+ it('renders skip button when onSkip is provided', () => {
+ const { getByTestId } = render();
+ expect(getByTestId('lookupsUploadSkipButton')).toBeInTheDocument();
+ expect(getByTestId('lookupsUploadSkipButton')).toHaveTextContent('Skip');
+ });
+
+ it('calls onSkip when skip button is clicked', () => {
+ const onSkip = jest.fn();
+ const { getByTestId } = render();
+ fireEvent.click(getByTestId('lookupsUploadSkipButton'));
+ expect(onSkip).toHaveBeenCalledTimes(1);
+ });
});
diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/lookups/lookups_file_upload/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/lookups/lookups_file_upload/index.tsx
index 35f0fda5ef036..80dca4bd93c72 100644
--- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/lookups/lookups_file_upload/index.tsx
+++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/common/components/migration_steps/lookups/lookups_file_upload/index.tsx
@@ -6,7 +6,14 @@
*/
import React, { useCallback, useMemo, useRef, useState } from 'react';
-import { EuiFilePicker, EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiText } from '@elastic/eui';
+import {
+ EuiButtonEmpty,
+ EuiFilePicker,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiFormRow,
+ EuiText,
+} from '@elastic/eui';
import type {
EuiFilePickerClass,
EuiFilePickerProps,
@@ -23,6 +30,7 @@ export interface LookupsFileUploadProps {
apiError?: string;
isLoading?: boolean;
migrationSource: MigrationSource;
+ onSkip?: () => void;
}
const CONFIGS: Record = {
@@ -37,7 +45,7 @@ const CONFIGS: Record = {
};
export const LookupsFileUpload = React.memo(
- ({ createResources, apiError, isLoading, migrationSource }) => {
+ ({ createResources, apiError, isLoading, migrationSource, onSkip }) => {
const [lookupResources, setLookupResources] = useState([]);
const filePickerRef = useRef(null);
@@ -170,7 +178,18 @@ export const LookupsFileUpload = React.memo(
-
+
+ {onSkip && (
+
+
+ {i18n.SKIP_BUTTON}
+
+
+ )}
({
api: {
getMissingResources: jest.fn(),
},
+ telemetry: {
+ reportSetupLookupNameCopied: jest.fn(),
+ },
},
},
notifications: {
@@ -85,6 +90,23 @@ jest.mock('../../logic/use_start_migration', () => {
};
});
+jest.mock('../../../../common/hooks/use_experimental_features', () => ({
+ useIsExperimentalFeatureEnabled: jest.fn(() => true),
+}));
+
+const mockUseMissingResources = jest.fn();
+jest.mock('../../../common/hooks/use_missing_resources', () => ({
+ useMissingResources: (...args: unknown[]) => mockUseMissingResources(...args),
+}));
+
+jest.mock('../../service/hooks/use_enhance_rules', () => ({
+ useEnhanceRules: () => ({ enhanceRules: jest.fn(), isLoading: false, error: null }),
+}));
+
+jest.mock('../../../../common/hooks/use_app_toasts', () => ({
+ useAppToasts: () => ({ addError: jest.fn(), addSuccess: jest.fn() }),
+}));
+
jest.mock('../../hooks/use_start_rules_migration_modal');
const useStartRulesMigrationModalMock = useStartRulesMigrationModal as jest.MockedFunction<
typeof useStartRulesMigrationModal
@@ -92,6 +114,12 @@ const useStartRulesMigrationModalMock = useStartRulesMigrationModal as jest.Mock
describe('MigrationDataInputFlyout', () => {
beforeEach(() => {
+ mockUseMissingResources.mockReturnValue({
+ missingResourcesIndexed: undefined,
+ onMissingResourcesFetched: jest.fn(),
+ missingResourceCount: 0,
+ });
+
useStartRulesMigrationModalMock.mockImplementation(({ onStartMigrationWithSettings }) => {
return {
modal: (
@@ -271,4 +299,68 @@ describe('MigrationDataInputFlyout', () => {
skipPrebuiltRulesMatching: false,
});
});
+
+ describe('QRadar skip reference set step', () => {
+ const MISSING_LOOKUPS = { macros: [], lookups: ['ref_set_1', 'ref_set_2'] };
+
+ beforeEach(() => {
+ const react = jest.requireActual('react');
+ mockUseMissingResources.mockImplementation(
+ ({
+ handleMissingResourcesIndexed,
+ migrationSource,
+ }: {
+ handleMissingResourcesIndexed?: HandleMissingResourcesIndexed;
+ migrationSource: MigrationSource;
+ }) => {
+ react.useEffect(() => {
+ handleMissingResourcesIndexed?.({
+ migrationSource,
+ newMissingResourcesIndexed: MISSING_LOOKUPS,
+ });
+ }, [handleMissingResourcesIndexed, migrationSource]);
+
+ return {
+ missingResourcesIndexed: MISSING_LOOKUPS,
+ onMissingResourcesFetched: jest.fn(),
+ missingResourceCount: MISSING_LOOKUPS.lookups.length,
+ };
+ }
+ );
+ });
+
+ const qradarMigrationStats = getRuleMigrationStatsMock({
+ id: 'qradar-migration-1',
+ status: SiemMigrationTaskStatus.READY,
+ vendor: MigrationSource.QRADAR,
+ });
+
+ it('advances from Reference Set step to Enhancements step when skip button is clicked', async () => {
+ const { getByTestId, queryByTestId } = render(
+
+
+
+ );
+
+ await waitFor(() => {
+ expect(getByTestId('lookupsUploadSkipButton')).toBeInTheDocument();
+ });
+
+ expect(getByTestId('referenceSetsUploadStepNumber')).toHaveTextContent('Current step is 2');
+ expect(getByTestId('enhancementsStepNumber')).toHaveTextContent('3');
+ expect(queryByTestId('enhancementTypeSelect')).not.toBeInTheDocument();
+
+ fireEvent.click(getByTestId('lookupsUploadSkipButton'));
+
+ await waitFor(() => {
+ expect(getByTestId('enhancementsStepNumber')).toHaveTextContent('Current step is 3');
+ });
+
+ expect(getByTestId('enhancementTypeSelect')).toBeInTheDocument();
+ expect(getByTestId('enhancementFilePicker')).toBeInTheDocument();
+
+ expect(queryByTestId('lookupsUploadSkipButton')).not.toBeInTheDocument();
+ expect(queryByTestId('referenceSetsUploadDescription')).not.toBeInTheDocument();
+ });
+ });
});
diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/reference_set/reference_set_data_input.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/reference_set/reference_set_data_input.test.tsx
index 305d7011f9a62..7b21ffb409a23 100644
--- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/reference_set/reference_set_data_input.test.tsx
+++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/reference_set/reference_set_data_input.test.tsx
@@ -5,7 +5,7 @@
* 2.0.
*/
-import { render } from '@testing-library/react';
+import { fireEvent, render } from '@testing-library/react';
import React from 'react';
import { ReferenceSetDataInput } from './reference_set_data_input';
import { getRuleMigrationStatsMock } from '../../../../__mocks__';
@@ -81,7 +81,7 @@ describe('ReferenceSetDataInput', () => {
);
expect(getByTestId('referenceSetsUploadDescription')).toBeInTheDocument();
expect(getByTestId('referenceSetsUploadDescription')).toHaveTextContent(
- `We've also found reference sets within your rules. To fully translate those rules containing these reference sets, follow the step-by-step guide to export and upload them all.`
+ `We've also found reference sets within your rules. To fully translate those rules containing these reference sets, upload them all`
);
});
@@ -111,4 +111,33 @@ describe('ReferenceSetDataInput', () => {
);
expect(queryByTestId('referenceSetsUploadDescription')).not.toBeInTheDocument();
});
+
+ it('renders skip button when step is current', () => {
+ const { getByTestId } = render(
+
+
+
+ );
+ expect(getByTestId('lookupsUploadSkipButton')).toBeInTheDocument();
+ expect(getByTestId('lookupsUploadSkipButton')).toHaveTextContent('Skip');
+ });
+
+ it('calls setDataInputStep with Enhancements when skip button is clicked', () => {
+ const { getByTestId } = render(
+
+
+
+ );
+ fireEvent.click(getByTestId('lookupsUploadSkipButton'));
+ expect(defaultProps.setDataInputStep).toHaveBeenCalledWith(QradarDataInputStep.Enhancements);
+ });
+
+ it('does not render skip button when step is not current', () => {
+ const { queryByTestId } = render(
+
+
+
+ );
+ expect(queryByTestId('lookupsUploadSkipButton')).not.toBeInTheDocument();
+ });
});
diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/reference_set/reference_set_data_input.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/reference_set/reference_set_data_input.tsx
index fabdbccbade77..baf33d7bdec25 100644
--- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/reference_set/reference_set_data_input.tsx
+++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/reference_set/reference_set_data_input.tsx
@@ -23,7 +23,7 @@ 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 { QradarDataInputStep, type OnResourcesCreated } from '../../types';
+import { QradarDataInputStep } from '../../types';
import * as i18n from './translations';
import { useMissingReferenceSetsListStep } from './sub_steps/missing_reference_set_list';
import { useReferencesFileUploadStep } from './sub_steps/reference_sets_file_upload';
@@ -32,7 +32,7 @@ import { type MigrationStepProps } from '../../../../../common/types';
interface ReferenceSetDataInputSubStepsProps {
migrationStats: RuleMigrationTaskStats;
missingReferenceSet: string[];
- onAllReferenceSetCreated: OnResourcesCreated;
+ onComplete: () => void;
}
export const ReferenceSetDataInput = React.memo(
@@ -41,15 +41,16 @@ export const ReferenceSetDataInput = React.memo(
() => missingResourcesIndexed?.lookups,
[missingResourcesIndexed]
);
- const onAllReferenceSetCreated = useCallback(() => {
- setDataInputStep(QradarDataInputStep.Enhancements);
- }, [setDataInputStep]);
const dataInputStatus = useMemo(
() => getEuiStepStatus(QradarDataInputStep.ReferenceSet, dataInputStep),
[dataInputStep]
);
+ const onComplete = useCallback(() => {
+ setDataInputStep(QradarDataInputStep.Enhancements);
+ }, [setDataInputStep]);
+
return (
@@ -81,7 +82,7 @@ export const ReferenceSetDataInput = React.memo(
>
@@ -96,7 +97,7 @@ ReferenceSetDataInput.displayName = 'ReferenceSetDataInput';
const END = 10 as const;
type SubStep = 1 | 2 | typeof END;
export const ReferenceSetDataInputSubSteps = React.memo(
- ({ migrationStats, missingReferenceSet, onAllReferenceSetCreated }) => {
+ ({ migrationStats, missingReferenceSet, onComplete }) => {
const { telemetry } = useKibana().services.siemMigrations.rules;
const [subStep, setSubStep] = useState(1);
const [uploadedLookups, setUploadedLookups] = useState({});
@@ -111,9 +112,9 @@ export const ReferenceSetDataInputSubSteps = React.memo {
if (missingReferenceSet.every((referenceSet) => uploadedLookups[referenceSet] != null)) {
setSubStep(END);
- onAllReferenceSetCreated();
+ onComplete();
}
- }, [uploadedLookups, missingReferenceSet, onAllReferenceSetCreated]);
+ }, [uploadedLookups, missingReferenceSet, onComplete]);
// Copy query step
const onCopied = useCallback(() => {
@@ -139,6 +140,7 @@ export const ReferenceSetDataInputSubSteps = React.memo(() => [copyStep, uploadStep], [copyStep, uploadStep]);
diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/reference_set/sub_steps/reference_sets_file_upload/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/reference_set/sub_steps/reference_sets_file_upload/index.tsx
index be7e6c5976e1d..eb903f66522e8 100644
--- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/reference_set/sub_steps/reference_sets_file_upload/index.tsx
+++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/reference_set/sub_steps/reference_sets_file_upload/index.tsx
@@ -20,11 +20,13 @@ export interface RulesFileUploadStepProps {
migrationStats: RuleMigrationTaskStats;
missingLookups: string[];
addUploadedLookups: AddUploadedLookups;
+ onSkip?: () => void;
}
export const useReferencesFileUploadStep = ({
status,
migrationStats,
addUploadedLookups,
+ onSkip,
}: RulesFileUploadStepProps): EuiStepProps => {
const { upsertResources, isLoading, error } = useUpsertResources(addUploadedLookups);
@@ -61,6 +63,7 @@ export const useReferencesFileUploadStep = ({
isLoading={isLoading}
apiError={error?.message}
migrationSource={MigrationSource.QRADAR}
+ onSkip={onSkip}
/>
),
};
diff --git a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/reference_set/translations.ts b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/reference_set/translations.ts
index 6312089ea50c3..8b9e627b57b11 100644
--- a/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/reference_set/translations.ts
+++ b/x-pack/solutions/security/plugins/security_solution/public/siem_migrations/rules/components/data_input_flyout/steps/reference_set/translations.ts
@@ -14,6 +14,6 @@ export const REFERENCE_SET_DATA_INPUT_TITLE = i18n.translate(
export const REFERENCE_SET_DATA_INPUT_DESCRIPTION = i18n.translate(
'xpack.securitySolution.siemMigrations.rules.dataInputFlyout.referenceSet.description',
{
- defaultMessage: `We've also found reference sets within your rules. To fully translate those rules containing these reference sets, follow the step-by-step guide to export and upload them all.`,
+ defaultMessage: `We've also found reference sets within your rules. To fully translate those rules containing these reference sets, upload them all.`,
}
);