diff --git a/x-pack/plugins/security_solution/common/siem_migrations/constants.ts b/x-pack/plugins/security_solution/common/siem_migrations/constants.ts
index a910cb90f1664..789947150a67e 100644
--- a/x-pack/plugins/security_solution/common/siem_migrations/constants.ts
+++ b/x-pack/plugins/security_solution/common/siem_migrations/constants.ts
@@ -46,3 +46,11 @@ export enum SiemMigrationRuleTranslationResult {
export const DEFAULT_TRANSLATION_RISK_SCORE = 21;
export const DEFAULT_TRANSLATION_SEVERITY: Severity = 'low';
+
+export const DEFAULT_TRANSLATION_FIELDS = {
+ risk_score: DEFAULT_TRANSLATION_RISK_SCORE,
+ severity: DEFAULT_TRANSLATION_SEVERITY,
+ from: 'now-360s',
+ to: 'now',
+ interval: '5m',
+} as const;
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 cc2b9fbad3451..179cf064c4926 100644
--- a/x-pack/plugins/security_solution/public/siem_migrations/routes.tsx
+++ b/x-pack/plugins/security_solution/public/siem_migrations/routes.tsx
@@ -10,16 +10,19 @@ import { Routes, Route } from '@kbn/shared-ux-router';
import type { SecuritySubPluginRoutes } from '../app/types';
import { SIEM_MIGRATIONS_RULES_PATH, SecurityPageName } from '../../common/constants';
-import { RulesPage } from './rules/pages';
+import { MigrationRulesPage } from './rules/pages';
import { PluginTemplateWrapper } from '../common/components/plugin_template_wrapper';
import { SecurityRoutePageWrapper } from '../common/components/security_route_page_wrapper';
-export const RulesRoutes = () => {
+export const SiemMigrationsRoutes = () => {
return (
-
+
@@ -29,6 +32,6 @@ export const RulesRoutes = () => {
export const routes: SecuritySubPluginRoutes = [
{
path: SIEM_MIGRATIONS_RULES_PATH,
- component: RulesRoutes,
+ component: SiemMigrationsRoutes,
},
];
diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/use_get_migration_rules_query.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/use_get_migration_rules_query.ts
deleted file mode 100644
index 138b2a31e9727..0000000000000
--- a/x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/use_get_migration_rules_query.ts
+++ /dev/null
@@ -1,78 +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 { UseQueryOptions } from '@tanstack/react-query';
-import { useQuery, useQueryClient } from '@tanstack/react-query';
-import { replaceParams } from '@kbn/openapi-common/shared';
-import { useCallback } from 'react';
-import type { RuleMigration } from '../../../../../common/siem_migrations/model/rule_migration.gen';
-import { DEFAULT_QUERY_OPTIONS } from './constants';
-import { getRuleMigrations } from '../api';
-import { SIEM_RULE_MIGRATION_PATH } from '../../../../../common/siem_migrations/constants';
-
-interface UseGetMigrationRulesQueryProps {
- migrationId: string;
- page?: number;
- perPage?: number;
- searchTerm?: string;
-}
-
-export interface MigrationRulesQueryResponse {
- ruleMigrations: RuleMigration[];
- total: number;
-}
-
-export const useGetMigrationRulesQuery = (
- queryArgs: UseGetMigrationRulesQueryProps,
- queryOptions?: UseQueryOptions<
- MigrationRulesQueryResponse,
- Error,
- MigrationRulesQueryResponse,
- [...string[], UseGetMigrationRulesQueryProps]
- >
-) => {
- const { migrationId } = queryArgs;
- const SPECIFIC_MIGRATION_PATH = replaceParams(SIEM_RULE_MIGRATION_PATH, {
- migration_id: migrationId,
- });
- return useQuery(
- ['GET', SPECIFIC_MIGRATION_PATH, queryArgs],
- async ({ signal }) => {
- const response = await getRuleMigrations({ signal, ...queryArgs });
-
- return { ruleMigrations: response.data, total: response.total };
- },
- {
- ...DEFAULT_QUERY_OPTIONS,
- ...queryOptions,
- }
- );
-};
-
-/**
- * We should use this hook to invalidate the rule migrations cache. For
- * example, rule migrations mutations, like installing a rule, should lead to cache invalidation.
- *
- * @returns A rule migrations cache invalidation callback
- */
-export const useInvalidateGetMigrationRulesQuery = (migrationId: string) => {
- const queryClient = useQueryClient();
-
- const SPECIFIC_MIGRATION_PATH = replaceParams(SIEM_RULE_MIGRATION_PATH, {
- migration_id: migrationId,
- });
-
- return useCallback(() => {
- /**
- * Invalidate all queries that start with SPECIFIC_MIGRATION_PATH. This
- * includes the in-memory query cache and paged query cache.
- */
- queryClient.invalidateQueries(['GET', SPECIFIC_MIGRATION_PATH], {
- refetchType: 'active',
- });
- }, [SPECIFIC_MIGRATION_PATH, queryClient]);
-};
diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/use_get_migration_translation_stats_query.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/use_get_migration_translation_stats_query.ts
deleted file mode 100644
index e58b9be20d19c..0000000000000
--- a/x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/use_get_migration_translation_stats_query.ts
+++ /dev/null
@@ -1,60 +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 { UseQueryOptions } from '@tanstack/react-query';
-import { useQuery, useQueryClient } from '@tanstack/react-query';
-import { replaceParams } from '@kbn/openapi-common/shared';
-import { useCallback } from 'react';
-import { DEFAULT_QUERY_OPTIONS } from './constants';
-import { getRuleMigrationTranslationStats } from '../api';
-import type { GetRuleMigrationTranslationStatsResponse } from '../../../../../common/siem_migrations/model/api/rules/rule_migration.gen';
-import { SIEM_RULE_MIGRATION_TRANSLATION_STATS_PATH } from '../../../../../common/siem_migrations/constants';
-
-export const useGetMigrationTranslationStatsQuery = (
- migrationId: string,
- options?: UseQueryOptions
-) => {
- const SPECIFIC_MIGRATION_TRANSLATION_PATH = replaceParams(
- SIEM_RULE_MIGRATION_TRANSLATION_STATS_PATH,
- {
- migration_id: migrationId,
- }
- );
- return useQuery(
- ['GET', SPECIFIC_MIGRATION_TRANSLATION_PATH],
- async ({ signal }) => {
- return getRuleMigrationTranslationStats({ migrationId, signal });
- },
- {
- ...DEFAULT_QUERY_OPTIONS,
- ...options,
- }
- );
-};
-
-/**
- * We should use this hook to invalidate the translation stats cache. For
- * example, rule migrations mutations, like installing a rule, should lead to cache invalidation.
- *
- * @returns A translation stats cache invalidation callback
- */
-export const useInvalidateGetMigrationTranslationStatsQuery = (migrationId: string) => {
- const queryClient = useQueryClient();
-
- const SPECIFIC_MIGRATION_TRANSLATION_PATH = replaceParams(
- SIEM_RULE_MIGRATION_TRANSLATION_STATS_PATH,
- {
- migration_id: migrationId,
- }
- );
-
- return useCallback(() => {
- queryClient.invalidateQueries(['GET', SPECIFIC_MIGRATION_TRANSLATION_PATH], {
- refetchType: 'active',
- });
- }, [SPECIFIC_MIGRATION_TRANSLATION_PATH, queryClient]);
-};
diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/use_install_migration_rules_mutation.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/use_install_migration_rules_mutation.ts
deleted file mode 100644
index 536f9e772e5d8..0000000000000
--- a/x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/use_install_migration_rules_mutation.ts
+++ /dev/null
@@ -1,40 +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 { UseMutationOptions } from '@tanstack/react-query';
-import { useMutation } from '@tanstack/react-query';
-import type { InstallMigrationRulesResponse } from '../../../../../common/siem_migrations/model/api/rules/rule_migration.gen';
-import { SIEM_RULE_MIGRATION_INSTALL_PATH } from '../../../../../common/siem_migrations/constants';
-import { installMigrationRules } from '../api';
-import { useInvalidateGetMigrationRulesQuery } from './use_get_migration_rules_query';
-import { useInvalidateGetMigrationTranslationStatsQuery } from './use_get_migration_translation_stats_query';
-
-export const INSTALL_MIGRATION_RULES_MUTATION_KEY = ['POST', SIEM_RULE_MIGRATION_INSTALL_PATH];
-
-export const useInstallMigrationRulesMutation = (
- migrationId: string,
- options?: UseMutationOptions
-) => {
- const invalidateGetRuleMigrationsQuery = useInvalidateGetMigrationRulesQuery(migrationId);
- const invalidateGetMigrationTranslationStatsQuery =
- useInvalidateGetMigrationTranslationStatsQuery(migrationId);
-
- return useMutation(
- (ids: string[]) => installMigrationRules({ migrationId, ids }),
- {
- ...options,
- mutationKey: INSTALL_MIGRATION_RULES_MUTATION_KEY,
- onSettled: (...args) => {
- invalidateGetRuleMigrationsQuery();
- invalidateGetMigrationTranslationStatsQuery();
-
- if (options?.onSettled) {
- options.onSettled(...args);
- }
- },
- }
- );
-};
diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/use_install_translated_migration_rules_mutation.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/use_install_translated_migration_rules_mutation.ts
deleted file mode 100644
index 3c1dda0b457c4..0000000000000
--- a/x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/use_install_translated_migration_rules_mutation.ts
+++ /dev/null
@@ -1,43 +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 { UseMutationOptions } from '@tanstack/react-query';
-import { useMutation } from '@tanstack/react-query';
-import type { InstallTranslatedMigrationRulesResponse } from '../../../../../common/siem_migrations/model/api/rules/rule_migration.gen';
-import { SIEM_RULE_MIGRATION_INSTALL_TRANSLATED_PATH } from '../../../../../common/siem_migrations/constants';
-import { installTranslatedMigrationRules } from '../api';
-import { useInvalidateGetMigrationRulesQuery } from './use_get_migration_rules_query';
-import { useInvalidateGetMigrationTranslationStatsQuery } from './use_get_migration_translation_stats_query';
-
-export const INSTALL_ALL_MIGRATION_RULES_MUTATION_KEY = [
- 'POST',
- SIEM_RULE_MIGRATION_INSTALL_TRANSLATED_PATH,
-];
-
-export const useInstallTranslatedMigrationRulesMutation = (
- migrationId: string,
- options?: UseMutationOptions
-) => {
- const invalidateGetRuleMigrationsQuery = useInvalidateGetMigrationRulesQuery(migrationId);
- const invalidateGetMigrationTranslationStatsQuery =
- useInvalidateGetMigrationTranslationStatsQuery(migrationId);
-
- return useMutation(
- () => installTranslatedMigrationRules({ migrationId }),
- {
- ...options,
- mutationKey: INSTALL_ALL_MIGRATION_RULES_MUTATION_KEY,
- onSettled: (...args) => {
- invalidateGetRuleMigrationsQuery();
- invalidateGetMigrationTranslationStatsQuery();
-
- if (options?.onSettled) {
- options.onSettled(...args);
- }
- },
- }
- );
-};
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/index.ts
similarity index 95%
rename from x-pack/plugins/security_solution/public/siem_migrations/rules/api/api.ts
rename to x-pack/plugins/security_solution/public/siem_migrations/rules/api/index.ts
index 160d78f1edbb6..592b93f438197 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/index.ts
@@ -25,7 +25,6 @@ import type {
InstallMigrationRulesResponse,
StartRuleMigrationRequestBody,
} from '../../../../common/siem_migrations/model/api/rules/rule_migration.gen';
-import type { InstallTranslatedRulesProps, InstallRulesProps } from '../types';
/**
* Retrieves the stats for all the existing migrations, aggregated by `migration_id`.
@@ -134,7 +133,11 @@ export const installMigrationRules = async ({
migrationId,
ids,
signal,
-}: InstallRulesProps): Promise => {
+}: {
+ migrationId: string;
+ ids: string[];
+ signal?: AbortSignal;
+}): Promise => {
return KibanaServices.get().http.fetch(
replaceParams(SIEM_RULE_MIGRATION_INSTALL_PATH, { migration_id: migrationId }),
{
@@ -149,7 +152,10 @@ export const installMigrationRules = async ({
export const installTranslatedMigrationRules = async ({
migrationId,
signal,
-}: InstallTranslatedRulesProps): Promise => {
+}: {
+ migrationId: string;
+ signal?: AbortSignal;
+}): Promise => {
return KibanaServices.get().http.fetch(
replaceParams(SIEM_RULE_MIGRATION_INSTALL_TRANSLATED_PATH, { migration_id: migrationId }),
{
diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/header_buttons/index.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/header_buttons/index.tsx
index ba73bd9c84946..728873f046d2e 100644
--- a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/header_buttons/index.tsx
+++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/header_buttons/index.tsx
@@ -10,12 +10,13 @@ import React, { useMemo } from 'react';
import type { EuiComboBoxOptionOption } from '@elastic/eui';
import { EuiComboBox, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import * as i18n from './translations';
+import type { RuleMigrationTask } from '../../types';
export interface HeaderButtonsProps {
/**
- * Available rule migrations ids
+ * Available rule migrations stats
*/
- migrationsIds: string[];
+ ruleMigrationsStats: RuleMigrationTask[];
/**
* Selected rule migration id
@@ -30,55 +31,53 @@ export interface HeaderButtonsProps {
onMigrationIdChange: (selectedId?: string) => void;
}
-const HeaderButtonsComponent: React.FC = ({
- migrationsIds,
- selectedMigrationId,
- onMigrationIdChange,
-}) => {
- 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]);
+export const HeaderButtons: React.FC = React.memo(
+ ({ ruleMigrationsStats, selectedMigrationId, onMigrationIdChange }) => {
+ const migrationOptions = useMemo(() => {
+ const options: Array> = ruleMigrationsStats.map(
+ ({ id, number }) => ({
+ value: id,
+ 'data-test-subj': `migrationSelectionOption-${number}`,
+ label: i18n.SIEM_MIGRATIONS_OPTION_LABEL(number),
+ })
+ );
+ return options;
+ }, [ruleMigrationsStats]);
+ const selectedMigrationOption = useMemo>>(() => {
+ const stats = ruleMigrationsStats.find(({ id }) => id === selectedMigrationId);
+ return stats
+ ? [
+ {
+ value: selectedMigrationId,
+ 'data-test-subj': `migrationSelectionOption-${stats.number}`,
+ label: i18n.SIEM_MIGRATIONS_OPTION_LABEL(stats.number),
+ },
+ ]
+ : [];
+ }, [ruleMigrationsStats, selectedMigrationId]);
- const onChange = (selected: Array>) => {
- onMigrationIdChange(selected[0].value);
- };
+ const onChange = (selected: Array>) => {
+ onMigrationIdChange(selected[0].value);
+ };
- if (!migrationsIds.length) {
- return null;
- }
-
- return (
-
-
-
-
-
- );
-};
+ if (!ruleMigrationsStats.length) {
+ return null;
+ }
-export const HeaderButtons = React.memo(HeaderButtonsComponent);
+ return (
+
+
+
+
+
+ );
+ }
+);
HeaderButtons.displayName = 'HeaderButtons';
diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details_flyout/constants.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rule_details_flyout/constants.ts
similarity index 100%
rename from x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details_flyout/constants.ts
rename to x-pack/plugins/security_solution/public/siem_migrations/rules/components/rule_details_flyout/constants.ts
diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rule_details_flyout/index.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rule_details_flyout/index.tsx
new file mode 100644
index 0000000000000..9353d0063b8ab
--- /dev/null
+++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rule_details_flyout/index.tsx
@@ -0,0 +1,194 @@
+/*
+ * 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 { 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 {
+ DEFAULT_TRANSLATION_SEVERITY,
+ DEFAULT_TRANSLATION_FIELDS,
+} from '../../../../../common/siem_migrations/constants';
+import type { RuleMigration } from '../../../../../common/siem_migrations/model/rule_migration.gen';
+import {
+ RuleOverviewTab,
+ useOverviewTabSections,
+} from '../../../../detection_engine/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';
+
+/*
+ * 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 MigrationRuleDetailsFlyoutProps {
+ ruleActions?: React.ReactNode;
+ ruleMigration: RuleMigration;
+ size?: EuiFlyoutProps['size'];
+ extraTabs?: EuiTabbedContentTab[];
+ closeFlyout: () => void;
+}
+
+export const MigrationRuleDetailsFlyout: React.FC = React.memo(
+ ({
+ ruleActions,
+ ruleMigration,
+ size = 'm',
+ extraTabs = [],
+ closeFlyout,
+ }: MigrationRuleDetailsFlyoutProps) => {
+ 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_TRANSLATION_FIELDS,
+ severity:
+ (ruleMigration.elastic_rule?.severity as Severity) ?? DEFAULT_TRANSLATION_SEVERITY,
+ } 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}
+
+
+
+ );
+ }
+);
+MigrationRuleDetailsFlyout.displayName = 'MigrationRuleDetailsFlyout';
diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details_flyout/translation_tab/header.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rule_details_flyout/translation_tab/header.tsx
similarity index 82%
rename from x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details_flyout/translation_tab/header.tsx
rename to x-pack/plugins/security_solution/public/siem_migrations/rules/components/rule_details_flyout/translation_tab/header.tsx
index 57e99440e60a1..2775c9569917a 100644
--- a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details_flyout/translation_tab/header.tsx
+++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rule_details_flyout/translation_tab/header.tsx
@@ -9,7 +9,7 @@ import React from 'react';
import { EuiFlexGroup, EuiTitle } from '@elastic/eui';
import * as i18n from './translations';
-export function TranslationTabHeader(): JSX.Element {
+export const TranslationTabHeader: React.FC = React.memo(() => {
return (
@@ -17,4 +17,5 @@ export function TranslationTabHeader(): JSX.Element {
);
-}
+});
+TranslationTabHeader.displayName = 'TranslationTabHeader';
diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details_flyout/translation_tab/index.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rule_details_flyout/translation_tab/index.tsx
similarity index 92%
rename from x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details_flyout/translation_tab/index.tsx
rename to x-pack/plugins/security_solution/public/siem_migrations/rules/components/rule_details_flyout/translation_tab/index.tsx
index f2ac76c78434b..a2e590b85ac09 100644
--- a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details_flyout/translation_tab/index.tsx
+++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rule_details_flyout/translation_tab/index.tsx
@@ -22,7 +22,7 @@ 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 { MigrationRuleQuery } from './migration_rule_query';
import * as i18n from './translations';
import {
convertTranslationResultIntoColor,
@@ -33,7 +33,7 @@ interface TranslationTabProps {
ruleMigration: RuleMigration;
}
-export const TranslationTab = ({ ruleMigration }: TranslationTabProps) => {
+export const TranslationTab: React.FC = React.memo(({ ruleMigration }) => {
const { euiTheme } = useEuiTheme();
const name = ruleMigration.elastic_rule?.title ?? ruleMigration.original_rule.title;
@@ -81,7 +81,7 @@ export const TranslationTab = ({ ruleMigration }: TranslationTabProps) => {
- {
`}
/>
- {
>
);
-};
+});
+TranslationTab.displayName = 'TranslationTab';
diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rule_details_flyout/translation_tab/migration_rule_query.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rule_details_flyout/translation_tab/migration_rule_query.tsx
new file mode 100644
index 0000000000000..534f765da97bc
--- /dev/null
+++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rule_details_flyout/translation_tab/migration_rule_query.tsx
@@ -0,0 +1,73 @@
+/*
+ * 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 {
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiHorizontalRule,
+ EuiMarkdownEditor,
+ EuiMarkdownFormat,
+ EuiTitle,
+ useEuiTheme,
+} from '@elastic/eui';
+import { css } from '@emotion/react';
+import * as i18n from './translations';
+
+interface MigrationRuleQueryProps {
+ title: string;
+ query: string;
+ canEdit?: boolean;
+}
+
+export const MigrationRuleQuery: React.FC = React.memo(
+ ({ title, query, canEdit }) => {
+ const { euiTheme } = useEuiTheme();
+
+ const headerComponent = useMemo(() => {
+ return (
+
+
+
+ {title}
+
+
+
+ );
+ }, [euiTheme, title]);
+
+ const queryTextComponent = useMemo(() => {
+ if (canEdit) {
+ return (
+ {}}
+ height={400}
+ initialViewMode={'viewing'}
+ />
+ );
+ } else {
+ return {query};
+ }
+ }, [canEdit, query]);
+
+ return (
+ <>
+ {headerComponent}
+
+ {queryTextComponent}
+ >
+ );
+ }
+);
+MigrationRuleQuery.displayName = 'MigrationRuleQuery';
diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details_flyout/translation_tab/translations.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rule_details_flyout/translation_tab/translations.ts
similarity index 100%
rename from x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details_flyout/translation_tab/translations.ts
rename to x-pack/plugins/security_solution/public/siem_migrations/rules/components/rule_details_flyout/translation_tab/translations.ts
diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details_flyout/translations.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rule_details_flyout/translations.ts
similarity index 100%
rename from x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details_flyout/translations.ts
rename to x-pack/plugins/security_solution/public/siem_migrations/rules/components/rule_details_flyout/translations.ts
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/empty_migration.tsx
similarity index 93%
rename from x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/no_items_message.tsx
rename to x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/empty_migration.tsx
index 7aeaac7ab2f6b..a8bd20d4a557e 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/empty_migration.tsx
@@ -11,7 +11,7 @@ import { SecurityPageName } from '../../../../../common';
import { useGetSecuritySolutionLinkProps } from '../../../../common/components/links';
import * as i18n from './translations';
-const NoItemsMessageComponent = () => {
+export const EmptyMigration: React.FC = React.memo(() => {
const getSecuritySolutionLinkProps = useGetSecuritySolutionLinkProps();
const { onClick: onClickLink } = getSecuritySolutionLinkProps({
deepLinkId: SecurityPageName.landing,
@@ -47,6 +47,5 @@ const NoItemsMessageComponent = () => {
);
-};
-
-export const NoItemsMessage = React.memo(NoItemsMessageComponent);
+});
+EmptyMigration.displayName = 'EmptyMigration';
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 82793d3e1fd8c..e7af1af93e2ba 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
@@ -17,20 +17,22 @@ import {
} from '@elastic/eui';
import React, { useCallback, useMemo, useState } from 'react';
+import { useAppToasts } from '../../../../common/hooks/use_app_toasts';
import type { RuleMigration } from '../../../../../common/siem_migrations/model/rule_migration.gen';
-import { NoItemsMessage } from './no_items_message';
-import { useRulesTableColumns } from '../../hooks/use_rules_table_columns';
-import { useRulePreviewFlyout } from '../../hooks/use_rule_preview_flyout';
+import { EmptyMigration } from './empty_migration';
+import { useMigrationRulesTableColumns } from '../../hooks/use_migration_rules_table_columns';
+import { useMigrationRuleDetailsFlyout } from '../../hooks/use_migration_rule_preview_flyout';
import { useInstallMigrationRules } from '../../logic/use_install_migration_rules';
import { useGetMigrationRules } from '../../logic/use_get_migration_rules';
import { useInstallTranslatedMigrationRules } from '../../logic/use_install_translated_migration_rules';
-import { BulkActions } from './bulk_actions';
import { useGetMigrationTranslationStats } from '../../logic/use_get_migration_translation_stats';
+import * as logicI18n from '../../logic/translations';
+import { BulkActions } from './bulk_actions';
import { SearchField } from './search_field';
const DEFAULT_PAGE_SIZE = 10;
-export interface RulesTableComponentProps {
+export interface MigrationRulesTableProps {
/**
* Selected rule migration id
*/
@@ -40,143 +42,152 @@ export interface RulesTableComponentProps {
/**
* Table Component for displaying SIEM rules migrations
*/
-const RulesTableComponent: React.FC = ({ migrationId }) => {
- const [pageIndex, setPageIndex] = useState(0);
- const [pageSize, setPageSize] = useState(DEFAULT_PAGE_SIZE);
- const [searchTerm, setSearchTerm] = useState();
-
- const { data: translationStats, isLoading: isStatsLoading } =
- useGetMigrationTranslationStats(migrationId);
-
- const {
- data: { ruleMigrations, total } = { ruleMigrations: [], total: 0 },
- isLoading: isDataLoading,
- } = useGetMigrationRules({
- migrationId,
- page: pageIndex,
- perPage: pageSize,
- searchTerm,
- });
-
- const [selectedRuleMigrations, setSelectedRuleMigrations] = useState([]);
-
- const pagination = useMemo(() => {
- return {
- pageIndex,
- pageSize,
- totalItemCount: total,
- };
- }, [pageIndex, pageSize, total]);
-
- const onTableChange = useCallback(({ page, sort }: CriteriaWithPagination) => {
- if (page) {
- setPageIndex(page.index);
- setPageSize(page.size);
- }
- }, []);
-
- const handleOnSearch = useCallback((value: string) => {
- setSearchTerm(value.trim());
- }, []);
-
- const { mutateAsync: installMigrationRules } = useInstallMigrationRules(migrationId);
- const { mutateAsync: installTranslatedMigrationRules } =
- useInstallTranslatedMigrationRules(migrationId);
-
- const [isTableLoading, setTableLoading] = useState(false);
- const installSingleRule = useCallback(
- async (migrationRule: RuleMigration, enable?: boolean) => {
- setTableLoading(true);
- try {
- await installMigrationRules([migrationRule.id]);
- } finally {
- setTableLoading(false);
- }
- },
- [installMigrationRules]
- );
-
- const installTranslatedRules = useCallback(
- async (enable?: boolean) => {
- setTableLoading(true);
- try {
- await installTranslatedMigrationRules();
- } finally {
- setTableLoading(false);
+export const MigrationRulesTable: React.FC = React.memo(
+ ({ migrationId }) => {
+ const { addError } = useAppToasts();
+
+ const [pageIndex, setPageIndex] = useState(0);
+ const [pageSize, setPageSize] = useState(DEFAULT_PAGE_SIZE);
+ const [searchTerm, setSearchTerm] = useState();
+
+ const { data: translationStats, isLoading: isStatsLoading } =
+ useGetMigrationTranslationStats(migrationId);
+
+ const {
+ data: { ruleMigrations, total } = { ruleMigrations: [], total: 0 },
+ isLoading: isDataLoading,
+ } = useGetMigrationRules({
+ migrationId,
+ page: pageIndex,
+ perPage: pageSize,
+ searchTerm,
+ });
+
+ const [selectedRuleMigrations, setSelectedRuleMigrations] = useState([]);
+
+ const pagination = useMemo(() => {
+ return {
+ pageIndex,
+ pageSize,
+ totalItemCount: total,
+ };
+ }, [pageIndex, pageSize, total]);
+
+ const onTableChange = useCallback(({ page, sort }: CriteriaWithPagination) => {
+ if (page) {
+ setPageIndex(page.index);
+ setPageSize(page.size);
}
- },
- [installTranslatedMigrationRules]
- );
-
- const ruleActionsFactory = useCallback(
- (ruleMigration: RuleMigration, closeRulePreview: () => void) => {
- // TODO: Add flyout action buttons
- return null;
- },
- []
- );
-
- const { rulePreviewFlyout, openRulePreview } = useRulePreviewFlyout({
- ruleActionsFactory,
- });
-
- const rulesColumns = useRulesTableColumns({
- disableActions: isTableLoading,
- openMigrationRulePreview: openRulePreview,
- installMigrationRule: installSingleRule,
- });
-
- return (
- <>
-
-
-
- >
+ }, []);
+
+ const handleOnSearch = useCallback((value: string) => {
+ setSearchTerm(value.trim());
+ }, []);
+
+ const { mutateAsync: installMigrationRules } = useInstallMigrationRules(migrationId);
+ const { mutateAsync: installTranslatedMigrationRules } =
+ useInstallTranslatedMigrationRules(migrationId);
+
+ const [isTableLoading, setTableLoading] = useState(false);
+ const installSingleRule = useCallback(
+ async (migrationRule: RuleMigration, enable?: boolean) => {
+ setTableLoading(true);
+ try {
+ await installMigrationRules([migrationRule.id]);
+ } catch (error) {
+ addError(error, { title: logicI18n.INSTALL_MIGRATION_RULES_FAILURE });
+ } finally {
+ setTableLoading(false);
}
- loadedContent={
- !translationStats?.rules.total ? (
-
- ) : (
+ },
+ [addError, installMigrationRules]
+ );
+
+ const installTranslatedRules = useCallback(
+ async (enable?: boolean) => {
+ setTableLoading(true);
+ try {
+ await installTranslatedMigrationRules();
+ } catch (error) {
+ addError(error, { title: logicI18n.INSTALL_MIGRATION_RULES_FAILURE });
+ } finally {
+ setTableLoading(false);
+ }
+ },
+ [addError, installTranslatedMigrationRules]
+ );
+
+ const ruleActionsFactory = useCallback(
+ (ruleMigration: RuleMigration, closeRulePreview: () => void) => {
+ // TODO: Add flyout action buttons
+ return null;
+ },
+ []
+ );
+
+ const {
+ migrationRuleDetailsFlyout: rulePreviewFlyout,
+ openMigrationRuleDetails: openRulePreview,
+ } = useMigrationRuleDetailsFlyout({
+ ruleActionsFactory,
+ });
+
+ const rulesColumns = useMigrationRulesTableColumns({
+ disableActions: isTableLoading,
+ openMigrationRuleDetails: openRulePreview,
+ installMigrationRule: installSingleRule,
+ });
+
+ return (
+ <>
+
-
-
-
-
-
-
-
-
-
-
- loading={isTableLoading}
- items={ruleMigrations}
- pagination={pagination}
- onChange={onTableChange}
- selection={{
- selectable: () => true,
- onSelectionChange: setSelectedRuleMigrations,
- initialSelected: selectedRuleMigrations,
- }}
- itemId={'id'}
- data-test-subj={'rules-translation-table'}
- columns={rulesColumns}
- />
+
+
>
- )
- }
- />
- {rulePreviewFlyout}
- >
- );
-};
-
-export const RulesTable = React.memo(RulesTableComponent);
-RulesTable.displayName = 'RulesTable';
+ }
+ loadedContent={
+ !translationStats?.rules.total ? (
+
+ ) : (
+ <>
+
+
+
+
+
+
+
+
+
+
+ loading={isTableLoading}
+ items={ruleMigrations}
+ pagination={pagination}
+ onChange={onTableChange}
+ selection={{
+ selectable: () => true,
+ onSelectionChange: setSelectedRuleMigrations,
+ initialSelected: selectedRuleMigrations,
+ }}
+ itemId={'id'}
+ data-test-subj={'rules-translation-table'}
+ columns={rulesColumns}
+ />
+ >
+ )
+ }
+ />
+ {rulePreviewFlyout}
+ >
+ );
+ }
+);
+MigrationRulesTable.displayName = 'MigrationRulesTable';
diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/search_field.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/search_field.tsx
index 5bd18851ba595..7b7a576cb1dd9 100644
--- a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/search_field.tsx
+++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/search_field.tsx
@@ -7,19 +7,9 @@
import type { ChangeEvent } from 'react';
import React, { useCallback, useEffect, useState } from 'react';
-import styled from 'styled-components';
import { EuiFieldSearch, EuiFlexItem } from '@elastic/eui';
import * as i18n from './translations';
-const SearchBarWrapper = styled(EuiFlexItem)`
- min-width: 200px;
- & .euiPopover {
- // This is needed to "cancel" styles passed down from EuiTourStep that
- // interfere with EuiFieldSearch and don't allow it to take the full width
- display: block;
- }
-`;
-
interface SearchFieldProps {
initialValue?: string;
onSearch: (value: string) => void;
@@ -39,7 +29,7 @@ export const SearchField: React.FC = React.memo(
}, [initialValue]);
return (
-
+
= React.memo(
onSearch={onSearch}
data-test-subj="ruleSearchField"
/>
-
+
);
}
);
diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/actions.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/actions.tsx
index 7122949dee907..45de70582d4b1 100644
--- a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/actions.tsx
+++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/actions.tsx
@@ -17,14 +17,14 @@ import type { TableColumn } from './constants';
interface ActionNameProps {
disableActions?: boolean;
migrationRule: RuleMigration;
- openMigrationRulePreview: (migrationRule: RuleMigration) => void;
+ openMigrationRuleDetails: (migrationRule: RuleMigration) => void;
installMigrationRule: (migrationRule: RuleMigration, enable?: boolean) => void;
}
const ActionName = ({
disableActions,
migrationRule,
- openMigrationRulePreview,
+ openMigrationRuleDetails,
installMigrationRule,
}: ActionNameProps) => {
const { navigateToApp } = useKibana().services.application;
@@ -72,7 +72,7 @@ const ActionName = ({
{
- openMigrationRulePreview(migrationRule);
+ openMigrationRuleDetails(migrationRule);
}}
data-test-subj="editRule"
>
@@ -83,13 +83,13 @@ const ActionName = ({
interface CreateActionsColumnProps {
disableActions?: boolean;
- openMigrationRulePreview: (migrationRule: RuleMigration) => void;
+ openMigrationRuleDetails: (migrationRule: RuleMigration) => void;
installMigrationRule: (migrationRule: RuleMigration, enable?: boolean) => void;
}
export const createActionsColumn = ({
disableActions,
- openMigrationRulePreview,
+ openMigrationRuleDetails,
installMigrationRule,
}: CreateActionsColumnProps): TableColumn => {
return {
@@ -100,7 +100,7 @@ export const createActionsColumn = ({
);
diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/name.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/name.tsx
index 7b7cf228895fc..085a2f5c6a254 100644
--- a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/name.tsx
+++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/name.tsx
@@ -14,14 +14,14 @@ import type { TableColumn } from './constants';
interface NameProps {
name: string;
rule: RuleMigration;
- openMigrationRulePreview: (rule: RuleMigration) => void;
+ openMigrationRuleDetails: (rule: RuleMigration) => void;
}
-const Name = ({ name, rule, openMigrationRulePreview }: NameProps) => {
+const Name = ({ name, rule, openMigrationRuleDetails }: NameProps) => {
return (
{
- openMigrationRulePreview(rule);
+ openMigrationRuleDetails(rule);
}}
data-test-subj="ruleName"
>
@@ -31,15 +31,15 @@ const Name = ({ name, rule, openMigrationRulePreview }: NameProps) => {
};
export const createNameColumn = ({
- openMigrationRulePreview,
+ openMigrationRuleDetails,
}: {
- openMigrationRulePreview: (rule: RuleMigration) => void;
+ openMigrationRuleDetails: (rule: RuleMigration) => void;
}): TableColumn => {
return {
field: 'original_rule.title',
name: i18n.COLUMN_NAME,
render: (value: RuleMigration['original_rule']['title'], rule: RuleMigration) => (
-
+
),
sortable: true,
truncateText: true,
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 171fe0c451826..60f0ed94862ca 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
@@ -19,31 +19,27 @@ const statusToColorMap: Record = {
untranslatable: euiColorVis9,
};
-interface Props {
+interface StatusBadgeProps {
value?: RuleMigrationTranslationResult;
installedRuleId?: string;
'data-test-subj'?: string;
}
-const StatusBadgeComponent: React.FC = ({
- value,
- installedRuleId,
- 'data-test-subj': dataTestSubj = 'translation-result',
-}) => {
- const translationResult = installedRuleId ? 'full' : value ?? 'untranslatable';
- const displayValue = convertTranslationResultIntoText(translationResult);
- const color = statusToColorMap[translationResult];
+export const StatusBadge: React.FC = React.memo(
+ ({ value, installedRuleId, 'data-test-subj': dataTestSubj = 'translation-result' }) => {
+ const translationResult = installedRuleId ? 'full' : value ?? 'untranslatable';
+ const displayValue = convertTranslationResultIntoText(translationResult);
+ const color = statusToColorMap[translationResult];
- return (
-
- {displayValue}
-
- );
-};
-
-export const StatusBadge = React.memo(StatusBadgeComponent);
+ return (
+
+ {displayValue}
+
+ );
+ }
+);
StatusBadge.displayName = 'StatusBadge';
diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details_flyout/index.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details_flyout/index.tsx
deleted file mode 100644
index b6dce09c311e1..0000000000000
--- a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details_flyout/index.tsx
+++ /dev/null
@@ -1,246 +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 { 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 {
- DEFAULT_TRANSLATION_RISK_SCORE,
- DEFAULT_TRANSLATION_SEVERITY,
-} from '../../../../../common/siem_migrations/constants';
-import type { RuleMigration } from '../../../../../common/siem_migrations/model/rule_migration.gen';
-import {
- RuleOverviewTab,
- useOverviewTabSections,
-} from '../../../../detection_engine/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';
-
-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[];
- closeFlyout: () => void;
-}
-
-export const TranslationDetailsFlyout = ({
- ruleActions,
- ruleMigration,
- size = 'm',
- extraTabs = [],
- 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/siem_migrations/rules/components/translation_details_flyout/translation_tab/rule_query.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details_flyout/translation_tab/rule_query.tsx
deleted file mode 100644
index 50977cafb18d0..0000000000000
--- a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details_flyout/translation_tab/rule_query.tsx
+++ /dev/null
@@ -1,49 +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, { useMemo } from 'react';
-import { EuiMarkdownEditor, EuiMarkdownFormat, EuiTitle } from '@elastic/eui';
-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 {
- 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/siem_migrations/rules/components/unknown_migration/index.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/unknown_migration/index.tsx
index 0a33869eff418..dd48d3b357e18 100644
--- a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/unknown_migration/index.tsx
+++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/unknown_migration/index.tsx
@@ -9,7 +9,7 @@ import React from 'react';
import { EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import * as i18n from './translations';
-const UnknownMigrationComponent = () => {
+export const UnknownMigration: React.FC = React.memo(() => {
return (
{
title={{i18n.UNKNOWN_MIGRATION}
}
titleSize="s"
body={i18n.UNKNOWN_MIGRATION_BODY}
- data-test-subj="noMigrationsAvailable"
+ data-test-subj="unknownMigration"
/>
);
-};
-
-export const UnknownMigration = React.memo(UnknownMigrationComponent);
+});
UnknownMigration.displayName = 'UnknownMigration';
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_migration_rule_preview_flyout.tsx
similarity index 55%
rename from x-pack/plugins/security_solution/public/siem_migrations/rules/hooks/use_rule_preview_flyout.tsx
rename to x-pack/plugins/security_solution/public/siem_migrations/rules/hooks/use_migration_rule_preview_flyout.tsx
index 1721b4e280aad..4823e48de97c6 100644
--- 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_migration_rule_preview_flyout.tsx
@@ -9,28 +9,28 @@ 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';
+import { MigrationRuleDetailsFlyout } from '../components/rule_details_flyout';
-interface UseRulePreviewFlyoutParams {
+interface UseMigrationRuleDetailsFlyoutParams {
ruleActionsFactory: (ruleMigration: RuleMigration, closeRulePreview: () => void) => ReactNode;
extraTabsFactory?: (ruleMigration: RuleMigration) => EuiTabbedContentTab[];
}
-interface UseRulePreviewFlyoutResult {
- rulePreviewFlyout: ReactNode;
- openRulePreview: (rule: RuleMigration) => void;
- closeRulePreview: () => void;
+interface UseMigrationRuleDetailsFlyoutResult {
+ migrationRuleDetailsFlyout: ReactNode;
+ openMigrationRuleDetails: (rule: RuleMigration) => void;
+ closeMigrationRuleDetails: () => void;
}
-export function useRulePreviewFlyout({
+export function useMigrationRuleDetailsFlyout({
extraTabsFactory,
ruleActionsFactory,
-}: UseRulePreviewFlyoutParams): UseRulePreviewFlyoutResult {
- const [ruleMigration, setRuleMigrationForPreview] = useState();
- const closeRulePreview = useCallback(() => setRuleMigrationForPreview(undefined), []);
+}: UseMigrationRuleDetailsFlyoutParams): UseMigrationRuleDetailsFlyoutResult {
+ const [ruleMigration, setMigrationRuleForPreview] = useState();
+ const closeMigrationRuleDetails = useCallback(() => setMigrationRuleForPreview(undefined), []);
const ruleActions = useMemo(
- () => ruleMigration && ruleActionsFactory(ruleMigration, closeRulePreview),
- [ruleMigration, ruleActionsFactory, closeRulePreview]
+ () => ruleMigration && ruleActionsFactory(ruleMigration, closeMigrationRuleDetails),
+ [ruleMigration, ruleActionsFactory, closeMigrationRuleDetails]
);
const extraTabs = useMemo(
() => (ruleMigration && extraTabsFactory ? extraTabsFactory(ruleMigration) : []),
@@ -38,18 +38,18 @@ export function useRulePreviewFlyout({
);
return {
- rulePreviewFlyout: ruleMigration && (
-
),
- openRulePreview: useCallback((rule: RuleMigration) => {
- setRuleMigrationForPreview(rule);
+ openMigrationRuleDetails: useCallback((rule: RuleMigration) => {
+ setMigrationRuleForPreview(rule);
}, []),
- closeRulePreview,
+ closeMigrationRuleDetails,
};
}
diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/hooks/use_rules_table_columns.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/hooks/use_migration_rules_table_columns.tsx
similarity index 78%
rename from x-pack/plugins/security_solution/public/siem_migrations/rules/hooks/use_rules_table_columns.tsx
rename to x-pack/plugins/security_solution/public/siem_migrations/rules/hooks/use_migration_rules_table_columns.tsx
index 219d2f17de441..b8b37bccaffd3 100644
--- a/x-pack/plugins/security_solution/public/siem_migrations/rules/hooks/use_rules_table_columns.tsx
+++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/hooks/use_migration_rules_table_columns.tsx
@@ -17,28 +17,28 @@ import {
createUpdatedColumn,
} from '../components/rules_table_columns';
-export const useRulesTableColumns = ({
+export const useMigrationRulesTableColumns = ({
disableActions,
- openMigrationRulePreview,
+ openMigrationRuleDetails,
installMigrationRule,
}: {
disableActions?: boolean;
- openMigrationRulePreview: (rule: RuleMigration) => void;
+ openMigrationRuleDetails: (rule: RuleMigration) => void;
installMigrationRule: (migrationRule: RuleMigration, enable?: boolean) => void;
}): TableColumn[] => {
return useMemo(
() => [
createUpdatedColumn(),
- createNameColumn({ openMigrationRulePreview }),
+ createNameColumn({ openMigrationRuleDetails }),
createStatusColumn(),
createRiskScoreColumn(),
createSeverityColumn(),
createActionsColumn({
disableActions,
- openMigrationRulePreview,
+ openMigrationRuleDetails,
installMigrationRule,
}),
],
- [disableActions, installMigrationRule, openMigrationRulePreview]
+ [disableActions, installMigrationRule, openMigrationRuleDetails]
);
};
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/logic/constants.ts
similarity index 100%
rename from x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/constants.ts
rename to x-pack/plugins/security_solution/public/siem_migrations/rules/logic/constants.ts
diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/logic/use_get_migration_rules.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/logic/use_get_migration_rules.ts
index 92f06b2e37428..5f59ceb9f76c2 100644
--- a/x-pack/plugins/security_solution/public/siem_migrations/rules/logic/use_get_migration_rules.ts
+++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/logic/use_get_migration_rules.ts
@@ -5,9 +5,14 @@
* 2.0.
*/
+import { useQuery, useQueryClient } from '@tanstack/react-query';
+import { replaceParams } from '@kbn/openapi-common/shared';
+import { useCallback } from 'react';
+import { SIEM_RULE_MIGRATION_PATH } from '../../../../common/siem_migrations/constants';
import { useAppToasts } from '../../../common/hooks/use_app_toasts';
-import { useGetMigrationRulesQuery } from '../api/hooks/use_get_migration_rules_query';
import * as i18n from './translations';
+import { getRuleMigrations } from '../api';
+import { DEFAULT_QUERY_OPTIONS } from './constants';
export const useGetMigrationRules = (params: {
migrationId: string;
@@ -17,9 +22,47 @@ export const useGetMigrationRules = (params: {
}) => {
const { addError } = useAppToasts();
- return useGetMigrationRulesQuery(params, {
- onError: (error) => {
- addError(error, { title: i18n.GET_MIGRATION_RULES_FAILURE });
+ const { migrationId } = params;
+ const SPECIFIC_MIGRATION_PATH = replaceParams(SIEM_RULE_MIGRATION_PATH, {
+ migration_id: migrationId,
+ });
+
+ return useQuery(
+ ['GET', SPECIFIC_MIGRATION_PATH, params],
+ async ({ signal }) => {
+ const response = await getRuleMigrations({ signal, ...params });
+
+ return { ruleMigrations: response.data, total: response.total };
},
+ {
+ ...DEFAULT_QUERY_OPTIONS,
+ onError: (error) => {
+ addError(error, { title: i18n.GET_MIGRATION_RULES_FAILURE });
+ },
+ }
+ );
+};
+
+/**
+ * We should use this hook to invalidate the rule migrations cache. For
+ * example, rule migrations mutations, like installing a rule, should lead to cache invalidation.
+ *
+ * @returns A rule migrations cache invalidation callback
+ */
+export const useInvalidateGetMigrationRules = (migrationId: string) => {
+ const queryClient = useQueryClient();
+
+ const SPECIFIC_MIGRATION_PATH = replaceParams(SIEM_RULE_MIGRATION_PATH, {
+ migration_id: migrationId,
});
+
+ return useCallback(() => {
+ /**
+ * Invalidate all queries that start with SPECIFIC_MIGRATION_PATH. This
+ * includes the in-memory query cache and paged query cache.
+ */
+ queryClient.invalidateQueries(['GET', SPECIFIC_MIGRATION_PATH], {
+ refetchType: 'active',
+ });
+ }, [SPECIFIC_MIGRATION_PATH, queryClient]);
};
diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/logic/use_get_migration_translation_stats.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/logic/use_get_migration_translation_stats.ts
index 081876ba266a9..b19a1133e3061 100644
--- a/x-pack/plugins/security_solution/public/siem_migrations/rules/logic/use_get_migration_translation_stats.ts
+++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/logic/use_get_migration_translation_stats.ts
@@ -5,16 +5,58 @@
* 2.0.
*/
+import { replaceParams } from '@kbn/openapi-common/shared';
+import { useQuery, useQueryClient } from '@tanstack/react-query';
+import { useCallback } from 'react';
+import type { GetRuleMigrationTranslationStatsResponse } from '../../../../common/siem_migrations/model/api/rules/rule_migration.gen';
+import { SIEM_RULE_MIGRATION_TRANSLATION_STATS_PATH } from '../../../../common/siem_migrations/constants';
import { useAppToasts } from '../../../common/hooks/use_app_toasts';
-import { useGetMigrationTranslationStatsQuery } from '../api/hooks/use_get_migration_translation_stats_query';
import * as i18n from './translations';
+import { getRuleMigrationTranslationStats } from '../api';
+import { DEFAULT_QUERY_OPTIONS } from './constants';
export const useGetMigrationTranslationStats = (migrationId: string) => {
const { addError } = useAppToasts();
- return useGetMigrationTranslationStatsQuery(migrationId, {
- onError: (error) => {
- addError(error, { title: i18n.GET_MIGRATION_TRANSLATION_STATS_FAILURE });
+ const SPECIFIC_MIGRATION_TRANSLATION_PATH = replaceParams(
+ SIEM_RULE_MIGRATION_TRANSLATION_STATS_PATH,
+ {
+ migration_id: migrationId,
+ }
+ );
+ return useQuery(
+ ['GET', SPECIFIC_MIGRATION_TRANSLATION_PATH],
+ async ({ signal }) => {
+ return getRuleMigrationTranslationStats({ migrationId, signal });
},
- });
+ {
+ ...DEFAULT_QUERY_OPTIONS,
+ onError: (error) => {
+ addError(error, { title: i18n.GET_MIGRATION_TRANSLATION_STATS_FAILURE });
+ },
+ }
+ );
+};
+
+/**
+ * We should use this hook to invalidate the translation stats cache. For
+ * example, rule migrations mutations, like installing a rule, should lead to cache invalidation.
+ *
+ * @returns A translation stats cache invalidation callback
+ */
+export const useInvalidateGetMigrationTranslationStats = (migrationId: string) => {
+ const queryClient = useQueryClient();
+
+ const SPECIFIC_MIGRATION_TRANSLATION_PATH = replaceParams(
+ SIEM_RULE_MIGRATION_TRANSLATION_STATS_PATH,
+ {
+ migration_id: migrationId,
+ }
+ );
+
+ return useCallback(() => {
+ queryClient.invalidateQueries(['GET', SPECIFIC_MIGRATION_TRANSLATION_PATH], {
+ refetchType: 'active',
+ });
+ }, [SPECIFIC_MIGRATION_TRANSLATION_PATH, queryClient]);
};
diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/logic/use_install_migration_rules.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/logic/use_install_migration_rules.ts
index dcc19f290f87f..755faa03bff14 100644
--- a/x-pack/plugins/security_solution/public/siem_migrations/rules/logic/use_install_migration_rules.ts
+++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/logic/use_install_migration_rules.ts
@@ -5,16 +5,35 @@
* 2.0.
*/
+import { useMutation } from '@tanstack/react-query';
+import { SIEM_RULE_MIGRATION_INSTALL_PATH } from '../../../../common/siem_migrations/constants';
+import type { InstallMigrationRulesResponse } from '../../../../common/siem_migrations/model/api/rules/rule_migration.gen';
import { useAppToasts } from '../../../common/hooks/use_app_toasts';
-import { useInstallMigrationRulesMutation } from '../api/hooks/use_install_migration_rules_mutation';
import * as i18n from './translations';
+import { useInvalidateGetMigrationRules } from './use_get_migration_rules';
+import { useInvalidateGetMigrationTranslationStats } from './use_get_migration_translation_stats';
+import { installMigrationRules } from '../api';
+
+export const INSTALL_MIGRATION_RULES_MUTATION_KEY = ['POST', SIEM_RULE_MIGRATION_INSTALL_PATH];
export const useInstallMigrationRules = (migrationId: string) => {
const { addError } = useAppToasts();
- return useInstallMigrationRulesMutation(migrationId, {
- onError: (error) => {
- addError(error, { title: i18n.INSTALL_MIGRATION_RULES_FAILURE });
- },
- });
+ const invalidateGetRuleMigrations = useInvalidateGetMigrationRules(migrationId);
+ const invalidateGetMigrationTranslationStats =
+ useInvalidateGetMigrationTranslationStats(migrationId);
+
+ return useMutation(
+ (ids: string[]) => installMigrationRules({ migrationId, ids }),
+ {
+ mutationKey: INSTALL_MIGRATION_RULES_MUTATION_KEY,
+ onError: (error) => {
+ addError(error, { title: i18n.INSTALL_MIGRATION_RULES_FAILURE });
+ },
+ onSettled: () => {
+ invalidateGetRuleMigrations();
+ invalidateGetMigrationTranslationStats();
+ },
+ }
+ );
};
diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/logic/use_install_translated_migration_rules.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/logic/use_install_translated_migration_rules.ts
index 67ee3f099aca0..b0d9e11136396 100644
--- a/x-pack/plugins/security_solution/public/siem_migrations/rules/logic/use_install_translated_migration_rules.ts
+++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/logic/use_install_translated_migration_rules.ts
@@ -5,16 +5,38 @@
* 2.0.
*/
+import { useMutation } from '@tanstack/react-query';
+import type { InstallTranslatedMigrationRulesResponse } from '../../../../common/siem_migrations/model/api/rules/rule_migration.gen';
+import { SIEM_RULE_MIGRATION_INSTALL_TRANSLATED_PATH } from '../../../../common/siem_migrations/constants';
import { useAppToasts } from '../../../common/hooks/use_app_toasts';
-import { useInstallTranslatedMigrationRulesMutation } from '../api/hooks/use_install_translated_migration_rules_mutation';
import * as i18n from './translations';
+import { useInvalidateGetMigrationRules } from './use_get_migration_rules';
+import { useInvalidateGetMigrationTranslationStats } from './use_get_migration_translation_stats';
+import { installTranslatedMigrationRules } from '../api';
+
+export const INSTALL_ALL_MIGRATION_RULES_MUTATION_KEY = [
+ 'POST',
+ SIEM_RULE_MIGRATION_INSTALL_TRANSLATED_PATH,
+];
export const useInstallTranslatedMigrationRules = (migrationId: string) => {
const { addError } = useAppToasts();
- return useInstallTranslatedMigrationRulesMutation(migrationId, {
- onError: (error) => {
- addError(error, { title: i18n.INSTALL_MIGRATION_RULES_FAILURE });
- },
- });
+ const invalidateGetRuleMigrations = useInvalidateGetMigrationRules(migrationId);
+ const invalidateGetMigrationTranslationStats =
+ useInvalidateGetMigrationTranslationStats(migrationId);
+
+ return useMutation(
+ () => installTranslatedMigrationRules({ migrationId }),
+ {
+ mutationKey: INSTALL_ALL_MIGRATION_RULES_MUTATION_KEY,
+ onError: (error) => {
+ addError(error, { title: i18n.INSTALL_MIGRATION_RULES_FAILURE });
+ },
+ onSettled: () => {
+ invalidateGetRuleMigrations();
+ invalidateGetMigrationTranslationStats();
+ },
+ }
+ );
};
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 dabdb83cccbab..018aa5d77559e 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
@@ -9,22 +9,23 @@ import React, { useEffect, useMemo } from 'react';
import { EuiSkeletonLoading, EuiSkeletonText, EuiSkeletonTitle } from '@elastic/eui';
import type { RouteComponentProps } from 'react-router-dom';
+import { SiemMigrationTaskStatus } from '../../../../common/siem_migrations/constants';
import { useNavigation } from '../../../common/lib/kibana';
import { HeaderPage } from '../../../common/components/header_page';
import { SecuritySolutionPageWrapper } from '../../../common/components/page_wrapper';
import { SecurityPageName } from '../../../app/types';
import * as i18n from './translations';
-import { RulesTable } from '../components/rules_table';
+import { MigrationRulesTable } from '../components/rules_table';
import { NeedAdminForUpdateRulesCallOut } from '../../../detections/components/callouts/need_admin_for_update_callout';
import { MissingPrivilegesCallOut } from '../../../detections/components/callouts/missing_privileges_callout';
import { HeaderButtons } from '../components/header_buttons';
import { UnknownMigration } from '../components/unknown_migration';
import { useLatestStats } from '../hooks/use_latest_stats';
-type RulesMigrationPageProps = RouteComponentProps<{ migrationId?: string }>;
+type MigrationRulesPageProps = RouteComponentProps<{ migrationId?: string }>;
-export const RulesPage: React.FC = React.memo(
+export const MigrationRulesPage: React.FC = React.memo(
({
match: {
params: { migrationId },
@@ -34,13 +35,13 @@ export const RulesPage: React.FC = React.memo(
const { data: ruleMigrationsStatsAll, isLoading: isLoadingMigrationsStats } = useLatestStats();
- const migrationsIds = useMemo(() => {
+ const finishedRuleMigrationsStats = useMemo(() => {
if (isLoadingMigrationsStats || !ruleMigrationsStatsAll?.length) {
return [];
}
- return ruleMigrationsStatsAll
- .filter((migration) => migration.status === 'finished')
- .map((migration) => migration.id);
+ return ruleMigrationsStatsAll.filter(
+ (migration) => migration.status === SiemMigrationTaskStatus.FINISHED
+ );
}, [isLoadingMigrationsStats, ruleMigrationsStatsAll]);
useEffect(() => {
@@ -49,27 +50,30 @@ export const RulesPage: React.FC = React.memo(
}
// Navigate to landing page if there are no migrations
- if (!migrationsIds.length) {
+ if (!finishedRuleMigrationsStats.length) {
navigateTo({ deepLinkId: SecurityPageName.landing, path: 'siem_migrations' });
return;
}
// Navigate to the most recent migration if none is selected
if (!migrationId) {
- navigateTo({ deepLinkId: SecurityPageName.siemMigrationsRules, path: migrationsIds[0] });
+ navigateTo({
+ deepLinkId: SecurityPageName.siemMigrationsRules,
+ path: finishedRuleMigrationsStats[0].id,
+ });
}
- }, [isLoadingMigrationsStats, migrationId, migrationsIds, navigateTo]);
+ }, [isLoadingMigrationsStats, migrationId, finishedRuleMigrationsStats, navigateTo]);
const onMigrationIdChange = (selectedId?: string) => {
navigateTo({ deepLinkId: SecurityPageName.siemMigrationsRules, path: selectedId });
};
const content = useMemo(() => {
- if (!migrationId || !migrationsIds.includes(migrationId)) {
+ if (!migrationId || !finishedRuleMigrationsStats.some((stats) => stats.id === migrationId)) {
return ;
}
- return ;
- }, [migrationId, migrationsIds]);
+ return ;
+ }, [migrationId, finishedRuleMigrationsStats]);
return (
<>
@@ -79,7 +83,7 @@ export const RulesPage: React.FC = React.memo(
@@ -99,4 +103,4 @@ export const RulesPage: React.FC = React.memo(
);
}
);
-RulesPage.displayName = 'RulesPage';
+MigrationRulesPage.displayName = 'MigrationRulesPage';
diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/service/rule_migrations_service.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/service/rule_migrations_service.ts
index a872d79a46027..3162cc3d58e63 100644
--- a/x-pack/plugins/security_solution/public/siem_migrations/rules/service/rule_migrations_service.ts
+++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/service/rule_migrations_service.ts
@@ -12,7 +12,7 @@ import { SiemMigrationTaskStatus } from '../../../../common/siem_migrations/cons
import type { StartPluginsDependencies } from '../../../types';
import { ExperimentalFeaturesService } from '../../../common/experimental_features_service';
import { licenseService } from '../../../common/hooks/use_license';
-import { getRuleMigrationsStatsAll, startRuleMigration } from '../api/api';
+import { getRuleMigrationsStatsAll, startRuleMigration } from '../api';
import type { RuleMigrationTask } from '../types';
import { getSuccessToast } from './success_notification';
import { RuleMigrationsStorage } from './storage';
diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/types.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/types.ts
index b395fa0199de8..4c704e97179c0 100644
--- a/x-pack/plugins/security_solution/public/siem_migrations/rules/types.ts
+++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/types.ts
@@ -11,14 +11,3 @@ export interface RuleMigrationTask extends RuleMigrationTaskStats {
/** The sequential number of the migration */
number: number;
}
-
-export interface InstallRulesProps {
- migrationId: string;
- ids: string[];
- signal?: AbortSignal;
-}
-
-export interface InstallTranslatedRulesProps {
- migrationId: string;
- signal?: AbortSignal;
-}
diff --git a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/util/installation.ts b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/util/installation.ts
index 756b4b99612c7..df86a1f953656 100644
--- a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/util/installation.ts
+++ b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/util/installation.ts
@@ -42,7 +42,7 @@ const installPrebuiltRules = async (
const rulesToUpdate: UpdateRuleMigrationInput[] = [];
const assetsToInstall: PrebuiltRuleAsset[] = [];
rulesToInstall.forEach((ruleToInstall) => {
- // If prebuilt rule has already been install, then just update migration rule with the installed rule id
+ // If prebuilt rule has already been installed, then just update migration rule with the installed rule id
const installedRule = currentRules.find(
(rule) => rule.rule_id === ruleToInstall.elastic_rule?.prebuilt_rule_id
);