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 @@ -21,7 +21,7 @@ import * as api from '../api';
import { getMissingCapabilitiesToast } from '../../common/service/notifications/missing_capabilities_notification';
import { getNoConnectorToast } from '../../common/service/notifications/no_connector_notification';
import { SiemMigrationTaskStatus } from '../../../../common/siem_migrations/constants';
import { getSuccessToast } from './notification/success_notification';
import { raiseSuccessToast } from './notification/success_notification';
import type { CapabilitiesLevel, MissingCapability } from '../../common/service/capabilities';
import { getMissingCapabilitiesChecker } from '../../common/service/capabilities';
import { requiredDashboardMigrationCapabilities } from './capabilities';
Expand Down Expand Up @@ -221,7 +221,7 @@ export class SiemDashboardMigrationsService extends SiemMigrationsServiceBase<Da
}

protected sendFinishedMigrationNotification(taskStats: DashboardMigrationStats) {
this.core.notifications.toasts.addSuccess(getSuccessToast(taskStats, this.core));
raiseSuccessToast(taskStats, this.core);
}

/** Deletes a dashboard migration by its ID, refreshing the stats to remove it from the list */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,36 +13,41 @@ import {
useNavigation,
NavigationProvider,
} from '@kbn/security-solution-navigation';
import type { ToastInput } from '@kbn/core-notifications-browser';
import { toMountPoint } from '@kbn/react-kibana-mount';
import { FormattedMessage } from '@kbn/i18n-react';
import { EuiButton, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import type { DashboardMigrationTaskStats } from '../../../../../common/siem_migrations/model/dashboard_migration.gen';

export const getSuccessToast = (
export const raiseSuccessToast = (
migrationStats: DashboardMigrationTaskStats,
core: CoreStart
): ToastInput => ({
color: 'success',
iconType: 'check',
toastLifeTimeMs: 1000 * 60 * 30, // 30 minutes
title: i18n.translate(
'xpack.securitySolution.siemMigrations.dashboardsService.polling.successTitle',
{
defaultMessage: 'Dashboards translation complete.',
}
),
text: toMountPoint(
<NavigationProvider core={core}>
<SuccessToastContent migrationStats={migrationStats} />
</NavigationProvider>,
core
),
});
): void => {
const toast = core.notifications.toasts.addSuccess({
color: 'success',
iconType: 'check',
toastLifeTimeMs: 1000 * 60 * 30, // 30 minutes
title: i18n.translate(
'xpack.securitySolution.siemMigrations.dashboardsService.polling.successTitle',
{
defaultMessage: 'Dashboards translation complete.',
}
),
text: toMountPoint(
<NavigationProvider core={core}>
<SuccessToastContent
migrationStats={migrationStats}
dismissHandler={() => core.notifications.toasts.remove(toast)}
/>
</NavigationProvider>,
core
),
});
};

const SuccessToastContent: React.FC<{ migrationStats: DashboardMigrationTaskStats }> = ({
migrationStats,
}) => {
const SuccessToastContent: React.FC<{
migrationStats: DashboardMigrationTaskStats;
dismissHandler: () => void;
}> = ({ migrationStats, dismissHandler }) => {
const { navigateTo, getAppUrl } = useNavigation();

const navParams = useMemo(() => {
Expand All @@ -56,8 +61,9 @@ const SuccessToastContent: React.FC<{ migrationStats: DashboardMigrationTaskStat
deepLinkId: SecurityPageName.siemMigrationsDashboards,
path: migrationStats.id,
});
dismissHandler();
},
[navigateTo, migrationStats.id]
[navigateTo, migrationStats.id, dismissHandler]
);
const url = useMemo(() => getAppUrl(navParams), [getAppUrl, navParams]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@

import React from 'react';
import { render } from '@testing-library/react';
import { coreMock } from '@kbn/core/public/mocks';
import { useNavigation } from '@kbn/security-solution-navigation';
import { SuccessToastContent, getSuccessToast } from './success_notification';
import { SuccessToastContent } from './success_notification';
import { getRuleMigrationStatsMock } from '../../__mocks__';
import { TestProviders } from '../../../../common/mock';

Expand All @@ -34,7 +33,7 @@ describe('Success Notification', () => {
it('renders the component with correct text and button', () => {
const { getByText, getByRole } = render(
<TestProviders>
<SuccessToastContent migration={getRuleMigrationStatsMock()} />
<SuccessToastContent migration={getRuleMigrationStatsMock()} dismissHandler={jest.fn()} />
</TestProviders>
);

Expand All @@ -52,7 +51,7 @@ describe('Success Notification', () => {
it('calls navigateTo when the button is clicked', () => {
const { getByRole } = render(
<TestProviders>
<SuccessToastContent migration={getRuleMigrationStatsMock()} />
<SuccessToastContent migration={getRuleMigrationStatsMock()} dismissHandler={jest.fn()} />
</TestProviders>
);

Expand All @@ -65,19 +64,4 @@ describe('Success Notification', () => {
});
});
});

describe('getSuccessToast', () => {
it('returns a toast object with the correct properties', () => {
const migration = getRuleMigrationStatsMock();
const toast = getSuccessToast(migration, coreMock.createStart());

expect(toast).toEqual({
color: 'success',
iconType: 'check',
text: expect.any(Function),
title: 'Rules translation complete.',
toastLifeTimeMs: 1800000,
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -13,34 +13,45 @@ import {
useNavigation,
NavigationProvider,
} from '@kbn/security-solution-navigation';
import type { ToastInput } from '@kbn/core-notifications-browser';
import { toMountPoint } from '@kbn/react-kibana-mount';
import { FormattedMessage } from '@kbn/i18n-react';
import { EuiButton, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import type { RuleMigrationStats } from '../../types';

export const getSuccessToast = (migration: RuleMigrationStats, core: CoreStart): ToastInput => ({
color: 'success',
iconType: 'check',
toastLifeTimeMs: 1000 * 60 * 30, // 30 minutes
title: i18n.translate('xpack.securitySolution.siemMigrations.rulesService.polling.successTitle', {
defaultMessage: 'Rules translation complete.',
}),
text: toMountPoint(
<NavigationProvider core={core}>
<SuccessToastContent migration={migration} />
</NavigationProvider>,
core
),
});
export const raiseSuccessToast = (migration: RuleMigrationStats, core: CoreStart) => {
const toast = core.notifications.toasts.addSuccess({
color: 'success',
iconType: 'check',
toastLifeTimeMs: 1000 * 60 * 30, // 30 minutes
title: i18n.translate(
'xpack.securitySolution.siemMigrations.rulesService.polling.successTitle',
{
defaultMessage: 'Rules translation complete.',
}
),
text: toMountPoint(
<NavigationProvider core={core}>
<SuccessToastContent
migration={migration}
dismissHandler={() => core.notifications.toasts.remove(toast)}
/>
</NavigationProvider>,
core
),
});
};

export const SuccessToastContent: React.FC<{ migration: RuleMigrationStats }> = ({ migration }) => {
export const SuccessToastContent: React.FC<{
migration: RuleMigrationStats;
dismissHandler: () => void;
}> = ({ migration, dismissHandler }) => {
const navigation = { deepLinkId: SecurityPageName.siemMigrationsRules, path: migration.id };

const { navigateTo, getAppUrl } = useNavigation();
const onClick: React.MouseEventHandler = (ev) => {
ev.preventDefault();
navigateTo(navigation);
dismissHandler();
};
const url = getAppUrl(navigation);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import { SiemRulesMigrationsService } from './rule_migrations_service';
import type { CreateRuleMigrationRulesRequestBody } from '../../../../common/siem_migrations/model/api/rules/rule_migration.gen';
import { TASK_STATS_POLLING_SLEEP_SECONDS } from '../../common/constants';
import { getMissingCapabilitiesChecker } from '../../common/service';
import { raiseSuccessToast } from './notification/success_notification';

// --- Mocks for external modules ---

Expand Down Expand Up @@ -67,7 +68,7 @@ jest.mock('../../../common/hooks/use_license', () => ({
}));

jest.mock('./notification/success_notification', () => ({
getSuccessToast: jest.fn().mockReturnValue({ title: 'Success' }),
raiseSuccessToast: jest.fn(),
}));

jest.mock('../../common/service/notifications/no_connector_notification', () => ({
Expand Down Expand Up @@ -369,7 +370,7 @@ describe('SiemRulesMigrationsService', () => {
expect(getStatsMock).toHaveBeenCalledTimes(2);

// Expect that a success toast was added when the migration finished.
expect(mockNotifications.toasts.addSuccess).toHaveBeenCalled();
expect(raiseSuccessToast).toHaveBeenCalled();

// Restore real timers.
jest.useRealTimers();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import {
getNoConnectorToast,
} from '../../common/service';
import type { GetMigrationStatsParams, GetMigrationsStatsAllParams } from '../../common/types';
import { getSuccessToast } from './notification/success_notification';
import { raiseSuccessToast } from './notification/success_notification';
import { START_STOP_POLLING_SLEEP_SECONDS } from '../../common/constants';

const CREATE_MIGRATION_BODY_BATCH_SIZE = 50;
Expand Down Expand Up @@ -238,6 +238,6 @@ export class SiemRulesMigrationsService extends SiemMigrationsServiceBase<RuleMi
}

protected sendFinishedMigrationNotification(taskStats: RuleMigrationStats) {
this.core.notifications.toasts.addSuccess(getSuccessToast(taskStats, this.core));
raiseSuccessToast(taskStats, this.core);
}
}