[Discover] Remove usage of deprecated React rendering utilities (#181623)

## Summary

Partially addresses https://github.com/elastic/kibana-team/issues/805

These changes come up from searching in the code and finding where
certain kinds of deprecated AppEx-SharedUX modules are imported.
**Reviewers: Please interact with critical paths through the UI
components touched in this PR, ESPECIALLY in terms of testing dark mode
and i18n.**

This focuses on code within **Discover**. Due to related type-safety
needs there are also some minor changes in the **Data** plugin.

<img width="1196" alt="image"
src="7f8d3707-94f0-4746-8dd5-dd858ce027f9">

Note: this also makes inclusion of `i18n` and `analytics` dependencies
consistent. Analytics is an optional dependency for the SharedUX
modules, which wrap `KibanaErrorBoundaryProvider` and is designed to
capture telemetry about errors that are caught in the error boundary.

### Checklist

Delete any items that are not applicable to this PR.

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [ ] This renders correctly on smaller devices using a responsive
layout. (You can test this [in your
browser](https://www.browserstack.com/guide/responsive-testing-on-local-server))
- [ ] This was checked for [cross-browser
compatibility](https://www.elastic.co/support/matrix#matrix_browsers)

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Julia Rechkunova <julia.rechkunova@gmail.com>
This commit is contained in:
Tim Sullivan 2024-04-26 11:48:06 -07:00 committed by GitHub
parent a05355713e
commit bc87224b41
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
42 changed files with 468 additions and 584 deletions

View file

@ -16,8 +16,6 @@
"share",
"unifiedSearch"
],
"requiredBundles": [
"kibanaReact"
]
"requiredBundles": []
}
}

View file

@ -39,7 +39,7 @@ const LINKS: ExampleLink[] = [
];
export const renderApp = (
{ notifications, savedObjects, http, application }: CoreStart,
{ notifications, savedObjects, http, application, ...startServices }: CoreStart,
{ data, navigation, unifiedSearch }: AppPluginStartDependencies,
{ element, history }: AppMountParameters
) => {
@ -60,6 +60,7 @@ export const renderApp = (
data={data}
http={http}
unifiedSearch={unifiedSearch}
{...startServices}
/>
</Route>
<Route path={LINKS[1].path}>

View file

@ -36,7 +36,7 @@ import type { DataView, DataViewField } from '@kbn/data-views-plugin/public';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import { RequestAdapter } from '@kbn/inspector-plugin/common';
import { toMountPoint } from '@kbn/kibana-react-plugin/public';
import { toMountPoint } from '@kbn/react-kibana-mount';
import { NavigationPublicPluginStart } from '@kbn/navigation-plugin/public';
import { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public';
import React, { useEffect, useState } from 'react';
@ -44,9 +44,8 @@ import { lastValueFrom } from 'rxjs';
import { PLUGIN_ID, PLUGIN_NAME, SERVER_SEARCH_ROUTE_PATH } from '../../common';
import { IMyStrategyResponse } from '../../common/types';
interface SearchExamplesAppDeps {
notifications: CoreStart['notifications'];
http: CoreStart['http'];
interface SearchExamplesAppDeps
extends Pick<CoreStart, 'notifications' | 'http' | 'analytics' | 'i18n' | 'theme'> {
navigation: NavigationPublicPluginStart;
data: DataPublicPluginStart;
unifiedSearch: UnifiedSearchPublicPluginStart;
@ -86,6 +85,7 @@ export const SearchExamplesApp = ({
navigation,
data,
unifiedSearch,
...startServices
}: SearchExamplesAppDeps) => {
const { IndexPatternSelect } = unifiedSearch.ui;
const [getCool, setGetCool] = useState<boolean>(false);
@ -234,7 +234,7 @@ export const SearchExamplesApp = ({
notifications.toasts.addSuccess(
{
title: 'Query result',
text: toMountPoint(message),
text: toMountPoint(message, startServices),
},
{
toastLifeTimeMs: 300000,
@ -243,7 +243,7 @@ export const SearchExamplesApp = ({
if (res.warning) {
notifications.toasts.addWarning({
title: 'Warning',
text: toMountPoint(res.warning),
text: toMountPoint(res.warning, startServices),
});
}
}
@ -337,7 +337,7 @@ export const SearchExamplesApp = ({
notifications.toasts.addSuccess(
{
title: 'Query result',
text: toMountPoint(message),
text: toMountPoint(message, startServices),
},
{
toastLifeTimeMs: 300000,

View file

@ -20,7 +20,6 @@
"@kbn/data-views-plugin",
"@kbn/inspector-plugin",
"@kbn/kibana-utils-plugin",
"@kbn/kibana-react-plugin",
"@kbn/navigation-plugin",
"@kbn/share-plugin",
"@kbn/developer-examples-plugin",
@ -34,5 +33,6 @@
"@kbn/shared-ux-router",
"@kbn/search-response-warnings",
"@kbn/shared-ux-link-redirect-app",
"@kbn/react-kibana-mount",
]
}

View file

@ -7,17 +7,16 @@
*/
import { estypes } from '@elastic/elasticsearch';
import type { ThemeServiceStart } from '@kbn/core/public';
import type { I18nStart } from '@kbn/core-i18n-browser';
import { notificationServiceMock } from '@kbn/core-notifications-browser-mocks';
import { coreMock } from '@kbn/core/public/mocks';
import type { Start as InspectorStart, RequestAdapter } from '@kbn/inspector-plugin/public';
import { handleWarnings } from './handle_warnings';
describe('handleWarnings', () => {
const notifications = notificationServiceMock.createStartContract();
const coreStart = coreMock.createStart();
const addWarningSpy = jest.spyOn(coreStart.notifications.toasts, 'addWarning');
beforeEach(() => {
notifications.toasts.addWarning.mockClear();
addWarningSpy.mockClear();
});
it('should not show notifications when there are no warnings', () => {
@ -34,14 +33,12 @@ describe('handleWarnings', () => {
},
} as estypes.SearchResponse,
services: {
i18n: {} as unknown as I18nStart,
inspector: {} as unknown as InspectorStart,
notifications,
theme: {} as unknown as ThemeServiceStart,
...coreStart,
},
});
expect(notifications.toasts.addWarning).toBeCalledTimes(0);
expect(addWarningSpy).toBeCalledTimes(0);
});
it('should show notifications for warnings when there is no callback', () => {
@ -57,14 +54,12 @@ describe('handleWarnings', () => {
hits: { hits: [] },
} as estypes.SearchResponse,
services: {
i18n: {} as unknown as I18nStart,
inspector: {} as unknown as InspectorStart,
notifications,
theme: {} as unknown as ThemeServiceStart,
...coreStart,
},
});
expect(notifications.toasts.addWarning).toBeCalledTimes(1);
expect(addWarningSpy).toBeCalledTimes(1);
});
it('should show notifications for warnings not handled by callback', () => {
@ -82,15 +77,13 @@ describe('handleWarnings', () => {
hits: { hits: [] },
} as estypes.SearchResponse,
services: {
i18n: {} as unknown as I18nStart,
inspector: {} as unknown as InspectorStart,
notifications,
theme: {} as unknown as ThemeServiceStart,
...coreStart,
},
});
expect(callbackMock).toBeCalledTimes(1);
expect(notifications.toasts.addWarning).toBeCalledTimes(1);
expect(addWarningSpy).toBeCalledTimes(1);
});
it('should not show notifications for warnings handled by callback', () => {
@ -108,14 +101,12 @@ describe('handleWarnings', () => {
hits: { hits: [] },
} as estypes.SearchResponse,
services: {
i18n: {} as unknown as I18nStart,
inspector: {} as unknown as InspectorStart,
notifications,
theme: {} as unknown as ThemeServiceStart,
...coreStart,
},
});
expect(callbackMock).toBeCalledTimes(1);
expect(notifications.toasts.addWarning).toBeCalledTimes(0);
expect(addWarningSpy).toBeCalledTimes(0);
});
});

View file

@ -9,7 +9,11 @@
import React from 'react';
import { EuiButtonEmpty, EuiText } from '@elastic/eui';
import { estypes } from '@elastic/elasticsearch';
import type { NotificationsStart, ThemeServiceStart } from '@kbn/core/public';
import type {
AnalyticsServiceStart,
NotificationsStart,
ThemeServiceStart,
} from '@kbn/core/public';
import { toMountPoint } from '@kbn/react-kibana-mount';
import type { I18nStart } from '@kbn/core-i18n-browser';
import type { Start as InspectorStart, RequestAdapter } from '@kbn/inspector-plugin/public';
@ -26,6 +30,7 @@ import {
} from './components/search_response_warnings/i18n_utils';
interface Services {
analytics: AnalyticsServiceStart;
i18n: I18nStart;
inspector: InspectorStart;
notifications: NotificationsStart;
@ -94,7 +99,7 @@ export function handleWarnings({
{viewDetailsLabel}
</EuiButtonEmpty>
</>,
{ theme: services.theme, i18n: services.i18n }
services
),
});
}

View file

@ -10,7 +10,6 @@
"@kbn/core",
"@kbn/react-kibana-mount",
"@kbn/core-i18n-browser",
"@kbn/core-notifications-browser-mocks",
],
"exclude": ["target/**/*"]
}

View file

@ -21,7 +21,7 @@ import { RequestAdapter } from '@kbn/inspector-plugin/common/adapters/request';
import { DataViewsContract } from '@kbn/data-views-plugin/common';
import { ExpressionsSetup } from '@kbn/expressions-plugin/public';
import { FieldFormatsStart } from '@kbn/field-formats-plugin/public';
import { toMountPoint } from '@kbn/kibana-react-plugin/public';
import { toMountPoint } from '@kbn/react-kibana-mount';
import { Storage } from '@kbn/kibana-utils-plugin/public';
import { ManagementSetup } from '@kbn/management-plugin/public';
import { ScreenshotModePluginStart } from '@kbn/screenshot-mode-plugin/public';
@ -226,7 +226,16 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
}
public start(
{ http, theme, uiSettings, chrome, application, notifications, i18n: i18nStart }: CoreStart,
{
analytics,
http,
theme,
uiSettings,
chrome,
application,
notifications,
i18n: i18nStart,
}: CoreStart,
{
fieldFormats,
indexPatterns,
@ -245,6 +254,7 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
const aggs = this.aggsService.start({ fieldFormats, indexPatterns });
const warningsServices = {
analytics,
i18n: i18nStart,
inspector,
notifications,
@ -303,7 +313,7 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
tourDisabled: screenshotMode.isScreenshotMode(),
})
),
{ theme$: theme.theme$ }
{ analytics, i18n: i18nStart, theme }
),
});
}

View file

@ -54,7 +54,8 @@
"@kbn/es-types",
"@kbn/code-editor",
"@kbn/core-test-helpers-model-versions",
"@kbn/esql-utils"
"@kbn/esql-utils",
"@kbn/react-kibana-mount"
],
"exclude": [
"target/**/*",

View file

@ -80,7 +80,7 @@ export const getEditorOpener =
showManagementLink={Boolean(editData && editData.isPersisted())}
/>
</KibanaReactContextProvider>,
{ theme: core.theme, i18n: core.i18n }
core
),
{
hideCloseButton: true,

View file

@ -7,8 +7,8 @@
*/
import React from 'react';
jest.mock('@kbn/kibana-react-plugin/public', () => {
const original = jest.requireActual('@kbn/kibana-react-plugin/public');
jest.mock('@kbn/react-kibana-mount', () => {
const original = jest.requireActual('@kbn/react-kibana-mount');
return {
...original,
@ -43,7 +43,7 @@ describe('DataViewEditorPlugin', () => {
});
test('should expose a handler to open the data view field editor', async () => {
const startApi = await plugin.start(coreStart, pluginStart);
const startApi = plugin.start(coreStart, pluginStart);
expect(startApi.openEditor).toBeDefined();
});
@ -58,13 +58,13 @@ describe('DataViewEditorPlugin', () => {
openFlyout,
},
};
const { openEditor } = await plugin.start(coreStartMocked, pluginStart);
const { openEditor } = plugin.start(coreStartMocked, pluginStart);
openEditor({ onSave: onSaveSpy });
expect(openFlyout).toHaveBeenCalled();
const [[{ __reactMount__ }]] = openFlyout.mock.calls;
const [[__reactMount__]] = openFlyout.mock.calls;
expect(__reactMount__.props.children.type).toBe(DataViewEditorLazy);
// We force call the "onSave" prop from the <RuntimeFieldEditorFlyoutContent /> component
@ -77,7 +77,7 @@ describe('DataViewEditorPlugin', () => {
});
test('should return a handler to close the flyout', async () => {
const { openEditor } = await plugin.start(coreStart, pluginStart);
const { openEditor } = plugin.start(coreStart, pluginStart);
const closeEditorHandler = openEditor({ onSave: noop });
expect(typeof closeEditorHandler).toBe('function');

View file

@ -13,7 +13,9 @@ export type {
} from '@kbn/data-plugin/public';
export type { DataView, DataViewField, DataViewSpec } from '@kbn/data-views-plugin/public';
export { createKibanaReactContext, toMountPoint, useKibana } from '@kbn/kibana-react-plugin/public';
export { createKibanaReactContext, useKibana } from '@kbn/kibana-react-plugin/public';
export { toMountPoint } from '@kbn/react-kibana-mount';
export { CodeEditor } from '@kbn/code-editor';

View file

@ -114,7 +114,7 @@ export const getFieldDeleteModalOpener =
closeModal={closeModal}
confirmDelete={onConfirmDelete}
/>,
{ theme$: core.theme.theme$ }
core
)
);

View file

@ -200,7 +200,7 @@ export const getFieldEditorOpener =
uiSettings={uiSettings}
/>
</KibanaReactContextProvider>,
{ theme: core.theme, i18n: core.i18n }
core
),
{
className: euiFlyoutClassname,

View file

@ -8,8 +8,8 @@
import React from 'react';
import { registerTestBed } from '@kbn/test-jest-helpers';
jest.mock('@kbn/kibana-react-plugin/public', () => {
const original = jest.requireActual('@kbn/kibana-react-plugin/public');
jest.mock('@kbn/react-kibana-mount', () => {
const original = jest.requireActual('@kbn/react-kibana-mount');
return {
...original,
@ -46,7 +46,7 @@ describe('DataViewFieldEditorPlugin', () => {
});
test('should expose a handler to open the indexpattern field editor', async () => {
const startApi = await plugin.start(coreStart, pluginStart);
const startApi = plugin.start(coreStart, pluginStart);
expect(startApi.openEditor).toBeDefined();
});
@ -61,13 +61,13 @@ describe('DataViewFieldEditorPlugin', () => {
openFlyout,
},
};
const { openEditor } = await plugin.start(coreStartMocked, pluginStart);
const { openEditor } = plugin.start(coreStartMocked, pluginStart);
openEditor({ onSave: onSaveSpy, ctx: { dataView: {} as any } });
expect(openFlyout).toHaveBeenCalled();
const [[{ __reactMount__ }]] = openFlyout.mock.calls;
const [[__reactMount__]] = openFlyout.mock.calls;
expect(__reactMount__.props.children.type).toBe(FieldEditorLoader);
// We force call the "onSave" prop from the <RuntimeFieldEditorFlyoutContent /> component
@ -80,14 +80,14 @@ describe('DataViewFieldEditorPlugin', () => {
});
test('should return a handler to close the flyout', async () => {
const { openEditor } = await plugin.start(coreStart, pluginStart);
const { openEditor } = plugin.start(coreStart, pluginStart);
const closeEditorHandler = openEditor({ onSave: noop, ctx: { dataView: {} as any } });
expect(typeof closeEditorHandler).toBe('function');
});
test('should expose a handler to open field deletion modal', async () => {
const startApi = await plugin.start(coreStart, pluginStart);
const startApi = plugin.start(coreStart, pluginStart);
expect(startApi.openDeleteModal).toBeDefined();
});
@ -111,7 +111,7 @@ describe('DataViewFieldEditorPlugin', () => {
updateSavedObject: jest.fn(),
},
};
const { openDeleteModal } = await plugin.start(coreStartMocked, pluginStartMocked);
const { openDeleteModal } = plugin.start(coreStartMocked, pluginStartMocked);
const indexPatternMock = {
removeRuntimeField: removeFieldSpy,
@ -145,14 +145,14 @@ describe('DataViewFieldEditorPlugin', () => {
});
test('should return a handler to close the modal', async () => {
const { openDeleteModal } = await plugin.start(coreStart, pluginStart);
const { openDeleteModal } = plugin.start(coreStart, pluginStart);
const closeModal = openDeleteModal({ fieldName: ['a'], ctx: { dataView: {} as any } });
expect(typeof closeModal).toBe('function');
});
test('should expose a render props component to delete runtime fields', async () => {
const { DeleteRuntimeFieldProvider } = await plugin.start(coreStart, pluginStart);
const { DeleteRuntimeFieldProvider } = plugin.start(coreStart, pluginStart);
const TestComponent = ({ callback }: { callback: (...args: any[]) => void }) => {
return (

View file

@ -27,7 +27,9 @@ export type {
} from '@kbn/data-views-plugin/common';
export { KBN_FIELD_TYPES, ES_FIELD_TYPES } from '@kbn/data-plugin/common';
export { createKibanaReactContext, toMountPoint } from '@kbn/kibana-react-plugin/public';
export { createKibanaReactContext } from '@kbn/kibana-react-plugin/public';
export { toMountPoint } from '@kbn/react-kibana-mount';
export { CodeEditor } from '@kbn/code-editor';

View file

@ -80,6 +80,7 @@ export const EditIndexPattern = withRouter(
IndexPatternEditor,
savedObjectsManagement,
application,
...startServices
} = useKibana<IndexPatternManagmentContext>().services;
const [fields, setFields] = useState<DataViewField[]>(indexPattern.getNonScriptedFields());
const [compositeRuntimeFields, setCompositeRuntimeFields] = useState<
@ -167,6 +168,7 @@ export const EditIndexPattern = withRouter(
onDelete: () => {
history.push('');
},
startServices,
});
const isRollup =

View file

@ -1,403 +1,281 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`IndexedFieldsTable IndexedFieldsTable with rollup index pattern should render normally 1`] = `
<div>
<Table
deleteField={[Function]}
editField={[Function]}
indexPattern={
Object {
"getFormatterForFieldNoDefault": [Function],
"getNonScriptedFields": [Function],
"type": "rollup",
"typeMeta": Object {
"aggs": Object {
"avg": Object {
"amount": Object {
"agg": "avg",
},
},
"date_histogram": Object {
"timestamp": Object {
"agg": "date_histogram",
"delay": "30s",
"fixed_interval": "30s",
"time_zone": "UTC",
},
},
"histogram": Object {
"amount": Object {
"agg": "histogram",
"interval": 5,
},
},
"max": Object {
"amount": Object {
"agg": "max",
},
},
"min": Object {
"amount": Object {
"agg": "min",
},
},
"sum": Object {
"amount": Object {
"agg": "sum",
},
},
"terms": Object {
"Elastic": Object {
"agg": "terms",
},
},
"value_count": Object {
"amount": Object {
"agg": "value_count",
},
},
},
"params": Object {
"rollup-index": "rollup",
},
Object {
"items": Array [
Object {
"displayName": "Elastic",
"esTypes": Array [
"keyword",
],
"excluded": false,
"format": "",
"hasRuntime": false,
"id": "Elastic",
"info": Array [
"Rollup aggregations:",
"terms",
],
"isMapped": false,
"isUserEditable": false,
"kbnType": undefined,
"name": "Elastic",
"searchable": true,
"type": "keyword",
},
Object {
"displayName": "timestamp",
"esTypes": Array [
"date",
],
"excluded": false,
"format": "",
"hasRuntime": false,
"id": "timestamp",
"info": Array [
"Rollup aggregations:",
"date_histogram (interval: 30s, delay: 30s, UTC)",
],
"isMapped": false,
"isUserEditable": false,
"kbnType": undefined,
"name": "timestamp",
"type": "date",
},
Object {
"displayName": "conflictingField",
"esTypes": Array [
"keyword",
"long",
],
"excluded": false,
"format": "",
"hasRuntime": false,
"id": "conflictingField",
"info": Array [],
"isMapped": false,
"isUserEditable": false,
"kbnType": undefined,
"name": "conflictingField",
"type": "keyword, long",
},
Object {
"displayName": "amount",
"esTypes": Array [
"long",
],
"excluded": false,
"format": "",
"hasRuntime": false,
"id": "amount",
"info": Array [
"Rollup aggregations:",
"histogram (interval: 5)",
"avg",
"max",
"min",
"sum",
"value_count",
],
"isMapped": false,
"isUserEditable": false,
"kbnType": undefined,
"name": "amount",
"type": "long",
},
Object {
"displayName": "runtime",
"esTypes": Array [
"long",
],
"excluded": false,
"format": "",
"hasRuntime": true,
"id": "runtime",
"info": Array [],
"isMapped": false,
"isUserEditable": false,
"kbnType": "number",
"name": "runtime",
"runtimeField": Object {
"script": Object {
"source": "emit('Hello');",
},
}
}
items={
Array [
Object {
"displayName": "Elastic",
"esTypes": Array [
"keyword",
],
"excluded": false,
"format": "",
"hasRuntime": false,
"id": "Elastic",
"info": Array [
"Rollup aggregations:",
"terms",
],
"isMapped": false,
"isUserEditable": false,
"kbnType": undefined,
"name": "Elastic",
"searchable": true,
"type": "keyword",
},
Object {
"displayName": "timestamp",
"esTypes": Array [
"date",
],
"excluded": false,
"format": "",
"hasRuntime": false,
"id": "timestamp",
"info": Array [
"Rollup aggregations:",
"date_histogram (interval: 30s, delay: 30s, UTC)",
],
"isMapped": false,
"isUserEditable": false,
"kbnType": undefined,
"name": "timestamp",
"type": "date",
},
Object {
"displayName": "conflictingField",
"esTypes": Array [
"keyword",
"long",
],
"excluded": false,
"format": "",
"hasRuntime": false,
"id": "conflictingField",
"info": Array [],
"isMapped": false,
"isUserEditable": false,
"kbnType": undefined,
"name": "conflictingField",
"type": "keyword, long",
},
Object {
"displayName": "amount",
"esTypes": Array [
"long",
],
"excluded": false,
"format": "",
"hasRuntime": false,
"id": "amount",
"info": Array [
"Rollup aggregations:",
"histogram (interval: 5)",
"avg",
"max",
"min",
"sum",
"value_count",
],
"isMapped": false,
"isUserEditable": false,
"kbnType": undefined,
"name": "amount",
"type": "long",
},
Object {
"displayName": "runtime",
"esTypes": Array [
"long",
],
"excluded": false,
"format": "",
"hasRuntime": true,
"id": "runtime",
"info": Array [],
"isMapped": false,
"isUserEditable": false,
"kbnType": "number",
"name": "runtime",
"runtimeField": Object {
"script": Object {
"source": "emit('Hello');",
},
"type": "long",
},
"type": "long",
},
]
}
openModal={[Function]}
theme={Object {}}
/>
</div>
"type": "long",
},
"type": "long",
},
],
}
`;
exports[`IndexedFieldsTable should filter based on the query bar 1`] = `
<div>
<Table
deleteField={[Function]}
editField={[Function]}
indexPattern={
Object {
"getFormatterForFieldNoDefault": [Function],
"getNonScriptedFields": [Function],
}
}
items={
Array [
Object {
"displayName": "Elastic",
"esTypes": Array [
"keyword",
],
"excluded": false,
"format": "",
"hasRuntime": false,
"id": "Elastic",
"info": Array [],
"isMapped": false,
"isUserEditable": false,
"kbnType": undefined,
"name": "Elastic",
"searchable": true,
"type": "keyword",
},
]
}
openModal={[Function]}
theme={Object {}}
/>
</div>
Object {
"items": Array [
Object {
"displayName": "Elastic",
"esTypes": Array [
"keyword",
],
"excluded": false,
"format": "",
"hasRuntime": false,
"id": "Elastic",
"info": Array [],
"isMapped": false,
"isUserEditable": false,
"kbnType": undefined,
"name": "Elastic",
"searchable": true,
"type": "keyword",
},
],
}
`;
exports[`IndexedFieldsTable should filter based on the schema filter 1`] = `
<div>
<Table
deleteField={[Function]}
editField={[Function]}
indexPattern={
Object {
"getFormatterForFieldNoDefault": [Function],
"getNonScriptedFields": [Function],
}
}
items={
Array [
Object {
"displayName": "runtime",
"esTypes": Array [
"long",
],
"excluded": false,
"format": "",
"hasRuntime": true,
"id": "runtime",
"info": Array [],
"isMapped": false,
"isUserEditable": false,
"kbnType": "number",
"name": "runtime",
"runtimeField": Object {
"script": Object {
"source": "emit('Hello');",
},
"type": "long",
},
"type": "long",
Object {
"items": Array [
Object {
"displayName": "runtime",
"esTypes": Array [
"long",
],
"excluded": false,
"format": "",
"hasRuntime": true,
"id": "runtime",
"info": Array [],
"isMapped": false,
"isUserEditable": false,
"kbnType": "number",
"name": "runtime",
"runtimeField": Object {
"script": Object {
"source": "emit('Hello');",
},
]
}
openModal={[Function]}
theme={Object {}}
/>
</div>
"type": "long",
},
"type": "long",
},
],
}
`;
exports[`IndexedFieldsTable should filter based on the type filter 1`] = `
<div>
<Table
deleteField={[Function]}
editField={[Function]}
indexPattern={
Object {
"getFormatterForFieldNoDefault": [Function],
"getNonScriptedFields": [Function],
}
}
items={
Array [
Object {
"displayName": "timestamp",
"esTypes": Array [
"date",
],
"excluded": false,
"format": "",
"hasRuntime": false,
"id": "timestamp",
"info": Array [],
"isMapped": false,
"isUserEditable": false,
"kbnType": undefined,
"name": "timestamp",
"type": "date",
},
]
}
openModal={[Function]}
theme={Object {}}
/>
</div>
Object {
"items": Array [
Object {
"displayName": "timestamp",
"esTypes": Array [
"date",
],
"excluded": false,
"format": "",
"hasRuntime": false,
"id": "timestamp",
"info": Array [],
"isMapped": false,
"isUserEditable": false,
"kbnType": undefined,
"name": "timestamp",
"type": "date",
},
],
}
`;
exports[`IndexedFieldsTable should render normally 1`] = `
<div>
<Table
deleteField={[Function]}
editField={[Function]}
indexPattern={
Object {
"getFormatterForFieldNoDefault": [Function],
"getNonScriptedFields": [Function],
}
}
items={
Array [
Object {
"displayName": "Elastic",
"esTypes": Array [
"keyword",
],
"excluded": false,
"format": "",
"hasRuntime": false,
"id": "Elastic",
"info": Array [],
"isMapped": false,
"isUserEditable": false,
"kbnType": undefined,
"name": "Elastic",
"searchable": true,
"type": "keyword",
Object {
"items": Array [
Object {
"displayName": "Elastic",
"esTypes": Array [
"keyword",
],
"excluded": false,
"format": "",
"hasRuntime": false,
"id": "Elastic",
"info": Array [],
"isMapped": false,
"isUserEditable": false,
"kbnType": undefined,
"name": "Elastic",
"searchable": true,
"type": "keyword",
},
Object {
"displayName": "timestamp",
"esTypes": Array [
"date",
],
"excluded": false,
"format": "",
"hasRuntime": false,
"id": "timestamp",
"info": Array [],
"isMapped": false,
"isUserEditable": false,
"kbnType": undefined,
"name": "timestamp",
"type": "date",
},
Object {
"displayName": "conflictingField",
"esTypes": Array [
"keyword",
"long",
],
"excluded": false,
"format": "",
"hasRuntime": false,
"id": "conflictingField",
"info": Array [],
"isMapped": false,
"isUserEditable": false,
"kbnType": undefined,
"name": "conflictingField",
"type": "keyword, long",
},
Object {
"displayName": "amount",
"esTypes": Array [
"long",
],
"excluded": false,
"format": "",
"hasRuntime": false,
"id": "amount",
"info": Array [],
"isMapped": false,
"isUserEditable": false,
"kbnType": undefined,
"name": "amount",
"type": "long",
},
Object {
"displayName": "runtime",
"esTypes": Array [
"long",
],
"excluded": false,
"format": "",
"hasRuntime": true,
"id": "runtime",
"info": Array [],
"isMapped": false,
"isUserEditable": false,
"kbnType": "number",
"name": "runtime",
"runtimeField": Object {
"script": Object {
"source": "emit('Hello');",
},
Object {
"displayName": "timestamp",
"esTypes": Array [
"date",
],
"excluded": false,
"format": "",
"hasRuntime": false,
"id": "timestamp",
"info": Array [],
"isMapped": false,
"isUserEditable": false,
"kbnType": undefined,
"name": "timestamp",
"type": "date",
},
Object {
"displayName": "conflictingField",
"esTypes": Array [
"keyword",
"long",
],
"excluded": false,
"format": "",
"hasRuntime": false,
"id": "conflictingField",
"info": Array [],
"isMapped": false,
"isUserEditable": false,
"kbnType": undefined,
"name": "conflictingField",
"type": "keyword, long",
},
Object {
"displayName": "amount",
"esTypes": Array [
"long",
],
"excluded": false,
"format": "",
"hasRuntime": false,
"id": "amount",
"info": Array [],
"isMapped": false,
"isUserEditable": false,
"kbnType": undefined,
"name": "amount",
"type": "long",
},
Object {
"displayName": "runtime",
"esTypes": Array [
"long",
],
"excluded": false,
"format": "",
"hasRuntime": true,
"id": "runtime",
"info": Array [],
"isMapped": false,
"isUserEditable": false,
"kbnType": "number",
"name": "runtime",
"runtimeField": Object {
"script": Object {
"source": "emit('Hello');",
},
"type": "long",
},
"type": "long",
},
]
}
openModal={[Function]}
theme={Object {}}
/>
</div>
"type": "long",
},
"type": "long",
},
],
}
`;

View file

@ -11,9 +11,9 @@ import { shallow } from 'enzyme';
import { DataView } from '@kbn/data-views-plugin/public';
import { IndexedFieldItem } from '../../types';
import { Table, renderFieldName, getConflictModalContent, showDelete } from './table';
import { overlayServiceMock, themeServiceMock } from '@kbn/core/public/mocks';
import { coreMock, overlayServiceMock } from '@kbn/core/public/mocks';
const theme = themeServiceMock.createStartContract();
const coreStart = coreMock.createStart();
const indexPattern = {
timeFieldName: 'timestamp',
@ -91,7 +91,7 @@ const renderTable = (
editField={editField}
deleteField={() => {}}
openModal={overlayServiceMock.createStartContract().openModal}
theme={theme}
startServices={coreStart}
/>
);

View file

@ -7,7 +7,7 @@
*/
import React, { PureComponent } from 'react';
import { OverlayModalStart, ThemeServiceStart } from '@kbn/core/public';
import { OverlayModalStart } from '@kbn/core/public';
import { FieldDescription } from '@kbn/field-utils';
import {
EuiIcon,
@ -29,9 +29,10 @@ import {
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import { toMountPoint } from '@kbn/kibana-react-plugin/public';
import { toMountPoint } from '@kbn/react-kibana-mount';
import { DataView } from '@kbn/data-views-plugin/public';
import { StartServices } from '../../../../../types';
import { IndexedFieldItem } from '../../types';
export const showDelete = (field: IndexedFieldItem) =>
@ -205,7 +206,7 @@ interface IndexedFieldProps {
editField: (field: IndexedFieldItem) => void;
deleteField: (fieldName: string[]) => void;
openModal: OverlayModalStart['open'];
theme: ThemeServiceStart;
startServices: StartServices;
}
const getItems = (conflictDescriptions: IndexedFieldItem['conflictDescriptions']) => {
@ -343,7 +344,7 @@ const getConflictBtn = (
fieldName: string,
conflictDescriptions: IndexedFieldItem['conflictDescriptions'],
openModal: IndexedFieldProps['openModal'],
theme: ThemeServiceStart
startServices: StartServices
) => {
const onClick = () => {
const overlayRef = openModal(
@ -355,7 +356,7 @@ const getConflictBtn = (
fieldName,
conflictDescriptions,
}),
{ theme$: theme.theme$ }
startServices
)
);
};
@ -393,7 +394,7 @@ export class Table extends PureComponent<IndexedFieldProps> {
field.name,
field.conflictDescriptions,
this.props.openModal,
this.props.theme
this.props.startServices
)
: ''}
</span>
@ -414,7 +415,7 @@ export class Table extends PureComponent<IndexedFieldProps> {
name: nameHeader,
dataType: 'string',
sortable: true,
render: (value: string, field: IndexedFieldItem) => {
render: (_value: string, field: IndexedFieldItem) => {
return renderFieldName(field, indexPattern.timeFieldName);
},
width: '38%',

View file

@ -8,6 +8,7 @@
import React from 'react';
import { shallow, ShallowWrapper } from 'enzyme';
import { coreMock } from '@kbn/core/public/mocks';
import { DataViewField, DataView, DataViewType } from '@kbn/data-views-plugin/public';
import { IndexedFieldsTable } from './indexed_fields_table';
import { getFieldInfo } from '../../utils';
@ -28,8 +29,8 @@ jest.mock('./components/table', () => ({
}));
const helpers = {
editField: (fieldName: string) => {},
deleteField: (fieldName: string[]) => {},
editField: (_fieldName: string) => {},
deleteField: (_fieldName: string[]) => {},
// getFieldInfo handles non rollups as well
getFieldInfo,
};
@ -99,6 +100,8 @@ const fields = [
},
].map(mockFieldToIndexPatternField);
const startServices = coreMock.createStart();
const mockedServices = {
userEditPermission: false,
openModal: () => ({ onClose: new Promise<void>(() => {}), close: async () => {} }),
@ -119,6 +122,7 @@ describe('IndexedFieldsTable', () => {
schemaFieldTypeFilter={[]}
fieldFilter=""
compositeRuntimeFields={{}}
startServices={startServices}
{...mockedServices}
/>
);
@ -126,7 +130,7 @@ describe('IndexedFieldsTable', () => {
await new Promise((resolve) => process.nextTick(resolve));
component.update();
expect(component).toMatchSnapshot();
expect({ items: component.props().children.props.items }).toMatchSnapshot();
});
test('should filter based on the query bar', async () => {
@ -142,6 +146,7 @@ describe('IndexedFieldsTable', () => {
schemaFieldTypeFilter={[]}
fieldFilter=""
compositeRuntimeFields={{}}
startServices={startServices}
{...mockedServices}
/>
);
@ -150,7 +155,7 @@ describe('IndexedFieldsTable', () => {
component.setProps({ fieldFilter: 'Elast' });
component.update();
expect(component).toMatchSnapshot();
expect({ items: component.props().children.props.items }).toMatchSnapshot();
});
test('should filter based on the type filter', async () => {
@ -166,6 +171,7 @@ describe('IndexedFieldsTable', () => {
schemaFieldTypeFilter={[]}
fieldFilter=""
compositeRuntimeFields={{}}
startServices={startServices}
{...mockedServices}
/>
);
@ -174,7 +180,7 @@ describe('IndexedFieldsTable', () => {
component.setProps({ indexedFieldTypeFilter: ['date'] });
component.update();
expect(component).toMatchSnapshot();
expect({ items: component.props().children.props.items }).toMatchSnapshot();
});
test('should filter based on the schema filter', async () => {
@ -190,6 +196,7 @@ describe('IndexedFieldsTable', () => {
schemaFieldTypeFilter={[]}
fieldFilter=""
compositeRuntimeFields={{}}
startServices={startServices}
{...mockedServices}
/>
);
@ -198,7 +205,7 @@ describe('IndexedFieldsTable', () => {
component.setProps({ schemaFieldTypeFilter: ['runtime'] });
component.update();
expect(component).toMatchSnapshot();
expect({ items: component.props().children.props.items }).toMatchSnapshot();
});
describe('IndexedFieldsTable with rollup index pattern', () => {
@ -215,6 +222,7 @@ describe('IndexedFieldsTable', () => {
schemaFieldTypeFilter={[]}
fieldFilter=""
compositeRuntimeFields={{}}
startServices={startServices}
{...mockedServices}
/>
);
@ -222,7 +230,7 @@ describe('IndexedFieldsTable', () => {
await new Promise((resolve) => process.nextTick(resolve));
component.update();
expect(component).toMatchSnapshot();
expect({ items: component.props().children.props.items }).toMatchSnapshot();
});
});
});

View file

@ -8,10 +8,11 @@
import React, { Component } from 'react';
import { createSelector } from 'reselect';
import { OverlayStart, ThemeServiceStart } from '@kbn/core/public';
import { OverlayStart } from '@kbn/core/public';
import { DataViewField, DataView, RuntimeField } from '@kbn/data-views-plugin/public';
import { Table } from './components/table';
import { IndexedFieldItem } from './types';
import { StartServices } from '../../../types';
interface IndexedFieldsTableProps {
fields: DataViewField[];
@ -27,8 +28,8 @@ interface IndexedFieldsTableProps {
fieldWildcardMatcher: (filters: string[] | undefined) => (val: string) => boolean;
userEditPermission: boolean;
openModal: OverlayStart['openModal'];
theme: ThemeServiceStart;
compositeRuntimeFields: Record<string, RuntimeField>;
startServices: StartServices;
}
interface IndexedFieldsTableState {
@ -196,7 +197,7 @@ export class IndexedFieldsTable extends Component<
editField={(field) => this.props.helpers.editField(field.name)}
deleteField={(fieldNames) => this.props.helpers.deleteField(fieldNames)}
openModal={this.props.openModal}
theme={this.props.theme}
startServices={this.props.startServices}
/>
</div>
);

View file

@ -10,8 +10,9 @@ import { i18n } from '@kbn/i18n';
import type { IUiSettingsClient, OverlayStart } from '@kbn/core/public';
import { asyncForEach } from '@kbn/std';
import { EuiConfirmModalProps } from '@elastic/eui';
import { toMountPoint } from '@kbn/kibana-react-plugin/public';
import { toMountPoint } from '@kbn/react-kibana-mount';
import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public';
import type { StartServices } from '../../types';
const confirmModalOptionsDelete = {
confirmButtonText: i18n.translate('indexPatternManagement.editIndexPattern.deleteButton', {
@ -36,15 +37,18 @@ interface RemoveDataViewDeps {
uiSettings: IUiSettingsClient;
overlays: OverlayStart;
onDelete: () => void;
startServices: StartServices;
}
export const removeDataView =
({ dataViews, overlays, onDelete }: RemoveDataViewDeps) =>
({ dataViews, overlays, onDelete, startServices }: RemoveDataViewDeps) =>
(dataViewArray: RemoveDataViewProps[], msg: JSX.Element) => {
overlays.openConfirm(toMountPoint(msg), confirmModalOptionsDelete).then(async (isConfirmed) => {
if (isConfirmed) {
await asyncForEach(dataViewArray, async ({ id }) => dataViews.delete(id));
onDelete();
}
});
overlays
.openConfirm(toMountPoint(msg, startServices), confirmModalOptionsDelete)
.then(async (isConfirmed) => {
if (isConfirmed) {
await asyncForEach(dataViewArray, async ({ id }) => dataViews.delete(id));
onDelete();
}
});
};

View file

@ -178,11 +178,11 @@ export const Tabs: React.FC<TabsProps> = ({
docLinks,
dataViewFieldEditor,
overlays,
theme,
dataViews,
http,
application,
savedObjectsManagement,
...startServices
} = useKibana<IndexPatternManagmentContext>().services;
const [fieldFilter, setFieldFilter] = useState<string>('');
const [syncingStateFunc, setSyncingStateFunc] = useState<{
@ -377,7 +377,7 @@ export const Tabs: React.FC<TabsProps> = ({
isOpen={isIndexedFilterOpen}
closePopover={() => setIsIndexedFilterOpen(false)}
>
{indexedFieldTypes.map((item, index) => {
{indexedFieldTypes.map((item) => {
const isSelected = filteredIndexedFieldTypeFilter.includes(item.value);
return (
<EuiFilterSelectItem
@ -582,8 +582,8 @@ export const Tabs: React.FC<TabsProps> = ({
getFieldInfo,
}}
openModal={overlays.openModal}
theme={theme}
userEditPermission={dataViews.getCanSaveSync()}
startServices={startServices}
/>
)}
</DeleteRuntimeFieldProvider>
@ -661,7 +661,7 @@ export const Tabs: React.FC<TabsProps> = ({
DeleteRuntimeFieldProvider,
refreshFields,
overlays,
theme,
startServices,
dataViews,
compositeRuntimeFields,
http,

View file

@ -89,6 +89,7 @@ export const IndexPatternTable = ({
overlays,
docLinks,
noDataPage,
...startServices
} = useKibana<IndexPatternManagmentContext>().services;
const [query, setQuery] = useState('');
const [showCreateDialog, setShowCreateDialog] = useState<boolean>(showCreateDialogProp);
@ -128,6 +129,7 @@ export const IndexPatternTable = ({
setSelectedItems([]);
dataViewController.loadDataViews();
},
startServices,
});
if (selectedItems.length === 0) {
return;
@ -183,6 +185,7 @@ export const IndexPatternTable = ({
uiSettings,
overlays,
onDelete: () => dataViewController.loadDataViews(),
startServices,
});
const alertColumn = {
@ -218,7 +221,7 @@ export const IndexPatternTable = ({
defaultMessage: 'Name',
}),
width: spaces ? '70%' : '90%',
render: (name: string, dataView: IndexPatternTableItem) => (
render: (_name: string, dataView: IndexPatternTableItem) => (
<div>
<EuiLink
{...reactRouterNavigate(history, `patterns/${dataView.id}`)}
@ -261,7 +264,7 @@ export const IndexPatternTable = ({
defaultMessage: 'Spaces',
}),
width: '20%',
render: (name: string, dataView: IndexPatternTableItem) => {
render: (_name: string, dataView: IndexPatternTableItem) => {
return spaces ? (
<SpacesList
spacesApi={spaces}

View file

@ -53,8 +53,7 @@ export async function mountManagementSection(
overlays,
http,
docLinks,
theme,
i18n: coreI18n,
...startServices
},
{
data,
@ -93,9 +92,9 @@ export async function mountManagementSection(
IndexPatternEditor: dataViewEditor.IndexPatternEditorComponent,
fieldFormats,
spaces: spaces?.hasOnlyDefaultSpace ? undefined : spaces,
theme,
savedObjectsManagement,
noDataPage,
...startServices,
};
const editPath = '/dataView/:id/field/:fieldName';
@ -103,7 +102,7 @@ export async function mountManagementSection(
const createEditPath = dataViews.scriptedFieldsEnabled ? [editPath, createPath] : [editPath];
ReactDOM.render(
<KibanaRenderContextProvider theme={theme} i18n={coreI18n}>
<KibanaRenderContextProvider {...startServices}>
<KibanaContextProvider services={deps}>
<Router history={params.history}>
<Routes>

View file

@ -25,6 +25,9 @@ import {
} from './plugin';
import { IndexPatternManagmentContext } from './types';
const coreSetup = coreMock.createSetup();
const coreStart = coreMock.createStart();
const createSetupContract = (): IndexPatternManagementSetup => ({});
const createStartContract = (): IndexPatternManagementStart => ({});
@ -32,7 +35,7 @@ const createStartContract = (): IndexPatternManagementStart => ({});
const createInstance = async () => {
const plugin = new IndexPatternManagementPlugin({} as PluginInitializerContext);
const setup = plugin.setup(coreMock.createSetup(), {
const setup = plugin.setup(coreSetup, {
management: managementPluginMock.createSetupContract(),
urlForwarding: urlForwardingPluginMock.createSetupContract(),
noDataPage: noDataPagePublicMock.createSetup(),
@ -59,9 +62,6 @@ const docLinks = {
const createIndexPatternManagmentContext = (): {
[key in keyof IndexPatternManagmentContext]: any;
} => {
const { application, chrome, uiSettings, notifications, overlays, theme, settings } =
coreMock.createStart();
const { http } = coreMock.createSetup();
const data = dataPluginMock.createStartContract();
const dataViewFieldEditor = indexPatternFieldEditorPluginMock.createStartContract();
const dataViews = dataViewPluginMocks.createStartContract();
@ -69,13 +69,7 @@ const createIndexPatternManagmentContext = (): {
const savedObjectsManagement = savedObjectsManagementPluginMock.createStartContract();
return {
application,
chrome,
uiSettings,
settings,
notifications,
overlays,
http,
...coreStart,
docLinks,
data,
dataViews,
@ -88,7 +82,6 @@ const createIndexPatternManagmentContext = (): {
IndexPatternEditor:
indexPatternEditorPluginMock.createStartContract().IndexPatternEditorComponent,
fieldFormats: fieldFormatsServiceMock.createStartContract(),
theme,
savedObjectsManagement,
};
};

View file

@ -8,13 +8,13 @@
import type {
ChromeStart,
CoreStart,
IUiSettingsClient,
OverlayStart,
NotificationsStart,
DocLinksStart,
HttpSetup,
ApplicationStart,
ThemeServiceStart,
} from '@kbn/core/public';
import type { DataPublicPluginStart } from '@kbn/data-plugin/public';
import type { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public';
@ -30,7 +30,9 @@ import type { SettingsStart } from '@kbn/core-ui-settings-browser';
import type { NoDataPagePluginSetup } from '@kbn/no-data-page-plugin/public';
import type { IndexPatternManagementStart } from '.';
export interface IndexPatternManagmentContext {
export type StartServices = Pick<CoreStart, 'analytics' | 'i18n' | 'theme'>;
export interface IndexPatternManagmentContext extends StartServices {
application: ApplicationStart;
chrome: ChromeStart;
uiSettings: IUiSettingsClient;
@ -49,7 +51,6 @@ export interface IndexPatternManagmentContext {
IndexPatternEditor: DataViewEditorStart['IndexPatternEditorComponent'];
fieldFormats: FieldFormatsStart;
spaces?: SpacesPluginStart;
theme: ThemeServiceStart;
savedObjectsManagement: SavedObjectsManagementPluginStart;
noDataPage?: NoDataPagePluginSetup;
}

View file

@ -43,6 +43,7 @@
"@kbn/shared-ux-page-analytics-no-data",
"@kbn/core-http-browser",
"@kbn/code-editor",
"@kbn/react-kibana-mount",
],
"exclude": [
"target/**/*",

View file

@ -105,10 +105,7 @@ export function useContextAppFetch({
setState(createError('anchorStatus', FailureReason.UNKNOWN, error));
toastNotifications.addDanger({
title: errorTitle,
text: toMountPoint(<Markdown readOnly>{error.message}</Markdown>, {
theme: services.core.theme,
i18n: services.core.i18n,
}),
text: toMountPoint(<Markdown readOnly>{error.message}</Markdown>, services),
});
}
}, [
@ -160,10 +157,7 @@ export function useContextAppFetch({
setState(createError(statusKey, FailureReason.UNKNOWN, error));
toastNotifications.addDanger({
title: errorTitle,
text: toMountPoint(<Markdown readOnly>{error.message}</Markdown>, {
theme: services.core.theme,
i18n: services.core.i18n,
}),
text: toMountPoint(<Markdown readOnly>{error.message}</Markdown>, services),
});
}
},

View file

@ -48,10 +48,7 @@ export const renderApp = ({
experimentalFeatures={experimentalFeatures}
history={history}
/>,
{
theme: core.theme,
i18n: core.i18n,
}
core
)(element);
return () => {

View file

@ -145,7 +145,7 @@ const mountComponent = async ({
stateContainer.searchSessionManager = createSearchSessionMock(session).searchSessionManager;
const component = mountWithIntl(
<KibanaRenderContextProvider theme={services.core.theme} i18n={services.core.i18n}>
<KibanaRenderContextProvider {...services.core}>
<KibanaContextProvider services={services}>
<DiscoverMainProvider value={stateContainer}>
<DiscoverHistogramLayout {...props} />

View file

@ -128,7 +128,7 @@ const mountComponent = async ({
};
const component = mountWithIntl(
<KibanaRenderContextProvider theme={services.core.theme} i18n={services.core.i18n}>
<KibanaRenderContextProvider {...services.core}>
<KibanaContextProvider services={services}>
<DiscoverMainProvider value={stateContainer}>
<DiscoverMainContent {...props} />

View file

@ -218,7 +218,7 @@ export function openAlertsPopover({
document.body.appendChild(container);
const element = (
<KibanaRenderContextProvider theme={services.core.theme} i18n={services.core.i18n}>
<KibanaRenderContextProvider {...services.core}>
<KibanaContextProvider services={services}>
<AlertsPopover
onClose={closeAlertsPopover}

View file

@ -36,7 +36,7 @@ export function showOpenSearchPanel({
document.body.appendChild(container);
const element = (
<KibanaRenderContextProvider theme={services.core.theme} i18n={services.core.i18n}>
<KibanaRenderContextProvider {...services.core}>
<KibanaContextProvider services={services}>
<OpenSearchPanel onClose={onClose} onOpenSavedSearch={onOpenSavedSearch} />
</KibanaContextProvider>

View file

@ -43,10 +43,7 @@ export function NotFoundRoute() {
/>
</p>
</EuiCallOut>,
{
theme: core.theme,
i18n: core.i18n,
}
core
)
);

View file

@ -84,10 +84,7 @@ export const getAlertUtils = (
});
toastNotifications.addDanger({
title: errorTitle,
text: toMountPoint(<Markdown readOnly>{error.message}</Markdown>, {
theme: core.theme,
i18n: core.i18n,
}),
text: toMountPoint(<Markdown readOnly>{error.message}</Markdown>, core),
});
throw new Error(errorTitle);
}
@ -107,10 +104,7 @@ export const getAlertUtils = (
});
toastNotifications.addDanger({
title: errorTitle,
text: toMountPoint(<Markdown markdownContent={error.message} readOnly />, {
theme: core.theme,
i18n: core.i18n,
}),
text: toMountPoint(<Markdown markdownContent={error.message} readOnly />, core),
});
throw new Error(errorTitle);
}

View file

@ -14,6 +14,7 @@ import {
CoreStart,
DocLinksStart,
ToastsStart,
I18nStart,
IUiSettingsClient,
PluginInitializerContext,
HttpStart,
@ -77,6 +78,7 @@ export interface DiscoverServices {
application: ApplicationStart;
addBasePath: (path: string) => string;
analytics: AnalyticsServiceStart;
i18n: I18nStart;
capabilities: Capabilities;
chrome: ChromeStart;
core: CoreStart;
@ -160,6 +162,7 @@ export const buildServices = memoize(
data: plugins.data,
docLinks: core.docLinks,
embeddable: plugins.embeddable,
i18n: core.i18n,
theme: core.theme,
fieldFormats: plugins.fieldFormats,
filterManager: plugins.data.query.filterManager,

View file

@ -7,34 +7,31 @@
*/
import React from 'react';
import { I18nProvider } from '@kbn/i18n-react';
import { DocTableEmbeddable, DocTableEmbeddableProps } from './doc_table_embeddable';
export function DiscoverDocTableEmbeddable(renderProps: DocTableEmbeddableProps) {
return (
<I18nProvider>
<DocTableEmbeddable
columns={renderProps.columns}
rows={renderProps.rows}
rowsPerPageState={renderProps.rowsPerPageState}
sampleSizeState={renderProps.sampleSizeState}
onUpdateRowsPerPage={renderProps.onUpdateRowsPerPage}
totalHitCount={renderProps.totalHitCount}
dataView={renderProps.dataView}
onSort={renderProps.onSort}
onAddColumn={renderProps.onAddColumn}
onMoveColumn={renderProps.onMoveColumn}
onRemoveColumn={renderProps.onRemoveColumn}
sort={renderProps.sort}
filters={renderProps.filters}
onFilter={renderProps.onFilter}
useNewFieldsApi={renderProps.useNewFieldsApi}
searchDescription={renderProps.searchDescription}
sharedItemTitle={renderProps.sharedItemTitle}
isLoading={renderProps.isLoading}
isPlainRecord={renderProps.isPlainRecord}
interceptedWarnings={renderProps.interceptedWarnings}
/>
</I18nProvider>
<DocTableEmbeddable
columns={renderProps.columns}
rows={renderProps.rows}
rowsPerPageState={renderProps.rowsPerPageState}
sampleSizeState={renderProps.sampleSizeState}
onUpdateRowsPerPage={renderProps.onUpdateRowsPerPage}
totalHitCount={renderProps.totalHitCount}
dataView={renderProps.dataView}
onSort={renderProps.onSort}
onAddColumn={renderProps.onAddColumn}
onMoveColumn={renderProps.onMoveColumn}
onRemoveColumn={renderProps.onRemoveColumn}
sort={renderProps.sort}
filters={renderProps.filters}
onFilter={renderProps.onFilter}
useNewFieldsApi={renderProps.useNewFieldsApi}
searchDescription={renderProps.searchDescription}
sharedItemTitle={renderProps.sharedItemTitle}
isLoading={renderProps.isLoading}
isPlainRecord={renderProps.isPlainRecord}
interceptedWarnings={renderProps.interceptedWarnings}
/>
);
}

View file

@ -651,10 +651,7 @@ export class SavedSearchEmbeddable
Array.isArray(searchProps.columns)
) {
ReactDOM.render(
<KibanaRenderContextProvider
theme={searchProps.services.core.theme}
i18n={searchProps.services.core.i18n}
>
<KibanaRenderContextProvider {...searchProps.services.core}>
<KibanaContextProvider services={searchProps.services}>
<FieldStatisticsTable
dataView={searchProps.dataView}
@ -694,10 +691,7 @@ export class SavedSearchEmbeddable
const { getTriggerCompatibleActions } = searchProps.services.uiActions;
ReactDOM.render(
<KibanaRenderContextProvider
theme={searchProps.services.core.theme}
i18n={searchProps.services.core.i18n}
>
<KibanaRenderContextProvider {...searchProps.services.core}>
<KibanaContextProvider services={searchProps.services}>
<CellActionsProvider getTriggerCompatibleActions={getTriggerCompatibleActions}>
<SavedSearchEmbeddableComponent

View file

@ -10,15 +10,19 @@ import React from 'react';
import ReactDOM from 'react-dom';
import { EuiConfirmModal } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render';
import { StartRenderServices } from '../plugin';
let isOpenConfirmPanel = false;
export const showConfirmPanel = ({
onConfirm,
onCancel,
startServices,
}: {
onConfirm: () => void;
onCancel: () => void;
startServices: StartRenderServices;
}) => {
if (isOpenConfirmPanel) {
return;
@ -34,32 +38,34 @@ export const showConfirmPanel = ({
document.body.appendChild(container);
const element = (
<EuiConfirmModal
title={i18n.translate('discover.confirmDataViewSave.title', {
defaultMessage: 'Save data view',
})}
onCancel={() => {
onClose();
onCancel();
}}
onConfirm={() => {
onClose();
onConfirm();
}}
cancelButtonText={i18n.translate('discover.confirmDataViewSave.cancel', {
defaultMessage: 'Cancel',
})}
confirmButtonText={i18n.translate('discover.confirmDataViewSave.saveAndContinue', {
defaultMessage: 'Save and continue',
})}
defaultFocusedButton="confirm"
>
<p>
{i18n.translate('discover.confirmDataViewSave.message', {
defaultMessage: 'The action you chose requires a saved data view.',
<KibanaRenderContextProvider {...startServices}>
<EuiConfirmModal
title={i18n.translate('discover.confirmDataViewSave.title', {
defaultMessage: 'Save data view',
})}
</p>
</EuiConfirmModal>
onCancel={() => {
onClose();
onCancel();
}}
onConfirm={() => {
onClose();
onConfirm();
}}
cancelButtonText={i18n.translate('discover.confirmDataViewSave.cancel', {
defaultMessage: 'Cancel',
})}
confirmButtonText={i18n.translate('discover.confirmDataViewSave.saveAndContinue', {
defaultMessage: 'Save and continue',
})}
defaultFocusedButton="confirm"
>
<p>
{i18n.translate('discover.confirmDataViewSave.message', {
defaultMessage: 'The action you chose requires a saved data view.',
})}
</p>
</EuiConfirmModal>
</KibanaRenderContextProvider>
);
ReactDOM.render(element, container);
};

View file

@ -198,6 +198,8 @@ export interface DiscoverStartPlugins {
noDataPage?: NoDataPagePluginStart;
}
export type StartRenderServices = Pick<CoreStart, 'analytics' | 'i18n' | 'theme'>;
/**
* Contains Discover, one of the oldest parts of Kibana
* Discover provides embeddables for Dashboards