mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
Re-Bootstrap siem app (#43421)
* Change the bootstrap of the app to allow embeddable * add embeddable library * make sure to use new platform to get kibana version * review
This commit is contained in:
parent
91c8ad5595
commit
a498d3964a
66 changed files with 650 additions and 793 deletions
|
@ -6,6 +6,13 @@
|
|||
|
||||
export const APP_ID = 'siem';
|
||||
export const APP_NAME = 'SIEM';
|
||||
export const DEFAULT_BYTES_FORMAT = 'format:bytes:defaultPattern';
|
||||
export const DEFAULT_DATE_FORMAT = 'dateFormat';
|
||||
export const DEFAULT_DATE_FORMAT_TZ = 'dateFormat:tz';
|
||||
export const DEFAULT_DARK_MODE = 'theme:darkMode';
|
||||
export const DEFAULT_INDEX_KEY = 'siem:defaultIndex';
|
||||
export const DEFAULT_ANOMALY_SCORE = 'siem:defaultAnomalyScore';
|
||||
export const DEFAULT_MAX_TABLE_QUERY_SIZE = 10000;
|
||||
export const DEFAULT_SCALE_DATE_FORMAT = 'dateFormat:scaled';
|
||||
export const DEFAULT_KBN_VERSION = 'kbnVersion';
|
||||
export const DEFAULT_TIMEZONE_BROWSER = 'timezoneBrowser';
|
||||
|
|
|
@ -73,6 +73,7 @@ export function siem(kibana: any) {
|
|||
mappings: savedObjectMappings,
|
||||
},
|
||||
init(server: Server) {
|
||||
server.injectUiAppVars('siem', async () => server.getInjectedUiAppVars('kibana'));
|
||||
initServerWithKibana(server);
|
||||
},
|
||||
});
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
import chrome from 'ui/chrome';
|
||||
import { SiemRootController } from './start_app';
|
||||
|
||||
import 'uiExports/autocompleteProviders';
|
||||
import 'uiExports/embeddableFactories';
|
||||
|
||||
import { compose } from '../lib/compose/kibana_compose';
|
||||
|
||||
import { startApp } from './start_app';
|
||||
|
||||
startApp(compose());
|
||||
// load the application
|
||||
chrome.setRootController('siem', SiemRootController);
|
||||
|
|
|
@ -5,8 +5,9 @@
|
|||
*/
|
||||
|
||||
import { createHashHistory } from 'history';
|
||||
import React from 'react';
|
||||
import React, { memo } from 'react';
|
||||
import { ApolloProvider } from 'react-apollo';
|
||||
import { render, unmountComponentAtNode } from 'react-dom';
|
||||
import { Provider as ReduxStoreProvider } from 'react-redux';
|
||||
import { ThemeProvider } from 'styled-components';
|
||||
|
||||
|
@ -17,45 +18,67 @@ import { BehaviorSubject } from 'rxjs';
|
|||
import { pluck } from 'rxjs/operators';
|
||||
import { I18nContext } from 'ui/i18n';
|
||||
|
||||
import { DEFAULT_DARK_MODE } from '../../common/constants';
|
||||
import { ErrorToastDispatcher } from '../components/error_toast_dispatcher';
|
||||
import { KibanaConfigContext } from '../lib/adapters/framework/kibana_framework_adapter';
|
||||
import { compose } from '../lib/compose/kibana_compose';
|
||||
import { AppFrontendLibs } from '../lib/lib';
|
||||
import { PageRouter } from '../routes';
|
||||
import { createStore } from '../store';
|
||||
import { GlobalToaster, ManageGlobalToaster } from '../components/toasters';
|
||||
import { MlCapabilitiesProvider } from '../components/ml/permissions/ml_capabilities_provider';
|
||||
import { useKibanaUiSetting } from '../lib/settings/use_kibana_ui_setting';
|
||||
|
||||
export const startApp = async (libs: AppFrontendLibs) => {
|
||||
const startApp = (libs: AppFrontendLibs) => {
|
||||
const history = createHashHistory();
|
||||
|
||||
const libs$ = new BehaviorSubject(libs);
|
||||
|
||||
const store = createStore(undefined, libs$.pipe(pluck('apolloClient')));
|
||||
|
||||
libs.framework.render(
|
||||
<EuiErrorBoundary>
|
||||
<I18nContext>
|
||||
<ManageGlobalToaster>
|
||||
<ReduxStoreProvider store={store}>
|
||||
<ApolloProvider client={libs.apolloClient}>
|
||||
<ThemeProvider
|
||||
theme={() => ({
|
||||
eui: libs.framework.darkMode ? euiDarkVars : euiLightVars,
|
||||
darkMode: libs.framework.darkMode,
|
||||
})}
|
||||
>
|
||||
<KibanaConfigContext.Provider value={libs.framework}>
|
||||
const AppPluginRoot = memo(() => {
|
||||
const [darkMode] = useKibanaUiSetting(DEFAULT_DARK_MODE);
|
||||
return (
|
||||
<EuiErrorBoundary>
|
||||
<I18nContext>
|
||||
<ManageGlobalToaster>
|
||||
<ReduxStoreProvider store={store}>
|
||||
<ApolloProvider client={libs.apolloClient}>
|
||||
<ThemeProvider
|
||||
theme={() => ({
|
||||
eui: darkMode ? euiDarkVars : euiLightVars,
|
||||
darkMode,
|
||||
})}
|
||||
>
|
||||
<MlCapabilitiesProvider>
|
||||
<PageRouter history={history} />
|
||||
</MlCapabilitiesProvider>
|
||||
</KibanaConfigContext.Provider>
|
||||
</ThemeProvider>
|
||||
<ErrorToastDispatcher />
|
||||
<GlobalToaster />
|
||||
</ApolloProvider>
|
||||
</ReduxStoreProvider>
|
||||
</ManageGlobalToaster>
|
||||
</I18nContext>
|
||||
</EuiErrorBoundary>
|
||||
);
|
||||
</ThemeProvider>
|
||||
<ErrorToastDispatcher />
|
||||
<GlobalToaster />
|
||||
</ApolloProvider>
|
||||
</ReduxStoreProvider>
|
||||
</ManageGlobalToaster>
|
||||
</I18nContext>
|
||||
</EuiErrorBoundary>
|
||||
);
|
||||
});
|
||||
return <AppPluginRoot />;
|
||||
};
|
||||
|
||||
const ROOT_ELEMENT_ID = 'react-siem-root';
|
||||
|
||||
const App = memo(() => {
|
||||
const libs: AppFrontendLibs = compose();
|
||||
return <div id={ROOT_ELEMENT_ID}>{startApp(libs)}</div>;
|
||||
});
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export const SiemRootController = ($scope: any, $element: any) => {
|
||||
const domNode: Element = $element[0];
|
||||
|
||||
render(<App />, domNode);
|
||||
|
||||
$scope.$on('$destroy', () => {
|
||||
unmountComponentAtNode(domNode);
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { compose } from '../lib/compose/testing_compose';
|
||||
|
||||
import { startApp } from './start_app';
|
||||
|
||||
startApp(compose());
|
|
@ -12,6 +12,8 @@ import { PreferenceFormattedBytes } from '../formatted_bytes';
|
|||
|
||||
import { Bytes } from '.';
|
||||
|
||||
jest.mock('../../lib/settings/use_kibana_ui_setting');
|
||||
|
||||
describe('Bytes', () => {
|
||||
test('it renders the expected formatted bytes', () => {
|
||||
const wrapper = mount(
|
||||
|
|
|
@ -15,6 +15,8 @@ import { EventDetails } from './event_details';
|
|||
import { mockBrowserFields } from '../../containers/source/mock';
|
||||
import { defaultHeaders } from '../../mock/header';
|
||||
|
||||
jest.mock('../../lib/settings/use_kibana_ui_setting');
|
||||
|
||||
describe('EventDetails', () => {
|
||||
describe('rendering', () => {
|
||||
test('should match snapshot', () => {
|
||||
|
|
|
@ -14,6 +14,8 @@ import { EventFieldsBrowser } from './event_fields_browser';
|
|||
import { mockBrowserFields } from '../../containers/source/mock';
|
||||
import { defaultHeaders } from '../../mock/header';
|
||||
|
||||
jest.mock('../../lib/settings/use_kibana_ui_setting');
|
||||
|
||||
describe('EventFieldsBrowser', () => {
|
||||
describe('column headers', () => {
|
||||
['Field', 'Value', 'Description'].forEach(header => {
|
||||
|
|
|
@ -8,53 +8,56 @@ import { mount, shallow } from 'enzyme';
|
|||
import toJson from 'enzyme-to-json';
|
||||
import * as React from 'react';
|
||||
|
||||
import { mockFrameworks, TestProviders } from '../../mock';
|
||||
import { useKibanaUiSetting } from '../../lib/settings/use_kibana_ui_setting';
|
||||
import { mockFrameworks, getMockKibanaUiSetting } from '../../mock';
|
||||
|
||||
import { PreferenceFormattedBytes } from '.';
|
||||
|
||||
const mockUseKibanaUiSetting: jest.Mock = useKibanaUiSetting as jest.Mock;
|
||||
jest.mock('../../lib/settings/use_kibana_ui_setting', () => ({
|
||||
useKibanaUiSetting: jest.fn(),
|
||||
}));
|
||||
|
||||
describe('formatted_bytes', () => {
|
||||
describe('PreferenceFormattedBytes', () => {
|
||||
describe('rendering', () => {
|
||||
const bytes = '2806422';
|
||||
|
||||
test('renders correctly against snapshot', () => {
|
||||
mockUseKibanaUiSetting.mockImplementation(
|
||||
getMockKibanaUiSetting(mockFrameworks.default_browser)
|
||||
);
|
||||
const wrapper = shallow(<PreferenceFormattedBytes value={bytes} />);
|
||||
expect(toJson(wrapper)).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('it renders bytes to hardcoded format when no configuration exists', () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders mockFramework={{}}>
|
||||
<PreferenceFormattedBytes value={bytes} />
|
||||
</TestProviders>
|
||||
);
|
||||
mockUseKibanaUiSetting.mockImplementation(() => [null]);
|
||||
const wrapper = mount(<PreferenceFormattedBytes value={bytes} />);
|
||||
expect(wrapper.text()).toEqual('2.676MB');
|
||||
});
|
||||
|
||||
test('it renders bytes according to the default format', () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders mockFramework={mockFrameworks.default_browser}>
|
||||
<PreferenceFormattedBytes value={bytes} />
|
||||
</TestProviders>
|
||||
mockUseKibanaUiSetting.mockImplementation(
|
||||
getMockKibanaUiSetting(mockFrameworks.default_browser)
|
||||
);
|
||||
const wrapper = mount(<PreferenceFormattedBytes value={bytes} />);
|
||||
expect(wrapper.text()).toEqual('2.676MB');
|
||||
});
|
||||
|
||||
test('it renders bytes supplied as a number according to the default format', () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders mockFramework={mockFrameworks.default_browser}>
|
||||
<PreferenceFormattedBytes value={+bytes} />
|
||||
</TestProviders>
|
||||
mockUseKibanaUiSetting.mockImplementation(
|
||||
getMockKibanaUiSetting(mockFrameworks.default_browser)
|
||||
);
|
||||
const wrapper = mount(<PreferenceFormattedBytes value={+bytes} />);
|
||||
expect(wrapper.text()).toEqual('2.676MB');
|
||||
});
|
||||
|
||||
test('it renders bytes according to new format', () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders mockFramework={mockFrameworks.bytes_short}>
|
||||
<PreferenceFormattedBytes value={bytes} />
|
||||
</TestProviders>
|
||||
mockUseKibanaUiSetting.mockImplementation(
|
||||
getMockKibanaUiSetting(mockFrameworks.bytes_short)
|
||||
);
|
||||
const wrapper = mount(<PreferenceFormattedBytes value={bytes} />);
|
||||
expect(wrapper.text()).toEqual('3MB');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,22 +5,15 @@
|
|||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import { useContext } from 'react';
|
||||
import numeral from '@elastic/numeral';
|
||||
|
||||
import {
|
||||
AppKibanaFrameworkAdapter,
|
||||
KibanaConfigContext,
|
||||
} from '../../lib/adapters/framework/kibana_framework_adapter';
|
||||
import { DEFAULT_BYTES_FORMAT } from '../../../common/constants';
|
||||
import { useKibanaUiSetting } from '../../lib/settings/use_kibana_ui_setting';
|
||||
|
||||
export const PreferenceFormattedBytes = React.memo<{ value: string | number }>(({ value }) => {
|
||||
const config: Partial<AppKibanaFrameworkAdapter> = useContext(KibanaConfigContext);
|
||||
const [bytesFormat] = useKibanaUiSetting(DEFAULT_BYTES_FORMAT);
|
||||
return (
|
||||
<>
|
||||
{config.bytesFormat
|
||||
? numeral(value).format(config.bytesFormat)
|
||||
: numeral(value).format('0,0.[000]b')}
|
||||
</>
|
||||
<>{bytesFormat ? numeral(value).format(bytesFormat) : numeral(value).format('0,0.[000]b')}</>
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
@ -9,22 +9,27 @@ import toJson from 'enzyme-to-json';
|
|||
import moment from 'moment-timezone';
|
||||
import * as React from 'react';
|
||||
|
||||
import { AppTestingFrameworkAdapter } from '../../lib/adapters/framework/testing_framework_adapter';
|
||||
import { mockFrameworks, TestProviders } from '../../mock';
|
||||
import { useKibanaUiSetting } from '../../lib/settings/use_kibana_ui_setting';
|
||||
|
||||
import { mockFrameworks, TestProviders, MockFrameworks, getMockKibanaUiSetting } from '../../mock';
|
||||
|
||||
import { PreferenceFormattedDate, FormattedDate } from '.';
|
||||
import { getEmptyValue } from '../empty_value';
|
||||
import { KibanaConfigContext } from '../../lib/adapters/framework/kibana_framework_adapter';
|
||||
|
||||
const mockUseKibanaUiSetting: jest.Mock = useKibanaUiSetting as jest.Mock;
|
||||
jest.mock('../../lib/settings/use_kibana_ui_setting', () => ({
|
||||
useKibanaUiSetting: jest.fn(),
|
||||
}));
|
||||
|
||||
describe('formatted_date', () => {
|
||||
describe('PreferenceFormattedDate', () => {
|
||||
describe('rendering', () => {
|
||||
beforeEach(() => {
|
||||
mockUseKibanaUiSetting.mockClear();
|
||||
});
|
||||
const isoDateString = '2019-02-25T22:27:05.000Z';
|
||||
const isoDate = new Date(isoDateString);
|
||||
const configFormattedDateString = (
|
||||
dateString: string,
|
||||
config: Partial<AppTestingFrameworkAdapter>
|
||||
): string =>
|
||||
const configFormattedDateString = (dateString: string, config: MockFrameworks): string =>
|
||||
moment
|
||||
.tz(
|
||||
dateString,
|
||||
|
@ -38,42 +43,37 @@ describe('formatted_date', () => {
|
|||
});
|
||||
|
||||
test('it renders the UTC ISO8601 date string supplied when no configuration exists', () => {
|
||||
const wrapper = mount(
|
||||
<KibanaConfigContext.Provider value={{}}>
|
||||
<PreferenceFormattedDate value={isoDate} />
|
||||
</KibanaConfigContext.Provider>
|
||||
);
|
||||
mockUseKibanaUiSetting.mockImplementation(() => [null]);
|
||||
const wrapper = mount(<PreferenceFormattedDate value={isoDate} />);
|
||||
expect(wrapper.text()).toEqual(isoDateString);
|
||||
});
|
||||
|
||||
test('it renders the UTC ISO8601 date supplied when the default configuration exists', () => {
|
||||
const wrapper = mount(
|
||||
<KibanaConfigContext.Provider value={mockFrameworks.default_UTC}>
|
||||
<PreferenceFormattedDate value={isoDate} />
|
||||
</KibanaConfigContext.Provider>
|
||||
mockUseKibanaUiSetting.mockImplementation(
|
||||
getMockKibanaUiSetting(mockFrameworks.default_UTC)
|
||||
);
|
||||
|
||||
const wrapper = mount(<PreferenceFormattedDate value={isoDate} />);
|
||||
expect(wrapper.text()).toEqual(
|
||||
configFormattedDateString(isoDateString, mockFrameworks.default_UTC)
|
||||
);
|
||||
});
|
||||
|
||||
test('it renders the correct tz when the default browser configuration exists', () => {
|
||||
const wrapper = mount(
|
||||
<KibanaConfigContext.Provider value={mockFrameworks.default_browser}>
|
||||
<PreferenceFormattedDate value={isoDate} />
|
||||
</KibanaConfigContext.Provider>
|
||||
mockUseKibanaUiSetting.mockImplementation(
|
||||
getMockKibanaUiSetting(mockFrameworks.default_browser)
|
||||
);
|
||||
const wrapper = mount(<PreferenceFormattedDate value={isoDate} />);
|
||||
expect(wrapper.text()).toEqual(
|
||||
configFormattedDateString(isoDateString, mockFrameworks.default_browser)
|
||||
);
|
||||
});
|
||||
|
||||
test('it renders the correct tz when a non-UTC configuration exists', () => {
|
||||
const wrapper = mount(
|
||||
<KibanaConfigContext.Provider value={mockFrameworks.default_MT}>
|
||||
<PreferenceFormattedDate value={isoDate} />
|
||||
</KibanaConfigContext.Provider>
|
||||
mockUseKibanaUiSetting.mockImplementation(
|
||||
getMockKibanaUiSetting(mockFrameworks.default_MT)
|
||||
);
|
||||
const wrapper = mount(<PreferenceFormattedDate value={isoDate} />);
|
||||
expect(wrapper.text()).toEqual(
|
||||
configFormattedDateString(isoDateString, mockFrameworks.default_MT)
|
||||
);
|
||||
|
@ -83,72 +83,79 @@ describe('formatted_date', () => {
|
|||
|
||||
describe('FormattedDate', () => {
|
||||
describe('rendering', () => {
|
||||
beforeEach(() => {
|
||||
mockUseKibanaUiSetting.mockClear();
|
||||
});
|
||||
|
||||
test('it renders against a numeric epoch', () => {
|
||||
const wrapper = mount(
|
||||
<KibanaConfigContext.Provider value={mockFrameworks.default_UTC}>
|
||||
<FormattedDate fieldName="@timestamp" value={1559079339000} />
|
||||
</KibanaConfigContext.Provider>
|
||||
mockUseKibanaUiSetting.mockImplementation(
|
||||
getMockKibanaUiSetting(mockFrameworks.default_UTC)
|
||||
);
|
||||
const wrapper = mount(<FormattedDate fieldName="@timestamp" value={1559079339000} />);
|
||||
expect(wrapper.text()).toEqual('May 28, 2019 @ 21:35:39.000');
|
||||
});
|
||||
|
||||
test('it renders against a string epoch', () => {
|
||||
const wrapper = mount(
|
||||
<KibanaConfigContext.Provider value={mockFrameworks.default_UTC}>
|
||||
<FormattedDate fieldName="@timestamp" value={'1559079339000'} />
|
||||
</KibanaConfigContext.Provider>
|
||||
mockUseKibanaUiSetting.mockImplementation(
|
||||
getMockKibanaUiSetting(mockFrameworks.default_UTC)
|
||||
);
|
||||
const wrapper = mount(<FormattedDate fieldName="@timestamp" value={'1559079339000'} />);
|
||||
expect(wrapper.text()).toEqual('May 28, 2019 @ 21:35:39.000');
|
||||
});
|
||||
|
||||
test('it renders against a ISO string', () => {
|
||||
mockUseKibanaUiSetting.mockImplementation(
|
||||
getMockKibanaUiSetting(mockFrameworks.default_UTC)
|
||||
);
|
||||
const wrapper = mount(
|
||||
<KibanaConfigContext.Provider value={mockFrameworks.default_UTC}>
|
||||
<FormattedDate fieldName="@timestamp" value={'2019-05-28T22:04:49.957Z'} />
|
||||
</KibanaConfigContext.Provider>
|
||||
<FormattedDate fieldName="@timestamp" value={'2019-05-28T22:04:49.957Z'} />
|
||||
);
|
||||
expect(wrapper.text()).toEqual('May 28, 2019 @ 22:04:49.957');
|
||||
});
|
||||
|
||||
test('it renders against an empty string as an empty string placeholder', () => {
|
||||
mockUseKibanaUiSetting.mockImplementation(
|
||||
getMockKibanaUiSetting(mockFrameworks.default_UTC)
|
||||
);
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<KibanaConfigContext.Provider value={mockFrameworks.default_UTC}>
|
||||
<FormattedDate fieldName="@timestamp" value={''} />
|
||||
</KibanaConfigContext.Provider>
|
||||
<FormattedDate fieldName="@timestamp" value={''} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(wrapper.text()).toEqual('(Empty String)');
|
||||
});
|
||||
|
||||
test('it renders against an null as a EMPTY_VALUE', () => {
|
||||
mockUseKibanaUiSetting.mockImplementation(
|
||||
getMockKibanaUiSetting(mockFrameworks.default_UTC)
|
||||
);
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<KibanaConfigContext.Provider value={mockFrameworks.default_UTC}>
|
||||
<FormattedDate fieldName="@timestamp" value={null} />
|
||||
</KibanaConfigContext.Provider>
|
||||
<FormattedDate fieldName="@timestamp" value={null} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(wrapper.text()).toEqual(getEmptyValue());
|
||||
});
|
||||
|
||||
test('it renders against an undefined as a EMPTY_VALUE', () => {
|
||||
mockUseKibanaUiSetting.mockImplementation(
|
||||
getMockKibanaUiSetting(mockFrameworks.default_UTC)
|
||||
);
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<KibanaConfigContext.Provider value={mockFrameworks.default_UTC}>
|
||||
<FormattedDate fieldName="@timestamp" value={undefined} />
|
||||
</KibanaConfigContext.Provider>
|
||||
<FormattedDate fieldName="@timestamp" value={undefined} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(wrapper.text()).toEqual(getEmptyValue());
|
||||
});
|
||||
|
||||
test('it renders against an invalid date time as just the string its self', () => {
|
||||
mockUseKibanaUiSetting.mockImplementation(
|
||||
getMockKibanaUiSetting(mockFrameworks.default_UTC)
|
||||
);
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<KibanaConfigContext.Provider value={mockFrameworks.default_UTC}>
|
||||
<FormattedDate fieldName="@timestamp" value={'Rebecca Evan Braden'} />
|
||||
</KibanaConfigContext.Provider>
|
||||
<FormattedDate fieldName="@timestamp" value={'Rebecca Evan Braden'} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(wrapper.text()).toEqual('Rebecca Evan Braden');
|
||||
|
|
|
@ -6,25 +6,27 @@
|
|||
|
||||
import moment from 'moment-timezone';
|
||||
import * as React from 'react';
|
||||
import { useContext } from 'react';
|
||||
import { pure } from 'recompose';
|
||||
|
||||
import {
|
||||
AppKibanaFrameworkAdapter,
|
||||
KibanaConfigContext,
|
||||
} from '../../lib/adapters/framework/kibana_framework_adapter';
|
||||
DEFAULT_DATE_FORMAT,
|
||||
DEFAULT_DATE_FORMAT_TZ,
|
||||
DEFAULT_TIMEZONE_BROWSER,
|
||||
} from '../../../common/constants';
|
||||
import { useKibanaUiSetting } from '../../lib/settings/use_kibana_ui_setting';
|
||||
import { getOrEmptyTagFromValue } from '../empty_value';
|
||||
import { LocalizedDateTooltip } from '../localized_date_tooltip';
|
||||
import { getMaybeDate } from './maybe_date';
|
||||
|
||||
export const PreferenceFormattedDate = pure<{ value: Date }>(({ value }) => {
|
||||
const config: Partial<AppKibanaFrameworkAdapter> = useContext(KibanaConfigContext);
|
||||
const [dateFormat] = useKibanaUiSetting(DEFAULT_DATE_FORMAT);
|
||||
const [dateFormatTz] = useKibanaUiSetting(DEFAULT_DATE_FORMAT_TZ);
|
||||
const [timezone] = useKibanaUiSetting(DEFAULT_TIMEZONE_BROWSER);
|
||||
|
||||
return (
|
||||
<>
|
||||
{config.dateFormat && config.dateFormatTz && config.timezone
|
||||
? moment
|
||||
.tz(value, config.dateFormatTz === 'Browser' ? config.timezone : config.dateFormatTz)
|
||||
.format(config.dateFormat)
|
||||
{dateFormat && dateFormatTz && timezone
|
||||
? moment.tz(value, dateFormatTz === 'Browser' ? timezone : dateFormatTz).format(dateFormat)
|
||||
: moment.utc(value).toISOString()}
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
import { InfluencerInput } from '../types';
|
||||
import { influencersOrCriteriaToString, getThreshold } from './use_anomalies_table_data';
|
||||
import { AppKibanaFrameworkAdapter } from '../../../lib/adapters/framework/kibana_framework_adapter';
|
||||
|
||||
describe('use_anomalies_table_data', () => {
|
||||
test('should return a reduced single influencer to string', () => {
|
||||
|
@ -43,43 +42,32 @@ describe('use_anomalies_table_data', () => {
|
|||
|
||||
describe('#getThreshold', () => {
|
||||
test('should return 0 if given something below -1', () => {
|
||||
const config: Partial<AppKibanaFrameworkAdapter> = {
|
||||
anomalyScore: -100,
|
||||
};
|
||||
expect(getThreshold(config, -1)).toEqual(0);
|
||||
const anomalyScore = -100;
|
||||
expect(getThreshold(anomalyScore, -1)).toEqual(0);
|
||||
});
|
||||
|
||||
test('should return 100 if given something above 100', () => {
|
||||
const config: Partial<AppKibanaFrameworkAdapter> = {
|
||||
anomalyScore: 1000,
|
||||
};
|
||||
expect(getThreshold(config, -1)).toEqual(100);
|
||||
const anomalyScore = 1000;
|
||||
expect(getThreshold(anomalyScore, -1)).toEqual(100);
|
||||
});
|
||||
|
||||
test('should return overridden value if passed in as non negative 1', () => {
|
||||
const config: Partial<AppKibanaFrameworkAdapter> = {
|
||||
anomalyScore: 75,
|
||||
};
|
||||
expect(getThreshold(config, 50)).toEqual(50);
|
||||
const anomalyScore = 75;
|
||||
expect(getThreshold(anomalyScore, 50)).toEqual(50);
|
||||
});
|
||||
|
||||
test('should return 50 if no anomalyScore was set', () => {
|
||||
const config: Partial<AppKibanaFrameworkAdapter> = {};
|
||||
expect(getThreshold(config, -1)).toEqual(50);
|
||||
expect(getThreshold(undefined, -1)).toEqual(50);
|
||||
});
|
||||
|
||||
test('should return custom setting', () => {
|
||||
const config: Partial<AppKibanaFrameworkAdapter> = {
|
||||
anomalyScore: 75,
|
||||
};
|
||||
expect(getThreshold(config, -1)).toEqual(75);
|
||||
const anomalyScore = 75;
|
||||
expect(getThreshold(anomalyScore, -1)).toEqual(75);
|
||||
});
|
||||
|
||||
test('should round down a value up if sent in a floating point number', () => {
|
||||
const config: Partial<AppKibanaFrameworkAdapter> = {
|
||||
anomalyScore: 75.01,
|
||||
};
|
||||
expect(getThreshold(config, -1)).toEqual(75);
|
||||
const anomalyScore = 75.01;
|
||||
expect(getThreshold(anomalyScore, -1)).toEqual(75);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,13 +5,8 @@
|
|||
*/
|
||||
|
||||
import { useState, useEffect, useContext } from 'react';
|
||||
import moment from 'moment-timezone';
|
||||
import { anomaliesTableData } from '../api/anomalies_table_data';
|
||||
import { InfluencerInput, Anomalies, CriteriaFields } from '../types';
|
||||
import {
|
||||
KibanaConfigContext,
|
||||
AppKibanaFrameworkAdapter,
|
||||
} from '../../../lib/adapters/framework/kibana_framework_adapter';
|
||||
import { hasMlUserPermissions } from '../permissions/has_ml_user_permissions';
|
||||
import { MlCapabilitiesContext } from '../permissions/ml_capabilities_provider';
|
||||
import { useSiemJobs } from '../../ml_popover/hooks/use_siem_jobs';
|
||||
|
@ -19,6 +14,12 @@ import { useStateToaster } from '../../toasters';
|
|||
import { errorToToaster } from '../api/error_to_toaster';
|
||||
|
||||
import * as i18n from './translations';
|
||||
import { useKibanaUiSetting } from '../../../lib/settings/use_kibana_ui_setting';
|
||||
import {
|
||||
DEFAULT_ANOMALY_SCORE,
|
||||
DEFAULT_TIMEZONE_BROWSER,
|
||||
DEFAULT_KBN_VERSION,
|
||||
} from '../../../../common/constants';
|
||||
|
||||
interface Args {
|
||||
influencers?: InfluencerInput[];
|
||||
|
@ -38,30 +39,17 @@ export const influencersOrCriteriaToString = (
|
|||
? ''
|
||||
: influencers.reduce((accum, item) => `${accum}${item.fieldName}:${item.fieldValue}`, '');
|
||||
|
||||
export const getTimeZone = (config: Partial<AppKibanaFrameworkAdapter>): string => {
|
||||
if (config.dateFormatTz !== 'Browser' && config.dateFormatTz != null) {
|
||||
return config.dateFormatTz;
|
||||
} else if (config.dateFormatTz === 'Browser' && config.timezone != null) {
|
||||
return config.timezone;
|
||||
} else {
|
||||
return moment.tz.guess();
|
||||
}
|
||||
};
|
||||
|
||||
export const getThreshold = (
|
||||
config: Partial<AppKibanaFrameworkAdapter>,
|
||||
threshold: number
|
||||
): number => {
|
||||
export const getThreshold = (anomalyScore: number | undefined, threshold: number): number => {
|
||||
if (threshold !== -1) {
|
||||
return threshold;
|
||||
} else if (config.anomalyScore == null) {
|
||||
} else if (anomalyScore == null) {
|
||||
return 50;
|
||||
} else if (config.anomalyScore < 0) {
|
||||
} else if (anomalyScore < 0) {
|
||||
return 0;
|
||||
} else if (config.anomalyScore > 100) {
|
||||
} else if (anomalyScore > 100) {
|
||||
return 100;
|
||||
} else {
|
||||
return Math.floor(config.anomalyScore);
|
||||
return Math.floor(anomalyScore);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -76,10 +64,12 @@ export const useAnomaliesTableData = ({
|
|||
const [tableData, setTableData] = useState<Anomalies | null>(null);
|
||||
const [, siemJobs] = useSiemJobs(true);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const config = useContext(KibanaConfigContext);
|
||||
const capabilities = useContext(MlCapabilitiesContext);
|
||||
const userPermissions = hasMlUserPermissions(capabilities);
|
||||
const [, dispatchToaster] = useStateToaster();
|
||||
const [timezone] = useKibanaUiSetting(DEFAULT_TIMEZONE_BROWSER);
|
||||
const [anomalyScore] = useKibanaUiSetting(DEFAULT_ANOMALY_SCORE);
|
||||
const [kbnVersion] = useKibanaUiSetting(DEFAULT_KBN_VERSION);
|
||||
|
||||
const fetchFunc = async (
|
||||
influencersInput: InfluencerInput[],
|
||||
|
@ -94,16 +84,16 @@ export const useAnomaliesTableData = ({
|
|||
jobIds: siemJobs,
|
||||
criteriaFields: criteriaFieldsInput,
|
||||
aggregationInterval: 'auto',
|
||||
threshold: getThreshold(config, threshold),
|
||||
threshold: getThreshold(anomalyScore, threshold),
|
||||
earliestMs,
|
||||
latestMs,
|
||||
influencers: influencersInput,
|
||||
dateFormatTz: getTimeZone(config),
|
||||
dateFormatTz: timezone,
|
||||
maxRecords: 500,
|
||||
maxExamples: 10,
|
||||
},
|
||||
{
|
||||
'kbn-version': config.kbnVersion,
|
||||
'kbn-version': kbnVersion,
|
||||
}
|
||||
);
|
||||
setTableData(data);
|
||||
|
|
|
@ -5,9 +5,11 @@
|
|||
*/
|
||||
|
||||
import chrome from 'ui/chrome';
|
||||
|
||||
import { useKibanaUiSetting } from '../../../lib/settings/use_kibana_ui_setting';
|
||||
import { DEFAULT_KBN_VERSION } from '../../../../common/constants';
|
||||
import { Anomalies, InfluencerInput, CriteriaFields } from '../types';
|
||||
import { throwIfNotOk } from './throw_if_not_ok';
|
||||
|
||||
export interface Body {
|
||||
jobIds: string[];
|
||||
criteriaFields: CriteriaFields[];
|
||||
|
@ -25,6 +27,7 @@ export const anomaliesTableData = async (
|
|||
body: Body,
|
||||
headers: Record<string, string | undefined>
|
||||
): Promise<Anomalies> => {
|
||||
const [kbnVersion] = useKibanaUiSetting(DEFAULT_KBN_VERSION);
|
||||
const response = await fetch(`${chrome.getBasePath()}/api/ml/results/anomalies_table_data`, {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
|
@ -32,7 +35,7 @@ export const anomaliesTableData = async (
|
|||
headers: {
|
||||
'kbn-system-api': 'true',
|
||||
'content-Type': 'application/json',
|
||||
'kbn-xsrf': chrome.getXsrfToken(),
|
||||
'kbn-xsrf': kbnVersion,
|
||||
...headers,
|
||||
},
|
||||
});
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
*/
|
||||
|
||||
import chrome from 'ui/chrome';
|
||||
|
||||
import { DEFAULT_KBN_VERSION } from '../../../../common/constants';
|
||||
import { useKibanaUiSetting } from '../../../lib/settings/use_kibana_ui_setting';
|
||||
import { InfluencerInput, MlCapabilities } from '../types';
|
||||
import { throwIfNotOk } from './throw_if_not_ok';
|
||||
|
||||
|
@ -24,13 +27,14 @@ export interface Body {
|
|||
export const getMlCapabilities = async (
|
||||
headers: Record<string, string | undefined>
|
||||
): Promise<MlCapabilities> => {
|
||||
const [kbnVersion] = useKibanaUiSetting(DEFAULT_KBN_VERSION);
|
||||
const response = await fetch(`${chrome.getBasePath()}/api/ml/ml_capabilities`, {
|
||||
method: 'GET',
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'kbn-system-api': 'true',
|
||||
'content-Type': 'application/json',
|
||||
'kbn-xsrf': chrome.getXsrfToken(),
|
||||
'kbn-xsrf': kbnVersion,
|
||||
...headers,
|
||||
},
|
||||
});
|
||||
|
|
|
@ -4,13 +4,15 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React, { useState, useEffect, useContext } from 'react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
|
||||
import { MlCapabilities } from '../types';
|
||||
import { getMlCapabilities } from '../api/get_ml_capabilities';
|
||||
import { KibanaConfigContext } from '../../../lib/adapters/framework/kibana_framework_adapter';
|
||||
import { emptyMlCapabilities } from '../empty_ml_capabilities';
|
||||
import { errorToToaster } from '../api/error_to_toaster';
|
||||
import { useStateToaster } from '../../toasters';
|
||||
import { useKibanaUiSetting } from '../../../lib/settings/use_kibana_ui_setting';
|
||||
import { DEFAULT_KBN_VERSION } from '../../../../common/constants';
|
||||
|
||||
import * as i18n from './translations';
|
||||
|
||||
|
@ -20,12 +22,12 @@ MlCapabilitiesContext.displayName = 'MlCapabilitiesContext';
|
|||
|
||||
export const MlCapabilitiesProvider = React.memo<{ children: JSX.Element }>(({ children }) => {
|
||||
const [capabilities, setCapabilities] = useState(emptyMlCapabilities);
|
||||
const config = useContext(KibanaConfigContext);
|
||||
const [, dispatchToaster] = useStateToaster();
|
||||
const [kbnVersion] = useKibanaUiSetting(DEFAULT_KBN_VERSION);
|
||||
|
||||
const fetchFunc = async () => {
|
||||
try {
|
||||
const mlCapabilities = await getMlCapabilities({ 'kbn-version': config.kbnVersion });
|
||||
const mlCapabilities = await getMlCapabilities({ 'kbn-version': kbnVersion });
|
||||
setCapabilities(mlCapabilities);
|
||||
} catch (error) {
|
||||
errorToToaster({
|
||||
|
|
|
@ -16,9 +16,10 @@ import { Anomalies } from '../types';
|
|||
const endDate: number = new Date('3000-01-01T00:00:00.000Z').valueOf();
|
||||
const narrowDateRange = jest.fn();
|
||||
|
||||
jest.mock('../../../lib/settings/use_kibana_ui_setting');
|
||||
|
||||
describe('anomaly_scores', () => {
|
||||
let anomalies: Anomalies = cloneDeep(mockAnomalies);
|
||||
|
||||
beforeEach(() => {
|
||||
anomalies = cloneDeep(mockAnomalies);
|
||||
});
|
||||
|
|
|
@ -17,6 +17,8 @@ import { Anomalies } from '../types';
|
|||
const endDate: number = new Date('3000-01-01T00:00:00.000Z').valueOf();
|
||||
const narrowDateRange = jest.fn();
|
||||
|
||||
jest.mock('../../../lib/settings/use_kibana_ui_setting');
|
||||
|
||||
describe('anomaly_scores', () => {
|
||||
let anomalies: Anomalies = cloneDeep(mockAnomalies);
|
||||
|
||||
|
|
|
@ -12,6 +12,8 @@ import { createDescriptionList } from './create_description_list';
|
|||
import { EuiDescriptionList } from '@elastic/eui';
|
||||
import { Anomaly } from '../types';
|
||||
|
||||
jest.mock('../../../lib/settings/use_kibana_ui_setting');
|
||||
|
||||
const endDate: number = new Date('3000-01-01T00:00:00.000Z').valueOf();
|
||||
|
||||
describe('create_description_list', () => {
|
||||
|
|
|
@ -20,6 +20,8 @@ import {
|
|||
throwIfErrorAttached,
|
||||
throwIfErrorAttachedToSetup,
|
||||
} from '../ml/api/throw_if_not_ok';
|
||||
import { useKibanaUiSetting } from '../../lib/settings/use_kibana_ui_setting';
|
||||
import { DEFAULT_KBN_VERSION } from '../../../common/constants';
|
||||
|
||||
const emptyIndexPattern: string[] = [];
|
||||
|
||||
|
@ -29,13 +31,14 @@ const emptyIndexPattern: string[] = [];
|
|||
* @param headers
|
||||
*/
|
||||
export const groupsData = async (headers: Record<string, string | undefined>): Promise<Group[]> => {
|
||||
const [kbnVersion] = useKibanaUiSetting(DEFAULT_KBN_VERSION);
|
||||
const response = await fetch(`${chrome.getBasePath()}/api/ml/jobs/groups`, {
|
||||
method: 'GET',
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
'kbn-system-api': 'true',
|
||||
'kbn-xsrf': chrome.getXsrfToken(),
|
||||
'kbn-xsrf': kbnVersion,
|
||||
...headers,
|
||||
},
|
||||
});
|
||||
|
@ -59,6 +62,7 @@ export const setupMlJob = async ({
|
|||
prefix = '',
|
||||
headers = {},
|
||||
}: MlSetupArgs): Promise<SetupMlResponse> => {
|
||||
const [kbnVersion] = useKibanaUiSetting(DEFAULT_KBN_VERSION);
|
||||
const response = await fetch(`${chrome.getBasePath()}/api/ml/modules/setup/${configTemplate}`, {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
|
@ -72,7 +76,7 @@ export const setupMlJob = async ({
|
|||
headers: {
|
||||
'kbn-system-api': 'true',
|
||||
'content-type': 'application/json',
|
||||
'kbn-xsrf': chrome.getXsrfToken(),
|
||||
'kbn-xsrf': kbnVersion,
|
||||
...headers,
|
||||
},
|
||||
});
|
||||
|
@ -94,6 +98,7 @@ export const startDatafeeds = async (
|
|||
headers: Record<string, string | undefined>,
|
||||
start = 0
|
||||
): Promise<StartDatafeedResponse> => {
|
||||
const [kbnVersion] = useKibanaUiSetting(DEFAULT_KBN_VERSION);
|
||||
const response = await fetch(`${chrome.getBasePath()}/api/ml/jobs/force_start_datafeeds`, {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
|
@ -104,7 +109,7 @@ export const startDatafeeds = async (
|
|||
headers: {
|
||||
'kbn-system-api': 'true',
|
||||
'content-type': 'application/json',
|
||||
'kbn-xsrf': chrome.getXsrfToken(),
|
||||
'kbn-xsrf': kbnVersion,
|
||||
...headers,
|
||||
},
|
||||
});
|
||||
|
@ -124,6 +129,7 @@ export const stopDatafeeds = async (
|
|||
datafeedIds: string[],
|
||||
headers: Record<string, string | undefined>
|
||||
): Promise<[StopDatafeedResponse, CloseJobsResponse]> => {
|
||||
const [kbnVersion] = useKibanaUiSetting(DEFAULT_KBN_VERSION);
|
||||
const stopDatafeedsResponse = await fetch(`${chrome.getBasePath()}/api/ml/jobs/stop_datafeeds`, {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
|
@ -133,7 +139,7 @@ export const stopDatafeeds = async (
|
|||
headers: {
|
||||
'kbn-system-api': 'true',
|
||||
'content-type': 'application/json',
|
||||
'kbn-xsrf': chrome.getXsrfToken(),
|
||||
'kbn-xsrf': kbnVersion,
|
||||
...headers,
|
||||
},
|
||||
});
|
||||
|
@ -155,7 +161,7 @@ export const stopDatafeeds = async (
|
|||
headers: {
|
||||
'content-type': 'application/json',
|
||||
'kbn-system-api': 'true',
|
||||
'kbn-xsrf': chrome.getXsrfToken(),
|
||||
'kbn-xsrf': kbnVersion,
|
||||
...headers,
|
||||
},
|
||||
});
|
||||
|
@ -174,13 +180,14 @@ export const jobsSummary = async (
|
|||
jobIds: string[],
|
||||
headers: Record<string, string | undefined>
|
||||
): Promise<Job[]> => {
|
||||
const [kbnVersion] = useKibanaUiSetting(DEFAULT_KBN_VERSION);
|
||||
const response = await fetch(`${chrome.getBasePath()}/api/ml/jobs/jobs_summary`, {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({ jobIds }),
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
'kbn-xsrf': chrome.getXsrfToken(),
|
||||
'kbn-xsrf': kbnVersion,
|
||||
'kbn-system-api': 'true',
|
||||
...headers,
|
||||
},
|
||||
|
@ -197,6 +204,7 @@ export const jobsSummary = async (
|
|||
export const getIndexPatterns = async (
|
||||
headers: Record<string, string | undefined>
|
||||
): Promise<string[]> => {
|
||||
const [kbnVersion] = useKibanaUiSetting(DEFAULT_KBN_VERSION);
|
||||
const response = await fetch(
|
||||
`${chrome.getBasePath()}/api/saved_objects/_find?type=index-pattern&fields=title&fields=type&per_page=10000`,
|
||||
{
|
||||
|
@ -204,7 +212,7 @@ export const getIndexPatterns = async (
|
|||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
'kbn-xsrf': chrome.getXsrfToken(),
|
||||
'kbn-xsrf': kbnVersion,
|
||||
'kbn-system-api': 'true',
|
||||
...headers,
|
||||
},
|
||||
|
|
|
@ -4,11 +4,13 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { useContext, useEffect, useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { getIndexPatterns } from '../api';
|
||||
import { KibanaConfigContext } from '../../../lib/adapters/framework/kibana_framework_adapter';
|
||||
import { useStateToaster } from '../../toasters';
|
||||
import { errorToToaster } from '../../ml/api/error_to_toaster';
|
||||
import { useKibanaUiSetting } from '../../../lib/settings/use_kibana_ui_setting';
|
||||
import { DEFAULT_KBN_VERSION } from '../../../../common/constants';
|
||||
|
||||
import * as i18n from './translations';
|
||||
|
||||
|
@ -17,13 +19,13 @@ type Return = [boolean, string[]];
|
|||
export const useIndexPatterns = (refreshToggle = false): Return => {
|
||||
const [indexPatterns, setIndexPatterns] = useState<string[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const config = useContext(KibanaConfigContext);
|
||||
const [, dispatchToaster] = useStateToaster();
|
||||
const [kbnVersion] = useKibanaUiSetting(DEFAULT_KBN_VERSION);
|
||||
|
||||
const fetchFunc = async () => {
|
||||
try {
|
||||
const data = await getIndexPatterns({
|
||||
'kbn-version': config.kbnVersion,
|
||||
'kbn-version': kbnVersion,
|
||||
});
|
||||
|
||||
setIndexPatterns(data);
|
||||
|
|
|
@ -5,13 +5,15 @@
|
|||
*/
|
||||
|
||||
import { useContext, useEffect, useState } from 'react';
|
||||
|
||||
import { jobsSummary } from '../api';
|
||||
import { Job } from '../types';
|
||||
import { KibanaConfigContext } from '../../../lib/adapters/framework/kibana_framework_adapter';
|
||||
import { hasMlUserPermissions } from '../../ml/permissions/has_ml_user_permissions';
|
||||
import { MlCapabilitiesContext } from '../../ml/permissions/ml_capabilities_provider';
|
||||
import { useStateToaster } from '../../toasters';
|
||||
import { errorToToaster } from '../../ml/api/error_to_toaster';
|
||||
import { useKibanaUiSetting } from '../../../lib/settings/use_kibana_ui_setting';
|
||||
import { DEFAULT_KBN_VERSION } from '../../../../common/constants';
|
||||
|
||||
import * as i18n from './translations';
|
||||
|
||||
|
@ -25,16 +27,16 @@ export const getSiemJobsFromJobsSummary = (data: Job[]) =>
|
|||
export const useJobSummaryData = (jobIds: string[] = [], refreshToggle = false): Return => {
|
||||
const [jobSummaryData, setJobSummaryData] = useState<Job[] | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const config = useContext(KibanaConfigContext);
|
||||
const capabilities = useContext(MlCapabilitiesContext);
|
||||
const userPermissions = hasMlUserPermissions(capabilities);
|
||||
const [, dispatchToaster] = useStateToaster();
|
||||
const [kbnVersion] = useKibanaUiSetting(DEFAULT_KBN_VERSION);
|
||||
|
||||
const fetchFunc = async () => {
|
||||
if (userPermissions) {
|
||||
try {
|
||||
const data: Job[] = await jobsSummary(jobIds, {
|
||||
'kbn-version': config.kbnVersion,
|
||||
'kbn-version': kbnVersion,
|
||||
});
|
||||
|
||||
// TODO: API returns all jobs even though we specified jobIds -- jobsSummary call seems to match request in ML App?
|
||||
|
|
|
@ -5,13 +5,15 @@
|
|||
*/
|
||||
|
||||
import { useState, useEffect, useContext } from 'react';
|
||||
|
||||
import { groupsData } from '../api';
|
||||
import { Group } from '.././types';
|
||||
import { KibanaConfigContext } from '../../../lib/adapters/framework/kibana_framework_adapter';
|
||||
import { hasMlUserPermissions } from '../../ml/permissions/has_ml_user_permissions';
|
||||
import { MlCapabilitiesContext } from '../../ml/permissions/ml_capabilities_provider';
|
||||
import { useStateToaster } from '../../toasters';
|
||||
import { errorToToaster } from '../../ml/api/error_to_toaster';
|
||||
import { useKibanaUiSetting } from '../../../lib/settings/use_kibana_ui_setting';
|
||||
import { DEFAULT_KBN_VERSION } from '../../../../common/constants';
|
||||
|
||||
import * as i18n from './translations';
|
||||
|
||||
|
@ -25,16 +27,16 @@ export const getSiemJobIdsFromGroupsData = (data: Group[]) =>
|
|||
export const useSiemJobs = (refetchData: boolean): Return => {
|
||||
const [siemJobs, setSiemJobs] = useState<string[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const config = useContext(KibanaConfigContext);
|
||||
const capabilities = useContext(MlCapabilitiesContext);
|
||||
const userPermissions = hasMlUserPermissions(capabilities);
|
||||
const [, dispatchToaster] = useStateToaster();
|
||||
const [kbnVersion] = useKibanaUiSetting(DEFAULT_KBN_VERSION);
|
||||
|
||||
const fetchFunc = async () => {
|
||||
if (userPermissions) {
|
||||
try {
|
||||
const data = await groupsData({
|
||||
'kbn-version': config.kbnVersion,
|
||||
'kbn-version': kbnVersion,
|
||||
});
|
||||
|
||||
const siemJobIds = getSiemJobIdsFromGroupsData(data);
|
||||
|
|
|
@ -12,6 +12,8 @@ import { MlPopover } from './ml_popover';
|
|||
/* eslint-disable no-console */
|
||||
const originalError = console.error;
|
||||
|
||||
jest.mock('../../lib/settings/use_kibana_ui_setting');
|
||||
|
||||
jest.mock('../ml/permissions/has_ml_admin_permissions', () => ({
|
||||
hasMlAdminPermissions: () => true,
|
||||
}));
|
||||
|
|
|
@ -4,14 +4,13 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { EuiButton, EuiPopover, EuiPopoverTitle, EuiSpacer } from '@elastic/eui';
|
||||
import React, { useContext, useEffect, useReducer, useState } from 'react';
|
||||
|
||||
import styled from 'styled-components';
|
||||
import moment from 'moment';
|
||||
import { EuiButton, EuiPopover, EuiPopoverTitle, EuiSpacer } from '@elastic/eui';
|
||||
|
||||
import { useJobSummaryData } from './hooks/use_job_summary_data';
|
||||
import * as i18n from './translations';
|
||||
import { KibanaConfigContext } from '../../lib/adapters/framework/kibana_framework_adapter';
|
||||
import { Job } from './types';
|
||||
import { hasMlAdminPermissions } from '../ml/permissions/has_ml_admin_permissions';
|
||||
import { MlCapabilitiesContext } from '../ml/permissions/ml_capabilities_provider';
|
||||
|
@ -26,6 +25,8 @@ import { getConfigTemplatesToInstall, getJobsToDisplay, getJobsToInstall } from
|
|||
import { configTemplates, siemJobPrefix } from './config_templates';
|
||||
import { useStateToaster } from '../toasters';
|
||||
import { errorToToaster } from '../ml/api/error_to_toaster';
|
||||
import { useKibanaUiSetting } from '../../lib/settings/use_kibana_ui_setting';
|
||||
import { DEFAULT_KBN_VERSION } from '../../../common/constants';
|
||||
|
||||
const PopoverContentsDiv = styled.div`
|
||||
max-width: 550px;
|
||||
|
@ -94,11 +95,10 @@ export const MlPopover = React.memo(() => {
|
|||
const [isCreatingJobs, setIsCreatingJobs] = useState(false);
|
||||
const [filterQuery, setFilterQuery] = useState('');
|
||||
const [, dispatchToaster] = useStateToaster();
|
||||
|
||||
const [, configuredIndexPatterns] = useIndexPatterns(refreshToggle);
|
||||
const config = useContext(KibanaConfigContext);
|
||||
const capabilities = useContext(MlCapabilitiesContext);
|
||||
const headers = { 'kbn-version': config.kbnVersion };
|
||||
const [kbnVersion] = useKibanaUiSetting(DEFAULT_KBN_VERSION);
|
||||
const headers = { 'kbn-version': kbnVersion };
|
||||
|
||||
// Enable/Disable Job & Datafeed -- passed to JobsTable for use as callback on JobSwitch
|
||||
const enableDatafeed = async (jobName: string, latestTimestampMs: number, enable: boolean) => {
|
||||
|
|
|
@ -57,6 +57,8 @@ import {
|
|||
NETWORK_TRANSPORT_FIELD_NAME,
|
||||
} from '../source_destination/field_names';
|
||||
|
||||
jest.mock('../../lib/settings/use_kibana_ui_setting');
|
||||
|
||||
const getNetflowInstance = () => (
|
||||
<Netflow
|
||||
contextId="test"
|
||||
|
|
|
@ -20,6 +20,8 @@ import { StatefulOpenTimeline } from '.';
|
|||
import { NotePreviews } from './note_previews';
|
||||
import { OPEN_TIMELINE_CLASS_NAME } from './helpers';
|
||||
|
||||
jest.mock('../../lib/settings/use_kibana_ui_setting');
|
||||
|
||||
const getStateChildComponent = (
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
wrapper: ReactWrapper<any, Readonly<{}>, React.Component<{}, {}, any>>
|
||||
|
|
|
@ -17,6 +17,8 @@ import { mockTimelineResults } from '../../mock/timeline_results';
|
|||
import { OpenTimeline } from './open_timeline';
|
||||
import { DEFAULT_SORT_DIRECTION, DEFAULT_SORT_FIELD } from './constants';
|
||||
|
||||
jest.mock('../../lib/settings/use_kibana_ui_setting');
|
||||
|
||||
describe('OpenTimeline', () => {
|
||||
const theme = () => ({ eui: euiDarkVars, darkMode: true });
|
||||
const title = 'All Timelines / Open Timelines';
|
||||
|
|
|
@ -18,6 +18,8 @@ import * as i18n from '../translations';
|
|||
|
||||
import { OpenTimelineModalButton } from '.';
|
||||
|
||||
jest.mock('../../../lib/settings/use_kibana_ui_setting');
|
||||
|
||||
const getStateChildComponent = (
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
wrapper: ReactWrapper<any, Readonly<{}>, React.Component<{}, {}, any>>
|
||||
|
|
|
@ -17,6 +17,8 @@ import { mockTimelineResults } from '../../../mock/timeline_results';
|
|||
import { OpenTimelineModal } from './open_timeline_modal';
|
||||
import { DEFAULT_SORT_DIRECTION, DEFAULT_SORT_FIELD } from '../constants';
|
||||
|
||||
jest.mock('../../../lib/settings/use_kibana_ui_setting');
|
||||
|
||||
describe('OpenTimelineModal', () => {
|
||||
const theme = () => ({ eui: euiDarkVars, darkMode: true });
|
||||
const title = 'All Timelines / Open Timelines';
|
||||
|
|
|
@ -15,6 +15,8 @@ import { OpenTimelineResult } from '../types';
|
|||
import { TimelinesTable } from '.';
|
||||
import { DEFAULT_SORT_DIRECTION, DEFAULT_SORT_FIELD } from '../constants';
|
||||
|
||||
jest.mock('../../../lib/settings/use_kibana_ui_setting');
|
||||
|
||||
describe('#getActionsColumns', () => {
|
||||
let mockResults: OpenTimelineResult[];
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@ import { TimelinesTable } from '.';
|
|||
import * as i18n from '../translations';
|
||||
import { DEFAULT_SORT_DIRECTION, DEFAULT_SORT_FIELD } from '../constants';
|
||||
|
||||
jest.mock('../../../lib/settings/use_kibana_ui_setting');
|
||||
|
||||
describe('#getCommonColumns', () => {
|
||||
const theme = () => ({ eui: euiDarkVars, darkMode: true });
|
||||
let mockResults: OpenTimelineResult[];
|
||||
|
|
|
@ -18,6 +18,8 @@ import { TimelinesTable } from '.';
|
|||
import * as i18n from '../translations';
|
||||
import { DEFAULT_SORT_DIRECTION, DEFAULT_SORT_FIELD } from '../constants';
|
||||
|
||||
jest.mock('../../../lib/settings/use_kibana_ui_setting');
|
||||
|
||||
describe('#getExtendedColumns', () => {
|
||||
let mockResults: OpenTimelineResult[];
|
||||
|
||||
|
|
|
@ -15,6 +15,8 @@ import { TimelinesTable } from '.';
|
|||
import { OpenTimelineResult } from '../types';
|
||||
import { DEFAULT_SORT_DIRECTION, DEFAULT_SORT_FIELD } from '../constants';
|
||||
|
||||
jest.mock('../../../lib/settings/use_kibana_ui_setting');
|
||||
|
||||
describe('#getActionsColumns', () => {
|
||||
let mockResults: OpenTimelineResult[];
|
||||
|
||||
|
|
|
@ -16,6 +16,8 @@ import { TimelinesTable, TimelinesTableProps } from '.';
|
|||
import * as i18n from '../translations';
|
||||
import { DEFAULT_SORT_DIRECTION, DEFAULT_SORT_FIELD } from '../constants';
|
||||
|
||||
jest.mock('../../../lib/settings/use_kibana_ui_setting');
|
||||
|
||||
describe('TimelinesTable', () => {
|
||||
let mockResults: OpenTimelineResult[];
|
||||
|
||||
|
|
|
@ -16,6 +16,8 @@ import '../../../../mock/ui_settings';
|
|||
|
||||
import { FirstLastSeenHost, FirstLastSeenHostType } from '.';
|
||||
|
||||
jest.mock('../../../../lib/settings/use_kibana_ui_setting');
|
||||
|
||||
describe('FirstLastSeen Component', () => {
|
||||
// this is just a little hack to silence a warning that we'll get until react
|
||||
// fixes this: https://github.com/facebook/react/pull/14853
|
||||
|
|
|
@ -11,7 +11,9 @@ import { getOr } from 'lodash/fp';
|
|||
import React, { useContext, useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { DEFAULT_DARK_MODE } from '../../../../../common/constants';
|
||||
import { DescriptionList } from '../../../../../common/utility_types';
|
||||
import { useKibanaUiSetting } from '../../../../lib/settings/use_kibana_ui_setting';
|
||||
import { getEmptyTagValue } from '../../../empty_value';
|
||||
import { DefaultFieldRenderer, hostIdRenderer } from '../../../field_renderers/field_renderers';
|
||||
import { InspectButton } from '../../../inspect';
|
||||
|
@ -26,7 +28,6 @@ import { OverviewWrapper } from '../../index';
|
|||
import { FirstLastSeenHost, FirstLastSeenHostType } from '../first_last_seen_host';
|
||||
|
||||
import * as i18n from './translations';
|
||||
import { KibanaConfigContext } from '../../../../lib/adapters/framework/kibana_framework_adapter';
|
||||
|
||||
interface HostSummaryProps {
|
||||
data: HostItem;
|
||||
|
@ -69,7 +70,7 @@ export const HostOverview = React.memo<HostSummaryProps>(
|
|||
const [showInspect, setShowInspect] = useState(false);
|
||||
const capabilities = useContext(MlCapabilitiesContext);
|
||||
const userPermissions = hasMlUserPermissions(capabilities);
|
||||
const config = useContext(KibanaConfigContext);
|
||||
const [darkMode] = useKibanaUiSetting(DEFAULT_DARK_MODE);
|
||||
|
||||
const getDefaultRenderer = (fieldName: string, fieldData: HostItem) => (
|
||||
<DefaultFieldRenderer
|
||||
|
@ -195,7 +196,7 @@ export const HostOverview = React.memo<HostSummaryProps>(
|
|||
<Loader
|
||||
overlay
|
||||
overlayBackground={
|
||||
config.darkMode ? darkTheme.euiPageBackgroundColor : lightTheme.euiPageBackgroundColor
|
||||
darkMode ? darkTheme.euiPageBackgroundColor : lightTheme.euiPageBackgroundColor
|
||||
}
|
||||
size="xl"
|
||||
/>
|
||||
|
|
|
@ -1,173 +1,162 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Hosts Table rendering it renders the default Hosts table 1`] = `
|
||||
<ContextProvider
|
||||
value={
|
||||
<Connect(HostsTableComponent)
|
||||
data={
|
||||
Array [
|
||||
Object {
|
||||
"cursor": Object {
|
||||
"value": "98966fa2013c396155c460d35c0902be",
|
||||
},
|
||||
"node": Object {
|
||||
"_id": "cPsuhGcB0WOhS6qyTKC0",
|
||||
"host": Object {
|
||||
"name": Array [
|
||||
"elrond.elstc.co",
|
||||
],
|
||||
"os": Object {
|
||||
"name": Array [
|
||||
"Ubuntu",
|
||||
],
|
||||
"version": Array [
|
||||
"18.04.1 LTS (Bionic Beaver)",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"cursor": Object {
|
||||
"value": "aa7ca589f1b8220002f2fc61c64cfbf1",
|
||||
},
|
||||
"node": Object {
|
||||
"_id": "KwQDiWcB0WOhS6qyXmrW",
|
||||
"cloud": Object {
|
||||
"instance": Object {
|
||||
"id": Array [
|
||||
"423232333829362673777",
|
||||
],
|
||||
},
|
||||
"machine": Object {
|
||||
"type": Array [
|
||||
"custom-4-16384",
|
||||
],
|
||||
},
|
||||
"provider": Array [
|
||||
"gce",
|
||||
],
|
||||
"region": Array [
|
||||
"us-east-1",
|
||||
],
|
||||
},
|
||||
"host": Object {
|
||||
"name": Array [
|
||||
"siem-kibana",
|
||||
],
|
||||
"os": Object {
|
||||
"name": Array [
|
||||
"Debian GNU/Linux",
|
||||
],
|
||||
"version": Array [
|
||||
"9 (stretch)",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
fakeTotalCount={50}
|
||||
id="hostsQuery"
|
||||
indexPattern={
|
||||
Object {
|
||||
"bytesFormat": "0,0.[000]b",
|
||||
"dateFormat": "MMM D, YYYY @ HH:mm:ss.SSS",
|
||||
"dateFormatTz": "UTC",
|
||||
"timezone": "UTC",
|
||||
"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",
|
||||
},
|
||||
],
|
||||
"title": "filebeat-*,auditbeat-*,packetbeat-*",
|
||||
}
|
||||
}
|
||||
>
|
||||
<Connect(HostsTableComponent)
|
||||
data={
|
||||
Array [
|
||||
Object {
|
||||
"cursor": Object {
|
||||
"value": "98966fa2013c396155c460d35c0902be",
|
||||
},
|
||||
"node": Object {
|
||||
"_id": "cPsuhGcB0WOhS6qyTKC0",
|
||||
"host": Object {
|
||||
"name": Array [
|
||||
"elrond.elstc.co",
|
||||
],
|
||||
"os": Object {
|
||||
"name": Array [
|
||||
"Ubuntu",
|
||||
],
|
||||
"version": Array [
|
||||
"18.04.1 LTS (Bionic Beaver)",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"cursor": Object {
|
||||
"value": "aa7ca589f1b8220002f2fc61c64cfbf1",
|
||||
},
|
||||
"node": Object {
|
||||
"_id": "KwQDiWcB0WOhS6qyXmrW",
|
||||
"cloud": Object {
|
||||
"instance": Object {
|
||||
"id": Array [
|
||||
"423232333829362673777",
|
||||
],
|
||||
},
|
||||
"machine": Object {
|
||||
"type": Array [
|
||||
"custom-4-16384",
|
||||
],
|
||||
},
|
||||
"provider": Array [
|
||||
"gce",
|
||||
],
|
||||
"region": Array [
|
||||
"us-east-1",
|
||||
],
|
||||
},
|
||||
"host": Object {
|
||||
"name": Array [
|
||||
"siem-kibana",
|
||||
],
|
||||
"os": Object {
|
||||
"name": Array [
|
||||
"Debian GNU/Linux",
|
||||
],
|
||||
"version": Array [
|
||||
"9 (stretch)",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
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",
|
||||
},
|
||||
],
|
||||
"title": "filebeat-*,auditbeat-*,packetbeat-*",
|
||||
}
|
||||
}
|
||||
loadPage={[MockFunction]}
|
||||
loading={false}
|
||||
showMorePagesIndicator={true}
|
||||
totalCount={4}
|
||||
type="page"
|
||||
/>
|
||||
</ContextProvider>
|
||||
loadPage={[MockFunction]}
|
||||
loading={false}
|
||||
showMorePagesIndicator={true}
|
||||
totalCount={4}
|
||||
type="page"
|
||||
/>
|
||||
`;
|
||||
|
|
|
@ -13,7 +13,6 @@ import { Provider as ReduxStoreProvider } from 'react-redux';
|
|||
|
||||
import {
|
||||
apolloClientObservable,
|
||||
mockFrameworks,
|
||||
mockIndexPattern,
|
||||
mockGlobalState,
|
||||
TestProviders,
|
||||
|
@ -22,7 +21,6 @@ import { createStore, hostsModel, State } from '../../../../store';
|
|||
|
||||
import { HostsTable } from './index';
|
||||
import { mockData } from './mock';
|
||||
import { KibanaConfigContext } from '../../../../lib/adapters/framework/kibana_framework_adapter';
|
||||
|
||||
describe('Hosts Table', () => {
|
||||
const loadPage = jest.fn();
|
||||
|
@ -38,23 +36,17 @@ describe('Hosts Table', () => {
|
|||
test('it renders the default Hosts table', () => {
|
||||
const wrapper = shallow(
|
||||
<ReduxStoreProvider store={store}>
|
||||
<KibanaConfigContext.Provider value={mockFrameworks.default_UTC}>
|
||||
<HostsTable
|
||||
data={mockData.Hosts.edges}
|
||||
id="hostsQuery"
|
||||
indexPattern={mockIndexPattern}
|
||||
fakeTotalCount={getOr(50, 'fakeTotalCount', mockData.Hosts.pageInfo)}
|
||||
loading={false}
|
||||
loadPage={loadPage}
|
||||
showMorePagesIndicator={getOr(
|
||||
false,
|
||||
'showMorePagesIndicator',
|
||||
mockData.Hosts.pageInfo
|
||||
)}
|
||||
totalCount={mockData.Hosts.totalCount}
|
||||
type={hostsModel.HostsType.page}
|
||||
/>
|
||||
</KibanaConfigContext.Provider>
|
||||
<HostsTable
|
||||
data={mockData.Hosts.edges}
|
||||
id="hostsQuery"
|
||||
indexPattern={mockIndexPattern}
|
||||
fakeTotalCount={getOr(50, 'fakeTotalCount', mockData.Hosts.pageInfo)}
|
||||
loading={false}
|
||||
loadPage={loadPage}
|
||||
showMorePagesIndicator={getOr(false, 'showMorePagesIndicator', mockData.Hosts.pageInfo)}
|
||||
totalCount={mockData.Hosts.totalCount}
|
||||
type={hostsModel.HostsType.page}
|
||||
/>
|
||||
</ReduxStoreProvider>
|
||||
);
|
||||
|
||||
|
|
|
@ -23,6 +23,8 @@ import { createStore, networkModel, State } from '../../../../store';
|
|||
import { DomainsTable } from '.';
|
||||
import { mockDomainsData } from './mock';
|
||||
|
||||
jest.mock('../../../../lib/settings/use_kibana_ui_setting');
|
||||
|
||||
describe('Domains Table Component', () => {
|
||||
const loadPage = jest.fn();
|
||||
const ip = '10.10.10.10';
|
||||
|
|
|
@ -11,7 +11,9 @@ import React, { useContext, useState } from 'react';
|
|||
import { pure } from 'recompose';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { DEFAULT_DARK_MODE } from '../../../../../common/constants';
|
||||
import { DescriptionList } from '../../../../../common/utility_types';
|
||||
import { useKibanaUiSetting } from '../../../../lib/settings/use_kibana_ui_setting';
|
||||
import { FlowTarget, IpOverviewData, Overview } from '../../../../graphql/types';
|
||||
import { networkModel } from '../../../../store';
|
||||
import { getEmptyTagValue } from '../../../empty_value';
|
||||
|
@ -26,7 +28,6 @@ import {
|
|||
whoisRenderer,
|
||||
} from '../../../field_renderers/field_renderers';
|
||||
import * as i18n from './translations';
|
||||
import { KibanaConfigContext } from '../../../../lib/adapters/framework/kibana_framework_adapter';
|
||||
import { OverviewWrapper } from '../../index';
|
||||
import { Loader } from '../../../loader';
|
||||
import { Anomalies, NarrowDateRange } from '../../../ml/types';
|
||||
|
@ -85,7 +86,7 @@ export const IpOverview = pure<IpOverviewProps>(
|
|||
const [showInspect, setShowInspect] = useState(false);
|
||||
const capabilities = useContext(MlCapabilitiesContext);
|
||||
const userPermissions = hasMlUserPermissions(capabilities);
|
||||
const config = useContext(KibanaConfigContext);
|
||||
const [darkMode] = useKibanaUiSetting(DEFAULT_DARK_MODE);
|
||||
const typeData: Overview = data[flowTarget]!;
|
||||
const column: DescriptionList[] = [
|
||||
{
|
||||
|
@ -164,7 +165,7 @@ export const IpOverview = pure<IpOverviewProps>(
|
|||
<Loader
|
||||
overlay
|
||||
overlayBackground={
|
||||
config.darkMode ? darkTheme.euiPageBackgroundColor : lightTheme.euiPageBackgroundColor
|
||||
darkMode ? darkTheme.euiPageBackgroundColor : lightTheme.euiPageBackgroundColor
|
||||
}
|
||||
size="xl"
|
||||
/>
|
||||
|
|
|
@ -17,6 +17,8 @@ import { createStore, networkModel, State } from '../../../../store';
|
|||
import { NetworkDnsTable } from '.';
|
||||
import { mockData } from './mock';
|
||||
|
||||
jest.mock('../../../../lib/settings/use_kibana_ui_setting');
|
||||
|
||||
describe('NetworkTopNFlow Table Component', () => {
|
||||
const loadPage = jest.fn();
|
||||
const state: State = mockGlobalState;
|
||||
|
|
|
@ -23,6 +23,8 @@ import { createStore, networkModel, State } from '../../../../store';
|
|||
import { NetworkTopNFlowTable, NetworkTopNFlowTableId } from '.';
|
||||
import { mockData } from './mock';
|
||||
|
||||
jest.mock('../../../../lib/settings/use_kibana_ui_setting');
|
||||
|
||||
describe('NetworkTopNFlow Table Component', () => {
|
||||
const loadPage = jest.fn();
|
||||
const state: State = mockGlobalState;
|
||||
|
|
|
@ -17,6 +17,8 @@ import { createStore, networkModel, State } from '../../../../store';
|
|||
import { TlsTable } from '.';
|
||||
import { mockTlsData } from './mock';
|
||||
|
||||
jest.mock('../../../../lib/settings/use_kibana_ui_setting');
|
||||
|
||||
describe('Tls Table Component', () => {
|
||||
const loadPage = jest.fn();
|
||||
const state: State = mockGlobalState;
|
||||
|
|
|
@ -47,6 +47,8 @@ import {
|
|||
NETWORK_TRANSPORT_FIELD_NAME,
|
||||
} from './field_names';
|
||||
|
||||
jest.mock('../../lib/settings/use_kibana_ui_setting');
|
||||
|
||||
const getSourceDestinationInstance = () => (
|
||||
<SourceDestination
|
||||
contextId="test"
|
||||
|
|
|
@ -18,6 +18,8 @@ import { columnRenderers, rowRenderers } from './renderers';
|
|||
import { Sort } from './sort';
|
||||
import { wait } from '../../../lib/helpers';
|
||||
|
||||
jest.mock('../../../lib/settings/use_kibana_ui_setting');
|
||||
|
||||
const testBodyHeight = 700;
|
||||
const mockGetNotesByIds = (eventId: string[]) => [];
|
||||
const mockSort: Sort = {
|
||||
|
|
|
@ -13,6 +13,8 @@ import { mockTimelineData, TestProviders } from '../../../../mock';
|
|||
import { getEmptyValue } from '../../../empty_value';
|
||||
import { FormattedFieldValue } from './formatted_field';
|
||||
|
||||
jest.mock('../../../../lib/settings/use_kibana_ui_setting');
|
||||
|
||||
describe('Events', () => {
|
||||
test('renders correctly against snapshot', () => {
|
||||
const wrapper = shallow(
|
||||
|
|
|
@ -24,6 +24,8 @@ export const justIdAndTimestamp: Ecs = {
|
|||
timestamp: '2018-11-12T19:03:25.936Z',
|
||||
};
|
||||
|
||||
jest.mock('../../../../../lib/settings/use_kibana_ui_setting');
|
||||
|
||||
describe('netflowRowRenderer', () => {
|
||||
test('renders correctly against snapshot', () => {
|
||||
const browserFields: BrowserFields = {};
|
||||
|
|
|
@ -17,6 +17,8 @@ import { getEmptyValue } from '../../../empty_value';
|
|||
import { plainColumnRenderer } from './plain_column_renderer';
|
||||
import { getValues, deleteItemIdx, findItem } from './helpers';
|
||||
|
||||
jest.mock('../../../../lib/settings/use_kibana_ui_setting');
|
||||
|
||||
const mockFramework = mockFrameworks.default_UTC;
|
||||
|
||||
describe('plain_column_renderer', () => {
|
||||
|
|
|
@ -1,201 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line max-classes-per-file
|
||||
import { IModule, IScope } from 'angular';
|
||||
import * as React from 'react';
|
||||
import * as ReactDOM from 'react-dom';
|
||||
|
||||
import { UIRoutes as KibanaUIRoutes } from 'ui/routes';
|
||||
|
||||
import { DEFAULT_INDEX_KEY, DEFAULT_ANOMALY_SCORE } from '../../../../common/constants';
|
||||
import {
|
||||
AppBufferedKibanaServiceCall,
|
||||
AppFrameworkAdapter,
|
||||
AppKibanaAdapterServiceRefs,
|
||||
AppKibanaUIConfig,
|
||||
AppTimezoneProvider,
|
||||
AppUiKibanaAdapterScope,
|
||||
} from '../../lib';
|
||||
|
||||
const ROOT_ELEMENT_ID = 'react-siem-root';
|
||||
const BREADCRUMBS_ELEMENT_ID = 'react-siem-breadcrumbs';
|
||||
|
||||
export const KibanaConfigContext = React.createContext<Partial<AppKibanaFrameworkAdapter>>({});
|
||||
|
||||
export class AppKibanaFrameworkAdapter implements AppFrameworkAdapter {
|
||||
public bytesFormat?: string;
|
||||
public dateFormat?: string;
|
||||
public dateFormatTz?: string;
|
||||
public darkMode?: boolean;
|
||||
public indexPattern?: string;
|
||||
public anomalyScore?: number;
|
||||
public kbnVersion?: string;
|
||||
public scaledDateFormat?: string;
|
||||
public timezone?: string;
|
||||
|
||||
private adapterService: KibanaAdapterServiceProvider;
|
||||
private timezoneProvider: AppTimezoneProvider;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
private rootComponent: React.ReactElement<any> | null = null;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
private breadcrumbsComponent: React.ReactElement<any> | null = null;
|
||||
|
||||
constructor(uiModule: IModule, uiRoutes: KibanaUIRoutes, timezoneProvider: AppTimezoneProvider) {
|
||||
this.adapterService = new KibanaAdapterServiceProvider();
|
||||
this.timezoneProvider = timezoneProvider;
|
||||
this.register(uiModule, uiRoutes);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
public setUISettings = (key: string, value: any) => {
|
||||
this.adapterService.callOrBuffer(({ config }) => {
|
||||
config.set(key, value);
|
||||
});
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
public render = (component: React.ReactElement<any>) => {
|
||||
this.adapterService.callOrBuffer(() => (this.rootComponent = component));
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
public renderBreadcrumbs = (component: React.ReactElement<any>) => {
|
||||
this.adapterService.callOrBuffer(() => (this.breadcrumbsComponent = component));
|
||||
};
|
||||
|
||||
private register = (adapterModule: IModule, uiRoutes: KibanaUIRoutes) => {
|
||||
adapterModule.provider('kibanaAdapter', this.adapterService);
|
||||
|
||||
adapterModule.directive('appUiKibanaAdapter', () => ({
|
||||
controller: ($scope: AppUiKibanaAdapterScope, $element: JQLite) => ({
|
||||
$onDestroy: () => {
|
||||
const targetRootElement = $element[0].querySelector(`#${ROOT_ELEMENT_ID}`);
|
||||
const targetBreadcrumbsElement = $element[0].querySelector(`#${ROOT_ELEMENT_ID}`);
|
||||
|
||||
if (targetRootElement) {
|
||||
ReactDOM.unmountComponentAtNode(targetRootElement);
|
||||
}
|
||||
|
||||
if (targetBreadcrumbsElement) {
|
||||
ReactDOM.unmountComponentAtNode(targetBreadcrumbsElement);
|
||||
}
|
||||
},
|
||||
$onInit: () => {
|
||||
$scope.topNavMenu = [];
|
||||
},
|
||||
$postLink: () => {
|
||||
$scope.$watchGroup(
|
||||
[
|
||||
() => this.breadcrumbsComponent,
|
||||
() => $element[0].querySelector(`#${BREADCRUMBS_ELEMENT_ID}`),
|
||||
],
|
||||
([breadcrumbsComponent, targetElement]) => {
|
||||
if (!targetElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (breadcrumbsComponent) {
|
||||
ReactDOM.render(breadcrumbsComponent, targetElement);
|
||||
} else {
|
||||
ReactDOM.unmountComponentAtNode(targetElement);
|
||||
}
|
||||
}
|
||||
);
|
||||
$scope.$watchGroup(
|
||||
[() => this.rootComponent, () => $element[0].querySelector(`#${ROOT_ELEMENT_ID}`)],
|
||||
([rootComponent, targetElement]) => {
|
||||
if (!targetElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (rootComponent) {
|
||||
ReactDOM.render(rootComponent, targetElement);
|
||||
} else {
|
||||
ReactDOM.unmountComponentAtNode(targetElement);
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
}),
|
||||
scope: true,
|
||||
template: `
|
||||
<div id="${ROOT_ELEMENT_ID}"></div>
|
||||
`,
|
||||
}));
|
||||
|
||||
adapterModule.run((
|
||||
config: AppKibanaUIConfig,
|
||||
kbnVersion: string,
|
||||
Private: <Provider>(provider: Provider) => Provider,
|
||||
// @ts-ignore: inject kibanaAdapter to force eager installation
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
kibanaAdapter: any
|
||||
) => {
|
||||
this.timezone = Private(this.timezoneProvider)();
|
||||
this.kbnVersion = kbnVersion;
|
||||
this.bytesFormat = config.get('format:bytes:defaultPattern');
|
||||
this.dateFormat = config.get('dateFormat');
|
||||
this.dateFormatTz = config.get('dateFormat:tz');
|
||||
try {
|
||||
this.darkMode = config.get('theme:darkMode');
|
||||
} catch (e) {
|
||||
this.darkMode = false;
|
||||
}
|
||||
this.indexPattern = config.get(DEFAULT_INDEX_KEY);
|
||||
this.anomalyScore = config.get(DEFAULT_ANOMALY_SCORE);
|
||||
this.scaledDateFormat = config.get('dateFormat:scaled');
|
||||
});
|
||||
|
||||
uiRoutes.enable();
|
||||
|
||||
uiRoutes.otherwise({
|
||||
reloadOnSearch: false,
|
||||
template: '<app-ui-kibana-adapter></app-ui-kibana-adapter>',
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
class KibanaAdapterServiceProvider {
|
||||
public serviceRefs: AppKibanaAdapterServiceRefs | null = null;
|
||||
public bufferedCalls: Array<AppBufferedKibanaServiceCall<AppKibanaAdapterServiceRefs>> = [];
|
||||
|
||||
public $get($rootScope: IScope, config: AppKibanaUIConfig) {
|
||||
this.serviceRefs = {
|
||||
config,
|
||||
rootScope: $rootScope,
|
||||
};
|
||||
|
||||
this.applyBufferedCalls(this.bufferedCalls);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public callOrBuffer(serviceCall: (serviceRefs: AppKibanaAdapterServiceRefs) => void) {
|
||||
if (this.serviceRefs !== null) {
|
||||
this.applyBufferedCalls([serviceCall]);
|
||||
} else {
|
||||
this.bufferedCalls.push(serviceCall);
|
||||
}
|
||||
}
|
||||
|
||||
public applyBufferedCalls(
|
||||
bufferedCalls: Array<AppBufferedKibanaServiceCall<AppKibanaAdapterServiceRefs>>
|
||||
) {
|
||||
if (!this.serviceRefs) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.serviceRefs.rootScope.$apply(() => {
|
||||
bufferedCalls.forEach(serviceCall => {
|
||||
if (!this.serviceRefs) {
|
||||
return;
|
||||
}
|
||||
return serviceCall(this.serviceRefs);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { AppFrameworkAdapter } from '../../lib';
|
||||
|
||||
export class AppTestingFrameworkAdapter implements AppFrameworkAdapter {
|
||||
public appState?: object;
|
||||
public bytesFormat?: string;
|
||||
public dateFormat?: string;
|
||||
public dateFormatTz?: string;
|
||||
public indexPattern?: string;
|
||||
public anomalyScore?: number;
|
||||
public kbnVersion?: string;
|
||||
public scaledDateFormat?: string;
|
||||
public timezone?: string;
|
||||
|
||||
constructor() {
|
||||
this.appState = {};
|
||||
}
|
||||
|
||||
public render() {
|
||||
return;
|
||||
}
|
||||
public renderBreadcrumbs() {
|
||||
return;
|
||||
}
|
||||
public setUISettings() {
|
||||
return;
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { ajax } from 'rxjs/ajax';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
import { AppObservableApi, AppObservableApiPostParams, AppObservableApiResponse } from '../../lib';
|
||||
|
||||
export class AppKibanaObservableApiAdapter implements AppObservableApi {
|
||||
private basePath: string;
|
||||
private defaultHeaders: {
|
||||
[headerName: string]: string;
|
||||
};
|
||||
|
||||
constructor({ basePath, xsrfToken }: { basePath: string; xsrfToken: string }) {
|
||||
this.basePath = basePath;
|
||||
this.defaultHeaders = {
|
||||
'kbn-version': xsrfToken,
|
||||
};
|
||||
}
|
||||
|
||||
public post = <RequestBody extends {} = {}, ResponseBody extends {} = {}>({
|
||||
url,
|
||||
body,
|
||||
}: AppObservableApiPostParams<RequestBody>): AppObservableApiResponse<ResponseBody> =>
|
||||
ajax({
|
||||
body: body ? JSON.stringify(body) : undefined,
|
||||
headers: {
|
||||
...this.defaultHeaders,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
method: 'POST',
|
||||
responseType: 'json',
|
||||
timeout: 30000,
|
||||
url: `${this.basePath}/api/${url}`,
|
||||
withCredentials: true,
|
||||
}).pipe(map(({ response, status }) => ({ response, status })));
|
||||
}
|
|
@ -8,6 +8,7 @@ import { HttpLink } from 'apollo-link-http';
|
|||
import { withClientState } from 'apollo-link-state';
|
||||
import { InMemoryCache } from 'apollo-cache-inmemory';
|
||||
import chrome from 'ui/chrome';
|
||||
|
||||
import { errorLink, reTryOneTimeOnErrorLink } from '../../containers/errors';
|
||||
|
||||
export const getLinks = (cache: InMemoryCache) => [
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { ILocationProvider } from 'angular';
|
||||
import { InMemoryCache, IntrospectionFragmentMatcher } from 'apollo-cache-inmemory';
|
||||
import ApolloClient from 'apollo-client';
|
||||
import { ApolloLink } from 'apollo-link';
|
||||
|
@ -12,13 +13,8 @@ import 'ui/autoload/all';
|
|||
import chrome from 'ui/chrome';
|
||||
// @ts-ignore: path dynamic for kibana
|
||||
import { uiModules } from 'ui/modules';
|
||||
import uiRoutes from 'ui/routes';
|
||||
// @ts-ignore: path dynamic for kibana
|
||||
import { timezoneProvider } from 'ui/vis/lib/timezone';
|
||||
|
||||
import introspectionQueryResultData from '../../graphql/introspection.json';
|
||||
import { AppKibanaFrameworkAdapter } from '../adapters/framework/kibana_framework_adapter';
|
||||
import { AppKibanaObservableApiAdapter } from '../adapters/observable_api/kibana_observable_api';
|
||||
import { AppFrontendLibs } from '../lib';
|
||||
import { getLinks } from './helpers';
|
||||
|
||||
|
@ -30,11 +26,6 @@ export function compose(): AppFrontendLibs {
|
|||
}),
|
||||
});
|
||||
|
||||
const observableApi = new AppKibanaObservableApiAdapter({
|
||||
basePath: chrome.getBasePath(),
|
||||
xsrfToken: chrome.getXsrfToken(),
|
||||
});
|
||||
|
||||
const graphQLOptions = {
|
||||
connectToDevTools: process.env.NODE_ENV !== 'production',
|
||||
cache,
|
||||
|
@ -45,12 +36,19 @@ export function compose(): AppFrontendLibs {
|
|||
|
||||
const appModule = uiModules.get('app/siem');
|
||||
|
||||
const framework = new AppKibanaFrameworkAdapter(appModule, uiRoutes, timezoneProvider);
|
||||
// disable angular's location provider
|
||||
appModule.config(($locationProvider: ILocationProvider) => {
|
||||
$locationProvider.html5Mode({
|
||||
enabled: false,
|
||||
requireBase: false,
|
||||
rewriteLinks: false,
|
||||
});
|
||||
});
|
||||
|
||||
// const framework = new AppKibanaFrameworkAdapter(appModule, uiRoutes, timezoneProvider);
|
||||
|
||||
const libs: AppFrontendLibs = {
|
||||
apolloClient,
|
||||
framework,
|
||||
observableApi,
|
||||
};
|
||||
return libs;
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { InMemoryCache } from 'apollo-cache-inmemory';
|
||||
import ApolloClient from 'apollo-client';
|
||||
import { SchemaLink } from 'apollo-link-schema';
|
||||
import { addMockFunctionsToSchema, makeExecutableSchema } from 'graphql-tools';
|
||||
import 'ui/autoload/all';
|
||||
// @ts-ignore: path dynamic for kibana
|
||||
import chrome from 'ui/chrome';
|
||||
// @ts-ignore: path dynamic for kibana
|
||||
import { uiModules } from 'ui/modules';
|
||||
import uiRoutes from 'ui/routes';
|
||||
// @ts-ignore: path dynamic for kibana
|
||||
import { timezoneProvider } from 'ui/vis/lib/timezone';
|
||||
|
||||
import { AppKibanaFrameworkAdapter } from '../adapters/framework/kibana_framework_adapter';
|
||||
import { AppKibanaObservableApiAdapter } from '../adapters/observable_api/kibana_observable_api';
|
||||
import { AppFrontendLibs } from '../lib';
|
||||
|
||||
export function compose(): AppFrontendLibs {
|
||||
const appModule = uiModules.get('app/siem');
|
||||
const observableApi = new AppKibanaObservableApiAdapter({
|
||||
basePath: chrome.getBasePath(),
|
||||
xsrfToken: chrome.getXsrfToken(),
|
||||
});
|
||||
const framework = new AppKibanaFrameworkAdapter(appModule, uiRoutes, timezoneProvider);
|
||||
const typeDefs = `
|
||||
Query {}
|
||||
`;
|
||||
|
||||
const mocks = {
|
||||
Mutation: () => undefined,
|
||||
Query: () => undefined,
|
||||
};
|
||||
|
||||
const schema = makeExecutableSchema({ typeDefs });
|
||||
addMockFunctionsToSchema({
|
||||
mocks,
|
||||
schema,
|
||||
});
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const cache = new InMemoryCache((window as any).__APOLLO_CLIENT__);
|
||||
|
||||
const apolloClient = new ApolloClient({
|
||||
cache,
|
||||
link: new SchemaLink({ schema }),
|
||||
});
|
||||
|
||||
const libs: AppFrontendLibs = {
|
||||
apolloClient,
|
||||
framework,
|
||||
observableApi,
|
||||
};
|
||||
return libs;
|
||||
}
|
|
@ -7,13 +7,9 @@
|
|||
import { IScope } from 'angular';
|
||||
import { NormalizedCacheObject } from 'apollo-cache-inmemory';
|
||||
import ApolloClient from 'apollo-client';
|
||||
import React from 'react';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
export interface AppFrontendLibs {
|
||||
framework: AppFrameworkAdapter;
|
||||
apolloClient: AppApolloClient;
|
||||
observableApi: AppObservableApi;
|
||||
}
|
||||
|
||||
export type AppTimezoneProvider = () => string;
|
||||
|
@ -34,33 +30,6 @@ export interface AppFrameworkAdapter {
|
|||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
setUISettings(key: string, value: any): void;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
render(component: React.ReactElement<any>): void;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
renderBreadcrumbs(component: React.ReactElement<any>): void;
|
||||
}
|
||||
|
||||
export interface AppObservableApiPostParams<RequestBody extends {} = {}> {
|
||||
url: string;
|
||||
body?: RequestBody;
|
||||
}
|
||||
|
||||
export type AppObservableApiResponse<BodyType extends {} = {}> = Observable<{
|
||||
status: number;
|
||||
response: BodyType;
|
||||
}>;
|
||||
|
||||
export interface AppObservableApi {
|
||||
post<RequestBody extends {} = {}, ResponseBody extends {} = {}>(
|
||||
params: AppObservableApiPostParams<RequestBody>
|
||||
): AppObservableApiResponse<ResponseBody>;
|
||||
}
|
||||
|
||||
export interface AppUiKibanaAdapterScope extends IScope {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
breadcrumbs: any[];
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
topNavMenu: any[];
|
||||
}
|
||||
|
||||
export interface AppKibanaUIConfig {
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { mockFrameworks, getMockKibanaUiSetting } from '../../../mock';
|
||||
|
||||
type GenericValue = string | boolean | number;
|
||||
|
||||
export const useKibanaUiSetting = (key: string, defaultValue?: GenericValue) => {
|
||||
return getMockKibanaUiSetting(mockFrameworks.default_UTC)(key);
|
||||
};
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { npSetup, npStart } from 'ui/new_platform';
|
||||
// @ts-ignore: path dynamic for kibana
|
||||
import { timezoneProvider } from 'ui/vis/lib/timezone';
|
||||
|
||||
import { DEFAULT_KBN_VERSION, DEFAULT_TIMEZONE_BROWSER } from '../../../common/constants';
|
||||
import { useObservable } from './use_observable';
|
||||
|
||||
type GenericValue = string | boolean | number;
|
||||
|
||||
/**
|
||||
* This hook behaves like a `useState` hook in that it provides a requested
|
||||
* setting value (with an optional default) from the Kibana UI settings (also
|
||||
* known as "advanced settings") and a setter to change that setting:
|
||||
*
|
||||
* ```
|
||||
* const [darkMode, setDarkMode] = useKibanaUiSetting('theme:darkMode');
|
||||
* ```
|
||||
*
|
||||
* This is not just a static consumption of the value, but will reactively
|
||||
* update when the underlying setting subscription of the `UiSettingsClient`
|
||||
* notifies of a change.
|
||||
*
|
||||
* Unlike the `useState`, it doesn't give type guarantees for the value,
|
||||
* because the underlying `UiSettingsClient` doesn't support that.
|
||||
*/
|
||||
export const useKibanaUiSetting = (key: string, defaultValue?: GenericValue) => {
|
||||
const uiSettingsClient = npSetup.core.uiSettings;
|
||||
const uiInjectedMetadata = npStart.core.injectedMetadata;
|
||||
|
||||
if (key === DEFAULT_KBN_VERSION) {
|
||||
return [uiInjectedMetadata.getKibanaVersion()];
|
||||
}
|
||||
|
||||
if (key === DEFAULT_TIMEZONE_BROWSER) {
|
||||
return [useMemo(() => timezoneProvider(uiSettingsClient)(), [uiSettingsClient])];
|
||||
}
|
||||
|
||||
const uiSetting$ = useMemo(() => uiSettingsClient.get$(key, defaultValue), [uiSettingsClient]);
|
||||
const uiSetting = useObservable(uiSetting$);
|
||||
const setUiSetting = useCallback((value: GenericValue) => uiSettingsClient.set(key, value), [
|
||||
uiSettingsClient,
|
||||
]);
|
||||
return [uiSetting, setUiSetting];
|
||||
};
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
import * as React from 'react';
|
||||
|
||||
import { DEFAULT_KBN_VERSION, DEFAULT_TIMEZONE_BROWSER } from '../../../common/constants';
|
||||
import { HookWrapper } from '../../mock/hook_wrapper';
|
||||
import { useKibanaUiSetting } from './use_kibana_ui_setting';
|
||||
import { mount } from 'enzyme';
|
||||
|
||||
jest.mock('ui/new_platform', () => ({
|
||||
npStart: {
|
||||
core: {
|
||||
injectedMetadata: {
|
||||
getKibanaVersion: () => '8.0.0',
|
||||
},
|
||||
},
|
||||
},
|
||||
npSetup: {
|
||||
core: {
|
||||
uiSettings: {
|
||||
get$: () => 'world',
|
||||
},
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
jest.mock('ui/vis/lib/timezone', () => ({
|
||||
timezoneProvider: () => () => 'America/New_York',
|
||||
}));
|
||||
|
||||
jest.mock('./use_observable', () => ({
|
||||
useObservable: (val: string) => val,
|
||||
}));
|
||||
|
||||
describe('useKibanaUiSetting', () => {
|
||||
test('getKibanaVersion', () => {
|
||||
const [kbnVersion] = useKibanaUiSetting(DEFAULT_KBN_VERSION);
|
||||
expect(kbnVersion).toEqual('8.0.0');
|
||||
});
|
||||
|
||||
test('getTimezone', () => {
|
||||
const wrapper = mount(
|
||||
<HookWrapper hook={() => useKibanaUiSetting(DEFAULT_TIMEZONE_BROWSER)} />
|
||||
);
|
||||
expect(wrapper.text()).toEqual('["America/New_York"]');
|
||||
});
|
||||
|
||||
test('get any ui settings', () => {
|
||||
const wrapper = mount(<HookWrapper hook={() => useKibanaUiSetting('hello')} />);
|
||||
expect(wrapper.text()).toEqual('["world",null]');
|
||||
});
|
||||
});
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
export function useObservable<T>(observable$: Observable<T>): T | undefined;
|
||||
export function useObservable<T>(observable$: Observable<T>, initialValue: T): T;
|
||||
export function useObservable<T>(observable$: Observable<T>, initialValue?: T): T | undefined {
|
||||
const [value, update] = useState<T | undefined>(initialValue);
|
||||
|
||||
useEffect(() => {
|
||||
const s = observable$.subscribe(update);
|
||||
return () => s.unsubscribe();
|
||||
}, [observable$]);
|
||||
|
||||
return value;
|
||||
}
|
|
@ -3,10 +3,37 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
import {
|
||||
DEFAULT_DATE_FORMAT,
|
||||
DEFAULT_DATE_FORMAT_TZ,
|
||||
DEFAULT_BYTES_FORMAT,
|
||||
DEFAULT_KBN_VERSION,
|
||||
DEFAULT_TIMEZONE_BROWSER,
|
||||
} from '../../common/constants';
|
||||
|
||||
import { AppTestingFrameworkAdapter } from '../lib/adapters/framework/testing_framework_adapter';
|
||||
export interface MockFrameworks {
|
||||
bytesFormat: string;
|
||||
dateFormat: string;
|
||||
dateFormatTz: string;
|
||||
timezone: string;
|
||||
}
|
||||
|
||||
export const mockFrameworks: Readonly<Record<string, Partial<AppTestingFrameworkAdapter>>> = {
|
||||
export const getMockKibanaUiSetting = (config: MockFrameworks) => (key: string) => {
|
||||
if (key === DEFAULT_DATE_FORMAT) {
|
||||
return [config.dateFormat];
|
||||
} else if (key === DEFAULT_DATE_FORMAT_TZ) {
|
||||
return [config.dateFormatTz];
|
||||
} else if (key === DEFAULT_BYTES_FORMAT) {
|
||||
return [config.bytesFormat];
|
||||
} else if (key === DEFAULT_KBN_VERSION) {
|
||||
return ['8.0.0'];
|
||||
} else if (key === DEFAULT_TIMEZONE_BROWSER) {
|
||||
return config && config.timezone ? [config.timezone] : ['America/New_York'];
|
||||
}
|
||||
return [null];
|
||||
};
|
||||
|
||||
export const mockFrameworks: Readonly<Record<string, MockFrameworks>> = {
|
||||
bytes_short: {
|
||||
bytesFormat: '0b',
|
||||
dateFormat: 'MMM D, YYYY @ HH:mm:ss.SSS',
|
||||
|
|
|
@ -18,17 +18,13 @@ import { Store } from 'redux';
|
|||
import { BehaviorSubject } from 'rxjs';
|
||||
import { ThemeProvider } from 'styled-components';
|
||||
|
||||
import { KibanaConfigContext } from '../lib/adapters/framework/kibana_framework_adapter';
|
||||
import { AppTestingFrameworkAdapter } from '../lib/adapters/framework/testing_framework_adapter';
|
||||
import { createStore, State } from '../store';
|
||||
import { mockGlobalState } from './global_state';
|
||||
import { mockFrameworks } from './kibana_config';
|
||||
|
||||
const state: State = mockGlobalState;
|
||||
|
||||
interface Props {
|
||||
children: React.ReactNode;
|
||||
mockFramework?: Partial<AppTestingFrameworkAdapter>;
|
||||
store?: Store;
|
||||
onDragEnd?: (result: DropResult, provided: ResponderProvided) => void;
|
||||
}
|
||||
|
@ -42,19 +38,12 @@ export const apolloClientObservable = new BehaviorSubject(apolloClient);
|
|||
|
||||
/** A utility for wrapping children in the providers required to run most tests */
|
||||
export const TestProviders = pure<Props>(
|
||||
({
|
||||
children,
|
||||
store = createStore(state, apolloClientObservable),
|
||||
mockFramework = mockFrameworks.default_UTC,
|
||||
onDragEnd = jest.fn(),
|
||||
}) => (
|
||||
({ children, store = createStore(state, apolloClientObservable), onDragEnd = jest.fn() }) => (
|
||||
<I18nProvider>
|
||||
<ApolloProvider client={apolloClient}>
|
||||
<ReduxStoreProvider store={store}>
|
||||
<ThemeProvider theme={() => ({ eui: euiDarkVars, darkMode: true })}>
|
||||
<KibanaConfigContext.Provider value={mockFramework}>
|
||||
<DragDropContext onDragEnd={onDragEnd}>{children}</DragDropContext>
|
||||
</KibanaConfigContext.Provider>
|
||||
<DragDropContext onDragEnd={onDragEnd}>{children}</DragDropContext>
|
||||
</ThemeProvider>
|
||||
</ReduxStoreProvider>
|
||||
</ApolloProvider>
|
||||
|
|
|
@ -17,6 +17,8 @@ import { TestProviders } from '../../mock';
|
|||
import { MockedProvider } from 'react-apollo/test-utils';
|
||||
import { cloneDeep } from 'lodash/fp';
|
||||
|
||||
jest.mock('../../lib/settings/use_kibana_ui_setting');
|
||||
|
||||
jest.mock('ui/documentation_links', () => ({
|
||||
documentationLinks: {
|
||||
kibana: 'http://www.example.com',
|
||||
|
|
|
@ -21,6 +21,8 @@ import { mocksSource } from '../../containers/source/mock';
|
|||
import { InputsModelId } from '../../store/inputs/constants';
|
||||
import { ActionCreator } from 'typescript-fsa';
|
||||
|
||||
jest.mock('../../lib/settings/use_kibana_ui_setting');
|
||||
|
||||
type Action = 'PUSH' | 'POP' | 'REPLACE';
|
||||
const pop: Action = 'POP';
|
||||
|
||||
|
|
|
@ -17,6 +17,8 @@ import { TestProviders } from '../../mock';
|
|||
import { MockedProvider } from 'react-apollo/test-utils';
|
||||
import { cloneDeep } from 'lodash/fp';
|
||||
|
||||
jest.mock('../../lib/settings/use_kibana_ui_setting');
|
||||
|
||||
jest.mock('ui/documentation_links', () => ({
|
||||
documentationLinks: {
|
||||
kibana: 'http://www.example.com',
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue