diff --git a/changelogs/fragments/8166.yml b/changelogs/fragments/8166.yml new file mode 100644 index 000000000000..4a74935df5ef --- /dev/null +++ b/changelogs/fragments/8166.yml @@ -0,0 +1,2 @@ +fix: +- Fixes UI issues in Discover and data configurator ([#8166](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/8166)) \ No newline at end of file diff --git a/src/plugins/dashboard/public/application/components/dashboard_top_nav/__snapshots__/dashboard_top_nav.test.tsx.snap b/src/plugins/dashboard/public/application/components/dashboard_top_nav/__snapshots__/dashboard_top_nav.test.tsx.snap index 01c2616bf0ea..df0e5af66a0b 100644 --- a/src/plugins/dashboard/public/application/components/dashboard_top_nav/__snapshots__/dashboard_top_nav.test.tsx.snap +++ b/src/plugins/dashboard/public/application/components/dashboard_top_nav/__snapshots__/dashboard_top_nav.test.tsx.snap @@ -315,6 +315,7 @@ exports[`Dashboard top nav render in embed mode 1`] = ` }, "indexPatterns": Object { "clearCache": [MockFunction], + "create": [MockFunction], "createField": [MockFunction], "createFieldList": [MockFunction], "ensureDefaultIndexPattern": [MockFunction], @@ -322,6 +323,7 @@ exports[`Dashboard top nav render in embed mode 1`] = ` "get": [MockFunction], "getDefault": [MockFunction], "make": [Function], + "saveToCache": [MockFunction], }, "query": Object { "addToQueryLog": [MockFunction], @@ -1380,6 +1382,7 @@ exports[`Dashboard top nav render in embed mode, and force hide filter bar 1`] = }, "indexPatterns": Object { "clearCache": [MockFunction], + "create": [MockFunction], "createField": [MockFunction], "createFieldList": [MockFunction], "ensureDefaultIndexPattern": [MockFunction], @@ -1387,6 +1390,7 @@ exports[`Dashboard top nav render in embed mode, and force hide filter bar 1`] = "get": [MockFunction], "getDefault": [MockFunction], "make": [Function], + "saveToCache": [MockFunction], }, "query": Object { "addToQueryLog": [MockFunction], @@ -2445,6 +2449,7 @@ exports[`Dashboard top nav render in embed mode, components can be forced show b }, "indexPatterns": Object { "clearCache": [MockFunction], + "create": [MockFunction], "createField": [MockFunction], "createFieldList": [MockFunction], "ensureDefaultIndexPattern": [MockFunction], @@ -2452,6 +2457,7 @@ exports[`Dashboard top nav render in embed mode, components can be forced show b "get": [MockFunction], "getDefault": [MockFunction], "make": [Function], + "saveToCache": [MockFunction], }, "query": Object { "addToQueryLog": [MockFunction], @@ -3510,6 +3516,7 @@ exports[`Dashboard top nav render in full screen mode with appended URL param bu }, "indexPatterns": Object { "clearCache": [MockFunction], + "create": [MockFunction], "createField": [MockFunction], "createFieldList": [MockFunction], "ensureDefaultIndexPattern": [MockFunction], @@ -3517,6 +3524,7 @@ exports[`Dashboard top nav render in full screen mode with appended URL param bu "get": [MockFunction], "getDefault": [MockFunction], "make": [Function], + "saveToCache": [MockFunction], }, "query": Object { "addToQueryLog": [MockFunction], @@ -4575,6 +4583,7 @@ exports[`Dashboard top nav render in full screen mode, no componenets should be }, "indexPatterns": Object { "clearCache": [MockFunction], + "create": [MockFunction], "createField": [MockFunction], "createFieldList": [MockFunction], "ensureDefaultIndexPattern": [MockFunction], @@ -4582,6 +4591,7 @@ exports[`Dashboard top nav render in full screen mode, no componenets should be "get": [MockFunction], "getDefault": [MockFunction], "make": [Function], + "saveToCache": [MockFunction], }, "query": Object { "addToQueryLog": [MockFunction], @@ -5640,6 +5650,7 @@ exports[`Dashboard top nav render with all components 1`] = ` }, "indexPatterns": Object { "clearCache": [MockFunction], + "create": [MockFunction], "createField": [MockFunction], "createFieldList": [MockFunction], "ensureDefaultIndexPattern": [MockFunction], @@ -5647,6 +5658,7 @@ exports[`Dashboard top nav render with all components 1`] = ` "get": [MockFunction], "getDefault": [MockFunction], "make": [Function], + "saveToCache": [MockFunction], }, "query": Object { "addToQueryLog": [MockFunction], diff --git a/src/plugins/data/public/mocks.ts b/src/plugins/data/public/mocks.ts index 2b5f30981c12..d838c983665d 100644 --- a/src/plugins/data/public/mocks.ts +++ b/src/plugins/data/public/mocks.ts @@ -91,6 +91,12 @@ const createStartContract = (isEnhancementsEnabled: boolean = false): Start => { }) ), clearCache: jest.fn(), + create: jest.fn().mockResolvedValue({ + id: 'test-index-pattern', + title: 'Test Index Pattern', + type: 'INDEX_PATTERN', + }), + saveToCache: jest.fn(), } as unknown) as IndexPatternsContract, dataSources: dataSourceServiceMock.createStartContract(), }; diff --git a/src/plugins/data/public/query/query_string/dataset_service/dataset_service.test.ts b/src/plugins/data/public/query/query_string/dataset_service/dataset_service.test.ts index 02b9eb0759fc..d994d3a7699a 100644 --- a/src/plugins/data/public/query/query_string/dataset_service/dataset_service.test.ts +++ b/src/plugins/data/public/query/query_string/dataset_service/dataset_service.test.ts @@ -5,15 +5,19 @@ import { DatasetService } from './dataset_service'; import { coreMock } from '../../../../../../core/public/mocks'; -import { DataStorage } from 'src/plugins/data/common'; +import { DEFAULT_DATA, DataStorage, Dataset } from 'src/plugins/data/common'; import { DataStructure } from '../../../../common'; import { IDataPluginServices } from '../../../types'; +import { indexPatternTypeConfig } from './lib'; +import { dataPluginMock } from '../../../mocks'; +import { IndexPatternsContract } from '../../..'; describe('DatasetService', () => { let service: DatasetService; let uiSettings: ReturnType['uiSettings']; let sessionStorage: DataStorage; let mockDataPluginServices: jest.Mocked; + let indexPatterns: IndexPatternsContract; beforeEach(() => { uiSettings = coreMock.createSetup().uiSettings; @@ -21,6 +25,8 @@ describe('DatasetService', () => { mockDataPluginServices = {} as jest.Mocked; service = new DatasetService(uiSettings, sessionStorage); + indexPatterns = dataPluginMock.createStartContract().indexPatterns; + service.init(indexPatterns); }); const mockResult = { @@ -98,4 +104,29 @@ describe('DatasetService', () => { expect(service.getLastCacheTime()).toEqual(time); }); + test('calling cacheDataset on dataset caches it', async () => { + const mockDataset = { + id: 'test-dataset', + title: 'Test Dataset', + type: mockType.id, + } as Dataset; + service.registerType(mockType); + + await service.cacheDataset(mockDataset); + expect(indexPatterns.create).toHaveBeenCalledTimes(1); + expect(indexPatterns.saveToCache).toHaveBeenCalledTimes(1); + }); + + test('calling cacheDataset on index pattern does not cache it', async () => { + service.registerType(indexPatternTypeConfig); + const mockDataset = { + id: 'test-index-pattern', + title: 'Test Index Pattern', + type: DEFAULT_DATA.SET_TYPES.INDEX_PATTERN, + } as Dataset; + + await service.cacheDataset(mockDataset); + expect(indexPatterns.create).toHaveBeenCalledTimes(0); + expect(indexPatterns.saveToCache).toHaveBeenCalledTimes(0); + }); }); diff --git a/src/plugins/data/public/query/query_string/dataset_service/dataset_service.ts b/src/plugins/data/public/query/query_string/dataset_service/dataset_service.ts index 5f10b3d67193..2ea646c56abc 100644 --- a/src/plugins/data/public/query/query_string/dataset_service/dataset_service.ts +++ b/src/plugins/data/public/query/query_string/dataset_service/dataset_service.ts @@ -9,7 +9,6 @@ import { DataStructure, IndexPatternSpec, DEFAULT_DATA, - IFieldType, UI_SETTINGS, DataStorage, CachedDataStructure, @@ -64,14 +63,11 @@ export class DatasetService { public async cacheDataset(dataset: Dataset): Promise { const type = this.getType(dataset.type); - if (dataset) { + if (dataset && dataset.type !== DEFAULT_DATA.SET_TYPES.INDEX_PATTERN) { const spec = { id: dataset.id, title: dataset.title, - timeFieldName: { - name: dataset.timeFieldName, - type: 'date', - } as Partial, + timeFieldName: dataset.timeFieldName, fields: await type?.fetchFields(dataset), dataSourceRef: dataset.dataSource ? { diff --git a/src/plugins/data/public/query/query_string/dataset_service/lib/index_type.ts b/src/plugins/data/public/query/query_string/dataset_service/lib/index_type.ts index 2c7f4bbffb2e..cd2e45b8d25b 100644 --- a/src/plugins/data/public/query/query_string/dataset_service/lib/index_type.ts +++ b/src/plugins/data/public/query/query_string/dataset_service/lib/index_type.ts @@ -80,6 +80,7 @@ export const indexTypeConfig: DatasetTypeConfig = { return fields.map((field: any) => ({ name: field.name, type: field.type, + aggregatable: field?.aggregatable, })); }, diff --git a/src/plugins/data/public/query/query_string/language_service/types.ts b/src/plugins/data/public/query/query_string/language_service/types.ts index dff25464db08..6fe7119789d4 100644 --- a/src/plugins/data/public/query/query_string/language_service/types.ts +++ b/src/plugins/data/public/query/query_string/language_service/types.ts @@ -52,4 +52,5 @@ export interface LanguageConfig { showDocLinks?: boolean; editorSupportedAppNames?: string[]; supportedAppNames?: string[]; + hideDatePicker?: boolean; } diff --git a/src/plugins/data/public/ui/dataset_selector/configurator.tsx b/src/plugins/data/public/ui/dataset_selector/configurator.tsx index 164f677e27a2..db1cb80dd6e3 100644 --- a/src/plugins/data/public/ui/dataset_selector/configurator.tsx +++ b/src/plugins/data/public/ui/dataset_selector/configurator.tsx @@ -18,8 +18,8 @@ import { } from '@elastic/eui'; import { i18n } from '@osd/i18n'; import { FormattedMessage } from '@osd/i18n/react'; -import React, { useEffect, useState } from 'react'; -import { BaseDataset, Dataset, DatasetField } from '../../../common'; +import React, { useEffect, useMemo, useState } from 'react'; +import { BaseDataset, DEFAULT_DATA, Dataset, DatasetField } from '../../../common'; import { getIndexPatterns, getQueryService } from '../../services'; export const Configurator = ({ @@ -41,8 +41,14 @@ export const Configurator = ({ const languages = type?.supportedLanguages(baseDataset) || []; const [dataset, setDataset] = useState(baseDataset); - const [timeFields, setTimeFields] = useState(); + const [timeFields, setTimeFields] = useState([]); const [timeFieldName, setTimeFieldName] = useState(dataset.timeFieldName); + const noTimeFilter = i18n.translate( + 'data.explorer.datasetSelector.advancedSelector.configurator.timeField.noTimeFieldOptionLabel', + { + defaultMessage: "I don't want to use the time filter", + } + ); const [language, setLanguage] = useState(() => { const currentLanguage = queryString.getQuery().language; if (languages.includes(currentLanguage)) { @@ -51,6 +57,18 @@ export const Configurator = ({ return languages[0]; }); + const submitDisabled = useMemo(() => { + return ( + timeFieldName === undefined && + !( + languageService.getLanguage(language)?.hideDatePicker || + dataset.type === DEFAULT_DATA.SET_TYPES.INDEX_PATTERN + ) && + timeFields && + timeFields.length > 0 + ); + }, [dataset, language, timeFieldName, timeFields, languageService]); + useEffect(() => { const fetchFields = async () => { const datasetFields = await queryString @@ -97,33 +115,6 @@ export const Configurator = ({ > - {timeFields && timeFields.length > 0 && ( - - ({ - text: field.displayName || field.name, - value: field.name, - })), - { text: '-----', value: '', disabled: true }, - { text: 'No time field', value: undefined }, - ]} - value={timeFieldName} - onChange={(e) => { - const value = e.target.value === 'undefined' ? undefined : e.target.value; - setTimeFieldName(value); - setDataset({ ...dataset, timeFieldName: value }); - }} - /> - - )} + {!languageService.getLanguage(language)?.hideDatePicker && + (dataset.type === DEFAULT_DATA.SET_TYPES.INDEX_PATTERN ? ( + + + + ) : ( + + ({ + text: field.displayName || field.name, + value: field.name, + })), + { text: '-----', value: '-----', disabled: true }, + { text: noTimeFilter, value: noTimeFilter }, + ]} + value={timeFieldName} + onChange={(e) => { + const value = e.target.value === noTimeFilter ? undefined : e.target.value; + setTimeFieldName(e.target.value); + setDataset({ ...dataset, timeFieldName: value }); + }} + hasNoInitialSelection + /> + + ))} @@ -165,6 +196,7 @@ export const Configurator = ({ onConfirm(dataset); }} fill + disabled={submitDisabled} > diff --git a/src/plugins/query_enhancements/public/plugin.tsx b/src/plugins/query_enhancements/public/plugin.tsx index a3cec8802880..ad8a3aca412c 100644 --- a/src/plugins/query_enhancements/public/plugin.tsx +++ b/src/plugins/query_enhancements/public/plugin.tsx @@ -100,6 +100,7 @@ export class QueryEnhancementsPlugin editor: enhancedSQLQueryEditor, editorSupportedAppNames: ['discover'], supportedAppNames: ['discover', 'data-explorer'], + hideDatePicker: true, }; queryString.getLanguageService().registerLanguage(sqlLanguageConfig);