Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
/*
* 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 { v4 as uuidv4 } from 'uuid';
import { SiemMigrationTaskStatus } from '../../../../common/siem_migrations/constants';
import type {
GetRuleMigrationResponse,
GetRuleMigrationTranslationStatsResponse,
} from '../../../../common/siem_migrations/model/api/rules/rule_migration.gen';
import type { RuleMigrationStats } from '../../rules/types';

const getMockMigrationResultRule = ({
migrationId,
translationResult = 'full',
status = 'completed',
}: {
migrationId: string;
status?: GetRuleMigrationResponse['data'][number]['status'];
translationResult?: GetRuleMigrationResponse['data'][number]['translation_result'];
}): GetRuleMigrationResponse['data'][number] => {
const ruleId = uuidv4();
return {
migration_id: migrationId,
original_rule: {
id: ruleId,
vendor: 'splunk',
title: ` 'Rule Title - ${ruleId}'`,
description: `Rule Title Description - ${ruleId}`,
query: 'some query',
query_language: 'spl',
},
'@timestamp': '2025-03-06T15:00:01.036Z',
status,
created_by: 'u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0',
updated_by: 'u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0',
updated_at: '2025-03-06T15:01:37.321Z',
comments: [
{
created_at: '2025-03-06T15:01:06.390Z',
message: '## Prebuilt Rule Matching Summary\nNo related prebuilt rule found.',
created_by: 'assistant',
},
],
translation_result: translationResult,
elastic_rule: {
severity: 'low',
risk_score: 21,
query:
'FROM index metadata _id,_version,_index\n| WHERE MATCH(host.hostname, "vendor_sales")',
description: `Converted Splunk Rule to Elastic Rule - ${ruleId}`,
query_language: 'esql',
title: `Converted Splunk Rule - ${ruleId}`,
integration_ids: ['endpoint'],
},
id: ruleId,
};
};

export const mockedMigrationLatestStatsData: RuleMigrationStats[] = [
{
id: '1',
number: 1,
status: SiemMigrationTaskStatus.FINISHED,
rules: {
total: 1,
pending: 0,
processing: 0,
completed: 1,
failed: 0,
},
last_updated_at: '2025-03-06T15:01:37.321Z',
created_at: '2025-03-06T15:01:37.321Z',
},
{
id: '2',
number: 2,
status: SiemMigrationTaskStatus.FINISHED,
rules: {
total: 2,
pending: 0,
processing: 0,
completed: 2,
failed: 0,
},

created_at: '2025-03-06T15:01:37.321Z',
last_updated_at: '2025-03-06T15:01:37.321Z',
},
];

export const mockedMigrationResultsObj: Record<string, GetRuleMigrationResponse> = {
'1': {
total: 2,
data: [
getMockMigrationResultRule({
migrationId: '1',
translationResult: 'full',
status: 'completed',
}),
getMockMigrationResultRule({
migrationId: '1',
translationResult: 'untranslatable',
status: 'failed',
}),
],
},
};

export const mockedMigrationTranslationStats: Record<
string,
GetRuleMigrationTranslationStatsResponse
> = {
'1': {
id: '1',
rules: {
total: 2,
success: {
total: 2,
result: {
full: 1,
partial: 0,
untranslatable: 1,
},
installable: 1,
prebuilt: 0,
},
failed: 0,
},
},
};

const mockRefreshStats = jest.fn();
export const mockedLatestStatsEmpty = {
data: [],
isLoading: false,
refreshStats: mockRefreshStats,
};

export const mockedLatestStats = {
...mockedLatestStatsEmpty,
data: mockedMigrationLatestStatsData,
};
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,12 @@ export const MigrationRulesTable: React.FC<MigrationRulesTableProps> = React.mem
<EmptyMigration />
) : (
<>
<EuiFlexGroup gutterSize="m" justifyContent="flexEnd" wrap>
<EuiFlexGroup
data-test-subj="siemMigrationsRulesTable"
gutterSize="m"
justifyContent="flexEnd"
wrap
>
<EuiFlexItem>
<SearchField initialValue={searchTerm} onSearch={handleOnSearch} />
</EuiFlexItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ interface NameProps {
const Name = ({ rule, openMigrationRuleDetails }: NameProps) => {
if (rule.status === SiemMigrationStatus.FAILED) {
return (
<EuiText color="danger" size="s">
<EuiText data-test-subj="ruleName" color="danger" size="s">
{rule.original_rule.title}
</EuiText>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import * as i18n from './translations';
export const UnknownMigration: React.FC = React.memo(() => {
return (
<EuiFlexGroup
data-test-subj="siemMigrationsUnknown"
alignItems="center"
gutterSize="s"
responsive={false}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* 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 { EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template';
import { SecurityPageName } from '@kbn/deeplinks-security';
import { css } from '@emotion/react';
import { SecuritySolutionLinkButton } from '../../../common/components/links';
import * as i18n from './translations';
import { OnboardingCardId, OnboardingTopicId } from '../../../onboarding/constants';

export const EmptyMigrationRulesPage = () => {
return (
<KibanaPageTemplate.Section color="plain" paddingSize="none">
<EuiFlexGroup
css={css`
/**
* 240px compensates for the kibana header, action bar and page header.
* It also compensates for the extra margin that header introduces
*/
min-height: calc(100vh - 240px);
`}
justifyContent="center"
alignItems="center"
>
<EuiFlexItem>
<EuiEmptyPrompt
title={
<span data-test-subj="siemMigrationsTranslatedRulesEmptyPageHeader">
{i18n.TRANSLATED_RULES_EMPTY_PAGE_TITLE}
</span>
}
actions={
<SecuritySolutionLinkButton
deepLinkId={SecurityPageName.landing}
path={`${OnboardingTopicId.siemMigrations}#${OnboardingCardId.siemMigrationsRules}`}
>
{i18n.TRANSLATED_RULES_EMPTY_PAGE_CTA}
</SecuritySolutionLinkButton>
}
iconType={'logoSecurity'}
body={
<span data-test-subj="siemMigrationsTranslatedRulesEmptyPageMessage">
{i18n.TRANSLATED_RULES_EMPTY_PAGE_MESSAGE}
</span>
}
/>
</EuiFlexItem>
</EuiFlexGroup>
</KibanaPageTemplate.Section>
);
};
Loading