[UnifiedDocViewer] Remove usage of KibanaContextProvider (#167202)

## Summary

Removes usages of `KibanaContextProvider` to simplify the API of the
`UnifiedDocViewer` component. Instead, necessary services are accessed
from the plugin itself (via `getUnifiedDocViewerServices`). Removes the
`useUnifiedDocViewerServices` hook since it's no longer needed.

Resolves #168380

### Checklist

- [ ]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [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

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Lukas Olson 2023-12-01 14:21:16 -07:00 committed by GitHub
parent 8fdfa633e5
commit 1533f304a8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 78 additions and 147 deletions

View file

@ -18,6 +18,7 @@ import { dataViewMock } from '@kbn/discover-utils/src/__mocks__';
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
import { setUnifiedDocViewerServices } from '@kbn/unified-doc-viewer-plugin/public/plugin';
import { mockUnifiedDocViewerServices } from '@kbn/unified-doc-viewer-plugin/public/__mocks__';
import type { UnifiedDocViewerServices } from '@kbn/unified-doc-viewer-plugin/public/types';
const mockSearchApi = jest.fn();
@ -68,7 +69,14 @@ async function mountDoc(update = false) {
locator: { getUrl: jest.fn(() => Promise.resolve('mock-url')) },
chrome: { setBreadcrumbs: jest.fn() },
};
setUnifiedDocViewerServices(mockUnifiedDocViewerServices);
setUnifiedDocViewerServices({
...mockUnifiedDocViewerServices,
data: {
search: {
search: mockSearchApi,
},
},
} as unknown as UnifiedDocViewerServices);
await act(async () => {
comp = mountWithIntl(
<KibanaContextProvider services={services}>

View file

@ -7,16 +7,11 @@
*/
import React from 'react';
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
import type { DocViewRenderProps } from '@kbn/unified-doc-viewer/types';
import { DocViewer } from '@kbn/unified-doc-viewer';
import { getUnifiedDocViewerServices } from '../../plugin';
export function UnifiedDocViewer(props: DocViewRenderProps) {
const services = getUnifiedDocViewerServices();
return (
<KibanaContextProvider services={services}>
<DocViewer docViews={services.unifiedDocViewer.getDocViews(props.hit)} {...props} />
</KibanaContextProvider>
);
const { unifiedDocViewer } = getUnifiedDocViewerServices();
return <DocViewer docViews={unifiedDocViewer.getDocViews(props.hit)} {...props} />;
}

View file

@ -7,25 +7,20 @@
*/
import React from 'react';
import type { DataView } from '@kbn/data-views-plugin/public';
import { mountWithIntl } from '@kbn/test-jest-helpers';
import { DocViewerSource } from './source';
import * as hooks from '../../hooks/use_es_doc_search';
import * as useUiSettingHook from '@kbn/kibana-react-plugin/public/ui_settings/use_ui_setting';
import { EuiButton, EuiEmptyPrompt, EuiLoadingSpinner } from '@elastic/eui';
import { JsonCodeEditorCommon } from '../json_code_editor';
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
import { buildDataTableRecord } from '@kbn/discover-utils';
import { of } from 'rxjs';
import { setUnifiedDocViewerServices } from '../../plugin';
import type { UnifiedDocViewerServices } from '../../types';
const mockDataView = {
getComputedFields: () => [],
} as never;
const getMock = jest.fn(() => Promise.resolve(mockDataView));
const mockDataViewService = {
get: getMock,
} as unknown as DataView;
const services = {
setUnifiedDocViewerServices({
uiSettings: {
get: (key: string) => {
if (key === 'discover:useNewFieldsApi') {
@ -33,29 +28,21 @@ const services = {
}
},
},
data: {
dataViewService: mockDataViewService,
},
theme: {
theme$: of({ darkMode: false }),
},
};
} as UnifiedDocViewerServices);
describe('Source Viewer component', () => {
test('renders loading state', () => {
jest.spyOn(hooks, 'useEsDocSearch').mockImplementation(() => [0, null, () => {}]);
const comp = mountWithIntl(
<KibanaContextProvider services={services}>
<DocViewerSource
id={'1'}
index={'index1'}
dataView={mockDataView}
width={123}
hasLineNumbers={true}
onRefresh={() => {}}
/>
</KibanaContextProvider>
<DocViewerSource
id={'1'}
index={'index1'}
dataView={mockDataView}
width={123}
hasLineNumbers={true}
onRefresh={() => {}}
/>
);
const loadingIndicator = comp.find(EuiLoadingSpinner);
expect(loadingIndicator).not.toBe(null);
@ -65,16 +52,14 @@ describe('Source Viewer component', () => {
jest.spyOn(hooks, 'useEsDocSearch').mockImplementation(() => [3, null, () => {}]);
const comp = mountWithIntl(
<KibanaContextProvider services={services}>
<DocViewerSource
id={'1'}
index={'index1'}
dataView={mockDataView}
width={123}
hasLineNumbers={true}
onRefresh={() => {}}
/>
</KibanaContextProvider>
<DocViewerSource
id={'1'}
index={'index1'}
dataView={mockDataView}
width={123}
hasLineNumbers={true}
onRefresh={() => {}}
/>
);
const errorPrompt = comp.find(EuiEmptyPrompt);
expect(errorPrompt.length).toBe(1);
@ -105,16 +90,14 @@ describe('Source Viewer component', () => {
return false;
});
const comp = mountWithIntl(
<KibanaContextProvider services={services}>
<DocViewerSource
id={'1'}
index={'index1'}
dataView={mockDataView}
width={123}
hasLineNumbers={true}
onRefresh={() => {}}
/>
</KibanaContextProvider>
<DocViewerSource
id={'1'}
index={'index1'}
dataView={mockDataView}
width={123}
hasLineNumbers={true}
onRefresh={() => {}}
/>
);
const jsonCodeEditor = comp.find(JsonCodeEditorCommon);
expect(jsonCodeEditor).not.toBe(null);

View file

@ -16,7 +16,8 @@ import type { DataView } from '@kbn/data-views-plugin/public';
import type { DataTableRecord } from '@kbn/discover-utils/types';
import { ElasticRequestState } from '@kbn/unified-doc-viewer';
import { DOC_TABLE_LEGACY, SEARCH_FIELDS_FROM_SOURCE } from '@kbn/discover-utils';
import { useEsDocSearch, useUnifiedDocViewerServices } from '../../hooks';
import { getUnifiedDocViewerServices } from '../../plugin';
import { useEsDocSearch } from '../../hooks';
import { getHeight } from './get_height';
import { JSONCodeEditorCommonMemoized } from '../json_code_editor';
@ -51,7 +52,7 @@ export const DocViewerSource = ({
const [editor, setEditor] = useState<monaco.editor.IStandaloneCodeEditor>();
const [editorHeight, setEditorHeight] = useState<number>();
const [jsonValue, setJsonValue] = useState<string>('');
const { uiSettings } = useUnifiedDocViewerServices();
const { uiSettings } = getUnifiedDocViewerServices();
const useNewFieldsApi = !uiSettings.get(SEARCH_FIELDS_FROM_SOURCE);
const useDocExplorer = !uiSettings.get(DOC_TABLE_LEGACY);
const [requestState, hit] = useEsDocSearch({

View file

@ -12,9 +12,9 @@ import { findTestSubject } from '@elastic/eui/lib/test';
import { DocViewerLegacyTable } from './table';
import type { DataView } from '@kbn/data-views-plugin/public';
import type { DocViewRenderProps } from '@kbn/unified-doc-viewer/types';
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
import { buildDataTableRecord } from '@kbn/discover-utils';
import type { UnifiedDocViewerServices } from '../../../hooks';
import { setUnifiedDocViewerServices } from '../../../plugin';
import type { UnifiedDocViewerServices } from '../../../types';
const services = {
uiSettings: {
@ -77,11 +77,8 @@ const mountComponent = (
props: DocViewRenderProps,
overrides?: Partial<UnifiedDocViewerServices>
) => {
return mountWithIntl(
<KibanaContextProvider services={{ ...services, ...overrides }}>
<DocViewerLegacyTable {...props} />{' '}
</KibanaContextProvider>
);
setUnifiedDocViewerServices({ ...services, ...overrides } as UnifiedDocViewerServices);
return mountWithIntl(<DocViewerLegacyTable {...props} />);
};
describe('DocViewTable at Discover', () => {

View file

@ -18,7 +18,7 @@ import {
isNestedFieldParent,
} from '@kbn/discover-utils';
import type { DocViewRenderProps, FieldRecordLegacy } from '@kbn/unified-doc-viewer/types';
import { useUnifiedDocViewerServices } from '../../../hooks';
import { getUnifiedDocViewerServices } from '../../../plugin';
import { ACTIONS_COLUMN, MAIN_COLUMNS } from './table_columns';
export const DocViewerLegacyTable = ({
@ -30,7 +30,7 @@ export const DocViewerLegacyTable = ({
onAddColumn,
onRemoveColumn,
}: DocViewRenderProps) => {
const { fieldFormats, uiSettings } = useUnifiedDocViewerServices();
const { fieldFormats, uiSettings } = getUnifiedDocViewerServices();
const showMultiFields = useMemo(() => uiSettings.get(SHOW_MULTIFIELDS), [uiSettings]);
const mapping = useCallback((name: string) => dataView.fields.getByName(name), [dataView.fields]);

View file

@ -41,7 +41,7 @@ import {
import { fieldNameWildcardMatcher, getFieldSearchMatchingHighlight } from '@kbn/field-utils';
import type { DocViewRenderProps, FieldRecordLegacy } from '@kbn/unified-doc-viewer/types';
import { FieldName } from '@kbn/unified-doc-viewer';
import { useUnifiedDocViewerServices } from '../../hooks';
import { getUnifiedDocViewerServices } from '../../plugin';
import { TableFieldValue } from './table_cell_value';
import { TableActions } from './table_cell_actions';
@ -116,7 +116,7 @@ export const DocViewerTable = ({
}: DocViewRenderProps) => {
const showActionsInsideTableCell = useIsWithinBreakpoints(['xl'], true);
const { fieldFormats, storage, uiSettings } = useUnifiedDocViewerServices();
const { fieldFormats, storage, uiSettings } = getUnifiedDocViewerServices();
const showMultiFields = uiSettings.get(SHOW_MULTIFIELDS);
const currentDataViewId = dataView.id!;

View file

@ -6,5 +6,4 @@
* Side Public License, v 1.
*/
export * from './use_doc_viewer_services';
export * from './use_es_doc_search';

View file

@ -1,30 +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
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { AnalyticsServiceStart } from '@kbn/core-analytics-browser';
import type { DataPublicPluginStart } from '@kbn/data-plugin/public';
import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public';
import type { Storage } from '@kbn/kibana-utils-plugin/public';
import type { IUiSettingsClient } from '@kbn/core-ui-settings-browser';
import { useKibana } from '@kbn/kibana-react-plugin/public';
import type { UnifiedDocViewerStart } from '../plugin';
export interface UnifiedDocViewerServices {
analytics: AnalyticsServiceStart;
data: DataPublicPluginStart;
fieldFormats: FieldFormatsStart;
storage: Storage;
uiSettings: IUiSettingsClient;
unifiedDocViewer: UnifiedDocViewerStart;
}
export function useUnifiedDocViewerServices(): UnifiedDocViewerServices {
const { services } = useKibana<UnifiedDocViewerServices>();
const { analytics, data, fieldFormats, storage, uiSettings, unifiedDocViewer } = services;
return { analytics, data, fieldFormats, storage, uiSettings, unifiedDocViewer };
}

View file

@ -15,12 +15,12 @@ import {
SEARCH_FIELDS_FROM_SOURCE as mockSearchFieldsFromSource,
buildDataTableRecord,
} from '@kbn/discover-utils';
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
import React from 'react';
import { setUnifiedDocViewerServices } from '../plugin';
import { UnifiedDocViewerServices } from '../types';
const index = 'test-index';
const mockSearchResult = new Subject();
const services = {
setUnifiedDocViewerServices({
data: {
search: {
search: jest.fn(() => {
@ -35,7 +35,7 @@ const services = {
}
},
},
};
} as unknown as UnifiedDocViewerServices);
describe('Test of <Doc /> helper / hook', () => {
test('buildSearchBody given useNewFieldsApi is false', () => {
@ -237,9 +237,6 @@ describe('Test of <Doc /> helper / hook', () => {
const hook = renderHook((p: EsDocSearchProps) => useEsDocSearch(p), {
initialProps: props,
wrapper: ({ children }) => (
<KibanaContextProvider services={services}>{children}</KibanaContextProvider>
),
});
expect(hook.result.current.slice(0, 2)).toEqual([ElasticRequestState.Loading, null]);
@ -261,9 +258,6 @@ describe('Test of <Doc /> helper / hook', () => {
const hook = renderHook((p: EsDocSearchProps) => useEsDocSearch(p), {
initialProps: props,
wrapper: ({ children }) => (
<KibanaContextProvider services={services}>{children}</KibanaContextProvider>
),
});
await act(async () => {
@ -315,9 +309,6 @@ describe('Test of <Doc /> helper / hook', () => {
const hook = renderHook((p: EsDocSearchProps) => useEsDocSearch(p), {
initialProps: props,
wrapper: ({ children }) => (
<KibanaContextProvider services={services}>{children}</KibanaContextProvider>
),
});
expect(hook.result.current.slice(0, 2)).toEqual([

View file

@ -14,7 +14,7 @@ import { reportPerformanceMetricEvent } from '@kbn/ebt-tools';
import type { DataTableRecord } from '@kbn/discover-utils/types';
import { SEARCH_FIELDS_FROM_SOURCE, buildDataTableRecord } from '@kbn/discover-utils';
import { ElasticRequestState } from '@kbn/unified-doc-viewer';
import { useUnifiedDocViewerServices } from './use_doc_viewer_services';
import { getUnifiedDocViewerServices } from '../plugin';
type RequestBody = Pick<estypes.SearchRequest, 'body'>;
@ -53,7 +53,7 @@ export function useEsDocSearch({
}: EsDocSearchProps): [ElasticRequestState, DataTableRecord | null, () => void] {
const [status, setStatus] = useState(ElasticRequestState.Loading);
const [hit, setHit] = useState<DataTableRecord | null>(null);
const { data, uiSettings, analytics } = useUnifiedDocViewerServices();
const { data, uiSettings, analytics } = getUnifiedDocViewerServices();
const useNewFieldsApi = useMemo(() => !uiSettings.get(SEARCH_FIELDS_FROM_SOURCE), [uiSettings]);
const requestData = useCallback(async () => {

View file

@ -34,6 +34,6 @@ export const UnifiedDocViewer = withSuspense<DocViewRenderProps>(
</EuiDelayRender>
);
export { useEsDocSearch, useUnifiedDocViewerServices } from './hooks';
export { useEsDocSearch } from './hooks';
export const plugin = () => new UnifiedDocViewerPublicPlugin();

View file

@ -16,7 +16,7 @@ import { createGetterSetter, Storage } from '@kbn/kibana-utils-plugin/public';
import { DataPublicPluginStart } from '@kbn/data-plugin/public';
import { FieldFormatsStart } from '@kbn/field-formats-plugin/public';
import { CoreStart } from '@kbn/core/public';
import { type UnifiedDocViewerServices, useUnifiedDocViewerServices } from './hooks';
import type { UnifiedDocViewerServices } from './types';
export const [getUnifiedDocViewerServices, setUnifiedDocViewerServices] =
createGetterSetter<UnifiedDocViewerServices>('UnifiedDocViewerServices');
@ -50,8 +50,7 @@ export class UnifiedDocViewerPublicPlugin
}),
order: 10,
component: (props) => {
// eslint-disable-next-line react-hooks/rules-of-hooks
const { uiSettings } = useUnifiedDocViewerServices();
const { uiSettings } = getUnifiedDocViewerServices();
const DocView = uiSettings.get(DOC_TABLE_LEGACY) ? DocViewerLegacyTable : DocViewerTable;
return (

View file

@ -7,5 +7,21 @@
*/
export type { JsonCodeEditorProps } from './components';
export type { EsDocSearchProps, UnifiedDocViewerServices } from './hooks';
export type { EsDocSearchProps } from './hooks';
export type { UnifiedDocViewerSetup, UnifiedDocViewerStart } from './plugin';
import type { AnalyticsServiceStart } from '@kbn/core-analytics-browser';
import type { DataPublicPluginStart } from '@kbn/data-plugin/public';
import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public';
import type { Storage } from '@kbn/kibana-utils-plugin/public';
import type { IUiSettingsClient } from '@kbn/core-ui-settings-browser';
import type { UnifiedDocViewerStart } from './plugin';
export interface UnifiedDocViewerServices {
analytics: AnalyticsServiceStart;
data: DataPublicPluginStart;
fieldFormats: FieldFormatsStart;
storage: Storage;
uiSettings: IUiSettingsClient;
unifiedDocViewer: UnifiedDocViewerStart;
}

View file

@ -6,13 +6,9 @@
*/
import { EuiButtonIcon, EuiFlyout, EuiFlyoutBody, EuiFlyoutHeader, EuiTitle } from '@elastic/eui';
import { UnifiedDocViewer, useEsDocSearch } from '@kbn/unified-doc-viewer-plugin/public';
import React, { useState, MouseEvent } from 'react';
import { useUnifiedDocViewerServices } from '@kbn/unified-doc-viewer-plugin/public';
import { buildDataTableRecord } from '@kbn/discover-utils';
import { UnifiedDocViewer } from '@kbn/unified-doc-viewer-plugin/public';
import { i18n } from '@kbn/i18n';
import { useFetcher } from '@kbn/observability-shared-plugin/public';
import { DataTableRecord } from '@kbn/discover-utils/src/types';
import { useDateFormat } from '../../../../../hooks/use_date_format';
import { LoadingState } from '../../monitors_page/overview/overview/monitor_detail_flyout';
import { useSyntheticsDataView } from '../../../contexts/synthetics_data_view_context';
@ -20,35 +16,12 @@ import { SYNTHETICS_INDEX_PATTERN } from '../../../../../../common/constants';
import { Ping } from '../../../../../../common/runtime_types';
export const ViewDocument = ({ ping }: { ping: Ping }) => {
const { data } = useUnifiedDocViewerServices();
const [isFlyoutVisible, setIsFlyoutVisible] = useState<boolean>(false);
const dataView = useSyntheticsDataView();
const formatter = useDateFormat();
const { data: hit } = useFetcher<Promise<DataTableRecord | undefined>>(async () => {
if (!dataView?.id || !isFlyoutVisible) return;
const response = await data.search
.search({
params: {
index: SYNTHETICS_INDEX_PATTERN,
body: {
query: {
ids: {
values: [ping.docId],
},
},
fields: ['*'],
_source: false,
},
},
})
.toPromise();
const docs = response?.rawResponse?.hits?.hits ?? [];
if (docs.length > 0) {
return buildDataTableRecord(docs[0], dataView);
}
}, [data, dataView, ping.docId, isFlyoutVisible]);
const [, hit] = useEsDocSearch({ id: ping.docId, index: SYNTHETICS_INDEX_PATTERN, dataView });
return (
<>

View file

@ -78,7 +78,6 @@
"@kbn/shared-ux-page-kibana-template",
"@kbn/observability-ai-assistant-plugin",
"@kbn/unified-doc-viewer-plugin",
"@kbn/discover-utils",
"@kbn/shared-ux-link-redirect-app"
],
"exclude": [