-
-
- );
-}
diff --git a/src/plugins/discover/public/application/main/components/field_stats_table/index.ts b/src/plugins/discover/public/application/main/components/field_stats_table/index.ts
index 39f3dd81e74e6..b418366481fa0 100644
--- a/src/plugins/discover/public/application/main/components/field_stats_table/index.ts
+++ b/src/plugins/discover/public/application/main/components/field_stats_table/index.ts
@@ -7,4 +7,3 @@
*/
export { FieldStatisticsTable } from './field_stats_table';
-export { FieldStatsTableSavedSearchEmbeddable } from './field_stats_table_saved_search_embeddable';
diff --git a/src/plugins/discover/public/application/main/components/layout/discover_documents.test.tsx b/src/plugins/discover/public/application/main/components/layout/discover_documents.test.tsx
index 45c064d06c51f..5f9d2d41f862d 100644
--- a/src/plugins/discover/public/application/main/components/layout/discover_documents.test.tsx
+++ b/src/plugins/discover/public/application/main/components/layout/discover_documents.test.tsx
@@ -19,15 +19,11 @@ import { FetchStatus } from '../../../types';
import { DiscoverDocuments } from './discover_documents';
import { indexPatternMock } from '../../../../__mocks__/index_pattern';
import { ElasticSearchHit } from 'src/plugins/discover/public/types';
-
-jest.mock('../../../../kibana_services', () => ({
- ...jest.requireActual('../../../../kibana_services'),
- getServices: () => jest.requireActual('../../../../__mocks__/services').discoverServiceMock,
-}));
+import { KibanaContextProvider } from '../../../../../../kibana_react/public';
setHeaderActionMenuMounter(jest.fn());
-function getProps(fetchStatus: FetchStatus, hits: ElasticSearchHit[]) {
+function mountComponent(fetchStatus: FetchStatus, hits: ElasticSearchHit[]) {
const services = discoverServiceMock;
services.data.query.timefilter.timefilter.getTime = () => {
return { from: '2020-05-14T11:05:13.590', to: '2020-05-14T11:20:13.590' };
@@ -38,40 +34,41 @@ function getProps(fetchStatus: FetchStatus, hits: ElasticSearchHit[]) {
result: hits,
}) as DataDocuments$;
- return {
+ const props = {
expandedDoc: undefined,
indexPattern: indexPatternMock,
onAddFilter: jest.fn(),
savedSearch: savedSearchMock,
documents$,
searchSource: documents$,
- services,
setExpandedDoc: jest.fn(),
state: { columns: [] },
stateContainer: {} as GetStateReturn,
navigateTo: jest.fn(),
};
+
+ return mountWithIntl(
+
+
+
+ );
}
describe('Discover documents layout', () => {
test('render loading when loading and no documents', () => {
- const component = mountWithIntl(
);
+ const component = mountComponent(FetchStatus.LOADING, []);
expect(component.find('.dscDocuments__loading').exists()).toBeTruthy();
expect(component.find('.dscTable').exists()).toBeFalsy();
});
test('render complete when loading but documents were already fetched', () => {
- const component = mountWithIntl(
-
- );
+ const component = mountComponent(FetchStatus.LOADING, esHits as ElasticSearchHit[]);
expect(component.find('.dscDocuments__loading').exists()).toBeFalsy();
expect(component.find('.dscTable').exists()).toBeTruthy();
});
test('render complete', () => {
- const component = mountWithIntl(
-
- );
+ const component = mountComponent(FetchStatus.COMPLETE, esHits as ElasticSearchHit[]);
expect(component.find('.dscDocuments__loading').exists()).toBeFalsy();
expect(component.find('.dscTable').exists()).toBeTruthy();
});
diff --git a/src/plugins/discover/public/application/main/components/layout/discover_documents.tsx b/src/plugins/discover/public/application/main/components/layout/discover_documents.tsx
index d2b767ce5bcd8..c955157a9f703 100644
--- a/src/plugins/discover/public/application/main/components/layout/discover_documents.tsx
+++ b/src/plugins/discover/public/application/main/components/layout/discover_documents.tsx
@@ -14,6 +14,7 @@ import {
EuiScreenReaderOnly,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
+import { useDiscoverServices } from '../../../../utils/use_discover_services';
import { DocViewFilterFn } from '../../../../services/doc_views/doc_views_types';
import { DiscoverGrid } from '../../../../components/discover_grid/discover_grid';
import { FetchStatus } from '../../../types';
@@ -27,7 +28,6 @@ import { useColumns } from '../../../../utils/use_data_grid_columns';
import { DataView } from '../../../../../../data/common';
import { SavedSearch } from '../../../../services/saved_searches';
import { DataDocumentsMsg, DataDocuments$ } from '../../utils/use_saved_search';
-import { DiscoverServices } from '../../../../build_services';
import { AppState, GetStateReturn } from '../../services/discover_state';
import { useDataState } from '../../utils/use_data_state';
import { DocTableInfinite } from '../../../../components/doc_table/doc_table_infinite';
@@ -43,7 +43,6 @@ function DiscoverDocumentsComponent({
indexPattern,
onAddFilter,
savedSearch,
- services,
setExpandedDoc,
state,
stateContainer,
@@ -54,12 +53,11 @@ function DiscoverDocumentsComponent({
navigateTo: (url: string) => void;
onAddFilter: DocViewFilterFn;
savedSearch: SavedSearch;
- services: DiscoverServices;
setExpandedDoc: (doc?: ElasticSearchHit) => void;
state: AppState;
stateContainer: GetStateReturn;
}) {
- const { capabilities, indexPatterns, uiSettings } = services;
+ const { capabilities, indexPatterns, uiSettings } = useDiscoverServices();
const useNewFieldsApi = useMemo(() => !uiSettings.get(SEARCH_FIELDS_FROM_SOURCE), [uiSettings]);
const isLegacy = useMemo(() => uiSettings.get(DOC_TABLE_LEGACY), [uiSettings]);
@@ -160,7 +158,6 @@ function DiscoverDocumentsComponent({
searchTitle={savedSearch.title}
setExpandedDoc={setExpandedDoc}
showTimeCol={showTimeCol}
- services={services}
settings={state.grid}
onAddColumn={onAddColumn}
onFilter={onAddFilter as DocViewFilterFn}
diff --git a/src/plugins/discover/public/application/main/components/layout/discover_layout.test.tsx b/src/plugins/discover/public/application/main/components/layout/discover_layout.test.tsx
index c8cfd3603c9f0..b258987e3ea30 100644
--- a/src/plugins/discover/public/application/main/components/layout/discover_layout.test.tsx
+++ b/src/plugins/discover/public/application/main/components/layout/discover_layout.test.tsx
@@ -32,23 +32,13 @@ import { RequestAdapter } from '../../../../../../inspector';
import { Chart } from '../chart/point_series';
import { DiscoverSidebar } from '../sidebar/discover_sidebar';
import { ElasticSearchHit } from '../../../../types';
-
-jest.mock('../../../../kibana_services', () => ({
- ...jest.requireActual('../../../../kibana_services'),
- getServices: () => ({
- fieldFormats: {
- getDefaultInstance: jest.fn(() => ({ convert: (value: unknown) => value })),
- getFormatterForField: jest.fn(() => ({ convert: (value: unknown) => value })),
- },
- uiSettings: {
- get: jest.fn((key: string) => key === 'discover:maxDocFieldsDisplayed' && 50),
- },
- }),
-}));
+import { KibanaContextProvider } from '../../../../../../kibana_react/public';
+import { FieldFormatsStart } from '../../../../../../field_formats/public';
+import { IUiSettingsClient } from 'kibana/public';
setHeaderActionMenuMounter(jest.fn());
-function getProps(indexPattern: DataView, wasSidebarClosed?: boolean): DiscoverLayoutProps {
+function mountComponent(indexPattern: DataView, prevSidebarClosed?: boolean) {
const searchSourceMock = createSearchSourceMock({});
const services = discoverServiceMock;
services.data.query.timefilter.timefilter.getAbsoluteTime = () => {
@@ -56,9 +46,17 @@ function getProps(indexPattern: DataView, wasSidebarClosed?: boolean): DiscoverL
};
services.storage.get = (key: string) => {
if (key === SIDEBAR_CLOSED_KEY) {
- return wasSidebarClosed;
+ return prevSidebarClosed;
}
};
+ services.fieldFormats = {
+ getDefaultInstance: jest.fn(() => ({ convert: (value: unknown) => value })),
+ getFormatterForField: jest.fn(() => ({ convert: (value: unknown) => value })),
+ } as unknown as FieldFormatsStart;
+ services.uiSettings = {
+ ...services.uiSettings,
+ get: jest.fn((key: string) => key === 'discover:maxDocFieldsDisplayed' && 50),
+ } as unknown as IUiSettingsClient;
const indexPatternList = [indexPattern].map((ip) => {
return { ...ip, ...{ attributes: { title: ip.title } } };
@@ -135,7 +133,7 @@ function getProps(indexPattern: DataView, wasSidebarClosed?: boolean): DiscoverL
charts$,
};
- return {
+ const props = {
indexPattern,
indexPatternList,
inspectorAdapters: { requests: new RequestAdapter() },
@@ -147,45 +145,42 @@ function getProps(indexPattern: DataView, wasSidebarClosed?: boolean): DiscoverL
savedSearchData$,
savedSearchRefetch$: new Subject(),
searchSource: searchSourceMock,
- services,
state: { columns: [] },
stateContainer: {} as GetStateReturn,
setExpandedDoc: jest.fn(),
};
+
+ return mountWithIntl(
+
+
+
+ );
}
describe('Discover component', () => {
test('selected index pattern without time field displays no chart toggle', () => {
- const component = mountWithIntl(
);
+ const component = mountComponent(indexPatternMock);
expect(component.find('[data-test-subj="discoverChartOptionsToggle"]').exists()).toBeFalsy();
});
test('selected index pattern with time field displays chart toggle', () => {
- const component = mountWithIntl(
-
- );
+ const component = mountComponent(indexPatternWithTimefieldMock);
expect(component.find('[data-test-subj="discoverChartOptionsToggle"]').exists()).toBeTruthy();
});
describe('sidebar', () => {
test('should be opened if discover:sidebarClosed was not set', () => {
- const component = mountWithIntl(
-
- );
+ const component = mountComponent(indexPatternWithTimefieldMock, undefined);
expect(component.find(DiscoverSidebar).length).toBe(1);
});
test('should be opened if discover:sidebarClosed is false', () => {
- const component = mountWithIntl(
-
- );
+ const component = mountComponent(indexPatternWithTimefieldMock, false);
expect(component.find(DiscoverSidebar).length).toBe(1);
});
test('should be closed if discover:sidebarClosed is true', () => {
- const component = mountWithIntl(
-
- );
+ const component = mountComponent(indexPatternWithTimefieldMock, true);
expect(component.find(DiscoverSidebar).length).toBe(0);
});
});
diff --git a/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx b/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx
index e98605326cc32..5601596a4d73b 100644
--- a/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx
+++ b/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx
@@ -21,6 +21,7 @@ import {
import { i18n } from '@kbn/i18n';
import { METRIC_TYPE } from '@kbn/analytics';
import classNames from 'classnames';
+import { useDiscoverServices } from '../../../../utils/use_discover_services';
import { DiscoverNoResults } from '../no_results';
import { LoadingSpinner } from '../loading_spinner/loading_spinner';
import { esFilters } from '../../../../../../data/public';
@@ -73,7 +74,6 @@ export function DiscoverLayout({
savedSearchData$,
savedSearch,
searchSource,
- services,
state,
stateContainer,
}: DiscoverLayoutProps) {
@@ -87,7 +87,8 @@ export function DiscoverLayout({
storage,
history,
spaces,
- } = services;
+ inspector,
+ } = useDiscoverServices();
const { main$, charts$, totalHits$ } = savedSearchData$;
const [inspectorSession, setInspectorSession] = useState
(undefined);
@@ -142,11 +143,11 @@ export function DiscoverLayout({
const onOpenInspector = useCallback(() => {
// prevent overlapping
setExpandedDoc(undefined);
- const session = services.inspector.open(inspectorAdapters, {
+ const session = inspector.open(inspectorAdapters, {
title: savedSearch.title,
});
setInspectorSession(session);
- }, [setExpandedDoc, inspectorAdapters, savedSearch, services.inspector]);
+ }, [setExpandedDoc, inspectorAdapters, savedSearch, inspector]);
useEffect(() => {
return () => {
@@ -214,7 +215,6 @@ export function DiscoverLayout({
savedQuery={state.savedQuery}
savedSearch={savedSearch}
searchSource={searchSource}
- services={services}
stateContainer={stateContainer}
updateQuery={onUpdateQuery}
resetSavedSearch={resetSavedSearch}
@@ -239,7 +239,6 @@ export function DiscoverLayout({
onRemoveField={onRemoveColumn}
onChangeIndexPattern={onChangeIndexPattern}
selectedIndexPattern={indexPattern}
- services={services}
state={state}
isClosed={isSidebarClosed}
trackUiMetric={trackUiMetric}
@@ -308,7 +307,6 @@ export function DiscoverLayout({
savedSearch={savedSearch}
savedSearchDataChart$={charts$}
savedSearchDataTotalHits$={totalHits$}
- services={services}
stateContainer={stateContainer}
isTimeBased={isTimeBased}
viewMode={viewMode}
@@ -326,7 +324,6 @@ export function DiscoverLayout({
navigateTo={navigateTo}
onAddFilter={onAddFilter as DocViewFilterFn}
savedSearch={savedSearch}
- services={services}
setExpandedDoc={setExpandedDoc}
state={state}
stateContainer={stateContainer}
@@ -334,7 +331,6 @@ export function DiscoverLayout({
) : (
{
- return {
- getServices: () => ({
- docLinks: {
- links: {
- query: {
- luceneQuerySyntax: 'documentation-link',
- },
- },
- },
- }),
- };
-});
+import { KibanaContextProvider } from '../../../../../../kibana_react/public';
beforeEach(() => {
jest.clearAllMocks();
});
function mountAndFindSubjects(props: Omit) {
- const component = mountWithIntl( {}} {...props} />);
+ const services = {
+ docLinks: {
+ links: {
+ query: {
+ luceneQuerySyntax: 'documentation-link',
+ },
+ },
+ },
+ };
+ const component = mountWithIntl(
+
+ {}} {...props} />
+
+ );
return {
mainMsg: findTestSubject(component, 'discoverNoResults').exists(),
timeFieldMsg: findTestSubject(component, 'discoverNoResultsTimefilter').exists(),
diff --git a/src/plugins/discover/public/application/main/components/sidebar/__snapshots__/discover_index_pattern_management.test.tsx.snap b/src/plugins/discover/public/application/main/components/sidebar/__snapshots__/discover_index_pattern_management.test.tsx.snap
index afadc293f6420..94aa55ff23853 100644
--- a/src/plugins/discover/public/application/main/components/sidebar/__snapshots__/discover_index_pattern_management.test.tsx.snap
+++ b/src/plugins/discover/public/application/main/components/sidebar/__snapshots__/discover_index_pattern_management.test.tsx.snap
@@ -1,8 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Discover DataView Management renders correctly 1`] = `
-
-
+
-
-
+
+ }
+ closePopover={[Function]}
+ data-test-subj="discover-addRuntimeField-popover"
+ display="inlineBlock"
+ hasArrow={true}
+ isOpen={false}
+ ownFocus={true}
+ panelPaddingSize="s"
+ >
+
+
-
-
+ type="boxesHorizontal"
+ >
+
+
+
+
+
-
-
-
+
+
+
`;
diff --git a/src/plugins/discover/public/application/main/components/sidebar/discover_field.test.tsx b/src/plugins/discover/public/application/main/components/sidebar/discover_field.test.tsx
index c68339575023a..758738a6cbc56 100644
--- a/src/plugins/discover/public/application/main/components/sidebar/discover_field.test.tsx
+++ b/src/plugins/discover/public/application/main/components/sidebar/discover_field.test.tsx
@@ -13,6 +13,7 @@ import { mountWithIntl } from '@kbn/test/jest';
import { DiscoverField } from './discover_field';
import { DataViewField } from '../../../../../../data/common';
import { stubIndexPattern } from '../../../../../../data/common/stubs';
+import { KibanaContextProvider } from '../../../../../../kibana_react/public';
jest.mock('../../../../kibana_services', () => ({
getUiActions: jest.fn(() => {
@@ -20,25 +21,6 @@ jest.mock('../../../../kibana_services', () => ({
getTriggerCompatibleActions: jest.fn(() => []),
};
}),
- getServices: () => ({
- history: () => ({
- location: {
- search: '',
- },
- }),
- capabilities: {
- visualize: {
- show: true,
- },
- },
- uiSettings: {
- get: (key: string) => {
- if (key === 'fields:popularLimit') {
- return 5;
- }
- },
- },
- }),
}));
function getComponent({
@@ -73,7 +55,30 @@ function getComponent({
showDetails,
selected,
};
- const comp = mountWithIntl(
);
+ const services = {
+ history: () => ({
+ location: {
+ search: '',
+ },
+ }),
+ capabilities: {
+ visualize: {
+ show: true,
+ },
+ },
+ uiSettings: {
+ get: (key: string) => {
+ if (key === 'fields:popularLimit') {
+ return 5;
+ }
+ },
+ },
+ };
+ const comp = mountWithIntl(
+
+
+
+ );
return { comp, props };
}
diff --git a/src/plugins/discover/public/application/main/components/sidebar/discover_index_pattern_management.test.tsx b/src/plugins/discover/public/application/main/components/sidebar/discover_index_pattern_management.test.tsx
index d44091c27d297..8ab82924a6c23 100644
--- a/src/plugins/discover/public/application/main/components/sidebar/discover_index_pattern_management.test.tsx
+++ b/src/plugins/discover/public/application/main/components/sidebar/discover_index_pattern_management.test.tsx
@@ -12,6 +12,7 @@ import { EuiContextMenuPanel, EuiPopover, EuiContextMenuItem } from '@elastic/eu
import { DiscoverServices } from '../../../../build_services';
import { DiscoverIndexPatternManagement } from './discover_index_pattern_management';
import { stubLogstashIndexPattern } from '../../../../../../data/common/stubs';
+import { KibanaContextProvider } from '../../../../../../kibana_react/public';
const mockServices = {
history: () => ({
@@ -56,12 +57,13 @@ describe('Discover DataView Management', () => {
const mountComponent = () => {
return mountWithIntl(
-
+
+
+
);
};
diff --git a/src/plugins/discover/public/application/main/components/sidebar/discover_index_pattern_management.tsx b/src/plugins/discover/public/application/main/components/sidebar/discover_index_pattern_management.tsx
index ce201f6ed3ae5..0655357d55983 100644
--- a/src/plugins/discover/public/application/main/components/sidebar/discover_index_pattern_management.tsx
+++ b/src/plugins/discover/public/application/main/components/sidebar/discover_index_pattern_management.tsx
@@ -9,7 +9,7 @@
import React, { useState } from 'react';
import { EuiButtonIcon, EuiContextMenuItem, EuiContextMenuPanel, EuiPopover } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
-import { DiscoverServices } from '../../../../build_services';
+import { useDiscoverServices } from '../../../../utils/use_discover_services';
import { DataView } from '../../../../../../data/common';
export interface DiscoverIndexPatternManagementProps {
@@ -17,10 +17,6 @@ export interface DiscoverIndexPatternManagementProps {
* Currently selected index pattern
*/
selectedIndexPattern?: DataView;
- /**
- * Discover plugin services;
- */
- services: DiscoverServices;
/**
* Read from the Fields API
*/
@@ -33,7 +29,7 @@ export interface DiscoverIndexPatternManagementProps {
}
export function DiscoverIndexPatternManagement(props: DiscoverIndexPatternManagementProps) {
- const { dataViewFieldEditor, core } = props.services;
+ const { dataViewFieldEditor, core } = useDiscoverServices();
const { useNewFieldsApi, selectedIndexPattern, editField } = props;
const dataViewEditPermission = dataViewFieldEditor?.userPermissions.editIndexPattern();
const canEditDataViewField = !!dataViewEditPermission && useNewFieldsApi;
diff --git a/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar.test.tsx b/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar.test.tsx
index 95c167524af48..e236d7e8a1b89 100644
--- a/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar.test.tsx
+++ b/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar.test.tsx
@@ -23,10 +23,7 @@ import { discoverServiceMock as mockDiscoverServices } from '../../../../__mocks
import { stubLogstashIndexPattern } from '../../../../../../data/common/stubs';
import { VIEW_MODE } from '../../../../components/view_mode_toggle';
import { ElasticSearchHit } from '../../../../types';
-
-jest.mock('../../../../kibana_services', () => ({
- getServices: () => mockDiscoverServices,
-}));
+import { KibanaContextProvider } from '../../../../../../kibana_react/public';
function getCompProps(): DiscoverSidebarProps {
const indexPattern = stubLogstashIndexPattern;
@@ -59,7 +56,6 @@ function getCompProps(): DiscoverSidebarProps {
onAddField: jest.fn(),
onRemoveField: jest.fn(),
selectedIndexPattern: indexPattern,
- services: mockDiscoverServices,
state: {},
trackUiMetric: jest.fn(),
fieldFilter: getDefaultFieldFilter(),
@@ -76,7 +72,11 @@ describe('discover sidebar', function () {
beforeAll(() => {
props = getCompProps();
- comp = mountWithIntl(
);
+ comp = mountWithIntl(
+
+
+
+ );
});
it('should have Selected Fields and Available Fields with Popular Fields sections', function () {
diff --git a/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar.tsx b/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar.tsx
index fd5c838c42f91..087a5a6ae312b 100644
--- a/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar.tsx
+++ b/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar.tsx
@@ -25,6 +25,7 @@ import useShallowCompareEffect from 'react-use/lib/useShallowCompareEffect';
import { isEqual, sortBy } from 'lodash';
import { FormattedMessage } from '@kbn/i18n-react';
+import { useDiscoverServices } from '../../../../utils/use_discover_services';
import { DiscoverField } from './discover_field';
import { DiscoverIndexPattern } from './discover_index_pattern';
import { DiscoverFieldSearch } from './discover_field_search';
@@ -93,7 +94,6 @@ export function DiscoverSidebarComponent({
onAddFilter,
onRemoveField,
selectedIndexPattern,
- services,
setFieldFilter,
trackUiMetric,
useNewFieldsApi = false,
@@ -105,9 +105,9 @@ export function DiscoverSidebarComponent({
editField,
viewMode,
}: DiscoverSidebarProps) {
+ const { uiSettings, dataViewFieldEditor } = useDiscoverServices();
const [fields, setFields] = useState
(null);
- const { dataViewFieldEditor } = services;
const dataViewFieldEditPermission = dataViewFieldEditor?.userPermissions.editIndexPattern();
const canEditDataViewField = !!dataViewFieldEditPermission && useNewFieldsApi;
const [scrollContainer, setScrollContainer] = useState(null);
@@ -138,10 +138,7 @@ export function DiscoverSidebarComponent({
[documents, columns, selectedIndexPattern]
);
- const popularLimit = useMemo(
- () => services.uiSettings.get(FIELDS_LIMIT_SETTING),
- [services.uiSettings]
- );
+ const popularLimit = useMemo(() => uiSettings.get(FIELDS_LIMIT_SETTING), [uiSettings]);
const {
selected: selectedFields,
@@ -299,7 +296,6 @@ export function DiscoverSidebarComponent({
({
@@ -62,7 +63,6 @@ jest.mock('../../../../kibana_services', () => ({
getTriggerCompatibleActions: jest.fn(() => []),
};
}),
- getServices: () => mockServices,
}));
jest.mock('../../utils/calc_field_counts', () => ({
@@ -100,7 +100,6 @@ function getCompProps(): DiscoverSidebarResponsiveProps {
onAddField: jest.fn(),
onRemoveField: jest.fn(),
selectedIndexPattern: indexPattern,
- services: mockServices,
state: {},
trackUiMetric: jest.fn(),
onEditRuntimeField: jest.fn(),
@@ -114,7 +113,11 @@ describe('discover responsive sidebar', function () {
beforeAll(() => {
props = getCompProps();
- comp = mountWithIntl();
+ comp = mountWithIntl(
+
+
+
+ );
});
it('should have Selected Fields and Available Fields with Popular Fields sections', function () {
diff --git a/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar_responsive.tsx b/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar_responsive.tsx
index df79b4a03578e..abc59ff282863 100644
--- a/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar_responsive.tsx
+++ b/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar_responsive.tsx
@@ -26,12 +26,12 @@ import {
EuiFlexGroup,
EuiFlexItem,
} from '@elastic/eui';
+import { useDiscoverServices } from '../../../../utils/use_discover_services';
import { DiscoverIndexPattern } from './discover_index_pattern';
import { DataViewField, DataView, DataViewAttributes } from '../../../../../../data/common';
import { SavedObject } from '../../../../../../../core/types';
import { getDefaultFieldFilter } from './lib/field_filter';
import { DiscoverSidebar } from './discover_sidebar';
-import { DiscoverServices } from '../../../../build_services';
import { AppState } from '../../services/discover_state';
import { DiscoverIndexPatternManagement } from './discover_index_pattern_management';
import { DataDocuments$ } from '../../utils/use_saved_search';
@@ -80,10 +80,6 @@ export interface DiscoverSidebarResponsiveProps {
* Currently selected index pattern
*/
selectedIndexPattern?: DataView;
- /**
- * Discover plugin services;
- */
- services: DiscoverServices;
/**
* Discover App state
*/
@@ -118,6 +114,7 @@ export interface DiscoverSidebarResponsiveProps {
* Mobile: Index pattern selector is visible and a button to trigger a flyout with all elements
*/
export function DiscoverSidebarResponsive(props: DiscoverSidebarResponsiveProps) {
+ const services = useDiscoverServices();
const { selectedIndexPattern, onEditRuntimeField, useNewFieldsApi, onChangeIndexPattern } = props;
const [fieldFilter, setFieldFilter] = useState(getDefaultFieldFilter());
const [isFlyoutVisible, setIsFlyoutVisible] = useState(false);
@@ -170,7 +167,7 @@ export function DiscoverSidebarResponsive(props: DiscoverSidebarResponsiveProps)
setIsFlyoutVisible(false);
}, []);
- const { dataViewFieldEditor } = props.services;
+ const { dataViewFieldEditor } = services;
const editField = useCallback(
(fieldName?: string) => {
@@ -244,7 +241,6 @@ export function DiscoverSidebarResponsive(props: DiscoverSidebarResponsiveProps)
({
+ ...jest.requireActual('../../../../../../kibana_react/public'),
+ useKibana: () => ({
+ services: jest.requireActual('../../../../__mocks__/services').discoverServiceMock,
+ }),
+}));
+
function getProps(savePermissions = true): DiscoverTopNavProps {
discoverServiceMock.capabilities.discover!.save = savePermissions;
@@ -27,7 +34,6 @@ function getProps(savePermissions = true): DiscoverTopNavProps {
indexPattern: indexPatternMock,
savedSearch: savedSearchMock,
navigateTo: jest.fn(),
- services: discoverServiceMock,
query: {} as Query,
savedQuery: '',
updateQuery: jest.fn(),
diff --git a/src/plugins/discover/public/application/main/components/top_nav/discover_topnav.tsx b/src/plugins/discover/public/application/main/components/top_nav/discover_topnav.tsx
index 2e8261ce165da..63e75c74af795 100644
--- a/src/plugins/discover/public/application/main/components/top_nav/discover_topnav.tsx
+++ b/src/plugins/discover/public/application/main/components/top_nav/discover_topnav.tsx
@@ -7,6 +7,7 @@
*/
import React, { useCallback, useMemo } from 'react';
import { useHistory } from 'react-router-dom';
+import { useDiscoverServices } from '../../../../utils/use_discover_services';
import { DiscoverLayoutProps } from '../layout/types';
import { getTopNavLinks } from './get_top_nav_links';
import { Query, TimeRange } from '../../../../../../data/common/query';
@@ -16,7 +17,7 @@ import { DataViewType } from '../../../../../../data_views/common';
export type DiscoverTopNavProps = Pick<
DiscoverLayoutProps,
- 'indexPattern' | 'navigateTo' | 'savedSearch' | 'services' | 'searchSource'
+ 'indexPattern' | 'navigateTo' | 'savedSearch' | 'searchSource'
> & {
onOpenInspector: () => void;
query?: Query;
@@ -36,7 +37,6 @@ export const DiscoverTopNav = ({
searchSource,
navigateTo,
savedSearch,
- services,
resetSavedSearch,
}: DiscoverTopNavProps) => {
const history = useHistory();
@@ -44,6 +44,7 @@ export const DiscoverTopNav = ({
() => indexPattern.isTimeBased() && indexPattern.type !== DataViewType.ROLLUP,
[indexPattern]
);
+ const services = useDiscoverServices();
const { TopNavMenu } = services.navigation.ui;
const onOpenSavedSearch = useCallback(
diff --git a/src/plugins/discover/public/application/main/components/top_nav/get_top_nav_links.ts b/src/plugins/discover/public/application/main/components/top_nav/get_top_nav_links.ts
index 8c7d5700b3d87..0a8bcae983d35 100644
--- a/src/plugins/discover/public/application/main/components/top_nav/get_top_nav_links.ts
+++ b/src/plugins/discover/public/application/main/components/top_nav/get_top_nav_links.ts
@@ -53,6 +53,7 @@ export const getTopNavLinks = ({
I18nContext: services.core.i18n.Context,
anchorElement,
theme$: services.core.theme.theme$,
+ services,
}),
testId: 'discoverOptionsButton',
};
@@ -97,6 +98,7 @@ export const getTopNavLinks = ({
onOpenSavedSearch,
I18nContext: services.core.i18n.Context,
theme$: services.core.theme.theme$,
+ services,
}),
};
diff --git a/src/plugins/discover/public/application/main/components/top_nav/open_options_popover.test.tsx b/src/plugins/discover/public/application/main/components/top_nav/open_options_popover.test.tsx
index 8363bfdc57616..c2059915b2af8 100644
--- a/src/plugins/discover/public/application/main/components/top_nav/open_options_popover.test.tsx
+++ b/src/plugins/discover/public/application/main/components/top_nav/open_options_popover.test.tsx
@@ -9,41 +9,30 @@
import React from 'react';
import { mountWithIntl } from '@kbn/test/jest';
import { findTestSubject } from '@elastic/eui/lib/test';
-import { getServices } from '../../../../kibana_services';
-
-jest.mock('../../../../kibana_services', () => {
- const mockUiSettings = new Map();
- return {
- getServices: () => ({
- core: {
- uiSettings: {
- get: (key: string) => {
- return mockUiSettings.get(key);
- },
- set: (key: string, value: boolean) => {
- mockUiSettings.set(key, value);
- },
- },
- },
- addBasePath: (path: string) => path,
- }),
- };
-});
import { OptionsPopover } from './open_options_popover';
+import { KibanaContextProvider } from '../../../../../../kibana_react/public';
test('should display the correct text if datagrid is selected', () => {
const element = document.createElement('div');
- const component = mountWithIntl();
+ const component = mountWithIntl(
+ '', core: { uiSettings: { get: () => false } } }}
+ >
+
+
+ );
expect(findTestSubject(component, 'docTableMode').text()).toBe('Document Explorer');
});
test('should display the correct text if legacy table is selected', () => {
- const {
- core: { uiSettings },
- } = getServices();
- uiSettings.set('doc_table:legacy', true);
const element = document.createElement('div');
- const component = mountWithIntl();
+ const component = mountWithIntl(
+ '', core: { uiSettings: { get: () => true } } }}
+ >
+
+
+ );
expect(findTestSubject(component, 'docTableMode').text()).toBe('Classic');
});
diff --git a/src/plugins/discover/public/application/main/components/top_nav/open_options_popover.tsx b/src/plugins/discover/public/application/main/components/top_nav/open_options_popover.tsx
index ea0cd804efec0..b52aa21414664 100644
--- a/src/plugins/discover/public/application/main/components/top_nav/open_options_popover.tsx
+++ b/src/plugins/discover/public/application/main/components/top_nav/open_options_popover.tsx
@@ -23,9 +23,10 @@ import {
} from '@elastic/eui';
import './open_options_popover.scss';
import { Observable } from 'rxjs';
+import { useDiscoverServices } from '../../../../utils/use_discover_services';
+import { DiscoverServices } from '../../../../build_services';
import { DOC_TABLE_LEGACY } from '../../../../../common';
-import { getServices } from '../../../../kibana_services';
-import { KibanaThemeProvider } from '../../../../../../kibana_react/public';
+import { KibanaContextProvider, KibanaThemeProvider } from '../../../../../../kibana_react/public';
const container = document.createElement('div');
let isOpen = false;
@@ -39,7 +40,7 @@ export function OptionsPopover(props: OptionsPopoverProps) {
const {
core: { uiSettings },
addBasePath,
- } = getServices();
+ } = useDiscoverServices();
const isLegacy = uiSettings.get(DOC_TABLE_LEGACY);
const mode = isLegacy
@@ -128,10 +129,12 @@ export function openOptionsPopover({
I18nContext,
anchorElement,
theme$,
+ services,
}: {
I18nContext: I18nStart['Context'];
anchorElement: HTMLElement;
theme$: Observable;
+ services: DiscoverServices;
}) {
if (isOpen) {
onClose();
@@ -143,9 +146,11 @@ export function openOptionsPopover({
const element = (
-
-
-
+
+
+
+
+
);
ReactDOM.render(element, container);
diff --git a/src/plugins/discover/public/application/main/components/top_nav/open_search_panel.test.tsx b/src/plugins/discover/public/application/main/components/top_nav/open_search_panel.test.tsx
index 80c70d9b1aff5..ad4c356ce63e0 100644
--- a/src/plugins/discover/public/application/main/components/top_nav/open_search_panel.test.tsx
+++ b/src/plugins/discover/public/application/main/components/top_nav/open_search_panel.test.tsx
@@ -9,39 +9,37 @@
import React from 'react';
import { shallow } from 'enzyme';
-const mockCapabilities = jest.fn().mockReturnValue({
- savedObjectsManagement: {
- edit: true,
- },
-});
-
-jest.mock('../../../../kibana_services', () => {
- return {
- getServices: () => ({
- core: { uiSettings: {}, savedObjects: {} },
- addBasePath: (path: string) => path,
- capabilities: mockCapabilities(),
- }),
- };
-});
+describe('OpenSearchPanel', () => {
+ beforeEach(() => {
+ jest.resetModules();
+ });
-import { OpenSearchPanel } from './open_search_panel';
+ test('render', async () => {
+ jest.doMock('../../../../utils/use_discover_services', () => ({
+ useDiscoverServices: jest.fn().mockImplementation(() => ({
+ core: { uiSettings: {}, savedObjects: {} },
+ addBasePath: (path: string) => path,
+ capabilities: { savedObjectsManagement: { edit: true } },
+ })),
+ }));
+ const { OpenSearchPanel } = await import('./open_search_panel');
-describe('OpenSearchPanel', () => {
- test('render', () => {
const component = shallow(
);
expect(component).toMatchSnapshot();
});
- test('should not render manage searches button without permissions', () => {
- mockCapabilities.mockReturnValue({
- savedObjectsManagement: {
- edit: false,
- delete: false,
- },
- });
+ test('should not render manage searches button without permissions', async () => {
+ jest.doMock('../../../../utils/use_discover_services', () => ({
+ useDiscoverServices: jest.fn().mockImplementation(() => ({
+ core: { uiSettings: {}, savedObjects: {} },
+ addBasePath: (path: string) => path,
+ capabilities: { savedObjectsManagement: { edit: false, delete: false } },
+ })),
+ }));
+ const { OpenSearchPanel } = await import('./open_search_panel');
+
const component = shallow(
);
diff --git a/src/plugins/discover/public/application/main/components/top_nav/open_search_panel.tsx b/src/plugins/discover/public/application/main/components/top_nav/open_search_panel.tsx
index ce6d151261243..3c972a3f4bb98 100644
--- a/src/plugins/discover/public/application/main/components/top_nav/open_search_panel.tsx
+++ b/src/plugins/discover/public/application/main/components/top_nav/open_search_panel.tsx
@@ -21,7 +21,7 @@ import {
EuiTitle,
} from '@elastic/eui';
import { SavedObjectFinderUi } from '../../../../../../saved_objects/public';
-import { getServices } from '../../../../kibana_services';
+import { useDiscoverServices } from '../../../../utils/use_discover_services';
const SEARCH_OBJECT_TYPE = 'search';
@@ -35,7 +35,7 @@ export function OpenSearchPanel(props: OpenSearchPanelProps) {
core: { uiSettings, savedObjects },
addBasePath,
capabilities,
- } = getServices();
+ } = useDiscoverServices();
const hasSavedObjectPermission =
capabilities.savedObjectsManagement?.edit || capabilities.savedObjectsManagement?.delete;
diff --git a/src/plugins/discover/public/application/main/components/top_nav/show_open_search_panel.tsx b/src/plugins/discover/public/application/main/components/top_nav/show_open_search_panel.tsx
index d506de357675a..6ba1ffd15130a 100644
--- a/src/plugins/discover/public/application/main/components/top_nav/show_open_search_panel.tsx
+++ b/src/plugins/discover/public/application/main/components/top_nav/show_open_search_panel.tsx
@@ -10,8 +10,9 @@ import React from 'react';
import ReactDOM from 'react-dom';
import { CoreTheme, I18nStart } from 'kibana/public';
import { Observable } from 'rxjs';
+import { DiscoverServices } from '../../../../build_services';
import { OpenSearchPanel } from './open_search_panel';
-import { KibanaThemeProvider } from '../../../../../../kibana_react/public';
+import { KibanaContextProvider, KibanaThemeProvider } from '../../../../../../kibana_react/public';
let isOpen = false;
@@ -19,10 +20,12 @@ export function showOpenSearchPanel({
I18nContext,
onOpenSavedSearch,
theme$,
+ services,
}: {
I18nContext: I18nStart['Context'];
onOpenSavedSearch: (id: string) => void;
theme$: Observable;
+ services: DiscoverServices;
}) {
if (isOpen) {
return;
@@ -39,9 +42,11 @@ export function showOpenSearchPanel({
document.body.appendChild(container);
const element = (
-
-
-
+
+
+
+
+
);
ReactDOM.render(element, container);
diff --git a/src/plugins/discover/public/application/main/discover_main_app.test.tsx b/src/plugins/discover/public/application/main/discover_main_app.test.tsx
index cb2bad306f43f..d1699900b1498 100644
--- a/src/plugins/discover/public/application/main/discover_main_app.test.tsx
+++ b/src/plugins/discover/public/application/main/discover_main_app.test.tsx
@@ -9,32 +9,38 @@ import React from 'react';
import { mountWithIntl } from '@kbn/test/jest';
import { indexPatternMock } from '../../__mocks__/index_pattern';
import { DiscoverMainApp } from './discover_main_app';
-import { discoverServiceMock } from '../../__mocks__/services';
import { savedSearchMock } from '../../__mocks__/saved_search';
-import { createSearchSessionMock } from '../../__mocks__/search_session';
import { SavedObject } from '../../../../../core/types';
import { IndexPatternAttributes } from '../../../../data/common';
import { setHeaderActionMenuMounter } from '../../kibana_services';
import { findTestSubject } from '@elastic/eui/lib/test';
+import { KibanaContextProvider } from '../../../../kibana_react/public';
+import { discoverServiceMock } from '../../__mocks__/services';
+import { Router } from 'react-router-dom';
+import { createMemoryHistory } from 'history';
setHeaderActionMenuMounter(jest.fn());
describe('DiscoverMainApp', () => {
test('renders', () => {
- const { history } = createSearchSessionMock();
const indexPatternList = [indexPatternMock].map((ip) => {
return { ...ip, ...{ attributes: { title: ip.title } } };
}) as unknown as Array>;
-
const props = {
indexPatternList,
- services: discoverServiceMock,
savedSearch: savedSearchMock,
- navigateTo: jest.fn(),
- history,
};
+ const history = createMemoryHistory({
+ initialEntries: ['/'],
+ });
- const component = mountWithIntl();
+ const component = mountWithIntl(
+
+
+
+
+
+ );
expect(findTestSubject(component, 'indexPattern-switch-link').text()).toBe(
indexPatternMock.title
diff --git a/src/plugins/discover/public/application/main/discover_main_app.tsx b/src/plugins/discover/public/application/main/discover_main_app.tsx
index 1ef6641e9bc72..846a1fe33c826 100644
--- a/src/plugins/discover/public/application/main/discover_main_app.tsx
+++ b/src/plugins/discover/public/application/main/discover_main_app.tsx
@@ -6,32 +6,24 @@
* Side Public License, v 1.
*/
import React, { useCallback, useEffect, useState } from 'react';
-import { History } from 'history';
+import { useHistory } from 'react-router-dom';
import { DiscoverLayout } from './components/layout';
import { setBreadcrumbsTitle } from '../../utils/breadcrumbs';
import { addHelpMenuToAppChrome } from '../../components/help_menu/help_menu_util';
import { useDiscoverState } from './utils/use_discover_state';
import { useUrl } from './utils/use_url';
import { IndexPatternAttributes, SavedObject } from '../../../../data/common';
-import { DiscoverServices } from '../../build_services';
import { SavedSearch } from '../../services/saved_searches';
import { ElasticSearchHit } from '../../types';
+import { useDiscoverServices } from '../../utils/use_discover_services';
const DiscoverLayoutMemoized = React.memo(DiscoverLayout);
export interface DiscoverMainProps {
- /**
- * Instance of browser history
- */
- history: History;
/**
* List of available index patterns
*/
indexPatternList: Array>;
- /**
- * Kibana core services used by discover
- */
- services: DiscoverServices;
/**
* Current instance of SavedSearch
*/
@@ -39,8 +31,10 @@ export interface DiscoverMainProps {
}
export function DiscoverMainApp(props: DiscoverMainProps) {
- const { savedSearch, services, history, indexPatternList } = props;
+ const { savedSearch, indexPatternList } = props;
+ const services = useDiscoverServices();
const { chrome, docLinks, uiSettings: config, data } = services;
+ const history = useHistory();
const [expandedDoc, setExpandedDoc] = useState(undefined);
const navigateTo = useCallback(
(path: string) => {
@@ -113,7 +107,6 @@ export function DiscoverMainApp(props: DiscoverMainProps) {
savedSearchData$={data$}
savedSearchRefetch$={refetch$}
searchSource={searchSource}
- services={services}
state={state}
stateContainer={stateContainer}
/>
diff --git a/src/plugins/discover/public/application/main/discover_main_route.tsx b/src/plugins/discover/public/application/main/discover_main_route.tsx
index f1d7cc2385cd0..d5950085b94c7 100644
--- a/src/plugins/discover/public/application/main/discover_main_route.tsx
+++ b/src/plugins/discover/public/application/main/discover_main_route.tsx
@@ -6,8 +6,7 @@
* Side Public License, v 1.
*/
import React, { useEffect, useState, memo, useCallback } from 'react';
-import { History } from 'history';
-import { useParams } from 'react-router-dom';
+import { useParams, useHistory } from 'react-router-dom';
import { IndexPatternAttributes, ISearchSource, SavedObject } from 'src/plugins/data/common';
import {
@@ -23,23 +22,18 @@ import { redirectWhenMissing } from '../../../../kibana_utils/public';
import { DataViewSavedObjectConflictError } from '../../../../data_views/common';
import { LoadingIndicator } from '../../components/common/loading_indicator';
import { DiscoverError } from '../../components/common/error_alert';
-import { DiscoverRouteProps } from '../types';
+import { useDiscoverServices } from '../../utils/use_discover_services';
import { getUrlTracker } from '../../kibana_services';
const DiscoverMainAppMemoized = memo(DiscoverMainApp);
-export interface DiscoverMainProps extends DiscoverRouteProps {
- /**
- * Instance of browser history
- */
- history: History;
-}
-
interface DiscoverLandingParams {
id: string;
}
-export function DiscoverMainRoute({ services, history }: DiscoverMainProps) {
+export function DiscoverMainRoute() {
+ const history = useHistory();
+ const services = useDiscoverServices();
const {
core,
chrome,
@@ -178,12 +172,5 @@ export function DiscoverMainRoute({ services, history }: DiscoverMainProps) {
return ;
}
- return (
-
- );
+ return ;
}
diff --git a/src/plugins/discover/public/application/not_found/not_found_route.tsx b/src/plugins/discover/public/application/not_found/not_found_route.tsx
index 7b42e85584428..28f525039dd1e 100644
--- a/src/plugins/discover/public/application/not_found/not_found_route.tsx
+++ b/src/plugins/discover/public/application/not_found/not_found_route.tsx
@@ -11,19 +11,13 @@ import { EuiCallOut } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { Redirect } from 'react-router-dom';
import { toMountPoint, wrapWithTheme } from '../../../../kibana_react/public';
-import { DiscoverServices } from '../../build_services';
import { getUrlTracker } from '../../kibana_services';
+import { useDiscoverServices } from '../../utils/use_discover_services';
-export interface NotFoundRouteProps {
- /**
- * Kibana core services used by discover
- */
- services: DiscoverServices;
-}
let bannerId: string | undefined;
-export function NotFoundRoute(props: NotFoundRouteProps) {
- const { services } = props;
+export function NotFoundRoute() {
+ const services = useDiscoverServices();
const { urlForwarding, core, history } = services;
const currentLocation = history().location.pathname;
diff --git a/src/plugins/discover/public/application/types.ts b/src/plugins/discover/public/application/types.ts
index f33b8bb22b58c..f04f3bf77c2f9 100644
--- a/src/plugins/discover/public/application/types.ts
+++ b/src/plugins/discover/public/application/types.ts
@@ -6,7 +6,6 @@
* Side Public License, v 1.
*/
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
-import { DiscoverServices } from '../build_services';
export enum FetchStatus {
UNINITIALIZED = 'uninitialized',
@@ -25,10 +24,3 @@ export type EsHitRecord = Required<
isAnchor?: boolean;
};
export type EsHitRecordList = EsHitRecord[];
-
-export interface DiscoverRouteProps {
- /**
- * Kibana core services used by discover
- */
- services: DiscoverServices;
-}
diff --git a/src/plugins/discover/public/build_services.ts b/src/plugins/discover/public/build_services.ts
index b77228e309286..393893432538b 100644
--- a/src/plugins/discover/public/build_services.ts
+++ b/src/plugins/discover/public/build_services.ts
@@ -7,6 +7,7 @@
*/
import { History } from 'history';
+import { memoize } from 'lodash';
import {
Capabilities,
@@ -72,7 +73,7 @@ export interface DiscoverServices {
spaces?: SpacesApi;
}
-export function buildServices(
+export const buildServices = memoize(function (
core: CoreStart,
plugins: DiscoverStartPlugins,
context: PluginInitializerContext
@@ -109,4 +110,4 @@ export function buildServices(
http: core.http,
spaces: plugins.spaces,
};
-}
+});
diff --git a/src/plugins/discover/public/components/discover_grid/discover_grid.test.tsx b/src/plugins/discover/public/components/discover_grid/discover_grid.test.tsx
index 11f32890f29ea..c4ef4ffef3234 100644
--- a/src/plugins/discover/public/components/discover_grid/discover_grid.test.tsx
+++ b/src/plugins/discover/public/components/discover_grid/discover_grid.test.tsx
@@ -14,20 +14,12 @@ import { esHits } from '../../__mocks__/es_hits';
import { indexPatternMock } from '../../__mocks__/index_pattern';
import { mountWithIntl } from '@kbn/test/jest';
import { DiscoverGrid, DiscoverGridProps } from './discover_grid';
-import { uiSettingsMock } from '../../__mocks__/ui_settings';
-import { DiscoverServices } from '../../build_services';
import { getDocId } from './discover_grid_document_selection';
import { ElasticSearchHit } from '../../types';
-
-jest.mock('../../kibana_services', () => ({
- ...jest.requireActual('../../kibana_services'),
- getServices: () => jest.requireActual('../../__mocks__/services').discoverServiceMock,
-}));
+import { KibanaContextProvider } from '../../../../kibana_react/public';
+import { discoverServiceMock } from '../../__mocks__/services';
function getProps() {
- const servicesMock = {
- uiSettings: uiSettingsMock,
- } as DiscoverServices;
return {
ariaLabelledBy: '',
columns: [],
@@ -44,7 +36,6 @@ function getProps() {
sampleSize: 30,
searchDescription: '',
searchTitle: '',
- services: servicesMock,
setExpandedDoc: jest.fn(),
settings: {},
showTimeCol: true,
@@ -54,7 +45,13 @@ function getProps() {
}
function getComponent() {
- return mountWithIntl();
+ const Proxy = (props: DiscoverGridProps) => (
+
+
+
+ );
+
+ return mountWithIntl();
}
function getSelectedDocNr(component: ReactWrapper) {
diff --git a/src/plugins/discover/public/components/discover_grid/discover_grid.tsx b/src/plugins/discover/public/components/discover_grid/discover_grid.tsx
index 93cbbb924f40b..4307afbeb9e38 100644
--- a/src/plugins/discover/public/components/discover_grid/discover_grid.tsx
+++ b/src/plugins/discover/public/components/discover_grid/discover_grid.tsx
@@ -39,7 +39,6 @@ import {
pageSizeArr,
toolbarVisibility as toolbarVisibilityDefaults,
} from './constants';
-import { DiscoverServices } from '../../build_services';
import { getDisplayedColumns } from '../../utils/columns';
import {
DOC_HIDE_TIME_COLUMN_SETTING,
@@ -50,6 +49,7 @@ import { DiscoverGridDocumentToolbarBtn, getDocId } from './discover_grid_docume
import { SortPairArr } from '../doc_table/lib/get_sort';
import { getFieldsToShow } from '../../utils/get_fields_to_show';
import { ElasticSearchHit } from '../../types';
+import { useDiscoverServices } from '../../utils/use_discover_services';
interface SortObj {
id: string;
@@ -130,10 +130,6 @@ export interface DiscoverGridProps {
* Saved search title
*/
searchTitle?: string;
- /**
- * Discover plugin services
- */
- services: DiscoverServices;
/**
* Determines whether the time columns should be displayed (legacy settings)
*/
@@ -182,7 +178,6 @@ export const DiscoverGrid = ({
sampleSize,
searchDescription,
searchTitle,
- services,
setExpandedDoc,
settings,
showTimeCol,
@@ -193,6 +188,7 @@ export const DiscoverGrid = ({
controlColumnIds = CONTROL_COLUMN_IDS_DEFAULT,
className,
}: DiscoverGridProps) => {
+ const services = useDiscoverServices();
const [selectedDocs, setSelectedDocs] = useState([]);
const [isFilterActive, setIsFilterActive] = useState(false);
const displayedColumns = getDisplayedColumns(columns, indexPattern);
@@ -481,7 +477,6 @@ export const DiscoverGrid = ({
onAddColumn={onAddColumn}
onClose={() => setExpandedDoc(undefined)}
setExpandedDoc={setExpandedDoc}
- services={services}
/>
)}
diff --git a/src/plugins/discover/public/components/discover_grid/discover_grid_flyout.test.tsx b/src/plugins/discover/public/components/discover_grid/discover_grid_flyout.test.tsx
index 64e97b824a2f9..a6c5ecdcdf35c 100644
--- a/src/plugins/discover/public/components/discover_grid/discover_grid_flyout.test.tsx
+++ b/src/plugins/discover/public/components/discover_grid/discover_grid_flyout.test.tsx
@@ -9,7 +9,7 @@
import React from 'react';
import { findTestSubject } from '@elastic/eui/lib/test';
import { mountWithIntl } from '@kbn/test/jest';
-import { DiscoverGridFlyout } from './discover_grid_flyout';
+import { DiscoverGridFlyout, DiscoverGridFlyoutProps } from './discover_grid_flyout';
import { esHits } from '../../__mocks__/es_hits';
import { createFilterManagerMock } from '../../../../data/public/query/filter_manager/filter_manager.mock';
import { indexPatternMock } from '../../__mocks__/index_pattern';
@@ -17,34 +17,54 @@ import { DiscoverServices } from '../../build_services';
import { DocViewsRegistry } from '../../services/doc_views/doc_views_registry';
import { setDocViewsRegistry } from '../../kibana_services';
import { indexPatternWithTimefieldMock } from '../../__mocks__/index_pattern_with_timefield';
+import { KibanaContextProvider } from '../../../../kibana_react/public';
+import { IndexPattern } from '../../../../data/common';
+import { ElasticSearchHit } from '../../types';
describe('Discover flyout', function () {
setDocViewsRegistry(new DocViewsRegistry());
- const getProps = () => {
+ const mountComponent = ({
+ indexPattern,
+ hits,
+ hitIndex,
+ }: {
+ indexPattern?: IndexPattern;
+ hits?: ElasticSearchHit[];
+ hitIndex?: number;
+ }) => {
const onClose = jest.fn();
const services = {
filterManager: createFilterManagerMock(),
addBasePath: (path: string) => `/base${path}`,
+ history: () => ({ location: {} }),
} as unknown as DiscoverServices;
- return {
+ const props = {
columns: ['date'],
- indexPattern: indexPatternMock,
- hit: esHits[0],
- hits: esHits,
+ indexPattern: indexPattern || indexPatternMock,
+ hit: hitIndex ? esHits[hitIndex] : esHits[0],
+ hits: hits || esHits,
onAddColumn: jest.fn(),
onClose,
onFilter: jest.fn(),
onRemoveColumn: jest.fn(),
- services,
setExpandedDoc: jest.fn(),
};
+
+ const Proxy = (newProps: DiscoverGridFlyoutProps) => (
+
+
+
+ );
+
+ const component = mountWithIntl();
+
+ return { component, props };
};
it('should be rendered correctly using an index pattern without timefield', async () => {
- const props = getProps();
- const component = mountWithIntl();
+ const { component, props } = mountComponent({});
const url = findTestSubject(component, 'docTableRowAction').prop('href');
expect(url).toMatchInlineSnapshot(`"/base/app/discover#/doc/the-index-pattern-id/i?id=1"`);
@@ -53,9 +73,7 @@ describe('Discover flyout', function () {
});
it('should be rendered correctly using an index pattern with timefield', async () => {
- const props = getProps();
- props.indexPattern = indexPatternWithTimefieldMock;
- const component = mountWithIntl();
+ const { component, props } = mountComponent({ indexPattern: indexPatternWithTimefieldMock });
const actions = findTestSubject(component, 'docTableRowAction');
expect(actions.length).toBe(2);
@@ -70,24 +88,20 @@ describe('Discover flyout', function () {
});
it('displays document navigation when there is more than 1 doc available', async () => {
- const props = getProps();
- const component = mountWithIntl();
+ const { component } = mountComponent({ indexPattern: indexPatternWithTimefieldMock });
const docNav = findTestSubject(component, 'dscDocNavigation');
expect(docNav.length).toBeTruthy();
});
it('displays no document navigation when there are 0 docs available', async () => {
- const props = getProps();
- props.hits = [];
- const component = mountWithIntl();
+ const { component } = mountComponent({ hits: [] });
const docNav = findTestSubject(component, 'dscDocNavigation');
expect(docNav.length).toBeFalsy();
});
it('displays no document navigation when the expanded doc is not part of the given docs', async () => {
// scenario: you've expanded a doc, and in the next request differed docs where fetched
- const props = getProps();
- props.hits = [
+ const hits = [
{
_index: 'new',
_id: '1',
@@ -103,15 +117,14 @@ describe('Discover flyout', function () {
_source: { date: '2020-20-01T12:12:12.124', name: 'test2', extension: 'jpg' },
},
];
- const component = mountWithIntl();
+ const { component } = mountComponent({ hits });
const docNav = findTestSubject(component, 'dscDocNavigation');
expect(docNav.length).toBeFalsy();
});
it('allows you to navigate to the next doc, if expanded doc is the first', async () => {
// scenario: you've expanded a doc, and in the next request different docs where fetched
- const props = getProps();
- const component = mountWithIntl();
+ const { component, props } = mountComponent({});
findTestSubject(component, 'pagination-button-next').simulate('click');
// we selected 1, so we'd expect 2
expect(props.setExpandedDoc.mock.calls[0][0]._id).toBe('2');
@@ -119,34 +132,28 @@ describe('Discover flyout', function () {
it('doesnt allow you to navigate to the previous doc, if expanded doc is the first', async () => {
// scenario: you've expanded a doc, and in the next request differed docs where fetched
- const props = getProps();
- const component = mountWithIntl();
+ const { component, props } = mountComponent({});
findTestSubject(component, 'pagination-button-previous').simulate('click');
expect(props.setExpandedDoc).toHaveBeenCalledTimes(0);
});
it('doesnt allow you to navigate to the next doc, if expanded doc is the last', async () => {
// scenario: you've expanded a doc, and in the next request differed docs where fetched
- const props = getProps();
- props.hit = props.hits[props.hits.length - 1];
- const component = mountWithIntl();
+ const { component, props } = mountComponent({ hitIndex: esHits.length - 1 });
findTestSubject(component, 'pagination-button-next').simulate('click');
expect(props.setExpandedDoc).toHaveBeenCalledTimes(0);
});
it('allows you to navigate to the previous doc, if expanded doc is the last', async () => {
// scenario: you've expanded a doc, and in the next request differed docs where fetched
- const props = getProps();
- props.hit = props.hits[props.hits.length - 1];
- const component = mountWithIntl();
+ const { component, props } = mountComponent({ hitIndex: esHits.length - 1 });
findTestSubject(component, 'pagination-button-previous').simulate('click');
expect(props.setExpandedDoc).toHaveBeenCalledTimes(1);
expect(props.setExpandedDoc.mock.calls[0][0]._id).toBe('4');
});
it('allows navigating with arrow keys through documents', () => {
- const props = getProps();
- const component = mountWithIntl();
+ const { component, props } = mountComponent({});
findTestSubject(component, 'docTableDetailsFlyout').simulate('keydown', { key: 'ArrowRight' });
expect(props.setExpandedDoc).toHaveBeenCalledWith(expect.objectContaining({ _id: '2' }));
component.setProps({ ...props, hit: props.hits[1] });
@@ -155,8 +162,7 @@ describe('Discover flyout', function () {
});
it('should not navigate with keypresses when already at the border of documents', () => {
- const props = getProps();
- const component = mountWithIntl();
+ const { component, props } = mountComponent({});
findTestSubject(component, 'docTableDetailsFlyout').simulate('keydown', { key: 'ArrowLeft' });
expect(props.setExpandedDoc).not.toHaveBeenCalled();
component.setProps({ ...props, hit: props.hits[props.hits.length - 1] });
diff --git a/src/plugins/discover/public/components/discover_grid/discover_grid_flyout.tsx b/src/plugins/discover/public/components/discover_grid/discover_grid_flyout.tsx
index 726c211fe418b..371eb014eab8f 100644
--- a/src/plugins/discover/public/components/discover_grid/discover_grid_flyout.tsx
+++ b/src/plugins/discover/public/components/discover_grid/discover_grid_flyout.tsx
@@ -26,11 +26,11 @@ import {
} from '@elastic/eui';
import { DocViewer } from '../../services/doc_views/components/doc_viewer/doc_viewer';
import { DocViewFilterFn } from '../../services/doc_views/doc_views_types';
-import { DiscoverServices } from '../../build_services';
import { useNavigationProps } from '../../utils/use_navigation_props';
import { ElasticSearchHit } from '../../types';
+import { useDiscoverServices } from '../../utils/use_discover_services';
-interface Props {
+export interface DiscoverGridFlyoutProps {
columns: string[];
hit: ElasticSearchHit;
hits?: ElasticSearchHit[];
@@ -39,7 +39,6 @@ interface Props {
onClose: () => void;
onFilter: DocViewFilterFn;
onRemoveColumn: (column: string) => void;
- services: DiscoverServices;
setExpandedDoc: (doc: ElasticSearchHit) => void;
}
@@ -67,9 +66,9 @@ export function DiscoverGridFlyout({
onClose,
onRemoveColumn,
onAddColumn,
- services,
setExpandedDoc,
-}: Props) {
+}: DiscoverGridFlyoutProps) {
+ const services = useDiscoverServices();
// Get actual hit with updated highlighted searches
const actualHit = useMemo(() => hits?.find(({ _id }) => _id === hit?._id) || hit, [hit, hits]);
const pageCount = useMemo(() => (hits ? hits.length : 0), [hits]);
diff --git a/src/plugins/discover/public/components/discover_grid/get_render_cell_value.test.tsx b/src/plugins/discover/public/components/discover_grid/get_render_cell_value.test.tsx
index 07ed170258fb1..d3af215059af0 100644
--- a/src/plugins/discover/public/components/discover_grid/get_render_cell_value.test.tsx
+++ b/src/plugins/discover/public/components/discover_grid/get_render_cell_value.test.tsx
@@ -7,29 +7,27 @@
*/
import React from 'react';
-import { ReactWrapper, shallow } from 'enzyme';
+import { shallow } from 'enzyme';
import { getRenderCellValueFn } from './get_render_cell_value';
import { indexPatternMock } from '../../__mocks__/index_pattern';
import { flattenHit } from 'src/plugins/data/common';
import { ElasticSearchHit } from '../../types';
-jest.mock('../../../../kibana_react/public', () => ({
- useUiSetting: () => true,
- withKibana: (comp: ReactWrapper) => {
- return comp;
- },
-}));
-
-jest.mock('../../kibana_services', () => ({
- getServices: () => ({
+jest.mock('../../utils/use_discover_services', () => {
+ const services = {
uiSettings: {
- get: jest.fn((key) => key === 'discover:maxDocFieldsDisplayed' && 200),
+ get: (key: string) => key === 'discover:maxDocFieldsDisplayed' && 200,
},
fieldFormats: {
getDefaultInstance: jest.fn(() => ({ convert: (value: unknown) => (value ? value : '-') })),
},
- }),
-}));
+ };
+ const originalModule = jest.requireActual('../../utils/use_discover_services');
+ return {
+ ...originalModule,
+ useDiscoverServices: () => services,
+ };
+});
const rowsSource: ElasticSearchHit[] = [
{
diff --git a/src/plugins/discover/public/components/discover_grid/get_render_cell_value.tsx b/src/plugins/discover/public/components/discover_grid/get_render_cell_value.tsx
index 5e1a1a7e39db8..fe2607415ace1 100644
--- a/src/plugins/discover/public/components/discover_grid/get_render_cell_value.tsx
+++ b/src/plugins/discover/public/components/discover_grid/get_render_cell_value.tsx
@@ -6,8 +6,9 @@
* Side Public License, v 1.
*/
-import React, { Fragment, useContext, useEffect } from 'react';
+import React, { Fragment, useContext, useEffect, useMemo } from 'react';
import { euiLightVars as themeLight, euiDarkVars as themeDark } from '@kbn/ui-theme';
+
import type { DataView, DataViewField } from 'src/plugins/data/common';
import {
EuiDataGridCellValueElementProps,
@@ -15,6 +16,7 @@ import {
EuiDescriptionListTitle,
EuiDescriptionListDescription,
} from '@elastic/eui';
+import { FieldFormatsStart } from '../../../../field_formats/public';
import { DiscoverGridContext } from './discover_grid_context';
import { JsonCodeEditor } from '../json_code_editor/json_code_editor';
import { defaultMonacoEditorWidth } from './constants';
@@ -22,10 +24,12 @@ import { EsHitRecord } from '../../application/types';
import { formatFieldValue } from '../../utils/format_value';
import { formatHit } from '../../utils/format_hit';
import { ElasticSearchHit } from '../../types';
+import { useDiscoverServices } from '../../utils/use_discover_services';
+import { MAX_DOC_FIELDS_DISPLAYED } from '../../../common';
export const getRenderCellValueFn =
(
- indexPattern: DataView,
+ dataView: DataView,
rows: ElasticSearchHit[] | undefined,
rowsFlattened: Array>,
useNewFieldsApi: boolean,
@@ -33,12 +37,16 @@ export const getRenderCellValueFn =
maxDocFieldsDisplayed: number
) =>
({ rowIndex, columnId, isDetails, setCellProps }: EuiDataGridCellValueElementProps) => {
+ const { uiSettings, fieldFormats } = useDiscoverServices();
+
+ const maxEntries = useMemo(() => uiSettings.get(MAX_DOC_FIELDS_DISPLAYED), [uiSettings]);
+
const row = rows ? rows[rowIndex] : undefined;
const rowFlattened = rowsFlattened
? (rowsFlattened[rowIndex] as Record)
: undefined;
- const field = indexPattern.fields.getByName(columnId);
+ const field = dataView.fields.getByName(columnId);
const ctx = useContext(DiscoverGridContext);
useEffect(() => {
@@ -75,23 +83,24 @@ export const getRenderCellValueFn =
);
if (isDetails) {
- return renderPopoverContent(
- row,
+ return renderPopoverContent({
+ rowRaw: row,
rowFlattened,
field,
columnId,
- indexPattern,
- useTopLevelObjectColumns
- );
+ dataView,
+ useTopLevelObjectColumns,
+ fieldFormats,
+ });
}
if (field?.type === '_source' || useTopLevelObjectColumns) {
const pairs = useTopLevelObjectColumns
- ? getTopLevelObjectPairs(row, columnId, indexPattern, fieldsToShow).slice(
+ ? getTopLevelObjectPairs(row, columnId, dataView, fieldsToShow).slice(
0,
maxDocFieldsDisplayed
)
- : formatHit(row, indexPattern, fieldsToShow);
+ : formatHit(row, dataView, fieldsToShow, maxEntries, fieldFormats);
return (
@@ -113,7 +122,7 @@ export const getRenderCellValueFn =
// formatFieldValue guarantees sanitized values
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{
- __html: formatFieldValue(rowFlattened[columnId], row, indexPattern, field),
+ __html: formatFieldValue(rowFlattened[columnId], row, fieldFormats, dataView, field),
}}
/>
);
@@ -134,14 +143,23 @@ function getInnerColumns(fields: Record, columnId: string) {
/**
* Helper function for the cell popover
*/
-function renderPopoverContent(
- rowRaw: ElasticSearchHit,
- rowFlattened: Record,
- field: DataViewField | undefined,
- columnId: string,
- dataView: DataView,
- useTopLevelObjectColumns: boolean
-) {
+function renderPopoverContent({
+ rowRaw,
+ rowFlattened,
+ field,
+ columnId,
+ dataView,
+ useTopLevelObjectColumns,
+ fieldFormats,
+}: {
+ rowRaw: ElasticSearchHit;
+ rowFlattened: Record;
+ field: DataViewField | undefined;
+ columnId: string;
+ dataView: DataView;
+ useTopLevelObjectColumns: boolean;
+ fieldFormats: FieldFormatsStart;
+}) {
if (useTopLevelObjectColumns || field?.type === '_source') {
const json = useTopLevelObjectColumns
? getInnerColumns(rowRaw.fields as Record, columnId)
@@ -156,7 +174,7 @@ function renderPopoverContent(
// formatFieldValue guarantees sanitized values
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{
- __html: formatFieldValue(rowFlattened[columnId], rowRaw, dataView, field),
+ __html: formatFieldValue(rowFlattened[columnId], rowRaw, fieldFormats, dataView, field),
}}
/>
);
diff --git a/src/plugins/discover/public/components/doc_table/components/table_header/table_header.test.tsx b/src/plugins/discover/public/components/doc_table/components/table_header/table_header.test.tsx
index bdb57e3f1b586..60e9c25cb4532 100644
--- a/src/plugins/discover/public/components/doc_table/components/table_header/table_header.test.tsx
+++ b/src/plugins/discover/public/components/doc_table/components/table_header/table_header.test.tsx
@@ -12,6 +12,19 @@ import type { DataView, DataViewField } from 'src/plugins/data/common';
import { TableHeader } from './table_header';
import { findTestSubject } from '@elastic/eui/lib/test';
import { SortOrder } from './helpers';
+import { KibanaContextProvider } from '../../../../../../kibana_react/public';
+import { DOC_HIDE_TIME_COLUMN_SETTING } from '../../../../../common';
+import { FORMATS_UI_SETTINGS } from '../../../../../../field_formats/common';
+
+const defaultUiSettings = {
+ get: (key: string) => {
+ if (key === DOC_HIDE_TIME_COLUMN_SETTING) {
+ return false;
+ } else if (key === FORMATS_UI_SETTINGS.SHORT_DOTS_ENABLE) {
+ return false;
+ }
+ },
+};
function getMockIndexPattern() {
return {
@@ -66,11 +79,13 @@ describe('TableHeader with time column', () => {
const props = getMockProps();
const wrapper = mountWithIntl(
-
+
+
+
);
test('renders correctly', () => {
@@ -140,11 +155,24 @@ describe('TableHeader without time column', () => {
const props = getMockProps({ hideTimeColumn: true });
const wrapper = mountWithIntl(
-
+ {
+ if (key === DOC_HIDE_TIME_COLUMN_SETTING) {
+ return true;
+ }
+ },
+ },
+ }}
+ >
+
+
);
test('renders correctly', () => {
diff --git a/src/plugins/discover/public/components/doc_table/components/table_header/table_header.tsx b/src/plugins/discover/public/components/doc_table/components/table_header/table_header.tsx
index d78c17f9aca46..ffc0517ed5dd7 100644
--- a/src/plugins/discover/public/components/doc_table/components/table_header/table_header.tsx
+++ b/src/plugins/discover/public/components/doc_table/components/table_header/table_header.tsx
@@ -6,18 +6,18 @@
* Side Public License, v 1.
*/
-import React from 'react';
+import React, { useMemo } from 'react';
import type { DataView } from 'src/plugins/data/common';
import { TableHeaderColumn } from './table_header_column';
import { SortOrder, getDisplayedColumns } from './helpers';
import { getDefaultSort } from '../../lib/get_default_sort';
+import { useDiscoverServices } from '../../../../utils/use_discover_services';
+import { DOC_HIDE_TIME_COLUMN_SETTING, SORT_DEFAULT_ORDER_SETTING } from '../../../../../common';
+import { FORMATS_UI_SETTINGS } from '../../../../../../field_formats/common';
interface Props {
columns: string[];
- defaultSortOrder: string;
- hideTimeColumn: boolean;
indexPattern: DataView;
- isShortDots: boolean;
onChangeSortOrder?: (sortOrder: SortOrder[]) => void;
onMoveColumn?: (name: string, index: number) => void;
onRemoveColumn?: (name: string) => void;
@@ -26,15 +26,21 @@ interface Props {
export function TableHeader({
columns,
- defaultSortOrder,
- hideTimeColumn,
indexPattern,
- isShortDots,
onChangeSortOrder,
onMoveColumn,
onRemoveColumn,
sortOrder,
}: Props) {
+ const { uiSettings } = useDiscoverServices();
+ const [defaultSortOrder, hideTimeColumn, isShortDots] = useMemo(
+ () => [
+ uiSettings.get(SORT_DEFAULT_ORDER_SETTING, 'desc'),
+ uiSettings.get(DOC_HIDE_TIME_COLUMN_SETTING, false),
+ uiSettings.get(FORMATS_UI_SETTINGS.SHORT_DOTS_ENABLE),
+ ],
+ [uiSettings]
+ );
const displayedColumns = getDisplayedColumns(columns, indexPattern, hideTimeColumn, isShortDots);
return (
diff --git a/src/plugins/discover/public/components/doc_table/components/table_row.test.tsx b/src/plugins/discover/public/components/doc_table/components/table_row.test.tsx
index 7b0e4d821af65..084fddc991f74 100644
--- a/src/plugins/discover/public/components/doc_table/components/table_row.test.tsx
+++ b/src/plugins/discover/public/components/doc_table/components/table_row.test.tsx
@@ -9,28 +9,50 @@
import React from 'react';
import { mountWithIntl, findTestSubject } from '@kbn/test/jest';
import { TableRow, TableRowProps } from './table_row';
-import { setDocViewsRegistry, setServices } from '../../../kibana_services';
+import { setDocViewsRegistry } from '../../../kibana_services';
import { createFilterManagerMock } from '../../../../../data/public/query/filter_manager/filter_manager.mock';
-import { DiscoverServices } from '../../../build_services';
import { indexPatternWithTimefieldMock } from '../../../__mocks__/index_pattern_with_timefield';
-import { uiSettingsMock } from '../../../__mocks__/ui_settings';
import { DocViewsRegistry } from '../../../services/doc_views/doc_views_registry';
+import { KibanaContextProvider } from '../../../../../kibana_react/public';
+import { discoverServiceMock } from '../../../__mocks__/services';
+
+import {
+ DOC_HIDE_TIME_COLUMN_SETTING,
+ MAX_DOC_FIELDS_DISPLAYED,
+} from '../../../../../discover/common';
jest.mock('../lib/row_formatter', () => {
const originalModule = jest.requireActual('../lib/row_formatter');
return {
...originalModule,
- formatRow: () => mocked_document_cell,
+ formatRow: () => {
+ return mocked_document_cell;
+ },
};
});
const mountComponent = (props: TableRowProps) => {
return mountWithIntl(
-
+ {
+ if (key === DOC_HIDE_TIME_COLUMN_SETTING) {
+ return true;
+ } else if (key === MAX_DOC_FIELDS_DISPLAYED) {
+ return 100;
+ }
+ },
+ },
+ }}
+ >
+
+
);
};
@@ -50,27 +72,18 @@ const mockHit = {
const mockFilterManager = createFilterManagerMock();
describe('Doc table row component', () => {
- let mockInlineFilter;
- let defaultProps: TableRowProps;
+ const mockInlineFilter = jest.fn();
+ const defaultProps = {
+ columns: ['_source'],
+ filter: mockInlineFilter,
+ indexPattern: indexPatternWithTimefieldMock,
+ row: mockHit,
+ useNewFieldsApi: true,
+ filterManager: mockFilterManager,
+ addBasePath: (path: string) => path,
+ } as unknown as TableRowProps;
beforeEach(() => {
- mockInlineFilter = jest.fn();
-
- defaultProps = {
- columns: ['_source'],
- filter: mockInlineFilter,
- indexPattern: indexPatternWithTimefieldMock,
- row: mockHit,
- useNewFieldsApi: true,
- filterManager: mockFilterManager,
- addBasePath: (path: string) => path,
- hideTimeColumn: true,
- } as unknown as TableRowProps;
-
- setServices({
- uiSettings: uiSettingsMock,
- } as unknown as DiscoverServices);
-
setDocViewsRegistry(new DocViewsRegistry());
});
diff --git a/src/plugins/discover/public/components/doc_table/components/table_row.tsx b/src/plugins/discover/public/components/doc_table/components/table_row.tsx
index 8494c03f36fce..fde6edfb69cdf 100644
--- a/src/plugins/discover/public/components/doc_table/components/table_row.tsx
+++ b/src/plugins/discover/public/components/doc_table/components/table_row.tsx
@@ -13,13 +13,14 @@ import { EuiButtonEmpty, EuiIcon } from '@elastic/eui';
import { formatFieldValue } from '../../../utils/format_value';
import { flattenHit, DataView } from '../../../../../data/common';
import { DocViewer } from '../../../services/doc_views/components/doc_viewer/doc_viewer';
-import { FilterManager } from '../../../../../data/public';
import { TableCell } from './table_row/table_cell';
import { formatRow, formatTopLevelObject } from '../lib/row_formatter';
import { useNavigationProps } from '../../../utils/use_navigation_props';
import { DocViewFilterFn } from '../../../services/doc_views/doc_views_types';
import { ElasticSearchHit } from '../../../types';
import { TableRowDetails } from './table_row_details';
+import { useDiscoverServices } from '../../../utils/use_discover_services';
+import { DOC_HIDE_TIME_COLUMN_SETTING, MAX_DOC_FIELDS_DISPLAYED } from '../../../../common';
export type DocTableRow = ElasticSearchHit & {
isAnchor?: boolean;
@@ -28,15 +29,12 @@ export type DocTableRow = ElasticSearchHit & {
export interface TableRowProps {
columns: string[];
filter: DocViewFilterFn;
- indexPattern: DataView;
row: DocTableRow;
- onAddColumn?: (column: string) => void;
- onRemoveColumn?: (column: string) => void;
+ indexPattern: DataView;
useNewFieldsApi: boolean;
- hideTimeColumn: boolean;
- filterManager: FilterManager;
- addBasePath: (path: string) => string;
fieldsToShow: string[];
+ onAddColumn?: (column: string) => void;
+ onRemoveColumn?: (column: string) => void;
}
export const TableRow = ({
@@ -46,12 +44,17 @@ export const TableRow = ({
indexPattern,
useNewFieldsApi,
fieldsToShow,
- hideTimeColumn,
onAddColumn,
onRemoveColumn,
- filterManager,
- addBasePath,
}: TableRowProps) => {
+ const { uiSettings, filterManager, fieldFormats, addBasePath } = useDiscoverServices();
+ const [maxEntries, hideTimeColumn] = useMemo(
+ () => [
+ uiSettings.get(MAX_DOC_FIELDS_DISPLAYED),
+ uiSettings.get(DOC_HIDE_TIME_COLUMN_SETTING, false),
+ ],
+ [uiSettings]
+ );
const [open, setOpen] = useState(false);
const docTableRowClassName = classNames('kbnDocTable__row', {
// eslint-disable-next-line @typescript-eslint/naming-convention
@@ -75,12 +78,13 @@ export const TableRow = ({
// If we're formatting the _source column, don't use the regular field formatter,
// but our Discover mechanism to format a hit in a better human-readable way.
if (fieldName === '_source') {
- return formatRow(row, indexPattern, fieldsToShow);
+ return formatRow(row, indexPattern, fieldsToShow, maxEntries, fieldFormats);
}
const formattedField = formatFieldValue(
flattenedRow[fieldName],
row,
+ fieldFormats,
indexPattern,
mapping(fieldName)
);
@@ -142,7 +146,7 @@ export const TableRow = ({
}
if (columns.length === 0 && useNewFieldsApi) {
- const formatted = formatRow(row, indexPattern, fieldsToShow);
+ const formatted = formatRow(row, indexPattern, fieldsToShow, maxEntries, fieldFormats);
rowCells.push(
{
+ const services = useDiscoverServices();
const tableWrapperRef = useRef(null);
const {
curPageIndex,
@@ -72,8 +73,8 @@ export const DocTableEmbeddable = (props: DocTableEmbeddableProps) => {
);
const sampleSize = useMemo(() => {
- return getServices().uiSettings.get(SAMPLE_SIZE_SETTING, 500);
- }, []);
+ return services.uiSettings.get(SAMPLE_SIZE_SETTING, 500);
+ }, [services]);
const renderDocTable = useCallback(
(renderProps: DocTableRenderProps) => {
diff --git a/src/plugins/discover/public/components/doc_table/doc_table_infinite.tsx b/src/plugins/discover/public/components/doc_table/doc_table_infinite.tsx
index c3d86c646d407..8cda3b421815c 100644
--- a/src/plugins/discover/public/components/doc_table/doc_table_infinite.tsx
+++ b/src/plugins/discover/public/components/doc_table/doc_table_infinite.tsx
@@ -6,14 +6,16 @@
* Side Public License, v 1.
*/
-import React, { Fragment, memo, useCallback, useEffect, useRef, useState } from 'react';
+import React, { Fragment, memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import './index.scss';
import { FormattedMessage } from '@kbn/i18n-react';
import { debounce } from 'lodash';
import { EuiButtonEmpty } from '@elastic/eui';
+import { SAMPLE_SIZE_SETTING } from '../../../common';
import { DocTableProps, DocTableRenderProps, DocTableWrapper } from './doc_table_wrapper';
import { SkipBottomButton } from '../../application/main/components/skip_bottom_button';
import { shouldLoadNextDocPatch } from './lib/should_load_next_doc_patch';
+import { useDiscoverServices } from '../../utils/use_discover_services';
const FOOTER_PADDING = { padding: 0 };
@@ -28,7 +30,6 @@ interface DocTableInfiniteContentProps extends DocTableRenderProps {
const DocTableInfiniteContent = ({
rows,
columnLength,
- sampleSize,
limit,
onSkipBottomButtonClick,
renderHeader,
@@ -36,6 +37,10 @@ const DocTableInfiniteContent = ({
onSetMaxLimit,
onBackToTop,
}: DocTableInfiniteContentProps) => {
+ const { uiSettings } = useDiscoverServices();
+
+ const sampleSize = useMemo(() => uiSettings.get(SAMPLE_SIZE_SETTING, 500), [uiSettings]);
+
const onSkipBottomButton = useCallback(() => {
onSetMaxLimit();
onSkipBottomButtonClick();
diff --git a/src/plugins/discover/public/components/doc_table/doc_table_wrapper.test.tsx b/src/plugins/discover/public/components/doc_table/doc_table_wrapper.test.tsx
index c6da2315a1757..3634a47e3bcf1 100644
--- a/src/plugins/discover/public/components/doc_table/doc_table_wrapper.test.tsx
+++ b/src/plugins/discover/public/components/doc_table/doc_table_wrapper.test.tsx
@@ -8,21 +8,15 @@
import React from 'react';
import { findTestSubject, mountWithIntl } from '@kbn/test/jest';
-import { setServices } from '../../kibana_services';
import { indexPatternMock } from '../../__mocks__/index_pattern';
-import { DocTableWrapper, DocTableWrapperProps } from './doc_table_wrapper';
+import { DocTableWrapper } from './doc_table_wrapper';
import { DocTableRow } from './components/table_row';
import { discoverServiceMock } from '../../__mocks__/services';
-
-const mountComponent = (props: DocTableWrapperProps) => {
- return mountWithIntl();
-};
+import { KibanaContextProvider } from '../../../../kibana_react/public';
describe('Doc table component', () => {
- let defaultProps: DocTableWrapperProps;
-
- const initDefaults = (rows?: DocTableRow[]) => {
- defaultProps = {
+ const mountComponent = (rows?: DocTableRow[]) => {
+ const props = {
columns: ['_source'],
indexPattern: indexPatternMock,
rows: rows || [
@@ -53,21 +47,23 @@ describe('Doc table component', () => {
},
};
- setServices(discoverServiceMock);
+ return mountWithIntl(
+
+
+
+ );
};
it('should render infinite table correctly', () => {
- initDefaults();
- const component = mountComponent(defaultProps);
- expect(findTestSubject(component, defaultProps.dataTestSubj).exists()).toBeTruthy();
+ const component = mountComponent();
+ expect(findTestSubject(component, 'discoverDocTable').exists()).toBeTruthy();
expect(findTestSubject(component, 'docTable').exists()).toBeTruthy();
expect(component.find('.kbnDocTable__error').exists()).toBeFalsy();
});
it('should render error fallback if rows array is empty', () => {
- initDefaults([]);
- const component = mountComponent(defaultProps);
- expect(findTestSubject(component, defaultProps.dataTestSubj).exists()).toBeTruthy();
+ const component = mountComponent([]);
+ expect(findTestSubject(component, 'discoverDocTable').exists()).toBeTruthy();
expect(findTestSubject(component, 'docTable').exists()).toBeFalsy();
expect(component.find('.kbnDocTable__error').exists()).toBeTruthy();
});
diff --git a/src/plugins/discover/public/components/doc_table/doc_table_wrapper.tsx b/src/plugins/discover/public/components/doc_table/doc_table_wrapper.tsx
index 0cbfb36844943..cab38790efc4a 100644
--- a/src/plugins/discover/public/components/doc_table/doc_table_wrapper.tsx
+++ b/src/plugins/discover/public/components/doc_table/doc_table_wrapper.tsx
@@ -11,18 +11,12 @@ import { EuiIcon, EuiSpacer, EuiText } from '@elastic/eui';
import type { DataView, DataViewField } from 'src/plugins/data/common';
import { FormattedMessage } from '@kbn/i18n-react';
import { TableHeader } from './components/table_header/table_header';
-import { FORMATS_UI_SETTINGS } from '../../../../field_formats/common';
-import {
- DOC_HIDE_TIME_COLUMN_SETTING,
- SAMPLE_SIZE_SETTING,
- SHOW_MULTIFIELDS,
- SORT_DEFAULT_ORDER_SETTING,
-} from '../../../common';
-import { getServices } from '../../kibana_services';
+import { SHOW_MULTIFIELDS } from '../../../common';
import { SortOrder } from './components/table_header/helpers';
import { DocTableRow, TableRow } from './components/table_row';
import { DocViewFilterFn } from '../../services/doc_views/doc_views_types';
import { getFieldsToShow } from '../../utils/get_fields_to_show';
+import { useDiscoverServices } from '../../utils/use_discover_services';
export interface DocTableProps {
/**
@@ -86,7 +80,6 @@ export interface DocTableProps {
export interface DocTableRenderProps {
columnLength: number;
rows: DocTableRow[];
- sampleSize: number;
renderRows: (row: DocTableRow[]) => JSX.Element[];
renderHeader: () => JSX.Element;
onSkipBottomButtonClick: () => void;
@@ -122,26 +115,8 @@ export const DocTableWrapper = forwardRef(
}: DocTableWrapperProps,
ref
) => {
- const [
- defaultSortOrder,
- hideTimeColumn,
- isShortDots,
- sampleSize,
- showMultiFields,
- filterManager,
- addBasePath,
- ] = useMemo(() => {
- const services = getServices();
- return [
- services.uiSettings.get(SORT_DEFAULT_ORDER_SETTING, 'desc'),
- services.uiSettings.get(DOC_HIDE_TIME_COLUMN_SETTING, false),
- services.uiSettings.get(FORMATS_UI_SETTINGS.SHORT_DOTS_ENABLE),
- services.uiSettings.get(SAMPLE_SIZE_SETTING, 500),
- services.uiSettings.get(SHOW_MULTIFIELDS, false),
- services.filterManager,
- services.addBasePath,
- ];
- }, []);
+ const { uiSettings } = useDiscoverServices();
+ const showMultiFields = useMemo(() => uiSettings.get(SHOW_MULTIFIELDS, false), [uiSettings]);
const onSkipBottomButtonClick = useCallback(async () => {
// delay scrolling to after the rows have been rendered
@@ -169,27 +144,14 @@ export const DocTableWrapper = forwardRef(
() => (
),
- [
- columns,
- defaultSortOrder,
- hideTimeColumn,
- indexPattern,
- isShortDots,
- onMoveColumn,
- onRemoveColumn,
- onSort,
- sort,
- ]
+ [columns, indexPattern, onMoveColumn, onRemoveColumn, onSort, sort]
);
const renderRows = useCallback(
@@ -202,27 +164,12 @@ export const DocTableWrapper = forwardRef(
indexPattern={indexPattern}
row={current}
useNewFieldsApi={useNewFieldsApi}
- hideTimeColumn={hideTimeColumn}
onAddColumn={onAddColumn}
- onRemoveColumn={onRemoveColumn}
- filterManager={filterManager}
- addBasePath={addBasePath}
fieldsToShow={fieldsToShow}
/>
));
},
- [
- columns,
- onFilter,
- indexPattern,
- useNewFieldsApi,
- hideTimeColumn,
- onAddColumn,
- onRemoveColumn,
- filterManager,
- addBasePath,
- fieldsToShow,
- ]
+ [columns, onFilter, indexPattern, useNewFieldsApi, onAddColumn, fieldsToShow]
);
return (
@@ -239,7 +186,6 @@ export const DocTableWrapper = forwardRef(
render({
columnLength: columns.length,
rows,
- sampleSize,
onSkipBottomButtonClick,
renderHeader,
renderRows,
diff --git a/src/plugins/discover/public/components/doc_table/lib/row_formatter.test.ts b/src/plugins/discover/public/components/doc_table/lib/row_formatter.test.ts
index 039b8c4ada684..683713af12c8c 100644
--- a/src/plugins/discover/public/components/doc_table/lib/row_formatter.test.ts
+++ b/src/plugins/discover/public/components/doc_table/lib/row_formatter.test.ts
@@ -10,7 +10,6 @@ import ReactDOM from 'react-dom/server';
import { formatRow, formatTopLevelObject } from './row_formatter';
import { DataView } from '../../../../../data/common';
import { fieldFormatsMock } from '../../../../../field_formats/common/mocks';
-import { setServices } from '../../../kibana_services';
import { DiscoverServices } from '../../../build_services';
import { stubbedSavedObjectIndexPattern } from '../../../../../data/common/stubs';
@@ -27,6 +26,7 @@ describe('Row formatter', () => {
also: 'with "quotes" or \'single quotes\'',
},
};
+ let services: DiscoverServices;
const createIndexPattern = () => {
const id = 'my-index';
@@ -49,19 +49,17 @@ describe('Row formatter', () => {
const fieldsToShow = indexPattern.fields.getAll().map((fld) => fld.name);
beforeEach(() => {
- setServices({
- uiSettings: {
- get: () => 100,
- },
+ services = {
fieldFormats: {
getDefaultInstance: jest.fn(() => ({ convert: (value: unknown) => value })),
getFormatterForField: jest.fn(() => ({ convert: (value: unknown) => value })),
},
- } as unknown as DiscoverServices);
+ } as unknown as DiscoverServices;
});
it('formats document properly', () => {
- expect(formatRow(hit, indexPattern, fieldsToShow)).toMatchInlineSnapshot(`
+ expect(formatRow(hit, indexPattern, fieldsToShow, 100, services.fieldFormats))
+ .toMatchInlineSnapshot(`
{
});
it('limits number of rendered items', () => {
- setServices({
+ services = {
uiSettings: {
get: () => 1,
},
@@ -104,8 +102,8 @@ describe('Row formatter', () => {
getDefaultInstance: jest.fn(() => ({ convert: (value: unknown) => value })),
getFormatterForField: jest.fn(() => ({ convert: (value: unknown) => value })),
},
- } as unknown as DiscoverServices);
- expect(formatRow(hit, indexPattern, [])).toMatchInlineSnapshot(`
+ } as unknown as DiscoverServices;
+ expect(formatRow(hit, indexPattern, [], 1, services.fieldFormats)).toMatchInlineSnapshot(`
{
});
it('formats document with highlighted fields first', () => {
- expect(formatRow({ ...hit, highlight: { number: ['42'] } }, indexPattern, fieldsToShow))
- .toMatchInlineSnapshot(`
+ expect(
+ formatRow(
+ { ...hit, highlight: { number: ['42'] } },
+ indexPattern,
+ fieldsToShow,
+ 100,
+ services.fieldFormats
+ )
+ ).toMatchInlineSnapshot(`
{
'object.value': [5, 10],
getByName: jest.fn(),
},
- indexPattern
+ indexPattern,
+ 100
)
).toMatchInlineSnapshot(`
{
formatTopLevelObject(
{ fields: { 'a.zzz': [100], 'a.ccc': [50] } },
{ 'a.zzz': [100], 'a.ccc': [50], getByName: jest.fn() },
- indexPattern
+ indexPattern,
+ 100
)
);
expect(formatted.indexOf('a.ccc:')).toBeLessThan(formatted.indexOf('a.zzz:'));
@@ -249,7 +256,8 @@ describe('Row formatter', () => {
'object.keys': ['a', 'b'],
getByName: jest.fn(),
},
- indexPattern
+ indexPattern,
+ 100
)
).toMatchInlineSnapshot(`
{
'object.value': [5, 10],
getByName: jest.fn(),
},
- indexPattern
+ indexPattern,
+ 100
)
).toMatchInlineSnapshot(`
{
export const formatRow = (
hit: estypes.SearchHit,
indexPattern: DataView,
- fieldsToShow: string[]
+ fieldsToShow: string[],
+ maxEntries: number,
+ fieldFormats: FieldFormatsStart
) => {
- const pairs = formatHit(hit, indexPattern, fieldsToShow);
+ const pairs = formatHit(hit, indexPattern, fieldsToShow, maxEntries, fieldFormats);
return ;
};
@@ -52,7 +53,8 @@ export const formatTopLevelObject = (
row: Record,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
fields: Record,
- indexPattern: DataView
+ indexPattern: DataView,
+ maxEntries: number
) => {
const highlights = row.highlight ?? {};
const highlightPairs: Array<[string, string]> = [];
@@ -77,6 +79,5 @@ export const formatTopLevelObject = (
const pairs = highlights[key] ? highlightPairs : sourcePairs;
pairs.push([displayKey ? displayKey : key, formatted]);
});
- const maxEntries = getServices().uiSettings.get(MAX_DOC_FIELDS_DISPLAYED);
return ;
};
diff --git a/src/plugins/discover/public/embeddable/saved_search_embeddable.tsx b/src/plugins/discover/public/embeddable/saved_search_embeddable.tsx
index b203b6452c5ef..5e0f06f143a0c 100644
--- a/src/plugins/discover/public/embeddable/saved_search_embeddable.tsx
+++ b/src/plugins/discover/public/embeddable/saved_search_embeddable.tsx
@@ -11,6 +11,7 @@ import React from 'react';
import ReactDOM from 'react-dom';
import { i18n } from '@kbn/i18n';
import { isEqual } from 'lodash';
+import { I18nProvider } from '@kbn/i18n-react';
import { Container, Embeddable } from '../../../embeddable/public';
import { ISearchEmbeddable, SearchInput, SearchOutput } from './types';
import { SavedSearch } from '../services/saved_searches';
@@ -28,7 +29,6 @@ import {
} from '../../../data/common';
import { SavedSearchEmbeddableComponent } from './saved_search_embeddable_component';
import { UiActionsStart } from '../../../ui_actions/public';
-import { getServices } from '../kibana_services';
import {
DOC_HIDE_TIME_COLUMN_SETTING,
DOC_TABLE_LEGACY,
@@ -46,9 +46,9 @@ import { getDefaultSort } from '../components/doc_table';
import { SortOrder } from '../components/doc_table/components/table_header/helpers';
import { VIEW_MODE } from '../components/view_mode_toggle';
import { updateSearchSource } from './utils/update_search_source';
-import { FieldStatsTableSavedSearchEmbeddable } from '../application/main/components/field_stats_table';
+import { FieldStatisticsTable } from '../application/main/components/field_stats_table';
import { ElasticSearchHit } from '../types';
-import { KibanaThemeProvider } from '../../../kibana_react/public';
+import { KibanaContextProvider, KibanaThemeProvider } from '../../../kibana_react/public';
export type SearchProps = Partial &
Partial & {
@@ -56,6 +56,7 @@ export type SearchProps = Partial &
description?: string;
sharedItemTitle?: string;
inspectorAdapters?: Adapters;
+ services: DiscoverServices;
filter?: (field: DataViewField, value: string[], operator: string) => void;
hits?: ElasticSearchHit[];
@@ -337,7 +338,7 @@ export class SavedSearchEmbeddable
? this.savedSearch.sort
: getDefaultSort(
this.searchProps?.indexPattern,
- getServices().uiSettings.get(SORT_DEFAULT_ORDER_SETTING, 'desc')
+ this.services.uiSettings.get(SORT_DEFAULT_ORDER_SETTING, 'desc')
);
searchProps.sort = this.input.sort || savedSearchSort;
searchProps.sharedItemTitle = this.panelTitle;
@@ -392,18 +393,21 @@ export class SavedSearchEmbeddable
Array.isArray(searchProps.columns)
) {
ReactDOM.render(
-
-
- ,
+
+
+
+
+
+
+ ,
domNode
);
return;
@@ -416,9 +420,13 @@ export class SavedSearchEmbeddable
};
if (searchProps.services) {
ReactDOM.render(
-
-
- ,
+
+
+
+
+
+
+ ,
domNode
);
}
diff --git a/src/plugins/discover/public/embeddable/saved_search_grid.tsx b/src/plugins/discover/public/embeddable/saved_search_grid.tsx
index f0423eac4f963..b4785b9911da1 100644
--- a/src/plugins/discover/public/embeddable/saved_search_grid.tsx
+++ b/src/plugins/discover/public/embeddable/saved_search_grid.tsx
@@ -5,51 +5,34 @@
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
-import React, { useState } from 'react';
-import { I18nProvider } from '@kbn/i18n-react';
+import React, { useState, memo } from 'react';
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
+import { I18nProvider } from '@kbn/i18n-react';
import { DiscoverGrid, DiscoverGridProps } from '../components/discover_grid/discover_grid';
-import { getServices } from '../kibana_services';
import { TotalDocuments } from '../application/main/components/total_documents/total_documents';
import { ElasticSearchHit } from '../types';
-import { KibanaContextProvider } from '../../../kibana_react/public';
export interface DiscoverGridEmbeddableProps extends DiscoverGridProps {
totalHitCount: number;
}
-export const DataGridMemoized = React.memo((props: DiscoverGridProps) => (
-
-));
+export const DataGridMemoized = memo(DiscoverGrid);
export function DiscoverGridEmbeddable(props: DiscoverGridEmbeddableProps) {
- const services = getServices();
const [expandedDoc, setExpandedDoc] = useState(undefined);
return (
-
-
- {props.totalHitCount !== 0 && (
-
-
-
- )}
-
-
+
+ {props.totalHitCount !== 0 && (
+
+
-
-
+ )}
+
+
+
+
);
}
diff --git a/src/plugins/discover/public/embeddable/search_embeddable_factory.ts b/src/plugins/discover/public/embeddable/search_embeddable_factory.ts
index 8fbedf3979663..be391282ea57d 100644
--- a/src/plugins/discover/public/embeddable/search_embeddable_factory.ts
+++ b/src/plugins/discover/public/embeddable/search_embeddable_factory.ts
@@ -8,7 +8,6 @@
import { i18n } from '@kbn/i18n';
import { UiActionsStart } from 'src/plugins/ui_actions/public';
-import { getServices } from '../kibana_services';
import {
EmbeddableFactoryDefinition,
Container,
@@ -25,6 +24,7 @@ import {
getSavedSearchUrl,
throwErrorOnSavedSearchUrlConflict,
} from '../services/saved_searches';
+import { DiscoverServices } from '../build_services';
interface StartServices {
executeTriggerActions: UiActionsStart['executeTriggerActions'];
@@ -43,7 +43,10 @@ export class SearchEmbeddableFactory
getIconForSavedObject: () => 'discoverApp',
};
- constructor(private getStartServices: () => Promise) {}
+ constructor(
+ private getStartServices: () => Promise,
+ private getDiscoverServices: () => Promise
+ ) {}
public canCreateNew() {
return false;
@@ -64,7 +67,7 @@ export class SearchEmbeddableFactory
input: Partial & { id: string; timeRange: TimeRange },
parent?: Container
): Promise => {
- const services = getServices();
+ const services = await this.getDiscoverServices();
const filterManager = services.filterManager;
const url = getSavedSearchUrl(savedObjectId);
const editUrl = services.addBasePath(`/app/discover${url}`);
@@ -88,9 +91,9 @@ export class SearchEmbeddableFactory
editUrl,
editPath: url,
filterManager,
- editable: getServices().capabilities.discover.save as boolean,
+ editable: services.capabilities.discover.save as boolean,
indexPatterns: indexPattern ? [indexPattern] : [],
- services: getServices(),
+ services,
},
input,
executeTriggerActions,
diff --git a/src/plugins/discover/public/embeddable/view_saved_search_action.test.ts b/src/plugins/discover/public/embeddable/view_saved_search_action.test.ts
index c18999473f26d..7306e56e09fa8 100644
--- a/src/plugins/discover/public/embeddable/view_saved_search_action.test.ts
+++ b/src/plugins/discover/public/embeddable/view_saved_search_action.test.ts
@@ -11,14 +11,11 @@ import { ContactCardEmbeddable } from 'src/plugins/embeddable/public/lib/test_sa
import { ViewSavedSearchAction } from './view_saved_search_action';
import { SavedSearchEmbeddable } from './saved_search_embeddable';
import { createStartContractMock } from '../__mocks__/start_contract';
-import { uiSettingsServiceMock } from '../../../../core/public/mocks';
import { savedSearchMock } from '../__mocks__/saved_search';
import { discoverServiceMock } from '../__mocks__/services';
import { DataView } from 'src/plugins/data/common';
import { createFilterManagerMock } from 'src/plugins/data/public/query/filter_manager/filter_manager.mock';
import { ViewMode } from 'src/plugins/embeddable/public';
-import { setServices } from '../kibana_services';
-import type { DiscoverServices } from '../build_services';
const applicationMock = createStartContractMock();
const savedSearch = savedSearchMock;
@@ -48,11 +45,6 @@ const embeddableConfig = {
};
describe('view saved search action', () => {
- beforeEach(() => {
- setServices({
- uiSettings: uiSettingsServiceMock.createStartContract(),
- } as unknown as DiscoverServices);
- });
it('is compatible when embeddable is of type saved search, in view mode && appropriate permissions are set', async () => {
const action = new ViewSavedSearchAction(applicationMock);
const embeddable = new SavedSearchEmbeddable(
diff --git a/src/plugins/discover/public/kibana_services.ts b/src/plugins/discover/public/kibana_services.ts
index ffdfd82058693..f055d2b67ade1 100644
--- a/src/plugins/discover/public/kibana_services.ts
+++ b/src/plugins/discover/public/kibana_services.ts
@@ -10,24 +10,12 @@ import { once } from 'lodash';
import { createHashHistory } from 'history';
import type { ScopedHistory, AppMountParameters } from 'kibana/public';
import type { UiActionsStart } from 'src/plugins/ui_actions/public';
-import { DiscoverServices, HistoryLocationState } from './build_services';
+import { HistoryLocationState } from './build_services';
import { createGetterSetter } from '../../kibana_utils/public';
import { DocViewsRegistry } from './services/doc_views/doc_views_registry';
-let services: DiscoverServices | null = null;
let uiActions: UiActionsStart;
-export function getServices(): DiscoverServices {
- if (!services) {
- throw new Error('Discover services are not yet available');
- }
- return services;
-}
-
-export function setServices(newServices: DiscoverServices) {
- services = newServices;
-}
-
export const setUiActions = (pluginUiActions: UiActionsStart) => (uiActions = pluginUiActions);
export const getUiActions = () => uiActions;
diff --git a/src/plugins/discover/public/plugin.tsx b/src/plugins/discover/public/plugin.tsx
index e881253a7d6d2..43c03a59b5b25 100644
--- a/src/plugins/discover/public/plugin.tsx
+++ b/src/plugins/discover/public/plugin.tsx
@@ -37,13 +37,11 @@ import { DocViewsRegistry } from './services/doc_views/doc_views_registry';
import {
setDocViewsRegistry,
setUrlTracker,
- setServices,
setHeaderActionMenuMounter,
setUiActions,
setScopedHistory,
getScopedHistory,
syncHistoryLocations,
- getServices,
} from './kibana_services';
import { registerFeature } from './register_feature';
import { buildServices } from './build_services';
@@ -64,6 +62,7 @@ import type { SpacesPluginStart } from '../../../../x-pack/plugins/spaces/public
import { FieldFormatsStart } from '../../field_formats/public';
import { injectTruncateStyles } from './utils/truncate_styles';
import { DOC_TABLE_LEGACY, TRUNCATE_MAX_HEIGHT } from '../common';
+import { useDiscoverServices } from './utils/use_discover_services';
declare module '../../share/public' {
export interface UrlGeneratorStateMapping {
@@ -211,10 +210,7 @@ export class DiscoverPlugin
private urlGenerator?: DiscoverStart['urlGenerator'];
private locator?: DiscoverAppLocator;
- setup(
- core: CoreSetup,
- plugins: DiscoverSetupPlugins
- ): DiscoverSetup {
+ setup(core: CoreSetup, plugins: DiscoverSetupPlugins) {
const baseUrl = core.http.basePath.prepend('/app/discover');
if (plugins.share) {
@@ -242,9 +238,12 @@ export class DiscoverPlugin
}),
order: 10,
component: (props) => {
- const Component = getServices().uiSettings.get(DOC_TABLE_LEGACY)
+ // eslint-disable-next-line react-hooks/rules-of-hooks
+ const services = useDiscoverServices();
+ const DocView = services.uiSettings.get(DOC_TABLE_LEGACY)
? DocViewerLegacyTable
: DocViewerTable;
+
return (
}
>
-
+
);
},
@@ -339,7 +338,6 @@ export class DiscoverPlugin
defaultPath: '#/',
category: DEFAULT_APP_CATEGORIES.kibana,
mount: async (params: AppMountParameters) => {
- const [, depsStart] = await core.getStartServices();
setScopedHistory(params.history);
setHeaderActionMenuMounter(params.setHeaderActionMenu);
syncHistoryLocations();
@@ -349,14 +347,18 @@ export class DiscoverPlugin
const unlistenParentHistory = params.history.listen(() => {
window.dispatchEvent(new HashChangeEvent('hashchange'));
});
+
+ const [coreStart, discoverStartPlugins] = await core.getStartServices();
+ const services = buildServices(coreStart, discoverStartPlugins, this.initializerContext);
+
// make sure the index pattern list is up to date
- await depsStart.data.indexPatterns.clearCache();
+ await discoverStartPlugins.data.indexPatterns.clearCache();
const { renderApp } = await import('./application');
// FIXME: Temporarily hide overflow-y in Discover app when Field Stats table is shown
// due to EUI bug https://github.com/elastic/eui/pull/5152
params.element.classList.add('dscAppWrapper');
- const unmount = renderApp(params.element);
+ const unmount = renderApp(params.element, services);
return () => {
unlistenParentHistory();
unmount();
@@ -413,10 +415,7 @@ export class DiscoverPlugin
uiActions.addTriggerAction('CONTEXT_MENU_TRIGGER', viewSavedSearchAction);
setUiActions(plugins.uiActions);
- const services = buildServices(core, plugins, this.initializerContext);
- setServices(services);
-
- injectTruncateStyles(services.uiSettings.get(TRUNCATE_MAX_HEIGHT));
+ injectTruncateStyles(core.uiSettings.get(TRUNCATE_MAX_HEIGHT));
return {
urlGenerator: this.urlGenerator,
@@ -439,7 +438,12 @@ export class DiscoverPlugin
};
};
- const factory = new SearchEmbeddableFactory(getStartServices);
+ const getDiscoverServices = async () => {
+ const [coreStart, discoverStartPlugins] = await core.getStartServices();
+ return buildServices(coreStart, discoverStartPlugins, this.initializerContext);
+ };
+
+ const factory = new SearchEmbeddableFactory(getStartServices, getDiscoverServices);
plugins.embeddable.registerEmbeddableFactory(factory.type, factory);
}
}
diff --git a/src/plugins/discover/public/services/doc_views/components/doc_viewer/doc_viewer.test.tsx b/src/plugins/discover/public/services/doc_views/components/doc_viewer/doc_viewer.test.tsx
index bedf1047bc4ec..2d946db20dd03 100644
--- a/src/plugins/discover/public/services/doc_views/components/doc_viewer/doc_viewer.test.tsx
+++ b/src/plugins/discover/public/services/doc_views/components/doc_viewer/doc_viewer.test.tsx
@@ -17,11 +17,6 @@ jest.mock('../../../../kibana_services', () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let registry: any[] = [];
return {
- getServices: () => ({
- uiSettings: {
- get: jest.fn(),
- },
- }),
getDocViewsRegistry: () => ({
// eslint-disable-next-line @typescript-eslint/no-explicit-any
addDocView(view: any) {
@@ -37,6 +32,16 @@ jest.mock('../../../../kibana_services', () => {
};
});
+jest.mock('../../../../utils/use_discover_services', () => {
+ return {
+ useDiscoverServices: {
+ uiSettings: {
+ get: jest.fn(),
+ },
+ },
+ };
+});
+
beforeEach(() => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(getDocViewsRegistry() as any).resetRegistry();
diff --git a/src/plugins/discover/public/services/doc_views/components/doc_viewer/doc_viewer_tab.tsx b/src/plugins/discover/public/services/doc_views/components/doc_viewer/doc_viewer_tab.tsx
index f43e445737820..107db6f1a588e 100644
--- a/src/plugins/discover/public/services/doc_views/components/doc_viewer/doc_viewer_tab.tsx
+++ b/src/plugins/discover/public/services/doc_views/components/doc_viewer/doc_viewer_tab.tsx
@@ -11,8 +11,6 @@ import { isEqual } from 'lodash';
import { DocViewRenderTab } from './doc_viewer_render_tab';
import { DocViewerError } from './doc_viewer_render_error';
import { DocViewRenderFn, DocViewRenderProps } from '../../doc_views_types';
-import { getServices } from '../../../../kibana_services';
-import { KibanaContextProvider } from '../../../../../../kibana_react/public';
interface Props {
id: number;
@@ -67,11 +65,7 @@ export class DocViewerTab extends React.Component {
// doc view is provided by a react component
if (Component) {
- return (
-
-
-
- );
+ return ;
}
return (
diff --git a/src/plugins/discover/public/services/doc_views/components/doc_viewer_source/__snapshots__/source.test.tsx.snap b/src/plugins/discover/public/services/doc_views/components/doc_viewer_source/__snapshots__/source.test.tsx.snap
index b78463a44e977..41b7ee37413d9 100644
--- a/src/plugins/discover/public/services/doc_views/components/doc_viewer_source/__snapshots__/source.test.tsx.snap
+++ b/src/plugins/discover/public/services/doc_views/components/doc_viewer_source/__snapshots__/source.test.tsx.snap
@@ -10,108 +10,6 @@ exports[`Source Viewer component renders error state 1`] = `
"getComputedFields": [Function],
}
}
- intl={
- Object {
- "defaultFormats": Object {},
- "defaultLocale": "en",
- "formatDate": [Function],
- "formatHTMLMessage": [Function],
- "formatMessage": [Function],
- "formatNumber": [Function],
- "formatPlural": [Function],
- "formatRelative": [Function],
- "formatTime": [Function],
- "formats": Object {
- "date": Object {
- "full": Object {
- "day": "numeric",
- "month": "long",
- "weekday": "long",
- "year": "numeric",
- },
- "long": Object {
- "day": "numeric",
- "month": "long",
- "year": "numeric",
- },
- "medium": Object {
- "day": "numeric",
- "month": "short",
- "year": "numeric",
- },
- "short": Object {
- "day": "numeric",
- "month": "numeric",
- "year": "2-digit",
- },
- },
- "number": Object {
- "currency": Object {
- "style": "currency",
- },
- "percent": Object {
- "style": "percent",
- },
- },
- "relative": Object {
- "days": Object {
- "units": "day",
- },
- "hours": Object {
- "units": "hour",
- },
- "minutes": Object {
- "units": "minute",
- },
- "months": Object {
- "units": "month",
- },
- "seconds": Object {
- "units": "second",
- },
- "years": Object {
- "units": "year",
- },
- },
- "time": Object {
- "full": Object {
- "hour": "numeric",
- "minute": "numeric",
- "second": "numeric",
- "timeZoneName": "short",
- },
- "long": Object {
- "hour": "numeric",
- "minute": "numeric",
- "second": "numeric",
- "timeZoneName": "short",
- },
- "medium": Object {
- "hour": "numeric",
- "minute": "numeric",
- "second": "numeric",
- },
- "short": Object {
- "hour": "numeric",
- "minute": "numeric",
- },
- },
- },
- "formatters": Object {
- "getDateTimeFormat": [Function],
- "getMessageFormat": [Function],
- "getNumberFormat": [Function],
- "getPluralFormat": [Function],
- "getRelativeFormat": [Function],
- },
- "locale": "en",
- "messages": Object {},
- "now": [Function],
- "onError": [Function],
- "textComponent": Symbol(react.fragment),
- "timeZone": null,
- }
- }
width={123}
>
({
- getServices: jest.fn(),
-}));
-
-import { getServices } from '../../../../kibana_services';
+import { KibanaContextProvider } from '../../../../../../kibana_react/public';
const mockIndexPattern = {
getComputedFields: () => [],
@@ -28,8 +23,7 @@ const getMock = jest.fn(() => Promise.resolve(mockIndexPattern));
const mockIndexPatternService = {
get: getMock,
} as unknown as DataView;
-
-(getServices as jest.Mock).mockImplementation(() => ({
+const services = {
uiSettings: {
get: (key: string) => {
if (key === 'discover:useNewFieldsApi') {
@@ -40,21 +34,24 @@ const mockIndexPatternService = {
data: {
indexPatternService: mockIndexPatternService,
},
-}));
+};
+
describe('Source Viewer component', () => {
test('renders loading state', () => {
jest.spyOn(hooks, 'useEsDocSearch').mockImplementation(() => [0, null, () => {}]);
const comp = mountWithIntl(
-
+
+
+
);
- expect(comp).toMatchSnapshot();
+ expect(comp.children()).toMatchSnapshot();
const loadingIndicator = comp.find(EuiLoadingSpinner);
expect(loadingIndicator).not.toBe(null);
});
@@ -63,15 +60,17 @@ describe('Source Viewer component', () => {
jest.spyOn(hooks, 'useEsDocSearch').mockImplementation(() => [3, null, () => {}]);
const comp = mountWithIntl(
-
+
+
+
);
- expect(comp).toMatchSnapshot();
+ expect(comp.children()).toMatchSnapshot();
const errorPrompt = comp.find(EuiEmptyPrompt);
expect(errorPrompt.length).toBe(1);
const refreshButton = comp.find(EuiButton);
@@ -102,15 +101,17 @@ describe('Source Viewer component', () => {
return false;
});
const comp = mountWithIntl(
-
+
+
+
);
- expect(comp).toMatchSnapshot();
+ expect(comp.children()).toMatchSnapshot();
const jsonCodeEditor = comp.find(JsonCodeEditorCommon);
expect(jsonCodeEditor).not.toBe(null);
});
diff --git a/src/plugins/discover/public/services/doc_views/components/doc_viewer_source/source.tsx b/src/plugins/discover/public/services/doc_views/components/doc_viewer_source/source.tsx
index 6712d1491606f..9f1cbb7069712 100644
--- a/src/plugins/discover/public/services/doc_views/components/doc_viewer_source/source.tsx
+++ b/src/plugins/discover/public/services/doc_views/components/doc_viewer_source/source.tsx
@@ -12,8 +12,8 @@ import { FormattedMessage } from '@kbn/i18n-react';
import { monaco } from '@kbn/monaco';
import { EuiButton, EuiEmptyPrompt, EuiLoadingSpinner, EuiSpacer, EuiText } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
+import { useDiscoverServices } from '../../../../utils/use_discover_services';
import { JSONCodeEditorCommonMemoized } from '../../../../components/json_code_editor/json_code_editor_common';
-import { getServices } from '../../../../kibana_services';
import { SEARCH_FIELDS_FROM_SOURCE } from '../../../../../common';
import { useEsDocSearch } from '../../../../utils/use_es_doc_search';
import { DataView } from '../../../../../../data_views/common';
@@ -36,7 +36,8 @@ export const DocViewerSource = ({
}: SourceViewerProps) => {
const [editor, setEditor] = useState
();
const [jsonValue, setJsonValue] = useState('');
- const useNewFieldsApi = !getServices().uiSettings.get(SEARCH_FIELDS_FROM_SOURCE);
+ const { uiSettings } = useDiscoverServices();
+ const useNewFieldsApi = !uiSettings.get(SEARCH_FIELDS_FROM_SOURCE);
const [reqState, hit, requestData] = useEsDocSearch({
id,
index,
diff --git a/src/plugins/discover/public/services/doc_views/components/doc_viewer_table/legacy/table.test.tsx b/src/plugins/discover/public/services/doc_views/components/doc_viewer_table/legacy/table.test.tsx
index 76977034da1b4..cb85315e7dd42 100644
--- a/src/plugins/discover/public/services/doc_views/components/doc_viewer_table/legacy/table.test.tsx
+++ b/src/plugins/discover/public/services/doc_views/components/doc_viewer_table/legacy/table.test.tsx
@@ -12,15 +12,11 @@ import { findTestSubject } from '@elastic/eui/lib/test';
import { DocViewerLegacyTable } from './table';
import { DataView } from '../../../../../../../data/common';
import { DocViewRenderProps } from '../../../doc_views_types';
-
-jest.mock('../../../../../kibana_services', () => ({
- getServices: jest.fn(),
-}));
-
-import { getServices } from '../../../../../kibana_services';
import { ElasticSearchHit } from '../../../../../types';
+import { KibanaContextProvider } from '../../../../../../../kibana_react/public';
+import { DiscoverServices } from 'src/plugins/discover/public/build_services';
-(getServices as jest.Mock).mockImplementation(() => ({
+const services = {
uiSettings: {
get: (key: string) => {
if (key === 'discover:showMultiFields') {
@@ -32,7 +28,7 @@ import { ElasticSearchHit } from '../../../../../types';
getDefaultInstance: jest.fn(() => ({ convert: (value: unknown) => value })),
getFormatterForField: jest.fn(() => ({ convert: (value: unknown) => value })),
},
-}));
+};
const indexPattern = {
fields: {
@@ -77,8 +73,12 @@ indexPattern.fields.getByName = (name: string) => {
return indexPattern.fields.getAll().find((field) => field.name === name);
};
-const mountComponent = (props: DocViewRenderProps) => {
- return mountWithIntl();
+const mountComponent = (props: DocViewRenderProps, overrides?: Partial) => {
+ return mountWithIntl(
+
+ {' '}
+
+ );
};
describe('DocViewTable at Discover', () => {
@@ -424,14 +424,16 @@ describe('DocViewTable at Discover Doc with Fields API', () => {
});
it('does not render multifield rows if showMultiFields flag is not set', () => {
- (getServices as jest.Mock).mockImplementationOnce(() => ({
+ const overridedServices = {
uiSettings: {
get: (key: string) => {
- return key === 'discover:showMultiFields' && false;
+ if (key === 'discover:showMultiFields') {
+ return false;
+ }
},
},
- }));
- const component = mountComponent(props);
+ } as unknown as DiscoverServices;
+ const component = mountComponent(props, overridedServices);
const categoryKeywordRow = findTestSubject(component, 'tableDocViewRow-category.keyword');
expect(categoryKeywordRow.length).toBe(0);
diff --git a/src/plugins/discover/public/services/doc_views/components/doc_viewer_table/legacy/table.tsx b/src/plugins/discover/public/services/doc_views/components/doc_viewer_table/legacy/table.tsx
index 517093635897e..e78ed2ccadd06 100644
--- a/src/plugins/discover/public/services/doc_views/components/doc_viewer_table/legacy/table.tsx
+++ b/src/plugins/discover/public/services/doc_views/components/doc_viewer_table/legacy/table.tsx
@@ -9,9 +9,9 @@
import '../table.scss';
import React, { useCallback, useMemo } from 'react';
import { EuiInMemoryTable } from '@elastic/eui';
+import { useDiscoverServices } from '../../../../../utils/use_discover_services';
import { flattenHit } from '../../../../../../../data/common';
import { SHOW_MULTIFIELDS } from '../../../../../../common';
-import { getServices } from '../../../../../kibana_services';
import { DocViewRenderProps, FieldRecordLegacy } from '../../../doc_views_types';
import { ACTIONS_COLUMN, MAIN_COLUMNS } from './table_columns';
import { getFieldsToShow } from '../../../../../utils/get_fields_to_show';
@@ -27,7 +27,8 @@ export const DocViewerLegacyTable = ({
onAddColumn,
onRemoveColumn,
}: DocViewRenderProps) => {
- const showMultiFields = getServices().uiSettings.get(SHOW_MULTIFIELDS);
+ const { fieldFormats, uiSettings } = useDiscoverServices();
+ const showMultiFields = useMemo(() => uiSettings.get(SHOW_MULTIFIELDS), [uiSettings]);
const mapping = useCallback((name: string) => dataView.fields.getByName(name), [dataView.fields]);
const tableColumns = useMemo(() => {
@@ -89,7 +90,13 @@ export const DocViewerLegacyTable = ({
scripted: Boolean(fieldMapping?.scripted),
},
value: {
- formattedValue: formatFieldValue(flattened[field], hit, dataView, fieldMapping),
+ formattedValue: formatFieldValue(
+ flattened[field],
+ hit,
+ fieldFormats,
+ dataView,
+ fieldMapping
+ ),
ignored,
},
};
diff --git a/src/plugins/discover/public/services/doc_views/components/doc_viewer_table/table.tsx b/src/plugins/discover/public/services/doc_views/components/doc_viewer_table/table.tsx
index 65806bb03a0bd..521d7d6e75eb2 100644
--- a/src/plugins/discover/public/services/doc_views/components/doc_viewer_table/table.tsx
+++ b/src/plugins/discover/public/services/doc_views/components/doc_viewer_table/table.tsx
@@ -27,12 +27,12 @@ import {
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import { debounce } from 'lodash';
+import { useDiscoverServices } from '../../../../utils/use_discover_services';
import { Storage } from '../../../../../../kibana_utils/public';
import { usePager } from '../../../../utils/use_pager';
import { FieldName } from '../../../../components/field_name/field_name';
import { flattenHit } from '../../../../../../data/common';
import { SHOW_MULTIFIELDS } from '../../../../../common';
-import { getServices } from '../../../../kibana_services';
import { DocViewRenderProps, FieldRecordLegacy } from '../../doc_views_types';
import { getFieldsToShow } from '../../../../utils/get_fields_to_show';
import { getIgnoredReason } from '../../../../utils/get_ignored_reason';
@@ -108,7 +108,7 @@ export const DocViewerTable = ({
onAddColumn,
onRemoveColumn,
}: DocViewRenderProps) => {
- const { storage, uiSettings } = getServices();
+ const { storage, uiSettings, fieldFormats } = useDiscoverServices();
const showMultiFields = uiSettings.get(SHOW_MULTIFIELDS);
const currentDataViewId = dataView.id!;
const isSingleDocView = !filter;
@@ -178,21 +178,28 @@ export const DocViewerTable = ({
onTogglePinned,
},
value: {
- formattedValue: formatFieldValue(flattened[field], hit, dataView, fieldMapping),
+ formattedValue: formatFieldValue(
+ flattened[field],
+ hit,
+ fieldFormats,
+ dataView,
+ fieldMapping
+ ),
ignored,
},
};
},
[
- columns,
- filter,
- flattened,
- hit,
- dataView,
mapping,
+ dataView,
+ hit,
onToggleColumn,
- onTogglePinned,
+ filter,
+ columns,
+ flattened,
pinnedFields,
+ onTogglePinned,
+ fieldFormats,
]
);
diff --git a/src/plugins/discover/public/services/doc_views/doc_views_types.ts b/src/plugins/discover/public/services/doc_views/doc_views_types.ts
index e213adcb89553..0287884c8b6f6 100644
--- a/src/plugins/discover/public/services/doc_views/doc_views_types.ts
+++ b/src/plugins/discover/public/services/doc_views/doc_views_types.ts
@@ -6,7 +6,6 @@
* Side Public License, v 1.
*/
-import { ComponentType } from 'react';
import { DataView, DataViewField } from '../../../../data/common';
import { ElasticSearchHit } from '../../types';
import { IgnoredReason } from '../../utils/get_ignored_reason';
@@ -34,7 +33,7 @@ export interface DocViewRenderProps {
onAddColumn?: (columnName: string) => void;
onRemoveColumn?: (columnName: string) => void;
}
-export type DocViewerComponent = ComponentType;
+export type DocViewerComponent = React.FC;
export type DocViewRenderFn = (
domeNode: HTMLDivElement,
renderProps: DocViewRenderProps
diff --git a/src/plugins/discover/public/utils/format_hit.test.ts b/src/plugins/discover/public/utils/format_hit.test.ts
index 8d37b87e884c4..601d88cdedc96 100644
--- a/src/plugins/discover/public/utils/format_hit.test.ts
+++ b/src/plugins/discover/public/utils/format_hit.test.ts
@@ -10,11 +10,6 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import { indexPatternMock as dataViewMock } from '../__mocks__/index_pattern';
import { formatHit } from './format_hit';
import { discoverServiceMock } from '../__mocks__/services';
-import { MAX_DOC_FIELDS_DISPLAYED } from '../../common';
-
-jest.mock('../kibana_services', () => ({
- getServices: () => jest.requireActual('../__mocks__/services').discoverServiceMock,
-}));
describe('formatHit', () => {
let hit: estypes.SearchHit;
@@ -32,9 +27,6 @@ describe('formatHit', () => {
(dataViewMock.getFormatterForField as jest.Mock).mockReturnValue({
convert: (value: unknown) => `formatted:${value}`,
});
- (discoverServiceMock.uiSettings.get as jest.Mock).mockImplementation(
- (key) => key === MAX_DOC_FIELDS_DISPLAYED && 220
- );
});
afterEach(() => {
@@ -42,7 +34,13 @@ describe('formatHit', () => {
});
it('formats a document as expected', () => {
- const formatted = formatHit(hit, dataViewMock, ['message', 'extension', 'object.value']);
+ const formatted = formatHit(
+ hit,
+ dataViewMock,
+ ['message', 'extension', 'object.value'],
+ 220,
+ discoverServiceMock.fieldFormats
+ );
expect(formatted).toEqual([
['extension', 'formatted:png'],
['message', 'formatted:foobar'],
@@ -53,11 +51,13 @@ describe('formatHit', () => {
});
it('orders highlighted fields first', () => {
- const formatted = formatHit({ ...hit, highlight: { message: ['%%'] } }, dataViewMock, [
- 'message',
- 'extension',
- 'object.value',
- ]);
+ const formatted = formatHit(
+ { ...hit, highlight: { message: ['%%'] } },
+ dataViewMock,
+ ['message', 'extension', 'object.value'],
+ 220,
+ discoverServiceMock.fieldFormats
+ );
expect(formatted.map(([fieldName]) => fieldName)).toEqual([
'message',
'extension',
@@ -68,10 +68,13 @@ describe('formatHit', () => {
});
it('only limits count of pairs based on advanced setting', () => {
- (discoverServiceMock.uiSettings.get as jest.Mock).mockImplementation(
- (key) => key === MAX_DOC_FIELDS_DISPLAYED && 2
+ const formatted = formatHit(
+ hit,
+ dataViewMock,
+ ['message', 'extension', 'object.value'],
+ 2,
+ discoverServiceMock.fieldFormats
);
- const formatted = formatHit(hit, dataViewMock, ['message', 'extension', 'object.value']);
expect(formatted).toEqual([
['extension', 'formatted:png'],
['message', 'formatted:foobar'],
@@ -80,7 +83,13 @@ describe('formatHit', () => {
});
it('should not include fields not mentioned in fieldsToShow', () => {
- const formatted = formatHit(hit, dataViewMock, ['message', 'object.value']);
+ const formatted = formatHit(
+ hit,
+ dataViewMock,
+ ['message', 'object.value'],
+ 220,
+ discoverServiceMock.fieldFormats
+ );
expect(formatted).toEqual([
['message', 'formatted:foobar'],
['object.value', 'formatted:42,13'],
@@ -90,7 +99,13 @@ describe('formatHit', () => {
});
it('should filter fields based on their real name not displayName', () => {
- const formatted = formatHit(hit, dataViewMock, ['bytes']);
+ const formatted = formatHit(
+ hit,
+ dataViewMock,
+ ['bytes'],
+ 220,
+ discoverServiceMock.fieldFormats
+ );
expect(formatted).toEqual([
['bytesDisplayName', 'formatted:123'],
['_index', 'formatted:logs'],
diff --git a/src/plugins/discover/public/utils/format_hit.ts b/src/plugins/discover/public/utils/format_hit.ts
index 4a06162714a2a..4c94fd294ba3a 100644
--- a/src/plugins/discover/public/utils/format_hit.ts
+++ b/src/plugins/discover/public/utils/format_hit.ts
@@ -8,9 +8,8 @@
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import { i18n } from '@kbn/i18n';
+import { FieldFormatsStart } from '../../../field_formats/public';
import { DataView, flattenHit } from '../../../data/common';
-import { MAX_DOC_FIELDS_DISPLAYED } from '../../common';
-import { getServices } from '../kibana_services';
import { formatFieldValue } from './format_value';
const formattedHitCache = new WeakMap();
@@ -28,7 +27,9 @@ type FormattedHit = Array;
export function formatHit(
hit: estypes.SearchHit,
dataView: DataView,
- fieldsToShow: string[]
+ fieldsToShow: string[],
+ maxEntries: number,
+ fieldFormats: FieldFormatsStart
): FormattedHit {
const cached = formattedHitCache.get(hit);
if (cached) {
@@ -50,7 +51,13 @@ export function formatHit(
const displayKey = dataView.fields.getByName(key)?.displayName;
const pairs = highlights[key] ? highlightPairs : sourcePairs;
// Format the raw value using the regular field formatters for that field
- const formattedValue = formatFieldValue(val, hit, dataView, dataView.fields.getByName(key));
+ const formattedValue = formatFieldValue(
+ val,
+ hit,
+ fieldFormats,
+ dataView,
+ dataView.fields.getByName(key)
+ );
// If the field was a mapped field, we validate it against the fieldsToShow list, if not
// we always include it into the result.
if (displayKey) {
@@ -61,7 +68,6 @@ export function formatHit(
pairs.push([key, formattedValue]);
}
});
- const maxEntries = getServices().uiSettings.get(MAX_DOC_FIELDS_DISPLAYED);
const pairs = [...highlightPairs, ...sourcePairs];
const formatted =
// If document has more formatted fields than configured via MAX_DOC_FIELDS_DISPLAYED we cut
diff --git a/src/plugins/discover/public/utils/format_value.test.ts b/src/plugins/discover/public/utils/format_value.test.ts
index 4684547b7cf3e..9fbf38c21b4b7 100644
--- a/src/plugins/discover/public/utils/format_value.test.ts
+++ b/src/plugins/discover/public/utils/format_value.test.ts
@@ -6,22 +6,18 @@
* Side Public License, v 1.
*/
+import { FieldFormatsStart } from '../../../field_formats/public';
import type { FieldFormat } from '../../../field_formats/common';
import { indexPatternMock } from '../__mocks__/index_pattern';
import { formatFieldValue } from './format_value';
-import { getServices } from '../kibana_services';
-
-jest.mock('../kibana_services', () => {
- const services = {
- fieldFormats: {
- getDefaultInstance: jest.fn(
- () => ({ convert: (value: unknown) => value } as FieldFormat)
- ),
- },
- };
- return { getServices: () => services };
-});
+const services = {
+ fieldFormats: {
+ getDefaultInstance: jest.fn(
+ () => ({ convert: (value: unknown) => value } as FieldFormat)
+ ),
+ } as unknown as FieldFormatsStart,
+};
const hit = {
_id: '1',
@@ -34,7 +30,6 @@ const hit = {
describe('formatFieldValue', () => {
afterEach(() => {
(indexPatternMock.getFormatterForField as jest.Mock).mockReset();
- (getServices().fieldFormats.getDefaultInstance as jest.Mock).mockReset();
});
it('should call correct fieldFormatter for field', () => {
@@ -42,28 +37,32 @@ describe('formatFieldValue', () => {
const convertMock = jest.fn((value: unknown) => `formatted:${value}`);
formatterForFieldMock.mockReturnValue({ convert: convertMock });
const field = indexPatternMock.fields.getByName('message');
- expect(formatFieldValue('foo', hit, indexPatternMock, field)).toBe('formatted:foo');
+ expect(formatFieldValue('foo', hit, services.fieldFormats, indexPatternMock, field)).toBe(
+ 'formatted:foo'
+ );
expect(indexPatternMock.getFormatterForField).toHaveBeenCalledWith(field);
expect(convertMock).toHaveBeenCalledWith('foo', 'html', { field, hit });
});
it('should call default string formatter if no field specified', () => {
const convertMock = jest.fn((value: unknown) => `formatted:${value}`);
- (getServices().fieldFormats.getDefaultInstance as jest.Mock).mockReturnValue({
+ (services.fieldFormats.getDefaultInstance as jest.Mock).mockReturnValue({
convert: convertMock,
});
- expect(formatFieldValue('foo', hit, indexPatternMock)).toBe('formatted:foo');
- expect(getServices().fieldFormats.getDefaultInstance).toHaveBeenCalledWith('string');
+ expect(formatFieldValue('foo', hit, services.fieldFormats, indexPatternMock)).toBe(
+ 'formatted:foo'
+ );
+ expect(services.fieldFormats.getDefaultInstance).toHaveBeenCalledWith('string');
expect(convertMock).toHaveBeenCalledWith('foo', 'html', { field: undefined, hit });
});
it('should call default string formatter if no indexPattern is specified', () => {
const convertMock = jest.fn((value: unknown) => `formatted:${value}`);
- (getServices().fieldFormats.getDefaultInstance as jest.Mock).mockReturnValue({
+ (services.fieldFormats.getDefaultInstance as jest.Mock).mockReturnValue({
convert: convertMock,
});
- expect(formatFieldValue('foo', hit)).toBe('formatted:foo');
- expect(getServices().fieldFormats.getDefaultInstance).toHaveBeenCalledWith('string');
+ expect(formatFieldValue('foo', hit, services.fieldFormats)).toBe('formatted:foo');
+ expect(services.fieldFormats.getDefaultInstance).toHaveBeenCalledWith('string');
expect(convertMock).toHaveBeenCalledWith('foo', 'html', { field: undefined, hit });
});
});
diff --git a/src/plugins/discover/public/utils/format_value.ts b/src/plugins/discover/public/utils/format_value.ts
index 7a2a67b063191..432978f7fb41f 100644
--- a/src/plugins/discover/public/utils/format_value.ts
+++ b/src/plugins/discover/public/utils/format_value.ts
@@ -7,8 +7,8 @@
*/
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
+import { FieldFormatsStart } from '../../../field_formats/public';
import { DataView, DataViewField, KBN_FIELD_TYPES } from '../../../data/common';
-import { getServices } from '../kibana_services';
/**
* Formats the value of a specific field using the appropriate field formatter if available
@@ -23,14 +23,15 @@ import { getServices } from '../kibana_services';
export function formatFieldValue(
value: unknown,
hit: estypes.SearchHit,
+ fieldFormats: FieldFormatsStart,
dataView?: DataView,
field?: DataViewField
): string {
if (!dataView || !field) {
// If either no field is available or no data view, we'll use the default
// string formatter to format that field.
- return getServices()
- .fieldFormats.getDefaultInstance(KBN_FIELD_TYPES.STRING)
+ return fieldFormats
+ .getDefaultInstance(KBN_FIELD_TYPES.STRING)
.convert(value, 'html', { hit, field });
}
diff --git a/src/plugins/discover/public/utils/use_discover_services.ts b/src/plugins/discover/public/utils/use_discover_services.ts
new file mode 100644
index 0000000000000..d9a6a2d77e481
--- /dev/null
+++ b/src/plugins/discover/public/utils/use_discover_services.ts
@@ -0,0 +1,12 @@
+/*
+ * 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 { useKibana } from '../../../kibana_react/public';
+import { DiscoverServices } from '../build_services';
+
+export const useDiscoverServices = () => useKibana().services;
diff --git a/src/plugins/discover/public/utils/use_es_doc_search.test.tsx b/src/plugins/discover/public/utils/use_es_doc_search.test.tsx
index 91115f70aebf2..629a2b4d10470 100644
--- a/src/plugins/discover/public/utils/use_es_doc_search.test.tsx
+++ b/src/plugins/discover/public/utils/use_es_doc_search.test.tsx
@@ -13,27 +13,27 @@ import { DataView } from 'src/plugins/data/common';
import { DocProps } from '../application/doc/components/doc';
import { ElasticRequestState } from '../application/doc/types';
import { SEARCH_FIELDS_FROM_SOURCE as mockSearchFieldsFromSource } from '../../common';
+import { KibanaContextProvider } from '../../../kibana_react/public';
+import React from 'react';
const mockSearchResult = new Observable();
-jest.mock('../kibana_services', () => ({
- getServices: () => ({
- data: {
- search: {
- search: jest.fn(() => {
- return mockSearchResult;
- }),
- },
+const services = {
+ data: {
+ search: {
+ search: jest.fn(() => {
+ return mockSearchResult;
+ }),
},
- uiSettings: {
- get: (key: string) => {
- if (key === mockSearchFieldsFromSource) {
- return false;
- }
- },
+ },
+ uiSettings: {
+ get: (key: string) => {
+ if (key === mockSearchFieldsFromSource) {
+ return false;
+ }
},
- }),
-}));
+ },
+};
describe('Test of helper / hook', () => {
test('buildSearchBody given useNewFieldsApi is false', () => {
@@ -181,7 +181,12 @@ describe('Test of helper / hook', () => {
indexPattern,
} as unknown as DocProps;
- const { result } = renderHook((p: DocProps) => useEsDocSearch(p), { initialProps: props });
+ const { result } = renderHook((p: DocProps) => useEsDocSearch(p), {
+ initialProps: props,
+ wrapper: ({ children }) => (
+ {children}
+ ),
+ });
expect(result.current.slice(0, 2)).toEqual([ElasticRequestState.Loading, null]);
});
diff --git a/src/plugins/discover/public/utils/use_es_doc_search.ts b/src/plugins/discover/public/utils/use_es_doc_search.ts
index 1c8fd2f77888e..ac94fccdd3e12 100644
--- a/src/plugins/discover/public/utils/use_es_doc_search.ts
+++ b/src/plugins/discover/public/utils/use_es_doc_search.ts
@@ -11,9 +11,9 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import { DataView } from '../../../data/common';
import { DocProps } from '../application/doc/components/doc';
import { ElasticRequestState } from '../application/doc/types';
-import { getServices } from '../kibana_services';
import { SEARCH_FIELDS_FROM_SOURCE } from '../../common';
import { ElasticSearchHit } from '../types';
+import { useDiscoverServices } from './use_discover_services';
type RequestBody = Pick;
@@ -69,7 +69,7 @@ export function useEsDocSearch({
}: DocProps): [ElasticRequestState, ElasticSearchHit | null, () => void] {
const [status, setStatus] = useState(ElasticRequestState.Loading);
const [hit, setHit] = useState(null);
- const { data, uiSettings } = useMemo(() => getServices(), []);
+ const { data, uiSettings } = useDiscoverServices();
const useNewFieldsApi = useMemo(() => !uiSettings.get(SEARCH_FIELDS_FROM_SOURCE), [uiSettings]);
const requestData = useCallback(async () => {
diff --git a/src/plugins/discover/public/utils/use_navigation_props.test.tsx b/src/plugins/discover/public/utils/use_navigation_props.test.tsx
index 29d4976f265c3..de1f1dbcc9b01 100644
--- a/src/plugins/discover/public/utils/use_navigation_props.test.tsx
+++ b/src/plugins/discover/public/utils/use_navigation_props.test.tsx
@@ -17,8 +17,7 @@ import {
} from './use_navigation_props';
import { Router } from 'react-router-dom';
import { createMemoryHistory } from 'history';
-import { setServices } from '../kibana_services';
-import { DiscoverServices } from '../build_services';
+import { KibanaContextProvider } from '../../../kibana_react/public';
const filterManager = createFilterManagerMock();
const defaultProps = {
@@ -45,16 +44,17 @@ const getContextRoute = () => {
return `/context/${defaultProps.indexPatternId}/${defaultProps.rowId}`;
};
-const render = () => {
+const render = (withRouter = true, props?: Partial) => {
const history = createMemoryHistory({
initialEntries: ['/' + getSearch()],
});
- setServices({ history: () => history } as unknown as DiscoverServices);
const wrapper = ({ children }: { children: ReactElement }) => (
- {children}
+ history }}>
+ {withRouter ? {children} : children}
+
);
return {
- result: renderHook(() => useNavigationProps(defaultProps), { wrapper }).result,
+ result: renderHook(() => useNavigationProps({ ...defaultProps, ...props }), { wrapper }).result,
history,
};
};
@@ -81,12 +81,7 @@ describe('useNavigationProps', () => {
});
test('should create valid links to the context and single doc pages from embeddable', () => {
- const { result } = renderHook(() =>
- useNavigationProps({
- ...defaultProps,
- addBasePath: (val: string) => `${basePathPrefix}${val}`,
- })
- );
+ const { result } = render(false, { addBasePath: (val: string) => `${basePathPrefix}${val}` });
expect(result.current.singleDocProps.href!).toEqual(
`${basePathPrefix}/app/discover#${getSingeDocRoute()}?id=${defaultProps.rowId}`
diff --git a/src/plugins/discover/public/utils/use_navigation_props.tsx b/src/plugins/discover/public/utils/use_navigation_props.tsx
index 6f1dedf75e730..963499c4cad57 100644
--- a/src/plugins/discover/public/utils/use_navigation_props.tsx
+++ b/src/plugins/discover/public/utils/use_navigation_props.tsx
@@ -8,11 +8,12 @@
import { useMemo, useRef } from 'react';
import { useHistory, matchPath } from 'react-router-dom';
+import type { Location } from 'history';
import { stringify } from 'query-string';
import rison from 'rison-node';
import { esFilters, FilterManager } from '../../../data/public';
import { url } from '../../../kibana_utils/common';
-import { getServices } from '../kibana_services';
+import { useDiscoverServices } from './use_discover_services';
export type DiscoverNavigationProps = { onClick: () => void } | { href: string };
@@ -53,12 +54,13 @@ export const getContextHash = (columns: string[], filterManager: FilterManager)
* Current history object should be used in callback, since url state might be changed
* after expanded document opened.
*/
-const getCurrentBreadcrumbs = (isContextRoute: boolean, prevBreadcrumb?: string) => {
- const { history: getHistory } = getServices();
- const currentHistory = getHistory();
- return isContextRoute
- ? prevBreadcrumb
- : '#' + currentHistory?.location.pathname + currentHistory?.location.search;
+
+const getCurrentBreadcrumbs = (
+ isContextRoute: boolean,
+ currentLocation: Location,
+ prevBreadcrumb?: string
+) => {
+ return isContextRoute ? prevBreadcrumb : '#' + currentLocation.pathname + currentLocation.search;
};
export const useMainRouteBreadcrumb = () => {
@@ -75,6 +77,8 @@ export const useNavigationProps = ({
addBasePath,
}: UseNavigationProps) => {
const history = useHistory();
+ const currentLocation = useDiscoverServices().history().location;
+
const prevBreadcrumb = useRef(history?.location.state?.breadcrumb).current;
const contextSearchHash = useMemo(
() => getContextHash(columns, filterManager),
@@ -95,7 +99,9 @@ export const useNavigationProps = ({
history.push({
pathname: `/doc/${indexPatternId}/${rowIndex}`,
search: `?id=${encodeURIComponent(rowId)}`,
- state: { breadcrumb: getCurrentBreadcrumbs(!!isContextRoute, prevBreadcrumb) },
+ state: {
+ breadcrumb: getCurrentBreadcrumbs(!!isContextRoute, currentLocation, prevBreadcrumb),
+ },
});
};
@@ -105,7 +111,9 @@ export const useNavigationProps = ({
String(rowId)
)}`,
search: `?${contextSearchHash}`,
- state: { breadcrumb: getCurrentBreadcrumbs(!!isContextRoute, prevBreadcrumb) },
+ state: {
+ breadcrumb: getCurrentBreadcrumbs(!!isContextRoute, currentLocation, prevBreadcrumb),
+ },
});
return {
diff --git a/src/plugins/discover/public/utils/with_query_params.test.tsx b/src/plugins/discover/public/utils/with_query_params.test.tsx
index d897c3327a06f..3d416d6a3e8b5 100644
--- a/src/plugins/discover/public/utils/with_query_params.test.tsx
+++ b/src/plugins/discover/public/utils/with_query_params.test.tsx
@@ -11,13 +11,6 @@ import { Router } from 'react-router-dom';
import { createMemoryHistory } from 'history';
import { mountWithIntl } from '@kbn/test/jest';
import { withQueryParams } from './with_query_params';
-import { DiscoverServices } from '../build_services';
-import { DiscoverRouteProps } from '../application/types';
-
-interface ComponentProps extends DiscoverRouteProps {
- id: string;
- query: string;
-}
const mountComponent = (children: ReactElement, query = '') => {
const history = createMemoryHistory({
@@ -29,27 +22,16 @@ const mountComponent = (children: ReactElement, query = '') => {
describe('withQueryParams', () => {
it('should display error message, when query does not contain required parameters', () => {
const Component = withQueryParams(() => , ['id', 'query']);
- const component = mountComponent();
+ const component = mountComponent();
expect(component.html()).toContain('Cannot load this page');
expect(component.html()).toContain('URL query string is missing id, query.');
});
it('should not display error message, when query contain required parameters', () => {
- const Component = withQueryParams(
- ({ id, query }: ComponentProps) => (
-
- {id} and {query} are presented
-
- ),
- ['id', 'query']
- );
- const component = mountComponent(
- ,
- '?id=one&query=another'
- );
+ const Component = withQueryParams(() => , ['id', 'query']);
+ const component = mountComponent(, '?id=one&query=another');
- expect(component.html()).toContain('one and another are presented');
expect(component.html()).not.toContain('URL query string is missing id, query.');
});
});
diff --git a/src/plugins/discover/public/utils/with_query_params.tsx b/src/plugins/discover/public/utils/with_query_params.tsx
index 66f0dd72c64de..159ba6740cf64 100644
--- a/src/plugins/discover/public/utils/with_query_params.tsx
+++ b/src/plugins/discover/public/utils/with_query_params.tsx
@@ -9,20 +9,12 @@
import React, { useMemo } from 'react';
import { i18n } from '@kbn/i18n';
import { useLocation } from 'react-router-dom';
-import { DiscoverRouteProps } from '../application/types';
import { DiscoverError } from '../components/common/error_alert';
-function useQuery() {
- const { search } = useLocation();
- return useMemo(() => new URLSearchParams(search), [search]);
-}
-
-export const withQueryParams = (
- Component: React.ComponentType
,
- requiredParams: string[]
-) => {
- return (routeProps: DiscoverRouteProps) => {
- const query = useQuery();
+export function withQueryParams(Component: React.ComponentType, requiredParams: string[]) {
+ return () => {
+ const { search } = useLocation();
+ const query = useMemo(() => new URLSearchParams(search), [search]);
const missingParamNames = useMemo(
() => requiredParams.filter((currentParamName) => !query.get(currentParamName)),
@@ -42,6 +34,6 @@ export const withQueryParams = (
const queryProps = Object.fromEntries(
requiredParams.map((current) => [[current], query.get(current)])
);
- return ;
+ return ;
};
-};
+}