[RAM] Move maintenance window callout to @kbn/alerts-ui-shared package (#160678)

## Summary

Moves the Security Solution's `MaintenanceWindowCallout` into a shared
KBN package to make it more accessible by other plugins.

### Checklist

- [x] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Zacqary Adam Xeper 2023-07-06 14:34:55 -05:00 committed by GitHub
parent bcb1649f29
commit 0dc73122a5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 289 additions and 204 deletions

View file

@ -8,3 +8,4 @@
export { AlertLifecycleStatusBadge } from './src/alert_lifecycle_status_badge';
export type { AlertLifecycleStatusBadgeProps } from './src/alert_lifecycle_status_badge';
export { MaintenanceWindowCallout } from './src/maintenance_window_callout';

View file

@ -0,0 +1,20 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { KibanaServices } from './types';
export const fetchActiveMaintenanceWindows = async (
http: KibanaServices['http'],
signal?: AbortSignal
) =>
http.fetch(INTERNAL_ALERTING_API_GET_ACTIVE_MAINTENANCE_WINDOWS_PATH, {
method: 'GET',
signal,
});
const INTERNAL_ALERTING_API_GET_ACTIVE_MAINTENANCE_WINDOWS_PATH = `/internal/alerting/rules/maintenance_window/_active`;

View file

@ -1,33 +1,36 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import React from 'react';
import { render, waitFor, cleanup } from '@testing-library/react';
import { I18nProvider } from '@kbn/i18n-react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { render, waitFor, cleanup } from '@testing-library/react';
import {
MaintenanceWindowStatus,
MAINTENANCE_WINDOW_FEATURE_ID,
} from '@kbn/alerting-plugin/common';
import type { MaintenanceWindow } from '@kbn/alerting-plugin/common';
import type { AsApiContract } from '@kbn/alerting-plugin/server/routes/lib';
import { useKibana } from '../../../../common/lib/kibana';
import { useAppToasts } from '../../../../common/hooks/use_app_toasts';
import { useAppToastsMock } from '../../../../common/hooks/use_app_toasts.mock';
import { MaintenanceWindowCallout } from './maintenance_window_callout';
import { TestProviders } from '../../../../common/mock';
import { MaintenanceWindowCallout } from '.';
import { fetchActiveMaintenanceWindows } from './api';
jest.mock('../../../../common/hooks/use_app_toasts');
jest.mock('./api', () => ({
fetchActiveMaintenanceWindows: jest.fn(() => Promise.resolve([])),
}));
jest.mock('../../../../common/lib/kibana');
const TestProviders: React.FC<{}> = ({ children }) => {
const queryClient = new QueryClient();
return (
<I18nProvider>
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
</I18nProvider>
);
};
const RUNNING_MAINTENANCE_WINDOW_1: Partial<MaintenanceWindow> = {
title: 'Running maintenance window 1',
@ -72,29 +75,37 @@ const UPCOMING_MAINTENANCE_WINDOW: Partial<MaintenanceWindow> = {
],
};
const useKibanaMock = useKibana as jest.Mock;
const fetchActiveMaintenanceWindowsMock = fetchActiveMaintenanceWindows as jest.Mock;
describe('MaintenanceWindowCallout', () => {
let appToastsMock: jest.Mocked<ReturnType<typeof useAppToastsMock.create>>;
const kibanaServicesMock = {
application: {
capabilities: {
[MAINTENANCE_WINDOW_FEATURE_ID]: {
save: true,
show: true,
},
},
},
notifications: {
toasts: {
addError: jest.fn(),
add: jest.fn(),
remove: jest.fn(),
get$: jest.fn(),
addInfo: jest.fn(),
addWarning: jest.fn(),
addDanger: jest.fn(),
addSuccess: jest.fn(),
},
},
http: {
fetch: jest.fn(),
},
};
describe('MaintenanceWindowCallout', () => {
beforeEach(() => {
jest.resetAllMocks();
appToastsMock = useAppToastsMock.create();
(useAppToasts as jest.Mock).mockReturnValue(appToastsMock);
useKibanaMock.mockReturnValue({
services: {
application: {
capabilities: {
[MAINTENANCE_WINDOW_FEATURE_ID]: {
save: true,
show: true,
},
},
},
},
});
});
afterEach(() => {
@ -105,7 +116,10 @@ describe('MaintenanceWindowCallout', () => {
it('should be visible if currently there is at least one "running" maintenance window', async () => {
fetchActiveMaintenanceWindowsMock.mockResolvedValue([RUNNING_MAINTENANCE_WINDOW_1]);
const { findAllByText } = render(<MaintenanceWindowCallout />, { wrapper: TestProviders });
const { findAllByText } = render(
<MaintenanceWindowCallout kibanaServices={kibanaServicesMock} />,
{ wrapper: TestProviders }
);
expect(await findAllByText('Maintenance window is running')).toHaveLength(1);
expect(fetchActiveMaintenanceWindowsMock).toHaveBeenCalledTimes(1);
@ -117,7 +131,10 @@ describe('MaintenanceWindowCallout', () => {
RUNNING_MAINTENANCE_WINDOW_2,
]);
const { findAllByText } = render(<MaintenanceWindowCallout />, { wrapper: TestProviders });
const { findAllByText } = render(
<MaintenanceWindowCallout kibanaServices={kibanaServicesMock} />,
{ wrapper: TestProviders }
);
expect(await findAllByText('Maintenance window is running')).toHaveLength(1);
expect(fetchActiveMaintenanceWindowsMock).toHaveBeenCalledTimes(1);
@ -126,8 +143,12 @@ describe('MaintenanceWindowCallout', () => {
it('should be visible if currently there is a recurring "running" maintenance window', async () => {
fetchActiveMaintenanceWindowsMock.mockResolvedValue([RECURRING_RUNNING_MAINTENANCE_WINDOW]);
const { findByText } = render(<MaintenanceWindowCallout />, { wrapper: TestProviders });
const { findByText } = render(
<MaintenanceWindowCallout kibanaServices={kibanaServicesMock} />,
{ wrapper: TestProviders }
);
// @ts-expect-error Jest types are incomplete in packages
expect(await findByText('Maintenance window is running')).toBeInTheDocument();
expect(fetchActiveMaintenanceWindowsMock).toHaveBeenCalledTimes(1);
});
@ -137,8 +158,10 @@ describe('MaintenanceWindowCallout', () => {
[] // API returns an empty array if there are no active maintenance windows
);
const { container } = render(<MaintenanceWindowCallout />, { wrapper: TestProviders });
const { container } = render(<MaintenanceWindowCallout kibanaServices={kibanaServicesMock} />, {
wrapper: TestProviders,
});
// @ts-expect-error Jest types are incomplete in packages
expect(container).toBeEmptyDOMElement();
expect(fetchActiveMaintenanceWindowsMock).toHaveBeenCalledTimes(1);
});
@ -146,8 +169,10 @@ describe('MaintenanceWindowCallout', () => {
it('should NOT be visible if currently there are only "upcoming" maintenance windows', async () => {
fetchActiveMaintenanceWindowsMock.mockResolvedValue([UPCOMING_MAINTENANCE_WINDOW]);
const { container } = render(<MaintenanceWindowCallout />, { wrapper: TestProviders });
const { container } = render(<MaintenanceWindowCallout kibanaServices={kibanaServicesMock} />, {
wrapper: TestProviders,
});
// @ts-expect-error Jest types are incomplete in packages
expect(container).toBeEmptyDOMElement();
expect(fetchActiveMaintenanceWindowsMock).toHaveBeenCalledTimes(1);
});
@ -179,11 +204,13 @@ describe('MaintenanceWindowCallout', () => {
const mockError = new Error('Network error');
fetchActiveMaintenanceWindowsMock.mockRejectedValue(mockError);
render(<MaintenanceWindowCallout />, { wrapper: createReactQueryWrapper() });
render(<MaintenanceWindowCallout kibanaServices={kibanaServicesMock} />, {
wrapper: createReactQueryWrapper(),
});
await waitFor(() => {
expect(appToastsMock.addError).toHaveBeenCalledTimes(1);
expect(appToastsMock.addError).toHaveBeenCalledWith(mockError, {
expect(kibanaServicesMock.notifications.toasts.addError).toHaveBeenCalledTimes(1);
expect(kibanaServicesMock.notifications.toasts.addError).toHaveBeenCalledWith(mockError, {
title: 'Failed to check if maintenance windows are active',
toastMessage: 'Rule notifications are stopped while the maintenance window is running.',
});
@ -191,42 +218,44 @@ describe('MaintenanceWindowCallout', () => {
});
it('should return null if window maintenance privilege is NONE', async () => {
useKibanaMock.mockReturnValue({
services: {
application: {
capabilities: {
[MAINTENANCE_WINDOW_FEATURE_ID]: {
save: false,
show: false,
},
const servicesMock = {
...kibanaServicesMock,
application: {
capabilities: {
[MAINTENANCE_WINDOW_FEATURE_ID]: {
save: false,
show: false,
},
},
},
});
};
fetchActiveMaintenanceWindowsMock.mockResolvedValue([RUNNING_MAINTENANCE_WINDOW_1]);
const { container } = render(<MaintenanceWindowCallout />, { wrapper: TestProviders });
const { container } = render(<MaintenanceWindowCallout kibanaServices={servicesMock} />, {
wrapper: TestProviders,
});
// @ts-expect-error Jest types are incomplete in packages
expect(container).toBeEmptyDOMElement();
});
it('should work as expected if window maintenance privilege is READ ', async () => {
useKibanaMock.mockReturnValue({
services: {
application: {
capabilities: {
[MAINTENANCE_WINDOW_FEATURE_ID]: {
save: false,
show: true,
},
const servicesMock = {
...kibanaServicesMock,
application: {
capabilities: {
[MAINTENANCE_WINDOW_FEATURE_ID]: {
save: false,
show: true,
},
},
},
});
};
fetchActiveMaintenanceWindowsMock.mockResolvedValue([RUNNING_MAINTENANCE_WINDOW_1]);
const { findByText } = render(<MaintenanceWindowCallout />, { wrapper: TestProviders });
const { findByText } = render(<MaintenanceWindowCallout kibanaServices={servicesMock} />, {
wrapper: TestProviders,
});
// @ts-expect-error Jest types are incomplete in packages
expect(await findByText('Maintenance window is running')).toBeInTheDocument();
});
});

View file

@ -0,0 +1,60 @@
/*
* 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import React from 'react';
import { i18n } from '@kbn/i18n';
import { EuiCallOut } from '@elastic/eui';
import { MaintenanceWindow, MaintenanceWindowStatus, KibanaServices } from './types';
import { useFetchActiveMaintenanceWindows } from './use_fetch_active_maintenance_windows';
const MAINTENANCE_WINDOW_FEATURE_ID = 'maintenanceWindow';
const MAINTENANCE_WINDOW_RUNNING = i18n.translate(
'alertsUIShared.maintenanceWindowCallout.maintenanceWindowActive',
{
defaultMessage: 'Maintenance window is running',
}
);
const MAINTENANCE_WINDOW_RUNNING_DESCRIPTION = i18n.translate(
'alertsUIShared.maintenanceWindowCallout.maintenanceWindowActiveDescription',
{
defaultMessage: 'Rule notifications are stopped while the maintenance window is running.',
}
);
export function MaintenanceWindowCallout({
kibanaServices,
}: {
kibanaServices: KibanaServices;
}): JSX.Element | null {
const {
application: { capabilities },
} = kibanaServices;
const isMaintenanceWindowDisabled =
!capabilities[MAINTENANCE_WINDOW_FEATURE_ID].show &&
!capabilities[MAINTENANCE_WINDOW_FEATURE_ID].save;
const { data } = useFetchActiveMaintenanceWindows(kibanaServices, {
enabled: !isMaintenanceWindowDisabled,
});
if (isMaintenanceWindowDisabled) {
return null;
}
const activeMaintenanceWindows = (data as MaintenanceWindow[]) || [];
if (activeMaintenanceWindows.some(({ status }) => status === MaintenanceWindowStatus.Running)) {
return (
<EuiCallOut title={MAINTENANCE_WINDOW_RUNNING} color="warning" iconType="iInCircle">
{MAINTENANCE_WINDOW_RUNNING_DESCRIPTION}
</EuiCallOut>
);
}
return null;
}

View file

@ -0,0 +1,65 @@
/*
* 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { WeekdayStr, Options } from '@kbn/rrule';
import { CoreStart } from '@kbn/core/public';
export enum MaintenanceWindowStatus {
Running = 'running',
Upcoming = 'upcoming',
Finished = 'finished',
Archived = 'archived',
}
export interface MaintenanceWindowModificationMetadata {
createdBy: string | null;
updatedBy: string | null;
createdAt: string;
updatedAt: string;
}
export interface DateRange {
gte: string;
lte: string;
}
export interface MaintenanceWindowSOProperties {
title: string;
enabled: boolean;
duration: number;
expirationDate: string;
events: DateRange[];
rRule: RRuleParams;
}
export type MaintenanceWindowSOAttributes = MaintenanceWindowSOProperties &
MaintenanceWindowModificationMetadata;
export type MaintenanceWindow = MaintenanceWindowSOAttributes & {
status: MaintenanceWindowStatus;
eventStartTime: string | null;
eventEndTime: string | null;
id: string;
};
export type RRuleParams = Partial<RRuleRecord> & Pick<RRuleRecord, 'dtstart' | 'tzid'>;
// An iCal RRULE to define a recurrence schedule, see https://github.com/jakubroztocil/rrule for the spec
export type RRuleRecord = Omit<Options, 'dtstart' | 'byweekday' | 'wkst' | 'until'> & {
dtstart: string;
byweekday?: Array<WeekdayStr | string | number>;
wkst?: WeekdayStr;
until?: string;
};
export interface KibanaServices {
application: {
capabilities: Record<string, any>;
};
http: Pick<CoreStart['http'], 'fetch'>;
notifications: Pick<CoreStart['notifications'], 'toasts'>;
}

View file

@ -0,0 +1,42 @@
/*
* 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { UseQueryOptions } from '@tanstack/react-query';
import { useQuery } from '@tanstack/react-query';
import { i18n } from '@kbn/i18n';
import { KibanaServices } from './types';
import { fetchActiveMaintenanceWindows } from './api';
export const useFetchActiveMaintenanceWindows = (
{ http, notifications: { toasts } }: KibanaServices,
{ enabled }: Pick<UseQueryOptions, 'enabled'>
) => {
return useQuery(
['GET', INTERNAL_ALERTING_API_GET_ACTIVE_MAINTENANCE_WINDOWS_PATH],
({ signal }) => fetchActiveMaintenanceWindows(http, signal),
{
enabled,
refetchInterval: 60000,
onError: (error: Error) => {
toasts.addError(error, { title: FETCH_ERROR, toastMessage: FETCH_ERROR_DESCRIPTION });
},
}
);
};
const INTERNAL_ALERTING_API_GET_ACTIVE_MAINTENANCE_WINDOWS_PATH = `/internal/alerting/rules/maintenance_window/_active`;
const FETCH_ERROR = i18n.translate('alertsUIShared.maintenanceWindowCallout.fetchError', {
defaultMessage: 'Failed to check if maintenance windows are active',
});
const FETCH_ERROR_DESCRIPTION = i18n.translate(
'alertsUIShared.maintenanceWindowCallout.fetchErrorDescription',
{
defaultMessage: 'Rule notifications are stopped while the maintenance window is running.',
}
);

View file

@ -17,6 +17,10 @@
],
"kbn_references": [
"@kbn/i18n",
"@kbn/rule-data-utils"
"@kbn/rule-data-utils",
"@kbn/core",
"@kbn/i18n-react",
"@kbn/alerting-plugin",
"@kbn/rrule"
]
}

View file

@ -1,18 +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 { MaintenanceWindow } from '@kbn/alerting-plugin/common/maintenance_window';
import { INTERNAL_ALERTING_API_GET_ACTIVE_MAINTENANCE_WINDOWS_PATH } from '@kbn/alerting-plugin/common';
import { KibanaServices } from '../../../../common/lib/kibana';
export const fetchActiveMaintenanceWindows = async (
signal?: AbortSignal
): Promise<MaintenanceWindow[]> =>
KibanaServices.get().http.fetch(INTERNAL_ALERTING_API_GET_ACTIVE_MAINTENANCE_WINDOWS_PATH, {
method: 'GET',
signal,
});

View file

@ -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 React from 'react';
import { EuiCallOut } from '@elastic/eui';
import {
MaintenanceWindowStatus,
MAINTENANCE_WINDOW_FEATURE_ID,
} from '@kbn/alerting-plugin/common';
import { useFetchActiveMaintenanceWindows } from './use_fetch_active_maintenance_windows';
import * as i18n from './translations';
import { useKibana } from '../../../../common/lib/kibana';
export function MaintenanceWindowCallout(): JSX.Element | null {
const {
application: { capabilities },
} = useKibana().services;
const isMaintenanceWindowDisabled =
!capabilities[MAINTENANCE_WINDOW_FEATURE_ID].show &&
!capabilities[MAINTENANCE_WINDOW_FEATURE_ID].save;
const { data } = useFetchActiveMaintenanceWindows({ enabled: !isMaintenanceWindowDisabled });
if (isMaintenanceWindowDisabled) {
return null;
}
const activeMaintenanceWindows = data || [];
if (activeMaintenanceWindows.some(({ status }) => status === MaintenanceWindowStatus.Running)) {
return (
<EuiCallOut title={i18n.MAINTENANCE_WINDOW_RUNNING} color="warning" iconType="iInCircle">
{i18n.MAINTENANCE_WINDOW_RUNNING_DESCRIPTION}
</EuiCallOut>
);
}
return null;
}

View file

@ -1,36 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
export const MAINTENANCE_WINDOW_RUNNING = i18n.translate(
'xpack.securitySolution.detectionEngine.ruleManagementUi.maintenanceWindowCallout.maintenanceWindowActive',
{
defaultMessage: 'Maintenance window is running',
}
);
export const MAINTENANCE_WINDOW_RUNNING_DESCRIPTION = i18n.translate(
'xpack.securitySolution.detectionEngine.ruleManagementUi.maintenanceWindowCallout.maintenanceWindowActiveDescription',
{
defaultMessage: 'Rule notifications are stopped while the maintenance window is running.',
}
);
export const FETCH_ERROR = i18n.translate(
'xpack.securitySolution.detectionEngine.ruleManagementUi.maintenanceWindowCallout.fetchError',
{
defaultMessage: 'Failed to check if maintenance windows are active',
}
);
export const FETCH_ERROR_DESCRIPTION = i18n.translate(
'xpack.securitySolution.detectionEngine.ruleManagementUi.maintenanceWindowCallout.fetchErrorDescription',
{
defaultMessage: 'Rule notifications are stopped while the maintenance window is running.',
}
);

View file

@ -1,29 +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 } from '@tanstack/react-query';
import { INTERNAL_ALERTING_API_GET_ACTIVE_MAINTENANCE_WINDOWS_PATH } from '@kbn/alerting-plugin/common';
import { useAppToasts } from '../../../../common/hooks/use_app_toasts';
import * as i18n from './translations';
import { fetchActiveMaintenanceWindows } from './api';
export const useFetchActiveMaintenanceWindows = ({ enabled }: Pick<UseQueryOptions, 'enabled'>) => {
const { addError } = useAppToasts();
return useQuery(
['GET', INTERNAL_ALERTING_API_GET_ACTIVE_MAINTENANCE_WINDOWS_PATH],
({ signal }) => fetchActiveMaintenanceWindows(signal),
{
enabled,
refetchInterval: 60000,
onError: (error) => {
addError(error, { title: i18n.FETCH_ERROR, toastMessage: i18n.FETCH_ERROR_DESCRIPTION });
},
}
);
};

View file

@ -6,6 +6,7 @@
*/
import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiToolTip } from '@elastic/eui';
import { MaintenanceWindowCallout } from '@kbn/alerts-ui-shared';
import React, { useCallback } from 'react';
import { APP_UI_ID } from '../../../../../common/constants';
import { SecurityPageName } from '../../../../app/types';
@ -29,7 +30,6 @@ import * as i18n from '../../../../detections/pages/detection_engine/rules/trans
import { useInvalidateFetchRuleManagementFiltersQuery } from '../../../rule_management/api/hooks/use_fetch_rule_management_filters_query';
import { useInvalidateFindRulesQuery } from '../../../rule_management/api/hooks/use_find_rules_query';
import { importRules } from '../../../rule_management/logic';
import { MaintenanceWindowCallout } from '../../components/maintenance_window_callout/maintenance_window_callout';
import { AllRules } from '../../components/rules_table';
import { RulesPageTourComponent } from '../../components/rules_table/alternative_tour/tour';
import { RulesTableContextProvider } from '../../components/rules_table/rules_table/rules_table_context';
@ -38,7 +38,8 @@ import { SuperHeader } from './super_header';
const RulesPageComponent: React.FC = () => {
const [isImportModalVisible, showImportModal, hideImportModal] = useBoolState();
const [isValueListFlyoutVisible, showValueListFlyout, hideValueListFlyout] = useBoolState();
const { navigateToApp } = useKibana().services.application;
const kibanaServices = useKibana().services;
const { navigateToApp } = kibanaServices.application;
const invalidateFindRulesQuery = useInvalidateFindRulesQuery();
const invalidateFetchRuleManagementFilters = useInvalidateFetchRuleManagementFiltersQuery();
const invalidateRules = useCallback(() => {
@ -145,7 +146,7 @@ const RulesPageComponent: React.FC = () => {
</EuiFlexItem>
</EuiFlexGroup>
</SuperHeader>
<MaintenanceWindowCallout />
<MaintenanceWindowCallout kibanaServices={kibanaServices} />
<AllRules data-test-subj="all-rules" />
</SecuritySolutionPageWrapper>
</RulesTableContextProvider>

View file

@ -161,6 +161,7 @@
"@kbn/discover-plugin",
"@kbn/field-formats-plugin",
"@kbn/dev-proc-runner",
"@kbn/cloud-chat-plugin"
"@kbn/cloud-chat-plugin",
"@kbn/alerts-ui-shared"
]
}

View file

@ -31031,10 +31031,6 @@
"xpack.securitySolution.detectionEngine.ruleDetails.ruleExecutionLog.timestampColumnTooltip": "Date et heures auxquelles l'exécution de la règle a été lancée.",
"xpack.securitySolution.detectionEngine.ruleDetails.ruleExecutionResultsTab": "Résultats d'exécution",
"xpack.securitySolution.detectionEngine.ruleDetails.unknownDescription": "Inconnu",
"xpack.securitySolution.detectionEngine.ruleManagementUi.maintenanceWindowCallout.fetchError": "Impossible de vérifier si une fenêtre de maintenance est en cours d'exécution",
"xpack.securitySolution.detectionEngine.ruleManagementUi.maintenanceWindowCallout.fetchErrorDescription": "Les actions de notification ne s'exécutent pas lorsqu'une fenêtre de maintenance est en cours.",
"xpack.securitySolution.detectionEngine.ruleManagementUi.maintenanceWindowCallout.maintenanceWindowActive": "Une fenêtre de maintenance est en cours d'exécution",
"xpack.securitySolution.detectionEngine.ruleManagementUi.maintenanceWindowCallout.maintenanceWindowActiveDescription": "Les actions de notification ne s'exécutent pas lorsqu'une fenêtre de maintenance est en cours.",
"xpack.securitySolution.detectionEngine.ruleManagementUi.rulesTable.mlJobsWarning.popover.buttonLabel": "Visitez la page des détails de règle pour effectuer votre investigation",
"xpack.securitySolution.detectionEngine.ruleManagementUi.rulesTable.mlJobsWarning.popover.description": "Les tâches suivantes ne sont pas en cours d'exécution et la règle pourra donc générer des résultats incorrects :",
"xpack.securitySolution.detectionEngine.ruleMonitoring.eventTypeFilter.filterTitle": "Type d'événement",

View file

@ -31016,10 +31016,6 @@
"xpack.securitySolution.detectionEngine.ruleDetails.ruleExecutionLog.timestampColumnTooltip": "日時ルール実行が開始されました。",
"xpack.securitySolution.detectionEngine.ruleDetails.ruleExecutionResultsTab": "実行結果",
"xpack.securitySolution.detectionEngine.ruleDetails.unknownDescription": "不明",
"xpack.securitySolution.detectionEngine.ruleManagementUi.maintenanceWindowCallout.fetchError": "現在保守時間枠が実行中かどうかを確認できませんでした",
"xpack.securitySolution.detectionEngine.ruleManagementUi.maintenanceWindowCallout.fetchErrorDescription": "保守時間枠が実行中の場合は通知アクションが実行されません。",
"xpack.securitySolution.detectionEngine.ruleManagementUi.maintenanceWindowCallout.maintenanceWindowActive": "現在保守時間枠が実行中です",
"xpack.securitySolution.detectionEngine.ruleManagementUi.maintenanceWindowCallout.maintenanceWindowActiveDescription": "保守時間枠が実行中の場合は通知アクションが実行されません。",
"xpack.securitySolution.detectionEngine.ruleManagementUi.rulesTable.mlJobsWarning.popover.buttonLabel": "ルール詳細ページを表示して調査してください",
"xpack.securitySolution.detectionEngine.ruleManagementUi.rulesTable.mlJobsWarning.popover.description": "次のジョブが実行されていないため、ルールで正しくない結果が生成されている可能性があります。",
"xpack.securitySolution.detectionEngine.ruleMonitoring.eventTypeFilter.filterTitle": "イベントタイプ",

View file

@ -31012,10 +31012,6 @@
"xpack.securitySolution.detectionEngine.ruleDetails.ruleExecutionLog.timestampColumnTooltip": "已发起日期时间规则执行。",
"xpack.securitySolution.detectionEngine.ruleDetails.ruleExecutionResultsTab": "执行结果",
"xpack.securitySolution.detectionEngine.ruleDetails.unknownDescription": "未知",
"xpack.securitySolution.detectionEngine.ruleManagementUi.maintenanceWindowCallout.fetchError": "无法检查当前是否运行有任何维护窗口",
"xpack.securitySolution.detectionEngine.ruleManagementUi.maintenanceWindowCallout.fetchErrorDescription": "维护窗口正在运行时,通知操作无法运行。",
"xpack.securitySolution.detectionEngine.ruleManagementUi.maintenanceWindowCallout.maintenanceWindowActive": "维护窗口当前正在运行",
"xpack.securitySolution.detectionEngine.ruleManagementUi.maintenanceWindowCallout.maintenanceWindowActiveDescription": "维护窗口正在运行时,通知操作无法运行。",
"xpack.securitySolution.detectionEngine.ruleManagementUi.rulesTable.mlJobsWarning.popover.buttonLabel": "访问规则详情页面以进行调查",
"xpack.securitySolution.detectionEngine.ruleManagementUi.rulesTable.mlJobsWarning.popover.description": "以下作业未运行,可能导致规则生成错误的结果:",
"xpack.securitySolution.detectionEngine.ruleMonitoring.eventTypeFilter.filterTitle": "事件类型",