+
getTimelineShowStatus(state, TimelineId.active)
);
- const endpointMetadataIndex = useMemo(() => {
- return [ENDPOINT_METADATA_INDEX];
- }, []);
- const [, { indexExists: metadataIndexExists }] = useFetchIndex(endpointMetadataIndex, true);
- const { indicesExist } = useSourcererScope();
- const securityIndicesExist = indicesExist || metadataIndexExists;
+ const showEmptyState = useShowPagesWithEmptyView();
+ const emptyStateProps = showEmptyState ? NO_DATA_PAGE_TEMPLATE_PROPS : {};
// StyledKibanaPageTemplate is a styled EuiPageTemplate. Security solution currently passes the header and page content as the children of StyledKibanaPageTemplate, as opposed to using the pageHeader prop, which may account for any style discrepancies, such as the bottom border not extending the full width of the page, between EuiPageTemplate and the security solution pages.
- return securityIndicesExist ? (
+ return (
-
-
- {children}
-
+ {showEmptyState ? (
+ children
+ ) : (
+ <>
+
+
+ {children}
+
+ >
+ )}
- ) : (
-
);
});
diff --git a/x-pack/plugins/security_solution/public/common/utils/empty_view/use_show_pages_with_empty_view.test.tsx b/x-pack/plugins/security_solution/public/common/utils/empty_view/use_show_pages_with_empty_view.test.tsx
new file mode 100644
index 0000000000000..981f7e9e876ea
--- /dev/null
+++ b/x-pack/plugins/security_solution/public/common/utils/empty_view/use_show_pages_with_empty_view.test.tsx
@@ -0,0 +1,51 @@
+/*
+ * 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 { renderHook, act } from '@testing-library/react-hooks';
+import { useShowPagesWithEmptyView } from './use_show_pages_with_empty_view';
+
+jest.mock('../route/use_route_spy', () => ({
+ useRouteSpy: jest
+ .fn()
+ .mockImplementationOnce(() => [{ pageName: 'hosts' }])
+ .mockImplementationOnce(() => [{ pageName: 'rules' }])
+ .mockImplementationOnce(() => [{ pageName: 'network' }]),
+}));
+jest.mock('../../../common/containers/sourcerer', () => ({
+ useSourcererScope: jest
+ .fn()
+ .mockImplementationOnce(() => [{ indicesExist: false }])
+ .mockImplementationOnce(() => [{ indicesExist: false }])
+ .mockImplementationOnce(() => [{ indicesExist: true }]),
+}));
+
+describe('use show pages with empty view', () => {
+ it('shows empty view when on an elligible page and indices do not exist', async () => {
+ await act(async () => {
+ const { result, waitForNextUpdate } = renderHook(() => useShowPagesWithEmptyView());
+ await waitForNextUpdate();
+ const emptyResult = result.current;
+ expect(emptyResult).toEqual(true);
+ });
+ });
+ it('does not show empty view when on an inelligible page and indices do not exist', async () => {
+ await act(async () => {
+ const { result, waitForNextUpdate } = renderHook(() => useShowPagesWithEmptyView());
+ await waitForNextUpdate();
+ const emptyResult = result.current;
+ expect(emptyResult).toEqual(false);
+ });
+ });
+ it('shows empty view when on an elligible page and indices do exist', async () => {
+ await act(async () => {
+ const { result, waitForNextUpdate } = renderHook(() => useShowPagesWithEmptyView());
+ await waitForNextUpdate();
+ const emptyResult = result.current;
+ expect(emptyResult).toEqual(true);
+ });
+ });
+});
diff --git a/x-pack/plugins/security_solution/public/common/utils/empty_view/use_show_pages_with_empty_view.tsx b/x-pack/plugins/security_solution/public/common/utils/empty_view/use_show_pages_with_empty_view.tsx
new file mode 100644
index 0000000000000..10cc4be10a61b
--- /dev/null
+++ b/x-pack/plugins/security_solution/public/common/utils/empty_view/use_show_pages_with_empty_view.tsx
@@ -0,0 +1,41 @@
+/*
+ * 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 { useState, useEffect } from 'react';
+import { useRouteSpy } from '../route/use_route_spy';
+import { SecurityPageName } from '../../../app/types';
+import { useSourcererScope } from '../../../common/containers/sourcerer';
+
+// Used to detect if we're on a top level page that is empty and set page background color to match the subdued Empty State
+const isPageNameWithEmptyView = (currentName: string) => {
+ const pageNamesWithEmptyView: string[] = [
+ SecurityPageName.hosts,
+ SecurityPageName.network,
+ SecurityPageName.timelines,
+ SecurityPageName.overview,
+ ];
+ return pageNamesWithEmptyView.includes(currentName);
+};
+
+export const useShowPagesWithEmptyView = () => {
+ const [{ pageName }] = useRouteSpy();
+ const { indicesExist } = useSourcererScope();
+
+ const shouldShowEmptyState = isPageNameWithEmptyView(pageName) && !indicesExist;
+
+ const [showEmptyState, setShowEmptyState] = useState(shouldShowEmptyState);
+
+ useEffect(() => {
+ if (shouldShowEmptyState) {
+ setShowEmptyState(true);
+ } else {
+ setShowEmptyState(false);
+ }
+ }, [shouldShowEmptyState]);
+
+ return showEmptyState;
+};
diff --git a/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx b/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx
index 627f5e5aef507..9bf046f40edb4 100644
--- a/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx
+++ b/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx
@@ -219,8 +219,6 @@ const HostDetailsComponent: React.FC = ({ detailName, hostDeta
>
) : (
-
-
)}
diff --git a/x-pack/plugins/security_solution/public/hosts/pages/hosts.tsx b/x-pack/plugins/security_solution/public/hosts/pages/hosts.tsx
index f647819798ab7..8e6a635624bfe 100644
--- a/x-pack/plugins/security_solution/public/hosts/pages/hosts.tsx
+++ b/x-pack/plugins/security_solution/public/hosts/pages/hosts.tsx
@@ -216,8 +216,6 @@ const HostsComponent = () => {
) : (
-
-
)}
diff --git a/x-pack/plugins/security_solution/public/network/pages/details/index.tsx b/x-pack/plugins/security_solution/public/network/pages/details/index.tsx
index a3f953fc24fe2..5aee4022a7f30 100644
--- a/x-pack/plugins/security_solution/public/network/pages/details/index.tsx
+++ b/x-pack/plugins/security_solution/public/network/pages/details/index.tsx
@@ -302,8 +302,6 @@ const NetworkDetailsComponent: React.FC = () => {
>
) : (
-
-
)}
diff --git a/x-pack/plugins/security_solution/public/network/pages/network.tsx b/x-pack/plugins/security_solution/public/network/pages/network.tsx
index 928570417c524..fe8a9a93f97c7 100644
--- a/x-pack/plugins/security_solution/public/network/pages/network.tsx
+++ b/x-pack/plugins/security_solution/public/network/pages/network.tsx
@@ -221,7 +221,6 @@ const NetworkComponent = React.memo(
) : (
-
)}
diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_empty/index.test.tsx b/x-pack/plugins/security_solution/public/overview/components/overview_empty/index.test.tsx
index 61e9e66f1bb87..36ecc3371c056 100644
--- a/x-pack/plugins/security_solution/public/overview/components/overview_empty/index.test.tsx
+++ b/x-pack/plugins/security_solution/public/overview/components/overview_empty/index.test.tsx
@@ -42,17 +42,13 @@ describe('OverviewEmpty', () => {
});
it('render with correct actions ', () => {
- expect(wrapper.find('[data-test-subj="empty-page"]').prop('noDataConfig')).toEqual({
- actions: {
- elasticAgent: {
- category: 'security',
- description:
- 'Use Elastic Agent to collect security events and protect your endpoints from threats.',
- title: 'Add a Security integration',
- },
+ expect(wrapper.find('[data-test-subj="empty-page"]').prop('actions')).toEqual({
+ elasticAgent: {
+ category: 'security',
+ description:
+ 'Use Elastic Agent to collect security events and protect your endpoints from threats.',
+ title: 'Add a Security integration',
},
- docsLink: 'https://www.elastic.co/guide/en/security/mocked-test-branch/index.html',
- solution: 'Security',
});
});
});
@@ -67,17 +63,13 @@ describe('OverviewEmpty', () => {
});
it('render with correct actions ', () => {
- expect(wrapper.find('[data-test-subj="empty-page"]').prop('noDataConfig')).toEqual({
- actions: {
- elasticAgent: {
- category: 'security',
- description:
- 'Use Elastic Agent to collect security events and protect your endpoints from threats.',
- title: 'Add a Security integration',
- },
+ expect(wrapper.find('[data-test-subj="empty-page"]').prop('actions')).toEqual({
+ elasticAgent: {
+ category: 'security',
+ description:
+ 'Use Elastic Agent to collect security events and protect your endpoints from threats.',
+ title: 'Add a Security integration',
},
- docsLink: 'https://www.elastic.co/guide/en/security/mocked-test-branch/index.html',
- solution: 'Security',
});
});
});
diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_empty/index.tsx b/x-pack/plugins/security_solution/public/overview/components/overview_empty/index.tsx
index 9b20c079002e6..023d010ec9a9b 100644
--- a/x-pack/plugins/security_solution/public/overview/components/overview_empty/index.tsx
+++ b/x-pack/plugins/security_solution/public/overview/components/overview_empty/index.tsx
@@ -11,7 +11,7 @@ import { useKibana } from '../../../common/lib/kibana';
import { SOLUTION_NAME } from '../../../../public/common/translations';
import {
- KibanaPageTemplate,
+ NoDataPage,
NoDataPageActionsProps,
} from '../../../../../../../src/plugins/kibana_react/public';
@@ -32,13 +32,11 @@ const OverviewEmptyComponent: React.FC = () => {
};
return (
-
);
};
diff --git a/x-pack/plugins/security_solution/public/timelines/pages/timelines_page.tsx b/x-pack/plugins/security_solution/public/timelines/pages/timelines_page.tsx
index 728153f47abd7..f79d513380349 100644
--- a/x-pack/plugins/security_solution/public/timelines/pages/timelines_page.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/pages/timelines_page.tsx
@@ -93,7 +93,6 @@ export const TimelinesPageComponent: React.FC = () => {
>
) : (
-
)}