Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
b067b98
[Security Solution] Make new Add Data page more fine grained
kevinlog Oct 14, 2021
cf6d00a
remove unused code
kevinlog Oct 14, 2021
70c01e1
Merge branch 'master' into task/make-empty-page-finer-grained
kibanamachine Oct 14, 2021
ebeaae0
pr comments
kevinlog Oct 14, 2021
ee6fd3a
Merge branch 'task/make-empty-page-finer-grained' of github.com:kevin…
kevinlog Oct 14, 2021
422c538
pr comments
kevinlog Oct 15, 2021
0969188
pr comments
kevinlog Oct 15, 2021
1c30c6d
Merge branch 'master' into task/make-empty-page-finer-grained
kibanamachine Oct 18, 2021
a0bf9c8
Merge branch 'master' into task/make-empty-page-finer-grained
kibanamachine Oct 18, 2021
c9ae5cc
Merge branch 'master' into task/make-empty-page-finer-grained
kibanamachine Oct 18, 2021
91a5714
Merge branch 'master' into task/make-empty-page-finer-grained
kibanamachine Oct 18, 2021
bb99649
Fixed nested page templates in favor of using the lower level NoDataPage
Oct 18, 2021
0f91b37
Merge branch 'task/make-empty-page-finer-grained' of github.com:kevin…
Oct 18, 2021
85c08e7
Merge branch 'master' into task/make-empty-page-finer-grained
kibanamachine Oct 18, 2021
607bb82
Merge branch 'master' into task/make-empty-page-finer-grained
kibanamachine Oct 19, 2021
e0194a2
Merge branch 'master' into task/make-empty-page-finer-grained
kibanamachine Oct 19, 2021
2a6ad51
Merge branch 'master' of https://github.com/elastic/kibana into task/…
kevinlog Oct 19, 2021
bb2ac37
Add `category` back in for integration URL and snap
Oct 19, 2021
e3b79fc
Fix category placement
Oct 19, 2021
43b0b85
Merge branch 'master' into task/make-empty-page-finer-grained
kibanamachine Oct 19, 2021
e5c2b58
Merge branch 'master' into task/make-empty-page-finer-grained
kibanamachine Oct 19, 2021
ae3b524
fix test
kevinlog Oct 19, 2021
1771206
Merge branch 'master' into task/make-empty-page-finer-grained
kibanamachine Oct 19, 2021
49599e1
Merge branch 'master' into task/make-empty-page-finer-grained
kibanamachine Oct 19, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ import {
EuiText,
EuiTextColor,
EuiLink,
CommonProps,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import classNames from 'classnames';
import { KibanaPageTemplateProps } from '../page_template';

import { ElasticAgentCard, NoDataCard } from './no_data_card';
Expand Down Expand Up @@ -63,7 +65,7 @@ export type NoDataPageActions = Partial<EuiCardProps> & {

export type NoDataPageActionsProps = Record<string, NoDataPageActions>;

export interface NoDataPageProps {
export interface NoDataPageProps extends CommonProps {
/**
* Single name for the current solution, used to auto-generate the title, logo, description, and button label
*/
Expand Down Expand Up @@ -94,6 +96,7 @@ export const NoDataPage: FunctionComponent<NoDataPageProps> = ({
actions,
docsLink,
pageTitle,
...rest
}) => {
// Convert obj data into an iterable array
const entries = Object.entries(actions);
Expand Down Expand Up @@ -131,7 +134,7 @@ export const NoDataPage: FunctionComponent<NoDataPageProps> = ({
}, [actions, sortedData, actionsKeys]);

return (
<div className="kbnNoDataPageContents">
<div {...rest} className={classNames('kbnNoDataPageContents', rest.className)}>
<EuiText textAlign="center">
<KibanaPageTemplateSolutionNavAvatar
name={solution}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ import styled from 'styled-components';
import { EuiPanel } from '@elastic/eui';
import { IS_DRAGGING_CLASS_NAME } from '@kbn/securitysolution-t-grid';
import { AppLeaveHandler } from '../../../../../../../src/core/public';
import { KibanaPageTemplate } from '../../../../../../../src/plugins/kibana_react/public';
import {
KibanaPageTemplate,
NO_DATA_PAGE_TEMPLATE_PROPS,
} from '../../../../../../../src/plugins/kibana_react/public';
import { useSecuritySolutionNavigation } from '../../../common/components/navigation/use_security_solution_navigation';
import { TimelineId } from '../../../../common/types/timeline';
import { getTimelineShowStatusByIdSelector } from '../../../timelines/components/flyout/selectors';
Expand All @@ -23,12 +26,7 @@ import {
} from './bottom_bar';
import { useShowTimeline } from '../../../common/utils/timeline/use_show_timeline';
import { gutterTimeline } from '../../../common/lib/helpers';
import { useSourcererScope } from '../../../common/containers/sourcerer';
import { OverviewEmpty } from '../../../overview/components/overview_empty';
import { ENDPOINT_METADATA_INDEX } from '../../../../common/constants';
import { useFetchIndex } from '../../../common/containers/source';

/* eslint-disable react/display-name */
import { useShowPagesWithEmptyView } from '../../../common/utils/empty_view/use_show_pages_with_empty_view';

/**
* Need to apply the styles via a className to effect the containing bottom bar
Expand Down Expand Up @@ -77,16 +75,12 @@ export const SecuritySolutionTemplateWrapper: React.FC<SecuritySolutionPageWrapp
const { show: isShowingTimelineOverlay } = useDeepEqualSelector((state) =>
getTimelineShowStatus(state, TimelineId.active)
);
const endpointMetadataIndex = useMemo<string[]>(() => {
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 (
<StyledKibanaPageTemplate
$isTimelineBottomBarVisible={isTimelineBottomBarVisible}
$isShowingTimelineOverlay={isShowingTimelineOverlay}
Expand All @@ -96,18 +90,23 @@ export const SecuritySolutionTemplateWrapper: React.FC<SecuritySolutionPageWrapp
solutionNav={solutionNav}
restrictWidth={false}
template="default"
{...emptyStateProps}
>
<GlobalKQLHeader />
<EuiPanel
className="securityPageWrapper"
data-test-subj="pageContainer"
hasShadow={false}
paddingSize="l"
>
{children}
</EuiPanel>
{showEmptyState ? (
children
) : (
<>
<GlobalKQLHeader />
<EuiPanel
className="securityPageWrapper"
data-test-subj="pageContainer"
hasShadow={false}
paddingSize="l"
>
{children}
</EuiPanel>
</>
)}
</StyledKibanaPageTemplate>
) : (
<OverviewEmpty />
);
});
Original file line number Diff line number Diff line change
@@ -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);
});
});
});
Original file line number Diff line number Diff line change
@@ -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;
};
Original file line number Diff line number Diff line change
Expand Up @@ -219,8 +219,6 @@ const HostDetailsComponent: React.FC<HostDetailsProps> = ({ detailName, hostDeta
</>
) : (
<SecuritySolutionPageWrapper>
<HeaderPage border title={detailName} />

<OverviewEmpty />
</SecuritySolutionPageWrapper>
)}
Expand Down
2 changes: 0 additions & 2 deletions x-pack/plugins/security_solution/public/hosts/pages/hosts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -216,8 +216,6 @@ const HostsComponent = () => {
</StyledFullHeightContainer>
) : (
<SecuritySolutionPageWrapper>
<HeaderPage border title={i18n.PAGE_TITLE} />

<OverviewEmpty />
</SecuritySolutionPageWrapper>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -302,8 +302,6 @@ const NetworkDetailsComponent: React.FC = () => {
</>
) : (
<SecuritySolutionPageWrapper>
<HeaderPage border title={ip} />

<OverviewEmpty />
</SecuritySolutionPageWrapper>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,6 @@ const NetworkComponent = React.memo<NetworkComponentProps>(
</StyledFullHeightContainer>
) : (
<SecuritySolutionPageWrapper>
<HeaderPage border title={i18n.PAGE_TITLE} />
<OverviewEmpty />
</SecuritySolutionPageWrapper>
)}
Expand Down
Loading