diff --git a/x-pack/plugins/security_solution/public/dashboards/components/status_prompt.test.tsx b/x-pack/plugins/security_solution/public/dashboards/components/status_prompt.test.tsx
index c173aa836af55..1677e78622c56 100644
--- a/x-pack/plugins/security_solution/public/dashboards/components/status_prompt.test.tsx
+++ b/x-pack/plugins/security_solution/public/dashboards/components/status_prompt.test.tsx
@@ -7,17 +7,17 @@
import { render } from '@testing-library/react';
import React from 'react';
import { DashboardViewPromptState } from '../hooks/use_dashboard_view_prompt_state';
-import { StatusPropmpt } from './status_prompt';
+import { StatusPrompt } from './status_prompt';
-describe('StatusPropmpt', () => {
+describe('StatusPrompt', () => {
it('hides by default', () => {
- const { queryByTestId } = render();
+ const { queryByTestId } = render();
expect(queryByTestId(`dashboardViewEmptyDefault`)).not.toBeInTheDocument();
});
it('shows when No Read Permission', () => {
const { queryByTestId } = render(
-
+
);
expect(
diff --git a/x-pack/plugins/security_solution/public/dashboards/components/status_prompt.tsx b/x-pack/plugins/security_solution/public/dashboards/components/status_prompt.tsx
index 7f0584ec0e882..6e4bb16374268 100644
--- a/x-pack/plugins/security_solution/public/dashboards/components/status_prompt.tsx
+++ b/x-pack/plugins/security_solution/public/dashboards/components/status_prompt.tsx
@@ -9,7 +9,7 @@ import { EuiPageTemplate } from '@elastic/eui';
import type { DashboardViewPromptState } from '../hooks/use_dashboard_view_prompt_state';
import { useDashboardViewPromptState } from '../hooks/use_dashboard_view_prompt_state';
-const StatusPropmptComponent = ({
+const StatusPromptComponent = ({
currentState,
}: {
currentState: DashboardViewPromptState | null;
@@ -21,5 +21,5 @@ const StatusPropmptComponent = ({
) : null;
};
-StatusPropmptComponent.displayName = 'StatusPropmptComponent';
-export const StatusPropmpt = React.memo(StatusPropmptComponent);
+StatusPromptComponent.displayName = 'StatusPromptComponent';
+export const StatusPrompt = React.memo(StatusPromptComponent);
diff --git a/x-pack/plugins/security_solution/public/dashboards/pages/details/index.test.tsx b/x-pack/plugins/security_solution/public/dashboards/pages/details/index.test.tsx
new file mode 100644
index 0000000000000..9eed2b4a7f5c2
--- /dev/null
+++ b/x-pack/plugins/security_solution/public/dashboards/pages/details/index.test.tsx
@@ -0,0 +1,107 @@
+/*
+ * 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 { render } from '@testing-library/react';
+import React from 'react';
+import { Router } from 'react-router-dom';
+import { DashboardView } from '.';
+import { useCapabilities } from '../../../common/lib/kibana';
+import { TestProviders } from '../../../common/mock';
+
+jest.mock('react-router-dom', () => {
+ const actual = jest.requireActual('react-router-dom');
+ return {
+ ...actual,
+ useParams: jest.fn().mockReturnValue({ detailName: 'mockSavedObjectId' }),
+ };
+});
+
+jest.mock('../../../common/lib/kibana', () => {
+ const actual = jest.requireActual('../../../common/lib/kibana');
+ return {
+ ...actual,
+ useCapabilities: jest.fn().mockReturnValue({ show: true, showWriteControls: true }),
+ };
+});
+
+jest.mock('../../../common/components/dashboards/dashboard_renderer', () => ({
+ DashboardRenderer: jest
+ .fn()
+ .mockImplementation((props) => (
+
+ )),
+}));
+
+type Action = 'PUSH' | 'POP' | 'REPLACE';
+const pop: Action = 'POP';
+const location = {
+ pathname: '/network',
+ search: '',
+ state: '',
+ hash: '',
+};
+const mockHistory = {
+ length: 2,
+ location,
+ action: pop,
+ push: jest.fn(),
+ replace: jest.fn(),
+ go: jest.fn(),
+ goBack: jest.fn(),
+ goForward: jest.fn(),
+ block: jest.fn(),
+ createHref: jest.fn(),
+ listen: jest.fn(),
+};
+
+describe('DashboardView', () => {
+ beforeEach(() => {
+ (useCapabilities as unknown as jest.Mock).mockReturnValue({
+ show: true,
+ showWriteControls: true,
+ });
+ });
+ test('render when no error state', () => {
+ const { queryByTestId } = render(
+
+
+ ,
+ { wrapper: TestProviders }
+ );
+
+ expect(queryByTestId(`dashboard-view-mockSavedObjectId`)).toBeInTheDocument();
+ });
+
+ test('render a prompt when error state exists', () => {
+ (useCapabilities as unknown as jest.Mock).mockReturnValue({
+ show: false,
+ showWriteControls: true,
+ });
+ const { queryByTestId } = render(
+
+
+ ,
+ { wrapper: TestProviders }
+ );
+
+ expect(queryByTestId(`dashboard-view-mockSavedObjectId`)).not.toBeInTheDocument();
+ expect(queryByTestId(`dashboard-view-error-prompt-wrapper`)).toBeInTheDocument();
+ });
+
+ test('render dashboard view with height', () => {
+ const { queryByTestId } = render(
+
+
+ ,
+ { wrapper: TestProviders }
+ );
+
+ expect(queryByTestId(`dashboard-view-wrapper`)).toHaveStyle({
+ 'min-height': `calc(100vh - 140px)`,
+ });
+ });
+});
diff --git a/x-pack/plugins/security_solution/public/dashboards/pages/details/index.tsx b/x-pack/plugins/security_solution/public/dashboards/pages/details/index.tsx
index 410906b29ae73..7fa8671004552 100644
--- a/x-pack/plugins/security_solution/public/dashboards/pages/details/index.tsx
+++ b/x-pack/plugins/security_solution/public/dashboards/pages/details/index.tsx
@@ -13,13 +13,13 @@ import type { DashboardCapabilities } from '@kbn/dashboard-plugin/common/types';
import { useParams } from 'react-router-dom';
import { pick } from 'lodash/fp';
-import { EuiLoadingSpinner } from '@elastic/eui';
+import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui';
import { SecurityPageName } from '../../../../common/constants';
import { SpyRoute } from '../../../common/utils/route/spy_routes';
import { useCapabilities } from '../../../common/lib/kibana';
import { DashboardViewPromptState } from '../../hooks/use_dashboard_view_prompt_state';
import { DashboardRenderer } from '../../../common/components/dashboards/dashboard_renderer';
-import { StatusPropmpt } from '../../components/status_prompt';
+import { StatusPrompt } from '../../components/status_prompt';
import { SiemSearchBar } from '../../../common/components/search_bar';
import { SecuritySolutionPageWrapper } from '../../../common/components/page_wrapper';
import { FiltersGlobal } from '../../../common/components/filters_global';
@@ -33,6 +33,8 @@ import { EditDashboardButton } from '../../components/edit_dashboard_button';
type DashboardDetails = Record;
+const dashboardViewFlexGroupStyle = { minHeight: `calc(100vh - 140px)` };
+
const DashboardViewComponent: React.FC = () => {
const { fromStr, toStr, from, to } = useDeepEqualSelector((state) =>
pick(['fromStr', 'toStr', 'from', 'to'], inputsSelectors.globalTimeRangeSelector(state))
@@ -76,34 +78,47 @@ const DashboardViewComponent: React.FC = () => {
)}
- }>
- {showWriteControls && dashboardExists && (
-
+
+
+ }>
+ {showWriteControls && dashboardExists && (
+
+ )}
+
+
+ {!errorState && (
+
+
+
)}
-
-
- {!errorState && (
-
+
+
+ )}
+
- )}
-
-
-
+
>
);