From 0ee7970d485548e8f3fcfcb537847a38be854864 Mon Sep 17 00:00:00 2001 From: Bohdan Tsymbala Date: Wed, 29 Jul 2020 15:08:49 +0200 Subject: [PATCH 1/3] Added close button to toast notifications by migrating to different API that is more widely used in Kibana and Security solution in particular. --- .../endpoint_hosts/view/details/index.tsx | 11 ++++----- .../pages/policy/view/policy_details.test.tsx | 12 +++++----- .../pages/policy/view/policy_details.tsx | 15 ++++++------ .../pages/policy/view/policy_list.tsx | 23 +++++++++---------- 4 files changed, 29 insertions(+), 32 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/index.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/index.tsx index 71b3885308558..36fdd494e5581 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/index.tsx @@ -18,7 +18,7 @@ import { import { useHistory } from 'react-router-dom'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; -import { useKibana } from '../../../../../../../../../src/plugins/kibana_react/public'; +import { useToasts } from '../../../../../common/lib/kibana'; import { useHostSelector } from '../hooks'; import { urlFromQueryParams } from '../url_from_query_params'; import { @@ -44,7 +44,7 @@ import { useFormatUrl } from '../../../../../common/components/link_to'; export const HostDetailsFlyout = memo(() => { const history = useHistory(); - const { notifications } = useKibana(); + const toasts = useToasts(); const queryParams = useHostSelector(uiQueryParams); const { selected_host: selectedHost, ...queryParamsWithoutSelectedHost } = queryParams; const details = useHostSelector(detailsData); @@ -58,23 +58,22 @@ export const HostDetailsFlyout = memo(() => { useEffect(() => { if (error !== undefined) { - notifications.toasts.danger({ + toasts.addDanger({ title: ( ), - body: ( + text: ( ), - toastLifeTimeMs: 10000, }); } - }, [error, notifications.toasts]); + }, [error, toasts]); return ( diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.test.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.test.tsx index 8612b15f89857..4f45e2a9d4056 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.test.tsx @@ -255,11 +255,11 @@ describe('Policy Details', () => { policyView.update(); // Toast notification should be shown - const toastAddMock = coreStart.notifications.toasts.add.mock; + const toastAddMock = coreStart.notifications.toasts.addSuccess.mock; expect(toastAddMock.calls).toHaveLength(1); expect(toastAddMock.calls[0][0]).toMatchObject({ - color: 'success', - iconType: 'check', + title: 'Success!', + text: expect.any(Object), }); }); it('should show an error notification toast if update fails', async () => { @@ -270,11 +270,11 @@ describe('Policy Details', () => { policyView.update(); // Toast notification should be shown - const toastAddMock = coreStart.notifications.toasts.add.mock; + const toastAddMock = coreStart.notifications.toasts.addDanger.mock; expect(toastAddMock.calls).toHaveLength(1); expect(toastAddMock.calls[0][0]).toMatchObject({ - color: 'danger', - iconType: 'alert', + title: 'Failed!', + text: expect.any(Object), }); }); }); diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.tsx index 9576e1aedcaf1..5d3d11ec4880c 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.tsx @@ -36,6 +36,7 @@ import { AgentsSummary } from './agents_summary'; import { VerticalDivider } from './vertical_divider'; import { WindowsEvents, MacEvents, LinuxEvents } from './policy_forms/events'; import { MalwareProtections } from './policy_forms/protections/malware'; +import { useToasts } from '../../../../common/lib/kibana'; import { AppAction } from '../../../../common/store/actions'; import { useNavigateByRouterEventHandler } from '../../../../common/hooks/endpoint/use_navigate_by_router_event_handler'; import { PageViewHeaderTitle } from '../../../../common/components/endpoint/page_view'; @@ -51,11 +52,11 @@ import { PolicyDetailsRouteState } from '../../../../../common/endpoint/types'; export const PolicyDetails = React.memo(() => { const dispatch = useDispatch<(action: AppAction) => void>(); const { - notifications, services: { application: { navigateToApp }, }, } = useKibana(); + const toasts = useToasts(); const { formatUrl, search } = useFormatUrl(SecurityPageName.administration); const { state: locationRouteState } = useLocation(); @@ -75,15 +76,14 @@ export const PolicyDetails = React.memo(() => { useEffect(() => { if (policyUpdateStatus) { if (policyUpdateStatus.success) { - notifications.toasts.success({ - toastLifeTimeMs: 10000, + toasts.addSuccess({ title: i18n.translate( 'xpack.securitySolution.endpoint.policy.details.updateSuccessTitle', { defaultMessage: 'Success!', } ), - body: ( + text: ( { navigateToApp(...routeState.onSaveNavigateTo); } } else { - notifications.toasts.danger({ - toastLifeTimeMs: 10000, + toasts.addDanger({ title: i18n.translate('xpack.securitySolution.endpoint.policy.details.updateErrorTitle', { defaultMessage: 'Failed!', }), - body: <>{policyUpdateStatus.error!.message}, + text: <>{policyUpdateStatus.error!.message}, }); } } - }, [navigateToApp, notifications.toasts, policyName, policyUpdateStatus, routeState]); + }, [navigateToApp, toasts, policyName, policyUpdateStatus, routeState]); const handleBackToListOnClick = useNavigateByRouterEventHandler(getPoliciesPath()); diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_list.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_list.tsx index 20b6534f7664e..bfbb9bcaee33f 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_list.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_list.tsx @@ -36,6 +36,7 @@ import { CreateStructuredSelector } from '../../../../common/store'; import * as selectors from '../store/policy_list/selectors'; import { usePolicyListSelector } from './policy_hooks'; import { PolicyListAction } from '../store/policy_list'; +import { useToasts } from '../../../../common/lib/kibana'; import { useKibana } from '../../../../../../../../src/plugins/kibana_react/public'; import { Immutable, PolicyData } from '../../../../../common/endpoint/types'; import { useNavigateByRouterEventHandler } from '../../../../common/hooks/endpoint/use_navigate_by_router_event_handler'; @@ -124,7 +125,8 @@ const PolicyLink: React.FC<{ name: string; route: string; href: string }> = ({ const selector = (createStructuredSelector as CreateStructuredSelector)(selectors); export const PolicyList = React.memo(() => { - const { services, notifications } = useKibana(); + const { services } = useKibana(); + const toasts = useToasts(); const history = useHistory(); const location = useLocation(); const { formatUrl, search } = useFormatUrl(SecurityPageName.administration); @@ -167,13 +169,12 @@ export const PolicyList = React.memo(() => { useEffect(() => { if (apiError) { - notifications.toasts.danger({ + toasts.addDanger({ title: apiError.error, - body: apiError.message, - toastLifeTimeMs: 10000, + text: apiError.message, }); } - }, [apiError, dispatch, notifications.toasts]); + }, [apiError, dispatch, toasts]); // Handle showing update statuses useEffect(() => { @@ -181,12 +182,11 @@ export const PolicyList = React.memo(() => { if (deleteStatus === true) { setPolicyIdToDelete(''); setShowDelete(false); - notifications.toasts.success({ - toastLifeTimeMs: 10000, + toasts.addSuccess({ title: i18n.translate('xpack.securitySolution.endpoint.policyList.deleteSuccessToast', { defaultMessage: 'Success!', }), - body: ( + text: ( { ), }); } else { - notifications.toasts.danger({ - toastLifeTimeMs: 10000, + toasts.addDanger({ title: i18n.translate('xpack.securitySolution.endpoint.policyList.deleteFailedToast', { defaultMessage: 'Failed!', }), - body: i18n.translate('xpack.securitySolution.endpoint.policyList.deleteFailedToastBody', { + text: i18n.translate('xpack.securitySolution.endpoint.policyList.deleteFailedToastBody', { defaultMessage: 'Failed to delete policy', }), }); } } - }, [notifications.toasts, deleteStatus]); + }, [toasts, deleteStatus]); const paginationSetup = useMemo(() => { return { From 8f48a45f79366efaebb14ea86554396fc1c1940f Mon Sep 17 00:00:00 2001 From: Bohdan Tsymbala Date: Wed, 29 Jul 2020 18:21:24 +0200 Subject: [PATCH 2/3] Fixed type check errors. --- .../endpoint_hosts/view/details/index.tsx | 18 ++++++------------ .../pages/policy/view/policy_details.tsx | 6 +++--- .../pages/policy/view/policy_list.tsx | 10 +++++----- 3 files changed, 14 insertions(+), 20 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/index.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/index.tsx index f5fb7857d367c..b22ff406a1605 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/index.tsx @@ -59,18 +59,12 @@ export const HostDetailsFlyout = memo(() => { useEffect(() => { if (error !== undefined) { toasts.addDanger({ - title: ( - - ), - text: ( - - ), + title: i18n.translate('xpack.securitySolution.endpoint.host.details.errorTitle', { + defaultMessage: 'Could not find host', + }), + text: i18n.translate('xpack.securitySolution.endpoint.host.details.errorBody', { + defaultMessage: 'Please exit the flyout and select an available host.', + }), }); } }, [error, toasts]); diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.tsx index 05ab8dc98dc19..d309faf59d044 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.tsx @@ -31,7 +31,7 @@ import { isLoading, apiError, } from '../store/policy_details/selectors'; -import { useKibana } from '../../../../../../../../src/plugins/kibana_react/public'; +import { useKibana, toMountPoint } from '../../../../../../../../src/plugins/kibana_react/public'; import { AgentsSummary } from './agents_summary'; import { VerticalDivider } from './vertical_divider'; import { WindowsEvents, MacEvents, LinuxEvents } from './policy_forms/events'; @@ -84,7 +84,7 @@ export const PolicyDetails = React.memo(() => { defaultMessage: 'Success!', } ), - text: ( + text: toMountPoint( { title: i18n.translate('xpack.securitySolution.endpoint.policy.details.updateErrorTitle', { defaultMessage: 'Failed!', }), - text: <>{policyUpdateStatus.error!.message}, + text: policyUpdateStatus.error!.message, }); } } diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_list.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_list.tsx index c1884fcf2d9a1..246dbeb39886f 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_list.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_list.tsx @@ -186,11 +186,11 @@ export const PolicyList = React.memo(() => { title: i18n.translate('xpack.securitySolution.endpoint.policyList.deleteSuccessToast', { defaultMessage: 'Success!', }), - text: ( - + text: i18n.translate( + 'xpack.securitySolution.endpoint.policyList.deleteSuccessToastDetails', + { + defaultMessage: 'Policy has been deleted.', + } ), }); } else { From 6fe94f6915458d6f3a2a06f7f8dfd136c1df0c97 Mon Sep 17 00:00:00 2001 From: Bohdan Tsymbala Date: Wed, 29 Jul 2020 19:25:52 +0200 Subject: [PATCH 3/3] Fixed tests. --- .../management/pages/policy/view/policy_details.test.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.test.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.test.tsx index f81620d439254..03ab32dcb2b66 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_details.test.tsx @@ -259,7 +259,7 @@ describe('Policy Details', () => { expect(toastAddMock.calls).toHaveLength(1); expect(toastAddMock.calls[0][0]).toMatchObject({ title: 'Success!', - text: expect.any(Object), + text: expect.any(Function), }); }); it('should show an error notification toast if update fails', async () => { @@ -274,7 +274,7 @@ describe('Policy Details', () => { expect(toastAddMock.calls).toHaveLength(1); expect(toastAddMock.calls[0][0]).toMatchObject({ title: 'Failed!', - text: expect.any(Object), + text: expect.any(String), }); }); });