mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
Siem inspect query (#39980)
* First query inspection on a component * add inspect on all the query of the server side * add inspect in all component in host and details page * add inspect on network and ip detail page * fix server-side unit tests * fix unit test * fix UI types + old unit test * implement design/Michael suggestion * add inspect on overview page + some clean up * fix tooltip * fix unit test * clean up * remove the fancy skipquery since it broke everything * add timeline inspect + fade-in/out of the inspect button to avoid ink on the page * disable inspect timeline when no data * clean up + add unit testing * update inspect query for Kpi widgets * Fix api integration test * Review II * review II missing
This commit is contained in:
parent
84952e0c91
commit
49c5f7b8ed
163 changed files with 4303 additions and 1011 deletions
|
@ -56,4 +56,9 @@ export const sharedSchema = gql`
|
|||
endCursor: CursorType
|
||||
hasNextPage: Boolean
|
||||
}
|
||||
|
||||
type Inspect {
|
||||
dsl: [String!]!
|
||||
response: [String!]!
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -319,5 +319,5 @@ const SuggestionsPanel = euiStyled(EuiPanel).attrs({
|
|||
width: 100%;
|
||||
margin-top: 2px;
|
||||
overflow: hidden;
|
||||
z-index: ${props => props.theme.eui.euiZLevel1};;
|
||||
z-index: ${props => props.theme.eui.euiZLevel1};
|
||||
`;
|
||||
|
|
|
@ -10,6 +10,7 @@ import { pure } from 'recompose';
|
|||
import { Dispatch } from 'redux';
|
||||
import { ActionCreator } from 'typescript-fsa';
|
||||
|
||||
import { isEmpty, get } from 'lodash/fp';
|
||||
import { History } from '../../../lib/history';
|
||||
import { Note } from '../../../lib/note';
|
||||
import {
|
||||
|
@ -37,8 +38,9 @@ interface OwnProps {
|
|||
interface StateReduxProps {
|
||||
description: string;
|
||||
getNotesByIds: (noteIds: string[]) => Note[];
|
||||
isFavorite: boolean;
|
||||
isDataInTimeline: boolean;
|
||||
isDatepickerLocked: boolean;
|
||||
isFavorite: boolean;
|
||||
noteIds: string[];
|
||||
title: string;
|
||||
width: number;
|
||||
|
@ -78,6 +80,7 @@ const statefulFlyoutHeader = pure<Props>(
|
|||
description,
|
||||
getNotesByIds,
|
||||
isFavorite,
|
||||
isDataInTimeline,
|
||||
isDatepickerLocked,
|
||||
title,
|
||||
width = DEFAULT_TIMELINE_WIDTH,
|
||||
|
@ -95,6 +98,7 @@ const statefulFlyoutHeader = pure<Props>(
|
|||
createTimeline={createTimeline}
|
||||
description={description}
|
||||
getNotesByIds={getNotesByIds}
|
||||
isDataInTimeline={isDataInTimeline}
|
||||
isDatepickerLocked={isDatepickerLocked}
|
||||
isFavorite={isFavorite}
|
||||
title={title}
|
||||
|
@ -121,8 +125,10 @@ const makeMapStateToProps = () => {
|
|||
const timeline: TimelineModel = getTimeline(state, timelineId);
|
||||
const globalInput: inputsModel.InputsRange = getGlobalInput(state);
|
||||
const {
|
||||
dataProviders,
|
||||
description = '',
|
||||
isFavorite = false,
|
||||
kqlQuery,
|
||||
title = '',
|
||||
noteIds = [],
|
||||
width = DEFAULT_TIMELINE_WIDTH,
|
||||
|
@ -134,6 +140,8 @@ const makeMapStateToProps = () => {
|
|||
description,
|
||||
getNotesByIds: getNotesByIds(state),
|
||||
history,
|
||||
isDataInTimeline:
|
||||
!isEmpty(dataProviders) || !isEmpty(get('filterQuery.kuery.expression', kqlQuery)),
|
||||
isFavorite,
|
||||
isDatepickerLocked: globalInput.linkTo.includes('timeline'),
|
||||
noteIds,
|
||||
|
|
|
@ -9,6 +9,8 @@ import React from 'react';
|
|||
import { pure } from 'recompose';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { InspectButton } from '../inspect';
|
||||
|
||||
const Header = styled.header<{ border?: boolean }>`
|
||||
${props => `
|
||||
margin-bottom: ${props.theme.eui.euiSizeL};
|
||||
|
@ -24,28 +26,37 @@ const Header = styled.header<{ border?: boolean }>`
|
|||
export interface HeaderPanelProps {
|
||||
border?: boolean;
|
||||
children?: React.ReactNode;
|
||||
id?: string;
|
||||
subtitle?: string | React.ReactNode;
|
||||
showInspect?: boolean;
|
||||
title: string | React.ReactNode;
|
||||
tooltip?: string;
|
||||
}
|
||||
|
||||
export const HeaderPanel = pure<HeaderPanelProps>(
|
||||
({ border, children, subtitle, title, tooltip }) => (
|
||||
({ border, children, id, showInspect = false, subtitle, title, tooltip }) => (
|
||||
<Header border={border}>
|
||||
<EuiFlexGroup alignItems="center">
|
||||
<EuiFlexGroup alignItems="center" gutterSize="m">
|
||||
<EuiFlexItem>
|
||||
<EuiTitle>
|
||||
<h2 data-test-subj="page_headline_title">
|
||||
{title}{' '}
|
||||
{tooltip && <EuiIconTip color="subdued" content={tooltip} position="top" size="l" />}
|
||||
</h2>
|
||||
</EuiTitle>
|
||||
|
||||
<EuiFlexGroup alignItems="center" gutterSize="none">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiTitle>
|
||||
<h2 data-test-subj="page_headline_title">{title}</h2>
|
||||
</EuiTitle>
|
||||
</EuiFlexItem>
|
||||
{tooltip && (
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiIconTip color="subdued" content={tooltip} position="top" size="l" />
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
</EuiFlexGroup>
|
||||
<EuiText color="subdued" size="s">
|
||||
{subtitle}
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
|
||||
<EuiFlexItem grow={false}>
|
||||
{id && <InspectButton queryId={id} inspectIndex={0} show={showInspect} title={title} />}
|
||||
</EuiFlexItem>
|
||||
{children && <EuiFlexItem grow={false}>{children}</EuiFlexItem>}
|
||||
</EuiFlexGroup>
|
||||
</Header>
|
||||
|
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { mount } from 'enzyme';
|
||||
import * as React from 'react';
|
||||
|
||||
import {
|
||||
TestProviderWithoutDragAndDrop,
|
||||
mockGlobalState,
|
||||
apolloClientObservable,
|
||||
} from '../../mock';
|
||||
import { createStore, State } from '../../store';
|
||||
import { UpdateQueryParams, upsertQuery } from '../../store/inputs/helpers';
|
||||
|
||||
import { InspectButton } from '.';
|
||||
import { cloneDeep } from 'lodash/fp';
|
||||
|
||||
describe('Inspect Button', () => {
|
||||
const refetch = jest.fn();
|
||||
const state: State = mockGlobalState;
|
||||
const newQuery: UpdateQueryParams = {
|
||||
inputId: 'global',
|
||||
id: 'myQuery',
|
||||
inspect: null,
|
||||
loading: false,
|
||||
refetch,
|
||||
state: state.inputs,
|
||||
};
|
||||
|
||||
let store = createStore(state, apolloClientObservable);
|
||||
|
||||
describe('Render', () => {
|
||||
beforeEach(() => {
|
||||
const myState = cloneDeep(state);
|
||||
myState.inputs = upsertQuery(newQuery);
|
||||
store = createStore(myState, apolloClientObservable);
|
||||
});
|
||||
test('Eui Empty Button', () => {
|
||||
const wrapper = mount(
|
||||
<TestProviderWithoutDragAndDrop store={store}>
|
||||
<InspectButton queryId={newQuery.id} inputId="timeline" show={true} title="My title" />
|
||||
</TestProviderWithoutDragAndDrop>
|
||||
);
|
||||
expect(
|
||||
wrapper
|
||||
.find('button[data-test-subj="inspect-empty-button"]')
|
||||
.first()
|
||||
.exists()
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
test('Eui Icon Button', () => {
|
||||
const wrapper = mount(
|
||||
<TestProviderWithoutDragAndDrop store={store}>
|
||||
<InspectButton queryId={newQuery.id} show={true} title="My title" />
|
||||
</TestProviderWithoutDragAndDrop>
|
||||
);
|
||||
expect(
|
||||
wrapper
|
||||
.find('button[data-test-subj="inspect-icon-button"]')
|
||||
.first()
|
||||
.exists()
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
test('Eui Empty Button disabled', () => {
|
||||
const wrapper = mount(
|
||||
<TestProviderWithoutDragAndDrop store={store}>
|
||||
<InspectButton isDisabled={true} queryId={newQuery.id} show={true} title="My title" />
|
||||
</TestProviderWithoutDragAndDrop>
|
||||
);
|
||||
expect(wrapper.find('.euiButtonIcon').get(0).props.disabled).toBe(true);
|
||||
});
|
||||
|
||||
test('Eui Icon Button disabled', () => {
|
||||
const wrapper = mount(
|
||||
<TestProviderWithoutDragAndDrop store={store}>
|
||||
<InspectButton isDisabled={true} queryId={newQuery.id} show={true} title="My title" />
|
||||
</TestProviderWithoutDragAndDrop>
|
||||
);
|
||||
expect(wrapper.find('.euiButtonIcon').get(0).props.disabled).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Modal Inspect - happy path', () => {
|
||||
beforeEach(() => {
|
||||
const myState = cloneDeep(state);
|
||||
const myQuery = cloneDeep(newQuery);
|
||||
myQuery.inspect = {
|
||||
dsl: ['my dsl'],
|
||||
response: ['my response'],
|
||||
};
|
||||
myState.inputs = upsertQuery(myQuery);
|
||||
store = createStore(myState, apolloClientObservable);
|
||||
});
|
||||
test('Open Inspect Modal', () => {
|
||||
const wrapper = mount(
|
||||
<TestProviderWithoutDragAndDrop store={store}>
|
||||
<InspectButton queryId={newQuery.id} show={true} title="My title" />
|
||||
</TestProviderWithoutDragAndDrop>
|
||||
);
|
||||
wrapper
|
||||
.find('button[data-test-subj="inspect-icon-button"]')
|
||||
.first()
|
||||
.simulate('click');
|
||||
|
||||
wrapper.update();
|
||||
|
||||
expect(store.getState().inputs.global.query[0].isInspected).toBe(true);
|
||||
expect(
|
||||
wrapper
|
||||
.find('button[data-test-subj="modal-inspect-close"]')
|
||||
.first()
|
||||
.exists()
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
test('Close Inspect Modal', () => {
|
||||
const wrapper = mount(
|
||||
<TestProviderWithoutDragAndDrop store={store}>
|
||||
<InspectButton queryId={newQuery.id} show={true} title="My title" />
|
||||
</TestProviderWithoutDragAndDrop>
|
||||
);
|
||||
wrapper
|
||||
.find('button[data-test-subj="inspect-icon-button"]')
|
||||
.first()
|
||||
.simulate('click');
|
||||
|
||||
wrapper.update();
|
||||
|
||||
wrapper
|
||||
.find('button[data-test-subj="modal-inspect-close"]')
|
||||
.first()
|
||||
.simulate('click');
|
||||
|
||||
wrapper.update();
|
||||
|
||||
expect(store.getState().inputs.global.query[0].isInspected).toBe(false);
|
||||
expect(
|
||||
wrapper
|
||||
.find('button[data-test-subj="modal-inspect-close"]')
|
||||
.first()
|
||||
.exists()
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
test('Do not Open Inspect Modal if it is loading', () => {
|
||||
const wrapper = mount(
|
||||
<TestProviderWithoutDragAndDrop store={store}>
|
||||
<InspectButton queryId={newQuery.id} show={true} title="My title" />
|
||||
</TestProviderWithoutDragAndDrop>
|
||||
);
|
||||
store.getState().inputs.global.query[0].loading = true;
|
||||
wrapper
|
||||
.find('button[data-test-subj="inspect-icon-button"]')
|
||||
.first()
|
||||
.simulate('click');
|
||||
|
||||
wrapper.update();
|
||||
|
||||
expect(store.getState().inputs.global.query[0].isInspected).toBe(true);
|
||||
expect(
|
||||
wrapper
|
||||
.find('button[data-test-subj="modal-inspect-close"]')
|
||||
.first()
|
||||
.exists()
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
152
x-pack/legacy/plugins/siem/public/components/inspect/index.tsx
Normal file
152
x-pack/legacy/plugins/siem/public/components/inspect/index.tsx
Normal file
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { EuiButtonEmpty, EuiButtonIcon } from '@elastic/eui';
|
||||
import { getOr } from 'lodash/fp';
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { ActionCreator } from 'typescript-fsa';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { pure } from 'recompose';
|
||||
import { inputsModel, inputsSelectors, State } from '../../store';
|
||||
import { InputsModelId } from '../../store/inputs/constants';
|
||||
import { inputsActions } from '../../store/inputs';
|
||||
|
||||
import { ModalInspectQuery } from './modal';
|
||||
import * as i18n from './translations';
|
||||
|
||||
const InspectContainer = styled.div<{ showInspect: boolean }>`
|
||||
.euiButtonIcon {
|
||||
${props => (props.showInspect ? 'opacity: 1;' : 'opacity: 0')}
|
||||
transition: opacity ${props => getOr(250, 'theme.eui.euiAnimSpeedNormal', props)} ease;
|
||||
}
|
||||
`;
|
||||
|
||||
interface OwnProps {
|
||||
queryId: string;
|
||||
inputId?: InputsModelId;
|
||||
inspectIndex?: number;
|
||||
isDisabled?: boolean;
|
||||
onCloseInspect?: () => void;
|
||||
show: boolean;
|
||||
title: string | React.ReactElement | React.ReactNode;
|
||||
}
|
||||
|
||||
interface InspectButtonReducer {
|
||||
id: string;
|
||||
isInspected: boolean;
|
||||
loading: boolean;
|
||||
inspect: inputsModel.InspectQuery | null;
|
||||
selectedInspectIndex: number;
|
||||
}
|
||||
|
||||
interface InspectButtonDispatch {
|
||||
setIsInspected: ActionCreator<{
|
||||
id: string;
|
||||
inputId: InputsModelId;
|
||||
isInspected: boolean;
|
||||
selectedInspectIndex: number;
|
||||
}>;
|
||||
}
|
||||
|
||||
type InspectButtonProps = OwnProps & InspectButtonReducer & InspectButtonDispatch;
|
||||
|
||||
const InspectButtonComponent = pure<InspectButtonProps>(
|
||||
({
|
||||
inputId = 'global',
|
||||
inspect,
|
||||
isDisabled,
|
||||
isInspected,
|
||||
loading,
|
||||
inspectIndex = 0,
|
||||
onCloseInspect,
|
||||
queryId = '',
|
||||
selectedInspectIndex,
|
||||
setIsInspected,
|
||||
show,
|
||||
title = '',
|
||||
}: InspectButtonProps) => (
|
||||
<InspectContainer showInspect={show}>
|
||||
{inputId === 'timeline' && (
|
||||
<EuiButtonEmpty
|
||||
aria-label={i18n.INSPECT}
|
||||
data-test-subj="inspect-empty-button"
|
||||
color="text"
|
||||
iconSide="left"
|
||||
iconType="inspect"
|
||||
isDisabled={loading || isDisabled}
|
||||
isLoading={loading}
|
||||
onClick={() => {
|
||||
setIsInspected({
|
||||
id: queryId,
|
||||
inputId,
|
||||
isInspected: true,
|
||||
selectedInspectIndex: inspectIndex,
|
||||
});
|
||||
}}
|
||||
>
|
||||
{i18n.INSPECT}
|
||||
</EuiButtonEmpty>
|
||||
)}
|
||||
{inputId === 'global' && (
|
||||
<EuiButtonIcon
|
||||
aria-label={i18n.INSPECT}
|
||||
className={show ? '' : ''}
|
||||
data-test-subj="inspect-icon-button"
|
||||
iconSize="m"
|
||||
iconType="inspect"
|
||||
isDisabled={loading || isDisabled}
|
||||
title={i18n.INSPECT}
|
||||
onClick={() => {
|
||||
setIsInspected({
|
||||
id: queryId,
|
||||
inputId,
|
||||
isInspected: true,
|
||||
selectedInspectIndex: inspectIndex,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<ModalInspectQuery
|
||||
closeModal={() => {
|
||||
if (onCloseInspect != null) {
|
||||
onCloseInspect();
|
||||
}
|
||||
setIsInspected({
|
||||
id: queryId,
|
||||
inputId,
|
||||
isInspected: false,
|
||||
selectedInspectIndex: inspectIndex,
|
||||
});
|
||||
}}
|
||||
isShowing={!loading && selectedInspectIndex === inspectIndex && isInspected}
|
||||
request={inspect != null && inspect.dsl.length > 0 ? inspect.dsl[inspectIndex] : null}
|
||||
response={
|
||||
inspect != null && inspect.response.length > 0 ? inspect.response[inspectIndex] : null
|
||||
}
|
||||
title={title}
|
||||
data-test-subj="inspect-modal"
|
||||
/>
|
||||
</InspectContainer>
|
||||
)
|
||||
);
|
||||
|
||||
const makeMapStateToProps = () => {
|
||||
const getGlobalQuery = inputsSelectors.globalQueryByIdSelector();
|
||||
const getTimelineQuery = inputsSelectors.timelineQueryByIdSelector();
|
||||
const mapStateToProps = (state: State, { inputId = 'global', queryId }: OwnProps) => {
|
||||
return inputId === 'global' ? getGlobalQuery(state, queryId) : getTimelineQuery(state, queryId);
|
||||
};
|
||||
return mapStateToProps;
|
||||
};
|
||||
|
||||
export const InspectButton = connect(
|
||||
makeMapStateToProps,
|
||||
{
|
||||
setIsInspected: inputsActions.setInspectionParameter,
|
||||
}
|
||||
)(InspectButtonComponent);
|
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { mount } from 'enzyme';
|
||||
import React from 'react';
|
||||
|
||||
import { ModalInspectQuery } from './modal';
|
||||
|
||||
describe('Modal Inspect', () => {
|
||||
const closeModal = jest.fn();
|
||||
describe('rendering', () => {
|
||||
test('when isShowing is positive and request and response are not null', () => {
|
||||
const wrapper = mount(
|
||||
<ModalInspectQuery
|
||||
closeModal={closeModal}
|
||||
isShowing={true}
|
||||
request="My request"
|
||||
response="My response"
|
||||
title="My title"
|
||||
/>
|
||||
);
|
||||
expect(
|
||||
wrapper
|
||||
.find('[data-test-subj="modal-inspect-euiModal"]')
|
||||
.first()
|
||||
.exists()
|
||||
).toBe(true);
|
||||
expect(
|
||||
wrapper
|
||||
.find('.euiModalHeader__title')
|
||||
.first()
|
||||
.text()
|
||||
).toBe('Inspect My title');
|
||||
});
|
||||
|
||||
test('when isShowing is negative and request and response are not null', () => {
|
||||
const wrapper = mount(
|
||||
<ModalInspectQuery
|
||||
closeModal={closeModal}
|
||||
isShowing={false}
|
||||
request="My request"
|
||||
response="My response"
|
||||
title="My title"
|
||||
/>
|
||||
);
|
||||
expect(
|
||||
wrapper
|
||||
.find('[data-test-subj="modal-inspect-euiModal"]')
|
||||
.first()
|
||||
.exists()
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
test('when isShowing is positive and request is null and response is not null', () => {
|
||||
const wrapper = mount(
|
||||
<ModalInspectQuery
|
||||
closeModal={closeModal}
|
||||
isShowing={true}
|
||||
request={null}
|
||||
response="My response"
|
||||
title="My title"
|
||||
/>
|
||||
);
|
||||
expect(
|
||||
wrapper
|
||||
.find('[data-test-subj="modal-inspect-euiModal"]')
|
||||
.first()
|
||||
.exists()
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
test('when isShowing is positive and request is not null and response is null', () => {
|
||||
const wrapper = mount(
|
||||
<ModalInspectQuery
|
||||
closeModal={closeModal}
|
||||
isShowing={true}
|
||||
request="My request"
|
||||
response={null}
|
||||
title="My title"
|
||||
/>
|
||||
);
|
||||
expect(
|
||||
wrapper
|
||||
.find('[data-test-subj="modal-inspect-euiModal"]')
|
||||
.first()
|
||||
.exists()
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('functionality from tab request/response', () => {
|
||||
test('Click on request Tab', () => {
|
||||
const wrapper = mount(
|
||||
<ModalInspectQuery
|
||||
closeModal={closeModal}
|
||||
isShowing={true}
|
||||
request="My request"
|
||||
response="My response"
|
||||
title="My title"
|
||||
/>
|
||||
);
|
||||
|
||||
wrapper
|
||||
.find('.euiTab')
|
||||
.first()
|
||||
.simulate('click');
|
||||
wrapper.update();
|
||||
|
||||
expect(
|
||||
wrapper
|
||||
.find('.euiCodeBlock')
|
||||
.first()
|
||||
.text()
|
||||
).toBe('My request');
|
||||
});
|
||||
|
||||
test('Click on response Tab', () => {
|
||||
const wrapper = mount(
|
||||
<ModalInspectQuery
|
||||
closeModal={closeModal}
|
||||
isShowing={true}
|
||||
request="My request"
|
||||
response="My response"
|
||||
title="My title"
|
||||
/>
|
||||
);
|
||||
|
||||
wrapper
|
||||
.find('.euiTab')
|
||||
.at(1)
|
||||
.simulate('click');
|
||||
wrapper.update();
|
||||
|
||||
expect(
|
||||
wrapper
|
||||
.find('.euiCodeBlock')
|
||||
.first()
|
||||
.text()
|
||||
).toBe('My response');
|
||||
});
|
||||
});
|
||||
|
||||
describe('events', () => {
|
||||
test('Make sure that toggle function has been called when you click on the close button', () => {
|
||||
const wrapper = mount(
|
||||
<ModalInspectQuery
|
||||
closeModal={closeModal}
|
||||
isShowing={true}
|
||||
request="My request"
|
||||
response="my response"
|
||||
title="My title"
|
||||
/>
|
||||
);
|
||||
|
||||
wrapper.find('button[data-test-subj="modal-inspect-close"]').simulate('click');
|
||||
wrapper.update();
|
||||
expect(closeModal).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
114
x-pack/legacy/plugins/siem/public/components/inspect/modal.tsx
Normal file
114
x-pack/legacy/plugins/siem/public/components/inspect/modal.tsx
Normal file
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import {
|
||||
EuiButton,
|
||||
EuiCodeBlock,
|
||||
EuiModal,
|
||||
EuiModalBody,
|
||||
EuiModalHeader,
|
||||
EuiModalHeaderTitle,
|
||||
EuiModalFooter,
|
||||
EuiOverlayMask,
|
||||
EuiSpacer,
|
||||
EuiTabbedContent,
|
||||
} from '@elastic/eui';
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import * as i18n from './translations';
|
||||
|
||||
interface ModalInspectProps {
|
||||
closeModal: () => void;
|
||||
isShowing: boolean;
|
||||
request: string | null;
|
||||
response: string | null;
|
||||
title: string | React.ReactElement | React.ReactNode;
|
||||
}
|
||||
|
||||
const MyEuiModal = styled(EuiModal)`
|
||||
.euiModal__flex {
|
||||
width: 60vw;
|
||||
}
|
||||
.euiCodeBlock {
|
||||
height: auto !important;
|
||||
max-width: 718px;
|
||||
}
|
||||
`;
|
||||
|
||||
export const ModalInspectQuery = ({
|
||||
closeModal,
|
||||
isShowing = false,
|
||||
request,
|
||||
response,
|
||||
title,
|
||||
}: ModalInspectProps) => {
|
||||
if (!isShowing || request == null || response == null) {
|
||||
return null;
|
||||
}
|
||||
const tabs = [
|
||||
{
|
||||
id: 'request',
|
||||
name: 'Request',
|
||||
content: (
|
||||
<>
|
||||
<EuiSpacer />
|
||||
<EuiCodeBlock
|
||||
language="js"
|
||||
fontSize="m"
|
||||
paddingSize="m"
|
||||
color="dark"
|
||||
overflowHeight={300}
|
||||
isCopyable
|
||||
>
|
||||
{request}
|
||||
</EuiCodeBlock>
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 'response',
|
||||
name: 'Response',
|
||||
content: (
|
||||
<>
|
||||
<EuiSpacer />
|
||||
<EuiCodeBlock
|
||||
language="js"
|
||||
fontSize="m"
|
||||
paddingSize="m"
|
||||
color="dark"
|
||||
overflowHeight={300}
|
||||
isCopyable
|
||||
>
|
||||
{response}
|
||||
</EuiCodeBlock>
|
||||
</>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<EuiOverlayMask>
|
||||
<MyEuiModal onClose={closeModal} data-test-subj="modal-inspect-euiModal">
|
||||
<EuiModalHeader>
|
||||
<EuiModalHeaderTitle>
|
||||
{i18n.INSPECT} {title}
|
||||
</EuiModalHeaderTitle>
|
||||
</EuiModalHeader>
|
||||
|
||||
<EuiModalBody>
|
||||
<EuiTabbedContent tabs={tabs} initialSelectedTab={tabs[1]} autoFocus="selected" />
|
||||
</EuiModalBody>
|
||||
|
||||
<EuiModalFooter>
|
||||
<EuiButton onClick={closeModal} fill data-test-subj="modal-inspect-close">
|
||||
{i18n.CLOSE}
|
||||
</EuiButton>
|
||||
</EuiModalFooter>
|
||||
</MyEuiModal>
|
||||
</EuiOverlayMask>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
export const INSPECT = i18n.translate('xpack.siem.inspectDescription', {
|
||||
defaultMessage: 'Inspect',
|
||||
});
|
||||
|
||||
export const CLOSE = i18n.translate('xpack.siem.inspect.modal.closeTitle', {
|
||||
defaultMessage: 'Close',
|
||||
});
|
|
@ -81,6 +81,7 @@ interface BasicTableProps<T, U = T, V = T, W = T, X = T, Y = T, Z = T, AA = T, A
|
|||
headerTitle: string | React.ReactElement;
|
||||
headerTooltip?: string;
|
||||
headerUnit: string | React.ReactElement;
|
||||
id?: string;
|
||||
itemsPerRow?: ItemsPerRow[];
|
||||
limit: number;
|
||||
loading: boolean;
|
||||
|
@ -97,6 +98,7 @@ interface BasicTableState {
|
|||
isEmptyTable: boolean;
|
||||
isPopoverOpen: boolean;
|
||||
paginationLoading: boolean;
|
||||
showInspect: boolean;
|
||||
}
|
||||
|
||||
type Func<T> = (arg: T) => string | number;
|
||||
|
@ -120,6 +122,7 @@ export class LoadMoreTable<T, U, V, W, X, Y, Z, AA, AB> extends React.PureCompon
|
|||
isEmptyTable: this.props.pageOfItems.length === 0,
|
||||
isPopoverOpen: false,
|
||||
paginationLoading: false,
|
||||
showInspect: false,
|
||||
};
|
||||
|
||||
static getDerivedStateFromProps<T, U, V, W, X, Y, Z, AA, AB>(
|
||||
|
@ -145,6 +148,7 @@ export class LoadMoreTable<T, U, V, W, X, Y, Z, AA, AB> extends React.PureCompon
|
|||
headerTitle,
|
||||
headerTooltip,
|
||||
headerUnit,
|
||||
id,
|
||||
itemsPerRow,
|
||||
limit,
|
||||
loading,
|
||||
|
@ -196,7 +200,11 @@ export class LoadMoreTable<T, U, V, W, X, Y, Z, AA, AB> extends React.PureCompon
|
|||
</EuiContextMenuItem>
|
||||
));
|
||||
return (
|
||||
<EuiPanel data-test-subj={dataTestSubj}>
|
||||
<EuiPanel
|
||||
data-test-subj={dataTestSubj}
|
||||
onMouseEnter={this.mouseEnter}
|
||||
onMouseLeave={this.mouseLeave}
|
||||
>
|
||||
<BasicTableContainer>
|
||||
{loading && (
|
||||
<>
|
||||
|
@ -213,7 +221,9 @@ export class LoadMoreTable<T, U, V, W, X, Y, Z, AA, AB> extends React.PureCompon
|
|||
)}
|
||||
|
||||
<HeaderPanel
|
||||
subtitle={`${i18n.SHOWING}: ${headerCount.toLocaleString()} ${headerUnit}`}
|
||||
id={id}
|
||||
showInspect={this.state.showInspect}
|
||||
subtitle={<>{`${i18n.SHOWING}: ${headerCount.toLocaleString()} ${headerUnit}`}</>}
|
||||
title={headerTitle}
|
||||
tooltip={headerTooltip}
|
||||
>
|
||||
|
@ -287,6 +297,20 @@ export class LoadMoreTable<T, U, V, W, X, Y, Z, AA, AB> extends React.PureCompon
|
|||
);
|
||||
}
|
||||
|
||||
private mouseEnter = () => {
|
||||
this.setState(prevState => ({
|
||||
...prevState,
|
||||
showInspect: true,
|
||||
}));
|
||||
};
|
||||
|
||||
private mouseLeave = () => {
|
||||
this.setState(prevState => ({
|
||||
...prevState,
|
||||
showInspect: false,
|
||||
}));
|
||||
};
|
||||
|
||||
private onButtonClick = () => {
|
||||
this.setState(prevState => ({
|
||||
...prevState,
|
||||
|
|
|
@ -101,6 +101,7 @@ exports[`Authentication Table Component rendering it renders the authentication
|
|||
]
|
||||
}
|
||||
hasNextPage={true}
|
||||
id="authentication"
|
||||
loadMore={[MockFunction]}
|
||||
loading={false}
|
||||
nextCursor="aa7ca589f1b8220002f2fc61c64cfbf1"
|
||||
|
|
|
@ -34,12 +34,13 @@ describe('Authentication Table Component', () => {
|
|||
const wrapper = shallow(
|
||||
<ReduxStoreProvider store={store}>
|
||||
<AuthenticationTable
|
||||
loading={false}
|
||||
data={mockData.Authentications.edges}
|
||||
totalCount={mockData.Authentications.totalCount}
|
||||
hasNextPage={getOr(false, 'hasNextPage', mockData.Authentications.pageInfo)!}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockData.Authentications.pageInfo)}
|
||||
id="authentication"
|
||||
loading={false}
|
||||
loadMore={loadMore}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockData.Authentications.pageInfo)}
|
||||
totalCount={mockData.Authentications.totalCount}
|
||||
type={hostsModel.HostsType.page}
|
||||
/>
|
||||
</ReduxStoreProvider>
|
||||
|
|
|
@ -29,6 +29,7 @@ import { getRowItemDraggables } from '../../../tables/helpers';
|
|||
interface OwnProps {
|
||||
data: AuthenticationsEdges[];
|
||||
loading: boolean;
|
||||
id: string;
|
||||
hasNextPage: boolean;
|
||||
nextCursor: string;
|
||||
totalCount: number;
|
||||
|
@ -71,6 +72,7 @@ const AuthenticationTableComponent = pure<AuthenticationTableProps>(
|
|||
({
|
||||
data,
|
||||
hasNextPage,
|
||||
id,
|
||||
limit,
|
||||
loading,
|
||||
loadMore,
|
||||
|
@ -85,6 +87,7 @@ const AuthenticationTableComponent = pure<AuthenticationTableProps>(
|
|||
headerCount={totalCount}
|
||||
headerTitle={i18n.AUTHENTICATIONS}
|
||||
headerUnit={i18n.UNIT(totalCount)}
|
||||
id={id}
|
||||
itemsPerRow={rowItems}
|
||||
limit={limit}
|
||||
loading={loading}
|
||||
|
|
|
@ -137,6 +137,7 @@ exports[`Load More Events Table Component rendering it renders the events table
|
|||
]
|
||||
}
|
||||
hasNextPage={true}
|
||||
id="events"
|
||||
loadMore={[MockFunction]}
|
||||
loading={false}
|
||||
nextCursor="1546878704036"
|
||||
|
|
|
@ -34,13 +34,14 @@ describe('Load More Events Table Component', () => {
|
|||
const wrapper = shallow(
|
||||
<ReduxStoreProvider store={store}>
|
||||
<EventsTable
|
||||
loading={false}
|
||||
data={mockData.Events.edges.map(i => i.node)}
|
||||
totalCount={mockData.Events.totalCount}
|
||||
tiebreaker={getOr(null, 'endCursor.tiebreaker', mockData.Events.pageInfo)!}
|
||||
hasNextPage={getOr(false, 'hasNextPage', mockData.Events.pageInfo)!}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockData.Events.pageInfo)}
|
||||
id="events"
|
||||
loading={false}
|
||||
loadMore={loadMore}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockData.Events.pageInfo)}
|
||||
tiebreaker={getOr(null, 'endCursor.tiebreaker', mockData.Events.pageInfo)!}
|
||||
totalCount={mockData.Events.totalCount}
|
||||
type={hostsModel.HostsType.page}
|
||||
/>
|
||||
</ReduxStoreProvider>
|
||||
|
|
|
@ -27,6 +27,7 @@ interface OwnProps {
|
|||
data: Ecs[];
|
||||
loading: boolean;
|
||||
hasNextPage: boolean;
|
||||
id: string;
|
||||
nextCursor: string;
|
||||
tiebreaker: string;
|
||||
totalCount: number;
|
||||
|
@ -67,6 +68,7 @@ const EventsTableComponent = pure<EventsTableProps>(
|
|||
({
|
||||
data,
|
||||
hasNextPage,
|
||||
id,
|
||||
limit,
|
||||
loading,
|
||||
loadMore,
|
||||
|
@ -82,6 +84,7 @@ const EventsTableComponent = pure<EventsTableProps>(
|
|||
headerCount={totalCount}
|
||||
headerTitle={i18n.EVENTS}
|
||||
headerUnit={i18n.UNIT(totalCount)}
|
||||
id={id}
|
||||
itemsPerRow={rowItems}
|
||||
limit={limit}
|
||||
loading={loading}
|
||||
|
|
|
@ -194,6 +194,7 @@ exports[`Host Summary Component rendering it renders the default Host Summary 1`
|
|||
}
|
||||
}
|
||||
endDate={1560837600000}
|
||||
id="hostOverview"
|
||||
isLoadingAnomaliesData={false}
|
||||
loading={false}
|
||||
narrowDateRange={[MockFunction]}
|
||||
|
|
|
@ -40,13 +40,14 @@ describe('Host Summary Component', () => {
|
|||
const wrapper = shallow(
|
||||
<TestProviders>
|
||||
<HostOverview
|
||||
startDate={new Date('2019-06-15T06:00:00.000Z').valueOf()}
|
||||
endDate={new Date('2019-06-18T06:00:00.000Z').valueOf()}
|
||||
loading={false}
|
||||
data={mockData.Hosts.edges[0].node}
|
||||
anomaliesData={mockAnomalies}
|
||||
data={mockData.Hosts.edges[0].node}
|
||||
endDate={new Date('2019-06-18T06:00:00.000Z').valueOf()}
|
||||
id="hostOverview"
|
||||
isLoadingAnomaliesData={false}
|
||||
loading={false}
|
||||
narrowDateRange={jest.fn()}
|
||||
startDate={new Date('2019-06-15T06:00:00.000Z').valueOf()}
|
||||
/>
|
||||
</TestProviders>
|
||||
);
|
||||
|
|
|
@ -6,26 +6,28 @@
|
|||
|
||||
import { EuiDescriptionList, EuiFlexItem } from '@elastic/eui';
|
||||
import { getOr } from 'lodash/fp';
|
||||
import React, { useContext } from 'react';
|
||||
import React, { useContext, useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { DescriptionList } from '../../../../../common/utility_types';
|
||||
import { HostItem } from '../../../../graphql/types';
|
||||
import { getEmptyTagValue } from '../../../empty_value';
|
||||
|
||||
import * as i18n from './translations';
|
||||
import { FirstLastSeenHost, FirstLastSeenHostType } from '../first_last_seen_host';
|
||||
import { DefaultFieldRenderer, hostIdRenderer } from '../../../field_renderers/field_renderers';
|
||||
import { InspectButton } from '../../../inspect';
|
||||
import { HostItem } from '../../../../graphql/types';
|
||||
import { LoadingPanel } from '../../../loading';
|
||||
import { LoadingOverlay, OverviewWrapper } from '../../index';
|
||||
import { IPDetailsLink } from '../../../links';
|
||||
import { AnomalyScores } from '../../../ml/score/anomaly_scores';
|
||||
import { Anomalies, NarrowDateRange } from '../../../ml/types';
|
||||
import { MlCapabilitiesContext } from '../../../ml/permissions/ml_capabilities_provider';
|
||||
import { hasMlUserPermissions } from '../../../ml/permissions/has_ml_user_permissions';
|
||||
import { AnomalyScores } from '../../../ml/score/anomaly_scores';
|
||||
import { Anomalies, NarrowDateRange } from '../../../ml/types';
|
||||
import { LoadingOverlay, OverviewWrapper } from '../../index';
|
||||
import { FirstLastSeenHost, FirstLastSeenHostType } from '../first_last_seen_host';
|
||||
|
||||
import * as i18n from './translations';
|
||||
|
||||
interface HostSummaryProps {
|
||||
data: HostItem;
|
||||
id: string;
|
||||
loading: boolean;
|
||||
isLoadingAnomaliesData: boolean;
|
||||
anomaliesData: Anomalies | null;
|
||||
|
@ -52,14 +54,17 @@ export const HostOverview = React.memo<HostSummaryProps>(
|
|||
({
|
||||
data,
|
||||
loading,
|
||||
id,
|
||||
startDate,
|
||||
endDate,
|
||||
isLoadingAnomaliesData,
|
||||
anomaliesData,
|
||||
narrowDateRange,
|
||||
}) => {
|
||||
const [showInspect, setShowInspect] = useState(false);
|
||||
const capabilities = useContext(MlCapabilitiesContext);
|
||||
const userPermissions = hasMlUserPermissions(capabilities);
|
||||
|
||||
const getDefaultRenderer = (fieldName: string, fieldData: HostItem) => (
|
||||
<DefaultFieldRenderer
|
||||
rowItems={getOr([], fieldName, fieldData)}
|
||||
|
@ -165,7 +170,10 @@ export const HostOverview = React.memo<HostSummaryProps>(
|
|||
];
|
||||
|
||||
return (
|
||||
<OverviewWrapper>
|
||||
<OverviewWrapper
|
||||
onMouseEnter={() => setShowInspect(true)}
|
||||
onMouseLeave={() => setShowInspect(false)}
|
||||
>
|
||||
{loading && (
|
||||
<>
|
||||
<LoadingOverlay />
|
||||
|
@ -179,6 +187,12 @@ export const HostOverview = React.memo<HostSummaryProps>(
|
|||
/>
|
||||
</>
|
||||
)}
|
||||
<InspectButton
|
||||
queryId={id}
|
||||
show={showInspect}
|
||||
title={i18n.INSPECT_TITLE}
|
||||
inspectIndex={0}
|
||||
/>
|
||||
{descriptionLists.map((descriptionList, index) =>
|
||||
getDescriptionList(descriptionList, index)
|
||||
)}
|
||||
|
|
|
@ -71,3 +71,7 @@ export const INSTANCE_ID = i18n.translate('xpack.siem.host.details.overview.inst
|
|||
export const MACHINE_TYPE = i18n.translate('xpack.siem.host.details.overview.machineTypeTitle', {
|
||||
defaultMessage: 'Machine Type',
|
||||
});
|
||||
|
||||
export const INSPECT_TITLE = i18n.translate('xpack.siem.host.details.overview.inspectTitle', {
|
||||
defaultMessage: 'Host overview',
|
||||
});
|
||||
|
|
|
@ -77,6 +77,7 @@ exports[`Load More Table Component rendering it renders the default Hosts table
|
|||
]
|
||||
}
|
||||
hasNextPage={true}
|
||||
id="hostsQuery"
|
||||
indexPattern={
|
||||
Object {
|
||||
"fields": Array [
|
||||
|
|
|
@ -40,13 +40,14 @@ describe('Load More Table Component', () => {
|
|||
<ReduxStoreProvider store={store}>
|
||||
<KibanaConfigContext.Provider value={mockFrameworks.default_UTC}>
|
||||
<HostsTable
|
||||
indexPattern={mockIndexPattern}
|
||||
loading={false}
|
||||
data={mockData.Hosts.edges}
|
||||
totalCount={mockData.Hosts.totalCount}
|
||||
id="hostsQuery"
|
||||
indexPattern={mockIndexPattern}
|
||||
hasNextPage={getOr(false, 'hasNextPage', mockData.Hosts.pageInfo)!}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockData.Hosts.pageInfo)}
|
||||
loading={false}
|
||||
loadMore={loadMore}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockData.Hosts.pageInfo)}
|
||||
totalCount={mockData.Hosts.totalCount}
|
||||
type={hostsModel.HostsType.page}
|
||||
/>
|
||||
</KibanaConfigContext.Provider>
|
||||
|
@ -61,6 +62,7 @@ describe('Load More Table Component', () => {
|
|||
<MockedProvider>
|
||||
<TestProviders store={store}>
|
||||
<HostsTable
|
||||
id="hostsQuery"
|
||||
indexPattern={mockIndexPattern}
|
||||
loading={false}
|
||||
data={mockData.Hosts.edges}
|
||||
|
@ -79,6 +81,7 @@ describe('Load More Table Component', () => {
|
|||
<MockedProvider>
|
||||
<TestProviders store={store}>
|
||||
<HostsTable
|
||||
id="hostsQuery"
|
||||
indexPattern={mockIndexPattern}
|
||||
loading={false}
|
||||
data={mockData.Hosts.edges}
|
||||
|
|
|
@ -35,6 +35,7 @@ import * as i18n from './translations';
|
|||
interface OwnProps {
|
||||
data: HostsEdges[];
|
||||
loading: boolean;
|
||||
id: string;
|
||||
indexPattern: StaticIndexPattern;
|
||||
hasNextPage: boolean;
|
||||
nextCursor: string;
|
||||
|
@ -105,6 +106,7 @@ class HostsTableComponent extends React.PureComponent<HostsTableProps> {
|
|||
data,
|
||||
direction,
|
||||
hasNextPage,
|
||||
id,
|
||||
indexPattern,
|
||||
limit,
|
||||
loading,
|
||||
|
@ -120,6 +122,7 @@ class HostsTableComponent extends React.PureComponent<HostsTableProps> {
|
|||
headerCount={totalCount}
|
||||
headerTitle={i18n.HOSTS}
|
||||
headerUnit={i18n.UNIT(totalCount)}
|
||||
id={id}
|
||||
itemsPerRow={rowItems}
|
||||
limit={limit}
|
||||
loading={loading}
|
||||
|
|
|
@ -25,6 +25,7 @@ exports[`kpiHostsComponent render it should render KpiHostDetailsData 1`] = `
|
|||
]
|
||||
}
|
||||
grow={1}
|
||||
index={0}
|
||||
key="authentication"
|
||||
/>
|
||||
<Memo()
|
||||
|
@ -51,6 +52,7 @@ exports[`kpiHostsComponent render it should render KpiHostDetailsData 1`] = `
|
|||
]
|
||||
}
|
||||
grow={1}
|
||||
index={1}
|
||||
key="uniqueIps"
|
||||
/>
|
||||
</EuiFlexGroup>
|
||||
|
@ -72,6 +74,7 @@ exports[`kpiHostsComponent render it should render KpiHostsData 1`] = `
|
|||
]
|
||||
}
|
||||
grow={2}
|
||||
index={0}
|
||||
key="hosts"
|
||||
/>
|
||||
<Memo()
|
||||
|
@ -97,6 +100,7 @@ exports[`kpiHostsComponent render it should render KpiHostsData 1`] = `
|
|||
]
|
||||
}
|
||||
grow={4}
|
||||
index={1}
|
||||
key="authentication"
|
||||
/>
|
||||
<Memo()
|
||||
|
@ -123,6 +127,7 @@ exports[`kpiHostsComponent render it should render KpiHostsData 1`] = `
|
|||
]
|
||||
}
|
||||
grow={4}
|
||||
index={2}
|
||||
key="uniqueIps"
|
||||
/>
|
||||
</EuiFlexGroup>
|
||||
|
|
|
@ -14,24 +14,33 @@ import { kpiHostsMapping } from './kpi_hosts_mapping';
|
|||
import { kpiHostDetailsMapping } from './kpi_host_details_mapping';
|
||||
|
||||
describe('kpiHostsComponent', () => {
|
||||
const ID = 'kpiHost';
|
||||
const from = new Date('2019-06-15T06:00:00.000Z').valueOf();
|
||||
const to = new Date('2019-06-18T06:00:00.000Z').valueOf();
|
||||
describe('render', () => {
|
||||
test('it should render spinner if it is loading', () => {
|
||||
const wrapper: ShallowWrapper = shallow(
|
||||
<KpiHostsComponent data={mockKpiHostsData} loading={true} />
|
||||
<KpiHostsComponent data={mockKpiHostsData} from={from} id={ID} loading={true} to={to} />
|
||||
);
|
||||
expect(toJson(wrapper)).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('it should render KpiHostsData', () => {
|
||||
const wrapper: ShallowWrapper = shallow(
|
||||
<KpiHostsComponent data={mockKpiHostsData} loading={false} />
|
||||
<KpiHostsComponent data={mockKpiHostsData} from={from} id={ID} loading={false} to={to} />
|
||||
);
|
||||
expect(toJson(wrapper)).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('it should render KpiHostDetailsData', () => {
|
||||
const wrapper: ShallowWrapper = shallow(
|
||||
<KpiHostsComponent data={mockKpiHostDetailsData} loading={false} />
|
||||
<KpiHostsComponent
|
||||
data={mockKpiHostDetailsData}
|
||||
from={from}
|
||||
id={ID}
|
||||
loading={false}
|
||||
to={to}
|
||||
/>
|
||||
);
|
||||
expect(toJson(wrapper)).toMatchSnapshot();
|
||||
});
|
||||
|
@ -47,7 +56,7 @@ describe('kpiHostsComponent', () => {
|
|||
});
|
||||
|
||||
beforeEach(() => {
|
||||
shallow(<KpiHostsComponent data={data} loading={false} />);
|
||||
shallow(<KpiHostsComponent data={data} from={from} id={ID} loading={false} to={to} />);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
@ -59,7 +68,7 @@ describe('kpiHostsComponent', () => {
|
|||
});
|
||||
|
||||
test(`it should apply correct mapping by given data type`, () => {
|
||||
expect(mockUseKpiMatrixStatus).toBeCalledWith(mapping, data);
|
||||
expect(mockUseKpiMatrixStatus).toBeCalledWith(mapping, data, ID, from, to);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -16,14 +16,19 @@ import { kpiHostDetailsMapping } from './kpi_host_details_mapping';
|
|||
|
||||
const kpiWidgetHeight = 247;
|
||||
|
||||
interface KpiHostsProps {
|
||||
data: KpiHostsData;
|
||||
interface GenericKpiHostProps {
|
||||
from: number;
|
||||
id: string;
|
||||
loading: boolean;
|
||||
to: number;
|
||||
}
|
||||
|
||||
interface KpiHostDetailsProps {
|
||||
interface KpiHostsProps extends GenericKpiHostProps {
|
||||
data: KpiHostsData;
|
||||
}
|
||||
|
||||
interface KpiHostDetailsProps extends GenericKpiHostProps {
|
||||
data: KpiHostDetailsData;
|
||||
loading: boolean;
|
||||
}
|
||||
|
||||
const FlexGroupSpinner = styled(EuiFlexGroup)`
|
||||
|
@ -32,10 +37,16 @@ const FlexGroupSpinner = styled(EuiFlexGroup)`
|
|||
}
|
||||
`;
|
||||
|
||||
export const KpiHostsComponent = ({ data, loading }: KpiHostsProps | KpiHostDetailsProps) => {
|
||||
export const KpiHostsComponent = ({
|
||||
data,
|
||||
from,
|
||||
loading,
|
||||
id,
|
||||
to,
|
||||
}: KpiHostsProps | KpiHostDetailsProps) => {
|
||||
const mappings =
|
||||
(data as KpiHostsData).hosts !== undefined ? kpiHostsMapping : kpiHostDetailsMapping;
|
||||
const statItemsProps: StatItemsProps[] = useKpiMatrixStatus(mappings, data);
|
||||
const statItemsProps: StatItemsProps[] = useKpiMatrixStatus(mappings, data, id, from, to);
|
||||
return loading ? (
|
||||
<FlexGroupSpinner justifyContent="center" alignItems="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
|
@ -44,7 +55,7 @@ export const KpiHostsComponent = ({ data, loading }: KpiHostsProps | KpiHostDeta
|
|||
</FlexGroupSpinner>
|
||||
) : (
|
||||
<EuiFlexGroup>
|
||||
{statItemsProps.map(mappedStatItemProps => {
|
||||
{statItemsProps.map((mappedStatItemProps, idx) => {
|
||||
return <StatItemsComponent {...mappedStatItemProps} />;
|
||||
})}
|
||||
</EuiFlexGroup>
|
||||
|
|
|
@ -15,6 +15,7 @@ const euiColorVis9 = '#920000';
|
|||
export const kpiHostDetailsMapping: Readonly<StatItems[]> = [
|
||||
{
|
||||
key: 'authentication',
|
||||
index: 0,
|
||||
fields: [
|
||||
{
|
||||
key: 'authSuccess',
|
||||
|
@ -38,6 +39,7 @@ export const kpiHostDetailsMapping: Readonly<StatItems[]> = [
|
|||
},
|
||||
{
|
||||
key: 'uniqueIps',
|
||||
index: 1,
|
||||
fields: [
|
||||
{
|
||||
key: 'uniqueSourceIps',
|
||||
|
|
|
@ -16,6 +16,7 @@ const euiColorVis9 = '#920000';
|
|||
export const kpiHostsMapping: Readonly<StatItems[]> = [
|
||||
{
|
||||
key: 'hosts',
|
||||
index: 0,
|
||||
fields: [
|
||||
{
|
||||
key: 'hosts',
|
||||
|
@ -30,6 +31,7 @@ export const kpiHostsMapping: Readonly<StatItems[]> = [
|
|||
},
|
||||
{
|
||||
key: 'authentication',
|
||||
index: 1,
|
||||
fields: [
|
||||
{
|
||||
key: 'authSuccess',
|
||||
|
@ -53,6 +55,7 @@ export const kpiHostsMapping: Readonly<StatItems[]> = [
|
|||
},
|
||||
{
|
||||
key: 'uniqueIps',
|
||||
index: 2,
|
||||
fields: [
|
||||
{
|
||||
key: 'uniqueSourceIps',
|
||||
|
|
|
@ -202,6 +202,7 @@ exports[`UncommonProcess Table Component rendering it renders the default Uncomm
|
|||
]
|
||||
}
|
||||
hasNextPage={true}
|
||||
id="uncommonProcess"
|
||||
loadMore={[MockFunction]}
|
||||
loading={false}
|
||||
nextCursor="aa7ca589f1b8220002f2fc61c64cfbf1"
|
||||
|
|
|
@ -24,12 +24,13 @@ describe('UncommonProcess Table Component', () => {
|
|||
const wrapper = shallow(
|
||||
<TestProviders>
|
||||
<UncommonProcessTable
|
||||
loading={false}
|
||||
data={mockData.UncommonProcess.edges}
|
||||
totalCount={mockData.UncommonProcess.totalCount}
|
||||
hasNextPage={getOr(false, 'hasNextPage', mockData.UncommonProcess.pageInfo)!}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockData.UncommonProcess.pageInfo)}
|
||||
id="uncommonProcess"
|
||||
loading={false}
|
||||
loadMore={loadMore}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockData.UncommonProcess.pageInfo)}
|
||||
totalCount={mockData.UncommonProcess.totalCount}
|
||||
type={hostsModel.HostsType.page}
|
||||
/>
|
||||
</TestProviders>
|
||||
|
@ -42,12 +43,13 @@ describe('UncommonProcess Table Component', () => {
|
|||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<UncommonProcessTable
|
||||
loading={false}
|
||||
data={mockData.UncommonProcess.edges}
|
||||
totalCount={mockData.UncommonProcess.totalCount}
|
||||
hasNextPage={getOr(false, 'hasNextPage', mockData.UncommonProcess.pageInfo)!}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockData.UncommonProcess.pageInfo)}
|
||||
id="uncommonProcess"
|
||||
loading={false}
|
||||
loadMore={loadMore}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockData.UncommonProcess.pageInfo)}
|
||||
totalCount={mockData.UncommonProcess.totalCount}
|
||||
type={hostsModel.HostsType.page}
|
||||
/>
|
||||
</TestProviders>
|
||||
|
@ -66,12 +68,13 @@ describe('UncommonProcess Table Component', () => {
|
|||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<UncommonProcessTable
|
||||
loading={false}
|
||||
data={mockData.UncommonProcess.edges}
|
||||
totalCount={mockData.UncommonProcess.totalCount}
|
||||
hasNextPage={getOr(false, 'hasNextPage', mockData.UncommonProcess.pageInfo)!}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockData.UncommonProcess.pageInfo)}
|
||||
id="uncommonProcess"
|
||||
loading={false}
|
||||
loadMore={loadMore}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockData.UncommonProcess.pageInfo)}
|
||||
totalCount={mockData.UncommonProcess.totalCount}
|
||||
type={hostsModel.HostsType.page}
|
||||
/>
|
||||
</TestProviders>
|
||||
|
@ -91,12 +94,13 @@ describe('UncommonProcess Table Component', () => {
|
|||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<UncommonProcessTable
|
||||
loading={false}
|
||||
data={mockData.UncommonProcess.edges}
|
||||
totalCount={mockData.UncommonProcess.totalCount}
|
||||
hasNextPage={getOr(false, 'hasNextPage', mockData.UncommonProcess.pageInfo)!}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockData.UncommonProcess.pageInfo)}
|
||||
id="uncommonProcess"
|
||||
loading={false}
|
||||
loadMore={loadMore}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockData.UncommonProcess.pageInfo)}
|
||||
totalCount={mockData.UncommonProcess.totalCount}
|
||||
type={hostsModel.HostsType.page}
|
||||
/>
|
||||
</TestProviders>
|
||||
|
@ -116,12 +120,13 @@ describe('UncommonProcess Table Component', () => {
|
|||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<UncommonProcessTable
|
||||
loading={false}
|
||||
data={mockData.UncommonProcess.edges}
|
||||
totalCount={mockData.UncommonProcess.totalCount}
|
||||
hasNextPage={getOr(false, 'hasNextPage', mockData.UncommonProcess.pageInfo)!}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockData.UncommonProcess.pageInfo)}
|
||||
id="uncommonProcess"
|
||||
loading={false}
|
||||
loadMore={loadMore}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockData.UncommonProcess.pageInfo)}
|
||||
totalCount={mockData.UncommonProcess.totalCount}
|
||||
type={hostsModel.HostsType.page}
|
||||
/>
|
||||
</TestProviders>
|
||||
|
@ -141,12 +146,13 @@ describe('UncommonProcess Table Component', () => {
|
|||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<UncommonProcessTable
|
||||
loading={false}
|
||||
data={mockData.UncommonProcess.edges}
|
||||
totalCount={mockData.UncommonProcess.totalCount}
|
||||
hasNextPage={getOr(false, 'hasNextPage', mockData.UncommonProcess.pageInfo)!}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockData.UncommonProcess.pageInfo)}
|
||||
id="uncommonProcess"
|
||||
loading={false}
|
||||
loadMore={loadMore}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockData.UncommonProcess.pageInfo)}
|
||||
totalCount={mockData.UncommonProcess.totalCount}
|
||||
type={hostsModel.HostsType.page}
|
||||
/>
|
||||
</TestProviders>
|
||||
|
@ -166,12 +172,13 @@ describe('UncommonProcess Table Component', () => {
|
|||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<UncommonProcessTable
|
||||
loading={false}
|
||||
data={mockData.UncommonProcess.edges}
|
||||
totalCount={mockData.UncommonProcess.totalCount}
|
||||
hasNextPage={getOr(false, 'hasNextPage', mockData.UncommonProcess.pageInfo)!}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockData.UncommonProcess.pageInfo)}
|
||||
id="uncommonProcess"
|
||||
loading={false}
|
||||
loadMore={loadMore}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockData.UncommonProcess.pageInfo)}
|
||||
totalCount={mockData.UncommonProcess.totalCount}
|
||||
type={hostsModel.HostsType.page}
|
||||
/>
|
||||
</TestProviders>
|
||||
|
@ -190,12 +197,13 @@ describe('UncommonProcess Table Component', () => {
|
|||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<UncommonProcessTable
|
||||
loading={false}
|
||||
data={mockData.UncommonProcess.edges}
|
||||
totalCount={mockData.UncommonProcess.totalCount}
|
||||
hasNextPage={getOr(false, 'hasNextPage', mockData.UncommonProcess.pageInfo)!}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockData.UncommonProcess.pageInfo)}
|
||||
id="uncommonProcess"
|
||||
loading={false}
|
||||
loadMore={loadMore}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockData.UncommonProcess.pageInfo)}
|
||||
totalCount={mockData.UncommonProcess.totalCount}
|
||||
type={hostsModel.HostsType.page}
|
||||
/>
|
||||
</TestProviders>
|
||||
|
@ -214,12 +222,13 @@ describe('UncommonProcess Table Component', () => {
|
|||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<UncommonProcessTable
|
||||
loading={false}
|
||||
data={mockData.UncommonProcess.edges}
|
||||
totalCount={mockData.UncommonProcess.totalCount}
|
||||
hasNextPage={getOr(false, 'hasNextPage', mockData.UncommonProcess.pageInfo)!}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockData.UncommonProcess.pageInfo)}
|
||||
id="uncommonProcess"
|
||||
loading={false}
|
||||
loadMore={loadMore}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockData.UncommonProcess.pageInfo)}
|
||||
totalCount={mockData.UncommonProcess.totalCount}
|
||||
type={hostsModel.HostsType.page}
|
||||
/>
|
||||
</TestProviders>
|
||||
|
|
|
@ -23,6 +23,7 @@ interface OwnProps {
|
|||
data: UncommonProcessesEdges[];
|
||||
loading: boolean;
|
||||
hasNextPage: boolean;
|
||||
id: string;
|
||||
nextCursor: string;
|
||||
totalCount: number;
|
||||
loadMore: (cursor: string) => void;
|
||||
|
@ -72,6 +73,7 @@ const UncommonProcessTableComponent = pure<UncommonProcessTableProps>(
|
|||
({
|
||||
data,
|
||||
hasNextPage,
|
||||
id,
|
||||
limit,
|
||||
loading,
|
||||
loadMore,
|
||||
|
@ -86,6 +88,7 @@ const UncommonProcessTableComponent = pure<UncommonProcessTableProps>(
|
|||
headerCount={totalCount}
|
||||
headerTitle={i18n.UNCOMMON_PROCESSES}
|
||||
headerUnit={i18n.UNIT(totalCount)}
|
||||
id={id}
|
||||
itemsPerRow={rowItems}
|
||||
limit={limit}
|
||||
loading={loading}
|
||||
|
|
|
@ -119,6 +119,11 @@ export const MoreRowItems = styled(EuiIcon)`
|
|||
|
||||
export const OverviewWrapper = styled(EuiFlexGroup)`
|
||||
position: relative;
|
||||
.euiButtonIcon {
|
||||
position: absolute;
|
||||
top: -10px;
|
||||
right: 10px;
|
||||
}
|
||||
`;
|
||||
|
||||
export const LoadingOverlay = styled.div`
|
||||
|
|
|
@ -13,20 +13,28 @@ interface OwnProps {
|
|||
id: string;
|
||||
loading: boolean;
|
||||
refetch: inputsModel.Refetch;
|
||||
setQuery: (params: { id: string; loading: boolean; refetch: inputsModel.Refetch }) => void;
|
||||
setQuery: (
|
||||
params: {
|
||||
id: string;
|
||||
inspect: inputsModel.InspectQuery | null;
|
||||
loading: boolean;
|
||||
refetch: inputsModel.Refetch;
|
||||
}
|
||||
) => void;
|
||||
inspect?: inputsModel.InspectQuery;
|
||||
}
|
||||
|
||||
export function manageQuery<T>(WrappedComponent: React.ComponentClass<T> | React.ComponentType<T>) {
|
||||
class ManageQuery extends React.PureComponent<OwnProps & T> {
|
||||
public componentDidUpdate(prevProps: OwnProps) {
|
||||
const { loading, id, refetch, setQuery } = this.props;
|
||||
const { loading, id, refetch, setQuery, inspect = null } = this.props;
|
||||
if (prevProps.loading !== loading) {
|
||||
setQuery({ id, loading, refetch });
|
||||
setQuery({ id, inspect, loading, refetch });
|
||||
}
|
||||
}
|
||||
|
||||
public render() {
|
||||
const otherProps = omit(['id', 'refetch', 'setQuery'], this.props);
|
||||
const otherProps = omit(['refetch', 'setQuery'], this.props);
|
||||
return <WrappedComponent {...otherProps} />;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,6 +65,7 @@ exports[`Domains Table Component Rendering it renders the default Domains table
|
|||
}
|
||||
flowTarget="source"
|
||||
hasNextPage={false}
|
||||
id="domains"
|
||||
indexPattern={
|
||||
Object {
|
||||
"fields": Array [
|
||||
|
|
|
@ -39,15 +39,16 @@ describe('Domains Table Component', () => {
|
|||
const wrapper = shallow(
|
||||
<ReduxStoreProvider store={store}>
|
||||
<DomainsTable
|
||||
indexPattern={mockIndexPattern}
|
||||
ip={ip}
|
||||
totalCount={1}
|
||||
loading={false}
|
||||
loadMore={loadMore}
|
||||
data={mockDomainsData.edges}
|
||||
flowTarget={FlowTarget.source}
|
||||
hasNextPage={getOr(false, 'hasNextPage', mockDomainsData.pageInfo)!}
|
||||
id="domains"
|
||||
indexPattern={mockIndexPattern}
|
||||
ip={ip}
|
||||
loading={false}
|
||||
loadMore={loadMore}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockDomainsData.pageInfo)}
|
||||
totalCount={1}
|
||||
type={networkModel.NetworkType.details}
|
||||
/>
|
||||
</ReduxStoreProvider>
|
||||
|
@ -63,15 +64,16 @@ describe('Domains Table Component', () => {
|
|||
<MockedProvider>
|
||||
<TestProviders store={store}>
|
||||
<DomainsTable
|
||||
indexPattern={mockIndexPattern}
|
||||
ip={ip}
|
||||
totalCount={1}
|
||||
loading={false}
|
||||
loadMore={loadMore}
|
||||
data={mockDomainsData.edges}
|
||||
flowTarget={FlowTarget.source}
|
||||
indexPattern={mockIndexPattern}
|
||||
hasNextPage={getOr(false, 'hasNextPage', mockDomainsData.pageInfo)!}
|
||||
id="domains"
|
||||
ip={ip}
|
||||
loading={false}
|
||||
loadMore={loadMore}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockDomainsData.pageInfo)}
|
||||
totalCount={1}
|
||||
type={networkModel.NetworkType.details}
|
||||
/>
|
||||
</TestProviders>
|
||||
|
|
|
@ -31,6 +31,7 @@ interface OwnProps {
|
|||
flowTarget: FlowTarget;
|
||||
loading: boolean;
|
||||
hasNextPage: boolean;
|
||||
id: string;
|
||||
indexPattern: StaticIndexPattern;
|
||||
ip: string;
|
||||
nextCursor: string;
|
||||
|
@ -89,6 +90,7 @@ class DomainsTableComponent extends React.PureComponent<DomainsTableProps> {
|
|||
data,
|
||||
domainsSortField,
|
||||
hasNextPage,
|
||||
id,
|
||||
indexPattern,
|
||||
ip,
|
||||
limit,
|
||||
|
@ -122,6 +124,7 @@ class DomainsTableComponent extends React.PureComponent<DomainsTableProps> {
|
|||
}
|
||||
headerTitle={i18n.DOMAINS}
|
||||
headerUnit={i18n.UNIT(totalCount)}
|
||||
id={id}
|
||||
itemsPerRow={rowItems}
|
||||
limit={limit}
|
||||
loading={loading}
|
||||
|
|
|
@ -150,6 +150,7 @@ exports[`IP Overview Component rendering it renders the default IP Overview 1`]
|
|||
}
|
||||
endDate={1560837600000}
|
||||
flowTarget="source"
|
||||
id="ipOverview"
|
||||
ip="10.10.10.10"
|
||||
isLoadingAnomaliesData={false}
|
||||
loading={false}
|
||||
|
|
|
@ -29,19 +29,20 @@ describe('IP Overview Component', () => {
|
|||
|
||||
describe('rendering', () => {
|
||||
const mockProps = {
|
||||
anomaliesData: mockAnomalies,
|
||||
data: mockData.IpOverview,
|
||||
endDate: new Date('2019-06-18T06:00:00.000Z').valueOf(),
|
||||
flowTarget: FlowTarget.source,
|
||||
loading: false,
|
||||
id: 'ipOverview',
|
||||
ip: '10.10.10.10',
|
||||
data: mockData.IpOverview,
|
||||
isLoadingAnomaliesData: false,
|
||||
narrowDateRange: (jest.fn() as unknown) as NarrowDateRange,
|
||||
startDate: new Date('2019-06-15T06:00:00.000Z').valueOf(),
|
||||
type: networkModel.NetworkType.details,
|
||||
updateFlowTargetAction: (jest.fn() as unknown) as ActionCreator<{
|
||||
flowTarget: FlowTarget;
|
||||
}>,
|
||||
startDate: new Date('2019-06-15T06:00:00.000Z').valueOf(),
|
||||
endDate: new Date('2019-06-18T06:00:00.000Z').valueOf(),
|
||||
anomaliesData: mockAnomalies,
|
||||
isLoadingAnomaliesData: false,
|
||||
narrowDateRange: (jest.fn() as unknown) as NarrowDateRange,
|
||||
};
|
||||
|
||||
test('it renders the default IP Overview', () => {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import { EuiDescriptionList, EuiFlexItem } from '@elastic/eui';
|
||||
import React, { useContext } from 'react';
|
||||
import React, { useContext, useState } from 'react';
|
||||
import { pure } from 'recompose';
|
||||
import styled from 'styled-components';
|
||||
|
||||
|
@ -30,10 +30,12 @@ import { Anomalies, NarrowDateRange } from '../../../ml/types';
|
|||
import { AnomalyScores } from '../../../ml/score/anomaly_scores';
|
||||
import { MlCapabilitiesContext } from '../../../ml/permissions/ml_capabilities_provider';
|
||||
import { hasMlUserPermissions } from '../../../ml/permissions/has_ml_user_permissions';
|
||||
import { InspectButton } from '../../../inspect';
|
||||
|
||||
interface OwnProps {
|
||||
data: IpOverviewData;
|
||||
flowTarget: FlowTarget;
|
||||
id: string;
|
||||
ip: string;
|
||||
loading: boolean;
|
||||
isLoadingAnomaliesData: boolean;
|
||||
|
@ -64,6 +66,7 @@ const getDescriptionList = (descriptionList: DescriptionList[], key: number) =>
|
|||
|
||||
export const IpOverview = pure<IpOverviewProps>(
|
||||
({
|
||||
id,
|
||||
ip,
|
||||
data,
|
||||
loading,
|
||||
|
@ -74,6 +77,7 @@ export const IpOverview = pure<IpOverviewProps>(
|
|||
anomaliesData,
|
||||
narrowDateRange,
|
||||
}) => {
|
||||
const [showInspect, setShowInspect] = useState(false);
|
||||
const capabilities = useContext(MlCapabilitiesContext);
|
||||
const userPermissions = hasMlUserPermissions(capabilities);
|
||||
const typeData: Overview = data[flowTarget]!;
|
||||
|
@ -135,7 +139,10 @@ export const IpOverview = pure<IpOverviewProps>(
|
|||
],
|
||||
];
|
||||
return (
|
||||
<OverviewWrapper>
|
||||
<OverviewWrapper
|
||||
onMouseEnter={() => setShowInspect(true)}
|
||||
onMouseLeave={() => setShowInspect(false)}
|
||||
>
|
||||
{loading && (
|
||||
<>
|
||||
<LoadingOverlay />
|
||||
|
@ -149,6 +156,12 @@ export const IpOverview = pure<IpOverviewProps>(
|
|||
/>
|
||||
</>
|
||||
)}
|
||||
<InspectButton
|
||||
queryId={id}
|
||||
show={showInspect}
|
||||
title={i18n.INSPECT_TITLE}
|
||||
inspectIndex={0}
|
||||
/>
|
||||
{descriptionLists.map((descriptionList, index) =>
|
||||
getDescriptionList(descriptionList, index)
|
||||
)}
|
||||
|
|
|
@ -83,3 +83,10 @@ export const AS_DESTINATION = i18n.translate(
|
|||
defaultMessage: 'As Destination',
|
||||
}
|
||||
);
|
||||
|
||||
export const INSPECT_TITLE = i18n.translate(
|
||||
'xpack.siem.network.ipDetails.ipOverview.inspectTitle',
|
||||
{
|
||||
defaultMessage: 'IP overview',
|
||||
}
|
||||
);
|
||||
|
|
|
@ -32,7 +32,10 @@ exports[`KpiNetwork Component rendering it renders loading icons 1`] = `
|
|||
],
|
||||
}
|
||||
}
|
||||
from={1560578400000}
|
||||
id="kpiNetwork"
|
||||
loading={true}
|
||||
to={1560837600000}
|
||||
/>
|
||||
`;
|
||||
|
||||
|
@ -68,6 +71,9 @@ exports[`KpiNetwork Component rendering it renders the default widget 1`] = `
|
|||
],
|
||||
}
|
||||
}
|
||||
from={1560578400000}
|
||||
id="kpiNetwork"
|
||||
loading={false}
|
||||
to={1560837600000}
|
||||
/>
|
||||
`;
|
||||
|
|
|
@ -17,6 +17,8 @@ import { mockData } from './mock';
|
|||
|
||||
describe('KpiNetwork Component', () => {
|
||||
const state: State = mockGlobalState;
|
||||
const from = new Date('2019-06-15T06:00:00.000Z').valueOf();
|
||||
const to = new Date('2019-06-18T06:00:00.000Z').valueOf();
|
||||
|
||||
let store = createStore(state, apolloClientObservable);
|
||||
|
||||
|
@ -28,7 +30,13 @@ describe('KpiNetwork Component', () => {
|
|||
test('it renders loading icons', () => {
|
||||
const wrapper = shallow(
|
||||
<ReduxStoreProvider store={store}>
|
||||
<KpiNetworkComponent data={mockData.KpiNetwork} loading={true} />
|
||||
<KpiNetworkComponent
|
||||
data={mockData.KpiNetwork}
|
||||
from={from}
|
||||
id="kpiNetwork"
|
||||
loading={true}
|
||||
to={to}
|
||||
/>
|
||||
</ReduxStoreProvider>
|
||||
);
|
||||
|
||||
|
@ -38,7 +46,13 @@ describe('KpiNetwork Component', () => {
|
|||
test('it renders the default widget', () => {
|
||||
const wrapper = shallow(
|
||||
<ReduxStoreProvider store={store}>
|
||||
<KpiNetworkComponent data={mockData.KpiNetwork} loading={false} />
|
||||
<KpiNetworkComponent
|
||||
data={mockData.KpiNetwork}
|
||||
from={from}
|
||||
id="kpiNetwork"
|
||||
loading={false}
|
||||
to={to}
|
||||
/>
|
||||
</ReduxStoreProvider>
|
||||
);
|
||||
|
||||
|
|
|
@ -30,12 +30,16 @@ const euiColorVis3 = '#490092';
|
|||
|
||||
interface KpiNetworkProps {
|
||||
data: KpiNetworkData;
|
||||
from: number;
|
||||
id: string;
|
||||
loading: boolean;
|
||||
to: number;
|
||||
}
|
||||
|
||||
export const fieldTitleChartMapping: Readonly<StatItems[]> = [
|
||||
{
|
||||
key: 'UniqueIps',
|
||||
index: 4,
|
||||
fields: [
|
||||
{
|
||||
key: 'uniqueSourcePrivateIps',
|
||||
|
@ -64,6 +68,7 @@ export const fieldTitleChartMapping: Readonly<StatItems[]> = [
|
|||
const fieldTitleMatrixMapping: Readonly<StatItems[]> = [
|
||||
{
|
||||
key: 'networkEvents',
|
||||
index: 0,
|
||||
fields: [
|
||||
{
|
||||
key: 'networkEvents',
|
||||
|
@ -76,6 +81,7 @@ const fieldTitleMatrixMapping: Readonly<StatItems[]> = [
|
|||
},
|
||||
{
|
||||
key: 'dnsQueries',
|
||||
index: 1,
|
||||
fields: [
|
||||
{
|
||||
key: 'dnsQueries',
|
||||
|
@ -86,6 +92,7 @@ const fieldTitleMatrixMapping: Readonly<StatItems[]> = [
|
|||
},
|
||||
{
|
||||
key: 'uniqueFlowId',
|
||||
index: 2,
|
||||
fields: [
|
||||
{
|
||||
key: 'uniqueFlowId',
|
||||
|
@ -96,6 +103,7 @@ const fieldTitleMatrixMapping: Readonly<StatItems[]> = [
|
|||
},
|
||||
{
|
||||
key: 'tlsHandshakes',
|
||||
index: 3,
|
||||
fields: [
|
||||
{
|
||||
key: 'tlsHandshakes',
|
||||
|
@ -113,41 +121,61 @@ const FlexGroup = styled(EuiFlexGroup)`
|
|||
export const KpiNetworkBaseComponent = ({
|
||||
fieldsMapping,
|
||||
data,
|
||||
id,
|
||||
from,
|
||||
to,
|
||||
}: {
|
||||
fieldsMapping: Readonly<StatItems[]>;
|
||||
data: KpiNetworkData;
|
||||
id: string;
|
||||
from: number;
|
||||
to: number;
|
||||
}) => {
|
||||
const statItemsProps: StatItemsProps[] = useKpiMatrixStatus(fieldsMapping, data);
|
||||
const statItemsProps: StatItemsProps[] = useKpiMatrixStatus(fieldsMapping, data, id, from, to);
|
||||
|
||||
return (
|
||||
<EuiFlexGroup wrap>
|
||||
{statItemsProps.map(mappedStatItemProps => {
|
||||
{statItemsProps.map((mappedStatItemProps, idx) => {
|
||||
return <StatItemsComponent {...mappedStatItemProps} />;
|
||||
})}
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
};
|
||||
|
||||
export const KpiNetworkComponent = React.memo<KpiNetworkProps>(({ data, loading }) => {
|
||||
return loading ? (
|
||||
<FlexGroup justifyContent="center" alignItems="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiLoadingSpinner size="xl" />
|
||||
</EuiFlexItem>
|
||||
</FlexGroup>
|
||||
) : (
|
||||
<EuiFlexGroup wrap>
|
||||
<EuiFlexItem grow={1}>
|
||||
{_chunk(kipsPerRow, fieldTitleMatrixMapping).map((mappingsPerLine, idx) => (
|
||||
<React.Fragment key={`kpi-network-row-${idx}`}>
|
||||
{idx % kipsPerRow === 1 && <EuiSpacer size="l" />}
|
||||
<KpiNetworkBaseComponent data={data} fieldsMapping={mappingsPerLine} />
|
||||
</React.Fragment>
|
||||
))}
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={1}>
|
||||
<KpiNetworkBaseComponent data={data} fieldsMapping={fieldTitleChartMapping} />
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
});
|
||||
export const KpiNetworkComponent = React.memo<KpiNetworkProps>(
|
||||
({ data, from, id, loading, to }) => {
|
||||
return loading ? (
|
||||
<FlexGroup justifyContent="center" alignItems="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiLoadingSpinner size="xl" />
|
||||
</EuiFlexItem>
|
||||
</FlexGroup>
|
||||
) : (
|
||||
<EuiFlexGroup wrap>
|
||||
<EuiFlexItem grow={1}>
|
||||
{_chunk(kipsPerRow, fieldTitleMatrixMapping).map((mappingsPerLine, idx) => (
|
||||
<React.Fragment key={`kpi-network-row-${idx}`}>
|
||||
{idx % kipsPerRow === 1 && <EuiSpacer size="l" />}
|
||||
<KpiNetworkBaseComponent
|
||||
data={data}
|
||||
id={id}
|
||||
fieldsMapping={mappingsPerLine}
|
||||
from={from}
|
||||
to={to}
|
||||
/>
|
||||
</React.Fragment>
|
||||
))}
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={1}>
|
||||
<KpiNetworkBaseComponent
|
||||
data={data}
|
||||
id={id}
|
||||
fieldsMapping={fieldTitleChartMapping}
|
||||
from={from}
|
||||
to={to}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
|
|
@ -40,6 +40,7 @@ export const mockData: { KpiNetwork: KpiNetworkData } = {
|
|||
|
||||
const mockMappingItems: StatItems = {
|
||||
key: 'UniqueIps',
|
||||
index: 0,
|
||||
fields: [
|
||||
{
|
||||
key: 'uniqueSourcePrivateIps',
|
||||
|
@ -150,28 +151,6 @@ export const mockEnableChartsInitialData = {
|
|||
};
|
||||
|
||||
export const mockEnableChartsData = {
|
||||
fields: [
|
||||
{
|
||||
key: 'uniqueSourcePrivateIps',
|
||||
value: 383,
|
||||
name: 'Src.',
|
||||
description: 'Source',
|
||||
color: '#DB1374',
|
||||
icon: 'visMapCoordinate',
|
||||
},
|
||||
{
|
||||
key: 'uniqueDestinationPrivateIps',
|
||||
value: 18,
|
||||
name: 'Dest.',
|
||||
description: 'Destination',
|
||||
color: '#490092',
|
||||
icon: 'visMapCoordinate',
|
||||
},
|
||||
],
|
||||
description: 'Unique Private IPs',
|
||||
enableAreaChart: true,
|
||||
enableBarChart: true,
|
||||
grow: 2,
|
||||
areaChart: [
|
||||
{
|
||||
key: 'uniqueSourcePrivateIpsHistogram',
|
||||
|
@ -211,4 +190,30 @@ export const mockEnableChartsData = {
|
|||
value: [{ x: 'Dest.', y: 18, g: 'uniqueDestinationPrivateIps' }],
|
||||
},
|
||||
],
|
||||
description: 'Unique Private IPs',
|
||||
enableAreaChart: true,
|
||||
enableBarChart: true,
|
||||
fields: [
|
||||
{
|
||||
key: 'uniqueSourcePrivateIps',
|
||||
value: 383,
|
||||
name: 'Src.',
|
||||
description: 'Source',
|
||||
color: '#DB1374',
|
||||
icon: 'visMapCoordinate',
|
||||
},
|
||||
{
|
||||
key: 'uniqueDestinationPrivateIps',
|
||||
value: 18,
|
||||
name: 'Dest.',
|
||||
description: 'Destination',
|
||||
color: '#490092',
|
||||
icon: 'visMapCoordinate',
|
||||
},
|
||||
],
|
||||
from: 1560578400000,
|
||||
grow: 2,
|
||||
id: 'statItem',
|
||||
index: 4,
|
||||
to: 1560837600000,
|
||||
};
|
||||
|
|
|
@ -137,6 +137,7 @@ exports[`NetworkTopNFlow Table Component rendering it renders the default Networ
|
|||
]
|
||||
}
|
||||
hasNextPage={true}
|
||||
id="dns"
|
||||
loadMore={[MockFunction]}
|
||||
loading={false}
|
||||
nextCursor="10"
|
||||
|
|
|
@ -32,12 +32,13 @@ describe('NetworkTopNFlow Table Component', () => {
|
|||
const wrapper = shallow(
|
||||
<ReduxStoreProvider store={store}>
|
||||
<NetworkDnsTable
|
||||
loading={false}
|
||||
data={mockData.NetworkDns.edges}
|
||||
totalCount={mockData.NetworkDns.totalCount}
|
||||
hasNextPage={getOr(false, 'hasNextPage', mockData.NetworkDns.pageInfo)!}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockData.NetworkDns.pageInfo)}
|
||||
id="dns"
|
||||
loading={false}
|
||||
loadMore={loadMore}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockData.NetworkDns.pageInfo)}
|
||||
totalCount={mockData.NetworkDns.totalCount}
|
||||
type={networkModel.NetworkType.page}
|
||||
/>
|
||||
</ReduxStoreProvider>
|
||||
|
@ -53,12 +54,13 @@ describe('NetworkTopNFlow Table Component', () => {
|
|||
<MockedProvider>
|
||||
<TestProviders store={store}>
|
||||
<NetworkDnsTable
|
||||
loading={false}
|
||||
data={mockData.NetworkDns.edges}
|
||||
totalCount={mockData.NetworkDns.totalCount}
|
||||
hasNextPage={getOr(false, 'hasNextPage', mockData.NetworkDns.pageInfo)!}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockData.NetworkDns.pageInfo)}
|
||||
id="dns"
|
||||
loading={false}
|
||||
loadMore={loadMore}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockData.NetworkDns.pageInfo)}
|
||||
totalCount={mockData.NetworkDns.totalCount}
|
||||
type={networkModel.NetworkType.page}
|
||||
/>
|
||||
</TestProviders>
|
||||
|
|
|
@ -22,6 +22,7 @@ interface OwnProps {
|
|||
data: NetworkDnsEdges[];
|
||||
loading: boolean;
|
||||
hasNextPage: boolean;
|
||||
id: string;
|
||||
nextCursor: string;
|
||||
loadMore: (cursor: string) => void;
|
||||
totalCount: number;
|
||||
|
@ -80,6 +81,7 @@ class NetworkDnsTableComponent extends React.PureComponent<NetworkDnsTableProps>
|
|||
limit,
|
||||
loading,
|
||||
loadMore,
|
||||
id,
|
||||
nextCursor,
|
||||
totalCount,
|
||||
type,
|
||||
|
@ -96,6 +98,7 @@ class NetworkDnsTableComponent extends React.PureComponent<NetworkDnsTableProps>
|
|||
headerTitle={i18n.TOP_DNS_DOMAINS}
|
||||
headerTooltip={i18n.TOOLTIP}
|
||||
headerUnit={i18n.UNIT(totalCount)}
|
||||
id={id}
|
||||
itemsPerRow={rowItems}
|
||||
limit={limit}
|
||||
loading={loading}
|
||||
|
|
|
@ -52,6 +52,7 @@ exports[`NetworkTopNFlow Table Component rendering it renders the default Networ
|
|||
]
|
||||
}
|
||||
hasNextPage={true}
|
||||
id="topNFlow"
|
||||
indexPattern={
|
||||
Object {
|
||||
"fields": Array [
|
||||
|
|
|
@ -38,13 +38,14 @@ describe('NetworkTopNFlow Table Component', () => {
|
|||
const wrapper = shallow(
|
||||
<ReduxStoreProvider store={store}>
|
||||
<NetworkTopNFlowTable
|
||||
data={mockData.NetworkTopNFlow.edges}
|
||||
hasNextPage={getOr(false, 'hasNextPage', mockData.NetworkTopNFlow.pageInfo)!}
|
||||
id="topNFlow"
|
||||
indexPattern={mockIndexPattern}
|
||||
loading={false}
|
||||
data={mockData.NetworkTopNFlow.edges}
|
||||
totalCount={mockData.NetworkTopNFlow.totalCount}
|
||||
hasNextPage={getOr(false, 'hasNextPage', mockData.NetworkTopNFlow.pageInfo)!}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockData.NetworkTopNFlow.pageInfo)}
|
||||
loadMore={loadMore}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockData.NetworkTopNFlow.pageInfo)}
|
||||
totalCount={mockData.NetworkTopNFlow.totalCount}
|
||||
type={networkModel.NetworkType.page}
|
||||
/>
|
||||
</ReduxStoreProvider>
|
||||
|
@ -64,13 +65,14 @@ describe('NetworkTopNFlow Table Component', () => {
|
|||
<MockedProvider>
|
||||
<TestProviders store={store}>
|
||||
<NetworkTopNFlowTable
|
||||
data={mockData.NetworkTopNFlow.edges}
|
||||
hasNextPage={getOr(false, 'hasNextPage', mockData.NetworkTopNFlow.pageInfo)!}
|
||||
id="topNFlow"
|
||||
indexPattern={mockIndexPattern}
|
||||
loading={false}
|
||||
data={mockData.NetworkTopNFlow.edges}
|
||||
totalCount={mockData.NetworkTopNFlow.totalCount}
|
||||
hasNextPage={getOr(false, 'hasNextPage', mockData.NetworkTopNFlow.pageInfo)!}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockData.NetworkTopNFlow.pageInfo)}
|
||||
loadMore={loadMore}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockData.NetworkTopNFlow.pageInfo)}
|
||||
totalCount={mockData.NetworkTopNFlow.totalCount}
|
||||
type={networkModel.NetworkType.page}
|
||||
/>
|
||||
</TestProviders>
|
||||
|
@ -100,13 +102,14 @@ describe('NetworkTopNFlow Table Component', () => {
|
|||
<MockedProvider>
|
||||
<TestProviders store={store}>
|
||||
<NetworkTopNFlowTable
|
||||
data={mockData.NetworkTopNFlow.edges}
|
||||
hasNextPage={getOr(false, 'hasNextPage', mockData.NetworkTopNFlow.pageInfo)!}
|
||||
id="topNFlow"
|
||||
indexPattern={mockIndexPattern}
|
||||
loading={false}
|
||||
data={mockData.NetworkTopNFlow.edges}
|
||||
totalCount={mockData.NetworkTopNFlow.totalCount}
|
||||
hasNextPage={getOr(false, 'hasNextPage', mockData.NetworkTopNFlow.pageInfo)!}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockData.NetworkTopNFlow.pageInfo)}
|
||||
loadMore={loadMore}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockData.NetworkTopNFlow.pageInfo)}
|
||||
totalCount={mockData.NetworkTopNFlow.totalCount}
|
||||
type={networkModel.NetworkType.page}
|
||||
/>
|
||||
</TestProviders>
|
||||
|
@ -141,13 +144,14 @@ describe('NetworkTopNFlow Table Component', () => {
|
|||
<MockedProvider>
|
||||
<TestProviders store={store}>
|
||||
<NetworkTopNFlowTable
|
||||
data={mockData.NetworkTopNFlow.edges}
|
||||
hasNextPage={getOr(false, 'hasNextPage', mockData.NetworkTopNFlow.pageInfo)!}
|
||||
id="topNFlow"
|
||||
indexPattern={mockIndexPattern}
|
||||
loading={false}
|
||||
data={mockData.NetworkTopNFlow.edges}
|
||||
totalCount={mockData.NetworkTopNFlow.totalCount}
|
||||
hasNextPage={getOr(false, 'hasNextPage', mockData.NetworkTopNFlow.pageInfo)!}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockData.NetworkTopNFlow.pageInfo)}
|
||||
loadMore={loadMore}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockData.NetworkTopNFlow.pageInfo)}
|
||||
totalCount={mockData.NetworkTopNFlow.totalCount}
|
||||
type={networkModel.NetworkType.page}
|
||||
/>
|
||||
</TestProviders>
|
||||
|
|
|
@ -29,6 +29,7 @@ import * as i18n from './translations';
|
|||
|
||||
interface OwnProps {
|
||||
data: NetworkTopNFlowEdges[];
|
||||
id: string;
|
||||
indexPattern: StaticIndexPattern;
|
||||
loading: boolean;
|
||||
hasNextPage: boolean;
|
||||
|
@ -93,6 +94,7 @@ class NetworkTopNFlowTableComponent extends React.PureComponent<NetworkTopNFlowT
|
|||
const {
|
||||
data,
|
||||
hasNextPage,
|
||||
id,
|
||||
indexPattern,
|
||||
limit,
|
||||
loading,
|
||||
|
@ -124,7 +126,7 @@ class NetworkTopNFlowTableComponent extends React.PureComponent<NetworkTopNFlowT
|
|||
hasNextPage={hasNextPage}
|
||||
headerCount={totalCount}
|
||||
headerSupplement={
|
||||
<EuiFlexGroup alignItems="center">
|
||||
<EuiFlexGroup alignItems="center" gutterSize="m">
|
||||
<EuiFlexItem grow={false}>
|
||||
<SelectTypeItem
|
||||
grow={false}
|
||||
|
@ -156,6 +158,7 @@ class NetworkTopNFlowTableComponent extends React.PureComponent<NetworkTopNFlowT
|
|||
}
|
||||
headerTitle={i18n.TOP_TALKERS}
|
||||
headerUnit={i18n.UNIT(totalCount)}
|
||||
id={id}
|
||||
itemsPerRow={rowItems}
|
||||
limit={limit}
|
||||
loading={loading}
|
||||
|
|
|
@ -79,6 +79,7 @@ exports[`Tls Table Component Rendering it renders the default Domains table 1`]
|
|||
]
|
||||
}
|
||||
hasNextPage={false}
|
||||
id="tls"
|
||||
loadMore={[MockFunction]}
|
||||
loading={false}
|
||||
nextCursor="10"
|
||||
|
|
|
@ -32,12 +32,13 @@ describe('Tls Table Component', () => {
|
|||
const wrapper = shallow(
|
||||
<ReduxStoreProvider store={store}>
|
||||
<TlsTable
|
||||
totalCount={1}
|
||||
loading={false}
|
||||
loadMore={loadMore}
|
||||
data={mockTlsData.edges}
|
||||
hasNextPage={getOr(false, 'hasNextPage', mockTlsData.pageInfo)!}
|
||||
id="tls"
|
||||
loading={false}
|
||||
loadMore={loadMore}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockTlsData.pageInfo)}
|
||||
totalCount={1}
|
||||
type={networkModel.NetworkType.details}
|
||||
/>
|
||||
</ReduxStoreProvider>
|
||||
|
@ -53,12 +54,13 @@ describe('Tls Table Component', () => {
|
|||
<MockedProvider>
|
||||
<TestProviders store={store}>
|
||||
<TlsTable
|
||||
totalCount={1}
|
||||
loading={false}
|
||||
loadMore={loadMore}
|
||||
data={mockTlsData.edges}
|
||||
hasNextPage={getOr(false, 'hasNextPage', mockTlsData.pageInfo)!}
|
||||
id="tls"
|
||||
loading={false}
|
||||
loadMore={loadMore}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockTlsData.pageInfo)}
|
||||
totalCount={1}
|
||||
type={networkModel.NetworkType.details}
|
||||
/>
|
||||
</TestProviders>
|
||||
|
|
|
@ -20,6 +20,7 @@ interface OwnProps {
|
|||
data: TlsEdges[];
|
||||
loading: boolean;
|
||||
hasNextPage: boolean;
|
||||
id: string;
|
||||
nextCursor: string;
|
||||
totalCount: number;
|
||||
loadMore: (cursor: string) => void;
|
||||
|
@ -74,6 +75,7 @@ class TlsTableComponent extends React.PureComponent<TlsTableProps> {
|
|||
limit,
|
||||
loading,
|
||||
loadMore,
|
||||
id,
|
||||
totalCount,
|
||||
nextCursor,
|
||||
updateTlsLimit,
|
||||
|
@ -86,6 +88,7 @@ class TlsTableComponent extends React.PureComponent<TlsTableProps> {
|
|||
headerCount={totalCount}
|
||||
headerTitle={i18n.TRANSPORT_LAYER_SECURITY}
|
||||
headerUnit={i18n.UNIT(totalCount)}
|
||||
id={id}
|
||||
itemsPerRow={rowItems}
|
||||
limit={limit}
|
||||
loading={loading}
|
||||
|
|
|
@ -72,6 +72,7 @@ exports[`Users Table Component Rendering it renders the default Users table 1`]
|
|||
}
|
||||
flowTarget="source"
|
||||
hasNextPage={false}
|
||||
id="user"
|
||||
loadMore={[MockFunction]}
|
||||
loading={false}
|
||||
nextCursor="10"
|
||||
|
|
|
@ -33,13 +33,14 @@ describe('Users Table Component', () => {
|
|||
const wrapper = shallow(
|
||||
<ReduxStoreProvider store={store}>
|
||||
<UsersTable
|
||||
totalCount={1}
|
||||
loading={false}
|
||||
loadMore={loadMore}
|
||||
data={mockUsersData.edges}
|
||||
flowTarget={FlowTarget.source}
|
||||
hasNextPage={getOr(false, 'hasNextPage', mockUsersData.pageInfo)!}
|
||||
id="user"
|
||||
loading={false}
|
||||
loadMore={loadMore}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockUsersData.pageInfo)!}
|
||||
totalCount={1}
|
||||
type={networkModel.NetworkType.details}
|
||||
/>
|
||||
</ReduxStoreProvider>
|
||||
|
@ -55,13 +56,14 @@ describe('Users Table Component', () => {
|
|||
<MockedProvider>
|
||||
<TestProviders store={store}>
|
||||
<UsersTable
|
||||
totalCount={1}
|
||||
loading={false}
|
||||
loadMore={loadMore}
|
||||
data={mockUsersData.edges}
|
||||
flowTarget={FlowTarget.source}
|
||||
hasNextPage={getOr(false, 'hasNextPage', mockUsersData.pageInfo)!}
|
||||
id="user"
|
||||
loading={false}
|
||||
loadMore={loadMore}
|
||||
nextCursor={getOr(null, 'endCursor.value', mockUsersData.pageInfo)!}
|
||||
totalCount={1}
|
||||
type={networkModel.NetworkType.details}
|
||||
/>
|
||||
</TestProviders>
|
||||
|
|
|
@ -23,6 +23,7 @@ interface OwnProps {
|
|||
flowTarget: FlowTarget;
|
||||
loading: boolean;
|
||||
hasNextPage: boolean;
|
||||
id: string;
|
||||
nextCursor: string;
|
||||
totalCount: number;
|
||||
loadMore: (cursor: string) => void;
|
||||
|
@ -77,6 +78,7 @@ class UsersTableComponent extends React.PureComponent<UsersTableProps> {
|
|||
limit,
|
||||
loading,
|
||||
loadMore,
|
||||
id,
|
||||
totalCount,
|
||||
nextCursor,
|
||||
updateUsersLimit,
|
||||
|
@ -91,6 +93,7 @@ class UsersTableComponent extends React.PureComponent<UsersTableProps> {
|
|||
headerCount={totalCount}
|
||||
headerTitle={i18n.USERS}
|
||||
headerUnit={i18n.UNIT(totalCount)}
|
||||
id={id}
|
||||
itemsPerRow={rowItems}
|
||||
limit={limit}
|
||||
loading={loading}
|
||||
|
|
|
@ -6,12 +6,15 @@
|
|||
|
||||
import { EuiButton, EuiFlexItem, EuiPanel } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { pure } from 'recompose';
|
||||
|
||||
import { HeaderPanel } from '../../../header_panel';
|
||||
import { manageQuery } from '../../../page/manage_query';
|
||||
import { OverviewHostQuery } from '../../../../containers/overview/overview_host';
|
||||
import {
|
||||
ID as OverviewHostQueryId,
|
||||
OverviewHostQuery,
|
||||
} from '../../../../containers/overview/overview_host';
|
||||
import { inputsModel } from '../../../../store/inputs';
|
||||
import { OverviewHostStats } from '../overview_host_stats';
|
||||
|
||||
|
@ -19,43 +22,59 @@ export interface OwnProps {
|
|||
startDate: number;
|
||||
endDate: number;
|
||||
setQuery: (
|
||||
{ id, loading, refetch }: { id: string; loading: boolean; refetch: inputsModel.Refetch }
|
||||
{
|
||||
id,
|
||||
inspect,
|
||||
loading,
|
||||
refetch,
|
||||
}: {
|
||||
id: string;
|
||||
inspect: inputsModel.InspectQuery | null;
|
||||
loading: boolean;
|
||||
refetch: inputsModel.Refetch;
|
||||
}
|
||||
) => void;
|
||||
}
|
||||
|
||||
const OverviewHostStatsManage = manageQuery(OverviewHostStats);
|
||||
type OverviewHostProps = OwnProps;
|
||||
export const OverviewHost = pure<OverviewHostProps>(({ endDate, startDate, setQuery }) => (
|
||||
<EuiFlexItem>
|
||||
<EuiPanel>
|
||||
<HeaderPanel
|
||||
border
|
||||
subtitle={
|
||||
<FormattedMessage
|
||||
id="xpack.siem.overview.hostsSubtitle"
|
||||
defaultMessage="Showing: Last 24 Hours"
|
||||
/>
|
||||
}
|
||||
title={
|
||||
<FormattedMessage id="xpack.siem.overview.hostsTitle" defaultMessage="Host Events" />
|
||||
}
|
||||
>
|
||||
<EuiButton href="#/link-to/hosts">
|
||||
<FormattedMessage id="xpack.siem.overview.hostsAction" defaultMessage="View Hosts" />
|
||||
</EuiButton>
|
||||
</HeaderPanel>
|
||||
export const OverviewHost = pure<OverviewHostProps>(({ endDate, startDate, setQuery }) => {
|
||||
const [isHover, setIsHover] = useState(false);
|
||||
return (
|
||||
<EuiFlexItem>
|
||||
<EuiPanel onMouseEnter={() => setIsHover(true)} onMouseLeave={() => setIsHover(false)}>
|
||||
<HeaderPanel
|
||||
border
|
||||
id={OverviewHostQueryId}
|
||||
showInspect={isHover}
|
||||
subtitle={
|
||||
<FormattedMessage
|
||||
id="xpack.siem.overview.hostsSubtitle"
|
||||
defaultMessage="Showing: Last 24 Hours"
|
||||
/>
|
||||
}
|
||||
title={
|
||||
<FormattedMessage id="xpack.siem.overview.hostsTitle" defaultMessage="Host Events" />
|
||||
}
|
||||
>
|
||||
<EuiButton href="#/link-to/hosts">
|
||||
<FormattedMessage id="xpack.siem.overview.hostsAction" defaultMessage="View Hosts" />
|
||||
</EuiButton>
|
||||
</HeaderPanel>
|
||||
|
||||
<OverviewHostQuery endDate={endDate} sourceId="default" startDate={startDate}>
|
||||
{({ overviewHost, loading, id, refetch }) => (
|
||||
<OverviewHostStatsManage
|
||||
loading={loading}
|
||||
data={overviewHost}
|
||||
setQuery={setQuery}
|
||||
id={id}
|
||||
refetch={refetch}
|
||||
/>
|
||||
)}
|
||||
</OverviewHostQuery>
|
||||
</EuiPanel>
|
||||
</EuiFlexItem>
|
||||
));
|
||||
<OverviewHostQuery endDate={endDate} sourceId="default" startDate={startDate}>
|
||||
{({ overviewHost, loading, id, inspect, refetch }) => (
|
||||
<OverviewHostStatsManage
|
||||
loading={loading}
|
||||
data={overviewHost}
|
||||
setQuery={setQuery}
|
||||
id={id}
|
||||
inspect={inspect}
|
||||
refetch={refetch}
|
||||
/>
|
||||
)}
|
||||
</OverviewHostQuery>
|
||||
</EuiPanel>
|
||||
</EuiFlexItem>
|
||||
);
|
||||
});
|
||||
|
|
|
@ -6,12 +6,15 @@
|
|||
|
||||
import { EuiButton, EuiFlexItem, EuiPanel } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { pure } from 'recompose';
|
||||
|
||||
import { HeaderPanel } from '../../../header_panel';
|
||||
import { manageQuery } from '../../../page/manage_query';
|
||||
import { OverviewNetworkQuery } from '../../../../containers/overview/overview_network';
|
||||
import {
|
||||
ID as OverviewNetworkQueryId,
|
||||
OverviewNetworkQuery,
|
||||
} from '../../../../containers/overview/overview_network';
|
||||
import { inputsModel } from '../../../../store/inputs';
|
||||
import { OverviewNetworkStats } from '../overview_network_stats';
|
||||
|
||||
|
@ -19,43 +22,65 @@ export interface OwnProps {
|
|||
startDate: number;
|
||||
endDate: number;
|
||||
setQuery: (
|
||||
{ id, loading, refetch }: { id: string; loading: boolean; refetch: inputsModel.Refetch }
|
||||
{
|
||||
id,
|
||||
inspect,
|
||||
loading,
|
||||
refetch,
|
||||
}: {
|
||||
id: string;
|
||||
inspect: inputsModel.InspectQuery | null;
|
||||
loading: boolean;
|
||||
refetch: inputsModel.Refetch;
|
||||
}
|
||||
) => void;
|
||||
}
|
||||
|
||||
const OverviewNetworkStatsManage = manageQuery(OverviewNetworkStats);
|
||||
|
||||
export const OverviewNetwork = pure<OwnProps>(({ endDate, startDate, setQuery }) => (
|
||||
<EuiFlexItem>
|
||||
<EuiPanel>
|
||||
<HeaderPanel
|
||||
border
|
||||
subtitle={
|
||||
<FormattedMessage
|
||||
id="xpack.siem.overview.networkSubtitle"
|
||||
defaultMessage="Showing: Last 24 Hours"
|
||||
/>
|
||||
}
|
||||
title={
|
||||
<FormattedMessage id="xpack.siem.overview.networkTitle" defaultMessage="Network Events" />
|
||||
}
|
||||
>
|
||||
<EuiButton href="#/link-to/network/">
|
||||
<FormattedMessage id="xpack.siem.overview.networkAction" defaultMessage="View Network" />
|
||||
</EuiButton>
|
||||
</HeaderPanel>
|
||||
export const OverviewNetwork = pure<OwnProps>(({ endDate, startDate, setQuery }) => {
|
||||
const [isHover, setIsHover] = useState(false);
|
||||
return (
|
||||
<EuiFlexItem>
|
||||
<EuiPanel onMouseEnter={() => setIsHover(true)} onMouseLeave={() => setIsHover(false)}>
|
||||
<HeaderPanel
|
||||
border
|
||||
id={OverviewNetworkQueryId}
|
||||
showInspect={isHover}
|
||||
subtitle={
|
||||
<FormattedMessage
|
||||
id="xpack.siem.overview.networkSubtitle"
|
||||
defaultMessage="Showing: Last 24 Hours"
|
||||
/>
|
||||
}
|
||||
title={
|
||||
<FormattedMessage
|
||||
id="xpack.siem.overview.networkTitle"
|
||||
defaultMessage="Network Events"
|
||||
/>
|
||||
}
|
||||
>
|
||||
<EuiButton href="#/link-to/network/">
|
||||
<FormattedMessage
|
||||
id="xpack.siem.overview.networkAction"
|
||||
defaultMessage="View Network"
|
||||
/>
|
||||
</EuiButton>
|
||||
</HeaderPanel>
|
||||
|
||||
<OverviewNetworkQuery endDate={endDate} sourceId="default" startDate={startDate}>
|
||||
{({ overviewNetwork, loading, id, refetch }) => (
|
||||
<OverviewNetworkStatsManage
|
||||
loading={loading}
|
||||
data={overviewNetwork}
|
||||
setQuery={setQuery}
|
||||
id={id}
|
||||
refetch={refetch}
|
||||
/>
|
||||
)}
|
||||
</OverviewNetworkQuery>
|
||||
</EuiPanel>
|
||||
</EuiFlexItem>
|
||||
));
|
||||
<OverviewNetworkQuery endDate={endDate} sourceId="default" startDate={startDate}>
|
||||
{({ overviewNetwork, loading, id, inspect, refetch }) => (
|
||||
<OverviewNetworkStatsManage
|
||||
loading={loading}
|
||||
data={overviewNetwork}
|
||||
id={id}
|
||||
inspect={inspect}
|
||||
setQuery={setQuery}
|
||||
refetch={refetch}
|
||||
/>
|
||||
)}
|
||||
</OverviewNetworkQuery>
|
||||
</EuiPanel>
|
||||
</EuiFlexItem>
|
||||
);
|
||||
});
|
||||
|
|
|
@ -24,32 +24,158 @@ exports[`Stat Items Component disable charts it renders the default widget 1`] =
|
|||
},
|
||||
]
|
||||
}
|
||||
from={1560578400000}
|
||||
id="statItems"
|
||||
index={0}
|
||||
key="mock-keys"
|
||||
to={1560837600000}
|
||||
>
|
||||
<Styled(EuiFlexItem)>
|
||||
<EuiFlexItem
|
||||
className="sc-bwzfXH hrDDAP"
|
||||
className="sc-bxivhb bQCHAr"
|
||||
>
|
||||
<div
|
||||
className="euiFlexItem sc-bwzfXH hrDDAP"
|
||||
className="euiFlexItem sc-bxivhb bQCHAr"
|
||||
>
|
||||
<EuiPanel
|
||||
grow={true}
|
||||
hasShadow={false}
|
||||
onMouseEnter={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
paddingSize="m"
|
||||
>
|
||||
<div
|
||||
className="euiPanel euiPanel--paddingMedium"
|
||||
onMouseEnter={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
>
|
||||
<EuiTitle
|
||||
size="xxxs"
|
||||
<EuiFlexGroup
|
||||
gutterSize="none"
|
||||
>
|
||||
<h6
|
||||
className="euiTitle euiTitle--xxxsmall"
|
||||
<div
|
||||
className="euiFlexGroup euiFlexGroup--directionRow euiFlexGroup--responsive"
|
||||
>
|
||||
HOSTS
|
||||
</h6>
|
||||
</EuiTitle>
|
||||
<EuiFlexItem>
|
||||
<div
|
||||
className="euiFlexItem"
|
||||
>
|
||||
<EuiTitle
|
||||
size="xxxs"
|
||||
>
|
||||
<h6
|
||||
className="euiTitle euiTitle--xxxsmall"
|
||||
>
|
||||
HOSTS
|
||||
</h6>
|
||||
</EuiTitle>
|
||||
</div>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<div
|
||||
className="euiFlexItem euiFlexItem--flexGrowZero"
|
||||
>
|
||||
<Connect(pure(Component))
|
||||
inspectIndex={0}
|
||||
queryId="statItems"
|
||||
show={false}
|
||||
title="KPI HOSTS"
|
||||
>
|
||||
<pure(Component)
|
||||
id=""
|
||||
inspect={null}
|
||||
inspectIndex={0}
|
||||
isInspected={false}
|
||||
loading={false}
|
||||
queryId="statItems"
|
||||
refetch={null}
|
||||
selectedInspectIndex={0}
|
||||
setIsInspected={[Function]}
|
||||
show={false}
|
||||
title="KPI HOSTS"
|
||||
>
|
||||
<Component
|
||||
id=""
|
||||
inspect={null}
|
||||
inspectIndex={0}
|
||||
isInspected={false}
|
||||
loading={false}
|
||||
queryId="statItems"
|
||||
refetch={null}
|
||||
selectedInspectIndex={0}
|
||||
setIsInspected={[Function]}
|
||||
show={false}
|
||||
title="KPI HOSTS"
|
||||
>
|
||||
<styled.div
|
||||
showInspect={false}
|
||||
>
|
||||
<div
|
||||
className="sc-htpNat inAMCx"
|
||||
>
|
||||
<EuiButtonIcon
|
||||
aria-label="Inspect"
|
||||
className=""
|
||||
color="primary"
|
||||
data-test-subj="inspect-icon-button"
|
||||
iconSize="m"
|
||||
iconType="inspect"
|
||||
onClick={[Function]}
|
||||
title="Inspect"
|
||||
type="button"
|
||||
>
|
||||
<button
|
||||
aria-label="Inspect"
|
||||
className="euiButtonIcon euiButtonIcon--primary"
|
||||
data-test-subj="inspect-icon-button"
|
||||
onClick={[Function]}
|
||||
title="Inspect"
|
||||
type="button"
|
||||
>
|
||||
<EuiIcon
|
||||
aria-hidden="true"
|
||||
className="euiButtonIcon__icon"
|
||||
size="m"
|
||||
type="inspect"
|
||||
>
|
||||
<EuiIconEmpty
|
||||
aria-hidden="true"
|
||||
className="euiIcon euiIcon--medium euiIcon-isLoading euiButtonIcon__icon"
|
||||
focusable="false"
|
||||
style={null}
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
className="euiIcon euiIcon--medium euiIcon-isLoading euiButtonIcon__icon"
|
||||
focusable="false"
|
||||
height={16}
|
||||
style={null}
|
||||
viewBox="0 0 16 16"
|
||||
width={16}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
/>
|
||||
</EuiIconEmpty>
|
||||
</EuiIcon>
|
||||
</button>
|
||||
</EuiButtonIcon>
|
||||
<ModalInspectQuery
|
||||
closeModal={[Function]}
|
||||
data-test-subj="inspect-modal"
|
||||
isShowing={false}
|
||||
request={null}
|
||||
response={null}
|
||||
title="KPI HOSTS"
|
||||
/>
|
||||
</div>
|
||||
</styled.div>
|
||||
</Component>
|
||||
</pure(Component)>
|
||||
</Connect(pure(Component))>
|
||||
</div>
|
||||
</EuiFlexItem>
|
||||
</div>
|
||||
</EuiFlexGroup>
|
||||
<EuiFlexGroup>
|
||||
<div
|
||||
className="euiFlexGroup euiFlexGroup--gutterLarge euiFlexGroup--directionRow euiFlexGroup--responsive"
|
||||
|
@ -58,10 +184,10 @@ exports[`Stat Items Component disable charts it renders the default widget 1`] =
|
|||
key="stat-items-field-hosts"
|
||||
>
|
||||
<EuiFlexItem
|
||||
className="sc-bwzfXH hrDDAP"
|
||||
className="sc-bxivhb bQCHAr"
|
||||
>
|
||||
<div
|
||||
className="euiFlexItem sc-bwzfXH hrDDAP"
|
||||
className="euiFlexItem sc-bxivhb bQCHAr"
|
||||
>
|
||||
<EuiFlexGroup
|
||||
alignItems="center"
|
||||
|
@ -73,17 +199,17 @@ exports[`Stat Items Component disable charts it renders the default widget 1`] =
|
|||
>
|
||||
<Styled(EuiFlexItem)>
|
||||
<EuiFlexItem
|
||||
className="sc-bwzfXH hrDDAP"
|
||||
className="sc-bxivhb bQCHAr"
|
||||
>
|
||||
<div
|
||||
className="euiFlexItem sc-bwzfXH hrDDAP"
|
||||
className="euiFlexItem sc-bxivhb bQCHAr"
|
||||
>
|
||||
<Styled(EuiTitle)>
|
||||
<EuiTitle
|
||||
className="sc-htpNat bTDdmQ"
|
||||
className="sc-ifAKCX bfXlPM"
|
||||
>
|
||||
<p
|
||||
className="euiTitle euiTitle--medium sc-htpNat bTDdmQ"
|
||||
className="euiTitle euiTitle--medium sc-ifAKCX bfXlPM"
|
||||
data-test-subj="stat-title"
|
||||
>
|
||||
--
|
||||
|
@ -141,32 +267,158 @@ exports[`Stat Items Component disable charts it renders the default widget 2`] =
|
|||
},
|
||||
]
|
||||
}
|
||||
from={1560578400000}
|
||||
id="statItems"
|
||||
index={0}
|
||||
key="mock-keys"
|
||||
to={1560837600000}
|
||||
>
|
||||
<Styled(EuiFlexItem)>
|
||||
<EuiFlexItem
|
||||
className="sc-bwzfXH hrDDAP"
|
||||
className="sc-bxivhb bQCHAr"
|
||||
>
|
||||
<div
|
||||
className="euiFlexItem sc-bwzfXH hrDDAP"
|
||||
className="euiFlexItem sc-bxivhb bQCHAr"
|
||||
>
|
||||
<EuiPanel
|
||||
grow={true}
|
||||
hasShadow={false}
|
||||
onMouseEnter={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
paddingSize="m"
|
||||
>
|
||||
<div
|
||||
className="euiPanel euiPanel--paddingMedium"
|
||||
onMouseEnter={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
>
|
||||
<EuiTitle
|
||||
size="xxxs"
|
||||
<EuiFlexGroup
|
||||
gutterSize="none"
|
||||
>
|
||||
<h6
|
||||
className="euiTitle euiTitle--xxxsmall"
|
||||
<div
|
||||
className="euiFlexGroup euiFlexGroup--directionRow euiFlexGroup--responsive"
|
||||
>
|
||||
HOSTS
|
||||
</h6>
|
||||
</EuiTitle>
|
||||
<EuiFlexItem>
|
||||
<div
|
||||
className="euiFlexItem"
|
||||
>
|
||||
<EuiTitle
|
||||
size="xxxs"
|
||||
>
|
||||
<h6
|
||||
className="euiTitle euiTitle--xxxsmall"
|
||||
>
|
||||
HOSTS
|
||||
</h6>
|
||||
</EuiTitle>
|
||||
</div>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<div
|
||||
className="euiFlexItem euiFlexItem--flexGrowZero"
|
||||
>
|
||||
<Connect(pure(Component))
|
||||
inspectIndex={0}
|
||||
queryId="statItems"
|
||||
show={false}
|
||||
title="KPI HOSTS"
|
||||
>
|
||||
<pure(Component)
|
||||
id=""
|
||||
inspect={null}
|
||||
inspectIndex={0}
|
||||
isInspected={false}
|
||||
loading={false}
|
||||
queryId="statItems"
|
||||
refetch={null}
|
||||
selectedInspectIndex={0}
|
||||
setIsInspected={[Function]}
|
||||
show={false}
|
||||
title="KPI HOSTS"
|
||||
>
|
||||
<Component
|
||||
id=""
|
||||
inspect={null}
|
||||
inspectIndex={0}
|
||||
isInspected={false}
|
||||
loading={false}
|
||||
queryId="statItems"
|
||||
refetch={null}
|
||||
selectedInspectIndex={0}
|
||||
setIsInspected={[Function]}
|
||||
show={false}
|
||||
title="KPI HOSTS"
|
||||
>
|
||||
<styled.div
|
||||
showInspect={false}
|
||||
>
|
||||
<div
|
||||
className="sc-htpNat inAMCx"
|
||||
>
|
||||
<EuiButtonIcon
|
||||
aria-label="Inspect"
|
||||
className=""
|
||||
color="primary"
|
||||
data-test-subj="inspect-icon-button"
|
||||
iconSize="m"
|
||||
iconType="inspect"
|
||||
onClick={[Function]}
|
||||
title="Inspect"
|
||||
type="button"
|
||||
>
|
||||
<button
|
||||
aria-label="Inspect"
|
||||
className="euiButtonIcon euiButtonIcon--primary"
|
||||
data-test-subj="inspect-icon-button"
|
||||
onClick={[Function]}
|
||||
title="Inspect"
|
||||
type="button"
|
||||
>
|
||||
<EuiIcon
|
||||
aria-hidden="true"
|
||||
className="euiButtonIcon__icon"
|
||||
size="m"
|
||||
type="inspect"
|
||||
>
|
||||
<EuiIconEmpty
|
||||
aria-hidden="true"
|
||||
className="euiIcon euiIcon--medium euiIcon-isLoading euiButtonIcon__icon"
|
||||
focusable="false"
|
||||
style={null}
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
className="euiIcon euiIcon--medium euiIcon-isLoading euiButtonIcon__icon"
|
||||
focusable="false"
|
||||
height={16}
|
||||
style={null}
|
||||
viewBox="0 0 16 16"
|
||||
width={16}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
/>
|
||||
</EuiIconEmpty>
|
||||
</EuiIcon>
|
||||
</button>
|
||||
</EuiButtonIcon>
|
||||
<ModalInspectQuery
|
||||
closeModal={[Function]}
|
||||
data-test-subj="inspect-modal"
|
||||
isShowing={false}
|
||||
request={null}
|
||||
response={null}
|
||||
title="KPI HOSTS"
|
||||
/>
|
||||
</div>
|
||||
</styled.div>
|
||||
</Component>
|
||||
</pure(Component)>
|
||||
</Connect(pure(Component))>
|
||||
</div>
|
||||
</EuiFlexItem>
|
||||
</div>
|
||||
</EuiFlexGroup>
|
||||
<EuiFlexGroup>
|
||||
<div
|
||||
className="euiFlexGroup euiFlexGroup--gutterLarge euiFlexGroup--directionRow euiFlexGroup--responsive"
|
||||
|
@ -175,10 +427,10 @@ exports[`Stat Items Component disable charts it renders the default widget 2`] =
|
|||
key="stat-items-field-hosts"
|
||||
>
|
||||
<EuiFlexItem
|
||||
className="sc-bwzfXH hrDDAP"
|
||||
className="sc-bxivhb bQCHAr"
|
||||
>
|
||||
<div
|
||||
className="euiFlexItem sc-bwzfXH hrDDAP"
|
||||
className="euiFlexItem sc-bxivhb bQCHAr"
|
||||
>
|
||||
<EuiFlexGroup
|
||||
alignItems="center"
|
||||
|
@ -191,17 +443,17 @@ exports[`Stat Items Component disable charts it renders the default widget 2`] =
|
|||
0
|
||||
<Styled(EuiFlexItem)>
|
||||
<EuiFlexItem
|
||||
className="sc-bwzfXH hrDDAP"
|
||||
className="sc-bxivhb bQCHAr"
|
||||
>
|
||||
<div
|
||||
className="euiFlexItem sc-bwzfXH hrDDAP"
|
||||
className="euiFlexItem sc-bxivhb bQCHAr"
|
||||
>
|
||||
<Styled(EuiTitle)>
|
||||
<EuiTitle
|
||||
className="sc-htpNat bTDdmQ"
|
||||
className="sc-ifAKCX bfXlPM"
|
||||
>
|
||||
<p
|
||||
className="euiTitle euiTitle--medium sc-htpNat bTDdmQ"
|
||||
className="euiTitle euiTitle--medium sc-ifAKCX bfXlPM"
|
||||
data-test-subj="stat-title"
|
||||
>
|
||||
--
|
||||
|
@ -331,32 +583,158 @@ exports[`Stat Items Component rendering kpis with charts it renders the default
|
|||
},
|
||||
]
|
||||
}
|
||||
from={1560578400000}
|
||||
id="statItems"
|
||||
index={0}
|
||||
key="mock-keys"
|
||||
to={1560837600000}
|
||||
>
|
||||
<Styled(EuiFlexItem)>
|
||||
<EuiFlexItem
|
||||
className="sc-bwzfXH hrDDAP"
|
||||
className="sc-bxivhb bQCHAr"
|
||||
>
|
||||
<div
|
||||
className="euiFlexItem sc-bwzfXH hrDDAP"
|
||||
className="euiFlexItem sc-bxivhb bQCHAr"
|
||||
>
|
||||
<EuiPanel
|
||||
grow={true}
|
||||
hasShadow={false}
|
||||
onMouseEnter={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
paddingSize="m"
|
||||
>
|
||||
<div
|
||||
className="euiPanel euiPanel--paddingMedium"
|
||||
onMouseEnter={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
>
|
||||
<EuiTitle
|
||||
size="xxxs"
|
||||
<EuiFlexGroup
|
||||
gutterSize="none"
|
||||
>
|
||||
<h6
|
||||
className="euiTitle euiTitle--xxxsmall"
|
||||
<div
|
||||
className="euiFlexGroup euiFlexGroup--directionRow euiFlexGroup--responsive"
|
||||
>
|
||||
UNIQUE_PRIVATE_IPS
|
||||
</h6>
|
||||
</EuiTitle>
|
||||
<EuiFlexItem>
|
||||
<div
|
||||
className="euiFlexItem"
|
||||
>
|
||||
<EuiTitle
|
||||
size="xxxs"
|
||||
>
|
||||
<h6
|
||||
className="euiTitle euiTitle--xxxsmall"
|
||||
>
|
||||
UNIQUE_PRIVATE_IPS
|
||||
</h6>
|
||||
</EuiTitle>
|
||||
</div>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<div
|
||||
className="euiFlexItem euiFlexItem--flexGrowZero"
|
||||
>
|
||||
<Connect(pure(Component))
|
||||
inspectIndex={0}
|
||||
queryId="statItems"
|
||||
show={false}
|
||||
title="KPI UNIQUE_PRIVATE_IPS"
|
||||
>
|
||||
<pure(Component)
|
||||
id=""
|
||||
inspect={null}
|
||||
inspectIndex={0}
|
||||
isInspected={false}
|
||||
loading={false}
|
||||
queryId="statItems"
|
||||
refetch={null}
|
||||
selectedInspectIndex={0}
|
||||
setIsInspected={[Function]}
|
||||
show={false}
|
||||
title="KPI UNIQUE_PRIVATE_IPS"
|
||||
>
|
||||
<Component
|
||||
id=""
|
||||
inspect={null}
|
||||
inspectIndex={0}
|
||||
isInspected={false}
|
||||
loading={false}
|
||||
queryId="statItems"
|
||||
refetch={null}
|
||||
selectedInspectIndex={0}
|
||||
setIsInspected={[Function]}
|
||||
show={false}
|
||||
title="KPI UNIQUE_PRIVATE_IPS"
|
||||
>
|
||||
<styled.div
|
||||
showInspect={false}
|
||||
>
|
||||
<div
|
||||
className="sc-htpNat inAMCx"
|
||||
>
|
||||
<EuiButtonIcon
|
||||
aria-label="Inspect"
|
||||
className=""
|
||||
color="primary"
|
||||
data-test-subj="inspect-icon-button"
|
||||
iconSize="m"
|
||||
iconType="inspect"
|
||||
onClick={[Function]}
|
||||
title="Inspect"
|
||||
type="button"
|
||||
>
|
||||
<button
|
||||
aria-label="Inspect"
|
||||
className="euiButtonIcon euiButtonIcon--primary"
|
||||
data-test-subj="inspect-icon-button"
|
||||
onClick={[Function]}
|
||||
title="Inspect"
|
||||
type="button"
|
||||
>
|
||||
<EuiIcon
|
||||
aria-hidden="true"
|
||||
className="euiButtonIcon__icon"
|
||||
size="m"
|
||||
type="inspect"
|
||||
>
|
||||
<EuiIconEmpty
|
||||
aria-hidden="true"
|
||||
className="euiIcon euiIcon--medium euiIcon-isLoading euiButtonIcon__icon"
|
||||
focusable="false"
|
||||
style={null}
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
className="euiIcon euiIcon--medium euiIcon-isLoading euiButtonIcon__icon"
|
||||
focusable="false"
|
||||
height={16}
|
||||
style={null}
|
||||
viewBox="0 0 16 16"
|
||||
width={16}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
/>
|
||||
</EuiIconEmpty>
|
||||
</EuiIcon>
|
||||
</button>
|
||||
</EuiButtonIcon>
|
||||
<ModalInspectQuery
|
||||
closeModal={[Function]}
|
||||
data-test-subj="inspect-modal"
|
||||
isShowing={false}
|
||||
request={null}
|
||||
response={null}
|
||||
title="KPI UNIQUE_PRIVATE_IPS"
|
||||
/>
|
||||
</div>
|
||||
</styled.div>
|
||||
</Component>
|
||||
</pure(Component)>
|
||||
</Connect(pure(Component))>
|
||||
</div>
|
||||
</EuiFlexItem>
|
||||
</div>
|
||||
</EuiFlexGroup>
|
||||
<EuiFlexGroup>
|
||||
<div
|
||||
className="euiFlexGroup euiFlexGroup--gutterLarge euiFlexGroup--directionRow euiFlexGroup--responsive"
|
||||
|
@ -365,10 +743,10 @@ exports[`Stat Items Component rendering kpis with charts it renders the default
|
|||
key="stat-items-field-uniqueSourceIps"
|
||||
>
|
||||
<EuiFlexItem
|
||||
className="sc-bwzfXH hrDDAP"
|
||||
className="sc-bxivhb bQCHAr"
|
||||
>
|
||||
<div
|
||||
className="euiFlexItem sc-bwzfXH hrDDAP"
|
||||
className="euiFlexItem sc-bxivhb bQCHAr"
|
||||
>
|
||||
<EuiFlexGroup
|
||||
alignItems="center"
|
||||
|
@ -382,11 +760,11 @@ exports[`Stat Items Component rendering kpis with charts it renders the default
|
|||
grow={false}
|
||||
>
|
||||
<EuiFlexItem
|
||||
className="sc-bwzfXH hrDDAP"
|
||||
className="sc-bxivhb bQCHAr"
|
||||
grow={false}
|
||||
>
|
||||
<div
|
||||
className="euiFlexItem euiFlexItem--flexGrowZero sc-bwzfXH hrDDAP"
|
||||
className="euiFlexItem euiFlexItem--flexGrowZero sc-bxivhb bQCHAr"
|
||||
>
|
||||
<EuiIcon
|
||||
color="#DB1374"
|
||||
|
@ -425,17 +803,17 @@ exports[`Stat Items Component rendering kpis with charts it renders the default
|
|||
</Styled(EuiFlexItem)>
|
||||
<Styled(EuiFlexItem)>
|
||||
<EuiFlexItem
|
||||
className="sc-bwzfXH hrDDAP"
|
||||
className="sc-bxivhb bQCHAr"
|
||||
>
|
||||
<div
|
||||
className="euiFlexItem sc-bwzfXH hrDDAP"
|
||||
className="euiFlexItem sc-bxivhb bQCHAr"
|
||||
>
|
||||
<Styled(EuiTitle)>
|
||||
<EuiTitle
|
||||
className="sc-htpNat bTDdmQ"
|
||||
className="sc-ifAKCX bfXlPM"
|
||||
>
|
||||
<p
|
||||
className="euiTitle euiTitle--medium sc-htpNat bTDdmQ"
|
||||
className="euiTitle euiTitle--medium sc-ifAKCX bfXlPM"
|
||||
data-test-subj="stat-title"
|
||||
>
|
||||
1,714
|
||||
|
@ -456,10 +834,10 @@ exports[`Stat Items Component rendering kpis with charts it renders the default
|
|||
key="stat-items-field-uniqueDestinationIps"
|
||||
>
|
||||
<EuiFlexItem
|
||||
className="sc-bwzfXH hrDDAP"
|
||||
className="sc-bxivhb bQCHAr"
|
||||
>
|
||||
<div
|
||||
className="euiFlexItem sc-bwzfXH hrDDAP"
|
||||
className="euiFlexItem sc-bxivhb bQCHAr"
|
||||
>
|
||||
<EuiFlexGroup
|
||||
alignItems="center"
|
||||
|
@ -473,11 +851,11 @@ exports[`Stat Items Component rendering kpis with charts it renders the default
|
|||
grow={false}
|
||||
>
|
||||
<EuiFlexItem
|
||||
className="sc-bwzfXH hrDDAP"
|
||||
className="sc-bxivhb bQCHAr"
|
||||
grow={false}
|
||||
>
|
||||
<div
|
||||
className="euiFlexItem euiFlexItem--flexGrowZero sc-bwzfXH hrDDAP"
|
||||
className="euiFlexItem euiFlexItem--flexGrowZero sc-bxivhb bQCHAr"
|
||||
>
|
||||
<EuiIcon
|
||||
color="#490092"
|
||||
|
@ -516,17 +894,17 @@ exports[`Stat Items Component rendering kpis with charts it renders the default
|
|||
</Styled(EuiFlexItem)>
|
||||
<Styled(EuiFlexItem)>
|
||||
<EuiFlexItem
|
||||
className="sc-bwzfXH hrDDAP"
|
||||
className="sc-bxivhb bQCHAr"
|
||||
>
|
||||
<div
|
||||
className="euiFlexItem sc-bwzfXH hrDDAP"
|
||||
className="euiFlexItem sc-bxivhb bQCHAr"
|
||||
>
|
||||
<Styled(EuiTitle)>
|
||||
<EuiTitle
|
||||
className="sc-htpNat bTDdmQ"
|
||||
className="sc-ifAKCX bfXlPM"
|
||||
>
|
||||
<p
|
||||
className="euiTitle euiTitle--medium sc-htpNat bTDdmQ"
|
||||
className="euiTitle euiTitle--medium sc-ifAKCX bfXlPM"
|
||||
data-test-subj="stat-title"
|
||||
>
|
||||
2,359
|
||||
|
@ -556,10 +934,10 @@ exports[`Stat Items Component rendering kpis with charts it renders the default
|
|||
>
|
||||
<Styled(EuiFlexItem)>
|
||||
<EuiFlexItem
|
||||
className="sc-bwzfXH hrDDAP"
|
||||
className="sc-bxivhb bQCHAr"
|
||||
>
|
||||
<div
|
||||
className="euiFlexItem sc-bwzfXH hrDDAP"
|
||||
className="euiFlexItem sc-bxivhb bQCHAr"
|
||||
>
|
||||
<Memo(mockConstructor)
|
||||
barChart={
|
||||
|
@ -603,74 +981,65 @@ exports[`Stat Items Component rendering kpis with charts it renders the default
|
|||
</Styled(EuiFlexItem)>
|
||||
<Styled(EuiFlexItem)>
|
||||
<EuiFlexItem
|
||||
className="sc-bwzfXH hrDDAP"
|
||||
className="sc-bxivhb bQCHAr"
|
||||
>
|
||||
<div
|
||||
className="euiFlexItem sc-bwzfXH hrDDAP"
|
||||
className="euiFlexItem sc-bxivhb bQCHAr"
|
||||
>
|
||||
<Connect(GlobalTimeComponent)>
|
||||
<GlobalTimeComponent
|
||||
deleteAllQuery={[Function]}
|
||||
from={0}
|
||||
setGlobalQuery={[Function]}
|
||||
to={1}
|
||||
>
|
||||
<Memo(mockConstructor)
|
||||
areaChart={
|
||||
Array [
|
||||
<Memo(mockConstructor)
|
||||
areaChart={
|
||||
Array [
|
||||
Object {
|
||||
"color": "#DB1374",
|
||||
"key": "uniqueSourceIpsHistogram",
|
||||
"value": Array [
|
||||
Object {
|
||||
"color": "#DB1374",
|
||||
"key": "uniqueSourceIpsHistogram",
|
||||
"value": Array [
|
||||
Object {
|
||||
"x": 1556888400000,
|
||||
"y": 565975,
|
||||
},
|
||||
Object {
|
||||
"x": 1556931600000,
|
||||
"y": 1084366,
|
||||
},
|
||||
Object {
|
||||
"x": 1556974800000,
|
||||
"y": 12280,
|
||||
},
|
||||
],
|
||||
"x": 1556888400000,
|
||||
"y": 565975,
|
||||
},
|
||||
Object {
|
||||
"color": "#490092",
|
||||
"key": "uniqueDestinationIpsHistogram",
|
||||
"value": Array [
|
||||
Object {
|
||||
"x": 1556888400000,
|
||||
"y": 565975,
|
||||
},
|
||||
Object {
|
||||
"x": 1556931600000,
|
||||
"y": 1084366,
|
||||
},
|
||||
Object {
|
||||
"x": 1556974800000,
|
||||
"y": 12280,
|
||||
},
|
||||
],
|
||||
"x": 1556931600000,
|
||||
"y": 1084366,
|
||||
},
|
||||
]
|
||||
}
|
||||
configs={
|
||||
Object {
|
||||
"axis": Object {
|
||||
"xTickFormatter": [Function],
|
||||
"yTickFormatter": [Function],
|
||||
Object {
|
||||
"x": 1556974800000,
|
||||
"y": 12280,
|
||||
},
|
||||
"series": Object {
|
||||
"xScaleType": "time",
|
||||
"yScaleType": "linear",
|
||||
],
|
||||
},
|
||||
Object {
|
||||
"color": "#490092",
|
||||
"key": "uniqueDestinationIpsHistogram",
|
||||
"value": Array [
|
||||
Object {
|
||||
"x": 1556888400000,
|
||||
"y": 565975,
|
||||
},
|
||||
}
|
||||
}
|
||||
/>
|
||||
</GlobalTimeComponent>
|
||||
</Connect(GlobalTimeComponent)>
|
||||
Object {
|
||||
"x": 1556931600000,
|
||||
"y": 1084366,
|
||||
},
|
||||
Object {
|
||||
"x": 1556974800000,
|
||||
"y": 12280,
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
}
|
||||
configs={
|
||||
Object {
|
||||
"axis": Object {
|
||||
"xTickFormatter": [Function],
|
||||
"yTickFormatter": [Function],
|
||||
},
|
||||
"series": Object {
|
||||
"xScaleType": "time",
|
||||
"yScaleType": "linear",
|
||||
},
|
||||
}
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</EuiFlexItem>
|
||||
</Styled(EuiFlexItem)>
|
||||
|
|
|
@ -33,9 +33,11 @@ import { KpiNetworkData, KpiHostsData } from '../../graphql/types';
|
|||
jest.mock('../charts/barchart');
|
||||
jest.mock('../charts/areachart');
|
||||
|
||||
const from = new Date('2019-06-15T06:00:00.000Z').valueOf();
|
||||
const to = new Date('2019-06-18T06:00:00.000Z').valueOf();
|
||||
|
||||
describe('Stat Items Component', () => {
|
||||
const state: State = mockGlobalState;
|
||||
|
||||
const store = createStore(state, apolloClientObservable);
|
||||
|
||||
describe.each([
|
||||
|
@ -43,9 +45,13 @@ describe('Stat Items Component', () => {
|
|||
mount(
|
||||
<ReduxStoreProvider store={store}>
|
||||
<StatItemsComponent
|
||||
fields={[{ key: 'hosts', value: null, color: '#3185FC', icon: 'cross' }]}
|
||||
description="HOSTS"
|
||||
fields={[{ key: 'hosts', value: null, color: '#3185FC', icon: 'cross' }]}
|
||||
from={from}
|
||||
id="statItems"
|
||||
index={0}
|
||||
key="mock-keys"
|
||||
to={to}
|
||||
/>
|
||||
</ReduxStoreProvider>
|
||||
),
|
||||
|
@ -54,11 +60,15 @@ describe('Stat Items Component', () => {
|
|||
mount(
|
||||
<ReduxStoreProvider store={store}>
|
||||
<StatItemsComponent
|
||||
fields={[{ key: 'hosts', value: null, color: '#3185FC', icon: 'cross' }]}
|
||||
description="HOSTS"
|
||||
areaChart={[]}
|
||||
barChart={[]}
|
||||
description="HOSTS"
|
||||
fields={[{ key: 'hosts', value: null, color: '#3185FC', icon: 'cross' }]}
|
||||
from={from}
|
||||
id="statItems"
|
||||
index={0}
|
||||
key="mock-keys"
|
||||
to={to}
|
||||
/>
|
||||
</ReduxStoreProvider>
|
||||
),
|
||||
|
@ -91,24 +101,6 @@ describe('Stat Items Component', () => {
|
|||
|
||||
describe('rendering kpis with charts', () => {
|
||||
const mockStatItemsData: StatItemsProps = {
|
||||
fields: [
|
||||
{
|
||||
key: 'uniqueSourceIps',
|
||||
description: 'Source',
|
||||
value: 1714,
|
||||
color: '#DB1374',
|
||||
icon: 'cross',
|
||||
},
|
||||
{
|
||||
key: 'uniqueDestinationIps',
|
||||
description: 'Dest.',
|
||||
value: 2359,
|
||||
color: '#490092',
|
||||
icon: 'cross',
|
||||
},
|
||||
],
|
||||
enableAreaChart: true,
|
||||
enableBarChart: true,
|
||||
areaChart: [
|
||||
{
|
||||
key: 'uniqueSourceIpsHistogram',
|
||||
|
@ -138,7 +130,29 @@ describe('Stat Items Component', () => {
|
|||
},
|
||||
],
|
||||
description: 'UNIQUE_PRIVATE_IPS',
|
||||
enableAreaChart: true,
|
||||
enableBarChart: true,
|
||||
fields: [
|
||||
{
|
||||
key: 'uniqueSourceIps',
|
||||
description: 'Source',
|
||||
value: 1714,
|
||||
color: '#DB1374',
|
||||
icon: 'cross',
|
||||
},
|
||||
{
|
||||
key: 'uniqueDestinationIps',
|
||||
description: 'Dest.',
|
||||
value: 2359,
|
||||
color: '#490092',
|
||||
icon: 'cross',
|
||||
},
|
||||
],
|
||||
from,
|
||||
id: 'statItems',
|
||||
index: 0,
|
||||
key: 'mock-keys',
|
||||
to,
|
||||
};
|
||||
let wrapper: ReactWrapper;
|
||||
beforeAll(() => {
|
||||
|
@ -212,7 +226,13 @@ describe('useKpiMatrixStatus', () => {
|
|||
fieldsMapping: Readonly<StatItems[]>;
|
||||
data: KpiNetworkData | KpiHostsData;
|
||||
}) => {
|
||||
const statItemsProps: StatItemsProps[] = useKpiMatrixStatus(fieldsMapping, data);
|
||||
const statItemsProps: StatItemsProps[] = useKpiMatrixStatus(
|
||||
fieldsMapping,
|
||||
data,
|
||||
'statItem',
|
||||
from,
|
||||
to
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { ScaleType, niceTimeFormatter } from '@elastic/charts';
|
||||
import {
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
|
@ -13,17 +14,17 @@ import {
|
|||
EuiTitle,
|
||||
IconType,
|
||||
} from '@elastic/eui';
|
||||
import { get, getOr } from 'lodash/fp';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { get, getOr } from 'lodash/fp';
|
||||
import { ScaleType, niceTimeFormatter } from '@elastic/charts';
|
||||
import { BarChart } from '../charts/barchart';
|
||||
import { AreaChart } from '../charts/areachart';
|
||||
import { getEmptyTagValue } from '../empty_value';
|
||||
import { ChartConfigsData, ChartData, ChartSeriesConfigs } from '../charts/common';
|
||||
import { KpiHostsData, KpiNetworkData } from '../../graphql/types';
|
||||
import { GlobalTime } from '../../containers/global_time';
|
||||
import { AreaChart } from '../charts/areachart';
|
||||
import { BarChart } from '../charts/barchart';
|
||||
import { ChartConfigsData, ChartData, ChartSeriesConfigs } from '../charts/common';
|
||||
import { getEmptyTagValue } from '../empty_value';
|
||||
|
||||
import { InspectButton } from '../inspect';
|
||||
|
||||
const FlexItem = styled(EuiFlexItem)`
|
||||
min-width: 0;
|
||||
|
@ -51,6 +52,7 @@ export interface StatItems {
|
|||
enableAreaChart?: boolean;
|
||||
enableBarChart?: boolean;
|
||||
grow?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | true | false | null;
|
||||
index: number;
|
||||
areachartConfigs?: ChartSeriesConfigs;
|
||||
barchartConfigs?: ChartSeriesConfigs;
|
||||
}
|
||||
|
@ -58,6 +60,10 @@ export interface StatItems {
|
|||
export interface StatItemsProps extends StatItems {
|
||||
areaChart?: ChartConfigsData[];
|
||||
barChart?: ChartConfigsData[];
|
||||
from: number;
|
||||
id: string;
|
||||
|
||||
to: number;
|
||||
}
|
||||
|
||||
export const numberFormatter = (value: string | number): string => value.toLocaleString();
|
||||
|
@ -128,7 +134,10 @@ export const addValueToBarChart = (
|
|||
|
||||
export const useKpiMatrixStatus = (
|
||||
mappings: Readonly<StatItems[]>,
|
||||
data: KpiHostsData | KpiNetworkData
|
||||
data: KpiHostsData | KpiNetworkData,
|
||||
id: string,
|
||||
from: number,
|
||||
to: number
|
||||
): StatItemsProps[] => {
|
||||
const [statItemsProps, setStatItemsProps] = useState(mappings as StatItemsProps[]);
|
||||
|
||||
|
@ -138,10 +147,13 @@ export const useKpiMatrixStatus = (
|
|||
mappings.map(stat => {
|
||||
return {
|
||||
...stat,
|
||||
key: `kpi-summary-${stat.key}`,
|
||||
fields: addValueToFields(stat.fields, data),
|
||||
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}`,
|
||||
from,
|
||||
to,
|
||||
};
|
||||
})
|
||||
);
|
||||
|
@ -153,7 +165,20 @@ export const useKpiMatrixStatus = (
|
|||
};
|
||||
|
||||
export const StatItemsComponent = React.memo<StatItemsProps>(
|
||||
({ fields, description, grow, barChart, areaChart, enableAreaChart, enableBarChart }) => {
|
||||
({
|
||||
areaChart,
|
||||
barChart,
|
||||
description,
|
||||
enableAreaChart,
|
||||
enableBarChart,
|
||||
fields,
|
||||
from,
|
||||
grow,
|
||||
id,
|
||||
index,
|
||||
to,
|
||||
}) => {
|
||||
const [isHover, setIsHover] = useState(false);
|
||||
const isBarChartDataAvailable =
|
||||
barChart &&
|
||||
barChart.length &&
|
||||
|
@ -164,10 +189,22 @@ export const StatItemsComponent = React.memo<StatItemsProps>(
|
|||
areaChart.every(item => item.value != null && item.value.length > 0);
|
||||
return (
|
||||
<FlexItem grow={grow}>
|
||||
<EuiPanel>
|
||||
<EuiTitle size="xxxs">
|
||||
<h6>{description}</h6>
|
||||
</EuiTitle>
|
||||
<EuiPanel onMouseEnter={() => setIsHover(true)} onMouseLeave={() => setIsHover(false)}>
|
||||
<EuiFlexGroup gutterSize={'none'}>
|
||||
<EuiFlexItem>
|
||||
<EuiTitle size="xxxs">
|
||||
<h6>{description}</h6>
|
||||
</EuiTitle>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<InspectButton
|
||||
queryId={id}
|
||||
title={`KPI ${description}`}
|
||||
inspectIndex={index}
|
||||
show={isHover}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
|
||||
<EuiFlexGroup>
|
||||
{fields.map(field => (
|
||||
|
@ -198,7 +235,6 @@ export const StatItemsComponent = React.memo<StatItemsProps>(
|
|||
</EuiFlexGroup>
|
||||
|
||||
{(enableAreaChart || enableBarChart) && <EuiHorizontalRule />}
|
||||
|
||||
<EuiFlexGroup>
|
||||
{enableBarChart && (
|
||||
<FlexItem>
|
||||
|
@ -206,13 +242,9 @@ export const StatItemsComponent = React.memo<StatItemsProps>(
|
|||
</FlexItem>
|
||||
)}
|
||||
|
||||
{enableAreaChart && (
|
||||
{enableAreaChart && from != null && to != null && (
|
||||
<FlexItem>
|
||||
<GlobalTime>
|
||||
{({ from, to }) => (
|
||||
<AreaChart areaChart={areaChart} configs={areachartConfigs(from, to)} />
|
||||
)}
|
||||
</GlobalTime>
|
||||
<AreaChart areaChart={areaChart} configs={areachartConfigs(from, to)} />
|
||||
</FlexItem>
|
||||
)}
|
||||
</EuiFlexGroup>
|
||||
|
|
|
@ -30,6 +30,7 @@ describe('Properties', () => {
|
|||
<Properties
|
||||
associateNote={jest.fn()}
|
||||
createTimeline={jest.fn()}
|
||||
isDataInTimeline={false}
|
||||
isDatepickerLocked={false}
|
||||
isFavorite={false}
|
||||
title=""
|
||||
|
@ -56,6 +57,7 @@ describe('Properties', () => {
|
|||
<Properties
|
||||
associateNote={jest.fn()}
|
||||
createTimeline={jest.fn()}
|
||||
isDataInTimeline={false}
|
||||
isDatepickerLocked={false}
|
||||
isFavorite={false}
|
||||
title=""
|
||||
|
@ -83,6 +85,7 @@ describe('Properties', () => {
|
|||
<Properties
|
||||
associateNote={jest.fn()}
|
||||
createTimeline={jest.fn()}
|
||||
isDataInTimeline={false}
|
||||
isDatepickerLocked={false}
|
||||
isFavorite={true}
|
||||
title=""
|
||||
|
@ -112,6 +115,7 @@ describe('Properties', () => {
|
|||
<Properties
|
||||
associateNote={jest.fn()}
|
||||
createTimeline={jest.fn()}
|
||||
isDataInTimeline={false}
|
||||
isDatepickerLocked={false}
|
||||
isFavorite={false}
|
||||
title={title}
|
||||
|
@ -144,6 +148,7 @@ describe('Properties', () => {
|
|||
<Properties
|
||||
associateNote={jest.fn()}
|
||||
createTimeline={jest.fn()}
|
||||
isDataInTimeline={false}
|
||||
isDatepickerLocked={false}
|
||||
isFavorite={false}
|
||||
title=""
|
||||
|
@ -176,6 +181,7 @@ describe('Properties', () => {
|
|||
<Properties
|
||||
associateNote={jest.fn()}
|
||||
createTimeline={jest.fn()}
|
||||
isDataInTimeline={false}
|
||||
isDatepickerLocked={true}
|
||||
isFavorite={false}
|
||||
title=""
|
||||
|
@ -207,6 +213,7 @@ describe('Properties', () => {
|
|||
<Properties
|
||||
associateNote={jest.fn()}
|
||||
createTimeline={jest.fn()}
|
||||
isDataInTimeline={false}
|
||||
isDatepickerLocked={false}
|
||||
isFavorite={false}
|
||||
title=""
|
||||
|
@ -241,6 +248,7 @@ describe('Properties', () => {
|
|||
<Properties
|
||||
associateNote={jest.fn()}
|
||||
createTimeline={jest.fn()}
|
||||
isDataInTimeline={false}
|
||||
isDatepickerLocked={false}
|
||||
isFavorite={false}
|
||||
title=""
|
||||
|
@ -277,6 +285,7 @@ describe('Properties', () => {
|
|||
<Properties
|
||||
associateNote={jest.fn()}
|
||||
createTimeline={jest.fn()}
|
||||
isDataInTimeline={false}
|
||||
isDatepickerLocked={false}
|
||||
isFavorite={false}
|
||||
title=""
|
||||
|
@ -311,6 +320,7 @@ describe('Properties', () => {
|
|||
<Properties
|
||||
associateNote={jest.fn()}
|
||||
createTimeline={jest.fn()}
|
||||
isDataInTimeline={false}
|
||||
isDatepickerLocked={false}
|
||||
isFavorite={false}
|
||||
title=""
|
||||
|
@ -345,6 +355,7 @@ describe('Properties', () => {
|
|||
<Properties
|
||||
associateNote={jest.fn()}
|
||||
createTimeline={jest.fn()}
|
||||
isDataInTimeline={false}
|
||||
isDatepickerLocked={false}
|
||||
isFavorite={false}
|
||||
title=""
|
||||
|
@ -377,6 +388,7 @@ describe('Properties', () => {
|
|||
<Properties
|
||||
associateNote={jest.fn()}
|
||||
createTimeline={jest.fn()}
|
||||
isDataInTimeline={false}
|
||||
isDatepickerLocked={false}
|
||||
isFavorite={false}
|
||||
title=""
|
||||
|
@ -406,6 +418,7 @@ describe('Properties', () => {
|
|||
<Properties
|
||||
associateNote={jest.fn()}
|
||||
createTimeline={jest.fn()}
|
||||
isDataInTimeline={false}
|
||||
isDatepickerLocked={false}
|
||||
isFavorite={false}
|
||||
title={title}
|
||||
|
@ -433,6 +446,7 @@ describe('Properties', () => {
|
|||
<Properties
|
||||
associateNote={jest.fn()}
|
||||
createTimeline={jest.fn()}
|
||||
isDataInTimeline={false}
|
||||
isDatepickerLocked={false}
|
||||
isFavorite={false}
|
||||
title=""
|
||||
|
|
|
@ -17,7 +17,10 @@ import * as React from 'react';
|
|||
import styled, { injectGlobal } from 'styled-components';
|
||||
|
||||
import { Note } from '../../../lib/note';
|
||||
import { InputsModelId } from '../../../store/inputs/constants';
|
||||
import { InspectButton } from '../../inspect';
|
||||
import { AssociateNote, UpdateNote } from '../../notes/helpers';
|
||||
import { OpenTimelineModalButton } from '../../open_timeline/open_timeline_modal';
|
||||
import { SuperDatePicker } from '../../super_date_picker';
|
||||
|
||||
import { Description, Name, NewTimeline, NotesButton, StarIcon } from './helpers';
|
||||
|
@ -29,8 +32,6 @@ import {
|
|||
LockIconContainer,
|
||||
} from './styles';
|
||||
import * as i18n from './translations';
|
||||
import { OpenTimelineModalButton } from '../../open_timeline/open_timeline_modal';
|
||||
import { InputsModelId } from '../../../store/inputs/constants';
|
||||
|
||||
type CreateTimeline = ({ id, show }: { id: string; show?: boolean }) => void;
|
||||
type UpdateIsFavorite = ({ id, isFavorite }: { id: string; isFavorite: boolean }) => void;
|
||||
|
@ -70,6 +71,7 @@ const HiddenFlexItem = styled(EuiFlexItem)`
|
|||
interface Props {
|
||||
associateNote: AssociateNote;
|
||||
createTimeline: CreateTimeline;
|
||||
isDataInTimeline: boolean;
|
||||
isDatepickerLocked: boolean;
|
||||
isFavorite: boolean;
|
||||
title: string;
|
||||
|
@ -136,6 +138,7 @@ export class Properties extends React.PureComponent<Props, State> {
|
|||
description,
|
||||
getNotesByIds,
|
||||
isFavorite,
|
||||
isDataInTimeline,
|
||||
isDatepickerLocked,
|
||||
title,
|
||||
noteIds,
|
||||
|
@ -269,6 +272,18 @@ export class Properties extends React.PureComponent<Props, State> {
|
|||
<OpenTimelineModalButton />
|
||||
</EuiFlexItem>
|
||||
|
||||
<EuiFlexItem grow={false}>
|
||||
<InspectButton
|
||||
queryId={timelineId}
|
||||
inputId="timeline"
|
||||
inspectIndex={0}
|
||||
isDisabled={!isDataInTimeline}
|
||||
onCloseInspect={this.onClosePopover}
|
||||
show={true}
|
||||
title={i18n.INSPECT_TIMELINE_TITLE}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
|
||||
{width < showNotesThreshold ? (
|
||||
<EuiFlexItem grow={false}>
|
||||
<NotesButton
|
||||
|
|
|
@ -32,6 +32,13 @@ export const TIMELINE_TITLE = i18n.translate(
|
|||
}
|
||||
);
|
||||
|
||||
export const INSPECT_TIMELINE_TITLE = i18n.translate(
|
||||
'xpack.siem.timeline.properties.inspectTimelineTitle',
|
||||
{
|
||||
defaultMessage: 'Timeline',
|
||||
}
|
||||
);
|
||||
|
||||
export const UNTITLED_TIMELINE = i18n.translate(
|
||||
'xpack.siem.timeline.properties.untitledTimelinePlaceholder',
|
||||
{
|
||||
|
|
|
@ -14,8 +14,9 @@ import { InputsModelId } from '../../store/inputs/constants';
|
|||
|
||||
interface TimelineRefetchDispatch {
|
||||
setTimelineQuery: ActionCreator<{
|
||||
inputId: InputsModelId;
|
||||
id: string;
|
||||
inputId: InputsModelId;
|
||||
inspect: inputsModel.InspectQuery | null;
|
||||
loading: boolean;
|
||||
refetch: inputsModel.Refetch;
|
||||
}>;
|
||||
|
@ -24,6 +25,7 @@ interface TimelineRefetchDispatch {
|
|||
interface TimelineRefetchProps {
|
||||
children: React.ReactNode;
|
||||
id: string;
|
||||
inspect: inputsModel.InspectQuery | null;
|
||||
loading: boolean;
|
||||
refetch: inputsModel.Refetch;
|
||||
}
|
||||
|
@ -32,9 +34,9 @@ type OwnProps = TimelineRefetchDispatch & TimelineRefetchProps;
|
|||
|
||||
class TimelineRefetchComponent extends React.PureComponent<OwnProps> {
|
||||
public componentDidUpdate(prevProps: OwnProps) {
|
||||
const { loading, id, refetch } = this.props;
|
||||
const { loading, id, inspect, refetch } = this.props;
|
||||
if (prevProps.loading !== loading) {
|
||||
this.props.setTimelineQuery({ inputId: 'timeline', id, loading, refetch });
|
||||
this.props.setTimelineQuery({ id, inputId: 'timeline', inspect, loading, refetch });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -140,6 +140,7 @@ export const Timeline = pure<Props>(
|
|||
|
||||
{combinedQueries != null ? (
|
||||
<TimelineQuery
|
||||
id={id}
|
||||
fields={columnsHeader.map(c => c.id)}
|
||||
sourceId="default"
|
||||
limit={itemsPerPage}
|
||||
|
@ -149,8 +150,17 @@ export const Timeline = pure<Props>(
|
|||
direction: sort.sortDirection as Direction,
|
||||
}}
|
||||
>
|
||||
{({ events, loading, totalCount, pageInfo, loadMore, getUpdatedAt, refetch }) => (
|
||||
<TimelineRefetch loading={loading} id={id} refetch={refetch}>
|
||||
{({
|
||||
events,
|
||||
inspect,
|
||||
loading,
|
||||
totalCount,
|
||||
pageInfo,
|
||||
loadMore,
|
||||
getUpdatedAt,
|
||||
refetch,
|
||||
}) => (
|
||||
<TimelineRefetch loading={loading} id={id} inspect={inspect} refetch={refetch}>
|
||||
<TimelineContext.Provider value={{ isLoading: loading }} />
|
||||
<StatefulBody
|
||||
browserFields={browserFields}
|
||||
|
|
|
@ -13,6 +13,7 @@ export const authenticationsQuery = gql`
|
|||
$pagination: PaginationInput!
|
||||
$filterQuery: String
|
||||
$defaultIndex: [String!]!
|
||||
$inspect: Boolean!
|
||||
) {
|
||||
source(id: $sourceId) {
|
||||
id
|
||||
|
@ -62,6 +63,10 @@ export const authenticationsQuery = gql`
|
|||
}
|
||||
hasNextPage
|
||||
}
|
||||
inspect @include(if: $inspect) {
|
||||
dsl
|
||||
response
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,14 +12,17 @@ import { connect } from 'react-redux';
|
|||
import chrome from 'ui/chrome';
|
||||
import { DEFAULT_INDEX_KEY } from '../../../common/constants';
|
||||
import { AuthenticationsEdges, GetAuthenticationsQuery, PageInfo } from '../../graphql/types';
|
||||
import { hostsModel, hostsSelectors, inputsModel, State } from '../../store';
|
||||
import { hostsModel, hostsSelectors, inputsModel, State, inputsSelectors } from '../../store';
|
||||
import { createFilter, getDefaultFetchPolicy } from '../helpers';
|
||||
import { QueryTemplate, QueryTemplateProps } from '../query_template';
|
||||
|
||||
import { authenticationsQuery } from './index.gql_query';
|
||||
|
||||
const ID = 'authenticationQuery';
|
||||
|
||||
export interface AuthenticationArgs {
|
||||
id: string;
|
||||
inspect: inputsModel.InspectQuery;
|
||||
authentications: AuthenticationsEdges[];
|
||||
totalCount: number;
|
||||
pageInfo: PageInfo;
|
||||
|
@ -34,6 +37,7 @@ export interface OwnProps extends QueryTemplateProps {
|
|||
}
|
||||
|
||||
export interface AuthenticationsComponentReduxProps {
|
||||
isInspected: boolean;
|
||||
limit: number;
|
||||
}
|
||||
|
||||
|
@ -46,7 +50,8 @@ class AuthenticationsComponentQuery extends QueryTemplate<
|
|||
> {
|
||||
public render() {
|
||||
const {
|
||||
id = 'authenticationQuery',
|
||||
id = ID,
|
||||
isInspected,
|
||||
children,
|
||||
filterQuery,
|
||||
skip,
|
||||
|
@ -75,6 +80,7 @@ class AuthenticationsComponentQuery extends QueryTemplate<
|
|||
},
|
||||
filterQuery: createFilter(filterQuery),
|
||||
defaultIndex: chrome.getUiSettingsClient().get(DEFAULT_INDEX_KEY),
|
||||
inspect: isInspected,
|
||||
}}
|
||||
>
|
||||
{({ data, loading, fetchMore, refetch }) => {
|
||||
|
@ -108,6 +114,7 @@ class AuthenticationsComponentQuery extends QueryTemplate<
|
|||
}));
|
||||
return children({
|
||||
id,
|
||||
inspect: getOr(null, 'source.Authentications.inspect', data),
|
||||
refetch,
|
||||
loading,
|
||||
totalCount: getOr(0, 'source.Authentications.totalCount', data),
|
||||
|
@ -123,8 +130,13 @@ class AuthenticationsComponentQuery extends QueryTemplate<
|
|||
|
||||
const makeMapStateToProps = () => {
|
||||
const getAuthenticationsSelector = hostsSelectors.authenticationsSelector();
|
||||
const mapStateToProps = (state: State, { type }: OwnProps) => {
|
||||
return getAuthenticationsSelector(state, type);
|
||||
const getQuery = inputsSelectors.globalQueryByIdSelector();
|
||||
const mapStateToProps = (state: State, { type, id = ID }: OwnProps) => {
|
||||
const { isInspected } = getQuery(state, id);
|
||||
return {
|
||||
...getAuthenticationsSelector(state, type),
|
||||
isInspected,
|
||||
};
|
||||
};
|
||||
return mapStateToProps;
|
||||
};
|
||||
|
|
|
@ -17,6 +17,7 @@ export const domainsQuery = gql`
|
|||
$sort: DomainsSortField!
|
||||
$timerange: TimerangeInput!
|
||||
$defaultIndex: [String!]!
|
||||
$inspect: Boolean!
|
||||
) {
|
||||
source(id: $sourceId) {
|
||||
id
|
||||
|
@ -61,6 +62,10 @@ export const domainsQuery = gql`
|
|||
}
|
||||
hasNextPage
|
||||
}
|
||||
inspect @include(if: $inspect) {
|
||||
dsl
|
||||
response
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,14 +19,17 @@ import {
|
|||
FlowTarget,
|
||||
PageInfo,
|
||||
} from '../../graphql/types';
|
||||
import { inputsModel, networkModel, networkSelectors, State } from '../../store';
|
||||
import { inputsModel, networkModel, networkSelectors, State, inputsSelectors } from '../../store';
|
||||
import { createFilter } from '../helpers';
|
||||
import { QueryTemplate, QueryTemplateProps } from '../query_template';
|
||||
|
||||
import { domainsQuery } from './index.gql_query';
|
||||
|
||||
const ID = 'domainsQuery';
|
||||
|
||||
export interface DomainsArgs {
|
||||
id: string;
|
||||
inspect: inputsModel.InspectQuery;
|
||||
domains: DomainsEdges[];
|
||||
totalCount: number;
|
||||
pageInfo: PageInfo;
|
||||
|
@ -43,6 +46,7 @@ export interface OwnProps extends QueryTemplateProps {
|
|||
}
|
||||
|
||||
export interface DomainsComponentReduxProps {
|
||||
isInspected: boolean;
|
||||
limit: number;
|
||||
domainsSortField: DomainsSortField;
|
||||
flowDirection: FlowDirection;
|
||||
|
@ -57,7 +61,8 @@ class DomainsComponentQuery extends QueryTemplate<
|
|||
> {
|
||||
public render() {
|
||||
const {
|
||||
id = 'domainsQuery',
|
||||
id = ID,
|
||||
isInspected,
|
||||
children,
|
||||
domainsSortField,
|
||||
filterQuery,
|
||||
|
@ -94,6 +99,7 @@ class DomainsComponentQuery extends QueryTemplate<
|
|||
},
|
||||
filterQuery: createFilter(filterQuery),
|
||||
defaultIndex: chrome.getUiSettingsClient().get(DEFAULT_INDEX_KEY),
|
||||
inspect: isInspected,
|
||||
}}
|
||||
>
|
||||
{({ data, loading, fetchMore, refetch }) => {
|
||||
|
@ -124,6 +130,7 @@ class DomainsComponentQuery extends QueryTemplate<
|
|||
}));
|
||||
return children({
|
||||
id,
|
||||
inspect: getOr(null, 'source.Domains.inspect', data),
|
||||
refetch,
|
||||
loading,
|
||||
totalCount: getOr(0, 'source.Domains.totalCount', data),
|
||||
|
@ -139,9 +146,14 @@ class DomainsComponentQuery extends QueryTemplate<
|
|||
|
||||
const makeMapStateToProps = () => {
|
||||
const getDomainsSelector = networkSelectors.domainsSelector();
|
||||
const mapStateToProps = (state: State) => ({
|
||||
...getDomainsSelector(state),
|
||||
});
|
||||
const getQuery = inputsSelectors.globalQueryByIdSelector();
|
||||
const mapStateToProps = (state: State, { id = ID }: OwnProps) => {
|
||||
const { isInspected } = getQuery(state, id);
|
||||
return {
|
||||
...getDomainsSelector(state),
|
||||
isInspected,
|
||||
};
|
||||
};
|
||||
|
||||
return mapStateToProps;
|
||||
};
|
||||
|
|
|
@ -14,6 +14,7 @@ export const eventsQuery = gql`
|
|||
$sortField: SortField!
|
||||
$filterQuery: String
|
||||
$defaultIndex: [String!]!
|
||||
$inspect: Boolean!
|
||||
) {
|
||||
source(id: $sourceId) {
|
||||
id
|
||||
|
@ -32,6 +33,10 @@ export const eventsQuery = gql`
|
|||
}
|
||||
hasNextPage
|
||||
}
|
||||
inspect @include(if: $inspect) {
|
||||
dsl
|
||||
response
|
||||
}
|
||||
edges {
|
||||
node {
|
||||
_id
|
||||
|
|
|
@ -12,14 +12,17 @@ import { connect } from 'react-redux';
|
|||
import chrome from 'ui/chrome';
|
||||
import { DEFAULT_INDEX_KEY } from '../../../common/constants';
|
||||
import { Direction, Ecs, GetEventsQuery, PageInfo } from '../../graphql/types';
|
||||
import { hostsModel, hostsSelectors, inputsModel, State } from '../../store';
|
||||
import { hostsModel, hostsSelectors, inputsModel, State, inputsSelectors } from '../../store';
|
||||
import { createFilter, getDefaultFetchPolicy } from '../helpers';
|
||||
import { QueryTemplate, QueryTemplateProps } from '../query_template';
|
||||
|
||||
import { eventsQuery } from './index.gql_query';
|
||||
|
||||
const ID = 'eventsQuery';
|
||||
|
||||
export interface EventsArgs {
|
||||
id: string;
|
||||
inspect: inputsModel.InspectQuery;
|
||||
events: Ecs[];
|
||||
loading: boolean;
|
||||
loadMore: (cursor: string, tiebreaker: string) => void;
|
||||
|
@ -34,6 +37,7 @@ export interface OwnProps extends QueryTemplateProps {
|
|||
}
|
||||
|
||||
export interface EventsComponentReduxProps {
|
||||
isInspected: boolean;
|
||||
limit: number;
|
||||
}
|
||||
|
||||
|
@ -48,7 +52,8 @@ class EventsComponentQuery extends QueryTemplate<
|
|||
const {
|
||||
children,
|
||||
filterQuery,
|
||||
id = 'eventsQuery',
|
||||
id = ID,
|
||||
isInspected,
|
||||
limit,
|
||||
skip,
|
||||
sourceId,
|
||||
|
@ -79,6 +84,7 @@ class EventsComponentQuery extends QueryTemplate<
|
|||
to: endDate!,
|
||||
},
|
||||
defaultIndex: chrome.getUiSettingsClient().get(DEFAULT_INDEX_KEY),
|
||||
inspect: isInspected,
|
||||
}}
|
||||
>
|
||||
{({ data, loading, fetchMore, refetch }) => {
|
||||
|
@ -110,6 +116,7 @@ class EventsComponentQuery extends QueryTemplate<
|
|||
}));
|
||||
return children!({
|
||||
id,
|
||||
inspect: getOr(null, 'source.Events.inspect', data),
|
||||
refetch,
|
||||
loading,
|
||||
totalCount: getOr(0, 'source.Events.totalCount', data),
|
||||
|
@ -125,8 +132,13 @@ class EventsComponentQuery extends QueryTemplate<
|
|||
|
||||
const makeMapStateToProps = () => {
|
||||
const getEventsSelector = hostsSelectors.eventsSelector();
|
||||
const mapStateToProps = (state: State, { type }: OwnProps) => {
|
||||
return getEventsSelector(state, type);
|
||||
const getQuery = inputsSelectors.globalQueryByIdSelector();
|
||||
const mapStateToProps = (state: State, { type, id = ID }: OwnProps) => {
|
||||
const { isInspected } = getQuery(state, id);
|
||||
return {
|
||||
...getEventsSelector(state, type),
|
||||
isInspected,
|
||||
};
|
||||
};
|
||||
return mapStateToProps;
|
||||
};
|
||||
|
|
|
@ -16,7 +16,17 @@ interface GlobalTimeArgs {
|
|||
from: number;
|
||||
to: number;
|
||||
setQuery: (
|
||||
{ id, loading, refetch }: { id: string; loading: boolean; refetch: inputsModel.Refetch }
|
||||
{
|
||||
id,
|
||||
inspect,
|
||||
loading,
|
||||
refetch,
|
||||
}: {
|
||||
id: string;
|
||||
inspect: inputsModel.InspectQuery | null;
|
||||
loading: boolean;
|
||||
refetch: inputsModel.Refetch;
|
||||
}
|
||||
) => void;
|
||||
}
|
||||
|
||||
|
@ -28,6 +38,7 @@ interface GlobalTimeDispatch {
|
|||
setGlobalQuery: ActionCreator<{
|
||||
inputId: InputsModelId;
|
||||
id: string;
|
||||
inspect: inputsModel.InspectQuery | null;
|
||||
loading: boolean;
|
||||
refetch: inputsModel.Refetch;
|
||||
}>;
|
||||
|
@ -42,7 +53,7 @@ interface GlobalTimeReduxState {
|
|||
type GlobalTimeProps = OwnProps & GlobalTimeReduxState & GlobalTimeDispatch;
|
||||
|
||||
class GlobalTimeComponent extends React.PureComponent<GlobalTimeProps> {
|
||||
public componentDidMount() {
|
||||
public componentWillUnmount() {
|
||||
this.props.deleteAllQuery({ id: 'global' });
|
||||
}
|
||||
|
||||
|
@ -53,8 +64,8 @@ class GlobalTimeComponent extends React.PureComponent<GlobalTimeProps> {
|
|||
{children({
|
||||
from,
|
||||
to,
|
||||
setQuery: ({ id, loading, refetch }) =>
|
||||
setGlobalQuery({ inputId: 'global', id, loading, refetch }),
|
||||
setQuery: ({ id, inspect, loading, refetch }) =>
|
||||
setGlobalQuery({ inputId: 'global', id, inspect, loading, refetch }),
|
||||
})}
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -14,6 +14,7 @@ export const HostsTableQuery = gql`
|
|||
$sort: HostsSortField!
|
||||
$filterQuery: String
|
||||
$defaultIndex: [String!]!
|
||||
$inspect: Boolean!
|
||||
) {
|
||||
source(id: $sourceId) {
|
||||
id
|
||||
|
@ -48,6 +49,10 @@ export const HostsTableQuery = gql`
|
|||
}
|
||||
hasNextPage
|
||||
}
|
||||
inspect @include(if: $inspect) {
|
||||
dsl
|
||||
response
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ import {
|
|||
HostsFields,
|
||||
PageInfo,
|
||||
} from '../../graphql/types';
|
||||
import { hostsModel, hostsSelectors, inputsModel, State } from '../../store';
|
||||
import { hostsModel, hostsSelectors, inputsModel, State, inputsSelectors } from '../../store';
|
||||
import { createFilter } from '../helpers';
|
||||
import { QueryTemplate, QueryTemplateProps } from '../query_template';
|
||||
|
||||
|
@ -27,8 +27,11 @@ import { HostsTableQuery } from './hosts_table.gql_query';
|
|||
|
||||
export { HostsFilter } from './filter';
|
||||
|
||||
const ID = 'hostsQuery';
|
||||
|
||||
export interface HostsArgs {
|
||||
id: string;
|
||||
inspect: inputsModel.InspectQuery;
|
||||
hosts: HostsEdges[];
|
||||
totalCount: number;
|
||||
pageInfo: PageInfo;
|
||||
|
@ -47,6 +50,7 @@ export interface OwnProps extends QueryTemplateProps {
|
|||
}
|
||||
|
||||
export interface HostsComponentReduxProps {
|
||||
isInspected: boolean;
|
||||
limit: number;
|
||||
sortField: HostsFields;
|
||||
direction: Direction;
|
||||
|
@ -71,7 +75,8 @@ class HostsComponentQuery extends QueryTemplate<
|
|||
|
||||
public render() {
|
||||
const {
|
||||
id = 'hostsQuery',
|
||||
id = ID,
|
||||
isInspected,
|
||||
children,
|
||||
direction,
|
||||
filterQuery,
|
||||
|
@ -82,6 +87,7 @@ class HostsComponentQuery extends QueryTemplate<
|
|||
sourceId,
|
||||
sortField,
|
||||
} = this.props;
|
||||
|
||||
const variables: GetHostsTableQuery.Variables = {
|
||||
sourceId,
|
||||
timerange: {
|
||||
|
@ -100,6 +106,7 @@ class HostsComponentQuery extends QueryTemplate<
|
|||
},
|
||||
filterQuery: createFilter(filterQuery),
|
||||
defaultIndex: chrome.getUiSettingsClient().get(DEFAULT_INDEX_KEY),
|
||||
inspect: isInspected,
|
||||
};
|
||||
return (
|
||||
<Query<GetHostsTableQuery.Query, GetHostsTableQuery.Variables>
|
||||
|
@ -136,6 +143,7 @@ class HostsComponentQuery extends QueryTemplate<
|
|||
}));
|
||||
return children({
|
||||
id,
|
||||
inspect: getOr(null, 'source.Hosts.inspect', data),
|
||||
refetch,
|
||||
loading,
|
||||
totalCount: getOr(0, 'source.Hosts.totalCount', data),
|
||||
|
@ -158,8 +166,13 @@ class HostsComponentQuery extends QueryTemplate<
|
|||
|
||||
const makeMapStateToProps = () => {
|
||||
const getHostsSelector = hostsSelectors.hostsSelector();
|
||||
const mapStateToProps = (state: State, { type }: OwnProps) => {
|
||||
return getHostsSelector(state, type);
|
||||
const getQuery = inputsSelectors.globalQueryByIdSelector();
|
||||
const mapStateToProps = (state: State, { type, id = ID }: OwnProps) => {
|
||||
const { isInspected } = getQuery(state, id);
|
||||
return {
|
||||
...getHostsSelector(state, type),
|
||||
isInspected,
|
||||
};
|
||||
};
|
||||
return mapStateToProps;
|
||||
};
|
||||
|
|
|
@ -12,6 +12,7 @@ export const HostOverviewQuery = gql`
|
|||
$hostName: String!
|
||||
$timerange: TimerangeInput!
|
||||
$defaultIndex: [String!]!
|
||||
$inspect: Boolean!
|
||||
) {
|
||||
source(id: $sourceId) {
|
||||
id
|
||||
|
@ -41,6 +42,10 @@ export const HostOverviewQuery = gql`
|
|||
provider
|
||||
region
|
||||
}
|
||||
inspect @include(if: $inspect) {
|
||||
dsl
|
||||
response
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,16 +8,20 @@ import { getOr } from 'lodash/fp';
|
|||
import React from 'react';
|
||||
import { Query } from 'react-apollo';
|
||||
import chrome from 'ui/chrome';
|
||||
import { connect } from 'react-redux';
|
||||
import { DEFAULT_INDEX_KEY } from '../../../../common/constants';
|
||||
import { inputsModel } from '../../../store';
|
||||
import { inputsModel, inputsSelectors, State } from '../../../store';
|
||||
import { getDefaultFetchPolicy } from '../../helpers';
|
||||
import { QueryTemplate, QueryTemplateProps } from '../../query_template';
|
||||
|
||||
import { HostOverviewQuery } from './host_overview.gql_query';
|
||||
import { GetHostOverviewQuery, HostItem } from '../../../graphql/types';
|
||||
|
||||
const ID = 'hostOverviewQuery';
|
||||
|
||||
export interface HostOverviewArgs {
|
||||
id: string;
|
||||
inspect: inputsModel.InspectQuery;
|
||||
hostOverview: HostItem;
|
||||
loading: boolean;
|
||||
refetch: inputsModel.Refetch;
|
||||
|
@ -25,6 +29,10 @@ export interface HostOverviewArgs {
|
|||
endDate: number;
|
||||
}
|
||||
|
||||
export interface HostOverviewReduxProps {
|
||||
isInspected: boolean;
|
||||
}
|
||||
|
||||
export interface OwnProps extends QueryTemplateProps {
|
||||
children: (args: HostOverviewArgs) => React.ReactNode;
|
||||
hostName: string;
|
||||
|
@ -32,14 +40,15 @@ export interface OwnProps extends QueryTemplateProps {
|
|||
endDate: number;
|
||||
}
|
||||
|
||||
export class HostOverviewByNameQuery extends QueryTemplate<
|
||||
OwnProps,
|
||||
class HostOverviewByNameComponentQuery extends QueryTemplate<
|
||||
OwnProps & HostOverviewReduxProps,
|
||||
GetHostOverviewQuery.Query,
|
||||
GetHostOverviewQuery.Variables
|
||||
> {
|
||||
public render() {
|
||||
const {
|
||||
id = 'hostOverviewQuery',
|
||||
id = ID,
|
||||
isInspected,
|
||||
children,
|
||||
hostName,
|
||||
skip,
|
||||
|
@ -62,12 +71,14 @@ export class HostOverviewByNameQuery extends QueryTemplate<
|
|||
to: endDate,
|
||||
},
|
||||
defaultIndex: chrome.getUiSettingsClient().get(DEFAULT_INDEX_KEY),
|
||||
inspect: isInspected,
|
||||
}}
|
||||
>
|
||||
{({ data, loading, refetch }) => {
|
||||
const hostOverview = getOr([], 'source.HostOverview', data);
|
||||
return children({
|
||||
id,
|
||||
inspect: getOr(null, 'source.HostOverview.inspect', data),
|
||||
refetch,
|
||||
loading,
|
||||
hostOverview,
|
||||
|
@ -79,3 +90,18 @@ export class HostOverviewByNameQuery extends QueryTemplate<
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
const makeMapStateToProps = () => {
|
||||
const getQuery = inputsSelectors.globalQueryByIdSelector();
|
||||
const mapStateToProps = (state: State, { id = ID }: OwnProps) => {
|
||||
const { isInspected } = getQuery(state, id);
|
||||
return {
|
||||
isInspected,
|
||||
};
|
||||
};
|
||||
return mapStateToProps;
|
||||
};
|
||||
|
||||
export const HostOverviewByNameQuery = connect(makeMapStateToProps)(
|
||||
HostOverviewByNameComponentQuery
|
||||
);
|
||||
|
|
|
@ -12,6 +12,7 @@ export const ipOverviewQuery = gql`
|
|||
$filterQuery: String
|
||||
$ip: String!
|
||||
$defaultIndex: [String!]!
|
||||
$inspect: Boolean!
|
||||
) {
|
||||
source(id: $sourceId) {
|
||||
id
|
||||
|
@ -72,6 +73,10 @@ export const ipOverviewQuery = gql`
|
|||
}
|
||||
type
|
||||
}
|
||||
inspect @include(if: $inspect) {
|
||||
dsl
|
||||
response
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,21 +7,30 @@
|
|||
import { getOr } from 'lodash/fp';
|
||||
import React from 'react';
|
||||
import { Query } from 'react-apollo';
|
||||
import { connect } from 'react-redux';
|
||||
import { pure } from 'recompose';
|
||||
|
||||
import chrome from 'ui/chrome';
|
||||
import { DEFAULT_INDEX_KEY } from '../../../common/constants';
|
||||
import { GetIpOverviewQuery, IpOverviewData } from '../../graphql/types';
|
||||
import { networkModel } from '../../store';
|
||||
import { networkModel, inputsModel, inputsSelectors, State } from '../../store';
|
||||
import { createFilter } from '../helpers';
|
||||
import { QueryTemplateProps } from '../query_template';
|
||||
|
||||
import { ipOverviewQuery } from './index.gql_query';
|
||||
|
||||
const ID = 'ipOverviewQuery';
|
||||
|
||||
export interface IpOverviewArgs {
|
||||
id: string;
|
||||
inspect: inputsModel.InspectQuery;
|
||||
ipOverviewData: IpOverviewData;
|
||||
loading: boolean;
|
||||
refetch: inputsModel.Refetch;
|
||||
}
|
||||
|
||||
export interface IpOverviewReduxProps {
|
||||
isInspected: boolean;
|
||||
}
|
||||
|
||||
export interface IpOverviewProps extends QueryTemplateProps {
|
||||
|
@ -30,8 +39,8 @@ export interface IpOverviewProps extends QueryTemplateProps {
|
|||
ip: string;
|
||||
}
|
||||
|
||||
export const IpOverviewQuery = pure<IpOverviewProps>(
|
||||
({ id = 'ipOverviewQuery', children, filterQuery, skip, sourceId, ip }) => (
|
||||
const IpOverviewComponentQuery = pure<IpOverviewProps & IpOverviewReduxProps>(
|
||||
({ id = ID, isInspected, children, filterQuery, skip, sourceId, ip }) => (
|
||||
<Query<GetIpOverviewQuery.Query, GetIpOverviewQuery.Variables>
|
||||
query={ipOverviewQuery}
|
||||
fetchPolicy="cache-and-network"
|
||||
|
@ -42,17 +51,33 @@ export const IpOverviewQuery = pure<IpOverviewProps>(
|
|||
filterQuery: createFilter(filterQuery),
|
||||
ip,
|
||||
defaultIndex: chrome.getUiSettingsClient().get(DEFAULT_INDEX_KEY),
|
||||
inspect: isInspected,
|
||||
}}
|
||||
>
|
||||
{({ data, loading }) => {
|
||||
{({ data, loading, refetch }) => {
|
||||
const init: IpOverviewData = { host: {} };
|
||||
const ipOverviewData: IpOverviewData = getOr(init, 'source.IpOverview', data);
|
||||
return children({
|
||||
id,
|
||||
inspect: getOr(null, 'source.IpOverview.inspect', data),
|
||||
ipOverviewData,
|
||||
loading,
|
||||
refetch,
|
||||
});
|
||||
}}
|
||||
</Query>
|
||||
)
|
||||
);
|
||||
|
||||
const makeMapStateToProps = () => {
|
||||
const getQuery = inputsSelectors.globalQueryByIdSelector();
|
||||
const mapStateToProps = (state: State, { id = ID }: IpOverviewProps) => {
|
||||
const { isInspected } = getQuery(state, id);
|
||||
return {
|
||||
isInspected,
|
||||
};
|
||||
};
|
||||
return mapStateToProps;
|
||||
};
|
||||
|
||||
export const IpOverviewQuery = connect(makeMapStateToProps)(IpOverviewComponentQuery);
|
||||
|
|
|
@ -17,6 +17,7 @@ export const kpiHostDetailsQuery = gql`
|
|||
$timerange: TimerangeInput!
|
||||
$filterQuery: String
|
||||
$defaultIndex: [String!]!
|
||||
$inspect: Boolean!
|
||||
) {
|
||||
source(id: $sourceId) {
|
||||
id
|
||||
|
@ -41,6 +42,10 @@ export const kpiHostDetailsQuery = gql`
|
|||
uniqueDestinationIpsHistogram {
|
||||
...KpiHostDetailsChartFields
|
||||
}
|
||||
inspect @include(if: $inspect) {
|
||||
dsl
|
||||
response
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,18 +7,23 @@
|
|||
import { getOr } from 'lodash/fp';
|
||||
import React from 'react';
|
||||
import { Query } from 'react-apollo';
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
import { pure } from 'recompose';
|
||||
import chrome from 'ui/chrome';
|
||||
|
||||
import { DEFAULT_INDEX_KEY } from '../../../common/constants';
|
||||
import { KpiHostDetailsData, GetKpiHostDetailsQuery } from '../../graphql/types';
|
||||
import { inputsModel } from '../../store';
|
||||
import { inputsModel, inputsSelectors, State } from '../../store';
|
||||
import { createFilter } from '../helpers';
|
||||
import { QueryTemplateProps } from '../query_template';
|
||||
|
||||
import { kpiHostDetailsQuery } from './index.gql_query';
|
||||
|
||||
const ID = 'kpiHostDetailsQuery';
|
||||
|
||||
export interface KpiHostDetailsArgs {
|
||||
id: string;
|
||||
inspect: inputsModel.InspectQuery;
|
||||
kpiHostDetails: KpiHostDetailsData;
|
||||
loading: boolean;
|
||||
refetch: inputsModel.Refetch;
|
||||
|
@ -28,8 +33,12 @@ export interface QueryKpiHostDetailsProps extends QueryTemplateProps {
|
|||
children: (args: KpiHostDetailsArgs) => React.ReactNode;
|
||||
}
|
||||
|
||||
export const KpiHostDetailsQuery = React.memo<QueryKpiHostDetailsProps>(
|
||||
({ id = 'kpiHostDetailsQuery', children, endDate, filterQuery, skip, sourceId, startDate }) => (
|
||||
export interface KpiHostDetailsReducer {
|
||||
isInspected: boolean;
|
||||
}
|
||||
|
||||
const KpiHostDetailsComponentQuery = pure<QueryKpiHostDetailsProps & KpiHostDetailsReducer>(
|
||||
({ id = ID, children, endDate, filterQuery, isInspected, skip, sourceId, startDate }) => (
|
||||
<Query<GetKpiHostDetailsQuery.Query, GetKpiHostDetailsQuery.Variables>
|
||||
query={kpiHostDetailsQuery}
|
||||
fetchPolicy="cache-and-network"
|
||||
|
@ -44,12 +53,14 @@ export const KpiHostDetailsQuery = React.memo<QueryKpiHostDetailsProps>(
|
|||
},
|
||||
filterQuery: createFilter(filterQuery),
|
||||
defaultIndex: chrome.getUiSettingsClient().get(DEFAULT_INDEX_KEY),
|
||||
inspect: isInspected,
|
||||
}}
|
||||
>
|
||||
{({ data, loading, refetch }) => {
|
||||
const kpiHostDetails = getOr({}, `source.KpiHostDetails`, data);
|
||||
return children({
|
||||
id,
|
||||
inspect: getOr(null, 'source.KpiHostDetails.inspect', data),
|
||||
kpiHostDetails,
|
||||
loading,
|
||||
refetch,
|
||||
|
@ -58,3 +69,16 @@ export const KpiHostDetailsQuery = React.memo<QueryKpiHostDetailsProps>(
|
|||
</Query>
|
||||
)
|
||||
);
|
||||
|
||||
const makeMapStateToProps = () => {
|
||||
const getQuery = inputsSelectors.globalQueryByIdSelector();
|
||||
const mapStateToProps = (state: State, { id = ID }: QueryKpiHostDetailsProps) => {
|
||||
const { isInspected } = getQuery(state, id);
|
||||
return {
|
||||
isInspected,
|
||||
};
|
||||
};
|
||||
return mapStateToProps;
|
||||
};
|
||||
|
||||
export const KpiHostDetailsQuery = connect(makeMapStateToProps)(KpiHostDetailsComponentQuery);
|
||||
|
|
|
@ -17,6 +17,7 @@ export const kpiHostsQuery = gql`
|
|||
$timerange: TimerangeInput!
|
||||
$filterQuery: String
|
||||
$defaultIndex: [String!]!
|
||||
$inspect: Boolean!
|
||||
) {
|
||||
source(id: $sourceId) {
|
||||
id
|
||||
|
@ -41,6 +42,10 @@ export const kpiHostsQuery = gql`
|
|||
uniqueDestinationIpsHistogram {
|
||||
...KpiHostChartFields
|
||||
}
|
||||
inspect @include(if: $inspect) {
|
||||
dsl
|
||||
response
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,29 +7,38 @@
|
|||
import { getOr } from 'lodash/fp';
|
||||
import React from 'react';
|
||||
import { Query } from 'react-apollo';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import chrome from 'ui/chrome';
|
||||
import { pure } from 'recompose';
|
||||
import { DEFAULT_INDEX_KEY } from '../../../common/constants';
|
||||
import { GetKpiHostsQuery, KpiHostsData } from '../../graphql/types';
|
||||
import { inputsModel } from '../../store';
|
||||
import { inputsModel, inputsSelectors, State } from '../../store';
|
||||
import { createFilter } from '../helpers';
|
||||
import { QueryTemplateProps } from '../query_template';
|
||||
|
||||
import { kpiHostsQuery } from './index.gql_query';
|
||||
|
||||
const ID = 'kpiHostsQuery';
|
||||
|
||||
export interface KpiHostsArgs {
|
||||
id: string;
|
||||
inspect: inputsModel.InspectQuery;
|
||||
kpiHosts: KpiHostsData;
|
||||
loading: boolean;
|
||||
refetch: inputsModel.Refetch;
|
||||
}
|
||||
|
||||
export interface KpiHostsReducer {
|
||||
isInspected: boolean;
|
||||
}
|
||||
|
||||
export interface KpiHostsProps extends QueryTemplateProps {
|
||||
children: (args: KpiHostsArgs) => React.ReactNode;
|
||||
}
|
||||
|
||||
export const KpiHostsQuery = React.memo<KpiHostsProps>(
|
||||
({ id = 'kpiHostsQuery', children, endDate, filterQuery, skip, sourceId, startDate }) => (
|
||||
const KpiHostsComponentQuery = pure<KpiHostsProps & KpiHostsReducer>(
|
||||
({ id = ID, children, endDate, filterQuery, isInspected, skip, sourceId, startDate }) => (
|
||||
<Query<GetKpiHostsQuery.Query, GetKpiHostsQuery.Variables>
|
||||
query={kpiHostsQuery}
|
||||
fetchPolicy="cache-and-network"
|
||||
|
@ -44,12 +53,14 @@ export const KpiHostsQuery = React.memo<KpiHostsProps>(
|
|||
},
|
||||
filterQuery: createFilter(filterQuery),
|
||||
defaultIndex: chrome.getUiSettingsClient().get(DEFAULT_INDEX_KEY),
|
||||
inspect: isInspected,
|
||||
}}
|
||||
>
|
||||
{({ data, loading, refetch }) => {
|
||||
const kpiHosts = getOr({}, `source.KpiHosts`, data);
|
||||
return children({
|
||||
id,
|
||||
inspect: getOr(null, 'source.KpiHosts.inspect', data),
|
||||
kpiHosts,
|
||||
loading,
|
||||
refetch,
|
||||
|
@ -58,3 +69,16 @@ export const KpiHostsQuery = React.memo<KpiHostsProps>(
|
|||
</Query>
|
||||
)
|
||||
);
|
||||
|
||||
const makeMapStateToProps = () => {
|
||||
const getQuery = inputsSelectors.globalQueryByIdSelector();
|
||||
const mapStateToProps = (state: State, { id = ID }: KpiHostsProps) => {
|
||||
const { isInspected } = getQuery(state, id);
|
||||
return {
|
||||
isInspected,
|
||||
};
|
||||
};
|
||||
return mapStateToProps;
|
||||
};
|
||||
|
||||
export const KpiHostsQuery = connect(makeMapStateToProps)(KpiHostsComponentQuery);
|
||||
|
|
|
@ -17,6 +17,7 @@ export const kpiNetworkQuery = gql`
|
|||
$timerange: TimerangeInput!
|
||||
$filterQuery: String
|
||||
$defaultIndex: [String!]!
|
||||
$inspect: Boolean!
|
||||
) {
|
||||
source(id: $sourceId) {
|
||||
id
|
||||
|
@ -33,6 +34,10 @@ export const kpiNetworkQuery = gql`
|
|||
}
|
||||
dnsQueries
|
||||
tlsHandshakes
|
||||
inspect @include(if: $inspect) {
|
||||
dsl
|
||||
response
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,29 +7,38 @@
|
|||
import { getOr } from 'lodash/fp';
|
||||
import React from 'react';
|
||||
import { Query } from 'react-apollo';
|
||||
import { connect } from 'react-redux';
|
||||
import { pure } from 'recompose';
|
||||
|
||||
import chrome from 'ui/chrome';
|
||||
import { DEFAULT_INDEX_KEY } from '../../../common/constants';
|
||||
import { GetKpiNetworkQuery, KpiNetworkData } from '../../graphql/types';
|
||||
import { inputsModel } from '../../store';
|
||||
import { inputsModel, inputsSelectors, State } from '../../store';
|
||||
import { createFilter } from '../helpers';
|
||||
import { QueryTemplateProps } from '../query_template';
|
||||
|
||||
import { kpiNetworkQuery } from './index.gql_query';
|
||||
|
||||
const ID = 'kpiNetworkQuery';
|
||||
|
||||
export interface KpiNetworkArgs {
|
||||
id: string;
|
||||
inspect: inputsModel.InspectQuery;
|
||||
kpiNetwork: KpiNetworkData;
|
||||
loading: boolean;
|
||||
refetch: inputsModel.Refetch;
|
||||
}
|
||||
|
||||
export interface KpiNetworkReducer {
|
||||
isInspected: boolean;
|
||||
}
|
||||
|
||||
export interface KpiNetworkProps extends QueryTemplateProps {
|
||||
children: (args: KpiNetworkArgs) => React.ReactNode;
|
||||
}
|
||||
|
||||
export const KpiNetworkQuery = React.memo<KpiNetworkProps>(
|
||||
({ id = 'kpiNetworkQuery', children, filterQuery, skip, sourceId, startDate, endDate }) => (
|
||||
const KpiNetworkComponentQuery = pure<KpiNetworkProps & KpiNetworkReducer>(
|
||||
({ id = ID, children, filterQuery, isInspected, skip, sourceId, startDate, endDate }) => (
|
||||
<Query<GetKpiNetworkQuery.Query, GetKpiNetworkQuery.Variables>
|
||||
query={kpiNetworkQuery}
|
||||
fetchPolicy="cache-and-network"
|
||||
|
@ -44,12 +53,14 @@ export const KpiNetworkQuery = React.memo<KpiNetworkProps>(
|
|||
},
|
||||
filterQuery: createFilter(filterQuery),
|
||||
defaultIndex: chrome.getUiSettingsClient().get(DEFAULT_INDEX_KEY),
|
||||
inspect: isInspected,
|
||||
}}
|
||||
>
|
||||
{({ data, loading, refetch }) => {
|
||||
const kpiNetwork = getOr({}, `source.KpiNetwork`, data);
|
||||
return children({
|
||||
id,
|
||||
inspect: getOr(null, 'source.KpiNetwork.inspect', data),
|
||||
kpiNetwork,
|
||||
loading,
|
||||
refetch,
|
||||
|
@ -58,3 +69,16 @@ export const KpiNetworkQuery = React.memo<KpiNetworkProps>(
|
|||
</Query>
|
||||
)
|
||||
);
|
||||
|
||||
const makeMapStateToProps = () => {
|
||||
const getQuery = inputsSelectors.globalQueryByIdSelector();
|
||||
const mapStateToProps = (state: State, { id = ID }: KpiNetworkProps) => {
|
||||
const { isInspected } = getQuery(state, id);
|
||||
return {
|
||||
isInspected,
|
||||
};
|
||||
};
|
||||
return mapStateToProps;
|
||||
};
|
||||
|
||||
export const KpiNetworkQuery = connect(makeMapStateToProps)(KpiNetworkComponentQuery);
|
||||
|
|
|
@ -15,6 +15,7 @@ export const networkDnsQuery = gql`
|
|||
$pagination: PaginationInput!
|
||||
$filterQuery: String
|
||||
$defaultIndex: [String!]!
|
||||
$inspect: Boolean!
|
||||
) {
|
||||
source(id: $sourceId) {
|
||||
id
|
||||
|
@ -46,6 +47,10 @@ export const networkDnsQuery = gql`
|
|||
}
|
||||
hasNextPage
|
||||
}
|
||||
inspect @include(if: $inspect) {
|
||||
dsl
|
||||
response
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,14 +17,17 @@ import {
|
|||
NetworkDnsSortField,
|
||||
PageInfo,
|
||||
} from '../../graphql/types';
|
||||
import { inputsModel, networkModel, networkSelectors, State } from '../../store';
|
||||
import { inputsModel, networkModel, networkSelectors, State, inputsSelectors } from '../../store';
|
||||
import { createFilter } from '../helpers';
|
||||
import { QueryTemplate, QueryTemplateProps } from '../query_template';
|
||||
|
||||
import { networkDnsQuery } from './index.gql_query';
|
||||
|
||||
const ID = 'networkDnsQuery';
|
||||
|
||||
export interface NetworkDnsArgs {
|
||||
id: string;
|
||||
inspect: inputsModel.InspectQuery;
|
||||
networkDns: NetworkDnsEdges[];
|
||||
totalCount: number;
|
||||
pageInfo: PageInfo;
|
||||
|
@ -39,6 +42,7 @@ export interface OwnProps extends QueryTemplateProps {
|
|||
}
|
||||
|
||||
export interface NetworkDnsComponentReduxProps {
|
||||
isInspected: boolean;
|
||||
limit: number;
|
||||
dnsSortField: NetworkDnsSortField;
|
||||
isPtrIncluded: boolean;
|
||||
|
@ -53,7 +57,8 @@ class NetworkDnsComponentQuery extends QueryTemplate<
|
|||
> {
|
||||
public render() {
|
||||
const {
|
||||
id = 'networkDnsQuery',
|
||||
id = ID,
|
||||
isInspected,
|
||||
children,
|
||||
dnsSortField,
|
||||
filterQuery,
|
||||
|
@ -86,6 +91,7 @@ class NetworkDnsComponentQuery extends QueryTemplate<
|
|||
},
|
||||
filterQuery: createFilter(filterQuery),
|
||||
defaultIndex: chrome.getUiSettingsClient().get(DEFAULT_INDEX_KEY),
|
||||
inspect: isInspected,
|
||||
}}
|
||||
>
|
||||
{({ data, loading, fetchMore, refetch }) => {
|
||||
|
@ -119,6 +125,7 @@ class NetworkDnsComponentQuery extends QueryTemplate<
|
|||
}));
|
||||
return children({
|
||||
id,
|
||||
inspect: getOr(null, 'source.NetworkDns.inspect', data),
|
||||
refetch,
|
||||
loading,
|
||||
totalCount: getOr(0, 'source.NetworkDns.totalCount', data),
|
||||
|
@ -134,7 +141,14 @@ class NetworkDnsComponentQuery extends QueryTemplate<
|
|||
|
||||
const makeMapStateToProps = () => {
|
||||
const getNetworkDnsSelector = networkSelectors.dnsSelector();
|
||||
const mapStateToProps = (state: State) => getNetworkDnsSelector(state);
|
||||
const getQuery = inputsSelectors.globalQueryByIdSelector();
|
||||
const mapStateToProps = (state: State, { id = ID }: OwnProps) => {
|
||||
const { isInspected } = getQuery(state, id);
|
||||
return {
|
||||
...getNetworkDnsSelector(state),
|
||||
isInspected,
|
||||
};
|
||||
};
|
||||
|
||||
return mapStateToProps;
|
||||
};
|
||||
|
|
|
@ -16,6 +16,7 @@ export const networkTopNFlowQuery = gql`
|
|||
$flowTarget: FlowTarget!
|
||||
$timerange: TimerangeInput!
|
||||
$defaultIndex: [String!]!
|
||||
$inspect: Boolean!
|
||||
) {
|
||||
source(id: $sourceId) {
|
||||
id
|
||||
|
@ -67,6 +68,10 @@ export const networkTopNFlowQuery = gql`
|
|||
}
|
||||
hasNextPage
|
||||
}
|
||||
inspect @include(if: $inspect) {
|
||||
dsl
|
||||
response
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,14 +19,17 @@ import {
|
|||
NetworkTopNFlowSortField,
|
||||
PageInfo,
|
||||
} from '../../graphql/types';
|
||||
import { inputsModel, networkModel, networkSelectors, State } from '../../store';
|
||||
import { inputsModel, networkModel, networkSelectors, State, inputsSelectors } from '../../store';
|
||||
import { createFilter } from '../helpers';
|
||||
import { QueryTemplate, QueryTemplateProps } from '../query_template';
|
||||
|
||||
import { networkTopNFlowQuery } from './index.gql_query';
|
||||
|
||||
const ID = 'networkTopNFlowQuery';
|
||||
|
||||
export interface NetworkTopNFlowArgs {
|
||||
id: string;
|
||||
inspect: inputsModel.InspectQuery;
|
||||
networkTopNFlow: NetworkTopNFlowEdges[];
|
||||
totalCount: number;
|
||||
pageInfo: PageInfo;
|
||||
|
@ -41,6 +44,7 @@ export interface OwnProps extends QueryTemplateProps {
|
|||
}
|
||||
|
||||
export interface NetworkTopNFlowComponentReduxProps {
|
||||
isInspected: boolean;
|
||||
limit: number;
|
||||
flowDirection: FlowDirection;
|
||||
topNFlowSort: NetworkTopNFlowSortField;
|
||||
|
@ -56,7 +60,8 @@ class NetworkTopNFlowComponentQuery extends QueryTemplate<
|
|||
> {
|
||||
public render() {
|
||||
const {
|
||||
id = 'networkTopNFlowQuery',
|
||||
id = ID,
|
||||
isInspected,
|
||||
children,
|
||||
filterQuery,
|
||||
skip,
|
||||
|
@ -91,6 +96,7 @@ class NetworkTopNFlowComponentQuery extends QueryTemplate<
|
|||
},
|
||||
filterQuery: createFilter(filterQuery),
|
||||
defaultIndex: chrome.getUiSettingsClient().get(DEFAULT_INDEX_KEY),
|
||||
inspect: isInspected,
|
||||
}}
|
||||
>
|
||||
{({ data, loading, fetchMore, refetch }) => {
|
||||
|
@ -124,6 +130,7 @@ class NetworkTopNFlowComponentQuery extends QueryTemplate<
|
|||
}));
|
||||
return children({
|
||||
id,
|
||||
inspect: getOr(null, 'source.NetworkTopNFlow.inspect', data),
|
||||
refetch,
|
||||
loading,
|
||||
totalCount: getOr(0, 'source.NetworkTopNFlow.totalCount', data),
|
||||
|
@ -139,8 +146,14 @@ class NetworkTopNFlowComponentQuery extends QueryTemplate<
|
|||
|
||||
const makeMapStateToProps = () => {
|
||||
const getNetworkTopNFlowSelector = networkSelectors.topNFlowSelector();
|
||||
const mapStateToProps = (state: State) => getNetworkTopNFlowSelector(state);
|
||||
|
||||
const getQuery = inputsSelectors.globalQueryByIdSelector();
|
||||
const mapStateToProps = (state: State, { id = ID }: OwnProps) => {
|
||||
const { isInspected } = getQuery(state, id);
|
||||
return {
|
||||
...getNetworkTopNFlowSelector(state),
|
||||
isInspected,
|
||||
};
|
||||
};
|
||||
return mapStateToProps;
|
||||
};
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ export const overviewHostQuery = gql`
|
|||
$timerange: TimerangeInput!
|
||||
$filterQuery: String
|
||||
$defaultIndex: [String!]!
|
||||
$inspect: Boolean!
|
||||
) {
|
||||
source(id: $sourceId) {
|
||||
id
|
||||
|
@ -24,6 +25,10 @@ export const overviewHostQuery = gql`
|
|||
auditbeatUser
|
||||
filebeatSystemModule
|
||||
winlogbeat
|
||||
inspect @include(if: $inspect) {
|
||||
dsl
|
||||
response
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,24 +7,33 @@
|
|||
import { getOr } from 'lodash/fp';
|
||||
import React from 'react';
|
||||
import { Query } from 'react-apollo';
|
||||
import { connect } from 'react-redux';
|
||||
import { pure } from 'recompose';
|
||||
|
||||
import chrome from 'ui/chrome';
|
||||
import { DEFAULT_INDEX_KEY } from '../../../../common/constants';
|
||||
import { GetOverviewHostQuery, OverviewHostData } from '../../../graphql/types';
|
||||
import { inputsModel } from '../../../store/inputs';
|
||||
import { inputsModel, inputsSelectors } from '../../../store/inputs';
|
||||
import { State } from '../../../store';
|
||||
import { createFilter } from '../../helpers';
|
||||
import { QueryTemplateProps } from '../../query_template';
|
||||
|
||||
import { overviewHostQuery } from './index.gql_query';
|
||||
|
||||
export const ID = 'overviewHostQuery';
|
||||
|
||||
export interface OverviewHostArgs {
|
||||
id: string;
|
||||
overviewHost: OverviewHostData;
|
||||
inspect: inputsModel.InspectQuery;
|
||||
loading: boolean;
|
||||
overviewHost: OverviewHostData;
|
||||
refetch: inputsModel.Refetch;
|
||||
}
|
||||
|
||||
export interface OverviewHostReducer {
|
||||
isInspected: boolean;
|
||||
}
|
||||
|
||||
export interface OverviewHostProps extends QueryTemplateProps {
|
||||
children: (args: OverviewHostArgs) => React.ReactNode;
|
||||
sourceId: string;
|
||||
|
@ -32,8 +41,8 @@ export interface OverviewHostProps extends QueryTemplateProps {
|
|||
startDate: number;
|
||||
}
|
||||
|
||||
export const OverviewHostQuery = pure<OverviewHostProps>(
|
||||
({ id = 'overviewHostQuery', children, filterQuery, sourceId, startDate, endDate }) => (
|
||||
const OverviewHostComponentQuery = pure<OverviewHostProps & OverviewHostReducer>(
|
||||
({ id = ID, children, filterQuery, isInspected, sourceId, startDate, endDate }) => (
|
||||
<Query<GetOverviewHostQuery.Query, GetOverviewHostQuery.Variables>
|
||||
query={overviewHostQuery}
|
||||
fetchPolicy="cache-and-network"
|
||||
|
@ -46,12 +55,14 @@ export const OverviewHostQuery = pure<OverviewHostProps>(
|
|||
},
|
||||
filterQuery: createFilter(filterQuery),
|
||||
defaultIndex: chrome.getUiSettingsClient().get(DEFAULT_INDEX_KEY),
|
||||
inspect: isInspected,
|
||||
}}
|
||||
>
|
||||
{({ data, loading, refetch }) => {
|
||||
const overviewHost = getOr({}, `source.OverviewHost`, data);
|
||||
return children({
|
||||
id,
|
||||
inspect: getOr(null, 'source.OverviewHost.inspect', data),
|
||||
overviewHost,
|
||||
loading,
|
||||
refetch,
|
||||
|
@ -60,3 +71,16 @@ export const OverviewHostQuery = pure<OverviewHostProps>(
|
|||
</Query>
|
||||
)
|
||||
);
|
||||
|
||||
const makeMapStateToProps = () => {
|
||||
const getQuery = inputsSelectors.globalQueryByIdSelector();
|
||||
const mapStateToProps = (state: State, { id = ID }: OverviewHostProps) => {
|
||||
const { isInspected } = getQuery(state, id);
|
||||
return {
|
||||
isInspected,
|
||||
};
|
||||
};
|
||||
return mapStateToProps;
|
||||
};
|
||||
|
||||
export const OverviewHostQuery = connect(makeMapStateToProps)(OverviewHostComponentQuery);
|
||||
|
|
|
@ -12,6 +12,7 @@ export const overviewNetworkQuery = gql`
|
|||
$timerange: TimerangeInput!
|
||||
$filterQuery: String
|
||||
$defaultIndex: [String!]!
|
||||
$inspect: Boolean!
|
||||
) {
|
||||
source(id: $sourceId) {
|
||||
id
|
||||
|
@ -29,6 +30,10 @@ export const overviewNetworkQuery = gql`
|
|||
packetbeatDNS
|
||||
packetbeatFlow
|
||||
packetbeatTLS
|
||||
inspect @include(if: $inspect) {
|
||||
dsl
|
||||
response
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,24 +7,33 @@
|
|||
import { getOr } from 'lodash/fp';
|
||||
import React from 'react';
|
||||
import { Query } from 'react-apollo';
|
||||
import { connect } from 'react-redux';
|
||||
import { pure } from 'recompose';
|
||||
|
||||
import chrome from 'ui/chrome';
|
||||
import { DEFAULT_INDEX_KEY } from '../../../../common/constants';
|
||||
import { GetOverviewNetworkQuery, OverviewNetworkData } from '../../../graphql/types';
|
||||
import { inputsModel } from '../../../store/inputs';
|
||||
import { State } from '../../../store';
|
||||
import { inputsModel, inputsSelectors } from '../../../store/inputs';
|
||||
import { createFilter } from '../../helpers';
|
||||
import { QueryTemplateProps } from '../../query_template';
|
||||
|
||||
import { overviewNetworkQuery } from './index.gql_query';
|
||||
|
||||
export const ID = 'overviewNetworkQuery';
|
||||
|
||||
export interface OverviewNetworkArgs {
|
||||
id: string;
|
||||
inspect: inputsModel.InspectQuery;
|
||||
overviewNetwork: OverviewNetworkData;
|
||||
loading: boolean;
|
||||
refetch: inputsModel.Refetch;
|
||||
}
|
||||
|
||||
export interface OverviewNetworkReducer {
|
||||
isInspected: boolean;
|
||||
}
|
||||
|
||||
export interface OverviewNetworkProps extends QueryTemplateProps {
|
||||
children: (args: OverviewNetworkArgs) => React.ReactNode;
|
||||
sourceId: string;
|
||||
|
@ -32,8 +41,8 @@ export interface OverviewNetworkProps extends QueryTemplateProps {
|
|||
startDate: number;
|
||||
}
|
||||
|
||||
export const OverviewNetworkQuery = pure<OverviewNetworkProps>(
|
||||
({ id = 'overviewNetworkQuery', children, filterQuery, sourceId, startDate, endDate }) => (
|
||||
export const OverviewNetworkComponentQuery = pure<OverviewNetworkProps & OverviewNetworkReducer>(
|
||||
({ id = ID, children, filterQuery, isInspected, sourceId, startDate, endDate }) => (
|
||||
<Query<GetOverviewNetworkQuery.Query, GetOverviewNetworkQuery.Variables>
|
||||
query={overviewNetworkQuery}
|
||||
fetchPolicy="cache-and-network"
|
||||
|
@ -47,12 +56,14 @@ export const OverviewNetworkQuery = pure<OverviewNetworkProps>(
|
|||
},
|
||||
filterQuery: createFilter(filterQuery),
|
||||
defaultIndex: chrome.getUiSettingsClient().get(DEFAULT_INDEX_KEY),
|
||||
inspect: isInspected,
|
||||
}}
|
||||
>
|
||||
{({ data, loading, refetch }) => {
|
||||
const overviewNetwork = getOr({}, `source.OverviewNetwork`, data);
|
||||
return children({
|
||||
id,
|
||||
inspect: getOr(null, 'source.OverviewNetwork.inspect', data),
|
||||
overviewNetwork,
|
||||
loading,
|
||||
refetch,
|
||||
|
@ -61,3 +72,16 @@ export const OverviewNetworkQuery = pure<OverviewNetworkProps>(
|
|||
</Query>
|
||||
)
|
||||
);
|
||||
|
||||
const makeMapStateToProps = () => {
|
||||
const getQuery = inputsSelectors.globalQueryByIdSelector();
|
||||
const mapStateToProps = (state: State, { id = ID }: OverviewNetworkProps) => {
|
||||
const { isInspected } = getQuery(state, id);
|
||||
return {
|
||||
isInspected,
|
||||
};
|
||||
};
|
||||
return mapStateToProps;
|
||||
};
|
||||
|
||||
export const OverviewNetworkQuery = connect(makeMapStateToProps)(OverviewNetworkComponentQuery);
|
||||
|
|
|
@ -14,6 +14,7 @@ export const timelineQuery = gql`
|
|||
$sortField: SortField!
|
||||
$filterQuery: String
|
||||
$defaultIndex: [String!]!
|
||||
$inspect: Boolean!
|
||||
) {
|
||||
source(id: $sourceId) {
|
||||
id
|
||||
|
@ -25,6 +26,10 @@ export const timelineQuery = gql`
|
|||
defaultIndex: $defaultIndex
|
||||
) {
|
||||
totalCount
|
||||
inspect @include(if: $inspect) {
|
||||
dsl
|
||||
response
|
||||
}
|
||||
pageInfo {
|
||||
endCursor {
|
||||
value
|
||||
|
|
|
@ -10,6 +10,7 @@ import React from 'react';
|
|||
import { Query } from 'react-apollo';
|
||||
|
||||
import chrome from 'ui/chrome';
|
||||
import { connect } from 'react-redux';
|
||||
import { DEFAULT_INDEX_KEY } from '../../../common/constants';
|
||||
import {
|
||||
GetTimelineQuery,
|
||||
|
@ -18,7 +19,7 @@ import {
|
|||
TimelineEdges,
|
||||
TimelineItem,
|
||||
} from '../../graphql/types';
|
||||
import { inputsModel } from '../../store';
|
||||
import { inputsModel, State, inputsSelectors } from '../../store';
|
||||
import { createFilter } from '../helpers';
|
||||
import { QueryTemplate, QueryTemplateProps } from '../query_template';
|
||||
|
||||
|
@ -27,6 +28,7 @@ import { timelineQuery } from './index.gql_query';
|
|||
export interface TimelineArgs {
|
||||
events: TimelineItem[];
|
||||
id: string;
|
||||
inspect: inputsModel.InspectQuery;
|
||||
loading: boolean;
|
||||
loadMore: (cursor: string, tieBreaker: string) => void;
|
||||
pageInfo: PageInfo;
|
||||
|
@ -35,22 +37,28 @@ export interface TimelineArgs {
|
|||
getUpdatedAt: () => number;
|
||||
}
|
||||
|
||||
export interface TimelineQueryReduxProps {
|
||||
isInspected: boolean;
|
||||
}
|
||||
|
||||
export interface OwnProps extends QueryTemplateProps {
|
||||
children?: (args: TimelineArgs) => React.ReactNode;
|
||||
id: string;
|
||||
limit: number;
|
||||
sortField: SortField;
|
||||
fields: string[];
|
||||
}
|
||||
type TimelineQueryProps = OwnProps & TimelineQueryReduxProps;
|
||||
|
||||
export class TimelineQuery extends QueryTemplate<
|
||||
OwnProps,
|
||||
class TimelineQueryComponent extends QueryTemplate<
|
||||
TimelineQueryProps,
|
||||
GetTimelineQuery.Query,
|
||||
GetTimelineQuery.Variables
|
||||
> {
|
||||
private updatedDate: number = Date.now();
|
||||
private memoizedTimelineEvents: (variables: string, events: TimelineEdges[]) => TimelineItem[];
|
||||
|
||||
constructor(props: OwnProps) {
|
||||
constructor(props: TimelineQueryProps) {
|
||||
super(props);
|
||||
this.memoizedTimelineEvents = memoizeOne(this.getTimelineEvents);
|
||||
}
|
||||
|
@ -58,7 +66,8 @@ export class TimelineQuery extends QueryTemplate<
|
|||
public render() {
|
||||
const {
|
||||
children,
|
||||
id = 'timelineQuery',
|
||||
id,
|
||||
isInspected,
|
||||
limit,
|
||||
fields,
|
||||
filterQuery,
|
||||
|
@ -72,6 +81,7 @@ export class TimelineQuery extends QueryTemplate<
|
|||
pagination: { limit, cursor: null, tiebreaker: null },
|
||||
sortField,
|
||||
defaultIndex: chrome.getUiSettingsClient().get(DEFAULT_INDEX_KEY),
|
||||
inspect: isInspected,
|
||||
};
|
||||
return (
|
||||
<Query<GetTimelineQuery.Query, GetTimelineQuery.Variables>
|
||||
|
@ -113,6 +123,7 @@ export class TimelineQuery extends QueryTemplate<
|
|||
this.updatedDate = Date.now();
|
||||
return children!({
|
||||
id,
|
||||
inspect: getOr(null, 'source.Timeline.inspect', data),
|
||||
refetch,
|
||||
loading,
|
||||
totalCount: getOr(0, 'source.Timeline.totalCount', data),
|
||||
|
@ -131,3 +142,16 @@ export class TimelineQuery extends QueryTemplate<
|
|||
private getTimelineEvents = (variables: string, timelineEdges: TimelineEdges[]): TimelineItem[] =>
|
||||
timelineEdges.map((e: TimelineEdges) => e.node);
|
||||
}
|
||||
|
||||
const makeMapStateToProps = () => {
|
||||
const getQuery = inputsSelectors.timelineQueryByIdSelector();
|
||||
const mapStateToProps = (state: State, { id }: OwnProps) => {
|
||||
const { isInspected } = getQuery(state, id);
|
||||
return {
|
||||
isInspected,
|
||||
};
|
||||
};
|
||||
return mapStateToProps;
|
||||
};
|
||||
|
||||
export const TimelineQuery = connect(makeMapStateToProps)(TimelineQueryComponent);
|
||||
|
|
|
@ -16,6 +16,7 @@ export const tlsQuery = gql`
|
|||
$sort: TlsSortField!
|
||||
$timerange: TimerangeInput!
|
||||
$defaultIndex: [String!]!
|
||||
$inspect: Boolean!
|
||||
) {
|
||||
source(id: $sourceId) {
|
||||
id
|
||||
|
@ -48,6 +49,10 @@ export const tlsQuery = gql`
|
|||
}
|
||||
hasNextPage
|
||||
}
|
||||
inspect @include(if: $inspect) {
|
||||
dsl
|
||||
response
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,14 +12,17 @@ import { connect } from 'react-redux';
|
|||
import chrome from 'ui/chrome';
|
||||
import { DEFAULT_INDEX_KEY } from '../../../common/constants';
|
||||
import { FlowTarget, PageInfo, TlsEdges, TlsSortField, GetTlsQuery } from '../../graphql/types';
|
||||
import { inputsModel, networkModel, networkSelectors, State } from '../../store';
|
||||
import { inputsModel, networkModel, networkSelectors, State, inputsSelectors } from '../../store';
|
||||
import { createFilter } from '../helpers';
|
||||
import { QueryTemplate, QueryTemplateProps } from '../query_template';
|
||||
|
||||
import { tlsQuery } from './index.gql_query';
|
||||
|
||||
const ID = 'tlsQuery';
|
||||
|
||||
export interface TlsArgs {
|
||||
id: string;
|
||||
inspect: inputsModel.InspectQuery;
|
||||
tls: TlsEdges[];
|
||||
totalCount: number;
|
||||
pageInfo: PageInfo;
|
||||
|
@ -36,6 +39,7 @@ export interface OwnProps extends QueryTemplateProps {
|
|||
}
|
||||
|
||||
export interface TlsComponentReduxProps {
|
||||
isInspected: boolean;
|
||||
limit: number;
|
||||
tlsSortField: TlsSortField;
|
||||
}
|
||||
|
@ -45,7 +49,8 @@ type TlsProps = OwnProps & TlsComponentReduxProps;
|
|||
class TlsComponentQuery extends QueryTemplate<TlsProps, GetTlsQuery.Query, GetTlsQuery.Variables> {
|
||||
public render() {
|
||||
const {
|
||||
id = 'tlsQuery',
|
||||
id = ID,
|
||||
isInspected,
|
||||
children,
|
||||
tlsSortField,
|
||||
filterQuery,
|
||||
|
@ -80,6 +85,7 @@ class TlsComponentQuery extends QueryTemplate<TlsProps, GetTlsQuery.Query, GetTl
|
|||
},
|
||||
filterQuery: createFilter(filterQuery),
|
||||
defaultIndex: chrome.getUiSettingsClient().get(DEFAULT_INDEX_KEY),
|
||||
inspect: isInspected,
|
||||
}}
|
||||
>
|
||||
{({ data, loading, fetchMore, refetch }) => {
|
||||
|
@ -110,6 +116,7 @@ class TlsComponentQuery extends QueryTemplate<TlsProps, GetTlsQuery.Query, GetTl
|
|||
}));
|
||||
return children({
|
||||
id,
|
||||
inspect: getOr(null, 'source.Tls.inspect', data),
|
||||
refetch,
|
||||
loading,
|
||||
totalCount: getOr(0, 'source.Tls.totalCount', data),
|
||||
|
@ -125,9 +132,14 @@ class TlsComponentQuery extends QueryTemplate<TlsProps, GetTlsQuery.Query, GetTl
|
|||
|
||||
const makeMapStateToProps = () => {
|
||||
const getTlsSelector = networkSelectors.tlsSelector();
|
||||
const mapStateToProps = (state: State) => ({
|
||||
...getTlsSelector(state),
|
||||
});
|
||||
const getQuery = inputsSelectors.globalQueryByIdSelector();
|
||||
const mapStateToProps = (state: State, { id = ID }: OwnProps) => {
|
||||
const { isInspected } = getQuery(state, id);
|
||||
return {
|
||||
...getTlsSelector(state),
|
||||
isInspected,
|
||||
};
|
||||
};
|
||||
|
||||
return mapStateToProps;
|
||||
};
|
||||
|
|
|
@ -13,6 +13,7 @@ export const uncommonProcessesQuery = gql`
|
|||
$pagination: PaginationInput!
|
||||
$filterQuery: String
|
||||
$defaultIndex: [String!]!
|
||||
$inspect: Boolean!
|
||||
) {
|
||||
source(id: $sourceId) {
|
||||
id
|
||||
|
@ -49,6 +50,10 @@ export const uncommonProcessesQuery = gql`
|
|||
}
|
||||
hasNextPage
|
||||
}
|
||||
inspect @include(if: $inspect) {
|
||||
dsl
|
||||
response
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,12 +12,14 @@ import { connect } from 'react-redux';
|
|||
import chrome from 'ui/chrome';
|
||||
import { DEFAULT_INDEX_KEY } from '../../../common/constants';
|
||||
import { GetUncommonProcessesQuery, PageInfo, UncommonProcessesEdges } from '../../graphql/types';
|
||||
import { hostsModel, hostsSelectors, inputsModel, State } from '../../store';
|
||||
import { hostsModel, hostsSelectors, inputsModel, State, inputsSelectors } from '../../store';
|
||||
import { createFilter, getDefaultFetchPolicy } from '../helpers';
|
||||
import { QueryTemplate, QueryTemplateProps } from '../query_template';
|
||||
|
||||
import { uncommonProcessesQuery } from './index.gql_query';
|
||||
|
||||
const ID = 'uncommonProcessesQuery';
|
||||
|
||||
export interface UncommonProcessesArgs {
|
||||
id: string;
|
||||
uncommonProcesses: UncommonProcessesEdges[];
|
||||
|
@ -26,6 +28,7 @@ export interface UncommonProcessesArgs {
|
|||
loading: boolean;
|
||||
loadMore: (cursor: string) => void;
|
||||
refetch: inputsModel.Refetch;
|
||||
inspect: inputsModel.InspectQuery;
|
||||
}
|
||||
|
||||
export interface OwnProps extends QueryTemplateProps {
|
||||
|
@ -34,6 +37,7 @@ export interface OwnProps extends QueryTemplateProps {
|
|||
}
|
||||
|
||||
export interface UncommonProcessesComponentReduxProps {
|
||||
isInspected: boolean;
|
||||
limit: number;
|
||||
}
|
||||
|
||||
|
@ -46,9 +50,10 @@ class UncommonProcessesComponentQuery extends QueryTemplate<
|
|||
> {
|
||||
public render() {
|
||||
const {
|
||||
id = 'uncommonProcessesQuery',
|
||||
id = ID,
|
||||
children,
|
||||
filterQuery,
|
||||
isInspected,
|
||||
skip,
|
||||
sourceId,
|
||||
startDate,
|
||||
|
@ -75,6 +80,7 @@ class UncommonProcessesComponentQuery extends QueryTemplate<
|
|||
},
|
||||
filterQuery: createFilter(filterQuery),
|
||||
defaultIndex: chrome.getUiSettingsClient().get(DEFAULT_INDEX_KEY),
|
||||
inspect: isInspected,
|
||||
}}
|
||||
>
|
||||
{({ data, loading, fetchMore, refetch }) => {
|
||||
|
@ -108,6 +114,7 @@ class UncommonProcessesComponentQuery extends QueryTemplate<
|
|||
}));
|
||||
return children({
|
||||
id,
|
||||
inspect: getOr(null, 'source.UncommonProcesses.inspect', data),
|
||||
loading,
|
||||
refetch,
|
||||
totalCount: getOr(0, 'source.UncommonProcesses.totalCount', data),
|
||||
|
@ -123,8 +130,13 @@ class UncommonProcessesComponentQuery extends QueryTemplate<
|
|||
|
||||
const makeMapStateToProps = () => {
|
||||
const getUncommonProcessesSelector = hostsSelectors.uncommonProcessesSelector();
|
||||
const mapStateToProps = (state: State, { type }: OwnProps) => {
|
||||
return getUncommonProcessesSelector(state, type);
|
||||
const getQuery = inputsSelectors.globalQueryByIdSelector();
|
||||
const mapStateToProps = (state: State, { type, id = ID }: OwnProps) => {
|
||||
const { isInspected } = getQuery(state, id);
|
||||
return {
|
||||
...getUncommonProcessesSelector(state, type),
|
||||
isInspected,
|
||||
};
|
||||
};
|
||||
return mapStateToProps;
|
||||
};
|
||||
|
|
|
@ -16,6 +16,7 @@ export const usersQuery = gql`
|
|||
$sort: UsersSortField!
|
||||
$timerange: TimerangeInput!
|
||||
$defaultIndex: [String!]!
|
||||
$inspect: Boolean!
|
||||
) {
|
||||
source(id: $sourceId) {
|
||||
id
|
||||
|
@ -49,6 +50,10 @@ export const usersQuery = gql`
|
|||
}
|
||||
hasNextPage
|
||||
}
|
||||
inspect @include(if: $inspect) {
|
||||
dsl
|
||||
response
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
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