diff --git a/changelogs/fragments/8837.yml b/changelogs/fragments/8837.yml new file mode 100644 index 000000000000..c5960bec454e --- /dev/null +++ b/changelogs/fragments/8837.yml @@ -0,0 +1,5 @@ +fix: +- Fix a typo while inspecting values for large numerals in OSD and the JS client ([#8837](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/8837)) + +feat: +- Add setting to turn extending numeric precision on or off ([#8837](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/8837)) \ No newline at end of file diff --git a/src/plugins/console/opensearch_dashboards.json b/src/plugins/console/opensearch_dashboards.json index 630eb58a6de7..944b49645b9e 100644 --- a/src/plugins/console/opensearch_dashboards.json +++ b/src/plugins/console/opensearch_dashboards.json @@ -3,7 +3,7 @@ "version": "opensearchDashboards", "server": true, "ui": true, - "requiredPlugins": ["devTools"], + "requiredPlugins": ["devTools", "data"], "optionalPlugins": ["usageCollection", "home", "dataSource"], "requiredBundles": [ "opensearchUiShared", diff --git a/src/plugins/console/public/application/hooks/use_send_current_request_to_opensearch/send_request_to_opensearch.test.ts b/src/plugins/console/public/application/hooks/use_send_current_request_to_opensearch/send_request_to_opensearch.test.ts index 47a73e4af98a..2e6a291b83a3 100644 --- a/src/plugins/console/public/application/hooks/use_send_current_request_to_opensearch/send_request_to_opensearch.test.ts +++ b/src/plugins/console/public/application/hooks/use_send_current_request_to_opensearch/send_request_to_opensearch.test.ts @@ -31,6 +31,10 @@ const dummyArgs: OpenSearchRequestArgs = { }; describe('test sendRequestToOpenSearch', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + it('test request success, json', () => { const mockHttpResponse = createMockHttpResponse( 200, @@ -47,9 +51,9 @@ describe('test sendRequestToOpenSearch', () => { }); }); - it('test request success, json with long numerals', () => { - const longPositive = BigInt(Number.MAX_SAFE_INTEGER) * 2n; - const longNegative = BigInt(Number.MIN_SAFE_INTEGER) * 2n; + it('test request success, json with long numerals when precision enabled', () => { + const longPositive = BigInt(Number.MAX_SAFE_INTEGER) * 2n + 1n; + const longNegative = BigInt(Number.MIN_SAFE_INTEGER) * 2n + 1n; const mockHttpResponse = createMockHttpResponse( 200, 'ok', @@ -60,14 +64,59 @@ describe('test sendRequestToOpenSearch', () => { } ); - jest.spyOn(opensearch, 'send').mockResolvedValue(mockHttpResponse); - sendRequestToOpenSearch(dummyArgs).then((result) => { + const send = jest.spyOn(opensearch, 'send'); + send.mockResolvedValue(mockHttpResponse); + sendRequestToOpenSearch({ + ...dummyArgs, + withLongNumeralsSupport: true, + }).then((result) => { + expect(send).toHaveBeenCalledWith( + expect.anything(), + dummyArgs.requests[0].method, + dummyArgs.requests[0].url, + dummyArgs.requests[0].data.join('\n') + '\n', + undefined, + true + ); const value = (result as any)[0].response.value; expect(value).toMatch(new RegExp(`"long-max": ${longPositive}[,\n]`)); expect(value).toMatch(new RegExp(`"long-min": ${longNegative}[,\n]`)); }); }); + it('test request success, json with long numerals when precision disabled', () => { + const longPositive = BigInt(Number.MAX_SAFE_INTEGER) * 2n + 1n; + const longNegative = BigInt(Number.MIN_SAFE_INTEGER) * 2n + 1n; + const mockHttpResponse = createMockHttpResponse( + 200, + 'ok', + [['Content-Type', 'application/json, utf-8']], + { + 'long-max': Number(longPositive), + 'long-min': Number(longNegative), + } + ); + + const send = jest.spyOn(opensearch, 'send'); + send.mockResolvedValue(mockHttpResponse); + sendRequestToOpenSearch({ + ...dummyArgs, + withLongNumeralsSupport: false, + }).then((result) => { + expect(send).toHaveBeenCalledWith( + expect.anything(), + dummyArgs.requests[0].method, + dummyArgs.requests[0].url, + dummyArgs.requests[0].data.join('\n') + '\n', + undefined, + false + ); + const value = (result as any)[0].response.value; + expect(value).toMatch(new RegExp(`"long-max": ${Number(longPositive)}[,\n]`)); + expect(value).toMatch(new RegExp(`"long-min": ${Number(longNegative)}[,\n]`)); + }); + }); + it('test request success, text', () => { const mockHttpResponse = createMockHttpResponse( 200, diff --git a/src/plugins/console/public/application/hooks/use_send_current_request_to_opensearch/send_request_to_opensearch.ts b/src/plugins/console/public/application/hooks/use_send_current_request_to_opensearch/send_request_to_opensearch.ts index 1cb992a7a99c..415d9dcbcf43 100644 --- a/src/plugins/console/public/application/hooks/use_send_current_request_to_opensearch/send_request_to_opensearch.ts +++ b/src/plugins/console/public/application/hooks/use_send_current_request_to_opensearch/send_request_to_opensearch.ts @@ -41,6 +41,7 @@ export interface OpenSearchRequestArgs { http: HttpSetup; requests: any; dataSourceId?: string; + withLongNumeralsSupport?: boolean; } export interface OpenSearchRequestObject { @@ -104,7 +105,8 @@ export function sendRequestToOpenSearch( opensearchMethod, opensearchPath, opensearchData, - args.dataSourceId + args.dataSourceId, + args.withLongNumeralsSupport ); if (reqId !== CURRENT_REQ_ID) { return; diff --git a/src/plugins/console/public/application/hooks/use_send_current_request_to_opensearch/use_send_current_request_to_opensearch.test.tsx b/src/plugins/console/public/application/hooks/use_send_current_request_to_opensearch/use_send_current_request_to_opensearch.test.tsx index 8955972d27a0..1a272652b6dc 100644 --- a/src/plugins/console/public/application/hooks/use_send_current_request_to_opensearch/use_send_current_request_to_opensearch.test.tsx +++ b/src/plugins/console/public/application/hooks/use_send_current_request_to_opensearch/use_send_current_request_to_opensearch.test.tsx @@ -28,6 +28,8 @@ * under the License. */ +import { UI_SETTINGS } from '../../../../../data/common'; + jest.mock('./send_request_to_opensearch', () => ({ sendRequestToOpenSearch: jest.fn() })); jest.mock('../../contexts/editor_context/editor_registry', () => ({ instance: { getInputEditor: jest.fn() }, @@ -74,9 +76,63 @@ describe('useSendCurrentRequestToOpenSearch', () => { const { result } = renderHook(() => useSendCurrentRequestToOpenSearch(), { wrapper: contexts }); await act(() => result.current()); + + expect(sendRequestToOpenSearch).toHaveBeenCalledWith({ + requests: ['test'], + http: mockContextValue.services.http, + }); + + // Second call should be the request success + const [, [requestSucceededCall]] = (dispatch as jest.Mock).mock.calls; + expect(requestSucceededCall).toEqual({ type: 'requestSuccess', payload: { data: [] } }); + }); + + it('calls sendRequestToOpenSearch turning withLongNumeralsSupport on when long-numerals is enabled', async () => { + // Set up mocks + (mockContextValue.services.settings.toJSON as jest.Mock).mockReturnValue({}); + (mockContextValue.services.uiSettings.get as jest.Mock).mockImplementation((key: string) => + Promise.resolve(key === UI_SETTINGS.DATA_WITH_LONG_NUMERALS ? true : undefined) + ); + + // This request should succeed + (sendRequestToOpenSearch as jest.Mock).mockResolvedValue([]); + (editorRegistry.getInputEditor as jest.Mock).mockImplementation(() => ({ + getRequestsInRange: () => ['test'], + })); + + const { result } = renderHook(() => useSendCurrentRequestToOpenSearch(), { wrapper: contexts }); + await act(() => result.current()); + expect(sendRequestToOpenSearch).toHaveBeenCalledWith({ + requests: ['test'], + http: mockContextValue.services.http, + withLongNumeralsSupport: true, + }); + + // Second call should be the request success + const [, [requestSucceededCall]] = (dispatch as jest.Mock).mock.calls; + expect(requestSucceededCall).toEqual({ type: 'requestSuccess', payload: { data: [] } }); + }); + + it('calls sendRequestToOpenSearch turning withLongNumeralsSupport off when long-numerals is disabled', async () => { + // Set up mocks + (mockContextValue.services.settings.toJSON as jest.Mock).mockReturnValue({}); + (mockContextValue.services.uiSettings.get as jest.Mock).mockImplementation((key: string) => + Promise.resolve(key === UI_SETTINGS.DATA_WITH_LONG_NUMERALS ? false : undefined) + ); + + // This request should succeed + (sendRequestToOpenSearch as jest.Mock).mockResolvedValue([]); + (editorRegistry.getInputEditor as jest.Mock).mockImplementation(() => ({ + getRequestsInRange: () => ['test'], + })); + + const { result } = renderHook(() => useSendCurrentRequestToOpenSearch(), { wrapper: contexts }); + await act(() => result.current()); + expect(sendRequestToOpenSearch).toHaveBeenCalledWith({ requests: ['test'], http: mockContextValue.services.http, + withLongNumeralsSupport: false, }); // Second call should be the request success diff --git a/src/plugins/console/public/application/hooks/use_send_current_request_to_opensearch/use_send_current_request_to_opensearch.ts b/src/plugins/console/public/application/hooks/use_send_current_request_to_opensearch/use_send_current_request_to_opensearch.ts index 81eabdf7a264..6e179276a888 100644 --- a/src/plugins/console/public/application/hooks/use_send_current_request_to_opensearch/use_send_current_request_to_opensearch.ts +++ b/src/plugins/console/public/application/hooks/use_send_current_request_to_opensearch/use_send_current_request_to_opensearch.ts @@ -37,10 +37,11 @@ import { track } from './track'; // @ts-ignore import { retrieveAutoCompleteInfo } from '../../../lib/mappings/mappings'; +import { UI_SETTINGS } from '../../../../../data/common'; export const useSendCurrentRequestToOpenSearch = (dataSourceId?: string) => { const { - services: { history, settings, notifications, trackUiMetric, http }, + services: { history, settings, notifications, trackUiMetric, http, uiSettings }, } = useServicesContext(); const dispatch = useRequestActionContext(); @@ -64,7 +65,14 @@ export const useSendCurrentRequestToOpenSearch = (dataSourceId?: string) => { // Fire and forget setTimeout(() => track(requests, editor, trackUiMetric), 0); - const results = await sendRequestToOpenSearch({ http, requests, dataSourceId }); + const withLongNumeralsSupport = await uiSettings.get(UI_SETTINGS.DATA_WITH_LONG_NUMERALS); + + const results = await sendRequestToOpenSearch({ + http, + requests, + dataSourceId, + withLongNumeralsSupport, + }); results.forEach(({ request: { path, method, data } }) => { try { @@ -112,5 +120,14 @@ export const useSendCurrentRequestToOpenSearch = (dataSourceId?: string) => { }); } } - }, [dispatch, http, dataSourceId, settings, notifications.toasts, trackUiMetric, history]); + }, [ + dispatch, + http, + dataSourceId, + settings, + notifications.toasts, + trackUiMetric, + history, + uiSettings, + ]); }; diff --git a/src/plugins/console/public/lib/opensearch/opensearch.ts b/src/plugins/console/public/lib/opensearch/opensearch.ts index 907323611358..e0d2163b4af4 100644 --- a/src/plugins/console/public/lib/opensearch/opensearch.ts +++ b/src/plugins/console/public/lib/opensearch/opensearch.ts @@ -46,7 +46,8 @@ export async function send( method: string, path: string, data: any, - dataSourceId?: string + dataSourceId?: string, + withLongNumeralsSupport?: boolean ): Promise { return await http.post('/api/console/proxy', { query: { @@ -57,7 +58,7 @@ export async function send( body: data, prependBasePath: true, asResponse: true, - withLongNumeralsSupport: true, + withLongNumeralsSupport, }); } diff --git a/src/plugins/data/common/constants.ts b/src/plugins/data/common/constants.ts index 65d144531fce..9951eb6cc18e 100644 --- a/src/plugins/data/common/constants.ts +++ b/src/plugins/data/common/constants.ts @@ -108,4 +108,5 @@ export const UI_SETTINGS = { QUERY_DATAFRAME_HYDRATION_STRATEGY: 'query:dataframe:hydrationStrategy', SEARCH_QUERY_LANGUAGE_BLOCKLIST: 'search:queryLanguageBlocklist', NEW_HOME_PAGE: 'home:useNewHomePage', + DATA_WITH_LONG_NUMERALS: 'data:withLongNumerals', } as const; diff --git a/src/plugins/data/common/index_patterns/index_patterns/index_patterns.test.ts b/src/plugins/data/common/index_patterns/index_patterns/index_patterns.test.ts index 4361e12dec16..eb14671992dd 100644 --- a/src/plugins/data/common/index_patterns/index_patterns/index_patterns.test.ts +++ b/src/plugins/data/common/index_patterns/index_patterns/index_patterns.test.ts @@ -33,6 +33,7 @@ import { IndexPatternsService, IndexPattern } from '.'; import { fieldFormatsMock } from '../../field_formats/mocks'; import { stubbedSavedObjectIndexPattern } from '../../../../../fixtures/stubbed_saved_object_index_pattern'; import { UiSettingsCommon, SavedObjectsClientCommon, SavedObject } from '../types'; +import { UI_SETTINGS } from '../../constants'; const createFieldsFetcher = jest.fn().mockImplementation(() => ({ getFieldsForWildcard: jest.fn().mockImplementation(() => { @@ -51,6 +52,7 @@ function setDocsourcePayload(id: string | null, providedPayload: any) { describe('IndexPatterns', () => { let indexPatterns: IndexPatternsService; let savedObjectsClient: SavedObjectsClientCommon; + const uiSettingsGet = jest.fn(); beforeEach(() => { const indexPatternObj = { id: 'id', version: 'a', attributes: { title: 'title' } }; @@ -83,9 +85,12 @@ describe('IndexPatterns', () => { }; }); + uiSettingsGet.mockClear(); + uiSettingsGet.mockReturnValue(Promise.resolve(false)); + indexPatterns = new IndexPatternsService({ uiSettings: ({ - get: () => Promise.resolve(false), + get: uiSettingsGet, getAll: () => {}, } as any) as UiSettingsCommon, savedObjectsClient: (savedObjectsClient as unknown) as SavedObjectsClientCommon, @@ -249,4 +254,13 @@ describe('IndexPatterns', () => { expect(indexPatterns.savedObjectToSpec(savedObject)).toMatchSnapshot(); }); + + test('correctly detects long-numerals support', async () => { + expect(await indexPatterns.isLongNumeralsSupported()).toBe(false); + + uiSettingsGet.mockImplementation((key: string) => + Promise.resolve(key === UI_SETTINGS.DATA_WITH_LONG_NUMERALS ? true : undefined) + ); + expect(await indexPatterns.isLongNumeralsSupported()).toBe(true); + }); }); diff --git a/src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts b/src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts index b58b8c01b56c..1919ed2cd429 100644 --- a/src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts +++ b/src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts @@ -747,6 +747,10 @@ export class IndexPatternsService { indexPatternCache.clear(indexPatternId); return this.savedObjectsClient.delete('index-pattern', indexPatternId); } + + isLongNumeralsSupported() { + return this.config.get(UI_SETTINGS.DATA_WITH_LONG_NUMERALS); + } } export type IndexPatternsContract = PublicMethodsOf; diff --git a/src/plugins/data/server/ui_settings.ts b/src/plugins/data/server/ui_settings.ts index e5da0986290d..13cee79cb450 100644 --- a/src/plugins/data/server/ui_settings.ts +++ b/src/plugins/data/server/ui_settings.ts @@ -535,6 +535,17 @@ export function getUiSettings( }), schema: schema.string(), }, + [UI_SETTINGS.DATA_WITH_LONG_NUMERALS]: { + name: i18n.translate('data.advancedSettings.data.withLongNumeralsTitle', { + defaultMessage: 'Extend Numeric Precision', + }), + value: true, + description: i18n.translate('data.advancedSettings.data.withLongNumeralsText', { + defaultMessage: + "Turn on for precise handling of extremely large numbers. Turn off to optimize performance when high precision for large values isn't required.", + }), + schema: schema.boolean(), + }, [UI_SETTINGS.TIMEPICKER_REFRESH_INTERVAL_DEFAULTS]: { name: i18n.translate('data.advancedSettings.timepicker.refreshIntervalDefaultsTitle', { defaultMessage: 'Time filter refresh interval', diff --git a/src/plugins/discover/public/application/components/doc/doc.test.tsx b/src/plugins/discover/public/application/components/doc/doc.test.tsx index 4a3fb740492a..50bc71012721 100644 --- a/src/plugins/discover/public/application/components/doc/doc.test.tsx +++ b/src/plugins/discover/public/application/components/doc/doc.test.tsx @@ -96,6 +96,7 @@ async function mountDoc(update = false, indexPatternGetter: any = null) { }; const indexPatternService = { get: indexPatternGetter ? indexPatternGetter : jest.fn(() => Promise.resolve(indexPattern)), + isLongNumeralsSupported: jest.fn(), } as any; const props = { diff --git a/src/plugins/discover/public/application/components/doc/use_opensearch_doc_search.test.tsx b/src/plugins/discover/public/application/components/doc/use_opensearch_doc_search.test.tsx index cb716a4f17cb..e3377e900d73 100644 --- a/src/plugins/discover/public/application/components/doc/use_opensearch_doc_search.test.tsx +++ b/src/plugins/discover/public/application/components/doc/use_opensearch_doc_search.test.tsx @@ -38,20 +38,30 @@ import { DocProps } from './doc'; import { Observable } from 'rxjs'; const mockSearchResult = new Observable(); +const mockDataSearchSearch = jest.fn(() => { + return mockSearchResult; +}); jest.mock('../../../opensearch_dashboards_services', () => ({ getServices: () => ({ data: { search: { - search: jest.fn(() => { - return mockSearchResult; - }), + search: mockDataSearchSearch, }, }, }), })); +const mockIndexPatternService = { + get: jest.fn(), + isLongNumeralsSupported: jest.fn(), +} as any; + describe('Test of helper / hook', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + test('buildSearchBody', () => { const indexPattern = { getComputedFields: () => ({ storedFields: [], scriptFields: [], docvalueFields: [] }), @@ -78,21 +88,69 @@ describe('Test of helper / hook', () => { const indexPattern = { getComputedFields: () => [], }; - const indexPatternService = { - get: jest.fn(() => Promise.resolve(indexPattern)), - } as any; + (mockIndexPatternService.get as jest.Mock).mockResolvedValue(indexPattern); + const props = { id: '1', index: 'index1', indexPatternId: 'xyz', - indexPatternService, + indexPatternService: mockIndexPatternService, } as DocProps; let hook; await act(async () => { hook = renderHook((p: DocProps) => useOpenSearchDocSearch(p), { initialProps: props }); }); + // @ts-ignore expect(hook.result.current).toEqual([OpenSearchRequestState.Loading, null, indexPattern]); - expect(indexPatternService.get).toHaveBeenCalled(); + expect(mockIndexPatternService.get).toHaveBeenCalled(); + }); + + test('useOpenSearchDocSearch using withLongNumeralsSupport when configured to', async () => { + (mockIndexPatternService.isLongNumeralsSupported as jest.Mock).mockReturnValue( + Promise.resolve(true) + ); + + const props = { + id: '1', + index: 'index1', + indexPatternId: 'xyz', + indexPatternService: mockIndexPatternService, + } as DocProps; + + await act(async () => { + renderHook((p: DocProps) => useOpenSearchDocSearch(p), { initialProps: props }); + }); + + expect(mockDataSearchSearch).toHaveBeenCalledWith( + expect.anything(), + expect.objectContaining({ + withLongNumeralsSupport: true, + }) + ); + }); + + test('useOpenSearchDocSearch without withLongNumeralsSupport when configured not to', async () => { + (mockIndexPatternService.isLongNumeralsSupported as jest.Mock).mockReturnValue( + Promise.resolve(false) + ); + + const props = { + id: '1', + index: 'index1', + indexPatternId: 'xyz', + indexPatternService: mockIndexPatternService, + } as DocProps; + + await act(async () => { + renderHook((p: DocProps) => useOpenSearchDocSearch(p), { initialProps: props }); + }); + + expect(mockDataSearchSearch).toHaveBeenCalledWith( + expect.anything(), + expect.objectContaining({ + withLongNumeralsSupport: false, + }) + ); }); }); diff --git a/src/plugins/discover/public/application/components/doc/use_opensearch_doc_search.ts b/src/plugins/discover/public/application/components/doc/use_opensearch_doc_search.ts index 4389485a3a77..ed06c0f4abce 100644 --- a/src/plugins/discover/public/application/components/doc/use_opensearch_doc_search.ts +++ b/src/plugins/discover/public/application/components/doc/use_opensearch_doc_search.ts @@ -77,6 +77,7 @@ export function useOpenSearchDocSearch({ useEffect(() => { async function requestData() { try { + const withLongNumeralsSupport = await indexPatternService.isLongNumeralsSupported(); const indexPatternEntity = await indexPatternService.get(indexPatternId); setIndexPattern(indexPatternEntity); @@ -90,7 +91,7 @@ export function useOpenSearchDocSearch({ }, }, { - withLongNumeralsSupport: true, + withLongNumeralsSupport, } ) .toPromise(); diff --git a/src/plugins/discover/public/application/view_components/utils/use_search.test.tsx b/src/plugins/discover/public/application/view_components/utils/use_search.test.tsx index f5021b90c1e7..62153bb064fc 100644 --- a/src/plugins/discover/public/application/view_components/utils/use_search.test.tsx +++ b/src/plugins/discover/public/application/view_components/utils/use_search.test.tsx @@ -13,9 +13,14 @@ import { createDataExplorerServicesMock } from '../../../../../data_explorer/pub import { DiscoverViewServices } from '../../../build_services'; import { discoverPluginMock } from '../../../mocks'; import { ResultStatus, useSearch } from './use_search'; +import { ISearchSource, UI_SETTINGS } from '../../../../../data/common'; jest.mock('./use_index_pattern', () => ({ - useIndexPattern: jest.fn(), + useIndexPattern: jest.fn().mockReturnValue(true), +})); + +jest.mock('../../helpers/validate_time_range', () => ({ + validateTimeRange: jest.fn().mockReturnValue(true), })); const mockQuery = { @@ -58,6 +63,10 @@ const mockSavedSearchEmptyQuery = { getOpenSearchType: jest.fn(), }; +jest.mock('./update_search_source', () => ({ + updateSearchSource: ({ searchSource }: { searchSource?: ISearchSource }) => searchSource, +})); + const createMockServices = (): DiscoverViewServices => { const dataExplorerServicesMock = createDataExplorerServicesMock(); const discoverServicesMock = discoverPluginMock.createDiscoverServicesMock(); @@ -187,7 +196,10 @@ describe('useSearch', () => { const initialStartTime = result.current.data$.getValue().queryStatus?.startTime; expect(initialStartTime).toBeDefined(); - rerender(); + act(() => { + rerender(); + }); + const newStartTime = result.current.data$.getValue().queryStatus?.startTime; expect(newStartTime).toBeDefined(); expect(newStartTime).not.toEqual(initialStartTime); @@ -272,4 +284,80 @@ describe('useSearch', () => { expect(services.data.query.queryString.setQuery).toBeCalledWith(mockDefaultQuery); }); + + it('should call fetch without long numerals support when configured not to', async () => { + const services = createMockServices(); + (services.uiSettings.get as jest.Mock).mockImplementation((key) => + Promise.resolve(key === UI_SETTINGS.DATA_WITH_LONG_NUMERALS ? false : undefined) + ); + + const mockDatasetUpdates$ = new Subject(); + services.data.query.queryString.getUpdates$ = jest.fn().mockReturnValue(mockDatasetUpdates$); + + const { waitForNextUpdate } = renderHook(() => useSearch(services), { + wrapper, + }); + + await act(async () => { + await waitForNextUpdate(); + }); + + act(() => { + mockDatasetUpdates$.next({ + dataset: { id: 'new-dataset-id', title: 'New Dataset', type: 'INDEX_PATTERN' }, + }); + }); + + await act(async () => { + try { + await waitForNextUpdate({ timeout: 1000 }); + } catch (_) { + // Do nothing. + } + }); + + expect(mockSavedSearch.searchSource.fetch).toHaveBeenCalledWith( + expect.objectContaining({ + withLongNumeralsSupport: false, + }) + ); + }); + + it('should call fetch with long numerals support when configured to', async () => { + const services = createMockServices(); + (services.uiSettings.get as jest.Mock).mockImplementation((key) => + Promise.resolve(key === UI_SETTINGS.DATA_WITH_LONG_NUMERALS ? true : undefined) + ); + + const mockDatasetUpdates$ = new Subject(); + services.data.query.queryString.getUpdates$ = jest.fn().mockReturnValue(mockDatasetUpdates$); + + const { waitForNextUpdate } = renderHook(() => useSearch(services), { + wrapper, + }); + + await act(async () => { + await waitForNextUpdate(); + }); + + act(() => { + mockDatasetUpdates$.next({ + dataset: { id: 'new-dataset-id', title: 'New Dataset', type: 'INDEX_PATTERN' }, + }); + }); + + await act(async () => { + try { + await waitForNextUpdate({ timeout: 1000 }); + } catch (_) { + // Do nothing. + } + }); + + expect(mockSavedSearch.searchSource.fetch).toHaveBeenCalledWith( + expect.objectContaining({ + withLongNumeralsSupport: true, + }) + ); + }); }); diff --git a/src/plugins/discover/public/application/view_components/utils/use_search.ts b/src/plugins/discover/public/application/view_components/utils/use_search.ts index 7923f0e717c2..9acb3e0e9d5f 100644 --- a/src/plugins/discover/public/application/view_components/utils/use_search.ts +++ b/src/plugins/discover/public/application/view_components/utils/use_search.ts @@ -13,7 +13,7 @@ import { useLocation } from 'react-router-dom'; import { useEffectOnce } from 'react-use'; import { RequestAdapter } from '../../../../../inspector/public'; import { DiscoverViewServices } from '../../../build_services'; -import { search } from '../../../../../data/public'; +import { search, UI_SETTINGS } from '../../../../../data/public'; import { validateTimeRange } from '../../helpers/validate_time_range'; import { updateSearchSource } from './update_search_source'; import { useIndexPattern } from './use_index_pattern'; @@ -246,7 +246,7 @@ export const useSearch = (services: DiscoverViewServices) => { // Execute the search const fetchResp = await searchSource.fetch({ abortSignal: fetchStateRef.current.abortController.signal, - withLongNumeralsSupport: true, + withLongNumeralsSupport: await services.uiSettings.get(UI_SETTINGS.DATA_WITH_LONG_NUMERALS), }); inspectorRequest @@ -353,11 +353,13 @@ export const useSearch = (services: DiscoverViewServices) => { timefilter.getAutoRefreshFetch$(), data.query.queryString.getUpdates$() ).pipe(debounceTime(100)); + const subscription = fetch$.subscribe(() => { if (skipInitialFetch.current) { skipInitialFetch.current = false; // Reset so future fetches will proceed normally return; // Skip the first fetch } + (async () => { try { await fetch();