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 && ( - + + + )} + - )} - - - + );