-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ResponseOps][Window Maintenance] Add the stop and archive actions to…
… the maintenance window table (#155201) Resolves #154814 ## Summary This pr adds the cancel/archive actions to the Maintenance Windows table, and adds an archive callout to the create form. @lcawl I think I need your help with some of the text in the modals 🙂 **Create Form:** Callout <img width="1370" alt="Screen Shot 2023-04-18 at 9 49 58 PM" src="https://user-images.githubusercontent.com/109488926/232945833-77f01988-e5c4-4d5f-a2f9-b361085964e2.png"> Modal <img width="1335" alt="Screen Shot 2023-04-18 at 9 50 05 PM" src="https://user-images.githubusercontent.com/109488926/232945810-dacb3a26-fa59-4e5e-995c-14b7f0977c10.png"> **Cancel Modal:** <img width="628" alt="Screen Shot 2023-04-18 at 9 52 18 PM" src="https://user-images.githubusercontent.com/109488926/232946092-c4001ccc-d2f9-475a-bc67-3b2ab6fdf31e.png"> **Cancel and Archive Modal:** <img width="621" alt="Screen Shot 2023-04-18 at 9 52 56 PM" src="https://user-images.githubusercontent.com/109488926/232946171-154f8601-d5aa-40f1-824a-bff25b4d3d91.png"> **Archive Modal:** <img width="611" alt="Screen Shot 2023-04-18 at 9 53 25 PM" src="https://user-images.githubusercontent.com/109488926/232946240-ee25bcd0-80d6-403c-9fb3-9aec89d11ebd.png"> **Unarchive Modal:** <img width="620" alt="Screen Shot 2023-04-18 at 9 54 16 PM" src="https://user-images.githubusercontent.com/109488926/232946350-814d0c05-5511-4fad-8ac4-0c5824d94b8e.png"> ### 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 <[email protected]> Co-authored-by: Lisa Cawley <[email protected]>
- Loading branch information
1 parent
da5a4b0
commit dbb8e2e
Showing
22 changed files
with
1,186 additions
and
59 deletions.
There are no files selected for viewing
116 changes: 116 additions & 0 deletions
116
x-pack/plugins/alerting/public/hooks/use_archive_maintenance_window.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
/* | ||
* 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 { act, renderHook } from '@testing-library/react-hooks/dom'; | ||
import { waitFor } from '@testing-library/dom'; | ||
|
||
import { MaintenanceWindow } from '../pages/maintenance_windows/types'; | ||
import { AppMockRenderer, createAppMockRenderer } from '../lib/test_utils'; | ||
import { useArchiveMaintenanceWindow } from './use_archive_maintenance_window'; | ||
|
||
const mockAddDanger = jest.fn(); | ||
const mockAddSuccess = jest.fn(); | ||
|
||
jest.mock('../utils/kibana_react', () => { | ||
const originalModule = jest.requireActual('../utils/kibana_react'); | ||
return { | ||
...originalModule, | ||
useKibana: () => { | ||
const { services } = originalModule.useKibana(); | ||
return { | ||
services: { | ||
...services, | ||
notifications: { toasts: { addSuccess: mockAddSuccess, addDanger: mockAddDanger } }, | ||
}, | ||
}; | ||
}, | ||
}; | ||
}); | ||
jest.mock('../services/maintenance_windows_api/archive', () => ({ | ||
archiveMaintenanceWindow: jest.fn(), | ||
})); | ||
|
||
const { archiveMaintenanceWindow } = jest.requireMock( | ||
'../services/maintenance_windows_api/archive' | ||
); | ||
|
||
const maintenanceWindow: MaintenanceWindow = { | ||
title: 'archive', | ||
duration: 1, | ||
rRule: { | ||
dtstart: '2023-03-23T19:16:21.293Z', | ||
tzid: 'America/New_York', | ||
}, | ||
}; | ||
|
||
let appMockRenderer: AppMockRenderer; | ||
|
||
describe('useArchiveMaintenanceWindow', () => { | ||
beforeEach(() => { | ||
jest.clearAllMocks(); | ||
|
||
appMockRenderer = createAppMockRenderer(); | ||
archiveMaintenanceWindow.mockResolvedValue(maintenanceWindow); | ||
}); | ||
|
||
it('should call onSuccess if api succeeds', async () => { | ||
const { result } = renderHook(() => useArchiveMaintenanceWindow(), { | ||
wrapper: appMockRenderer.AppWrapper, | ||
}); | ||
|
||
await act(async () => { | ||
await result.current.mutate({ maintenanceWindowId: '123', archive: true }); | ||
}); | ||
await waitFor(() => | ||
expect(mockAddSuccess).toBeCalledWith("Archived maintenance window 'archive'") | ||
); | ||
}); | ||
|
||
it('should call onError if api fails', async () => { | ||
archiveMaintenanceWindow.mockRejectedValue(''); | ||
|
||
const { result } = renderHook(() => useArchiveMaintenanceWindow(), { | ||
wrapper: appMockRenderer.AppWrapper, | ||
}); | ||
|
||
await act(async () => { | ||
await result.current.mutate({ maintenanceWindowId: '123', archive: true }); | ||
}); | ||
|
||
await waitFor(() => | ||
expect(mockAddDanger).toBeCalledWith('Failed to archive maintenance window.') | ||
); | ||
}); | ||
|
||
it('should call onSuccess if api succeeds (unarchive)', async () => { | ||
const { result } = renderHook(() => useArchiveMaintenanceWindow(), { | ||
wrapper: appMockRenderer.AppWrapper, | ||
}); | ||
|
||
await act(async () => { | ||
await result.current.mutate({ maintenanceWindowId: '123', archive: false }); | ||
}); | ||
await waitFor(() => | ||
expect(mockAddSuccess).toBeCalledWith("Unarchived maintenance window 'archive'") | ||
); | ||
}); | ||
|
||
it('should call onError if api fails (unarchive)', async () => { | ||
archiveMaintenanceWindow.mockRejectedValue(''); | ||
|
||
const { result } = renderHook(() => useArchiveMaintenanceWindow(), { | ||
wrapper: appMockRenderer.AppWrapper, | ||
}); | ||
|
||
await act(async () => { | ||
await result.current.mutate({ maintenanceWindowId: '123', archive: false }); | ||
}); | ||
|
||
await waitFor(() => | ||
expect(mockAddDanger).toBeCalledWith('Failed to unarchive maintenance window.') | ||
); | ||
}); | ||
}); |
56 changes: 56 additions & 0 deletions
56
x-pack/plugins/alerting/public/hooks/use_archive_maintenance_window.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
/* | ||
* 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'; | ||
import { useMutation } from '@tanstack/react-query'; | ||
|
||
import { useKibana } from '../utils/kibana_react'; | ||
import { archiveMaintenanceWindow } from '../services/maintenance_windows_api/archive'; | ||
|
||
export function useArchiveMaintenanceWindow() { | ||
const { | ||
http, | ||
notifications: { toasts }, | ||
} = useKibana().services; | ||
|
||
const mutationFn = ({ | ||
maintenanceWindowId, | ||
archive, | ||
}: { | ||
maintenanceWindowId: string; | ||
archive: boolean; | ||
}) => { | ||
return archiveMaintenanceWindow({ http, maintenanceWindowId, archive }); | ||
}; | ||
|
||
return useMutation(mutationFn, { | ||
onSuccess: (data, { archive }) => { | ||
const archiveToast = i18n.translate('xpack.alerting.maintenanceWindowsArchiveSuccess', { | ||
defaultMessage: "Archived maintenance window '{title}'", | ||
values: { | ||
title: data.title, | ||
}, | ||
}); | ||
const unarchiveToast = i18n.translate('xpack.alerting.maintenanceWindowsUnarchiveSuccess', { | ||
defaultMessage: "Unarchived maintenance window '{title}'", | ||
values: { | ||
title: data.title, | ||
}, | ||
}); | ||
toasts.addSuccess(archive ? archiveToast : unarchiveToast); | ||
}, | ||
onError: (error, { archive }) => { | ||
const archiveToast = i18n.translate('xpack.alerting.maintenanceWindowsArchiveFailure', { | ||
defaultMessage: 'Failed to archive maintenance window.', | ||
}); | ||
const unarchiveToast = i18n.translate('xpack.alerting.maintenanceWindowsUnarchiveFailure', { | ||
defaultMessage: 'Failed to unarchive maintenance window.', | ||
}); | ||
toasts.addDanger(archive ? archiveToast : unarchiveToast); | ||
}, | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
110 changes: 110 additions & 0 deletions
110
x-pack/plugins/alerting/public/hooks/use_finish_and_archive_maintenance_window.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
/* | ||
* 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 { act, renderHook } from '@testing-library/react-hooks/dom'; | ||
import { waitFor } from '@testing-library/dom'; | ||
|
||
import { MaintenanceWindow } from '../pages/maintenance_windows/types'; | ||
import { AppMockRenderer, createAppMockRenderer } from '../lib/test_utils'; | ||
import { useFinishAndArchiveMaintenanceWindow } from './use_finish_and_archive_maintenance_window'; | ||
|
||
const mockAddDanger = jest.fn(); | ||
const mockAddSuccess = jest.fn(); | ||
|
||
jest.mock('../utils/kibana_react', () => { | ||
const originalModule = jest.requireActual('../utils/kibana_react'); | ||
return { | ||
...originalModule, | ||
useKibana: () => { | ||
const { services } = originalModule.useKibana(); | ||
return { | ||
services: { | ||
...services, | ||
notifications: { toasts: { addSuccess: mockAddSuccess, addDanger: mockAddDanger } }, | ||
}, | ||
}; | ||
}, | ||
}; | ||
}); | ||
jest.mock('../services/maintenance_windows_api/finish', () => ({ | ||
finishMaintenanceWindow: jest.fn(), | ||
})); | ||
jest.mock('../services/maintenance_windows_api/archive', () => ({ | ||
archiveMaintenanceWindow: jest.fn(), | ||
})); | ||
|
||
const { finishMaintenanceWindow } = jest.requireMock('../services/maintenance_windows_api/finish'); | ||
const { archiveMaintenanceWindow } = jest.requireMock( | ||
'../services/maintenance_windows_api/archive' | ||
); | ||
|
||
const maintenanceWindow: MaintenanceWindow = { | ||
title: 'test', | ||
duration: 1, | ||
rRule: { | ||
dtstart: '2023-03-23T19:16:21.293Z', | ||
tzid: 'America/New_York', | ||
}, | ||
}; | ||
|
||
let appMockRenderer: AppMockRenderer; | ||
|
||
describe('useFinishAndArchiveMaintenanceWindow', () => { | ||
beforeEach(() => { | ||
jest.clearAllMocks(); | ||
|
||
appMockRenderer = createAppMockRenderer(); | ||
finishMaintenanceWindow.mockResolvedValue(maintenanceWindow); | ||
archiveMaintenanceWindow.mockResolvedValue(maintenanceWindow); | ||
}); | ||
|
||
it('should call onSuccess if api succeeds', async () => { | ||
const { result } = renderHook(() => useFinishAndArchiveMaintenanceWindow(), { | ||
wrapper: appMockRenderer.AppWrapper, | ||
}); | ||
|
||
await act(async () => { | ||
await result.current.mutate('123'); | ||
}); | ||
await waitFor(() => | ||
expect(mockAddSuccess).toBeCalledWith( | ||
"Cancelled and archived running maintenance window 'test'" | ||
) | ||
); | ||
}); | ||
|
||
it('should call onError if finish api fails', async () => { | ||
finishMaintenanceWindow.mockRejectedValue(''); | ||
|
||
const { result } = renderHook(() => useFinishAndArchiveMaintenanceWindow(), { | ||
wrapper: appMockRenderer.AppWrapper, | ||
}); | ||
|
||
await act(async () => { | ||
await result.current.mutate('123'); | ||
}); | ||
|
||
await waitFor(() => | ||
expect(mockAddDanger).toBeCalledWith('Failed to cancel and archive maintenance window.') | ||
); | ||
}); | ||
|
||
it('should call onError if archive api fails', async () => { | ||
archiveMaintenanceWindow.mockRejectedValue(''); | ||
|
||
const { result } = renderHook(() => useFinishAndArchiveMaintenanceWindow(), { | ||
wrapper: appMockRenderer.AppWrapper, | ||
}); | ||
|
||
await act(async () => { | ||
await result.current.mutate('123'); | ||
}); | ||
|
||
await waitFor(() => | ||
expect(mockAddDanger).toBeCalledWith('Failed to cancel and archive maintenance window.') | ||
); | ||
}); | ||
}); |
45 changes: 45 additions & 0 deletions
45
x-pack/plugins/alerting/public/hooks/use_finish_and_archive_maintenance_window.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
/* | ||
* 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'; | ||
import { useMutation } from '@tanstack/react-query'; | ||
|
||
import { useKibana } from '../utils/kibana_react'; | ||
import { finishMaintenanceWindow } from '../services/maintenance_windows_api/finish'; | ||
import { archiveMaintenanceWindow } from '../services/maintenance_windows_api/archive'; | ||
|
||
export function useFinishAndArchiveMaintenanceWindow() { | ||
const { | ||
http, | ||
notifications: { toasts }, | ||
} = useKibana().services; | ||
|
||
const mutationFn = async (maintenanceWindowId: string) => { | ||
await finishMaintenanceWindow({ http, maintenanceWindowId }); | ||
return archiveMaintenanceWindow({ http, maintenanceWindowId, archive: true }); | ||
}; | ||
|
||
return useMutation(mutationFn, { | ||
onSuccess: (data) => { | ||
toasts.addSuccess( | ||
i18n.translate('xpack.alerting.maintenanceWindowsFinishedAndArchiveSuccess', { | ||
defaultMessage: "Cancelled and archived running maintenance window '{title}'", | ||
values: { | ||
title: data.title, | ||
}, | ||
}) | ||
); | ||
}, | ||
onError: () => { | ||
toasts.addDanger( | ||
i18n.translate('xpack.alerting.maintenanceWindowsFinishedAndArchiveFailure', { | ||
defaultMessage: 'Failed to cancel and archive maintenance window.', | ||
}) | ||
); | ||
}, | ||
}); | ||
} |
Oops, something went wrong.