mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[Security Solution] Collapse KPI and Table queries on Explore pages (#127930)
This commit is contained in:
parent
98300c2364
commit
5e73ef5327
154 changed files with 3966 additions and 1145 deletions
|
@ -18,19 +18,25 @@ exports[`HeaderSection it renders 1`] = `
|
|||
responsive={false}
|
||||
>
|
||||
<EuiFlexItem>
|
||||
<EuiTitle
|
||||
size="m"
|
||||
<EuiFlexGroup
|
||||
gutterSize="none"
|
||||
>
|
||||
<h4
|
||||
data-test-subj="header-section-title"
|
||||
>
|
||||
<span
|
||||
className="eui-textBreakNormal"
|
||||
<EuiFlexItem>
|
||||
<EuiTitle
|
||||
size="m"
|
||||
>
|
||||
Test title
|
||||
</span>
|
||||
</h4>
|
||||
</EuiTitle>
|
||||
<h4
|
||||
data-test-subj="header-section-title"
|
||||
>
|
||||
<span
|
||||
className="eui-textBreakNormal"
|
||||
>
|
||||
Test title
|
||||
</span>
|
||||
</h4>
|
||||
</EuiTitle>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<Subtitle
|
||||
data-test-subj="header-section-subtitle"
|
||||
/>
|
||||
|
|
|
@ -180,4 +180,94 @@ describe('HeaderSection', () => {
|
|||
|
||||
expect(wrapper.find('[data-test-subj="inspect-icon-button"]').first().exists()).toBe(false);
|
||||
});
|
||||
|
||||
test('it does not render query-toggle-header when no arguments provided', () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<HeaderSection id="an id" title="Test title">
|
||||
<p>{'Test children'}</p>
|
||||
</HeaderSection>
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
expect(wrapper.find('[data-test-subj="query-toggle-header"]').first().exists()).toBe(false);
|
||||
});
|
||||
|
||||
test('it does render query-toggle-header when toggleQuery arguments provided', () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<HeaderSection id="an id" title="Test title" toggleQuery={jest.fn()} toggleStatus={true}>
|
||||
<p>{'Test children'}</p>
|
||||
</HeaderSection>
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
expect(wrapper.find('[data-test-subj="query-toggle-header"]').first().exists()).toBe(true);
|
||||
});
|
||||
|
||||
test('it does render everything but title when toggleStatus = true', () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<HeaderSection
|
||||
id="an id"
|
||||
title="Test title"
|
||||
subtitle="subtitle"
|
||||
headerFilters="headerFilters"
|
||||
toggleQuery={jest.fn()}
|
||||
toggleStatus={true}
|
||||
>
|
||||
<p>{'Test children'}</p>
|
||||
</HeaderSection>
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
expect(wrapper.find('[data-test-subj="query-toggle-header"]').first().prop('iconType')).toBe(
|
||||
'arrowDown'
|
||||
);
|
||||
expect(wrapper.find('[data-test-subj="header-section-supplements"]').first().exists()).toBe(
|
||||
true
|
||||
);
|
||||
expect(wrapper.find('[data-test-subj="header-section-subtitle"]').first().exists()).toBe(true);
|
||||
expect(wrapper.find('[data-test-subj="header-section-filters"]').first().exists()).toBe(true);
|
||||
expect(wrapper.find('[data-test-subj="inspect-icon-button"]').first().exists()).toBe(true);
|
||||
});
|
||||
test('it does not render anything but title when toggleStatus = false', () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<HeaderSection
|
||||
id="an id"
|
||||
title="Test title"
|
||||
subtitle="subtitle"
|
||||
headerFilters="headerFilters"
|
||||
toggleQuery={jest.fn()}
|
||||
toggleStatus={false}
|
||||
>
|
||||
<p>{'Test children'}</p>
|
||||
</HeaderSection>
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
expect(wrapper.find('[data-test-subj="query-toggle-header"]').first().prop('iconType')).toBe(
|
||||
'arrowRight'
|
||||
);
|
||||
expect(wrapper.find('[data-test-subj="header-section-supplements"]').first().exists()).toBe(
|
||||
false
|
||||
);
|
||||
expect(wrapper.find('[data-test-subj="header-section-filters"]').first().exists()).toBe(false);
|
||||
expect(wrapper.find('[data-test-subj="header-section-subtitle"]').first().exists()).toBe(false);
|
||||
expect(wrapper.find('[data-test-subj="inspect-icon-button"]').first().exists()).toBe(false);
|
||||
});
|
||||
|
||||
test('it toggles query when icon is clicked', () => {
|
||||
const mockToggle = jest.fn();
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<HeaderSection id="an id" title="Test title" toggleQuery={mockToggle} toggleStatus={true}>
|
||||
<p>{'Test children'}</p>
|
||||
</HeaderSection>
|
||||
</TestProviders>
|
||||
);
|
||||
wrapper.find('[data-test-subj="query-toggle-header"]').first().simulate('click');
|
||||
expect(mockToggle).toBeCalledWith(false);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,13 +5,21 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiIconTip, EuiTitle, EuiTitleSize } from '@elastic/eui';
|
||||
import React from 'react';
|
||||
import {
|
||||
EuiButtonIcon,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiIconTip,
|
||||
EuiTitle,
|
||||
EuiTitleSize,
|
||||
} from '@elastic/eui';
|
||||
import React, { useCallback } from 'react';
|
||||
import styled, { css } from 'styled-components';
|
||||
|
||||
import { InspectButton } from '../inspect';
|
||||
|
||||
import { Subtitle } from '../subtitle';
|
||||
import * as i18n from '../../containers/query_toggle/translations';
|
||||
|
||||
interface HeaderProps {
|
||||
border?: boolean;
|
||||
|
@ -51,6 +59,8 @@ export interface HeaderSectionProps extends HeaderProps {
|
|||
split?: boolean;
|
||||
stackHeader?: boolean;
|
||||
subtitle?: string | React.ReactNode;
|
||||
toggleQuery?: (status: boolean) => void;
|
||||
toggleStatus?: boolean;
|
||||
title: string | React.ReactNode;
|
||||
titleSize?: EuiTitleSize;
|
||||
tooltip?: string;
|
||||
|
@ -72,56 +82,87 @@ const HeaderSectionComponent: React.FC<HeaderSectionProps> = ({
|
|||
subtitle,
|
||||
title,
|
||||
titleSize = 'm',
|
||||
toggleQuery,
|
||||
toggleStatus = true,
|
||||
tooltip,
|
||||
}) => (
|
||||
<Header data-test-subj="header-section" border={border} height={height}>
|
||||
<EuiFlexGroup
|
||||
alignItems={stackHeader ? undefined : 'center'}
|
||||
direction={stackHeader ? 'column' : 'row'}
|
||||
gutterSize="s"
|
||||
>
|
||||
<EuiFlexItem grow={growLeftSplit}>
|
||||
<EuiFlexGroup alignItems="center" responsive={false} gutterSize="s">
|
||||
<EuiFlexItem>
|
||||
<EuiTitle size={titleSize}>
|
||||
<h4 data-test-subj="header-section-title">
|
||||
<span className="eui-textBreakNormal">{title}</span>
|
||||
{tooltip && (
|
||||
<>
|
||||
{' '}
|
||||
<EuiIconTip color="subdued" content={tooltip} size="l" type="iInCircle" />
|
||||
</>
|
||||
}) => {
|
||||
const toggle = useCallback(() => {
|
||||
if (toggleQuery) {
|
||||
toggleQuery(!toggleStatus);
|
||||
}
|
||||
}, [toggleQuery, toggleStatus]);
|
||||
return (
|
||||
<Header data-test-subj="header-section" border={border} height={height}>
|
||||
<EuiFlexGroup
|
||||
alignItems={stackHeader ? undefined : 'center'}
|
||||
direction={stackHeader ? 'column' : 'row'}
|
||||
gutterSize="s"
|
||||
>
|
||||
<EuiFlexItem grow={growLeftSplit}>
|
||||
<EuiFlexGroup alignItems="center" responsive={false} gutterSize="s">
|
||||
<EuiFlexItem>
|
||||
<EuiFlexGroup gutterSize={'none'}>
|
||||
{toggleQuery && (
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonIcon
|
||||
data-test-subj="query-toggle-header"
|
||||
aria-label={i18n.QUERY_BUTTON_TITLE(toggleStatus)}
|
||||
color="text"
|
||||
display="empty"
|
||||
iconType={toggleStatus ? 'arrowDown' : 'arrowRight'}
|
||||
onClick={toggle}
|
||||
size="s"
|
||||
title={i18n.QUERY_BUTTON_TITLE(toggleStatus)}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
</h4>
|
||||
</EuiTitle>
|
||||
<EuiFlexItem>
|
||||
<EuiTitle size={titleSize}>
|
||||
<h4 data-test-subj="header-section-title">
|
||||
<span className="eui-textBreakNormal">{title}</span>
|
||||
{tooltip && (
|
||||
<>
|
||||
{' '}
|
||||
<EuiIconTip color="subdued" content={tooltip} size="l" type="iInCircle" />
|
||||
</>
|
||||
)}
|
||||
</h4>
|
||||
</EuiTitle>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
|
||||
{!hideSubtitle && (
|
||||
<Subtitle data-test-subj="header-section-subtitle" items={subtitle} />
|
||||
)}
|
||||
</EuiFlexItem>
|
||||
|
||||
{id && showInspectButton && (
|
||||
<EuiFlexItem grow={false}>
|
||||
<InspectButton
|
||||
isDisabled={isInspectDisabled}
|
||||
queryId={id}
|
||||
multiple={inspectMultiple}
|
||||
title={title}
|
||||
/>
|
||||
{!hideSubtitle && toggleStatus && (
|
||||
<Subtitle data-test-subj="header-section-subtitle" items={subtitle} />
|
||||
)}
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
|
||||
{headerFilters && <EuiFlexItem grow={false}>{headerFilters}</EuiFlexItem>}
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
{id && showInspectButton && toggleStatus && (
|
||||
<EuiFlexItem grow={false}>
|
||||
<InspectButton
|
||||
isDisabled={isInspectDisabled}
|
||||
queryId={id}
|
||||
multiple={inspectMultiple}
|
||||
title={title}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
|
||||
{children && (
|
||||
<EuiFlexItem data-test-subj="header-section-supplements" grow={split ? true : false}>
|
||||
{children}
|
||||
{headerFilters && toggleStatus && (
|
||||
<EuiFlexItem data-test-subj="header-section-filters" grow={false}>
|
||||
{headerFilters}
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
</EuiFlexGroup>
|
||||
</Header>
|
||||
);
|
||||
|
||||
{children && toggleStatus && (
|
||||
<EuiFlexItem data-test-subj="header-section-supplements" grow={split ? true : false}>
|
||||
{children}
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
</EuiFlexGroup>
|
||||
</Header>
|
||||
);
|
||||
};
|
||||
|
||||
export const HeaderSection = React.memo(HeaderSectionComponent);
|
||||
|
|
|
@ -15,6 +15,9 @@ import { TestProviders } from '../../mock';
|
|||
import { mockRuntimeMappings } from '../../containers/source/mock';
|
||||
import { dnsTopDomainsLensAttributes } from '../visualization_actions/lens_attributes/network/dns_top_domains';
|
||||
import { useRouteSpy } from '../../utils/route/use_route_spy';
|
||||
import { useQueryToggle } from '../../containers/query_toggle';
|
||||
|
||||
jest.mock('../../containers/query_toggle');
|
||||
jest.mock('../../lib/kibana');
|
||||
|
||||
jest.mock('./matrix_loader', () => ({
|
||||
|
@ -25,9 +28,7 @@ jest.mock('../charts/barchart', () => ({
|
|||
BarChart: () => <div className="barchart" />,
|
||||
}));
|
||||
|
||||
jest.mock('../../containers/matrix_histogram', () => ({
|
||||
useMatrixHistogramCombined: jest.fn(),
|
||||
}));
|
||||
jest.mock('../../containers/matrix_histogram');
|
||||
|
||||
jest.mock('../visualization_actions', () => ({
|
||||
VisualizationActions: jest.fn(({ className }: { className: string }) => (
|
||||
|
@ -78,9 +79,13 @@ describe('Matrix Histogram Component', () => {
|
|||
title: 'mockTitle',
|
||||
runtimeMappings: mockRuntimeMappings,
|
||||
};
|
||||
|
||||
beforeAll(() => {
|
||||
(useMatrixHistogramCombined as jest.Mock).mockReturnValue([
|
||||
const mockUseMatrix = useMatrixHistogramCombined as jest.Mock;
|
||||
const mockUseQueryToggle = useQueryToggle as jest.Mock;
|
||||
const mockSetToggle = jest.fn();
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: true, setToggleStatus: mockSetToggle });
|
||||
mockUseMatrix.mockReturnValue([
|
||||
false,
|
||||
{
|
||||
data: null,
|
||||
|
@ -88,14 +93,16 @@ describe('Matrix Histogram Component', () => {
|
|||
totalCount: null,
|
||||
},
|
||||
]);
|
||||
wrapper = mount(<MatrixHistogram {...mockMatrixOverTimeHistogramProps} />, {
|
||||
wrappingComponent: TestProviders,
|
||||
});
|
||||
});
|
||||
|
||||
describe('on initial load', () => {
|
||||
beforeEach(() => {
|
||||
wrapper = mount(<MatrixHistogram {...mockMatrixOverTimeHistogramProps} />, {
|
||||
wrappingComponent: TestProviders,
|
||||
});
|
||||
});
|
||||
test('it requests Matrix Histogram', () => {
|
||||
expect(useMatrixHistogramCombined).toHaveBeenCalledWith({
|
||||
expect(mockUseMatrix).toHaveBeenCalledWith({
|
||||
endDate: mockMatrixOverTimeHistogramProps.endDate,
|
||||
errorMessage: mockMatrixOverTimeHistogramProps.errorMessage,
|
||||
histogramType: mockMatrixOverTimeHistogramProps.histogramType,
|
||||
|
@ -114,6 +121,9 @@ describe('Matrix Histogram Component', () => {
|
|||
|
||||
describe('spacer', () => {
|
||||
test('it renders a spacer by default', () => {
|
||||
wrapper = mount(<MatrixHistogram {...mockMatrixOverTimeHistogramProps} />, {
|
||||
wrappingComponent: TestProviders,
|
||||
});
|
||||
expect(wrapper.find('[data-test-subj="spacer"]').exists()).toBe(true);
|
||||
});
|
||||
|
||||
|
@ -129,8 +139,11 @@ describe('Matrix Histogram Component', () => {
|
|||
});
|
||||
|
||||
describe('not initial load', () => {
|
||||
beforeAll(() => {
|
||||
(useMatrixHistogramCombined as jest.Mock).mockReturnValue([
|
||||
beforeEach(() => {
|
||||
wrapper = mount(<MatrixHistogram {...mockMatrixOverTimeHistogramProps} />, {
|
||||
wrappingComponent: TestProviders,
|
||||
});
|
||||
mockUseMatrix.mockReturnValue([
|
||||
false,
|
||||
{
|
||||
data: [
|
||||
|
@ -159,6 +172,9 @@ describe('Matrix Histogram Component', () => {
|
|||
|
||||
describe('select dropdown', () => {
|
||||
test('should be hidden if only one option is provided', () => {
|
||||
wrapper = mount(<MatrixHistogram {...mockMatrixOverTimeHistogramProps} />, {
|
||||
wrappingComponent: TestProviders,
|
||||
});
|
||||
expect(wrapper.find('EuiSelect').exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
@ -287,4 +303,53 @@ describe('Matrix Histogram Component', () => {
|
|||
expect(wrapper.find('[data-test-subj="mock-viz-actions"]').exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('toggle query', () => {
|
||||
const testProps = {
|
||||
...mockMatrixOverTimeHistogramProps,
|
||||
lensAttributes: dnsTopDomainsLensAttributes,
|
||||
};
|
||||
|
||||
test('toggleQuery updates toggleStatus', () => {
|
||||
wrapper = mount(<MatrixHistogram {...testProps} />, {
|
||||
wrappingComponent: TestProviders,
|
||||
});
|
||||
expect(mockUseMatrix.mock.calls[0][0].skip).toEqual(false);
|
||||
wrapper.find('[data-test-subj="query-toggle-header"]').first().simulate('click');
|
||||
expect(mockSetToggle).toBeCalledWith(false);
|
||||
expect(mockUseMatrix.mock.calls[1][0].skip).toEqual(true);
|
||||
});
|
||||
|
||||
test('toggleStatus=true, do not skip', () => {
|
||||
wrapper = mount(<MatrixHistogram {...testProps} />, {
|
||||
wrappingComponent: TestProviders,
|
||||
});
|
||||
|
||||
expect(mockUseMatrix.mock.calls[0][0].skip).toEqual(false);
|
||||
});
|
||||
|
||||
test('toggleStatus=true, render components', () => {
|
||||
wrapper = mount(<MatrixHistogram {...testProps} />, {
|
||||
wrappingComponent: TestProviders,
|
||||
});
|
||||
expect(wrapper.find('MatrixLoader').exists()).toBe(true);
|
||||
});
|
||||
|
||||
test('toggleStatus=false, do not render components', () => {
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: false, setToggleStatus: mockSetToggle });
|
||||
wrapper = mount(<MatrixHistogram {...testProps} />, {
|
||||
wrappingComponent: TestProviders,
|
||||
});
|
||||
expect(wrapper.find('MatrixLoader').exists()).toBe(false);
|
||||
});
|
||||
|
||||
test('toggleStatus=false, skip', () => {
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: false, setToggleStatus: mockSetToggle });
|
||||
wrapper = mount(<MatrixHistogram {...testProps} />, {
|
||||
wrappingComponent: TestProviders,
|
||||
});
|
||||
|
||||
expect(mockUseMatrix.mock.calls[0][0].skip).toEqual(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -34,6 +34,7 @@ import { GetLensAttributes, LensAttributes } from '../visualization_actions/type
|
|||
import { useKibana, useGetUserCasesPermissions } from '../../lib/kibana';
|
||||
import { APP_ID, SecurityPageName } from '../../../../common/constants';
|
||||
import { useRouteSpy } from '../../utils/route/use_route_spy';
|
||||
import { useQueryToggle } from '../../containers/query_toggle';
|
||||
|
||||
export type MatrixHistogramComponentProps = MatrixHistogramProps &
|
||||
Omit<MatrixHistogramQueryProps, 'stackByField'> & {
|
||||
|
@ -148,6 +149,19 @@ export const MatrixHistogramComponent: React.FC<MatrixHistogramComponentProps> =
|
|||
},
|
||||
[defaultStackByOption, stackByOptions]
|
||||
);
|
||||
const { toggleStatus, setToggleStatus } = useQueryToggle(id);
|
||||
const [querySkip, setQuerySkip] = useState(skip || !toggleStatus);
|
||||
useEffect(() => {
|
||||
setQuerySkip(skip || !toggleStatus);
|
||||
}, [skip, toggleStatus]);
|
||||
const toggleQuery = useCallback(
|
||||
(status: boolean) => {
|
||||
setToggleStatus(status);
|
||||
// toggle on = skipQuery false
|
||||
setQuerySkip(!status);
|
||||
},
|
||||
[setQuerySkip, setToggleStatus]
|
||||
);
|
||||
|
||||
const matrixHistogramRequest = {
|
||||
endDate,
|
||||
|
@ -161,9 +175,8 @@ export const MatrixHistogramComponent: React.FC<MatrixHistogramComponentProps> =
|
|||
runtimeMappings,
|
||||
isPtrIncluded,
|
||||
docValueFields,
|
||||
skip,
|
||||
skip: querySkip,
|
||||
};
|
||||
|
||||
const [loading, { data, inspect, totalCount, refetch }] =
|
||||
useMatrixHistogramCombined(matrixHistogramRequest);
|
||||
const [{ pageName }] = useRouteSpy();
|
||||
|
@ -225,7 +238,7 @@ export const MatrixHistogramComponent: React.FC<MatrixHistogramComponentProps> =
|
|||
>
|
||||
<HistogramPanel
|
||||
data-test-subj={`${id}Panel`}
|
||||
height={panelHeight}
|
||||
height={toggleStatus ? panelHeight : undefined}
|
||||
paddingSize={paddingSize}
|
||||
>
|
||||
{loading && !isInitialLoading && (
|
||||
|
@ -239,8 +252,11 @@ export const MatrixHistogramComponent: React.FC<MatrixHistogramComponentProps> =
|
|||
|
||||
<HeaderSection
|
||||
id={id}
|
||||
height={toggleStatus ? undefined : 0}
|
||||
title={titleWithStackByField}
|
||||
titleSize={titleSize}
|
||||
toggleStatus={toggleStatus}
|
||||
toggleQuery={toggleQuery}
|
||||
subtitle={subtitleWithCounts}
|
||||
inspectMultiple
|
||||
showInspectButton={showInspectButton || !onHostOrNetworkPage}
|
||||
|
@ -276,17 +292,18 @@ export const MatrixHistogramComponent: React.FC<MatrixHistogramComponentProps> =
|
|||
<EuiFlexItem grow={false}>{headerChildren}</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</HeaderSection>
|
||||
|
||||
{isInitialLoading ? (
|
||||
<MatrixLoader />
|
||||
) : (
|
||||
<BarChart
|
||||
barChart={barChartData}
|
||||
configs={barchartConfigs}
|
||||
stackByField={selectedStackByOption.value}
|
||||
timelineId={timelineId}
|
||||
/>
|
||||
)}
|
||||
{toggleStatus ? (
|
||||
isInitialLoading ? (
|
||||
<MatrixLoader />
|
||||
) : (
|
||||
<BarChart
|
||||
barChart={barChartData}
|
||||
configs={barchartConfigs}
|
||||
stackByField={selectedStackByOption.value}
|
||||
timelineId={timelineId}
|
||||
/>
|
||||
)
|
||||
) : null}
|
||||
</HistogramPanel>
|
||||
</HoverVisibilityContainer>
|
||||
{showSpacer && <EuiSpacer data-test-subj="spacer" size="l" />}
|
||||
|
|
|
@ -10,7 +10,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui';
|
|||
import styled from 'styled-components';
|
||||
|
||||
const StyledEuiFlexGroup = styled(EuiFlexGroup)`
|
||||
flex 1;
|
||||
flex: 1;
|
||||
`;
|
||||
|
||||
const MatrixLoaderComponent = () => (
|
||||
|
|
|
@ -80,7 +80,9 @@ export const useAnomaliesTableData = ({
|
|||
earliestMs: number,
|
||||
latestMs: number
|
||||
) {
|
||||
if (isMlUser && !skip && jobIds.length > 0) {
|
||||
if (skip) {
|
||||
setLoading(false);
|
||||
} else if (isMlUser && !skip && jobIds.length > 0) {
|
||||
try {
|
||||
const data = await anomaliesTableData(
|
||||
{
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* 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 { mount } from 'enzyme';
|
||||
import { AnomaliesHostTable } from './anomalies_host_table';
|
||||
import { TestProviders } from '../../../mock';
|
||||
import React from 'react';
|
||||
import { useQueryToggle } from '../../../containers/query_toggle';
|
||||
import { useAnomaliesTableData } from '../anomaly/use_anomalies_table_data';
|
||||
import { HostsType } from '../../../../hosts/store/model';
|
||||
import { hasMlUserPermissions } from '../../../../../common/machine_learning/has_ml_user_permissions';
|
||||
|
||||
jest.mock('../../../containers/query_toggle');
|
||||
jest.mock('../anomaly/use_anomalies_table_data');
|
||||
jest.mock('../../../../../common/machine_learning/has_ml_user_permissions');
|
||||
|
||||
describe('Anomalies host table', () => {
|
||||
describe('toggle query', () => {
|
||||
const mockUseQueryToggle = useQueryToggle as jest.Mock;
|
||||
const mockUseAnomaliesTableData = useAnomaliesTableData as jest.Mock;
|
||||
const mockSetToggle = jest.fn();
|
||||
const testProps = {
|
||||
startDate: '2019-07-17T20:00:00.000Z',
|
||||
endDate: '2019-07-18T20:00:00.000Z',
|
||||
narrowDateRange: jest.fn(),
|
||||
skip: false,
|
||||
type: HostsType.page,
|
||||
};
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
(hasMlUserPermissions as jest.Mock).mockReturnValue(true);
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: true, setToggleStatus: mockSetToggle });
|
||||
mockUseAnomaliesTableData.mockReturnValue([
|
||||
false,
|
||||
{
|
||||
anomalies: [],
|
||||
interval: '10',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test('toggleQuery updates toggleStatus', () => {
|
||||
const wrapper = mount(<AnomaliesHostTable {...testProps} />, {
|
||||
wrappingComponent: TestProviders,
|
||||
});
|
||||
expect(mockUseAnomaliesTableData.mock.calls[0][0].skip).toEqual(false);
|
||||
wrapper.find('[data-test-subj="query-toggle-header"]').first().simulate('click');
|
||||
expect(mockSetToggle).toBeCalledWith(false);
|
||||
expect(mockUseAnomaliesTableData.mock.calls[1][0].skip).toEqual(true);
|
||||
});
|
||||
|
||||
test('toggleStatus=true, do not skip', () => {
|
||||
mount(<AnomaliesHostTable {...testProps} />, {
|
||||
wrappingComponent: TestProviders,
|
||||
});
|
||||
|
||||
expect(mockUseAnomaliesTableData.mock.calls[0][0].skip).toEqual(false);
|
||||
});
|
||||
|
||||
test('toggleStatus=true, render components', () => {
|
||||
const wrapper = mount(<AnomaliesHostTable {...testProps} />, {
|
||||
wrappingComponent: TestProviders,
|
||||
});
|
||||
expect(wrapper.find('[data-test-subj="host-anomalies-table"]').exists()).toBe(true);
|
||||
});
|
||||
|
||||
test('toggleStatus=false, do not render components', () => {
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: false, setToggleStatus: mockSetToggle });
|
||||
const wrapper = mount(<AnomaliesHostTable {...testProps} />, {
|
||||
wrappingComponent: TestProviders,
|
||||
});
|
||||
expect(wrapper.find('[data-test-subj="host-anomalies-table"]').exists()).toBe(false);
|
||||
});
|
||||
|
||||
test('toggleStatus=false, skip', () => {
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: false, setToggleStatus: mockSetToggle });
|
||||
mount(<AnomaliesHostTable {...testProps} />, {
|
||||
wrappingComponent: TestProviders,
|
||||
});
|
||||
|
||||
expect(mockUseAnomaliesTableData.mock.calls[0][0].skip).toEqual(true);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
|
||||
import { useAnomaliesTableData } from '../anomaly/use_anomalies_table_data';
|
||||
import { HeaderSection } from '../../header_section';
|
||||
|
@ -21,6 +21,7 @@ import { BasicTable } from './basic_table';
|
|||
import { getCriteriaFromHostType } from '../criteria/get_criteria_from_host_type';
|
||||
import { Panel } from '../../panel';
|
||||
import { anomaliesTableDefaultEquality } from './default_equality';
|
||||
import { useQueryToggle } from '../../../containers/query_toggle';
|
||||
|
||||
const sorting = {
|
||||
sort: {
|
||||
|
@ -37,10 +38,24 @@ const AnomaliesHostTableComponent: React.FC<AnomaliesHostTableProps> = ({
|
|||
type,
|
||||
}) => {
|
||||
const capabilities = useMlCapabilities();
|
||||
const { toggleStatus, setToggleStatus } = useQueryToggle(`AnomaliesHostTable`);
|
||||
const [querySkip, setQuerySkip] = useState(skip || !toggleStatus);
|
||||
useEffect(() => {
|
||||
setQuerySkip(skip || !toggleStatus);
|
||||
}, [skip, toggleStatus]);
|
||||
const toggleQuery = useCallback(
|
||||
(status: boolean) => {
|
||||
setToggleStatus(status);
|
||||
// toggle on = skipQuery false
|
||||
setQuerySkip(!status);
|
||||
},
|
||||
[setQuerySkip, setToggleStatus]
|
||||
);
|
||||
|
||||
const [loading, tableData] = useAnomaliesTableData({
|
||||
startDate,
|
||||
endDate,
|
||||
skip,
|
||||
skip: querySkip,
|
||||
criteriaFields: getCriteriaFromHostType(type, hostName),
|
||||
filterQuery: {
|
||||
exists: { field: 'host.name' },
|
||||
|
@ -64,21 +79,26 @@ const AnomaliesHostTableComponent: React.FC<AnomaliesHostTableProps> = ({
|
|||
return (
|
||||
<Panel loading={loading}>
|
||||
<HeaderSection
|
||||
height={!toggleStatus ? 40 : undefined}
|
||||
subtitle={`${i18n.SHOWING}: ${pagination.totalItemCount.toLocaleString()} ${i18n.UNIT(
|
||||
pagination.totalItemCount
|
||||
)}`}
|
||||
title={i18n.ANOMALIES}
|
||||
toggleQuery={toggleQuery}
|
||||
toggleStatus={toggleStatus}
|
||||
tooltip={i18n.TOOLTIP}
|
||||
isInspectDisabled={skip}
|
||||
/>
|
||||
|
||||
<BasicTable
|
||||
// @ts-expect-error the Columns<T, U> type is not as specific as EUI's...
|
||||
columns={columns}
|
||||
items={hosts}
|
||||
pagination={pagination}
|
||||
sorting={sorting}
|
||||
/>
|
||||
{toggleStatus && (
|
||||
<BasicTable
|
||||
data-test-subj="host-anomalies-table"
|
||||
// @ts-expect-error the Columns<T, U> type is not as specific as EUI's...
|
||||
columns={columns}
|
||||
items={hosts}
|
||||
pagination={pagination}
|
||||
sorting={sorting}
|
||||
/>
|
||||
)}
|
||||
|
||||
{loading && (
|
||||
<Loader data-test-subj="anomalies-host-table-loading-panel" overlay size="xl" />
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* 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 { mount } from 'enzyme';
|
||||
import { AnomaliesNetworkTable } from './anomalies_network_table';
|
||||
import { TestProviders } from '../../../mock';
|
||||
import React from 'react';
|
||||
import { useQueryToggle } from '../../../containers/query_toggle';
|
||||
import { useAnomaliesTableData } from '../anomaly/use_anomalies_table_data';
|
||||
import { NetworkType } from '../../../../network/store/model';
|
||||
import { hasMlUserPermissions } from '../../../../../common/machine_learning/has_ml_user_permissions';
|
||||
import { FlowTarget } from '../../../../../common/search_strategy';
|
||||
|
||||
jest.mock('../../../containers/query_toggle');
|
||||
jest.mock('../anomaly/use_anomalies_table_data');
|
||||
jest.mock('../../../../../common/machine_learning/has_ml_user_permissions');
|
||||
|
||||
describe('Anomalies network table', () => {
|
||||
describe('toggle query', () => {
|
||||
const mockUseQueryToggle = useQueryToggle as jest.Mock;
|
||||
const mockUseAnomaliesTableData = useAnomaliesTableData as jest.Mock;
|
||||
const mockSetToggle = jest.fn();
|
||||
const testProps = {
|
||||
startDate: '2019-07-17T20:00:00.000Z',
|
||||
endDate: '2019-07-18T20:00:00.000Z',
|
||||
flowTarget: FlowTarget.destination,
|
||||
narrowDateRange: jest.fn(),
|
||||
skip: false,
|
||||
type: NetworkType.page,
|
||||
};
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
(hasMlUserPermissions as jest.Mock).mockReturnValue(true);
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: true, setToggleStatus: mockSetToggle });
|
||||
mockUseAnomaliesTableData.mockReturnValue([
|
||||
false,
|
||||
{
|
||||
anomalies: [],
|
||||
interval: '10',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test('toggleQuery updates toggleStatus', () => {
|
||||
const wrapper = mount(<AnomaliesNetworkTable {...testProps} />, {
|
||||
wrappingComponent: TestProviders,
|
||||
});
|
||||
expect(mockUseAnomaliesTableData.mock.calls[0][0].skip).toEqual(false);
|
||||
wrapper.find('[data-test-subj="query-toggle-header"]').first().simulate('click');
|
||||
expect(mockSetToggle).toBeCalledWith(false);
|
||||
expect(mockUseAnomaliesTableData.mock.calls[1][0].skip).toEqual(true);
|
||||
});
|
||||
|
||||
test('toggleStatus=true, do not skip', () => {
|
||||
mount(<AnomaliesNetworkTable {...testProps} />, {
|
||||
wrappingComponent: TestProviders,
|
||||
});
|
||||
|
||||
expect(mockUseAnomaliesTableData.mock.calls[0][0].skip).toEqual(false);
|
||||
});
|
||||
|
||||
test('toggleStatus=true, render components', () => {
|
||||
const wrapper = mount(<AnomaliesNetworkTable {...testProps} />, {
|
||||
wrappingComponent: TestProviders,
|
||||
});
|
||||
expect(wrapper.find('[data-test-subj="network-anomalies-table"]').exists()).toBe(true);
|
||||
});
|
||||
|
||||
test('toggleStatus=false, do not render components', () => {
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: false, setToggleStatus: mockSetToggle });
|
||||
const wrapper = mount(<AnomaliesNetworkTable {...testProps} />, {
|
||||
wrappingComponent: TestProviders,
|
||||
});
|
||||
expect(wrapper.find('[data-test-subj="network-anomalies-table"]').exists()).toBe(false);
|
||||
});
|
||||
|
||||
test('toggleStatus=false, skip', () => {
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: false, setToggleStatus: mockSetToggle });
|
||||
mount(<AnomaliesNetworkTable {...testProps} />, {
|
||||
wrappingComponent: TestProviders,
|
||||
});
|
||||
|
||||
expect(mockUseAnomaliesTableData.mock.calls[0][0].skip).toEqual(true);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { useAnomaliesTableData } from '../anomaly/use_anomalies_table_data';
|
||||
import { HeaderSection } from '../../header_section';
|
||||
|
||||
|
@ -20,6 +20,7 @@ import { BasicTable } from './basic_table';
|
|||
import { networkEquality } from './network_equality';
|
||||
import { getCriteriaFromNetworkType } from '../criteria/get_criteria_from_network_type';
|
||||
import { Panel } from '../../panel';
|
||||
import { useQueryToggle } from '../../../containers/query_toggle';
|
||||
|
||||
const sorting = {
|
||||
sort: {
|
||||
|
@ -37,10 +38,25 @@ const AnomaliesNetworkTableComponent: React.FC<AnomaliesNetworkTableProps> = ({
|
|||
flowTarget,
|
||||
}) => {
|
||||
const capabilities = useMlCapabilities();
|
||||
|
||||
const { toggleStatus, setToggleStatus } = useQueryToggle(`AnomaliesNetwork-${flowTarget}`);
|
||||
const [querySkip, setQuerySkip] = useState(skip || !toggleStatus);
|
||||
useEffect(() => {
|
||||
setQuerySkip(skip || !toggleStatus);
|
||||
}, [skip, toggleStatus]);
|
||||
const toggleQuery = useCallback(
|
||||
(status: boolean) => {
|
||||
setToggleStatus(status);
|
||||
// toggle on = skipQuery false
|
||||
setQuerySkip(!status);
|
||||
},
|
||||
[setQuerySkip, setToggleStatus]
|
||||
);
|
||||
|
||||
const [loading, tableData] = useAnomaliesTableData({
|
||||
startDate,
|
||||
endDate,
|
||||
skip,
|
||||
skip: querySkip,
|
||||
criteriaFields: getCriteriaFromNetworkType(type, ip, flowTarget),
|
||||
});
|
||||
|
||||
|
@ -63,18 +79,23 @@ const AnomaliesNetworkTableComponent: React.FC<AnomaliesNetworkTableProps> = ({
|
|||
subtitle={`${i18n.SHOWING}: ${pagination.totalItemCount.toLocaleString()} ${i18n.UNIT(
|
||||
pagination.totalItemCount
|
||||
)}`}
|
||||
height={!toggleStatus ? 40 : undefined}
|
||||
title={i18n.ANOMALIES}
|
||||
tooltip={i18n.TOOLTIP}
|
||||
toggleQuery={toggleQuery}
|
||||
toggleStatus={toggleStatus}
|
||||
isInspectDisabled={skip}
|
||||
/>
|
||||
|
||||
<BasicTable
|
||||
// @ts-expect-error the Columns<T, U> type is not as specific as EUI's...
|
||||
columns={columns}
|
||||
items={networks}
|
||||
pagination={pagination}
|
||||
sorting={sorting}
|
||||
/>
|
||||
{toggleStatus && (
|
||||
<BasicTable
|
||||
data-test-subj="network-anomalies-table"
|
||||
// @ts-expect-error the Columns<T, U> type is not as specific as EUI's...
|
||||
columns={columns}
|
||||
items={networks}
|
||||
pagination={pagination}
|
||||
sorting={sorting}
|
||||
/>
|
||||
)}
|
||||
|
||||
{loading && (
|
||||
<Loader data-test-subj="anomalies-network-table-loading-panel" overlay size="xl" />
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* 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 { mount } from 'enzyme';
|
||||
import { AnomaliesUserTable } from './anomalies_user_table';
|
||||
import { TestProviders } from '../../../mock';
|
||||
import React from 'react';
|
||||
import { useQueryToggle } from '../../../containers/query_toggle';
|
||||
import { useAnomaliesTableData } from '../anomaly/use_anomalies_table_data';
|
||||
import { UsersType } from '../../../../users/store/model';
|
||||
import { hasMlUserPermissions } from '../../../../../common/machine_learning/has_ml_user_permissions';
|
||||
|
||||
jest.mock('../../../containers/query_toggle');
|
||||
jest.mock('../anomaly/use_anomalies_table_data');
|
||||
jest.mock('../../../../../common/machine_learning/has_ml_user_permissions');
|
||||
|
||||
describe('Anomalies user table', () => {
|
||||
describe('toggle query', () => {
|
||||
const mockUseQueryToggle = useQueryToggle as jest.Mock;
|
||||
const mockUseAnomaliesTableData = useAnomaliesTableData as jest.Mock;
|
||||
const mockSetToggle = jest.fn();
|
||||
const testProps = {
|
||||
startDate: '2019-07-17T20:00:00.000Z',
|
||||
endDate: '2019-07-18T20:00:00.000Z',
|
||||
narrowDateRange: jest.fn(),
|
||||
userName: 'coolguy',
|
||||
skip: false,
|
||||
type: UsersType.page,
|
||||
};
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
(hasMlUserPermissions as jest.Mock).mockReturnValue(true);
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: true, setToggleStatus: mockSetToggle });
|
||||
mockUseAnomaliesTableData.mockReturnValue([
|
||||
false,
|
||||
{
|
||||
anomalies: [],
|
||||
interval: '10',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test('toggleQuery updates toggleStatus', () => {
|
||||
const wrapper = mount(<AnomaliesUserTable {...testProps} />, {
|
||||
wrappingComponent: TestProviders,
|
||||
});
|
||||
expect(mockUseAnomaliesTableData.mock.calls[0][0].skip).toEqual(false);
|
||||
wrapper.find('[data-test-subj="query-toggle-header"]').first().simulate('click');
|
||||
expect(mockSetToggle).toBeCalledWith(false);
|
||||
expect(mockUseAnomaliesTableData.mock.calls[1][0].skip).toEqual(true);
|
||||
});
|
||||
|
||||
test('toggleStatus=true, do not skip', () => {
|
||||
mount(<AnomaliesUserTable {...testProps} />, {
|
||||
wrappingComponent: TestProviders,
|
||||
});
|
||||
|
||||
expect(mockUseAnomaliesTableData.mock.calls[0][0].skip).toEqual(false);
|
||||
});
|
||||
|
||||
test('toggleStatus=true, render components', () => {
|
||||
const wrapper = mount(<AnomaliesUserTable {...testProps} />, {
|
||||
wrappingComponent: TestProviders,
|
||||
});
|
||||
expect(wrapper.find('[data-test-subj="user-anomalies-table"]').exists()).toBe(true);
|
||||
});
|
||||
|
||||
test('toggleStatus=false, do not render components', () => {
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: false, setToggleStatus: mockSetToggle });
|
||||
const wrapper = mount(<AnomaliesUserTable {...testProps} />, {
|
||||
wrappingComponent: TestProviders,
|
||||
});
|
||||
expect(wrapper.find('[data-test-subj="user-anomalies-table"]').exists()).toBe(false);
|
||||
});
|
||||
|
||||
test('toggleStatus=false, skip', () => {
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: false, setToggleStatus: mockSetToggle });
|
||||
mount(<AnomaliesUserTable {...testProps} />, {
|
||||
wrappingComponent: TestProviders,
|
||||
});
|
||||
|
||||
expect(mockUseAnomaliesTableData.mock.calls[0][0].skip).toEqual(true);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
|
||||
import { useAnomaliesTableData } from '../anomaly/use_anomalies_table_data';
|
||||
import { HeaderSection } from '../../header_section';
|
||||
|
@ -23,6 +23,7 @@ import { Panel } from '../../panel';
|
|||
import { anomaliesTableDefaultEquality } from './default_equality';
|
||||
import { convertAnomaliesToUsers } from './convert_anomalies_to_users';
|
||||
import { getAnomaliesUserTableColumnsCurated } from './get_anomalies_user_table_columns';
|
||||
import { useQueryToggle } from '../../../containers/query_toggle';
|
||||
|
||||
const sorting = {
|
||||
sort: {
|
||||
|
@ -40,10 +41,24 @@ const AnomaliesUserTableComponent: React.FC<AnomaliesUserTableProps> = ({
|
|||
}) => {
|
||||
const capabilities = useMlCapabilities();
|
||||
|
||||
const { toggleStatus, setToggleStatus } = useQueryToggle(`AnomaliesUserTable`);
|
||||
const [querySkip, setQuerySkip] = useState(skip || !toggleStatus);
|
||||
useEffect(() => {
|
||||
setQuerySkip(skip || !toggleStatus);
|
||||
}, [skip, toggleStatus]);
|
||||
const toggleQuery = useCallback(
|
||||
(status: boolean) => {
|
||||
setToggleStatus(status);
|
||||
// toggle on = skipQuery false
|
||||
setQuerySkip(!status);
|
||||
},
|
||||
[setQuerySkip, setToggleStatus]
|
||||
);
|
||||
|
||||
const [loading, tableData] = useAnomaliesTableData({
|
||||
startDate,
|
||||
endDate,
|
||||
skip,
|
||||
skip: querySkip,
|
||||
criteriaFields: getCriteriaFromUsersType(type, userName),
|
||||
filterQuery: {
|
||||
exists: { field: 'user.name' },
|
||||
|
@ -67,21 +82,27 @@ const AnomaliesUserTableComponent: React.FC<AnomaliesUserTableProps> = ({
|
|||
return (
|
||||
<Panel loading={loading} data-test-subj="user-anomalies-tab">
|
||||
<HeaderSection
|
||||
height={!toggleStatus ? 40 : undefined}
|
||||
subtitle={`${i18n.SHOWING}: ${pagination.totalItemCount.toLocaleString()} ${i18n.UNIT(
|
||||
pagination.totalItemCount
|
||||
)}`}
|
||||
title={i18n.ANOMALIES}
|
||||
toggleQuery={toggleQuery}
|
||||
toggleStatus={toggleStatus}
|
||||
tooltip={i18n.TOOLTIP}
|
||||
isInspectDisabled={skip}
|
||||
/>
|
||||
|
||||
<BasicTable
|
||||
// @ts-expect-error the Columns<T, U> type is not as specific as EUI's...
|
||||
columns={columns}
|
||||
items={users}
|
||||
pagination={pagination}
|
||||
sorting={sorting}
|
||||
/>
|
||||
{toggleStatus && (
|
||||
<BasicTable
|
||||
data-test-subj="user-anomalies-table"
|
||||
// @ts-expect-error the Columns<T, U> type is not as specific as EUI's...
|
||||
columns={columns}
|
||||
items={users}
|
||||
pagination={pagination}
|
||||
sorting={sorting}
|
||||
/>
|
||||
)}
|
||||
|
||||
{loading && (
|
||||
<Loader data-test-subj="anomalies-host-table-loading-panel" overlay size="xl" />
|
||||
|
|
|
@ -11,6 +11,8 @@ exports[`Paginated Table Component rendering it renders the default load more ta
|
|||
<HeaderSectionComponent
|
||||
subtitle="Showing: 1 Test Unit"
|
||||
title="Hosts"
|
||||
toggleQuery={[Function]}
|
||||
toggleStatus={true}
|
||||
tooltip="My test tooltip"
|
||||
>
|
||||
<p>
|
||||
|
@ -58,6 +60,7 @@ exports[`Paginated Table Component rendering it renders the default load more ta
|
|||
},
|
||||
]
|
||||
}
|
||||
data-test-subj="paginated-basic-table"
|
||||
items={
|
||||
Array [
|
||||
Object {
|
||||
|
|
|
@ -15,6 +15,8 @@ import { getHostsColumns, mockData, rowItems, sortedHosts } from './index.mock';
|
|||
import { ThemeProvider } from 'styled-components';
|
||||
import { getMockTheme } from '../../lib/kibana/kibana_react.mock';
|
||||
import { Direction } from '../../../../common/search_strategy';
|
||||
import { useQueryToggle } from '../../containers/query_toggle';
|
||||
jest.mock('../../containers/query_toggle');
|
||||
|
||||
jest.mock('react', () => {
|
||||
const r = jest.requireActual('react');
|
||||
|
@ -36,37 +38,41 @@ const mockTheme = getMockTheme({
|
|||
});
|
||||
|
||||
describe('Paginated Table Component', () => {
|
||||
let loadPage: jest.Mock<number>;
|
||||
let updateLimitPagination: jest.Mock<number>;
|
||||
let updateActivePage: jest.Mock<number>;
|
||||
const loadPage = jest.fn();
|
||||
const updateLimitPagination = jest.fn();
|
||||
const updateActivePage = jest.fn();
|
||||
const mockUseQueryToggle = useQueryToggle as jest.Mock;
|
||||
const mockSetToggle = jest.fn();
|
||||
const mockSetQuerySkip = jest.fn();
|
||||
|
||||
beforeEach(() => {
|
||||
loadPage = jest.fn();
|
||||
updateLimitPagination = jest.fn();
|
||||
updateActivePage = jest.fn();
|
||||
jest.clearAllMocks();
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: true, setToggleStatus: mockSetToggle });
|
||||
});
|
||||
|
||||
const testProps = {
|
||||
activePage: 0,
|
||||
columns: getHostsColumns(),
|
||||
headerCount: 1,
|
||||
headerSupplement: <p>{'My test supplement.'}</p>,
|
||||
headerTitle: 'Hosts',
|
||||
headerTooltip: 'My test tooltip',
|
||||
headerUnit: 'Test Unit',
|
||||
itemsPerRow: rowItems,
|
||||
limit: 1,
|
||||
loading: false,
|
||||
loadPage,
|
||||
pageOfItems: mockData.Hosts.edges,
|
||||
setQuerySkip: jest.fn(),
|
||||
showMorePagesIndicator: true,
|
||||
totalCount: 10,
|
||||
updateActivePage,
|
||||
updateLimitPagination: (limit: number) => updateLimitPagination({ limit }),
|
||||
};
|
||||
|
||||
describe('rendering', () => {
|
||||
test('it renders the default load more table', () => {
|
||||
const wrapper = shallow(
|
||||
<PaginatedTable
|
||||
activePage={0}
|
||||
columns={getHostsColumns()}
|
||||
headerCount={1}
|
||||
headerSupplement={<p>{'My test supplement.'}</p>}
|
||||
headerTitle="Hosts"
|
||||
headerTooltip="My test tooltip"
|
||||
headerUnit="Test Unit"
|
||||
itemsPerRow={rowItems}
|
||||
limit={1}
|
||||
loading={false}
|
||||
loadPage={loadPage}
|
||||
pageOfItems={mockData.Hosts.edges}
|
||||
showMorePagesIndicator={true}
|
||||
totalCount={10}
|
||||
updateActivePage={updateActivePage}
|
||||
updateLimitPagination={(limit) => updateLimitPagination({ limit })}
|
||||
/>
|
||||
);
|
||||
const wrapper = shallow(<PaginatedTable {...testProps} />);
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
@ -74,24 +80,7 @@ describe('Paginated Table Component', () => {
|
|||
test('it renders the loading panel at the beginning ', () => {
|
||||
const wrapper = mount(
|
||||
<ThemeProvider theme={mockTheme}>
|
||||
<PaginatedTable
|
||||
activePage={0}
|
||||
columns={getHostsColumns()}
|
||||
headerCount={-1}
|
||||
headerSupplement={<p>{'My test supplement.'}</p>}
|
||||
headerTitle="Hosts"
|
||||
headerTooltip="My test tooltip"
|
||||
headerUnit="Test Unit"
|
||||
itemsPerRow={rowItems}
|
||||
limit={1}
|
||||
loading={true}
|
||||
loadPage={loadPage}
|
||||
pageOfItems={[]}
|
||||
showMorePagesIndicator={true}
|
||||
totalCount={10}
|
||||
updateActivePage={updateActivePage}
|
||||
updateLimitPagination={(limit) => updateLimitPagination({ limit })}
|
||||
/>
|
||||
<PaginatedTable {...testProps} headerCount={-1} loading={true} pageOfItems={[]} />
|
||||
</ThemeProvider>
|
||||
);
|
||||
|
||||
|
@ -103,24 +92,7 @@ describe('Paginated Table Component', () => {
|
|||
test('it renders the over loading panel after data has been in the table ', () => {
|
||||
const wrapper = mount(
|
||||
<ThemeProvider theme={mockTheme}>
|
||||
<PaginatedTable
|
||||
activePage={0}
|
||||
columns={getHostsColumns()}
|
||||
headerCount={1}
|
||||
headerSupplement={<p>{'My test supplement.'}</p>}
|
||||
headerTitle="Hosts"
|
||||
headerTooltip="My test tooltip"
|
||||
headerUnit="Test Unit"
|
||||
itemsPerRow={rowItems}
|
||||
limit={1}
|
||||
loading={true}
|
||||
loadPage={loadPage}
|
||||
pageOfItems={mockData.Hosts.edges}
|
||||
showMorePagesIndicator={true}
|
||||
totalCount={10}
|
||||
updateActivePage={updateActivePage}
|
||||
updateLimitPagination={(limit) => updateLimitPagination({ limit })}
|
||||
/>
|
||||
<PaginatedTable {...testProps} loading={true} />
|
||||
</ThemeProvider>
|
||||
);
|
||||
|
||||
|
@ -130,24 +102,7 @@ describe('Paginated Table Component', () => {
|
|||
test('it renders the correct amount of pages and starts at activePage: 0', () => {
|
||||
const wrapper = mount(
|
||||
<ThemeProvider theme={mockTheme}>
|
||||
<PaginatedTable
|
||||
activePage={0}
|
||||
columns={getHostsColumns()}
|
||||
headerCount={1}
|
||||
headerSupplement={<p>{'My test supplement.'}</p>}
|
||||
headerTitle="Hosts"
|
||||
headerTooltip="My test tooltip"
|
||||
headerUnit="Test Unit"
|
||||
itemsPerRow={rowItems}
|
||||
limit={1}
|
||||
loading={false}
|
||||
loadPage={loadPage}
|
||||
pageOfItems={mockData.Hosts.edges}
|
||||
showMorePagesIndicator={true}
|
||||
totalCount={10}
|
||||
updateActivePage={updateActivePage}
|
||||
updateLimitPagination={(limit) => updateLimitPagination({ limit })}
|
||||
/>
|
||||
<PaginatedTable {...testProps} />
|
||||
</ThemeProvider>
|
||||
);
|
||||
|
||||
|
@ -167,24 +122,7 @@ describe('Paginated Table Component', () => {
|
|||
test('it render popover to select new limit in table', () => {
|
||||
const wrapper = mount(
|
||||
<ThemeProvider theme={mockTheme}>
|
||||
<PaginatedTable
|
||||
activePage={0}
|
||||
columns={getHostsColumns()}
|
||||
headerCount={1}
|
||||
headerSupplement={<p>{'My test supplement.'}</p>}
|
||||
headerTitle="Hosts"
|
||||
headerTooltip="My test tooltip"
|
||||
headerUnit="Test Unit"
|
||||
itemsPerRow={rowItems}
|
||||
limit={2}
|
||||
loading={false}
|
||||
loadPage={loadPage}
|
||||
pageOfItems={mockData.Hosts.edges}
|
||||
showMorePagesIndicator={true}
|
||||
totalCount={10}
|
||||
updateActivePage={updateActivePage}
|
||||
updateLimitPagination={(limit) => updateLimitPagination({ limit })}
|
||||
/>
|
||||
<PaginatedTable {...testProps} limit={2} />
|
||||
</ThemeProvider>
|
||||
);
|
||||
|
||||
|
@ -195,24 +133,7 @@ describe('Paginated Table Component', () => {
|
|||
test('it will NOT render popover to select new limit in table if props itemsPerRow is empty', () => {
|
||||
const wrapper = mount(
|
||||
<ThemeProvider theme={mockTheme}>
|
||||
<PaginatedTable
|
||||
activePage={0}
|
||||
columns={getHostsColumns()}
|
||||
headerCount={1}
|
||||
headerSupplement={<p>{'My test supplement.'}</p>}
|
||||
headerTitle="Hosts"
|
||||
headerTooltip="My test tooltip"
|
||||
headerUnit="Test Unit"
|
||||
itemsPerRow={[]}
|
||||
limit={2}
|
||||
loading={false}
|
||||
loadPage={loadPage}
|
||||
pageOfItems={mockData.Hosts.edges}
|
||||
showMorePagesIndicator={true}
|
||||
totalCount={10}
|
||||
updateActivePage={updateActivePage}
|
||||
updateLimitPagination={(limit) => updateLimitPagination({ limit })}
|
||||
/>
|
||||
<PaginatedTable {...testProps} itemsPerRow={[]} limit={2} />
|
||||
</ThemeProvider>
|
||||
);
|
||||
|
||||
|
@ -224,24 +145,11 @@ describe('Paginated Table Component', () => {
|
|||
const wrapper = mount(
|
||||
<ThemeProvider theme={mockTheme}>
|
||||
<PaginatedTable
|
||||
activePage={0}
|
||||
{...testProps}
|
||||
columns={sortedHosts}
|
||||
headerCount={1}
|
||||
headerSupplement={<p>{'My test supplement.'}</p>}
|
||||
headerTitle="Hosts"
|
||||
headerTooltip="My test tooltip"
|
||||
headerUnit="Test Unit"
|
||||
itemsPerRow={rowItems}
|
||||
limit={2}
|
||||
loading={false}
|
||||
loadPage={jest.fn()}
|
||||
onChange={mockOnChange}
|
||||
pageOfItems={mockData.Hosts.edges}
|
||||
showMorePagesIndicator={true}
|
||||
sorting={{ direction: Direction.asc, field: 'node.host.name' }}
|
||||
totalCount={10}
|
||||
updateActivePage={updateActivePage}
|
||||
updateLimitPagination={(limit) => updateLimitPagination({ limit })}
|
||||
/>
|
||||
</ThemeProvider>
|
||||
);
|
||||
|
@ -253,22 +161,9 @@ describe('Paginated Table Component', () => {
|
|||
const wrapper = mount(
|
||||
<ThemeProvider theme={mockTheme}>
|
||||
<PaginatedTable
|
||||
activePage={0}
|
||||
columns={getHostsColumns()}
|
||||
headerCount={1}
|
||||
headerSupplement={<p>{'My test supplement.'}</p>}
|
||||
headerTitle="Hosts"
|
||||
headerTooltip="My test tooltip"
|
||||
headerUnit="Test Unit"
|
||||
itemsPerRow={rowItems}
|
||||
{...testProps}
|
||||
limit={DEFAULT_MAX_TABLE_QUERY_SIZE}
|
||||
loading={false}
|
||||
loadPage={loadPage}
|
||||
pageOfItems={mockData.Hosts.edges}
|
||||
showMorePagesIndicator={true}
|
||||
totalCount={DEFAULT_MAX_TABLE_QUERY_SIZE * 3}
|
||||
updateActivePage={updateActivePage}
|
||||
updateLimitPagination={(limit) => updateLimitPagination({ limit })}
|
||||
/>
|
||||
</ThemeProvider>
|
||||
);
|
||||
|
@ -279,24 +174,7 @@ describe('Paginated Table Component', () => {
|
|||
test('Should show items per row if totalCount is greater than items', () => {
|
||||
const wrapper = mount(
|
||||
<ThemeProvider theme={mockTheme}>
|
||||
<PaginatedTable
|
||||
activePage={0}
|
||||
columns={getHostsColumns()}
|
||||
headerCount={1}
|
||||
headerSupplement={<p>{'My test supplement.'}</p>}
|
||||
headerTitle="Hosts"
|
||||
headerTooltip="My test tooltip"
|
||||
headerUnit="Test Unit"
|
||||
itemsPerRow={rowItems}
|
||||
limit={DEFAULT_MAX_TABLE_QUERY_SIZE}
|
||||
loading={false}
|
||||
loadPage={loadPage}
|
||||
pageOfItems={mockData.Hosts.edges}
|
||||
showMorePagesIndicator={true}
|
||||
totalCount={30}
|
||||
updateActivePage={updateActivePage}
|
||||
updateLimitPagination={(limit) => updateLimitPagination({ limit })}
|
||||
/>
|
||||
<PaginatedTable {...testProps} limit={DEFAULT_MAX_TABLE_QUERY_SIZE} totalCount={30} />
|
||||
</ThemeProvider>
|
||||
);
|
||||
expect(wrapper.find('[data-test-subj="loadingMoreSizeRowPopover"]').exists()).toBeTruthy();
|
||||
|
@ -305,24 +183,7 @@ describe('Paginated Table Component', () => {
|
|||
test('Should hide items per row if totalCount is less than items', () => {
|
||||
const wrapper = mount(
|
||||
<ThemeProvider theme={mockTheme}>
|
||||
<PaginatedTable
|
||||
activePage={0}
|
||||
columns={getHostsColumns()}
|
||||
headerCount={1}
|
||||
headerSupplement={<p>{'My test supplement.'}</p>}
|
||||
headerTitle="Hosts"
|
||||
headerTooltip="My test tooltip"
|
||||
headerUnit="Test Unit"
|
||||
itemsPerRow={rowItems}
|
||||
limit={DEFAULT_MAX_TABLE_QUERY_SIZE}
|
||||
loading={false}
|
||||
loadPage={loadPage}
|
||||
pageOfItems={mockData.Hosts.edges}
|
||||
showMorePagesIndicator={true}
|
||||
totalCount={1}
|
||||
updateActivePage={updateActivePage}
|
||||
updateLimitPagination={(limit) => updateLimitPagination({ limit })}
|
||||
/>
|
||||
<PaginatedTable {...testProps} limit={DEFAULT_MAX_TABLE_QUERY_SIZE} totalCount={1} />
|
||||
</ThemeProvider>
|
||||
);
|
||||
expect(wrapper.find('[data-test-subj="loadingMoreSizeRowPopover"]').exists()).toBeFalsy();
|
||||
|
@ -331,24 +192,7 @@ describe('Paginated Table Component', () => {
|
|||
test('Should hide pagination if totalCount is zero', () => {
|
||||
const wrapper = mount(
|
||||
<ThemeProvider theme={mockTheme}>
|
||||
<PaginatedTable
|
||||
activePage={0}
|
||||
columns={getHostsColumns()}
|
||||
headerCount={1}
|
||||
headerSupplement={<p>{'My test supplement.'}</p>}
|
||||
headerTitle="Hosts"
|
||||
headerTooltip="My test tooltip"
|
||||
headerUnit="Test Unit"
|
||||
itemsPerRow={rowItems}
|
||||
limit={DEFAULT_MAX_TABLE_QUERY_SIZE}
|
||||
loading={false}
|
||||
loadPage={loadPage}
|
||||
pageOfItems={mockData.Hosts.edges}
|
||||
showMorePagesIndicator={true}
|
||||
totalCount={0}
|
||||
updateActivePage={updateActivePage}
|
||||
updateLimitPagination={(limit) => updateLimitPagination({ limit })}
|
||||
/>
|
||||
<PaginatedTable {...testProps} limit={DEFAULT_MAX_TABLE_QUERY_SIZE} totalCount={0} />
|
||||
</ThemeProvider>
|
||||
);
|
||||
|
||||
|
@ -360,24 +204,7 @@ describe('Paginated Table Component', () => {
|
|||
test('should call updateActivePage with 1 when clicking to the first page', () => {
|
||||
const wrapper = mount(
|
||||
<ThemeProvider theme={mockTheme}>
|
||||
<PaginatedTable
|
||||
activePage={0}
|
||||
columns={getHostsColumns()}
|
||||
headerCount={1}
|
||||
headerSupplement={<p>{'My test supplement.'}</p>}
|
||||
headerTitle="Hosts"
|
||||
headerTooltip="My test tooltip"
|
||||
headerUnit="Test Unit"
|
||||
itemsPerRow={rowItems}
|
||||
limit={1}
|
||||
loading={false}
|
||||
loadPage={loadPage}
|
||||
pageOfItems={mockData.Hosts.edges}
|
||||
showMorePagesIndicator={true}
|
||||
totalCount={10}
|
||||
updateActivePage={updateActivePage}
|
||||
updateLimitPagination={(limit) => updateLimitPagination({ limit })}
|
||||
/>
|
||||
<PaginatedTable {...testProps} />
|
||||
</ThemeProvider>
|
||||
);
|
||||
wrapper.find('[data-test-subj="pagination-button-next"]').first().simulate('click');
|
||||
|
@ -387,24 +214,7 @@ describe('Paginated Table Component', () => {
|
|||
test('Should call updateActivePage with 0 when you pick a new limit', () => {
|
||||
const wrapper = mount(
|
||||
<ThemeProvider theme={mockTheme}>
|
||||
<PaginatedTable
|
||||
activePage={0}
|
||||
columns={getHostsColumns()}
|
||||
headerCount={1}
|
||||
headerSupplement={<p>{'My test supplement.'}</p>}
|
||||
headerTitle="Hosts"
|
||||
headerTooltip="My test tooltip"
|
||||
headerUnit="Test Unit"
|
||||
itemsPerRow={rowItems}
|
||||
limit={2}
|
||||
loading={false}
|
||||
loadPage={loadPage}
|
||||
pageOfItems={mockData.Hosts.edges}
|
||||
showMorePagesIndicator={true}
|
||||
totalCount={10}
|
||||
updateActivePage={updateActivePage}
|
||||
updateLimitPagination={(limit) => updateLimitPagination({ limit })}
|
||||
/>
|
||||
<PaginatedTable {...testProps} limit={2} />
|
||||
</ThemeProvider>
|
||||
);
|
||||
wrapper.find('[data-test-subj="pagination-button-next"]').first().simulate('click');
|
||||
|
@ -417,22 +227,8 @@ describe('Paginated Table Component', () => {
|
|||
|
||||
test('should update the page when the activePage is changed from redux', () => {
|
||||
const ourProps: BasicTableProps<unknown> = {
|
||||
...testProps,
|
||||
activePage: 3,
|
||||
columns: getHostsColumns(),
|
||||
headerCount: 1,
|
||||
headerSupplement: <p>{'My test supplement.'}</p>,
|
||||
headerTitle: 'Hosts',
|
||||
headerTooltip: 'My test tooltip',
|
||||
headerUnit: 'Test Unit',
|
||||
itemsPerRow: rowItems,
|
||||
limit: 1,
|
||||
loading: false,
|
||||
loadPage,
|
||||
pageOfItems: mockData.Hosts.edges,
|
||||
showMorePagesIndicator: true,
|
||||
totalCount: 10,
|
||||
updateActivePage,
|
||||
updateLimitPagination: (limit) => updateLimitPagination({ limit }),
|
||||
};
|
||||
|
||||
// enzyme does not allow us to pass props to child of HOC
|
||||
|
@ -462,24 +258,7 @@ describe('Paginated Table Component', () => {
|
|||
test('Should call updateLimitPagination when you pick a new limit', () => {
|
||||
const wrapper = mount(
|
||||
<ThemeProvider theme={mockTheme}>
|
||||
<PaginatedTable
|
||||
activePage={0}
|
||||
columns={getHostsColumns()}
|
||||
headerCount={1}
|
||||
headerSupplement={<p>{'My test supplement.'}</p>}
|
||||
headerTitle="Hosts"
|
||||
headerTooltip="My test tooltip"
|
||||
headerUnit="Test Unit"
|
||||
itemsPerRow={rowItems}
|
||||
limit={2}
|
||||
loading={false}
|
||||
loadPage={loadPage}
|
||||
pageOfItems={mockData.Hosts.edges}
|
||||
showMorePagesIndicator={true}
|
||||
totalCount={10}
|
||||
updateActivePage={updateActivePage}
|
||||
updateLimitPagination={(limit) => updateLimitPagination({ limit })}
|
||||
/>
|
||||
<PaginatedTable {...testProps} limit={2} />
|
||||
</ThemeProvider>
|
||||
);
|
||||
|
||||
|
@ -494,24 +273,11 @@ describe('Paginated Table Component', () => {
|
|||
const wrapper = mount(
|
||||
<ThemeProvider theme={mockTheme}>
|
||||
<PaginatedTable
|
||||
activePage={0}
|
||||
{...testProps}
|
||||
columns={sortedHosts}
|
||||
headerCount={1}
|
||||
headerSupplement={<p>{'My test supplement.'}</p>}
|
||||
headerTitle="Hosts"
|
||||
headerTooltip="My test tooltip"
|
||||
headerUnit="Test Unit"
|
||||
itemsPerRow={rowItems}
|
||||
limit={2}
|
||||
loading={false}
|
||||
loadPage={jest.fn()}
|
||||
onChange={mockOnChange}
|
||||
pageOfItems={mockData.Hosts.edges}
|
||||
showMorePagesIndicator={true}
|
||||
sorting={{ direction: Direction.asc, field: 'node.host.name' }}
|
||||
totalCount={10}
|
||||
updateActivePage={updateActivePage}
|
||||
updateLimitPagination={(limit) => updateLimitPagination({ limit })}
|
||||
/>
|
||||
</ThemeProvider>
|
||||
);
|
||||
|
@ -524,4 +290,41 @@ describe('Paginated Table Component', () => {
|
|||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Toggle query', () => {
|
||||
test('toggleQuery updates toggleStatus', () => {
|
||||
const wrapper = mount(
|
||||
<ThemeProvider theme={mockTheme}>
|
||||
<PaginatedTable {...testProps} setQuerySkip={mockSetQuerySkip} />
|
||||
</ThemeProvider>
|
||||
);
|
||||
wrapper.find('[data-test-subj="query-toggle-header"]').first().simulate('click');
|
||||
expect(mockSetToggle).toBeCalledWith(false);
|
||||
expect(mockSetQuerySkip).toBeCalledWith(true);
|
||||
});
|
||||
|
||||
test('toggleStatus=true, render table', () => {
|
||||
const wrapper = mount(
|
||||
<ThemeProvider theme={mockTheme}>
|
||||
<PaginatedTable {...testProps} />
|
||||
</ThemeProvider>
|
||||
);
|
||||
expect(wrapper.find('[data-test-subj="paginated-basic-table"]').first().exists()).toEqual(
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
test('toggleStatus=false, hide table', () => {
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: false, setToggleStatus: mockSetToggle });
|
||||
|
||||
const wrapper = mount(
|
||||
<ThemeProvider theme={mockTheme}>
|
||||
<PaginatedTable {...testProps} />
|
||||
</ThemeProvider>
|
||||
);
|
||||
expect(wrapper.find('[data-test-subj="paginated-basic-table"]').first().exists()).toEqual(
|
||||
false
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -20,7 +20,7 @@ import {
|
|||
EuiTableRowCellProps,
|
||||
} from '@elastic/eui';
|
||||
import { noop } from 'lodash/fp';
|
||||
import React, { FC, memo, useState, useMemo, useEffect, ComponentType } from 'react';
|
||||
import React, { FC, memo, useState, useMemo, useEffect, ComponentType, useCallback } from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { Direction } from '../../../../common/search_strategy';
|
||||
|
@ -49,6 +49,7 @@ import { useStateToaster } from '../toasters';
|
|||
import * as i18n from './translations';
|
||||
import { Panel } from '../panel';
|
||||
import { InspectButtonContainer } from '../inspect';
|
||||
import { useQueryToggle } from '../../containers/query_toggle';
|
||||
|
||||
const DEFAULT_DATA_TEST_SUBJ = 'paginated-table';
|
||||
|
||||
|
@ -113,6 +114,7 @@ export interface BasicTableProps<T> {
|
|||
onChange?: (criteria: Criteria) => void;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
pageOfItems: any[];
|
||||
setQuerySkip: (skip: boolean) => void;
|
||||
showMorePagesIndicator: boolean;
|
||||
sorting?: SortingBasicTable;
|
||||
split?: boolean;
|
||||
|
@ -153,6 +155,7 @@ const PaginatedTableComponent: FC<SiemTables> = ({
|
|||
loadPage,
|
||||
onChange = noop,
|
||||
pageOfItems,
|
||||
setQuerySkip,
|
||||
showMorePagesIndicator,
|
||||
sorting = null,
|
||||
split,
|
||||
|
@ -253,10 +256,24 @@ const PaginatedTableComponent: FC<SiemTables> = ({
|
|||
[sorting]
|
||||
);
|
||||
|
||||
const { toggleStatus, setToggleStatus } = useQueryToggle(id);
|
||||
|
||||
const toggleQuery = useCallback(
|
||||
(status: boolean) => {
|
||||
setToggleStatus(status);
|
||||
// toggle on = skipQuery false
|
||||
setQuerySkip(!status);
|
||||
},
|
||||
[setQuerySkip, setToggleStatus]
|
||||
);
|
||||
|
||||
return (
|
||||
<InspectButtonContainer show={!loadingInitial}>
|
||||
<Panel data-test-subj={`${dataTestSubj}-loading-${loading}`} loading={loading}>
|
||||
<HeaderSection
|
||||
height={!toggleStatus ? 40 : undefined}
|
||||
toggleStatus={toggleStatus}
|
||||
toggleQuery={toggleQuery}
|
||||
headerFilters={headerFilters}
|
||||
id={id}
|
||||
split={split}
|
||||
|
@ -274,50 +291,56 @@ const PaginatedTableComponent: FC<SiemTables> = ({
|
|||
>
|
||||
{!loadingInitial && headerSupplement}
|
||||
</HeaderSection>
|
||||
{toggleStatus &&
|
||||
(loadingInitial ? (
|
||||
<EuiLoadingContent data-test-subj="initialLoadingPanelPaginatedTable" lines={10} />
|
||||
) : (
|
||||
<>
|
||||
<BasicTable
|
||||
data-test-subj="paginated-basic-table"
|
||||
columns={columns}
|
||||
items={pageOfItems}
|
||||
onChange={onChange}
|
||||
sorting={tableSorting}
|
||||
/>
|
||||
<FooterAction>
|
||||
<EuiFlexItem>
|
||||
{itemsPerRow &&
|
||||
itemsPerRow.length > 0 &&
|
||||
totalCount >= itemsPerRow[0].numberOfRow && (
|
||||
<EuiPopover
|
||||
id="customizablePagination"
|
||||
data-test-subj="loadingMoreSizeRowPopover"
|
||||
button={button}
|
||||
isOpen={isPopoverOpen}
|
||||
closePopover={closePopover}
|
||||
panelPaddingSize="none"
|
||||
repositionOnScroll
|
||||
>
|
||||
<EuiContextMenuPanel
|
||||
items={rowItems}
|
||||
data-test-subj="loadingMorePickSizeRow"
|
||||
/>
|
||||
</EuiPopover>
|
||||
)}
|
||||
</EuiFlexItem>
|
||||
|
||||
{loadingInitial ? (
|
||||
<EuiLoadingContent data-test-subj="initialLoadingPanelPaginatedTable" lines={10} />
|
||||
) : (
|
||||
<>
|
||||
<BasicTable
|
||||
columns={columns}
|
||||
items={pageOfItems}
|
||||
onChange={onChange}
|
||||
sorting={tableSorting}
|
||||
/>
|
||||
<FooterAction>
|
||||
<EuiFlexItem>
|
||||
{itemsPerRow && itemsPerRow.length > 0 && totalCount >= itemsPerRow[0].numberOfRow && (
|
||||
<EuiPopover
|
||||
id="customizablePagination"
|
||||
data-test-subj="loadingMoreSizeRowPopover"
|
||||
button={button}
|
||||
isOpen={isPopoverOpen}
|
||||
closePopover={closePopover}
|
||||
panelPaddingSize="none"
|
||||
repositionOnScroll
|
||||
>
|
||||
<EuiContextMenuPanel items={rowItems} data-test-subj="loadingMorePickSizeRow" />
|
||||
</EuiPopover>
|
||||
)}
|
||||
</EuiFlexItem>
|
||||
|
||||
<PaginationWrapper grow={false}>
|
||||
{totalCount > 0 && (
|
||||
<EuiPagination
|
||||
data-test-subj="numberedPagination"
|
||||
pageCount={pageCount}
|
||||
activePage={myActivePage}
|
||||
onPageClick={goToPage}
|
||||
/>
|
||||
)}
|
||||
</PaginationWrapper>
|
||||
</FooterAction>
|
||||
{(isInspect || myLoading) && (
|
||||
<Loader data-test-subj="loadingPanelPaginatedTable" overlay size="xl" />
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<PaginationWrapper grow={false}>
|
||||
{totalCount > 0 && (
|
||||
<EuiPagination
|
||||
data-test-subj="numberedPagination"
|
||||
pageCount={pageCount}
|
||||
activePage={myActivePage}
|
||||
onPageClick={goToPage}
|
||||
/>
|
||||
)}
|
||||
</PaginationWrapper>
|
||||
</FooterAction>
|
||||
{(isInspect || myLoading) && (
|
||||
<Loader data-test-subj="loadingPanelPaginatedTable" overlay size="xl" />
|
||||
)}
|
||||
</>
|
||||
))}
|
||||
</Panel>
|
||||
</InspectButtonContainer>
|
||||
);
|
||||
|
|
|
@ -41,6 +41,7 @@ import {
|
|||
NetworkKpiStrategyResponse,
|
||||
} from '../../../../common/search_strategy';
|
||||
import { getMockTheme } from '../../lib/kibana/kibana_react.mock';
|
||||
import * as module from '../../containers/query_toggle';
|
||||
|
||||
const from = '2019-06-15T06:00:00.000Z';
|
||||
const to = '2019-06-18T06:00:00.000Z';
|
||||
|
@ -53,26 +54,37 @@ jest.mock('../charts/barchart', () => {
|
|||
return { BarChart: () => <div className="barchart" /> };
|
||||
});
|
||||
|
||||
const mockSetToggle = jest.fn();
|
||||
|
||||
jest
|
||||
.spyOn(module, 'useQueryToggle')
|
||||
.mockImplementation(() => ({ toggleStatus: true, setToggleStatus: mockSetToggle }));
|
||||
const mockSetQuerySkip = jest.fn();
|
||||
describe('Stat Items Component', () => {
|
||||
const mockTheme = getMockTheme({ eui: { euiColorMediumShade: '#ece' } });
|
||||
const state: State = mockGlobalState;
|
||||
const { storage } = createSecuritySolutionStorageMock();
|
||||
const store = createStore(state, SUB_PLUGINS_REDUCER, kibanaObservable, storage);
|
||||
|
||||
const testProps = {
|
||||
description: 'HOSTS',
|
||||
fields: [{ key: 'hosts', value: null, color: '#6092C0', icon: 'cross' }],
|
||||
from,
|
||||
id: 'statItems',
|
||||
key: 'mock-keys',
|
||||
loading: false,
|
||||
setQuerySkip: mockSetQuerySkip,
|
||||
to,
|
||||
narrowDateRange: mockNarrowDateRange,
|
||||
};
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
describe.each([
|
||||
[
|
||||
mount(
|
||||
<ThemeProvider theme={mockTheme}>
|
||||
<ReduxStoreProvider store={store}>
|
||||
<StatItemsComponent
|
||||
description="HOSTS"
|
||||
fields={[{ key: 'hosts', value: null, color: '#6092C0', icon: 'cross' }]}
|
||||
from={from}
|
||||
id="statItems"
|
||||
key="mock-keys"
|
||||
to={to}
|
||||
narrowDateRange={mockNarrowDateRange}
|
||||
/>
|
||||
<StatItemsComponent {...testProps} />
|
||||
</ReduxStoreProvider>
|
||||
</ThemeProvider>
|
||||
),
|
||||
|
@ -81,17 +93,7 @@ describe('Stat Items Component', () => {
|
|||
mount(
|
||||
<ThemeProvider theme={mockTheme}>
|
||||
<ReduxStoreProvider store={store}>
|
||||
<StatItemsComponent
|
||||
areaChart={[]}
|
||||
barChart={[]}
|
||||
description="HOSTS"
|
||||
fields={[{ key: 'hosts', value: null, color: '#6092C0', icon: 'cross' }]}
|
||||
from={from}
|
||||
id="statItems"
|
||||
key="mock-keys"
|
||||
to={to}
|
||||
narrowDateRange={mockNarrowDateRange}
|
||||
/>
|
||||
<StatItemsComponent areaChart={[]} barChart={[]} {...testProps} />
|
||||
</ReduxStoreProvider>
|
||||
</ThemeProvider>
|
||||
),
|
||||
|
@ -118,62 +120,59 @@ describe('Stat Items Component', () => {
|
|||
});
|
||||
});
|
||||
|
||||
const mockStatItemsData: StatItemsProps = {
|
||||
...testProps,
|
||||
areaChart: [
|
||||
{
|
||||
key: 'uniqueSourceIpsHistogram',
|
||||
value: [
|
||||
{ x: new Date('2019-05-03T13:00:00.000Z').toISOString(), y: 565975 },
|
||||
{ x: new Date('2019-05-04T01:00:00.000Z').toISOString(), y: 1084366 },
|
||||
{ x: new Date('2019-05-04T13:00:00.000Z').toISOString(), y: 12280 },
|
||||
],
|
||||
color: '#D36086',
|
||||
},
|
||||
{
|
||||
key: 'uniqueDestinationIpsHistogram',
|
||||
value: [
|
||||
{ x: new Date('2019-05-03T13:00:00.000Z').toISOString(), y: 565975 },
|
||||
{ x: new Date('2019-05-04T01:00:00.000Z').toISOString(), y: 1084366 },
|
||||
{ x: new Date('2019-05-04T13:00:00.000Z').toISOString(), y: 12280 },
|
||||
],
|
||||
color: '#9170B8',
|
||||
},
|
||||
],
|
||||
barChart: [
|
||||
{ key: 'uniqueSourceIps', value: [{ x: 'uniqueSourceIps', y: '1714' }], color: '#D36086' },
|
||||
{
|
||||
key: 'uniqueDestinationIps',
|
||||
value: [{ x: 'uniqueDestinationIps', y: 2354 }],
|
||||
color: '#9170B8',
|
||||
},
|
||||
],
|
||||
description: 'UNIQUE_PRIVATE_IPS',
|
||||
enableAreaChart: true,
|
||||
enableBarChart: true,
|
||||
fields: [
|
||||
{
|
||||
key: 'uniqueSourceIps',
|
||||
description: 'Source',
|
||||
value: 1714,
|
||||
color: '#D36086',
|
||||
icon: 'cross',
|
||||
},
|
||||
{
|
||||
key: 'uniqueDestinationIps',
|
||||
description: 'Dest.',
|
||||
value: 2359,
|
||||
color: '#9170B8',
|
||||
icon: 'cross',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
let wrapper: ReactWrapper;
|
||||
describe('rendering kpis with charts', () => {
|
||||
const mockStatItemsData: StatItemsProps = {
|
||||
areaChart: [
|
||||
{
|
||||
key: 'uniqueSourceIpsHistogram',
|
||||
value: [
|
||||
{ x: new Date('2019-05-03T13:00:00.000Z').toISOString(), y: 565975 },
|
||||
{ x: new Date('2019-05-04T01:00:00.000Z').toISOString(), y: 1084366 },
|
||||
{ x: new Date('2019-05-04T13:00:00.000Z').toISOString(), y: 12280 },
|
||||
],
|
||||
color: '#D36086',
|
||||
},
|
||||
{
|
||||
key: 'uniqueDestinationIpsHistogram',
|
||||
value: [
|
||||
{ x: new Date('2019-05-03T13:00:00.000Z').toISOString(), y: 565975 },
|
||||
{ x: new Date('2019-05-04T01:00:00.000Z').toISOString(), y: 1084366 },
|
||||
{ x: new Date('2019-05-04T13:00:00.000Z').toISOString(), y: 12280 },
|
||||
],
|
||||
color: '#9170B8',
|
||||
},
|
||||
],
|
||||
barChart: [
|
||||
{ key: 'uniqueSourceIps', value: [{ x: 'uniqueSourceIps', y: '1714' }], color: '#D36086' },
|
||||
{
|
||||
key: 'uniqueDestinationIps',
|
||||
value: [{ x: 'uniqueDestinationIps', y: 2354 }],
|
||||
color: '#9170B8',
|
||||
},
|
||||
],
|
||||
description: 'UNIQUE_PRIVATE_IPS',
|
||||
enableAreaChart: true,
|
||||
enableBarChart: true,
|
||||
fields: [
|
||||
{
|
||||
key: 'uniqueSourceIps',
|
||||
description: 'Source',
|
||||
value: 1714,
|
||||
color: '#D36086',
|
||||
icon: 'cross',
|
||||
},
|
||||
{
|
||||
key: 'uniqueDestinationIps',
|
||||
description: 'Dest.',
|
||||
value: 2359,
|
||||
color: '#9170B8',
|
||||
icon: 'cross',
|
||||
},
|
||||
],
|
||||
from,
|
||||
id: 'statItems',
|
||||
key: 'mock-keys',
|
||||
to,
|
||||
narrowDateRange: mockNarrowDateRange,
|
||||
};
|
||||
let wrapper: ReactWrapper;
|
||||
beforeAll(() => {
|
||||
wrapper = mount(
|
||||
<ReduxStoreProvider store={store}>
|
||||
|
@ -202,6 +201,43 @@ describe('Stat Items Component', () => {
|
|||
expect(wrapper.find(EuiHorizontalRule)).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
describe('Toggle query', () => {
|
||||
test('toggleQuery updates toggleStatus', () => {
|
||||
wrapper = mount(
|
||||
<ReduxStoreProvider store={store}>
|
||||
<StatItemsComponent {...mockStatItemsData} />
|
||||
</ReduxStoreProvider>
|
||||
);
|
||||
wrapper.find('[data-test-subj="query-toggle-stat"]').first().simulate('click');
|
||||
expect(mockSetToggle).toBeCalledWith(false);
|
||||
expect(mockSetQuerySkip).toBeCalledWith(true);
|
||||
});
|
||||
test('toggleStatus=true, render all', () => {
|
||||
wrapper = mount(
|
||||
<ReduxStoreProvider store={store}>
|
||||
<StatItemsComponent {...mockStatItemsData} />
|
||||
</ReduxStoreProvider>
|
||||
);
|
||||
|
||||
expect(wrapper.find('[data-test-subj="inspect-icon-button"]').first().exists()).toEqual(true);
|
||||
expect(wrapper.find('[data-test-subj="stat-title"]').first().exists()).toEqual(true);
|
||||
});
|
||||
test('toggleStatus=false, render none', () => {
|
||||
jest
|
||||
.spyOn(module, 'useQueryToggle')
|
||||
.mockImplementation(() => ({ toggleStatus: false, setToggleStatus: mockSetToggle }));
|
||||
wrapper = mount(
|
||||
<ReduxStoreProvider store={store}>
|
||||
<StatItemsComponent {...mockStatItemsData} />
|
||||
</ReduxStoreProvider>
|
||||
);
|
||||
|
||||
expect(wrapper.find('[data-test-subj="inspect-icon-button"]').first().exists()).toEqual(
|
||||
false
|
||||
);
|
||||
expect(wrapper.find('[data-test-subj="stat-title"]').first().exists()).toEqual(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('addValueToFields', () => {
|
||||
|
@ -244,7 +280,9 @@ describe('useKpiMatrixStatus', () => {
|
|||
'statItem',
|
||||
from,
|
||||
to,
|
||||
mockNarrowDateRange
|
||||
mockNarrowDateRange,
|
||||
mockSetQuerySkip,
|
||||
false
|
||||
);
|
||||
|
||||
return (
|
||||
|
@ -262,8 +300,10 @@ describe('useKpiMatrixStatus', () => {
|
|||
<MockHookWrapperComponent fieldsMapping={mockNetworkMappings} data={mockData} />
|
||||
</>
|
||||
);
|
||||
|
||||
expect(wrapper.find('MockChildComponent').get(0).props).toEqual(mockEnableChartsData);
|
||||
const result = { ...wrapper.find('MockChildComponent').get(0).props };
|
||||
const { setQuerySkip, ...restResult } = result;
|
||||
const { setQuerySkip: a, ...restExpect } = mockEnableChartsData;
|
||||
expect(restResult).toEqual(restExpect);
|
||||
});
|
||||
|
||||
test('it should not append areaChart if enableAreaChart is off', () => {
|
||||
|
|
|
@ -12,13 +12,16 @@ import {
|
|||
EuiPanel,
|
||||
EuiHorizontalRule,
|
||||
EuiIcon,
|
||||
EuiButtonIcon,
|
||||
EuiLoadingSpinner,
|
||||
EuiTitle,
|
||||
IconType,
|
||||
} from '@elastic/eui';
|
||||
import { get, getOr } from 'lodash/fp';
|
||||
import React, { useState, useEffect, useMemo } from 'react';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import deepEqual from 'fast-deep-equal';
|
||||
import { useQueryToggle } from '../../containers/query_toggle';
|
||||
|
||||
import {
|
||||
HostsKpiStrategyResponse,
|
||||
|
@ -34,6 +37,7 @@ import { InspectButton } from '../inspect';
|
|||
import { VisualizationActions, HISTOGRAM_ACTIONS_BUTTON_CLASS } from '../visualization_actions';
|
||||
import { HoverVisibilityContainer } from '../hover_visibility_container';
|
||||
import { LensAttributes } from '../visualization_actions/types';
|
||||
import * as i18n from '../../containers/query_toggle/translations';
|
||||
import { UserskKpiStrategyResponse } from '../../../../common/search_strategy/security_solution/users';
|
||||
|
||||
const FlexItem = styled(EuiFlexItem)`
|
||||
|
@ -84,6 +88,8 @@ export interface StatItemsProps extends StatItems {
|
|||
narrowDateRange: UpdateDateRange;
|
||||
to: string;
|
||||
showInspectButton?: boolean;
|
||||
loading: boolean;
|
||||
setQuerySkip: (skip: boolean) => void;
|
||||
}
|
||||
|
||||
export const numberFormatter = (value: string | number): string => value.toLocaleString();
|
||||
|
@ -176,33 +182,27 @@ export const useKpiMatrixStatus = (
|
|||
id: string,
|
||||
from: string,
|
||||
to: string,
|
||||
narrowDateRange: UpdateDateRange
|
||||
): StatItemsProps[] => {
|
||||
const [statItemsProps, setStatItemsProps] = useState(mappings as StatItemsProps[]);
|
||||
|
||||
useEffect(() => {
|
||||
setStatItemsProps(
|
||||
mappings.map((stat) => {
|
||||
return {
|
||||
...stat,
|
||||
areaChart: stat.enableAreaChart ? addValueToAreaChart(stat.fields, data) : undefined,
|
||||
barChart: stat.enableBarChart ? addValueToBarChart(stat.fields, data) : undefined,
|
||||
fields: addValueToFields(stat.fields, data),
|
||||
id,
|
||||
key: `kpi-summary-${stat.key}`,
|
||||
statKey: `${stat.key}`,
|
||||
from,
|
||||
to,
|
||||
narrowDateRange,
|
||||
};
|
||||
})
|
||||
);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [data]);
|
||||
|
||||
return statItemsProps;
|
||||
};
|
||||
|
||||
narrowDateRange: UpdateDateRange,
|
||||
setQuerySkip: (skip: boolean) => void,
|
||||
loading: boolean
|
||||
): StatItemsProps[] =>
|
||||
mappings.map((stat) => ({
|
||||
...stat,
|
||||
areaChart: stat.enableAreaChart ? addValueToAreaChart(stat.fields, data) : undefined,
|
||||
barChart: stat.enableBarChart ? addValueToBarChart(stat.fields, data) : undefined,
|
||||
fields: addValueToFields(stat.fields, data),
|
||||
id,
|
||||
key: `kpi-summary-${stat.key}`,
|
||||
statKey: `${stat.key}`,
|
||||
from,
|
||||
to,
|
||||
narrowDateRange,
|
||||
setQuerySkip,
|
||||
loading,
|
||||
}));
|
||||
const StyledTitle = styled.h6`
|
||||
line-height: 200%;
|
||||
`;
|
||||
export const StatItemsComponent = React.memo<StatItemsProps>(
|
||||
({
|
||||
areaChart,
|
||||
|
@ -214,13 +214,15 @@ export const StatItemsComponent = React.memo<StatItemsProps>(
|
|||
from,
|
||||
grow,
|
||||
id,
|
||||
showInspectButton,
|
||||
loading = false,
|
||||
showInspectButton = true,
|
||||
index,
|
||||
narrowDateRange,
|
||||
statKey = 'item',
|
||||
to,
|
||||
barChartLensAttributes,
|
||||
areaChartLensAttributes,
|
||||
setQuerySkip,
|
||||
}) => {
|
||||
const isBarChartDataAvailable =
|
||||
barChart &&
|
||||
|
@ -239,101 +241,143 @@ export const StatItemsComponent = React.memo<StatItemsProps>(
|
|||
[from, to]
|
||||
);
|
||||
|
||||
const { toggleStatus, setToggleStatus } = useQueryToggle(id);
|
||||
|
||||
const toggleQuery = useCallback(
|
||||
(status: boolean) => {
|
||||
setToggleStatus(status);
|
||||
// toggle on = skipQuery false
|
||||
setQuerySkip(!status);
|
||||
},
|
||||
[setQuerySkip, setToggleStatus]
|
||||
);
|
||||
const toggle = useCallback(() => toggleQuery(!toggleStatus), [toggleQuery, toggleStatus]);
|
||||
|
||||
return (
|
||||
<FlexItem grow={grow} data-test-subj={`stat-${statKey}`}>
|
||||
<EuiPanel hasBorder>
|
||||
<EuiFlexGroup gutterSize={'none'}>
|
||||
<EuiFlexItem>
|
||||
<EuiTitle size="xxxs">
|
||||
<h6>{description}</h6>
|
||||
</EuiTitle>
|
||||
<EuiFlexGroup gutterSize={'none'}>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonIcon
|
||||
aria-label={i18n.QUERY_BUTTON_TITLE(toggleStatus)}
|
||||
data-test-subj="query-toggle-stat"
|
||||
color="text"
|
||||
display="empty"
|
||||
iconType={toggleStatus ? 'arrowDown' : 'arrowRight'}
|
||||
onClick={toggle}
|
||||
size="xs"
|
||||
title={i18n.QUERY_BUTTON_TITLE(toggleStatus)}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiTitle size="xxxs">
|
||||
<StyledTitle>{description}</StyledTitle>
|
||||
</EuiTitle>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
{showInspectButton && (
|
||||
{showInspectButton && toggleStatus && !loading && (
|
||||
<EuiFlexItem grow={false}>
|
||||
<InspectButton queryId={id} title={description} inspectIndex={index} />
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
</EuiFlexGroup>
|
||||
{loading && (
|
||||
<EuiFlexGroup justifyContent="center" alignItems="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiLoadingSpinner size="l" />
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
)}
|
||||
{toggleStatus && !loading && (
|
||||
<>
|
||||
<EuiFlexGroup>
|
||||
{fields.map((field) => (
|
||||
<FlexItem key={`stat-items-field-${field.key}`}>
|
||||
<EuiFlexGroup alignItems="center" gutterSize="m" responsive={false}>
|
||||
{(isAreaChartDataAvailable || isBarChartDataAvailable) && field.icon && (
|
||||
<FlexItem grow={false}>
|
||||
<EuiIcon
|
||||
type={field.icon}
|
||||
color={field.color}
|
||||
size="l"
|
||||
data-test-subj="stat-icon"
|
||||
/>
|
||||
</FlexItem>
|
||||
)}
|
||||
|
||||
<EuiFlexGroup>
|
||||
{fields.map((field) => (
|
||||
<FlexItem key={`stat-items-field-${field.key}`}>
|
||||
<EuiFlexGroup alignItems="center" gutterSize="m" responsive={false}>
|
||||
{(isAreaChartDataAvailable || isBarChartDataAvailable) && field.icon && (
|
||||
<FlexItem grow={false}>
|
||||
<EuiIcon
|
||||
type={field.icon}
|
||||
color={field.color}
|
||||
size="l"
|
||||
data-test-subj="stat-icon"
|
||||
<FlexItem>
|
||||
<HoverVisibilityContainer
|
||||
targetClassNames={[HISTOGRAM_ACTIONS_BUTTON_CLASS]}
|
||||
>
|
||||
<StatValue>
|
||||
<p data-test-subj="stat-title">
|
||||
{field.value != null
|
||||
? field.value.toLocaleString()
|
||||
: getEmptyTagValue()}{' '}
|
||||
{field.description}
|
||||
</p>
|
||||
</StatValue>
|
||||
{field.lensAttributes && timerange && (
|
||||
<VisualizationActions
|
||||
lensAttributes={field.lensAttributes}
|
||||
queryId={id}
|
||||
inspectIndex={index}
|
||||
timerange={timerange}
|
||||
title={description}
|
||||
className="viz-actions"
|
||||
/>
|
||||
)}
|
||||
</HoverVisibilityContainer>
|
||||
</FlexItem>
|
||||
</EuiFlexGroup>
|
||||
</FlexItem>
|
||||
))}
|
||||
</EuiFlexGroup>
|
||||
|
||||
{(enableAreaChart || enableBarChart) && <EuiHorizontalRule />}
|
||||
<EuiFlexGroup>
|
||||
{enableBarChart && (
|
||||
<FlexItem>
|
||||
<BarChart
|
||||
barChart={barChart}
|
||||
configs={barchartConfigs()}
|
||||
visualizationActionsOptions={{
|
||||
lensAttributes: barChartLensAttributes,
|
||||
queryId: id,
|
||||
inspectIndex: index,
|
||||
timerange,
|
||||
title: description,
|
||||
}}
|
||||
/>
|
||||
</FlexItem>
|
||||
)}
|
||||
|
||||
{enableAreaChart && from != null && to != null && (
|
||||
<>
|
||||
<FlexItem>
|
||||
<AreaChart
|
||||
areaChart={areaChart}
|
||||
configs={areachartConfigs({
|
||||
xTickFormatter: histogramDateTimeFormatter([from, to]),
|
||||
onBrushEnd: narrowDateRange,
|
||||
})}
|
||||
visualizationActionsOptions={{
|
||||
lensAttributes: areaChartLensAttributes,
|
||||
queryId: id,
|
||||
inspectIndex: index,
|
||||
timerange,
|
||||
title: description,
|
||||
}}
|
||||
/>
|
||||
</FlexItem>
|
||||
)}
|
||||
|
||||
<FlexItem>
|
||||
<HoverVisibilityContainer targetClassNames={[HISTOGRAM_ACTIONS_BUTTON_CLASS]}>
|
||||
<StatValue>
|
||||
<p data-test-subj="stat-title">
|
||||
{field.value != null ? field.value.toLocaleString() : getEmptyTagValue()}{' '}
|
||||
{field.description}
|
||||
</p>
|
||||
</StatValue>
|
||||
{field.lensAttributes && timerange && (
|
||||
<VisualizationActions
|
||||
lensAttributes={field.lensAttributes}
|
||||
queryId={id}
|
||||
inspectIndex={index}
|
||||
timerange={timerange}
|
||||
title={description}
|
||||
className="viz-actions"
|
||||
/>
|
||||
)}
|
||||
</HoverVisibilityContainer>
|
||||
</FlexItem>
|
||||
</EuiFlexGroup>
|
||||
</FlexItem>
|
||||
))}
|
||||
</EuiFlexGroup>
|
||||
|
||||
{(enableAreaChart || enableBarChart) && <EuiHorizontalRule />}
|
||||
<EuiFlexGroup>
|
||||
{enableBarChart && (
|
||||
<FlexItem>
|
||||
<BarChart
|
||||
barChart={barChart}
|
||||
configs={barchartConfigs()}
|
||||
visualizationActionsOptions={{
|
||||
lensAttributes: barChartLensAttributes,
|
||||
queryId: id,
|
||||
inspectIndex: index,
|
||||
timerange,
|
||||
title: description,
|
||||
}}
|
||||
/>
|
||||
</FlexItem>
|
||||
)}
|
||||
|
||||
{enableAreaChart && from != null && to != null && (
|
||||
<>
|
||||
<FlexItem>
|
||||
<AreaChart
|
||||
areaChart={areaChart}
|
||||
configs={areachartConfigs({
|
||||
xTickFormatter: histogramDateTimeFormatter([from, to]),
|
||||
onBrushEnd: narrowDateRange,
|
||||
})}
|
||||
visualizationActionsOptions={{
|
||||
lensAttributes: areaChartLensAttributes,
|
||||
queryId: id,
|
||||
inspectIndex: index,
|
||||
timerange,
|
||||
title: description,
|
||||
}}
|
||||
/>
|
||||
</FlexItem>
|
||||
</>
|
||||
)}
|
||||
</EuiFlexGroup>
|
||||
</>
|
||||
)}
|
||||
</EuiFlexGroup>
|
||||
</>
|
||||
)}
|
||||
</EuiPanel>
|
||||
</FlexItem>
|
||||
);
|
||||
|
@ -344,6 +388,8 @@ export const StatItemsComponent = React.memo<StatItemsProps>(
|
|||
prevProps.enableBarChart === nextProps.enableBarChart &&
|
||||
prevProps.from === nextProps.from &&
|
||||
prevProps.grow === nextProps.grow &&
|
||||
prevProps.loading === nextProps.loading &&
|
||||
prevProps.setQuerySkip === nextProps.setQuerySkip &&
|
||||
prevProps.id === nextProps.id &&
|
||||
prevProps.index === nextProps.index &&
|
||||
prevProps.narrowDateRange === nextProps.narrowDateRange &&
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
*/
|
||||
|
||||
import { renderHook, act } from '@testing-library/react-hooks';
|
||||
|
||||
import { useKibana } from '../../../common/lib/kibana';
|
||||
import { useMatrixHistogram, useMatrixHistogramCombined } from '.';
|
||||
import { MatrixHistogramType } from '../../../../common/search_strategy';
|
||||
|
@ -39,6 +38,7 @@ describe('useMatrixHistogram', () => {
|
|||
indexNames: [],
|
||||
stackByField: 'event.module',
|
||||
startDate: new Date(Date.now()).toISOString(),
|
||||
skip: false,
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
|
@ -145,6 +145,17 @@ describe('useMatrixHistogram', () => {
|
|||
mockDnsSearchStrategyResponse.rawResponse.aggregations?.dns_name_query_count.buckets
|
||||
);
|
||||
});
|
||||
|
||||
it('skip = true will cancel any running request', () => {
|
||||
const abortSpy = jest.spyOn(AbortController.prototype, 'abort');
|
||||
const localProps = { ...props };
|
||||
const { rerender } = renderHook(() => useMatrixHistogram(localProps), {
|
||||
wrapper: TestProviders,
|
||||
});
|
||||
localProps.skip = true;
|
||||
act(() => rerender());
|
||||
expect(abortSpy).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
});
|
||||
|
||||
describe('useMatrixHistogramCombined', () => {
|
||||
|
|
|
@ -229,6 +229,14 @@ export const useMatrixHistogram = ({
|
|||
};
|
||||
}, [matrixHistogramRequest, hostsSearch, skip]);
|
||||
|
||||
useEffect(() => {
|
||||
if (skip) {
|
||||
setLoading(false);
|
||||
searchSubscription$.current.unsubscribe();
|
||||
abortCtrl.current.abort();
|
||||
}
|
||||
}, [skip]);
|
||||
|
||||
const runMatrixHistogramSearch = useCallback(
|
||||
(to: string, from: string) => {
|
||||
hostsSearch({
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* 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,
|
||||
RenderResult,
|
||||
WaitForNextUpdate,
|
||||
cleanup,
|
||||
} from '@testing-library/react-hooks';
|
||||
import { QueryToggle, useQueryToggle } from '.';
|
||||
import { RouteSpyState } from '../../utils/route/types';
|
||||
import { SecurityPageName } from '../../../../common/constants';
|
||||
import { useKibana } from '../../lib/kibana';
|
||||
|
||||
const mockRouteSpy: RouteSpyState = {
|
||||
pageName: SecurityPageName.overview,
|
||||
detailName: undefined,
|
||||
tabName: undefined,
|
||||
search: '',
|
||||
pathName: '/',
|
||||
};
|
||||
jest.mock('../../lib/kibana');
|
||||
jest.mock('../../utils/route/use_route_spy', () => ({
|
||||
useRouteSpy: () => [mockRouteSpy],
|
||||
}));
|
||||
|
||||
describe('useQueryToggle', () => {
|
||||
let result: RenderResult<QueryToggle>;
|
||||
let waitForNextUpdate: WaitForNextUpdate;
|
||||
const mockSet = jest.fn();
|
||||
beforeAll(() => {
|
||||
(useKibana as jest.Mock).mockReturnValue({
|
||||
services: {
|
||||
storage: {
|
||||
get: () => true,
|
||||
set: mockSet,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
it('Toggles local storage', async () => {
|
||||
await act(async () => {
|
||||
({ result, waitForNextUpdate } = renderHook(() => useQueryToggle('queryId')));
|
||||
await waitForNextUpdate();
|
||||
expect(result.current.toggleStatus).toEqual(true);
|
||||
});
|
||||
act(() => {
|
||||
result.current.setToggleStatus(false);
|
||||
});
|
||||
expect(result.current.toggleStatus).toEqual(false);
|
||||
expect(mockSet).toBeCalledWith('kibana.siem:queryId.query.toggle:overview', false);
|
||||
cleanup();
|
||||
});
|
||||
it('null storage key, do not set', async () => {
|
||||
await act(async () => {
|
||||
({ result, waitForNextUpdate } = renderHook(() => useQueryToggle()));
|
||||
await waitForNextUpdate();
|
||||
expect(result.current.toggleStatus).toEqual(true);
|
||||
});
|
||||
act(() => {
|
||||
result.current.setToggleStatus(false);
|
||||
});
|
||||
expect(mockSet).not.toBeCalled();
|
||||
cleanup();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* 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 { useEffect, useCallback, useState } from 'react';
|
||||
import { useKibana } from '../../lib/kibana';
|
||||
import { useRouteSpy } from '../../utils/route/use_route_spy';
|
||||
|
||||
export const getUniqueStorageKey = (pageName: string, id?: string): string | null =>
|
||||
id && pageName.length > 0 ? `kibana.siem:${id}.query.toggle:${pageName}` : null;
|
||||
export interface QueryToggle {
|
||||
toggleStatus: boolean;
|
||||
setToggleStatus: (b: boolean) => void;
|
||||
}
|
||||
|
||||
export const useQueryToggle = (id?: string): QueryToggle => {
|
||||
const [{ pageName }] = useRouteSpy();
|
||||
const {
|
||||
services: { storage },
|
||||
} = useKibana();
|
||||
const storageKey = getUniqueStorageKey(pageName, id);
|
||||
|
||||
const [storageValue, setStorageValue] = useState(
|
||||
storageKey != null ? storage.get(storageKey) ?? true : true
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (storageKey != null) {
|
||||
setStorageValue(storage.get(storageKey) ?? true);
|
||||
}
|
||||
}, [storage, storageKey]);
|
||||
|
||||
const setToggleStatus = useCallback(
|
||||
(isOpen: boolean) => {
|
||||
if (storageKey != null) {
|
||||
storage.set(storageKey, isOpen);
|
||||
setStorageValue(isOpen);
|
||||
}
|
||||
},
|
||||
[storage, storageKey]
|
||||
);
|
||||
|
||||
return id
|
||||
? {
|
||||
toggleStatus: storageValue,
|
||||
setToggleStatus,
|
||||
}
|
||||
: {
|
||||
toggleStatus: true,
|
||||
setToggleStatus: () => {},
|
||||
};
|
||||
};
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* 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 { i18n } from '@kbn/i18n';
|
||||
|
||||
export const QUERY_BUTTON_TITLE = (buttonOn: boolean) =>
|
||||
buttonOn
|
||||
? i18n.translate('xpack.securitySolution.toggleQuery.on', {
|
||||
defaultMessage: 'Open',
|
||||
})
|
||||
: i18n.translate('xpack.securitySolution.toggleQuery.off', {
|
||||
defaultMessage: 'Closed',
|
||||
});
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import { useSearchStrategy } from './index';
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
import { act, renderHook } from '@testing-library/react-hooks';
|
||||
|
||||
import { useObservable } from '@kbn/securitysolution-hook-utils';
|
||||
import { FactoryQueryTypes } from '../../../../common/search_strategy';
|
||||
|
@ -200,4 +200,19 @@ describe('useSearchStrategy', () => {
|
|||
|
||||
expect(start).toBeCalledWith(expect.objectContaining({ signal }));
|
||||
});
|
||||
it('skip = true will cancel any running request', () => {
|
||||
const abortSpy = jest.fn();
|
||||
const signal = new AbortController().signal;
|
||||
jest.spyOn(window, 'AbortController').mockReturnValue({ abort: abortSpy, signal });
|
||||
const factoryQueryType = 'fakeQueryType' as FactoryQueryTypes;
|
||||
const localProps = {
|
||||
...userSearchStrategyProps,
|
||||
skip: false,
|
||||
factoryQueryType,
|
||||
};
|
||||
const { rerender } = renderHook(() => useSearchStrategy<FactoryQueryTypes>(localProps));
|
||||
localProps.skip = true;
|
||||
act(() => rerender());
|
||||
expect(abortSpy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -96,6 +96,7 @@ export const useSearchStrategy = <QueryType extends FactoryQueryTypes>({
|
|||
factoryQueryType,
|
||||
initialResult,
|
||||
errorMessage,
|
||||
skip = false,
|
||||
}: {
|
||||
factoryQueryType: QueryType;
|
||||
/**
|
||||
|
@ -106,6 +107,7 @@ export const useSearchStrategy = <QueryType extends FactoryQueryTypes>({
|
|||
* Message displayed to the user on a Toast when an erro happens.
|
||||
*/
|
||||
errorMessage?: string;
|
||||
skip?: boolean;
|
||||
}) => {
|
||||
const abortCtrl = useRef(new AbortController());
|
||||
const { getTransformChangesIfTheyExist } = useTransforms();
|
||||
|
@ -154,6 +156,12 @@ export const useSearchStrategy = <QueryType extends FactoryQueryTypes>({
|
|||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (skip) {
|
||||
abortCtrl.current.abort();
|
||||
}
|
||||
}, [skip]);
|
||||
|
||||
const [formatedResult, inspect] = useMemo(
|
||||
() => [
|
||||
result
|
||||
|
|
|
@ -12,7 +12,9 @@ import { mount } from 'enzyme';
|
|||
import { TestProviders } from '../../../../common/mock';
|
||||
|
||||
import { AlertsCountPanel } from './index';
|
||||
import { useQueryToggle } from '../../../../common/containers/query_toggle';
|
||||
|
||||
jest.mock('../../../../common/containers/query_toggle');
|
||||
jest.mock('react-router-dom', () => {
|
||||
const actual = jest.requireActual('react-router-dom');
|
||||
return { ...actual, useLocation: jest.fn().mockReturnValue({ pathname: '' }) };
|
||||
|
@ -22,6 +24,12 @@ describe('AlertsCountPanel', () => {
|
|||
const defaultProps = {
|
||||
signalIndexName: 'signalIndexName',
|
||||
};
|
||||
const mockSetToggle = jest.fn();
|
||||
const mockUseQueryToggle = useQueryToggle as jest.Mock;
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: true, setToggleStatus: mockSetToggle });
|
||||
});
|
||||
|
||||
it('renders correctly', async () => {
|
||||
await act(async () => {
|
||||
|
@ -54,4 +62,38 @@ describe('AlertsCountPanel', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
describe('toggleQuery', () => {
|
||||
it('toggles', async () => {
|
||||
await act(async () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<AlertsCountPanel {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
wrapper.find('[data-test-subj="query-toggle-header"]').first().simulate('click');
|
||||
expect(mockSetToggle).toBeCalledWith(false);
|
||||
});
|
||||
});
|
||||
it('toggleStatus=true, render', async () => {
|
||||
await act(async () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<AlertsCountPanel {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(wrapper.find('[data-test-subj="alertsCountTable"]').exists()).toEqual(true);
|
||||
});
|
||||
});
|
||||
it('toggleStatus=false, hide', async () => {
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: false, setToggleStatus: mockSetToggle });
|
||||
await act(async () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<AlertsCountPanel {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(wrapper.find('[data-test-subj="alertsCountTable"]').exists()).toEqual(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import { MappingRuntimeFields } from '@elastic/elasticsearch/lib/api/types';
|
||||
import React, { memo, useMemo, useState, useEffect } from 'react';
|
||||
import React, { memo, useMemo, useState, useEffect, useCallback } from 'react';
|
||||
import uuid from 'uuid';
|
||||
|
||||
import type { Filter, Query } from '@kbn/es-query';
|
||||
|
@ -24,6 +24,7 @@ import type { AlertsCountAggregation } from './types';
|
|||
import { DEFAULT_STACK_BY_FIELD } from '../common/config';
|
||||
import { KpiPanel, StackByComboBox } from '../common/components';
|
||||
import { useInspectButton } from '../common/hooks';
|
||||
import { useQueryToggle } from '../../../../common/containers/query_toggle';
|
||||
|
||||
export const DETECTIONS_ALERTS_COUNT_ID = 'detections-alerts-count';
|
||||
|
||||
|
@ -64,6 +65,20 @@ export const AlertsCountPanel = memo<AlertsCountPanelProps>(
|
|||
}
|
||||
}, [query, filters]);
|
||||
|
||||
const { toggleStatus, setToggleStatus } = useQueryToggle(DETECTIONS_ALERTS_COUNT_ID);
|
||||
const [querySkip, setQuerySkip] = useState(!toggleStatus);
|
||||
useEffect(() => {
|
||||
setQuerySkip(!toggleStatus);
|
||||
}, [toggleStatus]);
|
||||
const toggleQuery = useCallback(
|
||||
(status: boolean) => {
|
||||
setToggleStatus(status);
|
||||
// toggle on = skipQuery false
|
||||
setQuerySkip(!status);
|
||||
},
|
||||
[setQuerySkip, setToggleStatus]
|
||||
);
|
||||
|
||||
const {
|
||||
loading: isLoadingAlerts,
|
||||
data: alertsData,
|
||||
|
@ -80,6 +95,7 @@ export const AlertsCountPanel = memo<AlertsCountPanelProps>(
|
|||
runtimeMappings
|
||||
),
|
||||
indexName: signalIndexName,
|
||||
skip: querySkip,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -99,21 +115,26 @@ export const AlertsCountPanel = memo<AlertsCountPanelProps>(
|
|||
});
|
||||
|
||||
return (
|
||||
<InspectButtonContainer>
|
||||
<KpiPanel hasBorder data-test-subj="alertsCountPanel">
|
||||
<InspectButtonContainer show={toggleStatus}>
|
||||
<KpiPanel $toggleStatus={toggleStatus} hasBorder data-test-subj="alertsCountPanel">
|
||||
<HeaderSection
|
||||
height={!toggleStatus ? 30 : undefined}
|
||||
id={uniqueQueryId}
|
||||
title={i18n.COUNT_TABLE_TITLE}
|
||||
titleSize="s"
|
||||
hideSubtitle
|
||||
toggleStatus={toggleStatus}
|
||||
toggleQuery={toggleQuery}
|
||||
>
|
||||
<StackByComboBox selected={selectedStackByOption} onSelect={setSelectedStackByOption} />
|
||||
</HeaderSection>
|
||||
<AlertsCount
|
||||
data={alertsData}
|
||||
loading={isLoadingAlerts}
|
||||
selectedStackByOption={selectedStackByOption}
|
||||
/>
|
||||
{toggleStatus && (
|
||||
<AlertsCount
|
||||
data={alertsData}
|
||||
loading={isLoadingAlerts}
|
||||
selectedStackByOption={selectedStackByOption}
|
||||
/>
|
||||
)}
|
||||
</KpiPanel>
|
||||
</InspectButtonContainer>
|
||||
);
|
||||
|
|
|
@ -12,9 +12,13 @@ import { mount } from 'enzyme';
|
|||
import type { Filter } from '@kbn/es-query';
|
||||
import { TestProviders } from '../../../../common/mock';
|
||||
import { SecurityPageName } from '../../../../app/types';
|
||||
import { MatrixLoader } from '../../../../common/components/matrix_histogram/matrix_loader';
|
||||
|
||||
import { AlertsHistogramPanel } from './index';
|
||||
import * as helpers from './helpers';
|
||||
import { useQueryToggle } from '../../../../common/containers/query_toggle';
|
||||
|
||||
jest.mock('../../../../common/containers/query_toggle');
|
||||
|
||||
jest.mock('react-router-dom', () => {
|
||||
const originalModule = jest.requireActual('react-router-dom');
|
||||
|
@ -91,6 +95,12 @@ describe('AlertsHistogramPanel', () => {
|
|||
updateDateRange: jest.fn(),
|
||||
};
|
||||
|
||||
const mockSetToggle = jest.fn();
|
||||
const mockUseQueryToggle = useQueryToggle as jest.Mock;
|
||||
beforeEach(() => {
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: true, setToggleStatus: mockSetToggle });
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
jest.restoreAllMocks();
|
||||
|
@ -339,4 +349,40 @@ describe('AlertsHistogramPanel', () => {
|
|||
`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('toggleQuery', () => {
|
||||
it('toggles', async () => {
|
||||
await act(async () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<AlertsHistogramPanel {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
wrapper.find('[data-test-subj="query-toggle-header"]').first().simulate('click');
|
||||
expect(mockSetToggle).toBeCalledWith(false);
|
||||
});
|
||||
});
|
||||
it('toggleStatus=true, render', async () => {
|
||||
await act(async () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<AlertsHistogramPanel {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
expect(wrapper.find(MatrixLoader).exists()).toEqual(true);
|
||||
});
|
||||
});
|
||||
it('toggleStatus=false, hide', async () => {
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: false, setToggleStatus: mockSetToggle });
|
||||
await act(async () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<AlertsHistogramPanel {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(wrapper.find(MatrixLoader).exists()).toEqual(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -45,6 +45,7 @@ import type { AlertsStackByField } from '../common/types';
|
|||
import { KpiPanel, StackByComboBox } from '../common/components';
|
||||
|
||||
import { useInspectButton } from '../common/hooks';
|
||||
import { useQueryToggle } from '../../../../common/containers/query_toggle';
|
||||
|
||||
const defaultTotalAlertsObj: AlertsTotal = {
|
||||
value: 0,
|
||||
|
@ -116,6 +117,19 @@ export const AlertsHistogramPanel = memo<AlertsHistogramPanelProps>(
|
|||
onlyField == null ? defaultStackByOption : onlyField
|
||||
);
|
||||
|
||||
const { toggleStatus, setToggleStatus } = useQueryToggle(DETECTIONS_HISTOGRAM_ID);
|
||||
const [querySkip, setQuerySkip] = useState(!toggleStatus);
|
||||
useEffect(() => {
|
||||
setQuerySkip(!toggleStatus);
|
||||
}, [toggleStatus]);
|
||||
const toggleQuery = useCallback(
|
||||
(status: boolean) => {
|
||||
setToggleStatus(status);
|
||||
// toggle on = skipQuery false
|
||||
setQuerySkip(!status);
|
||||
},
|
||||
[setQuerySkip, setToggleStatus]
|
||||
);
|
||||
const {
|
||||
loading: isLoadingAlerts,
|
||||
data: alertsData,
|
||||
|
@ -132,6 +146,7 @@ export const AlertsHistogramPanel = memo<AlertsHistogramPanelProps>(
|
|||
runtimeMappings
|
||||
),
|
||||
indexName: signalIndexName,
|
||||
skip: querySkip,
|
||||
});
|
||||
|
||||
const kibana = useKibana();
|
||||
|
@ -270,17 +285,21 @@ export const AlertsHistogramPanel = memo<AlertsHistogramPanelProps>(
|
|||
);
|
||||
|
||||
return (
|
||||
<InspectButtonContainer show={!isInitialLoading}>
|
||||
<InspectButtonContainer show={!isInitialLoading && toggleStatus}>
|
||||
<KpiPanel
|
||||
height={PANEL_HEIGHT}
|
||||
hasBorder
|
||||
paddingSize={paddingSize}
|
||||
data-test-subj="alerts-histogram-panel"
|
||||
$toggleStatus={toggleStatus}
|
||||
>
|
||||
<HeaderSection
|
||||
id={uniqueQueryId}
|
||||
height={!toggleStatus ? 30 : undefined}
|
||||
title={titleText}
|
||||
titleSize={titleSize}
|
||||
toggleStatus={toggleStatus}
|
||||
toggleQuery={toggleQuery}
|
||||
subtitle={!isInitialLoading && showTotalAlertsCount && totalAlerts}
|
||||
isInspectDisabled={isInspectDisabled}
|
||||
hideSubtitle
|
||||
|
@ -301,21 +320,23 @@ export const AlertsHistogramPanel = memo<AlertsHistogramPanelProps>(
|
|||
</EuiFlexGroup>
|
||||
</HeaderSection>
|
||||
|
||||
{isInitialLoading ? (
|
||||
<MatrixLoader />
|
||||
) : (
|
||||
<AlertsHistogram
|
||||
chartHeight={chartHeight}
|
||||
data={formattedAlertsData}
|
||||
from={from}
|
||||
legendItems={legendItems}
|
||||
legendPosition={legendPosition}
|
||||
loading={isLoadingAlerts}
|
||||
to={to}
|
||||
showLegend={showLegend}
|
||||
updateDateRange={updateDateRange}
|
||||
/>
|
||||
)}
|
||||
{toggleStatus ? (
|
||||
isInitialLoading ? (
|
||||
<MatrixLoader />
|
||||
) : (
|
||||
<AlertsHistogram
|
||||
chartHeight={chartHeight}
|
||||
data={formattedAlertsData}
|
||||
from={from}
|
||||
legendItems={legendItems}
|
||||
legendPosition={legendPosition}
|
||||
loading={isLoadingAlerts}
|
||||
to={to}
|
||||
showLegend={showLegend}
|
||||
updateDateRange={updateDateRange}
|
||||
/>
|
||||
)
|
||||
) : null}
|
||||
</KpiPanel>
|
||||
</InspectButtonContainer>
|
||||
);
|
||||
|
|
|
@ -12,17 +12,23 @@ import { PANEL_HEIGHT, MOBILE_PANEL_HEIGHT } from './config';
|
|||
import { useStackByFields } from './hooks';
|
||||
import * as i18n from './translations';
|
||||
|
||||
export const KpiPanel = styled(EuiPanel)<{ height?: number }>`
|
||||
export const KpiPanel = styled(EuiPanel)<{ height?: number; $toggleStatus: boolean }>`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
height: ${MOBILE_PANEL_HEIGHT}px;
|
||||
|
||||
@media only screen and (min-width: ${(props) => props.theme.eui.euiBreakpoints.m}) {
|
||||
${({ $toggleStatus }) =>
|
||||
$toggleStatus &&
|
||||
`
|
||||
height: ${PANEL_HEIGHT}px;
|
||||
`}
|
||||
}
|
||||
${({ $toggleStatus }) =>
|
||||
$toggleStatus &&
|
||||
`
|
||||
height: ${MOBILE_PANEL_HEIGHT}px;
|
||||
`}
|
||||
`;
|
||||
interface StackedBySelectProps {
|
||||
selected: string;
|
||||
|
|
|
@ -129,4 +129,22 @@ describe('useQueryAlerts', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('skip', async () => {
|
||||
const abortSpy = jest.spyOn(AbortController.prototype, 'abort');
|
||||
await act(async () => {
|
||||
const localProps = { query: mockAlertsQuery, indexName, skip: false };
|
||||
const { rerender, waitForNextUpdate } = renderHook<
|
||||
[object, string],
|
||||
ReturnQueryAlerts<unknown, unknown>
|
||||
>(() => useQueryAlerts<unknown, unknown>(localProps));
|
||||
await waitForNextUpdate();
|
||||
await waitForNextUpdate();
|
||||
|
||||
localProps.skip = true;
|
||||
act(() => rerender());
|
||||
act(() => rerender());
|
||||
expect(abortSpy).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -94,6 +94,12 @@ export const useQueryAlerts = <Hit, Aggs>({
|
|||
if (!isEmpty(query) && !skip) {
|
||||
fetchData();
|
||||
}
|
||||
if (skip) {
|
||||
setLoading(false);
|
||||
isSubscribed = false;
|
||||
abortCtrl.abort();
|
||||
}
|
||||
|
||||
return () => {
|
||||
isSubscribed = false;
|
||||
abortCtrl.abort();
|
||||
|
|
|
@ -105,6 +105,7 @@ exports[`Authentication Table Component rendering it renders the authentication
|
|||
isInspect={false}
|
||||
loadPage={[MockFunction]}
|
||||
loading={false}
|
||||
setQuerySkip={[MockFunction]}
|
||||
showMorePagesIndicator={true}
|
||||
totalCount={54}
|
||||
type="page"
|
||||
|
|
|
@ -45,6 +45,7 @@ describe('Authentication Table Component', () => {
|
|||
isInspect={false}
|
||||
loading={false}
|
||||
loadPage={loadPage}
|
||||
setQuerySkip={jest.fn()}
|
||||
showMorePagesIndicator={getOr(
|
||||
false,
|
||||
'showMorePagesIndicator',
|
||||
|
|
|
@ -43,6 +43,7 @@ interface AuthenticationTableProps {
|
|||
loadPage: (newActivePage: number) => void;
|
||||
id: string;
|
||||
isInspect: boolean;
|
||||
setQuerySkip: (skip: boolean) => void;
|
||||
showMorePagesIndicator: boolean;
|
||||
totalCount: number;
|
||||
type: hostsModel.HostsType;
|
||||
|
@ -78,6 +79,7 @@ const AuthenticationTableComponent: React.FC<AuthenticationTableProps> = ({
|
|||
isInspect,
|
||||
loading,
|
||||
loadPage,
|
||||
setQuerySkip,
|
||||
showMorePagesIndicator,
|
||||
totalCount,
|
||||
type,
|
||||
|
@ -133,6 +135,7 @@ const AuthenticationTableComponent: React.FC<AuthenticationTableProps> = ({
|
|||
loading={loading}
|
||||
loadPage={loadPage}
|
||||
pageOfItems={data}
|
||||
setQuerySkip={setQuerySkip}
|
||||
showMorePagesIndicator={showMorePagesIndicator}
|
||||
totalCount={fakeTotalCount}
|
||||
updateLimitPagination={updateLimitPagination}
|
||||
|
|
|
@ -54,6 +54,7 @@ interface HostRiskScoreTableProps {
|
|||
isInspect: boolean;
|
||||
loading: boolean;
|
||||
loadPage: (newActivePage: number) => void;
|
||||
setQuerySkip: (skip: boolean) => void;
|
||||
severityCount: SeverityCount;
|
||||
totalCount: number;
|
||||
type: hostsModel.HostsType;
|
||||
|
@ -71,6 +72,7 @@ const HostRiskScoreTableComponent: React.FC<HostRiskScoreTableProps> = ({
|
|||
isInspect,
|
||||
loading,
|
||||
loadPage,
|
||||
setQuerySkip,
|
||||
severityCount,
|
||||
totalCount,
|
||||
type,
|
||||
|
@ -207,6 +209,7 @@ const HostRiskScoreTableComponent: React.FC<HostRiskScoreTableProps> = ({
|
|||
loadPage={loadPage}
|
||||
onChange={onSort}
|
||||
pageOfItems={data}
|
||||
setQuerySkip={setQuerySkip}
|
||||
showMorePagesIndicator={false}
|
||||
sorting={sort}
|
||||
split={true}
|
||||
|
|
|
@ -36,6 +36,7 @@ exports[`Hosts Table rendering it renders the default Hosts table 1`] = `
|
|||
isInspect={false}
|
||||
loadPage={[MockFunction]}
|
||||
loading={false}
|
||||
setQuerySkip={[MockFunction]}
|
||||
showMorePagesIndicator={false}
|
||||
totalCount={-1}
|
||||
type="page"
|
||||
|
|
|
@ -69,6 +69,7 @@ describe('Hosts Table', () => {
|
|||
fakeTotalCount={0}
|
||||
loading={false}
|
||||
loadPage={loadPage}
|
||||
setQuerySkip={jest.fn()}
|
||||
showMorePagesIndicator={false}
|
||||
totalCount={-1}
|
||||
type={hostsModel.HostsType.page}
|
||||
|
@ -91,6 +92,7 @@ describe('Hosts Table', () => {
|
|||
data={mockData}
|
||||
totalCount={0}
|
||||
fakeTotalCount={-1}
|
||||
setQuerySkip={jest.fn()}
|
||||
showMorePagesIndicator={false}
|
||||
loadPage={loadPage}
|
||||
type={hostsModel.HostsType.page}
|
||||
|
@ -113,6 +115,7 @@ describe('Hosts Table', () => {
|
|||
data={mockData}
|
||||
totalCount={0}
|
||||
fakeTotalCount={-1}
|
||||
setQuerySkip={jest.fn()}
|
||||
showMorePagesIndicator={false}
|
||||
loadPage={loadPage}
|
||||
type={hostsModel.HostsType.page}
|
||||
|
@ -136,6 +139,7 @@ describe('Hosts Table', () => {
|
|||
data={mockData}
|
||||
totalCount={0}
|
||||
fakeTotalCount={-1}
|
||||
setQuerySkip={jest.fn()}
|
||||
showMorePagesIndicator={false}
|
||||
loadPage={loadPage}
|
||||
type={hostsModel.HostsType.page}
|
||||
|
|
|
@ -42,6 +42,7 @@ interface HostsTableProps {
|
|||
isInspect: boolean;
|
||||
loading: boolean;
|
||||
loadPage: (newActivePage: number) => void;
|
||||
setQuerySkip: (skip: boolean) => void;
|
||||
showMorePagesIndicator: boolean;
|
||||
totalCount: number;
|
||||
type: hostsModel.HostsType;
|
||||
|
@ -77,6 +78,7 @@ const HostsTableComponent: React.FC<HostsTableProps> = ({
|
|||
isInspect,
|
||||
loading,
|
||||
loadPage,
|
||||
setQuerySkip,
|
||||
showMorePagesIndicator,
|
||||
totalCount,
|
||||
type,
|
||||
|
@ -172,6 +174,7 @@ const HostsTableComponent: React.FC<HostsTableProps> = ({
|
|||
loadPage={loadPage}
|
||||
onChange={onChange}
|
||||
pageOfItems={data}
|
||||
setQuerySkip={setQuerySkip}
|
||||
showMorePagesIndicator={showMorePagesIndicator}
|
||||
sorting={sorting}
|
||||
totalCount={fakeTotalCount}
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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 { useHostsKpiAuthentications } from '../../../containers/kpi_hosts/authentications';
|
||||
import { useQueryToggle } from '../../../../common/containers/query_toggle';
|
||||
import { render } from '@testing-library/react';
|
||||
import { TestProviders } from '../../../../common/mock';
|
||||
import React from 'react';
|
||||
import { HostsKpiAuthentications } from './index';
|
||||
|
||||
jest.mock('../../../../common/containers/query_toggle');
|
||||
jest.mock('../../../containers/kpi_hosts/authentications');
|
||||
jest.mock('../common', () => ({
|
||||
KpiBaseComponentManage: () => <span data-test-subj="KpiBaseComponentManage" />,
|
||||
}));
|
||||
|
||||
describe('Authentications KPI', () => {
|
||||
const mockUseHostsKpiAuthentications = useHostsKpiAuthentications as jest.Mock;
|
||||
const mockUseQueryToggle = useQueryToggle as jest.Mock;
|
||||
const defaultProps = {
|
||||
from: '2019-06-25T04:31:59.345Z',
|
||||
to: '2019-06-25T06:31:59.345Z',
|
||||
indexNames: [],
|
||||
narrowDateRange: jest.fn(),
|
||||
setQuery: jest.fn(),
|
||||
skip: false,
|
||||
};
|
||||
beforeEach(() => {
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: true, setToggleStatus: jest.fn() });
|
||||
mockUseHostsKpiAuthentications.mockReturnValue([
|
||||
false,
|
||||
{
|
||||
id: '123',
|
||||
inspect: {
|
||||
dsl: [],
|
||||
response: [],
|
||||
},
|
||||
refetch: jest.fn(),
|
||||
},
|
||||
]);
|
||||
});
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
it('toggleStatus=true, do not skip', () => {
|
||||
render(
|
||||
<TestProviders>
|
||||
<HostsKpiAuthentications {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(mockUseHostsKpiAuthentications.mock.calls[0][0].skip).toEqual(false);
|
||||
});
|
||||
it('toggleStatus=false, skip', () => {
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: false, setToggleStatus: jest.fn() });
|
||||
render(
|
||||
<TestProviders>
|
||||
<HostsKpiAuthentications {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(mockUseHostsKpiAuthentications.mock.calls[0][0].skip).toEqual(true);
|
||||
});
|
||||
});
|
|
@ -5,17 +5,18 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import { StatItems } from '../../../../common/components/stat_items';
|
||||
import { kpiUserAuthenticationsAreaLensAttributes } from '../../../../common/components/visualization_actions/lens_attributes/hosts/kpi_user_authentications_area';
|
||||
import { kpiUserAuthenticationsBarLensAttributes } from '../../../../common/components/visualization_actions/lens_attributes/hosts/kpi_user_authentications_bar';
|
||||
import { kpiUserAuthenticationsMetricSuccessLensAttributes } from '../../../../common/components/visualization_actions/lens_attributes/hosts/kpi_user_authentications_metric_success';
|
||||
import { kpiUserAuthenticationsMetricFailureLensAttributes } from '../../../../common/components/visualization_actions/lens_attributes/hosts/kpi_user_authentication_metric_failure';
|
||||
import { useHostsKpiAuthentications } from '../../../containers/kpi_hosts/authentications';
|
||||
import { useHostsKpiAuthentications, ID } from '../../../containers/kpi_hosts/authentications';
|
||||
import { KpiBaseComponentManage } from '../common';
|
||||
import { HostsKpiProps, HostsKpiChartColors } from '../types';
|
||||
import * as i18n from './translations';
|
||||
import { useQueryToggle } from '../../../../common/containers/query_toggle';
|
||||
|
||||
export const fieldsMapping: Readonly<StatItems[]> = [
|
||||
{
|
||||
|
@ -57,12 +58,17 @@ const HostsKpiAuthenticationsComponent: React.FC<HostsKpiProps> = ({
|
|||
setQuery,
|
||||
skip,
|
||||
}) => {
|
||||
const { toggleStatus } = useQueryToggle(ID);
|
||||
const [querySkip, setQuerySkip] = useState(skip || !toggleStatus);
|
||||
useEffect(() => {
|
||||
setQuerySkip(skip || !toggleStatus);
|
||||
}, [skip, toggleStatus]);
|
||||
const [loading, { refetch, id, inspect, ...data }] = useHostsKpiAuthentications({
|
||||
filterQuery,
|
||||
endDate: to,
|
||||
indexNames,
|
||||
startDate: from,
|
||||
skip,
|
||||
skip: querySkip,
|
||||
});
|
||||
|
||||
return (
|
||||
|
@ -77,6 +83,7 @@ const HostsKpiAuthenticationsComponent: React.FC<HostsKpiProps> = ({
|
|||
narrowDateRange={narrowDateRange}
|
||||
refetch={refetch}
|
||||
setQuery={setQuery}
|
||||
setQuerySkip={setQuerySkip}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { EuiFlexItem, EuiLoadingSpinner, EuiFlexGroup } from '@elastic/eui';
|
||||
import { EuiFlexGroup } from '@elastic/eui';
|
||||
import styled from 'styled-components';
|
||||
import deepEqual from 'fast-deep-equal';
|
||||
|
||||
|
@ -42,10 +42,11 @@ interface KpiBaseComponentProps {
|
|||
from: string;
|
||||
to: string;
|
||||
narrowDateRange: UpdateDateRange;
|
||||
setQuerySkip: (skip: boolean) => void;
|
||||
}
|
||||
|
||||
export const KpiBaseComponent = React.memo<KpiBaseComponentProps>(
|
||||
({ fieldsMapping, data, id, loading = false, from, to, narrowDateRange }) => {
|
||||
({ fieldsMapping, data, id, loading = false, from, to, narrowDateRange, setQuerySkip }) => {
|
||||
const { cases } = useKibana().services;
|
||||
const CasesContext = cases.ui.getCasesContext();
|
||||
const userPermissions = useGetUserCasesPermissions();
|
||||
|
@ -57,13 +58,11 @@ export const KpiBaseComponent = React.memo<KpiBaseComponentProps>(
|
|||
id,
|
||||
from,
|
||||
to,
|
||||
narrowDateRange
|
||||
narrowDateRange,
|
||||
setQuerySkip,
|
||||
loading
|
||||
);
|
||||
|
||||
if (loading) {
|
||||
return <KpiBaseComponentLoader />;
|
||||
}
|
||||
|
||||
return (
|
||||
<EuiFlexGroup wrap>
|
||||
<CasesContext owner={[APP_ID]} userCanCrud={userCanCrud ?? false}>
|
||||
|
@ -87,11 +86,3 @@ export const KpiBaseComponent = React.memo<KpiBaseComponentProps>(
|
|||
KpiBaseComponent.displayName = 'KpiBaseComponent';
|
||||
|
||||
export const KpiBaseComponentManage = manageQuery(KpiBaseComponent);
|
||||
|
||||
export const KpiBaseComponentLoader: React.FC = () => (
|
||||
<FlexGroup justifyContent="center" alignItems="center" data-test-subj="KpiLoader">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiLoadingSpinner size="xl" />
|
||||
</EuiFlexItem>
|
||||
</FlexGroup>
|
||||
);
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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 { useHostsKpiHosts } from '../../../containers/kpi_hosts/hosts';
|
||||
import { useQueryToggle } from '../../../../common/containers/query_toggle';
|
||||
import { render } from '@testing-library/react';
|
||||
import { TestProviders } from '../../../../common/mock';
|
||||
import React from 'react';
|
||||
import { HostsKpiHosts } from './index';
|
||||
|
||||
jest.mock('../../../../common/containers/query_toggle');
|
||||
jest.mock('../../../containers/kpi_hosts/hosts');
|
||||
jest.mock('../common', () => ({
|
||||
KpiBaseComponentManage: () => <span data-test-subj="KpiBaseComponentManage" />,
|
||||
}));
|
||||
|
||||
describe('Hosts KPI', () => {
|
||||
const mockUseHostsKpiHosts = useHostsKpiHosts as jest.Mock;
|
||||
const mockUseQueryToggle = useQueryToggle as jest.Mock;
|
||||
const defaultProps = {
|
||||
from: '2019-06-25T04:31:59.345Z',
|
||||
to: '2019-06-25T06:31:59.345Z',
|
||||
indexNames: [],
|
||||
narrowDateRange: jest.fn(),
|
||||
setQuery: jest.fn(),
|
||||
skip: false,
|
||||
};
|
||||
beforeEach(() => {
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: true, setToggleStatus: jest.fn() });
|
||||
mockUseHostsKpiHosts.mockReturnValue([
|
||||
false,
|
||||
{
|
||||
id: '123',
|
||||
inspect: {
|
||||
dsl: [],
|
||||
response: [],
|
||||
},
|
||||
refetch: jest.fn(),
|
||||
},
|
||||
]);
|
||||
});
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
it('toggleStatus=true, do not skip', () => {
|
||||
render(
|
||||
<TestProviders>
|
||||
<HostsKpiHosts {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(mockUseHostsKpiHosts.mock.calls[0][0].skip).toEqual(false);
|
||||
});
|
||||
it('toggleStatus=false, skip', () => {
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: false, setToggleStatus: jest.fn() });
|
||||
render(
|
||||
<TestProviders>
|
||||
<HostsKpiHosts {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(mockUseHostsKpiHosts.mock.calls[0][0].skip).toEqual(true);
|
||||
});
|
||||
});
|
|
@ -5,15 +5,16 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import { StatItems } from '../../../../common/components/stat_items';
|
||||
import { kpiHostAreaLensAttributes } from '../../../../common/components/visualization_actions/lens_attributes/hosts/kpi_host_area';
|
||||
import { kpiHostMetricLensAttributes } from '../../../../common/components/visualization_actions/lens_attributes/hosts/kpi_host_metric';
|
||||
import { useHostsKpiHosts } from '../../../containers/kpi_hosts/hosts';
|
||||
import { useHostsKpiHosts, ID } from '../../../containers/kpi_hosts/hosts';
|
||||
import { KpiBaseComponentManage } from '../common';
|
||||
import { HostsKpiProps, HostsKpiChartColors } from '../types';
|
||||
import * as i18n from './translations';
|
||||
import { useQueryToggle } from '../../../../common/containers/query_toggle';
|
||||
|
||||
export const fieldsMapping: Readonly<StatItems[]> = [
|
||||
{
|
||||
|
@ -42,12 +43,17 @@ const HostsKpiHostsComponent: React.FC<HostsKpiProps> = ({
|
|||
setQuery,
|
||||
skip,
|
||||
}) => {
|
||||
const { toggleStatus } = useQueryToggle(ID);
|
||||
const [querySkip, setQuerySkip] = useState(skip || !toggleStatus);
|
||||
useEffect(() => {
|
||||
setQuerySkip(skip || !toggleStatus);
|
||||
}, [skip, toggleStatus]);
|
||||
const [loading, { refetch, id, inspect, ...data }] = useHostsKpiHosts({
|
||||
filterQuery,
|
||||
endDate: to,
|
||||
indexNames,
|
||||
startDate: from,
|
||||
skip,
|
||||
skip: querySkip,
|
||||
});
|
||||
|
||||
return (
|
||||
|
@ -62,6 +68,7 @@ const HostsKpiHostsComponent: React.FC<HostsKpiProps> = ({
|
|||
narrowDateRange={narrowDateRange}
|
||||
refetch={refetch}
|
||||
setQuery={setQuery}
|
||||
setQuerySkip={setQuerySkip}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -11,6 +11,7 @@ import {
|
|||
EuiHorizontalRule,
|
||||
EuiIcon,
|
||||
EuiPanel,
|
||||
EuiLoadingSpinner,
|
||||
EuiTitle,
|
||||
EuiText,
|
||||
} from '@elastic/eui';
|
||||
|
@ -22,7 +23,6 @@ import {
|
|||
BUTTON_CLASS as INPECT_BUTTON_CLASS,
|
||||
} from '../../../../common/components/inspect';
|
||||
|
||||
import { KpiBaseComponentLoader } from '../common';
|
||||
import * as i18n from './translations';
|
||||
|
||||
import { useInspectQuery } from '../../../../common/hooks/use_inspect_query';
|
||||
|
@ -36,6 +36,13 @@ import { HoverVisibilityContainer } from '../../../../common/components/hover_vi
|
|||
import { KpiRiskScoreStrategyResponse, RiskSeverity } from '../../../../../common/search_strategy';
|
||||
import { RiskScore } from '../../../../common/components/severity/common';
|
||||
|
||||
const KpiBaseComponentLoader: React.FC = () => (
|
||||
<EuiFlexGroup justifyContent="center" alignItems="center" data-test-subj="KpiLoader">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiLoadingSpinner size="xl" />
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
const QUERY_ID = 'hostsKpiRiskyHostsQuery';
|
||||
|
||||
const HostCount = styled(EuiText)`
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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 { useHostsKpiUniqueIps } from '../../../containers/kpi_hosts/unique_ips';
|
||||
import { useQueryToggle } from '../../../../common/containers/query_toggle';
|
||||
import { render } from '@testing-library/react';
|
||||
import { TestProviders } from '../../../../common/mock';
|
||||
import React from 'react';
|
||||
import { HostsKpiUniqueIps } from './index';
|
||||
|
||||
jest.mock('../../../../common/containers/query_toggle');
|
||||
jest.mock('../../../containers/kpi_hosts/unique_ips');
|
||||
jest.mock('../common', () => ({
|
||||
KpiBaseComponentManage: () => <span data-test-subj="KpiBaseComponentManage" />,
|
||||
}));
|
||||
|
||||
describe('Unique IPs KPI', () => {
|
||||
const mockUseHostsKpiUniqueIps = useHostsKpiUniqueIps as jest.Mock;
|
||||
const mockUseQueryToggle = useQueryToggle as jest.Mock;
|
||||
const defaultProps = {
|
||||
from: '2019-06-25T04:31:59.345Z',
|
||||
to: '2019-06-25T06:31:59.345Z',
|
||||
indexNames: [],
|
||||
narrowDateRange: jest.fn(),
|
||||
setQuery: jest.fn(),
|
||||
skip: false,
|
||||
};
|
||||
beforeEach(() => {
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: true, setToggleStatus: jest.fn() });
|
||||
mockUseHostsKpiUniqueIps.mockReturnValue([
|
||||
false,
|
||||
{
|
||||
id: '123',
|
||||
inspect: {
|
||||
dsl: [],
|
||||
response: [],
|
||||
},
|
||||
refetch: jest.fn(),
|
||||
},
|
||||
]);
|
||||
});
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
it('toggleStatus=true, do not skip', () => {
|
||||
render(
|
||||
<TestProviders>
|
||||
<HostsKpiUniqueIps {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(mockUseHostsKpiUniqueIps.mock.calls[0][0].skip).toEqual(false);
|
||||
});
|
||||
it('toggleStatus=false, skip', () => {
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: false, setToggleStatus: jest.fn() });
|
||||
render(
|
||||
<TestProviders>
|
||||
<HostsKpiUniqueIps {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(mockUseHostsKpiUniqueIps.mock.calls[0][0].skip).toEqual(true);
|
||||
});
|
||||
});
|
|
@ -5,17 +5,18 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import { StatItems } from '../../../../common/components/stat_items';
|
||||
import { kpiUniqueIpsAreaLensAttributes } from '../../../../common/components/visualization_actions/lens_attributes/hosts/kpi_unique_ips_area';
|
||||
import { kpiUniqueIpsBarLensAttributes } from '../../../../common/components/visualization_actions/lens_attributes/hosts/kpi_unique_ips_bar';
|
||||
import { kpiUniqueIpsDestinationMetricLensAttributes } from '../../../../common/components/visualization_actions/lens_attributes/hosts/kpi_unique_ips_destination_metric';
|
||||
import { kpiUniqueIpsSourceMetricLensAttributes } from '../../../../common/components/visualization_actions/lens_attributes/hosts/kpi_unique_ips_source_metric';
|
||||
import { useHostsKpiUniqueIps } from '../../../containers/kpi_hosts/unique_ips';
|
||||
import { useHostsKpiUniqueIps, ID } from '../../../containers/kpi_hosts/unique_ips';
|
||||
import { KpiBaseComponentManage } from '../common';
|
||||
import { HostsKpiProps, HostsKpiChartColors } from '../types';
|
||||
import * as i18n from './translations';
|
||||
import { useQueryToggle } from '../../../../common/containers/query_toggle';
|
||||
|
||||
export const fieldsMapping: Readonly<StatItems[]> = [
|
||||
{
|
||||
|
@ -57,12 +58,17 @@ const HostsKpiUniqueIpsComponent: React.FC<HostsKpiProps> = ({
|
|||
setQuery,
|
||||
skip,
|
||||
}) => {
|
||||
const { toggleStatus } = useQueryToggle(ID);
|
||||
const [querySkip, setQuerySkip] = useState(skip || !toggleStatus);
|
||||
useEffect(() => {
|
||||
setQuerySkip(skip || !toggleStatus);
|
||||
}, [skip, toggleStatus]);
|
||||
const [loading, { refetch, id, inspect, ...data }] = useHostsKpiUniqueIps({
|
||||
filterQuery,
|
||||
endDate: to,
|
||||
indexNames,
|
||||
startDate: from,
|
||||
skip,
|
||||
skip: querySkip,
|
||||
});
|
||||
|
||||
return (
|
||||
|
@ -77,6 +83,7 @@ const HostsKpiUniqueIpsComponent: React.FC<HostsKpiProps> = ({
|
|||
narrowDateRange={narrowDateRange}
|
||||
refetch={refetch}
|
||||
setQuery={setQuery}
|
||||
setQuerySkip={setQuerySkip}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -5,16 +5,30 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { render } from '@testing-library/react';
|
||||
import { render, fireEvent } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { TopHostScoreContributors } from '.';
|
||||
import { TestProviders } from '../../../common/mock';
|
||||
import { useHostRiskScore } from '../../../risk_score/containers';
|
||||
import { useQueryToggle } from '../../../common/containers/query_toggle';
|
||||
|
||||
jest.mock('../../../common/containers/query_toggle');
|
||||
jest.mock('../../../risk_score/containers');
|
||||
const useHostRiskScoreMock = useHostRiskScore as jest.Mock;
|
||||
|
||||
const testProps = {
|
||||
setQuery: jest.fn(),
|
||||
deleteQuery: jest.fn(),
|
||||
hostName: 'test-host-name',
|
||||
from: '2020-07-07T08:20:18.966Z',
|
||||
to: '2020-07-08T08:20:18.966Z',
|
||||
};
|
||||
describe('Host Risk Flyout', () => {
|
||||
const mockUseQueryToggle = useQueryToggle as jest.Mock;
|
||||
const mockSetToggle = jest.fn();
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: true, setToggleStatus: mockSetToggle });
|
||||
});
|
||||
it('renders', () => {
|
||||
useHostRiskScoreMock.mockReturnValueOnce([
|
||||
true,
|
||||
|
@ -26,13 +40,7 @@ describe('Host Risk Flyout', () => {
|
|||
|
||||
const { queryByTestId } = render(
|
||||
<TestProviders>
|
||||
<TopHostScoreContributors
|
||||
setQuery={jest.fn()}
|
||||
deleteQuery={jest.fn()}
|
||||
hostName={'test-host-name'}
|
||||
from={'2020-07-07T08:20:18.966Z'}
|
||||
to={'2020-07-08T08:20:18.966Z'}
|
||||
/>
|
||||
<TopHostScoreContributors {...testProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
|
@ -69,13 +77,7 @@ describe('Host Risk Flyout', () => {
|
|||
|
||||
const { queryAllByRole } = render(
|
||||
<TestProviders>
|
||||
<TopHostScoreContributors
|
||||
setQuery={jest.fn()}
|
||||
deleteQuery={jest.fn()}
|
||||
hostName={'test-host-name'}
|
||||
from={'2020-07-07T08:20:18.966Z'}
|
||||
to={'2020-07-08T08:20:18.966Z'}
|
||||
/>
|
||||
<TopHostScoreContributors {...testProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
|
@ -83,4 +85,66 @@ describe('Host Risk Flyout', () => {
|
|||
expect(queryAllByRole('row')[2]).toHaveTextContent('second');
|
||||
expect(queryAllByRole('row')[3]).toHaveTextContent('third');
|
||||
});
|
||||
|
||||
describe('toggleQuery', () => {
|
||||
beforeEach(() => {
|
||||
useHostRiskScoreMock.mockReturnValue([
|
||||
true,
|
||||
{
|
||||
data: [],
|
||||
isModuleEnabled: true,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test('toggleQuery updates toggleStatus', () => {
|
||||
const { getByTestId } = render(
|
||||
<TestProviders>
|
||||
<TopHostScoreContributors {...testProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(useHostRiskScoreMock.mock.calls[0][0].skip).toEqual(false);
|
||||
fireEvent.click(getByTestId('query-toggle-header'));
|
||||
expect(mockSetToggle).toBeCalledWith(false);
|
||||
expect(useHostRiskScoreMock.mock.calls[1][0].skip).toEqual(true);
|
||||
});
|
||||
|
||||
test('toggleStatus=true, do not skip', () => {
|
||||
render(
|
||||
<TestProviders>
|
||||
<TopHostScoreContributors {...testProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(useHostRiskScoreMock.mock.calls[0][0].skip).toEqual(false);
|
||||
});
|
||||
|
||||
test('toggleStatus=true, render components', () => {
|
||||
const { queryByTestId } = render(
|
||||
<TestProviders>
|
||||
<TopHostScoreContributors {...testProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(queryByTestId('topHostScoreContributors-table')).toBeTruthy();
|
||||
});
|
||||
|
||||
test('toggleStatus=false, do not render components', () => {
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: false, setToggleStatus: mockSetToggle });
|
||||
const { queryByTestId } = render(
|
||||
<TestProviders>
|
||||
<TopHostScoreContributors {...testProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(queryByTestId('topHostScoreContributors-table')).toBeFalsy();
|
||||
});
|
||||
|
||||
test('toggleStatus=false, skip', () => {
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: false, setToggleStatus: mockSetToggle });
|
||||
render(
|
||||
<TestProviders>
|
||||
<TopHostScoreContributors {...testProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(useHostRiskScoreMock.mock.calls[0][0].skip).toEqual(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { useMemo } from 'react';
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
|
||||
import {
|
||||
EuiFlexGroup,
|
||||
|
@ -27,6 +27,7 @@ import { HostsComponentsQueryProps } from '../../pages/navigation/types';
|
|||
|
||||
import { RuleLink } from '../../../detections/pages/detection_engine/rules/all/use_columns';
|
||||
import { HostRiskScoreQueryId, useHostRiskScore } from '../../../risk_score/containers';
|
||||
import { useQueryToggle } from '../../../common/containers/query_toggle';
|
||||
|
||||
export interface TopHostScoreContributorsProps
|
||||
extends Pick<HostsComponentsQueryProps, 'setQuery' | 'deleteQuery'> {
|
||||
|
@ -77,11 +78,27 @@ const TopHostScoreContributorsComponent: React.FC<TopHostScoreContributorsProps>
|
|||
|
||||
const sort = useMemo(() => ({ field: RiskScoreFields.timestamp, direction: Direction.desc }), []);
|
||||
|
||||
const { toggleStatus, setToggleStatus } = useQueryToggle(QUERY_ID);
|
||||
const [querySkip, setQuerySkip] = useState(!toggleStatus);
|
||||
useEffect(() => {
|
||||
setQuerySkip(!toggleStatus);
|
||||
}, [toggleStatus]);
|
||||
|
||||
const toggleQuery = useCallback(
|
||||
(status: boolean) => {
|
||||
setToggleStatus(status);
|
||||
// toggle on = skipQuery false
|
||||
setQuerySkip(!status);
|
||||
},
|
||||
[setQuerySkip, setToggleStatus]
|
||||
);
|
||||
|
||||
const [loading, { data, refetch, inspect }] = useHostRiskScore({
|
||||
filterQuery: hostName ? buildHostNamesFilter([hostName]) : undefined,
|
||||
timerange,
|
||||
onlyLatest: false,
|
||||
sort,
|
||||
skip: querySkip,
|
||||
pagination: {
|
||||
querySize: 1,
|
||||
cursorStart: 0,
|
||||
|
@ -119,24 +136,37 @@ const TopHostScoreContributorsComponent: React.FC<TopHostScoreContributorsProps>
|
|||
<EuiPanel hasBorder data-test-subj="topHostScoreContributors">
|
||||
<EuiFlexGroup gutterSize={'none'}>
|
||||
<EuiFlexItem grow={1}>
|
||||
<HeaderSection title={i18n.TOP_RISK_SCORE_CONTRIBUTORS} hideSubtitle />
|
||||
</EuiFlexItem>
|
||||
|
||||
<EuiFlexItem grow={false}>
|
||||
<InspectButton queryId={QUERY_ID} title={i18n.TOP_RISK_SCORE_CONTRIBUTORS} />
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
|
||||
<EuiFlexGroup gutterSize="none" direction="column">
|
||||
<EuiFlexItem grow={1}>
|
||||
<EuiInMemoryTable
|
||||
items={items}
|
||||
columns={columns}
|
||||
pagination={tablePagination}
|
||||
loading={loading}
|
||||
<HeaderSection
|
||||
height={!toggleStatus ? 40 : undefined}
|
||||
title={i18n.TOP_RISK_SCORE_CONTRIBUTORS}
|
||||
hideSubtitle
|
||||
toggleQuery={toggleQuery}
|
||||
toggleStatus={toggleStatus}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
{toggleStatus && (
|
||||
<EuiFlexItem grow={false}>
|
||||
<InspectButton queryId={QUERY_ID} title={i18n.TOP_RISK_SCORE_CONTRIBUTORS} />
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
</EuiFlexGroup>
|
||||
|
||||
{toggleStatus && (
|
||||
<EuiFlexGroup
|
||||
data-test-subj="topHostScoreContributors-table"
|
||||
gutterSize="none"
|
||||
direction="column"
|
||||
>
|
||||
<EuiFlexItem grow={1}>
|
||||
<EuiInMemoryTable
|
||||
items={items}
|
||||
columns={columns}
|
||||
pagination={tablePagination}
|
||||
loading={loading}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
)}
|
||||
</EuiPanel>
|
||||
</InspectButtonContainer>
|
||||
);
|
||||
|
|
|
@ -205,6 +205,7 @@ exports[`Uncommon Process Table Component rendering it renders the default Uncom
|
|||
isInspect={false}
|
||||
loadPage={[MockFunction]}
|
||||
loading={false}
|
||||
setQuerySkip={[MockFunction]}
|
||||
showMorePagesIndicator={true}
|
||||
totalCount={5}
|
||||
type="page"
|
||||
|
|
|
@ -36,21 +36,24 @@ describe('Uncommon Process Table Component', () => {
|
|||
const loadPage = jest.fn();
|
||||
const mount = useMountAppended();
|
||||
|
||||
const defaultProps = {
|
||||
data: mockData.edges,
|
||||
fakeTotalCount: getOr(50, 'fakeTotalCount', mockData.pageInfo),
|
||||
id: 'uncommonProcess',
|
||||
isInspect: false,
|
||||
loading: false,
|
||||
loadPage,
|
||||
setQuerySkip: jest.fn(),
|
||||
showMorePagesIndicator: getOr(false, 'showMorePagesIndicator', mockData.pageInfo),
|
||||
totalCount: mockData.totalCount,
|
||||
type: hostsModel.HostsType.page,
|
||||
};
|
||||
|
||||
describe('rendering', () => {
|
||||
test('it renders the default Uncommon process table', () => {
|
||||
const wrapper = shallow(
|
||||
<TestProviders>
|
||||
<UncommonProcessTable
|
||||
data={mockData.edges}
|
||||
fakeTotalCount={getOr(50, 'fakeTotalCount', mockData.pageInfo)}
|
||||
id="uncommonProcess"
|
||||
isInspect={false}
|
||||
loading={false}
|
||||
loadPage={loadPage}
|
||||
showMorePagesIndicator={getOr(false, 'showMorePagesIndicator', mockData.pageInfo)}
|
||||
totalCount={mockData.totalCount}
|
||||
type={hostsModel.HostsType.page}
|
||||
/>
|
||||
<UncommonProcessTable {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
|
@ -60,17 +63,7 @@ describe('Uncommon Process Table Component', () => {
|
|||
test('it has a double dash (empty value) without any hosts at all', () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<UncommonProcessTable
|
||||
data={mockData.edges}
|
||||
fakeTotalCount={getOr(50, 'fakeTotalCount', mockData.pageInfo)}
|
||||
id="uncommonProcess"
|
||||
isInspect={false}
|
||||
loading={false}
|
||||
loadPage={loadPage}
|
||||
showMorePagesIndicator={getOr(false, 'showMorePagesIndicator', mockData.pageInfo)}
|
||||
totalCount={mockData.totalCount}
|
||||
type={hostsModel.HostsType.page}
|
||||
/>
|
||||
<UncommonProcessTable {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(wrapper.find('.euiTableRow').at(0).find('.euiTableRowCell').at(3).text()).toBe(
|
||||
|
@ -81,17 +74,7 @@ describe('Uncommon Process Table Component', () => {
|
|||
test('it has a single host without any extra comma when the number of hosts is exactly 1', () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<UncommonProcessTable
|
||||
data={mockData.edges}
|
||||
fakeTotalCount={getOr(50, 'fakeTotalCount', mockData.pageInfo)}
|
||||
id="uncommonProcess"
|
||||
isInspect={false}
|
||||
loading={false}
|
||||
loadPage={loadPage}
|
||||
showMorePagesIndicator={getOr(false, 'showMorePagesIndicator', mockData.pageInfo)}
|
||||
totalCount={mockData.totalCount}
|
||||
type={hostsModel.HostsType.page}
|
||||
/>
|
||||
<UncommonProcessTable {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
|
@ -103,17 +86,7 @@ describe('Uncommon Process Table Component', () => {
|
|||
test('it has a single link when the number of hosts is exactly 1', () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<UncommonProcessTable
|
||||
data={mockData.edges}
|
||||
fakeTotalCount={getOr(50, 'fakeTotalCount', mockData.pageInfo)}
|
||||
id="uncommonProcess"
|
||||
isInspect={false}
|
||||
loading={false}
|
||||
loadPage={loadPage}
|
||||
showMorePagesIndicator={getOr(false, 'showMorePagesIndicator', mockData.pageInfo)}
|
||||
totalCount={mockData.totalCount}
|
||||
type={hostsModel.HostsType.page}
|
||||
/>
|
||||
<UncommonProcessTable {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
|
@ -125,17 +98,7 @@ describe('Uncommon Process Table Component', () => {
|
|||
test('it has a comma separated list of hosts when the number of hosts is greater than 1', () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<UncommonProcessTable
|
||||
data={mockData.edges}
|
||||
fakeTotalCount={getOr(50, 'fakeTotalCount', mockData.pageInfo)}
|
||||
id="uncommonProcess"
|
||||
isInspect={false}
|
||||
loading={false}
|
||||
loadPage={loadPage}
|
||||
showMorePagesIndicator={getOr(false, 'showMorePagesIndicator', mockData.pageInfo)}
|
||||
totalCount={mockData.totalCount}
|
||||
type={hostsModel.HostsType.page}
|
||||
/>
|
||||
<UncommonProcessTable {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
|
@ -147,17 +110,7 @@ describe('Uncommon Process Table Component', () => {
|
|||
test('it has 2 links when the number of hosts is equal to 2', () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<UncommonProcessTable
|
||||
data={mockData.edges}
|
||||
fakeTotalCount={getOr(50, 'fakeTotalCount', mockData.pageInfo)}
|
||||
id="uncommonProcess"
|
||||
isInspect={false}
|
||||
loading={false}
|
||||
loadPage={loadPage}
|
||||
showMorePagesIndicator={getOr(false, 'showMorePagesIndicator', mockData.pageInfo)}
|
||||
totalCount={mockData.totalCount}
|
||||
type={hostsModel.HostsType.page}
|
||||
/>
|
||||
<UncommonProcessTable {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
|
@ -169,17 +122,7 @@ describe('Uncommon Process Table Component', () => {
|
|||
test('it is empty when all hosts are invalid because they do not contain an id and a name', () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<UncommonProcessTable
|
||||
data={mockData.edges}
|
||||
fakeTotalCount={getOr(50, 'fakeTotalCount', mockData.pageInfo)}
|
||||
id="uncommonProcess"
|
||||
isInspect={false}
|
||||
loading={false}
|
||||
loadPage={loadPage}
|
||||
showMorePagesIndicator={getOr(false, 'showMorePagesIndicator', mockData.pageInfo)}
|
||||
totalCount={mockData.totalCount}
|
||||
type={hostsModel.HostsType.page}
|
||||
/>
|
||||
<UncommonProcessTable {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(wrapper.find('.euiTableRow').at(3).find('.euiTableRowCell').at(3).text()).toBe(
|
||||
|
@ -190,17 +133,7 @@ describe('Uncommon Process Table Component', () => {
|
|||
test('it has no link when all hosts are invalid because they do not contain an id and a name', () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<UncommonProcessTable
|
||||
data={mockData.edges}
|
||||
fakeTotalCount={getOr(50, 'fakeTotalCount', mockData.pageInfo)}
|
||||
id="uncommonProcess"
|
||||
isInspect={false}
|
||||
loading={false}
|
||||
loadPage={loadPage}
|
||||
showMorePagesIndicator={getOr(false, 'showMorePagesIndicator', mockData.pageInfo)}
|
||||
totalCount={mockData.totalCount}
|
||||
type={hostsModel.HostsType.page}
|
||||
/>
|
||||
<UncommonProcessTable {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(
|
||||
|
@ -211,17 +144,7 @@ describe('Uncommon Process Table Component', () => {
|
|||
test('it is returns two hosts when others are invalid because they do not contain an id and a name', () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<UncommonProcessTable
|
||||
data={mockData.edges}
|
||||
fakeTotalCount={getOr(50, 'fakeTotalCount', mockData.pageInfo)}
|
||||
id="uncommonProcess"
|
||||
isInspect={false}
|
||||
loading={false}
|
||||
loadPage={loadPage}
|
||||
showMorePagesIndicator={getOr(false, 'showMorePagesIndicator', mockData.pageInfo)}
|
||||
totalCount={mockData.totalCount}
|
||||
type={hostsModel.HostsType.page}
|
||||
/>
|
||||
<UncommonProcessTable {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(wrapper.find('.euiTableRow').at(4).find('.euiTableRowCell').at(3).text()).toBe(
|
||||
|
|
|
@ -30,6 +30,7 @@ interface UncommonProcessTableProps {
|
|||
isInspect: boolean;
|
||||
loading: boolean;
|
||||
loadPage: (newActivePage: number) => void;
|
||||
setQuerySkip: (skip: boolean) => void;
|
||||
showMorePagesIndicator: boolean;
|
||||
totalCount: number;
|
||||
type: hostsModel.HostsType;
|
||||
|
@ -72,6 +73,7 @@ const UncommonProcessTableComponent = React.memo<UncommonProcessTableProps>(
|
|||
loading,
|
||||
loadPage,
|
||||
totalCount,
|
||||
setQuerySkip,
|
||||
showMorePagesIndicator,
|
||||
type,
|
||||
}) => {
|
||||
|
@ -125,6 +127,7 @@ const UncommonProcessTableComponent = React.memo<UncommonProcessTableProps>(
|
|||
loading={loading}
|
||||
loadPage={loadPage}
|
||||
pageOfItems={data}
|
||||
setQuerySkip={setQuerySkip}
|
||||
showMorePagesIndicator={showMorePagesIndicator}
|
||||
totalCount={fakeTotalCount}
|
||||
updateLimitPagination={updateLimitPagination}
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* 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 { act, renderHook } from '@testing-library/react-hooks';
|
||||
import { TestProviders } from '../../../common/mock';
|
||||
import { useAuthentications } from './index';
|
||||
import { HostsType } from '../../store/model';
|
||||
|
||||
describe('authentications', () => {
|
||||
it('skip = true will cancel any running request', () => {
|
||||
const abortSpy = jest.spyOn(AbortController.prototype, 'abort');
|
||||
const localProps = {
|
||||
startDate: '2020-07-07T08:20:18.966Z',
|
||||
endDate: '2020-07-08T08:20:18.966Z',
|
||||
indexNames: ['cool'],
|
||||
type: HostsType.page,
|
||||
skip: false,
|
||||
};
|
||||
const { rerender } = renderHook(() => useAuthentications(localProps), {
|
||||
wrapper: TestProviders,
|
||||
});
|
||||
localProps.skip = true;
|
||||
act(() => rerender());
|
||||
expect(abortSpy).toHaveBeenCalledTimes(4);
|
||||
});
|
||||
});
|
|
@ -36,7 +36,7 @@ import * as i18n from './translations';
|
|||
import { useTransforms } from '../../../transforms/containers/use_transforms';
|
||||
import { useAppToasts } from '../../../common/hooks/use_app_toasts';
|
||||
|
||||
const ID = 'hostsAuthenticationsQuery';
|
||||
export const ID = 'hostsAuthenticationsQuery';
|
||||
|
||||
export interface AuthenticationArgs {
|
||||
authentications: AuthenticationsEdges[];
|
||||
|
@ -215,5 +215,13 @@ export const useAuthentications = ({
|
|||
};
|
||||
}, [authenticationsRequest, authenticationsSearch]);
|
||||
|
||||
useEffect(() => {
|
||||
if (skip) {
|
||||
setLoading(false);
|
||||
searchSubscription$.current.unsubscribe();
|
||||
abortCtrl.current.abort();
|
||||
}
|
||||
}, [skip]);
|
||||
|
||||
return [loading, authenticationsResponse];
|
||||
};
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* 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 { act, renderHook } from '@testing-library/react-hooks';
|
||||
import { TestProviders } from '../../../common/mock';
|
||||
import { useAllHost } from './index';
|
||||
import { HostsType } from '../../store/model';
|
||||
|
||||
describe('useAllHost', () => {
|
||||
it('skip = true will cancel any running request', () => {
|
||||
const abortSpy = jest.spyOn(AbortController.prototype, 'abort');
|
||||
const localProps = {
|
||||
startDate: '2020-07-07T08:20:18.966Z',
|
||||
endDate: '2020-07-08T08:20:18.966Z',
|
||||
indexNames: ['cool'],
|
||||
type: HostsType.page,
|
||||
skip: false,
|
||||
};
|
||||
const { rerender } = renderHook(() => useAllHost(localProps), {
|
||||
wrapper: TestProviders,
|
||||
});
|
||||
localProps.skip = true;
|
||||
act(() => rerender());
|
||||
expect(abortSpy).toHaveBeenCalledTimes(4);
|
||||
});
|
||||
});
|
|
@ -217,5 +217,13 @@ export const useAllHost = ({
|
|||
};
|
||||
}, [hostsRequest, hostsSearch]);
|
||||
|
||||
useEffect(() => {
|
||||
if (skip) {
|
||||
setLoading(false);
|
||||
searchSubscription.current.unsubscribe();
|
||||
abortCtrl.current.abort();
|
||||
}
|
||||
}, [skip]);
|
||||
|
||||
return [loading, hostsResponse];
|
||||
};
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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 { act, renderHook } from '@testing-library/react-hooks';
|
||||
import { TestProviders } from '../../../../common/mock';
|
||||
import { useHostsKpiAuthentications } from './index';
|
||||
|
||||
describe('kpi hosts - authentications', () => {
|
||||
it('skip = true will cancel any running request', () => {
|
||||
const abortSpy = jest.spyOn(AbortController.prototype, 'abort');
|
||||
const localProps = {
|
||||
startDate: '2020-07-07T08:20:18.966Z',
|
||||
endDate: '2020-07-08T08:20:18.966Z',
|
||||
indexNames: ['cool'],
|
||||
skip: false,
|
||||
};
|
||||
const { rerender } = renderHook(() => useHostsKpiAuthentications(localProps), {
|
||||
wrapper: TestProviders,
|
||||
});
|
||||
localProps.skip = true;
|
||||
act(() => rerender());
|
||||
expect(abortSpy).toHaveBeenCalledTimes(4);
|
||||
});
|
||||
});
|
|
@ -26,7 +26,7 @@ import * as i18n from './translations';
|
|||
import { getInspectResponse } from '../../../../helpers';
|
||||
import { InspectResponse } from '../../../../types';
|
||||
|
||||
const ID = 'hostsKpiAuthenticationsQuery';
|
||||
export const ID = 'hostsKpiAuthenticationsQuery';
|
||||
|
||||
export interface HostsKpiAuthenticationsArgs
|
||||
extends Omit<HostsKpiAuthenticationsStrategyResponse, 'rawResponse'> {
|
||||
|
@ -165,5 +165,13 @@ export const useHostsKpiAuthentications = ({
|
|||
};
|
||||
}, [hostsKpiAuthenticationsRequest, hostsKpiAuthenticationsSearch]);
|
||||
|
||||
useEffect(() => {
|
||||
if (skip) {
|
||||
setLoading(false);
|
||||
searchSubscription$.current.unsubscribe();
|
||||
abortCtrl.current.abort();
|
||||
}
|
||||
}, [skip]);
|
||||
|
||||
return [loading, hostsKpiAuthenticationsResponse];
|
||||
};
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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 { act, renderHook } from '@testing-library/react-hooks';
|
||||
import { TestProviders } from '../../../../common/mock';
|
||||
import { useHostsKpiHosts } from './index';
|
||||
|
||||
describe('kpi hosts - hosts', () => {
|
||||
it('skip = true will cancel any running request', () => {
|
||||
const abortSpy = jest.spyOn(AbortController.prototype, 'abort');
|
||||
const localProps = {
|
||||
startDate: '2020-07-07T08:20:18.966Z',
|
||||
endDate: '2020-07-08T08:20:18.966Z',
|
||||
indexNames: ['cool'],
|
||||
skip: false,
|
||||
};
|
||||
const { rerender } = renderHook(() => useHostsKpiHosts(localProps), {
|
||||
wrapper: TestProviders,
|
||||
});
|
||||
localProps.skip = true;
|
||||
act(() => rerender());
|
||||
expect(abortSpy).toHaveBeenCalledTimes(4);
|
||||
});
|
||||
});
|
|
@ -26,7 +26,7 @@ import * as i18n from './translations';
|
|||
import { getInspectResponse } from '../../../../helpers';
|
||||
import { InspectResponse } from '../../../../types';
|
||||
|
||||
const ID = 'hostsKpiHostsQuery';
|
||||
export const ID = 'hostsKpiHostsQuery';
|
||||
|
||||
export interface HostsKpiHostsArgs extends Omit<HostsKpiHostsStrategyResponse, 'rawResponse'> {
|
||||
id: string;
|
||||
|
@ -155,5 +155,13 @@ export const useHostsKpiHosts = ({
|
|||
};
|
||||
}, [hostsKpiHostsRequest, hostsKpiHostsSearch]);
|
||||
|
||||
useEffect(() => {
|
||||
if (skip) {
|
||||
setLoading(false);
|
||||
searchSubscription$.current.unsubscribe();
|
||||
abortCtrl.current.abort();
|
||||
}
|
||||
}, [skip]);
|
||||
|
||||
return [loading, hostsKpiHostsResponse];
|
||||
};
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export * from './authentications';
|
||||
export * from './hosts';
|
||||
export * from './unique_ips';
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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 { act, renderHook } from '@testing-library/react-hooks';
|
||||
import { TestProviders } from '../../../../common/mock';
|
||||
import { useHostsKpiUniqueIps } from './index';
|
||||
|
||||
describe('kpi hosts - Unique Ips', () => {
|
||||
it('skip = true will cancel any running request', () => {
|
||||
const abortSpy = jest.spyOn(AbortController.prototype, 'abort');
|
||||
const localProps = {
|
||||
startDate: '2020-07-07T08:20:18.966Z',
|
||||
endDate: '2020-07-08T08:20:18.966Z',
|
||||
indexNames: ['cool'],
|
||||
skip: false,
|
||||
};
|
||||
const { rerender } = renderHook(() => useHostsKpiUniqueIps(localProps), {
|
||||
wrapper: TestProviders,
|
||||
});
|
||||
localProps.skip = true;
|
||||
act(() => rerender());
|
||||
expect(abortSpy).toHaveBeenCalledTimes(4);
|
||||
});
|
||||
});
|
|
@ -26,7 +26,7 @@ import * as i18n from './translations';
|
|||
import { getInspectResponse } from '../../../../helpers';
|
||||
import { InspectResponse } from '../../../../types';
|
||||
|
||||
const ID = 'hostsKpiUniqueIpsQuery';
|
||||
export const ID = 'hostsKpiUniqueIpsQuery';
|
||||
|
||||
export interface HostsKpiUniqueIpsArgs
|
||||
extends Omit<HostsKpiUniqueIpsStrategyResponse, 'rawResponse'> {
|
||||
|
@ -163,5 +163,13 @@ export const useHostsKpiUniqueIps = ({
|
|||
};
|
||||
}, [hostsKpiUniqueIpsRequest, hostsKpiUniqueIpsSearch]);
|
||||
|
||||
useEffect(() => {
|
||||
if (skip) {
|
||||
setLoading(false);
|
||||
searchSubscription$.current.unsubscribe();
|
||||
abortCtrl.current.abort();
|
||||
}
|
||||
}, [skip]);
|
||||
|
||||
return [loading, hostsKpiUniqueIpsResponse];
|
||||
};
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* 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 { act, renderHook } from '@testing-library/react-hooks';
|
||||
import { TestProviders } from '../../../common/mock';
|
||||
import { useUncommonProcesses } from './index';
|
||||
import { HostsType } from '../../store/model';
|
||||
|
||||
describe('useUncommonProcesses', () => {
|
||||
it('skip = true will cancel any running request', () => {
|
||||
const abortSpy = jest.spyOn(AbortController.prototype, 'abort');
|
||||
const localProps = {
|
||||
startDate: '2020-07-07T08:20:18.966Z',
|
||||
endDate: '2020-07-08T08:20:18.966Z',
|
||||
indexNames: ['cool'],
|
||||
type: HostsType.page,
|
||||
skip: false,
|
||||
};
|
||||
const { rerender } = renderHook(() => useUncommonProcesses(localProps), {
|
||||
wrapper: TestProviders,
|
||||
});
|
||||
localProps.skip = true;
|
||||
act(() => rerender());
|
||||
expect(abortSpy).toHaveBeenCalledTimes(4);
|
||||
});
|
||||
});
|
|
@ -34,7 +34,7 @@ import { InspectResponse } from '../../../types';
|
|||
import { useDeepEqualSelector } from '../../../common/hooks/use_selector';
|
||||
import { useAppToasts } from '../../../common/hooks/use_app_toasts';
|
||||
|
||||
const ID = 'hostsUncommonProcessesQuery';
|
||||
export const ID = 'hostsUncommonProcessesQuery';
|
||||
|
||||
export interface UncommonProcessesArgs {
|
||||
id: string;
|
||||
|
@ -202,5 +202,13 @@ export const useUncommonProcesses = ({
|
|||
};
|
||||
}, [uncommonProcessesRequest, uncommonProcessesSearch]);
|
||||
|
||||
useEffect(() => {
|
||||
if (skip) {
|
||||
setLoading(false);
|
||||
searchSubscription$.current.unsubscribe();
|
||||
abortCtrl.current.abort();
|
||||
}
|
||||
}, [skip]);
|
||||
|
||||
return [loading, uncommonProcessesResponse];
|
||||
};
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* 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 React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import { TestProviders } from '../../../common/mock';
|
||||
import { useAuthentications } from '../../containers/authentications';
|
||||
import { useQueryToggle } from '../../../common/containers/query_toggle';
|
||||
import { AuthenticationsQueryTabBody } from './authentications_query_tab_body';
|
||||
import { HostsType } from '../../store/model';
|
||||
|
||||
jest.mock('../../containers/authentications');
|
||||
jest.mock('../../../common/containers/query_toggle');
|
||||
jest.mock('../../../common/lib/kibana');
|
||||
|
||||
describe('Authentications query tab body', () => {
|
||||
const mockUseAuthentications = useAuthentications as jest.Mock;
|
||||
const mockUseQueryToggle = useQueryToggle as jest.Mock;
|
||||
const defaultProps = {
|
||||
indexNames: [],
|
||||
setQuery: jest.fn(),
|
||||
skip: false,
|
||||
startDate: '2019-06-25T04:31:59.345Z',
|
||||
endDate: '2019-06-25T06:31:59.345Z',
|
||||
type: HostsType.page,
|
||||
};
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: true, setToggleStatus: jest.fn() });
|
||||
mockUseAuthentications.mockReturnValue([
|
||||
false,
|
||||
{
|
||||
authentications: [],
|
||||
id: '123',
|
||||
inspect: {
|
||||
dsl: [],
|
||||
response: [],
|
||||
},
|
||||
isInspected: false,
|
||||
totalCount: 0,
|
||||
pageInfo: { activePage: 1, fakeTotalCount: 100, showMorePagesIndicator: false },
|
||||
loadPage: jest.fn(),
|
||||
refetch: jest.fn(),
|
||||
},
|
||||
]);
|
||||
});
|
||||
it('toggleStatus=true, do not skip', () => {
|
||||
render(
|
||||
<TestProviders>
|
||||
<AuthenticationsQueryTabBody {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(mockUseAuthentications.mock.calls[0][0].skip).toEqual(false);
|
||||
});
|
||||
it('toggleStatus=false, skip', () => {
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: false, setToggleStatus: jest.fn() });
|
||||
render(
|
||||
<TestProviders>
|
||||
<AuthenticationsQueryTabBody {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(mockUseAuthentications.mock.calls[0][0].skip).toEqual(true);
|
||||
});
|
||||
});
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import { getOr } from 'lodash/fp';
|
||||
import React, { useEffect } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { AuthenticationTable } from '../../components/authentications_table';
|
||||
import { manageQuery } from '../../../common/components/page/manage_query';
|
||||
import { useAuthentications } from '../../containers/authentications';
|
||||
|
@ -22,6 +22,7 @@ import * as i18n from '../translations';
|
|||
import { MatrixHistogramType } from '../../../../common/search_strategy/security_solution';
|
||||
import { authenticationLensAttributes } from '../../../common/components/visualization_actions/lens_attributes/hosts/authentication';
|
||||
import { LensAttributes } from '../../../common/components/visualization_actions/types';
|
||||
import { useQueryToggle } from '../../../common/containers/query_toggle';
|
||||
|
||||
const AuthenticationTableManage = manageQuery(AuthenticationTable);
|
||||
|
||||
|
@ -76,6 +77,11 @@ const AuthenticationsQueryTabBodyComponent: React.FC<HostsComponentsQueryProps>
|
|||
startDate,
|
||||
type,
|
||||
}) => {
|
||||
const { toggleStatus } = useQueryToggle(ID);
|
||||
const [querySkip, setQuerySkip] = useState(skip || !toggleStatus);
|
||||
useEffect(() => {
|
||||
setQuerySkip(skip || !toggleStatus);
|
||||
}, [skip, toggleStatus]);
|
||||
const [
|
||||
loading,
|
||||
{ authentications, totalCount, pageInfo, loadPage, id, inspect, isInspected, refetch },
|
||||
|
@ -84,7 +90,7 @@ const AuthenticationsQueryTabBodyComponent: React.FC<HostsComponentsQueryProps>
|
|||
endDate,
|
||||
filterQuery,
|
||||
indexNames,
|
||||
skip,
|
||||
skip: querySkip,
|
||||
startDate,
|
||||
type,
|
||||
});
|
||||
|
@ -119,6 +125,7 @@ const AuthenticationsQueryTabBodyComponent: React.FC<HostsComponentsQueryProps>
|
|||
loading={loading}
|
||||
loadPage={loadPage}
|
||||
refetch={refetch}
|
||||
setQuerySkip={setQuerySkip}
|
||||
showMorePagesIndicator={getOr(false, 'showMorePagesIndicator', pageInfo)}
|
||||
setQuery={setQuery}
|
||||
totalCount={totalCount}
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* 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 React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import { TestProviders } from '../../../common/mock';
|
||||
import { useHostRiskScore, useHostRiskScoreKpi } from '../../../risk_score/containers';
|
||||
import { useQueryToggle } from '../../../common/containers/query_toggle';
|
||||
import { HostRiskScoreQueryTabBody } from './host_risk_score_tab_body';
|
||||
import { HostsType } from '../../store/model';
|
||||
|
||||
jest.mock('../../../risk_score/containers');
|
||||
jest.mock('../../../common/containers/query_toggle');
|
||||
jest.mock('../../../common/lib/kibana');
|
||||
|
||||
describe('Host risk score query tab body', () => {
|
||||
const mockUseHostRiskScore = useHostRiskScore as jest.Mock;
|
||||
const mockUseHostRiskScoreKpi = useHostRiskScoreKpi as jest.Mock;
|
||||
const mockUseQueryToggle = useQueryToggle as jest.Mock;
|
||||
const defaultProps = {
|
||||
indexNames: [],
|
||||
setQuery: jest.fn(),
|
||||
skip: false,
|
||||
startDate: '2019-06-25T04:31:59.345Z',
|
||||
endDate: '2019-06-25T06:31:59.345Z',
|
||||
type: HostsType.page,
|
||||
};
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: true, setToggleStatus: jest.fn() });
|
||||
mockUseHostRiskScoreKpi.mockReturnValue({
|
||||
loading: false,
|
||||
severityCount: {
|
||||
unknown: 12,
|
||||
low: 12,
|
||||
moderate: 12,
|
||||
high: 12,
|
||||
critical: 12,
|
||||
},
|
||||
});
|
||||
mockUseHostRiskScore.mockReturnValue([
|
||||
false,
|
||||
{
|
||||
hosts: [],
|
||||
id: '123',
|
||||
inspect: {
|
||||
dsl: [],
|
||||
response: [],
|
||||
},
|
||||
isInspected: false,
|
||||
totalCount: 0,
|
||||
pageInfo: { activePage: 1, fakeTotalCount: 100, showMorePagesIndicator: false },
|
||||
loadPage: jest.fn(),
|
||||
refetch: jest.fn(),
|
||||
},
|
||||
]);
|
||||
});
|
||||
it('toggleStatus=true, do not skip', () => {
|
||||
render(
|
||||
<TestProviders>
|
||||
<HostRiskScoreQueryTabBody {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(mockUseHostRiskScore.mock.calls[0][0].skip).toEqual(false);
|
||||
expect(mockUseHostRiskScoreKpi.mock.calls[0][0].skip).toEqual(false);
|
||||
});
|
||||
it('toggleStatus=false, skip', () => {
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: false, setToggleStatus: jest.fn() });
|
||||
render(
|
||||
<TestProviders>
|
||||
<HostRiskScoreQueryTabBody {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(mockUseHostRiskScore.mock.calls[0][0].skip).toEqual(true);
|
||||
expect(mockUseHostRiskScoreKpi.mock.calls[0][0].skip).toEqual(true);
|
||||
});
|
||||
});
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { useMemo } from 'react';
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import { noop } from 'lodash/fp';
|
||||
import { HostsComponentsQueryProps } from './types';
|
||||
import { manageQuery } from '../../../common/components/page/manage_query';
|
||||
|
@ -18,6 +18,7 @@ import {
|
|||
useHostRiskScore,
|
||||
useHostRiskScoreKpi,
|
||||
} from '../../../risk_score/containers';
|
||||
import { useQueryToggle } from '../../../common/containers/query_toggle';
|
||||
|
||||
const HostRiskScoreTableManage = manageQuery(HostRiskScoreTable);
|
||||
|
||||
|
@ -43,15 +44,22 @@ export const HostRiskScoreQueryTabBody = ({
|
|||
[activePage, limit]
|
||||
);
|
||||
|
||||
const { toggleStatus } = useQueryToggle(HostRiskScoreQueryId.HOSTS_BY_RISK);
|
||||
const [querySkip, setQuerySkip] = useState(skip || !toggleStatus);
|
||||
useEffect(() => {
|
||||
setQuerySkip(!toggleStatus);
|
||||
}, [toggleStatus]);
|
||||
|
||||
const [loading, { data, totalCount, inspect, isInspected, refetch }] = useHostRiskScore({
|
||||
filterQuery,
|
||||
skip,
|
||||
skip: querySkip,
|
||||
pagination,
|
||||
sort,
|
||||
});
|
||||
|
||||
const { severityCount, loading: isKpiLoading } = useHostRiskScoreKpi({
|
||||
filterQuery,
|
||||
skip: querySkip,
|
||||
});
|
||||
|
||||
return (
|
||||
|
@ -65,6 +73,7 @@ export const HostRiskScoreQueryTabBody = ({
|
|||
loadPage={noop} // It isn't necessary because PaginatedTable updates redux store and we load the page when activePage updates on the store
|
||||
refetch={refetch}
|
||||
setQuery={setQuery}
|
||||
setQuerySkip={setQuerySkip}
|
||||
severityCount={severityCount}
|
||||
totalCount={totalCount}
|
||||
type={type}
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* 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 React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import { TestProviders } from '../../../common/mock';
|
||||
import { useAllHost } from '../../containers/hosts';
|
||||
import { useQueryToggle } from '../../../common/containers/query_toggle';
|
||||
import { HostsQueryTabBody } from './hosts_query_tab_body';
|
||||
import { HostsType } from '../../store/model';
|
||||
|
||||
jest.mock('../../containers/hosts');
|
||||
jest.mock('../../../common/containers/query_toggle');
|
||||
jest.mock('../../../common/lib/kibana');
|
||||
|
||||
describe('Hosts query tab body', () => {
|
||||
const mockUseAllHost = useAllHost as jest.Mock;
|
||||
const mockUseQueryToggle = useQueryToggle as jest.Mock;
|
||||
const defaultProps = {
|
||||
indexNames: [],
|
||||
setQuery: jest.fn(),
|
||||
skip: false,
|
||||
startDate: '2019-06-25T04:31:59.345Z',
|
||||
endDate: '2019-06-25T06:31:59.345Z',
|
||||
type: HostsType.page,
|
||||
};
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: true, setToggleStatus: jest.fn() });
|
||||
mockUseAllHost.mockReturnValue([
|
||||
false,
|
||||
{
|
||||
hosts: [],
|
||||
id: '123',
|
||||
inspect: {
|
||||
dsl: [],
|
||||
response: [],
|
||||
},
|
||||
isInspected: false,
|
||||
totalCount: 0,
|
||||
pageInfo: { activePage: 1, fakeTotalCount: 100, showMorePagesIndicator: false },
|
||||
loadPage: jest.fn(),
|
||||
refetch: jest.fn(),
|
||||
},
|
||||
]);
|
||||
});
|
||||
it('toggleStatus=true, do not skip', () => {
|
||||
render(
|
||||
<TestProviders>
|
||||
<HostsQueryTabBody {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(mockUseAllHost.mock.calls[0][0].skip).toEqual(false);
|
||||
});
|
||||
it('toggleStatus=false, skip', () => {
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: false, setToggleStatus: jest.fn() });
|
||||
render(
|
||||
<TestProviders>
|
||||
<HostsQueryTabBody {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(mockUseAllHost.mock.calls[0][0].skip).toEqual(true);
|
||||
});
|
||||
});
|
|
@ -6,11 +6,12 @@
|
|||
*/
|
||||
|
||||
import { getOr } from 'lodash/fp';
|
||||
import React from 'react';
|
||||
import { useAllHost } from '../../containers/hosts';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useAllHost, ID } from '../../containers/hosts';
|
||||
import { HostsComponentsQueryProps } from './types';
|
||||
import { HostsTable } from '../../components/hosts_table';
|
||||
import { manageQuery } from '../../../common/components/page/manage_query';
|
||||
import { useQueryToggle } from '../../../common/containers/query_toggle';
|
||||
|
||||
const HostsTableManage = manageQuery(HostsTable);
|
||||
|
||||
|
@ -25,8 +26,21 @@ export const HostsQueryTabBody = ({
|
|||
startDate,
|
||||
type,
|
||||
}: HostsComponentsQueryProps) => {
|
||||
const { toggleStatus } = useQueryToggle(ID);
|
||||
const [querySkip, setQuerySkip] = useState(skip || !toggleStatus);
|
||||
useEffect(() => {
|
||||
setQuerySkip(skip || !toggleStatus);
|
||||
}, [skip, toggleStatus]);
|
||||
const [loading, { hosts, totalCount, pageInfo, loadPage, id, inspect, isInspected, refetch }] =
|
||||
useAllHost({ docValueFields, endDate, filterQuery, indexNames, skip, startDate, type });
|
||||
useAllHost({
|
||||
docValueFields,
|
||||
endDate,
|
||||
filterQuery,
|
||||
indexNames,
|
||||
skip: querySkip,
|
||||
startDate,
|
||||
type,
|
||||
});
|
||||
|
||||
return (
|
||||
<HostsTableManage
|
||||
|
@ -40,6 +54,7 @@ export const HostsQueryTabBody = ({
|
|||
loadPage={loadPage}
|
||||
refetch={refetch}
|
||||
setQuery={setQuery}
|
||||
setQuerySkip={setQuerySkip}
|
||||
showMorePagesIndicator={getOr(false, 'showMorePagesIndicator', pageInfo)}
|
||||
totalCount={totalCount}
|
||||
type={type}
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* 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 React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import { TestProviders } from '../../../common/mock';
|
||||
import { useUncommonProcesses } from '../../containers/uncommon_processes';
|
||||
import { useQueryToggle } from '../../../common/containers/query_toggle';
|
||||
import { UncommonProcessQueryTabBody } from './uncommon_process_query_tab_body';
|
||||
import { HostsType } from '../../store/model';
|
||||
|
||||
jest.mock('../../containers/uncommon_processes');
|
||||
jest.mock('../../../common/containers/query_toggle');
|
||||
jest.mock('../../../common/lib/kibana');
|
||||
|
||||
describe('Uncommon process query tab body', () => {
|
||||
const mockUseUncommonProcesses = useUncommonProcesses as jest.Mock;
|
||||
const mockUseQueryToggle = useQueryToggle as jest.Mock;
|
||||
const defaultProps = {
|
||||
indexNames: [],
|
||||
setQuery: jest.fn(),
|
||||
skip: false,
|
||||
startDate: '2019-06-25T04:31:59.345Z',
|
||||
endDate: '2019-06-25T06:31:59.345Z',
|
||||
type: HostsType.page,
|
||||
};
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: true, setToggleStatus: jest.fn() });
|
||||
mockUseUncommonProcesses.mockReturnValue([
|
||||
false,
|
||||
{
|
||||
uncommonProcesses: [],
|
||||
id: '123',
|
||||
inspect: {
|
||||
dsl: [],
|
||||
response: [],
|
||||
},
|
||||
isInspected: false,
|
||||
totalCount: 0,
|
||||
pageInfo: { activePage: 1, fakeTotalCount: 100, showMorePagesIndicator: false },
|
||||
loadPage: jest.fn(),
|
||||
refetch: jest.fn(),
|
||||
},
|
||||
]);
|
||||
});
|
||||
it('toggleStatus=true, do not skip', () => {
|
||||
render(
|
||||
<TestProviders>
|
||||
<UncommonProcessQueryTabBody {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(mockUseUncommonProcesses.mock.calls[0][0].skip).toEqual(false);
|
||||
});
|
||||
it('toggleStatus=false, skip', () => {
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: false, setToggleStatus: jest.fn() });
|
||||
render(
|
||||
<TestProviders>
|
||||
<UncommonProcessQueryTabBody {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(mockUseUncommonProcesses.mock.calls[0][0].skip).toEqual(true);
|
||||
});
|
||||
});
|
|
@ -6,11 +6,12 @@
|
|||
*/
|
||||
|
||||
import { getOr } from 'lodash/fp';
|
||||
import React from 'react';
|
||||
import { useUncommonProcesses } from '../../containers/uncommon_processes';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useUncommonProcesses, ID } from '../../containers/uncommon_processes';
|
||||
import { HostsComponentsQueryProps } from './types';
|
||||
import { UncommonProcessTable } from '../../components/uncommon_process_table';
|
||||
import { manageQuery } from '../../../common/components/page/manage_query';
|
||||
import { useQueryToggle } from '../../../common/containers/query_toggle';
|
||||
|
||||
const UncommonProcessTableManage = manageQuery(UncommonProcessTable);
|
||||
|
||||
|
@ -25,6 +26,11 @@ export const UncommonProcessQueryTabBody = ({
|
|||
startDate,
|
||||
type,
|
||||
}: HostsComponentsQueryProps) => {
|
||||
const { toggleStatus } = useQueryToggle(ID);
|
||||
const [querySkip, setQuerySkip] = useState(skip || !toggleStatus);
|
||||
useEffect(() => {
|
||||
setQuerySkip(skip || !toggleStatus);
|
||||
}, [skip, toggleStatus]);
|
||||
const [
|
||||
loading,
|
||||
{ uncommonProcesses, totalCount, pageInfo, loadPage, id, inspect, isInspected, refetch },
|
||||
|
@ -33,7 +39,7 @@ export const UncommonProcessQueryTabBody = ({
|
|||
endDate,
|
||||
filterQuery,
|
||||
indexNames,
|
||||
skip,
|
||||
skip: querySkip,
|
||||
startDate,
|
||||
type,
|
||||
});
|
||||
|
@ -49,6 +55,7 @@ export const UncommonProcessQueryTabBody = ({
|
|||
loadPage={loadPage}
|
||||
refetch={refetch}
|
||||
setQuery={setQuery}
|
||||
setQuerySkip={setQuerySkip}
|
||||
showMorePagesIndicator={getOr(false, 'showMorePagesIndicator', pageInfo)}
|
||||
totalCount={totalCount}
|
||||
type={type}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
exports[`Embeddable it renders 1`] = `
|
||||
<section
|
||||
className="siemEmbeddable"
|
||||
data-test-subj="siemEmbeddable"
|
||||
>
|
||||
<Panel
|
||||
hasBorder={true}
|
||||
|
|
|
@ -19,7 +19,7 @@ export interface EmbeddableProps {
|
|||
}
|
||||
|
||||
export const Embeddable = React.memo<EmbeddableProps>(({ children }) => (
|
||||
<section className="siemEmbeddable">
|
||||
<section className="siemEmbeddable" data-test-subj="siemEmbeddable">
|
||||
<Panel paddingSize="none" hasBorder>
|
||||
{children}
|
||||
</Panel>
|
||||
|
|
|
@ -109,7 +109,7 @@ describe('EmbeddedMapComponent', () => {
|
|||
|
||||
beforeEach(() => {
|
||||
setQuery.mockClear();
|
||||
mockGetStorage.mockReturnValue(false);
|
||||
mockGetStorage.mockReturnValue(true);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
@ -190,36 +190,40 @@ describe('EmbeddedMapComponent', () => {
|
|||
});
|
||||
|
||||
test('map hidden on close', async () => {
|
||||
mockGetStorage.mockReturnValue(false);
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<EmbeddedMapComponent {...testProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
expect(wrapper.find('[data-test-subj="siemEmbeddable"]').first().exists()).toEqual(false);
|
||||
|
||||
const container = wrapper.find('[data-test-subj="false-toggle-network-map"]').at(0);
|
||||
container.simulate('click');
|
||||
|
||||
await waitFor(() => {
|
||||
wrapper.update();
|
||||
expect(mockSetStorage).toHaveBeenNthCalledWith(1, 'network_map_visbile', true);
|
||||
expect(wrapper.find('[data-test-subj="siemEmbeddable"]').first().exists()).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
test('map visible on open', async () => {
|
||||
mockGetStorage.mockReturnValue(true);
|
||||
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<EmbeddedMapComponent {...testProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
expect(wrapper.find('[data-test-subj="siemEmbeddable"]').first().exists()).toEqual(true);
|
||||
const container = wrapper.find('[data-test-subj="true-toggle-network-map"]').at(0);
|
||||
container.simulate('click');
|
||||
|
||||
await waitFor(() => {
|
||||
wrapper.update();
|
||||
expect(mockSetStorage).toHaveBeenNthCalledWith(1, 'network_map_visbile', false);
|
||||
expect(wrapper.find('[data-test-subj="siemEmbeddable"]').first().exists()).toEqual(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -245,6 +245,29 @@ export const EmbeddedMapComponent = ({
|
|||
[storage]
|
||||
);
|
||||
|
||||
const content = useMemo(() => {
|
||||
if (!storageValue) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<Embeddable>
|
||||
<InPortal node={portalNode}>
|
||||
<MapToolTip />
|
||||
</InPortal>
|
||||
|
||||
<EmbeddableMap maintainRatio={!isIndexError}>
|
||||
{isIndexError ? (
|
||||
<IndexPatternsMissingPrompt data-test-subj="missing-prompt" />
|
||||
) : embeddable != null ? (
|
||||
<services.embeddable.EmbeddablePanel embeddable={embeddable} />
|
||||
) : (
|
||||
<Loader data-test-subj="loading-panel" overlay size="xl" />
|
||||
)}
|
||||
</EmbeddableMap>
|
||||
</Embeddable>
|
||||
);
|
||||
}, [embeddable, isIndexError, portalNode, services, storageValue]);
|
||||
|
||||
return isError ? null : (
|
||||
<StyledEuiAccordion
|
||||
onToggle={setDefaultMapVisibility}
|
||||
|
@ -265,21 +288,7 @@ export const EmbeddedMapComponent = ({
|
|||
paddingSize="none"
|
||||
initialIsOpen={storageValue}
|
||||
>
|
||||
<Embeddable>
|
||||
<InPortal node={portalNode}>
|
||||
<MapToolTip />
|
||||
</InPortal>
|
||||
|
||||
<EmbeddableMap maintainRatio={!isIndexError}>
|
||||
{isIndexError ? (
|
||||
<IndexPatternsMissingPrompt data-test-subj="missing-prompt" />
|
||||
) : embeddable != null ? (
|
||||
<services.embeddable.EmbeddablePanel embeddable={embeddable} />
|
||||
) : (
|
||||
<Loader data-test-subj="loading-panel" overlay size="xl" />
|
||||
)}
|
||||
</EmbeddableMap>
|
||||
</Embeddable>
|
||||
{content}
|
||||
</StyledEuiAccordion>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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 { useNetworkKpiDns } from '../../../containers/kpi_network/dns';
|
||||
import { useQueryToggle } from '../../../../common/containers/query_toggle';
|
||||
import { render } from '@testing-library/react';
|
||||
import { TestProviders } from '../../../../common/mock';
|
||||
import React from 'react';
|
||||
import { NetworkKpiDns } from './index';
|
||||
|
||||
jest.mock('../../../../common/containers/query_toggle');
|
||||
jest.mock('../../../containers/kpi_network/dns');
|
||||
jest.mock('../../../../hosts/components/kpi_hosts/common', () => ({
|
||||
KpiBaseComponentManage: () => <span data-test-subj="KpiBaseComponentManage" />,
|
||||
}));
|
||||
|
||||
describe('DNS KPI', () => {
|
||||
const mockUseNetworkKpiDns = useNetworkKpiDns as jest.Mock;
|
||||
const mockUseQueryToggle = useQueryToggle as jest.Mock;
|
||||
const defaultProps = {
|
||||
from: '2019-06-25T04:31:59.345Z',
|
||||
to: '2019-06-25T06:31:59.345Z',
|
||||
indexNames: [],
|
||||
narrowDateRange: jest.fn(),
|
||||
setQuery: jest.fn(),
|
||||
skip: false,
|
||||
};
|
||||
beforeEach(() => {
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: true, setToggleStatus: jest.fn() });
|
||||
mockUseNetworkKpiDns.mockReturnValue([
|
||||
false,
|
||||
{
|
||||
id: '123',
|
||||
inspect: {
|
||||
dsl: [],
|
||||
response: [],
|
||||
},
|
||||
refetch: jest.fn(),
|
||||
},
|
||||
]);
|
||||
});
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
it('toggleStatus=true, do not skip', () => {
|
||||
render(
|
||||
<TestProviders>
|
||||
<NetworkKpiDns {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(mockUseNetworkKpiDns.mock.calls[0][0].skip).toEqual(false);
|
||||
});
|
||||
it('toggleStatus=false, skip', () => {
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: false, setToggleStatus: jest.fn() });
|
||||
render(
|
||||
<TestProviders>
|
||||
<NetworkKpiDns {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(mockUseNetworkKpiDns.mock.calls[0][0].skip).toEqual(true);
|
||||
});
|
||||
});
|
|
@ -5,15 +5,16 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import { StatItems } from '../../../../common/components/stat_items';
|
||||
import { kpiDnsQueriesLensAttributes } from '../../../../common/components/visualization_actions/lens_attributes/network/kpi_dns_queries';
|
||||
import { useNetworkKpiDns, ID } from '../../../containers/kpi_network/dns';
|
||||
import { KpiBaseComponentManage } from '../../../../hosts/components/kpi_hosts/common';
|
||||
import { useNetworkKpiDns } from '../../../containers/kpi_network/dns';
|
||||
|
||||
import { NetworkKpiProps } from '../types';
|
||||
import * as i18n from './translations';
|
||||
import { useQueryToggle } from '../../../../common/containers/query_toggle';
|
||||
|
||||
export const fieldsMapping: Readonly<StatItems[]> = [
|
||||
{
|
||||
|
@ -38,12 +39,17 @@ const NetworkKpiDnsComponent: React.FC<NetworkKpiProps> = ({
|
|||
setQuery,
|
||||
skip,
|
||||
}) => {
|
||||
const { toggleStatus } = useQueryToggle(ID);
|
||||
const [querySkip, setQuerySkip] = useState(skip || !toggleStatus);
|
||||
useEffect(() => {
|
||||
setQuerySkip(skip || !toggleStatus);
|
||||
}, [skip, toggleStatus]);
|
||||
const [loading, { refetch, id, inspect, ...data }] = useNetworkKpiDns({
|
||||
filterQuery,
|
||||
endDate: to,
|
||||
indexNames,
|
||||
startDate: from,
|
||||
skip,
|
||||
skip: querySkip,
|
||||
});
|
||||
|
||||
return (
|
||||
|
@ -58,6 +64,7 @@ const NetworkKpiDnsComponent: React.FC<NetworkKpiProps> = ({
|
|||
narrowDateRange={narrowDateRange}
|
||||
refetch={refetch}
|
||||
setQuery={setQuery}
|
||||
setQuerySkip={setQuerySkip}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -227,7 +227,9 @@ export const mockEnableChartsData = {
|
|||
],
|
||||
from: '2019-06-15T06:00:00.000Z',
|
||||
id: 'statItem',
|
||||
loading: false,
|
||||
statKey: 'UniqueIps',
|
||||
setQuerySkip: jest.fn(),
|
||||
to: '2019-06-18T06:00:00.000Z',
|
||||
narrowDateRange: mockNarrowDateRange,
|
||||
areaChartLensAttributes: kpiUniquePrivateIpsAreaLensAttributes,
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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 { useNetworkKpiNetworkEvents } from '../../../containers/kpi_network/network_events';
|
||||
import { useQueryToggle } from '../../../../common/containers/query_toggle';
|
||||
import { render } from '@testing-library/react';
|
||||
import { TestProviders } from '../../../../common/mock';
|
||||
import React from 'react';
|
||||
import { NetworkKpiNetworkEvents } from './index';
|
||||
|
||||
jest.mock('../../../../common/containers/query_toggle');
|
||||
jest.mock('../../../containers/kpi_network/network_events');
|
||||
jest.mock('../../../../hosts/components/kpi_hosts/common', () => ({
|
||||
KpiBaseComponentManage: () => <span data-test-subj="KpiBaseComponentManage" />,
|
||||
}));
|
||||
|
||||
describe('Network Events KPI', () => {
|
||||
const mockUseNetworkKpiNetworkEvents = useNetworkKpiNetworkEvents as jest.Mock;
|
||||
const mockUseQueryToggle = useQueryToggle as jest.Mock;
|
||||
const defaultProps = {
|
||||
from: '2019-06-25T04:31:59.345Z',
|
||||
to: '2019-06-25T06:31:59.345Z',
|
||||
indexNames: [],
|
||||
narrowDateRange: jest.fn(),
|
||||
setQuery: jest.fn(),
|
||||
skip: false,
|
||||
};
|
||||
beforeEach(() => {
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: true, setToggleStatus: jest.fn() });
|
||||
mockUseNetworkKpiNetworkEvents.mockReturnValue([
|
||||
false,
|
||||
{
|
||||
id: '123',
|
||||
inspect: {
|
||||
dsl: [],
|
||||
response: [],
|
||||
},
|
||||
refetch: jest.fn(),
|
||||
},
|
||||
]);
|
||||
});
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
it('toggleStatus=true, do not skip', () => {
|
||||
render(
|
||||
<TestProviders>
|
||||
<NetworkKpiNetworkEvents {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(mockUseNetworkKpiNetworkEvents.mock.calls[0][0].skip).toEqual(false);
|
||||
});
|
||||
it('toggleStatus=false, skip', () => {
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: false, setToggleStatus: jest.fn() });
|
||||
render(
|
||||
<TestProviders>
|
||||
<NetworkKpiNetworkEvents {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(mockUseNetworkKpiNetworkEvents.mock.calls[0][0].skip).toEqual(true);
|
||||
});
|
||||
});
|
|
@ -5,16 +5,16 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { euiPaletteColorBlind } from '@elastic/eui';
|
||||
|
||||
import { StatItems } from '../../../../common/components/stat_items';
|
||||
import { useNetworkKpiNetworkEvents } from '../../../containers/kpi_network/network_events';
|
||||
|
||||
import { ID, useNetworkKpiNetworkEvents } from '../../../containers/kpi_network/network_events';
|
||||
import { NetworkKpiProps } from '../types';
|
||||
import * as i18n from './translations';
|
||||
import { kpiNetworkEventsLensAttributes } from '../../../../common/components/visualization_actions/lens_attributes/network/kpi_network_events';
|
||||
import { KpiBaseComponentManage } from '../../../../hosts/components/kpi_hosts/common';
|
||||
import { useQueryToggle } from '../../../../common/containers/query_toggle';
|
||||
|
||||
const euiVisColorPalette = euiPaletteColorBlind();
|
||||
const euiColorVis1 = euiVisColorPalette[1];
|
||||
|
@ -43,12 +43,17 @@ const NetworkKpiNetworkEventsComponent: React.FC<NetworkKpiProps> = ({
|
|||
setQuery,
|
||||
skip,
|
||||
}) => {
|
||||
const { toggleStatus } = useQueryToggle(ID);
|
||||
const [querySkip, setQuerySkip] = useState(skip || !toggleStatus);
|
||||
useEffect(() => {
|
||||
setQuerySkip(skip || !toggleStatus);
|
||||
}, [skip, toggleStatus]);
|
||||
const [loading, { refetch, id, inspect, ...data }] = useNetworkKpiNetworkEvents({
|
||||
filterQuery,
|
||||
endDate: to,
|
||||
indexNames,
|
||||
startDate: from,
|
||||
skip,
|
||||
skip: querySkip,
|
||||
});
|
||||
|
||||
return (
|
||||
|
@ -63,6 +68,7 @@ const NetworkKpiNetworkEventsComponent: React.FC<NetworkKpiProps> = ({
|
|||
narrowDateRange={narrowDateRange}
|
||||
refetch={refetch}
|
||||
setQuery={setQuery}
|
||||
setQuerySkip={setQuerySkip}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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 { useNetworkKpiTlsHandshakes } from '../../../containers/kpi_network/tls_handshakes';
|
||||
import { useQueryToggle } from '../../../../common/containers/query_toggle';
|
||||
import { render } from '@testing-library/react';
|
||||
import { TestProviders } from '../../../../common/mock';
|
||||
import React from 'react';
|
||||
import { NetworkKpiTlsHandshakes } from './index';
|
||||
|
||||
jest.mock('../../../../common/containers/query_toggle');
|
||||
jest.mock('../../../containers/kpi_network/tls_handshakes');
|
||||
jest.mock('../../../../hosts/components/kpi_hosts/common', () => ({
|
||||
KpiBaseComponentManage: () => <span data-test-subj="KpiBaseComponentManage" />,
|
||||
}));
|
||||
|
||||
describe('TLS Handshakes KPI', () => {
|
||||
const mockUseNetworkKpiTlsHandshakes = useNetworkKpiTlsHandshakes as jest.Mock;
|
||||
const mockUseQueryToggle = useQueryToggle as jest.Mock;
|
||||
const defaultProps = {
|
||||
from: '2019-06-25T04:31:59.345Z',
|
||||
to: '2019-06-25T06:31:59.345Z',
|
||||
indexNames: [],
|
||||
narrowDateRange: jest.fn(),
|
||||
setQuery: jest.fn(),
|
||||
skip: false,
|
||||
};
|
||||
beforeEach(() => {
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: true, setToggleStatus: jest.fn() });
|
||||
mockUseNetworkKpiTlsHandshakes.mockReturnValue([
|
||||
false,
|
||||
{
|
||||
id: '123',
|
||||
inspect: {
|
||||
dsl: [],
|
||||
response: [],
|
||||
},
|
||||
refetch: jest.fn(),
|
||||
},
|
||||
]);
|
||||
});
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
it('toggleStatus=true, do not skip', () => {
|
||||
render(
|
||||
<TestProviders>
|
||||
<NetworkKpiTlsHandshakes {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(mockUseNetworkKpiTlsHandshakes.mock.calls[0][0].skip).toEqual(false);
|
||||
});
|
||||
it('toggleStatus=false, skip', () => {
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: false, setToggleStatus: jest.fn() });
|
||||
render(
|
||||
<TestProviders>
|
||||
<NetworkKpiTlsHandshakes {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(mockUseNetworkKpiTlsHandshakes.mock.calls[0][0].skip).toEqual(true);
|
||||
});
|
||||
});
|
|
@ -5,14 +5,15 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import { StatItems } from '../../../../common/components/stat_items';
|
||||
import { kpiTlsHandshakesLensAttributes } from '../../../../common/components/visualization_actions/lens_attributes/network/kpi_tls_handshakes';
|
||||
import { useNetworkKpiTlsHandshakes, ID } from '../../../containers/kpi_network/tls_handshakes';
|
||||
import { KpiBaseComponentManage } from '../../../../hosts/components/kpi_hosts/common';
|
||||
import { useNetworkKpiTlsHandshakes } from '../../../containers/kpi_network/tls_handshakes';
|
||||
import { NetworkKpiProps } from '../types';
|
||||
import * as i18n from './translations';
|
||||
import { useQueryToggle } from '../../../../common/containers/query_toggle';
|
||||
|
||||
export const fieldsMapping: Readonly<StatItems[]> = [
|
||||
{
|
||||
|
@ -37,12 +38,17 @@ const NetworkKpiTlsHandshakesComponent: React.FC<NetworkKpiProps> = ({
|
|||
setQuery,
|
||||
skip,
|
||||
}) => {
|
||||
const { toggleStatus } = useQueryToggle(ID);
|
||||
const [querySkip, setQuerySkip] = useState(skip || !toggleStatus);
|
||||
useEffect(() => {
|
||||
setQuerySkip(skip || !toggleStatus);
|
||||
}, [skip, toggleStatus]);
|
||||
const [loading, { refetch, id, inspect, ...data }] = useNetworkKpiTlsHandshakes({
|
||||
filterQuery,
|
||||
endDate: to,
|
||||
indexNames,
|
||||
startDate: from,
|
||||
skip,
|
||||
skip: querySkip,
|
||||
});
|
||||
|
||||
return (
|
||||
|
@ -57,6 +63,7 @@ const NetworkKpiTlsHandshakesComponent: React.FC<NetworkKpiProps> = ({
|
|||
narrowDateRange={narrowDateRange}
|
||||
refetch={refetch}
|
||||
setQuery={setQuery}
|
||||
setQuerySkip={setQuerySkip}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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 { useNetworkKpiUniqueFlows } from '../../../containers/kpi_network/unique_flows';
|
||||
import { useQueryToggle } from '../../../../common/containers/query_toggle';
|
||||
import { render } from '@testing-library/react';
|
||||
import { TestProviders } from '../../../../common/mock';
|
||||
import React from 'react';
|
||||
import { NetworkKpiUniqueFlows } from './index';
|
||||
|
||||
jest.mock('../../../../common/containers/query_toggle');
|
||||
jest.mock('../../../containers/kpi_network/unique_flows');
|
||||
jest.mock('../../../../hosts/components/kpi_hosts/common', () => ({
|
||||
KpiBaseComponentManage: () => <span data-test-subj="KpiBaseComponentManage" />,
|
||||
}));
|
||||
|
||||
describe('Unique Flows KPI', () => {
|
||||
const mockUseNetworkKpiUniqueFlows = useNetworkKpiUniqueFlows as jest.Mock;
|
||||
const mockUseQueryToggle = useQueryToggle as jest.Mock;
|
||||
const defaultProps = {
|
||||
from: '2019-06-25T04:31:59.345Z',
|
||||
to: '2019-06-25T06:31:59.345Z',
|
||||
indexNames: [],
|
||||
narrowDateRange: jest.fn(),
|
||||
setQuery: jest.fn(),
|
||||
skip: false,
|
||||
};
|
||||
beforeEach(() => {
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: true, setToggleStatus: jest.fn() });
|
||||
mockUseNetworkKpiUniqueFlows.mockReturnValue([
|
||||
false,
|
||||
{
|
||||
id: '123',
|
||||
inspect: {
|
||||
dsl: [],
|
||||
response: [],
|
||||
},
|
||||
refetch: jest.fn(),
|
||||
},
|
||||
]);
|
||||
});
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
it('toggleStatus=true, do not skip', () => {
|
||||
render(
|
||||
<TestProviders>
|
||||
<NetworkKpiUniqueFlows {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(mockUseNetworkKpiUniqueFlows.mock.calls[0][0].skip).toEqual(false);
|
||||
});
|
||||
it('toggleStatus=false, skip', () => {
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: false, setToggleStatus: jest.fn() });
|
||||
render(
|
||||
<TestProviders>
|
||||
<NetworkKpiUniqueFlows {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(mockUseNetworkKpiUniqueFlows.mock.calls[0][0].skip).toEqual(true);
|
||||
});
|
||||
});
|
|
@ -5,14 +5,15 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
|
||||
import { StatItems } from '../../../../common/components/stat_items';
|
||||
import { kpiUniqueFlowIdsLensAttributes } from '../../../../common/components/visualization_actions/lens_attributes/network/kpi_unique_flow_ids';
|
||||
import { useNetworkKpiUniqueFlows, ID } from '../../../containers/kpi_network/unique_flows';
|
||||
import { KpiBaseComponentManage } from '../../../../hosts/components/kpi_hosts/common';
|
||||
import { useNetworkKpiUniqueFlows } from '../../../containers/kpi_network/unique_flows';
|
||||
import { NetworkKpiProps } from '../types';
|
||||
import * as i18n from './translations';
|
||||
import { useQueryToggle } from '../../../../common/containers/query_toggle';
|
||||
|
||||
export const fieldsMapping: Readonly<StatItems[]> = [
|
||||
{
|
||||
|
@ -37,12 +38,17 @@ const NetworkKpiUniqueFlowsComponent: React.FC<NetworkKpiProps> = ({
|
|||
setQuery,
|
||||
skip,
|
||||
}) => {
|
||||
const { toggleStatus } = useQueryToggle(ID);
|
||||
const [querySkip, setQuerySkip] = useState(skip || !toggleStatus);
|
||||
useEffect(() => {
|
||||
setQuerySkip(skip || !toggleStatus);
|
||||
}, [skip, toggleStatus]);
|
||||
const [loading, { refetch, id, inspect, ...data }] = useNetworkKpiUniqueFlows({
|
||||
filterQuery,
|
||||
endDate: to,
|
||||
indexNames,
|
||||
startDate: from,
|
||||
skip,
|
||||
skip: querySkip,
|
||||
});
|
||||
|
||||
return (
|
||||
|
@ -57,6 +63,7 @@ const NetworkKpiUniqueFlowsComponent: React.FC<NetworkKpiProps> = ({
|
|||
narrowDateRange={narrowDateRange}
|
||||
refetch={refetch}
|
||||
setQuery={setQuery}
|
||||
setQuerySkip={setQuerySkip}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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 { useNetworkKpiUniquePrivateIps } from '../../../containers/kpi_network/unique_private_ips';
|
||||
import { useQueryToggle } from '../../../../common/containers/query_toggle';
|
||||
import { render } from '@testing-library/react';
|
||||
import { TestProviders } from '../../../../common/mock';
|
||||
import React from 'react';
|
||||
import { NetworkKpiUniquePrivateIps } from './index';
|
||||
|
||||
jest.mock('../../../../common/containers/query_toggle');
|
||||
jest.mock('../../../containers/kpi_network/unique_private_ips');
|
||||
jest.mock('../../../../hosts/components/kpi_hosts/common', () => ({
|
||||
KpiBaseComponentManage: () => <span data-test-subj="KpiBaseComponentManage" />,
|
||||
}));
|
||||
|
||||
describe('Unique Private IPs KPI', () => {
|
||||
const mockUseNetworkKpiUniquePrivateIps = useNetworkKpiUniquePrivateIps as jest.Mock;
|
||||
const mockUseQueryToggle = useQueryToggle as jest.Mock;
|
||||
const defaultProps = {
|
||||
from: '2019-06-25T04:31:59.345Z',
|
||||
to: '2019-06-25T06:31:59.345Z',
|
||||
indexNames: [],
|
||||
narrowDateRange: jest.fn(),
|
||||
setQuery: jest.fn(),
|
||||
skip: false,
|
||||
};
|
||||
beforeEach(() => {
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: true, setToggleStatus: jest.fn() });
|
||||
mockUseNetworkKpiUniquePrivateIps.mockReturnValue([
|
||||
false,
|
||||
{
|
||||
id: '123',
|
||||
inspect: {
|
||||
dsl: [],
|
||||
response: [],
|
||||
},
|
||||
refetch: jest.fn(),
|
||||
},
|
||||
]);
|
||||
});
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
it('toggleStatus=true, do not skip', () => {
|
||||
render(
|
||||
<TestProviders>
|
||||
<NetworkKpiUniquePrivateIps {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(mockUseNetworkKpiUniquePrivateIps.mock.calls[0][0].skip).toEqual(false);
|
||||
});
|
||||
it('toggleStatus=false, skip', () => {
|
||||
mockUseQueryToggle.mockReturnValue({ toggleStatus: false, setToggleStatus: jest.fn() });
|
||||
render(
|
||||
<TestProviders>
|
||||
<NetworkKpiUniquePrivateIps {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(mockUseNetworkKpiUniquePrivateIps.mock.calls[0][0].skip).toEqual(true);
|
||||
});
|
||||
});
|
|
@ -5,11 +5,14 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { euiPaletteColorBlind } from '@elastic/eui';
|
||||
|
||||
import { StatItems } from '../../../../common/components/stat_items';
|
||||
import { useNetworkKpiUniquePrivateIps } from '../../../containers/kpi_network/unique_private_ips';
|
||||
import {
|
||||
useNetworkKpiUniquePrivateIps,
|
||||
ID,
|
||||
} from '../../../containers/kpi_network/unique_private_ips';
|
||||
import { NetworkKpiProps } from '../types';
|
||||
import * as i18n from './translations';
|
||||
import { kpiUniquePrivateIpsSourceMetricLensAttributes } from '../../../../common/components/visualization_actions/lens_attributes/network/kpi_unique_private_ips_source_metric';
|
||||
|
@ -17,6 +20,7 @@ import { kpiUniquePrivateIpsDestinationMetricLensAttributes } from '../../../../
|
|||
import { kpiUniquePrivateIpsAreaLensAttributes } from '../../../../common/components/visualization_actions/lens_attributes/network/kpi_unique_private_ips_area';
|
||||
import { kpiUniquePrivateIpsBarLensAttributes } from '../../../../common/components/visualization_actions/lens_attributes/network/kpi_unique_private_ips_bar';
|
||||
import { KpiBaseComponentManage } from '../../../../hosts/components/kpi_hosts/common';
|
||||
import { useQueryToggle } from '../../../../common/containers/query_toggle';
|
||||
|
||||
const euiVisColorPalette = euiPaletteColorBlind();
|
||||
const euiColorVis2 = euiVisColorPalette[2];
|
||||
|
@ -62,12 +66,17 @@ const NetworkKpiUniquePrivateIpsComponent: React.FC<NetworkKpiProps> = ({
|
|||
setQuery,
|
||||
skip,
|
||||
}) => {
|
||||
const { toggleStatus } = useQueryToggle(ID);
|
||||
const [querySkip, setQuerySkip] = useState(skip || !toggleStatus);
|
||||
useEffect(() => {
|
||||
setQuerySkip(skip || !toggleStatus);
|
||||
}, [skip, toggleStatus]);
|
||||
const [loading, { refetch, id, inspect, ...data }] = useNetworkKpiUniquePrivateIps({
|
||||
filterQuery,
|
||||
endDate: to,
|
||||
indexNames,
|
||||
startDate: from,
|
||||
skip,
|
||||
skip: querySkip,
|
||||
});
|
||||
|
||||
return (
|
||||
|
@ -82,6 +91,7 @@ const NetworkKpiUniquePrivateIpsComponent: React.FC<NetworkKpiProps> = ({
|
|||
narrowDateRange={narrowDateRange}
|
||||
refetch={refetch}
|
||||
setQuery={setQuery}
|
||||
setQuerySkip={setQuerySkip}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -141,6 +141,7 @@ exports[`NetworkTopNFlow Table Component rendering it renders the default Networ
|
|||
isInspect={false}
|
||||
loadPage={[MockFunction]}
|
||||
loading={false}
|
||||
setQuerySkip={[MockFunction]}
|
||||
showMorePagesIndicator={true}
|
||||
totalCount={80}
|
||||
type="page"
|
||||
|
|
|
@ -34,6 +34,19 @@ describe('NetworkTopNFlow Table Component', () => {
|
|||
let store = createStore(state, SUB_PLUGINS_REDUCER, kibanaObservable, storage);
|
||||
const mount = useMountAppended();
|
||||
|
||||
const defaultProps = {
|
||||
data: mockData.edges,
|
||||
fakeTotalCount: getOr(50, 'fakeTotalCount', mockData.pageInfo),
|
||||
id: 'dns',
|
||||
isInspect: false,
|
||||
loading: false,
|
||||
loadPage,
|
||||
setQuerySkip: jest.fn(),
|
||||
showMorePagesIndicator: getOr(false, 'showMorePagesIndicator', mockData.pageInfo),
|
||||
totalCount: mockData.totalCount,
|
||||
type: networkModel.NetworkType.page,
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
store = createStore(state, SUB_PLUGINS_REDUCER, kibanaObservable, storage);
|
||||
});
|
||||
|
@ -42,17 +55,7 @@ describe('NetworkTopNFlow Table Component', () => {
|
|||
test('it renders the default NetworkTopNFlow table', () => {
|
||||
const wrapper = shallow(
|
||||
<ReduxStoreProvider store={store}>
|
||||
<NetworkDnsTable
|
||||
data={mockData.edges}
|
||||
fakeTotalCount={getOr(50, 'fakeTotalCount', mockData.pageInfo)}
|
||||
id="dns"
|
||||
isInspect={false}
|
||||
loading={false}
|
||||
loadPage={loadPage}
|
||||
showMorePagesIndicator={getOr(false, 'showMorePagesIndicator', mockData.pageInfo)}
|
||||
totalCount={mockData.totalCount}
|
||||
type={networkModel.NetworkType.page}
|
||||
/>
|
||||
<NetworkDnsTable {...defaultProps} />
|
||||
</ReduxStoreProvider>
|
||||
);
|
||||
|
||||
|
@ -64,17 +67,7 @@ describe('NetworkTopNFlow Table Component', () => {
|
|||
test('when you click on the column header, you should show the sorting icon', () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders store={store}>
|
||||
<NetworkDnsTable
|
||||
data={mockData.edges}
|
||||
fakeTotalCount={getOr(50, 'fakeTotalCount', mockData.pageInfo)}
|
||||
id="dns"
|
||||
isInspect={false}
|
||||
loading={false}
|
||||
loadPage={loadPage}
|
||||
showMorePagesIndicator={getOr(false, 'showMorePagesIndicator', mockData.pageInfo)}
|
||||
totalCount={mockData.totalCount}
|
||||
type={networkModel.NetworkType.page}
|
||||
/>
|
||||
<NetworkDnsTable {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ interface NetworkDnsTableProps {
|
|||
isInspect: boolean;
|
||||
loading: boolean;
|
||||
loadPage: (newActivePage: number) => void;
|
||||
setQuerySkip: (skip: boolean) => void;
|
||||
showMorePagesIndicator: boolean;
|
||||
totalCount: number;
|
||||
type: networkModel.NetworkType;
|
||||
|
@ -56,6 +57,7 @@ const NetworkDnsTableComponent: React.FC<NetworkDnsTableProps> = ({
|
|||
loading,
|
||||
loadPage,
|
||||
showMorePagesIndicator,
|
||||
setQuerySkip,
|
||||
totalCount,
|
||||
type,
|
||||
}) => {
|
||||
|
@ -153,6 +155,7 @@ const NetworkDnsTableComponent: React.FC<NetworkDnsTableProps> = ({
|
|||
loadPage={loadPage}
|
||||
onChange={onChange}
|
||||
pageOfItems={data}
|
||||
setQuerySkip={setQuerySkip}
|
||||
showMorePagesIndicator={showMorePagesIndicator}
|
||||
sorting={sorting}
|
||||
totalCount={fakeTotalCount}
|
||||
|
|
|
@ -95,6 +95,7 @@ exports[`NetworkHttp Table Component rendering it renders the default NetworkHtt
|
|||
isInspect={false}
|
||||
loadPage={[MockFunction]}
|
||||
loading={false}
|
||||
setQuerySkip={[MockFunction]}
|
||||
showMorePagesIndicator={false}
|
||||
totalCount={4}
|
||||
type="page"
|
||||
|
|
|
@ -31,6 +31,18 @@ jest.mock('../../../common/components/link_to');
|
|||
describe('NetworkHttp Table Component', () => {
|
||||
const loadPage = jest.fn();
|
||||
const state: State = mockGlobalState;
|
||||
const defaultProps = {
|
||||
data: mockData.edges,
|
||||
fakeTotalCount: getOr(50, 'fakeTotalCount', mockData.pageInfo),
|
||||
id: 'http',
|
||||
isInspect: false,
|
||||
loading: false,
|
||||
loadPage,
|
||||
setQuerySkip: jest.fn(),
|
||||
showMorePagesIndicator: getOr(false, 'showMorePagesIndicator', mockData.pageInfo),
|
||||
totalCount: mockData.totalCount,
|
||||
type: networkModel.NetworkType.page,
|
||||
};
|
||||
|
||||
const { storage } = createSecuritySolutionStorageMock();
|
||||
let store = createStore(state, SUB_PLUGINS_REDUCER, kibanaObservable, storage);
|
||||
|
@ -44,17 +56,7 @@ describe('NetworkHttp Table Component', () => {
|
|||
test('it renders the default NetworkHttp table', () => {
|
||||
const wrapper = shallow(
|
||||
<ReduxStoreProvider store={store}>
|
||||
<NetworkHttpTable
|
||||
data={mockData.edges}
|
||||
fakeTotalCount={getOr(50, 'fakeTotalCount', mockData.pageInfo)}
|
||||
id="http"
|
||||
isInspect={false}
|
||||
loading={false}
|
||||
loadPage={loadPage}
|
||||
showMorePagesIndicator={getOr(false, 'showMorePagesIndicator', mockData.pageInfo)}
|
||||
totalCount={mockData.totalCount}
|
||||
type={networkModel.NetworkType.page}
|
||||
/>
|
||||
<NetworkHttpTable {...defaultProps} />
|
||||
</ReduxStoreProvider>
|
||||
);
|
||||
|
||||
|
@ -66,17 +68,7 @@ describe('NetworkHttp Table Component', () => {
|
|||
test('when you click on the column header, you should show the sorting icon', () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders store={store}>
|
||||
<NetworkHttpTable
|
||||
data={mockData.edges}
|
||||
fakeTotalCount={getOr(50, 'fakeTotalCount', mockData.pageInfo)}
|
||||
id="http"
|
||||
isInspect={false}
|
||||
loading={false}
|
||||
loadPage={loadPage}
|
||||
showMorePagesIndicator={getOr(false, 'showMorePagesIndicator', mockData.pageInfo)}
|
||||
totalCount={mockData.totalCount}
|
||||
type={networkModel.NetworkType.page}
|
||||
/>
|
||||
<NetworkHttpTable {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ interface NetworkHttpTableProps {
|
|||
isInspect: boolean;
|
||||
loading: boolean;
|
||||
loadPage: (newActivePage: number) => void;
|
||||
setQuerySkip: (skip: boolean) => void;
|
||||
showMorePagesIndicator: boolean;
|
||||
totalCount: number;
|
||||
type: networkModel.NetworkType;
|
||||
|
@ -46,6 +47,7 @@ const NetworkHttpTableComponent: React.FC<NetworkHttpTableProps> = ({
|
|||
isInspect,
|
||||
loading,
|
||||
loadPage,
|
||||
setQuerySkip,
|
||||
showMorePagesIndicator,
|
||||
totalCount,
|
||||
type,
|
||||
|
@ -123,6 +125,7 @@ const NetworkHttpTableComponent: React.FC<NetworkHttpTableProps> = ({
|
|||
loadPage={loadPage}
|
||||
onChange={onChange}
|
||||
pageOfItems={data}
|
||||
setQuerySkip={setQuerySkip}
|
||||
showMorePagesIndicator={showMorePagesIndicator}
|
||||
sorting={sorting}
|
||||
totalCount={fakeTotalCount}
|
||||
|
|
|
@ -151,6 +151,7 @@ exports[`NetworkTopCountries Table Component rendering it renders the IP Details
|
|||
isInspect={false}
|
||||
loadPage={[MockFunction]}
|
||||
loading={false}
|
||||
setQuerySkip={[MockFunction]}
|
||||
showMorePagesIndicator={true}
|
||||
totalCount={524}
|
||||
type="details"
|
||||
|
@ -308,6 +309,7 @@ exports[`NetworkTopCountries Table Component rendering it renders the default Ne
|
|||
isInspect={false}
|
||||
loadPage={[MockFunction]}
|
||||
loading={false}
|
||||
setQuerySkip={[MockFunction]}
|
||||
showMorePagesIndicator={true}
|
||||
totalCount={524}
|
||||
type="page"
|
||||
|
|
|
@ -33,6 +33,24 @@ describe('NetworkTopCountries Table Component', () => {
|
|||
const loadPage = jest.fn();
|
||||
const state: State = mockGlobalState;
|
||||
const mount = useMountAppended();
|
||||
const defaultProps = {
|
||||
data: mockData.NetworkTopCountries.edges,
|
||||
fakeTotalCount: getOr(50, 'fakeTotalCount', mockData.NetworkTopCountries.pageInfo),
|
||||
flowTargeted: FlowTargetSourceDest.source,
|
||||
id: 'topCountriesSource',
|
||||
indexPattern: mockIndexPattern,
|
||||
isInspect: false,
|
||||
loading: false,
|
||||
loadPage,
|
||||
setQuerySkip: jest.fn(),
|
||||
showMorePagesIndicator: getOr(
|
||||
false,
|
||||
'showMorePagesIndicator',
|
||||
mockData.NetworkTopCountries.pageInfo
|
||||
),
|
||||
totalCount: mockData.NetworkTopCountries.totalCount,
|
||||
type: networkModel.NetworkType.page,
|
||||
};
|
||||
|
||||
const { storage } = createSecuritySolutionStorageMock();
|
||||
let store = createStore(state, SUB_PLUGINS_REDUCER, kibanaObservable, storage);
|
||||
|
@ -45,23 +63,7 @@ describe('NetworkTopCountries Table Component', () => {
|
|||
test('it renders the default NetworkTopCountries table', () => {
|
||||
const wrapper = shallow(
|
||||
<ReduxStoreProvider store={store}>
|
||||
<NetworkTopCountriesTable
|
||||
data={mockData.NetworkTopCountries.edges}
|
||||
fakeTotalCount={getOr(50, 'fakeTotalCount', mockData.NetworkTopCountries.pageInfo)}
|
||||
flowTargeted={FlowTargetSourceDest.source}
|
||||
id="topCountriesSource"
|
||||
indexPattern={mockIndexPattern}
|
||||
isInspect={false}
|
||||
loading={false}
|
||||
loadPage={loadPage}
|
||||
showMorePagesIndicator={getOr(
|
||||
false,
|
||||
'showMorePagesIndicator',
|
||||
mockData.NetworkTopCountries.pageInfo
|
||||
)}
|
||||
totalCount={mockData.NetworkTopCountries.totalCount}
|
||||
type={networkModel.NetworkType.page}
|
||||
/>
|
||||
<NetworkTopCountriesTable {...defaultProps} />
|
||||
</ReduxStoreProvider>
|
||||
);
|
||||
|
||||
|
@ -70,23 +72,7 @@ describe('NetworkTopCountries Table Component', () => {
|
|||
test('it renders the IP Details NetworkTopCountries table', () => {
|
||||
const wrapper = shallow(
|
||||
<ReduxStoreProvider store={store}>
|
||||
<NetworkTopCountriesTable
|
||||
data={mockData.NetworkTopCountries.edges}
|
||||
fakeTotalCount={getOr(50, 'fakeTotalCount', mockData.NetworkTopCountries.pageInfo)}
|
||||
flowTargeted={FlowTargetSourceDest.source}
|
||||
id="topCountriesSource"
|
||||
indexPattern={mockIndexPattern}
|
||||
isInspect={false}
|
||||
loading={false}
|
||||
loadPage={loadPage}
|
||||
showMorePagesIndicator={getOr(
|
||||
false,
|
||||
'showMorePagesIndicator',
|
||||
mockData.NetworkTopCountries.pageInfo
|
||||
)}
|
||||
totalCount={mockData.NetworkTopCountries.totalCount}
|
||||
type={networkModel.NetworkType.details}
|
||||
/>
|
||||
<NetworkTopCountriesTable {...defaultProps} type={networkModel.NetworkType.details} />
|
||||
</ReduxStoreProvider>
|
||||
);
|
||||
|
||||
|
@ -98,23 +84,7 @@ describe('NetworkTopCountries Table Component', () => {
|
|||
test('when you click on the column header, you should show the sorting icon', () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders store={store}>
|
||||
<NetworkTopCountriesTable
|
||||
data={mockData.NetworkTopCountries.edges}
|
||||
fakeTotalCount={getOr(50, 'fakeTotalCount', mockData.NetworkTopCountries.pageInfo)}
|
||||
flowTargeted={FlowTargetSourceDest.source}
|
||||
id="topCountriesSource"
|
||||
isInspect={false}
|
||||
indexPattern={mockIndexPattern}
|
||||
loading={false}
|
||||
loadPage={loadPage}
|
||||
showMorePagesIndicator={getOr(
|
||||
false,
|
||||
'showMorePagesIndicator',
|
||||
mockData.NetworkTopCountries.pageInfo
|
||||
)}
|
||||
totalCount={mockData.NetworkTopCountries.totalCount}
|
||||
type={networkModel.NetworkType.page}
|
||||
/>
|
||||
<NetworkTopCountriesTable {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(store.getState().network.page.queries.topCountriesSource.sort).toEqual({
|
||||
|
|
|
@ -35,6 +35,7 @@ interface NetworkTopCountriesTableProps {
|
|||
isInspect: boolean;
|
||||
loading: boolean;
|
||||
loadPage: (newActivePage: number) => void;
|
||||
setQuerySkip: (skip: boolean) => void;
|
||||
showMorePagesIndicator: boolean;
|
||||
totalCount: number;
|
||||
type: networkModel.NetworkType;
|
||||
|
@ -62,6 +63,7 @@ const NetworkTopCountriesTableComponent: React.FC<NetworkTopCountriesTableProps>
|
|||
isInspect,
|
||||
loading,
|
||||
loadPage,
|
||||
setQuerySkip,
|
||||
showMorePagesIndicator,
|
||||
totalCount,
|
||||
type,
|
||||
|
@ -170,6 +172,7 @@ const NetworkTopCountriesTableComponent: React.FC<NetworkTopCountriesTableProps>
|
|||
loadPage={loadPage}
|
||||
onChange={onChange}
|
||||
pageOfItems={data}
|
||||
setQuerySkip={setQuerySkip}
|
||||
showMorePagesIndicator={showMorePagesIndicator}
|
||||
sorting={{ field, direction: sort.direction }}
|
||||
totalCount={fakeTotalCount}
|
||||
|
|
|
@ -99,6 +99,7 @@ exports[`NetworkTopNFlow Table Component rendering it renders the default Networ
|
|||
isInspect={false}
|
||||
loadPage={[MockFunction]}
|
||||
loading={false}
|
||||
setQuerySkip={[MockFunction]}
|
||||
showMorePagesIndicator={true}
|
||||
totalCount={524}
|
||||
type="details"
|
||||
|
@ -204,6 +205,7 @@ exports[`NetworkTopNFlow Table Component rendering it renders the default Networ
|
|||
isInspect={false}
|
||||
loadPage={[MockFunction]}
|
||||
loading={false}
|
||||
setQuerySkip={[MockFunction]}
|
||||
showMorePagesIndicator={true}
|
||||
totalCount={524}
|
||||
type="page"
|
||||
|
|
|
@ -35,6 +35,19 @@ describe('NetworkTopNFlow Table Component', () => {
|
|||
const { storage } = createSecuritySolutionStorageMock();
|
||||
let store = createStore(state, SUB_PLUGINS_REDUCER, kibanaObservable, storage);
|
||||
const mount = useMountAppended();
|
||||
const defaultProps = {
|
||||
data: mockData.edges,
|
||||
fakeTotalCount: getOr(50, 'fakeTotalCount', mockData.pageInfo),
|
||||
flowTargeted: FlowTargetSourceDest.source,
|
||||
id: 'topNFlowSource',
|
||||
isInspect: false,
|
||||
loading: false,
|
||||
loadPage,
|
||||
setQuerySkip: jest.fn(),
|
||||
showMorePagesIndicator: getOr(false, 'showMorePagesIndicator', mockData.pageInfo),
|
||||
totalCount: mockData.totalCount,
|
||||
type: networkModel.NetworkType.page,
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
store = createStore(state, SUB_PLUGINS_REDUCER, kibanaObservable, storage);
|
||||
|
@ -44,18 +57,7 @@ describe('NetworkTopNFlow Table Component', () => {
|
|||
test('it renders the default NetworkTopNFlow table on the Network page', () => {
|
||||
const wrapper = shallow(
|
||||
<ReduxStoreProvider store={store}>
|
||||
<NetworkTopNFlowTable
|
||||
data={mockData.edges}
|
||||
fakeTotalCount={getOr(50, 'fakeTotalCount', mockData.pageInfo)}
|
||||
flowTargeted={FlowTargetSourceDest.source}
|
||||
id="topNFlowSource"
|
||||
isInspect={false}
|
||||
loading={false}
|
||||
loadPage={loadPage}
|
||||
showMorePagesIndicator={getOr(false, 'showMorePagesIndicator', mockData.pageInfo)}
|
||||
totalCount={mockData.totalCount}
|
||||
type={networkModel.NetworkType.page}
|
||||
/>
|
||||
<NetworkTopNFlowTable {...defaultProps} />
|
||||
</ReduxStoreProvider>
|
||||
);
|
||||
|
||||
|
@ -65,18 +67,7 @@ describe('NetworkTopNFlow Table Component', () => {
|
|||
test('it renders the default NetworkTopNFlow table on the IP Details page', () => {
|
||||
const wrapper = shallow(
|
||||
<ReduxStoreProvider store={store}>
|
||||
<NetworkTopNFlowTable
|
||||
data={mockData.edges}
|
||||
fakeTotalCount={getOr(50, 'fakeTotalCount', mockData.pageInfo)}
|
||||
flowTargeted={FlowTargetSourceDest.source}
|
||||
id="topNFlowSource"
|
||||
isInspect={false}
|
||||
loading={false}
|
||||
loadPage={loadPage}
|
||||
showMorePagesIndicator={getOr(false, 'showMorePagesIndicator', mockData.pageInfo)}
|
||||
totalCount={mockData.totalCount}
|
||||
type={networkModel.NetworkType.details}
|
||||
/>
|
||||
<NetworkTopNFlowTable {...defaultProps} type={networkModel.NetworkType.details} />
|
||||
</ReduxStoreProvider>
|
||||
);
|
||||
|
||||
|
@ -88,18 +79,7 @@ describe('NetworkTopNFlow Table Component', () => {
|
|||
test('when you click on the column header, you should show the sorting icon', () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders store={store}>
|
||||
<NetworkTopNFlowTable
|
||||
data={mockData.edges}
|
||||
fakeTotalCount={getOr(50, 'fakeTotalCount', mockData.pageInfo)}
|
||||
flowTargeted={FlowTargetSourceDest.source}
|
||||
id="topNFlowSource"
|
||||
isInspect={false}
|
||||
loading={false}
|
||||
loadPage={loadPage}
|
||||
showMorePagesIndicator={getOr(false, 'showMorePagesIndicator', mockData.pageInfo)}
|
||||
totalCount={mockData.totalCount}
|
||||
type={networkModel.NetworkType.page}
|
||||
/>
|
||||
<NetworkTopNFlowTable {...defaultProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(store.getState().network.page.queries.topNFlowSource.sort).toEqual({
|
||||
|
|
|
@ -31,6 +31,7 @@ interface NetworkTopNFlowTableProps {
|
|||
isInspect: boolean;
|
||||
loading: boolean;
|
||||
loadPage: (newActivePage: number) => void;
|
||||
setQuerySkip: (skip: boolean) => void;
|
||||
showMorePagesIndicator: boolean;
|
||||
totalCount: number;
|
||||
type: networkModel.NetworkType;
|
||||
|
@ -57,6 +58,7 @@ const NetworkTopNFlowTableComponent: React.FC<NetworkTopNFlowTableProps> = ({
|
|||
isInspect,
|
||||
loading,
|
||||
loadPage,
|
||||
setQuerySkip,
|
||||
showMorePagesIndicator,
|
||||
totalCount,
|
||||
type,
|
||||
|
@ -166,6 +168,7 @@ const NetworkTopNFlowTableComponent: React.FC<NetworkTopNFlowTableProps> = ({
|
|||
loadPage={loadPage}
|
||||
onChange={onChange}
|
||||
pageOfItems={data}
|
||||
setQuerySkip={setQuerySkip}
|
||||
showMorePagesIndicator={showMorePagesIndicator}
|
||||
sorting={sorting}
|
||||
totalCount={fakeTotalCount}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue