mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[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:
parent
bcb1649f29
commit
0dc73122a5
16 changed files with 289 additions and 204 deletions
|
@ -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';
|
||||
|
|
|
@ -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`;
|
|
@ -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();
|
||||
});
|
||||
});
|
|
@ -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;
|
||||
}
|
|
@ -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'>;
|
||||
}
|
|
@ -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.',
|
||||
}
|
||||
);
|
|
@ -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"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
});
|
|
@ -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;
|
||||
}
|
|
@ -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.',
|
||||
}
|
||||
);
|
|
@ -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 });
|
||||
},
|
||||
}
|
||||
);
|
||||
};
|
|
@ -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>
|
||||
|
|
|
@ -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"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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": "イベントタイプ",
|
||||
|
|
|
@ -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": "事件类型",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue