From ef38287551f7b1c1649c2be32b3656f0c9f732eb Mon Sep 17 00:00:00 2001 From: spalger Date: Wed, 4 Mar 2020 12:50:04 -0700 Subject: [PATCH] Revert "[ML] Transforms: Deprecate custom KibanaContext. (#59133)" This reverts commit 29975fa614307bb9c513f1c6e1c0dedc2fd013af. --- .../transform/public/app/common/request.ts | 2 +- .../toast_notification_text.test.tsx | 10 +- .../app/hooks/use_search_items/index.ts | 8 - .../use_search_items => lib/kibana}/common.ts | 19 +- .../transform/public/app/lib/kibana/index.ts | 17 + .../public/app/lib/kibana/kibana_context.tsx | 72 ++ .../kibana/kibana_provider.tsx} | 56 +- .../lib/kibana/use_current_index_pattern.ts | 19 + .../clone_transform_section.tsx | 22 +- .../source_index_preview.test.tsx.snap | 598 +--------------- .../expanded_row.test.tsx | 2 + .../source_index_preview.test.tsx | 20 +- .../source_index_preview.tsx | 7 +- .../step_create_form.test.tsx.snap | 598 +--------------- .../step_create/step_create_form.test.tsx | 15 +- .../step_create/step_create_form.tsx | 10 +- .../__snapshots__/pivot_preview.test.tsx.snap | 638 ++---------------- .../step_define_form.test.tsx.snap | 581 +--------------- .../step_define_summary.test.tsx.snap | 121 +--- .../step_define/pivot_preview.test.tsx | 21 +- .../components/step_define/pivot_preview.tsx | 321 +++++---- .../step_define/step_define_form.test.tsx | 18 +- .../step_define/step_define_form.tsx | 57 +- .../step_define/step_define_summary.test.tsx | 14 +- .../step_define/step_define_summary.tsx | 53 +- .../step_details/step_details_form.tsx | 621 +++++++++-------- .../components/wizard/wizard.tsx | 31 +- .../create_transform_section.tsx | 70 +- .../legacy/plugins/transform/public/plugin.ts | 12 +- .../transform/public/shared_imports.ts | 1 - .../legacy/plugins/transform/public/shim.ts | 17 +- 31 files changed, 937 insertions(+), 3114 deletions(-) delete mode 100644 x-pack/legacy/plugins/transform/public/app/hooks/use_search_items/index.ts rename x-pack/legacy/plugins/transform/public/app/{hooks/use_search_items => lib/kibana}/common.ts (96%) create mode 100644 x-pack/legacy/plugins/transform/public/app/lib/kibana/index.ts create mode 100644 x-pack/legacy/plugins/transform/public/app/lib/kibana/kibana_context.tsx rename x-pack/legacy/plugins/transform/public/app/{hooks/use_search_items/use_search_items.ts => lib/kibana/kibana_provider.tsx} (53%) create mode 100644 x-pack/legacy/plugins/transform/public/app/lib/kibana/use_current_index_pattern.ts diff --git a/x-pack/legacy/plugins/transform/public/app/common/request.ts b/x-pack/legacy/plugins/transform/public/app/common/request.ts index 31089b86a2c2d..3b740de177ef8 100644 --- a/x-pack/legacy/plugins/transform/public/app/common/request.ts +++ b/x-pack/legacy/plugins/transform/public/app/common/request.ts @@ -7,7 +7,7 @@ import { DefaultOperator } from 'elasticsearch'; import { dictionaryToArray } from '../../../common/types/common'; -import { SavedSearchQuery } from '../hooks/use_search_items'; +import { SavedSearchQuery } from '../lib/kibana'; import { StepDefineExposedState } from '../sections/create_transform/components/step_define/step_define_form'; import { StepDetailsExposedState } from '../sections/create_transform/components/step_details/step_details_form'; diff --git a/x-pack/legacy/plugins/transform/public/app/components/toast_notification_text.test.tsx b/x-pack/legacy/plugins/transform/public/app/components/toast_notification_text.test.tsx index 095b57de97d9a..81af5c974fe04 100644 --- a/x-pack/legacy/plugins/transform/public/app/components/toast_notification_text.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/components/toast_notification_text.test.tsx @@ -7,13 +7,13 @@ import React from 'react'; import { render } from '@testing-library/react'; +import { KibanaContext } from '../lib/kibana'; import { createPublicShim } from '../../shim'; import { getAppProviders } from '../app_dependencies'; import { ToastNotificationText } from './toast_notification_text'; jest.mock('../../shared_imports'); -jest.mock('ui/new_platform'); describe('ToastNotificationText', () => { test('should render the text as plain text', () => { @@ -23,7 +23,9 @@ describe('ToastNotificationText', () => { }; const { container } = render( - + + + ); expect(container.textContent).toBe('a short text message'); @@ -37,7 +39,9 @@ describe('ToastNotificationText', () => { }; const { container } = render( - + + + ); expect(container.textContent).toBe( diff --git a/x-pack/legacy/plugins/transform/public/app/hooks/use_search_items/index.ts b/x-pack/legacy/plugins/transform/public/app/hooks/use_search_items/index.ts deleted file mode 100644 index aa4f04f43b335..0000000000000 --- a/x-pack/legacy/plugins/transform/public/app/hooks/use_search_items/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -export { SavedSearchQuery, SearchItems } from './common'; -export { useSearchItems } from './use_search_items'; diff --git a/x-pack/legacy/plugins/transform/public/app/hooks/use_search_items/common.ts b/x-pack/legacy/plugins/transform/public/app/lib/kibana/common.ts similarity index 96% rename from x-pack/legacy/plugins/transform/public/app/hooks/use_search_items/common.ts rename to x-pack/legacy/plugins/transform/public/app/lib/kibana/common.ts index 2258f8f33f01d..aa4cd21281e22 100644 --- a/x-pack/legacy/plugins/transform/public/app/hooks/use_search_items/common.ts +++ b/x-pack/legacy/plugins/transform/public/app/lib/kibana/common.ts @@ -14,8 +14,6 @@ import { import { matchAllQuery } from '../../common'; -export type SavedSearchQuery = object; - type IndexPatternId = string; type SavedSearchId = string; @@ -62,7 +60,7 @@ export function getIndexPatternIdByTitle(indexPatternTitle: string): string | un return indexPatternCache.find(d => d?.attributes?.title === indexPatternTitle)?.id; } -type CombinedQuery = Record<'bool', any> | object; +type CombinedQuery = Record<'bool', any> | unknown; export function loadCurrentIndexPattern( indexPatterns: IndexPatternsContract, @@ -81,20 +79,17 @@ export function loadCurrentSavedSearch(savedSearches: any, savedSearchId: SavedS function isIndexPattern(arg: any): arg is IndexPattern { return arg !== undefined; } - -export interface SearchItems { - indexPattern: IndexPattern; - savedSearch: any; - query: any; - combinedQuery: CombinedQuery; -} - // Helper for creating the items used for searching and job creation. export function createSearchItems( indexPattern: IndexPattern | undefined, savedSearch: any, config: IUiSettingsClient -): SearchItems { +): { + indexPattern: IndexPattern; + savedSearch: any; + query: any; + combinedQuery: CombinedQuery; +} { // query is only used by the data visualizer as it needs // a lucene query_string. // Using a blank query will cause match_all:{} to be used diff --git a/x-pack/legacy/plugins/transform/public/app/lib/kibana/index.ts b/x-pack/legacy/plugins/transform/public/app/lib/kibana/index.ts new file mode 100644 index 0000000000000..62107cb37ff2c --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/lib/kibana/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { getIndexPatternIdByTitle, loadIndexPatterns } from './common'; +export { + useKibanaContext, + InitializedKibanaContextValue, + KibanaContext, + KibanaContextValue, + SavedSearchQuery, + RenderOnlyWithInitializedKibanaContext, +} from './kibana_context'; +export { KibanaProvider } from './kibana_provider'; +export { useCurrentIndexPattern } from './use_current_index_pattern'; diff --git a/x-pack/legacy/plugins/transform/public/app/lib/kibana/kibana_context.tsx b/x-pack/legacy/plugins/transform/public/app/lib/kibana/kibana_context.tsx new file mode 100644 index 0000000000000..7677c491a7a59 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/lib/kibana/kibana_context.tsx @@ -0,0 +1,72 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { createContext, useContext, FC } from 'react'; + +import { IUiSettingsClient } from 'kibana/public'; + +import { + IndexPattern, + IndexPatternsContract, +} from '../../../../../../../../src/plugins/data/public'; +import { SavedSearch } from '../../../../../../../../src/plugins/discover/public/'; + +interface UninitializedKibanaContextValue { + initialized: false; +} + +export interface InitializedKibanaContextValue { + combinedQuery: any; + indexPatterns: IndexPatternsContract; + initialized: true; + kibanaConfig: IUiSettingsClient; + currentIndexPattern: IndexPattern; + currentSavedSearch?: SavedSearch; +} + +export type KibanaContextValue = UninitializedKibanaContextValue | InitializedKibanaContextValue; + +export function isKibanaContextInitialized(arg: any): arg is InitializedKibanaContextValue { + return arg.initialized; +} + +export type SavedSearchQuery = object; + +export const KibanaContext = createContext({ initialized: false }); + +/** + * Custom hook to get the current kibanaContext. + * + * @remarks + * This hook should only be used in components wrapped in `RenderOnlyWithInitializedKibanaContext`, + * otherwise it will throw an error when KibanaContext hasn't been initialized yet. + * In return you get the benefit of not having to check if it's been initialized in the component + * where it's used. + * + * @returns `kibanaContext` + */ +export const useKibanaContext = () => { + const kibanaContext = useContext(KibanaContext); + + if (!isKibanaContextInitialized(kibanaContext)) { + throw new Error('useKibanaContext: kibanaContext not initialized'); + } + + return kibanaContext; +}; + +/** + * Wrapper component to render children only if `kibanaContext` has been initialized. + * In combination with `useKibanaContext` this avoids having to check for the initialization + * in consuming components. + * + * @returns `children` or `null` depending on whether `kibanaContext` is initialized or not. + */ +export const RenderOnlyWithInitializedKibanaContext: FC = ({ children }) => { + const kibanaContext = useContext(KibanaContext); + + return isKibanaContextInitialized(kibanaContext) ? <>{children} : null; +}; diff --git a/x-pack/legacy/plugins/transform/public/app/hooks/use_search_items/use_search_items.ts b/x-pack/legacy/plugins/transform/public/app/lib/kibana/kibana_provider.tsx similarity index 53% rename from x-pack/legacy/plugins/transform/public/app/hooks/use_search_items/use_search_items.ts rename to x-pack/legacy/plugins/transform/public/app/lib/kibana/kibana_provider.tsx index 12fc75c20ffa4..f2574a4a85f29 100644 --- a/x-pack/legacy/plugins/transform/public/app/hooks/use_search_items/use_search_items.ts +++ b/x-pack/legacy/plugins/transform/public/app/lib/kibana/kibana_provider.tsx @@ -4,36 +4,30 @@ * you may not use this file except in compliance with the Elastic License. */ -import { useEffect, useState } from 'react'; - -import { createSavedSearchesLoader } from '../../../shared_imports'; +import React, { useEffect, useState, FC } from 'react'; import { useAppDependencies } from '../../app_dependencies'; import { createSearchItems, - getIndexPatternIdByTitle, loadCurrentIndexPattern, loadIndexPatterns, loadCurrentSavedSearch, - SearchItems, } from './common'; -export const useSearchItems = (defaultSavedObjectId: string | undefined) => { - const [savedObjectId, setSavedObjectId] = useState(defaultSavedObjectId); +import { InitializedKibanaContextValue, KibanaContext, KibanaContextValue } from './kibana_context'; + +interface Props { + savedObjectId: string; +} +export const KibanaProvider: FC = ({ savedObjectId, children }) => { const appDeps = useAppDependencies(); const indexPatterns = appDeps.plugins.data.indexPatterns; - const uiSettings = appDeps.core.uiSettings; const savedObjectsClient = appDeps.core.savedObjects.client; - const savedSearches = createSavedSearchesLoader({ - savedObjectsClient, - indexPatterns, - chrome: appDeps.core.chrome, - overlays: appDeps.core.overlays, - }); + const savedSearches = appDeps.plugins.savedSearches.getClient(); - const [searchItems, setSearchItems] = useState(undefined); + const [contextValue, setContextValue] = useState({ initialized: false }); async function fetchSavedObject(id: string) { await loadIndexPatterns(savedObjectsClient, indexPatterns); @@ -53,21 +47,31 @@ export const useSearchItems = (defaultSavedObjectId: string | undefined) => { // Just let fetchedSavedSearch stay undefined in case it doesn't exist. } - setSearchItems(createSearchItems(fetchedIndexPattern, fetchedSavedSearch, uiSettings)); + const kibanaConfig = appDeps.core.uiSettings; + + const { + indexPattern: currentIndexPattern, + savedSearch: currentSavedSearch, + combinedQuery, + } = createSearchItems(fetchedIndexPattern, fetchedSavedSearch, kibanaConfig); + + const kibanaContext: InitializedKibanaContextValue = { + indexPatterns, + initialized: true, + kibanaConfig, + combinedQuery, + currentIndexPattern, + currentSavedSearch, + }; + + setContextValue(kibanaContext); } useEffect(() => { - if (savedObjectId !== undefined) { - fetchSavedObject(savedObjectId); - } - // Run this only when savedObjectId changes. + fetchSavedObject(savedObjectId); + // fetchSavedObject should not be tracked. // eslint-disable-next-line react-hooks/exhaustive-deps }, [savedObjectId]); - return { - getIndexPatternIdByTitle, - loadIndexPatterns, - searchItems, - setSavedObjectId, - }; + return {children}; }; diff --git a/x-pack/legacy/plugins/transform/public/app/lib/kibana/use_current_index_pattern.ts b/x-pack/legacy/plugins/transform/public/app/lib/kibana/use_current_index_pattern.ts new file mode 100644 index 0000000000000..12c5bde171b8b --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/lib/kibana/use_current_index_pattern.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { useContext } from 'react'; + +import { isKibanaContextInitialized, KibanaContext } from './kibana_context'; + +export const useCurrentIndexPattern = () => { + const context = useContext(KibanaContext); + + if (!isKibanaContextInitialized(context)) { + throw new Error('useCurrentIndexPattern: kibanaContext not initialized'); + } + + return context.currentIndexPattern; +}; diff --git a/x-pack/legacy/plugins/transform/public/app/sections/clone_transform/clone_transform_section.tsx b/x-pack/legacy/plugins/transform/public/app/sections/clone_transform/clone_transform_section.tsx index 4618e96cbfd6e..c5c46dcac6c95 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/clone_transform/clone_transform_section.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/clone_transform/clone_transform_section.tsx @@ -22,7 +22,6 @@ import { } from '@elastic/eui'; import { useApi } from '../../hooks/use_api'; -import { useSearchItems } from '../../hooks/use_search_items'; import { APP_CREATE_TRANSFORM_CLUSTER_PRIVILEGES } from '../../../../common/constants'; @@ -30,6 +29,12 @@ import { useAppDependencies, useDocumentationLinks } from '../../app_dependencie import { TransformPivotConfig } from '../../common'; import { breadcrumbService, docTitleService, BREADCRUMB_SECTION } from '../../services/navigation'; import { PrivilegesWrapper } from '../../lib/authorization'; +import { + getIndexPatternIdByTitle, + loadIndexPatterns, + KibanaProvider, + RenderOnlyWithInitializedKibanaContext, +} from '../../lib/kibana'; import { Wizard } from '../create_transform/components/wizard'; @@ -75,12 +80,7 @@ export const CloneTransformSection: FC = ({ match }) => { const [transformConfig, setTransformConfig] = useState(); const [errorMessage, setErrorMessage] = useState(); const [isInitialized, setIsInitialized] = useState(false); - const { - getIndexPatternIdByTitle, - loadIndexPatterns, - searchItems, - setSavedObjectId, - } = useSearchItems(undefined); + const [savedObjectId, setSavedObjectId] = useState(undefined); const fetchTransformConfig = async () => { try { @@ -169,8 +169,12 @@ export const CloneTransformSection: FC = ({ match }) => {
{JSON.stringify(errorMessage)}
)} - {searchItems !== undefined && isInitialized === true && transformConfig !== undefined && ( - + {savedObjectId !== undefined && isInitialized === true && transformConfig !== undefined && ( + + + + + )} diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/__snapshots__/source_index_preview.test.tsx.snap b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/__snapshots__/source_index_preview.test.tsx.snap index 6d2d3d5c4a6a5..e43f2e37bb416 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/__snapshots__/source_index_preview.test.tsx.snap +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/__snapshots__/source_index_preview.test.tsx.snap @@ -1,584 +1,24 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Transform: Minimal initialization 1`] = ` - - - - + + - - - - - + } + /> + + `; diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/expanded_row.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/expanded_row.test.tsx index ddd1a1482fd35..bfde8f171874e 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/expanded_row.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/expanded_row.test.tsx @@ -39,6 +39,8 @@ describe('Transform: ', () => { }, }; + // Using a wrapping
element because shallow() would fail + // with the Provider being the outer most component. const wrapper = shallow(); expect(wrapper).toMatchSnapshot(); diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/source_index_preview.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/source_index_preview.test.tsx index ec79735741427..16949425284fd 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/source_index_preview.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/source_index_preview.test.tsx @@ -7,10 +7,8 @@ import { shallow } from 'enzyme'; import React from 'react'; -import { createPublicShim } from '../../../../../shim'; -import { getAppProviders } from '../../../../app_dependencies'; +import { KibanaContext } from '../../../../lib/kibana'; import { getPivotQuery } from '../../../../common'; -import { SearchItems } from '../../../../hooks/use_search_items'; import { SourceIndexPreview } from './source_index_preview'; @@ -20,24 +18,22 @@ jest.mock('react', () => { return { ...r, memo: (x: any) => x }; }); -jest.mock('ui/new_platform'); jest.mock('../../../../../shared_imports'); describe('Transform: ', () => { test('Minimal initialization', () => { const props = { - indexPattern: { - title: 'the-index-pattern-title', - fields: [] as any[], - } as SearchItems['indexPattern'], query: getPivotQuery('the-query'), }; - const Providers = getAppProviders(createPublicShim()); + // Using a wrapping
element because shallow() would fail + // with the Provider being the outer most component. const wrapper = shallow( - - - +
+ + + +
); expect(wrapper).toMatchSnapshot(); diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/source_index_preview.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/source_index_preview.tsx index 76ed12ff772f5..0c9dcfb9b1c04 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/source_index_preview.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/source_index_preview.tsx @@ -22,13 +22,14 @@ import { import { getNestedProperty } from '../../../../../../common/utils/object_utils'; +import { useCurrentIndexPattern } from '../../../../lib/kibana'; + import { euiDataGridStyle, euiDataGridToolbarSettings, EsFieldName, PivotQuery, } from '../../../../common'; -import { SearchItems } from '../../../../hooks/use_search_items'; import { getSourceIndexDevConsoleStatement } from './common'; import { SOURCE_INDEX_STATUS, useSourceIndexData } from './use_source_index_data'; @@ -48,13 +49,13 @@ const SourceIndexPreviewTitle: React.FC = ({ indexPatte ); interface Props { - indexPattern: SearchItems['indexPattern']; query: PivotQuery; } const defaultPagination = { pageIndex: 0, pageSize: 5 }; -export const SourceIndexPreview: React.FC = React.memo(({ indexPattern, query }) => { +export const SourceIndexPreview: React.FC = React.memo(({ query }) => { + const indexPattern = useCurrentIndexPattern(); const allFields = indexPattern.fields.map(f => f.name); const indexPatternFields: string[] = allFields.filter(f => { if (indexPattern.metaFields.includes(f)) { diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_create/__snapshots__/step_create_form.test.tsx.snap b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_create/__snapshots__/step_create_form.test.tsx.snap index db4ff0c1a99ae..e034badea9b11 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_create/__snapshots__/step_create_form.test.tsx.snap +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_create/__snapshots__/step_create_form.test.tsx.snap @@ -1,581 +1,27 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Transform: Minimal initialization 1`] = ` - - - - + + - - - - - + } + transformConfig={Object {}} + transformId="the-transform-id" + /> + +
`; diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.test.tsx index 80968fd6e2887..625c545ee8c46 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.test.tsx @@ -7,8 +7,7 @@ import { shallow } from 'enzyme'; import React from 'react'; -import { createPublicShim } from '../../../../../shim'; -import { getAppProviders } from '../../../../app_dependencies'; +import { KibanaContext } from '../../../../lib/kibana'; import { StepCreateForm } from './step_create_form'; @@ -18,7 +17,6 @@ jest.mock('react', () => { return { ...r, memo: (x: any) => x }; }); -jest.mock('ui/new_platform'); jest.mock('../../../../../shared_imports'); describe('Transform: ', () => { @@ -31,11 +29,14 @@ describe('Transform: ', () => { onChange() {}, }; - const Providers = getAppProviders(createPublicShim()); + // Using a wrapping
element because shallow() would fail + // with the Provider being the outer most component. const wrapper = shallow( - - - +
+ + + +
); expect(wrapper).toMatchSnapshot(); diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx index 4198c2ea0260d..bbeb97b6b8113 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx @@ -34,6 +34,7 @@ import { PROGRESS_REFRESH_INTERVAL_MS } from '../../../../../../common/constants import { getTransformProgress, getDiscoverUrl } from '../../../../common'; import { useApi } from '../../../../hooks/use_api'; +import { useKibanaContext } from '../../../../lib/kibana'; import { useAppDependencies, useToastNotifications } from '../../../../app_dependencies'; import { RedirectToTransformManagement } from '../../../../common/navigation'; import { ToastNotificationText } from '../../../../components'; @@ -75,8 +76,7 @@ export const StepCreateForm: FC = React.memo( ); const deps = useAppDependencies(); - const indexPatterns = deps.plugins.data.indexPatterns; - const uiSettings = deps.core.uiSettings; + const kibanaContext = useKibanaContext(); const toastNotifications = useToastNotifications(); useEffect(() => { @@ -176,7 +176,7 @@ export const StepCreateForm: FC = React.memo( const indexPatternName = transformConfig.dest.index; try { - const newIndexPattern = await indexPatterns.make(); + const newIndexPattern = await kibanaContext.indexPatterns.make(); Object.assign(newIndexPattern, { id: '', @@ -200,8 +200,8 @@ export const StepCreateForm: FC = React.memo( // check if there's a default index pattern, if not, // set the newly created one as the default index pattern. - if (!uiSettings.get('defaultIndex')) { - await uiSettings.set('defaultIndex', id); + if (!kibanaContext.kibanaConfig.get('defaultIndex')) { + await kibanaContext.kibanaConfig.set('defaultIndex', id); } toastNotifications.addSuccess( diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/__snapshots__/pivot_preview.test.tsx.snap b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/__snapshots__/pivot_preview.test.tsx.snap index bc0d983c6e022..a7da172a67b8a 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/__snapshots__/pivot_preview.test.tsx.snap +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/__snapshots__/pivot_preview.test.tsx.snap @@ -1,604 +1,44 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Transform: Minimal initialization 1`] = ` - - - - + + - - - - - + } + groupBy={ + Object { + "the-group-by-name": Object { + "agg": "terms", + "aggName": "the-group-by-agg-name", + "dropDownName": "the-group-by-drop-down-name", + "field": "the-group-by-field", + }, + } + } + query={ + Object { + "query_string": Object { + "default_operator": "AND", + "query": "the-query", + }, + } + } + /> + +
`; diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/__snapshots__/step_define_form.test.tsx.snap b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/__snapshots__/step_define_form.test.tsx.snap index 30c57a9f3f4ae..70a0bfc12b208 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/__snapshots__/step_define_form.test.tsx.snap +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/__snapshots__/step_define_form.test.tsx.snap @@ -1,572 +1,17 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Transform: Minimal initialization 1`] = ` - - - - - - - - - +
+ + + +
`; diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/__snapshots__/step_define_summary.test.tsx.snap b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/__snapshots__/step_define_summary.test.tsx.snap index 4955a0a95b7e9..b18233e5c53e3 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/__snapshots__/step_define_summary.test.tsx.snap +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/__snapshots__/step_define_summary.test.tsx.snap @@ -1,99 +1,42 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Transform: Minimal initialization 1`] = ` - - + -
- - - - - - - - -
-
- - - - - -
+ } + isAdvancedPivotEditorEnabled={false} + isAdvancedSourceEditorEnabled={false} + searchQuery="the-search-query" + searchString="the-query" + sourceConfigUpdated={false} + valid={true} + /> + +
`; diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/pivot_preview.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/pivot_preview.test.tsx index 6b49a305e515b..2ac4295da1eed 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/pivot_preview.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/pivot_preview.test.tsx @@ -7,8 +7,8 @@ import { shallow } from 'enzyme'; import React from 'react'; -import { createPublicShim } from '../../../../../shim'; -import { getAppProviders } from '../../../../app_dependencies'; +import { KibanaContext } from '../../../../lib/kibana'; + import { getPivotQuery, PivotAggsConfig, @@ -16,7 +16,6 @@ import { PIVOT_SUPPORTED_AGGS, PIVOT_SUPPORTED_GROUP_BY_AGGS, } from '../../../../common'; -import { SearchItems } from '../../../../hooks/use_search_items'; import { PivotPreview } from './pivot_preview'; @@ -26,7 +25,6 @@ jest.mock('react', () => { return { ...r, memo: (x: any) => x }; }); -jest.mock('ui/new_platform'); jest.mock('../../../../../shared_imports'); describe('Transform: ', () => { @@ -46,18 +44,17 @@ describe('Transform: ', () => { const props = { aggs: { 'the-agg-name': agg }, groupBy: { 'the-group-by-name': groupBy }, - indexPattern: { - title: 'the-index-pattern-title', - fields: [] as any[], - } as SearchItems['indexPattern'], query: getPivotQuery('the-query'), }; - const Providers = getAppProviders(createPublicShim()); + // Using a wrapping
element because shallow() would fail + // with the Provider being the outer most component. const wrapper = shallow( - - - +
+ + + +
); expect(wrapper).toMatchSnapshot(); diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/pivot_preview.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/pivot_preview.tsx index 9b32bbbae839e..b755956eae24e 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/pivot_preview.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/pivot_preview.tsx @@ -24,6 +24,8 @@ import { import { dictionaryToArray } from '../../../../../../common/types/common'; import { getNestedProperty } from '../../../../../../common/utils/object_utils'; +import { useCurrentIndexPattern } from '../../../../lib/kibana'; + import { euiDataGridStyle, euiDataGridToolbarSettings, @@ -34,7 +36,6 @@ import { PivotGroupByConfigDict, PivotQuery, } from '../../../../common'; -import { SearchItems } from '../../../../hooks/use_search_items'; import { getPivotPreviewDevConsoleStatement, multiColumnSortFactory } from './common'; import { PIVOT_PREVIEW_STATUS, usePivotPreviewData } from './use_pivot_preview_data'; @@ -102,186 +103,184 @@ const ErrorMessage: FC = ({ message }) => ( interface PivotPreviewProps { aggs: PivotAggsConfigDict; groupBy: PivotGroupByConfigDict; - indexPattern: SearchItems['indexPattern']; query: PivotQuery; } const defaultPagination = { pageIndex: 0, pageSize: 5 }; -export const PivotPreview: FC = React.memo( - ({ aggs, groupBy, indexPattern, query }) => { - const { - previewData: data, - previewMappings, - errorMessage, - previewRequest, - status, - } = usePivotPreviewData(indexPattern, query, aggs, groupBy); - const groupByArr = dictionaryToArray(groupBy); - - // Filters mapping properties of type `object`, which get returned for nested field parents. - const columnKeys = Object.keys(previewMappings.properties).filter( - key => previewMappings.properties[key].type !== 'object' - ); - columnKeys.sort(sortColumns(groupByArr)); - - // Column visibility - const [visibleColumns, setVisibleColumns] = useState(columnKeys); - - useEffect(() => { - setVisibleColumns(columnKeys); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [JSON.stringify(columnKeys)]); - - const [pagination, setPagination] = useState(defaultPagination); - - // Reset pagination if data changes. This is to avoid ending up with an empty table - // when for example the user selected a page that is not available with the updated data. - useEffect(() => { - setPagination(defaultPagination); - }, [data.length]); - - // EuiDataGrid State - const dataGridColumns = columnKeys.map(id => ({ id })); - - const onChangeItemsPerPage = useCallback( - pageSize => { - setPagination(p => { - const pageIndex = Math.floor((p.pageSize * p.pageIndex) / pageSize); - return { pageIndex, pageSize }; - }); - }, - [setPagination] - ); +export const PivotPreview: FC = React.memo(({ aggs, groupBy, query }) => { + const indexPattern = useCurrentIndexPattern(); + + const { + previewData: data, + previewMappings, + errorMessage, + previewRequest, + status, + } = usePivotPreviewData(indexPattern, query, aggs, groupBy); + const groupByArr = dictionaryToArray(groupBy); + + // Filters mapping properties of type `object`, which get returned for nested field parents. + const columnKeys = Object.keys(previewMappings.properties).filter( + key => previewMappings.properties[key].type !== 'object' + ); + columnKeys.sort(sortColumns(groupByArr)); + + // Column visibility + const [visibleColumns, setVisibleColumns] = useState(columnKeys); + + useEffect(() => { + setVisibleColumns(columnKeys); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [JSON.stringify(columnKeys)]); + + const [pagination, setPagination] = useState(defaultPagination); + + // Reset pagination if data changes. This is to avoid ending up with an empty table + // when for example the user selected a page that is not available with the updated data. + useEffect(() => { + setPagination(defaultPagination); + }, [data.length]); + + // EuiDataGrid State + const dataGridColumns = columnKeys.map(id => ({ id })); + + const onChangeItemsPerPage = useCallback( + pageSize => { + setPagination(p => { + const pageIndex = Math.floor((p.pageSize * p.pageIndex) / pageSize); + return { pageIndex, pageSize }; + }); + }, + [setPagination] + ); - const onChangePage = useCallback(pageIndex => setPagination(p => ({ ...p, pageIndex })), [ - setPagination, - ]); + const onChangePage = useCallback(pageIndex => setPagination(p => ({ ...p, pageIndex })), [ + setPagination, + ]); - // Sorting config - const [sortingColumns, setSortingColumns] = useState([]); - const onSort = useCallback(sc => setSortingColumns(sc), [setSortingColumns]); + // Sorting config + const [sortingColumns, setSortingColumns] = useState([]); + const onSort = useCallback(sc => setSortingColumns(sc), [setSortingColumns]); - if (sortingColumns.length > 0) { - data.sort(multiColumnSortFactory(sortingColumns)); - } + if (sortingColumns.length > 0) { + data.sort(multiColumnSortFactory(sortingColumns)); + } - const pageData = data.slice( - pagination.pageIndex * pagination.pageSize, - (pagination.pageIndex + 1) * pagination.pageSize - ); + const pageData = data.slice( + pagination.pageIndex * pagination.pageSize, + (pagination.pageIndex + 1) * pagination.pageSize + ); - const renderCellValue = useMemo(() => { - return ({ - rowIndex, - columnId, - setCellProps, - }: { - rowIndex: number; - columnId: string; - setCellProps: any; - }) => { - const adjustedRowIndex = rowIndex - pagination.pageIndex * pagination.pageSize; - - const cellValue = pageData.hasOwnProperty(adjustedRowIndex) - ? getNestedProperty(pageData[adjustedRowIndex], columnId, null) - : null; - - if (typeof cellValue === 'object' && cellValue !== null) { - return JSON.stringify(cellValue); - } + const renderCellValue = useMemo(() => { + return ({ + rowIndex, + columnId, + setCellProps, + }: { + rowIndex: number; + columnId: string; + setCellProps: any; + }) => { + const adjustedRowIndex = rowIndex - pagination.pageIndex * pagination.pageSize; + + const cellValue = pageData.hasOwnProperty(adjustedRowIndex) + ? getNestedProperty(pageData[adjustedRowIndex], columnId, null) + : null; + + if (typeof cellValue === 'object' && cellValue !== null) { + return JSON.stringify(cellValue); + } - if (cellValue === undefined) { - return null; - } + if (cellValue === undefined) { + return null; + } - return cellValue; - }; - }, [pageData, pagination.pageIndex, pagination.pageSize]); - - if (status === PIVOT_PREVIEW_STATUS.ERROR) { - return ( -
- - - - -
- ); - } + return cellValue; + }; + }, [pageData, pagination.pageIndex, pagination.pageSize]); - if (data.length === 0) { - let noDataMessage = i18n.translate( - 'xpack.transform.pivotPreview.PivotPreviewNoDataCalloutBody', - { - defaultMessage: - 'The preview request did not return any data. Please ensure the optional query returns data and that values exist for the field used by group-by and aggregation fields.', - } - ); + if (status === PIVOT_PREVIEW_STATUS.ERROR) { + return ( +
+ + + + +
+ ); + } - const aggsArr = dictionaryToArray(aggs); - if (aggsArr.length === 0 || groupByArr.length === 0) { - noDataMessage = i18n.translate( - 'xpack.transform.pivotPreview.PivotPreviewIncompleteConfigCalloutBody', - { - defaultMessage: 'Please choose at least one group-by field and aggregation.', - } - ); + if (data.length === 0) { + let noDataMessage = i18n.translate( + 'xpack.transform.pivotPreview.PivotPreviewNoDataCalloutBody', + { + defaultMessage: + 'The preview request did not return any data. Please ensure the optional query returns data and that values exist for the field used by group-by and aggregation fields.', } + ); - return ( -
- - -

{noDataMessage}

-
-
+ const aggsArr = dictionaryToArray(aggs); + if (aggsArr.length === 0 || groupByArr.length === 0) { + noDataMessage = i18n.translate( + 'xpack.transform.pivotPreview.PivotPreviewIncompleteConfigCalloutBody', + { + defaultMessage: 'Please choose at least one group-by field and aggregation.', + } ); } - - if (columnKeys.length === 0) { - return null; - } - return ( -
+
-
- {status === PIVOT_PREVIEW_STATUS.LOADING && } - {status !== PIVOT_PREVIEW_STATUS.LOADING && ( - - )} -
- {dataGridColumns.length > 0 && data.length > 0 && ( - - )} + +

{noDataMessage}

+
); } -); + + if (columnKeys.length === 0) { + return null; + } + + return ( +
+ +
+ {status === PIVOT_PREVIEW_STATUS.LOADING && } + {status !== PIVOT_PREVIEW_STATUS.LOADING && ( + + )} +
+ {dataGridColumns.length > 0 && data.length > 0 && ( + + )} +
+ ); +}); diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.test.tsx index f31af733fa3ee..44edd1340e8d6 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.test.tsx @@ -7,16 +7,14 @@ import { shallow } from 'enzyme'; import React from 'react'; -import { createPublicShim } from '../../../../../shim'; -import { getAppProviders } from '../../../../app_dependencies'; +import { KibanaContext } from '../../../../lib/kibana'; + import { PivotAggsConfigDict, PivotGroupByConfigDict, PIVOT_SUPPORTED_AGGS, PIVOT_SUPPORTED_GROUP_BY_AGGS, } from '../../../../common'; -import { SearchItems } from '../../../../hooks/use_search_items'; - import { StepDefineForm, getAggNameConflictToastMessages } from './step_define_form'; // workaround to make React.memo() work with enzyme @@ -25,16 +23,18 @@ jest.mock('react', () => { return { ...r, memo: (x: any) => x }; }); -jest.mock('ui/new_platform'); jest.mock('../../../../../shared_imports'); describe('Transform: ', () => { test('Minimal initialization', () => { - const Providers = getAppProviders(createPublicShim()); + // Using a wrapping
element because shallow() would fail + // with the Provider being the outer most component. const wrapper = shallow( - - {}} searchItems={{} as SearchItems} /> - +
+ + {}} /> + +
); expect(wrapper).toMatchSnapshot(); diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx index f61f54c38680e..9b96e4b1ee758 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx @@ -26,7 +26,6 @@ import { EuiSwitch, } from '@elastic/eui'; -import { SavedSearchQuery, SearchItems } from '../../../../hooks/use_search_items'; import { useXJsonMode, xJsonMode } from '../../../../hooks/use_x_json_mode'; import { useDocumentationLinks, useToastNotifications } from '../../../../app_dependencies'; import { TransformPivotConfig } from '../../../../common'; @@ -39,6 +38,12 @@ import { PivotPreview } from './pivot_preview'; import { KqlFilterBar } from '../../../../../shared_imports'; import { SwitchModal } from './switch_modal'; +import { + useKibanaContext, + InitializedKibanaContextValue, + SavedSearchQuery, +} from '../../../../lib/kibana'; + import { getPivotQuery, getPreviewRequestBody, @@ -73,14 +78,18 @@ export interface StepDefineExposedState { const defaultSearch = '*'; const emptySearch = ''; -export function getDefaultStepDefineState(searchItems: SearchItems): StepDefineExposedState { +export function getDefaultStepDefineState( + kibanaContext: InitializedKibanaContextValue +): StepDefineExposedState { return { aggList: {} as PivotAggsConfigDict, groupByList: {} as PivotGroupByConfigDict, isAdvancedPivotEditorEnabled: false, isAdvancedSourceEditorEnabled: false, - searchString: searchItems.savedSearch !== undefined ? searchItems.combinedQuery : defaultSearch, - searchQuery: searchItems.savedSearch !== undefined ? searchItems.combinedQuery : defaultSearch, + searchString: + kibanaContext.currentSavedSearch !== undefined ? kibanaContext.combinedQuery : defaultSearch, + searchQuery: + kibanaContext.currentSavedSearch !== undefined ? kibanaContext.combinedQuery : defaultSearch, sourceConfigUpdated: false, valid: false, }; @@ -233,14 +242,14 @@ export function getAggNameConflictToastMessages( interface Props { overrides?: StepDefineExposedState; onChange(s: StepDefineExposedState): void; - searchItems: SearchItems; } -export const StepDefineForm: FC = React.memo(({ overrides = {}, onChange, searchItems }) => { +export const StepDefineForm: FC = React.memo(({ overrides = {}, onChange }) => { + const kibanaContext = useKibanaContext(); const toastNotifications = useToastNotifications(); const { esQueryDsl, esTransformPivot } = useDocumentationLinks(); - const defaults = { ...getDefaultStepDefineState(searchItems), ...overrides }; + const defaults = { ...getDefaultStepDefineState(kibanaContext), ...overrides }; // The search filter const [searchString, setSearchString] = useState(defaults.searchString); @@ -258,7 +267,7 @@ export const StepDefineForm: FC = React.memo(({ overrides = {}, onChange, // The list of selected group by fields const [groupByList, setGroupByList] = useState(defaults.groupByList); - const { indexPattern } = searchItems; + const indexPattern = kibanaContext.currentIndexPattern; const { groupByOptions, @@ -559,7 +568,7 @@ export const StepDefineForm: FC = React.memo(({ overrides = {}, onChange,
- {searchItems.savedSearch === undefined && typeof searchString === 'string' && ( + {kibanaContext.currentSavedSearch === undefined && typeof searchString === 'string' && ( = React.memo(({ overrides = {}, onChange, )} - {searchItems.savedSearch === undefined && ( + {kibanaContext.currentSavedSearch === undefined && ( @@ -711,15 +720,16 @@ export const StepDefineForm: FC = React.memo(({ overrides = {}, onChange, )} - {searchItems.savedSearch !== undefined && searchItems.savedSearch.id !== undefined && ( - - {searchItems.savedSearch.title} - - )} + {kibanaContext.currentSavedSearch !== undefined && + kibanaContext.currentSavedSearch.id !== undefined && ( + + {kibanaContext.currentSavedSearch.title} + + )} {!isAdvancedPivotEditorEnabled && ( @@ -893,14 +903,9 @@ export const StepDefineForm: FC = React.memo(({ overrides = {}, onChange, - + - + ); diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_summary.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_summary.test.tsx index e3a9830ea1904..78f6fc30f9191 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_summary.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_summary.test.tsx @@ -7,14 +7,14 @@ import { shallow } from 'enzyme'; import React from 'react'; +import { KibanaContext } from '../../../../lib/kibana'; + import { PivotAggsConfig, PivotGroupByConfig, PIVOT_SUPPORTED_AGGS, PIVOT_SUPPORTED_GROUP_BY_AGGS, } from '../../../../common'; -import { SearchItems } from '../../../../hooks/use_search_items'; - import { StepDefineExposedState } from './step_define_form'; import { StepDefineSummary } from './step_define_summary'; @@ -40,7 +40,7 @@ describe('Transform: ', () => { aggName: 'the-group-by-agg-name', dropDownName: 'the-group-by-drop-down-name', }; - const formState: StepDefineExposedState = { + const props: StepDefineExposedState = { aggList: { 'the-agg-name': agg }, groupByList: { 'the-group-by-name': groupBy }, isAdvancedPivotEditorEnabled: false, @@ -51,8 +51,14 @@ describe('Transform: ', () => { valid: true, }; + // Using a wrapping
element because shallow() would fail + // with the Provider being the outer most component. const wrapper = shallow( - +
+ + + +
); expect(wrapper).toMatchSnapshot(); diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_summary.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_summary.tsx index f8fb9db9bd686..30c447f62c760 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_summary.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_summary.tsx @@ -17,27 +17,26 @@ import { EuiText, } from '@elastic/eui'; -import { getPivotQuery } from '../../../../common'; -import { SearchItems } from '../../../../hooks/use_search_items'; +import { useKibanaContext } from '../../../../lib/kibana'; import { AggListSummary } from '../aggregation_list'; import { GroupByListSummary } from '../group_by_list'; - import { PivotPreview } from './pivot_preview'; + +import { getPivotQuery } from '../../../../common'; import { StepDefineExposedState } from './step_define_form'; const defaultSearch = '*'; const emptySearch = ''; -interface Props { - formState: StepDefineExposedState; - searchItems: SearchItems; -} - -export const StepDefineSummary: FC = ({ - formState: { searchString, searchQuery, groupByList, aggList }, - searchItems, +export const StepDefineSummary: FC = ({ + searchString, + searchQuery, + groupByList, + aggList, }) => { + const kibanaContext = useKibanaContext(); + const pivotQuery = getPivotQuery(searchQuery); let useCodeBlock = false; let displaySearch; @@ -56,8 +55,8 @@ export const StepDefineSummary: FC = ({
- {searchItems.savedSearch !== undefined && - searchItems.savedSearch.id === undefined && + {kibanaContext.currentSavedSearch !== undefined && + kibanaContext.currentSavedSearch.id === undefined && typeof searchString === 'string' && ( = ({ defaultMessage: 'Index pattern', })} > - {searchItems.indexPattern.title} + {kibanaContext.currentIndexPattern.title} {useCodeBlock === false && displaySearch !== emptySearch && ( = ({ )} - {searchItems.savedSearch !== undefined && searchItems.savedSearch.id !== undefined && ( - - {searchItems.savedSearch.title} - - )} + {kibanaContext.currentSavedSearch !== undefined && + kibanaContext.currentSavedSearch.id !== undefined && ( + + {kibanaContext.currentSavedSearch.title} + + )} = ({ - + diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx index ea9483af49302..5ae2180bfe779 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx @@ -11,15 +11,11 @@ import { i18n } from '@kbn/i18n'; import { EuiLink, EuiSwitch, EuiFieldText, EuiForm, EuiFormRow, EuiSelect } from '@elastic/eui'; import { toMountPoint } from '../../../../../../../../../../src/plugins/kibana_react/public'; +import { useKibanaContext } from '../../../../lib/kibana'; import { isValidIndexName } from '../../../../../../common/utils/es_utils'; -import { - useAppDependencies, - useDocumentationLinks, - useToastNotifications, -} from '../../../../app_dependencies'; +import { useDocumentationLinks, useToastNotifications } from '../../../../app_dependencies'; import { ToastNotificationText } from '../../../../components'; -import { SearchItems } from '../../../../hooks/use_search_items'; import { useApi } from '../../../../hooks/use_api'; import { isTransformIdValid, TransformId, TransformPivotConfig } from '../../../../common'; @@ -71,129 +67,109 @@ export function applyTransformConfigToDetailsState( interface Props { overrides?: StepDetailsExposedState; onChange(s: StepDetailsExposedState): void; - searchItems: SearchItems; } -export const StepDetailsForm: FC = React.memo( - ({ overrides = {}, onChange, searchItems }) => { - const deps = useAppDependencies(); - const toastNotifications = useToastNotifications(); - const { esIndicesCreateIndex } = useDocumentationLinks(); +export const StepDetailsForm: FC = React.memo(({ overrides = {}, onChange }) => { + const kibanaContext = useKibanaContext(); + const toastNotifications = useToastNotifications(); + const { esIndicesCreateIndex } = useDocumentationLinks(); - const defaults = { ...getDefaultStepDetailsState(), ...overrides }; + const defaults = { ...getDefaultStepDetailsState(), ...overrides }; - const [transformId, setTransformId] = useState(defaults.transformId); - const [transformDescription, setTransformDescription] = useState( - defaults.transformDescription - ); - const [destinationIndex, setDestinationIndex] = useState( - defaults.destinationIndex - ); - const [transformIds, setTransformIds] = useState([]); - const [indexNames, setIndexNames] = useState([]); - const [indexPatternTitles, setIndexPatternTitles] = useState([]); - const [createIndexPattern, setCreateIndexPattern] = useState(defaults.createIndexPattern); + const [transformId, setTransformId] = useState(defaults.transformId); + const [transformDescription, setTransformDescription] = useState( + defaults.transformDescription + ); + const [destinationIndex, setDestinationIndex] = useState(defaults.destinationIndex); + const [transformIds, setTransformIds] = useState([]); + const [indexNames, setIndexNames] = useState([]); + const [indexPatternTitles, setIndexPatternTitles] = useState([]); + const [createIndexPattern, setCreateIndexPattern] = useState(defaults.createIndexPattern); - // Continuous mode state - const [isContinuousModeEnabled, setContinuousModeEnabled] = useState( - defaults.isContinuousModeEnabled - ); + // Continuous mode state + const [isContinuousModeEnabled, setContinuousModeEnabled] = useState( + defaults.isContinuousModeEnabled + ); - const api = useApi(); + const api = useApi(); - // fetch existing transform IDs and indices once for form validation - useEffect(() => { - // use an IIFE to avoid returning a Promise to useEffect. - (async function() { - try { - setTransformIds( - (await api.getTransforms()).transforms.map( - (transform: TransformPivotConfig) => transform.id - ) - ); - } catch (e) { - toastNotifications.addDanger({ - title: i18n.translate('xpack.transform.stepDetailsForm.errorGettingTransformList', { - defaultMessage: 'An error occurred getting the existing transform IDs:', - }), - text: toMountPoint(), - }); - } + // fetch existing transform IDs and indices once for form validation + useEffect(() => { + // use an IIFE to avoid returning a Promise to useEffect. + (async function() { + try { + setTransformIds( + (await api.getTransforms()).transforms.map( + (transform: TransformPivotConfig) => transform.id + ) + ); + } catch (e) { + toastNotifications.addDanger({ + title: i18n.translate('xpack.transform.stepDetailsForm.errorGettingTransformList', { + defaultMessage: 'An error occurred getting the existing transform IDs:', + }), + text: toMountPoint(), + }); + } - try { - setIndexNames((await api.getIndices()).map(index => index.name)); - } catch (e) { - toastNotifications.addDanger({ - title: i18n.translate('xpack.transform.stepDetailsForm.errorGettingIndexNames', { - defaultMessage: 'An error occurred getting the existing index names:', - }), - text: toMountPoint(), - }); - } + try { + setIndexNames((await api.getIndices()).map(index => index.name)); + } catch (e) { + toastNotifications.addDanger({ + title: i18n.translate('xpack.transform.stepDetailsForm.errorGettingIndexNames', { + defaultMessage: 'An error occurred getting the existing index names:', + }), + text: toMountPoint(), + }); + } - try { - setIndexPatternTitles(await deps.plugins.data.indexPatterns.getTitles()); - } catch (e) { - toastNotifications.addDanger({ - title: i18n.translate( - 'xpack.transform.stepDetailsForm.errorGettingIndexPatternTitles', - { - defaultMessage: 'An error occurred getting the existing index pattern titles:', - } - ), - text: toMountPoint(), - }); - } - })(); - // run once - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + try { + setIndexPatternTitles(await kibanaContext.indexPatterns.getTitles()); + } catch (e) { + toastNotifications.addDanger({ + title: i18n.translate('xpack.transform.stepDetailsForm.errorGettingIndexPatternTitles', { + defaultMessage: 'An error occurred getting the existing index pattern titles:', + }), + text: toMountPoint(), + }); + } + })(); + // custom comparison + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [kibanaContext.initialized]); - const dateFieldNames = searchItems.indexPattern.fields - .filter(f => f.type === 'date') - .map(f => f.name) - .sort(); - const isContinuousModeAvailable = dateFieldNames.length > 0; - const [continuousModeDateField, setContinuousModeDateField] = useState( - isContinuousModeAvailable ? dateFieldNames[0] : '' - ); - const [continuousModeDelay, setContinuousModeDelay] = useState(defaults.continuousModeDelay); - const isContinuousModeDelayValid = delayValidator(continuousModeDelay); + const dateFieldNames = kibanaContext.currentIndexPattern.fields + .filter(f => f.type === 'date') + .map(f => f.name) + .sort(); + const isContinuousModeAvailable = dateFieldNames.length > 0; + const [continuousModeDateField, setContinuousModeDateField] = useState( + isContinuousModeAvailable ? dateFieldNames[0] : '' + ); + const [continuousModeDelay, setContinuousModeDelay] = useState(defaults.continuousModeDelay); + const isContinuousModeDelayValid = delayValidator(continuousModeDelay); - const transformIdExists = transformIds.some(id => transformId === id); - const transformIdEmpty = transformId === ''; - const transformIdValid = isTransformIdValid(transformId); + const transformIdExists = transformIds.some(id => transformId === id); + const transformIdEmpty = transformId === ''; + const transformIdValid = isTransformIdValid(transformId); - const indexNameExists = indexNames.some(name => destinationIndex === name); - const indexNameEmpty = destinationIndex === ''; - const indexNameValid = isValidIndexName(destinationIndex); - const indexPatternTitleExists = indexPatternTitles.some(name => destinationIndex === name); + const indexNameExists = indexNames.some(name => destinationIndex === name); + const indexNameEmpty = destinationIndex === ''; + const indexNameValid = isValidIndexName(destinationIndex); + const indexPatternTitleExists = indexPatternTitles.some(name => destinationIndex === name); - const valid = - !transformIdEmpty && - transformIdValid && - !transformIdExists && - !indexNameEmpty && - indexNameValid && - (!indexPatternTitleExists || !createIndexPattern) && - (!isContinuousModeAvailable || (isContinuousModeAvailable && isContinuousModeDelayValid)); + const valid = + !transformIdEmpty && + transformIdValid && + !transformIdExists && + !indexNameEmpty && + indexNameValid && + (!indexPatternTitleExists || !createIndexPattern) && + (!isContinuousModeAvailable || (isContinuousModeAvailable && isContinuousModeDelayValid)); - // expose state to wizard - useEffect(() => { - onChange({ - continuousModeDateField, - continuousModeDelay, - createIndexPattern, - isContinuousModeEnabled, - transformId, - transformDescription, - destinationIndex, - touched: true, - valid, - }); - // custom comparison - /* eslint-disable react-hooks/exhaustive-deps */ - }, [ + // expose state to wizard + useEffect(() => { + onChange({ continuousModeDateField, continuousModeDelay, createIndexPattern, @@ -201,223 +177,232 @@ export const StepDetailsForm: FC = React.memo( transformId, transformDescription, destinationIndex, + touched: true, valid, - /* eslint-enable react-hooks/exhaustive-deps */ - ]); + }); + // custom comparison + /* eslint-disable react-hooks/exhaustive-deps */ + }, [ + continuousModeDateField, + continuousModeDelay, + createIndexPattern, + isContinuousModeEnabled, + transformId, + transformDescription, + destinationIndex, + valid, + /* eslint-enable react-hooks/exhaustive-deps */ + ]); - return ( -
- - + + + setTransformId(e.target.value)} + aria-label={i18n.translate( + 'xpack.transform.stepDetailsForm.transformIdInputAriaLabel', + { + defaultMessage: 'Choose a unique transform ID.', + } + )} isInvalid={(!transformIdEmpty && !transformIdValid) || transformIdExists} - error={[ - ...(!transformIdEmpty && !transformIdValid - ? [ - i18n.translate('xpack.transform.stepDetailsForm.transformIdInvalidError', { - defaultMessage: - 'Must contain lowercase alphanumeric characters (a-z and 0-9), hyphens, and underscores only and must start and end with alphanumeric characters.', - }), - ] - : []), - ...(transformIdExists - ? [ - i18n.translate('xpack.transform.stepDetailsForm.transformIdExistsError', { - defaultMessage: 'A transform with this ID already exists.', - }), - ] - : []), - ]} - > - setTransformId(e.target.value)} - aria-label={i18n.translate( - 'xpack.transform.stepDetailsForm.transformIdInputAriaLabel', - { - defaultMessage: 'Choose a unique transform ID.', - } - )} - isInvalid={(!transformIdEmpty && !transformIdValid) || transformIdExists} - data-test-subj="transformIdInput" - /> - - + + + setTransformDescription(e.target.value)} + aria-label={i18n.translate( + 'xpack.transform.stepDetailsForm.transformDescriptionInputAriaLabel', { - defaultMessage: 'Optional descriptive text.', + defaultMessage: 'Choose an optional transform description.', } )} - > - setTransformDescription(e.target.value)} - aria-label={i18n.translate( - 'xpack.transform.stepDetailsForm.transformDescriptionInputAriaLabel', + data-test-subj="transformDescriptionInput" + /> + + + {i18n.translate('xpack.transform.stepDetailsForm.destinationIndexInvalidError', { + defaultMessage: 'Invalid destination index name.', + })} +
+ + {i18n.translate( + 'xpack.transform.stepDetailsForm.destinationIndexInvalidErrorLink', + { + defaultMessage: 'Learn more about index name limitations.', + } + )} + + , + ] + } + > + setDestinationIndex(e.target.value)} + aria-label={i18n.translate( + 'xpack.transform.stepDetailsForm.destinationIndexInputAriaLabel', + { + defaultMessage: 'Choose a unique destination index name.', + } + )} + isInvalid={!indexNameEmpty && !indexNameValid} + data-test-subj="transformDestinationIndexInput" + /> +
+ + setCreateIndexPattern(!createIndexPattern)} + data-test-subj="transformCreateIndexPatternSwitch" + /> + + + setContinuousModeEnabled(!isContinuousModeEnabled)} + disabled={isContinuousModeAvailable === false} + data-test-subj="transformContinuousModeSwitch" + /> + + {isContinuousModeEnabled && ( + + - - - {i18n.translate('xpack.transform.stepDetailsForm.destinationIndexInvalidError', { - defaultMessage: 'Invalid destination index name.', - })} -
- - {i18n.translate( - 'xpack.transform.stepDetailsForm.destinationIndexInvalidErrorLink', - { - defaultMessage: 'Learn more about index name limitations.', - } - )} - -
, - ] - } - > - setDestinationIndex(e.target.value)} - aria-label={i18n.translate( - 'xpack.transform.stepDetailsForm.destinationIndexInputAriaLabel', + helpText={i18n.translate( + 'xpack.transform.stepDetailsForm.continuousModeDateFieldHelpText', { - defaultMessage: 'Choose a unique destination index name.', + defaultMessage: + 'Select the date field that can be used to identify new documents.', } )} - isInvalid={!indexNameEmpty && !indexNameValid} - data-test-subj="transformDestinationIndexInput" - /> -
- - setCreateIndexPattern(!createIndexPattern)} - data-test-subj="transformCreateIndexPatternSwitch" - /> - - - + ({ text }))} + value={continuousModeDateField} + onChange={e => setContinuousModeDateField(e.target.value)} + data-test-subj="transformContinuousDateFieldSelect" + /> + + setContinuousModeEnabled(!isContinuousModeEnabled)} - disabled={isContinuousModeAvailable === false} - data-test-subj="transformContinuousModeSwitch" - /> - - {isContinuousModeEnabled && ( - - - ({ text }))} - value={continuousModeDateField} - onChange={e => setContinuousModeDateField(e.target.value)} - data-test-subj="transformContinuousDateFieldSelect" - /> - - + setContinuousModeDelay(e.target.value)} + aria-label={i18n.translate( + 'xpack.transform.stepDetailsForm.continuousModeAriaLabel', { - defaultMessage: 'Time delay between current time and latest input data time.', + defaultMessage: 'Choose a delay.', } )} - > - setContinuousModeDelay(e.target.value)} - aria-label={i18n.translate( - 'xpack.transform.stepDetailsForm.continuousModeAriaLabel', - { - defaultMessage: 'Choose a delay.', - } - )} - isInvalid={!isContinuousModeDelayValid} - data-test-subj="transformContinuousDelayInput" - /> - - - )} -
-
- ); - } -); + isInvalid={!isContinuousModeDelayValid} + data-test-subj="transformContinuousDelayInput" + /> +
+ + )} +
+
+ ); +}); diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/wizard/wizard.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/wizard/wizard.tsx index 0773ecbb1d8d3..f1861755d9742 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/wizard/wizard.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/wizard/wizard.tsx @@ -10,8 +10,9 @@ import { i18n } from '@kbn/i18n'; import { EuiSteps, EuiStepStatus } from '@elastic/eui'; +import { useKibanaContext } from '../../../../lib/kibana'; + import { getCreateRequestBody, TransformPivotConfig } from '../../../../common'; -import { SearchItems } from '../../../../hooks/use_search_items'; import { applyTransformConfigToDefineState, @@ -45,7 +46,6 @@ interface DefinePivotStepProps { stepDefineState: StepDefineExposedState; setCurrentStep: React.Dispatch>; setStepDefineState: React.Dispatch>; - searchItems: SearchItems; } const StepDefine: FC = ({ @@ -53,7 +53,6 @@ const StepDefine: FC = ({ stepDefineState, setCurrentStep, setStepDefineState, - searchItems, }) => { const definePivotRef = useRef(null); @@ -62,36 +61,31 @@ const StepDefine: FC = ({
{isCurrentStep && ( - + setCurrentStep(WIZARD_STEPS.DETAILS)} nextActive={stepDefineState.valid} /> )} - {!isCurrentStep && ( - - )} + {!isCurrentStep && } ); }; interface WizardProps { cloneConfig?: TransformPivotConfig; - searchItems: SearchItems; } -export const Wizard: FC = React.memo(({ cloneConfig, searchItems }) => { +export const Wizard: FC = React.memo(({ cloneConfig }) => { + const kibanaContext = useKibanaContext(); + // The current WIZARD_STEP const [currentStep, setCurrentStep] = useState(WIZARD_STEPS.DEFINE); // The DEFINE state const [stepDefineState, setStepDefineState] = useState( - applyTransformConfigToDefineState(getDefaultStepDefineState(searchItems), cloneConfig) + applyTransformConfigToDefineState(getDefaultStepDefineState(kibanaContext), cloneConfig) ); // The DETAILS state @@ -101,11 +95,7 @@ export const Wizard: FC = React.memo(({ cloneConfig, searchItems }) const stepDetails = currentStep === WIZARD_STEPS.DETAILS ? ( - + ) : ( ); @@ -132,7 +122,7 @@ export const Wizard: FC = React.memo(({ cloneConfig, searchItems }) } }, []); - const { indexPattern } = searchItems; + const indexPattern = kibanaContext.currentIndexPattern; const transformConfig = getCreateRequestBody( indexPattern.title, @@ -164,7 +154,6 @@ export const Wizard: FC = React.memo(({ cloneConfig, searchItems }) stepDefineState={stepDefineState} setCurrentStep={setCurrentStep} setStepDefineState={setStepDefineState} - searchItems={searchItems} /> ), }, diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/create_transform_section.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/create_transform_section.tsx index d09fc0913590e..5196f281adf0a 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/create_transform_section.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/create_transform_section.tsx @@ -22,9 +22,9 @@ import { import { APP_CREATE_TRANSFORM_CLUSTER_PRIVILEGES } from '../../../../common/constants'; import { useDocumentationLinks } from '../../app_dependencies'; -import { useSearchItems } from '../../hooks/use_search_items'; import { breadcrumbService, docTitleService, BREADCRUMB_SECTION } from '../../services/navigation'; import { PrivilegesWrapper } from '../../lib/authorization'; +import { KibanaProvider, RenderOnlyWithInitializedKibanaContext } from '../../lib/kibana'; import { Wizard } from './components/wizard'; @@ -38,41 +38,43 @@ export const CreateTransformSection: FC = ({ match }) => { const { esTransform } = useDocumentationLinks(); - const { searchItems } = useSearchItems(match.params.savedObjectId); - return ( - - - - -

- -

-
- - - - - -
-
- - - {searchItems !== undefined && } - -
+ + + + + +

+ +

+
+ + + + + +
+
+ + + + + + +
+
); }; diff --git a/x-pack/legacy/plugins/transform/public/plugin.ts b/x-pack/legacy/plugins/transform/public/plugin.ts index 7b5fbbb4a2151..23fad00fb0786 100644 --- a/x-pack/legacy/plugins/transform/public/plugin.ts +++ b/x-pack/legacy/plugins/transform/public/plugin.ts @@ -11,6 +11,7 @@ import { breadcrumbService } from './app/services/navigation'; import { docTitleService } from './app/services/navigation'; import { textService } from './app/services/text'; import { uiMetricService } from './app/services/ui_metric'; +import { createSavedSearchesLoader } from '../../../../../src/plugins/discover/public'; export class Plugin { public start(core: ShimCore, plugins: ShimPlugins): void { @@ -26,7 +27,7 @@ export class Plugin { savedObjects, overlays, } = core; - const { data, management, uiMetric, xsrfToken } = plugins; + const { data, management, savedSearches: coreSavedSearches, uiMetric, xsrfToken } = plugins; // AppCore/AppPlugins to be passed on as React context const appDependencies = { @@ -45,6 +46,7 @@ export class Plugin { plugins: { data, management, + savedSearches: coreSavedSearches, xsrfToken, }, }; @@ -59,6 +61,14 @@ export class Plugin { }), order: 3, mount(params) { + const savedSearches = createSavedSearchesLoader({ + savedObjectsClient: core.savedObjects.client, + indexPatterns: plugins.data.indexPatterns, + chrome: core.chrome, + overlays: core.overlays, + }); + coreSavedSearches.setClient(savedSearches); + breadcrumbService.setup(params.setBreadcrumbs); params.setBreadcrumbs([ { diff --git a/x-pack/legacy/plugins/transform/public/shared_imports.ts b/x-pack/legacy/plugins/transform/public/shared_imports.ts index 1ca71f8c4aa77..b077cd8836c4b 100644 --- a/x-pack/legacy/plugins/transform/public/shared_imports.ts +++ b/x-pack/legacy/plugins/transform/public/shared_imports.ts @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -export { createSavedSearchesLoader } from '../../../../../src/plugins/discover/public'; export { XJsonMode } from '../../../../plugins/es_ui_shared/console_lang/ace/modes/x_json'; export { collapseLiteralStrings, diff --git a/x-pack/legacy/plugins/transform/public/shim.ts b/x-pack/legacy/plugins/transform/public/shim.ts index 9941aabcf3255..05f7626e25e9d 100644 --- a/x-pack/legacy/plugins/transform/public/shim.ts +++ b/x-pack/legacy/plugins/transform/public/shim.ts @@ -13,6 +13,7 @@ import { docTitle } from 'ui/doc_title/doc_title'; import { createUiStatsReporter } from '../../../../../src/legacy/core_plugins/ui_metric/public'; import { TRANSFORM_DOC_PATHS } from './app/constants'; +import { SavedSearchLoader } from '../../../../../src/plugins/discover/public'; export type NpCore = typeof npStart.core; export type NpPlugins = typeof npStart.plugins; @@ -32,7 +33,7 @@ export type AppCore = Pick< | 'overlays' | 'notifications' >; -export type AppPlugins = Pick; +export type AppPlugins = Pick; export interface AppDependencies { core: AppCore; @@ -60,10 +61,18 @@ export interface ShimPlugins extends NpPlugins { uiMetric: { createUiStatsReporter: typeof createUiStatsReporter; }; + savedSearches: { + getClient(): any; + setClient(client: any): void; + }; xsrfToken: string; } export function createPublicShim(): { core: ShimCore; plugins: ShimPlugins } { + // This is an Angular service, which is why we use this provider pattern + // to access it within our React app. + let savedSearches: SavedSearchLoader; + const { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } = npStart.core.docLinks; return { @@ -85,6 +94,12 @@ export function createPublicShim(): { core: ShimCore; plugins: ShimPlugins } { }, plugins: { ...npStart.plugins, + savedSearches: { + setClient: (client: any): void => { + savedSearches = client; + }, + getClient: (): any => savedSearches, + }, uiMetric: { createUiStatsReporter, },