From 123f3400a82f89a7be5a6c2d9526e62102530c47 Mon Sep 17 00:00:00 2001 From: Scotty Bollinger Date: Mon, 5 Apr 2021 10:19:32 -0500 Subject: [PATCH 01/26] [Workplace Search] Add sub nav and fix rendering bugs in Personal dashboard (#96100) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix route for private deferated source summary * Make schema types nullable Federated sources don’t have counts and the server returns null so our routes have to expect that sometimes these values will be null * Add SourceSubNav to Personal dashboard We are able to leverage the existing component with a couple a small change; the existing componet is a subnav in the larger Enterprise Search shared navigation component and does not include its styles. This caused the list items to render with bullet points next to them. Adding this class and displaying the nav items as block elements fixes this issue. Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../views/content_sources/components/source_sub_nav.tsx | 4 ++-- .../views/content_sources/private_sources_layout.test.tsx | 3 +++ .../views/content_sources/private_sources_layout.tsx | 3 +++ .../views/content_sources/source_logic.test.ts | 2 +- .../workplace_search/views/content_sources/source_logic.ts | 2 +- .../workplace_search/views/content_sources/sources.scss | 6 ++++++ .../server/routes/workplace_search/sources.ts | 6 +++--- 7 files changed, 19 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_sub_nav.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_sub_nav.tsx index 99cebd5ded585a..bf0c5471f7b574 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_sub_nav.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_sub_nav.tsx @@ -33,7 +33,7 @@ export const SourceSubNav: React.FC = () => { const isCustom = serviceType === CUSTOM_SERVICE_TYPE; return ( - <> +
{NAV.OVERVIEW} @@ -53,6 +53,6 @@ export const SourceSubNav: React.FC = () => { {NAV.SETTINGS} - +
); }; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/private_sources_layout.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/private_sources_layout.test.tsx index 488eb4b49853bd..9e3b50ea083eb9 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/private_sources_layout.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/private_sources_layout.test.tsx @@ -17,6 +17,8 @@ import { EuiCallOut } from '@elastic/eui'; import { ViewContentHeader } from '../../components/shared/view_content_header'; +import { SourceSubNav } from './components/source_sub_nav'; + import { PRIVATE_CAN_CREATE_PAGE_TITLE, PRIVATE_VIEW_ONLY_PAGE_TITLE, @@ -40,6 +42,7 @@ describe('PrivateSourcesLayout', () => { const wrapper = shallow({children}); expect(wrapper.find('[data-test-subj="TestChildren"]')).toHaveLength(1); + expect(wrapper.find(SourceSubNav)).toHaveLength(1); }); it('uses correct title and description when private sources are enabled', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/private_sources_layout.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/private_sources_layout.tsx index bdc2421432c8a3..2a6281075dc400 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/private_sources_layout.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/private_sources_layout.tsx @@ -14,6 +14,8 @@ import { EuiPage, EuiPageSideBar, EuiPageBody, EuiCallOut } from '@elastic/eui'; import { AppLogic } from '../../app_logic'; import { ViewContentHeader } from '../../components/shared/view_content_header'; +import { SourceSubNav } from './components/source_sub_nav'; + import { PRIVATE_DASHBOARD_READ_ONLY_MODE_WARNING, PRIVATE_CAN_CREATE_PAGE_TITLE, @@ -49,6 +51,7 @@ export const PrivateSourcesLayout: React.FC = ({ + {readOnlyMode && ( diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/source_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/source_logic.test.ts index d20d0576d11ce4..a9712cc4e1dc09 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/source_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/source_logic.test.ts @@ -214,7 +214,7 @@ describe('SourceLogic', () => { SourceLogic.actions.initializeFederatedSummary(contentSource.id); expect(http.get).toHaveBeenCalledWith( - '/api/workplace_search/org/sources/123/federated_summary' + '/api/workplace_search/account/sources/123/federated_summary' ); await promise; expect(onUpdateSummarySpy).toHaveBeenCalledWith(contentSource.summary); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/source_logic.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/source_logic.ts index 72700ce42c75d9..3da90c4fc77392 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/source_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/source_logic.ts @@ -156,7 +156,7 @@ export const SourceLogic = kea>({ } }, initializeFederatedSummary: async ({ sourceId }) => { - const route = `/api/workplace_search/org/sources/${sourceId}/federated_summary`; + const route = `/api/workplace_search/account/sources/${sourceId}/federated_summary`; try { const response = await HttpLogic.values.http.get(route); actions.onUpdateSummary(response.summary); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources.scss b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources.scss index f142567fb621f0..abab139e32369a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources.scss +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources.scss @@ -30,3 +30,9 @@ margin-left: -$sideBarWidth; } } + +.sourcesSubNav { + li { + display: block; + } +} diff --git a/x-pack/plugins/enterprise_search/server/routes/workplace_search/sources.ts b/x-pack/plugins/enterprise_search/server/routes/workplace_search/sources.ts index 8257dd0dc52b09..1dd6d859d88ade 100644 --- a/x-pack/plugins/enterprise_search/server/routes/workplace_search/sources.ts +++ b/x-pack/plugins/enterprise_search/server/routes/workplace_search/sources.ts @@ -22,9 +22,9 @@ const schemaValuesSchema = schema.recordOf( ); const pageSchema = schema.object({ - current: schema.number(), - size: schema.number(), - total_pages: schema.number(), + current: schema.nullable(schema.number()), + size: schema.nullable(schema.number()), + total_pages: schema.nullable(schema.number()), total_results: schema.number(), }); From ea03eb1bab086b6e6e526d8c1eb11ffa877d7d52 Mon Sep 17 00:00:00 2001 From: Scotty Bollinger Date: Mon, 5 Apr 2021 10:27:05 -0500 Subject: [PATCH 02/26] [Enterprise Search] Expose core.chrome.setIsVisible for use in Workplace Search (#95984) * Hide chrome for Workplace Search by default The Workplace Search Personal dashboard needs the chrome hidden. We hide it globally here first to prevent a flash of chrome on the Personal dashboard and unhide it for admin routes, which will be in a future commit * Add core.chrome.setIsVisible to KibanaLogic * Toggle chrome visibility for Workplace Search * Add test * Refactor to set context and chrome when pathname changes Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../applications/__mocks__/kibana_logic.mock.ts | 1 + .../enterprise_search/public/applications/index.tsx | 1 + .../applications/shared/kibana/kibana_logic.ts | 2 ++ .../applications/workplace_search/index.test.tsx | 4 +++- .../public/applications/workplace_search/index.tsx | 12 +++++++----- x-pack/plugins/enterprise_search/public/plugin.ts | 3 +++ 6 files changed, 17 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/enterprise_search/public/applications/__mocks__/kibana_logic.mock.ts b/x-pack/plugins/enterprise_search/public/applications/__mocks__/kibana_logic.mock.ts index 133f704fd59a9b..2325ddcf2b2704 100644 --- a/x-pack/plugins/enterprise_search/public/applications/__mocks__/kibana_logic.mock.ts +++ b/x-pack/plugins/enterprise_search/public/applications/__mocks__/kibana_logic.mock.ts @@ -19,6 +19,7 @@ export const mockKibanaValues = { history: mockHistory, navigateToUrl: jest.fn(), setBreadcrumbs: jest.fn(), + setChromeIsVisible: jest.fn(), setDocTitle: jest.fn(), renderHeaderActions: jest.fn(), }; diff --git a/x-pack/plugins/enterprise_search/public/applications/index.tsx b/x-pack/plugins/enterprise_search/public/applications/index.tsx index 155ff5b92ba277..c2bf77751528ae 100644 --- a/x-pack/plugins/enterprise_search/public/applications/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/index.tsx @@ -49,6 +49,7 @@ export const renderApp = ( history: params.history, navigateToUrl: core.application.navigateToUrl, setBreadcrumbs: core.chrome.setBreadcrumbs, + setChromeIsVisible: core.chrome.setIsVisible, setDocTitle: core.chrome.docTitle.change, renderHeaderActions: (HeaderActions) => params.setHeaderActionMenu((el) => renderHeaderActions(HeaderActions, store, el)), diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.ts b/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.ts index 8015d22f7c44ab..2bef7d373f1606 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.ts @@ -24,6 +24,7 @@ interface KibanaLogicProps { charts: ChartsPluginStart; navigateToUrl: ApplicationStart['navigateToUrl']; setBreadcrumbs(crumbs: ChromeBreadcrumb[]): void; + setChromeIsVisible(isVisible: boolean): void; setDocTitle(title: string): void; renderHeaderActions(HeaderActions: FC): void; } @@ -47,6 +48,7 @@ export const KibanaLogic = kea>({ {}, ], setBreadcrumbs: [props.setBreadcrumbs, {}], + setChromeIsVisible: [props.setChromeIsVisible, {}], setDocTitle: [props.setDocTitle, {}], renderHeaderActions: [props.renderHeaderActions, {}], }), diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.test.tsx index 48bdcd6551b650..a2c0ec18def4b8 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.test.tsx @@ -57,11 +57,13 @@ describe('WorkplaceSearchConfigured', () => { setMockActions({ initializeAppData, setContext }); }); - it('renders layout and header actions', () => { + it('renders layout, chrome, and header actions', () => { const wrapper = shallow(); expect(wrapper.find(Layout).first().prop('readOnlyMode')).toBeFalsy(); expect(wrapper.find(OverviewMVP)).toHaveLength(1); + + expect(mockKibanaValues.setChromeIsVisible).toHaveBeenCalledWith(true); expect(mockKibanaValues.renderHeaderActions).toHaveBeenCalledWith(WorkplaceSearchHeaderActions); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.tsx index c269a987dc0927..7a76de43be41ba 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.tsx @@ -53,7 +53,7 @@ export const WorkplaceSearch: React.FC = (props) => { export const WorkplaceSearchConfigured: React.FC = (props) => { const { hasInitialized } = useValues(AppLogic); const { initializeAppData, setContext } = useActions(AppLogic); - const { renderHeaderActions } = useValues(KibanaLogic); + const { renderHeaderActions, setChromeIsVisible } = useValues(KibanaLogic); const { errorConnecting, readOnlyMode } = useValues(HttpLogic); const { pathname } = useLocation(); @@ -66,11 +66,13 @@ export const WorkplaceSearchConfigured: React.FC = (props) => { * Personal dashboard urls begin with /p/ * EX: http://localhost:5601/app/enterprise_search/workplace_search/p/sources */ - const personalSourceUrlRegex = /^\/p\//g; // matches '/p/*' + useEffect(() => { + const personalSourceUrlRegex = /^\/p\//g; // matches '/p/*' + const isOrganization = !pathname.match(personalSourceUrlRegex); // TODO: Once auth is figured out, we need to have a check for the equivilent of `isAdmin`. - // TODO: Once auth is figured out, we need to have a check for the equivilent of `isAdmin`. - const isOrganization = !pathname.match(personalSourceUrlRegex); - setContext(isOrganization); + setContext(isOrganization); + setChromeIsVisible(isOrganization); + }, [pathname]); useEffect(() => { if (!hasInitialized) { diff --git a/x-pack/plugins/enterprise_search/public/plugin.ts b/x-pack/plugins/enterprise_search/public/plugin.ts index f00e81a5accf72..dd1a62d243d030 100644 --- a/x-pack/plugins/enterprise_search/public/plugin.ts +++ b/x-pack/plugins/enterprise_search/public/plugin.ts @@ -114,6 +114,9 @@ export class EnterpriseSearchPlugin implements Plugin { const { chrome, http } = kibanaDeps.core; chrome.docTitle.change(WORKPLACE_SEARCH_PLUGIN.NAME); + // The Workplace Search Personal dashboard needs the chrome hidden. We hide it globally + // here first to prevent a flash of chrome on the Personal dashboard and unhide it for admin routes. + chrome.setIsVisible(false); await this.getInitialData(http); const pluginData = this.getPluginData(); From 95e45ddebc6e86bb3d63f04bd7c4e56ad8ef55bb Mon Sep 17 00:00:00 2001 From: Pierre Gayvallet Date: Mon, 5 Apr 2021 18:00:13 +0200 Subject: [PATCH 03/26] Use plugin version in its publicPath (#95945) * Use plugin version in its publicPath * remove useless comment * fix types * update generated doc --- .../register_bundle_routes.test.ts | 15 +++++++------ .../bundle_routes/register_bundle_routes.ts | 8 +++---- src/core/server/legacy/legacy_service.test.ts | 1 + .../server/plugins/plugins_service.test.ts | 14 ++++++++++--- src/core/server/plugins/plugins_service.ts | 1 + src/core/server/plugins/plugins_system.ts | 1 + src/core/server/plugins/types.ts | 13 +++++++++--- .../bootstrap/get_plugin_bundle_paths.test.ts | 21 ++++++++++++------- .../bootstrap/get_plugin_bundle_paths.ts | 10 +++++++-- src/core/server/server.api.md | 8 +++---- 10 files changed, 63 insertions(+), 29 deletions(-) diff --git a/src/core/server/core_app/bundle_routes/register_bundle_routes.test.ts b/src/core/server/core_app/bundle_routes/register_bundle_routes.test.ts index d51c3691469575..830f4a9a943645 100644 --- a/src/core/server/core_app/bundle_routes/register_bundle_routes.test.ts +++ b/src/core/server/core_app/bundle_routes/register_bundle_routes.test.ts @@ -10,7 +10,7 @@ import { registerRouteForBundleMock } from './register_bundle_routes.test.mocks' import { PackageInfo } from '@kbn/config'; import { httpServiceMock } from '../../http/http_service.mock'; -import { UiPlugins } from '../../plugins'; +import { InternalPluginInfo, UiPlugins } from '../../plugins'; import { registerBundleRoutes } from './register_bundle_routes'; import { FileHashCache } from './file_hash_cache'; @@ -29,9 +29,12 @@ const createUiPlugins = (...ids: string[]): UiPlugins => ({ internal: ids.reduce((map, id) => { map.set(id, { publicTargetDir: `/plugins/${id}/public-target-dir`, + publicAssetsDir: `/plugins/${id}/public-assets-dir`, + version: '8.0.0', + requiredBundles: [], }); return map; - }, new Map()), + }, new Map()), }); describe('registerBundleRoutes', () => { @@ -86,16 +89,16 @@ describe('registerBundleRoutes', () => { fileHashCache: expect.any(FileHashCache), isDist: true, bundlesPath: '/plugins/plugin-a/public-target-dir', - publicPath: '/server-base-path/42/bundles/plugin/plugin-a/', - routePath: '/42/bundles/plugin/plugin-a/', + publicPath: '/server-base-path/42/bundles/plugin/plugin-a/8.0.0/', + routePath: '/42/bundles/plugin/plugin-a/8.0.0/', }); expect(registerRouteForBundleMock).toHaveBeenCalledWith(router, { fileHashCache: expect.any(FileHashCache), isDist: true, bundlesPath: '/plugins/plugin-b/public-target-dir', - publicPath: '/server-base-path/42/bundles/plugin/plugin-b/', - routePath: '/42/bundles/plugin/plugin-b/', + publicPath: '/server-base-path/42/bundles/plugin/plugin-b/8.0.0/', + routePath: '/42/bundles/plugin/plugin-b/8.0.0/', }); }); }); diff --git a/src/core/server/core_app/bundle_routes/register_bundle_routes.ts b/src/core/server/core_app/bundle_routes/register_bundle_routes.ts index ee54f8ef34622e..df46753747f5b8 100644 --- a/src/core/server/core_app/bundle_routes/register_bundle_routes.ts +++ b/src/core/server/core_app/bundle_routes/register_bundle_routes.ts @@ -27,7 +27,7 @@ import { registerRouteForBundle } from './bundles_route'; */ export function registerBundleRoutes({ router, - serverBasePath, // serverBasePath + serverBasePath, uiPlugins, packageInfo, }: { @@ -57,10 +57,10 @@ export function registerBundleRoutes({ isDist, }); - [...uiPlugins.internal.entries()].forEach(([id, { publicTargetDir }]) => { + [...uiPlugins.internal.entries()].forEach(([id, { publicTargetDir, version }]) => { registerRouteForBundle(router, { - publicPath: `${serverBasePath}/${buildNum}/bundles/plugin/${id}/`, - routePath: `/${buildNum}/bundles/plugin/${id}/`, + publicPath: `${serverBasePath}/${buildNum}/bundles/plugin/${id}/${version}/`, + routePath: `/${buildNum}/bundles/plugin/${id}/${version}/`, bundlesPath: publicTargetDir, fileHashCache, isDist, diff --git a/src/core/server/legacy/legacy_service.test.ts b/src/core/server/legacy/legacy_service.test.ts index d0a02b9859960b..67b5393f0b8381 100644 --- a/src/core/server/legacy/legacy_service.test.ts +++ b/src/core/server/legacy/legacy_service.test.ts @@ -91,6 +91,7 @@ beforeEach(() => { 'plugin-id', { requiredBundles: [], + version: '8.0.0', publicTargetDir: 'path/to/target/public', publicAssetsDir: '/plugins/name/assets/', }, diff --git a/src/core/server/plugins/plugins_service.test.ts b/src/core/server/plugins/plugins_service.test.ts index 2d54648d229502..6bf7a1fadb4d3c 100644 --- a/src/core/server/plugins/plugins_service.test.ts +++ b/src/core/server/plugins/plugins_service.test.ts @@ -562,12 +562,12 @@ describe('PluginsService', () => { plugin$: from([ createPlugin('plugin-1', { path: 'path-1', - version: 'some-version', + version: 'version-1', configPath: 'plugin1', }), createPlugin('plugin-2', { path: 'path-2', - version: 'some-version', + version: 'version-2', configPath: 'plugin2', }), ]), @@ -577,7 +577,7 @@ describe('PluginsService', () => { }); describe('uiPlugins.internal', () => { - it('includes disabled plugins', async () => { + it('contains internal properties for plugins', async () => { config$.next({ plugins: { initialize: true }, plugin1: { enabled: false } }); const { uiPlugins } = await pluginsService.discover({ environment: environmentSetup }); expect(uiPlugins.internal).toMatchInlineSnapshot(` @@ -586,15 +586,23 @@ describe('PluginsService', () => { "publicAssetsDir": /path-1/public/assets, "publicTargetDir": /path-1/target/public, "requiredBundles": Array [], + "version": "version-1", }, "plugin-2" => Object { "publicAssetsDir": /path-2/public/assets, "publicTargetDir": /path-2/target/public, "requiredBundles": Array [], + "version": "version-2", }, } `); }); + + it('includes disabled plugins', async () => { + config$.next({ plugins: { initialize: true }, plugin1: { enabled: false } }); + const { uiPlugins } = await pluginsService.discover({ environment: environmentSetup }); + expect([...uiPlugins.internal.keys()].sort()).toEqual(['plugin-1', 'plugin-2']); + }); }); describe('plugin initialization', () => { diff --git a/src/core/server/plugins/plugins_service.ts b/src/core/server/plugins/plugins_service.ts index 8b33e2cf4cc6be..09be40ecaf2a2c 100644 --- a/src/core/server/plugins/plugins_service.ts +++ b/src/core/server/plugins/plugins_service.ts @@ -222,6 +222,7 @@ export class PluginsService implements CoreService(); diff --git a/src/core/server/plugins/types.ts b/src/core/server/plugins/types.ts index a6086bd6f17e8e..3a01049c5e1fe3 100644 --- a/src/core/server/plugins/types.ts +++ b/src/core/server/plugins/types.ts @@ -224,12 +224,15 @@ export interface DiscoveredPlugin { */ export interface InternalPluginInfo { /** - * Bundles that must be loaded for this plugoin + * Version of the plugin + */ + readonly version: string; + /** + * Bundles that must be loaded for this plugin */ readonly requiredBundles: readonly string[]; /** - * Path to the target/public directory of the plugin which should be - * served + * Path to the target/public directory of the plugin which should be served */ readonly publicTargetDir: string; /** @@ -250,7 +253,9 @@ export interface Plugin< TPluginsStart extends object = object > { setup(core: CoreSetup, plugins: TPluginsSetup): TSetup; + start(core: CoreStart, plugins: TPluginsStart): TStart; + stop?(): void; } @@ -267,7 +272,9 @@ export interface AsyncPlugin< TPluginsStart extends object = object > { setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise; + start(core: CoreStart, plugins: TPluginsStart): TStart | Promise; + stop?(): void; } diff --git a/src/core/server/rendering/bootstrap/get_plugin_bundle_paths.test.ts b/src/core/server/rendering/bootstrap/get_plugin_bundle_paths.test.ts index ea3843884df317..0abd8fd5a00576 100644 --- a/src/core/server/rendering/bootstrap/get_plugin_bundle_paths.test.ts +++ b/src/core/server/rendering/bootstrap/get_plugin_bundle_paths.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { UiPlugins } from '../../plugins'; +import { InternalPluginInfo, UiPlugins } from '../../plugins'; import { getPluginsBundlePaths } from './get_plugin_bundle_paths'; const createUiPlugins = (pluginDeps: Record) => { @@ -16,12 +16,13 @@ const createUiPlugins = (pluginDeps: Record) => { browserConfigs: new Map(), }; - Object.entries(pluginDeps).forEach(([pluginId, deps]) => { + const addPlugin = (pluginId: string, deps: string[]) => { uiPlugins.internal.set(pluginId, { requiredBundles: deps, + version: '8.0.0', publicTargetDir: '', publicAssetsDir: '', - } as any); + } as InternalPluginInfo); uiPlugins.public.set(pluginId, { id: pluginId, configPath: 'config-path', @@ -29,6 +30,12 @@ const createUiPlugins = (pluginDeps: Record) => { requiredPlugins: [], requiredBundles: deps, }); + + deps.forEach((dep) => addPlugin(dep, [])); + }; + + Object.entries(pluginDeps).forEach(([pluginId, deps]) => { + addPlugin(pluginId, deps); }); return uiPlugins; @@ -56,13 +63,13 @@ describe('getPluginsBundlePaths', () => { }); expect(pluginBundlePaths.get('a')).toEqual({ - bundlePath: '/regular-bundle-path/plugin/a/a.plugin.js', - publicPath: '/regular-bundle-path/plugin/a/', + bundlePath: '/regular-bundle-path/plugin/a/8.0.0/a.plugin.js', + publicPath: '/regular-bundle-path/plugin/a/8.0.0/', }); expect(pluginBundlePaths.get('b')).toEqual({ - bundlePath: '/regular-bundle-path/plugin/b/b.plugin.js', - publicPath: '/regular-bundle-path/plugin/b/', + bundlePath: '/regular-bundle-path/plugin/b/8.0.0/b.plugin.js', + publicPath: '/regular-bundle-path/plugin/b/8.0.0/', }); }); }); diff --git a/src/core/server/rendering/bootstrap/get_plugin_bundle_paths.ts b/src/core/server/rendering/bootstrap/get_plugin_bundle_paths.ts index c8291b2720a92c..86ffdcf835f7b5 100644 --- a/src/core/server/rendering/bootstrap/get_plugin_bundle_paths.ts +++ b/src/core/server/rendering/bootstrap/get_plugin_bundle_paths.ts @@ -25,9 +25,15 @@ export const getPluginsBundlePaths = ({ while (pluginsToProcess.length > 0) { const pluginId = pluginsToProcess.pop() as string; + const plugin = uiPlugins.internal.get(pluginId); + if (!plugin) { + continue; + } + const { version } = plugin; + pluginBundlePaths.set(pluginId, { - publicPath: `${regularBundlePath}/plugin/${pluginId}/`, - bundlePath: `${regularBundlePath}/plugin/${pluginId}/${pluginId}.plugin.js`, + publicPath: `${regularBundlePath}/plugin/${pluginId}/${version}/`, + bundlePath: `${regularBundlePath}/plugin/${pluginId}/${version}/${pluginId}.plugin.js`, }); const pluginBundleIds = uiPlugins.internal.get(pluginId)?.requiredBundles ?? []; diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md index de96c5ccfb81ed..fb5fe3efd3e062 100644 --- a/src/core/server/server.api.md +++ b/src/core/server/server.api.md @@ -3259,9 +3259,9 @@ export const validBodyOutput: readonly ["data", "stream"]; // // src/core/server/elasticsearch/client/types.ts:94:7 - (ae-forgotten-export) The symbol "Explanation" needs to be exported by the entry point index.d.ts // src/core/server/http/router/response.ts:297:3 - (ae-forgotten-export) The symbol "KibanaResponse" needs to be exported by the entry point index.d.ts -// src/core/server/plugins/types.ts:286:3 - (ae-forgotten-export) The symbol "KibanaConfigType" needs to be exported by the entry point index.d.ts -// src/core/server/plugins/types.ts:286:3 - (ae-forgotten-export) The symbol "SharedGlobalConfigKeys" needs to be exported by the entry point index.d.ts -// src/core/server/plugins/types.ts:289:3 - (ae-forgotten-export) The symbol "SavedObjectsConfigType" needs to be exported by the entry point index.d.ts -// src/core/server/plugins/types.ts:394:5 - (ae-unresolved-link) The @link reference could not be resolved: The package "kibana" does not have an export "create" +// src/core/server/plugins/types.ts:293:3 - (ae-forgotten-export) The symbol "KibanaConfigType" needs to be exported by the entry point index.d.ts +// src/core/server/plugins/types.ts:293:3 - (ae-forgotten-export) The symbol "SharedGlobalConfigKeys" needs to be exported by the entry point index.d.ts +// src/core/server/plugins/types.ts:296:3 - (ae-forgotten-export) The symbol "SavedObjectsConfigType" needs to be exported by the entry point index.d.ts +// src/core/server/plugins/types.ts:401:5 - (ae-unresolved-link) The @link reference could not be resolved: The package "kibana" does not have an export "create" ``` From 8e11e2598e874d603e99bcfac407ef9e09784102 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Mon, 5 Apr 2021 12:04:20 -0400 Subject: [PATCH 04/26] [Maps] Enable all zoom levels for all users (#96093) --- .github/CODEOWNERS | 1 - docs/developer/plugin-list.asciidoc | 4 - packages/kbn-optimizer/limits.yml | 1 - .../service_settings/service_settings.test.js | 50 ++------- .../service_settings/service_settings.ts | 17 +-- .../service_settings_types.ts | 2 - src/plugins/maps_legacy/kibana.json | 2 +- .../public/map/base_maps_visualization.js | 3 +- .../maps_legacy/public/map/kibana_map.js | 23 ---- .../maps_legacy/public/map/map_messages.js | 105 ------------------ test/functional/apps/visualize/_tile_map.ts | 59 ---------- tsconfig.json | 1 - tsconfig.refs.json | 1 - .../plugins/maps_legacy_licensing/README.md | 4 - .../plugins/maps_legacy_licensing/kibana.json | 8 -- .../maps_legacy_licensing/public/index.ts | 12 -- .../maps_legacy_licensing/public/plugin.ts | 48 -------- .../maps_legacy_licensing/tsconfig.json | 15 --- .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - 20 files changed, 12 insertions(+), 346 deletions(-) delete mode 100644 src/plugins/maps_legacy/public/map/map_messages.js delete mode 100644 x-pack/plugins/maps_legacy_licensing/README.md delete mode 100644 x-pack/plugins/maps_legacy_licensing/kibana.json delete mode 100644 x-pack/plugins/maps_legacy_licensing/public/index.ts delete mode 100644 x-pack/plugins/maps_legacy_licensing/public/plugin.ts delete mode 100644 x-pack/plugins/maps_legacy_licensing/tsconfig.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index d14556ea1dabf5..b9afc197bac9c1 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -146,7 +146,6 @@ /x-pack/test/visual_regression/tests/maps/index.js @elastic/kibana-gis #CC# /src/plugins/maps_legacy/ @elastic/kibana-gis #CC# /x-pack/plugins/file_upload @elastic/kibana-gis -#CC# /x-pack/plugins/maps_legacy_licensing @elastic/kibana-gis /src/plugins/tile_map/ @elastic/kibana-gis /src/plugins/region_map/ @elastic/kibana-gis diff --git a/docs/developer/plugin-list.asciidoc b/docs/developer/plugin-list.asciidoc index bcf74936077ece..691d7fb82f3bc4 100644 --- a/docs/developer/plugin-list.asciidoc +++ b/docs/developer/plugin-list.asciidoc @@ -452,10 +452,6 @@ using the CURL scripts in the scripts folder. |Visualize geo data from Elasticsearch or 3rd party geo-services. -|{kib-repo}blob/{branch}/x-pack/plugins/maps_legacy_licensing/README.md[mapsLegacyLicensing] -|This plugin provides access to the detailed tile map services from Elastic. - - |{kib-repo}blob/{branch}/x-pack/plugins/ml/readme.md[ml] |This plugin provides access to the machine learning features provided by Elastic. diff --git a/packages/kbn-optimizer/limits.yml b/packages/kbn-optimizer/limits.yml index 3c9fd4f59a406e..a027768ad66a0a 100644 --- a/packages/kbn-optimizer/limits.yml +++ b/packages/kbn-optimizer/limits.yml @@ -51,7 +51,6 @@ pageLoadAssetSize: management: 46112 maps: 80000 mapsLegacy: 87859 - mapsLegacyLicensing: 20214 ml: 82187 monitoring: 80000 navigation: 37269 diff --git a/src/plugins/maps_ems/public/service_settings/service_settings.test.js b/src/plugins/maps_ems/public/service_settings/service_settings.test.js index 5bd371aace79bb..eb67997c253b97 100644 --- a/src/plugins/maps_ems/public/service_settings/service_settings.test.js +++ b/src/plugins/maps_ems/public/service_settings/service_settings.test.js @@ -103,43 +103,8 @@ describe('service_settings (FKA tile_map test)', function () { expect(tmsService.attribution.includes('OpenStreetMap')).toEqual(true); }); - describe('modify - url', function () { - let tilemapServices; - + describe('tms mods', function () { let serviceSettings; - async function assertQuery(expected) { - const attrs = await serviceSettings.getAttributesForTMSLayer(tilemapServices[0]); - const urlObject = url.parse(attrs.url, true); - Object.keys(expected).forEach((key) => { - expect(urlObject.query[key]).toEqual(expected[key]); - }); - } - - it('accepts an object', async () => { - serviceSettings = makeServiceSettings(); - serviceSettings.setQueryParams({ foo: 'bar' }); - tilemapServices = await serviceSettings.getTMSServices(); - await assertQuery({ foo: 'bar' }); - }); - - it('merged additions with previous values', async () => { - // ensure that changes are always additive - serviceSettings = makeServiceSettings(); - serviceSettings.setQueryParams({ foo: 'bar' }); - serviceSettings.setQueryParams({ bar: 'stool' }); - tilemapServices = await serviceSettings.getTMSServices(); - await assertQuery({ foo: 'bar', bar: 'stool' }); - }); - - it('overwrites conflicting previous values', async () => { - serviceSettings = makeServiceSettings(); - // ensure that conflicts are overwritten - serviceSettings.setQueryParams({ foo: 'bar' }); - serviceSettings.setQueryParams({ bar: 'stool' }); - serviceSettings.setQueryParams({ foo: 'tstool' }); - tilemapServices = await serviceSettings.getTMSServices(); - await assertQuery({ foo: 'tstool', bar: 'stool' }); - }); it('should merge in tilemap url', async () => { serviceSettings = makeServiceSettings( @@ -161,7 +126,7 @@ describe('service_settings (FKA tile_map test)', function () { id: 'road_map', name: 'Road Map - Bright', url: - 'https://tiles.foobar/raster/styles/osm-bright/{z}/{x}/{y}.png?elastic_tile_service_tos=agree&my_app_name=kibana&my_app_version=1.2.3', + 'https://tiles.foobar/raster/styles/osm-bright/{z}/{x}/{y}.png?elastic_tile_service_tos=agree&my_app_name=kibana&my_app_version=1.2.3&license=sspl', minZoom: 0, maxZoom: 10, attribution: @@ -208,19 +173,19 @@ describe('service_settings (FKA tile_map test)', function () { ); expect(desaturationFalse.url).toEqual( - 'https://tiles.foobar/raster/styles/osm-bright/{z}/{x}/{y}.png?elastic_tile_service_tos=agree&my_app_name=kibana&my_app_version=1.2.3' + 'https://tiles.foobar/raster/styles/osm-bright/{z}/{x}/{y}.png?elastic_tile_service_tos=agree&my_app_name=kibana&my_app_version=1.2.3&license=sspl' ); expect(desaturationFalse.maxZoom).toEqual(10); expect(desaturationTrue.url).toEqual( - 'https://tiles.foobar/raster/styles/osm-bright-desaturated/{z}/{x}/{y}.png?elastic_tile_service_tos=agree&my_app_name=kibana&my_app_version=1.2.3' + 'https://tiles.foobar/raster/styles/osm-bright-desaturated/{z}/{x}/{y}.png?elastic_tile_service_tos=agree&my_app_name=kibana&my_app_version=1.2.3&license=sspl' ); expect(desaturationTrue.maxZoom).toEqual(18); expect(darkThemeDesaturationFalse.url).toEqual( - 'https://tiles.foobar/raster/styles/dark-matter/{z}/{x}/{y}.png?elastic_tile_service_tos=agree&my_app_name=kibana&my_app_version=1.2.3' + 'https://tiles.foobar/raster/styles/dark-matter/{z}/{x}/{y}.png?elastic_tile_service_tos=agree&my_app_name=kibana&my_app_version=1.2.3&license=sspl' ); expect(darkThemeDesaturationFalse.maxZoom).toEqual(22); expect(darkThemeDesaturationTrue.url).toEqual( - 'https://tiles.foobar/raster/styles/dark-matter/{z}/{x}/{y}.png?elastic_tile_service_tos=agree&my_app_name=kibana&my_app_version=1.2.3' + 'https://tiles.foobar/raster/styles/dark-matter/{z}/{x}/{y}.png?elastic_tile_service_tos=agree&my_app_name=kibana&my_app_version=1.2.3&license=sspl' ); expect(darkThemeDesaturationTrue.maxZoom).toEqual(22); }); @@ -264,14 +229,13 @@ describe('service_settings (FKA tile_map test)', function () { describe('File layers', function () { it('should load manifest (all props)', async function () { const serviceSettings = makeServiceSettings(); - serviceSettings.setQueryParams({ foo: 'bar' }); const fileLayers = await serviceSettings.getFileLayers(); expect(fileLayers.length).toEqual(19); const assertions = fileLayers.map(async function (fileLayer) { expect(fileLayer.origin).toEqual(ORIGIN.EMS); const fileUrl = await serviceSettings.getUrlForRegionLayer(fileLayer); const urlObject = url.parse(fileUrl, true); - Object.keys({ foo: 'bar', elastic_tile_service_tos: 'agree' }).forEach((key) => { + Object.keys({ elastic_tile_service_tos: 'agree' }).forEach((key) => { expect(typeof urlObject.query[key]).toEqual('string'); }); }); diff --git a/src/plugins/maps_ems/public/service_settings/service_settings.ts b/src/plugins/maps_ems/public/service_settings/service_settings.ts index f7c735b6c3037d..412db42a1570c2 100644 --- a/src/plugins/maps_ems/public/service_settings/service_settings.ts +++ b/src/plugins/maps_ems/public/service_settings/service_settings.ts @@ -22,7 +22,6 @@ export class ServiceSettings implements IServiceSettings { private readonly _mapConfig: MapsEmsConfig; private readonly _tilemapsConfig: TileMapConfig; private readonly _hasTmsConfigured: boolean; - private _showZoomMessage: boolean; private readonly _emsClient: EMSClient; private readonly tmsOptionsFromConfig: any; @@ -31,7 +30,6 @@ export class ServiceSettings implements IServiceSettings { this._tilemapsConfig = tilemapsConfig; this._hasTmsConfigured = typeof tilemapsConfig.url === 'string' && tilemapsConfig.url !== ''; - this._showZoomMessage = true; this._emsClient = new EMSClient({ language: i18n.getLocale(), appVersion: getKibanaVersion(), @@ -45,6 +43,9 @@ export class ServiceSettings implements IServiceSettings { return fetch(...args); }, }); + // any kibana user, regardless of distribution, should get all zoom levels + // use `sspl` license to indicate this + this._emsClient.addQueryParams({ license: 'sspl' }); const markdownIt = new MarkdownIt({ html: false, @@ -58,18 +59,6 @@ export class ServiceSettings implements IServiceSettings { }); } - shouldShowZoomMessage({ origin }: { origin: string }): boolean { - return origin === ORIGIN.EMS && this._showZoomMessage; - } - - enableZoomMessage(): void { - this._showZoomMessage = true; - } - - disableZoomMessage(): void { - this._showZoomMessage = false; - } - __debugStubManifestCalls(manifestRetrieval: () => Promise): { removeStub: () => void } { const oldGetManifest = this._emsClient.getManifest; diff --git a/src/plugins/maps_ems/public/service_settings/service_settings_types.ts b/src/plugins/maps_ems/public/service_settings/service_settings_types.ts index 80a9aae8358441..6b04bd200eba85 100644 --- a/src/plugins/maps_ems/public/service_settings/service_settings_types.ts +++ b/src/plugins/maps_ems/public/service_settings/service_settings_types.ts @@ -46,8 +46,6 @@ export interface IServiceSettings { getFileLayers(): Promise; getUrlForRegionLayer(layer: FileLayer): Promise; setQueryParams(params: { [p: string]: string }): void; - enableZoomMessage(): void; - disableZoomMessage(): void; getAttributesForTMSLayer( tmsServiceConfig: TmsLayer, isDesaturated: boolean, diff --git a/src/plugins/maps_legacy/kibana.json b/src/plugins/maps_legacy/kibana.json index 8e283288e34b2b..f321274791a3b4 100644 --- a/src/plugins/maps_legacy/kibana.json +++ b/src/plugins/maps_legacy/kibana.json @@ -5,5 +5,5 @@ "ui": true, "server": true, "requiredPlugins": ["mapsEms"], - "requiredBundles": ["kibanaReact", "visDefaultEditor", "mapsEms"] + "requiredBundles": ["visDefaultEditor", "mapsEms"] } diff --git a/src/plugins/maps_legacy/public/map/base_maps_visualization.js b/src/plugins/maps_legacy/public/map/base_maps_visualization.js index 9cd574c5246e86..a261bcf6edd809 100644 --- a/src/plugins/maps_legacy/public/map/base_maps_visualization.js +++ b/src/plugins/maps_legacy/public/map/base_maps_visualization.js @@ -193,13 +193,12 @@ export function BaseMapsVisualizationProvider() { isDesaturated, isDarkMode ); - const showZoomMessage = serviceSettings.shouldShowZoomMessage(tmsLayer); const options = { ...tmsLayer }; delete options.id; delete options.subdomains; this._kibanaMap.setBaseLayer({ baseLayerType: 'tms', - options: { ...options, showZoomMessage, ...meta }, + options: { ...options, ...meta }, }); } diff --git a/src/plugins/maps_legacy/public/map/kibana_map.js b/src/plugins/maps_legacy/public/map/kibana_map.js index eea83154192897..62dbbda2588a50 100644 --- a/src/plugins/maps_legacy/public/map/kibana_map.js +++ b/src/plugins/maps_legacy/public/map/kibana_map.js @@ -7,13 +7,11 @@ */ import { EventEmitter } from 'events'; -import { createZoomWarningMsg } from './map_messages'; import $ from 'jquery'; import { get, isEqual, escape } from 'lodash'; import { zoomToPrecision } from './zoom_to_precision'; import { i18n } from '@kbn/i18n'; import { ORIGIN } from '../../../maps_ems/common'; -import { getToasts } from '../kibana_services'; import { L } from '../leaflet'; function makeFitControl(fitContainer, kibanaMap) { @@ -479,22 +477,6 @@ export class KibanaMap extends EventEmitter { this._updateLegend(); } - _addMaxZoomMessage = (layer) => { - const zoomWarningMsg = createZoomWarningMsg( - getToasts(), - this.getZoomLevel, - this.getMaxZoomLevel - ); - - this._leafletMap.on('zoomend', zoomWarningMsg); - this._containerNode.setAttribute('data-test-subj', 'zoomWarningEnabled'); - - layer.on('remove', () => { - this._leafletMap.off('zoomend', zoomWarningMsg); - this._containerNode.removeAttribute('data-test-subj'); - }); - }; - setLegendPosition(position) { if (this._legendPosition === position) { if (!this._leafletLegendControl) { @@ -572,11 +554,6 @@ export class KibanaMap extends EventEmitter { }); this._leafletBaseLayer = baseLayer; - if (settings.options.showZoomMessage) { - baseLayer.on('add', () => { - this._addMaxZoomMessage(baseLayer); - }); - } this._leafletBaseLayer.addTo(this._leafletMap); this._leafletBaseLayer.bringToBack(); if (settings.options.minZoom > this._leafletMap.getZoom()) { diff --git a/src/plugins/maps_legacy/public/map/map_messages.js b/src/plugins/maps_legacy/public/map/map_messages.js deleted file mode 100644 index f60d819f0b3909..00000000000000 --- a/src/plugins/maps_legacy/public/map/map_messages.js +++ /dev/null @@ -1,105 +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 - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import React from 'react'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiSpacer, EuiButtonEmpty } from '@elastic/eui'; -import { toMountPoint } from '../../../kibana_react/public'; - -export const createZoomWarningMsg = (function () { - let disableZoomMsg = false; - const setZoomMsg = (boolDisableMsg) => (disableZoomMsg = boolDisableMsg); - - class ZoomWarning extends React.Component { - constructor(props) { - super(props); - this.state = { - disabled: false, - }; - } - - render() { - return ( -
-

- - {`default distribution `} - - ), - ems: ( - - {`Elastic Maps Service`} - - ), - wms: ( - - {`Custom WMS Configuration`} - - ), - configSettings: ( - - {`Custom TMS Using Config Settings`} - - ), - }} - /> -

- - { - this.setState( - { - disabled: true, - }, - () => this.props.onChange(this.state.disabled) - ); - }} - data-test-subj="suppressZoomWarnings" - > - {`Don't show again`} - -
- ); - } - } - - const zoomToast = { - title: 'No additional zoom levels', - text: toMountPoint(), - 'data-test-subj': 'maxZoomWarning', - }; - - return (toastService, getZoomLevel, getMaxZoomLevel) => { - return () => { - const zoomLevel = getZoomLevel(); - const maxMapZoom = getMaxZoomLevel(); - if (!disableZoomMsg && zoomLevel === maxMapZoom) { - toastService.addDanger(zoomToast); - } - }; - }; -})(); diff --git a/test/functional/apps/visualize/_tile_map.ts b/test/functional/apps/visualize/_tile_map.ts index 668aec6ac5783d..3af467affa1fbe 100644 --- a/test/functional/apps/visualize/_tile_map.ts +++ b/test/functional/apps/visualize/_tile_map.ts @@ -15,7 +15,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const retry = getService('retry'); const inspector = getService('inspector'); const filterBar = getService('filterBar'); - const testSubjects = getService('testSubjects'); const browser = getService('browser'); const PageObjects = getPageObjects([ 'common', @@ -221,63 +220,5 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); }); }); - - describe('zoom warning behavior', function describeIndexTests() { - // Zoom warning is only applicable to OSS - this.tags(['skipCloud', 'skipFirefox']); - - const waitForLoading = false; - let zoomWarningEnabled; - let last = false; - const toastDefaultLife = 6000; - - before(async function () { - await browser.setWindowSize(1280, 1000); - - log.debug('navigateToApp visualize'); - await PageObjects.visualize.navigateToNewAggBasedVisualization(); - log.debug('clickTileMap'); - await PageObjects.visualize.clickTileMap(); - await PageObjects.visualize.clickNewSearch(); - - zoomWarningEnabled = await testSubjects.exists('zoomWarningEnabled'); - log.debug(`Zoom warning enabled: ${zoomWarningEnabled}`); - - const zoomLevel = 9; - for (let i = 0; i < zoomLevel; i++) { - await PageObjects.tileMap.clickMapZoomIn(); - } - }); - - beforeEach(async function () { - await PageObjects.tileMap.clickMapZoomIn(waitForLoading); - }); - - afterEach(async function () { - if (!last) { - await PageObjects.common.sleep(toastDefaultLife); - await PageObjects.tileMap.clickMapZoomOut(waitForLoading); - } - }); - - it('should show warning at zoom 10', async () => { - await testSubjects.existOrFail('maxZoomWarning'); - }); - - it('should continue providing zoom warning if left alone', async () => { - await testSubjects.existOrFail('maxZoomWarning'); - }); - - it('should suppress zoom warning if suppress warnings button clicked', async () => { - last = true; - await PageObjects.visChart.waitForVisualization(); - await testSubjects.click('suppressZoomWarnings'); - await PageObjects.tileMap.clickMapZoomOut(waitForLoading); - await testSubjects.waitForDeleted('suppressZoomWarnings'); - await PageObjects.tileMap.clickMapZoomIn(waitForLoading); - - await testSubjects.missingOrFail('maxZoomWarning'); - }); - }); }); } diff --git a/tsconfig.json b/tsconfig.json index 30944ac71fcc8a..7c06e808586401 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -181,7 +181,6 @@ { "path": "./x-pack/plugins/license_management/tsconfig.json" }, { "path": "./x-pack/plugins/licensing/tsconfig.json" }, { "path": "./x-pack/plugins/logstash/tsconfig.json" }, - { "path": "./x-pack/plugins/maps_legacy_licensing/tsconfig.json" }, { "path": "./x-pack/plugins/maps/tsconfig.json" }, { "path": "./x-pack/plugins/ml/tsconfig.json" }, { "path": "./x-pack/plugins/monitoring/tsconfig.json" }, diff --git a/tsconfig.refs.json b/tsconfig.refs.json index 2d9ddc1b9e5681..f13455a14b4df7 100644 --- a/tsconfig.refs.json +++ b/tsconfig.refs.json @@ -85,7 +85,6 @@ { "path": "./x-pack/plugins/license_management/tsconfig.json" }, { "path": "./x-pack/plugins/licensing/tsconfig.json" }, { "path": "./x-pack/plugins/logstash/tsconfig.json" }, - { "path": "./x-pack/plugins/maps_legacy_licensing/tsconfig.json" }, { "path": "./x-pack/plugins/maps/tsconfig.json" }, { "path": "./x-pack/plugins/ml/tsconfig.json" }, { "path": "./x-pack/plugins/monitoring/tsconfig.json" }, diff --git a/x-pack/plugins/maps_legacy_licensing/README.md b/x-pack/plugins/maps_legacy_licensing/README.md deleted file mode 100644 index 7c2ce84d848d43..00000000000000 --- a/x-pack/plugins/maps_legacy_licensing/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Tile Map Plugin - -This plugin provides access to the detailed tile map services from Elastic. - diff --git a/x-pack/plugins/maps_legacy_licensing/kibana.json b/x-pack/plugins/maps_legacy_licensing/kibana.json deleted file mode 100644 index 7a49e0aaa7be17..00000000000000 --- a/x-pack/plugins/maps_legacy_licensing/kibana.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "id": "mapsLegacyLicensing", - "version": "8.0.0", - "kibanaVersion": "kibana", - "server": false, - "ui": true, - "requiredPlugins": ["licensing", "mapsEms"] -} diff --git a/x-pack/plugins/maps_legacy_licensing/public/index.ts b/x-pack/plugins/maps_legacy_licensing/public/index.ts deleted file mode 100644 index 9105919eaa6353..00000000000000 --- a/x-pack/plugins/maps_legacy_licensing/public/index.ts +++ /dev/null @@ -1,12 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { MapsLegacyLicensing } from './plugin'; - -export function plugin() { - return new MapsLegacyLicensing(); -} diff --git a/x-pack/plugins/maps_legacy_licensing/public/plugin.ts b/x-pack/plugins/maps_legacy_licensing/public/plugin.ts deleted file mode 100644 index f8118575cd6a2a..00000000000000 --- a/x-pack/plugins/maps_legacy_licensing/public/plugin.ts +++ /dev/null @@ -1,48 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { CoreSetup, CoreStart, Plugin } from 'kibana/public'; -import { LicensingPluginSetup, ILicense } from '../../licensing/public'; -import { IServiceSettings, MapsEmsPluginSetup } from '../../../../src/plugins/maps_ems/public'; - -/** - * These are the interfaces with your public contracts. You should export these - * for other plugins to use in _their_ `SetupDeps`/`StartDeps` interfaces. - * @public - */ - -export interface MapsLegacyLicensingSetupDependencies { - licensing: LicensingPluginSetup; - mapsEms: MapsEmsPluginSetup; -} -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface MapsLegacyLicensingStartDependencies {} - -export type MapsLegacyLicensingSetup = ReturnType; -export type MapsLegacyLicensingStart = ReturnType; - -export class MapsLegacyLicensing - implements Plugin { - public setup(core: CoreSetup, plugins: MapsLegacyLicensingSetupDependencies) { - const { licensing, mapsEms } = plugins; - if (licensing) { - licensing.license$.subscribe(async (license: ILicense) => { - const serviceSettings: IServiceSettings = await mapsEms.getServiceSettings(); - const { uid, isActive } = license; - if (isActive && license.hasAtLeast('basic')) { - serviceSettings.setQueryParams({ license: uid || '' }); - serviceSettings.disableZoomMessage(); - } else { - serviceSettings.setQueryParams({ license: '' }); - serviceSettings.enableZoomMessage(); - } - }); - } - } - - public start(core: CoreStart, plugins: MapsLegacyLicensingStartDependencies) {} -} diff --git a/x-pack/plugins/maps_legacy_licensing/tsconfig.json b/x-pack/plugins/maps_legacy_licensing/tsconfig.json deleted file mode 100644 index 3b8102b5205a88..00000000000000 --- a/x-pack/plugins/maps_legacy_licensing/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "extends": "../../../tsconfig.project.json", - "compilerOptions": { - "composite": true, - "outDir": "./target/types", - "emitDeclarationOnly": true, - "declaration": true, - "declarationMap": true - }, - "include": ["public/**/*"], - "references": [ - { "path": "../licensing/tsconfig.json" }, - { "path": "../../../src/plugins/maps_ems/tsconfig.json" } - ] -} diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 133b4d0b6aaa85..6dc490b4ffc530 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -3080,7 +3080,6 @@ "maps_legacy.baseMapsVisualization.childShouldImplementMethodErrorMessage": "子はdata-updateに対応できるようこのメソッドを導入する必要があります", "maps_legacy.defaultDistributionMessage": "Mapsを入手するには、ElasticsearchとKibanaの{defaultDistribution}にアップグレードしてください。", "maps_legacy.kibanaMap.leaflet.fitDataBoundsAriaLabel": "データバウンドを合わせる", - "maps_legacy.kibanaMap.zoomWarning": "ズームレベルが最大に達しました。完全にズームインするには、ElasticsearchとKibanaの{defaultDistribution}にアップグレードしてください。{ems}ではより多くのズームレベルを無料で利用できます。または、独自のマップサーバーを構成できます。詳細は、{ wms }または{ configSettings}をご覧ください。", "maps_legacy.legacyMapDeprecationMessage": "Mapsを使用すると、複数のレイヤーとインデックスを追加する、個別のドキュメントをプロットする、データ値から特徴を表現する、ヒートマップ、グリッド、クラスターを追加するなど、さまざまなことが可能です。{getMapsMessage}", "maps_legacy.legacyMapDeprecationTitle": "{label}は8.0でMapsに移行されます。", "maps_legacy.openInMapsButtonLabel": "Mapsで表示", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 0f9d8b90a2578b..32574690b13f24 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -3101,7 +3101,6 @@ "maps_legacy.baseMapsVisualization.childShouldImplementMethodErrorMessage": "子对象应实现此方法以响应数据更新", "maps_legacy.defaultDistributionMessage": "要获取 Maps,请升级到 {defaultDistribution} 版的 Elasticsearch 和 Kibana。", "maps_legacy.kibanaMap.leaflet.fitDataBoundsAriaLabel": "适应数据边界", - "maps_legacy.kibanaMap.zoomWarning": "已达到缩放级别数目上限。要一直放大,请升级到 Elasticsearch 和 Kibana 的{defaultDistribution}。您可以通过 {ems} 免费使用其他缩放级别。或者,您可以配置自己的地图服务器。请前往 { wms } 或 { configSettings} 以获取详细信息。", "maps_legacy.legacyMapDeprecationMessage": "使用 Maps,可以添加多个图层和索引,绘制单个文档,使用数据值表示特征,添加热图、网格和集群,等等。{getMapsMessage}", "maps_legacy.legacyMapDeprecationTitle": "在 8.0 中,{label} 将迁移到 Maps。", "maps_legacy.openInMapsButtonLabel": "在 Maps 中查看", From bcb72c596a438f6a223e875395380afe1efc291c Mon Sep 17 00:00:00 2001 From: Andrew Goldstein Date: Mon, 5 Apr 2021 11:39:09 -0600 Subject: [PATCH 05/26] [RAC][Alert Triage][TGrid] Update the Alerts Table (TGrid) API to implement `renderCellValue` (#96098) ### [RAC][Alert Triage][TGrid] Update the Alerts Table (TGrid) API to implement `renderCellValue` - This PR implements a superset of the `renderCellValue` API from [EuiDataGrid](https://elastic.github.io/eui/#/tabular-content/data-grid) in the `TGrid` (Timeline grid) API - The TGrid API was also updated to accept a collection of `RowRenderer`s as a prop The API changes are summarized by the following screenshot: render-cell-value The following screenshot shows the `signal.rule.risk_score` column in the Alerts table being rendered with a green background color, using the same technique illustrated by `EuiDataGrid`'s [codesandbox example](https://codesandbox.io/s/nsmzs): alerts Note: In the screenshot above, the values in the Alerts table are also _not_ rendered as draggables. Related (RAC) issue: https://github.com/elastic/kibana/issues/94520 ### Details The `StatefulEventsViewer` has been updated to accept `renderCellValue` as a (required) prop: ``` renderCellValue: (props: CellValueElementProps) => React.ReactNode; ``` The type definition of `CellValueElementProps` is: ``` export type CellValueElementProps = EuiDataGridCellValueElementProps & { data: TimelineNonEcsData[]; eventId: string; // _id header: ColumnHeaderOptions; linkValues: string[] | undefined; timelineId: string; }; ``` The `CellValueElementProps` type above is a _superset_ of `EuiDataGridCellValueElementProps`. The additional properties above include the `data` returned by the TGrid when it performs IO to retrieve alerts and events. ### Using `renderCellValue` to control rendering The internal implementation of TGrid's cell rendering didn't change with this PR; it moved to `x-pack/plugins/security_solution/public/timelines/components/timeline/cell_rendering/default_cell_renderer.tsx` as shown below: ``` export const DefaultCellRenderer: React.FC = ({ columnId, data, eventId, header, linkValues, setCellProps, timelineId, }) => ( <> {getColumnRenderer(header.id, columnRenderers, data).renderColumn({ columnName: header.id, eventId, field: header, linkValues, timelineId, truncate: true, values: getMappedNonEcsValue({ data, fieldName: header.id, }), })} ); ``` Any usages of TGrid were updated to pass `DefaultCellRenderer` as the value of the `renderCellValue` prop, as shown in the screenshot below: render-cell-value The `EuiDataGrid` [codesandbox example](https://codesandbox.io/s/nsmzs) provides the following example `renderCellValue` implementation, which highlights a cell green based on it's numeric value: ``` const renderCellValue = useMemo(() => { return ({ rowIndex, columnId, setCellProps }) => { const data = useContext(DataContext); useEffect(() => { if (columnId === 'amount') { if (data.hasOwnProperty(rowIndex)) { const numeric = parseFloat( data[rowIndex][columnId].match(/\d+\.\d+/)[0], 10 ); setCellProps({ style: { backgroundColor: `rgba(0, 255, 0, ${numeric * 0.0002})`, }, }); } } }, [rowIndex, columnId, setCellProps, data]); function getFormatted() { return data[rowIndex][columnId].formatted ? data[rowIndex][columnId].formatted : data[rowIndex][columnId]; } return data.hasOwnProperty(rowIndex) ? getFormatted(rowIndex, columnId) : null; }; }, []); ``` The sample code above formats the `amount` column in the example `EuiDataGrid` with a green `backgroundColor` based on the value of the data, as shown in the screenshot below: datagrid-cell-formatting To demonstrate that similar styling can be applied to TGrid using the same technique illustrated by `EuiDataGrid`'s [codesandbox example](https://codesandbox.io/s/nsmzs), we can update the `DefaultCellRenderer` in `x-pack/plugins/security_solution/public/timelines/components/timeline/cell_rendering/default_cell_renderer.tsx` to apply a similar technique: ``` export const DefaultCellRenderer: React.FC = ({ columnId, data, eventId, header, linkValues, setCellProps, timelineId, }) => { useEffect(() => { if (columnId === 'signal.rule.risk_score') { const value = getMappedNonEcsValue({ data, fieldName: columnId, }); if (Array.isArray(value) && value.length > 0) { const numeric = parseFloat(value[0]); setCellProps({ style: { backgroundColor: `rgba(0, 255, 0, ${numeric * 0.002})`, }, }); } } }, [columnId, data, setCellProps]); return ( <> {getMappedNonEcsValue({ data, fieldName: columnId, })} ); }; ``` The example code above renders the `signal.rule.risk_score` column in the Alerts table with a green `backgroundColor` based on the value of the data, as shown in the screenshot below: alerts Note: In the screenshot above, the values in the Alerts table are not rendered as draggables. --- .../components/alerts_viewer/alerts_table.tsx | 4 + .../events_viewer/events_viewer.test.tsx | 6 + .../events_viewer/events_viewer.tsx | 14 +- .../components/events_viewer/index.test.tsx | 4 + .../common/components/events_viewer/index.tsx | 13 +- .../components/alerts_table/index.tsx | 4 + .../navigation/events_query_tab_body.tsx | 4 + .../components/flyout/pane/index.tsx | 8 +- .../__snapshots__/index.test.tsx.snap | 553 ++++++++-- .../body/data_driven_columns/index.test.tsx | 4 +- .../body/data_driven_columns/index.tsx | 30 +- .../stateful_cell.test.tsx | 171 +++ .../data_driven_columns/stateful_cell.tsx | 63 ++ .../body/events/event_column_view.test.tsx | 2 + .../body/events/event_column_view.tsx | 8 +- .../components/timeline/body/events/index.tsx | 8 +- .../timeline/body/events/stateful_event.tsx | 10 +- .../components/timeline/body/index.test.tsx | 8 +- .../components/timeline/body/index.tsx | 13 +- .../body/renderers/get_row_renderer.test.tsx | 16 +- .../timeline/body/renderers/index.ts | 2 +- .../default_cell_renderer.test.tsx | 107 ++ .../cell_rendering/default_cell_renderer.tsx | 39 + .../timeline/cell_rendering/index.tsx | 20 + .../__snapshots__/index.test.tsx.snap | 980 ++++++++++++++++++ .../timeline/eql_tab_content/index.test.tsx | 4 + .../timeline/eql_tab_content/index.tsx | 8 + .../components/timeline/index.test.tsx | 4 + .../timelines/components/timeline/index.tsx | 14 +- .../__snapshots__/index.test.tsx.snap | 980 ++++++++++++++++++ .../pinned_tab_content/index.test.tsx | 5 +- .../timeline/pinned_tab_content/index.tsx | 8 + .../__snapshots__/index.test.tsx.snap | 980 ++++++++++++++++++ .../timeline/query_tab_content/index.test.tsx | 4 + .../timeline/query_tab_content/index.tsx | 8 + .../timeline/tabs_content/index.tsx | 64 +- .../timeline/epic_local_storage.test.tsx | 5 +- 37 files changed, 4047 insertions(+), 128 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/stateful_cell.test.tsx create mode 100644 x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/stateful_cell.tsx create mode 100644 x-pack/plugins/security_solution/public/timelines/components/timeline/cell_rendering/default_cell_renderer.test.tsx create mode 100644 x-pack/plugins/security_solution/public/timelines/components/timeline/cell_rendering/default_cell_renderer.tsx create mode 100644 x-pack/plugins/security_solution/public/timelines/components/timeline/cell_rendering/index.tsx diff --git a/x-pack/plugins/security_solution/public/common/components/alerts_viewer/alerts_table.tsx b/x-pack/plugins/security_solution/public/common/components/alerts_viewer/alerts_table.tsx index af90d17fe62b8e..43d5c66655808b 100644 --- a/x-pack/plugins/security_solution/public/common/components/alerts_viewer/alerts_table.tsx +++ b/x-pack/plugins/security_solution/public/common/components/alerts_viewer/alerts_table.tsx @@ -12,6 +12,8 @@ import { TimelineIdLiteral } from '../../../../common/types/timeline'; import { StatefulEventsViewer } from '../events_viewer'; import { alertsDefaultModel } from './default_headers'; import { useManageTimeline } from '../../../timelines/components/manage_timeline'; +import { defaultRowRenderers } from '../../../timelines/components/timeline/body/renderers'; +import { DefaultCellRenderer } from '../../../timelines/components/timeline/cell_rendering/default_cell_renderer'; import * as i18n from './translations'; import { useKibana } from '../../lib/kibana'; import { SourcererScopeName } from '../../store/sourcerer/model'; @@ -91,6 +93,8 @@ const AlertsTableComponent: React.FC = ({ defaultModel={alertsDefaultModel} end={endDate} id={timelineId} + renderCellValue={DefaultCellRenderer} + rowRenderers={defaultRowRenderers} scopeId={SourcererScopeName.default} start={startDate} /> diff --git a/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.test.tsx b/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.test.tsx index 3ecc17589fe084..8962f5e6c51466 100644 --- a/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.test.tsx @@ -26,6 +26,8 @@ import { KqlMode } from '../../../timelines/store/timeline/model'; import { SortDirection } from '../../../timelines/components/timeline/body/sort'; import { AlertsTableFilterGroup } from '../../../detections/components/alerts_table/alerts_filter_group'; import { SourcererScopeName } from '../../store/sourcerer/model'; +import { defaultRowRenderers } from '../../../timelines/components/timeline/body/renderers'; +import { DefaultCellRenderer } from '../../../timelines/components/timeline/cell_rendering/default_cell_renderer'; import { useTimelineEvents } from '../../../timelines/containers'; jest.mock('../../../timelines/components/graph_overlay', () => ({ @@ -99,6 +101,8 @@ const eventsViewerDefaultProps = { query: '', language: 'kql', }, + renderCellValue: DefaultCellRenderer, + rowRenderers: defaultRowRenderers, start: from, sort: [ { @@ -118,6 +122,8 @@ describe('EventsViewer', () => { defaultModel: eventsDefaultModel, end: to, id: TimelineId.test, + renderCellValue: DefaultCellRenderer, + rowRenderers: defaultRowRenderers, start: from, scopeId: SourcererScopeName.timeline, }; diff --git a/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.tsx b/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.tsx index 050cd92b0556ea..e6e868f1a73654 100644 --- a/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.tsx +++ b/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.tsx @@ -4,7 +4,6 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - import { EuiFlexGroup, EuiFlexItem, EuiPanel } from '@elastic/eui'; import { isEmpty } from 'lodash/fp'; import React, { useEffect, useMemo, useState } from 'react'; @@ -41,7 +40,9 @@ import { useManageTimeline } from '../../../timelines/components/manage_timeline import { ExitFullScreen } from '../exit_full_screen'; import { useGlobalFullScreen } from '../../containers/use_full_screen'; import { TimelineId, TimelineTabs } from '../../../../common/types/timeline'; +import { RowRenderer } from '../../../timelines/components/timeline/body/renderers/row_renderer'; import { GraphOverlay } from '../../../timelines/components/graph_overlay'; +import { CellValueElementProps } from '../../../timelines/components/timeline/cell_rendering'; import { SELECTOR_TIMELINE_GLOBAL_CONTAINER } from '../../../timelines/components/timeline/styles'; export const EVENTS_VIEWER_HEADER_HEIGHT = 90; // px @@ -122,6 +123,8 @@ interface Props { kqlMode: KqlMode; query: Query; onRuleChange?: () => void; + renderCellValue: (props: CellValueElementProps) => React.ReactNode; + rowRenderers: RowRenderer[]; start: string; sort: Sort[]; utilityBar?: (refetch: inputsModel.Refetch, totalCount: number) => React.ReactNode; @@ -146,8 +149,10 @@ const EventsViewerComponent: React.FC = ({ itemsPerPage, itemsPerPageOptions, kqlMode, - query, onRuleChange, + query, + renderCellValue, + rowRenderers, start, sort, utilityBar, @@ -310,6 +315,8 @@ const EventsViewerComponent: React.FC = ({ isEventViewer={true} onRuleChange={onRuleChange} refetch={refetch} + renderCellValue={renderCellValue} + rowRenderers={rowRenderers} sort={sort} tabType={TimelineTabs.query} totalPages={calculateTotalPages({ @@ -343,6 +350,7 @@ const EventsViewerComponent: React.FC = ({ export const EventsViewer = React.memo( EventsViewerComponent, + // eslint-disable-next-line complexity (prevProps, nextProps) => deepEqual(prevProps.browserFields, nextProps.browserFields) && prevProps.columns === nextProps.columns && @@ -359,6 +367,8 @@ export const EventsViewer = React.memo( prevProps.itemsPerPageOptions === nextProps.itemsPerPageOptions && prevProps.kqlMode === nextProps.kqlMode && deepEqual(prevProps.query, nextProps.query) && + prevProps.renderCellValue === nextProps.renderCellValue && + prevProps.rowRenderers === nextProps.rowRenderers && prevProps.start === nextProps.start && deepEqual(prevProps.sort, nextProps.sort) && prevProps.utilityBar === nextProps.utilityBar && diff --git a/x-pack/plugins/security_solution/public/common/components/events_viewer/index.test.tsx b/x-pack/plugins/security_solution/public/common/components/events_viewer/index.test.tsx index 5004c23f9111c4..cd27177643b449 100644 --- a/x-pack/plugins/security_solution/public/common/components/events_viewer/index.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/events_viewer/index.test.tsx @@ -18,7 +18,9 @@ import { StatefulEventsViewer } from '.'; import { eventsDefaultModel } from './default_model'; import { TimelineId } from '../../../../common/types/timeline'; import { SourcererScopeName } from '../../store/sourcerer/model'; +import { DefaultCellRenderer } from '../../../timelines/components/timeline/cell_rendering/default_cell_renderer'; import { useTimelineEvents } from '../../../timelines/containers'; +import { defaultRowRenderers } from '../../../timelines/components/timeline/body/renderers'; jest.mock('../../../timelines/containers', () => ({ useTimelineEvents: jest.fn(), @@ -38,6 +40,8 @@ const testProps = { end: to, indexNames: [], id: TimelineId.test, + renderCellValue: DefaultCellRenderer, + rowRenderers: defaultRowRenderers, scopeId: SourcererScopeName.default, start: from, }; diff --git a/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx b/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx index 59dc756bb2b3e4..b58aa2236d2924 100644 --- a/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx @@ -22,6 +22,8 @@ import { useGlobalFullScreen } from '../../containers/use_full_screen'; import { SourcererScopeName } from '../../store/sourcerer/model'; import { useSourcererScope } from '../../containers/sourcerer'; import { DetailsPanel } from '../../../timelines/components/side_panel'; +import { RowRenderer } from '../../../timelines/components/timeline/body/renderers/row_renderer'; +import { CellValueElementProps } from '../../../timelines/components/timeline/cell_rendering'; const DEFAULT_EVENTS_VIEWER_HEIGHT = 652; @@ -41,6 +43,8 @@ export interface OwnProps { headerFilterGroup?: React.ReactNode; pageFilters?: Filter[]; onRuleChange?: () => void; + renderCellValue: (props: CellValueElementProps) => React.ReactNode; + rowRenderers: RowRenderer[]; utilityBar?: (refetch: inputsModel.Refetch, totalCount: number) => React.ReactNode; } @@ -67,8 +71,10 @@ const StatefulEventsViewerComponent: React.FC = ({ itemsPerPageOptions, kqlMode, pageFilters, - query, onRuleChange, + query, + renderCellValue, + rowRenderers, start, scopeId, showCheckboxes, @@ -129,6 +135,8 @@ const StatefulEventsViewerComponent: React.FC = ({ kqlMode={kqlMode} query={query} onRuleChange={onRuleChange} + renderCellValue={renderCellValue} + rowRenderers={rowRenderers} start={start} sort={sort} utilityBar={utilityBar} @@ -201,6 +209,7 @@ type PropsFromRedux = ConnectedProps; export const StatefulEventsViewer = connector( React.memo( StatefulEventsViewerComponent, + // eslint-disable-next-line complexity (prevProps, nextProps) => prevProps.id === nextProps.id && prevProps.scopeId === nextProps.scopeId && @@ -215,6 +224,8 @@ export const StatefulEventsViewer = connector( deepEqual(prevProps.itemsPerPageOptions, nextProps.itemsPerPageOptions) && prevProps.kqlMode === nextProps.kqlMode && deepEqual(prevProps.query, nextProps.query) && + prevProps.renderCellValue === nextProps.renderCellValue && + prevProps.rowRenderers === nextProps.rowRenderers && deepEqual(prevProps.sort, nextProps.sort) && prevProps.start === nextProps.start && deepEqual(prevProps.pageFilters, nextProps.pageFilters) && diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx index 6c88b8e29800ba..cf6db52d0cece3 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx @@ -48,6 +48,8 @@ import { import { SourcererScopeName } from '../../../common/store/sourcerer/model'; import { useSourcererScope } from '../../../common/containers/sourcerer'; import { buildTimeRangeFilter } from './helpers'; +import { DefaultCellRenderer } from '../../../timelines/components/timeline/cell_rendering/default_cell_renderer'; +import { defaultRowRenderers } from '../../../timelines/components/timeline/body/renderers'; interface OwnProps { timelineId: TimelineIdLiteral; @@ -336,6 +338,8 @@ export const AlertsTableComponent: React.FC = ({ headerFilterGroup={headerFilterGroup} id={timelineId} onRuleChange={onRuleChange} + renderCellValue={DefaultCellRenderer} + rowRenderers={defaultRowRenderers} scopeId={SourcererScopeName.detections} start={from} utilityBar={utilityBarCallback} diff --git a/x-pack/plugins/security_solution/public/hosts/pages/navigation/events_query_tab_body.tsx b/x-pack/plugins/security_solution/public/hosts/pages/navigation/events_query_tab_body.tsx index 922d52b6cfe5a6..f88709e6e95ac8 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/navigation/events_query_tab_body.tsx +++ b/x-pack/plugins/security_solution/public/hosts/pages/navigation/events_query_tab_body.tsx @@ -21,6 +21,8 @@ import { useGlobalFullScreen } from '../../../common/containers/use_full_screen' import * as i18n from '../translations'; import { MatrixHistogramType } from '../../../../common/search_strategy/security_solution'; import { useManageTimeline } from '../../../timelines/components/manage_timeline'; +import { defaultRowRenderers } from '../../../timelines/components/timeline/body/renderers'; +import { DefaultCellRenderer } from '../../../timelines/components/timeline/cell_rendering/default_cell_renderer'; import { SourcererScopeName } from '../../../common/store/sourcerer/model'; const EVENTS_HISTOGRAM_ID = 'eventsHistogramQuery'; @@ -96,6 +98,8 @@ const EventsQueryTabBodyComponent: React.FC = ({ defaultModel={eventsDefaultModel} end={endDate} id={TimelineId.hostsPageEvents} + renderCellValue={DefaultCellRenderer} + rowRenderers={defaultRowRenderers} scopeId={SourcererScopeName.default} start={startDate} pageFilters={pageFilters} diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/pane/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/pane/index.tsx index e63ffedf3da7c3..459706de36569c 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/flyout/pane/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/pane/index.tsx @@ -14,6 +14,8 @@ import { StatefulTimeline } from '../../timeline'; import { TimelineId } from '../../../../../common/types/timeline'; import * as i18n from './translations'; import { timelineActions } from '../../../store/timeline'; +import { defaultRowRenderers } from '../../timeline/body/renderers'; +import { DefaultCellRenderer } from '../../timeline/cell_rendering/default_cell_renderer'; import { focusActiveTimelineButton } from '../../timeline/helpers'; interface FlyoutPaneComponentProps { @@ -46,7 +48,11 @@ const FlyoutPaneComponent: React.FC = ({ timelineId }) onClose={handleClose} size="l" > - + ); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/__snapshots__/index.test.tsx.snap index 72d2956bd4086d..91d039a19495ca 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/__snapshots__/index.test.tsx.snap @@ -22,26 +22,77 @@ exports[`Columns it renders the expected columns 1`] = ` You are in a table cell. row: 2, column: 2

- @@ -63,15 +114,77 @@ exports[`Columns it renders the expected columns 1`] = ` You are in a table cell. row: 2, column: 3

- @@ -93,15 +206,77 @@ exports[`Columns it renders the expected columns 1`] = ` You are in a table cell. row: 2, column: 4

- @@ -123,15 +298,77 @@ exports[`Columns it renders the expected columns 1`] = ` You are in a table cell. row: 2, column: 5

- @@ -153,15 +390,77 @@ exports[`Columns it renders the expected columns 1`] = ` You are in a table cell. row: 2, column: 6

- @@ -183,15 +482,77 @@ exports[`Columns it renders the expected columns 1`] = ` You are in a table cell. row: 2, column: 7

- @@ -213,15 +574,77 @@ exports[`Columns it renders the expected columns 1`] = ` You are in a table cell. row: 2, column: 8

- diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/index.test.tsx index f20978c6ba7265..234e28e6231c50 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/index.test.tsx @@ -9,10 +9,10 @@ import { shallow } from 'enzyme'; import React from 'react'; +import { DefaultCellRenderer } from '../../cell_rendering/default_cell_renderer'; import '../../../../../common/mock/match_media'; import { mockTimelineData } from '../../../../../common/mock'; import { defaultHeaders } from '../column_headers/default_headers'; -import { columnRenderers } from '../renderers'; import { DataDrivenColumns } from '.'; @@ -25,11 +25,11 @@ describe('Columns', () => { ariaRowindex={2} _id={mockTimelineData[0]._id} columnHeaders={headersSansTimestamp} - columnRenderers={columnRenderers} data={mockTimelineData[0].data} ecsData={mockTimelineData[0].ecs} hasRowRenderers={false} notesCount={0} + renderCellValue={DefaultCellRenderer} timelineId="test" /> ); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/index.tsx index 5aba562749f017..aeb9af46ea2ec2 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/index.tsx @@ -9,6 +9,7 @@ import { EuiScreenReaderOnly } from '@elastic/eui'; import React from 'react'; import { getOr } from 'lodash/fp'; +import { CellValueElementProps } from '../../cell_rendering'; import { DRAGGABLE_KEYBOARD_WRAPPER_CLASS_NAME } from '../../../../../common/components/drag_and_drop/helpers'; import { Ecs } from '../../../../../../common/ecs'; import { TimelineNonEcsData } from '../../../../../../common/search_strategy/timeline'; @@ -16,20 +17,19 @@ import { TimelineTabs } from '../../../../../../common/types/timeline'; import { ColumnHeaderOptions } from '../../../../../timelines/store/timeline/model'; import { ARIA_COLUMN_INDEX_OFFSET } from '../../helpers'; import { EventsTd, EVENTS_TD_CLASS_NAME, EventsTdContent, EventsTdGroupData } from '../../styles'; -import { ColumnRenderer } from '../renderers/column_renderer'; -import { getColumnRenderer } from '../renderers/get_column_renderer'; +import { StatefulCell } from './stateful_cell'; import * as i18n from './translations'; interface Props { _id: string; ariaRowindex: number; columnHeaders: ColumnHeaderOptions[]; - columnRenderers: ColumnRenderer[]; data: TimelineNonEcsData[]; ecsData: Ecs; hasRowRenderers: boolean; notesCount: number; + renderCellValue: (props: CellValueElementProps) => React.ReactNode; tabType?: TimelineTabs; timelineId: string; } @@ -82,11 +82,11 @@ export const DataDrivenColumns = React.memo( _id, ariaRowindex, columnHeaders, - columnRenderers, data, ecsData, hasRowRenderers, notesCount, + renderCellValue, tabType, timelineId, }) => ( @@ -105,18 +105,16 @@ export const DataDrivenColumns = React.memo(

{i18n.YOU_ARE_IN_A_TABLE_CELL({ row: ariaRowindex, column: i + 2 })}

- {getColumnRenderer(header.id, columnRenderers, data).renderColumn({ - columnName: header.id, - eventId: _id, - field: header, - linkValues: getOr([], header.linkField ?? '', ecsData), - timelineId: tabType != null ? `${timelineId}-${tabType}` : timelineId, - truncate: true, - values: getMappedNonEcsValue({ - data, - fieldName: header.id, - }), - })} + {hasRowRenderers ? ( diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/stateful_cell.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/stateful_cell.test.tsx new file mode 100644 index 00000000000000..3c75bc7fb2649c --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/stateful_cell.test.tsx @@ -0,0 +1,171 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { mount } from 'enzyme'; +import { cloneDeep } from 'lodash/fp'; +import React, { useEffect } from 'react'; + +import { CellValueElementProps } from '../../cell_rendering'; +import { defaultHeaders, mockTimelineData } from '../../../../../common/mock'; +import { TimelineNonEcsData } from '../../../../../../common/search_strategy/timeline'; +import { TimelineTabs } from '../../../../../../common/types/timeline'; +import { ColumnHeaderOptions } from '../../../../store/timeline/model'; + +import { StatefulCell } from './stateful_cell'; +import { getMappedNonEcsValue } from '.'; + +/** + * This (test) component implement's `EuiDataGrid`'s `renderCellValue` interface, + * as documented here: https://elastic.github.io/eui/#/tabular-content/data-grid + * + * Its `CellValueElementProps` props are a superset of `EuiDataGridCellValueElementProps`. + * The `setCellProps` function, defined by the `EuiDataGridCellValueElementProps` interface, + * is typically called in a `useEffect`, as illustrated by `EuiDataGrid`'s code sandbox example: + * https://codesandbox.io/s/zhxmo + */ +const RenderCellValue: React.FC = ({ columnId, data, setCellProps }) => { + useEffect(() => { + // branching logic that conditionally renders a specific cell green: + if (columnId === defaultHeaders[0].id) { + const value = getMappedNonEcsValue({ + data, + fieldName: columnId, + }); + + if (value?.length) { + setCellProps({ + style: { + backgroundColor: 'green', + }, + }); + } + } + }, [columnId, data, setCellProps]); + + return ( +
+ {getMappedNonEcsValue({ + data, + fieldName: columnId, + })} +
+ ); +}; + +describe('StatefulCell', () => { + const ariaRowindex = 123; + const eventId = '_id-123'; + const linkValues = ['foo', 'bar', '@baz']; + const tabType = TimelineTabs.query; + const timelineId = 'test'; + + let header: ColumnHeaderOptions; + let data: TimelineNonEcsData[]; + beforeEach(() => { + data = cloneDeep(mockTimelineData[0].data); + header = cloneDeep(defaultHeaders[0]); + }); + + test('it invokes renderCellValue with the expected arguments when tabType is specified', () => { + const renderCellValue = jest.fn(); + + mount( + + ); + + expect(renderCellValue).toBeCalledWith( + expect.objectContaining({ + columnId: header.id, + eventId, + data, + header, + isExpandable: true, + isExpanded: false, + isDetails: false, + linkValues, + rowIndex: ariaRowindex - 1, + timelineId: `${timelineId}-${tabType}`, + }) + ); + }); + + test('it invokes renderCellValue with the expected arguments when tabType is NOT specified', () => { + const renderCellValue = jest.fn(); + + mount( + + ); + + expect(renderCellValue).toBeCalledWith( + expect.objectContaining({ + columnId: header.id, + eventId, + data, + header, + isExpandable: true, + isExpanded: false, + isDetails: false, + linkValues, + rowIndex: ariaRowindex - 1, + timelineId, + }) + ); + }); + + test('it renders the React.Node returned by renderCellValue', () => { + const renderCellValue = () =>
; + + const wrapper = mount( + + ); + + expect(wrapper.find('[data-test-subj="renderCellValue"]').exists()).toBe(true); + }); + + test("it renders a div with the styles set by `renderCellValue`'s `setCellProps` argument", () => { + const wrapper = mount( + + ); + + expect( + wrapper.find('[data-test-subj="statefulCell"]').getDOMNode().getAttribute('style') + ).toEqual('background-color: green;'); + }); +}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/stateful_cell.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/stateful_cell.tsx new file mode 100644 index 00000000000000..83f603364ba8cc --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/stateful_cell.tsx @@ -0,0 +1,63 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { HTMLAttributes, useState } from 'react'; + +import { CellValueElementProps } from '../../cell_rendering'; +import { TimelineNonEcsData } from '../../../../../../common/search_strategy/timeline'; +import { TimelineTabs } from '../../../../../../common/types/timeline'; +import { ColumnHeaderOptions } from '../../../../../timelines/store/timeline/model'; + +export interface CommonProps { + className?: string; + 'aria-label'?: string; + 'data-test-subj'?: string; +} + +const StatefulCellComponent = ({ + ariaRowindex, + data, + header, + eventId, + linkValues, + renderCellValue, + tabType, + timelineId, +}: { + ariaRowindex: number; + data: TimelineNonEcsData[]; + header: ColumnHeaderOptions; + eventId: string; + linkValues: string[] | undefined; + renderCellValue: (props: CellValueElementProps) => React.ReactNode; + tabType?: TimelineTabs; + timelineId: string; +}) => { + const [cellProps, setCellProps] = useState>({}); + + return ( +
+ {renderCellValue({ + columnId: header.id, + eventId, + data, + header, + isExpandable: true, + isExpanded: false, + isDetails: false, + linkValues, + rowIndex: ariaRowindex - 1, + setCellProps, + timelineId: tabType != null ? `${timelineId}-${tabType}` : timelineId, + })} +
+ ); +}; + +StatefulCellComponent.displayName = 'StatefulCellComponent'; + +export const StatefulCell = React.memo(StatefulCellComponent); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/event_column_view.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/event_column_view.test.tsx index abdfda3272d6ad..74724dedf4d11d 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/event_column_view.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/event_column_view.test.tsx @@ -14,6 +14,7 @@ import { DEFAULT_ACTIONS_COLUMN_WIDTH } from '../constants'; import * as i18n from '../translations'; import { EventColumnView } from './event_column_view'; +import { DefaultCellRenderer } from '../../cell_rendering/default_cell_renderer'; import { TimelineTabs, TimelineType, TimelineId } from '../../../../../../common/types/timeline'; import { useShallowEqualSelector } from '../../../../../common/hooks/use_selector'; @@ -56,6 +57,7 @@ describe('EventColumnView', () => { onRowSelected: jest.fn(), onUnPinEvent: jest.fn(), refetch: jest.fn(), + renderCellValue: DefaultCellRenderer, selectedEventIds: {}, showCheckboxes: false, showNotes: false, diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/event_column_view.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/event_column_view.tsx index c6caf0a7b5b155..a0a0aeb23e8f74 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/event_column_view.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/event_column_view.tsx @@ -7,6 +7,7 @@ import React, { useCallback, useMemo } from 'react'; +import { CellValueElementProps } from '../../cell_rendering'; import { useShallowEqualSelector } from '../../../../../common/hooks/use_selector'; import { Ecs } from '../../../../../../common/ecs'; import { TimelineNonEcsData } from '../../../../../../common/search_strategy/timeline'; @@ -21,7 +22,6 @@ import { getPinOnClick, InvestigateInResolverAction, } from '../helpers'; -import { ColumnRenderer } from '../renderers/column_renderer'; import { AlertContextMenu } from '../../../../../detections/components/alerts_table/timeline_actions/alert_context_menu'; import { InvestigateInTimelineAction } from '../../../../../detections/components/alerts_table/timeline_actions/investigate_in_timeline_action'; import { AddEventNoteAction } from '../actions/add_note_icon_item'; @@ -38,7 +38,6 @@ interface Props { actionsColumnWidth: number; ariaRowindex: number; columnHeaders: ColumnHeaderOptions[]; - columnRenderers: ColumnRenderer[]; data: TimelineNonEcsData[]; ecsData: Ecs; eventIdToNoteIds: Readonly>; @@ -51,6 +50,7 @@ interface Props { onRowSelected: OnRowSelected; onUnPinEvent: OnUnPinEvent; refetch: inputsModel.Refetch; + renderCellValue: (props: CellValueElementProps) => React.ReactNode; onRuleChange?: () => void; hasRowRenderers: boolean; selectedEventIds: Readonly>; @@ -69,7 +69,6 @@ export const EventColumnView = React.memo( actionsColumnWidth, ariaRowindex, columnHeaders, - columnRenderers, data, ecsData, eventIdToNoteIds, @@ -84,6 +83,7 @@ export const EventColumnView = React.memo( refetch, hasRowRenderers, onRuleChange, + renderCellValue, selectedEventIds, showCheckboxes, showNotes, @@ -227,11 +227,11 @@ export const EventColumnView = React.memo( _id={id} ariaRowindex={ariaRowindex} columnHeaders={columnHeaders} - columnRenderers={columnRenderers} data={data} ecsData={ecsData} hasRowRenderers={hasRowRenderers} notesCount={notesCount} + renderCellValue={renderCellValue} tabType={tabType} timelineId={timelineId} /> diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/index.tsx index d76b5834c233e6..7f8a3a92fb5bab 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/index.tsx @@ -8,6 +8,7 @@ import React from 'react'; import { isEmpty } from 'lodash'; +import { CellValueElementProps } from '../../cell_rendering'; import { inputsModel } from '../../../../../common/store'; import { BrowserFields } from '../../../../../common/containers/source'; import { @@ -18,7 +19,6 @@ import { TimelineTabs } from '../../../../../../common/types/timeline'; import { ColumnHeaderOptions } from '../../../../../timelines/store/timeline/model'; import { OnRowSelected } from '../../events'; import { EventsTbody } from '../../styles'; -import { ColumnRenderer } from '../renderers/column_renderer'; import { RowRenderer } from '../renderers/row_renderer'; import { StatefulEvent } from './stateful_event'; import { eventIsPinned } from '../helpers'; @@ -30,7 +30,6 @@ interface Props { actionsColumnWidth: number; browserFields: BrowserFields; columnHeaders: ColumnHeaderOptions[]; - columnRenderers: ColumnRenderer[]; containerRef: React.MutableRefObject; data: TimelineItem[]; eventIdToNoteIds: Readonly>; @@ -41,6 +40,7 @@ interface Props { onRowSelected: OnRowSelected; pinnedEventIds: Readonly>; refetch: inputsModel.Refetch; + renderCellValue: (props: CellValueElementProps) => React.ReactNode; onRuleChange?: () => void; rowRenderers: RowRenderer[]; selectedEventIds: Readonly>; @@ -52,7 +52,6 @@ const EventsComponent: React.FC = ({ actionsColumnWidth, browserFields, columnHeaders, - columnRenderers, containerRef, data, eventIdToNoteIds, @@ -64,6 +63,7 @@ const EventsComponent: React.FC = ({ pinnedEventIds, refetch, onRuleChange, + renderCellValue, rowRenderers, selectedEventIds, showCheckboxes, @@ -76,7 +76,6 @@ const EventsComponent: React.FC = ({ ariaRowindex={i + ARIA_ROW_INDEX_OFFSET} browserFields={browserFields} columnHeaders={columnHeaders} - columnRenderers={columnRenderers} containerRef={containerRef} event={event} eventIdToNoteIds={eventIdToNoteIds} @@ -88,6 +87,7 @@ const EventsComponent: React.FC = ({ lastFocusedAriaColindex={lastFocusedAriaColindex} loadingEventIds={loadingEventIds} onRowSelected={onRowSelected} + renderCellValue={renderCellValue} refetch={refetch} rowRenderers={rowRenderers} onRuleChange={onRuleChange} diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/stateful_event.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/stateful_event.tsx index 4191badd6b03fb..97ab088b615833 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/stateful_event.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/stateful_event.tsx @@ -8,6 +8,7 @@ import React, { useCallback, useMemo, useRef, useState } from 'react'; import { useDispatch } from 'react-redux'; +import { CellValueElementProps } from '../../cell_rendering'; import { useDeepEqualSelector } from '../../../../../common/hooks/use_selector'; import { TimelineExpandedDetailType, @@ -23,7 +24,6 @@ import { ColumnHeaderOptions } from '../../../../../timelines/store/timeline/mod import { OnPinEvent, OnRowSelected } from '../../events'; import { STATEFUL_EVENT_CSS_CLASS_NAME } from '../../helpers'; import { EventsTrGroup, EventsTrSupplement, EventsTrSupplementContainer } from '../../styles'; -import { ColumnRenderer } from '../renderers/column_renderer'; import { RowRenderer } from '../renderers/row_renderer'; import { isEventBuildingBlockType, getEventType, isEvenEqlSequence } from '../helpers'; import { NoteCards } from '../../../notes/note_cards'; @@ -45,7 +45,6 @@ interface Props { containerRef: React.MutableRefObject; browserFields: BrowserFields; columnHeaders: ColumnHeaderOptions[]; - columnRenderers: ColumnRenderer[]; event: TimelineItem; eventIdToNoteIds: Readonly>; isEventViewer?: boolean; @@ -56,6 +55,7 @@ interface Props { refetch: inputsModel.Refetch; ariaRowindex: number; onRuleChange?: () => void; + renderCellValue: (props: CellValueElementProps) => React.ReactNode; rowRenderers: RowRenderer[]; selectedEventIds: Readonly>; showCheckboxes: boolean; @@ -77,7 +77,6 @@ const StatefulEventComponent: React.FC = ({ browserFields, containerRef, columnHeaders, - columnRenderers, event, eventIdToNoteIds, isEventViewer = false, @@ -86,8 +85,9 @@ const StatefulEventComponent: React.FC = ({ loadingEventIds, onRowSelected, refetch, - onRuleChange, + renderCellValue, rowRenderers, + onRuleChange, ariaRowindex, selectedEventIds, showCheckboxes, @@ -259,7 +259,6 @@ const StatefulEventComponent: React.FC = ({ actionsColumnWidth={actionsColumnWidth} ariaRowindex={ariaRowindex} columnHeaders={columnHeaders} - columnRenderers={columnRenderers} data={event.data} ecsData={event.ecs} eventIdToNoteIds={eventIdToNoteIds} @@ -273,6 +272,7 @@ const StatefulEventComponent: React.FC = ({ onRowSelected={onRowSelected} onUnPinEvent={onUnPinEvent} refetch={refetch} + renderCellValue={renderCellValue} onRuleChange={onRuleChange} selectedEventIds={selectedEventIds} showCheckboxes={showCheckboxes} diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.test.tsx index 723e4c3de5c275..76dbfc553d228d 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.test.tsx @@ -8,6 +8,7 @@ import React from 'react'; import { waitFor } from '@testing-library/react'; +import { DefaultCellRenderer } from '../cell_rendering/default_cell_renderer'; import '../../../../common/mock/match_media'; import { mockBrowserFields } from '../../../../common/containers/source/mock'; import { Direction } from '../../../../../common/search_strategy'; @@ -19,6 +20,7 @@ import { Sort } from './sort'; import { useMountAppended } from '../../../../common/utils/use_mount_appended'; import { timelineActions } from '../../../store/timeline'; import { TimelineTabs } from '../../../../../common/types/timeline'; +import { defaultRowRenderers } from './renderers'; const mockSort: Sort[] = [ { @@ -39,8 +41,8 @@ jest.mock('react-redux', () => { }); jest.mock('../../../../common/hooks/use_selector', () => ({ - useShallowEqualSelector: jest.fn().mockReturnValue(mockTimelineModel), - useDeepEqualSelector: jest.fn().mockReturnValue(mockTimelineModel), + useShallowEqualSelector: () => mockTimelineModel, + useDeepEqualSelector: () => mockTimelineModel, })); jest.mock('../../../../common/components/link_to'); @@ -76,6 +78,8 @@ describe('Body', () => { loadingEventIds: [], pinnedEventIds: {}, refetch: jest.fn(), + renderCellValue: DefaultCellRenderer, + rowRenderers: defaultRowRenderers, selectedEventIds: {}, setSelected: (jest.fn() as unknown) as StatefulBodyProps['setSelected'], sort: mockSort, diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.tsx index 4df6eb16ccb623..59c0610c544e94 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.tsx @@ -11,6 +11,7 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { connect, ConnectedProps } from 'react-redux'; import deepEqual from 'fast-deep-equal'; +import { CellValueElementProps } from '../cell_rendering'; import { RowRendererId, TimelineId, TimelineTabs } from '../../../../../common/types/timeline'; import { FIRST_ARIA_INDEX, @@ -28,9 +29,9 @@ import { timelineActions, timelineSelectors } from '../../../store/timeline'; import { OnRowSelected, OnSelectAll } from '../events'; import { getActionsColumnWidth, getColumnHeaders } from './column_headers/helpers'; import { getEventIdToDataMapping } from './helpers'; -import { columnRenderers, rowRenderers } from './renderers'; import { Sort } from './sort'; import { plainRowRenderer } from './renderers/plain_row_renderer'; +import { RowRenderer } from './renderers/row_renderer'; import { EventsTable, TimelineBody, TimelineBodyGlobalStyle } from '../styles'; import { ColumnHeaders } from './column_headers'; import { Events } from './events'; @@ -44,6 +45,8 @@ interface OwnProps { isEventViewer?: boolean; sort: Sort[]; refetch: inputsModel.Refetch; + renderCellValue: (props: CellValueElementProps) => React.ReactNode; + rowRenderers: RowRenderer[]; tabType: TimelineTabs; totalPages: number; onRuleChange?: () => void; @@ -83,6 +86,8 @@ export const BodyComponent = React.memo( onRuleChange, showCheckboxes, refetch, + renderCellValue, + rowRenderers, sort, tabType, totalPages, @@ -141,7 +146,7 @@ export const BodyComponent = React.memo( if (!excludedRowRendererIds) return rowRenderers; return rowRenderers.filter((rowRenderer) => !excludedRowRendererIds.includes(rowRenderer.id)); - }, [excludedRowRendererIds]); + }, [excludedRowRendererIds, rowRenderers]); const actionsColumnWidth = useMemo( () => @@ -209,7 +214,6 @@ export const BodyComponent = React.memo( actionsColumnWidth={actionsColumnWidth} browserFields={browserFields} columnHeaders={columnHeaders} - columnRenderers={columnRenderers} data={data} eventIdToNoteIds={eventIdToNoteIds} id={id} @@ -219,6 +223,7 @@ export const BodyComponent = React.memo( onRowSelected={onRowSelected} pinnedEventIds={pinnedEventIds} refetch={refetch} + renderCellValue={renderCellValue} rowRenderers={enabledRowRenderers} onRuleChange={onRuleChange} selectedEventIds={selectedEventIds} @@ -244,6 +249,8 @@ export const BodyComponent = React.memo( prevProps.id === nextProps.id && prevProps.isEventViewer === nextProps.isEventViewer && prevProps.isSelectAllChecked === nextProps.isSelectAllChecked && + prevProps.renderCellValue === nextProps.renderCellValue && + prevProps.rowRenderers === nextProps.rowRenderers && prevProps.showCheckboxes === nextProps.showCheckboxes && prevProps.tabType === nextProps.tabType ); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/get_row_renderer.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/get_row_renderer.test.tsx index 6e36102da2de94..b92a4381d837b3 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/get_row_renderer.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/get_row_renderer.test.tsx @@ -17,7 +17,7 @@ import { mockTimelineData } from '../../../../../common/mock'; import { TestProviders } from '../../../../../common/mock/test_providers'; import { useMountAppended } from '../../../../../common/utils/use_mount_appended'; -import { rowRenderers } from '.'; +import { defaultRowRenderers } from '.'; import { getRowRenderer } from './get_row_renderer'; jest.mock('@elastic/eui', () => { @@ -48,7 +48,7 @@ describe('get_column_renderer', () => { }); test('renders correctly against snapshot', () => { - const rowRenderer = getRowRenderer(nonSuricata, rowRenderers); + const rowRenderer = getRowRenderer(nonSuricata, defaultRowRenderers); const row = rowRenderer?.renderRow({ browserFields: mockBrowserFields, data: nonSuricata, @@ -60,7 +60,7 @@ describe('get_column_renderer', () => { }); test('should render plain row data when it is a non suricata row', () => { - const rowRenderer = getRowRenderer(nonSuricata, rowRenderers); + const rowRenderer = getRowRenderer(nonSuricata, defaultRowRenderers); const row = rowRenderer?.renderRow({ browserFields: mockBrowserFields, data: nonSuricata, @@ -75,7 +75,7 @@ describe('get_column_renderer', () => { }); test('should render a suricata row data when it is a suricata row', () => { - const rowRenderer = getRowRenderer(suricata, rowRenderers); + const rowRenderer = getRowRenderer(suricata, defaultRowRenderers); const row = rowRenderer?.renderRow({ browserFields: mockBrowserFields, data: suricata, @@ -93,7 +93,7 @@ describe('get_column_renderer', () => { test('should render a suricata row data if event.category is network_traffic', () => { suricata.event = { ...suricata.event, ...{ category: ['network_traffic'] } }; - const rowRenderer = getRowRenderer(suricata, rowRenderers); + const rowRenderer = getRowRenderer(suricata, defaultRowRenderers); const row = rowRenderer?.renderRow({ browserFields: mockBrowserFields, data: suricata, @@ -111,7 +111,7 @@ describe('get_column_renderer', () => { test('should render a zeek row data if event.category is network_traffic', () => { zeek.event = { ...zeek.event, ...{ category: ['network_traffic'] } }; - const rowRenderer = getRowRenderer(zeek, rowRenderers); + const rowRenderer = getRowRenderer(zeek, defaultRowRenderers); const row = rowRenderer?.renderRow({ browserFields: mockBrowserFields, data: zeek, @@ -129,7 +129,7 @@ describe('get_column_renderer', () => { test('should render a system row data if event.category is network_traffic', () => { system.event = { ...system.event, ...{ category: ['network_traffic'] } }; - const rowRenderer = getRowRenderer(system, rowRenderers); + const rowRenderer = getRowRenderer(system, defaultRowRenderers); const row = rowRenderer?.renderRow({ browserFields: mockBrowserFields, data: system, @@ -147,7 +147,7 @@ describe('get_column_renderer', () => { test('should render a auditd row data if event.category is network_traffic', () => { auditd.event = { ...auditd.event, ...{ category: ['network_traffic'] } }; - const rowRenderer = getRowRenderer(auditd, rowRenderers); + const rowRenderer = getRowRenderer(auditd, defaultRowRenderers); const row = rowRenderer?.renderRow({ browserFields: mockBrowserFields, data: auditd, diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/index.ts b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/index.ts index 671d183c62e6d6..209a9414f62f18 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/index.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/index.ts @@ -23,7 +23,7 @@ import { systemRowRenderers } from './system/generic_row_renderer'; // Suricata and Zeek which is why Suricata and Zeek are above it. The // plainRowRenderer always returns true to everything which is why it always // should be last. -export const rowRenderers: RowRenderer[] = [ +export const defaultRowRenderers: RowRenderer[] = [ ...auditdRowRenderers, ...systemRowRenderers, suricataRowRenderer, diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/cell_rendering/default_cell_renderer.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/cell_rendering/default_cell_renderer.test.tsx new file mode 100644 index 00000000000000..5ac1dcf8805cf6 --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/cell_rendering/default_cell_renderer.test.tsx @@ -0,0 +1,107 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { mount } from 'enzyme'; +import { cloneDeep } from 'lodash/fp'; +import React from 'react'; + +import { columnRenderers } from '../body/renderers'; +import { getColumnRenderer } from '../body/renderers/get_column_renderer'; +import { DragDropContextWrapper } from '../../../../common/components/drag_and_drop/drag_drop_context_wrapper'; +import { DroppableWrapper } from '../../../../common/components/drag_and_drop/droppable_wrapper'; +import { mockBrowserFields } from '../../../../common/containers/source/mock'; +import { defaultHeaders, mockTimelineData, TestProviders } from '../../../../common/mock'; +import { DefaultCellRenderer } from './default_cell_renderer'; + +jest.mock('../body/renderers/get_column_renderer'); +const getColumnRendererMock = getColumnRenderer as jest.Mock; +const mockImplementation = { + renderColumn: jest.fn(), +}; + +describe('DefaultCellRenderer', () => { + const columnId = 'signal.rule.risk_score'; + const eventId = '_id-123'; + const isDetails = true; + const isExpandable = true; + const isExpanded = true; + const linkValues = ['foo', 'bar', '@baz']; + const rowIndex = 3; + const setCellProps = jest.fn(); + const timelineId = 'test'; + + beforeEach(() => { + jest.clearAllMocks(); + getColumnRendererMock.mockImplementation(() => mockImplementation); + }); + + test('it invokes `getColumnRenderer` with the expected arguments', () => { + const data = cloneDeep(mockTimelineData[0].data); + const header = cloneDeep(defaultHeaders[0]); + + mount( + + + + + + + + ); + + expect(getColumnRenderer).toBeCalledWith(header.id, columnRenderers, data); + }); + + test('it invokes `renderColumn` with the expected arguments', () => { + const data = cloneDeep(mockTimelineData[0].data); + const header = cloneDeep(defaultHeaders[0]); + + mount( + + + + + + + + ); + + expect(mockImplementation.renderColumn).toBeCalledWith({ + columnName: header.id, + eventId, + field: header, + linkValues, + timelineId, + truncate: true, + values: ['2018-11-05T19:03:25.937Z'], + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/cell_rendering/default_cell_renderer.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/cell_rendering/default_cell_renderer.tsx new file mode 100644 index 00000000000000..8d8f821107e7bc --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/cell_rendering/default_cell_renderer.tsx @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { getMappedNonEcsValue } from '../body/data_driven_columns'; +import { columnRenderers } from '../body/renderers'; +import { getColumnRenderer } from '../body/renderers/get_column_renderer'; + +import { CellValueElementProps } from '.'; + +export const DefaultCellRenderer: React.FC = ({ + columnId, + data, + eventId, + header, + linkValues, + setCellProps, + timelineId, +}) => ( + <> + {getColumnRenderer(header.id, columnRenderers, data).renderColumn({ + columnName: header.id, + eventId, + field: header, + linkValues, + timelineId, + truncate: true, + values: getMappedNonEcsValue({ + data, + fieldName: header.id, + }), + })} + +); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/cell_rendering/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/cell_rendering/index.tsx new file mode 100644 index 00000000000000..03e444e3a9afda --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/cell_rendering/index.tsx @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiDataGridCellValueElementProps } from '@elastic/eui'; + +import { TimelineNonEcsData } from '../../../../../common/search_strategy/timeline'; +import { ColumnHeaderOptions } from '../../../store/timeline/model'; + +/** The following props are provided to the function called by `renderCellValue` */ +export type CellValueElementProps = EuiDataGridCellValueElementProps & { + data: TimelineNonEcsData[]; + eventId: string; // _id + header: ColumnHeaderOptions; + linkValues: string[] | undefined; + timelineId: string; +}; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/eql_tab_content/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/timeline/eql_tab_content/__snapshots__/index.test.tsx.snap index 2595f29144b805..7d237ecaf92df1 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/eql_tab_content/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/eql_tab_content/__snapshots__/index.test.tsx.snap @@ -140,6 +140,986 @@ In other use cases the message field can be used to concatenate different values ] } onEventClosed={[MockFunction]} + renderCellValue={[Function]} + rowRenderers={ + Array [ + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_dns", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_security_event", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_security_event", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_fim", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_fim", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_fim", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_fim", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_fim", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_fim", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "alerts", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "alerts", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "alerts", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "alerts", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "alerts", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "alerts", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "alerts", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "alerts", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "alerts", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "alerts", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "library", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_fim", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "registry", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_socket", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_socket", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_socket", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_socket", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_socket", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_socket", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_socket", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_security_event", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_security_event", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_security_event", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_fim", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_fim", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_security_event", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_socket", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_socket", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "suricata", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "zeek", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "netflow", + "isInstance": [Function], + "renderRow": [Function], + }, + ] + } showExpandedDetails={false} start="2018-03-23T18:49:23.132Z" timelineId="test" diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/eql_tab_content/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/eql_tab_content/index.test.tsx index 7b77a915f2f057..e13bed1e2eff65 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/eql_tab_content/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/eql_tab_content/index.test.tsx @@ -9,6 +9,8 @@ import { shallow } from 'enzyme'; import React from 'react'; import useResizeObserver from 'use-resize-observer/polyfilled'; +import { defaultRowRenderers } from '../body/renderers'; +import { DefaultCellRenderer } from '../cell_rendering/default_cell_renderer'; import { defaultHeaders, mockTimelineData } from '../../../../common/mock'; import '../../../../common/mock/match_media'; import { TestProviders } from '../../../../common/mock/test_providers'; @@ -94,6 +96,8 @@ describe('Timeline', () => { itemsPerPage: 5, itemsPerPageOptions: [5, 10, 20], onEventClosed: jest.fn(), + renderCellValue: DefaultCellRenderer, + rowRenderers: defaultRowRenderers, showExpandedDetails: false, start: startDate, timerangeKind: 'absolute', diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/eql_tab_content/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/eql_tab_content/index.tsx index 51f8db4e796e52..6bb19ce5a6852c 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/eql_tab_content/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/eql_tab_content/index.tsx @@ -22,10 +22,12 @@ import deepEqual from 'fast-deep-equal'; import { InPortal } from 'react-reverse-portal'; import { timelineActions, timelineSelectors } from '../../../store/timeline'; +import { CellValueElementProps } from '../cell_rendering'; import { TimelineItem } from '../../../../../common/search_strategy'; import { useTimelineEvents } from '../../../containers/index'; import { defaultHeaders } from '../body/column_headers/default_headers'; import { StatefulBody } from '../body'; +import { RowRenderer } from '../body/renderers/row_renderer'; import { Footer, footerHeight } from '../footer'; import { calculateTotalPages } from '../helpers'; import { TimelineRefetch } from '../refetch_timeline'; @@ -133,6 +135,8 @@ const isTimerangeSame = (prevProps: Props, nextProps: Props) => prevProps.timerangeKind === nextProps.timerangeKind; interface OwnProps { + renderCellValue: (props: CellValueElementProps) => React.ReactNode; + rowRenderers: RowRenderer[]; timelineId: string; } @@ -154,6 +158,8 @@ export const EqlTabContentComponent: React.FC = ({ itemsPerPage, itemsPerPageOptions, onEventClosed, + renderCellValue, + rowRenderers, showExpandedDetails, start, timerangeKind, @@ -284,6 +290,8 @@ export const EqlTabContentComponent: React.FC = ({ data={isBlankTimeline ? EMPTY_EVENTS : events} id={timelineId} refetch={refetch} + renderCellValue={renderCellValue} + rowRenderers={rowRenderers} sort={NO_SORTING} tabType={TimelineTabs.eql} totalPages={calculateTotalPages({ diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/index.test.tsx index ee2ce8cf8103b5..db7a3cc3c9900b 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/index.test.tsx @@ -17,7 +17,9 @@ import { mockIndexNames, mockIndexPattern, TestProviders } from '../../../common import { StatefulTimeline, Props as StatefulTimelineOwnProps } from './index'; import { useTimelineEvents } from '../../containers/index'; +import { DefaultCellRenderer } from './cell_rendering/default_cell_renderer'; import { SELECTOR_TIMELINE_GLOBAL_CONTAINER } from './styles'; +import { defaultRowRenderers } from './body/renderers'; jest.mock('../../containers/index', () => ({ useTimelineEvents: jest.fn(), @@ -63,6 +65,8 @@ jest.mock('../../../common/containers/sourcerer', () => { }); describe('StatefulTimeline', () => { const props: StatefulTimelineOwnProps = { + renderCellValue: DefaultCellRenderer, + rowRenderers: defaultRowRenderers, timelineId: TimelineId.test, }; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/index.tsx index 6d2374dd8eef73..367357511c9c8e 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/index.tsx @@ -14,6 +14,8 @@ import styled from 'styled-components'; import { timelineActions, timelineSelectors } from '../../store/timeline'; import { timelineDefaults } from '../../../timelines/store/timeline/defaults'; import { defaultHeaders } from './body/column_headers/default_headers'; +import { RowRenderer } from './body/renderers/row_renderer'; +import { CellValueElementProps } from './cell_rendering'; import { isTab } from '../../../common/components/accessibility/helpers'; import { useSourcererScope } from '../../../common/containers/sourcerer'; import { SourcererScopeName } from '../../../common/store/sourcerer/model'; @@ -36,10 +38,12 @@ const TimelineTemplateBadge = styled.div` `; export interface Props { + renderCellValue: (props: CellValueElementProps) => React.ReactNode; + rowRenderers: RowRenderer[]; timelineId: TimelineId; } -const TimelineSavingProgressComponent: React.FC = ({ timelineId }) => { +const TimelineSavingProgressComponent: React.FC<{ timelineId: TimelineId }> = ({ timelineId }) => { const getTimeline = useMemo(() => timelineSelectors.getTimelineByIdSelector(), []); const isSaving = useShallowEqualSelector( (state) => (getTimeline(state, timelineId) ?? timelineDefaults).isSaving @@ -50,7 +54,11 @@ const TimelineSavingProgressComponent: React.FC = ({ timelineId }) => { const TimelineSavingProgress = React.memo(TimelineSavingProgressComponent); -const StatefulTimelineComponent: React.FC = ({ timelineId }) => { +const StatefulTimelineComponent: React.FC = ({ + renderCellValue, + rowRenderers, + timelineId, +}) => { const dispatch = useDispatch(); const containerElement = useRef(null); const getTimeline = useMemo(() => timelineSelectors.getTimelineByIdSelector(), []); @@ -131,6 +139,8 @@ const StatefulTimelineComponent: React.FC = ({ timelineId }) => { { timelineId: TimelineId.test, itemsPerPage: 5, itemsPerPageOptions: [5, 10, 20], + renderCellValue: DefaultCellRenderer, + rowRenderers: defaultRowRenderers, sort, pinnedEventIds: {}, showExpandedDetails: false, diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/pinned_tab_content/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/pinned_tab_content/index.tsx index a19a61d8268ff8..dfc14747dacf35 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/pinned_tab_content/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/pinned_tab_content/index.tsx @@ -14,10 +14,12 @@ import { connect, ConnectedProps } from 'react-redux'; import deepEqual from 'fast-deep-equal'; import { timelineActions, timelineSelectors } from '../../../store/timeline'; +import { CellValueElementProps } from '../cell_rendering'; import { Direction } from '../../../../../common/search_strategy'; import { useTimelineEvents } from '../../../containers/index'; import { defaultHeaders } from '../body/column_headers/default_headers'; import { StatefulBody } from '../body'; +import { RowRenderer } from '../body/renderers/row_renderer'; import { Footer, footerHeight } from '../footer'; import { requiredFieldsForActions } from '../../../../detections/components/alerts_table/default_config'; import { EventDetailsWidthProvider } from '../../../../common/components/events_viewer/event_details_width_context'; @@ -87,6 +89,8 @@ const VerticalRule = styled.div` VerticalRule.displayName = 'VerticalRule'; interface OwnProps { + renderCellValue: (props: CellValueElementProps) => React.ReactNode; + rowRenderers: RowRenderer[]; timelineId: string; } @@ -106,6 +110,8 @@ export const PinnedTabContentComponent: React.FC = ({ itemsPerPageOptions, pinnedEventIds, onEventClosed, + renderCellValue, + rowRenderers, showExpandedDetails, sort, }) => { @@ -217,6 +223,8 @@ export const PinnedTabContentComponent: React.FC = ({ data={events} id={timelineId} refetch={refetch} + renderCellValue={renderCellValue} + rowRenderers={rowRenderers} sort={sort} tabType={TimelineTabs.pinned} totalPages={calculateTotalPages({ diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/__snapshots__/index.test.tsx.snap index 0688a10b31eefb..46c85f634ff6b7 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/__snapshots__/index.test.tsx.snap @@ -276,6 +276,986 @@ In other use cases the message field can be used to concatenate different values kqlMode="search" kqlQueryExpression="" onEventClosed={[MockFunction]} + renderCellValue={[Function]} + rowRenderers={ + Array [ + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "auditd", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_dns", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_security_event", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_security_event", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_fim", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_fim", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_fim", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_fim", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_fim", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_fim", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "alerts", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "alerts", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "alerts", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "alerts", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "alerts", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "alerts", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "alerts", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "alerts", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "alerts", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "alerts", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "library", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_fim", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "registry", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_socket", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_socket", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_socket", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_socket", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_socket", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_socket", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_socket", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_security_event", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_security_event", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_security_event", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_fim", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_fim", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_security_event", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_file", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_socket", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system_socket", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "system", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "suricata", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "zeek", + "isInstance": [Function], + "renderRow": [Function], + }, + Object { + "id": "netflow", + "isInstance": [Function], + "renderRow": [Function], + }, + ] + } show={true} showCallOutUnauthorizedMsg={false} showExpandedDetails={false} diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.test.tsx index c7d27da64c6506..ede473acbfb2ab 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.test.tsx @@ -10,11 +10,13 @@ import React from 'react'; import useResizeObserver from 'use-resize-observer/polyfilled'; import { Direction } from '../../../../graphql/types'; +import { DefaultCellRenderer } from '../cell_rendering/default_cell_renderer'; import { defaultHeaders, mockTimelineData } from '../../../../common/mock'; import '../../../../common/mock/match_media'; import { TestProviders } from '../../../../common/mock/test_providers'; import { QueryTabContentComponent, Props as QueryTabContentComponentProps } from './index'; +import { defaultRowRenderers } from '../body/renderers'; import { Sort } from '../body/sort'; import { mockDataProviders } from '../data_providers/mock/mock_data_providers'; import { useMountAppended } from '../../../../common/utils/use_mount_appended'; @@ -106,6 +108,8 @@ describe('Timeline', () => { kqlMode: 'search' as QueryTabContentComponentProps['kqlMode'], kqlQueryExpression: '', onEventClosed: jest.fn(), + renderCellValue: DefaultCellRenderer, + rowRenderers: defaultRowRenderers, showCallOutUnauthorizedMsg: false, showExpandedDetails: false, sort, diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.tsx index 28fec7ded9ca22..74a0f023542197 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.tsx @@ -22,6 +22,8 @@ import deepEqual from 'fast-deep-equal'; import { InPortal } from 'react-reverse-portal'; import { timelineActions, timelineSelectors } from '../../../store/timeline'; +import { RowRenderer } from '../body/renderers/row_renderer'; +import { CellValueElementProps } from '../cell_rendering'; import { Direction, TimelineItem } from '../../../../../common/search_strategy'; import { useTimelineEvents } from '../../../containers/index'; import { useKibana } from '../../../../common/lib/kibana'; @@ -142,6 +144,8 @@ const compareQueryProps = (prevProps: Props, nextProps: Props) => deepEqual(prevProps.filters, nextProps.filters); interface OwnProps { + renderCellValue: (props: CellValueElementProps) => React.ReactNode; + rowRenderers: RowRenderer[]; timelineId: string; } @@ -164,6 +168,8 @@ export const QueryTabContentComponent: React.FC = ({ kqlMode, kqlQueryExpression, onEventClosed, + renderCellValue, + rowRenderers, show, showCallOutUnauthorizedMsg, showExpandedDetails, @@ -330,6 +336,8 @@ export const QueryTabContentComponent: React.FC = ({ data={isBlankTimeline ? EMPTY_EVENTS : events} id={timelineId} refetch={refetch} + renderCellValue={renderCellValue} + rowRenderers={rowRenderers} sort={sort} tabType={TimelineTabs.query} totalPages={calculateTotalPages({ diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs_content/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs_content/index.tsx index f29211d5198417..76a2ad0960322b 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs_content/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs_content/index.tsx @@ -20,6 +20,8 @@ import { TimelineEventsCountBadge, } from '../../../../common/hooks/use_timeline_events_count'; import { timelineActions } from '../../../store/timeline'; +import { RowRenderer } from '../body/renderers/row_renderer'; +import { CellValueElementProps } from '../cell_rendering'; import { getActiveTabSelector, getNoteIdsSelector, @@ -46,6 +48,8 @@ const NotesTabContent = lazy(() => import('../notes_tab_content')); const PinnedTabContent = lazy(() => import('../pinned_tab_content')); interface BasicTimelineTab { + renderCellValue: (props: CellValueElementProps) => React.ReactNode; + rowRenderers: RowRenderer[]; setTimelineFullScreen?: (fullScreen: boolean) => void; timelineFullScreen?: boolean; timelineId: TimelineId; @@ -53,16 +57,32 @@ interface BasicTimelineTab { graphEventId?: string; } -const QueryTab: React.FC<{ timelineId: TimelineId }> = memo(({ timelineId }) => ( +const QueryTab: React.FC<{ + renderCellValue: (props: CellValueElementProps) => React.ReactNode; + rowRenderers: RowRenderer[]; + timelineId: TimelineId; +}> = memo(({ renderCellValue, rowRenderers, timelineId }) => ( }> - + )); QueryTab.displayName = 'QueryTab'; -const EqlTab: React.FC<{ timelineId: TimelineId }> = memo(({ timelineId }) => ( +const EqlTab: React.FC<{ + renderCellValue: (props: CellValueElementProps) => React.ReactNode; + rowRenderers: RowRenderer[]; + timelineId: TimelineId; +}> = memo(({ renderCellValue, rowRenderers, timelineId }) => ( }> - + )); EqlTab.displayName = 'EqlTab'; @@ -81,9 +101,17 @@ const NotesTab: React.FC<{ timelineId: TimelineId }> = memo(({ timelineId }) => )); NotesTab.displayName = 'NotesTab'; -const PinnedTab: React.FC<{ timelineId: TimelineId }> = memo(({ timelineId }) => ( +const PinnedTab: React.FC<{ + renderCellValue: (props: CellValueElementProps) => React.ReactNode; + rowRenderers: RowRenderer[]; + timelineId: TimelineId; +}> = memo(({ renderCellValue, rowRenderers, timelineId }) => ( }> - + )); PinnedTab.displayName = 'PinnedTab'; @@ -91,7 +119,7 @@ PinnedTab.displayName = 'PinnedTab'; type ActiveTimelineTabProps = BasicTimelineTab & { activeTimelineTab: TimelineTabs }; const ActiveTimelineTab = memo( - ({ activeTimelineTab, timelineId, timelineType }) => { + ({ activeTimelineTab, renderCellValue, rowRenderers, timelineId, timelineType }) => { const getTab = useCallback( (tab: TimelineTabs) => { switch (tab) { @@ -119,14 +147,26 @@ const ActiveTimelineTab = memo( return ( <> - + - + {timelineType === TimelineType.default && ( - + )} @@ -160,6 +200,8 @@ const StyledEuiTab = styled(EuiTab)` `; const TabsContentComponent: React.FC = ({ + renderCellValue, + rowRenderers, timelineId, timelineFullScreen, timelineType, @@ -300,6 +342,8 @@ const TabsContentComponent: React.FC = ({ diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_local_storage.test.tsx b/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_local_storage.test.tsx index 3d92397f4ab507..0b70ba8991686c 100644 --- a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_local_storage.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_local_storage.test.tsx @@ -30,11 +30,12 @@ import { updateItemsPerPage, updateSort, } from './actions'; - +import { DefaultCellRenderer } from '../../components/timeline/cell_rendering/default_cell_renderer'; import { QueryTabContentComponent, Props as QueryTabContentComponentProps, } from '../../components/timeline/query_tab_content'; +import { defaultRowRenderers } from '../../components/timeline/body/renderers'; import { mockDataProviders } from '../../components/timeline/data_providers/mock/mock_data_providers'; import { Sort } from '../../components/timeline/body/sort'; import { Direction } from '../../../graphql/types'; @@ -90,6 +91,8 @@ describe('epicLocalStorage', () => { kqlMode: 'search' as QueryTabContentComponentProps['kqlMode'], kqlQueryExpression: '', onEventClosed: jest.fn(), + renderCellValue: DefaultCellRenderer, + rowRenderers: defaultRowRenderers, showCallOutUnauthorizedMsg: false, showExpandedDetails: false, start: startDate, From 1fad3175f9526882f4eab02829d73b75194e6b4e Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Mon, 5 Apr 2021 13:42:46 -0400 Subject: [PATCH 06/26] [Maps] Safe-erase text-field (#94873) --- .../properties/dynamic_text_property.test.tsx | 109 ++++++++++++++++++ .../properties/dynamic_text_property.ts | 4 +- .../properties/static_text_property.test.ts | 70 +++++++++++ .../vector/properties/static_text_property.ts | 4 +- 4 files changed, 185 insertions(+), 2 deletions(-) create mode 100644 x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_text_property.test.tsx create mode 100644 x-pack/plugins/maps/public/classes/styles/vector/properties/static_text_property.test.ts diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_text_property.test.tsx b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_text_property.test.tsx new file mode 100644 index 00000000000000..4550a27ac2d9a5 --- /dev/null +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_text_property.test.tsx @@ -0,0 +1,109 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +jest.mock('../components/vector_style_editor', () => ({ + VectorStyleEditor: () => { + return
mockVectorStyleEditor
; + }, +})); + +import React from 'react'; + +// @ts-ignore +import { DynamicTextProperty } from './dynamic_text_property'; +import { RawValue, VECTOR_STYLES } from '../../../../../common/constants'; +import { IField } from '../../../fields/field'; +import { Map as MbMap } from 'mapbox-gl'; +import { mockField, MockLayer, MockStyle } from './test_helpers/test_util'; +import { IVectorLayer } from '../../../layers/vector_layer'; + +export class MockMbMap { + _paintPropertyCalls: unknown[]; + _lastTextFieldValue: unknown | undefined; + + constructor(lastTextFieldValue?: unknown) { + this._paintPropertyCalls = []; + this._lastTextFieldValue = lastTextFieldValue; + } + setLayoutProperty(layerId: string, propName: string, value: undefined | 'string') { + if (propName !== 'text-field') { + throw new Error('should only use to test `text-field`'); + } + this._lastTextFieldValue = value; + this._paintPropertyCalls.push([layerId, value]); + } + + getLayoutProperty(layername: string, propName: string): unknown | undefined { + if (propName !== 'text-field') { + throw new Error('should only use to test `text-field`'); + } + return this._lastTextFieldValue; + } + + getPaintPropertyCalls(): unknown[] { + return this._paintPropertyCalls; + } +} + +const makeProperty = (mockStyle: MockStyle, field: IField | null) => { + return new DynamicTextProperty( + {}, + VECTOR_STYLES.LABEL_TEXT, + field, + (new MockLayer(mockStyle) as unknown) as IVectorLayer, + () => { + return (value: RawValue) => value + '_format'; + } + ); +}; + +describe('syncTextFieldWithMb', () => { + describe('with field', () => { + test('Should set', async () => { + const dynamicTextProperty = makeProperty(new MockStyle({ min: 0, max: 100 }), mockField); + const mockMbMap = (new MockMbMap() as unknown) as MbMap; + + dynamicTextProperty.syncTextFieldWithMb('foobar', mockMbMap); + + // @ts-expect-error + expect(mockMbMap.getPaintPropertyCalls()).toEqual([ + ['foobar', ['coalesce', ['get', '__kbn__dynamic__foobar__labelText'], '']], + ]); + }); + }); + + describe('without field', () => { + test('Should clear', async () => { + const dynamicTextProperty = makeProperty(new MockStyle({ min: 0, max: 100 }), null); + const mockMbMap = (new MockMbMap([ + 'foobar', + ['coalesce', ['get', '__kbn__dynamic__foobar__labelText'], ''], + ]) as unknown) as MbMap; + + dynamicTextProperty.syncTextFieldWithMb('foobar', mockMbMap); + + // @ts-expect-error + expect(mockMbMap.getPaintPropertyCalls()).toEqual([['foobar', undefined]]); + }); + + test('Should not clear when already cleared', async () => { + // This verifies a weird edge-case in mapbox-gl, where setting the `text-field` layout-property to null causes tiles to be invalidated. + // This triggers a refetch of the tile during panning and zooming + // This affects vector-tile rendering in tiled_vector_layers with custom vector_styles + // It does _not_ affect EMS, since that does not have a code-path where a `text-field` need to be resynced. + // Do not remove this logic without verifying that mapbox-gl does not re-issue tile-requests for previously requested tiles + + const dynamicTextProperty = makeProperty(new MockStyle({ min: 0, max: 100 }), null); + const mockMbMap = (new MockMbMap(undefined) as unknown) as MbMap; + + dynamicTextProperty.syncTextFieldWithMb('foobar', mockMbMap); + + // @ts-expect-error + expect(mockMbMap.getPaintPropertyCalls()).toEqual([]); + }); + }); +}); diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_text_property.ts b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_text_property.ts index 22ea3067b17481..e8612388a5ae16 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_text_property.ts +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_text_property.ts @@ -20,7 +20,9 @@ export class DynamicTextProperty extends DynamicStyleProperty { + return new StaticTextProperty({ value }, VECTOR_STYLES.LABEL_TEXT); +}; + +describe('syncTextFieldWithMb', () => { + test('Should set with value', async () => { + const dynamicTextProperty = makeProperty('foo'); + const mockMbMap = (new MockMbMap() as unknown) as MbMap; + + dynamicTextProperty.syncTextFieldWithMb('foobar', mockMbMap); + + // @ts-expect-error + expect(mockMbMap.getPaintPropertyCalls()).toEqual([['foobar', 'foo']]); + }); + + test('Should not clear when already cleared', async () => { + // This verifies a weird edge-case in mapbox-gl, where setting the `text-field` layout-property to null causes tiles to be invalidated. + // This triggers a refetch of the tile during panning and zooming + // This affects vector-tile rendering in tiled_vector_layers with custom vector_styles + // It does _not_ affect EMS, since that does not have a code-path where a `text-field` need to be resynced. + // Do not remove this logic without verifying that mapbox-gl does not re-issue tile-requests for previously requested tiles + + const dynamicTextProperty = makeProperty(''); + const mockMbMap = (new MockMbMap(undefined) as unknown) as MbMap; + + dynamicTextProperty.syncTextFieldWithMb('foobar', mockMbMap); + + // @ts-expect-error + expect(mockMbMap.getPaintPropertyCalls()).toEqual([]); + }); +}); diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/static_text_property.ts b/x-pack/plugins/maps/public/classes/styles/vector/properties/static_text_property.ts index b0016106b8c31c..fb05fa052db21e 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/static_text_property.ts +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/static_text_property.ts @@ -18,7 +18,9 @@ export class StaticTextProperty extends StaticStyleProperty if (this.getOptions().value.length) { mbMap.setLayoutProperty(mbLayerId, 'text-field', this.getOptions().value); } else { - mbMap.setLayoutProperty(mbLayerId, 'text-field', null); + if (typeof mbMap.getLayoutProperty(mbLayerId, 'text-field') !== 'undefined') { + mbMap.setLayoutProperty(mbLayerId, 'text-field', undefined); + } } } } From ad5f83a36230abeff79d01bfff0a104f5fd615d2 Mon Sep 17 00:00:00 2001 From: Jason Stoltzfus Date: Mon, 5 Apr 2021 13:49:54 -0400 Subject: [PATCH 07/26] [App Search] Added Sample Response section to Result Settings (#95971) --- .../result_settings/result_settings.tsx | 4 +- .../non_text_fields_body.tsx | 5 + .../text_fields_body.tsx | 13 ++ .../result_settings/sample_response/index.ts | 8 + .../sample_response/sample_response.test.tsx | 75 ++++++ .../sample_response/sample_response.tsx | 72 ++++++ .../sample_response_logic.test.ts | 214 ++++++++++++++++++ .../sample_response/sample_response_logic.ts | 100 ++++++++ .../components/result_settings/types.ts | 4 + .../routes/app_search/result_settings.test.ts | 44 ++++ .../routes/app_search/result_settings.ts | 18 ++ 11 files changed, 556 insertions(+), 1 deletion(-) create mode 100644 x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/sample_response/index.ts create mode 100644 x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/sample_response/sample_response.test.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/sample_response/sample_response.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/sample_response/sample_response_logic.test.ts create mode 100644 x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/sample_response/sample_response_logic.ts diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/result_settings.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/result_settings.tsx index 38db5c60e98a9d..7f4373835f8d52 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/result_settings.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/result_settings.tsx @@ -17,6 +17,8 @@ import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chro import { RESULT_SETTINGS_TITLE } from './constants'; import { ResultSettingsTable } from './result_settings_table'; +import { SampleResponse } from './sample_response'; + import { ResultSettingsLogic } from '.'; interface Props { @@ -40,7 +42,7 @@ export const ResultSettings: React.FC = ({ engineBreadcrumb }) => { -
TODO
+
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/result_settings_table/non_text_fields_body.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/result_settings_table/non_text_fields_body.tsx index 145654be204611..dc91b5039a3c92 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/result_settings_table/non_text_fields_body.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/result_settings_table/non_text_fields_body.tsx @@ -10,6 +10,7 @@ import React, { useMemo } from 'react'; import { useValues, useActions } from 'kea'; import { EuiTableRow, EuiTableRowCell, EuiCheckbox, EuiTableRowCellCheckbox } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { ResultSettingsLogic } from '..'; import { FieldResultSetting } from '../types'; @@ -33,6 +34,10 @@ export const NonTextFieldsBody: React.FC = () => { { { { { + const actions = { + queryChanged: jest.fn(), + getSearchResults: jest.fn(), + }; + + const values = { + reducedServerResultFields: {}, + query: 'foo', + response: { + bar: 'baz', + }, + }; + + beforeEach(() => { + jest.clearAllMocks(); + setMockActions(actions); + setMockValues(values); + }); + + it('renders a text box with the current user "query" value from state', () => { + const wrapper = shallow(); + expect(wrapper.find(EuiFieldSearch).prop('value')).toEqual('foo'); + }); + + it('updates the "query" value in state when a user updates the text in the text box', () => { + const wrapper = shallow(); + wrapper.find(EuiFieldSearch).simulate('change', { target: { value: 'bar' } }); + expect(actions.queryChanged).toHaveBeenCalledWith('bar'); + }); + + it('will call getSearchResults with the current value of query and reducedServerResultFields in a useEffect, which updates the displayed response', () => { + const wrapper = shallow(); + expect(wrapper.find(EuiFieldSearch).prop('value')).toEqual('foo'); + }); + + it('renders the response from the given user "query" in a code block', () => { + const wrapper = shallow(); + expect(wrapper.find(EuiCodeBlock).prop('children')).toEqual('{\n "bar": "baz"\n}'); + }); + + it('renders a plain old string in the code block if the response is a string', () => { + setMockValues({ + response: 'No results.', + }); + const wrapper = shallow(); + expect(wrapper.find(EuiCodeBlock).prop('children')).toEqual('No results.'); + }); + + it('will not render a code block at all if there is no response yet', () => { + setMockValues({ + response: null, + }); + const wrapper = shallow(); + expect(wrapper.find(EuiCodeBlock).exists()).toEqual(false); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/sample_response/sample_response.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/sample_response/sample_response.tsx new file mode 100644 index 00000000000000..ae91b9648356ce --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/sample_response/sample_response.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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useEffect } from 'react'; + +import { useActions, useValues } from 'kea'; + +import { + EuiCodeBlock, + EuiFieldSearch, + EuiFlexGroup, + EuiFlexItem, + EuiPanel, + EuiSpacer, + EuiTitle, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +import { ResultSettingsLogic } from '../result_settings_logic'; + +import { SampleResponseLogic } from './sample_response_logic'; + +export const SampleResponse: React.FC = () => { + const { reducedServerResultFields } = useValues(ResultSettingsLogic); + + const { query, response } = useValues(SampleResponseLogic); + const { queryChanged, getSearchResults } = useActions(SampleResponseLogic); + + useEffect(() => { + getSearchResults(query, reducedServerResultFields); + }, [query, reducedServerResultFields]); + + return ( + + + + +

+ {i18n.translate( + 'xpack.enterpriseSearch.appSearch.engine.resultSettings.sampleResponseTitle', + { defaultMessage: 'Sample response' } + )} +

+
+
+ + {/* TODO */} + +
+ + queryChanged(e.target.value)} + placeholder={i18n.translate( + 'xpack.enterpriseSearch.appSearch.engine.resultSettings.sampleResponse.inputPlaceholder', + { defaultMessage: 'Type a search query to test a response...' } + )} + data-test-subj="ResultSettingsQuerySampleResponse" + /> + + {!!response && ( + + {typeof response === 'string' ? response : JSON.stringify(response, null, 2)} + + )} +
+ ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/sample_response/sample_response_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/sample_response/sample_response_logic.test.ts new file mode 100644 index 00000000000000..79379306c1618b --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/sample_response/sample_response_logic.test.ts @@ -0,0 +1,214 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { LogicMounter, mockHttpValues } from '../../../../__mocks__'; +import '../../../__mocks__/engine_logic.mock'; + +import { nextTick } from '@kbn/test/jest'; + +import { flashAPIErrors } from '../../../../shared/flash_messages'; + +import { SampleResponseLogic } from './sample_response_logic'; + +describe('SampleResponseLogic', () => { + const { mount } = new LogicMounter(SampleResponseLogic); + const { http } = mockHttpValues; + + const DEFAULT_VALUES = { + query: '', + response: null, + }; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('has expected default values', () => { + mount(); + expect(SampleResponseLogic.values).toEqual({ + ...DEFAULT_VALUES, + }); + }); + + describe('actions', () => { + describe('queryChanged', () => { + it('updates the query', () => { + mount({ + query: '', + }); + + SampleResponseLogic.actions.queryChanged('foo'); + + expect(SampleResponseLogic.values).toEqual({ + ...DEFAULT_VALUES, + query: 'foo', + }); + }); + }); + + describe('getSearchResultsSuccess', () => { + it('sets the response from a search API request', () => { + mount({ + response: null, + }); + + SampleResponseLogic.actions.getSearchResultsSuccess({}); + + expect(SampleResponseLogic.values).toEqual({ + ...DEFAULT_VALUES, + response: {}, + }); + }); + }); + + describe('getSearchResultsFailure', () => { + it('sets a string response from a search API request', () => { + mount({ + response: null, + }); + + SampleResponseLogic.actions.getSearchResultsFailure('An error occured.'); + + expect(SampleResponseLogic.values).toEqual({ + ...DEFAULT_VALUES, + response: 'An error occured.', + }); + }); + }); + }); + + describe('listeners', () => { + describe('getSearchResults', () => { + beforeAll(() => jest.useFakeTimers()); + afterAll(() => jest.useRealTimers()); + + it('makes a search API request and calls getSearchResultsSuccess with the first result of the response', async () => { + mount(); + jest.spyOn(SampleResponseLogic.actions, 'getSearchResultsSuccess'); + + http.post.mockReturnValue( + Promise.resolve({ + results: [ + { id: { raw: 'foo' }, _meta: {} }, + { id: { raw: 'bar' }, _meta: {} }, + { id: { raw: 'baz' }, _meta: {} }, + ], + }) + ); + + SampleResponseLogic.actions.getSearchResults('foo', { foo: { raw: true } }); + jest.runAllTimers(); + await nextTick(); + + expect(SampleResponseLogic.actions.getSearchResultsSuccess).toHaveBeenCalledWith({ + // Note that the _meta field was stripped from the result + id: { raw: 'foo' }, + }); + }); + + it('calls getSearchResultsSuccess with a "No Results." message if there are no results', async () => { + mount(); + jest.spyOn(SampleResponseLogic.actions, 'getSearchResultsSuccess'); + + http.post.mockReturnValue( + Promise.resolve({ + results: [], + }) + ); + + SampleResponseLogic.actions.getSearchResults('foo', { foo: { raw: true } }); + jest.runAllTimers(); + await nextTick(); + + expect(SampleResponseLogic.actions.getSearchResultsSuccess).toHaveBeenCalledWith( + 'No results.' + ); + }); + + it('handles 500 errors by setting a generic error response and showing a flash message error', async () => { + mount(); + jest.spyOn(SampleResponseLogic.actions, 'getSearchResultsFailure'); + + const error = { + response: { + status: 500, + }, + }; + + http.post.mockReturnValueOnce(Promise.reject(error)); + + SampleResponseLogic.actions.getSearchResults('foo', { foo: { raw: true } }); + jest.runAllTimers(); + await nextTick(); + + expect(flashAPIErrors).toHaveBeenCalledWith(error); + expect(SampleResponseLogic.actions.getSearchResultsFailure).toHaveBeenCalledWith( + 'An error occured.' + ); + }); + + it('handles 400 errors by setting the response, but does not show a flash error message', async () => { + mount(); + jest.spyOn(SampleResponseLogic.actions, 'getSearchResultsFailure'); + + http.post.mockReturnValueOnce( + Promise.reject({ + response: { + status: 400, + }, + body: { + attributes: { + errors: ['A validation error occurred.'], + }, + }, + }) + ); + + SampleResponseLogic.actions.getSearchResults('foo', { foo: { raw: true } }); + jest.runAllTimers(); + await nextTick(); + + expect(SampleResponseLogic.actions.getSearchResultsFailure).toHaveBeenCalledWith({ + errors: ['A validation error occurred.'], + }); + }); + + it('sets a generic message on a 400 error if no custom message is provided in the response', async () => { + mount(); + jest.spyOn(SampleResponseLogic.actions, 'getSearchResultsFailure'); + + http.post.mockReturnValueOnce( + Promise.reject({ + response: { + status: 400, + }, + }) + ); + + SampleResponseLogic.actions.getSearchResults('foo', { foo: { raw: true } }); + jest.runAllTimers(); + await nextTick(); + + expect(SampleResponseLogic.actions.getSearchResultsFailure).toHaveBeenCalledWith( + 'An error occured.' + ); + }); + + it('does nothing if an empty object is passed for the resultFields parameter', async () => { + mount(); + jest.spyOn(SampleResponseLogic.actions, 'getSearchResultsSuccess'); + + SampleResponseLogic.actions.getSearchResults('foo', {}); + + jest.runAllTimers(); + await nextTick(); + + expect(SampleResponseLogic.actions.getSearchResultsSuccess).not.toHaveBeenCalled(); + }); + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/sample_response/sample_response_logic.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/sample_response/sample_response_logic.ts new file mode 100644 index 00000000000000..808a7ec9c65dce --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/sample_response/sample_response_logic.ts @@ -0,0 +1,100 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { kea, MakeLogicType } from 'kea'; + +import { i18n } from '@kbn/i18n'; + +import { flashAPIErrors } from '../../../../shared/flash_messages'; + +import { HttpLogic } from '../../../../shared/http'; +import { EngineLogic } from '../../engine'; + +import { SampleSearchResponse, ServerFieldResultSettingObject } from '../types'; + +const NO_RESULTS_MESSAGE = i18n.translate( + 'xpack.enterpriseSearch.appSearch.engine.resultSettings.sampleResponse.noResultsMessage', + { defaultMessage: 'No results.' } +); + +const ERROR_MESSAGE = i18n.translate( + 'xpack.enterpriseSearch.appSearch.engine.resultSettings.sampleResponse.errorMessage', + { defaultMessage: 'An error occured.' } +); + +interface SampleResponseValues { + query: string; + response: SampleSearchResponse | string | null; +} + +interface SampleResponseActions { + queryChanged: (query: string) => { query: string }; + getSearchResultsSuccess: ( + response: SampleSearchResponse | string + ) => { response: SampleSearchResponse | string }; + getSearchResultsFailure: (response: string) => { response: string }; + getSearchResults: ( + query: string, + resultFields: ServerFieldResultSettingObject + ) => { query: string; resultFields: ServerFieldResultSettingObject }; +} + +export const SampleResponseLogic = kea>({ + path: ['enterprise_search', 'app_search', 'sample_response_logic'], + actions: { + queryChanged: (query) => ({ query }), + getSearchResultsSuccess: (response) => ({ response }), + getSearchResultsFailure: (response) => ({ response }), + getSearchResults: (query, resultFields) => ({ query, resultFields }), + }, + reducers: { + query: ['', { queryChanged: (_, { query }) => query }], + response: [ + null, + { + getSearchResultsSuccess: (_, { response }) => response, + getSearchResultsFailure: (_, { response }) => response, + }, + ], + }, + listeners: ({ actions }) => ({ + getSearchResults: async ({ query, resultFields }, breakpoint) => { + if (Object.keys(resultFields).length < 1) return; + await breakpoint(250); + + const { http } = HttpLogic.values; + const { engineName } = EngineLogic.values; + + const url = `/api/app_search/engines/${engineName}/sample_response_search`; + + try { + const response = await http.post(url, { + body: JSON.stringify({ + query, + result_fields: resultFields, + }), + }); + + const result = response.results?.[0]; + actions.getSearchResultsSuccess( + result ? { ...result, _meta: undefined } : NO_RESULTS_MESSAGE + ); + } catch (e) { + if (e.response.status >= 500) { + // 4XX Validation errors are expected, as a user could enter something like 2 as a size, which is out of valid range. + // In this case, we simply render the message from the server as the response. + // + // 5xx Server errors are unexpected, and need to be reported in a flash message. + flashAPIErrors(e); + actions.getSearchResultsFailure(ERROR_MESSAGE); + } else { + actions.getSearchResultsFailure(e.body?.attributes || ERROR_MESSAGE); + } + } + }, + }), +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/types.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/types.ts index 96bf277314a7b2..18843112f46bf0 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/types.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result_settings/types.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { FieldValue } from '../result/types'; + export enum OpenModal { None, ConfirmResetModal, @@ -35,3 +37,5 @@ export interface FieldResultSetting { } export type FieldResultSettingObject = Record; + +export type SampleSearchResponse = Record; diff --git a/x-pack/plugins/enterprise_search/server/routes/app_search/result_settings.test.ts b/x-pack/plugins/enterprise_search/server/routes/app_search/result_settings.test.ts index 8d1a7e3ead37b5..e38380d60c6e9c 100644 --- a/x-pack/plugins/enterprise_search/server/routes/app_search/result_settings.test.ts +++ b/x-pack/plugins/enterprise_search/server/routes/app_search/result_settings.test.ts @@ -88,4 +88,48 @@ describe('result settings routes', () => { }); }); }); + + describe('POST /api/app_search/engines/{name}/sample_response_search', () => { + const mockRouter = new MockRouter({ + method: 'post', + path: '/api/app_search/engines/{engineName}/sample_response_search', + }); + + beforeEach(() => { + registerResultSettingsRoutes({ + ...mockDependencies, + router: mockRouter.router, + }); + }); + + it('creates a request to enterprise search', () => { + mockRouter.callRoute({ + params: { engineName: 'some-engine' }, + body: { + query: 'test', + result_fields: resultFields, + }, + }); + + expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({ + path: '/as/engines/:engineName/sample_response_search', + }); + }); + + describe('validates', () => { + it('correctly', () => { + const request = { + body: { + query: 'test', + result_fields: resultFields, + }, + }; + mockRouter.shouldValidate(request); + }); + it('missing required fields', () => { + const request = { body: {} }; + mockRouter.shouldThrow(request); + }); + }); + }); }); diff --git a/x-pack/plugins/enterprise_search/server/routes/app_search/result_settings.ts b/x-pack/plugins/enterprise_search/server/routes/app_search/result_settings.ts index 38cb4aa922738d..b091ae7a539c29 100644 --- a/x-pack/plugins/enterprise_search/server/routes/app_search/result_settings.ts +++ b/x-pack/plugins/enterprise_search/server/routes/app_search/result_settings.ts @@ -45,4 +45,22 @@ export function registerResultSettingsRoutes({ path: '/as/engines/:engineName/result_settings', }) ); + + router.post( + { + path: '/api/app_search/engines/{engineName}/sample_response_search', + validate: { + params: schema.object({ + engineName: schema.string(), + }), + body: schema.object({ + query: schema.string(), + result_fields: schema.recordOf(schema.string(), schema.object({}, { unknowns: 'allow' })), + }), + }, + }, + enterpriseSearchRequestHandler.createRequest({ + path: '/as/engines/:engineName/sample_response_search', + }) + ); } From e457f212c4e513b467fc9fd540b76d4a6949111f Mon Sep 17 00:00:00 2001 From: Mikhail Shustov Date: Mon, 5 Apr 2021 20:59:26 +0200 Subject: [PATCH 08/26] Revert "TS Incremental build exclude test files (#95610)" (#96223) This reverts commit b6e582c53ebb9c496c232408066b128d2ca2f92c. --- packages/kbn-storybook/tsconfig.json | 2 +- src/core/tsconfig.json | 2 +- src/dev/typescript/project.ts | 37 ++------ src/plugins/advanced_settings/tsconfig.json | 2 +- src/plugins/apm_oss/tsconfig.json | 2 +- src/plugins/bfetch/tsconfig.json | 2 +- src/plugins/charts/tsconfig.json | 2 +- src/plugins/console/tsconfig.json | 2 +- src/plugins/dashboard/tsconfig.json | 2 +- .../search/expressions/exists_filter.test.ts | 2 +- .../search/expressions/kibana_filter.test.ts | 2 +- .../search/expressions/phrase_filter.test.ts | 2 +- .../search/expressions/range_filter.test.ts | 2 +- src/plugins/data/tsconfig.json | 2 +- src/plugins/dev_tools/tsconfig.json | 2 +- src/plugins/discover/tsconfig.json | 2 +- src/plugins/embeddable/tsconfig.json | 2 +- src/plugins/es_ui_shared/tsconfig.json | 2 +- src/plugins/expressions/common/mocks.ts | 2 - src/plugins/expressions/common/util/index.ts | 1 + src/plugins/expressions/tsconfig.json | 2 +- src/plugins/home/tsconfig.json | 2 +- .../index_pattern_field_editor/tsconfig.json | 2 +- .../index_pattern_management/tsconfig.json | 2 +- src/plugins/input_control_vis/tsconfig.json | 2 +- src/plugins/inspector/tsconfig.json | 2 +- src/plugins/kibana_legacy/tsconfig.json | 2 +- src/plugins/kibana_overview/tsconfig.json | 2 +- src/plugins/kibana_react/tsconfig.json | 2 +- .../kibana_usage_collection/tsconfig.json | 2 +- src/plugins/kibana_utils/tsconfig.json | 2 +- src/plugins/legacy_export/tsconfig.json | 2 +- src/plugins/management/tsconfig.json | 2 +- src/plugins/maps_ems/tsconfig.json | 2 +- src/plugins/maps_legacy/tsconfig.json | 2 +- src/plugins/navigation/tsconfig.json | 2 +- src/plugins/newsfeed/tsconfig.json | 2 +- src/plugins/presentation_util/tsconfig.json | 2 +- src/plugins/region_map/tsconfig.json | 2 +- src/plugins/saved_objects/tsconfig.json | 2 +- .../saved_objects_management/tsconfig.json | 2 +- .../saved_objects_tagging_oss/tsconfig.json | 2 +- src/plugins/security_oss/tsconfig.json | 2 +- src/plugins/share/tsconfig.json | 2 +- src/plugins/spaces_oss/tsconfig.json | 2 +- src/plugins/telemetry/tsconfig.json | 2 +- .../tsconfig.json | 2 +- .../tsconfig.json | 2 +- src/plugins/tile_map/tsconfig.json | 2 +- src/plugins/timelion/tsconfig.json | 2 +- src/plugins/ui_actions/tsconfig.json | 2 +- src/plugins/url_forwarding/tsconfig.json | 2 +- src/plugins/usage_collection/tsconfig.json | 2 +- src/plugins/vis_default_editor/tsconfig.json | 2 +- src/plugins/vis_type_markdown/tsconfig.json | 2 +- src/plugins/vis_type_metric/tsconfig.json | 2 +- src/plugins/vis_type_table/tsconfig.json | 2 +- src/plugins/vis_type_tagcloud/tsconfig.json | 2 +- src/plugins/vis_type_timelion/tsconfig.json | 2 +- src/plugins/vis_type_timeseries/tsconfig.json | 2 +- src/plugins/vis_type_vega/tsconfig.json | 2 +- src/plugins/vis_type_vislib/tsconfig.json | 2 +- src/plugins/vis_type_xy/tsconfig.json | 2 +- src/plugins/visualizations/tsconfig.json | 2 +- src/plugins/visualize/tsconfig.json | 2 +- tsconfig.base.json | 3 +- tsconfig.json | 73 ---------------- tsconfig.project.json | 65 -------------- x-pack/plugins/actions/tsconfig.json | 2 +- x-pack/plugins/alerting/tsconfig.json | 2 +- x-pack/plugins/apm/e2e/tsconfig.json | 2 +- x-pack/plugins/apm/ftr_e2e/tsconfig.json | 4 +- .../apm/scripts/optimize-tsconfig/optimize.js | 2 +- .../apm/scripts/optimize-tsconfig/paths.js | 2 +- x-pack/plugins/apm/tsconfig.json | 2 +- x-pack/plugins/banners/tsconfig.json | 2 +- x-pack/plugins/beats_management/tsconfig.json | 2 +- .../canvas/storybook/addon/tsconfig.json | 2 +- x-pack/plugins/canvas/tsconfig.json | 2 +- x-pack/plugins/cloud/tsconfig.json | 2 +- .../plugins/console_extensions/tsconfig.json | 2 +- .../cross_cluster_replication/tsconfig.json | 2 +- .../plugins/dashboard_enhanced/tsconfig.json | 2 +- x-pack/plugins/dashboard_mode/tsconfig.json | 2 +- x-pack/plugins/data_enhanced/tsconfig.json | 2 +- .../plugins/discover_enhanced/tsconfig.json | 2 +- .../drilldowns/url_drilldown/tsconfig.json | 2 +- .../plugins/embeddable_enhanced/tsconfig.json | 2 +- .../encrypted_saved_objects/tsconfig.json | 2 +- .../plugins/enterprise_search/tsconfig.json | 2 +- x-pack/plugins/event_log/tsconfig.json | 2 +- x-pack/plugins/features/tsconfig.json | 2 +- x-pack/plugins/file_upload/tsconfig.json | 2 +- x-pack/plugins/fleet/tsconfig.json | 2 +- x-pack/plugins/global_search/tsconfig.json | 2 +- .../plugins/global_search_bar/tsconfig.json | 2 +- .../global_search_providers/tsconfig.json | 2 +- x-pack/plugins/graph/tsconfig.json | 4 +- x-pack/plugins/grokdebugger/tsconfig.json | 2 +- .../index_lifecycle_management/tsconfig.json | 3 +- x-pack/plugins/index_management/tsconfig.json | 4 +- .../infra/public/utils/enzyme_helpers.tsx | 87 +++++++++++++++++++ .../queries/metrics_hosts_anomalies.ts | 2 +- .../infra_ml/queries/metrics_k8s_anomalies.ts | 2 +- x-pack/plugins/infra/tsconfig.json | 2 +- x-pack/plugins/ingest_pipelines/tsconfig.json | 3 +- x-pack/plugins/lens/tsconfig.json | 4 +- .../plugins/license_management/tsconfig.json | 2 +- x-pack/plugins/licensing/tsconfig.json | 2 +- x-pack/plugins/logstash/tsconfig.json | 2 +- .../components/validated_number_input.tsx | 4 +- x-pack/plugins/maps/tsconfig.json | 2 +- .../routes/apidoc_scripts/tsconfig.json | 2 +- x-pack/plugins/ml/tsconfig.json | 2 +- x-pack/plugins/monitoring/tsconfig.json | 2 +- x-pack/plugins/observability/tsconfig.json | 2 +- x-pack/plugins/osquery/tsconfig.json | 2 +- x-pack/plugins/painless_lab/tsconfig.json | 2 +- x-pack/plugins/remote_clusters/tsconfig.json | 2 +- x-pack/plugins/reporting/tsconfig.json | 2 +- x-pack/plugins/rollup/tsconfig.json | 2 +- x-pack/plugins/runtime_fields/tsconfig.json | 2 +- .../saved_objects_tagging/tsconfig.json | 2 +- x-pack/plugins/searchprofiler/tsconfig.json | 2 +- x-pack/plugins/security/tsconfig.json | 2 +- .../security_solution/cypress/tsconfig.json | 2 +- x-pack/plugins/snapshot_restore/tsconfig.json | 4 +- x-pack/plugins/spaces/tsconfig.json | 2 +- x-pack/plugins/stack_alerts/tsconfig.json | 2 +- .../server/monitoring/workload_statistics.ts | 3 +- x-pack/plugins/task_manager/tsconfig.json | 2 +- .../telemetry_collection_xpack/tsconfig.json | 2 +- x-pack/plugins/transform/tsconfig.json | 2 +- .../plugins/triggers_actions_ui/tsconfig.json | 2 +- .../plugins/ui_actions_enhanced/tsconfig.json | 2 +- .../plugins/upgrade_assistant/tsconfig.json | 2 +- .../certificates/cert_monitors.test.tsx | 2 +- .../certificates/cert_search.test.tsx | 2 +- .../certificates/cert_status.test.tsx | 2 +- .../certificates/certificates_list.test.tsx | 2 +- .../certificates/fingerprint_col.test.tsx | 2 +- .../common/charts/duration_charts.test.tsx | 2 +- .../common/charts/monitor_bar_series.test.tsx | 3 +- .../common/header/page_header.test.tsx | 2 +- .../components/common/monitor_tags.test.tsx | 2 +- .../common/uptime_date_picker.test.tsx | 4 +- .../monitor/ml/ml_integerations.test.tsx | 2 +- .../monitor/ml/ml_manage_job.test.tsx | 2 +- .../monitor/monitor_charts.test.tsx | 2 +- .../components/monitor/monitor_title.test.tsx | 2 +- .../monitor_status.bar.test.tsx | 2 +- .../status_details/ssl_certificate.test.tsx | 6 +- .../overview/empty_state/empty_state.test.tsx | 2 +- .../columns/enable_alert.test.tsx | 2 +- .../filter_status_button.test.tsx | 3 +- .../monitor_list/monitor_list.test.tsx | 2 +- .../monitor_list_drawer.test.tsx | 2 +- .../monitor_list/status_filter.test.tsx | 4 +- .../settings/certificate_form.test.tsx | 2 +- .../components/settings/indices_form.test.tsx | 2 +- .../public/hooks/use_breadcrumbs.test.tsx | 5 +- .../public/hooks/use_url_params.test.tsx | 3 +- .../plugins/uptime/public/lib/helper/index.ts | 1 + x-pack/plugins/uptime/public/lib/index.ts | 9 ++ .../uptime/public/pages/certificates.test.tsx | 2 +- .../uptime/public/pages/monitor.test.tsx | 2 +- .../uptime/public/pages/not_found.test.tsx | 2 +- .../uptime/public/pages/overview.test.tsx | 2 +- x-pack/plugins/uptime/tsconfig.json | 3 +- x-pack/plugins/watcher/tsconfig.json | 2 +- x-pack/plugins/xpack_legacy/tsconfig.json | 2 +- 171 files changed, 281 insertions(+), 351 deletions(-) delete mode 100644 tsconfig.project.json create mode 100644 x-pack/plugins/infra/public/utils/enzyme_helpers.tsx create mode 100644 x-pack/plugins/uptime/public/lib/index.ts diff --git a/packages/kbn-storybook/tsconfig.json b/packages/kbn-storybook/tsconfig.json index 5c81c9100e6017..db10d4630ff9c8 100644 --- a/packages/kbn-storybook/tsconfig.json +++ b/packages/kbn-storybook/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../tsconfig.base.json", + "extends": "../../tsconfig.json", "compilerOptions": { "incremental": false, "outDir": "target", diff --git a/src/core/tsconfig.json b/src/core/tsconfig.json index f19e379482d3cf..855962070457e7 100644 --- a/src/core/tsconfig.json +++ b/src/core/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../tsconfig.project.json", + "extends": "../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/dev/typescript/project.ts b/src/dev/typescript/project.ts index 04a5de945619b8..8d92284e496379 100644 --- a/src/dev/typescript/project.ts +++ b/src/dev/typescript/project.ts @@ -7,7 +7,7 @@ */ import { basename, dirname, relative, resolve } from 'path'; -import { memoize } from 'lodash'; + import { IMinimatch, Minimatch } from 'minimatch'; import { REPO_ROOT } from '@kbn/utils'; @@ -26,10 +26,6 @@ function testMatchers(matchers: IMinimatch[], path: string) { return matchers.some((matcher) => matcher.match(path)); } -const parentProjectFactory = memoize(function (parentConfigPath: string) { - return new Project(parentConfigPath); -}); - export class Project { public directory: string; public name: string; @@ -38,7 +34,6 @@ export class Project { private readonly include: IMinimatch[]; private readonly exclude: IMinimatch[]; - private readonly parent?: Project; constructor( public tsConfigPath: string, @@ -46,16 +41,15 @@ export class Project { ) { this.config = parseTsConfig(tsConfigPath); - const { files, include, exclude = [], extends: extendsPath } = this.config as { + const { files, include, exclude = [] } = this.config as { files?: string[]; include?: string[]; exclude?: string[]; - extends?: string; }; if (files || !include) { throw new Error( - `[${tsConfigPath}]: tsconfig.json files in the Kibana repo must use "include" keys and not "files"` + 'tsconfig.json files in the Kibana repo must use "include" keys and not "files"' ); } @@ -64,30 +58,9 @@ export class Project { this.name = options.name || relative(REPO_ROOT, this.directory) || basename(this.directory); this.include = makeMatchers(this.directory, include); this.exclude = makeMatchers(this.directory, exclude); - - if (extendsPath !== undefined) { - const parentConfigPath = resolve(this.directory, extendsPath); - this.parent = parentProjectFactory(parentConfigPath); - } - } - - public isAbsolutePathSelected(path: string): boolean { - return this.isExcluded(path) ? false : this.isIncluded(path); } - public isExcluded(path: string): boolean { - if (testMatchers(this.exclude, path)) return true; - if (this.parent) { - return this.parent.isExcluded(path); - } - return false; - } - - public isIncluded(path: string): boolean { - if (testMatchers(this.include, path)) return true; - if (this.parent) { - return this.parent.isIncluded(path); - } - return false; + public isAbsolutePathSelected(path: string) { + return testMatchers(this.exclude, path) ? false : testMatchers(this.include, path); } } diff --git a/src/plugins/advanced_settings/tsconfig.json b/src/plugins/advanced_settings/tsconfig.json index 97a855959903de..4d62e410326b69 100644 --- a/src/plugins/advanced_settings/tsconfig.json +++ b/src/plugins/advanced_settings/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/apm_oss/tsconfig.json b/src/plugins/apm_oss/tsconfig.json index ccb123aaec83bc..aeb6837c69a998 100644 --- a/src/plugins/apm_oss/tsconfig.json +++ b/src/plugins/apm_oss/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/bfetch/tsconfig.json b/src/plugins/bfetch/tsconfig.json index 6c01479f1929ed..173ff725d07d02 100644 --- a/src/plugins/bfetch/tsconfig.json +++ b/src/plugins/bfetch/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/charts/tsconfig.json b/src/plugins/charts/tsconfig.json index 99edb2ffe3c162..a4f65d5937204c 100644 --- a/src/plugins/charts/tsconfig.json +++ b/src/plugins/charts/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/console/tsconfig.json b/src/plugins/console/tsconfig.json index d9f49036be8f8f..34aca5021bac4e 100644 --- a/src/plugins/console/tsconfig.json +++ b/src/plugins/console/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/dashboard/tsconfig.json b/src/plugins/dashboard/tsconfig.json index 452208b39af601..dd99119cfb4570 100644 --- a/src/plugins/dashboard/tsconfig.json +++ b/src/plugins/dashboard/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/data/common/search/expressions/exists_filter.test.ts b/src/plugins/data/common/search/expressions/exists_filter.test.ts index 60e8a9c7a09ce5..e3b53b22813983 100644 --- a/src/plugins/data/common/search/expressions/exists_filter.test.ts +++ b/src/plugins/data/common/search/expressions/exists_filter.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { createMockContext } from '../../../../expressions/common/mocks'; +import { createMockContext } from '../../../../expressions/common'; import { functionWrapper } from './utils'; import { existsFilterFunction } from './exists_filter'; diff --git a/src/plugins/data/common/search/expressions/kibana_filter.test.ts b/src/plugins/data/common/search/expressions/kibana_filter.test.ts index 56a9e1ce660cda..ac8ae55492cc06 100644 --- a/src/plugins/data/common/search/expressions/kibana_filter.test.ts +++ b/src/plugins/data/common/search/expressions/kibana_filter.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { createMockContext } from '../../../../expressions/common/mocks'; +import { createMockContext } from '../../../../expressions/common'; import { functionWrapper } from './utils'; import { kibanaFilterFunction } from './kibana_filter'; diff --git a/src/plugins/data/common/search/expressions/phrase_filter.test.ts b/src/plugins/data/common/search/expressions/phrase_filter.test.ts index 90e471e166f5eb..39bd907513a0df 100644 --- a/src/plugins/data/common/search/expressions/phrase_filter.test.ts +++ b/src/plugins/data/common/search/expressions/phrase_filter.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { createMockContext } from '../../../../expressions/common/mocks'; +import { createMockContext } from '../../../../expressions/common'; import { functionWrapper } from './utils'; import { phraseFilterFunction } from './phrase_filter'; diff --git a/src/plugins/data/common/search/expressions/range_filter.test.ts b/src/plugins/data/common/search/expressions/range_filter.test.ts index 129e6bd82e16a6..92670f8a044ba6 100644 --- a/src/plugins/data/common/search/expressions/range_filter.test.ts +++ b/src/plugins/data/common/search/expressions/range_filter.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { createMockContext } from '../../../../expressions/common/mocks'; +import { createMockContext } from '../../../../expressions/common'; import { functionWrapper } from './utils'; import { rangeFilterFunction } from './range_filter'; diff --git a/src/plugins/data/tsconfig.json b/src/plugins/data/tsconfig.json index b99a2f6f85904b..9c95878af631eb 100644 --- a/src/plugins/data/tsconfig.json +++ b/src/plugins/data/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/dev_tools/tsconfig.json b/src/plugins/dev_tools/tsconfig.json index f369396b17fbe8..c17b2341fd42f8 100644 --- a/src/plugins/dev_tools/tsconfig.json +++ b/src/plugins/dev_tools/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/discover/tsconfig.json b/src/plugins/discover/tsconfig.json index 96765d76a340b6..ec98199c3423ea 100644 --- a/src/plugins/discover/tsconfig.json +++ b/src/plugins/discover/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/embeddable/tsconfig.json b/src/plugins/embeddable/tsconfig.json index eacfa831ecee5d..27a887500fb68e 100644 --- a/src/plugins/embeddable/tsconfig.json +++ b/src/plugins/embeddable/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/es_ui_shared/tsconfig.json b/src/plugins/es_ui_shared/tsconfig.json index 3d102daaf3aaf2..9bcda2e0614de6 100644 --- a/src/plugins/es_ui_shared/tsconfig.json +++ b/src/plugins/es_ui_shared/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/expressions/common/mocks.ts b/src/plugins/expressions/common/mocks.ts index 20bdbca07f008b..eaeebd8e534924 100644 --- a/src/plugins/expressions/common/mocks.ts +++ b/src/plugins/expressions/common/mocks.ts @@ -34,5 +34,3 @@ export const createMockExecutionContext = ...extraContext, }; }; - -export { createMockContext } from './util/test_utils'; diff --git a/src/plugins/expressions/common/util/index.ts b/src/plugins/expressions/common/util/index.ts index 5f83d962d5aea8..470dfc3c2d436b 100644 --- a/src/plugins/expressions/common/util/index.ts +++ b/src/plugins/expressions/common/util/index.ts @@ -10,3 +10,4 @@ export * from './create_error'; export * from './get_by_alias'; export * from './tables_adapter'; export * from './expressions_inspector_adapter'; +export * from './test_utils'; diff --git a/src/plugins/expressions/tsconfig.json b/src/plugins/expressions/tsconfig.json index fe76ba3050a3bf..cce71013cefa55 100644 --- a/src/plugins/expressions/tsconfig.json +++ b/src/plugins/expressions/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/home/tsconfig.json b/src/plugins/home/tsconfig.json index 19ab5a8e6efec5..b15e1fc011b926 100644 --- a/src/plugins/home/tsconfig.json +++ b/src/plugins/home/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/index_pattern_field_editor/tsconfig.json b/src/plugins/index_pattern_field_editor/tsconfig.json index c638fd34c6bbbf..559b1aaf0fc26c 100644 --- a/src/plugins/index_pattern_field_editor/tsconfig.json +++ b/src/plugins/index_pattern_field_editor/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/index_pattern_management/tsconfig.json b/src/plugins/index_pattern_management/tsconfig.json index 3c8fdb1cf65979..37bd3e4aa5bbb9 100644 --- a/src/plugins/index_pattern_management/tsconfig.json +++ b/src/plugins/index_pattern_management/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/input_control_vis/tsconfig.json b/src/plugins/input_control_vis/tsconfig.json index c2f8d8783e822d..bef7bc394a6ccd 100644 --- a/src/plugins/input_control_vis/tsconfig.json +++ b/src/plugins/input_control_vis/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/inspector/tsconfig.json b/src/plugins/inspector/tsconfig.json index 0e42e577428c69..2a9c41464532c3 100644 --- a/src/plugins/inspector/tsconfig.json +++ b/src/plugins/inspector/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/kibana_legacy/tsconfig.json b/src/plugins/kibana_legacy/tsconfig.json index 0b3f42cd3b57b6..709036c9e82f43 100644 --- a/src/plugins/kibana_legacy/tsconfig.json +++ b/src/plugins/kibana_legacy/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/kibana_overview/tsconfig.json b/src/plugins/kibana_overview/tsconfig.json index 3396861cb9179b..ac3ac109cb35f0 100644 --- a/src/plugins/kibana_overview/tsconfig.json +++ b/src/plugins/kibana_overview/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/kibana_react/tsconfig.json b/src/plugins/kibana_react/tsconfig.json index 857b8cf83645ce..eb9a24ca141f6e 100644 --- a/src/plugins/kibana_react/tsconfig.json +++ b/src/plugins/kibana_react/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/kibana_usage_collection/tsconfig.json b/src/plugins/kibana_usage_collection/tsconfig.json index 100f1f03955d04..d664d936f66671 100644 --- a/src/plugins/kibana_usage_collection/tsconfig.json +++ b/src/plugins/kibana_usage_collection/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/kibana_utils/tsconfig.json b/src/plugins/kibana_utils/tsconfig.json index d9572707e86629..ae5e9b90af8077 100644 --- a/src/plugins/kibana_utils/tsconfig.json +++ b/src/plugins/kibana_utils/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/legacy_export/tsconfig.json b/src/plugins/legacy_export/tsconfig.json index d6689ea1067db6..ec006d492499ea 100644 --- a/src/plugins/legacy_export/tsconfig.json +++ b/src/plugins/legacy_export/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/management/tsconfig.json b/src/plugins/management/tsconfig.json index 3423299a53df7c..ba3661666631ab 100644 --- a/src/plugins/management/tsconfig.json +++ b/src/plugins/management/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/maps_ems/tsconfig.json b/src/plugins/maps_ems/tsconfig.json index 7f44da00d47a43..b85c3da66b83a0 100644 --- a/src/plugins/maps_ems/tsconfig.json +++ b/src/plugins/maps_ems/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/maps_legacy/tsconfig.json b/src/plugins/maps_legacy/tsconfig.json index c600024cc4a747..f757e35f785af5 100644 --- a/src/plugins/maps_legacy/tsconfig.json +++ b/src/plugins/maps_legacy/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/navigation/tsconfig.json b/src/plugins/navigation/tsconfig.json index bb86142e1c4431..07cfe10d7d81f9 100644 --- a/src/plugins/navigation/tsconfig.json +++ b/src/plugins/navigation/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/newsfeed/tsconfig.json b/src/plugins/newsfeed/tsconfig.json index 84626b2f3a6a86..66244a22336c77 100644 --- a/src/plugins/newsfeed/tsconfig.json +++ b/src/plugins/newsfeed/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/presentation_util/tsconfig.json b/src/plugins/presentation_util/tsconfig.json index cb39c5fb36f564..37b9380f6f2b9c 100644 --- a/src/plugins/presentation_util/tsconfig.json +++ b/src/plugins/presentation_util/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/region_map/tsconfig.json b/src/plugins/region_map/tsconfig.json index 385c31e6bd2d6d..899611d0274657 100644 --- a/src/plugins/region_map/tsconfig.json +++ b/src/plugins/region_map/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/saved_objects/tsconfig.json b/src/plugins/saved_objects/tsconfig.json index 46b3f9a5afcb67..d9045b91b9dfae 100644 --- a/src/plugins/saved_objects/tsconfig.json +++ b/src/plugins/saved_objects/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/saved_objects_management/tsconfig.json b/src/plugins/saved_objects_management/tsconfig.json index cb74b061792250..99849dea386181 100644 --- a/src/plugins/saved_objects_management/tsconfig.json +++ b/src/plugins/saved_objects_management/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/saved_objects_tagging_oss/tsconfig.json b/src/plugins/saved_objects_tagging_oss/tsconfig.json index ae566d96268954..b0059c71424bf5 100644 --- a/src/plugins/saved_objects_tagging_oss/tsconfig.json +++ b/src/plugins/saved_objects_tagging_oss/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/security_oss/tsconfig.json b/src/plugins/security_oss/tsconfig.json index 156e4ffee9d794..530e01a034b00a 100644 --- a/src/plugins/security_oss/tsconfig.json +++ b/src/plugins/security_oss/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/share/tsconfig.json b/src/plugins/share/tsconfig.json index 62c0b3739f4b79..985066915f1ddc 100644 --- a/src/plugins/share/tsconfig.json +++ b/src/plugins/share/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/spaces_oss/tsconfig.json b/src/plugins/spaces_oss/tsconfig.json index 96584842ec32bc..0cc82d7e5d1245 100644 --- a/src/plugins/spaces_oss/tsconfig.json +++ b/src/plugins/spaces_oss/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/telemetry/tsconfig.json b/src/plugins/telemetry/tsconfig.json index 40370082f99e23..bdced01d9eb6f0 100644 --- a/src/plugins/telemetry/tsconfig.json +++ b/src/plugins/telemetry/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/telemetry_collection_manager/tsconfig.json b/src/plugins/telemetry_collection_manager/tsconfig.json index 8bbc440fb1a540..1bba81769f0dd0 100644 --- a/src/plugins/telemetry_collection_manager/tsconfig.json +++ b/src/plugins/telemetry_collection_manager/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/telemetry_management_section/tsconfig.json b/src/plugins/telemetry_management_section/tsconfig.json index c6a21733b2d6b7..48e40814b8570d 100644 --- a/src/plugins/telemetry_management_section/tsconfig.json +++ b/src/plugins/telemetry_management_section/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/tile_map/tsconfig.json b/src/plugins/tile_map/tsconfig.json index 385c31e6bd2d6d..899611d0274657 100644 --- a/src/plugins/tile_map/tsconfig.json +++ b/src/plugins/tile_map/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/timelion/tsconfig.json b/src/plugins/timelion/tsconfig.json index bb8a48339d44ed..5b96d69a878ea6 100644 --- a/src/plugins/timelion/tsconfig.json +++ b/src/plugins/timelion/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/ui_actions/tsconfig.json b/src/plugins/ui_actions/tsconfig.json index 89b66d18705c26..a871d7215cdc52 100644 --- a/src/plugins/ui_actions/tsconfig.json +++ b/src/plugins/ui_actions/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/url_forwarding/tsconfig.json b/src/plugins/url_forwarding/tsconfig.json index f1916e4ce5957e..8e867a6bad14f6 100644 --- a/src/plugins/url_forwarding/tsconfig.json +++ b/src/plugins/url_forwarding/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/usage_collection/tsconfig.json b/src/plugins/usage_collection/tsconfig.json index b4a0721ef3672c..96b2c4d37e17c2 100644 --- a/src/plugins/usage_collection/tsconfig.json +++ b/src/plugins/usage_collection/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/vis_default_editor/tsconfig.json b/src/plugins/vis_default_editor/tsconfig.json index 54a84e08224a8d..27bb775c2d0e8a 100644 --- a/src/plugins/vis_default_editor/tsconfig.json +++ b/src/plugins/vis_default_editor/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/vis_type_markdown/tsconfig.json b/src/plugins/vis_type_markdown/tsconfig.json index f940c295e7cee0..d5ab89b98081b1 100644 --- a/src/plugins/vis_type_markdown/tsconfig.json +++ b/src/plugins/vis_type_markdown/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/vis_type_metric/tsconfig.json b/src/plugins/vis_type_metric/tsconfig.json index 8cee918a3dc82d..7441848d5a4308 100644 --- a/src/plugins/vis_type_metric/tsconfig.json +++ b/src/plugins/vis_type_metric/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/vis_type_table/tsconfig.json b/src/plugins/vis_type_table/tsconfig.json index 4f2e80575497b4..ccff3c349cf21c 100644 --- a/src/plugins/vis_type_table/tsconfig.json +++ b/src/plugins/vis_type_table/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/vis_type_tagcloud/tsconfig.json b/src/plugins/vis_type_tagcloud/tsconfig.json index f7f3688183a488..18bbad2257466c 100644 --- a/src/plugins/vis_type_tagcloud/tsconfig.json +++ b/src/plugins/vis_type_tagcloud/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/vis_type_timelion/tsconfig.json b/src/plugins/vis_type_timelion/tsconfig.json index d29fb25b153155..77f97de28366d0 100644 --- a/src/plugins/vis_type_timelion/tsconfig.json +++ b/src/plugins/vis_type_timelion/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/vis_type_timeseries/tsconfig.json b/src/plugins/vis_type_timeseries/tsconfig.json index edc2d25b867d1b..7b2dd4b608c1c4 100644 --- a/src/plugins/vis_type_timeseries/tsconfig.json +++ b/src/plugins/vis_type_timeseries/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/vis_type_vega/tsconfig.json b/src/plugins/vis_type_vega/tsconfig.json index f375a2483e24ff..4091dafcbe3572 100644 --- a/src/plugins/vis_type_vega/tsconfig.json +++ b/src/plugins/vis_type_vega/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/vis_type_vislib/tsconfig.json b/src/plugins/vis_type_vislib/tsconfig.json index 845628a6b86f91..74bc1440d9dbc6 100644 --- a/src/plugins/vis_type_vislib/tsconfig.json +++ b/src/plugins/vis_type_vislib/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/vis_type_xy/tsconfig.json b/src/plugins/vis_type_xy/tsconfig.json index 7e23b07bd80f6c..5cb0bc8d0bc8ed 100644 --- a/src/plugins/vis_type_xy/tsconfig.json +++ b/src/plugins/vis_type_xy/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/visualizations/tsconfig.json b/src/plugins/visualizations/tsconfig.json index 65de6908228b3a..d7c5e6a4b43663 100644 --- a/src/plugins/visualizations/tsconfig.json +++ b/src/plugins/visualizations/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/src/plugins/visualize/tsconfig.json b/src/plugins/visualize/tsconfig.json index 046202d82d1aaf..bc0891f3917466 100644 --- a/src/plugins/visualize/tsconfig.json +++ b/src/plugins/visualize/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/tsconfig.base.json b/tsconfig.base.json index c28ed0d8c87509..da4de5ef3712b3 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -56,6 +56,5 @@ "jest-styled-components", "@testing-library/jest-dom" ] - }, - "include": [] + } } diff --git a/tsconfig.json b/tsconfig.json index 7c06e808586401..40763ede1bbddd 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -19,79 +19,6 @@ "x-pack/plugins/cases/**/*", "x-pack/plugins/lists/**/*", "x-pack/plugins/security_solution/**/*", - - // tests - "src/**/*.test.ts", - "src/**/*.test.tsx", - "src/**/integration_tests/*", - "src/**/tests/*", - // mocks - "src/**/__mocks__/*", - "src/**/mock/*", - "src/**/mocks/*", - "src/**/*/mock.ts", - "src/**/*/mocks.ts", - "src/**/*/mocks.tsx", - "src/**/*.mock.ts", - "src/**/*.mock.tsx", - "src/**/*.mocks.ts", - "src/**/*.mocks.tsx", - - // test helpers - "src/**/test_helpers/*", - "src/**/test_utils/*", - "src/**/*/test_utils.ts", - "src/**/*/test_helpers.ts", - "src/**/*/test_helper.tsx", - - // stubs - "src/**/*/stubs.ts", - "src/**/*.stub.ts", - "src/**/*.stories.tsx", - "src/**/*/_mock_handler_arguments.ts", - - // tests - "x-pack/plugins/**/*.test.ts", - "x-pack/plugins/**/*.test.tsx", - "x-pack/plugins/**/test/**/*", - "x-pack/plugins/**/tests/*", - "x-pack/plugins/**/integration_tests/*", - "x-pack/plugins/**/tests_client_integration/*", - "x-pack/plugins/**/__fixtures__/*", - "x-pack/plugins/**/__stories__/*", - "x-pack/plugins/**/__jest__/**/*", - - // mocks - "x-pack/plugins/**/__mocks__/*", - "x-pack/plugins/**/mock/*", - "x-pack/plugins/**/mocks/*", - "x-pack/plugins/**/*/mock.ts", - "x-pack/plugins/**/*/mocks.ts", - "x-pack/plugins/**/*/mocks.tsx", - "x-pack/plugins/**/*.mock.ts", - "x-pack/plugins/**/*.mock.tsx", - "x-pack/plugins/**/*.mocks.ts", - "x-pack/plugins/**/*.mocks.tsx", - - // test helpers - "x-pack/plugins/**/test_helpers/*", - "x-pack/plugins/**/test_utils/*", - "x-pack/plugins/**/*/test_utils.ts", - "x-pack/plugins/**/*/test_helper.tsx", - "x-pack/plugins/**/*/test_helpers.ts", - "x-pack/plugins/ui_actions_enhanced/public/components/action_wizard/test_data.tsx", - "x-pack/plugins/uptime/server/lib/requests/helper.ts", - "x-pack/plugins/uptime/public/lib/helper/rtl_helpers.tsx", - "x-pack/plugins/uptime/public/lib/helper/enzyme_helpers.tsx", - "x-pack/plugins/observability/public/components/shared/exploratory_view/rtl_helpers.tsx", - "x-pack/plugins/apm/server/utils/test_helpers.tsx", - "x-pack/plugins/apm/public/utils/testHelpers.tsx", - - // stubs - "x-pack/plugins/**/*/stubs.ts", - "x-pack/plugins/**/*.stub.ts", - "x-pack/plugins/**/*.stories.tsx", - "x-pack/plugins/**/*/_mock_handler_arguments.ts" ], "exclude": [ "x-pack/plugins/security_solution/cypress/**/*" diff --git a/tsconfig.project.json b/tsconfig.project.json deleted file mode 100644 index 174c3fdf0fd544..00000000000000 --- a/tsconfig.project.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "extends": "./tsconfig.base.json", - "compilerOptions": { - "composite": true, - "emitDeclarationOnly": true, - "declaration": true, - "declarationMap": true - }, - "exclude": [ - // tests - "**/*.test.ts", - "**/*.test.tsx", - "**/integration_tests/*", - "**/test/**/*", - "**/test/*", - "**/tests/*", - "**/tests_client_integration/*", - "**/__fixtures__/*", - "**/__stories__/*", - "**/__jest__/**", - - // mocks - "**/__mocks__/*", - "**/mock/*", - "**/mocks/*", - "**/*/mock.ts", - "**/*/mocks.ts", - "**/*/mocks.tsx", - "**/*.mock.ts", - "**/*.mock.tsx", - "**/*.mocks.ts", - "**/*.mocks.tsx", - - // test helpers - "**/test_helpers/*", - "**/test_utils/*", - "**/*/test_utils.ts", - "**/*/test_helper.tsx", - "**/*/test_helpers.ts", - // x-pack/plugins/ui_actions_enhanced/public/components/action_wizard/test_data.tsx - "**/*/test_data.tsx", - "**/*/shared_columns_tests.tsx", - // x-pack/plugins/uptime/server/lib/requests/helper.ts - "**/*/requests/helper.ts", - // x-pack/plugins/uptime/public/lib/helper/rtl_helpers.tsx - "**/*/rtl_helpers.tsx", - // x-pack/plugins/uptime/public/lib/helper/enzyme_helpers.tsx - "**/*/enzyme_helpers.tsx", - // x-pack/plugins/apm/server/utils/test_helpers.tsx - "**/*/test_helpers.tsx", - // x-pack/plugins/apm/public/utils/testHelpers.tsx - "**/*/testHelpers.tsx", - - // stubs - "**/*/stubs.ts", - "**/*.stub.ts", - "**/*.stories.tsx", - "**/*/_mock_handler_arguments.ts" - ], - "include": [], - "types": [ - "node", - "flot" - ] -} diff --git a/x-pack/plugins/actions/tsconfig.json b/x-pack/plugins/actions/tsconfig.json index 10ebd09235236b..d5c1105c99ad0d 100644 --- a/x-pack/plugins/actions/tsconfig.json +++ b/x-pack/plugins/actions/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/alerting/tsconfig.json b/x-pack/plugins/alerting/tsconfig.json index 4010688746901e..86ab00faeb5ade 100644 --- a/x-pack/plugins/alerting/tsconfig.json +++ b/x-pack/plugins/alerting/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/apm/e2e/tsconfig.json b/x-pack/plugins/apm/e2e/tsconfig.json index 0c13dd717991cf..c4587349c7ad77 100644 --- a/x-pack/plugins/apm/e2e/tsconfig.json +++ b/x-pack/plugins/apm/e2e/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../../tsconfig.project.json", + "extends": "../../../../tsconfig.base.json", "exclude": ["tmp"], "include": ["./**/*"], "compilerOptions": { diff --git a/x-pack/plugins/apm/ftr_e2e/tsconfig.json b/x-pack/plugins/apm/ftr_e2e/tsconfig.json index f699943a254fa9..168801f7826075 100644 --- a/x-pack/plugins/apm/ftr_e2e/tsconfig.json +++ b/x-pack/plugins/apm/ftr_e2e/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../../tsconfig.project.json", + "extends": "../../../../tsconfig.base.json", "exclude": [ "tmp" ], @@ -12,4 +12,4 @@ "node" ] } -} +} \ No newline at end of file diff --git a/x-pack/plugins/apm/scripts/optimize-tsconfig/optimize.js b/x-pack/plugins/apm/scripts/optimize-tsconfig/optimize.js index 613435fe186bff..fed938119c4a64 100644 --- a/x-pack/plugins/apm/scripts/optimize-tsconfig/optimize.js +++ b/x-pack/plugins/apm/scripts/optimize-tsconfig/optimize.js @@ -22,7 +22,7 @@ const { kibanaRoot, tsconfigTpl, filesToIgnore } = require('./paths'); const { unoptimizeTsConfig } = require('./unoptimize'); async function prepareBaseTsConfig() { - const baseConfigFilename = path.resolve(kibanaRoot, 'tsconfig.project.json'); + const baseConfigFilename = path.resolve(kibanaRoot, 'tsconfig.base.json'); const config = json5.parse(await readFile(baseConfigFilename, 'utf-8')); await writeFile( diff --git a/x-pack/plugins/apm/scripts/optimize-tsconfig/paths.js b/x-pack/plugins/apm/scripts/optimize-tsconfig/paths.js index b501ec3a8eedf5..dbc207c9e6d260 100644 --- a/x-pack/plugins/apm/scripts/optimize-tsconfig/paths.js +++ b/x-pack/plugins/apm/scripts/optimize-tsconfig/paths.js @@ -12,7 +12,7 @@ const tsconfigTpl = path.resolve(__dirname, './tsconfig.json'); const filesToIgnore = [ path.resolve(kibanaRoot, 'tsconfig.json'), - path.resolve(kibanaRoot, 'tsconfig.project.json'), + path.resolve(kibanaRoot, 'tsconfig.base.json'), path.resolve(kibanaRoot, 'x-pack/plugins/apm', 'tsconfig.json'), ]; diff --git a/x-pack/plugins/apm/tsconfig.json b/x-pack/plugins/apm/tsconfig.json index ae2085dc240036..ffbf11c23f63ae 100644 --- a/x-pack/plugins/apm/tsconfig.json +++ b/x-pack/plugins/apm/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/banners/tsconfig.json b/x-pack/plugins/banners/tsconfig.json index 6c4c80173208bc..85608a8a78ad52 100644 --- a/x-pack/plugins/banners/tsconfig.json +++ b/x-pack/plugins/banners/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/beats_management/tsconfig.json b/x-pack/plugins/beats_management/tsconfig.json index 398438712b26b3..ad68cc900e6382 100644 --- a/x-pack/plugins/beats_management/tsconfig.json +++ b/x-pack/plugins/beats_management/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/canvas/storybook/addon/tsconfig.json b/x-pack/plugins/canvas/storybook/addon/tsconfig.json index b115d1c46546c8..2ab1856de661a1 100644 --- a/x-pack/plugins/canvas/storybook/addon/tsconfig.json +++ b/x-pack/plugins/canvas/storybook/addon/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../../../tsconfig.project.json", + "extends": "../../../../../tsconfig.base.json", "include": [ "src/**/*.ts", "src/**/*.tsx" diff --git a/x-pack/plugins/canvas/tsconfig.json b/x-pack/plugins/canvas/tsconfig.json index 679165f0a1b76c..487b68ba3542ba 100644 --- a/x-pack/plugins/canvas/tsconfig.json +++ b/x-pack/plugins/canvas/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/cloud/tsconfig.json b/x-pack/plugins/cloud/tsconfig.json index f6edb9fb7ccae5..46e81aa7fa0868 100644 --- a/x-pack/plugins/cloud/tsconfig.json +++ b/x-pack/plugins/cloud/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/console_extensions/tsconfig.json b/x-pack/plugins/console_extensions/tsconfig.json index edcd46c4fafc56..5ad28f230a0bbf 100644 --- a/x-pack/plugins/console_extensions/tsconfig.json +++ b/x-pack/plugins/console_extensions/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/cross_cluster_replication/tsconfig.json b/x-pack/plugins/cross_cluster_replication/tsconfig.json index 156a851abb8db3..9c7590b9c2553e 100644 --- a/x-pack/plugins/cross_cluster_replication/tsconfig.json +++ b/x-pack/plugins/cross_cluster_replication/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/dashboard_enhanced/tsconfig.json b/x-pack/plugins/dashboard_enhanced/tsconfig.json index f6acdddc6f997c..567c390edfa5af 100644 --- a/x-pack/plugins/dashboard_enhanced/tsconfig.json +++ b/x-pack/plugins/dashboard_enhanced/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/dashboard_mode/tsconfig.json b/x-pack/plugins/dashboard_mode/tsconfig.json index c4a11959ec3e3d..6e4ed11ffa7ff4 100644 --- a/x-pack/plugins/dashboard_mode/tsconfig.json +++ b/x-pack/plugins/dashboard_mode/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/data_enhanced/tsconfig.json b/x-pack/plugins/data_enhanced/tsconfig.json index 5538a2db3e4cd9..047b9b06516bad 100644 --- a/x-pack/plugins/data_enhanced/tsconfig.json +++ b/x-pack/plugins/data_enhanced/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/discover_enhanced/tsconfig.json b/x-pack/plugins/discover_enhanced/tsconfig.json index 2a055bd0e0710e..38a55e557909b6 100644 --- a/x-pack/plugins/discover_enhanced/tsconfig.json +++ b/x-pack/plugins/discover_enhanced/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/drilldowns/url_drilldown/tsconfig.json b/x-pack/plugins/drilldowns/url_drilldown/tsconfig.json index 99aea16a9aabad..50fe41c49b0c88 100644 --- a/x-pack/plugins/drilldowns/url_drilldown/tsconfig.json +++ b/x-pack/plugins/drilldowns/url_drilldown/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../../tsconfig.project.json", + "extends": "../../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/embeddable_enhanced/tsconfig.json b/x-pack/plugins/embeddable_enhanced/tsconfig.json index 32754f2fd55243..6e9eb69585cbc1 100644 --- a/x-pack/plugins/embeddable_enhanced/tsconfig.json +++ b/x-pack/plugins/embeddable_enhanced/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/encrypted_saved_objects/tsconfig.json b/x-pack/plugins/encrypted_saved_objects/tsconfig.json index 9eae8b7366bea3..2b51b313d34fcb 100644 --- a/x-pack/plugins/encrypted_saved_objects/tsconfig.json +++ b/x-pack/plugins/encrypted_saved_objects/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/enterprise_search/tsconfig.json b/x-pack/plugins/enterprise_search/tsconfig.json index a4f1c55463e758..6b4c50770b49f4 100644 --- a/x-pack/plugins/enterprise_search/tsconfig.json +++ b/x-pack/plugins/enterprise_search/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/event_log/tsconfig.json b/x-pack/plugins/event_log/tsconfig.json index e21dbc93b7b478..9b7cde10da3d60 100644 --- a/x-pack/plugins/event_log/tsconfig.json +++ b/x-pack/plugins/event_log/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/features/tsconfig.json b/x-pack/plugins/features/tsconfig.json index 11e2dbc8f093fd..1260af55fbff61 100644 --- a/x-pack/plugins/features/tsconfig.json +++ b/x-pack/plugins/features/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/file_upload/tsconfig.json b/x-pack/plugins/file_upload/tsconfig.json index 8a982f83632aa5..887a05af31174b 100644 --- a/x-pack/plugins/file_upload/tsconfig.json +++ b/x-pack/plugins/file_upload/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/fleet/tsconfig.json b/x-pack/plugins/fleet/tsconfig.json index 66849e017395b7..a20d82de3c859c 100644 --- a/x-pack/plugins/fleet/tsconfig.json +++ b/x-pack/plugins/fleet/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/global_search/tsconfig.json b/x-pack/plugins/global_search/tsconfig.json index 2571f7c2e29350..2d05328f445dfc 100644 --- a/x-pack/plugins/global_search/tsconfig.json +++ b/x-pack/plugins/global_search/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/global_search_bar/tsconfig.json b/x-pack/plugins/global_search_bar/tsconfig.json index 595d55c3c5a0dc..266eecc35c84bd 100644 --- a/x-pack/plugins/global_search_bar/tsconfig.json +++ b/x-pack/plugins/global_search_bar/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/global_search_providers/tsconfig.json b/x-pack/plugins/global_search_providers/tsconfig.json index 9be9a681ee7c59..f2759954a68452 100644 --- a/x-pack/plugins/global_search_providers/tsconfig.json +++ b/x-pack/plugins/global_search_providers/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/graph/tsconfig.json b/x-pack/plugins/graph/tsconfig.json index ae0d143455d523..741c603e3aae4a 100644 --- a/x-pack/plugins/graph/tsconfig.json +++ b/x-pack/plugins/graph/tsconfig.json @@ -1,6 +1,6 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", @@ -27,4 +27,4 @@ { "path": "../../../src/plugins/kibana_utils/tsconfig.json" }, { "path": "../../../src/plugins/kibana_react/tsconfig.json" } ] - } + } \ No newline at end of file diff --git a/x-pack/plugins/grokdebugger/tsconfig.json b/x-pack/plugins/grokdebugger/tsconfig.json index 3e9e2f78708143..51d2d0b6db0eac 100644 --- a/x-pack/plugins/grokdebugger/tsconfig.json +++ b/x-pack/plugins/grokdebugger/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/index_lifecycle_management/tsconfig.json b/x-pack/plugins/index_lifecycle_management/tsconfig.json index bf43817cbc407b..75bd775a367497 100644 --- a/x-pack/plugins/index_lifecycle_management/tsconfig.json +++ b/x-pack/plugins/index_lifecycle_management/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", @@ -8,6 +8,7 @@ "declarationMap": true }, "include": [ + "__jest__/**/*", "common/**/*", "public/**/*", "server/**/*", diff --git a/x-pack/plugins/index_management/tsconfig.json b/x-pack/plugins/index_management/tsconfig.json index 0766839a230b97..81a96a77cef832 100644 --- a/x-pack/plugins/index_management/tsconfig.json +++ b/x-pack/plugins/index_management/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", @@ -8,9 +8,11 @@ "declarationMap": true }, "include": [ + "__jest__/**/*", "common/**/*", "public/**/*", "server/**/*", + "test/**/*", "../../../typings/**/*", ], "references": [ diff --git a/x-pack/plugins/infra/public/utils/enzyme_helpers.tsx b/x-pack/plugins/infra/public/utils/enzyme_helpers.tsx new file mode 100644 index 00000000000000..33fbbd03d790a1 --- /dev/null +++ b/x-pack/plugins/infra/public/utils/enzyme_helpers.tsx @@ -0,0 +1,87 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +// eslint-disable-next-line import/no-extraneous-dependencies +import { mount, ReactWrapper } from 'enzyme'; +import React from 'react'; +import { act as reactAct } from 'react-dom/test-utils'; +/** + * A wrapper object to provide access to the state of a hook under test and to + * enable interaction with that hook. + */ +interface ReactHookWrapper { + /* Ensures that async React operations have settled before and after the + * given actor callback is called. The actor callback arguments provide easy + * access to the last hook value and allow for updating the arguments passed + * to the hook body to trigger reevaluation. + */ + act: (actor: (lastHookValue: HookValue, setArgs: (args: Args) => void) => void) => void; + /* The enzyme wrapper around the test component. */ + component: ReactWrapper; + /* The most recent value return the by test harness of the hook. */ + getLastHookValue: () => HookValue; + /* The jest Mock function that receives the hook values for introspection. */ + hookValueCallback: jest.Mock; +} + +/** + * Allows for execution of hooks inside of a test component which records the + * returned values. + * + * @param body A function that calls the hook and returns data derived from it + * @param WrapperComponent A component that, if provided, will be wrapped + * around the test component. This can be useful to provide context values. + * @return {ReactHookWrapper} An object providing access to the hook state and + * functions to interact with it. + */ +export const mountHook = ( + body: (args: Args) => HookValue, + WrapperComponent?: React.ComponentType, + initialArgs: Args = {} as Args +): ReactHookWrapper => { + const hookValueCallback = jest.fn(); + let component!: ReactWrapper; + + const act: ReactHookWrapper['act'] = (actor) => { + reactAct(() => { + actor(getLastHookValue(), (args: Args) => component.setProps(args)); + component.update(); + }); + }; + + const getLastHookValue = () => { + const calls = hookValueCallback.mock.calls; + if (calls.length <= 0) { + throw Error('No recent hook value present.'); + } + return calls[calls.length - 1][0]; + }; + + const HookComponent = (props: Args) => { + hookValueCallback(body(props)); + return null; + }; + const TestComponent: React.FunctionComponent = (args) => + WrapperComponent ? ( + + + + ) : ( + + ); + + reactAct(() => { + component = mount(); + }); + + return { + act, + component, + getLastHookValue, + hookValueCallback, + }; +}; diff --git a/x-pack/plugins/infra/server/lib/infra_ml/queries/metrics_hosts_anomalies.ts b/x-pack/plugins/infra/server/lib/infra_ml/queries/metrics_hosts_anomalies.ts index b9bfcd302fb838..ab50986c3b3d5b 100644 --- a/x-pack/plugins/infra/server/lib/infra_ml/queries/metrics_hosts_anomalies.ts +++ b/x-pack/plugins/infra/server/lib/infra_ml/queries/metrics_hosts_anomalies.ts @@ -84,7 +84,7 @@ export const createMetricsHostsAnomaliesQuery = ({ const sortOptions = [ { [sortToMlFieldMap[field]]: querySortDirection }, { [TIEBREAKER_FIELD]: querySortDirection }, // Tiebreaker - ] as const; + ]; const resultsQuery = { ...defaultRequestParameters, diff --git a/x-pack/plugins/infra/server/lib/infra_ml/queries/metrics_k8s_anomalies.ts b/x-pack/plugins/infra/server/lib/infra_ml/queries/metrics_k8s_anomalies.ts index 8dadcfe87c6f9e..8fb8df5eef3d75 100644 --- a/x-pack/plugins/infra/server/lib/infra_ml/queries/metrics_k8s_anomalies.ts +++ b/x-pack/plugins/infra/server/lib/infra_ml/queries/metrics_k8s_anomalies.ts @@ -83,7 +83,7 @@ export const createMetricsK8sAnomaliesQuery = ({ const sortOptions = [ { [sortToMlFieldMap[field]]: querySortDirection }, { [TIEBREAKER_FIELD]: querySortDirection }, // Tiebreaker - ] as const; + ]; const resultsQuery = { ...defaultRequestParameters, diff --git a/x-pack/plugins/infra/tsconfig.json b/x-pack/plugins/infra/tsconfig.json index b684e1866282f9..765af7974a2f13 100644 --- a/x-pack/plugins/infra/tsconfig.json +++ b/x-pack/plugins/infra/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/ingest_pipelines/tsconfig.json b/x-pack/plugins/ingest_pipelines/tsconfig.json index 5917b94caf76b3..a248bc9f337fe3 100644 --- a/x-pack/plugins/ingest_pipelines/tsconfig.json +++ b/x-pack/plugins/ingest_pipelines/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", @@ -11,6 +11,7 @@ "common/**/*", "public/**/*", "server/**/*", + "__jest__/**/*", "../../../typings/**/*" ], "references": [ diff --git a/x-pack/plugins/lens/tsconfig.json b/x-pack/plugins/lens/tsconfig.json index 69ef52535dd9d9..134f0b4185b840 100644 --- a/x-pack/plugins/lens/tsconfig.json +++ b/x-pack/plugins/lens/tsconfig.json @@ -1,6 +1,6 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", @@ -38,4 +38,4 @@ { "path": "../../../src/plugins/embeddable/tsconfig.json"}, { "path": "../../../src/plugins/presentation_util/tsconfig.json"}, ] - } + } \ No newline at end of file diff --git a/x-pack/plugins/license_management/tsconfig.json b/x-pack/plugins/license_management/tsconfig.json index 925049ca924cfb..e6cb0101ee838b 100644 --- a/x-pack/plugins/license_management/tsconfig.json +++ b/x-pack/plugins/license_management/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/licensing/tsconfig.json b/x-pack/plugins/licensing/tsconfig.json index 2d744e57c1895a..6118bcd81d342c 100644 --- a/x-pack/plugins/licensing/tsconfig.json +++ b/x-pack/plugins/licensing/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/logstash/tsconfig.json b/x-pack/plugins/logstash/tsconfig.json index 6430248e46396c..6f21cfdb0b1919 100644 --- a/x-pack/plugins/logstash/tsconfig.json +++ b/x-pack/plugins/logstash/tsconfig.json @@ -1,6 +1,6 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/maps/public/components/validated_number_input.tsx b/x-pack/plugins/maps/public/components/validated_number_input.tsx index 942f31074000f9..cd525cf1ee2c97 100644 --- a/x-pack/plugins/maps/public/components/validated_number_input.tsx +++ b/x-pack/plugins/maps/public/components/validated_number_input.tsx @@ -6,8 +6,8 @@ */ import React, { Component, ChangeEvent, ReactNode } from 'react'; -import { EuiFieldNumber, EuiFormRow } from '@elastic/eui'; -import type { EuiFormRowDisplayKeys } from '@elastic/eui/src/components/form/form_row/form_row'; +// @ts-expect-error +import { EuiFieldNumber, EuiFormRow, EuiFormRowDisplayKeys } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import _ from 'lodash'; diff --git a/x-pack/plugins/maps/tsconfig.json b/x-pack/plugins/maps/tsconfig.json index 59af94bea0b683..1b74b7ee7566a8 100644 --- a/x-pack/plugins/maps/tsconfig.json +++ b/x-pack/plugins/maps/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/ml/server/routes/apidoc_scripts/tsconfig.json b/x-pack/plugins/ml/server/routes/apidoc_scripts/tsconfig.json index 599dee1e56c0f8..6d01a853698b8e 100644 --- a/x-pack/plugins/ml/server/routes/apidoc_scripts/tsconfig.json +++ b/x-pack/plugins/ml/server/routes/apidoc_scripts/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../../../../tsconfig.project.json", + "extends": "../../../../../../tsconfig.base.json", "compilerOptions": { "outDir": "./target", "target": "es6", diff --git a/x-pack/plugins/ml/tsconfig.json b/x-pack/plugins/ml/tsconfig.json index b1135b867dc08d..6b396b1c596429 100644 --- a/x-pack/plugins/ml/tsconfig.json +++ b/x-pack/plugins/ml/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/monitoring/tsconfig.json b/x-pack/plugins/monitoring/tsconfig.json index b1999101f7c122..d0fb7e1a88dcfe 100644 --- a/x-pack/plugins/monitoring/tsconfig.json +++ b/x-pack/plugins/monitoring/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/observability/tsconfig.json b/x-pack/plugins/observability/tsconfig.json index cc6e298795e4a3..f55ae640a80263 100644 --- a/x-pack/plugins/observability/tsconfig.json +++ b/x-pack/plugins/observability/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/osquery/tsconfig.json b/x-pack/plugins/osquery/tsconfig.json index 03c9e451f3b52b..291b0f7c607cf1 100644 --- a/x-pack/plugins/osquery/tsconfig.json +++ b/x-pack/plugins/osquery/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/painless_lab/tsconfig.json b/x-pack/plugins/painless_lab/tsconfig.json index 2519206b0fcdb6..a869b21e06d4d5 100644 --- a/x-pack/plugins/painless_lab/tsconfig.json +++ b/x-pack/plugins/painless_lab/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/remote_clusters/tsconfig.json b/x-pack/plugins/remote_clusters/tsconfig.json index b48933bc9f1ecc..0bee6300cf0b29 100644 --- a/x-pack/plugins/remote_clusters/tsconfig.json +++ b/x-pack/plugins/remote_clusters/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/reporting/tsconfig.json b/x-pack/plugins/reporting/tsconfig.json index 4f252743ed078b..88e8d343f4700f 100644 --- a/x-pack/plugins/reporting/tsconfig.json +++ b/x-pack/plugins/reporting/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/rollup/tsconfig.json b/x-pack/plugins/rollup/tsconfig.json index bf589c62713d6d..9b994d1710ffc2 100644 --- a/x-pack/plugins/rollup/tsconfig.json +++ b/x-pack/plugins/rollup/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/runtime_fields/tsconfig.json b/x-pack/plugins/runtime_fields/tsconfig.json index e1ad141f1c702b..a1efe4c9cf2dd6 100644 --- a/x-pack/plugins/runtime_fields/tsconfig.json +++ b/x-pack/plugins/runtime_fields/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/saved_objects_tagging/tsconfig.json b/x-pack/plugins/saved_objects_tagging/tsconfig.json index 5c37481f982d91..d00156ad1277ca 100644 --- a/x-pack/plugins/saved_objects_tagging/tsconfig.json +++ b/x-pack/plugins/saved_objects_tagging/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/searchprofiler/tsconfig.json b/x-pack/plugins/searchprofiler/tsconfig.json index 57cd882422b391..f8ac3a61f7812a 100644 --- a/x-pack/plugins/searchprofiler/tsconfig.json +++ b/x-pack/plugins/searchprofiler/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/security/tsconfig.json b/x-pack/plugins/security/tsconfig.json index 4ace497dbd5ad6..6c3fd1851a8cbe 100644 --- a/x-pack/plugins/security/tsconfig.json +++ b/x-pack/plugins/security/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/security_solution/cypress/tsconfig.json b/x-pack/plugins/security_solution/cypress/tsconfig.json index bd8d9aa058bc3b..270d877a362a6d 100644 --- a/x-pack/plugins/security_solution/cypress/tsconfig.json +++ b/x-pack/plugins/security_solution/cypress/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../../tsconfig.project.json", + "extends": "../../../../tsconfig.base.json", "exclude": [], "include": [ "./**/*" diff --git a/x-pack/plugins/snapshot_restore/tsconfig.json b/x-pack/plugins/snapshot_restore/tsconfig.json index c496847e4dd9bc..39beda02977e1d 100644 --- a/x-pack/plugins/snapshot_restore/tsconfig.json +++ b/x-pack/plugins/snapshot_restore/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", @@ -8,9 +8,11 @@ "declarationMap": true }, "include": [ + "__jest__/**/*", "common/**/*", "public/**/*", "server/**/*", + "test/**/*", "../../../typings/**/*", ], "references": [ diff --git a/x-pack/plugins/spaces/tsconfig.json b/x-pack/plugins/spaces/tsconfig.json index 4c67cbe8912bd6..95fbecaa909366 100644 --- a/x-pack/plugins/spaces/tsconfig.json +++ b/x-pack/plugins/spaces/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/stack_alerts/tsconfig.json b/x-pack/plugins/stack_alerts/tsconfig.json index 97eb9a9a05b86e..c83935945c67b4 100644 --- a/x-pack/plugins/stack_alerts/tsconfig.json +++ b/x-pack/plugins/stack_alerts/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/task_manager/server/monitoring/workload_statistics.ts b/x-pack/plugins/task_manager/server/monitoring/workload_statistics.ts index 70b4ba55c2393f..c79b310822c3ec 100644 --- a/x-pack/plugins/task_manager/server/monitoring/workload_statistics.ts +++ b/x-pack/plugins/task_manager/server/monitoring/workload_statistics.ts @@ -56,7 +56,7 @@ export interface WorkloadAggregation { scheduleDensity: { range: { field: string; - ranges: [{ from: number; to: number }]; + ranges: [{ from: string; to: string }]; }; aggs: { histogram: { @@ -86,6 +86,7 @@ export interface WorkloadAggregation { // The type of a bucket in the scheduleDensity range aggregation type ScheduleDensityResult = AggregationResultOf< + // @ts-expect-error AggregationRange reqires from: number WorkloadAggregation['aggs']['idleTasks']['aggs']['scheduleDensity'], {} >['buckets'][0]; diff --git a/x-pack/plugins/task_manager/tsconfig.json b/x-pack/plugins/task_manager/tsconfig.json index 95a098e54619e6..a72b678da1f7c1 100644 --- a/x-pack/plugins/task_manager/tsconfig.json +++ b/x-pack/plugins/task_manager/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/telemetry_collection_xpack/tsconfig.json b/x-pack/plugins/telemetry_collection_xpack/tsconfig.json index 80488bd74617d1..476f5926f757a4 100644 --- a/x-pack/plugins/telemetry_collection_xpack/tsconfig.json +++ b/x-pack/plugins/telemetry_collection_xpack/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/transform/tsconfig.json b/x-pack/plugins/transform/tsconfig.json index 30da887cc1c431..2717f92c7a4df1 100644 --- a/x-pack/plugins/transform/tsconfig.json +++ b/x-pack/plugins/transform/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/triggers_actions_ui/tsconfig.json b/x-pack/plugins/triggers_actions_ui/tsconfig.json index b7a63d7043f496..8202449b222987 100644 --- a/x-pack/plugins/triggers_actions_ui/tsconfig.json +++ b/x-pack/plugins/triggers_actions_ui/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/ui_actions_enhanced/tsconfig.json b/x-pack/plugins/ui_actions_enhanced/tsconfig.json index 1513669cdc1ad0..39318770126e58 100644 --- a/x-pack/plugins/ui_actions_enhanced/tsconfig.json +++ b/x-pack/plugins/ui_actions_enhanced/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/upgrade_assistant/tsconfig.json b/x-pack/plugins/upgrade_assistant/tsconfig.json index 08e45bebf125b5..0d65c8ddd8fed0 100644 --- a/x-pack/plugins/upgrade_assistant/tsconfig.json +++ b/x-pack/plugins/upgrade_assistant/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/uptime/public/components/certificates/cert_monitors.test.tsx b/x-pack/plugins/uptime/public/components/certificates/cert_monitors.test.tsx index 719c90574b0887..5dfc11837b72d6 100644 --- a/x-pack/plugins/uptime/public/components/certificates/cert_monitors.test.tsx +++ b/x-pack/plugins/uptime/public/components/certificates/cert_monitors.test.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { CertMonitors } from './cert_monitors'; -import { renderWithRouter, shallowWithRouter } from '../../lib/helper/enzyme_helpers'; +import { renderWithRouter, shallowWithRouter } from '../../lib'; describe('CertMonitors', () => { const certMons = [ diff --git a/x-pack/plugins/uptime/public/components/certificates/cert_search.test.tsx b/x-pack/plugins/uptime/public/components/certificates/cert_search.test.tsx index a0166fc5737544..a991634de22a6c 100644 --- a/x-pack/plugins/uptime/public/components/certificates/cert_search.test.tsx +++ b/x-pack/plugins/uptime/public/components/certificates/cert_search.test.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { renderWithRouter, shallowWithRouter } from '../../lib/helper/enzyme_helpers'; +import { renderWithRouter, shallowWithRouter } from '../../lib'; import { CertificateSearch } from './cert_search'; describe('CertificatesSearch', () => { diff --git a/x-pack/plugins/uptime/public/components/certificates/cert_status.test.tsx b/x-pack/plugins/uptime/public/components/certificates/cert_status.test.tsx index 999d76f6908672..e331a6e5c34fea 100644 --- a/x-pack/plugins/uptime/public/components/certificates/cert_status.test.tsx +++ b/x-pack/plugins/uptime/public/components/certificates/cert_status.test.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { renderWithRouter, shallowWithRouter } from '../../lib/helper/enzyme_helpers'; +import { renderWithRouter, shallowWithRouter } from '../../lib'; import { CertStatus } from './cert_status'; import * as redux from 'react-redux'; import moment from 'moment'; diff --git a/x-pack/plugins/uptime/public/components/certificates/certificates_list.test.tsx b/x-pack/plugins/uptime/public/components/certificates/certificates_list.test.tsx index 8ae0cdb791d9b1..ec6a5d91a67c33 100644 --- a/x-pack/plugins/uptime/public/components/certificates/certificates_list.test.tsx +++ b/x-pack/plugins/uptime/public/components/certificates/certificates_list.test.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { shallowWithRouter } from '../../lib/helper/enzyme_helpers'; +import { shallowWithRouter } from '../../lib'; import { CertificateList, CertSort } from './certificates_list'; describe('CertificateList', () => { diff --git a/x-pack/plugins/uptime/public/components/certificates/fingerprint_col.test.tsx b/x-pack/plugins/uptime/public/components/certificates/fingerprint_col.test.tsx index 550b7f75623f0d..1affd1f990f90b 100644 --- a/x-pack/plugins/uptime/public/components/certificates/fingerprint_col.test.tsx +++ b/x-pack/plugins/uptime/public/components/certificates/fingerprint_col.test.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { renderWithRouter, shallowWithRouter } from '../../lib/helper/enzyme_helpers'; +import { renderWithRouter, shallowWithRouter } from '../../lib'; import { FingerprintCol } from './fingerprint_col'; import moment from 'moment'; diff --git a/x-pack/plugins/uptime/public/components/common/charts/duration_charts.test.tsx b/x-pack/plugins/uptime/public/components/common/charts/duration_charts.test.tsx index 72b1145a9f34e2..d7ae92a0e76544 100644 --- a/x-pack/plugins/uptime/public/components/common/charts/duration_charts.test.tsx +++ b/x-pack/plugins/uptime/public/components/common/charts/duration_charts.test.tsx @@ -9,7 +9,7 @@ import React from 'react'; import DateMath from '@elastic/datemath'; import { DurationChartComponent } from './duration_chart'; import { MonitorDurationResult } from '../../../../common/types'; -import { shallowWithRouter } from '../../../lib/helper/enzyme_helpers'; +import { shallowWithRouter } from '../../../lib'; describe('MonitorCharts component', () => { let dateMathSpy: any; diff --git a/x-pack/plugins/uptime/public/components/common/charts/monitor_bar_series.test.tsx b/x-pack/plugins/uptime/public/components/common/charts/monitor_bar_series.test.tsx index b11595eafae4fb..792b357b3baba8 100644 --- a/x-pack/plugins/uptime/public/components/common/charts/monitor_bar_series.test.tsx +++ b/x-pack/plugins/uptime/public/components/common/charts/monitor_bar_series.test.tsx @@ -7,8 +7,7 @@ import React from 'react'; import { MonitorBarSeries, MonitorBarSeriesProps } from './monitor_bar_series'; -import { renderWithRouter, shallowWithRouter } from '../../../lib/helper/enzyme_helpers'; -import { MountWithReduxProvider } from '../../../lib/helper/helper_with_redux'; +import { renderWithRouter, shallowWithRouter, MountWithReduxProvider } from '../../../lib'; import { HistogramPoint } from '../../../../common/runtime_types'; describe('MonitorBarSeries component', () => { diff --git a/x-pack/plugins/uptime/public/components/common/header/page_header.test.tsx b/x-pack/plugins/uptime/public/components/common/header/page_header.test.tsx index bede71b8ba03d8..6e04648a817f0c 100644 --- a/x-pack/plugins/uptime/public/components/common/header/page_header.test.tsx +++ b/x-pack/plugins/uptime/public/components/common/header/page_header.test.tsx @@ -9,7 +9,7 @@ import React from 'react'; import moment from 'moment'; import { PageHeader } from './page_header'; import { Ping } from '../../../../common/runtime_types'; -import { renderWithRouter } from '../../../lib/helper/enzyme_helpers'; +import { renderWithRouter } from '../../../lib'; import { mockReduxHooks } from '../../../lib/helper/test_helpers'; describe('PageHeader', () => { diff --git a/x-pack/plugins/uptime/public/components/common/monitor_tags.test.tsx b/x-pack/plugins/uptime/public/components/common/monitor_tags.test.tsx index 63465aefcdd433..fdb5498969d39d 100644 --- a/x-pack/plugins/uptime/public/components/common/monitor_tags.test.tsx +++ b/x-pack/plugins/uptime/public/components/common/monitor_tags.test.tsx @@ -10,7 +10,7 @@ import React from 'react'; import { MemoryRouter } from 'react-router-dom'; import { MonitorTags } from './monitor_tags'; import * as hooks from '../../hooks/use_url_params'; -import { renderWithRouter, shallowWithRouter } from '../../lib/helper/enzyme_helpers'; +import { renderWithRouter, shallowWithRouter } from '../../lib'; describe('MonitorTags component', () => { const summaryPing = { diff --git a/x-pack/plugins/uptime/public/components/common/uptime_date_picker.test.tsx b/x-pack/plugins/uptime/public/components/common/uptime_date_picker.test.tsx index d433e7fccd1b8e..4bfe7de33cba58 100644 --- a/x-pack/plugins/uptime/public/components/common/uptime_date_picker.test.tsx +++ b/x-pack/plugins/uptime/public/components/common/uptime_date_picker.test.tsx @@ -10,9 +10,9 @@ import { UptimeDatePicker } from './uptime_date_picker'; import { renderWithRouter, shallowWithRouter, + MountWithReduxProvider, mountWithRouterRedux, -} from '../../lib/helper/enzyme_helpers'; -import { MountWithReduxProvider } from '../../lib/helper/helper_with_redux'; +} from '../../lib'; import { UptimeStartupPluginsContextProvider } from '../../contexts'; import { startPlugins } from '../../lib/__mocks__/uptime_plugin_start_mock'; import { ClientPluginsStart } from '../../apps/plugin'; diff --git a/x-pack/plugins/uptime/public/components/monitor/ml/ml_integerations.test.tsx b/x-pack/plugins/uptime/public/components/monitor/ml/ml_integerations.test.tsx index 16d96148af3404..f29be50633fab7 100644 --- a/x-pack/plugins/uptime/public/components/monitor/ml/ml_integerations.test.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/ml/ml_integerations.test.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { MLIntegrationComponent } from './ml_integeration'; -import { renderWithRouter, shallowWithRouter } from '../../../lib/helper/enzyme_helpers'; +import { renderWithRouter, shallowWithRouter } from '../../../lib'; import * as redux from 'react-redux'; import { KibanaContextProvider } from '../../../../../../../src/plugins/kibana_react/public'; import { coreMock } from 'src/core/public/mocks'; diff --git a/x-pack/plugins/uptime/public/components/monitor/ml/ml_manage_job.test.tsx b/x-pack/plugins/uptime/public/components/monitor/ml/ml_manage_job.test.tsx index 6bff0b61d7349e..15a537a49ccf38 100644 --- a/x-pack/plugins/uptime/public/components/monitor/ml/ml_manage_job.test.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/ml/ml_manage_job.test.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { coreMock } from 'src/core/public/mocks'; import { ManageMLJobComponent } from './manage_ml_job'; import * as redux from 'react-redux'; -import { renderWithRouter, shallowWithRouter } from '../../../lib/helper/enzyme_helpers'; +import { renderWithRouter, shallowWithRouter } from '../../../lib'; import { KibanaContextProvider } from '../../../../../../../src/plugins/kibana_react/public'; const core = coreMock.createStart(); diff --git a/x-pack/plugins/uptime/public/components/monitor/monitor_charts.test.tsx b/x-pack/plugins/uptime/public/components/monitor/monitor_charts.test.tsx index a1be391833bc3f..3f107581c1eea7 100644 --- a/x-pack/plugins/uptime/public/components/monitor/monitor_charts.test.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/monitor_charts.test.tsx @@ -8,7 +8,7 @@ import React from 'react'; import DateMath from '@elastic/datemath'; import { MonitorCharts } from './monitor_charts'; -import { shallowWithRouter } from '../../lib/helper/enzyme_helpers'; +import { shallowWithRouter } from '../../lib'; describe('MonitorCharts component', () => { let dateMathSpy: any; diff --git a/x-pack/plugins/uptime/public/components/monitor/monitor_title.test.tsx b/x-pack/plugins/uptime/public/components/monitor/monitor_title.test.tsx index 682be99b9b4186..dabc0021898eb8 100644 --- a/x-pack/plugins/uptime/public/components/monitor/monitor_title.test.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/monitor_title.test.tsx @@ -10,7 +10,7 @@ import moment from 'moment'; import * as reactRouterDom from 'react-router-dom'; import { Ping } from '../../../common/runtime_types'; import { MonitorPageTitle } from './monitor_title'; -import { renderWithRouter } from '../../lib/helper/enzyme_helpers'; +import { renderWithRouter } from '../../lib'; import { mockReduxHooks } from '../../lib/helper/test_helpers'; jest.mock('react-router-dom', () => { diff --git a/x-pack/plugins/uptime/public/components/monitor/status_details/monitor_status.bar.test.tsx b/x-pack/plugins/uptime/public/components/monitor/status_details/monitor_status.bar.test.tsx index ba0853b5b1b60a..af3c47b9caf30b 100644 --- a/x-pack/plugins/uptime/public/components/monitor/status_details/monitor_status.bar.test.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/monitor_status.bar.test.tsx @@ -10,7 +10,7 @@ import React from 'react'; import { MonitorStatusBar } from './status_bar'; import { Ping } from '../../../../common/runtime_types'; import * as redux from 'react-redux'; -import { renderWithRouter } from '../../../lib/helper/enzyme_helpers'; +import { renderWithRouter } from '../../../lib'; import { createMemoryHistory } from 'history'; describe('MonitorStatusBar component', () => { diff --git a/x-pack/plugins/uptime/public/components/monitor/status_details/ssl_certificate.test.tsx b/x-pack/plugins/uptime/public/components/monitor/status_details/ssl_certificate.test.tsx index 0cb7ff7168404d..03ce292e63621a 100644 --- a/x-pack/plugins/uptime/public/components/monitor/status_details/ssl_certificate.test.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/ssl_certificate.test.tsx @@ -11,11 +11,7 @@ import { EuiIcon } from '@elastic/eui'; import { Tls } from '../../../../common/runtime_types'; import { MonitorSSLCertificate } from './status_bar'; import * as redux from 'react-redux'; -import { - mountWithRouter, - renderWithRouter, - shallowWithRouter, -} from '../../../lib/helper/enzyme_helpers'; +import { mountWithRouter, renderWithRouter, shallowWithRouter } from '../../../lib'; import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../common/constants'; describe('SSL Certificate component', () => { diff --git a/x-pack/plugins/uptime/public/components/overview/empty_state/empty_state.test.tsx b/x-pack/plugins/uptime/public/components/overview/empty_state/empty_state.test.tsx index c751e6a0c24fa0..a617ba0db1eb33 100644 --- a/x-pack/plugins/uptime/public/components/overview/empty_state/empty_state.test.tsx +++ b/x-pack/plugins/uptime/public/components/overview/empty_state/empty_state.test.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { EmptyStateComponent } from './empty_state'; import { StatesIndexStatus } from '../../../../common/runtime_types'; import { HttpFetchError, IHttpFetchError } from 'src/core/public'; -import { mountWithRouter, shallowWithRouter } from '../../../lib/helper/enzyme_helpers'; +import { mountWithRouter, shallowWithRouter } from '../../../lib'; describe('EmptyState component', () => { let statesIndexStatus: StatesIndexStatus; diff --git a/x-pack/plugins/uptime/public/components/overview/monitor_list/columns/enable_alert.test.tsx b/x-pack/plugins/uptime/public/components/overview/monitor_list/columns/enable_alert.test.tsx index a4e7f10d97bfc7..a325edc2431291 100644 --- a/x-pack/plugins/uptime/public/components/overview/monitor_list/columns/enable_alert.test.tsx +++ b/x-pack/plugins/uptime/public/components/overview/monitor_list/columns/enable_alert.test.tsx @@ -12,7 +12,7 @@ import { mountWithRouterRedux, renderWithRouterRedux, shallowWithRouterRedux, -} from '../../../../lib/helper/enzyme_helpers'; +} from '../../../../lib'; import { EuiPopover, EuiText } from '@elastic/eui'; import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../../common/constants'; import { ReactRouterEuiLink } from '../../../common/react_router_helpers'; diff --git a/x-pack/plugins/uptime/public/components/overview/monitor_list/filter_status_button.test.tsx b/x-pack/plugins/uptime/public/components/overview/monitor_list/filter_status_button.test.tsx index c95e3cd61c5fd7..4d0e82dc8a2969 100644 --- a/x-pack/plugins/uptime/public/components/overview/monitor_list/filter_status_button.test.tsx +++ b/x-pack/plugins/uptime/public/components/overview/monitor_list/filter_status_button.test.tsx @@ -7,8 +7,7 @@ import React from 'react'; import { FilterStatusButton, FilterStatusButtonProps } from './filter_status_button'; -import { renderWithRouter, shallowWithRouter } from '../../../lib/helper/enzyme_helpers'; -import { MountWithReduxProvider } from '../../../lib/helper/helper_with_redux'; +import { renderWithRouter, shallowWithRouter, MountWithReduxProvider } from '../../../lib'; describe('FilterStatusButton', () => { let props: FilterStatusButtonProps; diff --git a/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list.test.tsx b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list.test.tsx index f7a2ad9a536bd1..39f9b20624b630 100644 --- a/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list.test.tsx +++ b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list.test.tsx @@ -15,7 +15,7 @@ import { MonitorSummary, } from '../../../../common/runtime_types'; import { MonitorListComponent, noItemsMessage } from './monitor_list'; -import { renderWithRouter, shallowWithRouter } from '../../../lib/helper/enzyme_helpers'; +import { renderWithRouter, shallowWithRouter } from '../../../lib'; import * as redux from 'react-redux'; import moment from 'moment'; import { IHttpFetchError } from '../../../../../../../src/core/public'; diff --git a/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/monitor_list_drawer.test.tsx b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/monitor_list_drawer.test.tsx index 39c6d6bd9215d5..d044ad4e6a3a28 100644 --- a/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/monitor_list_drawer.test.tsx +++ b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/monitor_list_drawer.test.tsx @@ -9,7 +9,7 @@ import 'jest'; import React from 'react'; import { MonitorListDrawerComponent } from './monitor_list_drawer'; import { MonitorDetails, MonitorSummary, makePing } from '../../../../../common/runtime_types'; -import { shallowWithRouter } from '../../../../lib/helper/enzyme_helpers'; +import { shallowWithRouter } from '../../../../lib'; describe('MonitorListDrawer component', () => { let summary: MonitorSummary; diff --git a/x-pack/plugins/uptime/public/components/overview/monitor_list/status_filter.test.tsx b/x-pack/plugins/uptime/public/components/overview/monitor_list/status_filter.test.tsx index c2515ab55b126b..bbc4e13c9eca2c 100644 --- a/x-pack/plugins/uptime/public/components/overview/monitor_list/status_filter.test.tsx +++ b/x-pack/plugins/uptime/public/components/overview/monitor_list/status_filter.test.tsx @@ -10,8 +10,8 @@ import { mountWithRouter, renderWithRouter, shallowWithRouter, -} from '../../../lib/helper/enzyme_helpers'; -import { MountWithReduxProvider } from '../../../lib/helper/helper_with_redux'; + MountWithReduxProvider, +} from '../../../lib'; import { createMemoryHistory } from 'history'; import { StatusFilter } from './status_filter'; import { FilterStatusButton } from './filter_status_button'; diff --git a/x-pack/plugins/uptime/public/components/settings/certificate_form.test.tsx b/x-pack/plugins/uptime/public/components/settings/certificate_form.test.tsx index 051c4166d0fddf..84c9923bfc4192 100644 --- a/x-pack/plugins/uptime/public/components/settings/certificate_form.test.tsx +++ b/x-pack/plugins/uptime/public/components/settings/certificate_form.test.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { CertificateExpirationForm } from './certificate_form'; -import { shallowWithRouter, mountWithRouter } from '../../lib/helper/enzyme_helpers'; +import { shallowWithRouter, mountWithRouter } from '../../lib'; describe('CertificateForm', () => { it('shallow renders expected elements for valid props', () => { diff --git a/x-pack/plugins/uptime/public/components/settings/indices_form.test.tsx b/x-pack/plugins/uptime/public/components/settings/indices_form.test.tsx index fc2567ea98c451..67ca142d8a8ea8 100644 --- a/x-pack/plugins/uptime/public/components/settings/indices_form.test.tsx +++ b/x-pack/plugins/uptime/public/components/settings/indices_form.test.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { IndicesForm } from './indices_form'; -import { shallowWithRouter } from '../../lib/helper/enzyme_helpers'; +import { shallowWithRouter } from '../../lib'; describe('CertificateForm', () => { it('shallow renders expected elements for valid props', () => { diff --git a/x-pack/plugins/uptime/public/hooks/use_breadcrumbs.test.tsx b/x-pack/plugins/uptime/public/hooks/use_breadcrumbs.test.tsx index 7aeac9706af58c..6fc98fbaf1f5b0 100644 --- a/x-pack/plugins/uptime/public/hooks/use_breadcrumbs.test.tsx +++ b/x-pack/plugins/uptime/public/hooks/use_breadcrumbs.test.tsx @@ -8,11 +8,10 @@ import { ChromeBreadcrumb } from 'kibana/public'; import React from 'react'; import { Route } from 'react-router-dom'; -import { mountWithRouter } from '../lib/helper/enzyme_helpers'; +import { mountWithRouter } from '../lib'; import { OVERVIEW_ROUTE } from '../../common/constants'; import { KibanaContextProvider } from '../../../../../src/plugins/kibana_react/public'; -import { UptimeUrlParams, getSupportedUrlParams } from '../lib/helper'; -import { MountWithReduxProvider } from '../lib/helper/helper_with_redux'; +import { UptimeUrlParams, getSupportedUrlParams, MountWithReduxProvider } from '../lib/helper'; import { makeBaseBreadcrumb, useBreadcrumbs } from './use_breadcrumbs'; describe('useBreadcrumbs', () => { diff --git a/x-pack/plugins/uptime/public/hooks/use_url_params.test.tsx b/x-pack/plugins/uptime/public/hooks/use_url_params.test.tsx index 31580ec22d48cd..3ce112b1cb835a 100644 --- a/x-pack/plugins/uptime/public/hooks/use_url_params.test.tsx +++ b/x-pack/plugins/uptime/public/hooks/use_url_params.test.tsx @@ -9,8 +9,7 @@ import DateMath from '@elastic/datemath'; import React, { useState, Fragment } from 'react'; import { useUrlParams, UptimeUrlParamsHook } from './use_url_params'; import { UptimeRefreshContext } from '../contexts'; -import { MountWithReduxProvider } from '../lib/helper/helper_with_redux'; -import { mountWithRouter } from '../lib/helper/enzyme_helpers'; +import { mountWithRouter, MountWithReduxProvider } from '../lib'; import { createMemoryHistory } from 'history'; interface MockUrlParamsComponentProps { diff --git a/x-pack/plugins/uptime/public/lib/helper/index.ts b/x-pack/plugins/uptime/public/lib/helper/index.ts index 6546b5f9ae6c45..2fce3cc0e54dc6 100644 --- a/x-pack/plugins/uptime/public/lib/helper/index.ts +++ b/x-pack/plugins/uptime/public/lib/helper/index.ts @@ -10,3 +10,4 @@ export * from './observability_integration'; export { getChartDateLabel } from './charts'; export { seriesHasDownValues } from './series_has_down_values'; export { UptimeUrlParams, getSupportedUrlParams } from './url_params'; +export { MountWithReduxProvider } from './helper_with_redux'; diff --git a/x-pack/plugins/uptime/public/lib/index.ts b/x-pack/plugins/uptime/public/lib/index.ts new file mode 100644 index 00000000000000..9added9af65926 --- /dev/null +++ b/x-pack/plugins/uptime/public/lib/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { MountWithReduxProvider } from './helper'; +export * from './helper/enzyme_helpers'; diff --git a/x-pack/plugins/uptime/public/pages/certificates.test.tsx b/x-pack/plugins/uptime/public/pages/certificates.test.tsx index 1218a1882b3bf8..ff5f1afcaa2902 100644 --- a/x-pack/plugins/uptime/public/pages/certificates.test.tsx +++ b/x-pack/plugins/uptime/public/pages/certificates.test.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { shallowWithRouter } from '../lib/helper/enzyme_helpers'; +import { shallowWithRouter } from '../lib'; import { CertificatesPage } from './certificates'; describe('CertificatesPage', () => { diff --git a/x-pack/plugins/uptime/public/pages/monitor.test.tsx b/x-pack/plugins/uptime/public/pages/monitor.test.tsx index 2664f73d260757..80fcfcc271964d 100644 --- a/x-pack/plugins/uptime/public/pages/monitor.test.tsx +++ b/x-pack/plugins/uptime/public/pages/monitor.test.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { MonitorPage } from './monitor'; -import { shallowWithRouter } from '../lib/helper/enzyme_helpers'; +import { shallowWithRouter } from '../lib'; describe('MonitorPage', () => { it('shallow renders expected elements for valid props', () => { diff --git a/x-pack/plugins/uptime/public/pages/not_found.test.tsx b/x-pack/plugins/uptime/public/pages/not_found.test.tsx index cc9ea1a62cd0f4..8d5b20e45303d6 100644 --- a/x-pack/plugins/uptime/public/pages/not_found.test.tsx +++ b/x-pack/plugins/uptime/public/pages/not_found.test.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { shallowWithRouter } from '../lib/helper/enzyme_helpers'; +import { shallowWithRouter } from '../lib'; import { NotFoundPage } from './not_found'; describe('NotFoundPage', () => { diff --git a/x-pack/plugins/uptime/public/pages/overview.test.tsx b/x-pack/plugins/uptime/public/pages/overview.test.tsx index b4949a84a6e367..cfc140e6b22a31 100644 --- a/x-pack/plugins/uptime/public/pages/overview.test.tsx +++ b/x-pack/plugins/uptime/public/pages/overview.test.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { OverviewPageComponent } from './overview'; -import { shallowWithRouter } from '../lib/helper/enzyme_helpers'; +import { shallowWithRouter } from '../lib'; describe('MonitorPage', () => { const indexPattern = { diff --git a/x-pack/plugins/uptime/tsconfig.json b/x-pack/plugins/uptime/tsconfig.json index 0b982040017537..531ee2ecd8d2b1 100644 --- a/x-pack/plugins/uptime/tsconfig.json +++ b/x-pack/plugins/uptime/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", @@ -12,6 +12,7 @@ "public/**/*", "public/components/monitor/status_details/location_map/embeddables/low_poly_layer.json", "server/**/*", + "server/lib/requests/__fixtures__/monitor_charts_mock.json", "../../../typings/**/*" ], "references": [ diff --git a/x-pack/plugins/watcher/tsconfig.json b/x-pack/plugins/watcher/tsconfig.json index 41bcb015d2d94a..e8dabe8cd40a9c 100644 --- a/x-pack/plugins/watcher/tsconfig.json +++ b/x-pack/plugins/watcher/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", diff --git a/x-pack/plugins/xpack_legacy/tsconfig.json b/x-pack/plugins/xpack_legacy/tsconfig.json index fdac21a3913130..3bfc78b72cb3ef 100644 --- a/x-pack/plugins/xpack_legacy/tsconfig.json +++ b/x-pack/plugins/xpack_legacy/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../../tsconfig.project.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "composite": true, "outDir": "./target/types", From 2eae0969cbfe81ceb42b4d5e1146a2f172062ecd Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Mon, 5 Apr 2021 13:39:15 -0600 Subject: [PATCH 09/26] [file upload] document file upload privileges and provide actionable UI when failures occur (#95883) * [file upload] document file upload privileges and provide actionable UI when failures occur * doc link * call hasImportPermission * docs tweeks * tslint * Update docs/maps/import-geospatial-data.asciidoc Co-authored-by: gchaps <33642766+gchaps@users.noreply.github.com> * Update docs/maps/import-geospatial-data.asciidoc Co-authored-by: gchaps <33642766+gchaps@users.noreply.github.com> * Update docs/maps/import-geospatial-data.asciidoc Co-authored-by: gchaps <33642766+gchaps@users.noreply.github.com> * Update docs/maps/import-geospatial-data.asciidoc Co-authored-by: gchaps <33642766+gchaps@users.noreply.github.com> * review feedback * fix bullet list format * clean-up i18n ids * Update docs/maps/import-geospatial-data.asciidoc Co-authored-by: gchaps <33642766+gchaps@users.noreply.github.com> * documenation review feedback * add period to last privilege bullet item Co-authored-by: gchaps <33642766+gchaps@users.noreply.github.com> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- docs/maps/import-geospatial-data.asciidoc | 24 ++++ .../public/doc_links/doc_links_service.ts | 1 + x-pack/plugins/file_upload/common/types.ts | 5 +- .../components/import_complete_view.tsx | 133 +++++++++++++----- .../components/json_upload_and_parse.tsx | 26 ++++ .../file_upload/public/kibana_services.ts | 1 + .../translations/translations/ja-JP.json | 4 - .../translations/translations/zh-CN.json | 4 - 8 files changed, 154 insertions(+), 44 deletions(-) diff --git a/docs/maps/import-geospatial-data.asciidoc b/docs/maps/import-geospatial-data.asciidoc index fb4250368086e8..0218bac58815a7 100644 --- a/docs/maps/import-geospatial-data.asciidoc +++ b/docs/maps/import-geospatial-data.asciidoc @@ -6,6 +6,30 @@ To import geospatical data into the Elastic Stack, the data must be indexed as { Geospatial data comes in many formats. Choose an import tool based on the format of your geospatial data. +[discrete] +[[import-geospatial-privileges]] +=== Security privileges + +The {stack-security-features} provide roles and privileges that control which users can upload files. +You can manage your roles, privileges, and +spaces in **{stack-manage-app}** in {kib}. For more information, see +{ref}/security-privileges.html[Security privileges], +<>, and <>. + +To upload GeoJSON files in {kib} with *Maps*, you must have: + +* The `all` {kib} privilege for *Maps*. +* The `all` {kib} privilege for *Index Pattern Management*. +* The `create` and `create_index` index privileges for destination indices. +* To use the index in *Maps*, you must also have the `read` and `view_index_metadata` index privileges for destination indices. + +To upload CSV files in {kib} with the *{file-data-viz}*, you must have privileges to upload GeoJSON files and: + +* The `manage_pipeline` cluster privilege. +* The `read` {kib} privilege for *Machine Learning*. +* The `machine_learning_admin` or `machine_learning_user` role. + + [discrete] === Upload CSV with latitude and longitude columns diff --git a/src/core/public/doc_links/doc_links_service.ts b/src/core/public/doc_links/doc_links_service.ts index a946640f58b0d1..b179c998f1126f 100644 --- a/src/core/public/doc_links/doc_links_service.ts +++ b/src/core/public/doc_links/doc_links_service.ts @@ -216,6 +216,7 @@ export class DocLinksService { }, maps: { guide: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/maps.html`, + importGeospatialPrivileges: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/import-geospatial-data.html#import-geospatial-privileges`, }, monitoring: { alertsKibana: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/kibana-alerts.html`, diff --git a/x-pack/plugins/file_upload/common/types.ts b/x-pack/plugins/file_upload/common/types.ts index 0fc59e2b525a8f..11cf4ac3615bfa 100644 --- a/x-pack/plugins/file_upload/common/types.ts +++ b/x-pack/plugins/file_upload/common/types.ts @@ -5,6 +5,7 @@ * 2.0. */ +import type { estypes } from '@elastic/elasticsearch'; import { ES_FIELD_TYPES } from '../../../../src/plugins/data/common'; export interface HasImportPermission { @@ -83,7 +84,9 @@ export interface ImportResponse { pipelineId?: string; docCount: number; failures: ImportFailure[]; - error?: any; + error?: { + error: estypes.ErrorCause; + }; ingestError?: boolean; } diff --git a/x-pack/plugins/file_upload/public/components/import_complete_view.tsx b/x-pack/plugins/file_upload/public/components/import_complete_view.tsx index 29aed0cd52f7e1..a3bc2ed082b1af 100644 --- a/x-pack/plugins/file_upload/public/components/import_complete_view.tsx +++ b/x-pack/plugins/file_upload/public/components/import_complete_view.tsx @@ -7,19 +7,20 @@ import React, { Component, Fragment } from 'react'; import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; import { EuiButtonIcon, EuiCallOut, EuiCopy, EuiFlexGroup, EuiFlexItem, + EuiLink, EuiSpacer, EuiText, EuiTitle, } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; import { CodeEditor, KibanaContextProvider } from '../../../../../src/plugins/kibana_react/public'; -import { getHttp, getUiSettings } from '../kibana_services'; +import { getDocLinks, getHttp, getUiSettings } from '../kibana_services'; import { ImportResults } from '../importer'; const services = { @@ -27,8 +28,10 @@ const services = { }; interface Props { + failedPermissionCheck: boolean; importResults?: ImportResults; indexPatternResp?: object; + indexName: string; } export class ImportCompleteView extends Component { @@ -57,9 +60,12 @@ export class ImportCompleteView extends Component { iconType="copy" color="text" data-test-subj={copyButtonDataTestSubj} - aria-label={i18n.translate('xpack.fileUpload.copyButtonAriaLabel', { - defaultMessage: 'Copy to clipboard', - })} + aria-label={i18n.translate( + 'xpack.fileUpload.importComplete.copyButtonAriaLabel', + { + defaultMessage: 'Copy to clipboard', + } + )} /> )} @@ -90,21 +96,65 @@ export class ImportCompleteView extends Component { } _getStatusMsg() { + if (this.props.failedPermissionCheck) { + return ( + +

+ {i18n.translate('xpack.fileUpload.importComplete.permissionFailureMsg', { + defaultMessage: + 'You do not have permission to create or import data into index "{indexName}".', + values: { indexName: this.props.indexName }, + })} +

+ + {i18n.translate('xpack.fileUpload.importComplete.permission.docLink', { + defaultMessage: 'View file import permissions', + })} + +
+ ); + } + if (!this.props.importResults || !this.props.importResults.success) { - return i18n.translate('xpack.fileUpload.uploadFailureMsg', { - defaultMessage: 'File upload failed.', - }); + const errorMsg = + this.props.importResults && this.props.importResults.error + ? i18n.translate('xpack.fileUpload.importComplete.uploadFailureMsgErrorBlock', { + defaultMessage: 'Error: {reason}', + values: { reason: this.props.importResults.error.error.reason }, + }) + : ''; + return ( + +

{errorMsg}

+
+ ); } - const successMsg = i18n.translate('xpack.fileUpload.uploadSuccessMsg', { - defaultMessage: 'File upload complete: indexed {numFeatures} features.', + const successMsg = i18n.translate('xpack.fileUpload.importComplete.uploadSuccessMsg', { + defaultMessage: 'Indexed {numFeatures} features.', values: { numFeatures: this.props.importResults.docCount, }, }); const failedFeaturesMsg = this.props.importResults.failures?.length - ? i18n.translate('xpack.fileUpload.failedFeaturesMsg', { + ? i18n.translate('xpack.fileUpload.importComplete.failedFeaturesMsg', { defaultMessage: 'Unable to index {numFailures} features.', values: { numFailures: this.props.importResults.failures.length, @@ -112,47 +162,60 @@ export class ImportCompleteView extends Component { }) : ''; - return `${successMsg} ${failedFeaturesMsg}`; + return ( + +

{`${successMsg} ${failedFeaturesMsg}`}

+
+ ); + } + + _renderIndexManagementMsg() { + return this.props.importResults && this.props.importResults.success ? ( + +

+ + + + +

+
+ ) : null; } render() { return ( - -

{this._getStatusMsg()}

-
+ {this._getStatusMsg()} + {this._renderCodeEditor( this.props.importResults, - i18n.translate('xpack.fileUpload.jsonImport.indexingResponse', { + i18n.translate('xpack.fileUpload.importComplete.indexingResponse', { defaultMessage: 'Import response', }), 'indexRespCopyButton' )} {this._renderCodeEditor( this.props.indexPatternResp, - i18n.translate('xpack.fileUpload.jsonImport.indexPatternResponse', { + i18n.translate('xpack.fileUpload.importComplete.indexPatternResponse', { defaultMessage: 'Index pattern response', }), 'indexPatternRespCopyButton' )} - -
- - - - -
-
+ {this._renderIndexManagementMsg()}
); } diff --git a/x-pack/plugins/file_upload/public/components/json_upload_and_parse.tsx b/x-pack/plugins/file_upload/public/components/json_upload_and_parse.tsx index 371d68443bc2c8..d73c6e9c5fb3a4 100644 --- a/x-pack/plugins/file_upload/public/components/json_upload_and_parse.tsx +++ b/x-pack/plugins/file_upload/public/components/json_upload_and_parse.tsx @@ -16,6 +16,7 @@ import { FileUploadComponentProps } from '../lazy_load_bundle'; import { ImportResults } from '../importer'; import { GeoJsonImporter } from '../importer/geojson_importer'; import { Settings } from '../../common'; +import { hasImportPermission } from '../api'; enum PHASE { CONFIGURE = 'CONFIGURE', @@ -31,6 +32,7 @@ function getWritingToIndexMsg(progress: number) { } interface State { + failedPermissionCheck: boolean; geoFieldType: ES_FIELD_TYPES.GEO_POINT | ES_FIELD_TYPES.GEO_SHAPE; importStatus: string; importResults?: ImportResults; @@ -45,6 +47,7 @@ export class JsonUploadAndParse extends Component ); } diff --git a/x-pack/plugins/file_upload/public/kibana_services.ts b/x-pack/plugins/file_upload/public/kibana_services.ts index a604136ca34e49..dfe2785e7a2bcd 100644 --- a/x-pack/plugins/file_upload/public/kibana_services.ts +++ b/x-pack/plugins/file_upload/public/kibana_services.ts @@ -15,6 +15,7 @@ export function setStartServices(core: CoreStart, plugins: FileUploadStartDepend pluginsStart = plugins; } +export const getDocLinks = () => coreStart.docLinks; export const getIndexPatternService = () => pluginsStart.data.indexPatterns; export const getHttp = () => coreStart.http; export const getSavedObjectsClient = () => coreStart.savedObjects.client; diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 6dc490b4ffc530..dc038c1a7959dc 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -8169,10 +8169,6 @@ "xpack.fileUpload.indexSettings.indexNameAlreadyExistsErrorMessage": "インデックス名またはパターンはすでに存在します。", "xpack.fileUpload.indexSettings.indexNameContainsIllegalCharactersErrorMessage": "インデックス名に許可されていない文字が含まれています。", "xpack.fileUpload.indexSettings.indexNameGuidelines": "インデックス名ガイドライン", - "xpack.fileUpload.jsonImport.indexingResponse": "インデックス応答", - "xpack.fileUpload.jsonImport.indexMgmtLink": "インデックス管理", - "xpack.fileUpload.jsonImport.indexModsMsg": "次を使用すると、その他のインデックス修正を行うことができます。\n", - "xpack.fileUpload.jsonImport.indexPatternResponse": "インデックスパターン応答", "xpack.fileUpload.jsonUploadAndParse.dataIndexingError": "データインデックスエラー", "xpack.fileUpload.jsonUploadAndParse.indexPatternError": "インデックスパターンエラー", "xpack.fleet.agentBulkActions.clearSelection": "選択した項目をクリア", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 32574690b13f24..117c33a286d882 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -8242,10 +8242,6 @@ "xpack.fileUpload.indexSettings.indexNameAlreadyExistsErrorMessage": "索引名称或模式已存在。", "xpack.fileUpload.indexSettings.indexNameContainsIllegalCharactersErrorMessage": "索引名称包含非法字符。", "xpack.fileUpload.indexSettings.indexNameGuidelines": "索引名称指引", - "xpack.fileUpload.jsonImport.indexingResponse": "索引响应", - "xpack.fileUpload.jsonImport.indexMgmtLink": "索引管理", - "xpack.fileUpload.jsonImport.indexModsMsg": "要进一步做索引修改,可以使用\n", - "xpack.fileUpload.jsonImport.indexPatternResponse": "索引模式响应", "xpack.fileUpload.jsonUploadAndParse.dataIndexingError": "数据索引错误", "xpack.fileUpload.jsonUploadAndParse.indexPatternError": "索引模式错误", "xpack.fleet.agentBulkActions.agentsSelected": "已选择 {count, plural, other {# 个代理}}", From f9917a6c8a9d8cf41642e696e959e07ca4455f28 Mon Sep 17 00:00:00 2001 From: Clint Andrew Hall Date: Mon, 5 Apr 2021 15:28:15 -0500 Subject: [PATCH 10/26] Add Input Controls project configuration (#96238) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .github/workflows/project-assigner.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/project-assigner.yml b/.github/workflows/project-assigner.yml index d9d2d6d1ddb8b5..37d04abda7530e 100644 --- a/.github/workflows/project-assigner.yml +++ b/.github/workflows/project-assigner.yml @@ -11,7 +11,7 @@ jobs: uses: elastic/github-actions/project-assigner@v2.0.0 id: project_assigner with: - issue-mappings: '[{"label": "Feature:Lens", "projectNumber": 32, "columnName": "Long-term goals"}, {"label": "Feature:Canvas", "projectNumber": 38, "columnName": "Inbox"}, {"label": "Feature:Dashboard", "projectNumber": 68, "columnName": "Inbox"}, {"label": "Feature:Drilldowns", "projectNumber": 68, "columnName": "Inbox"}]' + issue-mappings: '[{"label": "Feature:Lens", "projectNumber": 32, "columnName": "Long-term goals"}, {"label": "Feature:Canvas", "projectNumber": 38, "columnName": "Inbox"}, {"label": "Feature:Dashboard", "projectNumber": 68, "columnName": "Inbox"}, {"label": "Feature:Drilldowns", "projectNumber": 68, "columnName": "Inbox"}], {"label": "Feature:Input Controls", "projectNumber": 72, "columnName": "Inbox"}]' ghToken: ${{ secrets.PROJECT_ASSIGNER_TOKEN }} From 5667435c382a49fa92df0a2acbc27fdb07b49192 Mon Sep 17 00:00:00 2001 From: Clint Andrew Hall Date: Mon, 5 Apr 2021 15:32:29 -0500 Subject: [PATCH 11/26] [tech-debt] Remove defunct opacity parameters from EUI shadow functions (#96191) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../canvas/public/components/page_manager/page_manager.scss | 2 +- .../canvas/public/components/workpad_page/workpad_page.scss | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/canvas/public/components/page_manager/page_manager.scss b/x-pack/plugins/canvas/public/components/page_manager/page_manager.scss index 2ed6884542b189..620e0eb113d361 100644 --- a/x-pack/plugins/canvas/public/components/page_manager/page_manager.scss +++ b/x-pack/plugins/canvas/public/components/page_manager/page_manager.scss @@ -66,7 +66,7 @@ text-decoration: none; .canvasPageManager__pagePreview { - @include euiBottomShadowMedium($opacity: .3); + @include euiBottomShadowMedium; } .canvasPageManager__controls { diff --git a/x-pack/plugins/canvas/public/components/workpad_page/workpad_page.scss b/x-pack/plugins/canvas/public/components/workpad_page/workpad_page.scss index 9266273406b848..e770f10927552c 100644 --- a/x-pack/plugins/canvas/public/components/workpad_page/workpad_page.scss +++ b/x-pack/plugins/canvas/public/components/workpad_page/workpad_page.scss @@ -1,5 +1,5 @@ .canvasPage { - @include euiBottomShadowFlat($opacity: .4); + @include euiBottomShadowFlat; z-index: initial; position: absolute; top: 0; From 56d9f3d96832f67283ee4a35e306f89fa59ad2f4 Mon Sep 17 00:00:00 2001 From: Constance Date: Mon, 5 Apr 2021 13:48:00 -0700 Subject: [PATCH 12/26] [App Search] API logs: Add log detail flyout (#96162) * Set up helper for showing JSON request/response bodies * Set up mock API log obj for tests to use * Add ApiLogLogic file for flyout handling * Add ApiLogFlyout component * Update views to load flyout * Update table to open flyout * Update x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/utils.ts * PR feedback: comments Co-authored-by: Byron Hulcher Co-authored-by: Byron Hulcher Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../api_logs/__mocks__/api_log.mock.ts | 17 +++ .../api_logs/api_log/api_log_flyout.test.tsx | 62 ++++++++ .../api_logs/api_log/api_log_flyout.tsx | 137 ++++++++++++++++++ .../api_logs/api_log/api_log_logic.test.tsx | 57 ++++++++ .../api_logs/api_log/api_log_logic.ts | 44 ++++++ .../components/api_logs/api_log/index.ts | 9 ++ .../components/api_logs/api_logs.tsx | 2 + .../api_logs/api_logs_logic.test.ts | 13 +- .../components/api_logs_table.test.tsx | 3 +- .../api_logs/components/api_logs_table.tsx | 4 +- .../app_search/components/api_logs/index.ts | 1 + .../components/api_logs/utils.test.ts | 21 ++- .../app_search/components/api_logs/utils.ts | 10 ++ .../components/recent_api_logs.tsx | 3 +- 14 files changed, 368 insertions(+), 15 deletions(-) create mode 100644 x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/__mocks__/api_log.mock.ts create mode 100644 x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_log/api_log_flyout.test.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_log/api_log_flyout.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_log/api_log_logic.test.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_log/api_log_logic.ts create mode 100644 x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_log/index.ts diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/__mocks__/api_log.mock.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/__mocks__/api_log.mock.ts new file mode 100644 index 00000000000000..6106cb049c7a1c --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/__mocks__/api_log.mock.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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const mockApiLog = { + timestamp: '1970-01-01T12:00:00.000Z', + http_method: 'POST', + status: 200, + user_agent: 'Mozilla/5.0', + full_request_path: '/api/as/v1/engines/national-parks-demo/search.json', + request_body: '{"query":"test search"}', + response_body: + '{"meta":{"page":{"current":1,"total_pages":0,"total_results":0,"size":20}},"results":[]}', +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_log/api_log_flyout.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_log/api_log_flyout.test.tsx new file mode 100644 index 00000000000000..6bebeee80465c8 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_log/api_log_flyout.test.tsx @@ -0,0 +1,62 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { setMockValues, setMockActions } from '../../../../__mocks__'; +import { mockApiLog } from '../__mocks__/api_log.mock'; + +import React from 'react'; + +import { shallow } from 'enzyme'; + +import { EuiFlyout, EuiBadge } from '@elastic/eui'; + +import { ApiLogFlyout, ApiLogHeading } from './api_log_flyout'; + +describe('ApiLogFlyout', () => { + const values = { + isFlyoutOpen: true, + apiLog: mockApiLog, + }; + const actions = { + closeFlyout: jest.fn(), + }; + + beforeEach(() => { + jest.clearAllMocks(); + setMockValues(values); + setMockActions(actions); + }); + + it('renders', () => { + const wrapper = shallow(); + + expect(wrapper.find('h2').text()).toEqual('Request details'); + expect(wrapper.find(ApiLogHeading).last().dive().find('h3').text()).toEqual('Response body'); + expect(wrapper.find(EuiBadge).prop('children')).toEqual('POST'); + }); + + it('closes the flyout', () => { + const wrapper = shallow(); + + wrapper.find(EuiFlyout).simulate('close'); + expect(actions.closeFlyout).toHaveBeenCalled(); + }); + + it('does not render if the flyout is not open', () => { + setMockValues({ ...values, isFlyoutOpen: false }); + const wrapper = shallow(); + + expect(wrapper.isEmptyRender()).toBe(true); + }); + + it('does not render if a current apiLog has not been set', () => { + setMockValues({ ...values, apiLog: null }); + const wrapper = shallow(); + + expect(wrapper.isEmptyRender()).toBe(true); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_log/api_log_flyout.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_log/api_log_flyout.tsx new file mode 100644 index 00000000000000..dd53e997da0f7d --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_log/api_log_flyout.tsx @@ -0,0 +1,137 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { useActions, useValues } from 'kea'; + +import { + EuiPortal, + EuiFlyout, + EuiFlyoutHeader, + EuiTitle, + EuiFlyoutBody, + EuiFlexGroup, + EuiFlexItem, + EuiSpacer, + EuiBadge, + EuiHealth, + EuiText, + EuiCode, + EuiCodeBlock, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +import { getStatusColor, attemptToFormatJson } from '../utils'; + +import { ApiLogLogic } from './'; + +export const ApiLogFlyout: React.FC = () => { + const { isFlyoutOpen, apiLog } = useValues(ApiLogLogic); + const { closeFlyout } = useActions(ApiLogLogic); + + if (!isFlyoutOpen) return null; + if (!apiLog) return null; + + return ( + + + + +

+ {i18n.translate('xpack.enterpriseSearch.appSearch.engine.apiLogs.flyout.title', { + defaultMessage: 'Request details', + })} +

+
+
+ + + + + {i18n.translate('xpack.enterpriseSearch.appSearch.engine.apiLogs.methodTitle', { + defaultMessage: 'Method', + })} + +
+ {apiLog.http_method} +
+
+ + + {i18n.translate('xpack.enterpriseSearch.appSearch.engine.apiLogs.statusTitle', { + defaultMessage: 'Status', + })} + + {apiLog.status} + + + + {i18n.translate('xpack.enterpriseSearch.appSearch.engine.apiLogs.timestampTitle', { + defaultMessage: 'Timestamp', + })} + + {apiLog.timestamp} + +
+ + + + {i18n.translate('xpack.enterpriseSearch.appSearch.engine.apiLogs.userAgentTitle', { + defaultMessage: 'User agent', + })} + + + {apiLog.user_agent} + + + + + {i18n.translate('xpack.enterpriseSearch.appSearch.engine.apiLogs.requestPathTitle', { + defaultMessage: 'Request path', + })} + + + {apiLog.full_request_path} + + + + + {i18n.translate('xpack.enterpriseSearch.appSearch.engine.apiLogs.requestBodyTitle', { + defaultMessage: 'Request body', + })} + + + {attemptToFormatJson(apiLog.request_body)} + + + + + {i18n.translate('xpack.enterpriseSearch.appSearch.engine.apiLogs.responseBodyTitle', { + defaultMessage: 'Response body', + })} + + + {attemptToFormatJson(apiLog.response_body)} + +
+
+
+ ); +}; + +export const ApiLogHeading: React.FC = ({ children }) => ( + +

{children}

+
+); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_log/api_log_logic.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_log/api_log_logic.test.tsx new file mode 100644 index 00000000000000..2b7ca7510e8e14 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_log/api_log_logic.test.tsx @@ -0,0 +1,57 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { LogicMounter } from '../../../../__mocks__'; +import { mockApiLog } from '../__mocks__/api_log.mock'; + +import { ApiLogLogic } from './'; + +describe('ApiLogLogic', () => { + const { mount } = new LogicMounter(ApiLogLogic); + + const DEFAULT_VALUES = { + isFlyoutOpen: false, + apiLog: null, + }; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('has expected default values', () => { + mount(); + expect(ApiLogLogic.values).toEqual(DEFAULT_VALUES); + }); + + describe('actions', () => { + describe('openFlyout', () => { + it('sets isFlyoutOpen to true & sets the current apiLog', () => { + mount({ isFlyoutOpen: false, apiLog: null }); + ApiLogLogic.actions.openFlyout(mockApiLog); + + expect(ApiLogLogic.values).toEqual({ + ...DEFAULT_VALUES, + isFlyoutOpen: true, + apiLog: mockApiLog, + }); + }); + }); + + describe('closeFlyout', () => { + it('sets isFlyoutOpen to false & resets the current apiLog', () => { + mount({ isFlyoutOpen: true, apiLog: mockApiLog }); + ApiLogLogic.actions.closeFlyout(); + + expect(ApiLogLogic.values).toEqual({ + ...DEFAULT_VALUES, + isFlyoutOpen: false, + apiLog: null, + }); + }); + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_log/api_log_logic.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_log/api_log_logic.ts new file mode 100644 index 00000000000000..8b7c5f70f605c3 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_log/api_log_logic.ts @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { kea, MakeLogicType } from 'kea'; + +import { ApiLog } from '../types'; + +interface ApiLogValues { + isFlyoutOpen: boolean; + apiLog: ApiLog | null; +} + +interface ApiLogActions { + openFlyout(apiLog: ApiLog): { apiLog: ApiLog }; + closeFlyout(): void; +} + +export const ApiLogLogic = kea>({ + path: ['enterprise_search', 'app_search', 'api_log_logic'], + actions: () => ({ + openFlyout: (apiLog) => ({ apiLog }), + closeFlyout: true, + }), + reducers: () => ({ + isFlyoutOpen: [ + false, + { + openFlyout: () => true, + closeFlyout: () => false, + }, + ], + apiLog: [ + null, + { + openFlyout: (_, { apiLog }) => apiLog, + closeFlyout: () => null, + }, + ], + }), +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_log/index.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_log/index.ts new file mode 100644 index 00000000000000..dcf949d9bf222f --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_log/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { ApiLogFlyout } from './api_log_flyout'; +export { ApiLogLogic } from './api_log_logic'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_logs.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_logs.tsx index 8ca15906783f93..4690911fad7724 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_logs.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_logs.tsx @@ -26,6 +26,7 @@ import { Loading } from '../../../shared/loading'; import { LogRetentionCallout, LogRetentionTooltip, LogRetentionOptions } from '../log_retention'; +import { ApiLogFlyout } from './api_log'; import { ApiLogsTable, NewApiEventsPrompt } from './components'; import { API_LOGS_TITLE, RECENT_API_EVENTS } from './constants'; @@ -75,6 +76,7 @@ export const ApiLogs: React.FC = ({ engineBreadcrumb }) => { + diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_logs_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_logs_logic.test.ts index 7b3ee80668ac7a..2eda4c6323fa5c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_logs_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_logs_logic.test.ts @@ -6,6 +6,7 @@ */ import { LogicMounter, mockHttpValues, mockFlashMessageHelpers } from '../../../__mocks__'; +import { mockApiLog } from './__mocks__/api_log.mock'; import '../../__mocks__/engine_logic.mock'; import { nextTick } from '@kbn/test/jest'; @@ -29,17 +30,7 @@ describe('ApiLogsLogic', () => { }; const MOCK_API_RESPONSE = { - results: [ - { - timestamp: '1970-01-01T12:00:00.000Z', - http_method: 'POST', - status: 200, - user_agent: 'some browser agent string', - full_request_path: '/api/as/v1/engines/national-parks-demo/search.json', - request_body: '{"someMockRequest":"hello"}', - response_body: '{"someMockResponse":"world"}', - }, - ], + results: [mockApiLog, mockApiLog], meta: { page: { current: 1, diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/components/api_logs_table.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/components/api_logs_table.test.tsx index 99fce81ca348f9..768295ec1389c6 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/components/api_logs_table.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/components/api_logs_table.test.tsx @@ -53,6 +53,7 @@ describe('ApiLogsTable', () => { }; const actions = { onPaginate: jest.fn(), + openFlyout: jest.fn(), }; beforeEach(() => { @@ -86,7 +87,7 @@ describe('ApiLogsTable', () => { expect(wrapper.find(EuiButtonEmpty)).toHaveLength(3); wrapper.find('[data-test-subj="ApiLogsTableDetailsButton"]').first().simulate('click'); - // TODO: API log details flyout + expect(actions.openFlyout).toHaveBeenCalled(); }); it('renders an empty prompt if no items are passed', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/components/api_logs_table.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/components/api_logs_table.tsx index 8ebcc4350f7fc7..5ecf8e1ba33307 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/components/api_logs_table.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/components/api_logs_table.tsx @@ -22,6 +22,7 @@ import { FormattedRelative } from '@kbn/i18n/react'; import { convertMetaToPagination, handlePageChange } from '../../../../shared/table_pagination'; +import { ApiLogLogic } from '../api_log'; import { ApiLogsLogic } from '../index'; import { ApiLog } from '../types'; import { getStatusColor } from '../utils'; @@ -34,6 +35,7 @@ interface Props { export const ApiLogsTable: React.FC = ({ hasPagination }) => { const { dataLoading, apiLogs, meta } = useValues(ApiLogsLogic); const { onPaginate } = useActions(ApiLogsLogic); + const { openFlyout } = useActions(ApiLogLogic); const columns: Array> = [ { @@ -81,7 +83,7 @@ export const ApiLogsTable: React.FC = ({ hasPagination }) => { size="s" className="apiLogDetailButton" data-test-subj="ApiLogsTableDetailsButton" - // TODO: flyout onclick + onClick={() => openFlyout(apiLog)} > {i18n.translate('xpack.enterpriseSearch.appSearch.engine.apiLogs.detailsButtonLabel', { defaultMessage: 'Details', diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/index.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/index.ts index 183956e51d8d4c..568026dab231fd 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/index.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/index.ts @@ -7,5 +7,6 @@ export { API_LOGS_TITLE } from './constants'; export { ApiLogsTable, NewApiEventsPrompt } from './components'; +export { ApiLogFlyout } from './api_log'; export { ApiLogs } from './api_logs'; export { ApiLogsLogic } from './api_logs_logic'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/utils.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/utils.test.ts index f9b6dcea2cbf37..ac464e2af353d4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/utils.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/utils.test.ts @@ -5,7 +5,9 @@ * 2.0. */ -import { getDateString, getStatusColor } from './utils'; +import dedent from 'dedent'; + +import { getDateString, getStatusColor, attemptToFormatJson } from './utils'; describe('getDateString', () => { const mockDate = jest @@ -32,3 +34,20 @@ describe('getStatusColor', () => { expect(getStatusColor(503)).toEqual('danger'); }); }); + +describe('attemptToFormatJson', () => { + it('takes an unformatted JSON string and correctly newlines/indents it', () => { + expect(attemptToFormatJson('{"hello":"world","lorem":{"ipsum":"dolor","sit":"amet"}}')) + .toEqual(dedent`{ + "hello": "world", + "lorem": { + "ipsum": "dolor", + "sit": "amet" + } + }`); + }); + + it('returns the original content if it is not properly formatted JSON', () => { + expect(attemptToFormatJson('{invalid json}')).toEqual('{invalid json}'); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/utils.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/utils.ts index 3217a1561ce767..7e5f19686f13bd 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/utils.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/utils.ts @@ -19,3 +19,13 @@ export const getStatusColor = (status: number) => { if (status >= 500) color = 'danger'; return color; }; + +export const attemptToFormatJson = (possibleJson: string) => { + try { + // it is JSON, we can format it with newlines/indentation + return JSON.stringify(JSON.parse(possibleJson), null, 2); + } catch { + // if it's not JSON, we return the original content + return possibleJson; + } +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/recent_api_logs.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/recent_api_logs.tsx index 3686f380407e21..18f27c3a1e8345 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/recent_api_logs.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/recent_api_logs.tsx @@ -13,7 +13,7 @@ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { EuiButtonEmptyTo } from '../../../../shared/react_router_helpers'; import { ENGINE_API_LOGS_PATH } from '../../../routes'; -import { ApiLogsLogic, ApiLogsTable, NewApiEventsPrompt } from '../../api_logs'; +import { ApiLogsLogic, ApiLogsTable, NewApiEventsPrompt, ApiLogFlyout } from '../../api_logs'; import { RECENT_API_EVENTS } from '../../api_logs/constants'; import { DataPanel } from '../../data_panel'; import { generateEnginePath } from '../../engine'; @@ -46,6 +46,7 @@ export const RecentApiLogs: React.FC = () => { hasBorder > + ); }; From 7da1b82b7ee07d94bee2dc2540a7161731e4c513 Mon Sep 17 00:00:00 2001 From: Rashmi Kulkarni Date: Mon, 5 Apr 2021 15:24:22 -0700 Subject: [PATCH 13/26] fixes a skipped management x-pack test (#96178) * fixes a skipped management x-pack test * modified the test to incoroporate the review comments Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../management/users/edit_user/user_form.tsx | 5 ++++ .../functional/apps/security/management.js | 29 ++++++++++--------- .../functional/page_objects/security_page.ts | 5 ++++ 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/x-pack/plugins/security/public/management/users/edit_user/user_form.tsx b/x-pack/plugins/security/public/management/users/edit_user/user_form.tsx index 8433f54a733437..29d87e31797cc9 100644 --- a/x-pack/plugins/security/public/management/users/edit_user/user_form.tsx +++ b/x-pack/plugins/security/public/management/users/edit_user/user_form.tsx @@ -262,6 +262,7 @@ export const UserForm: FunctionComponent = ({ > = ({ > = ({ > = ({ > = ({ > { - // await PageObjects.security.login('elastic', 'changeme'); await PageObjects.security.initTests(); await kibanaServer.uiSettings.update({ defaultIndex: 'logstash-*', @@ -43,20 +44,26 @@ export default function ({ getService, getPageObjects }) { await PageObjects.settings.navigateTo(); }); + after(async () => { + await security.role.delete('logstash-readonly'); + await security.user.delete('dashuser', 'new-user'); + await PageObjects.security.forceLogout(); + }); + describe('Security', () => { describe('navigation', () => { it('Can navigate to create user section', async () => { await PageObjects.security.clickElasticsearchUsers(); await PageObjects.security.clickCreateNewUser(); const currentUrl = await browser.getCurrentUrl(); - expect(currentUrl).to.contain(EDIT_USERS_PATH); + expect(currentUrl).to.contain(CREATE_USERS_PATH); }); it('Clicking cancel in create user section brings user back to listing', async () => { await PageObjects.security.clickCancelEditUser(); const currentUrl = await browser.getCurrentUrl(); expect(currentUrl).to.contain(USERS_PATH); - expect(currentUrl).to.not.contain(EDIT_USERS_PATH); + expect(currentUrl).to.not.contain(CREATE_USERS_PATH); }); it('Clicking save in create user section brings user back to listing', async () => { @@ -67,12 +74,11 @@ export default function ({ getService, getPageObjects }) { await testSubjects.setValue('passwordConfirmationInput', '123456'); await testSubjects.setValue('userFormFullNameInput', 'Full User Name'); await testSubjects.setValue('userFormEmailInput', 'example@example.com'); - - await PageObjects.security.clickSaveEditUser(); + await PageObjects.security.clickSaveCreateUser(); const currentUrl = await browser.getCurrentUrl(); expect(currentUrl).to.contain(USERS_PATH); - expect(currentUrl).to.not.contain(EDIT_USERS_PATH); + expect(currentUrl).to.not.contain(CREATE_USERS_PATH); }); it('Can navigate to edit user section', async () => { @@ -143,14 +149,11 @@ export default function ({ getService, getPageObjects }) { await testSubjects.setValue('passwordConfirmationInput', '123456'); await testSubjects.setValue('userFormFullNameInput', 'dashuser'); await testSubjects.setValue('userFormEmailInput', 'example@example.com'); - await PageObjects.security.assignRoleToUser('kibana_dashboard_only_user'); await PageObjects.security.assignRoleToUser('logstash-readonly'); - - await PageObjects.security.clickSaveEditUser(); - + await PageObjects.security.clickSaveCreateUser(); await PageObjects.settings.navigateTo(); await testSubjects.click('users'); - await PageObjects.settings.clickLinkText('kibana_dashboard_only_user'); + await find.clickByButtonText('logstash-readonly'); const currentUrl = await browser.getCurrentUrl(); expect(currentUrl).to.contain(EDIT_ROLES_PATH); }); diff --git a/x-pack/test/functional/page_objects/security_page.ts b/x-pack/test/functional/page_objects/security_page.ts index f153050018609c..97a5c517db794b 100644 --- a/x-pack/test/functional/page_objects/security_page.ts +++ b/x-pack/test/functional/page_objects/security_page.ts @@ -290,6 +290,11 @@ export function SecurityPageProvider({ getService, getPageObjects }: FtrProvider await PageObjects.header.waitUntilLoadingHasFinished(); } + async clickSaveCreateUser() { + await find.clickByButtonText('Create user'); + await PageObjects.header.waitUntilLoadingHasFinished(); + } + async clickSaveEditRole() { const saveButton = await retry.try(() => testSubjects.find('roleFormSaveButton')); await saveButton.moveMouseTo(); From d4b0f92c84ea44c2de3e95385f666ca4c9feb61f Mon Sep 17 00:00:00 2001 From: Nick Partridge Date: Mon, 5 Apr 2021 18:02:13 -0500 Subject: [PATCH 14/26] [Dashboard] Fix Lens and TSVB chart tooltip positioning relative to global headers (#94247) --- src/core/public/rendering/_base.scss | 14 ++++++++++++++ src/core/public/rendering/rendering_service.tsx | 1 + .../visualizations/views/timeseries/index.js | 1 + .../vis_type_xy/public/components/xy_settings.tsx | 4 +++- .../public/pie_visualization/render_function.tsx | 2 ++ .../__snapshots__/expression.test.tsx.snap | 7 +++++++ .../lens/public/xy_visualization/expression.tsx | 2 +- 7 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/core/public/rendering/_base.scss b/src/core/public/rendering/_base.scss index de13785a17f5b9..ed2d9bc0b3917e 100644 --- a/src/core/public/rendering/_base.scss +++ b/src/core/public/rendering/_base.scss @@ -11,6 +11,16 @@ min-height: 100%; } +#app-fixed-viewport { + pointer-events: none; + visibility: hidden; + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; +} + .app-wrapper { display: flex; flex-flow: column nowrap; @@ -35,6 +45,10 @@ @mixin kbnAffordForHeader($headerHeight) { padding-top: $headerHeight; + #app-fixed-viewport { + top: $headerHeight; + } + .euiFlyout, .euiCollapsibleNav { top: $headerHeight; diff --git a/src/core/public/rendering/rendering_service.tsx b/src/core/public/rendering/rendering_service.tsx index 843f2a253f33ec..787fa475c7d5f8 100644 --- a/src/core/public/rendering/rendering_service.tsx +++ b/src/core/public/rendering/rendering_service.tsx @@ -52,6 +52,7 @@ export class RenderingService { {chromeHeader}
+
{bannerComponent}
{appComponent}
diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/index.js b/src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/index.js index a90faea50f22a9..2911a9ee5d6e93 100644 --- a/src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/index.js +++ b/src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/index.js @@ -149,6 +149,7 @@ export const TimeSeries = ({ tooltip={{ snap: true, type: tooltipMode === 'show_focused' ? TooltipType.Follow : TooltipType.VerticalCursor, + boundary: document.getElementById('app-fixed-viewport') ?? undefined, headerFormatter: tooltipFormatter, }} externalPointerEvents={{ tooltip: { visible: false } }} diff --git a/src/plugins/vis_type_xy/public/components/xy_settings.tsx b/src/plugins/vis_type_xy/public/components/xy_settings.tsx index 59bed0060a6a6f..8922f512522a04 100644 --- a/src/plugins/vis_type_xy/public/components/xy_settings.tsx +++ b/src/plugins/vis_type_xy/public/components/xy_settings.tsx @@ -148,13 +148,15 @@ export const XYSettings: FC = ({ : headerValueFormatter && (tooltip.detailedTooltip ? undefined : ({ value }: any) => headerValueFormatter(value)); + const boundary = document.getElementById('app-fixed-viewport') ?? undefined; const tooltipProps: TooltipProps = tooltip.detailedTooltip ? { ...tooltip, + boundary, customTooltip: tooltip.detailedTooltip(headerFormatter), headerFormatter: undefined, } - : { ...tooltip, headerFormatter }; + : { ...tooltip, boundary, headerFormatter }; return (