Revert "[7.x][SIEM] apollo@3 (#51926)" (#59637)

* Revert "[SIEM] apollo@3 (#51926)"

* cleanup
This commit is contained in:
patrykkopycinski 2020-03-09 12:17:25 -07:00 committed by GitHub
parent 8e4a3b5447
commit 9d5582bcc4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
227 changed files with 55232 additions and 12568 deletions

View file

@ -75,31 +75,23 @@
"url": "https://github.com/elastic/kibana.git"
},
"resolutions": {
"**/@apollo/client": "^3.0.0-beta.37",
"**/@graphql-toolkit/common": "^0.9.7",
"**/@graphql-toolkit/core": "^0.9.7",
"**/@graphql-toolkit/graphql-file-loader": "^0.9.7",
"**/@graphql-toolkit/json-file-loader": "^0.9.7",
"**/@graphql-toolkit/schema-merging": "^0.9.7",
"**/@graphql-toolkit/url-loader": "^0.9.7",
"**/@types/node": "10.12.27",
"**/@types/react": "^16.9.19",
"**/@types/react-router": "^5.1.3",
"**/@types/hapi": "^17.0.18",
"**/@types/angular": "^1.6.56",
"**/@types/hoist-non-react-statics": "^3.3.1",
"**/apollo-link": "^1.2.13",
"**/deepmerge": "^4.2.2",
"**/fast-deep-equal": "^3.1.1",
"**/fast-glob": "3.1.1",
"**/typescript": "3.7.2",
"**/graphql-toolkit/lodash": "^4.17.13",
"**/hoist-non-react-statics": "^3.3.2",
"**/isomorphic-git/**/base64-js": "^1.2.1",
"**/image-diff/gm/debug": "^2.6.9",
"**/react-dom": "^16.12.0",
"**/react": "^16.12.0",
"**/react-test-renderer": "^16.12.0",
"**/deepmerge": "^4.2.2",
"**/serialize-javascript": "^2.1.1",
"**/typescript": "3.7.2"
"**/fast-deep-equal": "^3.1.1"
},
"workspaces": {
"packages": [
@ -329,6 +321,7 @@
"@types/getos": "^3.0.0",
"@types/glob": "^7.1.1",
"@types/globby": "^8.0.0",
"@types/graphql": "^0.13.2",
"@types/hapi": "^17.0.18",
"@types/hapi-auth-cookie": "^9.1.0",
"@types/has-ansi": "^3.0.0",

View file

@ -38,6 +38,7 @@ beforeAll(async () => {
await cpy('**/*', MOCK_REPO_DIR, {
cwd: MOCK_REPO_SRC,
parents: true,
deep: true,
});
});

View file

@ -44,6 +44,7 @@ beforeEach(async () => {
await cpy('**/*', MOCK_REPO_DIR, {
cwd: MOCK_REPO_SRC,
parents: true,
deep: true,
});
});

View file

@ -216,7 +216,7 @@ export function getWebpackConfig(bundle: Bundle, worker: WorkerConfig) {
},
resolve: {
extensions: ['.mjs', '.js', '.ts', '.tsx', '.json'],
extensions: ['.js', '.ts', '.tsx', '.json'],
alias: {
tinymath: require.resolve('tinymath/lib/tinymath.es5.js'),
},

File diff suppressed because one or more lines are too long

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { gql } from '@apollo/client';
import gql from 'graphql-tag';
export const rootSchema = gql`
schema {

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { gql } from '@apollo/client';
import gql from 'graphql-tag';
export const sharedSchema = gql`
input TimerangeInput {

View file

@ -6,7 +6,7 @@
import { createHashHistory, History } from 'history';
import React, { memo, useMemo, FC } from 'react';
import { ApolloProvider } from '@apollo/client';
import { ApolloProvider } from 'react-apollo';
import { Store } from 'redux';
import { Provider as ReduxStoreProvider } from 'react-redux';
import { ThemeProvider } from 'styled-components';
@ -30,6 +30,8 @@ import { createStore, createInitialState } from '../store';
import { GlobalToaster, ManageGlobalToaster } from '../components/toasters';
import { MlCapabilitiesProvider } from '../components/ml/permissions/ml_capabilities_provider';
import { ApolloClientContext } from '../utils/apollo_context';
interface AppPluginRootComponentProps {
apolloClient: AppApolloClient;
history: History;
@ -46,13 +48,15 @@ const AppPluginRootComponent: React.FC<AppPluginRootComponentProps> = ({
<ManageGlobalToaster>
<ReduxStoreProvider store={store}>
<ApolloProvider client={apolloClient}>
<ThemeProvider theme={theme}>
<MlCapabilitiesProvider>
<PageRouter history={history} />
</MlCapabilitiesProvider>
</ThemeProvider>
<ErrorToastDispatcher />
<GlobalToaster />
<ApolloClientContext.Provider value={apolloClient}>
<ThemeProvider theme={theme}>
<MlCapabilitiesProvider>
<PageRouter history={history} />
</MlCapabilitiesProvider>
</ThemeProvider>
<ErrorToastDispatcher />
<GlobalToaster />
</ApolloClientContext.Provider>
</ApolloProvider>
</ReduxStoreProvider>
</ManageGlobalToaster>

View file

@ -6,7 +6,7 @@
import { mount, shallow } from 'enzyme';
import React from 'react';
import { MockedProvider } from '@apollo/client/testing';
import { MockedProvider } from 'react-apollo/test-utils';
import { mockBrowserFields, mocksSource } from '../../containers/source/mock';
import { TestProviders } from '../../mock';
@ -20,7 +20,7 @@ describe('DragDropContextWrapper', () => {
const wrapper = shallow(
<TestProviders>
<MockedProvider mocks={[]} addTypename={false}>
<MockedProvider mocks={{}} addTypename={false}>
<DragDropContextWrapper browserFields={mockBrowserFields}>
{message}
</DragDropContextWrapper>

View file

@ -6,7 +6,7 @@
import { shallow } from 'enzyme';
import React from 'react';
import { MockedProvider } from '@apollo/client/testing';
import { MockedProvider } from 'react-apollo/test-utils';
import { mockBrowserFields, mocksSource } from '../../containers/source/mock';
import { TestProviders } from '../../mock';
@ -24,7 +24,7 @@ describe('DraggableWrapper', () => {
test('it renders against the snapshot', () => {
const wrapper = shallow(
<TestProviders>
<MockedProvider mocks={[]} addTypename={false}>
<MockedProvider mocks={{}} addTypename={false}>
<DragDropContextWrapper browserFields={mockBrowserFields}>
<DraggableWrapper dataProvider={dataProvider} render={() => message} />
</DragDropContextWrapper>

View file

@ -6,7 +6,7 @@
import { shallow } from 'enzyme';
import React from 'react';
import { MockedProvider } from '@apollo/client/testing';
import { MockedProvider } from 'react-apollo/test-utils';
import { mockBrowserFields, mocksSource } from '../../containers/source/mock';
import { TestProviders } from '../../mock';
@ -24,7 +24,7 @@ describe('DroppableWrapper', () => {
const wrapper = shallow(
<TestProviders>
<MockedProvider mocks={[]} addTypename={false}>
<MockedProvider mocks={{}} addTypename={false}>
<DragDropContextWrapper browserFields={mockBrowserFields}>
<DroppableWrapper droppableId="testing">{message}</DroppableWrapper>
</DragDropContextWrapper>

View file

@ -20,7 +20,7 @@ import { Draggable } from 'react-beautiful-dnd';
import styled from 'styled-components';
import { BrowserFields } from '../../containers/source';
import { Scalars } from '../../graphql/types';
import { ToStringArray } from '../../graphql/types';
import { WithCopyToClipboard } from '../../lib/clipboard/with_copy_to_clipboard';
import { ColumnHeaderOptions } from '../../store/timeline/model';
import { DragEffects } from '../drag_and_drop/draggable_wrapper';
@ -159,7 +159,7 @@ export const getColumns = ({
name: i18n.VALUE,
sortable: true,
truncateText: false,
render: (values: Scalars['ToStringArray'] | null | undefined, data: EventFieldsData) => (
render: (values: ToStringArray | null | undefined, data: EventFieldsData) => (
<EuiFlexGroup direction="column" alignItems="flexStart" component="span" gutterSize="none">
{values != null &&
values.map((value, i) => (

View file

@ -12,7 +12,7 @@ import {
DEFAULT_DATE_COLUMN_MIN_WIDTH,
DEFAULT_COLUMN_MIN_WIDTH,
} from '../timeline/body/constants';
import { Scalars } from '../../graphql/types';
import { ToStringArray } from '../../graphql/types';
import * as i18n from './translations';
@ -40,7 +40,7 @@ export interface Item {
field: JSX.Element;
fieldId: string;
type: string;
values: Scalars['ToStringArray'];
values: ToStringArray;
}
export const getColumnHeaderFromBrowserField = ({

View file

@ -5,8 +5,7 @@
*/
import React from 'react';
import { MockedProvider } from '@apollo/client/testing';
import { act } from '@testing-library/react';
import { MockedProvider } from 'react-apollo/test-utils';
import useResizeObserver from 'use-resize-observer/polyfilled';
import { mockIndexPattern, TestProviders } from '../../mock';
@ -53,7 +52,7 @@ describe('EventsViewer', () => {
</TestProviders>
);
await act(() => wait());
await wait();
wrapper.update();
expect(
@ -78,7 +77,7 @@ describe('EventsViewer', () => {
</TestProviders>
);
await act(() => wait());
await wait();
wrapper.update();
expect(
@ -103,7 +102,7 @@ describe('EventsViewer', () => {
</TestProviders>
);
await act(() => wait());
await wait();
wrapper.update();
expect(
@ -129,7 +128,7 @@ describe('EventsViewer', () => {
</TestProviders>
);
await act(() => wait());
await wait();
wrapper.update();
defaultHeaders.forEach(h =>

View file

@ -201,6 +201,7 @@ const EventsViewerComponent: React.FC<Props> = ({
getUpdatedAt={getUpdatedAt}
hasNextPage={getOr(false, 'hasNextPage', pageInfo)!}
height={footerHeight}
isEventViewer={true}
isLive={isLive}
isLoading={loading}
itemsCount={events.length}
@ -242,7 +243,7 @@ export const EventsViewer = React.memo(
prevProps.kqlMode === nextProps.kqlMode &&
deepEqual(prevProps.query, nextProps.query) &&
prevProps.start === nextProps.start &&
deepEqual(prevProps.sort, nextProps.sort) &&
prevProps.sort === nextProps.sort &&
deepEqual(prevProps.timelineTypeContext, nextProps.timelineTypeContext) &&
prevProps.utilityBar === nextProps.utilityBar
);

View file

@ -5,8 +5,7 @@
*/
import React from 'react';
import { MockedProvider } from '@apollo/client/testing';
import { act } from '@testing-library/react';
import { MockedProvider } from 'react-apollo/test-utils';
import useResizeObserver from 'use-resize-observer/polyfilled';
import { wait } from '../../lib/helpers';
@ -52,7 +51,7 @@ describe('StatefulEventsViewer', () => {
</TestProviders>
);
await act(() => wait());
await wait();
wrapper.update();
expect(
@ -78,7 +77,7 @@ describe('StatefulEventsViewer', () => {
</TestProviders>
);
await act(() => wait());
await wait();
wrapper.update();
expect(wrapper.find(`InspectButtonContainer`).exists()).toBe(true);

View file

@ -9,7 +9,6 @@ import { defaultTo, getOr } from 'lodash/fp';
import React, { useCallback } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import styled from 'styled-components';
import deepEqual from 'fast-deep-equal';
import { State, timelineSelectors } from '../../store';
import { DataProvider } from '../timeline/data_providers/data_provider';
@ -91,17 +90,7 @@ export const FlyoutComponent = React.memo<Props>(
/>
</>
);
},
(prevProps, nextProps) =>
prevProps.children === nextProps.children &&
deepEqual(prevProps.dataProviders, nextProps.dataProviders) &&
prevProps.flyoutHeight === nextProps.flyoutHeight &&
prevProps.headerHeight === nextProps.headerHeight &&
prevProps.show === nextProps.show &&
prevProps.showTimeline === nextProps.showTimeline &&
prevProps.timelineId === nextProps.timelineId &&
prevProps.usersViewing === nextProps.usersViewing &&
prevProps.width === nextProps.width
}
);
FlyoutComponent.displayName = 'FlyoutComponent';

View file

@ -9,106 +9,11 @@ exports[`HeaderGlobal it renders 1`] = `
justifyContent="spaceBetween"
wrap={true}
>
<FlexItem>
<EuiFlexGroup
alignItems="center"
responsive={false}
>
<FlexItem
grow={false}
>
<EuiLink
href="#/link-to/overview"
>
<EuiIcon
aria-label="SIEM"
size="l"
type="securityAnalyticsApp"
/>
</EuiLink>
</FlexItem>
<FlexItem
component="nav"
>
<SiemNavigationContainer
display="condensed"
navTabs={
Object {
"case": Object {
"disabled": false,
"href": "#/link-to/case",
"id": "case",
"name": "Cases",
"urlKey": "case",
},
"detections": Object {
"disabled": false,
"href": "#/link-to/detections",
"id": "detections",
"name": "Detections",
"urlKey": "detections",
},
"hosts": Object {
"disabled": false,
"href": "#/link-to/hosts",
"id": "hosts",
"name": "Hosts",
"urlKey": "host",
},
"network": Object {
"disabled": false,
"href": "#/link-to/network",
"id": "network",
"name": "Network",
"urlKey": "network",
},
"overview": Object {
"disabled": false,
"href": "#/link-to/overview",
"id": "overview",
"name": "Overview",
"urlKey": "overview",
},
"timelines": Object {
"disabled": false,
"href": "#/link-to/timelines",
"id": "timelines",
"name": "Timelines",
"urlKey": "timeline",
},
}
}
/>
</FlexItem>
</EuiFlexGroup>
</FlexItem>
<FlexItem
grow={false}
<WithSource
sourceId="default"
>
<EuiFlexGroup
alignItems="center"
gutterSize="s"
responsive={false}
wrap={true}
>
<FlexItem
grow={false}
>
<MlPopover />
</FlexItem>
<FlexItem
grow={false}
>
<EuiButtonEmpty
data-test-subj="add-data"
href="kibana#home/tutorial_directory/siem"
iconType="plusInCircle"
>
Add data
</EuiButtonEmpty>
</FlexItem>
</EuiFlexGroup>
</FlexItem>
<Component />
</WithSource>
</EuiFlexGroup>
</Wrapper>
`;

View file

@ -17,15 +17,10 @@ jest.mock('ui/new_platform');
jest.mock('../search_bar', () => ({
SiemSearchBar: () => null,
}));
jest.mock('../../containers/source', () => ({
useWithSource: () => ({
contentAvailable: true,
}),
}));
describe('HeaderGlobal', () => {
test('it renders', () => {
const wrapper = shallow(<HeaderGlobal contentAvailable />);
const wrapper = shallow(<HeaderGlobal />);
expect(wrapper).toMatchSnapshot();
});

View file

@ -16,6 +16,7 @@ import { getOverviewUrl } from '../link_to';
import { MlPopover } from '../ml_popover/ml_popover';
import { SiemNavigation } from '../navigation';
import * as i18n from './translations';
import { indicesExistOrDataTemporarilyUnavailable, WithSource } from '../../containers/source';
const Wrapper = styled.header`
${({ theme }) => css`
@ -33,64 +34,65 @@ const FlexItem = styled(EuiFlexItem)`
FlexItem.displayName = 'FlexItem';
interface HeaderGlobalProps {
contentAvailable: boolean;
hideDetectionEngine?: boolean;
}
export const HeaderGlobal = React.memo<HeaderGlobalProps>(
({ contentAvailable, hideDetectionEngine = false }) => (
<Wrapper className="siemHeaderGlobal">
<EuiFlexGroup alignItems="center" justifyContent="spaceBetween" wrap>
<>
<FlexItem>
<EuiFlexGroup alignItems="center" responsive={false}>
<FlexItem grow={false}>
<EuiLink href={getOverviewUrl()}>
<EuiIcon aria-label={i18n.SIEM} type="securityAnalyticsApp" size="l" />
</EuiLink>
</FlexItem>
<FlexItem component="nav">
{contentAvailable ? (
<SiemNavigation
display="condensed"
navTabs={
hideDetectionEngine
? pickBy((_, key) => key !== SiemPageName.detections, navTabs)
: navTabs
}
/>
) : (
<SiemNavigation
display="condensed"
navTabs={pickBy((_, key) => key === SiemPageName.overview, navTabs)}
/>
)}
</FlexItem>
</EuiFlexGroup>
</FlexItem>
<FlexItem grow={false}>
<EuiFlexGroup alignItems="center" gutterSize="s" responsive={false} wrap>
{contentAvailable && (
export const HeaderGlobal = React.memo<HeaderGlobalProps>(({ hideDetectionEngine = false }) => (
<Wrapper className="siemHeaderGlobal">
<EuiFlexGroup alignItems="center" justifyContent="spaceBetween" wrap>
<WithSource sourceId="default">
{({ indicesExist }) => (
<>
<FlexItem>
<EuiFlexGroup alignItems="center" responsive={false}>
<FlexItem grow={false}>
<MlPopover />
<EuiLink href={getOverviewUrl()}>
<EuiIcon aria-label={i18n.SIEM} type="securityAnalyticsApp" size="l" />
</EuiLink>
</FlexItem>
)}
<FlexItem grow={false}>
<EuiButtonEmpty
data-test-subj="add-data"
href="kibana#home/tutorial_directory/siem"
iconType="plusInCircle"
>
{i18n.BUTTON_ADD_DATA}
</EuiButtonEmpty>
</FlexItem>
</EuiFlexGroup>
</FlexItem>
</>
</EuiFlexGroup>
</Wrapper>
)
);
<FlexItem component="nav">
{indicesExistOrDataTemporarilyUnavailable(indicesExist) ? (
<SiemNavigation
display="condensed"
navTabs={
hideDetectionEngine
? pickBy((_, key) => key !== SiemPageName.detections, navTabs)
: navTabs
}
/>
) : (
<SiemNavigation
display="condensed"
navTabs={pickBy((_, key) => key === SiemPageName.overview, navTabs)}
/>
)}
</FlexItem>
</EuiFlexGroup>
</FlexItem>
<FlexItem grow={false}>
<EuiFlexGroup alignItems="center" gutterSize="s" responsive={false} wrap>
{indicesExistOrDataTemporarilyUnavailable(indicesExist) && (
<FlexItem grow={false}>
<MlPopover />
</FlexItem>
)}
<FlexItem grow={false}>
<EuiButtonEmpty
data-test-subj="add-data"
href="kibana#home/tutorial_directory/siem"
iconType="plusInCircle"
>
{i18n.BUTTON_ADD_DATA}
</EuiButtonEmpty>
</FlexItem>
</EuiFlexGroup>
</FlexItem>
</>
)}
</WithSource>
</EuiFlexGroup>
</Wrapper>
));
HeaderGlobal.displayName = 'HeaderGlobal';

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { ApolloClient } from '@apollo/client';
import ApolloClient from 'apollo-client';
import { getOr, set } from 'lodash/fp';
import { Action } from 'typescript-fsa';

View file

@ -6,15 +6,14 @@
import euiDarkVars from '@elastic/eui/dist/eui_theme_dark.json';
import { mount } from 'enzyme';
import { MockedProvider } from '@apollo/client/testing';
import { MockedProvider } from 'react-apollo/test-utils';
import React from 'react';
import { ThemeProvider } from 'styled-components';
import { act } from '@testing-library/react';
import { wait } from '../../lib/helpers';
import { TestProviderWithoutDragAndDrop } from '../../mock/test_providers';
import { mockOpenTimelineQueryResults, MockedProvidedQuery } from '../../mock/timeline_results';
import { DEFAULT_SEARCH_RESULTS_PER_PAGE } from '../../pages/timelines';
import { TestProviderWithoutDragAndDrop, apolloClient } from '../../mock/test_providers';
import { mockOpenTimelineQueryResults } from '../../mock/timeline_results';
import { DEFAULT_SEARCH_RESULTS_PER_PAGE } from '../../pages/timelines/timelines_page';
import { StatefulOpenTimeline } from '.';
import { NotePreviews } from './note_previews';
@ -25,19 +24,15 @@ jest.mock('../../lib/kibana');
describe('StatefulOpenTimeline', () => {
const theme = () => ({ eui: euiDarkVars, darkMode: true });
const title = 'All Timelines / Open Timelines';
let mocks: MockedProvidedQuery[];
beforeEach(() => {
mocks = mockOpenTimelineQueryResults;
});
test('it has the expected initial state', () => {
const wrapper = mount(
<ThemeProvider theme={theme}>
<TestProviderWithoutDragAndDrop>
<MockedProvider mocks={mocks} addTypename={false}>
<MockedProvider mocks={mockOpenTimelineQueryResults} addTypename={false}>
<StatefulOpenTimeline
data-test-subj="stateful-timeline"
apolloClient={apolloClient}
isModal={false}
defaultPageSize={DEFAULT_SEARCH_RESULTS_PER_PAGE}
title={title}
@ -66,13 +61,14 @@ describe('StatefulOpenTimeline', () => {
});
describe('#onQueryChange', () => {
test('it updates the query state with the expected trimmed value when the user enters a query', async () => {
test('it updates the query state with the expected trimmed value when the user enters a query', () => {
const wrapper = mount(
<ThemeProvider theme={theme}>
<TestProviderWithoutDragAndDrop>
<MockedProvider mocks={mocks} addTypename={false}>
<MockedProvider mocks={mockOpenTimelineQueryResults} addTypename={false}>
<StatefulOpenTimeline
data-test-subj="stateful-timeline"
apolloClient={apolloClient}
isModal={false}
defaultPageSize={DEFAULT_SEARCH_RESULTS_PER_PAGE}
title={title}
@ -81,11 +77,9 @@ describe('StatefulOpenTimeline', () => {
</TestProviderWithoutDragAndDrop>
</ThemeProvider>
);
wrapper
.find('[data-test-subj="search-bar"] input')
.simulate('keyup', { keyCode: 13, target: { value: ' abcd ' } });
expect(
wrapper
.find('[data-test-subj="search-row"]')
@ -98,8 +92,9 @@ describe('StatefulOpenTimeline', () => {
const wrapper = mount(
<ThemeProvider theme={theme}>
<TestProviderWithoutDragAndDrop>
<MockedProvider mocks={mocks} addTypename={false}>
<MockedProvider mocks={mockOpenTimelineQueryResults} addTypename={false}>
<StatefulOpenTimeline
apolloClient={apolloClient}
isModal={false}
defaultPageSize={DEFAULT_SEARCH_RESULTS_PER_PAGE}
title={title}
@ -109,7 +104,7 @@ describe('StatefulOpenTimeline', () => {
</ThemeProvider>
);
await act(() => wait());
await wait();
wrapper
.find('[data-test-subj="search-bar"] input')
@ -127,8 +122,9 @@ describe('StatefulOpenTimeline', () => {
const wrapper = mount(
<ThemeProvider theme={theme}>
<TestProviderWithoutDragAndDrop>
<MockedProvider mocks={mocks} addTypename={false}>
<MockedProvider mocks={mockOpenTimelineQueryResults} addTypename={false}>
<StatefulOpenTimeline
apolloClient={apolloClient}
isModal={false}
defaultPageSize={DEFAULT_SEARCH_RESULTS_PER_PAGE}
title={title}
@ -138,7 +134,7 @@ describe('StatefulOpenTimeline', () => {
</ThemeProvider>
);
await act(() => wait());
await wait();
wrapper
.find('[data-test-subj="search-bar"] input')
@ -158,8 +154,9 @@ describe('StatefulOpenTimeline', () => {
const wrapper = mount(
<ThemeProvider theme={theme}>
<TestProviderWithoutDragAndDrop>
<MockedProvider mocks={mocks} addTypename={false}>
<MockedProvider mocks={mockOpenTimelineQueryResults} addTypename={false}>
<StatefulOpenTimeline
apolloClient={apolloClient}
isModal={false}
defaultPageSize={DEFAULT_SEARCH_RESULTS_PER_PAGE}
title={title}
@ -169,7 +166,7 @@ describe('StatefulOpenTimeline', () => {
</ThemeProvider>
);
await act(() => wait());
await wait();
expect(
wrapper
@ -188,8 +185,9 @@ describe('StatefulOpenTimeline', () => {
const wrapper = mount(
<ThemeProvider theme={theme}>
<TestProviderWithoutDragAndDrop>
<MockedProvider mocks={mocks} addTypename={false}>
<MockedProvider mocks={mockOpenTimelineQueryResults} addTypename={false}>
<StatefulOpenTimeline
apolloClient={apolloClient}
isModal={false}
defaultPageSize={DEFAULT_SEARCH_RESULTS_PER_PAGE}
title={title}
@ -199,7 +197,7 @@ describe('StatefulOpenTimeline', () => {
</ThemeProvider>
);
await act(() => wait());
await wait();
wrapper
.find('.euiCheckbox__input')
@ -233,8 +231,9 @@ describe('StatefulOpenTimeline', () => {
const wrapper = mount(
<ThemeProvider theme={theme}>
<TestProviderWithoutDragAndDrop>
<MockedProvider mocks={mocks} addTypename={false}>
<MockedProvider mocks={mockOpenTimelineQueryResults} addTypename={false}>
<StatefulOpenTimeline
apolloClient={apolloClient}
isModal={false}
defaultPageSize={DEFAULT_SEARCH_RESULTS_PER_PAGE}
title={title}
@ -244,7 +243,7 @@ describe('StatefulOpenTimeline', () => {
</ThemeProvider>
);
await act(() => wait());
await wait();
wrapper
.find('.euiCheckbox__input')
@ -275,9 +274,10 @@ describe('StatefulOpenTimeline', () => {
const wrapper = mount(
<ThemeProvider theme={theme}>
<TestProviderWithoutDragAndDrop>
<MockedProvider mocks={mocks} addTypename={false}>
<MockedProvider mocks={mockOpenTimelineQueryResults} addTypename={false}>
<StatefulOpenTimeline
data-test-subj="stateful-timeline"
apolloClient={apolloClient}
isModal={false}
defaultPageSize={DEFAULT_SEARCH_RESULTS_PER_PAGE}
title={title}
@ -287,7 +287,7 @@ describe('StatefulOpenTimeline', () => {
</ThemeProvider>
);
await act(() => wait());
await wait();
wrapper
.find('.euiCheckbox__input')
@ -308,9 +308,10 @@ describe('StatefulOpenTimeline', () => {
const wrapper = mount(
<ThemeProvider theme={theme}>
<TestProviderWithoutDragAndDrop>
<MockedProvider mocks={mocks} addTypename={false}>
<MockedProvider mocks={mockOpenTimelineQueryResults} addTypename={false}>
<StatefulOpenTimeline
data-test-subj="stateful-timeline"
apolloClient={apolloClient}
isModal={false}
defaultPageSize={DEFAULT_SEARCH_RESULTS_PER_PAGE}
title={title}
@ -346,9 +347,10 @@ describe('StatefulOpenTimeline', () => {
const wrapper = mount(
<ThemeProvider theme={theme}>
<TestProviderWithoutDragAndDrop>
<MockedProvider mocks={mocks} addTypename={false}>
<MockedProvider mocks={mockOpenTimelineQueryResults} addTypename={false}>
<StatefulOpenTimeline
data-test-subj="stateful-timeline"
apolloClient={apolloClient}
isModal={false}
defaultPageSize={DEFAULT_SEARCH_RESULTS_PER_PAGE}
title={title}
@ -384,9 +386,10 @@ describe('StatefulOpenTimeline', () => {
const wrapper = mount(
<ThemeProvider theme={theme}>
<TestProviderWithoutDragAndDrop>
<MockedProvider mocks={mocks} addTypename={false}>
<MockedProvider mocks={mockOpenTimelineQueryResults} addTypename={false}>
<StatefulOpenTimeline
data-test-subj="stateful-timeline"
apolloClient={apolloClient}
isModal={false}
defaultPageSize={DEFAULT_SEARCH_RESULTS_PER_PAGE}
title={title}
@ -396,7 +399,7 @@ describe('StatefulOpenTimeline', () => {
</ThemeProvider>
);
await act(() => wait());
await wait();
wrapper.update();
expect(
@ -420,11 +423,10 @@ describe('StatefulOpenTimeline', () => {
'10849df0-7b44-11e9-a608-ab3d811609': (
<NotePreviews
notes={
mocks[0].result.data!.getAllTimeline.timeline[0].notes != null
? mocks[0].result.data!.getAllTimeline.timeline[0].notes.map(note => ({
...note,
savedObjectId: note.noteId,
}))
mockOpenTimelineQueryResults[0].result.data!.getAllTimeline.timeline[0].notes != null
? mockOpenTimelineQueryResults[0].result.data!.getAllTimeline.timeline[0].notes.map(
note => ({ ...note, savedObjectId: note.noteId })
)
: []
}
/>
@ -436,9 +438,10 @@ describe('StatefulOpenTimeline', () => {
const wrapper = mount(
<ThemeProvider theme={theme}>
<TestProviderWithoutDragAndDrop>
<MockedProvider mocks={mocks} addTypename={false}>
<MockedProvider mocks={mockOpenTimelineQueryResults} addTypename={false}>
<StatefulOpenTimeline
data-test-subj="stateful-timeline"
apolloClient={apolloClient}
isModal={false}
defaultPageSize={DEFAULT_SEARCH_RESULTS_PER_PAGE}
title={title}
@ -448,7 +451,7 @@ describe('StatefulOpenTimeline', () => {
</ThemeProvider>
);
await act(() => wait());
await wait();
wrapper.update();
@ -471,9 +474,10 @@ describe('StatefulOpenTimeline', () => {
const wrapper = mount(
<ThemeProvider theme={theme}>
<TestProviderWithoutDragAndDrop>
<MockedProvider mocks={mocks} addTypename={false}>
<MockedProvider mocks={mockOpenTimelineQueryResults} addTypename={false}>
<StatefulOpenTimeline
data-test-subj="stateful-timeline"
apolloClient={apolloClient}
isModal={false}
defaultPageSize={DEFAULT_SEARCH_RESULTS_PER_PAGE}
title={title}
@ -483,7 +487,7 @@ describe('StatefulOpenTimeline', () => {
</ThemeProvider>
);
await act(() => wait());
await wait();
expect(
wrapper
@ -493,14 +497,15 @@ describe('StatefulOpenTimeline', () => {
).toEqual(title);
});
describe.skip('#resetSelectionState', () => {
describe('#resetSelectionState', () => {
test('when the user deletes selected timelines, resetSelectionState is invoked to clear the selection state', async () => {
const wrapper = mount(
<ThemeProvider theme={theme}>
<TestProviderWithoutDragAndDrop>
<MockedProvider mocks={mocks} addTypename={false}>
<MockedProvider mocks={mockOpenTimelineQueryResults} addTypename={false}>
<StatefulOpenTimeline
data-test-subj="stateful-timeline"
apolloClient={apolloClient}
isModal={false}
defaultPageSize={DEFAULT_SEARCH_RESULTS_PER_PAGE}
title={title}
@ -514,7 +519,7 @@ describe('StatefulOpenTimeline', () => {
.find('[data-test-subj="open-timeline"]')
.last()
.prop('selectedItems');
await act(() => wait());
await wait();
expect(getSelectedItem().length).toEqual(0);
wrapper
.find('.euiCheckbox__input')
@ -532,10 +537,11 @@ describe('StatefulOpenTimeline', () => {
test('it renders the expected count of matching timelines when no query has been entered', async () => {
const wrapper = mount(
<ThemeProvider theme={theme}>
<MockedProvider mocks={mocks} addTypename={false}>
<MockedProvider mocks={mockOpenTimelineQueryResults} addTypename={false}>
<TestProviderWithoutDragAndDrop>
<StatefulOpenTimeline
data-test-subj="stateful-timeline"
apolloClient={apolloClient}
isModal={false}
defaultPageSize={DEFAULT_SEARCH_RESULTS_PER_PAGE}
title={title}
@ -545,12 +551,10 @@ describe('StatefulOpenTimeline', () => {
</ThemeProvider>
);
await act(() => wait());
await wait();
wrapper.update();
await act(() => wait());
expect(
wrapper
.find('[data-test-subj="query-message"]')
@ -566,9 +570,10 @@ describe('StatefulOpenTimeline', () => {
const wrapper = mount(
<ThemeProvider theme={theme}>
<TestProviderWithoutDragAndDrop>
<MockedProvider mocks={mocks} addTypename={false}>
<MockedProvider mocks={mockOpenTimelineQueryResults} addTypename={false}>
<StatefulOpenTimeline
data-test-subj="stateful-timeline"
apolloClient={apolloClient}
isModal={false}
defaultPageSize={DEFAULT_SEARCH_RESULTS_PER_PAGE}
title={title}
@ -578,18 +583,21 @@ describe('StatefulOpenTimeline', () => {
</ThemeProvider>
);
await act(() => wait());
await wait();
wrapper
.find(
`[data-test-subj="title-${mocks[0].result.data!.getAllTimeline.timeline[0].savedObjectId}"]`
`[data-test-subj="title-${
mockOpenTimelineQueryResults[0].result.data!.getAllTimeline.timeline[0].savedObjectId
}"]`
)
.first()
.simulate('click');
expect(onOpenTimeline).toHaveBeenCalledWith({
duplicate: false,
timelineId: mocks[0].result.data!.getAllTimeline.timeline[0].savedObjectId,
timelineId: mockOpenTimelineQueryResults[0].result.data!.getAllTimeline.timeline[0]
.savedObjectId,
});
});
@ -600,9 +608,10 @@ describe('StatefulOpenTimeline', () => {
const wrapper = mount(
<ThemeProvider theme={theme}>
<TestProviderWithoutDragAndDrop>
<MockedProvider mocks={mocks} addTypename={false}>
<MockedProvider mocks={mockOpenTimelineQueryResults} addTypename={false}>
<StatefulOpenTimeline
data-test-subj="stateful-timeline"
apolloClient={apolloClient}
isModal={false}
defaultPageSize={DEFAULT_SEARCH_RESULTS_PER_PAGE}
title={title}
@ -612,7 +621,7 @@ describe('StatefulOpenTimeline', () => {
</ThemeProvider>
);
await act(() => wait());
await wait();
wrapper
.find('[data-test-subj="open-duplicate"]')

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { useApolloClient } from '@apollo/client';
import ApolloClient from 'apollo-client';
import React, { useEffect, useState, useCallback } from 'react';
import { connect, ConnectedProps } from 'react-redux';
@ -43,6 +43,7 @@ import {
import { DEFAULT_SORT_FIELD, DEFAULT_SORT_DIRECTION } from './constants';
interface OwnProps<TCache = object> {
apolloClient: ApolloClient<TCache>;
/** Displays open timeline in modal */
isModal: boolean;
closeModalTimeline?: () => void;
@ -67,6 +68,7 @@ export const getSelectedTimelineIds = (selectedItems: OpenTimelineResult[]): str
/** Manages the state (e.g table selection) of the (pure) `OpenTimeline` component */
export const StatefulOpenTimelineComponent = React.memo<OpenTimelineOwnProps>(
({
apolloClient,
closeModalTimeline,
createNewTimeline,
defaultPageSize,
@ -78,7 +80,6 @@ export const StatefulOpenTimelineComponent = React.memo<OpenTimelineOwnProps>(
updateTimeline,
updateIsLoading,
}) => {
const apolloClient = useApolloClient();
/** Required by EuiTable for expandable rows: a map of `TimelineResult.savedObjectId` to rendered notes */
const [itemIdToExpandedNotesRowMap, setItemIdToExpandedNotesRowMap] = useState<
Record<string, JSX.Element>

View file

@ -10,7 +10,7 @@ import { mountWithIntl } from 'test_utils/enzyme_helpers';
import React from 'react';
import { ThemeProvider } from 'styled-components';
import { DEFAULT_SEARCH_RESULTS_PER_PAGE } from '../../pages/timelines';
import { DEFAULT_SEARCH_RESULTS_PER_PAGE } from '../../pages/timelines/timelines_page';
import { OpenTimelineResult } from './types';
import { TimelinesTableProps } from './timelines_table';
import { mockTimelineResults } from '../../mock/timeline_results';

View file

@ -7,9 +7,8 @@
import euiDarkVars from '@elastic/eui/dist/eui_theme_dark.json';
import { mount } from 'enzyme';
import React from 'react';
import { MockedProvider } from '@apollo/client/testing';
import { MockedProvider } from 'react-apollo/test-utils';
import { ThemeProvider } from 'styled-components';
import { act } from '@testing-library/react';
import { wait } from '../../../lib/helpers';
import { TestProviderWithoutDragAndDrop } from '../../../mock/test_providers';
@ -18,6 +17,9 @@ import { mockOpenTimelineQueryResults } from '../../../mock/timeline_results';
import { OpenTimelineModal } from '.';
jest.mock('../../../lib/kibana');
jest.mock('../../../utils/apollo_context', () => ({
useApolloClient: () => ({}),
}));
describe('OpenTimelineModal', () => {
const theme = () => ({ eui: euiDarkVars, darkMode: true });
@ -33,7 +35,7 @@ describe('OpenTimelineModal', () => {
</ThemeProvider>
);
await act(() => wait());
await wait();
wrapper.update();

View file

@ -8,6 +8,7 @@ import { EuiModal, EuiOverlayMask } from '@elastic/eui';
import React from 'react';
import { TimelineModel } from '../../../store/timeline/model';
import { useApolloClient } from '../../../utils/apollo_context';
import * as i18n from '../translations';
import { ActionTimelineToShow } from '../types';
@ -24,24 +25,31 @@ const DEFAULT_SEARCH_RESULTS_PER_PAGE = 10;
const OPEN_TIMELINE_MODAL_WIDTH = 1000; // px
export const OpenTimelineModal = React.memo<OpenTimelineModalProps>(
({ hideActions = [], modalTitle, onClose, onOpen }) => (
<EuiOverlayMask>
<EuiModal
data-test-subj="open-timeline-modal"
maxWidth={OPEN_TIMELINE_MODAL_WIDTH}
onClose={onClose}
>
<StatefulOpenTimeline
closeModalTimeline={onClose}
hideActions={hideActions}
isModal={true}
defaultPageSize={DEFAULT_SEARCH_RESULTS_PER_PAGE}
onOpenTimeline={onOpen}
title={modalTitle ?? i18n.OPEN_TIMELINE_TITLE}
/>
</EuiModal>
</EuiOverlayMask>
)
({ hideActions = [], modalTitle, onClose, onOpen }) => {
const apolloClient = useApolloClient();
if (!apolloClient) return null;
return (
<EuiOverlayMask>
<EuiModal
data-test-subj="open-timeline-modal"
maxWidth={OPEN_TIMELINE_MODAL_WIDTH}
onClose={onClose}
>
<StatefulOpenTimeline
apolloClient={apolloClient}
closeModalTimeline={onClose}
hideActions={hideActions}
isModal={true}
defaultPageSize={DEFAULT_SEARCH_RESULTS_PER_PAGE}
onOpenTimeline={onOpen}
title={modalTitle ?? i18n.OPEN_TIMELINE_TITLE}
/>
</EuiModal>
</EuiOverlayMask>
);
}
);
OpenTimelineModal.displayName = 'OpenTimelineModal';

View file

@ -10,7 +10,7 @@ import { mountWithIntl } from 'test_utils/enzyme_helpers';
import React from 'react';
import { ThemeProvider } from 'styled-components';
import { DEFAULT_SEARCH_RESULTS_PER_PAGE } from '../../../pages/timelines';
import { DEFAULT_SEARCH_RESULTS_PER_PAGE } from '../../../pages/timelines/timelines_page';
import { OpenTimelineResult } from '../types';
import { TimelinesTableProps } from '../timelines_table';
import { mockTimelineResults } from '../../../mock/timeline_results';

View file

@ -7,9 +7,8 @@
import euiDarkVars from '@elastic/eui/dist/eui_theme_dark.json';
import { mount } from 'enzyme';
import React from 'react';
import { MockedProvider } from '@apollo/client/testing';
import { MockedProvider } from 'react-apollo/test-utils';
import { ThemeProvider } from 'styled-components';
import { act } from '@testing-library/react';
import { wait } from '../../../lib/helpers';
import { TestProviderWithoutDragAndDrop } from '../../../mock/test_providers';
@ -30,7 +29,7 @@ describe('OpenTimelineModalButton', () => {
</TestProviderWithoutDragAndDrop>
);
await act(() => wait());
await wait();
wrapper.update();
@ -55,7 +54,7 @@ describe('OpenTimelineModalButton', () => {
</ThemeProvider>
);
await act(() => wait());
await wait();
wrapper
.find('[data-test-subj="open-timeline-button"]')

View file

@ -11,7 +11,7 @@ import { mountWithIntl } from 'test_utils/enzyme_helpers';
import React from 'react';
import { ThemeProvider } from 'styled-components';
import { DEFAULT_SEARCH_RESULTS_PER_PAGE } from '../../../pages/timelines';
import { DEFAULT_SEARCH_RESULTS_PER_PAGE } from '../../../pages/timelines/timelines_page';
import { mockTimelineResults } from '../../../mock/timeline_results';
import { OpenTimelineResult } from '../types';
import { TimelinesTable } from '.';

View file

@ -11,7 +11,7 @@ import React from 'react';
import { ThemeProvider } from 'styled-components';
import { mountWithIntl } from 'test_utils/enzyme_helpers';
import { DEFAULT_SEARCH_RESULTS_PER_PAGE } from '../../../pages/timelines';
import { DEFAULT_SEARCH_RESULTS_PER_PAGE } from '../../../pages/timelines/timelines_page';
import { getEmptyValue } from '../../empty_value';
import { OpenTimelineResult } from '../types';
import { mockTimelineResults } from '../../../mock/timeline_results';

View file

@ -10,7 +10,7 @@ import { mountWithIntl } from 'test_utils/enzyme_helpers';
import React from 'react';
import { ThemeProvider } from 'styled-components';
import { DEFAULT_SEARCH_RESULTS_PER_PAGE } from '../../../pages/timelines';
import { DEFAULT_SEARCH_RESULTS_PER_PAGE } from '../../../pages/timelines/timelines_page';
import { getEmptyValue } from '../../empty_value';
import { mockTimelineResults } from '../../../mock/timeline_results';
import { OpenTimelineResult } from '../types';

View file

@ -10,7 +10,7 @@ import { mountWithIntl } from 'test_utils/enzyme_helpers';
import React from 'react';
import { ThemeProvider } from 'styled-components';
import { DEFAULT_SEARCH_RESULTS_PER_PAGE } from '../../../pages/timelines';
import { DEFAULT_SEARCH_RESULTS_PER_PAGE } from '../../../pages/timelines/timelines_page';
import { mockTimelineResults } from '../../../mock/timeline_results';
import { TimelinesTable } from '.';
import { OpenTimelineResult } from '../types';

View file

@ -10,7 +10,7 @@ import { mountWithIntl } from 'test_utils/enzyme_helpers';
import React from 'react';
import { ThemeProvider } from 'styled-components';
import { DEFAULT_SEARCH_RESULTS_PER_PAGE } from '../../../pages/timelines';
import { DEFAULT_SEARCH_RESULTS_PER_PAGE } from '../../../pages/timelines/timelines_page';
import { mockTimelineResults } from '../../../mock/timeline_results';
import { OpenTimelineResult } from '../types';
import { TimelinesTable, TimelinesTableProps } from '.';

View file

@ -6,7 +6,7 @@
import { cloneDeep } from 'lodash/fp';
import React from 'react';
import { MockedProvider } from '@apollo/client/testing';
import { MockedProvider } from 'react-apollo/test-utils';
import { render, act } from '@testing-library/react';
import { mockFirstLastSeenHostQuery } from '../../../../containers/hosts/first_last_seen/mock';
@ -19,6 +19,16 @@ describe('FirstLastSeen Component', () => {
const firstSeen = 'Apr 8, 2019 @ 16:09:40.692';
const lastSeen = 'Apr 8, 2019 @ 18:35:45.064';
// Suppress warnings about "react-apollo" until we migrate to apollo@3
/* eslint-disable no-console */
const originalError = console.error;
beforeAll(() => {
console.error = jest.fn();
});
afterAll(() => {
console.error = originalError;
});
test('Loading', async () => {
const { container } = render(
<TestProviders>

View file

@ -6,6 +6,7 @@
import { EuiIcon, EuiLoadingSpinner, EuiText, EuiToolTip } from '@elastic/eui';
import React from 'react';
import { ApolloConsumer } from 'react-apollo';
import { useFirstLastSeenHostQuery } from '../../../../containers/hosts/first_last_seen';
import { getEmptyTagValue } from '../../../empty_value';
@ -18,37 +19,44 @@ export enum FirstLastSeenHostType {
export const FirstLastSeenHost = React.memo<{ hostname: string; type: FirstLastSeenHostType }>(
({ hostname, type }) => {
const { loading, firstSeen, lastSeen, errorMessage } = useFirstLastSeenHostQuery(
hostname,
'default'
);
if (errorMessage != null) {
return (
<EuiToolTip
position="top"
content={errorMessage}
data-test-subj="firstLastSeenErrorToolTip"
aria-label={`firstLastSeenError-${type}`}
id={`firstLastSeenError-${hostname}-${type}`}
>
<EuiIcon aria-describedby={`firstLastSeenError-${hostname}-${type}`} type="alert" />
</EuiToolTip>
);
}
const valueSeen = type === FirstLastSeenHostType.FIRST_SEEN ? firstSeen : lastSeen;
return (
<>
{loading && <EuiLoadingSpinner size="m" />}
{!loading && valueSeen != null && new Date(valueSeen).toString() === 'Invalid Date'
? valueSeen
: !loading &&
valueSeen != null && (
<EuiText size="s">
<FormattedRelativePreferenceDate value={`${valueSeen}`} />
</EuiText>
)}
{!loading && valueSeen == null && getEmptyTagValue()}
</>
<ApolloConsumer>
{client => {
const { loading, firstSeen, lastSeen, errorMessage } = useFirstLastSeenHostQuery(
hostname,
'default',
client
);
if (errorMessage != null) {
return (
<EuiToolTip
position="top"
content={errorMessage}
data-test-subj="firstLastSeenErrorToolTip"
aria-label={`firstLastSeenError-${type}`}
id={`firstLastSeenError-${hostname}-${type}`}
>
<EuiIcon aria-describedby={`firstLastSeenError-${hostname}-${type}`} type="alert" />
</EuiToolTip>
);
}
const valueSeen = type === FirstLastSeenHostType.FIRST_SEEN ? firstSeen : lastSeen;
return (
<>
{loading && <EuiLoadingSpinner size="m" />}
{!loading && valueSeen != null && new Date(valueSeen).toString() === 'Invalid Date'
? valueSeen
: !loading &&
valueSeen != null && (
<EuiText size="s">
<FormattedRelativePreferenceDate value={`${valueSeen}`} />
</EuiText>
)}
{!loading && valueSeen == null && getEmptyTagValue()}
</>
);
}}
</ApolloConsumer>
);
}
);

View file

@ -68,6 +68,97 @@ exports[`Hosts Table rendering it renders the default Hosts table 1`] = `
}
fakeTotalCount={50}
id="hostsQuery"
indexPattern={
Object {
"fields": Array [
Object {
"aggregatable": true,
"name": "@timestamp",
"searchable": true,
"type": "date",
},
Object {
"aggregatable": true,
"name": "@version",
"searchable": true,
"type": "string",
},
Object {
"aggregatable": true,
"name": "agent.ephemeral_id",
"searchable": true,
"type": "string",
},
Object {
"aggregatable": true,
"name": "agent.hostname",
"searchable": true,
"type": "string",
},
Object {
"aggregatable": true,
"name": "agent.id",
"searchable": true,
"type": "string",
},
Object {
"aggregatable": true,
"name": "agent.test1",
"searchable": true,
"type": "string",
},
Object {
"aggregatable": true,
"name": "agent.test2",
"searchable": true,
"type": "string",
},
Object {
"aggregatable": true,
"name": "agent.test3",
"searchable": true,
"type": "string",
},
Object {
"aggregatable": true,
"name": "agent.test4",
"searchable": true,
"type": "string",
},
Object {
"aggregatable": true,
"name": "agent.test5",
"searchable": true,
"type": "string",
},
Object {
"aggregatable": true,
"name": "agent.test6",
"searchable": true,
"type": "string",
},
Object {
"aggregatable": true,
"name": "agent.test7",
"searchable": true,
"type": "string",
},
Object {
"aggregatable": true,
"name": "agent.test8",
"searchable": true,
"type": "string",
},
Object {
"aggregatable": true,
"name": "host.name",
"searchable": true,
"type": "string",
},
],
"title": "filebeat-*,auditbeat-*,packetbeat-*",
}
}
isInspect={false}
loadPage={[MockFunction]}
loading={false}

View file

@ -7,9 +7,14 @@
import { shallow } from 'enzyme';
import { getOr } from 'lodash/fp';
import React from 'react';
import { MockedProvider } from '@apollo/client/testing';
import { MockedProvider } from 'react-apollo/test-utils';
import { apolloClientObservable, mockGlobalState, TestProviders } from '../../../../mock';
import {
apolloClientObservable,
mockIndexPattern,
mockGlobalState,
TestProviders,
} from '../../../../mock';
import { useMountAppended } from '../../../../utils/use_mount_appended';
import { createStore, hostsModel, State } from '../../../../store';
import { HostsTableType } from '../../../../store/hosts/model';
@ -44,6 +49,7 @@ describe('Hosts Table', () => {
data={mockData.Hosts.edges}
id="hostsQuery"
isInspect={false}
indexPattern={mockIndexPattern}
fakeTotalCount={getOr(50, 'fakeTotalCount', mockData.Hosts.pageInfo)}
loading={false}
loadPage={loadPage}
@ -66,6 +72,7 @@ describe('Hosts Table', () => {
<TestProviders store={store}>
<HostsTable
id="hostsQuery"
indexPattern={mockIndexPattern}
isInspect={false}
loading={false}
data={mockData.Hosts.edges}

View file

@ -6,6 +6,8 @@
import React, { useMemo, useCallback } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { IIndexPattern } from 'src/plugins/data/public';
import { hostsActions } from '../../../../store/actions';
import {
Direction,
@ -35,6 +37,7 @@ interface OwnProps {
data: HostsEdges[];
fakeTotalCount: number;
id: string;
indexPattern: IIndexPattern;
isInspect: boolean;
loading: boolean;
loadPage: (newActivePage: number) => void;
@ -75,6 +78,7 @@ const HostsTableComponent = React.memo<HostsTableProps>(
direction,
fakeTotalCount,
id,
indexPattern,
isInspect,
limit,
loading,

View file

@ -33,7 +33,9 @@ interface KpiHostDetailsProps extends GenericKpiHostProps {
}
const FlexGroupSpinner = styled(EuiFlexGroup)`
min-height: ${kpiWidgetHeight}px;
{
min-height: ${kpiWidgetHeight}px;
}
`;
FlexGroupSpinner.displayName = 'FlexGroupSpinner';

View file

@ -7,7 +7,7 @@
import { shallow } from 'enzyme';
import { getOr } from 'lodash/fp';
import React from 'react';
import { MockedProvider } from '@apollo/client/testing';
import { MockedProvider } from 'react-apollo/test-utils';
import { Provider as ReduxStoreProvider } from 'react-redux';
import { apolloClientObservable, mockGlobalState, TestProviders } from '../../../../mock';

View file

@ -7,7 +7,7 @@
import { shallow } from 'enzyme';
import { getOr } from 'lodash/fp';
import React from 'react';
import { MockedProvider } from '@apollo/client/testing';
import { MockedProvider } from 'react-apollo/test-utils';
import { Provider as ReduxStoreProvider } from 'react-redux';
import { apolloClientObservable, mockGlobalState, TestProviders } from '../../../../mock';

View file

@ -7,7 +7,7 @@
import { shallow } from 'enzyme';
import { getOr } from 'lodash/fp';
import React from 'react';
import { MockedProvider } from '@apollo/client/testing';
import { MockedProvider } from 'react-apollo/test-utils';
import { Provider as ReduxStoreProvider } from 'react-redux';
import { FlowTargetSourceDest } from '../../../../graphql/types';

View file

@ -7,7 +7,7 @@
import { shallow } from 'enzyme';
import { getOr } from 'lodash/fp';
import React from 'react';
import { MockedProvider } from '@apollo/client/testing';
import { MockedProvider } from 'react-apollo/test-utils';
import { Provider as ReduxStoreProvider } from 'react-redux';
import { FlowTargetSourceDest } from '../../../../graphql/types';

View file

@ -7,7 +7,7 @@
import { shallow } from 'enzyme';
import { getOr } from 'lodash/fp';
import React from 'react';
import { MockedProvider } from '@apollo/client/testing';
import { MockedProvider } from 'react-apollo/test-utils';
import { Provider as ReduxStoreProvider } from 'react-redux';
import { apolloClientObservable, mockGlobalState, TestProviders } from '../../../../mock';

View file

@ -7,7 +7,7 @@
import { shallow } from 'enzyme';
import { getOr } from 'lodash/fp';
import React from 'react';
import { MockedProvider } from '@apollo/client/testing';
import { MockedProvider } from 'react-apollo/test-utils';
import { Provider as ReduxStoreProvider } from 'react-redux';
import { FlowTarget } from '../../../../graphql/types';

View file

@ -7,13 +7,14 @@
import { cloneDeep } from 'lodash/fp';
import { mount } from 'enzyme';
import React from 'react';
import { MockedResponse, MockedProvider } from '@apollo/client/testing';
import { apolloClientObservable, mockGlobalState, TestProviders } from '../../../../mock';
import { OverviewHost } from '.';
import { createStore, State } from '../../../../store';
import { overviewHostQuery } from '../../../../containers/overview/overview_host/index.gql_query';
import { GetOverviewHostQuery } from '../../../../graphql/types';
import { MockedProvider } from 'react-apollo/test-utils';
import { wait } from '../../../../lib/helpers';
jest.mock('../../../../lib/kibana');
@ -21,7 +22,12 @@ jest.mock('../../../../lib/kibana');
const startDate = 1579553397080;
const endDate = 1579639797080;
interface MockedProvidedQuery extends MockedResponse {
interface MockedProvidedQuery {
request: {
query: GetOverviewHostQuery.Query;
fetchPolicy: string;
variables: GetOverviewHostQuery.Variables;
};
result: {
data: {
source: unknown;
@ -33,6 +39,7 @@ const mockOpenTimelineQueryResults: MockedProvidedQuery[] = [
{
request: {
query: overviewHostQuery,
fetchPolicy: 'cache-and-network',
variables: {
sourceId: 'default',
timerange: { interval: '12h', from: startDate, to: endDate },

View file

@ -7,13 +7,14 @@
import { cloneDeep } from 'lodash/fp';
import { mount } from 'enzyme';
import React from 'react';
import { MockedProvider, MockedResponse } from '@apollo/client/testing';
import { apolloClientObservable, mockGlobalState, TestProviders } from '../../../../mock';
import { OverviewNetwork } from '.';
import { createStore, State } from '../../../../store';
import { overviewNetworkQuery } from '../../../../containers/overview/overview_network/index.gql_query';
import { GetOverviewHostQuery } from '../../../../graphql/types';
import { MockedProvider } from 'react-apollo/test-utils';
import { wait } from '../../../../lib/helpers';
jest.mock('../../../../lib/kibana');
@ -21,7 +22,12 @@ jest.mock('../../../../lib/kibana');
const startDate = 1579553397080;
const endDate = 1579639797080;
interface MockedProvidedQuery extends MockedResponse {
interface MockedProvidedQuery {
request: {
query: GetOverviewHostQuery.Query;
fetchPolicy: string;
variables: GetOverviewHostQuery.Variables;
};
result: {
data: {
source: unknown;
@ -33,6 +39,7 @@ const mockOpenTimelineQueryResults: MockedProvidedQuery[] = [
{
request: {
query: overviewNetworkQuery,
fetchPolicy: 'cache-and-network',
variables: {
sourceId: 'default',
timerange: { interval: '12h', from: startDate, to: endDate },

View file

@ -50,9 +50,6 @@ const OverviewNetworkComponent: React.FC<OverviewNetworkProps> = ({
setQuery,
}) => {
const [defaultNumberFormat] = useUiSetting$<string>(DEFAULT_NUMBER_FORMAT);
const title = (
<FormattedMessage id="xpack.siem.overview.networkTitle" defaultMessage="Network events" />
);
return (
<EuiFlexItem>
@ -92,7 +89,12 @@ const OverviewNetworkComponent: React.FC<OverviewNetworkProps> = ({
<>{''}</>
)
}
title={title}
title={
<FormattedMessage
id="xpack.siem.overview.networkTitle"
defaultMessage="Network events"
/>
}
>
<EuiButton href={getNetworkUrl()}>
<FormattedMessage

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { useApolloClient } from '@apollo/client';
import ApolloClient from 'apollo-client';
import { EuiHorizontalRule, EuiLink, EuiText } from '@elastic/eui';
import React, { useCallback } from 'react';
import { connect, ConnectedProps } from 'react-redux';
@ -27,14 +27,14 @@ export interface MeApiResponse {
}
interface OwnProps {
apolloClient: ApolloClient<{}>;
filterBy: FilterMode;
}
export type Props = OwnProps & PropsFromRedux;
const StatefulRecentTimelinesComponent = React.memo<Props>(
({ filterBy, updateIsLoading, updateTimeline }) => {
const apolloClient = useApolloClient();
({ apolloClient, filterBy, updateIsLoading, updateTimeline }) => {
const actionDispatcher = updateIsLoading as ActionCreator<{ id: string; isLoading: boolean }>;
const onOpenTimeline: OnOpenTimeline = useCallback(
({ duplicate, timelineId }: { duplicate: boolean; timelineId: string }) => {

View file

@ -372,7 +372,7 @@ const mapDispatchToProps = (dispatch: Dispatch) => ({
dispatch(inputsActions.setSearchBarFilter({ id, filters })),
});
const connector = connect(makeMapStateToProps, mapDispatchToProps);
export const connector = connect(makeMapStateToProps, mapDispatchToProps);
type PropsFromRedux = ConnectedProps<typeof connector>;

View file

@ -18,7 +18,7 @@ import { get, getOr } from 'lodash/fp';
import React, { useState, useEffect } from 'react';
import styled from 'styled-components';
import { KpiHostsData, KpiHostDetailsData, KpiNetworkData } from '../../graphql/types';
import { KpiHostsData, KpiNetworkData } from '../../graphql/types';
import { AreaChart } from '../charts/areachart';
import { BarChart } from '../charts/barchart';
import { ChartSeriesData, ChartData, ChartSeriesConfigs, UpdateDateRange } from '../charts/common';
@ -112,12 +112,12 @@ export const barchartConfigs = (config?: { onElementClick?: ElementClickListener
export const addValueToFields = (
fields: StatItem[],
data: KpiHostsData | KpiHostDetailsData | KpiNetworkData
data: KpiHostsData | KpiNetworkData
): StatItem[] => fields.map(field => ({ ...field, value: get(field.key, data) }));
export const addValueToAreaChart = (
fields: StatItem[],
data: KpiHostsData | KpiHostDetailsData | KpiNetworkData
data: KpiHostsData | KpiNetworkData
): ChartSeriesData[] =>
fields
.filter(field => get(`${field.key}Histogram`, data) != null)
@ -129,7 +129,7 @@ export const addValueToAreaChart = (
export const addValueToBarChart = (
fields: StatItem[],
data: KpiHostsData | KpiHostDetailsData | KpiNetworkData
data: KpiHostsData | KpiNetworkData
): ChartSeriesData[] => {
if (fields.length === 0) return [];
return fields.reduce((acc: ChartSeriesData[], field: StatItem, idx: number) => {
@ -158,7 +158,7 @@ export const addValueToBarChart = (
export const useKpiMatrixStatus = (
mappings: Readonly<StatItems[]>,
data: KpiHostsData | KpiHostDetailsData | KpiNetworkData,
data: KpiHostsData | KpiNetworkData,
id: string,
from: number,
to: number,

View file

@ -306,7 +306,7 @@ const mapDispatchToProps = (dispatch: Dispatch) => ({
updateReduxTime: dispatchUpdateReduxTime(dispatch),
});
const connector = connect(makeMapStateToProps, mapDispatchToProps);
export const connector = connect(makeMapStateToProps, mapDispatchToProps);
type PropsFromRedux = ConnectedProps<typeof connector>;

View file

@ -11,7 +11,7 @@ import { eventHasNotes, eventIsPinned, getPinTooltip, stringifyEvent } from './h
describe('helpers', () => {
describe('stringifyEvent', () => {
test('it omits __typename when it appears at arbitrary levels', () => {
const toStringify: Ecs = ({
const toStringify: Ecs = {
__typename: 'level 0',
_id: '4',
timestamp: '2018-11-08T19:03:25.937Z',
@ -54,7 +54,7 @@ describe('helpers', () => {
region_name: ['neither'],
country_iso_code: ['sasquatch'],
},
} as unknown) as Ecs; // as cast so that `__typename` can be added for the tests even though it is not part of ECS
} as Ecs; // as cast so that `__typename` can be added for the tests even though it is not part of ECS
const expected: Ecs = {
_id: '4',
timestamp: '2018-11-08T19:03:25.937Z',

View file

@ -8,7 +8,6 @@ import { noop } from 'lodash/fp';
import memoizeOne from 'memoize-one';
import React, { useCallback, useEffect } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import deepEqual from 'fast-deep-equal';
import { BrowserFields } from '../../../containers/source';
import { TimelineItem } from '../../../graphql/types';
@ -194,7 +193,7 @@ const StatefulBodyComponent = React.memo<StatefulBodyComponentProps>(
return (
prevProps.browserFields === nextProps.browserFields &&
prevProps.columnHeaders === nextProps.columnHeaders &&
deepEqual(prevProps.data, nextProps.data) &&
prevProps.data === nextProps.data &&
prevProps.eventIdToNoteIds === nextProps.eventIdToNoteIds &&
prevProps.notesById === nextProps.notesById &&
prevProps.height === nextProps.height &&

View file

@ -7,7 +7,6 @@
import { memo, useEffect } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { IIndexPattern } from 'src/plugins/data/public';
import deepEqual from 'fast-deep-equal';
import { timelineSelectors, State } from '../../store';
import { inputsActions } from '../../store/actions';
@ -40,14 +39,7 @@ const TimelineKqlFetchComponent = memo<OwnProps>(
});
}, [kueryFilterQueryDraft, kueryFilterQuery, id]);
return null;
},
(prevProps, nextProps) =>
prevProps.id === nextProps.id &&
deepEqual(prevProps.indexPattern, nextProps.indexPattern) &&
prevProps.inputId === nextProps.inputId &&
prevProps.kueryFilterQuery === nextProps.kueryFilterQuery &&
prevProps.kueryFilterQueryDraft === nextProps.kueryFilterQueryDraft &&
prevProps.setTimelineQuery === nextProps.setTimelineQuery
}
);
const makeMapStateToProps = () => {
@ -66,7 +58,7 @@ const mapDispatchToProps = {
setTimelineQuery: inputsActions.setQuery,
};
const connector = connect(makeMapStateToProps, mapDispatchToProps);
export const connector = connect(makeMapStateToProps, mapDispatchToProps);
type PropsFromRedux = ConnectedProps<typeof connector>;

View file

@ -177,6 +177,7 @@ interface FooterProps {
getUpdatedAt: () => number;
hasNextPage: boolean;
height: number;
isEventViewer?: boolean;
isLive: boolean;
isLoading: boolean;
itemsCount: number;
@ -195,6 +196,7 @@ export const FooterComponent = ({
getUpdatedAt,
hasNextPage,
height,
isEventViewer,
isLive,
isLoading,
itemsCount,
@ -343,6 +345,7 @@ export const Footer = React.memo(
prevProps.compact === nextProps.compact &&
prevProps.hasNextPage === nextProps.hasNextPage &&
prevProps.height === nextProps.height &&
prevProps.isEventViewer === nextProps.isEventViewer &&
prevProps.isLive === nextProps.isLive &&
prevProps.isLoading === nextProps.isLoading &&
prevProps.itemsCount === nextProps.itemsCount &&

View file

@ -8,7 +8,6 @@ import { EuiCallOut } from '@elastic/eui';
import React from 'react';
import styled from 'styled-components';
import { IIndexPattern } from 'src/plugins/data/public';
import deepEqual from 'fast-deep-equal';
import { Sort } from '../body/sort';
import { DataProviders } from '../data_providers';
@ -92,19 +91,4 @@ export const TimelineHeaderComponent: React.FC<Props> = ({
</TimelineHeaderContainer>
);
export const TimelineHeader = React.memo(
TimelineHeaderComponent,
(prevProps, nextProps) =>
deepEqual(prevProps.browserFields, nextProps.browserFields) &&
prevProps.id === nextProps.id &&
deepEqual(prevProps.indexPattern, nextProps.indexPattern) &&
deepEqual(prevProps.dataProviders, nextProps.dataProviders) &&
prevProps.onChangeDataProviderKqlQuery === nextProps.onChangeDataProviderKqlQuery &&
prevProps.onChangeDroppableAndProvider === nextProps.onChangeDroppableAndProvider &&
prevProps.onDataProviderEdited === nextProps.onDataProviderEdited &&
prevProps.onDataProviderRemoved === nextProps.onDataProviderRemoved &&
prevProps.onToggleDataProviderEnabled === nextProps.onToggleDataProviderEnabled &&
prevProps.onToggleDataProviderExcluded === nextProps.onToggleDataProviderExcluded &&
prevProps.show === nextProps.show &&
prevProps.showCallOutUnauthorizedMsg === nextProps.showCallOutUnauthorizedMsg
);
export const TimelineHeader = React.memo(TimelineHeaderComponent);

View file

@ -6,7 +6,6 @@
import { isEmpty, isNumber, get } from 'lodash/fp';
import memoizeOne from 'memoize-one';
import deepEqual from 'fast-deep-equal';
import { escapeQueryValue, convertToBuildEsQuery } from '../../lib/keury';
@ -94,68 +93,65 @@ export const buildGlobalQuery = (dataProviders: DataProvider[], browserFields: B
}, '')
.trim();
export const combineQueries = memoizeOne(
({
config,
dataProviders,
indexPattern,
browserFields,
filters = [],
kqlQuery,
kqlMode,
start,
end,
isEventViewer,
}: {
config: EsQueryConfig;
dataProviders: DataProvider[];
indexPattern: IIndexPattern;
browserFields: BrowserFields;
filters: Filter[];
kqlQuery: Query;
kqlMode: string;
start: number;
end: number;
isEventViewer?: boolean;
}): { filterQuery: string } | null => {
const kuery: Query = { query: '', language: kqlQuery.language };
if (isEmpty(dataProviders) && isEmpty(kqlQuery.query) && isEmpty(filters) && !isEventViewer) {
return null;
} else if (isEmpty(dataProviders) && isEmpty(kqlQuery.query) && isEventViewer) {
kuery.query = `@timestamp >= ${start} and @timestamp <= ${end}`;
return {
filterQuery: convertToBuildEsQuery({ config, queries: [kuery], indexPattern, filters }),
};
} else if (isEmpty(dataProviders) && isEmpty(kqlQuery.query) && !isEmpty(filters)) {
kuery.query = `@timestamp >= ${start} and @timestamp <= ${end}`;
return {
filterQuery: convertToBuildEsQuery({ config, queries: [kuery], indexPattern, filters }),
};
} else if (isEmpty(dataProviders) && !isEmpty(kqlQuery.query)) {
kuery.query = `(${kqlQuery.query}) and @timestamp >= ${start} and @timestamp <= ${end}`;
return {
filterQuery: convertToBuildEsQuery({ config, queries: [kuery], indexPattern, filters }),
};
} else if (!isEmpty(dataProviders) && isEmpty(kqlQuery)) {
kuery.query = `(${buildGlobalQuery(
dataProviders,
browserFields
)}) and @timestamp >= ${start} and @timestamp <= ${end}`;
return {
filterQuery: convertToBuildEsQuery({ config, queries: [kuery], indexPattern, filters }),
};
}
const operatorKqlQuery = kqlMode === 'filter' ? 'and' : 'or';
const postpend = (q: string) => `${!isEmpty(q) ? ` ${operatorKqlQuery} (${q})` : ''}`;
kuery.query = `((${buildGlobalQuery(dataProviders, browserFields)})${postpend(
kqlQuery.query as string
export const combineQueries = ({
config,
dataProviders,
indexPattern,
browserFields,
filters = [],
kqlQuery,
kqlMode,
start,
end,
isEventViewer,
}: {
config: EsQueryConfig;
dataProviders: DataProvider[];
indexPattern: IIndexPattern;
browserFields: BrowserFields;
filters: Filter[];
kqlQuery: Query;
kqlMode: string;
start: number;
end: number;
isEventViewer?: boolean;
}): { filterQuery: string } | null => {
const kuery: Query = { query: '', language: kqlQuery.language };
if (isEmpty(dataProviders) && isEmpty(kqlQuery.query) && isEmpty(filters) && !isEventViewer) {
return null;
} else if (isEmpty(dataProviders) && isEmpty(kqlQuery.query) && isEventViewer) {
kuery.query = `@timestamp >= ${start} and @timestamp <= ${end}`;
return {
filterQuery: convertToBuildEsQuery({ config, queries: [kuery], indexPattern, filters }),
};
} else if (isEmpty(dataProviders) && isEmpty(kqlQuery.query) && !isEmpty(filters)) {
kuery.query = `@timestamp >= ${start} and @timestamp <= ${end}`;
return {
filterQuery: convertToBuildEsQuery({ config, queries: [kuery], indexPattern, filters }),
};
} else if (isEmpty(dataProviders) && !isEmpty(kqlQuery.query)) {
kuery.query = `(${kqlQuery.query}) and @timestamp >= ${start} and @timestamp <= ${end}`;
return {
filterQuery: convertToBuildEsQuery({ config, queries: [kuery], indexPattern, filters }),
};
} else if (!isEmpty(dataProviders) && isEmpty(kqlQuery)) {
kuery.query = `(${buildGlobalQuery(
dataProviders,
browserFields
)}) and @timestamp >= ${start} and @timestamp <= ${end}`;
return {
filterQuery: convertToBuildEsQuery({ config, queries: [kuery], indexPattern, filters }),
};
},
deepEqual
);
}
const operatorKqlQuery = kqlMode === 'filter' ? 'and' : 'or';
const postpend = (q: string) => `${!isEmpty(q) ? ` ${operatorKqlQuery} (${q})` : ''}`;
kuery.query = `((${buildGlobalQuery(dataProviders, browserFields)})${postpend(
kqlQuery.query as string
)}) and @timestamp >= ${start} and @timestamp <= ${end}`;
return {
filterQuery: convertToBuildEsQuery({ config, queries: [kuery], indexPattern, filters }),
};
};
interface CalculateBodyHeightParams {
/** The the height of the flyout container, which is typically the entire "page", not including the standard Kibana navigation */
@ -168,15 +164,13 @@ interface CalculateBodyHeightParams {
timelineFooterHeight?: number;
}
export const calculateBodyHeight = memoizeOne(
({
flyoutHeight = 0,
flyoutHeaderHeight = 0,
timelineHeaderHeight = 0,
timelineFooterHeight = 0,
}: CalculateBodyHeightParams): number =>
flyoutHeight - (flyoutHeaderHeight + timelineHeaderHeight + timelineFooterHeight)
);
export const calculateBodyHeight = ({
flyoutHeight = 0,
flyoutHeaderHeight = 0,
timelineHeaderHeight = 0,
timelineFooterHeight = 0,
}: CalculateBodyHeightParams): number =>
flyoutHeight - (flyoutHeaderHeight + timelineHeaderHeight + timelineFooterHeight);
/**
* The CSS class name of a "stateful event", which appears in both

View file

@ -8,7 +8,7 @@ import React, { useEffect, useCallback, useMemo } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import deepEqual from 'fast-deep-equal';
import { useWithSource } from '../../containers/source';
import { WithSource } from '../../containers/source';
import { useSignalIndex } from '../../containers/detection_engine/signals/use_signal_index';
import { inputsModel, inputsSelectors, State, timelineSelectors } from '../../store';
import { timelineActions } from '../../store/actions';
@ -34,8 +34,6 @@ export interface OwnProps {
type Props = OwnProps & PropsFromRedux;
const EMPTY_INDEX_TO_ADD: string[] = [];
const StatefulTimelineComponent = React.memo<Props>(
({
columns,
@ -77,7 +75,7 @@ const StatefulTimelineComponent = React.memo<Props>(
) {
return [signalIndexName];
}
return EMPTY_INDEX_TO_ADD;
return [];
}, [eventType, signalIndexExists, signalIndexName]);
const onDataProviderRemoved: OnDataProviderRemoved = useCallback(
@ -165,40 +163,42 @@ const StatefulTimelineComponent = React.memo<Props>(
}
}, []);
const { indexPattern, browserFields } = useWithSource(indexToAdd);
return (
<Timeline
browserFields={browserFields}
columns={columns}
dataProviders={dataProviders!}
end={end}
eventType={eventType}
filters={filters}
flyoutHeaderHeight={flyoutHeaderHeight}
flyoutHeight={flyoutHeight}
id={id}
indexPattern={indexPattern}
indexToAdd={indexToAdd}
isLive={isLive}
itemsPerPage={itemsPerPage!}
itemsPerPageOptions={itemsPerPageOptions!}
kqlMode={kqlMode}
kqlQueryExpression={kqlQueryExpression}
loadingIndexName={loading}
onChangeDataProviderKqlQuery={onChangeDataProviderKqlQuery}
onChangeDroppableAndProvider={onChangeDroppableAndProvider}
onChangeItemsPerPage={onChangeItemsPerPage}
onDataProviderEdited={onDataProviderEditedLocal}
onDataProviderRemoved={onDataProviderRemoved}
onToggleDataProviderEnabled={onToggleDataProviderEnabled}
onToggleDataProviderExcluded={onToggleDataProviderExcluded}
show={show!}
showCallOutUnauthorizedMsg={showCallOutUnauthorizedMsg}
sort={sort!}
start={start}
toggleColumn={toggleColumn}
/>
<WithSource sourceId="default" indexToAdd={indexToAdd}>
{({ indexPattern, browserFields }) => (
<Timeline
browserFields={browserFields}
columns={columns}
dataProviders={dataProviders!}
end={end}
eventType={eventType}
filters={filters}
flyoutHeaderHeight={flyoutHeaderHeight}
flyoutHeight={flyoutHeight}
id={id}
indexPattern={indexPattern}
indexToAdd={indexToAdd}
isLive={isLive}
itemsPerPage={itemsPerPage!}
itemsPerPageOptions={itemsPerPageOptions!}
kqlMode={kqlMode}
kqlQueryExpression={kqlQueryExpression}
loadingIndexName={loading}
onChangeDataProviderKqlQuery={onChangeDataProviderKqlQuery}
onChangeDroppableAndProvider={onChangeDroppableAndProvider}
onChangeItemsPerPage={onChangeItemsPerPage}
onDataProviderEdited={onDataProviderEditedLocal}
onDataProviderRemoved={onDataProviderRemoved}
onToggleDataProviderEnabled={onToggleDataProviderEnabled}
onToggleDataProviderExcluded={onToggleDataProviderExcluded}
show={show!}
showCallOutUnauthorizedMsg={showCallOutUnauthorizedMsg}
sort={sort!}
start={start}
toggleColumn={toggleColumn}
/>
)}
</WithSource>
);
},
(prevProps, nextProps) => {

View file

@ -228,7 +228,7 @@ const mapDispatchToProps = (dispatch: Dispatch) => ({
updateReduxTime: dispatchUpdateReduxTime(dispatch),
});
const connector = connect(makeMapStateToProps, mapDispatchToProps);
export const connector = connect(makeMapStateToProps, mapDispatchToProps);
type PropsFromRedux = ConnectedProps<typeof connector>;

View file

@ -6,7 +6,7 @@
import { shallow } from 'enzyme';
import React from 'react';
import { MockedProvider } from '@apollo/client/testing';
import { MockedProvider } from 'react-apollo/test-utils';
import useResizeObserver from 'use-resize-observer/polyfilled';
import { timelineQuery } from '../../containers/timeline/index.gql_query';

View file

@ -6,7 +6,7 @@
import { EuiFlexGroup } from '@elastic/eui';
import { getOr, isEmpty } from 'lodash/fp';
import React, { useMemo } from 'react';
import React from 'react';
import styled from 'styled-components';
import useResizeObserver from 'use-resize-observer/polyfilled';
@ -121,12 +121,6 @@ export const TimelineComponent: React.FC<Props> = ({
const { ref: measureRef, width = 0, height: timelineHeaderHeight = 0 } = useResizeObserver<
HTMLDivElement
>({});
const bodyHeight = calculateBodyHeight({
flyoutHeight,
flyoutHeaderHeight,
timelineHeaderHeight,
timelineFooterHeight: footerHeight,
});
const kibana = useKibana();
const combinedQueries = combineQueries({
config: esQuery.getEsQueryConfig(kibana.services.uiSettings),
@ -139,14 +133,7 @@ export const TimelineComponent: React.FC<Props> = ({
start,
end,
});
const sortField = {
sortFieldId: sort.columnId,
direction: sort.sortDirection as Direction,
};
const timelineQueryFields = useMemo(() => {
const columnsHeader = isEmpty(columns) ? defaultHeaders : columns;
return columnsHeader.map(c => c.id);
}, [columns]);
const columnsHeader = isEmpty(columns) ? defaultHeaders : columns;
return (
<TimelineContainer
@ -178,11 +165,14 @@ export const TimelineComponent: React.FC<Props> = ({
eventType={eventType}
id={id}
indexToAdd={indexToAdd}
fields={timelineQueryFields}
fields={columnsHeader.map(c => c.id)}
sourceId="default"
limit={itemsPerPage}
filterQuery={combinedQueries.filterQuery}
sortField={sortField}
sortField={{
sortFieldId: sort.columnId,
direction: sort.sortDirection as Direction,
}}
>
{({
events,
@ -206,7 +196,12 @@ export const TimelineComponent: React.FC<Props> = ({
browserFields={browserFields}
data={events}
id={id}
height={bodyHeight}
height={calculateBodyHeight({
flyoutHeight,
flyoutHeaderHeight,
timelineHeaderHeight,
timelineFooterHeight: footerHeight,
})}
sort={sort}
toggleColumn={toggleColumn}
/>

View file

@ -6,7 +6,6 @@
import { mount } from 'enzyme';
import React from 'react';
import { MockedProvider } from '@apollo/client/testing';
import { HookWrapper } from '../../mock';
import { SiemPageName } from '../../pages/home/types';
@ -73,11 +72,7 @@ describe('UrlStateContainer', () => {
pageName,
detailName,
}).relativeTimeSearch.undefinedQuery;
mount(
<MockedProvider>
<HookWrapper hookProps={mockProps} hook={args => useUrlStateHooks(args)} />
</MockedProvider>
);
mount(<HookWrapper hookProps={mockProps} hook={args => useUrlStateHooks(args)} />);
expect(mockSetRelativeRangeDatePicker.mock.calls[1][0]).toEqual({
from: 11223344556677,
@ -106,11 +101,7 @@ describe('UrlStateContainer', () => {
(page, namespaceLower, namespaceUpper, examplePath, type, pageName, detailName) => {
mockProps = getMockPropsObj({ page, examplePath, namespaceLower, pageName, detailName })
.absoluteTimeSearch.undefinedQuery;
mount(
<MockedProvider>
<HookWrapper hookProps={mockProps} hook={args => useUrlStateHooks(args)} />
</MockedProvider>
);
mount(<HookWrapper hookProps={mockProps} hook={args => useUrlStateHooks(args)} />);
expect(mockSetAbsoluteRangeDatePicker.mock.calls[1][0]).toEqual({
from: 1556736012685,
@ -135,11 +126,7 @@ describe('UrlStateContainer', () => {
(page, namespaceLower, namespaceUpper, examplePath, type, pageName, detailName) => {
mockProps = getMockPropsObj({ page, examplePath, namespaceLower, pageName, detailName })
.relativeTimeSearch.undefinedQuery;
mount(
<MockedProvider>
<HookWrapper hookProps={mockProps} hook={args => useUrlStateHooks(args)} />
</MockedProvider>
);
mount(<HookWrapper hookProps={mockProps} hook={args => useUrlStateHooks(args)} />);
expect(mockSetFilterQuery.mock.calls[0][0]).toEqual({
id: 'global',
@ -163,11 +150,7 @@ describe('UrlStateContainer', () => {
pageName,
detailName,
}).noSearch.definedQuery;
mount(
<MockedProvider>
<HookWrapper hookProps={mockProps} hook={args => useUrlStateHooks(args)} />
</MockedProvider>
);
mount(<HookWrapper hookProps={mockProps} hook={args => useUrlStateHooks(args)} />);
expect(
mockHistory.replace.mock.calls[mockHistory.replace.mock.calls.length - 1][0]
@ -197,9 +180,7 @@ describe('UrlStateContainer', () => {
detailName,
}).relativeTimeSearch.undefinedQuery;
const wrapper = mount(
<MockedProvider>
<HookWrapper hookProps={mockProps} hook={args => useUrlStateHooks(args)} />
</MockedProvider>
<HookWrapper hookProps={mockProps} hook={args => useUrlStateHooks(args)} />
);
wrapper.setProps({

View file

@ -52,4 +52,4 @@ const UseUrlStateComponent: React.FC<UrlStateProps> = props => {
return <UrlStateRedux {...urlStateReduxProps} />;
};
export const UseUrlState = React.memo(UseUrlStateComponent, deepEqual);
export const UseUrlState = React.memo(UseUrlStateComponent);

View file

@ -6,7 +6,6 @@
import { mount } from 'enzyme';
import React from 'react';
import { MockedProvider } from '@apollo/client/testing';
import { HookWrapper } from '../../mock/hook_wrapper';
import { SiemPageName } from '../../pages/home/types';
@ -47,8 +46,7 @@ describe('UrlStateContainer - lodash.throttle mocked to test update url', () =>
detailName: undefined,
}).noSearch.definedQuery;
const wrapper = mount(
<HookWrapper hookProps={mockProps} hook={args => useUrlStateHooks(args)} />,
{ wrappingComponent: MockedProvider }
<HookWrapper hookProps={mockProps} hook={args => useUrlStateHooks(args)} />
);
const newUrlState = {
@ -99,8 +97,7 @@ describe('UrlStateContainer - lodash.throttle mocked to test update url', () =>
detailName: undefined,
}).noSearch.undefinedQuery;
const wrapper = mount(
<HookWrapper hookProps={mockProps} hook={args => useUrlStateHooks(args)} />,
{ wrappingComponent: MockedProvider }
<HookWrapper hookProps={mockProps} hook={args => useUrlStateHooks(args)} />
);
const newUrlState = {
...mockProps.urlState,
@ -132,8 +129,7 @@ describe('UrlStateContainer - lodash.throttle mocked to test update url', () =>
}).noSearch.undefinedQuery;
const wrapper = mount(
<HookWrapper hookProps={mockProps} hook={args => useUrlStateHooks(args)} />,
{ wrappingComponent: MockedProvider }
<HookWrapper hookProps={mockProps} hook={args => useUrlStateHooks(args)} />
);
const newUrlState = {
...mockProps.urlState,
@ -165,9 +161,7 @@ describe('UrlStateContainer - lodash.throttle mocked to test update url', () =>
(page, namespaceLower, namespaceUpper, examplePath, type, pageName, detailName) => {
mockProps = getMockPropsObj({ page, examplePath, namespaceLower, pageName, detailName })
.noSearch.undefinedQuery;
mount(<HookWrapper hookProps={mockProps} hook={args => useUrlStateHooks(args)} />, {
wrappingComponent: MockedProvider,
});
mount(<HookWrapper hookProps={mockProps} hook={args => useUrlStateHooks(args)} />);
expect(mockHistory.replace.mock.calls[0][0]).toEqual({
hash: '',
@ -204,8 +198,7 @@ describe('UrlStateContainer - lodash.throttle mocked to test update url', () =>
detailName: undefined,
}).noSearch.definedQuery;
const wrapper = mount(
<HookWrapper hookProps={mockProps} hook={args => useUrlStateHooks(args)} />,
{ wrappingComponent: MockedProvider }
<HookWrapper hookProps={mockProps} hook={args => useUrlStateHooks(args)} />
);
expect(

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { ApolloClient } from '@apollo/client';
import ApolloClient from 'apollo-client';
import * as H from 'history';
import { ActionCreator } from 'typescript-fsa';
import {
@ -88,6 +88,9 @@ export type KeyUrlState = keyof UrlState;
export interface UrlStateProps {
navTabs: Record<string, NavTab>;
indexPattern?: IIndexPattern;
mapToUrlState?: (value: string) => UrlState;
onChange?: (urlState: UrlState, previousUrlState: UrlState) => void;
onInitialize?: (urlState: UrlState) => void;
}
export interface UrlStateStateToPropsType {

View file

@ -6,10 +6,10 @@
import { difference, isEmpty } from 'lodash/fp';
import { useEffect, useRef, useState } from 'react';
import { useApolloClient } from '@apollo/client';
import deepEqual from 'fast-deep-equal';
import { useKibana } from '../../lib/kibana';
import { useApolloClient } from '../../utils/apollo_context';
import { CONSTANTS, UrlStateType } from './constants';
import {
getQueryStringFromLocation,

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { gql } from '@apollo/client';
import gql from 'graphql-tag';
export const authenticationsQuery = gql`
query GetAuthenticationsQuery(

View file

@ -6,6 +6,7 @@
import { getOr } from 'lodash/fp';
import React from 'react';
import { Query } from 'react-apollo';
import { connect } from 'react-redux';
import { compose } from 'redux';
@ -13,7 +14,6 @@ import { DEFAULT_INDEX_KEY } from '../../../common/constants';
import {
AuthenticationsEdges,
GetAuthenticationsQuery,
GetAuthenticationsQueryComponent,
PageInfoPaginated,
} from '../../graphql/types';
import { hostsModel, hostsSelectors, inputsModel, State, inputsSelectors } from '../../store';
@ -22,6 +22,8 @@ import { generateTablePaginationOptions } from '../../components/paginated_table
import { withKibana, WithKibanaProps } from '../../lib/kibana';
import { QueryTemplatePaginated, QueryTemplatePaginatedProps } from '../query_template_paginated';
import { authenticationsQuery } from './index.gql_query';
const ID = 'authenticationQuery';
export interface AuthenticationArgs {
@ -37,7 +39,7 @@ export interface AuthenticationArgs {
}
export interface OwnProps extends QueryTemplatePaginatedProps {
children: (args: AuthenticationArgs) => React.ReactElement;
children: (args: AuthenticationArgs) => React.ReactNode;
type: hostsModel.HostsType;
}
@ -81,7 +83,8 @@ class AuthenticationsComponentQuery extends QueryTemplatePaginated<
inspect: isInspected,
};
return (
<GetAuthenticationsQueryComponent
<Query<GetAuthenticationsQuery.Query, GetAuthenticationsQuery.Variables>
query={authenticationsQuery}
fetchPolicy={getDefaultFetchPolicy()}
notifyOnNetworkStatusChange
skip={skip}
@ -123,7 +126,7 @@ class AuthenticationsComponentQuery extends QueryTemplatePaginated<
totalCount: getOr(-1, 'source.Authentications.totalCount', data),
});
}}
</GetAuthenticationsQueryComponent>
</Query>
);
}
}

View file

@ -5,15 +5,15 @@
*/
import { renderHook, act } from '@testing-library/react-hooks';
import { useApolloClient } from '@apollo/client';
import { defaultIndexPattern } from '../../../../default_index_pattern';
import { useApolloClient } from '../../../utils/apollo_context';
import { mocksSource } from '../../source/mock';
import { useFetchIndexPatterns, Return } from './fetch_index_patterns';
const mockUseApolloClient = useApolloClient as jest.Mock;
jest.mock('@apollo/client');
jest.mock('../../../utils/apollo_context');
describe('useFetchIndexPatterns', () => {
beforeEach(() => {

View file

@ -6,7 +6,6 @@
import { isEmpty, get } from 'lodash/fp';
import { useEffect, useState, Dispatch, SetStateAction } from 'react';
import { useApolloClient } from '@apollo/client';
import deepEqual from 'fast-deep-equal';
import { IIndexPattern } from '../../../../../../../../src/plugins/data/public';
@ -19,6 +18,7 @@ import {
import { useStateToaster } from '../../../components/toasters';
import { errorToToaster } from '../../../components/ml/api/error_to_toaster';
import { SourceQuery } from '../../../graphql/types';
import { useApolloClient } from '../../../utils/apollo_context';
import * as i18n from './translations';

View file

@ -5,7 +5,8 @@
*/
import { reTryOneTimeOnErrorHandler, errorLinkHandler } from '.';
import { ServerError, Operation } from '@apollo/client';
import { ServerError } from 'apollo-link-http-common';
import { Operation } from 'apollo-link';
import { GraphQLError } from 'graphql';
import * as store from '../../store';
import { onError } from 'apollo-link-error';

View file

@ -5,18 +5,16 @@
*/
import { get } from 'lodash/fp';
import { FetchPolicy } from '@apollo/client';
import React, { useEffect, useState } from 'react';
import { DEFAULT_INDEX_KEY } from '../../../../common/constants';
import {
LastEventIndexKey,
LastTimeDetails,
useGetLastEventTimeQueryQuery,
} from '../../../graphql/types';
import { GetLastEventTimeQuery, LastEventIndexKey, LastTimeDetails } from '../../../graphql/types';
import { inputsModel } from '../../../store';
import { QueryTemplateProps } from '../../query_template';
import { useUiSetting$ } from '../../../lib/kibana';
import { LastEventTimeGqlQuery } from './last_event_time.gql_query';
import { useApolloClient } from '../../../utils/apollo_context';
export interface LastEventTimeArgs {
id: string;
@ -26,29 +24,63 @@ export interface LastEventTimeArgs {
refetch: inputsModel.Refetch;
}
export const useLastEventTimeQuery = (
export interface OwnProps extends QueryTemplateProps {
children: (args: LastEventTimeArgs) => React.ReactNode;
indexKey: LastEventIndexKey;
}
export function useLastEventTimeQuery<TCache = object>(
indexKey: LastEventIndexKey,
details: LastTimeDetails,
sourceId: string
) => {
) {
const [loading, updateLoading] = useState(false);
const [lastSeen, updateLastSeen] = useState<number | null>(null);
const [errorMessage, updateErrorMessage] = useState<string | null>(null);
const [currentIndexKey, updateCurrentIndexKey] = useState<LastEventIndexKey | null>(null);
const [defaultIndex] = useUiSetting$<string[]>(DEFAULT_INDEX_KEY);
const options = {
query: LastEventTimeGqlQuery,
fetchPolicy: 'cache-first' as FetchPolicy,
variables: {
sourceId,
indexKey,
details,
defaultIndex,
},
};
const apolloClient = useApolloClient();
async function fetchLastEventTime(signal: AbortSignal) {
updateLoading(true);
if (apolloClient) {
apolloClient
.query<GetLastEventTimeQuery.Query, GetLastEventTimeQuery.Variables>({
query: LastEventTimeGqlQuery,
fetchPolicy: 'cache-first',
variables: {
sourceId,
indexKey,
details,
defaultIndex,
},
context: {
fetchOptions: {
signal,
},
},
})
.then(
result => {
updateLoading(false);
updateLastSeen(get('data.source.LastEventTime.lastSeen', result));
updateErrorMessage(null);
updateCurrentIndexKey(currentIndexKey);
},
error => {
updateLoading(false);
updateLastSeen(null);
updateErrorMessage(error.message);
}
);
}
}
const { data, loading, error } = useGetLastEventTimeQueryQuery(options);
const lastSeen = get('source.LastEventTime.lastSeen', data);
useEffect(() => {
const abortCtrl = new AbortController();
const signal = abortCtrl.signal;
fetchLastEventTime(signal);
return () => abortCtrl.abort();
}, [apolloClient, indexKey, details.hostName, details.ip]);
return {
lastSeen,
loading,
errorMessage: error?.message,
};
};
return { lastSeen, loading, errorMessage };
}

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { gql } from '@apollo/client';
import gql from 'graphql-tag';
export const LastEventTimeGqlQuery = gql`
query GetLastEventTimeQuery(

View file

@ -4,14 +4,16 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { MockedResponse } from '@apollo/client/testing';
import { defaultIndexPattern } from '../../../../default_index_pattern';
import { LastEventIndexKey } from '../../../graphql/types';
import { GetLastEventTimeQuery, LastEventIndexKey } from '../../../graphql/types';
import { LastEventTimeGqlQuery } from './last_event_time.gql_query';
interface MockLastEventTimeQuery extends MockedResponse {
interface MockLastEventTimeQuery {
request: {
query: GetLastEventTimeQuery.Query;
variables: GetLastEventTimeQuery.Variables;
};
result: {
data?: {
source: {
@ -22,6 +24,7 @@ interface MockLastEventTimeQuery extends MockedResponse {
};
};
};
errors?: [{ message: string }];
};
}

View file

@ -4,10 +4,10 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { useCallback, useState, useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import React, { useCallback, useState, useEffect } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { inputsModel, inputsSelectors } from '../../store';
import { inputsModel, inputsSelectors, State } from '../../store';
import { inputsActions } from '../../store/actions';
interface SetQuery {
@ -25,24 +25,31 @@ export interface GlobalTimeArgs {
isInitializing: boolean;
}
export const useGlobalTime = () => {
const [isInitializing, setIsInitializing] = useState(true);
const dispatch = useDispatch();
const { from, to } = useSelector(inputsSelectors.globalTimeRangeSelector);
interface OwnProps {
children: (args: GlobalTimeArgs) => React.ReactNode;
}
const deleteAllQuery = useCallback(props => dispatch(inputsActions.deleteAllQuery(props)), [
dispatch,
]);
type GlobalTimeProps = OwnProps & PropsFromRedux;
export const GlobalTimeComponent: React.FC<GlobalTimeProps> = ({
children,
deleteAllQuery,
deleteOneQuery,
from,
to,
setGlobalQuery,
}) => {
const [isInitializing, setIsInitializing] = useState(true);
const setQuery = useCallback(
({ id, inspect, loading, refetch }: SetQuery) =>
dispatch(inputsActions.setQuery({ inputId: 'global', id, inspect, loading, refetch })),
[dispatch]
setGlobalQuery({ inputId: 'global', id, inspect, loading, refetch }),
[setGlobalQuery]
);
const deleteQuery = useCallback(
({ id }: { id: string }) => dispatch(inputsActions.deleteOneQuery({ inputId: 'global', id })),
[dispatch]
({ id }: { id: string }) => deleteOneQuery({ inputId: 'global', id }),
[deleteOneQuery]
);
useEffect(() => {
@ -52,13 +59,37 @@ export const useGlobalTime = () => {
return () => {
deleteAllQuery({ id: 'global' });
};
}, [isInitializing, deleteAllQuery]);
}, []);
return (
<>
{children({
isInitializing,
from,
to,
setQuery,
deleteQuery,
})}
</>
);
};
const mapStateToProps = (state: State) => {
const timerange: inputsModel.TimeRange = inputsSelectors.globalTimeRangeSelector(state);
return {
isInitializing,
from,
to,
setQuery,
deleteQuery,
from: timerange.from,
to: timerange.to,
};
};
const mapDispatchToProps = {
deleteAllQuery: inputsActions.deleteAllQuery,
deleteOneQuery: inputsActions.deleteOneQuery,
setGlobalQuery: inputsActions.setQuery,
};
export const connector = connect(mapStateToProps, mapDispatchToProps);
type PropsFromRedux = ConnectedProps<typeof connector>;
export const GlobalTime = connector(React.memo(GlobalTimeComponent));

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { WatchQueryFetchPolicy } from '@apollo/client';
import { FetchPolicy } from 'apollo-client';
import { isString } from 'lodash/fp';
import { ESQuery } from '../../common/typed_json';
@ -12,4 +12,4 @@ import { ESQuery } from '../../common/typed_json';
export const createFilter = (filterQuery: ESQuery | string | undefined) =>
isString(filterQuery) ? filterQuery : JSON.stringify(filterQuery);
export const getDefaultFetchPolicy = (): WatchQueryFetchPolicy => 'cache-and-network';
export const getDefaultFetchPolicy = (): FetchPolicy => 'cache-and-network';

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { gql } from '@apollo/client';
import gql from 'graphql-tag';
export const HostFirstLastSeenGqlQuery = gql`
query GetHostFirstLastSeenQuery($sourceId: ID!, $hostName: String!, $defaultIndex: [String!]!) {

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { useApolloClient } from '@apollo/client';
import ApolloClient from 'apollo-client';
import { get } from 'lodash/fp';
import React, { useEffect, useState } from 'react';
@ -26,16 +26,19 @@ export interface FirstLastSeenHostArgs {
}
export interface OwnProps extends QueryTemplateProps {
children: (args: FirstLastSeenHostArgs) => React.ReactElement;
children: (args: FirstLastSeenHostArgs) => React.ReactNode;
hostName: string;
}
export function useFirstLastSeenHostQuery(hostName: string, sourceId: string) {
export function useFirstLastSeenHostQuery<TCache = object>(
hostName: string,
sourceId: string,
apolloClient: ApolloClient<TCache>
) {
const [loading, updateLoading] = useState(false);
const [firstSeen, updateFirstSeen] = useState<Date | null>(null);
const [lastSeen, updateLastSeen] = useState<Date | null>(null);
const [errorMessage, updateErrorMessage] = useState<string | null>(null);
const apolloClient = useApolloClient();
const [defaultIndex] = useUiSetting$<string[]>(DEFAULT_INDEX_KEY);
async function fetchFirstLastSeenHost(signal: AbortSignal) {

View file

@ -4,12 +4,16 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { MockedResponse } from '@apollo/client/testing';
import { defaultIndexPattern } from '../../../../default_index_pattern';
import { GetHostFirstLastSeenQuery } from '../../../graphql/types';
import { HostFirstLastSeenGqlQuery } from './first_last_seen.gql_query';
interface MockedProvidedQuery extends MockedResponse {
interface MockedProvidedQuery {
request: {
query: GetHostFirstLastSeenQuery.Query;
variables: GetHostFirstLastSeenQuery.Variables;
};
result: {
data?: {
source: {
@ -20,9 +24,9 @@ interface MockedProvidedQuery extends MockedResponse {
};
};
};
errors?: [{ message: string }];
};
}
export const mockFirstLastSeenHostQuery: MockedProvidedQuery[] = [
{
request: {

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { gql } from '@apollo/client';
import gql from 'graphql-tag';
export const HostsTableQuery = gql`
query GetHostsTableQuery(

View file

@ -7,6 +7,7 @@
import { get, getOr } from 'lodash/fp';
import memoizeOne from 'memoize-one';
import React from 'react';
import { Query } from 'react-apollo';
import { connect } from 'react-redux';
import { compose } from 'redux';
@ -14,7 +15,6 @@ import { DEFAULT_INDEX_KEY } from '../../../common/constants';
import {
Direction,
GetHostsTableQuery,
GetHostsTableQueryComponent,
HostsEdges,
HostsFields,
PageInfoPaginated,
@ -24,6 +24,7 @@ import { createFilter, getDefaultFetchPolicy } from '../helpers';
import { QueryTemplatePaginated, QueryTemplatePaginatedProps } from '../query_template_paginated';
import { withKibana, WithKibanaProps } from '../../lib/kibana';
import { HostsTableQuery } from './hosts_table.gql_query';
import { generateTablePaginationOptions } from '../../components/paginated_table/helpers';
const ID = 'hostsQuery';
@ -43,7 +44,7 @@ export interface HostsArgs {
}
export interface OwnProps extends QueryTemplatePaginatedProps {
children: (args: HostsArgs) => React.ReactElement;
children: (args: HostsArgs) => React.ReactNode;
type: hostsModel.HostsType;
startDate: number;
endDate: number;
@ -109,7 +110,8 @@ class HostsComponentQuery extends QueryTemplatePaginated<
inspect: isInspected,
};
return (
<GetHostsTableQueryComponent
<Query<GetHostsTableQuery.Query, GetHostsTableQuery.Variables>
query={HostsTableQuery}
fetchPolicy={getDefaultFetchPolicy()}
notifyOnNetworkStatusChange
skip={skip}
@ -152,7 +154,7 @@ class HostsComponentQuery extends QueryTemplatePaginated<
totalCount: getOr(-1, 'source.Hosts.totalCount', data),
});
}}
</GetHostsTableQueryComponent>
</Query>
);
}

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { gql } from '@apollo/client';
import gql from 'graphql-tag';
export const HostOverviewQuery = gql`
query GetHostOverviewQuery(

View file

@ -6,6 +6,7 @@
import { getOr } from 'lodash/fp';
import React from 'react';
import { Query } from 'react-apollo';
import { connect } from 'react-redux';
import { compose } from 'redux';
@ -15,11 +16,8 @@ import { getDefaultFetchPolicy } from '../../helpers';
import { QueryTemplate, QueryTemplateProps } from '../../query_template';
import { withKibana, WithKibanaProps } from '../../../lib/kibana';
import {
GetHostOverviewQuery,
GetHostOverviewQueryComponent,
HostItem,
} from '../../../graphql/types';
import { HostOverviewQuery } from './host_overview.gql_query';
import { GetHostOverviewQuery, HostItem } from '../../../graphql/types';
const ID = 'hostOverviewQuery';
@ -38,7 +36,7 @@ export interface HostOverviewReduxProps {
}
export interface OwnProps extends QueryTemplateProps {
children: (args: HostOverviewArgs) => React.ReactElement;
children: (args: HostOverviewArgs) => React.ReactNode;
hostName: string;
startDate: number;
endDate: number;
@ -64,7 +62,8 @@ class HostOverviewByNameComponentQuery extends QueryTemplate<
endDate,
} = this.props;
return (
<GetHostOverviewQueryComponent
<Query<GetHostOverviewQuery.Query, GetHostOverviewQuery.Variables>
query={HostOverviewQuery}
fetchPolicy={getDefaultFetchPolicy()}
notifyOnNetworkStatusChange
skip={skip}
@ -92,7 +91,7 @@ class HostOverviewByNameComponentQuery extends QueryTemplate<
endDate,
});
}}
</GetHostOverviewQueryComponent>
</Query>
);
}
}

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { gql } from '@apollo/client';
import gql from 'graphql-tag';
export const ipOverviewQuery = gql`
query GetIpOverviewQuery(

View file

@ -6,15 +6,18 @@
import { getOr } from 'lodash/fp';
import React from 'react';
import { Query } from 'react-apollo';
import { connect, ConnectedProps } from 'react-redux';
import { DEFAULT_INDEX_KEY } from '../../../common/constants';
import { GetIpOverviewQueryComponent, IpOverviewData } from '../../graphql/types';
import { GetIpOverviewQuery, IpOverviewData } from '../../graphql/types';
import { networkModel, inputsModel, inputsSelectors, State } from '../../store';
import { useUiSetting } from '../../lib/kibana';
import { createFilter, getDefaultFetchPolicy } from '../helpers';
import { QueryTemplateProps } from '../query_template';
import { ipOverviewQuery } from './index.gql_query';
const ID = 'ipOverviewQuery';
export interface IpOverviewArgs {
@ -26,14 +29,15 @@ export interface IpOverviewArgs {
}
export interface IpOverviewProps extends QueryTemplateProps {
children: (args: IpOverviewArgs) => React.ReactElement;
children: (args: IpOverviewArgs) => React.ReactNode;
type: networkModel.NetworkType;
ip: string;
}
const IpOverviewComponentQuery = React.memo<IpOverviewProps & PropsFromRedux>(
({ id = ID, isInspected, children, filterQuery, skip, sourceId, ip }) => (
<GetIpOverviewQueryComponent
<Query<GetIpOverviewQuery.Query, GetIpOverviewQuery.Variables>
query={ipOverviewQuery}
fetchPolicy={getDefaultFetchPolicy()}
notifyOnNetworkStatusChange
skip={skip}
@ -56,7 +60,7 @@ const IpOverviewComponentQuery = React.memo<IpOverviewProps & PropsFromRedux>(
refetch,
});
}}
</GetIpOverviewQueryComponent>
</Query>
)
);

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { gql } from '@apollo/client';
import gql from 'graphql-tag';
export const kpiHostDetailsQuery = gql`
fragment KpiHostDetailsChartFields on KpiHostHistogramData {

View file

@ -6,15 +6,18 @@
import { getOr } from 'lodash/fp';
import React from 'react';
import { Query } from 'react-apollo';
import { connect, ConnectedProps } from 'react-redux';
import { DEFAULT_INDEX_KEY } from '../../../common/constants';
import { KpiHostDetailsData, GetKpiHostDetailsQueryComponent } from '../../graphql/types';
import { KpiHostDetailsData, GetKpiHostDetailsQuery } from '../../graphql/types';
import { inputsModel, inputsSelectors, State } from '../../store';
import { useUiSetting } from '../../lib/kibana';
import { createFilter, getDefaultFetchPolicy } from '../helpers';
import { QueryTemplateProps } from '../query_template';
import { kpiHostDetailsQuery } from './index.gql_query';
const ID = 'kpiHostDetailsQuery';
export interface KpiHostDetailsArgs {
@ -26,12 +29,13 @@ export interface KpiHostDetailsArgs {
}
export interface QueryKpiHostDetailsProps extends QueryTemplateProps {
children: (args: KpiHostDetailsArgs) => React.ReactElement;
children: (args: KpiHostDetailsArgs) => React.ReactNode;
}
const KpiHostDetailsComponentQuery = React.memo<QueryKpiHostDetailsProps & PropsFromRedux>(
({ id = ID, children, endDate, filterQuery, isInspected, skip, sourceId, startDate }) => (
<GetKpiHostDetailsQueryComponent
<Query<GetKpiHostDetailsQuery.Query, GetKpiHostDetailsQuery.Variables>
query={kpiHostDetailsQuery}
fetchPolicy={getDefaultFetchPolicy()}
notifyOnNetworkStatusChange
skip={skip}
@ -57,7 +61,7 @@ const KpiHostDetailsComponentQuery = React.memo<QueryKpiHostDetailsProps & Props
refetch,
});
}}
</GetKpiHostDetailsQueryComponent>
</Query>
)
);

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { gql } from '@apollo/client';
import gql from 'graphql-tag';
export const kpiHostsQuery = gql`
fragment KpiHostChartFields on KpiHostHistogramData {

View file

@ -6,15 +6,18 @@
import { getOr } from 'lodash/fp';
import React from 'react';
import { Query } from 'react-apollo';
import { connect, ConnectedProps } from 'react-redux';
import { DEFAULT_INDEX_KEY } from '../../../common/constants';
import { GetKpiHostsQueryComponent, KpiHostsData } from '../../graphql/types';
import { GetKpiHostsQuery, KpiHostsData } from '../../graphql/types';
import { inputsModel, inputsSelectors, State } from '../../store';
import { useUiSetting } from '../../lib/kibana';
import { createFilter, getDefaultFetchPolicy } from '../helpers';
import { QueryTemplateProps } from '../query_template';
import { kpiHostsQuery } from './index.gql_query';
const ID = 'kpiHostsQuery';
export interface KpiHostsArgs {
@ -26,12 +29,13 @@ export interface KpiHostsArgs {
}
export interface KpiHostsProps extends QueryTemplateProps {
children: (args: KpiHostsArgs) => React.ReactElement;
children: (args: KpiHostsArgs) => React.ReactNode;
}
const KpiHostsComponentQuery = React.memo<KpiHostsProps & PropsFromRedux>(
({ id = ID, children, endDate, filterQuery, isInspected, skip, sourceId, startDate }) => (
<GetKpiHostsQueryComponent
<Query<GetKpiHostsQuery.Query, GetKpiHostsQuery.Variables>
query={kpiHostsQuery}
fetchPolicy={getDefaultFetchPolicy()}
notifyOnNetworkStatusChange
skip={skip}
@ -57,7 +61,7 @@ const KpiHostsComponentQuery = React.memo<KpiHostsProps & PropsFromRedux>(
refetch,
});
}}
</GetKpiHostsQueryComponent>
</Query>
)
);

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { gql } from '@apollo/client';
import gql from 'graphql-tag';
export const kpiNetworkQuery = gql`
fragment KpiNetworkChartFields on KpiNetworkHistogramData {

View file

@ -6,15 +6,18 @@
import { getOr } from 'lodash/fp';
import React from 'react';
import { Query } from 'react-apollo';
import { connect, ConnectedProps } from 'react-redux';
import { DEFAULT_INDEX_KEY } from '../../../common/constants';
import { GetKpiNetworkQueryComponent, KpiNetworkData } from '../../graphql/types';
import { GetKpiNetworkQuery, KpiNetworkData } from '../../graphql/types';
import { inputsModel, inputsSelectors, State } from '../../store';
import { useUiSetting } from '../../lib/kibana';
import { createFilter, getDefaultFetchPolicy } from '../helpers';
import { QueryTemplateProps } from '../query_template';
import { kpiNetworkQuery } from './index.gql_query';
const ID = 'kpiNetworkQuery';
export interface KpiNetworkArgs {
@ -26,12 +29,13 @@ export interface KpiNetworkArgs {
}
export interface KpiNetworkProps extends QueryTemplateProps {
children: (args: KpiNetworkArgs) => React.ReactElement;
children: (args: KpiNetworkArgs) => React.ReactNode;
}
const KpiNetworkComponentQuery = React.memo<KpiNetworkProps & PropsFromRedux>(
({ id = ID, children, filterQuery, isInspected, skip, sourceId, startDate, endDate }) => (
<GetKpiNetworkQueryComponent
<Query<GetKpiNetworkQuery.Query, GetKpiNetworkQuery.Variables>
query={kpiNetworkQuery}
fetchPolicy={getDefaultFetchPolicy()}
notifyOnNetworkStatusChange
skip={skip}
@ -57,7 +61,7 @@ const KpiNetworkComponentQuery = React.memo<KpiNetworkProps & PropsFromRedux>(
refetch,
});
}}
</GetKpiNetworkQueryComponent>
</Query>
)
);

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { gql } from '@apollo/client';
import gql from 'graphql-tag';
export const MatrixHistogramGqlQuery = gql`
query GetMatrixHistogramQuery(

View file

@ -7,8 +7,7 @@
import { useQuery } from '.';
import { mount } from 'enzyme';
import React from 'react';
import { useApolloClient } from '@apollo/client';
import { useApolloClient } from '../../utils/apollo_context';
import { errorToToaster } from '../../components/ml/api/error_to_toaster';
import { MatrixOverTimeHistogramData, HistogramType } from '../../graphql/types';
import { InspectQuery, Refetch } from '../../store/inputs/model';
@ -26,7 +25,7 @@ const mockQuery = jest.fn().mockResolvedValue({
});
const mockRejectQuery = jest.fn().mockRejectedValue(new Error());
jest.mock('@apollo/client', () => ({
jest.mock('../../utils/apollo_context', () => ({
useApolloClient: jest.fn(),
}));

View file

@ -4,14 +4,13 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { useEffect, useState, useRef } from 'react';
import { useApolloClient } from '@apollo/client';
import { MatrixHistogramQueryProps } from '../../components/matrix_histogram/types';
import { DEFAULT_INDEX_KEY } from '../../../common/constants';
import { useStateToaster } from '../../components/toasters';
import { errorToToaster } from '../../components/ml/api/error_to_toaster';
import { useUiSetting$ } from '../../lib/kibana';
import { createFilter } from '../helpers';
import { useApolloClient } from '../../utils/apollo_context';
import { inputsModel } from '../../store';
import { MatrixHistogramGqlQuery } from './index.gql_query';
import { GetMatrixHistogramQuery, MatrixOverTimeHistogramData } from '../../graphql/types';

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { gql } from '@apollo/client';
import gql from 'graphql-tag';
export const networkDnsQuery = gql`
query GetNetworkDnsQuery(

View file

@ -6,6 +6,7 @@
import { getOr } from 'lodash/fp';
import React from 'react';
import { Query } from 'react-apollo';
import { connect } from 'react-redux';
import { compose } from 'redux';
@ -14,7 +15,6 @@ import { ScaleType } from '@elastic/charts';
import { DEFAULT_INDEX_KEY } from '../../../common/constants';
import {
GetNetworkDnsQuery,
GetNetworkDnsQueryComponent,
NetworkDnsEdges,
NetworkDnsSortField,
PageInfoPaginated,
@ -25,6 +25,7 @@ import { withKibana, WithKibanaProps } from '../../lib/kibana';
import { generateTablePaginationOptions } from '../../components/paginated_table/helpers';
import { createFilter, getDefaultFetchPolicy } from '../helpers';
import { QueryTemplatePaginated, QueryTemplatePaginatedProps } from '../query_template_paginated';
import { networkDnsQuery } from './index.gql_query';
import { DEFAULT_TABLE_ACTIVE_PAGE, DEFAULT_TABLE_LIMIT } from '../../store/constants';
import { MatrixHistogram } from '../../components/matrix_histogram';
import { MatrixHistogramOption, GetSubTitle } from '../../components/matrix_histogram/types';
@ -48,7 +49,7 @@ export interface NetworkDnsArgs {
}
export interface OwnProps extends QueryTemplatePaginatedProps {
children: (args: NetworkDnsArgs) => React.ReactElement;
children: (args: NetworkDnsArgs) => React.ReactNode;
type: networkModel.NetworkType;
}
@ -116,9 +117,10 @@ export class NetworkDnsComponentQuery extends QueryTemplatePaginated<
};
return (
<GetNetworkDnsQueryComponent
<Query<GetNetworkDnsQuery.Query, GetNetworkDnsQuery.Variables>
fetchPolicy={getDefaultFetchPolicy()}
notifyOnNetworkStatusChange
query={networkDnsQuery}
skip={skip}
variables={variables}
>
@ -159,7 +161,7 @@ export class NetworkDnsComponentQuery extends QueryTemplatePaginated<
histogram: getOr(null, 'source.NetworkDns.histogram', data),
});
}}
</GetNetworkDnsQueryComponent>
</Query>
);
}
}

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { gql } from '@apollo/client';
import gql from 'graphql-tag';
export const networkHttpQuery = gql`
query GetNetworkHttpQuery(

View file

@ -6,13 +6,13 @@
import { getOr } from 'lodash/fp';
import React from 'react';
import { Query } from 'react-apollo';
import { connect } from 'react-redux';
import { compose } from 'redux';
import { DEFAULT_INDEX_KEY } from '../../../common/constants';
import {
GetNetworkHttpQuery,
GetNetworkHttpQueryComponent,
NetworkHttpEdges,
NetworkHttpSortField,
PageInfoPaginated,
@ -22,6 +22,7 @@ import { withKibana, WithKibanaProps } from '../../lib/kibana';
import { generateTablePaginationOptions } from '../../components/paginated_table/helpers';
import { createFilter, getDefaultFetchPolicy } from '../helpers';
import { QueryTemplatePaginated, QueryTemplatePaginatedProps } from '../query_template_paginated';
import { networkHttpQuery } from './index.gql_query';
const ID = 'networkHttpQuery';
@ -39,7 +40,7 @@ export interface NetworkHttpArgs {
}
export interface OwnProps extends QueryTemplatePaginatedProps {
children: (args: NetworkHttpArgs) => React.ReactElement;
children: (args: NetworkHttpArgs) => React.ReactNode;
ip?: string;
type: networkModel.NetworkType;
}
@ -89,9 +90,10 @@ class NetworkHttpComponentQuery extends QueryTemplatePaginated<
},
};
return (
<GetNetworkHttpQueryComponent
<Query<GetNetworkHttpQuery.Query, GetNetworkHttpQuery.Variables>
fetchPolicy={getDefaultFetchPolicy()}
notifyOnNetworkStatusChange
query={networkHttpQuery}
skip={skip}
variables={variables}
>
@ -131,7 +133,7 @@ class NetworkHttpComponentQuery extends QueryTemplatePaginated<
totalCount: getOr(-1, 'source.NetworkHttp.totalCount', data),
});
}}
</GetNetworkHttpQueryComponent>
</Query>
);
}
}

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { gql } from '@apollo/client';
import gql from 'graphql-tag';
export const networkTopCountriesQuery = gql`
query GetNetworkTopCountriesQuery(

Some files were not shown because too many files have changed in this diff Show more