From 708f06fc153ff9c92bfe54bd2be5b9b233a80151 Mon Sep 17 00:00:00 2001 From: Matthew Kime Date: Wed, 13 Oct 2021 07:15:26 -0500 Subject: [PATCH 01/55] [data views] add getDefaultDataView method (#113891) * add new method to data views api * add tests Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../common/data_views/data_views.test.ts | 58 +++++++++++++++++-- .../common/data_views/data_views.ts | 31 ++++++++++ 2 files changed, 84 insertions(+), 5 deletions(-) diff --git a/src/plugins/data_views/common/data_views/data_views.test.ts b/src/plugins/data_views/common/data_views/data_views.test.ts index 9a01e52ce48e2..210c926f92df7 100644 --- a/src/plugins/data_views/common/data_views/data_views.test.ts +++ b/src/plugins/data_views/common/data_views/data_views.test.ts @@ -50,9 +50,15 @@ describe('IndexPatterns', () => { let indexPatterns: DataViewsService; let savedObjectsClient: SavedObjectsClientCommon; let SOClientGetDelay = 0; + const uiSettings = { + get: () => Promise.resolve(false), + getAll: () => {}, + set: () => () => {}, + remove: jest.fn(), + } as any as UiSettingsCommon; + const indexPatternObj = { id: 'id', version: 'a', attributes: { title: 'title' } }; beforeEach(() => { - const indexPatternObj = { id: 'id', version: 'a', attributes: { title: 'title' } }; savedObjectsClient = {} as SavedObjectsClientCommon; savedObjectsClient.find = jest.fn( () => Promise.resolve([indexPatternObj]) as Promise>> @@ -86,10 +92,7 @@ describe('IndexPatterns', () => { }); indexPatterns = new DataViewsService({ - uiSettings: { - get: () => Promise.resolve(false), - getAll: () => {}, - } as any as UiSettingsCommon, + uiSettings, savedObjectsClient: savedObjectsClient as unknown as SavedObjectsClientCommon, apiClient: createFieldsFetcher(), fieldFormats, @@ -274,4 +277,49 @@ describe('IndexPatterns', () => { // successful subsequent request expect(async () => await indexPatterns.get(id)).toBeDefined(); }); + + describe('getDefaultDataView', () => { + test('gets default data view', async () => { + indexPatterns.clearCache(); + jest.clearAllMocks(); + + expect(await indexPatterns.getDefaultDataView()).toBeInstanceOf(DataView); + // make sure we're not pulling from cache + expect(savedObjectsClient.get).toBeCalledTimes(1); + expect(savedObjectsClient.find).toBeCalledTimes(1); + }); + + test('returns undefined if no data views exist', async () => { + savedObjectsClient.find = jest.fn( + () => Promise.resolve([]) as Promise>> + ); + savedObjectsClient.get = jest.fn(() => Promise.resolve(undefined) as Promise); + indexPatterns.clearCache(); + expect(await indexPatterns.getDefaultDataView()).toBeUndefined(); + }); + + test("default doesn't exist, grabs another data view", async () => { + indexPatterns.clearCache(); + jest.clearAllMocks(); + uiSettings.get = jest.fn().mockResolvedValue(['bar']); + + savedObjectsClient.find = jest.fn( + () => Promise.resolve([indexPatternObj]) as Promise>> + ); + + savedObjectsClient.get = jest.fn().mockResolvedValue({ + id: 'bar', + version: 'foo', + attributes: { + title: 'something', + }, + }); + + expect(await indexPatterns.getDefaultDataView()).toBeInstanceOf(DataView); + // make sure we're not pulling from cache + expect(savedObjectsClient.get).toBeCalledTimes(1); + expect(savedObjectsClient.find).toBeCalledTimes(1); + expect(uiSettings.remove).toBeCalledTimes(1); + }); + }); }); diff --git a/src/plugins/data_views/common/data_views/data_views.ts b/src/plugins/data_views/common/data_views/data_views.ts index 77ce1caaaad84..a76b531668162 100644 --- a/src/plugins/data_views/common/data_views/data_views.ts +++ b/src/plugins/data_views/common/data_views/data_views.ts @@ -79,6 +79,10 @@ export class DataViewsService { private onError: OnError; private dataViewCache: ReturnType; + /** + * @deprecated Use `getDefaultDataView` instead (when loading data view) and handle + * 'no data view' case in api consumer code - no more auto redirect + */ ensureDefaultDataView: EnsureDefaultDataView; constructor({ @@ -681,6 +685,33 @@ export class DataViewsService { this.dataViewCache.clear(indexPatternId); return this.savedObjectsClient.delete(DATA_VIEW_SAVED_OBJECT_TYPE, indexPatternId); } + + /** + * Returns the default data view as an object. If no default is found, or it is missing + * another data view is selected as default and returned. + * @returns default data view + */ + + async getDefaultDataView() { + const patterns = await this.getIds(); + let defaultId = await this.config.get('defaultIndex'); + let defined = !!defaultId; + const exists = patterns.includes(defaultId); + + if (defined && !exists) { + await this.config.remove('defaultIndex'); + defaultId = defined = false; + } + + if (patterns.length >= 1 && (await this.hasUserDataView().catch(() => true))) { + defaultId = patterns[0]; + await this.config.set('defaultIndex', defaultId); + } + + if (defaultId) { + return this.get(defaultId); + } + } } /** From 2afb43b8699d91463be52f57e78d277fbd319471 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Wed, 13 Oct 2021 14:52:48 +0200 Subject: [PATCH 02/55] Replace EuiCodeEditor with CodeEditor in app-services code (#114316) * code editor scripted fields * filter_editor * embeddable example * clean * update tests Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../dashboard_embeddable_examples/kibana.json | 3 +- .../public/app.tsx | 32 ++++++++++++------- .../public/by_value/input_editor.tsx | 13 ++++---- .../public/plugin.tsx | 3 +- .../tsconfig.json | 2 +- .../filter_editor/filter_editor.test.tsx | 8 ++--- .../ui/filter_bar/filter_editor/index.tsx | 15 +++++---- .../__snapshots__/field_editor.test.tsx.snap | 28 ++++++++++------ .../field_editor/field_editor.test.tsx | 12 +++++-- .../components/field_editor/field_editor.tsx | 20 ++++++------ test/examples/embeddables/dashboard.ts | 14 ++------ test/functional/page_objects/settings_page.ts | 10 ++---- 12 files changed, 85 insertions(+), 75 deletions(-) diff --git a/examples/dashboard_embeddable_examples/kibana.json b/examples/dashboard_embeddable_examples/kibana.json index e13f19194ef06..ba0c4a84836e7 100644 --- a/examples/dashboard_embeddable_examples/kibana.json +++ b/examples/dashboard_embeddable_examples/kibana.json @@ -16,6 +16,5 @@ "githubTeam": "kibana-presentation" }, "description": "Example app that shows how to embed a dashboard in an application", - "optionalPlugins": [], - "requiredBundles": ["esUiShared"] + "optionalPlugins": [] } diff --git a/examples/dashboard_embeddable_examples/public/app.tsx b/examples/dashboard_embeddable_examples/public/app.tsx index 8a6b5a90a22a8..c44d67c49f3d7 100644 --- a/examples/dashboard_embeddable_examples/public/app.tsx +++ b/examples/dashboard_embeddable_examples/public/app.tsx @@ -18,9 +18,10 @@ import { EuiSideNav, } from '@elastic/eui'; import 'brace/mode/json'; -import { AppMountParameters } from '../../../src/core/public'; +import { AppMountParameters, IUiSettingsClient } from '../../../src/core/public'; import { DashboardEmbeddableByValue } from './by_value/embeddable'; import { DashboardStart } from '../../../src/plugins/dashboard/public'; +import { KibanaContextProvider } from '../../../src/plugins/kibana_react/public'; interface PageDef { title: string; @@ -58,9 +59,14 @@ interface Props { DashboardContainerByValueRenderer: ReturnType< DashboardStart['getDashboardContainerByValueRenderer'] >; + uiSettings: IUiSettingsClient; } -const DashboardEmbeddableExplorerApp = ({ basename, DashboardContainerByValueRenderer }: Props) => { +const DashboardEmbeddableExplorerApp = ({ + basename, + DashboardContainerByValueRenderer, + uiSettings, +}: Props) => { const pages: PageDef[] = [ { title: 'By value dashboard embeddable', @@ -83,16 +89,18 @@ const DashboardEmbeddableExplorerApp = ({ basename, DashboardContainerByValueRen )); return ( - - - -