From 438de58b89c8c30ca7ba222f005cd5e7a391d63d Mon Sep 17 00:00:00 2001 From: Ievgen Sorokopud Date: Wed, 20 Nov 2024 14:05:26 +0100 Subject: [PATCH 1/7] [Rules migration][UI] Basic rule migrations UI (#10820) --- packages/deeplinks/security/deep_links.ts | 1 + .../security_solution/common/constants.ts | 1 + .../public/app/translations.ts | 4 + .../rule_management/api/api.ts | 62 +++++ .../use_get_rule_migrations.ts | 35 +++ .../use_get_rule_migrations_stats_all.ts | 30 +++ .../components/siem_migrations/constants.ts | 11 + .../siem_migrations_header_buttons.tsx | 63 +++++ .../siem_migrations_no_items_message.tsx | 53 ++++ .../siem_migrations/siem_migrations_table.tsx | 95 +++++++ .../siem_migrations_table_context.tsx | 188 +++++++++++++ .../siem_migrations_table_filters.tsx | 80 ++++++ .../status_badge/index.test.tsx | 19 ++ .../siem_migrations/status_badge/index.tsx | 48 ++++ .../translation_details/constants.ts | 9 + .../translation_details_flyout.tsx | 248 ++++++++++++++++++ .../translation_tab/header.tsx | 20 ++ .../translation_tab/index.tsx | 110 ++++++++ .../translation_tab/rule_query.tsx | 49 ++++ .../translation_tab/translations.ts | 43 +++ .../translation_details/translations.ts | 29 ++ .../siem_migrations/translations.ts | 89 +++++++ .../use_filter_siem_migrations_to_install.ts | 39 +++ .../use_siem_migrations_preview_flyout.tsx | 82 ++++++ .../use_siem_migrations_table_columns.tsx | 101 +++++++ .../components/siem_migrations/utils.tsx | 28 ++ .../hooks/use_is_siem_migrations_enabled.tsx | 12 + .../pages/siem_migrations/index.tsx | 70 +++++ .../pages/siem_migrations/translations.tsx | 15 ++ .../security_solution/public/rules/links.ts | 21 ++ .../security_solution/public/rules/routes.tsx | 72 +++-- 31 files changed, 1699 insertions(+), 28 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/siem_migrations/use_get_rule_migrations.ts create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/siem_migrations/use_get_rule_migrations_stats_all.ts create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/constants.ts create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/siem_migrations_header_buttons.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/siem_migrations_no_items_message.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/siem_migrations_table.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/siem_migrations_table_context.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/siem_migrations_table_filters.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/status_badge/index.test.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/status_badge/index.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/constants.ts create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/translation_details_flyout.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/translation_tab/header.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/translation_tab/index.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/translation_tab/rule_query.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/translation_tab/translations.ts create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/translations.ts create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translations.ts create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/use_filter_siem_migrations_to_install.ts create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/use_siem_migrations_preview_flyout.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/use_siem_migrations_table_columns.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/utils.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/hooks/use_is_siem_migrations_enabled.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/siem_migrations/index.tsx create mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/siem_migrations/translations.tsx diff --git a/packages/deeplinks/security/deep_links.ts b/packages/deeplinks/security/deep_links.ts index 644691bd5b8bc..1da816c63ce2f 100644 --- a/packages/deeplinks/security/deep_links.ts +++ b/packages/deeplinks/security/deep_links.ts @@ -69,6 +69,7 @@ export enum SecurityPageName { rulesAdd = 'rules-add', rulesCreate = 'rules-create', rulesLanding = 'rules-landing', + rulesSiemMigrations = 'rules-siem-migrations', /* * Warning: Computed values are not permitted in an enum with string valued members * All threat intelligence page names must match `TIPageId` in x-pack/plugins/threat_intelligence/public/common/navigation/types.ts diff --git a/x-pack/plugins/security_solution/common/constants.ts b/x-pack/plugins/security_solution/common/constants.ts index b366a0e555357..73e9ef7c39589 100644 --- a/x-pack/plugins/security_solution/common/constants.ts +++ b/x-pack/plugins/security_solution/common/constants.ts @@ -98,6 +98,7 @@ export const RULES_LANDING_PATH = `${RULES_PATH}/landing` as const; export const RULES_ADD_PATH = `${RULES_PATH}/add_rules` as const; export const RULES_UPDATES = `${RULES_PATH}/updates` as const; export const RULES_CREATE_PATH = `${RULES_PATH}/create` as const; +export const SIEM_MIGRATIONS_PATH = `${RULES_PATH}/siem_migrations` as const; export const EXCEPTIONS_PATH = '/exceptions' as const; export const EXCEPTION_LIST_DETAIL_PATH = `${EXCEPTIONS_PATH}/details/:detailName` as const; export const HOSTS_PATH = '/hosts' as const; diff --git a/x-pack/plugins/security_solution/public/app/translations.ts b/x-pack/plugins/security_solution/public/app/translations.ts index 709bb5f614f7b..2dae25954c3a9 100644 --- a/x-pack/plugins/security_solution/public/app/translations.ts +++ b/x-pack/plugins/security_solution/public/app/translations.ts @@ -101,6 +101,10 @@ export const EXCEPTIONS = i18n.translate('xpack.securitySolution.navigation.exce defaultMessage: 'Shared exception lists', }); +export const SIEM_MIGRATIONS = i18n.translate('xpack.securitySolution.navigation.siemMigrations', { + defaultMessage: 'SIEM Rules Migrations', +}); + export const ALERTS = i18n.translate('xpack.securitySolution.navigation.alerts', { defaultMessage: 'Alerts', }); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts index aea4b6672659e..b7d4b59cc54bb 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts @@ -13,6 +13,15 @@ import { INTERNAL_ALERTING_API_FIND_RULES_PATH } from '@kbn/alerting-plugin/comm import { BASE_ACTION_API_PATH } from '@kbn/actions-plugin/common'; import type { ActionType, AsApiContract } from '@kbn/actions-plugin/common'; import type { ActionResult } from '@kbn/actions-plugin/server'; +import { replaceParams } from '@kbn/openapi-common/shared'; +import type { + GetAllStatsRuleMigrationResponse, + GetRuleMigrationResponse, +} from '../../../../common/siem_migrations/model/api/rules/rule_migration.gen'; +import { + SIEM_RULE_MIGRATIONS_ALL_STATS_PATH, + SIEM_RULE_MIGRATION_PATH, +} from '../../../../common/siem_migrations/constants'; import { convertRulesFilterToKQL } from '../../../../common/detection_engine/rule_management/rule_filtering'; import type { UpgradeSpecificRulesRequest, @@ -698,3 +707,56 @@ export const bootstrapPrebuiltRules = async (): Promise => + KibanaServices.get().http.fetch( + SIEM_RULE_MIGRATIONS_ALL_STATS_PATH, + { + method: 'GET', + version: '1', + signal, + } + ); + +/** + * Retrieves all the migration rule documents of a specific migration. + * + * @param migrationId `id` of the migration to retrieve rule documents for + * @param signal AbortSignal for cancelling request + * + * @throws An error if response is not OK + */ +export const getRuleMigrations = async ({ + migrationId, + signal, +}: { + migrationId?: string; + signal: AbortSignal | undefined; +}): Promise => { + if (!migrationId) { + return []; + } + return KibanaServices.get().http.fetch( + replaceParams(SIEM_RULE_MIGRATION_PATH, { migration_id: migrationId }), + { + method: 'GET', + version: '1', + signal, + } + ); +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/siem_migrations/use_get_rule_migrations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/siem_migrations/use_get_rule_migrations.ts new file mode 100644 index 0000000000000..a295c376c30e3 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/siem_migrations/use_get_rule_migrations.ts @@ -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 type { UseQueryOptions } from '@tanstack/react-query'; +import { useQuery } from '@tanstack/react-query'; +import { replaceParams } from '@kbn/openapi-common/shared'; +import type { GetRuleMigrationResponse } from '../../../../../../common/siem_migrations/model/api/rules/rule_migration.gen'; +import { SIEM_RULE_MIGRATION_PATH } from '../../../../../../common/siem_migrations/constants'; +import { getRuleMigrations } from '../../api'; +import { DEFAULT_QUERY_OPTIONS } from '../constants'; + +export const useGetRuleMigrationsQuery = ( + migrationId?: string, + options?: UseQueryOptions +) => { + const SPECIFIC_MIGRATION_PATH = migrationId + ? replaceParams(SIEM_RULE_MIGRATION_PATH, { + migration_id: migrationId, + }) + : SIEM_RULE_MIGRATION_PATH; + return useQuery( + ['GET', SPECIFIC_MIGRATION_PATH], + async ({ signal }) => { + return getRuleMigrations({ migrationId, signal }); + }, + { + ...DEFAULT_QUERY_OPTIONS, + ...options, + } + ); +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/siem_migrations/use_get_rule_migrations_stats_all.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/siem_migrations/use_get_rule_migrations_stats_all.ts new file mode 100644 index 0000000000000..bb87f874632ec --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/siem_migrations/use_get_rule_migrations_stats_all.ts @@ -0,0 +1,30 @@ +/* + * 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 { UseQueryOptions } from '@tanstack/react-query'; +import { useQuery } from '@tanstack/react-query'; +import type { GetAllStatsRuleMigrationResponse } from '../../../../../../common/siem_migrations/model/api/rules/rule_migration.gen'; +import { SIEM_RULE_MIGRATIONS_ALL_STATS_PATH } from '../../../../../../common/siem_migrations/constants'; +import { getRuleMigrationsStatsAll } from '../../api'; +import { DEFAULT_QUERY_OPTIONS } from '../constants'; + +export const GET_RULE_MIGRATIONS_STATS_ALL_QUERY_KEY = ['GET', SIEM_RULE_MIGRATIONS_ALL_STATS_PATH]; + +export const useGetRuleMigrationsStatsAllQuery = ( + options?: UseQueryOptions +) => { + return useQuery( + GET_RULE_MIGRATIONS_STATS_ALL_QUERY_KEY, + async ({ signal }) => { + return getRuleMigrationsStatsAll({ signal }); + }, + { + ...DEFAULT_QUERY_OPTIONS, + ...options, + } + ); +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/constants.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/constants.ts new file mode 100644 index 0000000000000..7400d4b0bcb63 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/constants.ts @@ -0,0 +1,11 @@ +/* + * 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 { Severity } from '@kbn/securitysolution-io-ts-alerting-types'; + +export const DEFAULT_TRANSLATION_RISK_SCORE = 21; +export const DEFAULT_TRANSLATION_SEVERITY: Severity = 'low'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/siem_migrations_header_buttons.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/siem_migrations_header_buttons.tsx new file mode 100644 index 0000000000000..80ed7eb8983ee --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/siem_migrations_header_buttons.tsx @@ -0,0 +1,63 @@ +/* + * 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 { EuiComboBoxOptionOption } from '@elastic/eui'; +import { EuiComboBox, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import React, { useMemo } from 'react'; +import { useSiemMigrationsTableContext } from './siem_migrations_table_context'; +import * as i18n from './translations'; + +export const SiemMigrationsHeaderButtons = () => { + const { + state: { migrationsIds, selectedMigrationId }, + actions: { onMigrationIdChange }, + } = useSiemMigrationsTableContext(); + + const migrationOptions = useMemo(() => { + const options: Array> = migrationsIds.map((id, index) => ({ + value: id, + 'data-test-subj': `migrationSelectionOption-${index}`, + label: i18n.SIEM_MIGRATIONS_OPTION_LABEL(index + 1), + })); + return options; + }, [migrationsIds]); + const selectedMigrationOption = useMemo>>(() => { + const index = migrationsIds.findIndex((id) => id === selectedMigrationId); + return index !== -1 + ? [ + { + value: selectedMigrationId, + 'data-test-subj': `migrationSelectionOption-${index}`, + label: i18n.SIEM_MIGRATIONS_OPTION_LABEL(index + 1), + }, + ] + : []; + }, [migrationsIds, selectedMigrationId]); + + const onChange = (selected: Array>) => { + onMigrationIdChange(selected[0].value); + }; + + if (!migrationsIds.length) { + return null; + } + + return ( + + + + + + ); +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/siem_migrations_no_items_message.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/siem_migrations_no_items_message.tsx new file mode 100644 index 0000000000000..291fe8e49f400 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/siem_migrations_no_items_message.tsx @@ -0,0 +1,53 @@ +/* + * 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 { EuiButton, EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import React from 'react'; +import { SecurityPageName } from '../../../../../common'; +import { useGetSecuritySolutionLinkProps } from '../../../../common/components/links'; +import * as i18n from './translations'; + +const SiemMigrationsTableNoItemsMessageComponent = () => { + const getSecuritySolutionLinkProps = useGetSecuritySolutionLinkProps(); + const { onClick: onClickLink } = getSecuritySolutionLinkProps({ + deepLinkId: SecurityPageName.rules, + }); + + return ( + + + {i18n.NO_TRANSLATIONS_AVAILABLE_FOR_INSTALL}} + titleSize="s" + body={i18n.NO_TRANSLATIONS_AVAILABLE_FOR_INSTALL_BODY} + data-test-subj="noRulesTranslationAvailableForInstall" + /> + + + + {i18n.GO_BACK_TO_RULES_TABLE_BUTTON} + + + + ); +}; + +export const SiemMigrationsTableNoItemsMessage = React.memo( + SiemMigrationsTableNoItemsMessageComponent +); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/siem_migrations_table.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/siem_migrations_table.tsx new file mode 100644 index 0000000000000..79769fcb3d461 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/siem_migrations_table.tsx @@ -0,0 +1,95 @@ +/* + * 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 { + EuiInMemoryTable, + EuiSkeletonLoading, + EuiProgress, + EuiSkeletonTitle, + EuiSkeletonText, + EuiFlexGroup, + EuiFlexItem, +} from '@elastic/eui'; +import React from 'react'; + +import { + RULES_TABLE_INITIAL_PAGE_SIZE, + RULES_TABLE_PAGE_SIZE_OPTIONS, +} from '../rules_table/constants'; +import { SiemMigrationsTableNoItemsMessage } from './siem_migrations_no_items_message'; +import { useSiemMigrationsTableContext } from './siem_migrations_table_context'; +import { SiemMigrationsTableFilters } from './siem_migrations_table_filters'; +import { useSiemMigrationsTableColumns } from './use_siem_migrations_table_columns'; + +/** + * Table Component for displaying SIEM rules migrations + */ +export const SiemMigrationsTable = React.memo(() => { + const siemMigrationsTableContext = useSiemMigrationsTableContext(); + + const { + state: { ruleMigrations, isLoading, selectedRuleMigrations }, + actions: { selectRuleMigrations }, + } = siemMigrationsTableContext; + const rulesColumns = useSiemMigrationsTableColumns(); + + const shouldShowProgress = isLoading; + + return ( + <> + {shouldShowProgress && ( + + )} + + + + + } + loadedContent={ + !ruleMigrations.length ? ( + + ) : ( + <> + + + + + + + true, + onSelectionChange: selectRuleMigrations, + initialSelected: selectedRuleMigrations, + }} + itemId="rule_id" + data-test-subj="rules-translation-table" + columns={rulesColumns} + /> + + ) + } + /> + + ); +}); + +SiemMigrationsTable.displayName = 'SiemMigrationsTable'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/siem_migrations_table_context.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/siem_migrations_table_context.tsx new file mode 100644 index 0000000000000..8b66dbd4a8485 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/siem_migrations_table_context.tsx @@ -0,0 +1,188 @@ +/* + * 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 { Dispatch, SetStateAction } from 'react'; +import React, { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react'; +import type { RuleMigration } from '../../../../../common/siem_migrations/model/rule_migration.gen'; +import { useGetRuleMigrationsStatsAllQuery } from '../../../rule_management/api/hooks/siem_migrations/use_get_rule_migrations_stats_all'; +import { useGetRuleMigrationsQuery } from '../../../rule_management/api/hooks/siem_migrations/use_get_rule_migrations'; +import type { RuleSignatureId } from '../../../../../common/api/detection_engine'; +import { invariant } from '../../../../../common/utils/invariant'; +import type { SiemMigrationsTableFilterOptions } from './use_filter_siem_migrations_to_install'; +import { useFilterSiemMigrationsToInstall } from './use_filter_siem_migrations_to_install'; +import { useSiemMigrationsPreviewFlyout } from './use_siem_migrations_preview_flyout'; + +export interface SiemMigrationsTableState { + /** + * Available rule migrations ids + */ + migrationsIds: string[]; + /** + * Selected rule migration id + */ + selectedMigrationId: string | undefined; + /** + * Rule migrations available after applying `filterOptions` + */ + ruleMigrations: RuleMigration[]; + /** + * Currently selected table filter + */ + filterOptions: SiemMigrationsTableFilterOptions; + /** + * All unique tags for all rule translations + */ + tags: string[]; + /** + * If true then there is no cached data and the query is currently fetching. + */ + isLoading: boolean; + /** + * Rule rows selected in EUI InMemory Table + */ + selectedRuleMigrations: RuleMigration[]; +} + +export interface SiemMigrationsTableActions { + setFilterOptions: Dispatch>; + selectRuleMigrations: (rules: RuleMigration[]) => void; + openRuleTranslationPreview: (ruleId: RuleSignatureId) => void; + onMigrationIdChange: (selectedId?: string) => void; +} + +export interface SiemMigrationsContextType { + state: SiemMigrationsTableState; + actions: SiemMigrationsTableActions; +} + +const SiemMigrationsTableContext = createContext(null); + +interface SiemMigrationsTableContextProviderProps { + children: React.ReactNode; +} + +const SIEM_MIGRATIONS_INSTALL_FLYOUT_ANCHOR = 'installSiemMigrationsPreview'; + +export const SiemMigrationsTableContextProvider = ({ + children, +}: SiemMigrationsTableContextProviderProps) => { + const [selectedRuleMigrations, setSelectedRuleMigrations] = useState([]); + + const [filterOptions, setFilterOptions] = useState({ + filter: '', + tags: [], + }); + + const { data: ruleMigrationsStatsAll, isLoading: isLoadingMigrationsStats } = + useGetRuleMigrationsStatsAllQuery(); + const migrationsIds = useMemo(() => { + if (isLoadingMigrationsStats || !ruleMigrationsStatsAll?.length) { + return []; + } + return ruleMigrationsStatsAll + .filter((migration) => migration.status === 'finished') + .map((migration) => migration.migration_id); + }, [isLoadingMigrationsStats, ruleMigrationsStatsAll]); + + const [selectedMigrationId, setSelectedMigrationId] = useState(); + const onMigrationIdChange = (selectedId?: string) => { + setSelectedMigrationId(selectedId); + }; + + useEffect(() => { + if (!migrationsIds.length) { + return; + } + const index = migrationsIds.findIndex((id) => id === selectedMigrationId); + if (index === -1) { + setSelectedMigrationId(migrationsIds[0]); + } + }, [migrationsIds, selectedMigrationId]); + + const { data: ruleMigrations, isLoading: isLoadingRuleMigrations } = + useGetRuleMigrationsQuery(selectedMigrationId); + + const filteredRuleMigrations = useFilterSiemMigrationsToInstall({ + filterOptions, + ruleMigrations: ruleMigrations ?? [], + }); + + const tags = useMemo(() => [], []); + + const ruleActionsFactory = useCallback( + (ruleMigration: RuleMigration, closeRuleMigrationPreview: () => void) => { + // TODO: Add flyout action buttons + return null; + }, + [] + ); + + const { ruleMigrationPreviewFlyout, openRuleTranslationPreview } = useSiemMigrationsPreviewFlyout( + { + ruleMigrations: filteredRuleMigrations, + ruleActionsFactory, + flyoutProps: { + id: SIEM_MIGRATIONS_INSTALL_FLYOUT_ANCHOR, + dataTestSubj: SIEM_MIGRATIONS_INSTALL_FLYOUT_ANCHOR, + }, + } + ); + + const actions = useMemo( + () => ({ + setFilterOptions, + selectRuleMigrations: setSelectedRuleMigrations, + openRuleTranslationPreview, + onMigrationIdChange, + }), + [openRuleTranslationPreview] + ); + + const providerValue = useMemo(() => { + return { + state: { + migrationsIds, + selectedMigrationId, + ruleMigrations: filteredRuleMigrations, + filterOptions, + tags, + isLoading: isLoadingMigrationsStats || isLoadingRuleMigrations, + selectedRuleMigrations, + }, + actions, + }; + }, [ + migrationsIds, + selectedMigrationId, + filteredRuleMigrations, + filterOptions, + tags, + isLoadingMigrationsStats, + isLoadingRuleMigrations, + selectedRuleMigrations, + actions, + ]); + + return ( + + <> + {children} + {ruleMigrationPreviewFlyout} + + + ); +}; + +export const useSiemMigrationsTableContext = (): SiemMigrationsContextType => { + const rulesTableContext = useContext(SiemMigrationsTableContext); + invariant( + rulesTableContext, + 'useSiemMigrationsTableContext should be used inside SiemMigrationsTableContextProvider' + ); + + return rulesTableContext; +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/siem_migrations_table_filters.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/siem_migrations_table_filters.tsx new file mode 100644 index 0000000000000..a8e3f6764d2b5 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/siem_migrations_table_filters.tsx @@ -0,0 +1,80 @@ +/* + * 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 { EuiFilterGroup, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { isEqual } from 'lodash/fp'; +import React, { useCallback } from 'react'; +import styled from 'styled-components'; +import * as i18n from './translations'; +import { TagsFilterPopover } from '../rules_table/rules_table_filters/tags_filter_popover'; +import { RuleSearchField } from '../rules_table/rules_table_filters/rule_search_field'; +import { useSiemMigrationsTableContext } from './siem_migrations_table_context'; + +const FilterWrapper = styled(EuiFlexGroup)` + margin-bottom: ${({ theme }) => theme.eui.euiSizeM}; +`; + +/** + * Collection of filters for filtering data within the SIEM Rules Migrations table. + * Contains search bar and tag selection + */ +const SiemMigrationsTableFiltersComponent = () => { + const { + state: { filterOptions, tags }, + actions: { setFilterOptions }, + } = useSiemMigrationsTableContext(); + + const { tags: selectedTags } = filterOptions; + + const handleOnSearch = useCallback( + (filterString: string) => { + setFilterOptions((filters) => ({ + ...filters, + filter: filterString.trim(), + })); + }, + [setFilterOptions] + ); + + const handleSelectedTags = useCallback( + (newTags: string[]) => { + if (!isEqual(newTags, selectedTags)) { + setFilterOptions((filters) => ({ + ...filters, + tags: newTags, + })); + } + }, + [selectedTags, setFilterOptions] + ); + + return ( + + + + + + + + + ); +}; + +SiemMigrationsTableFiltersComponent.displayName = 'SiemMigrationsTableFiltersComponent'; + +export const SiemMigrationsTableFilters = React.memo(SiemMigrationsTableFiltersComponent); + +SiemMigrationsTableFilters.displayName = 'SiemMigrationsTableFilters'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/status_badge/index.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/status_badge/index.test.tsx new file mode 100644 index 0000000000000..aaf256cfb60b5 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/status_badge/index.test.tsx @@ -0,0 +1,19 @@ +/* + * 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 { shallow } from 'enzyme'; + +import { StatusBadge } from '.'; + +describe('StatusBadge', () => { + it('renders correctly', () => { + const wrapper = shallow(); + + expect(wrapper.find('HealthTruncateText')).toHaveLength(1); + }); +}); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/status_badge/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/status_badge/index.tsx new file mode 100644 index 0000000000000..1088805c127f2 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/status_badge/index.tsx @@ -0,0 +1,48 @@ +/* + * 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 { euiLightVars } from '@kbn/ui-theme'; + +import type { RuleMigrationTranslationResult } from '../../../../../../common/siem_migrations/model/rule_migration.gen'; +import { HealthTruncateText } from '../../../../../common/components/health_truncate_text'; +import { convertTranslationResultIntoText } from '../utils'; + +const { euiColorVis0, euiColorVis7, euiColorVis9 } = euiLightVars; +const statusToColorMap: Record = { + full: euiColorVis0, + partial: euiColorVis7, + untranslatable: euiColorVis9, +}; + +interface Props { + value?: RuleMigrationTranslationResult; + installedRuleId?: string; + 'data-test-subj'?: string; +} + +const StatusBadgeComponent: React.FC = ({ + value, + installedRuleId, + 'data-test-subj': dataTestSubj = 'translation-result', +}) => { + const translationResult = installedRuleId || !value ? 'full' : value; + const displayValue = convertTranslationResultIntoText(translationResult); + const color = statusToColorMap[translationResult]; + + return ( + + {displayValue} + + ); +}; + +export const StatusBadge = React.memo(StatusBadgeComponent); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/constants.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/constants.ts new file mode 100644 index 0000000000000..4d6bcd542b866 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/constants.ts @@ -0,0 +1,9 @@ +/* + * 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 const DEFAULT_DESCRIPTION_LIST_COLUMN_WIDTHS: [string, string] = ['50%', '50%']; +export const LARGE_DESCRIPTION_LIST_COLUMN_WIDTHS: [string, string] = ['30%', '70%']; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/translation_details_flyout.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/translation_details_flyout.tsx new file mode 100644 index 0000000000000..3a0793a320ebc --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/translation_details_flyout.tsx @@ -0,0 +1,248 @@ +/* + * 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 { FC, PropsWithChildren } from 'react'; +import React, { useMemo, useState, useEffect } from 'react'; +import styled from 'styled-components'; +import { css } from '@emotion/css'; +import { euiThemeVars } from '@kbn/ui-theme'; +import { + EuiButtonEmpty, + EuiTitle, + EuiFlyout, + EuiFlyoutHeader, + EuiFlyoutBody, + EuiFlyoutFooter, + EuiTabbedContent, + EuiSpacer, + EuiFlexGroup, + EuiFlexItem, + useGeneratedHtmlId, +} from '@elastic/eui'; +import type { EuiTabbedContentTab, EuiTabbedContentProps, EuiFlyoutProps } from '@elastic/eui'; + +import type { RuleMigration } from '../../../../../../common/siem_migrations/model/rule_migration.gen'; +import { + RuleOverviewTab, + useOverviewTabSections, +} from '../../../../rule_management/components/rule_details/rule_overview_tab'; +import { + type RuleResponse, + type Severity, +} from '../../../../../../common/api/detection_engine/model/rule_schema'; + +import * as i18n from './translations'; +import { + DEFAULT_DESCRIPTION_LIST_COLUMN_WIDTHS, + LARGE_DESCRIPTION_LIST_COLUMN_WIDTHS, +} from './constants'; +import { TranslationTab } from './translation_tab'; +import { DEFAULT_TRANSLATION_RISK_SCORE, DEFAULT_TRANSLATION_SEVERITY } from '../constants'; + +const StyledEuiFlyoutBody = styled(EuiFlyoutBody)` + .euiFlyoutBody__overflow { + display: flex; + flex: 1; + overflow: hidden; + + .euiFlyoutBody__overflowContent { + flex: 1; + overflow: hidden; + padding: ${({ theme }) => `0 ${theme.eui.euiSizeL} 0`}; + } + } +`; + +const StyledFlexGroup = styled(EuiFlexGroup)` + height: 100%; +`; + +const StyledEuiFlexItem = styled(EuiFlexItem)` + &.euiFlexItem { + flex: 1 0 0; + overflow: hidden; + } +`; + +const StyledEuiTabbedContent = styled(EuiTabbedContent)` + display: flex; + flex: 1; + flex-direction: column; + overflow: hidden; + + > [role='tabpanel'] { + display: flex; + flex: 1; + flex-direction: column; + overflow: hidden; + overflow-y: auto; + + ::-webkit-scrollbar { + -webkit-appearance: none; + width: 7px; + } + + ::-webkit-scrollbar-thumb { + border-radius: 4px; + background-color: rgba(0, 0, 0, 0.5); + -webkit-box-shadow: 0 0 1px rgba(255, 255, 255, 0.5); + } + } +`; + +/* + * Fixes tabs to the top and allows the content to scroll. + */ +const ScrollableFlyoutTabbedContent = (props: EuiTabbedContentProps) => ( + + + + + +); + +const tabPaddingClassName = css` + padding: 0 ${euiThemeVars.euiSizeM} ${euiThemeVars.euiSizeXL} ${euiThemeVars.euiSizeM}; +`; + +export const TabContentPadding: FC> = ({ children }) => ( +
{children}
+); + +interface TranslationDetailsFlyoutProps { + ruleActions?: React.ReactNode; + ruleMigration: RuleMigration; + size?: EuiFlyoutProps['size']; + extraTabs?: EuiTabbedContentTab[]; + dataTestSubj?: string; + id?: string; + closeFlyout: () => void; +} + +export const TranslationDetailsFlyout = ({ + ruleActions, + ruleMigration, + size = 'm', + extraTabs = [], + dataTestSubj, + id, + closeFlyout, +}: TranslationDetailsFlyoutProps) => { + const { expandedOverviewSections, toggleOverviewSection } = useOverviewTabSections(); + + const rule: RuleResponse = useMemo(() => { + const esqlLanguage = ruleMigration.elastic_rule?.query_language ?? 'esql'; + return { + type: esqlLanguage, + language: esqlLanguage, + name: ruleMigration.elastic_rule?.title, + description: ruleMigration.elastic_rule?.description, + query: ruleMigration.elastic_rule?.query, + + // Default values + severity: (ruleMigration.elastic_rule?.severity as Severity) ?? DEFAULT_TRANSLATION_SEVERITY, + risk_score: DEFAULT_TRANSLATION_RISK_SCORE, + from: 'now-360s', + to: 'now', + interval: '5m', + } as RuleResponse; // TODO: we need to adjust RuleOverviewTab to allow partial RuleResponse as a parameter + }, [ruleMigration]); + + const translationTab: EuiTabbedContentTab = useMemo( + () => ({ + id: 'translation', + name: i18n.TRANSLATION_TAB_LABEL, + content: ( + + + + ), + }), + [ruleMigration] + ); + + const overviewTab: EuiTabbedContentTab = useMemo( + () => ({ + id: 'overview', + name: i18n.OVERVIEW_TAB_LABEL, + content: ( + + + + ), + }), + [rule, size, expandedOverviewSections, toggleOverviewSection] + ); + + const tabs = useMemo(() => { + return [...extraTabs, translationTab, overviewTab]; + }, [extraTabs, translationTab, overviewTab]); + + const [selectedTabId, setSelectedTabId] = useState(tabs[0].id); + const selectedTab = tabs.find((tab) => tab.id === selectedTabId) ?? tabs[0]; + + useEffect(() => { + if (!tabs.find((tab) => tab.id === selectedTabId)) { + // Switch to first tab if currently selected tab is not available for this rule + setSelectedTabId(tabs[0].id); + } + }, [tabs, selectedTabId]); + + const onTabClick = (tab: EuiTabbedContentTab) => { + setSelectedTabId(tab.id); + }; + + const migrationsRulesFlyoutTitleId = useGeneratedHtmlId({ + prefix: 'migrationRulesFlyoutTitle', + }); + + return ( + + + +

{rule.name}

+
+ +
+ + + + + + + + {i18n.DISMISS_BUTTON_LABEL} + + + {ruleActions} + + +
+ ); +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/translation_tab/header.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/translation_tab/header.tsx new file mode 100644 index 0000000000000..57e99440e60a1 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/translation_tab/header.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 React from 'react'; +import { EuiFlexGroup, EuiTitle } from '@elastic/eui'; +import * as i18n from './translations'; + +export function TranslationTabHeader(): JSX.Element { + return ( + + +
{i18n.TAB_HEADER_TITLE}
+
+
+ ); +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/translation_tab/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/translation_tab/index.tsx new file mode 100644 index 0000000000000..5772b737e227b --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/translation_tab/index.tsx @@ -0,0 +1,110 @@ +/* + * 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 { + EuiAccordion, + EuiBadge, + EuiFieldText, + EuiFlexGroup, + EuiFlexItem, + EuiFormRow, + EuiSpacer, + EuiSplitPanel, + EuiTitle, + useEuiTheme, +} from '@elastic/eui'; +import { css } from '@emotion/css'; +import { FormattedMessage } from '@kbn/i18n-react'; +import type { RuleMigration } from '../../../../../../../common/siem_migrations/model/rule_migration.gen'; +import { TranslationTabHeader } from './header'; +import { RuleQueryComponent } from './rule_query'; +import * as i18n from './translations'; +import { convertTranslationResultIntoText } from '../../utils'; + +interface TranslationTabProps { + ruleMigration: RuleMigration; +} + +export const TranslationTab = ({ ruleMigration }: TranslationTabProps) => { + const { euiTheme } = useEuiTheme(); + + const name = ruleMigration.elastic_rule?.title ?? ruleMigration.original_rule.title; + const originalQuery = ruleMigration.original_rule.query; + const elasticQuery = ruleMigration.elastic_rule?.query ?? 'Prebuilt rule query'; + + return ( + <> + + + + + + } + initialIsOpen={true} + > + + + + + + + +

+ +

+
+
+ + {}} + onClickAriaLabel={'Click to update translation status'} + > + {convertTranslationResultIntoText(ruleMigration.translation_result)} + + +
+
+ + + + + + + + + + + +
+
+
+ + ); +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/translation_tab/rule_query.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/translation_tab/rule_query.tsx new file mode 100644 index 0000000000000..ee66cf0f0be8d --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/translation_tab/rule_query.tsx @@ -0,0 +1,49 @@ +/* + * 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, { useMemo } from 'react'; +import { EuiMarkdownEditor, EuiMarkdownFormat, EuiTitle } from '@elastic/eui'; +import { SideHeader } from '../../../../../rule_management/components/rule_details/three_way_diff/components/side_header'; +import { FinalSideHelpInfo } from '../../../../../rule_management/components/rule_details/three_way_diff/final_side/final_side_help_info'; +import * as i18n from './translations'; + +interface RuleQueryProps { + title: string; + query: string; + canEdit?: boolean; +} + +export const RuleQueryComponent = ({ title, query, canEdit }: RuleQueryProps) => { + const queryTextComponent = useMemo(() => { + if (canEdit) { + return ( + {}} + height={400} + initialViewMode={'viewing'} + /> + ); + } else { + return {query}; + } + }, [canEdit, query]); + return ( + <> + + +

+ {title} + +

+
+
+ {queryTextComponent} + + ); +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/translation_tab/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/translation_tab/translations.ts new file mode 100644 index 0000000000000..782c1fba8a1bb --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/translation_tab/translations.ts @@ -0,0 +1,43 @@ +/* + * 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 TAB_HEADER_TITLE = i18n.translate( + 'xpack.securitySolution.detectionEngine.translationDetails.translationTab.title', + { + defaultMessage: 'Translation', + } +); + +export const NAME_LABEL = i18n.translate( + 'xpack.securitySolution.detectionEngine.translationDetails.translationTab.nameLabel', + { + defaultMessage: 'Name', + } +); + +export const SPLUNK_QUERY_TITLE = i18n.translate( + 'xpack.securitySolution.detectionEngine.translationDetails.translationTab.splunkQueryTitle', + { + defaultMessage: 'Splunk query', + } +); + +export const ESQL_TRANSLATION_TITLE = i18n.translate( + 'xpack.securitySolution.detectionEngine.translationDetails.translationTab.esqlTranslationTitle', + { + defaultMessage: 'ES|QL translation', + } +); + +export const TRANSLATED_QUERY_AREAL_LABEL = i18n.translate( + 'xpack.securitySolution.detectionEngine.translationDetails.translationTab.queryArealLabel', + { + defaultMessage: 'Translated query', + } +); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/translations.ts new file mode 100644 index 0000000000000..fe5ca4700a301 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/translations.ts @@ -0,0 +1,29 @@ +/* + * 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 OVERVIEW_TAB_LABEL = i18n.translate( + 'xpack.securitySolution.detectionEngine.translationDetails.overviewTabLabel', + { + defaultMessage: 'Overview', + } +); + +export const TRANSLATION_TAB_LABEL = i18n.translate( + 'xpack.securitySolution.detectionEngine.translationDetails.translationTabLabel', + { + defaultMessage: 'Translation', + } +); + +export const DISMISS_BUTTON_LABEL = i18n.translate( + 'xpack.securitySolution.detectionEngine.translationDetails.dismissButtonLabel', + { + defaultMessage: 'Dismiss', + } +); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translations.ts new file mode 100644 index 0000000000000..60d4662f90646 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translations.ts @@ -0,0 +1,89 @@ +/* + * 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 SEARCH_PLACEHOLDER = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.siemMigrations.searchBarPlaceholder', + { + defaultMessage: 'Search by rule name', + } +); + +export const SIEM_TRANSLATION_RESULT_FULL_LABEL = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.siemMigrations.translationResult.full', + { + defaultMessage: 'Fully translated', + } +); + +export const SIEM_TRANSLATION_RESULT_PARTIAL_LABEL = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.siemMigrations.translationResult.partially', + { + defaultMessage: 'Partially translated', + } +); + +export const SIEM_TRANSLATION_RESULT_UNTRANSLATABLE_LABEL = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.siemMigrations.translationResult.untranslatable', + { + defaultMessage: 'Not translated', + } +); + +export const SIEM_TRANSLATION_RESULT_UNKNOWN_LABEL = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.siemMigrations.translationResult.unknown', + { + defaultMessage: 'Unknown', + } +); + +export const NO_TRANSLATIONS_AVAILABLE_FOR_INSTALL = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.siemMigrations.noRulesTitle', + { + defaultMessage: 'Empty migration', + } +); + +export const NO_TRANSLATIONS_AVAILABLE_FOR_INSTALL_BODY = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.siemMigrations.noRulesBodyTitle', + { + defaultMessage: 'There are no translations available for installation', + } +); + +export const GO_BACK_TO_RULES_TABLE_BUTTON = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.siemMigrations.goToMigrationsPageButton', + { + defaultMessage: 'Go back to SIEM Migrations', + } +); + +export const COLUMN_STATUS = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.siemMigrations.columns.statusTitle', + { + defaultMessage: 'Status', + } +); + +export const SIEM_MIGRATIONS_OPTION_AREAL_LABEL = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.siemMigrations.selectionOption.arealLabel', + { + defaultMessage: 'Select a migration', + } +); + +export const SIEM_MIGRATIONS_OPTION_LABEL = (optionIndex: number) => + i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.siemMigrations.selectionOption.title', + { + defaultMessage: 'SIEM rule migration {optionIndex}', + values: { + optionIndex, + }, + } + ); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/use_filter_siem_migrations_to_install.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/use_filter_siem_migrations_to_install.ts new file mode 100644 index 0000000000000..ef9f4a7369dc6 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/use_filter_siem_migrations_to_install.ts @@ -0,0 +1,39 @@ +/* + * 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 { useMemo } from 'react'; +import type { RuleMigration } from '../../../../../common/siem_migrations/model/rule_migration.gen'; +import type { FilterOptions } from '../../../rule_management/logic/types'; + +export type SiemMigrationsTableFilterOptions = Pick; + +export const useFilterSiemMigrationsToInstall = ({ + ruleMigrations, + filterOptions, +}: { + ruleMigrations: RuleMigration[]; + filterOptions: SiemMigrationsTableFilterOptions; +}) => { + const filteredRules = useMemo(() => { + const { filter, tags } = filterOptions; + return ruleMigrations.filter((migration) => { + const name = migration.elastic_rule?.title ?? migration.original_rule.title; + if (filter && !name.toLowerCase().includes(filter.toLowerCase())) { + return false; + } + + if (tags && tags.length > 0) { + // TODO: Uncomment this once tags are available for rule migrations + // return tags.every((tag) => migration.tags.includes(tag)); + } + + return true; + }); + }, [filterOptions, ruleMigrations]); + + return filteredRules; +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/use_siem_migrations_preview_flyout.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/use_siem_migrations_preview_flyout.tsx new file mode 100644 index 0000000000000..ede9acad5798a --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/use_siem_migrations_preview_flyout.tsx @@ -0,0 +1,82 @@ +/* + * 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 { ReactNode } from 'react'; +import React, { useCallback, useState, useMemo } from 'react'; +import type { EuiTabbedContentTab } from '@elastic/eui'; +import type { RuleMigration } from '../../../../../common/siem_migrations/model/rule_migration.gen'; +import { invariant } from '../../../../../common/utils/invariant'; +import type { RuleSignatureId } from '../../../../../common/api/detection_engine'; +import { TranslationDetailsFlyout } from './translation_details/translation_details_flyout'; + +interface UseSiemMigrationsPreviewFlyoutParams { + ruleMigrations: RuleMigration[]; + ruleActionsFactory: ( + ruleMigration: RuleMigration, + closeRuleMigrationPreview: () => void + ) => ReactNode; + extraTabsFactory?: (ruleMigration: RuleMigration) => EuiTabbedContentTab[]; + flyoutProps: SiemMigrationsPreviewFlyoutProps; +} + +interface SiemMigrationsPreviewFlyoutProps { + /** + * Rule preview flyout unique id used in HTML + */ + id: string; + dataTestSubj: string; +} + +interface UseSiemMigrationsPreviewFlyoutResult { + ruleMigrationPreviewFlyout: ReactNode; + openRuleTranslationPreview: (ruleId: RuleSignatureId) => void; + closeRuleMigrationPreview: () => void; +} + +export function useSiemMigrationsPreviewFlyout({ + ruleMigrations, + extraTabsFactory, + ruleActionsFactory, + flyoutProps, +}: UseSiemMigrationsPreviewFlyoutParams): UseSiemMigrationsPreviewFlyoutResult { + const [ruleMigration, setRuleMigrationForPreview] = useState(); + const closeRuleMigrationPreview = useCallback(() => setRuleMigrationForPreview(undefined), []); + const ruleActions = useMemo( + () => ruleMigration && ruleActionsFactory(ruleMigration, closeRuleMigrationPreview), + [ruleMigration, ruleActionsFactory, closeRuleMigrationPreview] + ); + const extraTabs = useMemo( + () => (ruleMigration && extraTabsFactory ? extraTabsFactory(ruleMigration) : []), + [ruleMigration, extraTabsFactory] + ); + + return { + ruleMigrationPreviewFlyout: ruleMigration && ( + + ), + openRuleTranslationPreview: useCallback( + (ruleId: RuleSignatureId) => { + const ruleMigrationToShowInFlyout = ruleMigrations.find( + (x) => x.original_rule.id === ruleId + ); + + invariant(ruleMigrationToShowInFlyout, `Rule migration with id ${ruleId} not found`); + setRuleMigrationForPreview(ruleMigrationToShowInFlyout); + }, + [ruleMigrations] + ), + closeRuleMigrationPreview, + }; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/use_siem_migrations_table_columns.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/use_siem_migrations_table_columns.tsx new file mode 100644 index 0000000000000..63a2cb9eee93f --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/use_siem_migrations_table_columns.tsx @@ -0,0 +1,101 @@ +/* + * 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 { EuiBasicTableColumn } from '@elastic/eui'; +import { EuiText, EuiLink } from '@elastic/eui'; +import React, { useMemo } from 'react'; +import type { Severity } from '@kbn/securitysolution-io-ts-alerting-types'; +import type { RuleMigration } from '../../../../../common/siem_migrations/model/rule_migration.gen'; +import { SeverityBadge } from '../../../../common/components/severity_badge'; +import * as rulesI18n from '../../../../detections/pages/detection_engine/rules/translations'; +import * as i18n from './translations'; +import { useSiemMigrationsTableContext } from './siem_migrations_table_context'; +import { getNormalizedSeverity } from '../rules_table/helpers'; +import { StatusBadge } from './status_badge'; +import { DEFAULT_TRANSLATION_RISK_SCORE, DEFAULT_TRANSLATION_SEVERITY } from './constants'; + +export type TableColumn = EuiBasicTableColumn; + +interface RuleNameProps { + name: string; + ruleId: string; +} + +const RuleName = ({ name, ruleId }: RuleNameProps) => { + const { + actions: { openRuleTranslationPreview: openRulePreview }, + } = useSiemMigrationsTableContext(); + + return ( + { + openRulePreview(ruleId); + }} + data-test-subj="ruleName" + > + {name} + + ); +}; + +export const RULE_NAME_COLUMN: TableColumn = { + field: 'original_rule.title', + name: rulesI18n.COLUMN_RULE, + render: (value: RuleMigration['original_rule']['title'], rule: RuleMigration) => ( + + ), + sortable: true, + truncateText: true, + width: '40%', + align: 'left', +}; + +const STATUS_COLUMN: TableColumn = { + field: 'translation_result', + name: i18n.COLUMN_STATUS, + render: (value: RuleMigration['translation_result'], rule: RuleMigration) => ( + + ), + sortable: false, + truncateText: true, + width: '12%', +}; + +export const useSiemMigrationsTableColumns = (): TableColumn[] => { + return useMemo( + () => [ + RULE_NAME_COLUMN, + STATUS_COLUMN, + { + field: 'risk_score', + name: rulesI18n.COLUMN_RISK_SCORE, + render: () => ( + + {DEFAULT_TRANSLATION_RISK_SCORE} + + ), + sortable: true, + truncateText: true, + width: '75px', + }, + { + field: 'elastic_rule.severity', + name: rulesI18n.COLUMN_SEVERITY, + render: (value?: Severity) => ( + + ), + sortable: ({ elastic_rule: elasticRule }: RuleMigration) => + getNormalizedSeverity( + (elasticRule?.severity as Severity) ?? DEFAULT_TRANSLATION_SEVERITY + ), + truncateText: true, + width: '12%', + }, + ], + [] + ); +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/utils.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/utils.tsx new file mode 100644 index 0000000000000..c75fc775a6832 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/utils.tsx @@ -0,0 +1,28 @@ +/* + * 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 { + RuleMigrationTranslationResultEnum, + type RuleMigrationTranslationResult, +} from '../../../../../common/siem_migrations/model/rule_migration.gen'; +import * as i18n from './translations'; + +export const convertTranslationResultIntoText = (status?: RuleMigrationTranslationResult) => { + switch (status) { + case RuleMigrationTranslationResultEnum.full: + return i18n.SIEM_TRANSLATION_RESULT_FULL_LABEL; + + case RuleMigrationTranslationResultEnum.partial: + return i18n.SIEM_TRANSLATION_RESULT_PARTIAL_LABEL; + + case RuleMigrationTranslationResultEnum.untranslatable: + return i18n.SIEM_TRANSLATION_RESULT_UNTRANSLATABLE_LABEL; + + default: + return i18n.SIEM_TRANSLATION_RESULT_UNKNOWN_LABEL; + } +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/hooks/use_is_siem_migrations_enabled.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/hooks/use_is_siem_migrations_enabled.tsx new file mode 100644 index 0000000000000..8755df3210d29 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/hooks/use_is_siem_migrations_enabled.tsx @@ -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. + */ + +import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; + +export const useIsSiemMigrationsEnabled = () => { + return useIsExperimentalFeatureEnabled('siemMigrationsEnabled'); +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/siem_migrations/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/siem_migrations/index.tsx new file mode 100644 index 0000000000000..4952953664716 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/siem_migrations/index.tsx @@ -0,0 +1,70 @@ +/* + * 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 { redirectToDetections } from '../../../../detections/pages/detection_engine/rules/helpers'; +import { SecurityPageName } from '../../../../app/types'; +import { HeaderPage } from '../../../../common/components/header_page'; +import { SecuritySolutionPageWrapper } from '../../../../common/components/page_wrapper'; +import { useKibana } from '../../../../common/lib/kibana'; +import { SpyRoute } from '../../../../common/utils/route/spy_routes'; + +import { useUserData } from '../../../../detections/components/user_info'; +import { useListsConfig } from '../../../../detections/containers/detection_engine/lists/use_lists_config'; + +import * as i18n from './translations'; +import { SiemMigrationsTable } from '../../components/siem_migrations/siem_migrations_table'; +import { SiemMigrationsTableContextProvider } from '../../components/siem_migrations/siem_migrations_table_context'; +import { APP_UI_ID } from '../../../../../common'; +import { NeedAdminForUpdateRulesCallOut } from '../../../../detections/components/callouts/need_admin_for_update_callout'; +import { MissingPrivilegesCallOut } from '../../../../detections/components/callouts/missing_privileges_callout'; +import { getDetectionEngineUrl } from '../../../../common/components/link_to'; +import { SiemMigrationsHeaderButtons } from '../../components/siem_migrations/siem_migrations_header_buttons'; + +const SiemMigrationsPageComponent: React.FC = () => { + const { navigateToApp } = useKibana().services.application; + + const [{ isSignalIndexExists, isAuthenticated, hasEncryptionKey }] = useUserData(); + const { needsConfiguration: needsListsConfiguration } = useListsConfig(); + + if ( + redirectToDetections( + isSignalIndexExists, + isAuthenticated, + hasEncryptionKey, + needsListsConfiguration + ) + ) { + navigateToApp(APP_UI_ID, { + deepLinkId: SecurityPageName.alerts, + path: getDetectionEngineUrl(), + }); + return null; + } + + return ( + <> + + + + + + + + + + + + + + + ); +}; + +export const SiemMigrationsPage = React.memo(SiemMigrationsPageComponent); +SiemMigrationsPage.displayName = 'SiemMigrationsPage'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/siem_migrations/translations.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/siem_migrations/translations.tsx new file mode 100644 index 0000000000000..1c5f8278fc4bc --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/siem_migrations/translations.tsx @@ -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 { i18n } from '@kbn/i18n'; + +export const PAGE_TITLE = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.siemMigrations.pageTitle', + { + defaultMessage: 'Translated rules', + } +); diff --git a/x-pack/plugins/security_solution/public/rules/links.ts b/x-pack/plugins/security_solution/public/rules/links.ts index 5564a8b9b4e2a..122b4cd16efa1 100644 --- a/x-pack/plugins/security_solution/public/rules/links.ts +++ b/x-pack/plugins/security_solution/public/rules/links.ts @@ -13,6 +13,7 @@ import { RULES_CREATE_PATH, RULES_LANDING_PATH, RULES_PATH, + SIEM_MIGRATIONS_PATH, SERVER_APP_ID, } from '../../common/constants'; import { @@ -21,6 +22,7 @@ import { CREATE_NEW_RULE, EXCEPTIONS, RULES, + SIEM_MIGRATIONS, SIEM_RULES, } from '../app/translations'; import { SecurityPageName } from '../app/types'; @@ -106,6 +108,24 @@ export const links: LinkItem = { }), ], }, + { + id: SecurityPageName.rulesSiemMigrations, + title: SIEM_MIGRATIONS, + description: i18n.translate('xpack.securitySolution.appLinks.siemMigrationsDescription', { + defaultMessage: 'SIEM Rules Migrations.', + }), + landingIcon: IconConsoleCloud, + path: SIEM_MIGRATIONS_PATH, + capabilities: [`${SERVER_APP_ID}.show`], + skipUrlState: true, + hideTimeline: true, + globalSearchKeywords: [ + i18n.translate('xpack.securitySolution.appLinks.siemMigrations', { + defaultMessage: 'SIEM Rules Migrations', + }), + ], + experimentalKey: 'siemMigrationsEnabled', + }, ], categories: [ { @@ -116,6 +136,7 @@ export const links: LinkItem = { SecurityPageName.rules, SecurityPageName.cloudSecurityPostureBenchmarks, SecurityPageName.exceptions, + SecurityPageName.rulesSiemMigrations, ], }, { diff --git a/x-pack/plugins/security_solution/public/rules/routes.tsx b/x-pack/plugins/security_solution/public/rules/routes.tsx index add8a5911df21..9a40509db45e3 100644 --- a/x-pack/plugins/security_solution/public/rules/routes.tsx +++ b/x-pack/plugins/security_solution/public/rules/routes.tsx @@ -30,38 +30,54 @@ import type { SecuritySubPluginRoutes } from '../app/types'; import { RulesLandingPage } from './landing'; import { CoverageOverviewPage } from '../detection_engine/rule_management_ui/pages/coverage_overview'; import { RuleDetailTabs } from '../detection_engine/rule_details_ui/pages/rule_details/use_rule_details_tabs'; +import { SiemMigrationsPage } from '../detection_engine/rule_management_ui/pages/siem_migrations'; +import { useIsSiemMigrationsEnabled } from '../detection_engine/rule_management_ui/hooks/use_is_siem_migrations_enabled'; -const RulesSubRoutes = [ - { - path: '/rules/id/:detailName/edit', - main: EditRulePage, - exact: true, - }, - { - path: `/rules/id/:detailName/:tabName(${RuleDetailTabs.alerts}|${RuleDetailTabs.exceptions}|${RuleDetailTabs.endpointExceptions}|${RuleDetailTabs.executionResults}|${RuleDetailTabs.executionEvents})`, - main: RuleDetailsPage, - exact: true, - }, - { - path: '/rules/create', - main: CreateRulePage, - exact: true, - }, - { - path: `/rules/:tabName(${AllRulesTabs.management}|${AllRulesTabs.monitoring}|${AllRulesTabs.updates})`, - main: RulesPage, - exact: true, - }, - { - path: '/rules/add_rules', - main: AddRulesPage, - exact: true, - }, -]; +const getRulesSubRoutes = (isSiemMigrationsEnabled: boolean) => { + return [ + { + path: '/rules/id/:detailName/edit', + main: EditRulePage, + exact: true, + }, + { + path: `/rules/id/:detailName/:tabName(${RuleDetailTabs.alerts}|${RuleDetailTabs.exceptions}|${RuleDetailTabs.endpointExceptions}|${RuleDetailTabs.executionResults}|${RuleDetailTabs.executionEvents})`, + main: RuleDetailsPage, + exact: true, + }, + { + path: '/rules/create', + main: CreateRulePage, + exact: true, + }, + { + path: `/rules/:tabName(${AllRulesTabs.management}|${AllRulesTabs.monitoring}|${AllRulesTabs.updates})`, + main: RulesPage, + exact: true, + }, + { + path: '/rules/add_rules', + main: AddRulesPage, + exact: true, + }, + ...(isSiemMigrationsEnabled + ? [ + { + path: '/rules/siem_migrations', + main: SiemMigrationsPage, + exact: true, + }, + ] + : []), + ]; +}; const RulesContainerComponent: React.FC = () => { useReadonlyHeader(i18n.READ_ONLY_BADGE_TOOLTIP); + const isSiemMigrationsEnabled = useIsSiemMigrationsEnabled(); + const rulesSubRoutes = getRulesSubRoutes(isSiemMigrationsEnabled); + return ( @@ -87,7 +103,7 @@ const RulesContainerComponent: React.FC = () => { - {RulesSubRoutes.map((route) => ( + {rulesSubRoutes.map((route) => ( Date: Thu, 21 Nov 2024 17:34:41 +0100 Subject: [PATCH 2/7] Review feedback: re-structuring --- packages/deeplinks/security/deep_links.ts | 2 +- .../security_solution/common/constants.ts | 3 +- .../rule_management/api/api.ts | 62 ---------------- .../pages/siem_migrations/index.tsx | 70 ------------------ .../public/lazy_sub_plugins.tsx | 2 + .../security_solution/public/plugin.tsx | 4 ++ .../security_solution/public/rules/links.ts | 24 +------ .../security_solution/public/rules/routes.tsx | 72 ++++++++----------- .../public/siem_migrations/constants.ts | 16 +++++ .../public/siem_migrations/index.ts | 19 +++++ .../public/siem_migrations/jest.config.js | 19 +++++ .../public/siem_migrations/links.ts | 35 +++++++++ .../public/siem_migrations/routes.tsx | 31 ++++++++ .../public/siem_migrations/rules/api/api.ts | 68 ++++++++++++++++++ .../rules/api/hooks/constants.ts | 13 ++++ .../api/hooks}/use_get_rule_migrations.ts | 8 +-- .../use_get_rule_migrations_stats_all.ts | 8 +-- .../rules/components}/constants.ts | 0 .../siem_migrations_header_buttons.tsx | 0 .../siem_migrations_no_items_message.tsx | 4 +- .../components}/siem_migrations_table.tsx | 2 +- .../siem_migrations_table_context.tsx | 10 +-- .../siem_migrations_table_filters.tsx | 4 +- .../components}/status_badge/index.test.tsx | 0 .../rules/components}/status_badge/index.tsx | 4 +- .../translation_details/constants.ts | 0 .../translation_details_flyout.tsx | 6 +- .../translation_tab/header.tsx | 0 .../translation_tab/index.tsx | 2 +- .../translation_tab/rule_query.tsx | 4 +- .../translation_tab/translations.ts | 0 .../translation_details/translations.ts | 0 .../rules/components}/translations.ts | 0 .../use_filter_siem_migrations_to_install.ts | 4 +- .../use_siem_migrations_preview_flyout.tsx | 6 +- .../use_siem_migrations_table_columns.tsx | 8 +-- .../rules/components}/utils.tsx | 2 +- .../siem_migrations/rules/pages/index.tsx | 70 ++++++++++++++++++ .../rules/pages}/translations.tsx | 0 .../plugins/security_solution/public/types.ts | 3 + 40 files changed, 350 insertions(+), 235 deletions(-) delete mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/siem_migrations/index.tsx create mode 100644 x-pack/plugins/security_solution/public/siem_migrations/constants.ts create mode 100644 x-pack/plugins/security_solution/public/siem_migrations/index.ts create mode 100644 x-pack/plugins/security_solution/public/siem_migrations/jest.config.js create mode 100644 x-pack/plugins/security_solution/public/siem_migrations/links.ts create mode 100644 x-pack/plugins/security_solution/public/siem_migrations/routes.tsx create mode 100644 x-pack/plugins/security_solution/public/siem_migrations/rules/api/api.ts create mode 100644 x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/constants.ts rename x-pack/plugins/security_solution/public/{detection_engine/rule_management/api/hooks/siem_migrations => siem_migrations/rules/api/hooks}/use_get_rule_migrations.ts (75%) rename x-pack/plugins/security_solution/public/{detection_engine/rule_management/api/hooks/siem_migrations => siem_migrations/rules/api/hooks}/use_get_rule_migrations_stats_all.ts (81%) rename x-pack/plugins/security_solution/public/{detection_engine/rule_management_ui/components/siem_migrations => siem_migrations/rules/components}/constants.ts (100%) rename x-pack/plugins/security_solution/public/{detection_engine/rule_management_ui/components/siem_migrations => siem_migrations/rules/components}/siem_migrations_header_buttons.tsx (100%) rename x-pack/plugins/security_solution/public/{detection_engine/rule_management_ui/components/siem_migrations => siem_migrations/rules/components}/siem_migrations_no_items_message.tsx (91%) rename x-pack/plugins/security_solution/public/{detection_engine/rule_management_ui/components/siem_migrations => siem_migrations/rules/components}/siem_migrations_table.tsx (96%) rename x-pack/plugins/security_solution/public/{detection_engine/rule_management_ui/components/siem_migrations => siem_migrations/rules/components}/siem_migrations_table_context.tsx (91%) rename x-pack/plugins/security_solution/public/{detection_engine/rule_management_ui/components/siem_migrations => siem_migrations/rules/components}/siem_migrations_table_filters.tsx (89%) rename x-pack/plugins/security_solution/public/{detection_engine/rule_management_ui/components/siem_migrations => siem_migrations/rules/components}/status_badge/index.test.tsx (100%) rename x-pack/plugins/security_solution/public/{detection_engine/rule_management_ui/components/siem_migrations => siem_migrations/rules/components}/status_badge/index.tsx (90%) rename x-pack/plugins/security_solution/public/{detection_engine/rule_management_ui/components/siem_migrations => siem_migrations/rules/components}/translation_details/constants.ts (100%) rename x-pack/plugins/security_solution/public/{detection_engine/rule_management_ui/components/siem_migrations => siem_migrations/rules/components}/translation_details/translation_details_flyout.tsx (96%) rename x-pack/plugins/security_solution/public/{detection_engine/rule_management_ui/components/siem_migrations => siem_migrations/rules/components}/translation_details/translation_tab/header.tsx (100%) rename x-pack/plugins/security_solution/public/{detection_engine/rule_management_ui/components/siem_migrations => siem_migrations/rules/components}/translation_details/translation_tab/index.tsx (97%) rename x-pack/plugins/security_solution/public/{detection_engine/rule_management_ui/components/siem_migrations => siem_migrations/rules/components}/translation_details/translation_tab/rule_query.tsx (80%) rename x-pack/plugins/security_solution/public/{detection_engine/rule_management_ui/components/siem_migrations => siem_migrations/rules/components}/translation_details/translation_tab/translations.ts (100%) rename x-pack/plugins/security_solution/public/{detection_engine/rule_management_ui/components/siem_migrations => siem_migrations/rules/components}/translation_details/translations.ts (100%) rename x-pack/plugins/security_solution/public/{detection_engine/rule_management_ui/components/siem_migrations => siem_migrations/rules/components}/translations.ts (100%) rename x-pack/plugins/security_solution/public/{detection_engine/rule_management_ui/components/siem_migrations => siem_migrations/rules/components}/use_filter_siem_migrations_to_install.ts (86%) rename x-pack/plugins/security_solution/public/{detection_engine/rule_management_ui/components/siem_migrations => siem_migrations/rules/components}/use_siem_migrations_preview_flyout.tsx (91%) rename x-pack/plugins/security_solution/public/{detection_engine/rule_management_ui/components/siem_migrations => siem_migrations/rules/components}/use_siem_migrations_table_columns.tsx (88%) rename x-pack/plugins/security_solution/public/{detection_engine/rule_management_ui/components/siem_migrations => siem_migrations/rules/components}/utils.tsx (92%) create mode 100644 x-pack/plugins/security_solution/public/siem_migrations/rules/pages/index.tsx rename x-pack/plugins/security_solution/public/{detection_engine/rule_management_ui/pages/siem_migrations => siem_migrations/rules/pages}/translations.tsx (100%) diff --git a/packages/deeplinks/security/deep_links.ts b/packages/deeplinks/security/deep_links.ts index 1da816c63ce2f..c1d9b3b3cb6af 100644 --- a/packages/deeplinks/security/deep_links.ts +++ b/packages/deeplinks/security/deep_links.ts @@ -69,7 +69,7 @@ export enum SecurityPageName { rulesAdd = 'rules-add', rulesCreate = 'rules-create', rulesLanding = 'rules-landing', - rulesSiemMigrations = 'rules-siem-migrations', + siemMigrationsRules = 'siem_migrations-rules', /* * Warning: Computed values are not permitted in an enum with string valued members * All threat intelligence page names must match `TIPageId` in x-pack/plugins/threat_intelligence/public/common/navigation/types.ts diff --git a/x-pack/plugins/security_solution/common/constants.ts b/x-pack/plugins/security_solution/common/constants.ts index 73e9ef7c39589..265af5a47e1fe 100644 --- a/x-pack/plugins/security_solution/common/constants.ts +++ b/x-pack/plugins/security_solution/common/constants.ts @@ -98,7 +98,6 @@ export const RULES_LANDING_PATH = `${RULES_PATH}/landing` as const; export const RULES_ADD_PATH = `${RULES_PATH}/add_rules` as const; export const RULES_UPDATES = `${RULES_PATH}/updates` as const; export const RULES_CREATE_PATH = `${RULES_PATH}/create` as const; -export const SIEM_MIGRATIONS_PATH = `${RULES_PATH}/siem_migrations` as const; export const EXCEPTIONS_PATH = '/exceptions' as const; export const EXCEPTION_LIST_DETAIL_PATH = `${EXCEPTIONS_PATH}/details/:detailName` as const; export const HOSTS_PATH = '/hosts' as const; @@ -139,6 +138,8 @@ export const APP_BLOCKLIST_PATH = `${APP_PATH}${BLOCKLIST_PATH}` as const; export const APP_RESPONSE_ACTIONS_HISTORY_PATH = `${APP_PATH}${RESPONSE_ACTIONS_HISTORY_PATH}` as const; export const NOTES_PATH = `${MANAGEMENT_PATH}/notes` as const; +export const SIEM_MIGRATIONS_PATH = '/siem_migrations' as const; +export const SIEM_MIGRATIONS_RULES_PATH = `${SIEM_MIGRATIONS_PATH}/rules` as const; // cloud logs to exclude from default index pattern export const EXCLUDE_ELASTIC_CLOUD_INDICES = ['-*elastic-cloud-logs-*']; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts index b7d4b59cc54bb..aea4b6672659e 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts @@ -13,15 +13,6 @@ import { INTERNAL_ALERTING_API_FIND_RULES_PATH } from '@kbn/alerting-plugin/comm import { BASE_ACTION_API_PATH } from '@kbn/actions-plugin/common'; import type { ActionType, AsApiContract } from '@kbn/actions-plugin/common'; import type { ActionResult } from '@kbn/actions-plugin/server'; -import { replaceParams } from '@kbn/openapi-common/shared'; -import type { - GetAllStatsRuleMigrationResponse, - GetRuleMigrationResponse, -} from '../../../../common/siem_migrations/model/api/rules/rule_migration.gen'; -import { - SIEM_RULE_MIGRATIONS_ALL_STATS_PATH, - SIEM_RULE_MIGRATION_PATH, -} from '../../../../common/siem_migrations/constants'; import { convertRulesFilterToKQL } from '../../../../common/detection_engine/rule_management/rule_filtering'; import type { UpgradeSpecificRulesRequest, @@ -707,56 +698,3 @@ export const bootstrapPrebuiltRules = async (): Promise => - KibanaServices.get().http.fetch( - SIEM_RULE_MIGRATIONS_ALL_STATS_PATH, - { - method: 'GET', - version: '1', - signal, - } - ); - -/** - * Retrieves all the migration rule documents of a specific migration. - * - * @param migrationId `id` of the migration to retrieve rule documents for - * @param signal AbortSignal for cancelling request - * - * @throws An error if response is not OK - */ -export const getRuleMigrations = async ({ - migrationId, - signal, -}: { - migrationId?: string; - signal: AbortSignal | undefined; -}): Promise => { - if (!migrationId) { - return []; - } - return KibanaServices.get().http.fetch( - replaceParams(SIEM_RULE_MIGRATION_PATH, { migration_id: migrationId }), - { - method: 'GET', - version: '1', - signal, - } - ); -}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/siem_migrations/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/siem_migrations/index.tsx deleted file mode 100644 index 4952953664716..0000000000000 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/siem_migrations/index.tsx +++ /dev/null @@ -1,70 +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 { redirectToDetections } from '../../../../detections/pages/detection_engine/rules/helpers'; -import { SecurityPageName } from '../../../../app/types'; -import { HeaderPage } from '../../../../common/components/header_page'; -import { SecuritySolutionPageWrapper } from '../../../../common/components/page_wrapper'; -import { useKibana } from '../../../../common/lib/kibana'; -import { SpyRoute } from '../../../../common/utils/route/spy_routes'; - -import { useUserData } from '../../../../detections/components/user_info'; -import { useListsConfig } from '../../../../detections/containers/detection_engine/lists/use_lists_config'; - -import * as i18n from './translations'; -import { SiemMigrationsTable } from '../../components/siem_migrations/siem_migrations_table'; -import { SiemMigrationsTableContextProvider } from '../../components/siem_migrations/siem_migrations_table_context'; -import { APP_UI_ID } from '../../../../../common'; -import { NeedAdminForUpdateRulesCallOut } from '../../../../detections/components/callouts/need_admin_for_update_callout'; -import { MissingPrivilegesCallOut } from '../../../../detections/components/callouts/missing_privileges_callout'; -import { getDetectionEngineUrl } from '../../../../common/components/link_to'; -import { SiemMigrationsHeaderButtons } from '../../components/siem_migrations/siem_migrations_header_buttons'; - -const SiemMigrationsPageComponent: React.FC = () => { - const { navigateToApp } = useKibana().services.application; - - const [{ isSignalIndexExists, isAuthenticated, hasEncryptionKey }] = useUserData(); - const { needsConfiguration: needsListsConfiguration } = useListsConfig(); - - if ( - redirectToDetections( - isSignalIndexExists, - isAuthenticated, - hasEncryptionKey, - needsListsConfiguration - ) - ) { - navigateToApp(APP_UI_ID, { - deepLinkId: SecurityPageName.alerts, - path: getDetectionEngineUrl(), - }); - return null; - } - - return ( - <> - - - - - - - - - - - - - - - ); -}; - -export const SiemMigrationsPage = React.memo(SiemMigrationsPageComponent); -SiemMigrationsPage.displayName = 'SiemMigrationsPage'; diff --git a/x-pack/plugins/security_solution/public/lazy_sub_plugins.tsx b/x-pack/plugins/security_solution/public/lazy_sub_plugins.tsx index 8bbba3885a2ab..1be423c988397 100644 --- a/x-pack/plugins/security_solution/public/lazy_sub_plugins.tsx +++ b/x-pack/plugins/security_solution/public/lazy_sub_plugins.tsx @@ -29,6 +29,7 @@ import { EntityAnalytics } from './entity_analytics'; import { Assets } from './assets'; import { Investigations } from './investigations'; import { MachineLearning } from './machine_learning'; +import { SiemMigrations } from './siem_migrations'; /** * The classes used to instantiate the sub plugins. These are grouped into a single object for the sake of bundling them in a single dynamic import. @@ -53,5 +54,6 @@ const subPluginClasses = { Assets, Investigations, MachineLearning, + SiemMigrations, }; export { subPluginClasses }; diff --git a/x-pack/plugins/security_solution/public/plugin.tsx b/x-pack/plugins/security_solution/public/plugin.tsx index b74d0cffdc88d..f933832264247 100644 --- a/x-pack/plugins/security_solution/public/plugin.tsx +++ b/x-pack/plugins/security_solution/public/plugin.tsx @@ -245,6 +245,7 @@ export class Plugin implements IPlugin { - return [ - { - path: '/rules/id/:detailName/edit', - main: EditRulePage, - exact: true, - }, - { - path: `/rules/id/:detailName/:tabName(${RuleDetailTabs.alerts}|${RuleDetailTabs.exceptions}|${RuleDetailTabs.endpointExceptions}|${RuleDetailTabs.executionResults}|${RuleDetailTabs.executionEvents})`, - main: RuleDetailsPage, - exact: true, - }, - { - path: '/rules/create', - main: CreateRulePage, - exact: true, - }, - { - path: `/rules/:tabName(${AllRulesTabs.management}|${AllRulesTabs.monitoring}|${AllRulesTabs.updates})`, - main: RulesPage, - exact: true, - }, - { - path: '/rules/add_rules', - main: AddRulesPage, - exact: true, - }, - ...(isSiemMigrationsEnabled - ? [ - { - path: '/rules/siem_migrations', - main: SiemMigrationsPage, - exact: true, - }, - ] - : []), - ]; -}; +const RulesSubRoutes = [ + { + path: '/rules/id/:detailName/edit', + main: EditRulePage, + exact: true, + }, + { + path: `/rules/id/:detailName/:tabName(${RuleDetailTabs.alerts}|${RuleDetailTabs.exceptions}|${RuleDetailTabs.endpointExceptions}|${RuleDetailTabs.executionResults}|${RuleDetailTabs.executionEvents})`, + main: RuleDetailsPage, + exact: true, + }, + { + path: '/rules/create', + main: CreateRulePage, + exact: true, + }, + { + path: `/rules/:tabName(${AllRulesTabs.management}|${AllRulesTabs.monitoring}|${AllRulesTabs.updates})`, + main: RulesPage, + exact: true, + }, + { + path: '/rules/add_rules', + main: AddRulesPage, + exact: true, + }, +]; const RulesContainerComponent: React.FC = () => { useReadonlyHeader(i18n.READ_ONLY_BADGE_TOOLTIP); - const isSiemMigrationsEnabled = useIsSiemMigrationsEnabled(); - const rulesSubRoutes = getRulesSubRoutes(isSiemMigrationsEnabled); - return ( @@ -103,7 +87,7 @@ const RulesContainerComponent: React.FC = () => { - {rulesSubRoutes.map((route) => ( + {RulesSubRoutes.map((route) => ( /x-pack/plugins/security_solution/public/siem_migrations'], + coverageDirectory: + '/target/kibana-coverage/jest/x-pack/plugins/security_solution/public/siem_migrations', + coverageReporters: ['text', 'html'], + collectCoverageFrom: [ + '/x-pack/plugins/security_solution/public/siem_migrations/**/*.{ts,tsx}', + ], + moduleNameMapper: require('../../server/__mocks__/module_name_map'), +}; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/links.ts b/x-pack/plugins/security_solution/public/siem_migrations/links.ts new file mode 100644 index 0000000000000..bcdd75baad40d --- /dev/null +++ b/x-pack/plugins/security_solution/public/siem_migrations/links.ts @@ -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 { i18n } from '@kbn/i18n'; +import { + SecurityPageName, + SERVER_APP_ID, + SIEM_MIGRATIONS_RULES_PATH, +} from '../../common/constants'; +import { SIEM_MIGRATIONS } from '../app/translations'; +import type { LinkItem } from '../common/links/types'; +import { IconConsoleCloud } from '../common/icons/console_cloud'; + +export const siemMigrationsLinks: LinkItem = { + id: SecurityPageName.siemMigrationsRules, + title: SIEM_MIGRATIONS, + description: i18n.translate('xpack.securitySolution.appLinks.siemMigrationsRulesDescription', { + defaultMessage: 'SIEM Rules Migrations.', + }), + landingIcon: IconConsoleCloud, + path: SIEM_MIGRATIONS_RULES_PATH, + capabilities: [`${SERVER_APP_ID}.show`], + skipUrlState: true, + hideTimeline: true, + globalSearchKeywords: [ + i18n.translate('xpack.securitySolution.appLinks.siemMigrationsRules', { + defaultMessage: 'SIEM Rules Migrations', + }), + ], + experimentalKey: 'siemMigrationsEnabled', +}; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/routes.tsx b/x-pack/plugins/security_solution/public/siem_migrations/routes.tsx new file mode 100644 index 0000000000000..3d6455911ab17 --- /dev/null +++ b/x-pack/plugins/security_solution/public/siem_migrations/routes.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 React from 'react'; + +import { TrackApplicationView } from '@kbn/usage-collection-plugin/public'; +import type { SecuritySubPluginRoutes } from '../app/types'; +import { SIEM_MIGRATIONS_RULES_PATH, SecurityPageName } from '../../common/constants'; +import { RulesPage } from './rules/pages'; +import { PluginTemplateWrapper } from '../common/components/plugin_template_wrapper'; + +export const RulesRoutes = () => { + return ( + + + + + + ); +}; + +export const routes: SecuritySubPluginRoutes = [ + { + path: SIEM_MIGRATIONS_RULES_PATH, + component: RulesRoutes, + }, +]; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/api/api.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/api/api.ts new file mode 100644 index 0000000000000..599bf10f22262 --- /dev/null +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/api/api.ts @@ -0,0 +1,68 @@ +/* + * 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 { replaceParams } from '@kbn/openapi-common/shared'; + +import { KibanaServices } from '../../../common/lib/kibana'; + +import { + SIEM_RULE_MIGRATIONS_ALL_STATS_PATH, + SIEM_RULE_MIGRATION_PATH, +} from '../../../../common/siem_migrations/constants'; +import type { + GetAllStatsRuleMigrationResponse, + GetRuleMigrationResponse, +} from '../../../../common/siem_migrations/model/api/rules/rule_migration.gen'; + +/** + * Retrieves the stats for all the existing migrations, aggregated by `migration_id`. + * + * @param signal AbortSignal for cancelling request + * + * @throws An error if response is not OK + */ +export const getRuleMigrationsStatsAll = async ({ + signal, +}: { + signal: AbortSignal | undefined; +}): Promise => + KibanaServices.get().http.fetch( + SIEM_RULE_MIGRATIONS_ALL_STATS_PATH, + { + method: 'GET', + version: '1', + signal, + } + ); + +/** + * Retrieves all the migration rule documents of a specific migration. + * + * @param migrationId `id` of the migration to retrieve rule documents for + * @param signal AbortSignal for cancelling request + * + * @throws An error if response is not OK + */ +export const getRuleMigrations = async ({ + migrationId, + signal, +}: { + migrationId?: string; + signal: AbortSignal | undefined; +}): Promise => { + if (!migrationId) { + return []; + } + return KibanaServices.get().http.fetch( + replaceParams(SIEM_RULE_MIGRATION_PATH, { migration_id: migrationId }), + { + method: 'GET', + version: '1', + signal, + } + ); +}; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/constants.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/constants.ts new file mode 100644 index 0000000000000..61e0d1e05f7f0 --- /dev/null +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/constants.ts @@ -0,0 +1,13 @@ +/* + * 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. + */ + +const ONE_MINUTE = 60000; + +export const DEFAULT_QUERY_OPTIONS = { + refetchIntervalInBackground: false, + staleTime: ONE_MINUTE * 5, +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/siem_migrations/use_get_rule_migrations.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/use_get_rule_migrations.ts similarity index 75% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/siem_migrations/use_get_rule_migrations.ts rename to x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/use_get_rule_migrations.ts index a295c376c30e3..56c6240213056 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/siem_migrations/use_get_rule_migrations.ts +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/use_get_rule_migrations.ts @@ -8,10 +8,10 @@ import type { UseQueryOptions } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query'; import { replaceParams } from '@kbn/openapi-common/shared'; -import type { GetRuleMigrationResponse } from '../../../../../../common/siem_migrations/model/api/rules/rule_migration.gen'; -import { SIEM_RULE_MIGRATION_PATH } from '../../../../../../common/siem_migrations/constants'; -import { getRuleMigrations } from '../../api'; -import { DEFAULT_QUERY_OPTIONS } from '../constants'; +import { DEFAULT_QUERY_OPTIONS } from './constants'; +import { getRuleMigrations } from '../api'; +import type { GetRuleMigrationResponse } from '../../../../../common/siem_migrations/model/api/rules/rule_migration.gen'; +import { SIEM_RULE_MIGRATION_PATH } from '../../../../../common/siem_migrations/constants'; export const useGetRuleMigrationsQuery = ( migrationId?: string, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/siem_migrations/use_get_rule_migrations_stats_all.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/use_get_rule_migrations_stats_all.ts similarity index 81% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/siem_migrations/use_get_rule_migrations_stats_all.ts rename to x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/use_get_rule_migrations_stats_all.ts index bb87f874632ec..026e407050e97 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/siem_migrations/use_get_rule_migrations_stats_all.ts +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/use_get_rule_migrations_stats_all.ts @@ -7,10 +7,10 @@ import type { UseQueryOptions } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query'; -import type { GetAllStatsRuleMigrationResponse } from '../../../../../../common/siem_migrations/model/api/rules/rule_migration.gen'; -import { SIEM_RULE_MIGRATIONS_ALL_STATS_PATH } from '../../../../../../common/siem_migrations/constants'; -import { getRuleMigrationsStatsAll } from '../../api'; -import { DEFAULT_QUERY_OPTIONS } from '../constants'; +import { DEFAULT_QUERY_OPTIONS } from './constants'; +import { getRuleMigrationsStatsAll } from '../api'; +import type { GetAllStatsRuleMigrationResponse } from '../../../../../common/siem_migrations/model/api/rules/rule_migration.gen'; +import { SIEM_RULE_MIGRATIONS_ALL_STATS_PATH } from '../../../../../common/siem_migrations/constants'; export const GET_RULE_MIGRATIONS_STATS_ALL_QUERY_KEY = ['GET', SIEM_RULE_MIGRATIONS_ALL_STATS_PATH]; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/constants.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/constants.ts similarity index 100% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/constants.ts rename to x-pack/plugins/security_solution/public/siem_migrations/rules/components/constants.ts diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/siem_migrations_header_buttons.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/siem_migrations_header_buttons.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/siem_migrations_header_buttons.tsx rename to x-pack/plugins/security_solution/public/siem_migrations/rules/components/siem_migrations_header_buttons.tsx diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/siem_migrations_no_items_message.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/siem_migrations_no_items_message.tsx similarity index 91% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/siem_migrations_no_items_message.tsx rename to x-pack/plugins/security_solution/public/siem_migrations/rules/components/siem_migrations_no_items_message.tsx index 291fe8e49f400..3ce9e21227471 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/siem_migrations_no_items_message.tsx +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/siem_migrations_no_items_message.tsx @@ -7,8 +7,8 @@ import { EuiButton, EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import React from 'react'; -import { SecurityPageName } from '../../../../../common'; -import { useGetSecuritySolutionLinkProps } from '../../../../common/components/links'; +import { SecurityPageName } from '../../../../common'; +import { useGetSecuritySolutionLinkProps } from '../../../common/components/links'; import * as i18n from './translations'; const SiemMigrationsTableNoItemsMessageComponent = () => { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/siem_migrations_table.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/siem_migrations_table.tsx similarity index 96% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/siem_migrations_table.tsx rename to x-pack/plugins/security_solution/public/siem_migrations/rules/components/siem_migrations_table.tsx index 79769fcb3d461..25aafd004ce96 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/siem_migrations_table.tsx +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/siem_migrations_table.tsx @@ -19,7 +19,7 @@ import React from 'react'; import { RULES_TABLE_INITIAL_PAGE_SIZE, RULES_TABLE_PAGE_SIZE_OPTIONS, -} from '../rules_table/constants'; +} from '../../../detection_engine/rule_management_ui/components/rules_table/constants'; import { SiemMigrationsTableNoItemsMessage } from './siem_migrations_no_items_message'; import { useSiemMigrationsTableContext } from './siem_migrations_table_context'; import { SiemMigrationsTableFilters } from './siem_migrations_table_filters'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/siem_migrations_table_context.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/siem_migrations_table_context.tsx similarity index 91% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/siem_migrations_table_context.tsx rename to x-pack/plugins/security_solution/public/siem_migrations/rules/components/siem_migrations_table_context.tsx index 8b66dbd4a8485..6cca599f53a4d 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/siem_migrations_table_context.tsx +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/siem_migrations_table_context.tsx @@ -7,14 +7,14 @@ import type { Dispatch, SetStateAction } from 'react'; import React, { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react'; -import type { RuleMigration } from '../../../../../common/siem_migrations/model/rule_migration.gen'; -import { useGetRuleMigrationsStatsAllQuery } from '../../../rule_management/api/hooks/siem_migrations/use_get_rule_migrations_stats_all'; -import { useGetRuleMigrationsQuery } from '../../../rule_management/api/hooks/siem_migrations/use_get_rule_migrations'; -import type { RuleSignatureId } from '../../../../../common/api/detection_engine'; -import { invariant } from '../../../../../common/utils/invariant'; +import type { RuleMigration } from '../../../../common/siem_migrations/model/rule_migration.gen'; +import type { RuleSignatureId } from '../../../../common/api/detection_engine'; +import { invariant } from '../../../../common/utils/invariant'; import type { SiemMigrationsTableFilterOptions } from './use_filter_siem_migrations_to_install'; import { useFilterSiemMigrationsToInstall } from './use_filter_siem_migrations_to_install'; import { useSiemMigrationsPreviewFlyout } from './use_siem_migrations_preview_flyout'; +import { useGetRuleMigrationsStatsAllQuery } from '../api/hooks/use_get_rule_migrations_stats_all'; +import { useGetRuleMigrationsQuery } from '../api/hooks/use_get_rule_migrations'; export interface SiemMigrationsTableState { /** diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/siem_migrations_table_filters.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/siem_migrations_table_filters.tsx similarity index 89% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/siem_migrations_table_filters.tsx rename to x-pack/plugins/security_solution/public/siem_migrations/rules/components/siem_migrations_table_filters.tsx index a8e3f6764d2b5..8faa94f289a62 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/siem_migrations_table_filters.tsx +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/siem_migrations_table_filters.tsx @@ -10,8 +10,8 @@ import { isEqual } from 'lodash/fp'; import React, { useCallback } from 'react'; import styled from 'styled-components'; import * as i18n from './translations'; -import { TagsFilterPopover } from '../rules_table/rules_table_filters/tags_filter_popover'; -import { RuleSearchField } from '../rules_table/rules_table_filters/rule_search_field'; +import { TagsFilterPopover } from '../../../detection_engine/rule_management_ui/components/rules_table/rules_table_filters/tags_filter_popover'; +import { RuleSearchField } from '../../../detection_engine/rule_management_ui/components/rules_table/rules_table_filters/rule_search_field'; import { useSiemMigrationsTableContext } from './siem_migrations_table_context'; const FilterWrapper = styled(EuiFlexGroup)` diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/status_badge/index.test.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/status_badge/index.test.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/status_badge/index.test.tsx rename to x-pack/plugins/security_solution/public/siem_migrations/rules/components/status_badge/index.test.tsx diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/status_badge/index.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/status_badge/index.tsx similarity index 90% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/status_badge/index.tsx rename to x-pack/plugins/security_solution/public/siem_migrations/rules/components/status_badge/index.tsx index 1088805c127f2..7f5728ac9bb96 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/status_badge/index.tsx +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/status_badge/index.tsx @@ -8,8 +8,8 @@ import React from 'react'; import { euiLightVars } from '@kbn/ui-theme'; -import type { RuleMigrationTranslationResult } from '../../../../../../common/siem_migrations/model/rule_migration.gen'; -import { HealthTruncateText } from '../../../../../common/components/health_truncate_text'; +import type { RuleMigrationTranslationResult } from '../../../../../common/siem_migrations/model/rule_migration.gen'; +import { HealthTruncateText } from '../../../../common/components/health_truncate_text'; import { convertTranslationResultIntoText } from '../utils'; const { euiColorVis0, euiColorVis7, euiColorVis9 } = euiLightVars; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/constants.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details/constants.ts similarity index 100% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/constants.ts rename to x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details/constants.ts diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/translation_details_flyout.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details/translation_details_flyout.tsx similarity index 96% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/translation_details_flyout.tsx rename to x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details/translation_details_flyout.tsx index 3a0793a320ebc..e33526e885c5a 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/translation_details_flyout.tsx +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details/translation_details_flyout.tsx @@ -25,15 +25,15 @@ import { } from '@elastic/eui'; import type { EuiTabbedContentTab, EuiTabbedContentProps, EuiFlyoutProps } from '@elastic/eui'; -import type { RuleMigration } from '../../../../../../common/siem_migrations/model/rule_migration.gen'; +import type { RuleMigration } from '../../../../../common/siem_migrations/model/rule_migration.gen'; import { RuleOverviewTab, useOverviewTabSections, -} from '../../../../rule_management/components/rule_details/rule_overview_tab'; +} from '../../../../detection_engine/rule_management/components/rule_details/rule_overview_tab'; import { type RuleResponse, type Severity, -} from '../../../../../../common/api/detection_engine/model/rule_schema'; +} from '../../../../../common/api/detection_engine/model/rule_schema'; import * as i18n from './translations'; import { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/translation_tab/header.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details/translation_tab/header.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/translation_tab/header.tsx rename to x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details/translation_tab/header.tsx diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/translation_tab/index.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details/translation_tab/index.tsx similarity index 97% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/translation_tab/index.tsx rename to x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details/translation_tab/index.tsx index 5772b737e227b..b3dcd8530ed2f 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/translation_tab/index.tsx +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details/translation_tab/index.tsx @@ -20,7 +20,7 @@ import { } from '@elastic/eui'; import { css } from '@emotion/css'; import { FormattedMessage } from '@kbn/i18n-react'; -import type { RuleMigration } from '../../../../../../../common/siem_migrations/model/rule_migration.gen'; +import type { RuleMigration } from '../../../../../../common/siem_migrations/model/rule_migration.gen'; import { TranslationTabHeader } from './header'; import { RuleQueryComponent } from './rule_query'; import * as i18n from './translations'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/translation_tab/rule_query.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details/translation_tab/rule_query.tsx similarity index 80% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/translation_tab/rule_query.tsx rename to x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details/translation_tab/rule_query.tsx index ee66cf0f0be8d..50977cafb18d0 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/translation_tab/rule_query.tsx +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details/translation_tab/rule_query.tsx @@ -7,8 +7,8 @@ import React, { useMemo } from 'react'; import { EuiMarkdownEditor, EuiMarkdownFormat, EuiTitle } from '@elastic/eui'; -import { SideHeader } from '../../../../../rule_management/components/rule_details/three_way_diff/components/side_header'; -import { FinalSideHelpInfo } from '../../../../../rule_management/components/rule_details/three_way_diff/final_side/final_side_help_info'; +import { SideHeader } from '../../../../../detection_engine/rule_management/components/rule_details/three_way_diff/components/side_header'; +import { FinalSideHelpInfo } from '../../../../../detection_engine/rule_management/components/rule_details/three_way_diff/final_side/final_side_help_info'; import * as i18n from './translations'; interface RuleQueryProps { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/translation_tab/translations.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details/translation_tab/translations.ts similarity index 100% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/translation_tab/translations.ts rename to x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details/translation_tab/translations.ts diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/translations.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details/translations.ts similarity index 100% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translation_details/translations.ts rename to x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details/translations.ts diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translations.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translations.ts similarity index 100% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/translations.ts rename to x-pack/plugins/security_solution/public/siem_migrations/rules/components/translations.ts diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/use_filter_siem_migrations_to_install.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/use_filter_siem_migrations_to_install.ts similarity index 86% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/use_filter_siem_migrations_to_install.ts rename to x-pack/plugins/security_solution/public/siem_migrations/rules/components/use_filter_siem_migrations_to_install.ts index ef9f4a7369dc6..bd4e20ba8e3de 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/use_filter_siem_migrations_to_install.ts +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/use_filter_siem_migrations_to_install.ts @@ -6,8 +6,8 @@ */ import { useMemo } from 'react'; -import type { RuleMigration } from '../../../../../common/siem_migrations/model/rule_migration.gen'; -import type { FilterOptions } from '../../../rule_management/logic/types'; +import type { RuleMigration } from '../../../../common/siem_migrations/model/rule_migration.gen'; +import type { FilterOptions } from '../../../detection_engine/rule_management/logic/types'; export type SiemMigrationsTableFilterOptions = Pick; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/use_siem_migrations_preview_flyout.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/use_siem_migrations_preview_flyout.tsx similarity index 91% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/use_siem_migrations_preview_flyout.tsx rename to x-pack/plugins/security_solution/public/siem_migrations/rules/components/use_siem_migrations_preview_flyout.tsx index ede9acad5798a..455d38fb4edf3 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/use_siem_migrations_preview_flyout.tsx +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/use_siem_migrations_preview_flyout.tsx @@ -8,9 +8,9 @@ import type { ReactNode } from 'react'; import React, { useCallback, useState, useMemo } from 'react'; import type { EuiTabbedContentTab } from '@elastic/eui'; -import type { RuleMigration } from '../../../../../common/siem_migrations/model/rule_migration.gen'; -import { invariant } from '../../../../../common/utils/invariant'; -import type { RuleSignatureId } from '../../../../../common/api/detection_engine'; +import type { RuleMigration } from '../../../../common/siem_migrations/model/rule_migration.gen'; +import { invariant } from '../../../../common/utils/invariant'; +import type { RuleSignatureId } from '../../../../common/api/detection_engine'; import { TranslationDetailsFlyout } from './translation_details/translation_details_flyout'; interface UseSiemMigrationsPreviewFlyoutParams { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/use_siem_migrations_table_columns.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/use_siem_migrations_table_columns.tsx similarity index 88% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/use_siem_migrations_table_columns.tsx rename to x-pack/plugins/security_solution/public/siem_migrations/rules/components/use_siem_migrations_table_columns.tsx index 63a2cb9eee93f..e4f20866c5d42 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/use_siem_migrations_table_columns.tsx +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/use_siem_migrations_table_columns.tsx @@ -9,12 +9,12 @@ import type { EuiBasicTableColumn } from '@elastic/eui'; import { EuiText, EuiLink } from '@elastic/eui'; import React, { useMemo } from 'react'; import type { Severity } from '@kbn/securitysolution-io-ts-alerting-types'; -import type { RuleMigration } from '../../../../../common/siem_migrations/model/rule_migration.gen'; -import { SeverityBadge } from '../../../../common/components/severity_badge'; -import * as rulesI18n from '../../../../detections/pages/detection_engine/rules/translations'; +import type { RuleMigration } from '../../../../common/siem_migrations/model/rule_migration.gen'; +import { SeverityBadge } from '../../../common/components/severity_badge'; +import * as rulesI18n from '../../../detections/pages/detection_engine/rules/translations'; import * as i18n from './translations'; import { useSiemMigrationsTableContext } from './siem_migrations_table_context'; -import { getNormalizedSeverity } from '../rules_table/helpers'; +import { getNormalizedSeverity } from '../../../detection_engine/rule_management_ui/components/rules_table/helpers'; import { StatusBadge } from './status_badge'; import { DEFAULT_TRANSLATION_RISK_SCORE, DEFAULT_TRANSLATION_SEVERITY } from './constants'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/utils.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/utils.tsx similarity index 92% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/utils.tsx rename to x-pack/plugins/security_solution/public/siem_migrations/rules/components/utils.tsx index c75fc775a6832..cd49311db21eb 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/siem_migrations/utils.tsx +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/utils.tsx @@ -8,7 +8,7 @@ import { RuleMigrationTranslationResultEnum, type RuleMigrationTranslationResult, -} from '../../../../../common/siem_migrations/model/rule_migration.gen'; +} from '../../../../common/siem_migrations/model/rule_migration.gen'; import * as i18n from './translations'; export const convertTranslationResultIntoText = (status?: RuleMigrationTranslationResult) => { diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/pages/index.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/pages/index.tsx new file mode 100644 index 0000000000000..ad438e41c1285 --- /dev/null +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/pages/index.tsx @@ -0,0 +1,70 @@ +/* + * 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 { redirectToDetections } from '../../../detections/pages/detection_engine/rules/helpers'; +import { SecurityPageName } from '../../../app/types'; +import { HeaderPage } from '../../../common/components/header_page'; +import { SecuritySolutionPageWrapper } from '../../../common/components/page_wrapper'; +import { useKibana } from '../../../common/lib/kibana'; +import { SpyRoute } from '../../../common/utils/route/spy_routes'; + +import { useUserData } from '../../../detections/components/user_info'; +import { useListsConfig } from '../../../detections/containers/detection_engine/lists/use_lists_config'; + +import * as i18n from './translations'; +import { SiemMigrationsTable } from '../components/siem_migrations_table'; +import { SiemMigrationsTableContextProvider } from '../components/siem_migrations_table_context'; +import { APP_UI_ID } from '../../../../common'; +import { NeedAdminForUpdateRulesCallOut } from '../../../detections/components/callouts/need_admin_for_update_callout'; +import { MissingPrivilegesCallOut } from '../../../detections/components/callouts/missing_privileges_callout'; +import { getDetectionEngineUrl } from '../../../common/components/link_to'; +import { SiemMigrationsHeaderButtons } from '../components/siem_migrations_header_buttons'; + +const RulesPageComponent: React.FC = () => { + const { navigateToApp } = useKibana().services.application; + + const [{ isSignalIndexExists, isAuthenticated, hasEncryptionKey }] = useUserData(); + const { needsConfiguration: needsListsConfiguration } = useListsConfig(); + + if ( + redirectToDetections( + isSignalIndexExists, + isAuthenticated, + hasEncryptionKey, + needsListsConfiguration + ) + ) { + navigateToApp(APP_UI_ID, { + deepLinkId: SecurityPageName.alerts, + path: getDetectionEngineUrl(), + }); + return null; + } + + return ( + <> + + + + + + + + + + + + + + + ); +}; + +export const RulesPage = React.memo(RulesPageComponent); +RulesPage.displayName = 'RulesPage'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/siem_migrations/translations.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/pages/translations.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/siem_migrations/translations.tsx rename to x-pack/plugins/security_solution/public/siem_migrations/rules/pages/translations.tsx diff --git a/x-pack/plugins/security_solution/public/types.ts b/x-pack/plugins/security_solution/public/types.ts index 6642e02d5ecd6..9829fe2ad0c25 100644 --- a/x-pack/plugins/security_solution/public/types.ts +++ b/x-pack/plugins/security_solution/public/types.ts @@ -83,6 +83,7 @@ import type { EntityAnalytics } from './entity_analytics'; import type { Assets } from './assets'; import type { Investigations } from './investigations'; import type { MachineLearning } from './machine_learning'; +import type { SiemMigrations } from './siem_migrations'; import type { Dashboards } from './dashboards'; import type { BreadcrumbsNav } from './common/breadcrumbs/types'; @@ -243,6 +244,7 @@ export interface SubPlugins { assets: Assets; investigations: Investigations; machineLearning: MachineLearning; + siemMigrations: SiemMigrations; } // TODO: find a better way to defined these types @@ -266,4 +268,5 @@ export interface StartedSubPlugins { assets: ReturnType; investigations: ReturnType; machineLearning: ReturnType; + siemMigrations: ReturnType; } From 8e0d110717594d429517d55e1806907d3174f112 Mon Sep 17 00:00:00 2001 From: Ievgen Sorokopud Date: Thu, 21 Nov 2024 18:05:33 +0100 Subject: [PATCH 3/7] Remove obsolete code --- .../security_solution/public/app/translations.ts | 9 ++++++--- .../hooks/use_is_siem_migrations_enabled.tsx | 12 ------------ .../public/siem_migrations/constants.ts | 16 ---------------- .../public/siem_migrations/links.ts | 4 ++-- 4 files changed, 8 insertions(+), 33 deletions(-) delete mode 100644 x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/hooks/use_is_siem_migrations_enabled.tsx delete mode 100644 x-pack/plugins/security_solution/public/siem_migrations/constants.ts diff --git a/x-pack/plugins/security_solution/public/app/translations.ts b/x-pack/plugins/security_solution/public/app/translations.ts index 2dae25954c3a9..1769a805f488f 100644 --- a/x-pack/plugins/security_solution/public/app/translations.ts +++ b/x-pack/plugins/security_solution/public/app/translations.ts @@ -101,9 +101,12 @@ export const EXCEPTIONS = i18n.translate('xpack.securitySolution.navigation.exce defaultMessage: 'Shared exception lists', }); -export const SIEM_MIGRATIONS = i18n.translate('xpack.securitySolution.navigation.siemMigrations', { - defaultMessage: 'SIEM Rules Migrations', -}); +export const SIEM_MIGRATIONS_RULES = i18n.translate( + 'xpack.securitySolution.navigation.siemMigrationsRules', + { + defaultMessage: 'SIEM Rules Migrations', + } +); export const ALERTS = i18n.translate('xpack.securitySolution.navigation.alerts', { defaultMessage: 'Alerts', diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/hooks/use_is_siem_migrations_enabled.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/hooks/use_is_siem_migrations_enabled.tsx deleted file mode 100644 index 8755df3210d29..0000000000000 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/hooks/use_is_siem_migrations_enabled.tsx +++ /dev/null @@ -1,12 +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 { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; - -export const useIsSiemMigrationsEnabled = () => { - return useIsExperimentalFeatureEnabled('siemMigrationsEnabled'); -}; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/constants.ts b/x-pack/plugins/security_solution/public/siem_migrations/constants.ts deleted file mode 100644 index 0eb277bd61875..0000000000000 --- a/x-pack/plugins/security_solution/public/siem_migrations/constants.ts +++ /dev/null @@ -1,16 +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 const PAGE_CONTENT_WIDTH = '1150px'; - -export enum OnboardingCardId { - integrations = 'integrations', - dashboards = 'dashboards', - rules = 'rules', - alerts = 'alerts', - assistant = 'assistant', - attackDiscovery = 'attack_discovery', -} diff --git a/x-pack/plugins/security_solution/public/siem_migrations/links.ts b/x-pack/plugins/security_solution/public/siem_migrations/links.ts index bcdd75baad40d..34db8a357785a 100644 --- a/x-pack/plugins/security_solution/public/siem_migrations/links.ts +++ b/x-pack/plugins/security_solution/public/siem_migrations/links.ts @@ -11,13 +11,13 @@ import { SERVER_APP_ID, SIEM_MIGRATIONS_RULES_PATH, } from '../../common/constants'; -import { SIEM_MIGRATIONS } from '../app/translations'; +import { SIEM_MIGRATIONS_RULES } from '../app/translations'; import type { LinkItem } from '../common/links/types'; import { IconConsoleCloud } from '../common/icons/console_cloud'; export const siemMigrationsLinks: LinkItem = { id: SecurityPageName.siemMigrationsRules, - title: SIEM_MIGRATIONS, + title: SIEM_MIGRATIONS_RULES, description: i18n.translate('xpack.securitySolution.appLinks.siemMigrationsRulesDescription', { defaultMessage: 'SIEM Rules Migrations.', }), From 27296a0aaa696bc3cdd022a7fe67ccf58cac1ded Mon Sep 17 00:00:00 2001 From: Ievgen Sorokopud Date: Thu, 21 Nov 2024 23:18:09 +0100 Subject: [PATCH 4/7] Set codeowners for the public siem_migrations folder --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 6a0a36feb9e21..d47a5b9397613 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -2061,6 +2061,7 @@ x-pack/test/security_solution_api_integration/test_suites/sources @elastic/secur /x-pack/plugins/security_solution/server/lib/siem_migrations @elastic/security-threat-hunting /x-pack/plugins/security_solution/common/siem_migrations @elastic/security-threat-hunting +/x-pack/plugins/security_solution/public/siem_migrations @elastic/security-threat-hunting ## Security Solution Threat Hunting areas - Threat Hunting Investigations From 745713407b8cf526ba470224c2f4caabbd3a7db6 Mon Sep 17 00:00:00 2001 From: Ievgen Sorokopud Date: Fri, 22 Nov 2024 13:04:12 +0100 Subject: [PATCH 5/7] Review feedback: get rid of the context Additionally: * updated folder structure * simplified namings --- .../index.tsx} | 35 +++- .../components/header_buttons/translations.ts | 23 +++ .../filters.tsx} | 42 ++-- .../rules/components/rules_table/index.tsx | 132 ++++++++++++ .../no_items_message.tsx} | 10 +- .../components/rules_table/translations.ts | 36 ++++ .../components/siem_migrations_table.tsx | 95 --------- .../siem_migrations_table_context.tsx | 188 ------------------ .../rules/components/status_badge/index.tsx | 3 +- .../constants.ts | 0 .../index.tsx} | 12 +- .../translation_tab/header.tsx | 0 .../translation_tab/index.tsx | 2 +- .../translation_tab/rule_query.tsx | 0 .../translation_tab/translations.ts | 10 +- .../translations.ts | 6 +- .../rules/components/translations.ts | 89 --------- .../use_siem_migrations_preview_flyout.tsx | 82 -------- .../rules/hooks/translations.ts | 15 ++ .../use_filter_rules_to_install.ts} | 6 +- .../rules/hooks/use_rule_preview_flyout.tsx | 55 +++++ .../use_rules_table_columns.tsx} | 52 ++--- .../siem_migrations/rules/pages/index.tsx | 67 +++++-- .../rules/pages/translations.tsx | 9 +- .../rules/{components => utils}/constants.ts | 0 .../utils.tsx => utils/helpers.tsx} | 0 .../rules/utils/translations.ts | 36 ++++ 27 files changed, 463 insertions(+), 542 deletions(-) rename x-pack/plugins/security_solution/public/siem_migrations/rules/components/{siem_migrations_header_buttons.tsx => header_buttons/index.tsx} (75%) create mode 100644 x-pack/plugins/security_solution/public/siem_migrations/rules/components/header_buttons/translations.ts rename x-pack/plugins/security_solution/public/siem_migrations/rules/components/{siem_migrations_table_filters.tsx => rules_table/filters.tsx} (65%) create mode 100644 x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/index.tsx rename x-pack/plugins/security_solution/public/siem_migrations/rules/components/{siem_migrations_no_items_message.tsx => rules_table/no_items_message.tsx} (82%) create mode 100644 x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/translations.ts delete mode 100644 x-pack/plugins/security_solution/public/siem_migrations/rules/components/siem_migrations_table.tsx delete mode 100644 x-pack/plugins/security_solution/public/siem_migrations/rules/components/siem_migrations_table_context.tsx rename x-pack/plugins/security_solution/public/siem_migrations/rules/components/{translation_details => translation_details_flyout}/constants.ts (100%) rename x-pack/plugins/security_solution/public/siem_migrations/rules/components/{translation_details/translation_details_flyout.tsx => translation_details_flyout/index.tsx} (97%) rename x-pack/plugins/security_solution/public/siem_migrations/rules/components/{translation_details => translation_details_flyout}/translation_tab/header.tsx (100%) rename x-pack/plugins/security_solution/public/siem_migrations/rules/components/{translation_details => translation_details_flyout}/translation_tab/index.tsx (98%) rename x-pack/plugins/security_solution/public/siem_migrations/rules/components/{translation_details => translation_details_flyout}/translation_tab/rule_query.tsx (100%) rename x-pack/plugins/security_solution/public/siem_migrations/rules/components/{translation_details => translation_details_flyout}/translation_tab/translations.ts (61%) rename x-pack/plugins/security_solution/public/siem_migrations/rules/components/{translation_details => translation_details_flyout}/translations.ts (68%) delete mode 100644 x-pack/plugins/security_solution/public/siem_migrations/rules/components/translations.ts delete mode 100644 x-pack/plugins/security_solution/public/siem_migrations/rules/components/use_siem_migrations_preview_flyout.tsx create mode 100644 x-pack/plugins/security_solution/public/siem_migrations/rules/hooks/translations.ts rename x-pack/plugins/security_solution/public/siem_migrations/rules/{components/use_filter_siem_migrations_to_install.ts => hooks/use_filter_rules_to_install.ts} (86%) create mode 100644 x-pack/plugins/security_solution/public/siem_migrations/rules/hooks/use_rule_preview_flyout.tsx rename x-pack/plugins/security_solution/public/siem_migrations/rules/{components/use_siem_migrations_table_columns.tsx => hooks/use_rules_table_columns.tsx} (71%) rename x-pack/plugins/security_solution/public/siem_migrations/rules/{components => utils}/constants.ts (100%) rename x-pack/plugins/security_solution/public/siem_migrations/rules/{components/utils.tsx => utils/helpers.tsx} (100%) create mode 100644 x-pack/plugins/security_solution/public/siem_migrations/rules/utils/translations.ts diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/siem_migrations_header_buttons.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/header_buttons/index.tsx similarity index 75% rename from x-pack/plugins/security_solution/public/siem_migrations/rules/components/siem_migrations_header_buttons.tsx rename to x-pack/plugins/security_solution/public/siem_migrations/rules/components/header_buttons/index.tsx index 80ed7eb8983ee..ba73bd9c84946 100644 --- a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/siem_migrations_header_buttons.tsx +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/header_buttons/index.tsx @@ -5,18 +5,36 @@ * 2.0. */ +import React, { useMemo } from 'react'; + import type { EuiComboBoxOptionOption } from '@elastic/eui'; import { EuiComboBox, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import React, { useMemo } from 'react'; -import { useSiemMigrationsTableContext } from './siem_migrations_table_context'; import * as i18n from './translations'; -export const SiemMigrationsHeaderButtons = () => { - const { - state: { migrationsIds, selectedMigrationId }, - actions: { onMigrationIdChange }, - } = useSiemMigrationsTableContext(); +export interface HeaderButtonsProps { + /** + * Available rule migrations ids + */ + migrationsIds: string[]; + /** + * Selected rule migration id + */ + selectedMigrationId: string | undefined; + + /** + * Handles migration selection changes + * @param selectedId Selected migration id + * @returns + */ + onMigrationIdChange: (selectedId?: string) => void; +} + +const HeaderButtonsComponent: React.FC = ({ + migrationsIds, + selectedMigrationId, + onMigrationIdChange, +}) => { const migrationOptions = useMemo(() => { const options: Array> = migrationsIds.map((id, index) => ({ value: id, @@ -61,3 +79,6 @@ export const SiemMigrationsHeaderButtons = () => { ); }; + +export const HeaderButtons = React.memo(HeaderButtonsComponent); +HeaderButtons.displayName = 'HeaderButtons'; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/header_buttons/translations.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/header_buttons/translations.ts new file mode 100644 index 0000000000000..e00721c70103a --- /dev/null +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/header_buttons/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 SIEM_MIGRATIONS_OPTION_AREAL_LABEL = i18n.translate( + 'xpack.securitySolution.siemMigrations.rules.selectionOption.arealLabel', + { + defaultMessage: 'Select a migration', + } +); + +export const SIEM_MIGRATIONS_OPTION_LABEL = (optionIndex: number) => + i18n.translate('xpack.securitySolution.siemMigrations.rules.selectionOption.title', { + defaultMessage: 'SIEM rule migration {optionIndex}', + values: { + optionIndex, + }, + }); diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/siem_migrations_table_filters.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/filters.tsx similarity index 65% rename from x-pack/plugins/security_solution/public/siem_migrations/rules/components/siem_migrations_table_filters.tsx rename to x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/filters.tsx index 8faa94f289a62..17b1065583073 100644 --- a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/siem_migrations_table_filters.tsx +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/filters.tsx @@ -7,27 +7,44 @@ import { EuiFilterGroup, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { isEqual } from 'lodash/fp'; +import type { Dispatch, SetStateAction } from 'react'; import React, { useCallback } from 'react'; import styled from 'styled-components'; import * as i18n from './translations'; -import { TagsFilterPopover } from '../../../detection_engine/rule_management_ui/components/rules_table/rules_table_filters/tags_filter_popover'; -import { RuleSearchField } from '../../../detection_engine/rule_management_ui/components/rules_table/rules_table_filters/rule_search_field'; -import { useSiemMigrationsTableContext } from './siem_migrations_table_context'; +import { TagsFilterPopover } from '../../../../detection_engine/rule_management_ui/components/rules_table/rules_table_filters/tags_filter_popover'; +import { RuleSearchField } from '../../../../detection_engine/rule_management_ui/components/rules_table/rules_table_filters/rule_search_field'; +import type { TableFilterOptions } from '../../hooks/use_filter_rules_to_install'; const FilterWrapper = styled(EuiFlexGroup)` margin-bottom: ${({ theme }) => theme.eui.euiSizeM}; `; +export interface FiltersComponentProps { + /** + * Currently selected table filter + */ + filterOptions: TableFilterOptions; + + /** + * All unique tags for all rule translations + */ + tags: string[]; + + /** + * Handles filter options changes + */ + setFilterOptions: Dispatch>; +} + /** * Collection of filters for filtering data within the SIEM Rules Migrations table. * Contains search bar and tag selection */ -const SiemMigrationsTableFiltersComponent = () => { - const { - state: { filterOptions, tags }, - actions: { setFilterOptions }, - } = useSiemMigrationsTableContext(); - +const FiltersComponent: React.FC = ({ + filterOptions, + tags, + setFilterOptions, +}) => { const { tags: selectedTags } = filterOptions; const handleOnSearch = useCallback( @@ -73,8 +90,5 @@ const SiemMigrationsTableFiltersComponent = () => { ); }; -SiemMigrationsTableFiltersComponent.displayName = 'SiemMigrationsTableFiltersComponent'; - -export const SiemMigrationsTableFilters = React.memo(SiemMigrationsTableFiltersComponent); - -SiemMigrationsTableFilters.displayName = 'SiemMigrationsTableFilters'; +export const Filters = React.memo(FiltersComponent); +Filters.displayName = 'Filters'; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/index.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/index.tsx new file mode 100644 index 0000000000000..8758fdcaf7b10 --- /dev/null +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/index.tsx @@ -0,0 +1,132 @@ +/* + * 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 { + EuiInMemoryTable, + EuiSkeletonLoading, + EuiProgress, + EuiSkeletonTitle, + EuiSkeletonText, + EuiFlexGroup, + EuiFlexItem, +} from '@elastic/eui'; +import React, { useMemo, useState } from 'react'; + +import type { RuleMigration } from '../../../../../common/siem_migrations/model/rule_migration.gen'; +import { + RULES_TABLE_INITIAL_PAGE_SIZE, + RULES_TABLE_PAGE_SIZE_OPTIONS, +} from '../../../../detection_engine/rule_management_ui/components/rules_table/constants'; +import { NoItemsMessage } from './no_items_message'; +import { Filters } from './filters'; +import { useRulesTableColumns } from '../../hooks/use_rules_table_columns'; +import { useGetRuleMigrationsQuery } from '../../api/hooks/use_get_rule_migrations'; +import type { TableFilterOptions } from '../../hooks/use_filter_rules_to_install'; +import { useFilterRulesToInstall } from '../../hooks/use_filter_rules_to_install'; + +export interface RulesTableComponentProps { + /** + * Selected rule migration id + */ + migrationId: string | undefined; + + /** + * Opens the flyout with the details of the rule migration + * @param rule Rule migration + * @returns + */ + openRulePreview: (rule: RuleMigration) => void; +} + +/** + * Table Component for displaying SIEM rules migrations + */ +const RulesTableComponent: React.FC = ({ + migrationId, + openRulePreview, +}) => { + const { data: ruleMigrations, isLoading } = useGetRuleMigrationsQuery(migrationId); + + const [selectedRuleMigrations, setSelectedRuleMigrations] = useState([]); + + const [filterOptions, setFilterOptions] = useState({ + filter: '', + tags: [], + }); + + const filteredRuleMigrations = useFilterRulesToInstall({ + filterOptions, + ruleMigrations: ruleMigrations ?? [], + }); + + const tags = useMemo(() => [], []); + + const shouldShowProgress = isLoading; + + const rulesColumns = useRulesTableColumns({ + openRulePreview, + }); + + return ( + <> + {shouldShowProgress && ( + + )} + + + + + } + loadedContent={ + !filteredRuleMigrations.length ? ( + + ) : ( + <> + + + + + + + true, + onSelectionChange: setSelectedRuleMigrations, + initialSelected: selectedRuleMigrations, + }} + itemId="rule_id" + data-test-subj="rules-translation-table" + columns={rulesColumns} + /> + + ) + } + /> + + ); +}; + +export const RulesTable = React.memo(RulesTableComponent); +RulesTable.displayName = 'RulesTable'; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/siem_migrations_no_items_message.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/no_items_message.tsx similarity index 82% rename from x-pack/plugins/security_solution/public/siem_migrations/rules/components/siem_migrations_no_items_message.tsx rename to x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/no_items_message.tsx index 3ce9e21227471..044375b66b78e 100644 --- a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/siem_migrations_no_items_message.tsx +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/no_items_message.tsx @@ -7,11 +7,11 @@ import { EuiButton, EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import React from 'react'; -import { SecurityPageName } from '../../../../common'; -import { useGetSecuritySolutionLinkProps } from '../../../common/components/links'; +import { SecurityPageName } from '../../../../../common'; +import { useGetSecuritySolutionLinkProps } from '../../../../common/components/links'; import * as i18n from './translations'; -const SiemMigrationsTableNoItemsMessageComponent = () => { +const NoItemsMessageComponent = () => { const getSecuritySolutionLinkProps = useGetSecuritySolutionLinkProps(); const { onClick: onClickLink } = getSecuritySolutionLinkProps({ deepLinkId: SecurityPageName.rules, @@ -48,6 +48,4 @@ const SiemMigrationsTableNoItemsMessageComponent = () => { ); }; -export const SiemMigrationsTableNoItemsMessage = React.memo( - SiemMigrationsTableNoItemsMessageComponent -); +export const NoItemsMessage = React.memo(NoItemsMessageComponent); diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/translations.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/translations.ts new file mode 100644 index 0000000000000..812f26f628e49 --- /dev/null +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/translations.ts @@ -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 { i18n } from '@kbn/i18n'; + +export const SEARCH_PLACEHOLDER = i18n.translate( + 'xpack.securitySolution.siemMigrations.rules.table.searchBarPlaceholder', + { + defaultMessage: 'Search by rule name', + } +); + +export const NO_TRANSLATIONS_AVAILABLE_FOR_INSTALL = i18n.translate( + 'xpack.securitySolution.siemMigrations.rules.table.noRulesTitle', + { + defaultMessage: 'Empty migration', + } +); + +export const NO_TRANSLATIONS_AVAILABLE_FOR_INSTALL_BODY = i18n.translate( + 'xpack.securitySolution.siemMigrations.rules.table.noRulesBodyTitle', + { + defaultMessage: 'There are no translations available for installation', + } +); + +export const GO_BACK_TO_RULES_TABLE_BUTTON = i18n.translate( + 'xpack.securitySolution.siemMigrations.rules.table.goToMigrationsPageButton', + { + defaultMessage: 'Go back to SIEM Migrations', + } +); diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/siem_migrations_table.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/siem_migrations_table.tsx deleted file mode 100644 index 25aafd004ce96..0000000000000 --- a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/siem_migrations_table.tsx +++ /dev/null @@ -1,95 +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 { - EuiInMemoryTable, - EuiSkeletonLoading, - EuiProgress, - EuiSkeletonTitle, - EuiSkeletonText, - EuiFlexGroup, - EuiFlexItem, -} from '@elastic/eui'; -import React from 'react'; - -import { - RULES_TABLE_INITIAL_PAGE_SIZE, - RULES_TABLE_PAGE_SIZE_OPTIONS, -} from '../../../detection_engine/rule_management_ui/components/rules_table/constants'; -import { SiemMigrationsTableNoItemsMessage } from './siem_migrations_no_items_message'; -import { useSiemMigrationsTableContext } from './siem_migrations_table_context'; -import { SiemMigrationsTableFilters } from './siem_migrations_table_filters'; -import { useSiemMigrationsTableColumns } from './use_siem_migrations_table_columns'; - -/** - * Table Component for displaying SIEM rules migrations - */ -export const SiemMigrationsTable = React.memo(() => { - const siemMigrationsTableContext = useSiemMigrationsTableContext(); - - const { - state: { ruleMigrations, isLoading, selectedRuleMigrations }, - actions: { selectRuleMigrations }, - } = siemMigrationsTableContext; - const rulesColumns = useSiemMigrationsTableColumns(); - - const shouldShowProgress = isLoading; - - return ( - <> - {shouldShowProgress && ( - - )} - - - - - } - loadedContent={ - !ruleMigrations.length ? ( - - ) : ( - <> - - - - - - - true, - onSelectionChange: selectRuleMigrations, - initialSelected: selectedRuleMigrations, - }} - itemId="rule_id" - data-test-subj="rules-translation-table" - columns={rulesColumns} - /> - - ) - } - /> - - ); -}); - -SiemMigrationsTable.displayName = 'SiemMigrationsTable'; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/siem_migrations_table_context.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/siem_migrations_table_context.tsx deleted file mode 100644 index 6cca599f53a4d..0000000000000 --- a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/siem_migrations_table_context.tsx +++ /dev/null @@ -1,188 +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 type { Dispatch, SetStateAction } from 'react'; -import React, { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react'; -import type { RuleMigration } from '../../../../common/siem_migrations/model/rule_migration.gen'; -import type { RuleSignatureId } from '../../../../common/api/detection_engine'; -import { invariant } from '../../../../common/utils/invariant'; -import type { SiemMigrationsTableFilterOptions } from './use_filter_siem_migrations_to_install'; -import { useFilterSiemMigrationsToInstall } from './use_filter_siem_migrations_to_install'; -import { useSiemMigrationsPreviewFlyout } from './use_siem_migrations_preview_flyout'; -import { useGetRuleMigrationsStatsAllQuery } from '../api/hooks/use_get_rule_migrations_stats_all'; -import { useGetRuleMigrationsQuery } from '../api/hooks/use_get_rule_migrations'; - -export interface SiemMigrationsTableState { - /** - * Available rule migrations ids - */ - migrationsIds: string[]; - /** - * Selected rule migration id - */ - selectedMigrationId: string | undefined; - /** - * Rule migrations available after applying `filterOptions` - */ - ruleMigrations: RuleMigration[]; - /** - * Currently selected table filter - */ - filterOptions: SiemMigrationsTableFilterOptions; - /** - * All unique tags for all rule translations - */ - tags: string[]; - /** - * If true then there is no cached data and the query is currently fetching. - */ - isLoading: boolean; - /** - * Rule rows selected in EUI InMemory Table - */ - selectedRuleMigrations: RuleMigration[]; -} - -export interface SiemMigrationsTableActions { - setFilterOptions: Dispatch>; - selectRuleMigrations: (rules: RuleMigration[]) => void; - openRuleTranslationPreview: (ruleId: RuleSignatureId) => void; - onMigrationIdChange: (selectedId?: string) => void; -} - -export interface SiemMigrationsContextType { - state: SiemMigrationsTableState; - actions: SiemMigrationsTableActions; -} - -const SiemMigrationsTableContext = createContext(null); - -interface SiemMigrationsTableContextProviderProps { - children: React.ReactNode; -} - -const SIEM_MIGRATIONS_INSTALL_FLYOUT_ANCHOR = 'installSiemMigrationsPreview'; - -export const SiemMigrationsTableContextProvider = ({ - children, -}: SiemMigrationsTableContextProviderProps) => { - const [selectedRuleMigrations, setSelectedRuleMigrations] = useState([]); - - const [filterOptions, setFilterOptions] = useState({ - filter: '', - tags: [], - }); - - const { data: ruleMigrationsStatsAll, isLoading: isLoadingMigrationsStats } = - useGetRuleMigrationsStatsAllQuery(); - const migrationsIds = useMemo(() => { - if (isLoadingMigrationsStats || !ruleMigrationsStatsAll?.length) { - return []; - } - return ruleMigrationsStatsAll - .filter((migration) => migration.status === 'finished') - .map((migration) => migration.migration_id); - }, [isLoadingMigrationsStats, ruleMigrationsStatsAll]); - - const [selectedMigrationId, setSelectedMigrationId] = useState(); - const onMigrationIdChange = (selectedId?: string) => { - setSelectedMigrationId(selectedId); - }; - - useEffect(() => { - if (!migrationsIds.length) { - return; - } - const index = migrationsIds.findIndex((id) => id === selectedMigrationId); - if (index === -1) { - setSelectedMigrationId(migrationsIds[0]); - } - }, [migrationsIds, selectedMigrationId]); - - const { data: ruleMigrations, isLoading: isLoadingRuleMigrations } = - useGetRuleMigrationsQuery(selectedMigrationId); - - const filteredRuleMigrations = useFilterSiemMigrationsToInstall({ - filterOptions, - ruleMigrations: ruleMigrations ?? [], - }); - - const tags = useMemo(() => [], []); - - const ruleActionsFactory = useCallback( - (ruleMigration: RuleMigration, closeRuleMigrationPreview: () => void) => { - // TODO: Add flyout action buttons - return null; - }, - [] - ); - - const { ruleMigrationPreviewFlyout, openRuleTranslationPreview } = useSiemMigrationsPreviewFlyout( - { - ruleMigrations: filteredRuleMigrations, - ruleActionsFactory, - flyoutProps: { - id: SIEM_MIGRATIONS_INSTALL_FLYOUT_ANCHOR, - dataTestSubj: SIEM_MIGRATIONS_INSTALL_FLYOUT_ANCHOR, - }, - } - ); - - const actions = useMemo( - () => ({ - setFilterOptions, - selectRuleMigrations: setSelectedRuleMigrations, - openRuleTranslationPreview, - onMigrationIdChange, - }), - [openRuleTranslationPreview] - ); - - const providerValue = useMemo(() => { - return { - state: { - migrationsIds, - selectedMigrationId, - ruleMigrations: filteredRuleMigrations, - filterOptions, - tags, - isLoading: isLoadingMigrationsStats || isLoadingRuleMigrations, - selectedRuleMigrations, - }, - actions, - }; - }, [ - migrationsIds, - selectedMigrationId, - filteredRuleMigrations, - filterOptions, - tags, - isLoadingMigrationsStats, - isLoadingRuleMigrations, - selectedRuleMigrations, - actions, - ]); - - return ( - - <> - {children} - {ruleMigrationPreviewFlyout} - - - ); -}; - -export const useSiemMigrationsTableContext = (): SiemMigrationsContextType => { - const rulesTableContext = useContext(SiemMigrationsTableContext); - invariant( - rulesTableContext, - 'useSiemMigrationsTableContext should be used inside SiemMigrationsTableContextProvider' - ); - - return rulesTableContext; -}; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/status_badge/index.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/status_badge/index.tsx index 7f5728ac9bb96..40b3c5ceb5719 100644 --- a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/status_badge/index.tsx +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/status_badge/index.tsx @@ -10,7 +10,7 @@ import { euiLightVars } from '@kbn/ui-theme'; import type { RuleMigrationTranslationResult } from '../../../../../common/siem_migrations/model/rule_migration.gen'; import { HealthTruncateText } from '../../../../common/components/health_truncate_text'; -import { convertTranslationResultIntoText } from '../utils'; +import { convertTranslationResultIntoText } from '../../utils/helpers'; const { euiColorVis0, euiColorVis7, euiColorVis9 } = euiLightVars; const statusToColorMap: Record = { @@ -46,3 +46,4 @@ const StatusBadgeComponent: React.FC = ({ }; export const StatusBadge = React.memo(StatusBadgeComponent); +StatusBadge.displayName = 'StatusBadge'; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details/constants.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details_flyout/constants.ts similarity index 100% rename from x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details/constants.ts rename to x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details_flyout/constants.ts diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details/translation_details_flyout.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details_flyout/index.tsx similarity index 97% rename from x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details/translation_details_flyout.tsx rename to x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details_flyout/index.tsx index e33526e885c5a..4aaff21281d64 100644 --- a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details/translation_details_flyout.tsx +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details_flyout/index.tsx @@ -41,7 +41,10 @@ import { LARGE_DESCRIPTION_LIST_COLUMN_WIDTHS, } from './constants'; import { TranslationTab } from './translation_tab'; -import { DEFAULT_TRANSLATION_RISK_SCORE, DEFAULT_TRANSLATION_SEVERITY } from '../constants'; +import { + DEFAULT_TRANSLATION_RISK_SCORE, + DEFAULT_TRANSLATION_SEVERITY, +} from '../../utils/constants'; const StyledEuiFlyoutBody = styled(EuiFlyoutBody)` .euiFlyoutBody__overflow { @@ -118,8 +121,6 @@ interface TranslationDetailsFlyoutProps { ruleMigration: RuleMigration; size?: EuiFlyoutProps['size']; extraTabs?: EuiTabbedContentTab[]; - dataTestSubj?: string; - id?: string; closeFlyout: () => void; } @@ -128,8 +129,6 @@ export const TranslationDetailsFlyout = ({ ruleMigration, size = 'm', extraTabs = [], - dataTestSubj, - id, closeFlyout, }: TranslationDetailsFlyoutProps) => { const { expandedOverviewSections, toggleOverviewSection } = useOverviewTabSections(); @@ -211,12 +210,11 @@ export const TranslationDetailsFlyout = ({ return ( diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details/translation_tab/header.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details_flyout/translation_tab/header.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details/translation_tab/header.tsx rename to x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details_flyout/translation_tab/header.tsx diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details/translation_tab/index.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details_flyout/translation_tab/index.tsx similarity index 98% rename from x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details/translation_tab/index.tsx rename to x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details_flyout/translation_tab/index.tsx index b3dcd8530ed2f..66836b8ea5631 100644 --- a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details/translation_tab/index.tsx +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details_flyout/translation_tab/index.tsx @@ -24,7 +24,7 @@ import type { RuleMigration } from '../../../../../../common/siem_migrations/mod import { TranslationTabHeader } from './header'; import { RuleQueryComponent } from './rule_query'; import * as i18n from './translations'; -import { convertTranslationResultIntoText } from '../../utils'; +import { convertTranslationResultIntoText } from '../../../utils/helpers'; interface TranslationTabProps { ruleMigration: RuleMigration; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details/translation_tab/rule_query.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details_flyout/translation_tab/rule_query.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details/translation_tab/rule_query.tsx rename to x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details_flyout/translation_tab/rule_query.tsx diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details/translation_tab/translations.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details_flyout/translation_tab/translations.ts similarity index 61% rename from x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details/translation_tab/translations.ts rename to x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details_flyout/translation_tab/translations.ts index 782c1fba8a1bb..e7532a5a8b2e3 100644 --- a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details/translation_tab/translations.ts +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details_flyout/translation_tab/translations.ts @@ -8,35 +8,35 @@ import { i18n } from '@kbn/i18n'; export const TAB_HEADER_TITLE = i18n.translate( - 'xpack.securitySolution.detectionEngine.translationDetails.translationTab.title', + 'xpack.securitySolution.siemMigrations.rules.translationDetails.translationTab.title', { defaultMessage: 'Translation', } ); export const NAME_LABEL = i18n.translate( - 'xpack.securitySolution.detectionEngine.translationDetails.translationTab.nameLabel', + 'xpack.securitySolution.siemMigrations.rules.translationDetails.translationTab.nameLabel', { defaultMessage: 'Name', } ); export const SPLUNK_QUERY_TITLE = i18n.translate( - 'xpack.securitySolution.detectionEngine.translationDetails.translationTab.splunkQueryTitle', + 'xpack.securitySolution.siemMigrations.rules.translationDetails.translationTab.splunkQueryTitle', { defaultMessage: 'Splunk query', } ); export const ESQL_TRANSLATION_TITLE = i18n.translate( - 'xpack.securitySolution.detectionEngine.translationDetails.translationTab.esqlTranslationTitle', + 'xpack.securitySolution.siemMigrations.rules.translationDetails.translationTab.esqlTranslationTitle', { defaultMessage: 'ES|QL translation', } ); export const TRANSLATED_QUERY_AREAL_LABEL = i18n.translate( - 'xpack.securitySolution.detectionEngine.translationDetails.translationTab.queryArealLabel', + 'xpack.securitySolution.siemMigrations.rules.translationDetails.translationTab.queryArealLabel', { defaultMessage: 'Translated query', } diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details/translations.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details_flyout/translations.ts similarity index 68% rename from x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details/translations.ts rename to x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details_flyout/translations.ts index fe5ca4700a301..8e6582b8c198e 100644 --- a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details/translations.ts +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details_flyout/translations.ts @@ -8,21 +8,21 @@ import { i18n } from '@kbn/i18n'; export const OVERVIEW_TAB_LABEL = i18n.translate( - 'xpack.securitySolution.detectionEngine.translationDetails.overviewTabLabel', + 'xpack.securitySolution.siemMigrations.rules.translationDetails.overviewTabLabel', { defaultMessage: 'Overview', } ); export const TRANSLATION_TAB_LABEL = i18n.translate( - 'xpack.securitySolution.detectionEngine.translationDetails.translationTabLabel', + 'xpack.securitySolution.siemMigrations.rules.translationDetails.translationTabLabel', { defaultMessage: 'Translation', } ); export const DISMISS_BUTTON_LABEL = i18n.translate( - 'xpack.securitySolution.detectionEngine.translationDetails.dismissButtonLabel', + 'xpack.securitySolution.siemMigrations.rules.translationDetails.dismissButtonLabel', { defaultMessage: 'Dismiss', } diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translations.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translations.ts deleted file mode 100644 index 60d4662f90646..0000000000000 --- a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translations.ts +++ /dev/null @@ -1,89 +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 { i18n } from '@kbn/i18n'; - -export const SEARCH_PLACEHOLDER = i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.siemMigrations.searchBarPlaceholder', - { - defaultMessage: 'Search by rule name', - } -); - -export const SIEM_TRANSLATION_RESULT_FULL_LABEL = i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.siemMigrations.translationResult.full', - { - defaultMessage: 'Fully translated', - } -); - -export const SIEM_TRANSLATION_RESULT_PARTIAL_LABEL = i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.siemMigrations.translationResult.partially', - { - defaultMessage: 'Partially translated', - } -); - -export const SIEM_TRANSLATION_RESULT_UNTRANSLATABLE_LABEL = i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.siemMigrations.translationResult.untranslatable', - { - defaultMessage: 'Not translated', - } -); - -export const SIEM_TRANSLATION_RESULT_UNKNOWN_LABEL = i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.siemMigrations.translationResult.unknown', - { - defaultMessage: 'Unknown', - } -); - -export const NO_TRANSLATIONS_AVAILABLE_FOR_INSTALL = i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.siemMigrations.noRulesTitle', - { - defaultMessage: 'Empty migration', - } -); - -export const NO_TRANSLATIONS_AVAILABLE_FOR_INSTALL_BODY = i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.siemMigrations.noRulesBodyTitle', - { - defaultMessage: 'There are no translations available for installation', - } -); - -export const GO_BACK_TO_RULES_TABLE_BUTTON = i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.siemMigrations.goToMigrationsPageButton', - { - defaultMessage: 'Go back to SIEM Migrations', - } -); - -export const COLUMN_STATUS = i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.siemMigrations.columns.statusTitle', - { - defaultMessage: 'Status', - } -); - -export const SIEM_MIGRATIONS_OPTION_AREAL_LABEL = i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.siemMigrations.selectionOption.arealLabel', - { - defaultMessage: 'Select a migration', - } -); - -export const SIEM_MIGRATIONS_OPTION_LABEL = (optionIndex: number) => - i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.siemMigrations.selectionOption.title', - { - defaultMessage: 'SIEM rule migration {optionIndex}', - values: { - optionIndex, - }, - } - ); diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/use_siem_migrations_preview_flyout.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/use_siem_migrations_preview_flyout.tsx deleted file mode 100644 index 455d38fb4edf3..0000000000000 --- a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/use_siem_migrations_preview_flyout.tsx +++ /dev/null @@ -1,82 +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 type { ReactNode } from 'react'; -import React, { useCallback, useState, useMemo } from 'react'; -import type { EuiTabbedContentTab } from '@elastic/eui'; -import type { RuleMigration } from '../../../../common/siem_migrations/model/rule_migration.gen'; -import { invariant } from '../../../../common/utils/invariant'; -import type { RuleSignatureId } from '../../../../common/api/detection_engine'; -import { TranslationDetailsFlyout } from './translation_details/translation_details_flyout'; - -interface UseSiemMigrationsPreviewFlyoutParams { - ruleMigrations: RuleMigration[]; - ruleActionsFactory: ( - ruleMigration: RuleMigration, - closeRuleMigrationPreview: () => void - ) => ReactNode; - extraTabsFactory?: (ruleMigration: RuleMigration) => EuiTabbedContentTab[]; - flyoutProps: SiemMigrationsPreviewFlyoutProps; -} - -interface SiemMigrationsPreviewFlyoutProps { - /** - * Rule preview flyout unique id used in HTML - */ - id: string; - dataTestSubj: string; -} - -interface UseSiemMigrationsPreviewFlyoutResult { - ruleMigrationPreviewFlyout: ReactNode; - openRuleTranslationPreview: (ruleId: RuleSignatureId) => void; - closeRuleMigrationPreview: () => void; -} - -export function useSiemMigrationsPreviewFlyout({ - ruleMigrations, - extraTabsFactory, - ruleActionsFactory, - flyoutProps, -}: UseSiemMigrationsPreviewFlyoutParams): UseSiemMigrationsPreviewFlyoutResult { - const [ruleMigration, setRuleMigrationForPreview] = useState(); - const closeRuleMigrationPreview = useCallback(() => setRuleMigrationForPreview(undefined), []); - const ruleActions = useMemo( - () => ruleMigration && ruleActionsFactory(ruleMigration, closeRuleMigrationPreview), - [ruleMigration, ruleActionsFactory, closeRuleMigrationPreview] - ); - const extraTabs = useMemo( - () => (ruleMigration && extraTabsFactory ? extraTabsFactory(ruleMigration) : []), - [ruleMigration, extraTabsFactory] - ); - - return { - ruleMigrationPreviewFlyout: ruleMigration && ( - - ), - openRuleTranslationPreview: useCallback( - (ruleId: RuleSignatureId) => { - const ruleMigrationToShowInFlyout = ruleMigrations.find( - (x) => x.original_rule.id === ruleId - ); - - invariant(ruleMigrationToShowInFlyout, `Rule migration with id ${ruleId} not found`); - setRuleMigrationForPreview(ruleMigrationToShowInFlyout); - }, - [ruleMigrations] - ), - closeRuleMigrationPreview, - }; -} diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/hooks/translations.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/hooks/translations.ts new file mode 100644 index 0000000000000..74845b5f257ad --- /dev/null +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/hooks/translations.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 { i18n } from '@kbn/i18n'; + +export const COLUMN_STATUS = i18n.translate( + 'xpack.securitySolution.siemMigrations.rules.columns.statusTitle', + { + defaultMessage: 'Status', + } +); diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/use_filter_siem_migrations_to_install.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/hooks/use_filter_rules_to_install.ts similarity index 86% rename from x-pack/plugins/security_solution/public/siem_migrations/rules/components/use_filter_siem_migrations_to_install.ts rename to x-pack/plugins/security_solution/public/siem_migrations/rules/hooks/use_filter_rules_to_install.ts index bd4e20ba8e3de..c362ddbfd6ee8 100644 --- a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/use_filter_siem_migrations_to_install.ts +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/hooks/use_filter_rules_to_install.ts @@ -9,14 +9,14 @@ import { useMemo } from 'react'; import type { RuleMigration } from '../../../../common/siem_migrations/model/rule_migration.gen'; import type { FilterOptions } from '../../../detection_engine/rule_management/logic/types'; -export type SiemMigrationsTableFilterOptions = Pick; +export type TableFilterOptions = Pick; -export const useFilterSiemMigrationsToInstall = ({ +export const useFilterRulesToInstall = ({ ruleMigrations, filterOptions, }: { ruleMigrations: RuleMigration[]; - filterOptions: SiemMigrationsTableFilterOptions; + filterOptions: TableFilterOptions; }) => { const filteredRules = useMemo(() => { const { filter, tags } = filterOptions; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/hooks/use_rule_preview_flyout.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/hooks/use_rule_preview_flyout.tsx new file mode 100644 index 0000000000000..1721b4e280aad --- /dev/null +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/hooks/use_rule_preview_flyout.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 type { ReactNode } from 'react'; +import React, { useCallback, useState, useMemo } from 'react'; +import type { EuiTabbedContentTab } from '@elastic/eui'; +import type { RuleMigration } from '../../../../common/siem_migrations/model/rule_migration.gen'; +import { TranslationDetailsFlyout } from '../components/translation_details_flyout'; + +interface UseRulePreviewFlyoutParams { + ruleActionsFactory: (ruleMigration: RuleMigration, closeRulePreview: () => void) => ReactNode; + extraTabsFactory?: (ruleMigration: RuleMigration) => EuiTabbedContentTab[]; +} + +interface UseRulePreviewFlyoutResult { + rulePreviewFlyout: ReactNode; + openRulePreview: (rule: RuleMigration) => void; + closeRulePreview: () => void; +} + +export function useRulePreviewFlyout({ + extraTabsFactory, + ruleActionsFactory, +}: UseRulePreviewFlyoutParams): UseRulePreviewFlyoutResult { + const [ruleMigration, setRuleMigrationForPreview] = useState(); + const closeRulePreview = useCallback(() => setRuleMigrationForPreview(undefined), []); + const ruleActions = useMemo( + () => ruleMigration && ruleActionsFactory(ruleMigration, closeRulePreview), + [ruleMigration, ruleActionsFactory, closeRulePreview] + ); + const extraTabs = useMemo( + () => (ruleMigration && extraTabsFactory ? extraTabsFactory(ruleMigration) : []), + [ruleMigration, extraTabsFactory] + ); + + return { + rulePreviewFlyout: ruleMigration && ( + + ), + openRulePreview: useCallback((rule: RuleMigration) => { + setRuleMigrationForPreview(rule); + }, []), + closeRulePreview, + }; +} diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/use_siem_migrations_table_columns.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/hooks/use_rules_table_columns.tsx similarity index 71% rename from x-pack/plugins/security_solution/public/siem_migrations/rules/components/use_siem_migrations_table_columns.tsx rename to x-pack/plugins/security_solution/public/siem_migrations/rules/hooks/use_rules_table_columns.tsx index e4f20866c5d42..3b13b9e631ccb 100644 --- a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/use_siem_migrations_table_columns.tsx +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/hooks/use_rules_table_columns.tsx @@ -13,27 +13,23 @@ import type { RuleMigration } from '../../../../common/siem_migrations/model/rul import { SeverityBadge } from '../../../common/components/severity_badge'; import * as rulesI18n from '../../../detections/pages/detection_engine/rules/translations'; import * as i18n from './translations'; -import { useSiemMigrationsTableContext } from './siem_migrations_table_context'; import { getNormalizedSeverity } from '../../../detection_engine/rule_management_ui/components/rules_table/helpers'; -import { StatusBadge } from './status_badge'; -import { DEFAULT_TRANSLATION_RISK_SCORE, DEFAULT_TRANSLATION_SEVERITY } from './constants'; +import { StatusBadge } from '../components/status_badge'; +import { DEFAULT_TRANSLATION_RISK_SCORE, DEFAULT_TRANSLATION_SEVERITY } from '../utils/constants'; export type TableColumn = EuiBasicTableColumn; interface RuleNameProps { name: string; - ruleId: string; + rule: RuleMigration; + openRulePreview: (rule: RuleMigration) => void; } -const RuleName = ({ name, ruleId }: RuleNameProps) => { - const { - actions: { openRuleTranslationPreview: openRulePreview }, - } = useSiemMigrationsTableContext(); - +const RuleName = ({ name, rule, openRulePreview }: RuleNameProps) => { return ( { - openRulePreview(ruleId); + openRulePreview(rule); }} data-test-subj="ruleName" > @@ -42,16 +38,22 @@ const RuleName = ({ name, ruleId }: RuleNameProps) => { ); }; -export const RULE_NAME_COLUMN: TableColumn = { - field: 'original_rule.title', - name: rulesI18n.COLUMN_RULE, - render: (value: RuleMigration['original_rule']['title'], rule: RuleMigration) => ( - - ), - sortable: true, - truncateText: true, - width: '40%', - align: 'left', +const createRuleNameColumn = ({ + openRulePreview, +}: { + openRulePreview: (rule: RuleMigration) => void; +}): TableColumn => { + return { + field: 'original_rule.title', + name: rulesI18n.COLUMN_RULE, + render: (value: RuleMigration['original_rule']['title'], rule: RuleMigration) => ( + + ), + sortable: true, + truncateText: true, + width: '40%', + align: 'left', + }; }; const STATUS_COLUMN: TableColumn = { @@ -65,10 +67,14 @@ const STATUS_COLUMN: TableColumn = { width: '12%', }; -export const useSiemMigrationsTableColumns = (): TableColumn[] => { +export const useRulesTableColumns = ({ + openRulePreview, +}: { + openRulePreview: (rule: RuleMigration) => void; +}): TableColumn[] => { return useMemo( () => [ - RULE_NAME_COLUMN, + createRuleNameColumn({ openRulePreview }), STATUS_COLUMN, { field: 'risk_score', @@ -96,6 +102,6 @@ export const useSiemMigrationsTableColumns = (): TableColumn[] => { width: '12%', }, ], - [] + [openRulePreview] ); }; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/pages/index.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/pages/index.tsx index ad438e41c1285..d4c4b53b761ab 100644 --- a/x-pack/plugins/security_solution/public/siem_migrations/rules/pages/index.tsx +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/pages/index.tsx @@ -5,8 +5,9 @@ * 2.0. */ -import React from 'react'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import type { RuleMigration } from '../../../../common/siem_migrations/model/rule_migration.gen'; import { redirectToDetections } from '../../../detections/pages/detection_engine/rules/helpers'; import { SecurityPageName } from '../../../app/types'; import { HeaderPage } from '../../../common/components/header_page'; @@ -18,13 +19,14 @@ import { useUserData } from '../../../detections/components/user_info'; import { useListsConfig } from '../../../detections/containers/detection_engine/lists/use_lists_config'; import * as i18n from './translations'; -import { SiemMigrationsTable } from '../components/siem_migrations_table'; -import { SiemMigrationsTableContextProvider } from '../components/siem_migrations_table_context'; +import { RulesTable } from '../components/rules_table'; import { APP_UI_ID } from '../../../../common'; import { NeedAdminForUpdateRulesCallOut } from '../../../detections/components/callouts/need_admin_for_update_callout'; import { MissingPrivilegesCallOut } from '../../../detections/components/callouts/missing_privileges_callout'; import { getDetectionEngineUrl } from '../../../common/components/link_to'; -import { SiemMigrationsHeaderButtons } from '../components/siem_migrations_header_buttons'; +import { HeaderButtons } from '../components/header_buttons'; +import { useGetRuleMigrationsStatsAllQuery } from '../api/hooks/use_get_rule_migrations_stats_all'; +import { useRulePreviewFlyout } from '../hooks/use_rule_preview_flyout'; const RulesPageComponent: React.FC = () => { const { navigateToApp } = useKibana().services.application; @@ -32,6 +34,44 @@ const RulesPageComponent: React.FC = () => { const [{ isSignalIndexExists, isAuthenticated, hasEncryptionKey }] = useUserData(); const { needsConfiguration: needsListsConfiguration } = useListsConfig(); + const { data: ruleMigrationsStatsAll, isLoading: isLoadingMigrationsStats } = + useGetRuleMigrationsStatsAllQuery(); + const migrationsIds = useMemo(() => { + if (isLoadingMigrationsStats || !ruleMigrationsStatsAll?.length) { + return []; + } + return ruleMigrationsStatsAll + .filter((migration) => migration.status === 'finished') + .map((migration) => migration.migration_id); + }, [isLoadingMigrationsStats, ruleMigrationsStatsAll]); + + const [selectedMigrationId, setSelectedMigrationId] = useState(); + const onMigrationIdChange = (selectedId?: string) => { + setSelectedMigrationId(selectedId); + }; + + useEffect(() => { + if (!migrationsIds.length) { + return; + } + const index = migrationsIds.findIndex((id) => id === selectedMigrationId); + if (index === -1) { + setSelectedMigrationId(migrationsIds[0]); + } + }, [migrationsIds, selectedMigrationId]); + + const ruleActionsFactory = useCallback( + (ruleMigration: RuleMigration, closeRulePreview: () => void) => { + // TODO: Add flyout action buttons + return null; + }, + [] + ); + + const { rulePreviewFlyout, openRulePreview } = useRulePreviewFlyout({ + ruleActionsFactory, + }); + if ( redirectToDetections( isSignalIndexExists, @@ -52,14 +92,17 @@ const RulesPageComponent: React.FC = () => { - - - - - - - - + + + + + + {rulePreviewFlyout} + diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/pages/translations.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/pages/translations.tsx index 1c5f8278fc4bc..3c95eaab8fe90 100644 --- a/x-pack/plugins/security_solution/public/siem_migrations/rules/pages/translations.tsx +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/pages/translations.tsx @@ -7,9 +7,6 @@ import { i18n } from '@kbn/i18n'; -export const PAGE_TITLE = i18n.translate( - 'xpack.securitySolution.detectionEngine.rules.siemMigrations.pageTitle', - { - defaultMessage: 'Translated rules', - } -); +export const PAGE_TITLE = i18n.translate('xpack.securitySolution.siemMigrations.rules.pageTitle', { + defaultMessage: 'Translated rules', +}); diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/constants.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/utils/constants.ts similarity index 100% rename from x-pack/plugins/security_solution/public/siem_migrations/rules/components/constants.ts rename to x-pack/plugins/security_solution/public/siem_migrations/rules/utils/constants.ts diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/utils.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/utils/helpers.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/siem_migrations/rules/components/utils.tsx rename to x-pack/plugins/security_solution/public/siem_migrations/rules/utils/helpers.tsx diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/utils/translations.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/utils/translations.ts new file mode 100644 index 0000000000000..bc098936c00f7 --- /dev/null +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/utils/translations.ts @@ -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 { i18n } from '@kbn/i18n'; + +export const SIEM_TRANSLATION_RESULT_FULL_LABEL = i18n.translate( + 'xpack.securitySolution.siemMigrations.rules.translationResult.full', + { + defaultMessage: 'Fully translated', + } +); + +export const SIEM_TRANSLATION_RESULT_PARTIAL_LABEL = i18n.translate( + 'xpack.securitySolution.siemMigrations.rules.translationResult.partially', + { + defaultMessage: 'Partially translated', + } +); + +export const SIEM_TRANSLATION_RESULT_UNTRANSLATABLE_LABEL = i18n.translate( + 'xpack.securitySolution.siemMigrations.rules.translationResult.untranslatable', + { + defaultMessage: 'Not translated', + } +); + +export const SIEM_TRANSLATION_RESULT_UNKNOWN_LABEL = i18n.translate( + 'xpack.securitySolution.siemMigrations.rules.translationResult.unknown', + { + defaultMessage: 'Unknown', + } +); From 3059a9c013d38a5f908df5ef16a745d7a7107510 Mon Sep 17 00:00:00 2001 From: Ievgen Sorokopud Date: Fri, 22 Nov 2024 13:29:14 +0100 Subject: [PATCH 6/7] Review feedback: handle `no migraions` state properly --- .../public/siem_migrations/routes.tsx | 6 +-- .../public/siem_migrations/rules/api/api.ts | 10 ++-- .../api/hooks/use_get_rule_migrations.ts | 10 ++-- .../rules/components/no_migrations/index.tsx | 53 +++++++++++++++++++ .../components/no_migrations/translations.ts | 29 ++++++++++ .../rules/components/rules_table/index.tsx | 2 +- .../rules_table/no_items_message.tsx | 5 +- .../siem_migrations/rules/pages/index.tsx | 47 +++++++--------- 8 files changed, 116 insertions(+), 46 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/siem_migrations/rules/components/no_migrations/index.tsx create mode 100644 x-pack/plugins/security_solution/public/siem_migrations/rules/components/no_migrations/translations.ts diff --git a/x-pack/plugins/security_solution/public/siem_migrations/routes.tsx b/x-pack/plugins/security_solution/public/siem_migrations/routes.tsx index 3d6455911ab17..610eb7e2a72d8 100644 --- a/x-pack/plugins/security_solution/public/siem_migrations/routes.tsx +++ b/x-pack/plugins/security_solution/public/siem_migrations/routes.tsx @@ -7,18 +7,18 @@ import React from 'react'; -import { TrackApplicationView } from '@kbn/usage-collection-plugin/public'; import type { SecuritySubPluginRoutes } from '../app/types'; import { SIEM_MIGRATIONS_RULES_PATH, SecurityPageName } from '../../common/constants'; import { RulesPage } from './rules/pages'; import { PluginTemplateWrapper } from '../common/components/plugin_template_wrapper'; +import { SecurityRoutePageWrapper } from '../common/components/security_route_page_wrapper'; export const RulesRoutes = () => { return ( - + - + ); }; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/api/api.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/api/api.ts index 599bf10f22262..7232cb722bd1a 100644 --- a/x-pack/plugins/security_solution/public/siem_migrations/rules/api/api.ts +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/api/api.ts @@ -29,8 +29,8 @@ export const getRuleMigrationsStatsAll = async ({ signal, }: { signal: AbortSignal | undefined; -}): Promise => - KibanaServices.get().http.fetch( +}): Promise => { + return KibanaServices.get().http.fetch( SIEM_RULE_MIGRATIONS_ALL_STATS_PATH, { method: 'GET', @@ -38,6 +38,7 @@ export const getRuleMigrationsStatsAll = async ({ signal, } ); +}; /** * Retrieves all the migration rule documents of a specific migration. @@ -51,12 +52,9 @@ export const getRuleMigrations = async ({ migrationId, signal, }: { - migrationId?: string; + migrationId: string; signal: AbortSignal | undefined; }): Promise => { - if (!migrationId) { - return []; - } return KibanaServices.get().http.fetch( replaceParams(SIEM_RULE_MIGRATION_PATH, { migration_id: migrationId }), { diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/use_get_rule_migrations.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/use_get_rule_migrations.ts index 56c6240213056..76cf01c6c35d0 100644 --- a/x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/use_get_rule_migrations.ts +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/use_get_rule_migrations.ts @@ -14,14 +14,12 @@ import type { GetRuleMigrationResponse } from '../../../../../common/siem_migrat import { SIEM_RULE_MIGRATION_PATH } from '../../../../../common/siem_migrations/constants'; export const useGetRuleMigrationsQuery = ( - migrationId?: string, + migrationId: string, options?: UseQueryOptions ) => { - const SPECIFIC_MIGRATION_PATH = migrationId - ? replaceParams(SIEM_RULE_MIGRATION_PATH, { - migration_id: migrationId, - }) - : SIEM_RULE_MIGRATION_PATH; + const SPECIFIC_MIGRATION_PATH = replaceParams(SIEM_RULE_MIGRATION_PATH, { + migration_id: migrationId, + }); return useQuery( ['GET', SPECIFIC_MIGRATION_PATH], async ({ signal }) => { diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/no_migrations/index.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/no_migrations/index.tsx new file mode 100644 index 0000000000000..e4b3701d94c73 --- /dev/null +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/no_migrations/index.tsx @@ -0,0 +1,53 @@ +/* + * 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 { EuiButton, EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import React from 'react'; +import { SecurityPageName } from '../../../../../common'; +import { useGetSecuritySolutionLinkProps } from '../../../../common/components/links'; +import * as i18n from './translations'; + +const NoMigrationsComponent = () => { + const getSecuritySolutionLinkProps = useGetSecuritySolutionLinkProps(); + const { onClick: onClickLink } = getSecuritySolutionLinkProps({ + deepLinkId: SecurityPageName.landing, + path: 'siem_migrations', + }); + + return ( + + + {i18n.NO_MIGRATIONS_AVAILABLE}} + titleSize="s" + body={i18n.NO_MIGRATIONS_AVAILABLE_BODY} + data-test-subj="noMigrationsAvailable" + /> + + + + {i18n.GO_BACK_TO_RULES_TABLE_BUTTON} + + + + ); +}; + +export const NoMigrations = React.memo(NoMigrationsComponent); +NoMigrations.displayName = 'NoMigrations'; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/no_migrations/translations.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/no_migrations/translations.ts new file mode 100644 index 0000000000000..77ec0454fb5a5 --- /dev/null +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/no_migrations/translations.ts @@ -0,0 +1,29 @@ +/* + * 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 NO_MIGRATIONS_AVAILABLE = i18n.translate( + 'xpack.securitySolution.siemMigrations.rules.noMigrationsTitle', + { + defaultMessage: 'No migrations', + } +); + +export const NO_MIGRATIONS_AVAILABLE_BODY = i18n.translate( + 'xpack.securitySolution.siemMigrations.rules.noMigrationsBodyTitle', + { + defaultMessage: 'There are no migrations available', + } +); + +export const GO_BACK_TO_RULES_TABLE_BUTTON = i18n.translate( + 'xpack.securitySolution.siemMigrations.rules.table.goToMigrationsPageButton', + { + defaultMessage: 'Go back to SIEM Migrations', + } +); diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/index.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/index.tsx index 8758fdcaf7b10..83c86de2a118c 100644 --- a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/index.tsx +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/index.tsx @@ -32,7 +32,7 @@ export interface RulesTableComponentProps { /** * Selected rule migration id */ - migrationId: string | undefined; + migrationId: string; /** * Opens the flyout with the details of the rule migration diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/no_items_message.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/no_items_message.tsx index 044375b66b78e..7aeaac7ab2f6b 100644 --- a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/no_items_message.tsx +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/no_items_message.tsx @@ -14,7 +14,8 @@ import * as i18n from './translations'; const NoItemsMessageComponent = () => { const getSecuritySolutionLinkProps = useGetSecuritySolutionLinkProps(); const { onClick: onClickLink } = getSecuritySolutionLinkProps({ - deepLinkId: SecurityPageName.rules, + deepLinkId: SecurityPageName.landing, + path: 'siem_migrations', }); return ( @@ -39,7 +40,7 @@ const NoItemsMessageComponent = () => { iconType="arrowLeft" color={'primary'} onClick={onClickLink} - data-test-subj="rulesTranslationGoBackToRulesTableBtn" + data-test-subj="goToSiemMigrationsButton" > {i18n.GO_BACK_TO_RULES_TABLE_BUTTON} diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/pages/index.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/pages/index.tsx index d4c4b53b761ab..616c85e7e7dee 100644 --- a/x-pack/plugins/security_solution/public/siem_migrations/rules/pages/index.tsx +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/pages/index.tsx @@ -7,35 +7,26 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import { EuiSkeletonLoading, EuiSkeletonText, EuiSkeletonTitle } from '@elastic/eui'; import type { RuleMigration } from '../../../../common/siem_migrations/model/rule_migration.gen'; -import { redirectToDetections } from '../../../detections/pages/detection_engine/rules/helpers'; import { SecurityPageName } from '../../../app/types'; import { HeaderPage } from '../../../common/components/header_page'; import { SecuritySolutionPageWrapper } from '../../../common/components/page_wrapper'; -import { useKibana } from '../../../common/lib/kibana'; import { SpyRoute } from '../../../common/utils/route/spy_routes'; -import { useUserData } from '../../../detections/components/user_info'; -import { useListsConfig } from '../../../detections/containers/detection_engine/lists/use_lists_config'; - import * as i18n from './translations'; import { RulesTable } from '../components/rules_table'; -import { APP_UI_ID } from '../../../../common'; import { NeedAdminForUpdateRulesCallOut } from '../../../detections/components/callouts/need_admin_for_update_callout'; import { MissingPrivilegesCallOut } from '../../../detections/components/callouts/missing_privileges_callout'; -import { getDetectionEngineUrl } from '../../../common/components/link_to'; import { HeaderButtons } from '../components/header_buttons'; import { useGetRuleMigrationsStatsAllQuery } from '../api/hooks/use_get_rule_migrations_stats_all'; import { useRulePreviewFlyout } from '../hooks/use_rule_preview_flyout'; +import { NoMigrations } from '../components/no_migrations'; const RulesPageComponent: React.FC = () => { - const { navigateToApp } = useKibana().services.application; - - const [{ isSignalIndexExists, isAuthenticated, hasEncryptionKey }] = useUserData(); - const { needsConfiguration: needsListsConfiguration } = useListsConfig(); - const { data: ruleMigrationsStatsAll, isLoading: isLoadingMigrationsStats } = useGetRuleMigrationsStatsAllQuery(); + const migrationsIds = useMemo(() => { if (isLoadingMigrationsStats || !ruleMigrationsStatsAll?.length) { return []; @@ -72,21 +63,6 @@ const RulesPageComponent: React.FC = () => { ruleActionsFactory, }); - if ( - redirectToDetections( - isSignalIndexExists, - isAuthenticated, - hasEncryptionKey, - needsListsConfiguration - ) - ) { - navigateToApp(APP_UI_ID, { - deepLinkId: SecurityPageName.alerts, - path: getDetectionEngineUrl(), - }); - return null; - } - return ( <> @@ -100,7 +76,22 @@ const RulesPageComponent: React.FC = () => { onMigrationIdChange={onMigrationIdChange} /> - + + + + + } + loadedContent={ + selectedMigrationId ? ( + + ) : ( + + ) + } + /> {rulePreviewFlyout} From c68b3685524569392e7f412af5eb4bcebd3bd5e4 Mon Sep 17 00:00:00 2001 From: Ievgen Sorokopud Date: Fri, 22 Nov 2024 13:35:48 +0100 Subject: [PATCH 7/7] Remove tags filter --- .../rules/components/rules_table/filters.tsx | 39 +------------------ .../rules/components/rules_table/index.tsx | 11 +----- .../hooks/use_filter_rules_to_install.ts | 10 +---- 3 files changed, 6 insertions(+), 54 deletions(-) diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/filters.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/filters.tsx index 17b1065583073..5f4ae3098b6a3 100644 --- a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/filters.tsx +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/filters.tsx @@ -5,13 +5,11 @@ * 2.0. */ -import { EuiFilterGroup, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import { isEqual } from 'lodash/fp'; +import { EuiFlexGroup } from '@elastic/eui'; import type { Dispatch, SetStateAction } from 'react'; import React, { useCallback } from 'react'; import styled from 'styled-components'; import * as i18n from './translations'; -import { TagsFilterPopover } from '../../../../detection_engine/rule_management_ui/components/rules_table/rules_table_filters/tags_filter_popover'; import { RuleSearchField } from '../../../../detection_engine/rule_management_ui/components/rules_table/rules_table_filters/rule_search_field'; import type { TableFilterOptions } from '../../hooks/use_filter_rules_to_install'; @@ -25,11 +23,6 @@ export interface FiltersComponentProps { */ filterOptions: TableFilterOptions; - /** - * All unique tags for all rule translations - */ - tags: string[]; - /** * Handles filter options changes */ @@ -40,13 +33,7 @@ export interface FiltersComponentProps { * Collection of filters for filtering data within the SIEM Rules Migrations table. * Contains search bar and tag selection */ -const FiltersComponent: React.FC = ({ - filterOptions, - tags, - setFilterOptions, -}) => { - const { tags: selectedTags } = filterOptions; - +const FiltersComponent: React.FC = ({ filterOptions, setFilterOptions }) => { const handleOnSearch = useCallback( (filterString: string) => { setFilterOptions((filters) => ({ @@ -57,18 +44,6 @@ const FiltersComponent: React.FC = ({ [setFilterOptions] ); - const handleSelectedTags = useCallback( - (newTags: string[]) => { - if (!isEqual(newTags, selectedTags)) { - setFilterOptions((filters) => ({ - ...filters, - tags: newTags, - })); - } - }, - [selectedTags, setFilterOptions] - ); - return ( = ({ onSearch={handleOnSearch} placeholder={i18n.SEARCH_PLACEHOLDER} /> - - - - - ); }; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/index.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/index.tsx index 83c86de2a118c..0cd3e07ea11a4 100644 --- a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/index.tsx +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/index.tsx @@ -14,7 +14,7 @@ import { EuiFlexGroup, EuiFlexItem, } from '@elastic/eui'; -import React, { useMemo, useState } from 'react'; +import React, { useState } from 'react'; import type { RuleMigration } from '../../../../../common/siem_migrations/model/rule_migration.gen'; import { @@ -55,7 +55,6 @@ const RulesTableComponent: React.FC = ({ const [filterOptions, setFilterOptions] = useState({ filter: '', - tags: [], }); const filteredRuleMigrations = useFilterRulesToInstall({ @@ -63,8 +62,6 @@ const RulesTableComponent: React.FC = ({ ruleMigrations: ruleMigrations ?? [], }); - const tags = useMemo(() => [], []); - const shouldShowProgress = isLoading; const rulesColumns = useRulesTableColumns({ @@ -96,11 +93,7 @@ const RulesTableComponent: React.FC = ({ <> - + diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/hooks/use_filter_rules_to_install.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/hooks/use_filter_rules_to_install.ts index c362ddbfd6ee8..f6862d3d90380 100644 --- a/x-pack/plugins/security_solution/public/siem_migrations/rules/hooks/use_filter_rules_to_install.ts +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/hooks/use_filter_rules_to_install.ts @@ -9,7 +9,7 @@ import { useMemo } from 'react'; import type { RuleMigration } from '../../../../common/siem_migrations/model/rule_migration.gen'; import type { FilterOptions } from '../../../detection_engine/rule_management/logic/types'; -export type TableFilterOptions = Pick; +export type TableFilterOptions = Pick; export const useFilterRulesToInstall = ({ ruleMigrations, @@ -19,18 +19,12 @@ export const useFilterRulesToInstall = ({ filterOptions: TableFilterOptions; }) => { const filteredRules = useMemo(() => { - const { filter, tags } = filterOptions; + const { filter } = filterOptions; return ruleMigrations.filter((migration) => { const name = migration.elastic_rule?.title ?? migration.original_rule.title; if (filter && !name.toLowerCase().includes(filter.toLowerCase())) { return false; } - - if (tags && tags.length > 0) { - // TODO: Uncomment this once tags are available for rule migrations - // return tags.every((tag) => migration.tags.includes(tag)); - } - return true; }); }, [filterOptions, ruleMigrations]);