[7.x] [ML] Use context and custom hooks to manage legacy dependencies. (#42244) (#42572)

* [ML] Use context and custom hooks to manage legacy dependencies. (#42244)
* [ML] [Job wizards] switching to new kibana context provider (#42512)
This commit is contained in:
Walter Rafelsberger 2019-08-06 08:27:30 +02:00 committed by GitHub
parent 975a4a2936
commit 7a1348ff09
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
62 changed files with 616 additions and 463 deletions

View file

@ -12,11 +12,6 @@ import { uiModules } from 'ui/modules';
const module = uiModules.get('apps/ml');
import 'ui/directives/kbn_href';
import chrome from 'ui/chrome';
import { timefilter } from 'ui/timefilter';
import { timeHistory } from 'ui/timefilter/time_history';
import { NavigationMenuContext } from '../../util/context_utils';
import { NavigationMenu } from './navigation_menu';
@ -25,12 +20,7 @@ module.directive('mlNavMenu', function () {
restrict: 'E',
transclude: true,
link: function (scope, element, attrs) {
ReactDOM.render(
<NavigationMenuContext.Provider value={{ chrome, timefilter, timeHistory }}>
<NavigationMenu tabId={attrs.name} />
</NavigationMenuContext.Provider>,
element[0]
);
ReactDOM.render(<NavigationMenu tabId={attrs.name} />, element[0]);
element.on('$destroy', () => {
ReactDOM.unmountComponentAtNode(element[0]);

View file

@ -4,12 +4,12 @@
* you may not use this file except in compliance with the Elastic License.
*/
import React, { FC, Fragment, useContext, useState, useEffect } from 'react';
import React, { FC, Fragment, useState, useEffect } from 'react';
import { EuiSuperDatePicker } from '@elastic/eui';
import { TimeHistory, TimeRange } from 'ui/timefilter/time_history';
import { mlTimefilterRefresh$ } from '../../../services/timefilter_refresh_service';
import { NavigationMenuContext } from '../../../util/context_utils';
import { useUiContext } from '../../../contexts/ui/use_ui_context';
interface Duration {
start: string;
@ -28,9 +28,8 @@ function getRecentlyUsedRangesFactory(timeHistory: TimeHistory) {
}
export const TopNav: FC = () => {
const navigationMenuContext = useContext(NavigationMenuContext);
const timefilter = navigationMenuContext.timefilter;
const getRecentlyUsedRanges = getRecentlyUsedRangesFactory(navigationMenuContext.timeHistory);
const { chrome, timefilter, timeHistory } = useUiContext();
const getRecentlyUsedRanges = getRecentlyUsedRangesFactory(timeHistory);
const [refreshInterval, setRefreshInterval] = useState(timefilter.getRefreshInterval());
const [time, setTime] = useState(timefilter.getTime());
@ -42,7 +41,7 @@ export const TopNav: FC = () => {
timefilter.isTimeRangeSelectorEnabled
);
const dateFormat = navigationMenuContext.chrome.getUiSettingsClient().get('dateFormat');
const dateFormat = chrome.getUiSettingsClient().get('dateFormat');
useEffect(() => {
timefilter.on('refreshIntervalUpdate', timefilterUpdateListener);

View file

@ -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 { IndexPattern } from 'ui/index_patterns';
export const indexPatternMock = ({
id: 'the-index-pattern-id',
title: 'the-index-pattern-title',
fields: [],
} as unknown) as IndexPattern;

View file

@ -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 { IndexPatterns } from 'ui/index_patterns';
export const indexPatternsMock = (new (class {
fieldFormats = [];
config = {};
savedObjectsClient = {};
refreshSavedObjectsCache = {};
clearCache = jest.fn();
get = jest.fn();
getDefault = jest.fn();
getFields = jest.fn();
getIds = jest.fn();
getTitles = jest.fn();
make = jest.fn();
})() as unknown) as IndexPatterns;

View file

@ -0,0 +1,11 @@
/*
* 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.
*/
export const kibanaConfigMock = {
get: <T>(key: string): T => ({} as T),
has: (key: string) => false,
set: (key: string, value: any) => {},
};

View file

@ -0,0 +1,22 @@
/*
* 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 { indexPatternMock } from './index_pattern';
import { indexPatternsMock } from './index_patterns';
import { kibanaConfigMock } from './kibana_config';
import { savedSearchMock } from './saved_search';
export const kibanaContextValueMock = {
combinedQuery: {
query: 'the-query-string',
language: 'the-query-language',
},
currentIndexPattern: indexPatternMock,
currentSavedSearch: savedSearchMock,
indexPatterns: indexPatternsMock,
kbnBaseUrl: 'url',
kibanaConfig: kibanaConfigMock,
};

View file

@ -0,0 +1,14 @@
/*
* 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.
*/
export const savedSearchMock = {
id: 'the-saved-search-id',
title: 'the-saved-search-title',
searchSource: {},
columns: [],
sort: [],
destroy: () => {},
};

View file

@ -0,0 +1,15 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
export {
KibanaContext,
KibanaContextValue,
SavedSearchQuery,
KibanaConfigTypeFix,
} from './kibana_context';
export { useKibanaContext } from './use_kibana_context';
export { useCurrentIndexPattern } from './use_current_index_pattern';
export { useCurrentSavedSearch } from './use_current_saved_search';

View file

@ -0,0 +1,45 @@
/*
* 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 React from 'react';
import { KibanaConfig } from 'src/legacy/server/kbn_server';
import { SavedSearch } from 'src/legacy/core_plugins/kibana/public/discover/types';
import { IndexPattern, IndexPatterns } from 'ui/index_patterns';
// set() method is missing in original d.ts
export interface KibanaConfigTypeFix extends KibanaConfig {
set(key: string, value: any): void;
}
export interface KibanaContextValue {
combinedQuery: any;
currentIndexPattern: IndexPattern;
currentSavedSearch: SavedSearch;
indexPatterns: IndexPatterns;
kbnBaseUrl: string;
kibanaConfig: KibanaConfigTypeFix;
}
export type SavedSearchQuery = object;
// This context provides dependencies which can be injected
// via angularjs only (like services, currentIndexPattern etc.).
// Because we cannot just import these dependencies, the default value
// for the context is just {} and of type `Partial<KibanaContextValue>`
// for the angularjs based dependencies. Therefore, the
// actual dependencies are set like we did previously with KibanaContext
// in the wrapping angularjs directive. In the custom hook we check if
// the dependencies are present with error reporting if they weren't
// added properly. That's why in tests, these custom hooks must not
// be mocked, instead <UiChrome.Provider value="mocked-value">` needs
// to be used. This guarantees that we have both properly set up
// TypeScript support and runtime checks for these dependencies.
// Multiple custom hooks can be created to access subsets of
// the overall context value if necessary too,
// see useCurrentIndexPattern() for example.
export const KibanaContext = React.createContext<Partial<KibanaContextValue>>({});

View file

@ -0,0 +1,19 @@
/*
* 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 { useContext } from 'react';
import { KibanaContext } from './kibana_context';
export const useCurrentIndexPattern = () => {
const context = useContext(KibanaContext);
if (context.currentIndexPattern === undefined) {
throw new Error('currentIndexPattern is undefined');
}
return context.currentIndexPattern;
};

View file

@ -0,0 +1,19 @@
/*
* 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 { useContext } from 'react';
import { KibanaContext } from './kibana_context';
export const useCurrentSavedSearch = () => {
const context = useContext(KibanaContext);
if (context.currentSavedSearch === undefined) {
throw new Error('currentSavedSearch is undefined');
}
return context.currentSavedSearch;
};

View file

@ -0,0 +1,26 @@
/*
* 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 { useContext } from 'react';
import { KibanaContext, KibanaContextValue } from './kibana_context';
export const useKibanaContext = () => {
const context = useContext(KibanaContext);
if (
context.combinedQuery === undefined ||
context.currentIndexPattern === undefined ||
context.currentSavedSearch === undefined ||
context.indexPatterns === undefined ||
context.kbnBaseUrl === undefined ||
context.kibanaConfig === undefined
) {
throw new Error('required attribute is undefined');
}
return context as KibanaContextValue;
};

View file

@ -0,0 +1,34 @@
/*
* 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.
*/
export const uiChromeMock = {
getBasePath: () => 'basePath',
getUiSettingsClient: () => {
return {
get: (key: string) => {
switch (key) {
case 'dateFormat':
case 'timepicker:timeDefaults':
return {};
case 'timepicker:refreshIntervalDefaults':
return { pause: false, value: 0 };
default:
throw new Error(`Unexpected config key: ${key}`);
}
},
};
},
};
export const uiTimefilterMock = {
getRefreshInterval: () => '30s',
getTime: () => ({ from: 0, to: 0 }),
on: (event: string, reload: () => void) => {},
};
export const uiTimeHistoryMock = {
get: () => [{ from: 0, to: 0 }],
};

View file

@ -0,0 +1,9 @@
/*
* 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 { uiChromeMock } from './mocks';
export const useUiChromeContext = () => uiChromeMock;

View file

@ -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 { uiChromeMock, uiTimefilterMock, uiTimeHistoryMock } from './mocks';
export const useUiContext = () => ({
chrome: uiChromeMock,
timefilter: uiTimefilterMock,
timeHistory: uiTimeHistoryMock,
});

View file

@ -0,0 +1,9 @@
/*
* 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.
*/
// We only export UiContext but not any custom hooks, because if we'd import them
// from here, mocking the hook from jest tests won't work as expected.
export { UiContext } from './ui_context';

View file

@ -0,0 +1,27 @@
/*
* 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 React from 'react';
import chrome from 'ui/chrome';
import { timefilter } from 'ui/timefilter';
import { timeHistory } from 'ui/timefilter/time_history';
// This provides ui/* based imports via React Context.
// Because these dependencies can use regular imports,
// they are just passed on as the default value
// of the Context which means it's not necessary
// to add <UiContext.Provider value="..." />... to the
// wrapping angular directive, reducing a lot of boilerplate.
// The custom hooks like useUiContext() need to be mocked in
// tests because we rely on the properly set up default value.
// Different custom hooks can be created to access parts only
// from the full context value, see useUiChromeContext() as an example.
export const UiContext = React.createContext({
chrome,
timefilter,
timeHistory,
});

View file

@ -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 { useContext } from 'react';
import { UiContext } from './ui_context';
export const useUiChromeContext = () => {
return useContext(UiContext).chrome;
};

View file

@ -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 { useContext } from 'react';
import { UiContext } from './ui_context';
export const useUiContext = () => {
return useContext(UiContext);
};

View file

@ -16,13 +16,6 @@ export {
MAX_COLUMNS,
} from './fields';
export { DropDownLabel, DropDownOption, Label } from './dropdown';
export {
KibanaContext,
KibanaContextValue,
isKibanaContext,
NullableKibanaContextValue,
SavedSearchQuery,
} from './kibana_context';
export {
isTransformIdValid,
refreshTransformList$,

View file

@ -1,38 +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 React from 'react';
import { IndexPattern } from 'ui/index_patterns';
export interface KibanaContextValue {
combinedQuery: any;
currentIndexPattern: IndexPattern;
currentSavedSearch: any;
indexPatterns: any;
kbnBaseUrl: string;
kibanaConfig: any;
}
export type SavedSearchQuery = object;
// Because we're only getting the actual contextvalue within a wrapping angular component,
// we need to initialize here with `null` because TypeScript doesn't allow createContext()
// without a default value. The nullable union type takes care of allowing
// the actual required type and `null`.
export type NullableKibanaContextValue = KibanaContextValue | null;
export const KibanaContext = React.createContext<NullableKibanaContextValue>(null);
export function isKibanaContext(arg: any): arg is KibanaContextValue {
return (
arg.combinedQuery !== undefined &&
arg.currentIndexPattern !== undefined &&
arg.currentSavedSearch !== undefined &&
arg.indexPatterns !== undefined &&
typeof arg.kbnBaseUrl === 'string' &&
arg.kibanaConfig !== undefined
);
}

View file

@ -6,8 +6,6 @@
import rison from 'rison-node';
import chrome from 'ui/chrome';
export function moveToDataFrameWizard() {
window.location.href = '#/data_frames/new_transform';
}
@ -16,7 +14,7 @@ export function moveToDataFrameTransformList() {
window.location.href = '#/data_frames';
}
export function moveToDiscover(indexPatternId: string, kbnBaseUrl: string) {
export function moveToDiscover(indexPatternId: string, baseUrl: string) {
const _g = rison.encode({});
// Add the index pattern ID to the appState part of the URL.
@ -24,7 +22,6 @@ export function moveToDiscover(indexPatternId: string, kbnBaseUrl: string) {
index: indexPatternId,
});
const baseUrl = chrome.addBasePath(kbnBaseUrl);
const hash = `#/discover?_g=${_g}&_a=${_a}`;
window.location.href = `${baseUrl}${hash}`;

View file

@ -9,6 +9,7 @@ import { DefaultOperator } from 'elasticsearch';
import { IndexPattern } from 'ui/index_patterns';
import { dictionaryToArray } from '../../../common/types/common';
import { SavedSearchQuery } from '../../contexts/kibana';
import { StepDefineExposedState } from '../pages/data_frame_new_pivot/components/step_define/step_define_form';
import { StepDetailsExposedState } from '../pages/data_frame_new_pivot/components/step_details/step_details_form';
@ -24,7 +25,6 @@ import {
import { PivotAggsConfig } from './pivot_aggs';
import { DateHistogramAgg, HistogramAgg, TermsAgg } from './pivot_group_by';
import { SavedSearchQuery } from './kibana_context';
import { PreviewRequestBody, CreateRequestBody } from './transform';
export interface SimpleQuery {

View file

@ -14,13 +14,8 @@ import uiChrome from 'ui/chrome';
const module = uiModules.get('apps/ml', ['react']);
import { I18nContext } from 'ui/i18n';
import chrome from 'ui/chrome';
import { timefilter } from 'ui/timefilter';
import { timeHistory } from 'ui/timefilter/time_history';
import { InjectorService } from '../../../../common/types/angular';
import { NavigationMenuContext } from '../../../util/context_utils';
import { Page } from './page';
module.directive('mlDataFrameAccessDenied', ($injector: InjectorService) => {
@ -41,9 +36,7 @@ module.directive('mlDataFrameAccessDenied', ($injector: InjectorService) => {
ReactDOM.render(
<I18nContext>
<NavigationMenuContext.Provider value={{ chrome, timefilter, timeHistory }}>
<Page goToKibana={goToKibana} retry={retry} />
</NavigationMenuContext.Provider>
<Page goToKibana={goToKibana} retry={retry} />
</I18nContext>,
element[0]
);

View file

@ -5,16 +5,42 @@ exports[`Data Frame: <SourceIndexPreview /> Minimal initialization 1`] = `
<ContextProvider
value={
Object {
"combinedQuery": Object {},
"combinedQuery": Object {
"language": "the-query-language",
"query": "the-query-string",
},
"currentIndexPattern": Object {
"fields": Array [],
"id": "the-index-pattern-id",
"title": "the-index-pattern-title",
},
"currentSavedSearch": Object {},
"indexPatterns": Object {},
"currentSavedSearch": Object {
"columns": Array [],
"destroy": [Function],
"id": "the-saved-search-id",
"searchSource": Object {},
"sort": Array [],
"title": "the-saved-search-title",
},
"indexPatterns": _temp {
"clearCache": [MockFunction],
"config": Object {},
"fieldFormats": Array [],
"get": [MockFunction],
"getDefault": [MockFunction],
"getFields": [MockFunction],
"getIds": [MockFunction],
"getTitles": [MockFunction],
"make": [MockFunction],
"refreshSavedObjectsCache": Object {},
"savedObjectsClient": Object {},
},
"kbnBaseUrl": "url",
"kibanaConfig": Object {},
"kibanaConfig": Object {
"get": [Function],
"has": [Function],
"set": [Function],
},
}
}
>

View file

@ -7,8 +7,10 @@
import { shallow } from 'enzyme';
import React from 'react';
import { IndexPattern } from 'ui/index_patterns';
import { getPivotQuery, KibanaContext } from '../../../../common';
import { KibanaContext } from '../../../../../contexts/kibana';
import { kibanaContextValueMock } from '../../../../../contexts/kibana/__mocks__/kibana_context_value';
import { getPivotQuery } from '../../../../common';
import { SourceIndexPreview } from './source_index_preview';
@ -20,12 +22,6 @@ jest.mock('react', () => {
describe('Data Frame: <SourceIndexPreview />', () => {
test('Minimal initialization', () => {
const currentIndexPattern = ({
id: 'the-index-pattern-id',
title: 'the-index-pattern-title',
fields: [],
} as unknown) as IndexPattern;
const props = {
query: getPivotQuery('the-query'),
};
@ -34,16 +30,7 @@ describe('Data Frame: <SourceIndexPreview />', () => {
// with the Provider being the outer most component.
const wrapper = shallow(
<div>
<KibanaContext.Provider
value={{
combinedQuery: {},
currentIndexPattern,
currentSavedSearch: {},
indexPatterns: {},
kbnBaseUrl: 'url',
kibanaConfig: {},
}}
>
<KibanaContext.Provider value={kibanaContextValueMock}>
<SourceIndexPreview {...props} />
</KibanaContext.Provider>
</div>

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import React, { FunctionComponent, useContext, useState } from 'react';
import React, { FunctionComponent, useState } from 'react';
import moment from 'moment-timezone';
import { i18n } from '@kbn/i18n';
@ -43,13 +43,13 @@ import { KBN_FIELD_TYPES } from '../../../../../../common/constants/field_types'
import { Dictionary } from '../../../../../../common/types/common';
import { formatHumanReadableDateTimeSeconds } from '../../../../../util/date_utils';
import { useCurrentIndexPattern } from '../../../../../contexts/kibana';
import {
isKibanaContext,
toggleSelectedField,
EsDoc,
EsFieldName,
MAX_COLUMNS,
KibanaContext,
PivotQuery,
} from '../../../../common';
@ -100,13 +100,7 @@ interface Props {
export const SourceIndexPreview: React.SFC<Props> = React.memo(({ cellClick, query }) => {
const [clearTable, setClearTable] = useState(false);
const kibanaContext = useContext(KibanaContext);
if (!isKibanaContext(kibanaContext)) {
return null;
}
const indexPattern = kibanaContext.currentIndexPattern;
const indexPattern = useCurrentIndexPattern();
const [selectedFields, setSelectedFields] = useState([] as EsFieldName[]);
const [isColumnsPopoverVisible, setColumnsPopoverVisible] = useState(false);

View file

@ -5,16 +5,42 @@ exports[`Data Frame: <StepCreateForm /> Minimal initialization 1`] = `
<ContextProvider
value={
Object {
"combinedQuery": Object {},
"combinedQuery": Object {
"language": "the-query-language",
"query": "the-query-string",
},
"currentIndexPattern": Object {
"fields": Array [],
"id": "the-index-pattern-id",
"title": "the-index-pattern-title",
},
"currentSavedSearch": Object {},
"indexPatterns": Object {},
"currentSavedSearch": Object {
"columns": Array [],
"destroy": [Function],
"id": "the-saved-search-id",
"searchSource": Object {},
"sort": Array [],
"title": "the-saved-search-title",
},
"indexPatterns": _temp {
"clearCache": [MockFunction],
"config": Object {},
"fieldFormats": Array [],
"get": [MockFunction],
"getDefault": [MockFunction],
"getFields": [MockFunction],
"getIds": [MockFunction],
"getTitles": [MockFunction],
"make": [MockFunction],
"refreshSavedObjectsCache": Object {},
"savedObjectsClient": Object {},
},
"kbnBaseUrl": "url",
"kibanaConfig": Object {},
"kibanaConfig": Object {
"get": [Function],
"has": [Function],
"set": [Function],
},
}
}
>

View file

@ -7,10 +7,12 @@
import { shallow } from 'enzyme';
import React from 'react';
import { KibanaContext } from '../../../../common';
import { KibanaContext } from '../../../../../contexts/kibana';
import { kibanaContextValueMock } from '../../../../../contexts/kibana/__mocks__/kibana_context_value';
import { StepCreateForm } from './step_create_form';
import { IndexPattern } from 'ui/index_patterns';
jest.mock('../../../../../contexts/ui/use_ui_chrome_context');
// workaround to make React.memo() work with enzyme
jest.mock('react', () => {
@ -28,26 +30,11 @@ describe('Data Frame: <StepCreateForm />', () => {
onChange() {},
};
const currentIndexPattern = ({
id: 'the-index-pattern-id',
title: 'the-index-pattern-title',
fields: [],
} as unknown) as IndexPattern;
// Using a wrapping <div> element because shallow() would fail
// with the Provider being the outer most component.
const wrapper = shallow(
<div>
<KibanaContext.Provider
value={{
combinedQuery: {},
currentIndexPattern,
currentSavedSearch: {},
indexPatterns: {},
kbnBaseUrl: 'url',
kibanaConfig: {},
}}
>
<KibanaContext.Provider value={kibanaContextValueMock}>
<StepCreateForm {...props} />
</KibanaContext.Provider>
</div>

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import React, { Fragment, SFC, useContext, useEffect, useState } from 'react';
import React, { Fragment, SFC, useEffect, useState } from 'react';
import { idx } from '@kbn/elastic-idx';
import { i18n } from '@kbn/i18n';
import { toastNotifications } from 'ui/notify';
@ -31,14 +31,11 @@ import {
} from '@elastic/eui';
import { ml } from '../../../../../services/ml_api_service';
import { useKibanaContext } from '../../../../../contexts/kibana/use_kibana_context';
import { useUiChromeContext } from '../../../../../contexts/ui/use_ui_chrome_context';
import { PROGRESS_JOBS_REFRESH_INTERVAL_MS } from '../../../../../../common/constants/jobs_list';
import {
isKibanaContext,
KibanaContext,
moveToDataFrameTransformList,
moveToDiscover,
} from '../../../../common';
import { moveToDataFrameTransformList, moveToDiscover } from '../../../../common';
export interface StepDetailsExposedState {
created: boolean;
@ -73,11 +70,8 @@ export const StepCreateForm: SFC<Props> = React.memo(
undefined
);
const kibanaContext = useContext(KibanaContext);
if (!isKibanaContext(kibanaContext)) {
return null;
}
const kibanaContext = useKibanaContext();
const baseUrl = useUiChromeContext().addBasePath(kibanaContext.kbnBaseUrl);
useEffect(() => {
onChange({ created, started, indexPatternId });
@ -156,6 +150,18 @@ export const StepCreateForm: SFC<Props> = React.memo(
const id = await newIndexPattern.create();
// id returns false if there's a duplicate index pattern.
if (id === false) {
toastNotifications.addDanger(
i18n.translate('xpack.ml.dataframe.stepCreateForm.duplicateIndexPatternErrorMessage', {
defaultMessage:
'An error occurred creating the Kibana index pattern {indexPatternName}: The index pattern already exists.',
values: { indexPatternName },
})
);
return;
}
// check if there's a default index pattern, if not,
// set the newly created one as the default index pattern.
if (!kibanaContext.kibanaConfig.get('defaultIndex')) {
@ -163,7 +169,7 @@ export const StepCreateForm: SFC<Props> = React.memo(
}
toastNotifications.addSuccess(
i18n.translate('xpack.ml.dataframe.stepCreateForm.reateIndexPatternSuccessMessage', {
i18n.translate('xpack.ml.dataframe.stepCreateForm.createIndexPatternSuccessMessage', {
defaultMessage: 'Kibana index pattern {indexPatternName} created successfully.',
values: { indexPatternName },
})
@ -391,7 +397,7 @@ export const StepCreateForm: SFC<Props> = React.memo(
defaultMessage: 'Use Discover to explore the data frame pivot.',
}
)}
onClick={() => moveToDiscover(indexPatternId, kibanaContext.kbnBaseUrl)}
onClick={() => moveToDiscover(indexPatternId, baseUrl)}
/>
</EuiFlexItem>
)}

View file

@ -5,16 +5,42 @@ exports[`Data Frame: <PivotPreview /> Minimal initialization 1`] = `
<ContextProvider
value={
Object {
"combinedQuery": Object {},
"combinedQuery": Object {
"language": "the-query-language",
"query": "the-query-string",
},
"currentIndexPattern": Object {
"fields": Array [],
"id": "the-index-pattern-id",
"title": "the-index-pattern-title",
},
"currentSavedSearch": Object {},
"indexPatterns": Object {},
"currentSavedSearch": Object {
"columns": Array [],
"destroy": [Function],
"id": "the-saved-search-id",
"searchSource": Object {},
"sort": Array [],
"title": "the-saved-search-title",
},
"indexPatterns": _temp {
"clearCache": [MockFunction],
"config": Object {},
"fieldFormats": Array [],
"get": [MockFunction],
"getDefault": [MockFunction],
"getFields": [MockFunction],
"getIds": [MockFunction],
"getTitles": [MockFunction],
"make": [MockFunction],
"refreshSavedObjectsCache": Object {},
"savedObjectsClient": Object {},
},
"kbnBaseUrl": "url",
"kibanaConfig": Object {},
"kibanaConfig": Object {
"get": [Function],
"has": [Function],
"set": [Function],
},
}
}
>

View file

@ -5,16 +5,42 @@ exports[`Data Frame: <DefinePivotForm /> Minimal initialization 1`] = `
<ContextProvider
value={
Object {
"combinedQuery": Object {},
"combinedQuery": Object {
"language": "the-query-language",
"query": "the-query-string",
},
"currentIndexPattern": Object {
"fields": Array [],
"id": "the-index-pattern-id",
"title": "the-index-pattern-title",
},
"currentSavedSearch": Object {},
"indexPatterns": Object {},
"currentSavedSearch": Object {
"columns": Array [],
"destroy": [Function],
"id": "the-saved-search-id",
"searchSource": Object {},
"sort": Array [],
"title": "the-saved-search-title",
},
"indexPatterns": _temp {
"clearCache": [MockFunction],
"config": Object {},
"fieldFormats": Array [],
"get": [MockFunction],
"getDefault": [MockFunction],
"getFields": [MockFunction],
"getIds": [MockFunction],
"getTitles": [MockFunction],
"make": [MockFunction],
"refreshSavedObjectsCache": Object {},
"savedObjectsClient": Object {},
},
"kbnBaseUrl": "url",
"kibanaConfig": Object {},
"kibanaConfig": Object {
"get": [Function],
"has": [Function],
"set": [Function],
},
}
}
>

View file

@ -5,16 +5,42 @@ exports[`Data Frame: <DefinePivotSummary /> Minimal initialization 1`] = `
<ContextProvider
value={
Object {
"combinedQuery": Object {},
"combinedQuery": Object {
"language": "the-query-language",
"query": "the-query-string",
},
"currentIndexPattern": Object {
"fields": Array [],
"id": "the-index-pattern-id",
"title": "the-index-pattern-title",
},
"currentSavedSearch": Object {},
"indexPatterns": Object {},
"currentSavedSearch": Object {
"columns": Array [],
"destroy": [Function],
"id": "the-saved-search-id",
"searchSource": Object {},
"sort": Array [],
"title": "the-saved-search-title",
},
"indexPatterns": _temp {
"clearCache": [MockFunction],
"config": Object {},
"fieldFormats": Array [],
"get": [MockFunction],
"getDefault": [MockFunction],
"getFields": [MockFunction],
"getIds": [MockFunction],
"getTitles": [MockFunction],
"make": [MockFunction],
"refreshSavedObjectsCache": Object {},
"savedObjectsClient": Object {},
},
"kbnBaseUrl": "url",
"kibanaConfig": Object {},
"kibanaConfig": Object {
"get": [Function],
"has": [Function],
"set": [Function],
},
}
}
>

View file

@ -7,17 +7,17 @@
import { shallow } from 'enzyme';
import React from 'react';
import { KibanaContext } from '../../../../../contexts/kibana';
import { kibanaContextValueMock } from '../../../../../contexts/kibana/__mocks__/kibana_context_value';
import {
getPivotQuery,
KibanaContext,
PivotAggsConfig,
PivotGroupByConfig,
PIVOT_SUPPORTED_AGGS,
PIVOT_SUPPORTED_GROUP_BY_AGGS,
} from '../../../../common';
import { IndexPattern } from 'ui/index_patterns';
import { PivotPreview } from './pivot_preview';
// workaround to make React.memo() work with enzyme
@ -28,12 +28,6 @@ jest.mock('react', () => {
describe('Data Frame: <PivotPreview />', () => {
test('Minimal initialization', () => {
const currentIndexPattern = ({
id: 'the-index-pattern-id',
title: 'the-index-pattern-title',
fields: [],
} as unknown) as IndexPattern;
const groupBy: PivotGroupByConfig = {
agg: PIVOT_SUPPORTED_GROUP_BY_AGGS.TERMS,
field: 'the-group-by-field',
@ -56,16 +50,7 @@ describe('Data Frame: <PivotPreview />', () => {
// with the Provider being the outer most component.
const wrapper = shallow(
<div>
<KibanaContext.Provider
value={{
combinedQuery: {},
currentIndexPattern,
currentSavedSearch: {},
indexPatterns: {},
kbnBaseUrl: 'url',
kibanaConfig: {},
}}
>
<KibanaContext.Provider value={kibanaContextValueMock}>
<PivotPreview {...props} />
</KibanaContext.Provider>
</div>

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import React, { SFC, useContext, useEffect, useRef, useState } from 'react';
import React, { SFC, useEffect, useRef, useState } from 'react';
import moment from 'moment-timezone';
import { i18n } from '@kbn/i18n';
@ -28,11 +28,11 @@ import { Dictionary, dictionaryToArray } from '../../../../../../common/types/co
import { ES_FIELD_TYPES } from '../../../../../../common/constants/field_types';
import { formatHumanReadableDateTimeSeconds } from '../../../../../util/date_utils';
import { useCurrentIndexPattern } from '../../../../../contexts/kibana';
import {
getFlattenedFields,
isKibanaContext,
PreviewRequestBody,
KibanaContext,
PivotAggsConfigDict,
PivotGroupByConfig,
PivotGroupByConfigDict,
@ -139,13 +139,8 @@ interface PivotPreviewProps {
export const PivotPreview: SFC<PivotPreviewProps> = React.memo(({ aggs, groupBy, query }) => {
const [clearTable, setClearTable] = useState(false);
const kibanaContext = useContext(KibanaContext);
const indexPattern = useCurrentIndexPattern();
if (!isKibanaContext(kibanaContext)) {
return null;
}
const indexPattern = kibanaContext.currentIndexPattern;
const {
dataFramePreviewData,
dataFramePreviewMappings,

View file

@ -7,14 +7,15 @@
import { shallow } from 'enzyme';
import React from 'react';
import { KibanaContext } from '../../../../../contexts/kibana';
import { kibanaContextValueMock } from '../../../../../contexts/kibana/__mocks__/kibana_context_value';
import {
KibanaContext,
PivotAggsConfigDict,
PivotGroupByConfigDict,
PIVOT_SUPPORTED_AGGS,
PIVOT_SUPPORTED_GROUP_BY_AGGS,
} from '../../../../common';
import { IndexPattern } from 'ui/index_patterns';
import { StepDefineForm, isAggNameConflict } from './step_define_form';
// workaround to make React.memo() work with enzyme
@ -25,26 +26,11 @@ jest.mock('react', () => {
describe('Data Frame: <DefinePivotForm />', () => {
test('Minimal initialization', () => {
const currentIndexPattern = ({
id: 'the-index-pattern-id',
title: 'the-index-pattern-title',
fields: [],
} as unknown) as IndexPattern;
// Using a wrapping <div> element because shallow() would fail
// with the Provider being the outer most component.
const wrapper = shallow(
<div>
<KibanaContext.Provider
value={{
combinedQuery: {},
currentIndexPattern,
currentSavedSearch: {},
indexPatterns: {},
kbnBaseUrl: 'url',
kibanaConfig: {},
}}
>
<KibanaContext.Provider value={kibanaContextValueMock}>
<StepDefineForm onChange={() => {}} />
</KibanaContext.Provider>
</div>

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import React, { Fragment, SFC, useContext, useEffect, useState } from 'react';
import React, { Fragment, SFC, useEffect, useState } from 'react';
import { i18n } from '@kbn/i18n';
@ -37,14 +37,17 @@ import { PivotPreview } from './pivot_preview';
import { KqlFilterBar } from '../../../../../components/kql_filter_bar';
import { SwitchModal } from './switch_modal';
import {
useKibanaContext,
KibanaContextValue,
SavedSearchQuery,
} from '../../../../../contexts/kibana';
import {
AggName,
DropDownLabel,
getPivotQuery,
getPreviewRequestBody,
isKibanaContext,
KibanaContext,
KibanaContextValue,
PivotAggDict,
PivotAggsConfig,
PivotAggsConfigDict,
@ -53,7 +56,6 @@ import {
PivotGroupByConfigDict,
PivotSupportedGroupByAggs,
PIVOT_SUPPORTED_AGGS,
SavedSearchQuery,
} from '../../../../common';
import { getPivotDropdownOptions } from './common';
@ -197,11 +199,7 @@ interface Props {
}
export const StepDefineForm: SFC<Props> = React.memo(({ overrides = {}, onChange }) => {
const kibanaContext = useContext(KibanaContext);
if (!isKibanaContext(kibanaContext)) {
return null;
}
const kibanaContext = useKibanaContext();
const indexPattern = kibanaContext.currentIndexPattern;

View file

@ -7,14 +7,15 @@
import { shallow } from 'enzyme';
import React from 'react';
import { KibanaContext } from '../../../../../contexts/kibana';
import { kibanaContextValueMock } from '../../../../../contexts/kibana/__mocks__/kibana_context_value';
import {
KibanaContext,
PivotAggsConfig,
PivotGroupByConfig,
PIVOT_SUPPORTED_AGGS,
PIVOT_SUPPORTED_GROUP_BY_AGGS,
} from '../../../../common';
import { IndexPattern } from 'ui/index_patterns';
import { StepDefineExposedState } from './step_define_form';
import { StepDefineSummary } from './step_define_summary';
@ -26,12 +27,6 @@ jest.mock('react', () => {
describe('Data Frame: <DefinePivotSummary />', () => {
test('Minimal initialization', () => {
const currentIndexPattern = ({
id: 'the-index-pattern-id',
title: 'the-index-pattern-title',
fields: [],
} as unknown) as IndexPattern;
const groupBy: PivotGroupByConfig = {
agg: PIVOT_SUPPORTED_GROUP_BY_AGGS.TERMS,
field: 'the-group-by-field',
@ -59,16 +54,7 @@ describe('Data Frame: <DefinePivotSummary />', () => {
// with the Provider being the outer most component.
const wrapper = shallow(
<div>
<KibanaContext.Provider
value={{
combinedQuery: {},
currentIndexPattern,
currentSavedSearch: {},
indexPatterns: {},
kbnBaseUrl: 'url',
kibanaConfig: {},
}}
>
<KibanaContext.Provider value={kibanaContextValueMock}>
<StepDefineSummary {...props} />
</KibanaContext.Provider>
</div>

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import React, { Fragment, SFC, useContext } from 'react';
import React, { Fragment, SFC } from 'react';
import { i18n } from '@kbn/i18n';
@ -17,11 +17,13 @@ import {
EuiText,
} from '@elastic/eui';
import { useKibanaContext } from '../../../../../contexts/kibana';
import { AggListSummary } from '../aggregation_list';
import { GroupByListSummary } from '../group_by_list';
import { PivotPreview } from './pivot_preview';
import { getPivotQuery, isKibanaContext, KibanaContext } from '../../../../common';
import { getPivotQuery } from '../../../../common';
import { StepDefineExposedState } from './step_define_form';
const defaultSearch = '*';
@ -33,11 +35,7 @@ export const StepDefineSummary: SFC<StepDefineExposedState> = ({
groupByList,
aggList,
}) => {
const kibanaContext = useContext(KibanaContext);
if (!isKibanaContext(kibanaContext)) {
return null;
}
const kibanaContext = useKibanaContext();
const pivotQuery = getPivotQuery(searchQuery);
let useCodeBlock = false;

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import React, { Fragment, SFC, useContext, useEffect, useState } from 'react';
import React, { Fragment, SFC, useEffect, useState } from 'react';
import { i18n } from '@kbn/i18n';
import { metadata } from 'ui/metadata';
@ -12,17 +12,16 @@ import { toastNotifications } from 'ui/notify';
import { EuiLink, EuiSwitch, EuiFieldText, EuiForm, EuiFormRow, EuiSelect } from '@elastic/eui';
import { useKibanaContext } from '../../../../../contexts/kibana';
import { isValidIndexName } from '../../../../../../common/util/es_utils';
import { ml } from '../../../../../services/ml_api_service';
import {
delayFormatRegex,
isKibanaContext,
isTransformIdValid,
DataFrameTransformId,
DataFrameTransformPivotConfig,
KibanaContext,
} from '../../../../common';
import { EsIndexName, IndexPatternTitle } from './common';
@ -58,11 +57,7 @@ interface Props {
}
export const StepDetailsForm: SFC<Props> = React.memo(({ overrides = {}, onChange }) => {
const kibanaContext = useContext(KibanaContext);
if (!isKibanaContext(kibanaContext)) {
return null;
}
const kibanaContext = useKibanaContext();
const defaults = { ...getDefaultStepDetailsState(), ...overrides };
@ -123,7 +118,7 @@ export const StepDetailsForm: SFC<Props> = React.memo(({ overrides = {}, onChang
}
try {
setIndexPatternTitles(await kibanaContext.indexPatterns.getTitles());
setIndexPatternTitles((await kibanaContext.indexPatterns.getTitles(false)) as string[]);
} catch (e) {
toastNotifications.addDanger(
i18n.translate('xpack.ml.dataframe.stepDetailsForm.errorGettingIndexPatternTitles', {

View file

@ -4,13 +4,15 @@
* you may not use this file except in compliance with the Elastic License.
*/
import React, { Fragment, SFC, useContext, useRef, useState } from 'react';
import React, { Fragment, SFC, useRef, useState } from 'react';
import { i18n } from '@kbn/i18n';
import { EuiSteps, EuiStepStatus } from '@elastic/eui';
import { isKibanaContext, getCreateRequestBody, KibanaContext } from '../../../../common';
import { useKibanaContext } from '../../../../../contexts/kibana';
import { getCreateRequestBody } from '../../../../common';
import {
StepDefineExposedState,
@ -61,11 +63,7 @@ const StepDefine: SFC<DefinePivotStepProps> = ({
};
export const Wizard: SFC = React.memo(() => {
const kibanaContext = useContext(KibanaContext);
if (!isKibanaContext(kibanaContext)) {
return null;
}
const kibanaContext = useKibanaContext();
const indexPattern = kibanaContext.currentIndexPattern;

View file

@ -7,16 +7,15 @@
import React from 'react';
import ReactDOM from 'react-dom';
import chrome from 'ui/chrome';
// @ts-ignore
import { uiModules } from 'ui/modules';
const module = uiModules.get('apps/ml', ['react']);
import { IndexPattern } from 'ui/index_patterns';
import { IndexPattern, IndexPatterns } from 'ui/index_patterns';
import { I18nContext } from 'ui/i18n';
import { IPrivate } from 'ui/private';
import { timefilter } from 'ui/timefilter';
import { timeHistory } from 'ui/timefilter/time_history';
import { InjectorService } from '../../../../common/types/angular';
// @ts-ignore
@ -28,8 +27,7 @@ type CreateSearchItems = () => {
combinedQuery: any;
};
import { NavigationMenuContext } from '../../../util/context_utils';
import { KibanaContext } from '../../common';
import { KibanaConfigTypeFix, KibanaContext } from '../../../contexts/kibana';
import { Page } from './page';
module.directive('mlNewDataFrame', ($injector: InjectorService) => {
@ -37,10 +35,10 @@ module.directive('mlNewDataFrame', ($injector: InjectorService) => {
scope: {},
restrict: 'E',
link: (scope: ng.IScope, element: ng.IAugmentedJQuery) => {
const indexPatterns = $injector.get('indexPatterns');
const indexPatterns = $injector.get<IndexPatterns>('indexPatterns');
const kbnBaseUrl = $injector.get<string>('kbnBaseUrl');
const kibanaConfig = $injector.get('config');
const Private: IPrivate = $injector.get('Private');
const kibanaConfig = $injector.get<KibanaConfigTypeFix>('config');
const Private = $injector.get<IPrivate>('Private');
timefilter.disableTimeRangeSelector();
timefilter.disableAutoRefreshSelector();
@ -59,11 +57,9 @@ module.directive('mlNewDataFrame', ($injector: InjectorService) => {
ReactDOM.render(
<I18nContext>
<NavigationMenuContext.Provider value={{ chrome, timefilter, timeHistory }}>
<KibanaContext.Provider value={kibanaContext}>
<Page />
</KibanaContext.Provider>
</NavigationMenuContext.Provider>
<KibanaContext.Provider value={kibanaContext}>
<Page />
</KibanaContext.Provider>
</I18nContext>,
element[0]
);

View file

@ -10,12 +10,8 @@ import ReactDOM from 'react-dom';
// @ts-ignore
import { uiModules } from 'ui/modules';
const module = uiModules.get('apps/ml', ['react']);
import chrome from 'ui/chrome';
import { timefilter } from 'ui/timefilter';
import { timeHistory } from 'ui/timefilter/time_history';
import { I18nContext } from 'ui/i18n';
import { NavigationMenuContext } from '../../../util/context_utils';
import { Page } from './page';
module.directive('mlDataFramePage', () => {
@ -25,9 +21,7 @@ module.directive('mlDataFramePage', () => {
link: (scope: ng.IScope, element: ng.IAugmentedJQuery) => {
ReactDOM.render(
<I18nContext>
<NavigationMenuContext.Provider value={{ chrome, timefilter, timeHistory }}>
<Page />
</NavigationMenuContext.Provider>
<Page />
</I18nContext>,
element[0]
);

View file

@ -22,11 +22,8 @@ import {
import { isFullLicense } from '../../license/check_license';
import { FormattedMessage, injectI18n } from '@kbn/i18n/react';
import chrome from 'ui/chrome';
import { timefilter } from 'ui/timefilter';
import { timeHistory } from 'ui/timefilter/time_history';
import { NavigationMenuContext } from '../../util/context_utils';
import { NavigationMenu } from '../../components/navigation_menu/navigation_menu';
function startTrialDescription() {
@ -57,7 +54,7 @@ export const DatavisualizerSelector = injectI18n(function (props) {
const startTrialVisible = isFullLicense() === false;
return (
<NavigationMenuContext.Provider value={{ chrome, timefilter, timeHistory }}>
<Fragment>
<NavigationMenu tabId="datavisualizer" />
<EuiPage restrictWidth={1000}>
<EuiPageBody>
@ -182,6 +179,6 @@ export const DatavisualizerSelector = injectI18n(function (props) {
)}
</EuiPageBody>
</EuiPage>
</NavigationMenuContext.Provider>
</Fragment>
);
});

View file

@ -17,12 +17,8 @@ import { uiModules } from 'ui/modules';
const module = uiModules.get('apps/ml');
import { I18nContext } from 'ui/i18n';
import chrome from 'ui/chrome';
import { timefilter } from 'ui/timefilter';
import { timeHistory } from 'ui/timefilter/time_history';
import { jobSelectServiceFactory } from '../components/job_selector/job_select_service_utils';
import { NavigationMenuContext } from '../util/context_utils';
import { Explorer } from './explorer';
import { EXPLORER_ACTION } from './explorer_constants';
@ -37,17 +33,15 @@ module.directive('mlExplorerReactWrapper', function (config, globalState) {
ReactDOM.render(
<I18nContext>
<NavigationMenuContext.Provider value={{ chrome, timefilter, timeHistory }}>
<Explorer {...{
appStateHandler: scope.appStateHandler,
config,
dateFormatTz,
globalState,
jobSelectService,
MlTimeBuckets: scope.MlTimeBuckets,
}}
/>
</NavigationMenuContext.Provider>
<Explorer {...{
appStateHandler: scope.appStateHandler,
config,
dateFormatTz,
globalState,
jobSelectService,
MlTimeBuckets: scope.MlTimeBuckets,
}}
/>
</I18nContext>,
element[0]
);

View file

@ -4,25 +4,22 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { FileDataVisualizerView } from './components/file_datavisualizer_view';
import React, { Fragment } from 'react';
import React from 'react';
import chrome from 'ui/chrome';
import { timefilter } from 'ui/timefilter';
import { timeHistory } from 'ui/timefilter/time_history';
import { NavigationMenuContext } from '../util/context_utils';
import { NavigationMenu } from '../components/navigation_menu/navigation_menu';
import { FileDataVisualizerView } from './components/file_datavisualizer_view';
export function FileDataVisualizerPage({ indexPatterns, kibanaConfig }) {
timefilter.disableTimeRangeSelector();
timefilter.disableAutoRefreshSelector();
return (
<NavigationMenuContext.Provider value={{ chrome, timefilter, timeHistory }}>
<Fragment>
<NavigationMenu tabId="datavisualizer" />
<FileDataVisualizerView indexPatterns={indexPatterns} kibanaConfig={kibanaConfig} />
</NavigationMenuContext.Provider>
</Fragment>
);
}

View file

@ -17,12 +17,8 @@ import { checkGetJobsPrivilege } from 'plugins/ml/privilege/check_privilege';
import { getMlNodeCount } from 'plugins/ml/ml_nodes_check/check_ml_nodes';
import { getJobManagementBreadcrumbs } from 'plugins/ml/jobs/breadcrumbs';
import { loadNewJobDefaults } from 'plugins/ml/jobs/new_job/utils/new_job_defaults';
import { NavigationMenuContext } from '../../util/context_utils';
import chrome from 'ui/chrome';
import uiRoutes from 'ui/routes';
import { timefilter } from 'ui/timefilter';
import { timeHistory } from 'ui/timefilter/time_history';
const template = `<jobs-page data-test-subj="mlPageJobManagement" />`;
@ -49,9 +45,7 @@ module.directive('jobsPage', function () {
link: (scope, element) => {
ReactDOM.render(
<I18nContext>
<NavigationMenuContext.Provider value={{ chrome, timefilter, timeHistory }}>
<JobsPage angularWrapperScope={scope} />
</NavigationMenuContext.Provider>
<JobsPage angularWrapperScope={scope} />
</I18nContext>,
element[0]
);

View file

@ -12,7 +12,7 @@ import moment from 'moment';
import { WizardNav } from '../wizard_nav';
import { WIZARD_STEPS, StepProps } from '../step_types';
import { JobCreatorContext } from '../job_creator_context';
import { KibanaContext, isKibanaContext } from '../../../../../data_frame/common/kibana_context';
import { useKibanaContext } from '../../../../../contexts/kibana';
import { FullTimeRangeSelector } from '../../../../../components/full_time_range_selector';
import { EventRateChart } from '../charts/event_rate_chart';
import { LineChartPoint } from '../../../common/chart_loader';
@ -26,10 +26,7 @@ export interface TimeRange {
end: number;
}
export const TimeRangeStep: FC<StepProps> = ({ setCurrentStep, isCurrentStep }) => {
const kibanaContext = useContext(KibanaContext);
if (!isKibanaContext(kibanaContext)) {
return null;
}
const kibanaContext = useKibanaContext();
const {
jobCreator,

View file

@ -5,10 +5,10 @@
*/
import moment from 'moment';
import React, { Fragment, FC, useContext, useState, useEffect } from 'react';
import React, { Fragment, FC, useState, useEffect } from 'react';
import { EuiDatePickerRange, EuiDatePicker } from '@elastic/eui';
import { KibanaContext, isKibanaContext } from '../../../../../data_frame/common/kibana_context';
import { useKibanaContext } from '../../../../../contexts/kibana';
import { TimeRange } from './time_range';
const WIDTH = '512px';
@ -21,11 +21,8 @@ interface Props {
type Moment = moment.Moment;
export const TimeRangePicker: FC<Props> = ({ setTimeRange, timeRange }) => {
const kibanaContext = useContext(KibanaContext);
if (!isKibanaContext(kibanaContext)) {
return null;
}
const dateFormat = kibanaContext.kibanaConfig.get('dateFormat');
const kibanaContext = useKibanaContext();
const dateFormat: string = kibanaContext.kibanaConfig.get('dateFormat');
const [startMoment, setStartMoment] = useState<Moment | undefined>(moment(timeRange.start));
const [endMoment, setEndMoment] = useState<Moment | undefined>(moment(timeRange.end));

View file

@ -11,6 +11,7 @@ import ReactDOM from 'react-dom';
import { uiModules } from 'ui/modules';
const module = uiModules.get('apps/ml', ['react']);
import { timefilter } from 'ui/timefilter';
import { IndexPatterns } from 'ui/index_patterns';
import { I18nContext } from 'ui/i18n';
import { IPrivate } from 'ui/private';
@ -20,7 +21,7 @@ import { SearchItemsProvider } from '../../../new_job/utils/new_job_utils';
import { Page, PageProps } from './page';
import { JOB_TYPE } from '../../common/job_creator/util/constants';
import { KibanaContext } from '../../../../data_frame/common/kibana_context';
import { KibanaContext, KibanaConfigTypeFix } from '../../../../contexts/kibana';
module.directive('mlNewJobPage', ($injector: InjectorService) => {
return {
@ -30,10 +31,10 @@ module.directive('mlNewJobPage', ($injector: InjectorService) => {
timefilter.disableTimeRangeSelector();
timefilter.disableAutoRefreshSelector();
const indexPatterns = $injector.get('indexPatterns');
const indexPatterns = $injector.get<IndexPatterns>('indexPatterns');
const kbnBaseUrl = $injector.get<string>('kbnBaseUrl');
const kibanaConfig = $injector.get('config');
const Private: IPrivate = $injector.get('Private');
const kibanaConfig = $injector.get<KibanaConfigTypeFix>('config');
const Private = $injector.get<IPrivate>('Private');
const $route = $injector.get<any>('$route');
const existingJobsAndGroups = $route.current.locals.existingJobsAndGroups;

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import React, { FC, useContext, useEffect, Fragment } from 'react';
import React, { FC, useEffect, Fragment } from 'react';
import { EuiPage, EuiPageBody, EuiPageContentBody } from '@elastic/eui';
import { Wizard } from './wizard';
@ -21,7 +21,7 @@ import {
import { ChartLoader } from '../../common/chart_loader';
import { ResultsLoader } from '../../common/results_loader';
import { JobValidator } from '../../common/job_validator';
import { KibanaContext, isKibanaContext } from '../../../../data_frame/common/kibana_context';
import { useKibanaContext } from '../../../../contexts/kibana';
import { getTimeFilterRange } from '../../../../components/full_time_range_selector';
import { MlTimeBuckets } from '../../../../util/ml_time_buckets';
import { newJobDefaults } from '../../../new_job/utils/new_job_defaults';
@ -38,10 +38,7 @@ export interface PageProps {
}
export const Page: FC<PageProps> = ({ existingJobsAndGroups, jobType }) => {
const kibanaContext = useContext(KibanaContext);
if (!isKibanaContext(kibanaContext)) {
return null;
}
const kibanaContext = useKibanaContext();
const jobDefaults = newJobDefaults();

View file

@ -17,14 +17,9 @@ import { checkGetJobsPrivilege, checkPermission } from '../../../privilege/check
import { checkMlNodesAvailable } from '../../../ml_nodes_check/check_ml_nodes';
import { getCreateCalendarBreadcrumbs, getEditCalendarBreadcrumbs } from '../../breadcrumbs';
import chrome from 'ui/chrome';
import uiRoutes from 'ui/routes';
import { timefilter } from 'ui/timefilter';
import { timeHistory } from 'ui/timefilter/time_history';
import { I18nContext } from 'ui/i18n';
import { NavigationMenuContext } from '../../../util/context_utils';
const template = `
<div class="euiSpacer euiSpacer--s" />
<ml-new-calendar />
@ -66,9 +61,7 @@ module.directive('mlNewCalendar', function ($route) {
ReactDOM.render(
<I18nContext>
<NavigationMenuContext.Provider value={{ chrome, timefilter, timeHistory }}>
<NewCalendar {...props} />
</NavigationMenuContext.Provider>
<NewCalendar {...props} />
</I18nContext>,
element[0]
);

View file

@ -16,14 +16,9 @@ import { checkGetJobsPrivilege, checkPermission } from '../../../privilege/check
import { getMlNodeCount } from '../../../ml_nodes_check/check_ml_nodes';
import { getCalendarManagementBreadcrumbs } from '../../breadcrumbs';
import chrome from 'ui/chrome';
import uiRoutes from 'ui/routes';
import { timefilter } from 'ui/timefilter';
import { timeHistory } from 'ui/timefilter/time_history';
import { I18nContext } from 'ui/i18n';
import { NavigationMenuContext } from '../../../util/context_utils';
const template = `
<div class="euiSpacer euiSpacer--s" />
<ml-calendars-list />
@ -54,9 +49,7 @@ module.directive('mlCalendarsList', function () {
ReactDOM.render(
<I18nContext>
<NavigationMenuContext.Provider value={{ chrome, timefilter, timeHistory }}>
<CalendarsList {...props} />
</NavigationMenuContext.Provider>
<CalendarsList {...props} />
</I18nContext>,
element[0]
);

View file

@ -18,14 +18,9 @@ import { checkGetJobsPrivilege, checkPermission } from 'plugins/ml/privilege/che
import { getMlNodeCount } from 'plugins/ml/ml_nodes_check/check_ml_nodes';
import { EditFilterList } from './edit_filter_list';
import chrome from 'ui/chrome';
import uiRoutes from 'ui/routes';
import { timefilter } from 'ui/timefilter';
import { timeHistory } from 'ui/timefilter/time_history';
import { I18nContext } from 'ui/i18n';
import { NavigationMenuContext } from '../../../util/context_utils';
const template = `
<div class="euiSpacer euiSpacer--s" />
<ml-edit-filter-list />
@ -65,9 +60,7 @@ module.directive('mlEditFilterList', function ($route) {
ReactDOM.render(
<I18nContext>
<NavigationMenuContext.Provider value={{ chrome, timefilter, timeHistory }}>
<EditFilterList {...props} />
</NavigationMenuContext.Provider>
<EditFilterList {...props} />
</I18nContext>,
element[0]
);

View file

@ -18,14 +18,9 @@ import { checkGetJobsPrivilege, checkPermission } from 'plugins/ml/privilege/che
import { getMlNodeCount } from 'plugins/ml/ml_nodes_check/check_ml_nodes';
import { FilterLists } from './filter_lists';
import chrome from 'ui/chrome';
import uiRoutes from 'ui/routes';
import { timefilter } from 'ui/timefilter';
import { timeHistory } from 'ui/timefilter/time_history';
import { I18nContext } from 'ui/i18n';
import { NavigationMenuContext } from '../../../util/context_utils';
const template = `
<div class="euiSpacer euiSpacer--s" />
<ml-filter-lists />
@ -55,9 +50,7 @@ module.directive('mlFilterLists', function () {
ReactDOM.render(
<I18nContext>
<NavigationMenuContext.Provider value={{ chrome, timefilter, timeHistory }}>
<FilterLists {...props} />
</NavigationMenuContext.Provider>
<FilterLists {...props} />
</I18nContext>,
element[0]
);

View file

@ -22,14 +22,14 @@ import {
import { FormattedMessage } from '@kbn/i18n/react';
import { useNavigationMenuContext } from '../util/context_utils';
import { useUiChromeContext } from '../contexts/ui/use_ui_chrome_context';
import { NavigationMenu } from '../components/navigation_menu/navigation_menu';
export function Settings({
canGetFilters,
canGetCalendars
}) {
const basePath = useNavigationMenuContext().chrome.getBasePath();
const basePath = useUiChromeContext().getBasePath();
return (
<Fragment>

View file

@ -5,27 +5,18 @@
*/
import { mountWithIntl } from 'test_utils/enzyme_helpers';
import PropTypes from 'prop-types';
import React from 'react';
import * as ContextUtils from '../util/context_utils';
import { Settings } from './settings';
const navigationMenuMock = ContextUtils.navigationMenuMock;
const mountOptions = {
context: { NavigationMenuContext: navigationMenuMock },
childContextTypes: { NavigationMenuContext: PropTypes.object }
};
jest.mock('../contexts/ui/use_ui_chrome_context');
jest.mock('../components/navigation_menu/navigation_menu', () => ({
NavigationMenu: () => <div id="mockNavigationMenu" />
NavigationMenu: () => <div id="mockNavigationMenu" />,
}));
jest.spyOn(ContextUtils, 'useNavigationMenuContext').mockImplementation(() => navigationMenuMock);
describe('Settings', () => {
test('Renders settings page with all buttons enabled.', () => {
const wrapper = mountWithIntl(<Settings canGetFilters={true} canGetCalendars={true} />, mountOptions);
const wrapper = mountWithIntl(<Settings canGetFilters={true} canGetCalendars={true} />);
const filterButton = wrapper
.find('[data-test-subj="ml_filter_lists_button"]')
@ -39,7 +30,7 @@ describe('Settings', () => {
});
test('Filter Lists button disabled if canGetFilters is false', () => {
const wrapper = mountWithIntl(<Settings canGetFilters={false} canGetCalendars={true} />, mountOptions);
const wrapper = mountWithIntl(<Settings canGetFilters={false} canGetCalendars={true} />);
const filterButton = wrapper
.find('[data-test-subj="ml_filter_lists_button"]')
@ -53,7 +44,7 @@ describe('Settings', () => {
});
test('Calendar management button disabled if canGetCalendars is false', () => {
const wrapper = mountWithIntl(<Settings canGetFilters={true} canGetCalendars={false} />, mountOptions);
const wrapper = mountWithIntl(<Settings canGetFilters={true} canGetCalendars={false} />);
const filterButton = wrapper
.find('[data-test-subj="ml_filter_lists_button"]')

View file

@ -15,14 +15,11 @@ const module = uiModules.get('apps/ml', ['react']);
import { checkFullLicense } from '../license/check_license';
import { checkGetJobsPrivilege, checkPermission } from '../privilege/check_privilege';
import { getMlNodeCount } from '../ml_nodes_check/check_ml_nodes';
import { NavigationMenuContext } from '../util/context_utils';
import { getSettingsBreadcrumbs } from './breadcrumbs';
import { I18nContext } from 'ui/i18n';
import chrome from 'ui/chrome';
import uiRoutes from 'ui/routes';
import { timefilter } from 'ui/timefilter';
import { timeHistory } from 'ui/timefilter/time_history';
const template = `
<div class="euiSpacer euiSpacer--s" />
@ -58,9 +55,7 @@ module.directive('mlSettings', function () {
ReactDOM.render(
<I18nContext>
<NavigationMenuContext.Provider value={{ chrome, timefilter, timeHistory }} >
<Settings canGetCalendars={canGetCalendars} canGetFilters={canGetFilters} />
</NavigationMenuContext.Provider>
<Settings canGetCalendars={canGetCalendars} canGetFilters={canGetFilters} />
</I18nContext>,
element[0]
);

View file

@ -14,9 +14,7 @@ import ReactDOM from 'react-dom';
import { uiModules } from 'ui/modules';
const module = uiModules.get('apps/ml');
import chrome from 'ui/chrome';
import { timefilter } from 'ui/timefilter';
import { timeHistory } from 'ui/timefilter/time_history';
import { I18nContext } from 'ui/i18n';
import '../components/controls';
@ -24,7 +22,6 @@ import '../components/controls';
import { severity$ } from '../components/controls/select_severity/select_severity';
import { interval$ } from '../components/controls/select_interval/select_interval';
import { subscribeAppStateToObservable } from '../util/app_state_utils';
import { NavigationMenuContext } from '../util/context_utils';
import { TimeSeriesExplorer } from './timeseriesexplorer';
import { APP_STATE_ACTION } from './timeseriesexplorer_constants';
@ -88,15 +85,13 @@ module.directive('mlTimeSeriesExplorer', function ($injector) {
ReactDOM.render(
<I18nContext>
<NavigationMenuContext.Provider value={{ chrome, timefilter, timeHistory }}>
<TimeSeriesExplorer {...{
appStateHandler,
dateFormatTz,
globalState,
timefilter,
}}
/>
</NavigationMenuContext.Provider>
<TimeSeriesExplorer {...{
appStateHandler,
dateFormatTz,
globalState,
timefilter,
}}
/>
</I18nContext>,
$element[0]
);

View file

@ -1,66 +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 React, { useContext } from 'react';
import { Chrome } from 'ui/chrome';
import { Timefilter } from 'ui/timefilter';
import { TimeHistory } from 'ui/timefilter/time_history';
export const ChromeContext = React.createContext<Chrome>({} as Chrome);
export const TimefilterContext = React.createContext<Timefilter>({} as Timefilter);
export const TimeHistoryContext = React.createContext<TimeHistory>({} as TimeHistory);
interface NavigationMenuContextValue {
chrome: Chrome;
timefilter: Timefilter;
timeHistory: TimeHistory;
}
export const NavigationMenuContext = React.createContext<NavigationMenuContextValue>({
chrome: {} as Chrome,
timefilter: {} as Timefilter,
timeHistory: {} as TimeHistory,
});
export const useNavigationMenuContext = () => {
return useContext(NavigationMenuContext);
};
// testing mocks
export const chromeMock = {
getBasePath: () => 'basePath',
getUiSettingsClient: () => {
return {
get: (key: string) => {
switch (key) {
case 'dateFormat':
case 'timepicker:timeDefaults':
return {};
case 'timepicker:refreshIntervalDefaults':
return { pause: false, value: 0 };
default:
throw new Error(`Unexpected config key: ${key}`);
}
},
};
},
} as Chrome;
export const timefilterMock = ({
getRefreshInterval: () => '30s',
getTime: () => ({ from: 0, to: 0 }),
on: (event: string, reload: () => void) => {},
} as unknown) as Timefilter;
export const timeHistoryMock = ({
get: () => [{ from: 0, to: 0 }],
} as unknown) as TimeHistory;
export const navigationMenuMock = {
chrome: chromeMock,
timefilter: timefilterMock,
timeHistory: timeHistoryMock,
};

View file

@ -6023,7 +6023,7 @@
"xpack.ml.dataframe.stepCreateForm.transformListCardTitle": "データフレームジョブ",
"xpack.ml.dataframe.stepCreateForm.progressErrorMessage": "進捗パーセンテージの取得中にエラーが発生しました: {error}",
"xpack.ml.dataframe.stepCreateForm.progressTitle": "進捗",
"xpack.ml.dataframe.stepCreateForm.reateIndexPatternSuccessMessage": "Kibana インデックスパターン {indexPatternName} が作成されました",
"xpack.ml.dataframe.stepCreateForm.createIndexPatternSuccessMessage": "Kibana インデックスパターン {indexPatternName} が作成されました",
"xpack.ml.dataframe.stepCreateForm.startDataFrameButton": "開始",
"xpack.ml.dataframe.stepCreateForm.startDataFrameDescription": "データフレームジョブを開始します。データフレームジョブは、クラスターの検索とインデックスによる負荷を増やします。過剰な負荷が生じた場合はジョブを停止してください。ジョブの開始後、データフレームジョブの閲覧を続けるオプションが提供されます。",
"xpack.ml.dataframe.stepCreateForm.startTransformErrorMessage": "データフレームジョブ {transformId} の開始中にエラーが発生しました: {error}",

View file

@ -6166,7 +6166,7 @@
"xpack.ml.dataframe.stepCreateForm.transformListCardTitle": "数据帧作业",
"xpack.ml.dataframe.stepCreateForm.progressErrorMessage": "获取进度百分比时出错:{error}",
"xpack.ml.dataframe.stepCreateForm.progressTitle": "进度",
"xpack.ml.dataframe.stepCreateForm.reateIndexPatternSuccessMessage": "Kibana 索引模式 {indexPatternName} 成功创建。",
"xpack.ml.dataframe.stepCreateForm.createIndexPatternSuccessMessage": "Kibana 索引模式 {indexPatternName} 成功创建。",
"xpack.ml.dataframe.stepCreateForm.startDataFrameButton": "开始",
"xpack.ml.dataframe.stepCreateForm.startDataFrameDescription": "启动数据帧作业。数据帧作业将增加集群的搜索和索引负荷。如果负荷超载,请停止作业。作业启动后,系统将为您提供继续浏览数据帧作业的选项。",
"xpack.ml.dataframe.stepCreateForm.startTransformErrorMessage": "启动数据帧作业 {transformId} 时发生错误:{error}",