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
Expand Up @@ -14,6 +14,7 @@ import {
EuiFlexGroup,
EuiFlexItem,
EuiSpacer,
EuiTitle,
EuiToolTip,
} from '@elastic/eui';
import { css } from '@emotion/react';
Expand Down Expand Up @@ -76,6 +77,7 @@ export function PackageCard({
onCardClick: onClickProp = undefined,
isCollectionCard = false,
titleLineClamp,
titleBadge,
descriptionLineClamp,
maxCardHeight,
minCardHeight,
Expand Down Expand Up @@ -231,6 +233,7 @@ export function PackageCard({
}

[class*='euiCard__titleButton'] {
width: 100%;
${getLineClampStyles(titleLineClamp)}
}

Expand All @@ -240,7 +243,7 @@ export function PackageCard({
isquickstart={isQuickstart}
betaBadgeProps={quickstartBadge(isQuickstart)}
layout="horizontal"
title={title || ''}
title={<CardTitle title={title} titleBadge={titleBadge} />}
titleSize="xs"
description={showDescription ? description : ''}
hasBorder
Expand Down Expand Up @@ -277,6 +280,30 @@ export function PackageCard({
);
}

const CardTitle = React.memo<Pick<IntegrationCardItem, 'title' | 'titleBadge'>>(
({ title, titleBadge }) => {
if (!titleBadge) {
return title;
}
return (
<EuiFlexGroup
direction="row"
alignItems="flexStart"
justifyContent="spaceBetween"
gutterSize="s"
responsive={false}
>
<EuiFlexItem>
<EuiTitle size="xs">
<h3>{title}</h3>
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem grow={false}>{titleBadge}</EuiFlexItem>
</EuiFlexGroup>
);
}
);

function quickstartBadge(isQuickstart: boolean): { label: string; color: 'accent' } | undefined {
return isQuickstart
? {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export interface IntegrationCardItem {
title: string;
// Security Solution uses this prop to determine how many lines the card title should be truncated
titleLineClamp?: number;
titleBadge?: React.ReactNode;
url: string;
version: string;
type?: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,7 @@ import type {
GetRuleMigrationRequestParamsInput,
GetRuleMigrationResponse,
GetRuleMigrationIntegrationsResponse,
GetRuleMigrationIntegrationsStatsResponse,
GetRuleMigrationPrebuiltRulesRequestParamsInput,
GetRuleMigrationPrebuiltRulesResponse,
GetRuleMigrationPrivilegesResponse,
Expand Down Expand Up @@ -1668,6 +1669,21 @@ finalize it.
})
.catch(catchAxiosErrorFormatAndThrow);
}
/**
* Retrieves the stats of all the integrations for all the rule migrations, including the number of rules associated with the integration
*/
async getRuleMigrationIntegrationsStats() {
this.log.info(`${new Date().toISOString()} Calling API GetRuleMigrationIntegrationsStats`);
return this.kbnClient
.request<GetRuleMigrationIntegrationsStatsResponse>({
path: '/internal/siem_migrations/rules/integrations/stats',
headers: {
[ELASTIC_HTTP_VERSION_HEADER]: '1',
},
method: 'GET',
})
.catch(catchAxiosErrorFormatAndThrow);
}
/**
* Retrieves all available prebuilt rules (installed and installable)
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ export const SIEM_RULE_MIGRATIONS_PATH = `${SIEM_MIGRATIONS_PATH}/rules` as cons
export const SIEM_RULE_MIGRATIONS_ALL_STATS_PATH = `${SIEM_RULE_MIGRATIONS_PATH}/stats` as const;
export const SIEM_RULE_MIGRATIONS_INTEGRATIONS_PATH =
`${SIEM_RULE_MIGRATIONS_PATH}/integrations` as const;
export const SIEM_RULE_MIGRATIONS_INTEGRATIONS_STATS_PATH =
`${SIEM_RULE_MIGRATIONS_PATH}/integrations/stats` as const;
export const SIEM_RULE_MIGRATION_PATH = `${SIEM_RULE_MIGRATIONS_PATH}/{migration_id}` as const;
export const SIEM_RULE_MIGRATION_RULES_PATH = `${SIEM_RULE_MIGRATION_PATH}/rules` as const;
export const SIEM_RULE_MIGRATION_START_PATH = `${SIEM_RULE_MIGRATION_PATH}/start` as const;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { ArrayFromString, BooleanFromString } from '@kbn/zod-helpers';

import {
RuleMigrationTaskStats,
RuleMigrationAllIntegrationsStats,
RuleMigration,
OriginalRule,
RuleMigrationRule,
Expand Down Expand Up @@ -89,6 +90,11 @@ export type GetRuleMigrationIntegrationsResponse = z.infer<
>;
export const GetRuleMigrationIntegrationsResponse = z.object({}).catchall(RelatedIntegration);

export type GetRuleMigrationIntegrationsStatsResponse = z.infer<
typeof GetRuleMigrationIntegrationsStatsResponse
>;
export const GetRuleMigrationIntegrationsStatsResponse = RuleMigrationAllIntegrationsStats;

export type GetRuleMigrationPrebuiltRulesRequestParams = z.infer<
typeof GetRuleMigrationPrebuiltRulesRequestParams
>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,23 @@ paths:
additionalProperties:
$ref: '../../../../../common/api/detection_engine/model/rule_schema/common_attributes.schema.yaml#/components/schemas/RelatedIntegration'

/internal/siem_migrations/rules/integrations/stats:
get:
summary: Retrieves the stats of all the integrations for all the rule migrations
operationId: GetRuleMigrationIntegrationsStats
x-codegen-enabled: true
x-internal: true
description: Retrieves the stats of all the integrations for all the rule migrations, including the number of rules associated with the integration
tags:
- SIEM Rule Migrations
responses:
200:
description: Indicates that related integrations stats have been retrieved correctly.
content:
application/json:
schema:
$ref: '../../rule_migration.schema.yaml#/components/schemas/RuleMigrationAllIntegrationsStats'

/internal/siem_migrations/rules:
put:
summary: Creates a new rule migration
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,27 @@ export const RuleMigrationRetryFilter = z.enum(['failed', 'not_fully_translated'
export type RuleMigrationRetryFilterEnum = typeof RuleMigrationRetryFilter.enum;
export const RuleMigrationRetryFilterEnum = RuleMigrationRetryFilter.enum;

/**
* The migration rules integration stats object.
*/
export type RuleMigrationIntegrationStats = z.infer<typeof RuleMigrationIntegrationStats>;
export const RuleMigrationIntegrationStats = z.object({
/**
* The integration id
*/
id: NonEmptyString,
/**
* The number of rules that are associated with the integration.
*/
total_rules: z.number().int(),
});

/**
* The integrations stats objects of all the rule of all the migrations.
*/
export type RuleMigrationAllIntegrationsStats = z.infer<typeof RuleMigrationAllIntegrationsStats>;
export const RuleMigrationAllIntegrationsStats = z.array(RuleMigrationIntegrationStats);

/**
* The type of the rule migration resource.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,26 @@ components:
- failed
- not_fully_translated

RuleMigrationAllIntegrationsStats:
type: array
description: The integrations stats objects of all the rule of all the migrations.
items:
description: The migration rules integration stats object.
$ref: '#/components/schemas/RuleMigrationIntegrationStats'
RuleMigrationIntegrationStats:
type: object
description: The migration rules integration stats object.
required:
- id
- total_rules
properties:
id:
description: The integration id
$ref: '../../../common/api/model/primitives.schema.yaml#/components/schemas/NonEmptyString'
total_rules:
type: integer
description: The number of rules that are associated with the integration.

## Rule migration resources

RuleMigrationResourceType:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@
*/
import React, { useEffect, useState } from 'react';

/**
* HOC to wrap a component with a lazy-loaded hook.
* This allows the component to use a hook that is imported dynamically,
* which can be useful for reducing the initial bundle size.
*
* @param Component - The component to wrap, it have to accept the hook as a prop (e.g. { useSomeHook: UseSomeHook }).
* @param hookImport - A function that returns a promise resolving to an object with the hook's prop (e.g. { useSomeHook: () => {} }).
* @param fallback - A fallback React node to render while the hook is being loaded.
*/
export const withLazyHook = <P extends {}, PInjected extends keyof P>(
Component: React.ComponentType<P>,
hookImport: () => Promise<Pick<P, PInjected>>,
Expand Down
Original file line number Diff line number Diff line change
@@ -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 { useMemo } from 'react';
import type { GetAppUrl } from '@kbn/security-solution-navigation/src/navigation';
import { useNavigation } from '@kbn/security-solution-navigation/src/navigation';
import { APP_UI_ID } from '../../../../common';

export const useIntegrationLinkState = (path: string) => {
const { getAppUrl } = useNavigation();

return useMemo(() => getIntegrationLinkState(path, getAppUrl), [getAppUrl, path]);
};

export const getIntegrationLinkState = (path: string, getAppUrl: GetAppUrl) => {
const url = getAppUrl({
appId: APP_UI_ID,
path,
});

return {
onCancelNavigateTo: [APP_UI_ID, { path }],
onCancelUrl: url,
onSaveNavigateTo: [APP_UI_ID, { path }],
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@

import React from 'react';

export const IntegrationsCardGridTabs = () => <div data-test-subj="integrationsCardGridTabs" />;
export const SecurityIntegrations = jest.fn(() => <div data-test-subj="securityIntegrations" />);
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@
*/
import React from 'react';

export const SecurityIntegrations = () => <div data-test-subj="securityIntegrations" />;
export const SecurityIntegrationsGridTabs = jest.fn(() => (
<div data-test-subj="securityIntegrationsGridTabs" />
));
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React from 'react';
import type { IntegrationCardItem } from '@kbn/fleet-plugin/public';

export const getDefaultAvailablePackages = () => ({
initialSelectedCategory: '',
selectedCategory: '',
setCategory: jest.fn(),
allCategories: [],
mainCategories: [],
availableSubCategories: [],
selectedSubCategory: '',
setSelectedSubCategory: jest.fn(),
searchTerm: '',
setSearchTerm: jest.fn(),
setUrlandPushHistory: jest.fn(),
setUrlandReplaceHistory: jest.fn(),
preference: '',
setPreference: jest.fn(),
isLoading: false,
isLoadingCategories: false,
isLoadingAllPackages: false,
isLoadingAppendCustomIntegrations: false,
eprPackageLoadingError: null,
eprCategoryLoadingError: null,
filteredCards: [] as IntegrationCardItem[],
});

export const mockAvailablePackages = jest.fn(() => getDefaultAvailablePackages());

export const withAvailablePackages = jest.fn(
(Component: React.ComponentType<{ availablePackages: unknown }>) =>
function WithAvailablePackages(props: object) {
return (
<div data-test-subj="withAvailablePackages">
<Component
{...{
...props,
availablePackages: mockAvailablePackages(),
}}
/>
</div>
);
}
);

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,4 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React from 'react';

export const PackageListGrid = () => <div data-test-subj="packageListGrid" />;
export { SecurityIntegrations } from './security_integrations';
Loading
Loading