diff --git a/.ci/Jenkinsfile_coverage b/.ci/Jenkinsfile_coverage index f2a58e7b6a7ac..c474998e6fd3d 100644 --- a/.ci/Jenkinsfile_coverage +++ b/.ci/Jenkinsfile_coverage @@ -3,7 +3,7 @@ library 'kibana-pipeline-library' kibanaLibrary.load() // load from the Jenkins instance -kibanaPipeline(timeoutMinutes: 180) { +kibanaPipeline(timeoutMinutes: 240) { catchErrors { withEnv([ 'CODE_COVERAGE=1', // Needed for multiple ci scripts, such as remote.ts, test/scripts/*.sh, schema.js, etc. diff --git a/.eslintignore b/.eslintignore index 2eaa498f86e5a..2ed9ecf971ff3 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,45 +1,48 @@ -node_modules -bower_components -/data -/optimize -/build -/target +**/*.js.snap +**/graphql/types.ts /.es -/plugins +/build /built_assets +/data /html_docs -/src/plugins/data/common/es_query/kuery/ast/_generated_/** -/src/plugins/vis_type_timelion/public/_generated_/** -/src/legacy/ui/public/flot-charts +/optimize +/plugins /test/fixtures/scenarios -/src/legacy/core_plugins/console/public/webpackShims +/x-pack/build +node_modules +target + +!/.eslintrc.js + +# plugin overrides +/src/core/lib/kbn_internal_native_observable /src/legacy/core_plugins/console/public/tests/webpackShims +/src/legacy/core_plugins/console/public/webpackShims +/src/legacy/plugin_discovery/plugin_pack/__tests__/fixtures/plugins/broken +/src/legacy/ui/public/flot-charts /src/legacy/ui/public/utils/decode_geo_hash.js +/src/plugins/data/common/es_query/kuery/ast/_generated_/** +/src/plugins/vis_type_timelion/public/_generated_/** /src/plugins/vis_type_timelion/public/webpackShims/jquery.flot.* -/src/core/lib/kbn_internal_native_observable -/packages/*/target -/packages/eslint-config-kibana -/packages/kbn-pm/dist -/packages/kbn-plugin-generator/sao_template/template -/packages/kbn-ui-framework/dist -/packages/kbn-ui-framework/doc_site/build -/packages/kbn-ui-framework/generator-kui/*/templates/ -/packages/kbn-test/src/functional_test_runner/__tests__/fixtures/ -/packages/kbn-test/src/functional_test_runner/lib/config/__tests__/fixtures/ -/x-pack/legacy/plugins/maps/public/vendor/** -/x-pack/coverage -/x-pack/build /x-pack/legacy/plugins/**/__tests__/fixtures/** -/packages/kbn-interpreter/src/common/lib/grammar.js +/x-pack/legacy/plugins/apm/e2e/cypress/**/snapshots.js /x-pack/legacy/plugins/canvas/canvas_plugin +/x-pack/legacy/plugins/canvas/canvas_plugin_src/lib/flot-charts /x-pack/legacy/plugins/canvas/shareable_runtime/build /x-pack/legacy/plugins/canvas/storybook -/x-pack/legacy/plugins/canvas/canvas_plugin_src/lib/flot-charts /x-pack/legacy/plugins/infra/common/graphql/types.ts /x-pack/legacy/plugins/infra/public/graphql/types.ts /x-pack/legacy/plugins/infra/server/graphql/types.ts -/x-pack/legacy/plugins/apm/e2e/cypress/**/snapshots.js -/src/legacy/plugin_discovery/plugin_pack/__tests__/fixtures/plugins/broken -**/graphql/types.ts -**/*.js.snap -!/.eslintrc.js +/x-pack/legacy/plugins/maps/public/vendor/** + +# package overrides +/packages/eslint-config-kibana +/packages/kbn-interpreter/src/common/lib/grammar.js +/packages/kbn-plugin-generator/sao_template/template +/packages/kbn-pm/dist +/packages/kbn-test/src/functional_test_runner/__tests__/fixtures/ +/packages/kbn-test/src/functional_test_runner/lib/config/__tests__/fixtures/ +/packages/kbn-ui-framework/dist +/packages/kbn-ui-framework/doc_site/build +/packages/kbn-ui-framework/generator-kui/*/templates/ + diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 7d1122682be7b..a97400ee09c0e 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -84,7 +84,6 @@ /x-pack/legacy/plugins/ingest_manager/ @elastic/ingest-management /x-pack/plugins/observability/ @elastic/logs-metrics-ui @elastic/apm-ui @elastic/uptime @elastic/ingest-management /x-pack/legacy/plugins/monitoring/ @elastic/stack-monitoring-ui -/x-pack/legacy/plugins/uptime @elastic/uptime /x-pack/plugins/uptime @elastic/uptime # Machine Learning @@ -167,8 +166,6 @@ /x-pack/plugins/telemetry_collection_xpack/ @elastic/pulse # Kibana Alerting Services -/x-pack/legacy/plugins/alerting/ @elastic/kibana-alerting-services -/x-pack/legacy/plugins/actions/ @elastic/kibana-alerting-services /x-pack/plugins/alerting/ @elastic/kibana-alerting-services /x-pack/plugins/actions/ @elastic/kibana-alerting-services /x-pack/plugins/event_log/ @elastic/kibana-alerting-services @@ -176,7 +173,6 @@ /x-pack/test/alerting_api_integration/ @elastic/kibana-alerting-services /x-pack/test/plugin_api_integration/plugins/task_manager/ @elastic/kibana-alerting-services /x-pack/test/plugin_api_integration/test_suites/task_manager/ @elastic/kibana-alerting-services -/x-pack/legacy/plugins/triggers_actions_ui/ @elastic/kibana-alerting-services /x-pack/plugins/triggers_actions_ui/ @elastic/kibana-alerting-services /x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/ @elastic/kibana-alerting-services /x-pack/test/functional_with_es_ssl/fixtures/plugins/alerts/ @elastic/kibana-alerting-services @@ -209,22 +205,21 @@ /x-pack/plugins/watcher/ @elastic/es-ui # Endpoint -/x-pack/plugins/endpoint/ @elastic/endpoint-app-team -/x-pack/test/api_integration/apis/endpoint/ @elastic/endpoint-app-team -/x-pack/test/endpoint_api_integration_no_ingest/ @elastic/endpoint-app-team -/x-pack/test/functional_endpoint/ @elastic/endpoint-app-team -/x-pack/test/functional_endpoint_ingest_failure/ @elastic/endpoint-app-team -/x-pack/test/functional/es_archives/endpoint/ @elastic/endpoint-app-team -/x-pack/test/plugin_functional/plugins/resolver_test/ @elastic/endpoint-app-team -/x-pack/test/plugin_functional/test_suites/resolver/ @elastic/endpoint-app-team +/x-pack/plugins/endpoint/ @elastic/endpoint-app-team @elastic/siem +/x-pack/test/api_integration/apis/endpoint/ @elastic/endpoint-app-team @elastic/siem +/x-pack/test/endpoint_api_integration_no_ingest/ @elastic/endpoint-app-team @elastic/siem +/x-pack/test/functional_endpoint/ @elastic/endpoint-app-team @elastic/siem +/x-pack/test/functional_endpoint_ingest_failure/ @elastic/endpoint-app-team @elastic/siem +/x-pack/test/functional/es_archives/endpoint/ @elastic/endpoint-app-team @elastic/siem +/x-pack/test/plugin_functional/plugins/resolver_test/ @elastic/endpoint-app-team @elastic/siem +/x-pack/test/plugin_functional/test_suites/resolver/ @elastic/endpoint-app-team @elastic/siem # SIEM -/x-pack/legacy/plugins/siem/ @elastic/siem -/x-pack/plugins/siem/ @elastic/siem -/x-pack/test/detection_engine_api_integration @elastic/siem -/x-pack/test/api_integration/apis/siem @elastic/siem -/x-pack/plugins/case @elastic/siem -/x-pack/plugins/lists @elastic/siem +/x-pack/plugins/siem/ @elastic/siem @elastic/endpoint-app-team +/x-pack/test/detection_engine_api_integration @elastic/siem @elastic/endpoint-app-team +/x-pack/test/api_integration/apis/siem @elastic/siem @elastic/endpoint-app-team +/x-pack/plugins/case @elastic/siem @elastic/endpoint-app-team +/x-pack/plugins/lists @elastic/siem @elastic/endpoint-app-team # Security Intelligence And Analytics /x-pack/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules @elastic/security-intelligence-analytics diff --git a/packages/kbn-optimizer/src/worker/webpack.config.ts b/packages/kbn-optimizer/src/worker/webpack.config.ts index 7411e2df1b613..cc3fa8c2720de 100644 --- a/packages/kbn-optimizer/src/worker/webpack.config.ts +++ b/packages/kbn-optimizer/src/worker/webpack.config.ts @@ -37,7 +37,7 @@ const ISTANBUL_PRESET_PATH = require.resolve('@kbn/babel-preset/istanbul_preset' const BABEL_PRESET_PATH = require.resolve('@kbn/babel-preset/webpack_preset'); const STATIC_BUNDLE_PLUGINS = [ - // { id: 'data', dirname: 'data' }, + { id: 'data', dirname: 'data' }, { id: 'kibanaReact', dirname: 'kibana_react' }, { id: 'kibanaUtils', dirname: 'kibana_utils' }, { id: 'esUiShared', dirname: 'es_ui_shared' }, @@ -60,13 +60,8 @@ function dynamicExternals(bundle: Bundle, context: string, request: string) { return; } - // don't allow any static bundle to rely on other static bundles - if (STATIC_BUNDLE_PLUGINS.some(p => bundle.id === p.id)) { - return; - } - - // ignore requests that don't include a /data/public, /kibana_react/public, or - // /kibana_utils/public segment as a cheap way to avoid doing path resolution + // ignore requests that don't include a /{dirname}/public for one of our + // "static" bundles as a cheap way to avoid doing path resolution // for paths that couldn't possibly resolve to what we're looking for const reqToStaticBundle = STATIC_BUNDLE_PLUGINS.some(p => request.includes(`/${p.dirname}/public`) diff --git a/renovate.json5 b/renovate.json5 index ffa006264873d..c0ddcaf4f23c8 100644 --- a/renovate.json5 +++ b/renovate.json5 @@ -846,6 +846,14 @@ '@types/semver', ], }, + { + groupSlug: 'set-value', + groupName: 'set-value related packages', + packageNames: [ + 'set-value', + '@types/set-value', + ], + }, { groupSlug: 'sinon', groupName: 'sinon related packages', diff --git a/src/core/public/plugins/plugin.test.mocks.ts b/src/core/public/plugins/plugin.test.mocks.ts index b877847aaa90e..422442c9ca4d2 100644 --- a/src/core/public/plugins/plugin.test.mocks.ts +++ b/src/core/public/plugins/plugin.test.mocks.ts @@ -24,8 +24,8 @@ export const mockPlugin = { }; export const mockInitializer = jest.fn(() => mockPlugin); -export const mockPluginLoader = jest.fn().mockResolvedValue(mockInitializer); +export const mockPluginReader = jest.fn(() => mockInitializer); -jest.mock('./plugin_loader', () => ({ - loadPluginBundle: mockPluginLoader, +jest.mock('./plugin_reader', () => ({ + read: mockPluginReader, })); diff --git a/src/core/public/plugins/plugin.test.ts b/src/core/public/plugins/plugin.test.ts index 39330711f7980..8fe745db9554d 100644 --- a/src/core/public/plugins/plugin.test.ts +++ b/src/core/public/plugins/plugin.test.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import { mockInitializer, mockPlugin, mockPluginLoader } from './plugin.test.mocks'; +import { mockInitializer, mockPlugin, mockPluginReader } from './plugin.test.mocks'; import { DiscoveredPlugin } from '../../server'; import { coreMock } from '../mocks'; @@ -38,10 +38,9 @@ function createManifest( let plugin: PluginWrapper>; const opaqueId = Symbol(); const initializerContext = coreMock.createPluginInitializerContext(); -const addBasePath = (path: string) => path; beforeEach(() => { - mockPluginLoader.mockClear(); + mockPluginReader.mockClear(); mockPlugin.setup.mockClear(); mockPlugin.start.mockClear(); mockPlugin.stop.mockClear(); @@ -49,20 +48,8 @@ beforeEach(() => { }); describe('PluginWrapper', () => { - test('`load` calls loadPluginBundle', () => { - plugin.load(addBasePath); - expect(mockPluginLoader).toHaveBeenCalledWith(addBasePath, 'plugin-a'); - }); - - test('`setup` fails if load is not called first', async () => { - await expect(plugin.setup({} as any, {} as any)).rejects.toThrowErrorMatchingInlineSnapshot( - `"Plugin \\"plugin-a\\" can't be setup since its bundle isn't loaded."` - ); - }); - test('`setup` fails if plugin.setup is not a function', async () => { mockInitializer.mockReturnValueOnce({ start: jest.fn() } as any); - await plugin.load(addBasePath); await expect(plugin.setup({} as any, {} as any)).rejects.toThrowErrorMatchingInlineSnapshot( `"Instance of plugin \\"plugin-a\\" does not define \\"setup\\" function."` ); @@ -70,20 +57,17 @@ describe('PluginWrapper', () => { test('`setup` fails if plugin.start is not a function', async () => { mockInitializer.mockReturnValueOnce({ setup: jest.fn() } as any); - await plugin.load(addBasePath); await expect(plugin.setup({} as any, {} as any)).rejects.toThrowErrorMatchingInlineSnapshot( `"Instance of plugin \\"plugin-a\\" does not define \\"start\\" function."` ); }); test('`setup` calls initializer with initializer context', async () => { - await plugin.load(addBasePath); await plugin.setup({} as any, {} as any); expect(mockInitializer).toHaveBeenCalledWith(initializerContext); }); test('`setup` calls plugin.setup with context and dependencies', async () => { - await plugin.load(addBasePath); const context = { any: 'thing' } as any; const deps = { otherDep: 'value' }; await plugin.setup(context, deps); @@ -91,14 +75,12 @@ describe('PluginWrapper', () => { }); test('`start` fails if setup is not called first', async () => { - await plugin.load(addBasePath); await expect(plugin.start({} as any, {} as any)).rejects.toThrowErrorMatchingInlineSnapshot( `"Plugin \\"plugin-a\\" can't be started since it isn't set up."` ); }); test('`start` calls plugin.start with context and dependencies', async () => { - await plugin.load(addBasePath); await plugin.setup({} as any, {} as any); const context = { any: 'thing' } as any; const deps = { otherDep: 'value' }; @@ -114,20 +96,21 @@ describe('PluginWrapper', () => { }; let startDependenciesResolved = false; - mockPluginLoader.mockResolvedValueOnce(() => ({ - setup: jest.fn(), - start: async () => { - // Add small delay to ensure startDependencies is not resolved until after the plugin instance's start resolves. - await new Promise(resolve => setTimeout(resolve, 10)); - expect(startDependenciesResolved).toBe(false); - return pluginStartContract; - }, - })); - await plugin.load(addBasePath); + mockPluginReader.mockReturnValueOnce( + jest.fn(() => ({ + setup: jest.fn(), + start: jest.fn(async () => { + // Add small delay to ensure startDependencies is not resolved until after the plugin instance's start resolves. + await new Promise(resolve => setTimeout(resolve, 10)); + expect(startDependenciesResolved).toBe(false); + return pluginStartContract; + }), + stop: jest.fn(), + })) + ); await plugin.setup({} as any, {} as any); const context = { any: 'thing' } as any; const deps = { otherDep: 'value' }; - // Add promise callback prior to calling `start` to ensure calls in `setup` will not resolve before `start` is // called. const startDependenciesCheck = plugin.startDependencies.then(res => { @@ -145,7 +128,6 @@ describe('PluginWrapper', () => { }); test('`stop` calls plugin.stop', async () => { - await plugin.load(addBasePath); await plugin.setup({} as any, {} as any); await plugin.stop(); expect(mockPlugin.stop).toHaveBeenCalled(); @@ -153,7 +135,6 @@ describe('PluginWrapper', () => { test('`stop` does not fail if plugin.stop does not exist', async () => { mockInitializer.mockReturnValueOnce({ setup: jest.fn(), start: jest.fn() } as any); - await plugin.load(addBasePath); await plugin.setup({} as any, {} as any); expect(() => plugin.stop()).not.toThrow(); }); diff --git a/src/core/public/plugins/plugin.ts b/src/core/public/plugins/plugin.ts index e51c45040c452..591165fcd2839 100644 --- a/src/core/public/plugins/plugin.ts +++ b/src/core/public/plugins/plugin.ts @@ -21,7 +21,7 @@ import { Subject } from 'rxjs'; import { first } from 'rxjs/operators'; import { DiscoveredPlugin, PluginOpaqueId } from '../../server'; import { PluginInitializerContext } from './plugin_context'; -import { loadPluginBundle } from './plugin_loader'; +import { read } from './plugin_reader'; import { CoreStart, CoreSetup } from '..'; /** @@ -69,7 +69,6 @@ export class PluginWrapper< public readonly configPath: DiscoveredPlugin['configPath']; public readonly requiredPlugins: DiscoveredPlugin['requiredPlugins']; public readonly optionalPlugins: DiscoveredPlugin['optionalPlugins']; - private initializer?: PluginInitializer; private instance?: Plugin; private readonly startDependencies$ = new Subject<[CoreStart, TPluginsStart, TStart]>(); @@ -86,18 +85,6 @@ export class PluginWrapper< this.optionalPlugins = discoveredPlugin.optionalPlugins; } - /** - * Loads the plugin's bundle into the browser. Should be called in parallel with all plugins - * using `Promise.all`. Must be called before `setup`. - * @param addBasePath Function that adds the base path to a string for plugin bundle path. - */ - public async load(addBasePath: (path: string) => string) { - this.initializer = await loadPluginBundle( - addBasePath, - this.name - ); - } - /** * Instantiates plugin and calls `setup` function exposed by the plugin initializer. * @param setupContext Context that consists of various core services tailored specifically @@ -146,11 +133,14 @@ export class PluginWrapper< } private async createPluginInstance() { - if (this.initializer === undefined) { - throw new Error(`Plugin "${this.name}" can't be setup since its bundle isn't loaded.`); - } - - const instance = this.initializer(this.initializerContext); + const initializer = read(this.name) as PluginInitializer< + TSetup, + TStart, + TPluginsSetup, + TPluginsStart + >; + + const instance = initializer(this.initializerContext); if (typeof instance.setup !== 'function') { throw new Error(`Instance of plugin "${this.name}" does not define "setup" function.`); diff --git a/src/core/public/plugins/plugin_loader.test.ts b/src/core/public/plugins/plugin_loader.test.ts deleted file mode 100644 index b4e2c3095f14a..0000000000000 --- a/src/core/public/plugins/plugin_loader.test.ts +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { CoreWindow, loadPluginBundle } from './plugin_loader'; - -let createdScriptTags = [] as any[]; -let appendChildSpy: jest.SpyInstance; -let createElementSpy: jest.SpyInstance< - HTMLElement, - [string, (ElementCreationOptions | undefined)?] ->; - -const coreWindow = (window as unknown) as CoreWindow; - -beforeEach(() => { - // Mock document.createElement to return fake tags we can use to inspect what - // loadPluginBundles does. - createdScriptTags = []; - createElementSpy = jest.spyOn(document, 'createElement').mockImplementation(() => { - const scriptTag = { setAttribute: jest.fn() } as any; - createdScriptTags.push(scriptTag); - return scriptTag; - }); - - // Mock document.body.appendChild to avoid errors about appending objects that aren't `Node`'s - // and so we can verify that the script tags were added to the page. - appendChildSpy = jest.spyOn(document.body, 'appendChild').mockReturnValue({} as any); - - // Mock global fields needed for loading modules. - coreWindow.__kbnBundles__ = {}; -}); - -afterEach(() => { - appendChildSpy.mockRestore(); - createElementSpy.mockRestore(); - delete coreWindow.__kbnBundles__; -}); - -const addBasePath = (path: string) => path; - -test('`loadPluginBundles` creates a script tag and loads initializer', async () => { - const loadPromise = loadPluginBundle(addBasePath, 'plugin-a'); - - // Verify it sets up the script tag correctly and adds it to document.body - expect(createdScriptTags).toHaveLength(1); - const fakeScriptTag = createdScriptTags[0]; - expect(fakeScriptTag.setAttribute).toHaveBeenCalledWith( - 'src', - '/bundles/plugin/plugin-a/plugin-a.plugin.js' - ); - expect(fakeScriptTag.setAttribute).toHaveBeenCalledWith('id', 'kbn-plugin-plugin-a'); - expect(fakeScriptTag.onload).toBeInstanceOf(Function); - expect(fakeScriptTag.onerror).toBeInstanceOf(Function); - expect(appendChildSpy).toHaveBeenCalledWith(fakeScriptTag); - - // Setup a fake initializer as if a plugin bundle had actually been loaded. - const fakeInitializer = jest.fn(); - coreWindow.__kbnBundles__['plugin/plugin-a'] = { plugin: fakeInitializer }; - // Call the onload callback - fakeScriptTag.onload(); - await expect(loadPromise).resolves.toEqual(fakeInitializer); -}); - -test('`loadPluginBundles` includes the basePath', async () => { - loadPluginBundle((path: string) => `/mybasepath${path}`, 'plugin-a'); - - // Verify it sets up the script tag correctly and adds it to document.body - expect(createdScriptTags).toHaveLength(1); - const fakeScriptTag = createdScriptTags[0]; - expect(fakeScriptTag.setAttribute).toHaveBeenCalledWith( - 'src', - '/mybasepath/bundles/plugin/plugin-a/plugin-a.plugin.js' - ); -}); - -test('`loadPluginBundles` rejects if script.onerror is called', async () => { - const loadPromise = loadPluginBundle(addBasePath, 'plugin-a'); - const fakeScriptTag1 = createdScriptTags[0]; - // Call the error on the second script - fakeScriptTag1.onerror(new Error('Whoa there!')); - - await expect(loadPromise).rejects.toThrowErrorMatchingInlineSnapshot( - `"Failed to load \\"plugin-a\\" bundle (/bundles/plugin/plugin-a/plugin-a.plugin.js)"` - ); -}); - -test('`loadPluginBundles` rejects if timeout is reached', async () => { - await expect( - // Override the timeout to 1 ms for testi. - loadPluginBundle(addBasePath, 'plugin-a', { timeoutMs: 1 }) - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Timeout reached when loading \\"plugin-a\\" bundle (/bundles/plugin/plugin-a/plugin-a.plugin.js)"` - ); -}); - -test('`loadPluginBundles` rejects if bundle does attach an initializer to window.__kbnBundles__', async () => { - const loadPromise = loadPluginBundle(addBasePath, 'plugin-a'); - - const fakeScriptTag1 = createdScriptTags[0]; - - // Setup a fake initializer as if a plugin bundle had actually been loaded. - coreWindow.__kbnBundles__['plugin/plugin-a'] = undefined; - // Call the onload callback - fakeScriptTag1.onload(); - - await expect(loadPromise).rejects.toThrowErrorMatchingInlineSnapshot( - `"Definition of plugin \\"plugin-a\\" should be a function (/bundles/plugin/plugin-a/plugin-a.plugin.js)."` - ); -}); diff --git a/src/core/public/plugins/plugin_loader.ts b/src/core/public/plugins/plugin_loader.ts deleted file mode 100644 index bf7711055e97b..0000000000000 --- a/src/core/public/plugins/plugin_loader.ts +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { PluginName } from '../../server'; -import { PluginInitializer } from './plugin'; - -/** - * Unknown variant for internal use only for when plugins are not known. - * @internal - */ -export type UnknownPluginInitializer = PluginInitializer>; - -/** - * Custom window type for loading bundles. Do not extend global Window to avoid leaking these types. - * @internal - */ -export interface CoreWindow { - __kbnBundles__: { - [pluginBundleName: string]: { plugin: UnknownPluginInitializer } | undefined; - }; -} - -/** - * Timeout for loading a single script in milliseconds. - * @internal - */ -export const LOAD_TIMEOUT = 120 * 1000; // 2 minutes - -/** - * Loads the bundle for a plugin onto the page and returns their PluginInitializer. This should - * be called for all plugins (once per plugin) in parallel using Promise.all. - * - * If this is slowing down browser load time, there are some ways we could make this faster: - * - Add these bundles in the generated bootstrap.js file so they're loaded immediately - * - Concatenate all the bundles files on the backend and serve them in single request. - * - Use HTTP/2 to load these bundles without having to open new connections for each. - * - * This may not be much of an issue since these should be cached by the browser after the first - * page load. - * - * @param basePath - * @param plugins - * @internal - */ -export const loadPluginBundle: LoadPluginBundle = < - TSetup, - TStart, - TPluginsSetup extends object, - TPluginsStart extends object ->( - addBasePath: (path: string) => string, - pluginName: PluginName, - { timeoutMs = LOAD_TIMEOUT }: { timeoutMs?: number } = {} -) => - new Promise>( - (resolve, reject) => { - const coreWindow = (window as unknown) as CoreWindow; - const exportId = `plugin/${pluginName}`; - - const readPluginExport = () => { - const PluginExport: any = coreWindow.__kbnBundles__[exportId]; - if (typeof PluginExport?.plugin !== 'function') { - reject( - new Error(`Definition of plugin "${pluginName}" should be a function (${bundlePath}).`) - ); - } else { - resolve( - PluginExport.plugin as PluginInitializer - ); - } - }; - - if (coreWindow.__kbnBundles__[exportId]) { - readPluginExport(); - return; - } - - const script = document.createElement('script'); - // Assumes that all plugin bundles get put into the bundles/plugins subdirectory - const bundlePath = addBasePath(`/bundles/plugin/${pluginName}/${pluginName}.plugin.js`); - script.setAttribute('src', bundlePath); - script.setAttribute('id', `kbn-plugin-${pluginName}`); - script.setAttribute('async', ''); - - const cleanupTag = () => { - clearTimeout(timeout); - // Set to null for IE memory leak issue. Webpack does the same thing. - // @ts-ignore - script.onload = script.onerror = null; - }; - - // Wire up resolve and reject - script.onload = () => { - cleanupTag(); - readPluginExport(); - }; - - script.onerror = () => { - cleanupTag(); - reject(new Error(`Failed to load "${pluginName}" bundle (${bundlePath})`)); - }; - - const timeout = setTimeout(() => { - cleanupTag(); - reject(new Error(`Timeout reached when loading "${pluginName}" bundle (${bundlePath})`)); - }, timeoutMs); - - // Add the script tag to the end of the body to start downloading - document.body.appendChild(script); - } - ); - -/** - * @internal - */ -export type LoadPluginBundle = < - TSetup, - TStart, - TPluginsSetup extends object, - TPluginsStart extends object ->( - addBasePath: (path: string) => string, - pluginName: PluginName, - options?: { timeoutMs?: number } -) => Promise>; diff --git a/src/core/public/plugins/plugin_reader.test.ts b/src/core/public/plugins/plugin_reader.test.ts new file mode 100644 index 0000000000000..d4324f81de8e6 --- /dev/null +++ b/src/core/public/plugins/plugin_reader.test.ts @@ -0,0 +1,53 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { CoreWindow, read, UnknownPluginInitializer } from './plugin_reader'; + +const coreWindow: CoreWindow = window as any; +beforeEach(() => { + coreWindow.__kbnBundles__ = {}; +}); + +it('handles undefined plugin exports', () => { + coreWindow.__kbnBundles__['plugin/foo'] = undefined; + + expect(() => { + read('foo'); + }).toThrowError(`Definition of plugin "foo" not found and may have failed to load.`); +}); + +it('handles plugin exports with a "plugin" export that is not a function', () => { + coreWindow.__kbnBundles__['plugin/foo'] = { + plugin: 1234, + } as any; + + expect(() => { + read('foo'); + }).toThrowError(`Definition of plugin "foo" should be a function.`); +}); + +it('returns the plugin initializer when the "plugin" named export is a function', () => { + const plugin: UnknownPluginInitializer = () => { + return undefined as any; + }; + + coreWindow.__kbnBundles__['plugin/foo'] = { plugin }; + + expect(read('foo')).toBe(plugin); +}); diff --git a/src/core/public/plugins/plugin_reader.ts b/src/core/public/plugins/plugin_reader.ts new file mode 100644 index 0000000000000..1907dfa6a3e99 --- /dev/null +++ b/src/core/public/plugins/plugin_reader.ts @@ -0,0 +1,52 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { PluginInitializer } from './plugin'; + +/** + * Unknown variant for internal use only for when plugins are not known. + * @internal + */ +export type UnknownPluginInitializer = PluginInitializer>; + +/** + * Custom window type for loading bundles. Do not extend global Window to avoid leaking these types. + * @internal + */ +export interface CoreWindow { + __kbnBundles__: { + [pluginBundleName: string]: { plugin: UnknownPluginInitializer } | undefined; + }; +} + +/** + * Reads the plugin's bundle declared in the global context. + */ +export function read(name: string) { + const coreWindow = (window as unknown) as CoreWindow; + const exportId = `plugin/${name}`; + const pluginExport = coreWindow.__kbnBundles__[exportId]; + if (!pluginExport) { + throw new Error(`Definition of plugin "${name}" not found and may have failed to load.`); + } else if (typeof pluginExport.plugin !== 'function') { + throw new Error(`Definition of plugin "${name}" should be a function.`); + } else { + return pluginExport.plugin; + } +} diff --git a/src/core/public/plugins/plugins_service.test.mocks.ts b/src/core/public/plugins/plugins_service.test.mocks.ts index a76078932518f..85b84e561056a 100644 --- a/src/core/public/plugins/plugins_service.test.mocks.ts +++ b/src/core/public/plugins/plugins_service.test.mocks.ts @@ -19,16 +19,16 @@ import { PluginName } from 'kibana/server'; import { Plugin } from './plugin'; -import { loadPluginBundleMock } from './plugin_loader.mock'; export type MockedPluginInitializer = jest.Mock>, any>; export const mockPluginInitializerProvider: jest.Mock< MockedPluginInitializer, [PluginName] -> = jest.fn().mockRejectedValue(new Error('No provider specified')); +> = jest.fn().mockImplementation(() => () => { + throw new Error('No provider specified'); +}); -export const mockLoadPluginBundle = loadPluginBundleMock.create(mockPluginInitializerProvider); -jest.mock('./plugin_loader', () => ({ - loadPluginBundle: mockLoadPluginBundle, +jest.mock('./plugin_reader', () => ({ + read: mockPluginInitializerProvider, })); diff --git a/src/core/public/plugins/plugins_service.test.ts b/src/core/public/plugins/plugins_service.test.ts index 688eaf4f2bfc7..6d71844bc19c8 100644 --- a/src/core/public/plugins/plugins_service.test.ts +++ b/src/core/public/plugins/plugins_service.test.ts @@ -21,7 +21,6 @@ import { omit, pick } from 'lodash'; import { MockedPluginInitializer, - mockLoadPluginBundle, mockPluginInitializerProvider, } from './plugins_service.test.mocks'; @@ -32,6 +31,7 @@ import { PluginsServiceStartDeps, PluginsServiceSetupDeps, } from './plugins_service'; + import { InjectedPluginMetadata } from '../injected_metadata'; import { notificationServiceMock } from '../notifications/notifications_service.mock'; import { applicationServiceMock } from '../application/application_service.mock'; @@ -152,10 +152,6 @@ describe('PluginsService', () => { ] as unknown) as [[PluginName, any]]); }); - afterEach(() => { - mockLoadPluginBundle.mockClear(); - }); - describe('#getOpaqueIds()', () => { it('returns dependency tree of symbols', () => { const pluginsService = new PluginsService(mockCoreContext, plugins); @@ -174,15 +170,6 @@ describe('PluginsService', () => { }); describe('#setup()', () => { - it('fails if any bundle cannot be loaded', async () => { - mockLoadPluginBundle.mockRejectedValueOnce(new Error('Could not load bundle')); - - const pluginsService = new PluginsService(mockCoreContext, plugins); - await expect(pluginsService.setup(mockSetupDeps)).rejects.toThrowErrorMatchingInlineSnapshot( - `"Could not load bundle"` - ); - }); - it('fails if any plugin instance does not have a setup function', async () => { mockPluginInitializers.set('pluginA', (() => ({})) as any); const pluginsService = new PluginsService(mockCoreContext, plugins); @@ -191,25 +178,6 @@ describe('PluginsService', () => { ); }); - it('calls loadPluginBundles with http and plugins', async () => { - const pluginsService = new PluginsService(mockCoreContext, plugins); - await pluginsService.setup(mockSetupDeps); - - expect(mockLoadPluginBundle).toHaveBeenCalledTimes(3); - expect(mockLoadPluginBundle).toHaveBeenCalledWith( - mockSetupDeps.http.basePath.prepend, - 'pluginA' - ); - expect(mockLoadPluginBundle).toHaveBeenCalledWith( - mockSetupDeps.http.basePath.prepend, - 'pluginB' - ); - expect(mockLoadPluginBundle).toHaveBeenCalledWith( - mockSetupDeps.http.basePath.prepend, - 'pluginC' - ); - }); - it('initializes plugins with PluginInitializerContext', async () => { const pluginsService = new PluginsService(mockCoreContext, plugins); await pluginsService.setup(mockSetupDeps); @@ -302,7 +270,6 @@ describe('PluginsService', () => { const pluginsService = new PluginsService(mockCoreContext, plugins); const promise = pluginsService.setup(mockSetupDeps); - jest.runAllTimers(); // load plugin bundles await flushPromises(); jest.runAllTimers(); // setup plugins diff --git a/src/core/public/plugins/plugins_service.ts b/src/core/public/plugins/plugins_service.ts index e698af689036d..862aa5043ad4b 100644 --- a/src/core/public/plugins/plugins_service.ts +++ b/src/core/public/plugins/plugins_service.ts @@ -93,9 +93,6 @@ export class PluginsService implements CoreService { - // Load plugin bundles - await this.loadPluginBundles(deps.http.basePath.prepend); - // Setup each plugin with required and optional plugin contracts const contracts = new Map(); for (const [pluginName, plugin] of this.plugins.entries()) { @@ -167,9 +164,4 @@ export class PluginsService implements CoreService string) { - // Load all bundles in parallel - return Promise.all([...this.plugins.values()].map(plugin => plugin.load(addBasePath))); - } } diff --git a/src/core/server/rendering/views/template.tsx b/src/core/server/rendering/views/template.tsx index b38259a84cb9c..73e119a5a97e7 100644 --- a/src/core/server/rendering/views/template.tsx +++ b/src/core/server/rendering/views/template.tsx @@ -104,6 +104,10 @@ export const Template: FunctionComponent = ({ + + {/* Inject stylesheets into the before scripts so that KP plugins with bundled styles will override them */} + + {createElement('kbn-csp', { diff --git a/src/dev/jest/config.js b/src/dev/jest/config.js index 43a2cbd78c502..c5387590fcf66 100644 --- a/src/dev/jest/config.js +++ b/src/dev/jest/config.js @@ -40,6 +40,7 @@ export default { ], collectCoverageFrom: [ 'src/plugins/**/*.{ts,tsx}', + '!src/plugins/**/{__test__,__snapshots__,__examples__,mocks,tests}/**/*', '!src/plugins/**/*.d.ts', 'packages/kbn-ui-framework/src/components/**/*.js', '!packages/kbn-ui-framework/src/components/index.js', diff --git a/src/legacy/core_plugins/kibana/public/discover/get_inner_angular.ts b/src/legacy/core_plugins/kibana/public/discover/get_inner_angular.ts index 6ccbc13aeeb57..6366466103652 100644 --- a/src/legacy/core_plugins/kibana/public/discover/get_inner_angular.ts +++ b/src/legacy/core_plugins/kibana/public/discover/get_inner_angular.ts @@ -21,6 +21,8 @@ // these are necessary to bootstrap the local angular. // They can stay even after NP cutover import angular from 'angular'; +// required for `ngSanitize` angular module +import 'angular-sanitize'; import { EuiIcon } from '@elastic/eui'; import { i18nDirective, i18nFilter, I18nProvider } from '@kbn/i18n/angular'; import { CoreStart, LegacyCoreStart } from 'kibana/public'; diff --git a/src/legacy/core_plugins/timelion/public/app.js b/src/legacy/core_plugins/timelion/public/app.js index 7f5c7d4664af8..80ffa440e7285 100644 --- a/src/legacy/core_plugins/timelion/public/app.js +++ b/src/legacy/core_plugins/timelion/public/app.js @@ -18,6 +18,8 @@ */ import _ from 'lodash'; +// required for `ngSanitize` angular module +import 'angular-sanitize'; import { i18n } from '@kbn/i18n'; diff --git a/src/legacy/server/kbn_server.d.ts b/src/legacy/server/kbn_server.d.ts index 0d2f3528c9019..02491ff872981 100644 --- a/src/legacy/server/kbn_server.d.ts +++ b/src/legacy/server/kbn_server.d.ts @@ -153,6 +153,7 @@ export default class KbnServer { public server: Server; public inject: Server['inject']; public pluginSpecs: any[]; + public uiBundles: any; constructor( settings: Record, diff --git a/src/legacy/ui/public/angular_ui_select.js b/src/legacy/ui/public/angular_ui_select.js index 92b1bf53520ce..99f92587507c9 100644 --- a/src/legacy/ui/public/angular_ui_select.js +++ b/src/legacy/ui/public/angular_ui_select.js @@ -19,6 +19,7 @@ import 'jquery'; import 'angular'; +// required for `ngSanitize` angular module import 'angular-sanitize'; import 'ui-select/dist/select'; diff --git a/src/legacy/ui/public/i18n/index.test.tsx b/src/legacy/ui/public/i18n/index.test.tsx index c7a778ac18bd3..be8ab4cf8d696 100644 --- a/src/legacy/ui/public/i18n/index.test.tsx +++ b/src/legacy/ui/public/i18n/index.test.tsx @@ -21,6 +21,7 @@ import { render } from 'enzyme'; import PropTypes from 'prop-types'; import React from 'react'; +jest.mock('angular-sanitize', () => {}); jest.mock('ui/new_platform', () => ({ npStart: { core: { diff --git a/src/legacy/ui/public/i18n/index.tsx b/src/legacy/ui/public/i18n/index.tsx index c918554563fcb..6f1120dce0c7c 100644 --- a/src/legacy/ui/public/i18n/index.tsx +++ b/src/legacy/ui/public/i18n/index.tsx @@ -18,6 +18,8 @@ */ import React from 'react'; +// required for `ngSanitize` angular module +import 'angular-sanitize'; import { i18nDirective, i18nFilter, I18nProvider } from '@kbn/i18n/angular'; // @ts-ignore diff --git a/src/legacy/ui/ui_render/bootstrap/template.js.hbs b/src/legacy/ui/ui_render/bootstrap/template.js.hbs index 8a71c6ccb1506..b60442690af3c 100644 --- a/src/legacy/ui/ui_render/bootstrap/template.js.hbs +++ b/src/legacy/ui/ui_render/bootstrap/template.js.hbs @@ -29,6 +29,7 @@ if (window.__kbnStrictCsp__ && window.__kbnCspNotEnforced__) { document.body.innerHTML = err.outerHTML; } + var stylesheetTarget = document.querySelector('head meta[name="add-styles-here"]') function loadStyleSheet(url, cb) { var dom = document.createElement('link'); dom.rel = 'stylesheet'; @@ -36,9 +37,10 @@ if (window.__kbnStrictCsp__ && window.__kbnCspNotEnforced__) { dom.href = url; dom.addEventListener('error', failure); dom.addEventListener('load', cb); - document.head.appendChild(dom); + document.head.insertBefore(dom, stylesheetTarget); } + var scriptsTarget = document.querySelector('head meta[name="add-scripts-here"]') function loadScript(url, cb) { var dom = document.createElement('script'); {{!-- NOTE: async = false is used to trigger async-download/ordered-execution as outlined here: https://www.html5rocks.com/en/tutorials/speed/script-loading/ --}} @@ -46,7 +48,7 @@ if (window.__kbnStrictCsp__ && window.__kbnCspNotEnforced__) { dom.src = url; dom.addEventListener('error', failure); dom.addEventListener('load', cb); - document.head.appendChild(dom); + document.head.insertBefore(dom, scriptsTarget); } function load(urls, cb) { diff --git a/src/legacy/ui/ui_render/ui_render_mixin.js b/src/legacy/ui/ui_render/ui_render_mixin.js index 801eecf5b608b..9b44395fa9c68 100644 --- a/src/legacy/ui/ui_render/ui_render_mixin.js +++ b/src/legacy/ui/ui_render/ui_render_mixin.js @@ -19,13 +19,15 @@ import { createHash } from 'crypto'; import Boom from 'boom'; -import { resolve } from 'path'; +import Path from 'path'; import { i18n } from '@kbn/i18n'; import * as UiSharedDeps from '@kbn/ui-shared-deps'; import { AppBootstrap } from './bootstrap'; import { getApmConfig } from '../apm'; import { DllCompiler } from '../../../optimize/dynamic_dll_plugin'; +const uniq = (...items) => Array.from(new Set(items)); + /** * @typedef {import('../../server/kbn_server').default} KbnServer * @typedef {import('../../server/kbn_server').ResponseToolkit} ResponseToolkit @@ -39,7 +41,7 @@ import { DllCompiler } from '../../../optimize/dynamic_dll_plugin'; */ export function uiRenderMixin(kbnServer, server, config) { // render all views from ./views - server.setupViews(resolve(__dirname, 'views')); + server.setupViews(Path.resolve(__dirname, 'views')); const translationsCache = { translations: null, hash: null }; server.route({ @@ -94,9 +96,12 @@ export function uiRenderMixin(kbnServer, server, config) { ? await uiSettings.get('theme:darkMode') : false; + const buildHash = server.newPlatform.env.packageInfo.buildNum; const basePath = config.get('server.basePath'); - const regularBundlePath = `${basePath}/bundles`; - const dllBundlePath = `${basePath}/built_assets/dlls`; + + const regularBundlePath = `${basePath}/${buildHash}/bundles`; + const dllBundlePath = `${basePath}/${buildHash}/built_assets/dlls`; + const dllStyleChunks = DllCompiler.getRawDllConfig().chunks.map( chunk => `${dllBundlePath}/vendors${chunk}.style.dll.css` ); @@ -106,15 +111,15 @@ export function uiRenderMixin(kbnServer, server, config) { const styleSheetPaths = [ ...(isCore ? [] : dllStyleChunks), - `${basePath}/bundles/kbn-ui-shared-deps/${UiSharedDeps.baseCssDistFilename}`, + `${regularBundlePath}/kbn-ui-shared-deps/${UiSharedDeps.baseCssDistFilename}`, ...(darkMode ? [ - `${basePath}/bundles/kbn-ui-shared-deps/${UiSharedDeps.darkCssDistFilename}`, + `${regularBundlePath}/kbn-ui-shared-deps/${UiSharedDeps.darkCssDistFilename}`, `${basePath}/node_modules/@kbn/ui-framework/dist/kui_dark.css`, `${regularBundlePath}/dark_theme.style.css`, ] : [ - `${basePath}/bundles/kbn-ui-shared-deps/${UiSharedDeps.lightCssDistFilename}`, + `${regularBundlePath}/kbn-ui-shared-deps/${UiSharedDeps.lightCssDistFilename}`, `${basePath}/node_modules/@kbn/ui-framework/dist/kui_light.css`, `${regularBundlePath}/light_theme.style.css`, ]), @@ -129,13 +134,23 @@ export function uiRenderMixin(kbnServer, server, config) { ) .map(path => path.localPath.endsWith('.scss') - ? `${basePath}/built_assets/css/${path.publicPath}` + ? `${basePath}/${buildHash}/built_assets/css/${path.publicPath}` : `${basePath}/${path.publicPath}` ) .reverse(), ]), ]; + const kpPluginIds = uniq( + // load these plugins first, they are "shared" and other bundles access their + // public/index exports without considering topographic sorting by plugin deps (for now) + 'kibanaUtils', + 'kibanaReact', + 'data', + 'esUiShared', + ...kbnServer.newPlatform.__internals.uiPlugins.public.keys() + ); + const jsDependencyPaths = [ ...UiSharedDeps.jsDepFilenames.map( filename => `${regularBundlePath}/kbn-ui-shared-deps/${filename}` @@ -148,20 +163,22 @@ export function uiRenderMixin(kbnServer, server, config) { ...dllJsChunks, `${regularBundlePath}/commons.bundle.js`, ]), - `${regularBundlePath}/plugin/kibanaUtils/kibanaUtils.plugin.js`, - `${regularBundlePath}/plugin/esUiShared/esUiShared.plugin.js`, - `${regularBundlePath}/plugin/kibanaReact/kibanaReact.plugin.js`, - ]; - const uiPluginIds = [...kbnServer.newPlatform.__internals.uiPlugins.public.keys()]; + ...kpPluginIds.map( + pluginId => `${regularBundlePath}/plugin/${pluginId}/${pluginId}.plugin.js` + ), + ]; // These paths should align with the bundle routes configured in - // src/optimize/bundles_route/bundles_route.js + // src/optimize/bundles_route/bundles_route.ts const publicPathMap = JSON.stringify({ core: `${regularBundlePath}/core/`, 'kbn-ui-shared-deps': `${regularBundlePath}/kbn-ui-shared-deps/`, - ...uiPluginIds.reduce( - (acc, pluginId) => ({ ...acc, [pluginId]: `${regularBundlePath}/plugin/${pluginId}/` }), + ...kpPluginIds.reduce( + (acc, pluginId) => ({ + ...acc, + [pluginId]: `${regularBundlePath}/plugin/${pluginId}/`, + }), {} ), }); diff --git a/src/optimize/bundles_route/__tests__/bundles_route.js b/src/optimize/bundles_route/__tests__/bundles_route.js index 0b2aeda11fb0e..902fa59b20569 100644 --- a/src/optimize/bundles_route/__tests__/bundles_route.js +++ b/src/optimize/bundles_route/__tests__/bundles_route.js @@ -32,6 +32,7 @@ import { PUBLIC_PATH_PLACEHOLDER } from '../../public_path_placeholder'; const chance = new Chance(); const outputFixture = resolve(__dirname, './fixtures/output'); +const pluginNoPlaceholderFixture = resolve(__dirname, './fixtures/plugin/no_placeholder'); const randomWordsCache = new Set(); const uniqueRandomWord = () => { @@ -58,6 +59,9 @@ describe('optimizer/bundle route', () => { dllBundlesPath = outputFixture, basePublicPath = '', builtCssPath = outputFixture, + npUiPluginPublicDirs = [], + buildHash = '1234', + isDist = false, } = options; const server = new Hapi.Server(); @@ -69,6 +73,9 @@ describe('optimizer/bundle route', () => { dllBundlesPath, basePublicPath, builtCssPath, + npUiPluginPublicDirs, + buildHash, + isDist, }) ); @@ -158,7 +165,7 @@ describe('optimizer/bundle route', () => { it('responds with exact file data', async () => { const server = createServer(); const response = await server.inject({ - url: '/bundles/image.png', + url: '/1234/bundles/image.png', }); expect(response.statusCode).to.be(200); @@ -173,7 +180,7 @@ describe('optimizer/bundle route', () => { it('responds with no content-length and exact file data', async () => { const server = createServer(); const response = await server.inject({ - url: '/bundles/no_placeholder.js', + url: '/1234/bundles/no_placeholder.js', }); expect(response.statusCode).to.be(200); @@ -187,12 +194,12 @@ describe('optimizer/bundle route', () => { }); describe('js file with placeholder', () => { - it('responds with no content-length and modified file data', async () => { + it('responds with no content-length and modifiedfile data ', async () => { const basePublicPath = `/${uniqueRandomWord()}`; const server = createServer({ basePublicPath }); const response = await server.inject({ - url: '/bundles/with_placeholder.js', + url: '/1234/bundles/with_placeholder.js', }); expect(response.statusCode).to.be(200); @@ -204,7 +211,7 @@ describe('optimizer/bundle route', () => { ); expect(response.result.indexOf(source)).to.be(-1); expect(response.result).to.be( - replaceAll(source, PUBLIC_PATH_PLACEHOLDER, `${basePublicPath}/bundles/`) + replaceAll(source, PUBLIC_PATH_PLACEHOLDER, `${basePublicPath}/1234/bundles/`) ); }); }); @@ -213,7 +220,7 @@ describe('optimizer/bundle route', () => { it('responds with no content-length and exact file data', async () => { const server = createServer(); const response = await server.inject({ - url: '/bundles/no_placeholder.css', + url: '/1234/bundles/no_placeholder.css', }); expect(response.statusCode).to.be(200); @@ -231,7 +238,7 @@ describe('optimizer/bundle route', () => { const server = createServer({ basePublicPath }); const response = await server.inject({ - url: '/bundles/with_placeholder.css', + url: '/1234/bundles/with_placeholder.css', }); expect(response.statusCode).to.be(200); @@ -240,7 +247,7 @@ describe('optimizer/bundle route', () => { expect(response.headers).to.have.property('content-type', 'text/css; charset=utf-8'); expect(response.result.indexOf(source)).to.be(-1); expect(response.result).to.be( - replaceAll(source, PUBLIC_PATH_PLACEHOLDER, `${basePublicPath}/bundles/`) + replaceAll(source, PUBLIC_PATH_PLACEHOLDER, `${basePublicPath}/1234/bundles/`) ); }); }); @@ -250,7 +257,7 @@ describe('optimizer/bundle route', () => { const server = createServer(); const response = await server.inject({ - url: '/bundles/../outside_output.js', + url: '/1234/bundles/../outside_output.js', }); expect(response.statusCode).to.be(404); @@ -267,7 +274,7 @@ describe('optimizer/bundle route', () => { const server = createServer(); const response = await server.inject({ - url: '/bundles/non_existent.js', + url: '/1234/bundles/non_existent.js', }); expect(response.statusCode).to.be(404); @@ -286,7 +293,7 @@ describe('optimizer/bundle route', () => { }); const response = await server.inject({ - url: '/bundles/with_placeholder.js', + url: '/1234/bundles/with_placeholder.js', }); expect(response.statusCode).to.be(404); @@ -306,7 +313,7 @@ describe('optimizer/bundle route', () => { sinon.assert.notCalled(createHash); const resp1 = await server.inject({ - url: '/bundles/no_placeholder.js', + url: '/1234/bundles/no_placeholder.js', }); sinon.assert.calledOnce(createHash); @@ -314,23 +321,23 @@ describe('optimizer/bundle route', () => { expect(resp1.statusCode).to.be(200); const resp2 = await server.inject({ - url: '/bundles/no_placeholder.js', + url: '/1234/bundles/no_placeholder.js', }); sinon.assert.notCalled(createHash); expect(resp2.statusCode).to.be(200); }); - it('is unique per basePublicPath although content is the same', async () => { + it('is unique per basePublicPath although content is the same (by default)', async () => { const basePublicPath1 = `/${uniqueRandomWord()}`; const basePublicPath2 = `/${uniqueRandomWord()}`; const [resp1, resp2] = await Promise.all([ createServer({ basePublicPath: basePublicPath1 }).inject({ - url: '/bundles/no_placeholder.js', + url: '/1234/bundles/no_placeholder.js', }), createServer({ basePublicPath: basePublicPath2 }).inject({ - url: '/bundles/no_placeholder.js', + url: '/1234/bundles/no_placeholder.js', }), ]); @@ -349,13 +356,13 @@ describe('optimizer/bundle route', () => { it('responds with 304 when etag and last modified are sent back', async () => { const server = createServer(); const resp = await server.inject({ - url: '/bundles/with_placeholder.js', + url: '/1234/bundles/with_placeholder.js', }); expect(resp.statusCode).to.be(200); const resp2 = await server.inject({ - url: '/bundles/with_placeholder.js', + url: '/1234/bundles/with_placeholder.js', headers: { 'if-modified-since': resp.headers['last-modified'], 'if-none-match': resp.headers.etag, @@ -366,4 +373,80 @@ describe('optimizer/bundle route', () => { expect(resp2.result).to.have.length(0); }); }); + + describe('kibana platform assets', () => { + describe('caching', () => { + describe('for non-distributable mode', () => { + it('uses "etag" header to invalidate cache', async () => { + const basePublicPath = `/${uniqueRandomWord()}`; + + const npUiPluginPublicDirs = [ + { + id: 'no_placeholder', + path: pluginNoPlaceholderFixture, + }, + ]; + const responce = await createServer({ basePublicPath, npUiPluginPublicDirs }).inject({ + url: '/1234/bundles/plugin/no_placeholder/no_placeholder.plugin.js', + }); + + expect(responce.statusCode).to.be(200); + + expect(responce.headers.etag).to.be.a('string'); + expect(responce.headers['cache-control']).to.be('must-revalidate'); + }); + + it('creates the same "etag" header for the same content with the same basePath', async () => { + const npUiPluginPublicDirs = [ + { + id: 'no_placeholder', + path: pluginNoPlaceholderFixture, + }, + ]; + const [resp1, resp2] = await Promise.all([ + createServer({ basePublicPath: '', npUiPluginPublicDirs }).inject({ + url: '/1234/bundles/plugin/no_placeholder/no_placeholder.plugin.js', + }), + createServer({ basePublicPath: '', npUiPluginPublicDirs }).inject({ + url: '/1234/bundles/plugin/no_placeholder/no_placeholder.plugin.js', + }), + ]); + + expect(resp1.statusCode).to.be(200); + expect(resp2.statusCode).to.be(200); + + expect(resp1.rawPayload).to.eql(resp2.rawPayload); + + expect(resp1.headers.etag).to.be.a('string'); + expect(resp2.headers.etag).to.be.a('string'); + expect(resp1.headers.etag).to.eql(resp2.headers.etag); + }); + }); + + describe('for distributable mode', () => { + it('commands to cache assets for each release for a year', async () => { + const basePublicPath = `/${uniqueRandomWord()}`; + + const npUiPluginPublicDirs = [ + { + id: 'no_placeholder', + path: pluginNoPlaceholderFixture, + }, + ]; + const responce = await createServer({ + basePublicPath, + npUiPluginPublicDirs, + isDist: true, + }).inject({ + url: '/1234/bundles/plugin/no_placeholder/no_placeholder.plugin.js', + }); + + expect(responce.statusCode).to.be(200); + + expect(responce.headers.etag).to.be(undefined); + expect(responce.headers['cache-control']).to.be('max-age=31536000'); + }); + }); + }); + }); }); diff --git a/src/optimize/bundles_route/bundles_route.js b/src/optimize/bundles_route/bundles_route.ts similarity index 74% rename from src/optimize/bundles_route/bundles_route.js rename to src/optimize/bundles_route/bundles_route.ts index 4030988c8552c..e9cfba0130d95 100644 --- a/src/optimize/bundles_route/bundles_route.js +++ b/src/optimize/bundles_route/bundles_route.ts @@ -18,10 +18,13 @@ */ import { isAbsolute, extname, join } from 'path'; -import LruCache from 'lru-cache'; + +import Hapi from 'hapi'; import * as UiSharedDeps from '@kbn/ui-shared-deps'; + import { createDynamicAssetResponse } from './dynamic_asset_response'; -import { assertIsNpUiPluginPublicDirs } from '../np_ui_plugin_public_dirs'; +import { FileHashCache } from './file_hash_cache'; +import { assertIsNpUiPluginPublicDirs, NpUiPluginPublicDirs } from '../np_ui_plugin_public_dirs'; import { fromRoot } from '../../core/server/utils'; /** @@ -44,11 +47,21 @@ export function createBundlesRoute({ basePublicPath, builtCssPath, npUiPluginPublicDirs = [], + buildHash, + isDist = false, +}: { + regularBundlesPath: string; + dllBundlesPath: string; + basePublicPath: string; + builtCssPath: string; + npUiPluginPublicDirs?: NpUiPluginPublicDirs; + buildHash: string; + isDist?: boolean; }) { // rather than calculate the fileHash on every request, we // provide a cache object to `resolveDynamicAssetResponse()` that // will store the 100 most recently used hashes. - const fileHashCache = new LruCache(100); + const fileHashCache = new FileHashCache(); assertIsNpUiPluginPublicDirs(npUiPluginPublicDirs); if (typeof regularBundlesPath !== 'string' || !isAbsolute(regularBundlesPath)) { @@ -73,45 +86,51 @@ export function createBundlesRoute({ return [ buildRouteForBundles({ - publicPath: `${basePublicPath}/bundles/kbn-ui-shared-deps/`, - routePath: '/bundles/kbn-ui-shared-deps/', + publicPath: `${basePublicPath}/${buildHash}/bundles/kbn-ui-shared-deps/`, + routePath: `/${buildHash}/bundles/kbn-ui-shared-deps/`, bundlesPath: UiSharedDeps.distDir, fileHashCache, replacePublicPath: false, + isDist, }), ...npUiPluginPublicDirs.map(({ id, path }) => buildRouteForBundles({ - publicPath: `${basePublicPath}/bundles/plugin/${id}/`, - routePath: `/bundles/plugin/${id}/`, + publicPath: `${basePublicPath}/${buildHash}/bundles/plugin/${id}/`, + routePath: `/${buildHash}/bundles/plugin/${id}/`, bundlesPath: path, fileHashCache, replacePublicPath: false, + isDist, }) ), buildRouteForBundles({ - publicPath: `${basePublicPath}/bundles/core/`, - routePath: `/bundles/core/`, + publicPath: `${basePublicPath}/${buildHash}/bundles/core/`, + routePath: `/${buildHash}/bundles/core/`, bundlesPath: fromRoot(join('src', 'core', 'target', 'public')), fileHashCache, replacePublicPath: false, + isDist, }), buildRouteForBundles({ - publicPath: `${basePublicPath}/bundles/`, - routePath: '/bundles/', + publicPath: `${basePublicPath}/${buildHash}/bundles/`, + routePath: `/${buildHash}/bundles/`, bundlesPath: regularBundlesPath, fileHashCache, + isDist, }), buildRouteForBundles({ - publicPath: `${basePublicPath}/built_assets/dlls/`, - routePath: '/built_assets/dlls/', + publicPath: `${basePublicPath}/${buildHash}/built_assets/dlls/`, + routePath: `/${buildHash}/built_assets/dlls/`, bundlesPath: dllBundlesPath, fileHashCache, + isDist, }), buildRouteForBundles({ publicPath: `${basePublicPath}/`, - routePath: '/built_assets/css/', + routePath: `/${buildHash}/built_assets/css/`, bundlesPath: builtCssPath, fileHashCache, + isDist, }), ]; } @@ -122,6 +141,14 @@ function buildRouteForBundles({ bundlesPath, fileHashCache, replacePublicPath = true, + isDist, +}: { + publicPath: string; + routePath: string; + bundlesPath: string; + fileHashCache: FileHashCache; + replacePublicPath?: boolean; + isDist: boolean; }) { return { method: 'GET', @@ -130,7 +157,7 @@ function buildRouteForBundles({ auth: false, ext: { onPreHandler: { - method(request, h) { + method(request: Hapi.Request, h: Hapi.ResponseToolkit) { const ext = extname(request.params.path); if (ext !== '.js' && ext !== '.css') { @@ -144,6 +171,7 @@ function buildRouteForBundles({ fileHashCache, publicPath, replacePublicPath, + isDist, }); }, }, diff --git a/src/optimize/bundles_route/dynamic_asset_response.js b/src/optimize/bundles_route/dynamic_asset_response.ts similarity index 67% rename from src/optimize/bundles_route/dynamic_asset_response.js rename to src/optimize/bundles_route/dynamic_asset_response.ts index 80c49a26270fd..a020c6935eeec 100644 --- a/src/optimize/bundles_route/dynamic_asset_response.js +++ b/src/optimize/bundles_route/dynamic_asset_response.ts @@ -17,15 +17,26 @@ * under the License. */ +import Fs from 'fs'; import { resolve } from 'path'; -import { open, fstat, createReadStream, close } from 'fs'; +import { promisify } from 'util'; import Boom from 'boom'; -import { fromNode as fcb } from 'bluebird'; +import Hapi from 'hapi'; +import { FileHashCache } from './file_hash_cache'; import { getFileHash } from './file_hash'; +// @ts-ignore import { replacePlaceholder } from '../public_path_placeholder'; +const MINUTE = 60; +const HOUR = 60 * MINUTE; +const DAY = 24 * HOUR; + +const asyncOpen = promisify(Fs.open); +const asyncClose = promisify(Fs.close); +const asyncFstat = promisify(Fs.fstat); + /** * Create a Hapi response for the requested path. This is designed * to replicate a subset of the features provided by Hapi's Inert @@ -44,55 +55,70 @@ import { replacePlaceholder } from '../public_path_placeholder'; * - cached hash/etag is based on the file on disk, but modified * by the public path so that individual public paths have * different etags, but can share a cache - * - * @param {Object} options - * @property {Hapi.Request} options.request - * @property {string} options.bundlesPath - * @property {string} options.publicPath - * @property {LruCache} options.fileHashCache */ -export async function createDynamicAssetResponse(options) { - const { request, h, bundlesPath, publicPath, fileHashCache, replacePublicPath } = options; +export async function createDynamicAssetResponse({ + request, + h, + bundlesPath, + publicPath, + fileHashCache, + replacePublicPath, + isDist, +}: { + request: Hapi.Request; + h: Hapi.ResponseToolkit; + bundlesPath: string; + publicPath: string; + fileHashCache: FileHashCache; + replacePublicPath: boolean; + isDist: boolean; +}) { + let fd: number | undefined; - let fd; try { const path = resolve(bundlesPath, request.params.path); // prevent path traversal, only process paths that resolve within bundlesPath if (!path.startsWith(bundlesPath)) { - throw Boom.forbidden(null, 'EACCES'); + throw Boom.forbidden(undefined, 'EACCES'); } // we use and manage a file descriptor mostly because // that's what Inert does, and since we are accessing // the file 2 or 3 times per request it seems logical - fd = await fcb(cb => open(path, 'r', cb)); + fd = await asyncOpen(path, 'r'); - const stat = await fcb(cb => fstat(fd, cb)); - const hash = await getFileHash(fileHashCache, path, stat, fd); + const stat = await asyncFstat(fd); + const hash = isDist ? undefined : await getFileHash(fileHashCache, path, stat, fd); - const read = createReadStream(null, { + const read = Fs.createReadStream(null as any, { fd, start: 0, autoClose: true, }); - fd = null; // read stream is now responsible for fd + fd = undefined; // read stream is now responsible for fd const content = replacePublicPath ? replacePlaceholder(read, publicPath) : read; - const etag = replacePublicPath ? `${hash}-${publicPath}` : hash; - return h + const response = h .response(content) .takeover() .code(200) - .etag(etag) - .header('cache-control', 'must-revalidate') .type(request.server.mime.path(path).type); + + if (isDist) { + response.header('cache-control', `max-age=${365 * DAY}`); + } else { + response.etag(`${hash}-${publicPath}`); + response.header('cache-control', 'must-revalidate'); + } + + return response; } catch (error) { if (fd) { try { - await fcb(cb => close(fd, cb)); - } catch (error) { + await asyncClose(fd); + } catch (_) { // ignore errors from close, we already have one to report // and it's very likely they are the same } diff --git a/src/optimize/bundles_route/file_hash.js b/src/optimize/bundles_route/file_hash.ts similarity index 73% rename from src/optimize/bundles_route/file_hash.js rename to src/optimize/bundles_route/file_hash.ts index d9464cf05eca1..7b0801098ed10 100644 --- a/src/optimize/bundles_route/file_hash.js +++ b/src/optimize/bundles_route/file_hash.ts @@ -18,20 +18,17 @@ */ import { createHash } from 'crypto'; -import { createReadStream } from 'fs'; +import Fs from 'fs'; import * as Rx from 'rxjs'; -import { merge, mergeMap, takeUntil } from 'rxjs/operators'; +import { takeUntil, map } from 'rxjs/operators'; + +import { FileHashCache } from './file_hash_cache'; /** * Get the hash of a file via a file descriptor - * @param {LruCache} cache - * @param {string} path - * @param {Fs.Stat} stat - * @param {Fs.FileDescriptor} fd - * @return {Promise} */ -export async function getFileHash(cache, path, stat, fd) { +export async function getFileHash(cache: FileHashCache, path: string, stat: Fs.Stats, fd: number) { const key = `${path}:${stat.ino}:${stat.size}:${stat.mtime.getTime()}`; const cached = cache.get(key); @@ -40,17 +37,21 @@ export async function getFileHash(cache, path, stat, fd) { } const hash = createHash('sha1'); - const read = createReadStream(null, { + const read = Fs.createReadStream(null as any, { fd, start: 0, autoClose: false, }); - const promise = Rx.fromEvent(read, 'data') - .pipe( - merge(Rx.fromEvent(read, 'error').pipe(mergeMap(Rx.throwError))), - takeUntil(Rx.fromEvent(read, 'end')) + const promise = Rx.merge( + Rx.fromEvent(read, 'data'), + Rx.fromEvent(read, 'error').pipe( + map(error => { + throw error; + }) ) + ) + .pipe(takeUntil(Rx.fromEvent(read, 'end'))) .forEach(chunk => hash.update(chunk)) .then(() => hash.digest('hex')) .catch(error => { diff --git a/src/optimize/bundles_route/file_hash_cache.ts b/src/optimize/bundles_route/file_hash_cache.ts new file mode 100644 index 0000000000000..a7cdabbff13a7 --- /dev/null +++ b/src/optimize/bundles_route/file_hash_cache.ts @@ -0,0 +1,36 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import LruCache from 'lru-cache'; + +export class FileHashCache { + private lru = new LruCache>(100); + + get(key: string) { + return this.lru.get(key); + } + + set(key: string, value: Promise) { + this.lru.set(key, value); + } + + del(key: string) { + this.lru.del(key); + } +} diff --git a/src/optimize/bundles_route/index.js b/src/optimize/bundles_route/index.ts similarity index 100% rename from src/optimize/bundles_route/index.js rename to src/optimize/bundles_route/index.ts diff --git a/src/optimize/bundles_route/proxy_bundles_route.js b/src/optimize/bundles_route/proxy_bundles_route.ts similarity index 70% rename from src/optimize/bundles_route/proxy_bundles_route.js rename to src/optimize/bundles_route/proxy_bundles_route.ts index fff0ec444d95b..1d189054324a1 100644 --- a/src/optimize/bundles_route/proxy_bundles_route.js +++ b/src/optimize/bundles_route/proxy_bundles_route.ts @@ -17,15 +17,23 @@ * under the License. */ -export function createProxyBundlesRoute({ host, port }) { +export function createProxyBundlesRoute({ + host, + port, + buildHash, +}: { + host: string; + port: number; + buildHash: string; +}) { return [ - buildProxyRouteForBundles('/bundles/', host, port), - buildProxyRouteForBundles('/built_assets/dlls/', host, port), - buildProxyRouteForBundles('/built_assets/css/', host, port), + buildProxyRouteForBundles(`/${buildHash}/bundles/`, host, port), + buildProxyRouteForBundles(`/${buildHash}/built_assets/dlls/`, host, port), + buildProxyRouteForBundles(`/${buildHash}/built_assets/css/`, host, port), ]; } -function buildProxyRouteForBundles(routePath, host, port) { +function buildProxyRouteForBundles(routePath: string, host: string, port: number) { return { path: `${routePath}{path*}`, method: 'GET', diff --git a/src/optimize/index.js b/src/optimize/index.js index b7b9f7712358a..363f81a6a3a96 100644 --- a/src/optimize/index.js +++ b/src/optimize/index.js @@ -17,72 +17,5 @@ * under the License. */ -import FsOptimizer from './fs_optimizer'; -import { createBundlesRoute } from './bundles_route'; -import { DllCompiler } from './dynamic_dll_plugin'; -import { fromRoot } from '../core/server/utils'; -import { getNpUiPluginPublicDirs } from './np_ui_plugin_public_dirs'; - -export default async (kbnServer, server, config) => { - if (!config.get('optimize.enabled')) return; - - // the watch optimizer sets up two threads, one is the server listening - // on 5601 and the other is a server listening on 5602 that builds the - // bundles in a "middleware" style. - // - // the server listening on 5601 may be restarted a number of times, depending - // on the watch setup managed by the cli. It proxies all bundles/* and built_assets/dlls/* - // requests to the other server. The server on 5602 is long running, in order - // to prevent complete rebuilds of the optimize content. - const watch = config.get('optimize.watch'); - if (watch) { - return await kbnServer.mixin(require('./watch/watch')); - } - - const { uiBundles } = kbnServer; - server.route( - createBundlesRoute({ - regularBundlesPath: uiBundles.getWorkingDir(), - dllBundlesPath: DllCompiler.getRawDllConfig().outputPath, - basePublicPath: config.get('server.basePath'), - builtCssPath: fromRoot('built_assets/css'), - npUiPluginPublicDirs: getNpUiPluginPublicDirs(kbnServer), - }) - ); - - // in prod, only bundle when something is missing or invalid - const reuseCache = config.get('optimize.useBundleCache') - ? await uiBundles.areAllBundleCachesValid() - : false; - - // we might not have any work to do - if (reuseCache) { - server.log(['debug', 'optimize'], `All bundles are cached and ready to go!`); - return; - } - - await uiBundles.resetBundleDir(); - - // only require the FsOptimizer when we need to - const optimizer = new FsOptimizer({ - logWithMetadata: (tags, message, metadata) => server.logWithMetadata(tags, message, metadata), - uiBundles, - profile: config.get('optimize.profile'), - sourceMaps: config.get('optimize.sourceMaps'), - workers: config.get('optimize.workers'), - }); - - server.log( - ['info', 'optimize'], - `Optimizing and caching ${uiBundles.getDescription()}. This may take a few minutes` - ); - - const start = Date.now(); - await optimizer.run(); - const seconds = ((Date.now() - start) / 1000).toFixed(2); - - server.log( - ['info', 'optimize'], - `Optimization of ${uiBundles.getDescription()} complete in ${seconds} seconds` - ); -}; +import { optimizeMixin } from './optimize_mixin'; +export default optimizeMixin; diff --git a/src/optimize/np_ui_plugin_public_dirs.js b/src/optimize/np_ui_plugin_public_dirs.ts similarity index 73% rename from src/optimize/np_ui_plugin_public_dirs.js rename to src/optimize/np_ui_plugin_public_dirs.ts index de05fd2b863b8..e7c3207948f6a 100644 --- a/src/optimize/np_ui_plugin_public_dirs.js +++ b/src/optimize/np_ui_plugin_public_dirs.ts @@ -16,8 +16,14 @@ * specific language governing permissions and limitations * under the License. */ +import KbnServer from '../legacy/server/kbn_server'; -export function getNpUiPluginPublicDirs(kbnServer) { +export type NpUiPluginPublicDirs = Array<{ + id: string; + path: string; +}>; + +export function getNpUiPluginPublicDirs(kbnServer: KbnServer): NpUiPluginPublicDirs { return Array.from(kbnServer.newPlatform.__internals.uiPlugins.internal.entries()).map( ([id, { publicTargetDir }]) => ({ id, @@ -26,17 +32,17 @@ export function getNpUiPluginPublicDirs(kbnServer) { ); } -export function isNpUiPluginPublicDirs(something) { +export function isNpUiPluginPublicDirs(x: any): x is NpUiPluginPublicDirs { return ( - Array.isArray(something) && - something.every( + Array.isArray(x) && + x.every( s => typeof s === 'object' && s && typeof s.id === 'string' && typeof s.path === 'string' ) ); } -export function assertIsNpUiPluginPublicDirs(something) { - if (!isNpUiPluginPublicDirs(something)) { +export function assertIsNpUiPluginPublicDirs(x: any): asserts x is NpUiPluginPublicDirs { + if (!isNpUiPluginPublicDirs(x)) { throw new TypeError( 'npUiPluginPublicDirs must be an array of objects with string `id` and `path` properties' ); diff --git a/src/optimize/optimize_mixin.ts b/src/optimize/optimize_mixin.ts new file mode 100644 index 0000000000000..9a3f08e2f667e --- /dev/null +++ b/src/optimize/optimize_mixin.ts @@ -0,0 +1,100 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import Hapi from 'hapi'; + +// @ts-ignore not TS yet +import FsOptimizer from './fs_optimizer'; +import { createBundlesRoute } from './bundles_route'; +// @ts-ignore not TS yet +import { DllCompiler } from './dynamic_dll_plugin'; +import { fromRoot } from '../core/server/utils'; +import { getNpUiPluginPublicDirs } from './np_ui_plugin_public_dirs'; +import KbnServer, { KibanaConfig } from '../legacy/server/kbn_server'; + +export const optimizeMixin = async ( + kbnServer: KbnServer, + server: Hapi.Server, + config: KibanaConfig +) => { + if (!config.get('optimize.enabled')) return; + + // the watch optimizer sets up two threads, one is the server listening + // on 5601 and the other is a server listening on 5602 that builds the + // bundles in a "middleware" style. + // + // the server listening on 5601 may be restarted a number of times, depending + // on the watch setup managed by the cli. It proxies all bundles/* and built_assets/dlls/* + // requests to the other server. The server on 5602 is long running, in order + // to prevent complete rebuilds of the optimize content. + const watch = config.get('optimize.watch'); + if (watch) { + // eslint-disable-next-line @typescript-eslint/no-var-requires + return await kbnServer.mixin(require('./watch/watch')); + } + + const { uiBundles } = kbnServer; + server.route( + createBundlesRoute({ + regularBundlesPath: uiBundles.getWorkingDir(), + dllBundlesPath: DllCompiler.getRawDllConfig().outputPath, + basePublicPath: config.get('server.basePath'), + builtCssPath: fromRoot('built_assets/css'), + npUiPluginPublicDirs: getNpUiPluginPublicDirs(kbnServer), + buildHash: kbnServer.newPlatform.env.packageInfo.buildNum.toString(), + isDist: kbnServer.newPlatform.env.packageInfo.dist, + }) + ); + + // in prod, only bundle when something is missing or invalid + const reuseCache = config.get('optimize.useBundleCache') + ? await uiBundles.areAllBundleCachesValid() + : false; + + // we might not have any work to do + if (reuseCache) { + server.log(['debug', 'optimize'], `All bundles are cached and ready to go!`); + return; + } + + await uiBundles.resetBundleDir(); + + // only require the FsOptimizer when we need to + const optimizer = new FsOptimizer({ + logWithMetadata: server.logWithMetadata, + uiBundles, + profile: config.get('optimize.profile'), + sourceMaps: config.get('optimize.sourceMaps'), + workers: config.get('optimize.workers'), + }); + + server.log( + ['info', 'optimize'], + `Optimizing and caching ${uiBundles.getDescription()}. This may take a few minutes` + ); + + const start = Date.now(); + await optimizer.run(); + const seconds = ((Date.now() - start) / 1000).toFixed(2); + + server.log( + ['info', 'optimize'], + `Optimization of ${uiBundles.getDescription()} complete in ${seconds} seconds` + ); +}; diff --git a/src/optimize/public_path_placeholder.js b/src/optimize/public_path_placeholder.ts similarity index 76% rename from src/optimize/public_path_placeholder.js rename to src/optimize/public_path_placeholder.ts index ef05d9e5ae704..1ec2b4a431aa6 100644 --- a/src/optimize/public_path_placeholder.js +++ b/src/optimize/public_path_placeholder.ts @@ -17,14 +17,20 @@ * under the License. */ -import { createReplaceStream } from '../legacy/utils'; +import Stream from 'stream'; +import Fs from 'fs'; import * as Rx from 'rxjs'; import { take, takeUntil } from 'rxjs/operators'; +import { createReplaceStream } from '../legacy/utils'; export const PUBLIC_PATH_PLACEHOLDER = '__REPLACE_WITH_PUBLIC_PATH__'; -export function replacePlaceholder(read, replacement) { +interface ClosableTransform extends Stream.Transform { + close(): void; +} + +export function replacePlaceholder(read: Stream.Readable, replacement: string) { const replace = createReplaceStream(PUBLIC_PATH_PLACEHOLDER, replacement); // handle errors on the read stream by proxying them @@ -37,13 +43,15 @@ export function replacePlaceholder(read, replacement) { replace.end(); }); - replace.close = () => { - read.unpipe(); + const closableReplace: ClosableTransform = Object.assign(replace, { + close: () => { + read.unpipe(); - if (read.close) { - read.close(); - } - }; + if ('close' in read) { + (read as Fs.ReadStream).close(); + } + }, + }); - return read.pipe(replace); + return read.pipe(closableReplace); } diff --git a/src/optimize/watch/optmzr_role.js b/src/optimize/watch/optmzr_role.js index a31ef7229e5da..1f6107996277c 100644 --- a/src/optimize/watch/optmzr_role.js +++ b/src/optimize/watch/optmzr_role.js @@ -49,7 +49,8 @@ export default async (kbnServer, kibanaHapiServer, config) => { config.get('optimize.watchPort'), config.get('server.basePath'), watchOptimizer, - getNpUiPluginPublicDirs(kbnServer) + getNpUiPluginPublicDirs(kbnServer), + kbnServer.newPlatform.env.packageInfo.buildNum.toString() ); watchOptimizer.status$.subscribe({ diff --git a/src/optimize/watch/proxy_role.js b/src/optimize/watch/proxy_role.js index 6093658ae1a2d..0f6f3b2d4b622 100644 --- a/src/optimize/watch/proxy_role.js +++ b/src/optimize/watch/proxy_role.js @@ -26,6 +26,7 @@ export default (kbnServer, server, config) => { createProxyBundlesRoute({ host: config.get('optimize.watchHost'), port: config.get('optimize.watchPort'), + buildHash: kbnServer.newPlatform.env.packageInfo.buildNum.toString(), }) ); diff --git a/src/optimize/watch/watch_optimizer.js b/src/optimize/watch/watch_optimizer.js index 6c20f21c7768e..cdff57a00c2e0 100644 --- a/src/optimize/watch/watch_optimizer.js +++ b/src/optimize/watch/watch_optimizer.js @@ -106,7 +106,7 @@ export default class WatchOptimizer extends BaseOptimizer { }); } - bindToServer(server, basePath, npUiPluginPublicDirs) { + bindToServer(server, basePath, npUiPluginPublicDirs, buildHash) { // pause all requests received while the compiler is running // and continue once an outcome is reached (aborting the request // with an error if it was a failure). @@ -118,6 +118,7 @@ export default class WatchOptimizer extends BaseOptimizer { server.route( createBundlesRoute({ npUiPluginPublicDirs: npUiPluginPublicDirs, + buildHash, regularBundlesPath: this.compiler.outputPath, dllBundlesPath: DllCompiler.getRawDllConfig().outputPath, basePublicPath: basePath, diff --git a/src/optimize/watch/watch_server.js b/src/optimize/watch/watch_server.js index 74a96dc8aea6e..81e04a5b83956 100644 --- a/src/optimize/watch/watch_server.js +++ b/src/optimize/watch/watch_server.js @@ -21,10 +21,11 @@ import { Server } from 'hapi'; import { registerHapiPlugins } from '../../legacy/server/http/register_hapi_plugins'; export default class WatchServer { - constructor(host, port, basePath, optimizer, npUiPluginPublicDirs) { + constructor(host, port, basePath, optimizer, npUiPluginPublicDirs, buildHash) { this.basePath = basePath; this.optimizer = optimizer; this.npUiPluginPublicDirs = npUiPluginPublicDirs; + this.buildHash = buildHash; this.server = new Server({ host: host, port: port, @@ -35,7 +36,12 @@ export default class WatchServer { async init() { await this.optimizer.init(); - this.optimizer.bindToServer(this.server, this.basePath, this.npUiPluginPublicDirs); + this.optimizer.bindToServer( + this.server, + this.basePath, + this.npUiPluginPublicDirs, + this.buildHash + ); await this.server.start(); } } diff --git a/src/plugins/dashboard/public/application/application.ts b/src/plugins/dashboard/public/application/application.ts index a1696298117b0..37f014d836075 100644 --- a/src/plugins/dashboard/public/application/application.ts +++ b/src/plugins/dashboard/public/application/application.ts @@ -21,6 +21,8 @@ import './index.scss'; import { EuiIcon } from '@elastic/eui'; import angular, { IModule } from 'angular'; +// required for `ngSanitize` angular module +import 'angular-sanitize'; import { i18nDirective, i18nFilter, I18nProvider } from '@kbn/i18n/angular'; import { AppMountContext, diff --git a/src/plugins/saved_objects_management/public/management_section/mount_section.tsx b/src/plugins/saved_objects_management/public/management_section/mount_section.tsx index fe3150fc0bb07..c1daf3445219f 100644 --- a/src/plugins/saved_objects_management/public/management_section/mount_section.tsx +++ b/src/plugins/saved_objects_management/public/management_section/mount_section.tsx @@ -17,23 +17,15 @@ * under the License. */ -import React, { useEffect } from 'react'; +import React, { lazy, Suspense } from 'react'; import ReactDOM from 'react-dom'; -import { HashRouter, Switch, Route, useParams, useLocation } from 'react-router-dom'; -import { parse } from 'query-string'; -import { get } from 'lodash'; -import { i18n } from '@kbn/i18n'; +import { HashRouter, Switch, Route } from 'react-router-dom'; import { I18nProvider } from '@kbn/i18n/react'; -import { CoreSetup, CoreStart, ChromeBreadcrumb, Capabilities } from 'src/core/public'; +import { EuiLoadingSpinner } from '@elastic/eui'; +import { CoreSetup, Capabilities } from 'src/core/public'; import { ManagementAppMountParams } from '../../../management/public'; -import { DataPublicPluginStart } from '../../../data/public'; import { StartDependencies, SavedObjectsManagementPluginStart } from '../plugin'; -import { - ISavedObjectsManagementServiceRegistry, - SavedObjectsManagementActionServiceStart, -} from '../services'; -import { SavedObjectsTable } from './objects_table'; -import { SavedObjectEdition } from './object_view'; +import { ISavedObjectsManagementServiceRegistry } from '../services'; import { getAllowedTypes } from './../lib'; interface MountParams { @@ -44,6 +36,8 @@ interface MountParams { let allowedObjectTypes: string[] | undefined; +const SavedObjectsEditionPage = lazy(() => import('./saved_objects_edition_page')); +const SavedObjectsTablePage = lazy(() => import('./saved_objects_table_page')); export const mountManagementSection = async ({ core, mountParams, @@ -63,23 +57,27 @@ export const mountManagementSection = async ({ - + }> + + - + }> + + @@ -103,110 +101,3 @@ const RedirectToHomeIfUnauthorized: React.FunctionComponent<{ } return children! as React.ReactElement; }; - -const SavedObjectsEditionPage = ({ - coreStart, - serviceRegistry, - setBreadcrumbs, -}: { - coreStart: CoreStart; - serviceRegistry: ISavedObjectsManagementServiceRegistry; - setBreadcrumbs: (crumbs: ChromeBreadcrumb[]) => void; -}) => { - const { service: serviceName, id } = useParams<{ service: string; id: string }>(); - const capabilities = coreStart.application.capabilities; - - const { search } = useLocation(); - const query = parse(search); - const service = serviceRegistry.get(serviceName); - - useEffect(() => { - setBreadcrumbs([ - { - text: i18n.translate('savedObjectsManagement.breadcrumb.index', { - defaultMessage: 'Saved objects', - }), - href: '#/management/kibana/objects', - }, - { - text: i18n.translate('savedObjectsManagement.breadcrumb.edit', { - defaultMessage: 'Edit {savedObjectType}', - values: { savedObjectType: service?.service.type ?? 'object' }, - }), - }, - ]); - }, [setBreadcrumbs, service]); - - return ( - - ); -}; - -const SavedObjectsTablePage = ({ - coreStart, - dataStart, - allowedTypes, - serviceRegistry, - actionRegistry, - setBreadcrumbs, -}: { - coreStart: CoreStart; - dataStart: DataPublicPluginStart; - allowedTypes: string[]; - serviceRegistry: ISavedObjectsManagementServiceRegistry; - actionRegistry: SavedObjectsManagementActionServiceStart; - setBreadcrumbs: (crumbs: ChromeBreadcrumb[]) => void; -}) => { - const capabilities = coreStart.application.capabilities; - const itemsPerPage = coreStart.uiSettings.get('savedObjects:perPage', 50); - - useEffect(() => { - setBreadcrumbs([ - { - text: i18n.translate('savedObjectsManagement.breadcrumb.index', { - defaultMessage: 'Saved objects', - }), - href: '#/management/kibana/objects', - }, - ]); - }, [setBreadcrumbs]); - - return ( - { - const { editUrl } = savedObject.meta; - if (editUrl) { - // previously, kbnUrl.change(object.meta.editUrl); was used. - // using direct access to location.hash seems the only option for now, - // as using react-router-dom will prefix the url with the router's basename - // which should be ignored there. - window.location.hash = editUrl; - } - }} - canGoInApp={savedObject => { - const { inAppUrl } = savedObject.meta; - return inAppUrl ? get(capabilities, inAppUrl.uiCapabilitiesPath) : false; - }} - /> - ); -}; diff --git a/src/plugins/saved_objects_management/public/management_section/saved_objects_edition_page.tsx b/src/plugins/saved_objects_management/public/management_section/saved_objects_edition_page.tsx new file mode 100644 index 0000000000000..5ac6e8e103c47 --- /dev/null +++ b/src/plugins/saved_objects_management/public/management_section/saved_objects_edition_page.tsx @@ -0,0 +1,76 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { useEffect } from 'react'; +import { useParams, useLocation } from 'react-router-dom'; +import { parse } from 'query-string'; +import { i18n } from '@kbn/i18n'; +import { CoreStart, ChromeBreadcrumb } from 'src/core/public'; +import { ISavedObjectsManagementServiceRegistry } from '../services'; +import { SavedObjectEdition } from './object_view'; + +const SavedObjectsEditionPage = ({ + coreStart, + serviceRegistry, + setBreadcrumbs, +}: { + coreStart: CoreStart; + serviceRegistry: ISavedObjectsManagementServiceRegistry; + setBreadcrumbs: (crumbs: ChromeBreadcrumb[]) => void; +}) => { + const { service: serviceName, id } = useParams<{ service: string; id: string }>(); + const capabilities = coreStart.application.capabilities; + + const { search } = useLocation(); + const query = parse(search); + const service = serviceRegistry.get(serviceName); + + useEffect(() => { + setBreadcrumbs([ + { + text: i18n.translate('savedObjectsManagement.breadcrumb.index', { + defaultMessage: 'Saved objects', + }), + href: '#/management/kibana/objects', + }, + { + text: i18n.translate('savedObjectsManagement.breadcrumb.edit', { + defaultMessage: 'Edit {savedObjectType}', + values: { savedObjectType: service?.service.type ?? 'object' }, + }), + }, + ]); + }, [setBreadcrumbs, service]); + + return ( + + ); +}; + +// eslint-disable-next-line import/no-default-export +export { SavedObjectsEditionPage as default }; diff --git a/src/plugins/saved_objects_management/public/management_section/saved_objects_table_page.tsx b/src/plugins/saved_objects_management/public/management_section/saved_objects_table_page.tsx new file mode 100644 index 0000000000000..7660d17f91c5b --- /dev/null +++ b/src/plugins/saved_objects_management/public/management_section/saved_objects_table_page.tsx @@ -0,0 +1,91 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { useEffect } from 'react'; +import { get } from 'lodash'; +import { i18n } from '@kbn/i18n'; +import { CoreStart, ChromeBreadcrumb } from 'src/core/public'; +import { DataPublicPluginStart } from '../../../data/public'; +import { + ISavedObjectsManagementServiceRegistry, + SavedObjectsManagementActionServiceStart, +} from '../services'; +import { SavedObjectsTable } from './objects_table'; + +const SavedObjectsTablePage = ({ + coreStart, + dataStart, + allowedTypes, + serviceRegistry, + actionRegistry, + setBreadcrumbs, +}: { + coreStart: CoreStart; + dataStart: DataPublicPluginStart; + allowedTypes: string[]; + serviceRegistry: ISavedObjectsManagementServiceRegistry; + actionRegistry: SavedObjectsManagementActionServiceStart; + setBreadcrumbs: (crumbs: ChromeBreadcrumb[]) => void; +}) => { + const capabilities = coreStart.application.capabilities; + const itemsPerPage = coreStart.uiSettings.get('savedObjects:perPage', 50); + + useEffect(() => { + setBreadcrumbs([ + { + text: i18n.translate('savedObjectsManagement.breadcrumb.index', { + defaultMessage: 'Saved objects', + }), + href: '#/management/kibana/objects', + }, + ]); + }, [setBreadcrumbs]); + + return ( + { + const { editUrl } = savedObject.meta; + if (editUrl) { + // previously, kbnUrl.change(object.meta.editUrl); was used. + // using direct access to location.hash seems the only option for now, + // as using react-router-dom will prefix the url with the router's basename + // which should be ignored there. + window.location.hash = editUrl; + } + }} + canGoInApp={savedObject => { + const { inAppUrl } = savedObject.meta; + return inAppUrl ? get(capabilities, inAppUrl.uiCapabilitiesPath) : false; + }} + /> + ); +}; +// eslint-disable-next-line import/no-default-export +export { SavedObjectsTablePage as default }; diff --git a/src/plugins/telemetry_management_section/public/components/__snapshots__/telemetry_management_section.test.tsx.snap b/src/plugins/telemetry_management_section/public/components/__snapshots__/telemetry_management_section.test.tsx.snap new file mode 100644 index 0000000000000..8c0117e5a7266 --- /dev/null +++ b/src/plugins/telemetry_management_section/public/components/__snapshots__/telemetry_management_section.test.tsx.snap @@ -0,0 +1,492 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`TelemetryManagementSectionComponent renders as expected 1`] = ` + + + + + + +

+ +

+
+
+
+ + + + , + } + } + /> +

+ } + /> + + +

+ + + , + } + } + /> +

+

+ + + +

+ , + "displayName": "Provide usage statistics", + "name": "telemetry:enabled", + "type": "boolean", + "value": true, + } + } + toasts={null} + /> +
+
+
+`; + +exports[`TelemetryManagementSectionComponent renders null because allowChangingOptInStatus is false 1`] = ` + +`; + +exports[`TelemetryManagementSectionComponent renders null because query does not match the SEARCH_TERMS 1`] = ` + +`; + +exports[`TelemetryManagementSectionComponent test the wrapper (for coverage purposes) 1`] = `""`; diff --git a/src/plugins/telemetry_management_section/public/components/telemetry_management_section.test.tsx b/src/plugins/telemetry_management_section/public/components/telemetry_management_section.test.tsx new file mode 100644 index 0000000000000..d0c2bd13f802d --- /dev/null +++ b/src/plugins/telemetry_management_section/public/components/telemetry_management_section.test.tsx @@ -0,0 +1,284 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { mountWithIntl, shallowWithIntl } from 'test_utils/enzyme_helpers'; +import { TelemetryManagementSection } from './telemetry_management_section'; +import { TelemetryService } from '../../../telemetry/public/services'; +import { coreMock } from '../../../../core/public/mocks'; +import { telemetryManagementSectionWrapper } from './telemetry_management_section_wrapper'; + +describe('TelemetryManagementSectionComponent', () => { + const coreStart = coreMock.createStart(); + const coreSetup = coreMock.createSetup(); + + it('renders as expected', () => { + const onQueryMatchChange = jest.fn(); + const telemetryService = new TelemetryService({ + config: { + enabled: true, + url: '', + banner: true, + allowChangingOptInStatus: true, + optIn: true, + optInStatusUrl: '', + sendUsageFrom: 'browser', + }, + reportOptInStatusChange: false, + notifications: coreStart.notifications, + http: coreSetup.http, + }); + + expect( + shallowWithIntl( + + ) + ).toMatchSnapshot(); + }); + + it('renders null because query does not match the SEARCH_TERMS', () => { + const onQueryMatchChange = jest.fn(); + const telemetryService = new TelemetryService({ + config: { + enabled: true, + url: '', + banner: true, + allowChangingOptInStatus: true, + optIn: false, + optInStatusUrl: '', + sendUsageFrom: 'browser', + }, + reportOptInStatusChange: false, + notifications: coreStart.notifications, + http: coreSetup.http, + }); + + const component = mountWithIntl( + + ); + try { + expect( + component.setProps({ ...component.props(), query: { text: 'asssdasdsad' } }) + ).toMatchSnapshot(); + expect(onQueryMatchChange).toHaveBeenCalledWith(false); + expect(onQueryMatchChange).toHaveBeenCalledTimes(1); + } finally { + component.unmount(); + } + }); + + it('renders because query matches the SEARCH_TERMS', () => { + const onQueryMatchChange = jest.fn(); + const telemetryService = new TelemetryService({ + config: { + enabled: true, + url: '', + banner: true, + allowChangingOptInStatus: true, + optIn: false, + optInStatusUrl: '', + sendUsageFrom: 'browser', + }, + reportOptInStatusChange: false, + notifications: coreStart.notifications, + http: coreSetup.http, + }); + + const component = mountWithIntl( + + ); + try { + expect( + component.setProps({ ...component.props(), query: { text: 'TeLEMetry' } }).html() + ).not.toBe(''); // Renders something. + // I can't check against snapshot because of https://github.com/facebook/jest/issues/8618 + // expect(component).toMatchSnapshot(); + + // It should also render if there is no query at all. + expect(component.setProps({ ...component.props(), query: {} }).html()).not.toBe(''); + expect(onQueryMatchChange).toHaveBeenCalledWith(true); + + // Should only be called once because the second time does not change the result + expect(onQueryMatchChange).toHaveBeenCalledTimes(1); + } finally { + component.unmount(); + } + }); + + it('renders null because allowChangingOptInStatus is false', () => { + const onQueryMatchChange = jest.fn(); + const telemetryService = new TelemetryService({ + config: { + enabled: true, + url: '', + banner: true, + allowChangingOptInStatus: false, + optIn: true, + optInStatusUrl: '', + sendUsageFrom: 'browser', + }, + reportOptInStatusChange: false, + notifications: coreStart.notifications, + http: coreSetup.http, + }); + + const component = mountWithIntl( + + ); + try { + expect(component).toMatchSnapshot(); + component.setProps({ ...component.props(), query: { text: 'TeLEMetry' } }); + expect(onQueryMatchChange).toHaveBeenCalledWith(false); + } finally { + component.unmount(); + } + }); + + it('shows the OptInExampleFlyout', () => { + const onQueryMatchChange = jest.fn(); + const telemetryService = new TelemetryService({ + config: { + enabled: true, + url: '', + banner: true, + allowChangingOptInStatus: true, + optIn: false, + optInStatusUrl: '', + sendUsageFrom: 'browser', + }, + reportOptInStatusChange: false, + notifications: coreStart.notifications, + http: coreSetup.http, + }); + + const component = mountWithIntl( + + ); + try { + const toggleExampleComponent = component.find('p > EuiLink[onClick]'); + const updatedView = toggleExampleComponent.simulate('click'); + updatedView.find('OptInExampleFlyout'); + updatedView.simulate('close'); + } finally { + component.unmount(); + } + }); + + it('toggles the OptIn button', async () => { + const onQueryMatchChange = jest.fn(); + const telemetryService = new TelemetryService({ + config: { + enabled: true, + url: '', + banner: true, + allowChangingOptInStatus: true, + optIn: false, + optInStatusUrl: '', + sendUsageFrom: 'browser', + }, + reportOptInStatusChange: false, + notifications: coreStart.notifications, + http: coreSetup.http, + }); + + const component = mountWithIntl( + + ); + try { + const toggleOptInComponent = component.find('Field'); + await expect( + toggleOptInComponent.prop('handleChange')() + ).resolves.toBe(true); + expect((component.state() as any).enabled).toBe(true); + await expect( + toggleOptInComponent.prop('handleChange')() + ).resolves.toBe(true); + expect((component.state() as any).enabled).toBe(false); + telemetryService.setOptIn = jest.fn().mockRejectedValue(Error('test-error')); + await expect( + toggleOptInComponent.prop('handleChange')() + ).rejects.toStrictEqual(Error('test-error')); + } finally { + component.unmount(); + } + }); + + it('test the wrapper (for coverage purposes)', () => { + const onQueryMatchChange = jest.fn(); + const telemetryService = new TelemetryService({ + config: { + enabled: true, + url: '', + banner: true, + allowChangingOptInStatus: false, + optIn: false, + optInStatusUrl: '', + sendUsageFrom: 'browser', + }, + reportOptInStatusChange: false, + notifications: coreStart.notifications, + http: coreSetup.http, + }); + const Wrapper = telemetryManagementSectionWrapper(telemetryService); + expect( + shallowWithIntl( + + ).html() + ).toMatchSnapshot(); + }); +}); diff --git a/src/plugins/telemetry_management_section/public/components/telemetry_management_section.tsx b/src/plugins/telemetry_management_section/public/components/telemetry_management_section.tsx index 26e075b666593..361c5ff719c54 100644 --- a/src/plugins/telemetry_management_section/public/components/telemetry_management_section.tsx +++ b/src/plugins/telemetry_management_section/public/components/telemetry_management_section.tsx @@ -69,7 +69,9 @@ export class TelemetryManagementSection extends Component { const { query } = nextProps; const searchTerm = (query.text || '').toLowerCase(); - const searchTermMatches = SEARCH_TERMS.some(term => term.indexOf(searchTerm) >= 0); + const searchTermMatches = + this.props.telemetryService.getCanChangeOptInStatus() && + SEARCH_TERMS.some(term => term.indexOf(searchTerm) >= 0); if (searchTermMatches !== this.state.queryMatches) { this.setState( diff --git a/src/plugins/vis_type_table/public/get_inner_angular.ts b/src/plugins/vis_type_table/public/get_inner_angular.ts index d69b9bba31b03..e8404f918d609 100644 --- a/src/plugins/vis_type_table/public/get_inner_angular.ts +++ b/src/plugins/vis_type_table/public/get_inner_angular.ts @@ -21,6 +21,8 @@ // these are necessary to bootstrap the local angular. // They can stay even after NP cutover import angular from 'angular'; +// required for `ngSanitize` angular module +import 'angular-sanitize'; import 'angular-recursion'; import { i18nDirective, i18nFilter, I18nProvider } from '@kbn/i18n/angular'; import { CoreStart, IUiSettingsClient, PluginInitializerContext } from 'kibana/public'; diff --git a/src/plugins/vis_type_timeseries/public/application/components/vis_editor.js b/src/plugins/vis_type_timeseries/public/application/components/vis_editor.js index 7075e86eb56bf..9fdb8ccc919b7 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/vis_editor.js +++ b/src/plugins/vis_type_timeseries/public/application/components/vis_editor.js @@ -240,3 +240,7 @@ VisEditor.propTypes = { timeRange: PropTypes.object, appState: PropTypes.object, }; + +// default export required for React.Lazy +// eslint-disable-next-line import/no-default-export +export { VisEditor as default }; diff --git a/src/plugins/vis_type_timeseries/public/application/components/vis_editor_lazy.tsx b/src/plugins/vis_type_timeseries/public/application/components/vis_editor_lazy.tsx new file mode 100644 index 0000000000000..d81bd95d8d771 --- /dev/null +++ b/src/plugins/vis_type_timeseries/public/application/components/vis_editor_lazy.tsx @@ -0,0 +1,30 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { lazy, Suspense } from 'react'; +import { EuiLoadingSpinner } from '@elastic/eui'; + +// @ts-ignore +const VisEditorComponent = lazy(() => import('./vis_editor')); + +export const VisEditor = (props: any) => ( + }> + + +); diff --git a/src/plugins/vis_type_timeseries/public/application/editor_controller.js b/src/plugins/vis_type_timeseries/public/application/editor_controller.js index af50d3a06d1fc..f21b5f947bca7 100644 --- a/src/plugins/vis_type_timeseries/public/application/editor_controller.js +++ b/src/plugins/vis_type_timeseries/public/application/editor_controller.js @@ -21,7 +21,7 @@ import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; import { fetchIndexPatternFields } from './lib/fetch_fields'; import { getSavedObjectsClient, getUISettings, getI18n } from '../services'; -import { VisEditor } from './components/vis_editor'; +import { VisEditor } from './components/vis_editor_lazy'; export class EditorController { constructor(el, vis, eventEmitter, embeddableHandler) { diff --git a/src/plugins/vis_type_timeseries/public/metrics_fn.ts b/src/plugins/vis_type_timeseries/public/metrics_fn.ts index 008b13cce6565..b573225feaab1 100644 --- a/src/plugins/vis_type_timeseries/public/metrics_fn.ts +++ b/src/plugins/vis_type_timeseries/public/metrics_fn.ts @@ -20,7 +20,6 @@ import { get } from 'lodash'; import { i18n } from '@kbn/i18n'; import { ExpressionFunctionDefinition, KibanaContext, Render } from '../../expressions/public'; -import { PersistedState } from '../../visualizations/public'; // @ts-ignore import { metricsRequestHandler } from './request_handler'; @@ -76,6 +75,7 @@ export const createMetricsFn = (): ExpressionFunctionDefinition< const params = JSON.parse(args.params); const uiStateParams = JSON.parse(args.uiState); const savedObjectId = args.savedObjectId; + const { PersistedState } = await import('../../visualizations/public'); const uiState = new PersistedState(uiStateParams); const response = await metricsRequestHandler({ diff --git a/src/plugins/vis_type_timeseries/public/metrics_type.ts b/src/plugins/vis_type_timeseries/public/metrics_type.ts index c525ce7fa0b3b..2b0734ceb4d4d 100644 --- a/src/plugins/vis_type_timeseries/public/metrics_type.ts +++ b/src/plugins/vis_type_timeseries/public/metrics_type.ts @@ -25,6 +25,7 @@ import { EditorController } from './application'; // @ts-ignore import { PANEL_TYPES } from '../common/panel_types'; import { defaultFeedbackMessage } from '../../kibana_utils/public'; +import { VisEditor } from './application/components/vis_editor_lazy'; export const metricsVisDefinition = { name: 'metrics', @@ -69,7 +70,7 @@ export const metricsVisDefinition = { show_legend: 1, show_grid: 1, }, - component: require('./application/components/vis_editor').VisEditor, + component: VisEditor, }, editor: EditorController, options: { diff --git a/src/plugins/visualize/public/application/application.ts b/src/plugins/visualize/public/application/application.ts index 9d8a1b98ef023..19551bba9a43e 100644 --- a/src/plugins/visualize/public/application/application.ts +++ b/src/plugins/visualize/public/application/application.ts @@ -20,6 +20,8 @@ import './index.scss'; import angular, { IModule } from 'angular'; +// required for `ngSanitize` angular module +import 'angular-sanitize'; import { i18nDirective, i18nFilter, I18nProvider } from '@kbn/i18n/angular'; import { AppMountContext } from 'kibana/public'; diff --git a/tasks/config/karma.js b/tasks/config/karma.js index 1ec7c831b4864..f87edbf04f220 100644 --- a/tasks/config/karma.js +++ b/tasks/config/karma.js @@ -25,6 +25,7 @@ import { DllCompiler } from '../../src/optimize/dynamic_dll_plugin'; const TOTAL_CI_SHARDS = 4; const ROOT = dirname(require.resolve('../../package.json')); +const buildHash = String(Number.MAX_SAFE_INTEGER); module.exports = function(grunt) { function pickBrowser() { @@ -57,27 +58,30 @@ module.exports = function(grunt) { 'http://localhost:5610/test_bundle/karma/globals.js', ...UiSharedDeps.jsDepFilenames.map( - chunkFilename => `http://localhost:5610/bundles/kbn-ui-shared-deps/${chunkFilename}` + chunkFilename => + `http://localhost:5610/${buildHash}/bundles/kbn-ui-shared-deps/${chunkFilename}` ), - `http://localhost:5610/bundles/kbn-ui-shared-deps/${UiSharedDeps.jsFilename}`, + `http://localhost:5610/${buildHash}/bundles/kbn-ui-shared-deps/${UiSharedDeps.jsFilename}`, - 'http://localhost:5610/built_assets/dlls/vendors_runtime.bundle.dll.js', + `http://localhost:5610/${buildHash}/built_assets/dlls/vendors_runtime.bundle.dll.js`, ...DllCompiler.getRawDllConfig().chunks.map( - chunk => `http://localhost:5610/built_assets/dlls/vendors${chunk}.bundle.dll.js` + chunk => + `http://localhost:5610/${buildHash}/built_assets/dlls/vendors${chunk}.bundle.dll.js` ), shardNum === undefined - ? `http://localhost:5610/bundles/tests.bundle.js` - : `http://localhost:5610/bundles/tests.bundle.js?shards=${TOTAL_CI_SHARDS}&shard_num=${shardNum}`, + ? `http://localhost:5610/${buildHash}/bundles/tests.bundle.js` + : `http://localhost:5610/${buildHash}/bundles/tests.bundle.js?shards=${TOTAL_CI_SHARDS}&shard_num=${shardNum}`, - `http://localhost:5610/bundles/kbn-ui-shared-deps/${UiSharedDeps.baseCssDistFilename}`, + `http://localhost:5610/${buildHash}/bundles/kbn-ui-shared-deps/${UiSharedDeps.baseCssDistFilename}`, // this causes tilemap tests to fail, probably because the eui styles haven't been // included in the karma harness a long some time, if ever // `http://localhost:5610/bundles/kbn-ui-shared-deps/${UiSharedDeps.lightCssDistFilename}`, ...DllCompiler.getRawDllConfig().chunks.map( - chunk => `http://localhost:5610/built_assets/dlls/vendors${chunk}.style.dll.css` + chunk => + `http://localhost:5610/${buildHash}/built_assets/dlls/vendors${chunk}.style.dll.css` ), - 'http://localhost:5610/bundles/tests.style.css', + `http://localhost:5610/${buildHash}/bundles/tests.style.css`, ]; } @@ -127,9 +131,9 @@ module.exports = function(grunt) { proxies: { '/tests/': 'http://localhost:5610/tests/', - '/bundles/': 'http://localhost:5610/bundles/', - '/built_assets/dlls/': 'http://localhost:5610/built_assets/dlls/', '/test_bundle/': 'http://localhost:5610/test_bundle/', + [`/${buildHash}/bundles/`]: `http://localhost:5610/${buildHash}/bundles/`, + [`/${buildHash}/built_assets/dlls/`]: `http://localhost:5610/${buildHash}/built_assets/dlls/`, }, client: { diff --git a/test/api_integration/apis/index.js b/test/api_integration/apis/index.js index c5bfc847d0041..0c4028905657d 100644 --- a/test/api_integration/apis/index.js +++ b/test/api_integration/apis/index.js @@ -33,5 +33,6 @@ export default function({ loadTestFile }) { loadTestFile(require.resolve('./status')); loadTestFile(require.resolve('./stats')); loadTestFile(require.resolve('./ui_metric')); + loadTestFile(require.resolve('./telemetry')); }); } diff --git a/src/core/public/plugins/plugin_loader.mock.ts b/test/api_integration/apis/telemetry/index.js similarity index 57% rename from src/core/public/plugins/plugin_loader.mock.ts rename to test/api_integration/apis/telemetry/index.js index abdd9d4ddce2a..c79f5cb470890 100644 --- a/src/core/public/plugins/plugin_loader.mock.ts +++ b/test/api_integration/apis/telemetry/index.js @@ -17,17 +17,10 @@ * under the License. */ -import { PluginName } from 'src/core/server'; -import { LoadPluginBundle, UnknownPluginInitializer } from './plugin_loader'; - -/** - * @param initializerProvider A function provided by the test to resolve initializers. - */ -const createLoadPluginBundleMock = ( - initializerProvider: (name: PluginName) => UnknownPluginInitializer -): jest.Mock, Parameters> => - jest.fn((addBasePath, pluginName, _ = {}) => { - return Promise.resolve(initializerProvider(pluginName)) as any; +export default function({ loadTestFile }) { + describe('Telemetry', () => { + loadTestFile(require.resolve('./telemetry_local')); + loadTestFile(require.resolve('./opt_in')); + loadTestFile(require.resolve('./telemetry_optin_notice_seen')); }); - -export const loadPluginBundleMock = { create: createLoadPluginBundleMock }; +} diff --git a/test/api_integration/apis/telemetry/opt_in.ts b/test/api_integration/apis/telemetry/opt_in.ts new file mode 100644 index 0000000000000..e4654ee3985f3 --- /dev/null +++ b/test/api_integration/apis/telemetry/opt_in.ts @@ -0,0 +1,123 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import expect from '@kbn/expect'; + +import { TelemetrySavedObjectAttributes } from 'src/plugins/telemetry/server/telemetry_repository'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default function optInTest({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + const kibanaServer = getService('kibanaServer'); + describe('/api/telemetry/v2/optIn API', () => { + let defaultAttributes: TelemetrySavedObjectAttributes; + let kibanaVersion: any; + before(async () => { + const kibanaVersionAccessor = kibanaServer.version; + kibanaVersion = await kibanaVersionAccessor.get(); + defaultAttributes = + (await getSavedObjectAttributes(supertest).catch(err => { + if (err.message === 'expected 200 "OK", got 404 "Not Found"') { + return null; + } + throw err; + })) || {}; + + expect(typeof kibanaVersion).to.eql('string'); + expect(kibanaVersion.length).to.be.greaterThan(0); + }); + + afterEach(async () => { + await updateSavedObjectAttributes(supertest, defaultAttributes); + }); + + it('should support sending false with allowChangingOptInStatus true', async () => { + await updateSavedObjectAttributes(supertest, { + ...defaultAttributes, + allowChangingOptInStatus: true, + }); + await postTelemetryV2Optin(supertest, false, 200); + const { enabled, lastVersionChecked } = await getSavedObjectAttributes(supertest); + expect(enabled).to.be(false); + expect(lastVersionChecked).to.be(kibanaVersion); + }); + + it('should support sending true with allowChangingOptInStatus true', async () => { + await updateSavedObjectAttributes(supertest, { + ...defaultAttributes, + allowChangingOptInStatus: true, + }); + await postTelemetryV2Optin(supertest, true, 200); + const { enabled, lastVersionChecked } = await getSavedObjectAttributes(supertest); + expect(enabled).to.be(true); + expect(lastVersionChecked).to.be(kibanaVersion); + }); + + it('should not support sending false with allowChangingOptInStatus false', async () => { + await updateSavedObjectAttributes(supertest, { + ...defaultAttributes, + allowChangingOptInStatus: false, + }); + await postTelemetryV2Optin(supertest, false, 400); + }); + + it('should not support sending true with allowChangingOptInStatus false', async () => { + await updateSavedObjectAttributes(supertest, { + ...defaultAttributes, + allowChangingOptInStatus: false, + }); + await postTelemetryV2Optin(supertest, true, 400); + }); + + it('should not support sending null', async () => { + await postTelemetryV2Optin(supertest, null, 400); + }); + + it('should not support sending junk', async () => { + await postTelemetryV2Optin(supertest, 42, 400); + }); + }); +} + +async function postTelemetryV2Optin(supertest: any, value: any, statusCode: number): Promise { + const { body } = await supertest + .post('/api/telemetry/v2/optIn') + .set('kbn-xsrf', 'xxx') + .send({ enabled: value }) + .expect(statusCode); + + return body; +} + +async function updateSavedObjectAttributes( + supertest: any, + attributes: TelemetrySavedObjectAttributes +): Promise { + return await supertest + .post('/api/saved_objects/telemetry/telemetry') + .query({ overwrite: true }) + .set('kbn-xsrf', 'xxx') + .send({ attributes }) + .expect(200); +} + +async function getSavedObjectAttributes(supertest: any): Promise { + const { body } = await supertest.get('/api/saved_objects/telemetry/telemetry').expect(200); + return body.attributes; +} diff --git a/test/api_integration/apis/telemetry/telemetry_local.js b/test/api_integration/apis/telemetry/telemetry_local.js new file mode 100644 index 0000000000000..84bfd8a755c11 --- /dev/null +++ b/test/api_integration/apis/telemetry/telemetry_local.js @@ -0,0 +1,133 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import expect from '@kbn/expect'; +import _ from 'lodash'; + +/* + * Create a single-level array with strings for all the paths to values in the + * source object, up to 3 deep. Going deeper than 3 causes a bit too much churn + * in the tests. + */ +function flatKeys(source) { + const recursivelyFlatKeys = (obj, path = [], depth = 0) => { + return depth < 3 && _.isObject(obj) + ? _.map(obj, (v, k) => recursivelyFlatKeys(v, [...path, k], depth + 1)) + : path.join('.'); + }; + + return _.uniq(_.flattenDeep(recursivelyFlatKeys(source))).sort((a, b) => a.localeCompare(b)); +} + +export default function({ getService }) { + const supertest = getService('supertest'); + + describe('/api/telemetry/v2/clusters/_stats', () => { + it('should pull local stats and validate data types', async () => { + const timeRange = { + min: '2018-07-23T22:07:00Z', + max: '2018-07-23T22:13:00Z', + }; + + const { body } = await supertest + .post('/api/telemetry/v2/clusters/_stats') + .set('kbn-xsrf', 'xxx') + .send({ timeRange, unencrypted: true }) + .expect(200); + + expect(body.length).to.be(1); + const stats = body[0]; + expect(stats.collection).to.be('local'); + expect(stats.stack_stats.kibana.count).to.be.a('number'); + expect(stats.stack_stats.kibana.indices).to.be.a('number'); + expect(stats.stack_stats.kibana.os.platforms[0].platform).to.be.a('string'); + expect(stats.stack_stats.kibana.os.platforms[0].count).to.be(1); + expect(stats.stack_stats.kibana.os.platformReleases[0].platformRelease).to.be.a('string'); + expect(stats.stack_stats.kibana.os.platformReleases[0].count).to.be(1); + expect(stats.stack_stats.kibana.plugins.telemetry.opt_in_status).to.be(false); + expect(stats.stack_stats.kibana.plugins.telemetry.usage_fetcher).to.be.a('string'); + expect(stats.stack_stats.kibana.plugins.stack_management).to.be.an('object'); + expect(stats.stack_stats.kibana.plugins.ui_metric).to.be.an('object'); + expect(stats.stack_stats.kibana.plugins.application_usage).to.be.an('object'); + expect(stats.stack_stats.kibana.plugins.kql.defaultQueryLanguage).to.be.a('string'); + expect(stats.stack_stats.kibana.plugins['tsvb-validation']).to.be.an('object'); + expect(stats.stack_stats.kibana.plugins.localization).to.be.an('object'); + expect(stats.stack_stats.kibana.plugins.csp.strict).to.be(true); + expect(stats.stack_stats.kibana.plugins.csp.warnLegacyBrowsers).to.be(true); + expect(stats.stack_stats.kibana.plugins.csp.rulesChangedFromDefault).to.be(false); + }); + + it('should pull local stats and validate fields', async () => { + const timeRange = { + min: '2018-07-23T22:07:00Z', + max: '2018-07-23T22:13:00Z', + }; + + const { body } = await supertest + .post('/api/telemetry/v2/clusters/_stats') + .set('kbn-xsrf', 'xxx') + .send({ timeRange, unencrypted: true }) + .expect(200); + + const stats = body[0]; + + const actual = flatKeys(stats); + expect(actual).to.be.an('array'); + const expected = [ + 'cluster_name', + 'cluster_stats.cluster_uuid', + 'cluster_stats.indices.analysis', + 'cluster_stats.indices.completion', + 'cluster_stats.indices.count', + 'cluster_stats.indices.docs', + 'cluster_stats.indices.fielddata', + 'cluster_stats.indices.mappings', + 'cluster_stats.indices.query_cache', + 'cluster_stats.indices.segments', + 'cluster_stats.indices.shards', + 'cluster_stats.indices.store', + 'cluster_stats.nodes.count', + 'cluster_stats.nodes.discovery_types', + 'cluster_stats.nodes.fs', + 'cluster_stats.nodes.ingest', + 'cluster_stats.nodes.jvm', + 'cluster_stats.nodes.network_types', + 'cluster_stats.nodes.os', + 'cluster_stats.nodes.packaging_types', + 'cluster_stats.nodes.plugins', + 'cluster_stats.nodes.process', + 'cluster_stats.nodes.versions', + 'cluster_stats.status', + 'cluster_stats.timestamp', + 'cluster_uuid', + 'collection', + 'collectionSource', + 'stack_stats.kibana.count', + 'stack_stats.kibana.indices', + 'stack_stats.kibana.os', + 'stack_stats.kibana.plugins', + 'stack_stats.kibana.versions', + 'timestamp', + 'version', + ]; + + expect(expected.every(m => actual.includes(m))).to.be.ok(); + }); + }); +} diff --git a/test/api_integration/apis/telemetry/telemetry_optin_notice_seen.ts b/test/api_integration/apis/telemetry/telemetry_optin_notice_seen.ts new file mode 100644 index 0000000000000..4413c672fb46c --- /dev/null +++ b/test/api_integration/apis/telemetry/telemetry_optin_notice_seen.ts @@ -0,0 +1,59 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import expect from '@kbn/expect'; +import { Client, DeleteDocumentParams, GetParams, GetResponse } from 'elasticsearch'; +import { TelemetrySavedObjectAttributes } from 'src/plugins/telemetry/server/telemetry_repository'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default function optInTest({ getService }: FtrProviderContext) { + const client: Client = getService('legacyEs'); + const supertest = getService('supertest'); + + describe('/api/telemetry/v2/userHasSeenNotice API Telemetry User has seen OptIn Notice', () => { + it('should update telemetry setting field via PUT', async () => { + try { + await client.delete({ + index: '.kibana', + id: 'telemetry:telemetry', + } as DeleteDocumentParams); + } catch (err) { + if (err.statusCode !== 404) { + throw err; + } + } + + await supertest + .put('/api/telemetry/v2/userHasSeenNotice') + .set('kbn-xsrf', 'xxx') + .expect(200); + + const { + _source: { telemetry }, + }: GetResponse<{ + telemetry: TelemetrySavedObjectAttributes; + }> = await client.get({ + index: '.kibana', + id: 'telemetry:telemetry', + } as GetParams); + + expect(telemetry.userHasSeenNotice).to.be(true); + }); + }); +} diff --git a/test/functional/page_objects/common_page.ts b/test/functional/page_objects/common_page.ts index 862e5127bb670..93debdcc37f0a 100644 --- a/test/functional/page_objects/common_page.ts +++ b/test/functional/page_objects/common_page.ts @@ -44,6 +44,7 @@ export function CommonPageProvider({ getService, getPageObjects }: FtrProviderCo ensureCurrentUrl: boolean; shouldLoginIfPrompted: boolean; useActualUrl: boolean; + insertTimestamp: boolean; } class CommonPage { @@ -65,7 +66,7 @@ export function CommonPageProvider({ getService, getPageObjects }: FtrProviderCo * Logins to Kibana as default user and navigates to provided app * @param appUrl Kibana URL */ - private async loginIfPrompted(appUrl: string) { + private async loginIfPrompted(appUrl: string, insertTimestamp: boolean) { let currentUrl = await browser.getCurrentUrl(); log.debug(`currentUrl = ${currentUrl}\n appUrl = ${appUrl}`); await testSubjects.find('kibanaChrome', 6 * defaultFindTimeout); // 60 sec waiting @@ -87,7 +88,7 @@ export function CommonPageProvider({ getService, getPageObjects }: FtrProviderCo '[data-test-subj="kibanaChrome"] nav:not(.ng-hide)', 6 * defaultFindTimeout ); - await browser.get(appUrl); + await browser.get(appUrl, insertTimestamp); currentUrl = await browser.getCurrentUrl(); log.debug(`Finished login process currentUrl = ${currentUrl}`); } @@ -95,7 +96,13 @@ export function CommonPageProvider({ getService, getPageObjects }: FtrProviderCo } private async navigate(navigateProps: NavigateProps) { - const { appConfig, ensureCurrentUrl, shouldLoginIfPrompted, useActualUrl } = navigateProps; + const { + appConfig, + ensureCurrentUrl, + shouldLoginIfPrompted, + useActualUrl, + insertTimestamp, + } = navigateProps; const appUrl = getUrl.noAuth(config.get('servers.kibana'), appConfig); await retry.try(async () => { @@ -111,7 +118,7 @@ export function CommonPageProvider({ getService, getPageObjects }: FtrProviderCo } const currentUrl = shouldLoginIfPrompted - ? await this.loginIfPrompted(appUrl) + ? await this.loginIfPrompted(appUrl, insertTimestamp) : await browser.getCurrentUrl(); if (ensureCurrentUrl && !currentUrl.includes(appUrl)) { @@ -134,6 +141,7 @@ export function CommonPageProvider({ getService, getPageObjects }: FtrProviderCo ensureCurrentUrl = true, shouldLoginIfPrompted = true, useActualUrl = false, + insertTimestamp = true, } = {} ) { const appConfig = { @@ -146,6 +154,7 @@ export function CommonPageProvider({ getService, getPageObjects }: FtrProviderCo ensureCurrentUrl, shouldLoginIfPrompted, useActualUrl, + insertTimestamp, }); } @@ -165,6 +174,7 @@ export function CommonPageProvider({ getService, getPageObjects }: FtrProviderCo ensureCurrentUrl = true, shouldLoginIfPrompted = true, useActualUrl = true, + insertTimestamp = true, } = {} ) { const appConfig = { @@ -178,6 +188,7 @@ export function CommonPageProvider({ getService, getPageObjects }: FtrProviderCo ensureCurrentUrl, shouldLoginIfPrompted, useActualUrl, + insertTimestamp, }); } @@ -208,7 +219,7 @@ export function CommonPageProvider({ getService, getPageObjects }: FtrProviderCo async navigateToApp( appName: string, - { basePath = '', shouldLoginIfPrompted = true, hash = '' } = {} + { basePath = '', shouldLoginIfPrompted = true, hash = '', insertTimestamp = true } = {} ) { let appUrl: string; if (config.has(['apps', appName])) { @@ -239,7 +250,7 @@ export function CommonPageProvider({ getService, getPageObjects }: FtrProviderCo log.debug('returned from get, calling refresh'); await browser.refresh(); let currentUrl = shouldLoginIfPrompted - ? await this.loginIfPrompted(appUrl) + ? await this.loginIfPrompted(appUrl, insertTimestamp) : await browser.getCurrentUrl(); if (currentUrl.includes('app/kibana')) { diff --git a/test/scripts/jenkins_xpack.sh b/test/scripts/jenkins_xpack.sh index 67d88b308ed91..951ba8e22d885 100755 --- a/test/scripts/jenkins_xpack.sh +++ b/test/scripts/jenkins_xpack.sh @@ -39,7 +39,7 @@ else # build runtime for canvas echo "NODE_ENV=$NODE_ENV" node ./legacy/plugins/canvas/scripts/shareable_runtime - node --max-old-space-size=6144 scripts/jest --ci --verbose --coverage + node --max-old-space-size=6144 scripts/jest --ci --verbose --detectOpenHandles --coverage # rename file in order to be unique one test -f ../target/kibana-coverage/jest/coverage-final.json \ && mv ../target/kibana-coverage/jest/coverage-final.json \ diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json index ae1a55254c702..4acb170d12574 100644 --- a/x-pack/.i18nrc.json +++ b/x-pack/.i18nrc.json @@ -43,7 +43,7 @@ "xpack.transform": "plugins/transform", "xpack.triggersActionsUI": "plugins/triggers_actions_ui", "xpack.upgradeAssistant": "plugins/upgrade_assistant", - "xpack.uptime": ["plugins/uptime", "legacy/plugins/uptime"], + "xpack.uptime": ["plugins/uptime"], "xpack.watcher": "plugins/watcher" }, "translations": [ diff --git a/x-pack/dev-tools/jest/create_jest_config.js b/x-pack/dev-tools/jest/create_jest_config.js index af5ace8e3cd3b..4f1251321b005 100644 --- a/x-pack/dev-tools/jest/create_jest_config.js +++ b/x-pack/dev-tools/jest/create_jest_config.js @@ -34,6 +34,20 @@ export function createJestConfig({ kibanaDirectory, xPackKibanaDirectory }) { '^test_utils/stub_web_worker': `${xPackKibanaDirectory}/test_utils/stub_web_worker.ts`, '^(!!)?file-loader!': fileMockPath, }, + collectCoverageFrom: [ + 'legacy/plugins/**/*.{js,jsx,ts,tsx}', + 'legacy/server/**/*.{js,jsx,ts,tsx}', + 'plugins/**/*.{js,jsx,ts,tsx}', + '!**/{__test__,__snapshots__,__examples__,integration_tests,tests}/**', + '!**/*.test.{js,ts,tsx}', + '!**/flot-charts/**', + '!**/test/**', + '!**/build/**', + '!**/scripts/**', + '!**/mocks/**', + '!**/plugins/apm/e2e/**', + ], + coveragePathIgnorePatterns: ['.*\\.d\\.ts'], coverageDirectory: '/../target/kibana-coverage/jest', coverageReporters: !!process.env.CODE_COVERAGE ? ['json'] : ['html'], setupFiles: [ diff --git a/x-pack/index.js b/x-pack/index.js index fe4c325405933..cfadddac3994a 100644 --- a/x-pack/index.js +++ b/x-pack/index.js @@ -16,12 +16,8 @@ import { spaces } from './legacy/plugins/spaces'; import { canvas } from './legacy/plugins/canvas'; import { infra } from './legacy/plugins/infra'; import { taskManager } from './legacy/plugins/task_manager'; -import { uptime } from './legacy/plugins/uptime'; import { encryptedSavedObjects } from './legacy/plugins/encrypted_saved_objects'; -import { actions } from './legacy/plugins/actions'; -import { alerting } from './legacy/plugins/alerting'; import { ingestManager } from './legacy/plugins/ingest_manager'; -import { triggersActionsUI } from './legacy/plugins/triggers_actions_ui'; module.exports = function(kibana) { return [ @@ -37,11 +33,7 @@ module.exports = function(kibana) { canvas(kibana), infra(kibana), taskManager(kibana), - uptime(kibana), encryptedSavedObjects(kibana), - actions(kibana), - alerting(kibana), ingestManager(kibana), - triggersActionsUI(kibana), ]; }; diff --git a/x-pack/legacy/plugins/actions/server/index.ts b/x-pack/legacy/plugins/actions/server/index.ts deleted file mode 100644 index 63dd6f99f9c24..0000000000000 --- a/x-pack/legacy/plugins/actions/server/index.ts +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -import { Root } from 'joi'; -import { Legacy } from 'kibana'; -import mappings from './mappings.json'; -import { - LegacyPluginApi, - LegacyPluginSpec, - ArrayOrItem, -} from '../../../../../src/legacy/plugin_discovery/types'; - -export function actions(kibana: LegacyPluginApi): ArrayOrItem { - return new kibana.Plugin({ - id: 'actions', - configPrefix: 'xpack.actions', - config(Joi: Root) { - return Joi.object({ - enabled: Joi.boolean().default(true), - }) - .unknown(true) - .default(); - }, - require: ['kibana', 'elasticsearch'], - isEnabled(config: Legacy.KibanaConfig) { - return ( - config.get('xpack.encryptedSavedObjects.enabled') === true && - config.get('xpack.actions.enabled') === true && - config.get('xpack.task_manager.enabled') === true - ); - }, - uiExports: { - mappings, - }, - } as Legacy.PluginSpecOptions); -} diff --git a/x-pack/legacy/plugins/alerting/server/index.ts b/x-pack/legacy/plugins/alerting/server/index.ts deleted file mode 100644 index 065af7dedebd9..0000000000000 --- a/x-pack/legacy/plugins/alerting/server/index.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { Legacy } from 'kibana'; -import { Root } from 'joi'; -import mappings from './mappings.json'; -import { - LegacyPluginApi, - LegacyPluginSpec, - ArrayOrItem, -} from '../../../../../src/legacy/plugin_discovery/types'; - -export function alerting(kibana: LegacyPluginApi): ArrayOrItem { - return new kibana.Plugin({ - id: 'alerting', - configPrefix: 'xpack.alerting', - require: ['kibana', 'elasticsearch', 'actions', 'task_manager', 'encryptedSavedObjects'], - isEnabled(config: Legacy.KibanaConfig) { - return ( - config.get('xpack.alerting.enabled') === true && - config.get('xpack.actions.enabled') === true && - config.get('xpack.encryptedSavedObjects.enabled') === true && - config.get('xpack.task_manager.enabled') === true - ); - }, - config(Joi: Root) { - return Joi.object() - .keys({ - enabled: Joi.boolean().default(true), - }) - .default(); - }, - uiExports: { - mappings, - }, - } as Legacy.PluginSpecOptions); -} diff --git a/x-pack/legacy/plugins/canvas/public/components/app/track_route_change.js b/x-pack/legacy/plugins/canvas/public/components/app/track_route_change.js index e837f5200a159..2886aa868eb9e 100644 --- a/x-pack/legacy/plugins/canvas/public/components/app/track_route_change.js +++ b/x-pack/legacy/plugins/canvas/public/components/app/track_route_change.js @@ -7,13 +7,17 @@ import { get } from 'lodash'; import { getWindow } from '../../lib/get_window'; import { CANVAS_APP } from '../../../common/lib/constants'; -import { getCoreStart, getStartPlugins } from '../../legacy'; +import { platformService } from '../../services'; export function trackRouteChange() { - const basePath = getCoreStart().http.basePath.get(); - // storage.set(LOCALSTORAGE_LASTPAGE, pathname); - getStartPlugins().__LEGACY.trackSubUrlForApp( - CANVAS_APP, - getStartPlugins().__LEGACY.absoluteToParsedUrl(get(getWindow(), 'location.href'), basePath) - ); + const basePath = platformService.getService().coreStart.http.basePath.get(); + + platformService + .getService() + .startPlugins.__LEGACY.trackSubUrlForApp( + CANVAS_APP, + platformService + .getService() + .startPlugins.__LEGACY.absoluteToParsedUrl(get(getWindow(), 'location.href'), basePath) + ); } diff --git a/x-pack/legacy/plugins/canvas/public/legacy.ts b/x-pack/legacy/plugins/canvas/public/legacy.ts index 5bb628909c32e..f83887bbcbdfd 100644 --- a/x-pack/legacy/plugins/canvas/public/legacy.ts +++ b/x-pack/legacy/plugins/canvas/public/legacy.ts @@ -35,8 +35,6 @@ const shimStartPlugins: CanvasStartDeps = { __LEGACY: { // ToDo: Copy directly into canvas absoluteToParsedUrl, - // ToDo: Copy directly into canvas - formatMsg, // ToDo: Won't be a part of New Platform. Will need to handle internally trackSubUrlForApp: chrome.trackSubUrlForApp, }, diff --git a/x-pack/legacy/plugins/canvas/public/lib/breadcrumbs.ts b/x-pack/legacy/plugins/canvas/public/lib/breadcrumbs.ts index 834d5868c35ea..57b513affd781 100644 --- a/x-pack/legacy/plugins/canvas/public/lib/breadcrumbs.ts +++ b/x-pack/legacy/plugins/canvas/public/lib/breadcrumbs.ts @@ -5,7 +5,7 @@ */ import { ChromeBreadcrumb } from '../../../../../../src/core/public'; -import { getCoreStart } from '../legacy'; +import { platformService } from '../services'; export const getBaseBreadcrumb = () => ({ text: 'Canvas', @@ -24,6 +24,6 @@ export const getWorkpadBreadcrumb = ({ }; export const setBreadcrumb = (paths: ChromeBreadcrumb | ChromeBreadcrumb[]) => { - const setBreadCrumbs = getCoreStart().chrome.setBreadcrumbs; + const setBreadCrumbs = platformService.getService().coreStart.chrome.setBreadcrumbs; setBreadCrumbs(Array.isArray(paths) ? paths : [paths]); }; diff --git a/x-pack/legacy/plugins/canvas/public/lib/custom_element_service.ts b/x-pack/legacy/plugins/canvas/public/lib/custom_element_service.ts index 4118bb81b8363..8952802dc2f2b 100644 --- a/x-pack/legacy/plugins/canvas/public/lib/custom_element_service.ts +++ b/x-pack/legacy/plugins/canvas/public/lib/custom_element_service.ts @@ -8,10 +8,10 @@ import { AxiosPromise } from 'axios'; import { API_ROUTE_CUSTOM_ELEMENT } from '../../common/lib/constants'; import { fetch } from '../../common/lib/fetch'; import { CustomElement } from '../../types'; -import { getCoreStart } from '../legacy'; +import { platformService } from '../services'; const getApiPath = function() { - const basePath = getCoreStart().http.basePath.get(); + const basePath = platformService.getService().coreStart.http.basePath.get(); return `${basePath}${API_ROUTE_CUSTOM_ELEMENT}`; }; diff --git a/x-pack/legacy/plugins/canvas/public/lib/documentation_links.ts b/x-pack/legacy/plugins/canvas/public/lib/documentation_links.ts index 40e09ee39d714..6430f7d87d4f7 100644 --- a/x-pack/legacy/plugins/canvas/public/lib/documentation_links.ts +++ b/x-pack/legacy/plugins/canvas/public/lib/documentation_links.ts @@ -4,13 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ -import { getCoreStart } from '../legacy'; +import { platformService } from '../services'; export const getDocumentationLinks = () => ({ - canvas: `${getCoreStart().docLinks.ELASTIC_WEBSITE_URL}guide/en/kibana/${ - getCoreStart().docLinks.DOC_LINK_VERSION + canvas: `${platformService.getService().coreStart.docLinks.ELASTIC_WEBSITE_URL}guide/en/kibana/${ + platformService.getService().coreStart.docLinks.DOC_LINK_VERSION }/canvas.html`, - numeral: `${getCoreStart().docLinks.ELASTIC_WEBSITE_URL}guide/en/kibana/${ - getCoreStart().docLinks.DOC_LINK_VERSION + numeral: `${platformService.getService().coreStart.docLinks.ELASTIC_WEBSITE_URL}guide/en/kibana/${ + platformService.getService().coreStart.docLinks.DOC_LINK_VERSION }/guide/numeral.html`, }); diff --git a/x-pack/legacy/plugins/canvas/public/lib/es_service.ts b/x-pack/legacy/plugins/canvas/public/lib/es_service.ts index 6aa4968f29155..184f4f3c8af7c 100644 --- a/x-pack/legacy/plugins/canvas/public/lib/es_service.ts +++ b/x-pack/legacy/plugins/canvas/public/lib/es_service.ts @@ -11,21 +11,21 @@ import { API_ROUTE } from '../../common/lib/constants'; import { fetch } from '../../common/lib/fetch'; import { ErrorStrings } from '../../i18n'; import { notifyService } from '../services'; -import { getCoreStart } from '../legacy'; +import { platformService } from '../services'; const { esService: strings } = ErrorStrings; const getApiPath = function() { - const basePath = getCoreStart().http.basePath.get(); + const basePath = platformService.getService().coreStart.http.basePath.get(); return basePath + API_ROUTE; }; const getSavedObjectsClient = function() { - return getCoreStart().savedObjects.client; + return platformService.getService().coreStart.savedObjects.client; }; const getAdvancedSettings = function() { - return getCoreStart().uiSettings; + return platformService.getService().coreStart.uiSettings; }; export const getFields = (index = '_all') => { diff --git a/x-pack/legacy/plugins/canvas/public/lib/workpad_service.js b/x-pack/legacy/plugins/canvas/public/lib/workpad_service.js index f3681f50c56a5..e6628399f53c2 100644 --- a/x-pack/legacy/plugins/canvas/public/lib/workpad_service.js +++ b/x-pack/legacy/plugins/canvas/public/lib/workpad_service.js @@ -11,7 +11,7 @@ import { DEFAULT_WORKPAD_CSS, } from '../../common/lib/constants'; import { fetch } from '../../common/lib/fetch'; -import { getCoreStart } from '../legacy'; +import { platformService } from '../services'; /* Remove any top level keys from the workpad which will be rejected by validation */ @@ -43,17 +43,17 @@ const sanitizeWorkpad = function(workpad) { }; const getApiPath = function() { - const basePath = getCoreStart().http.basePath.get(); + const basePath = platformService.getService().coreStart.http.basePath.get(); return `${basePath}${API_ROUTE_WORKPAD}`; }; const getApiPathStructures = function() { - const basePath = getCoreStart().http.basePath.get(); + const basePath = platformService.getService().coreStart.http.basePath.get(); return `${basePath}${API_ROUTE_WORKPAD_STRUCTURES}`; }; const getApiPathAssets = function() { - const basePath = getCoreStart().http.basePath.get(); + const basePath = platformService.getService().coreStart.http.basePath.get(); return `${basePath}${API_ROUTE_WORKPAD_ASSETS}`; }; diff --git a/x-pack/legacy/plugins/canvas/public/plugin.tsx b/x-pack/legacy/plugins/canvas/public/plugin.tsx index 36ce1974be272..baeb4ebd453d2 100644 --- a/x-pack/legacy/plugins/canvas/public/plugin.tsx +++ b/x-pack/legacy/plugins/canvas/public/plugin.tsx @@ -44,7 +44,6 @@ export interface CanvasStartDeps { uiActions: UiActionsStart; __LEGACY: { absoluteToParsedUrl: (url: string, basePath: string) => any; - formatMsg: any; trackSubUrlForApp: Chrome['trackSubUrlForApp']; }; } @@ -64,6 +63,7 @@ export class CanvasPlugin implements Plugin { // TODO: Do we want to completely move canvas_plugin_src into it's own plugin? private srcPlugin = new CanvasSrcPlugin(); + private startPlugins: CanvasStartDeps | undefined; public setup(core: CoreSetup, plugins: CanvasSetupDeps) { const { api: canvasApi, registries } = getPluginApi(plugins.expressions); @@ -73,14 +73,26 @@ export class CanvasPlugin core.application.register({ id: 'canvas', title: 'Canvas App', - async mount(context, params) { + mount: async (context, params) => { // Load application bundle const { renderApp, initializeCanvas, teardownCanvas } = await import('./application'); // Get start services const [coreStart, depsStart] = await core.getStartServices(); - const canvasStore = await initializeCanvas(core, coreStart, plugins, depsStart, registries); + // TODO: We only need this to get the __LEGACY stuff that isn't coming from getStartSevices. + // We won't need this as soon as we move over to NP Completely + if (!this.startPlugins) { + throw new Error('Start Plugins not ready at mount time'); + } + + const canvasStore = await initializeCanvas( + core, + coreStart, + plugins, + this.startPlugins, + registries + ); const unmount = renderApp(coreStart, depsStart, params, canvasStore); @@ -115,6 +127,7 @@ export class CanvasPlugin } public start(core: CoreStart, plugins: CanvasStartDeps) { + this.startPlugins = plugins; this.srcPlugin.start(core, plugins); initLoadingIndicator(core.http.addLoadingCountSource); } diff --git a/x-pack/legacy/plugins/canvas/public/services/index.ts b/x-pack/legacy/plugins/canvas/public/services/index.ts index 12c0a687bf308..17d836f1441c9 100644 --- a/x-pack/legacy/plugins/canvas/public/services/index.ts +++ b/x-pack/legacy/plugins/canvas/public/services/index.ts @@ -7,6 +7,7 @@ import { CoreSetup, CoreStart } from '../../../../../../src/core/public'; import { CanvasSetupDeps, CanvasStartDeps } from '../plugin'; import { notifyServiceFactory } from './notify'; +import { platformServiceFactory } from './platform'; export type CanvasServiceFactory = ( coreSetup: CoreSetup, @@ -49,6 +50,7 @@ export type ServiceFromProvider

= P extends CanvasServiceProvider ? export const services = { notify: new CanvasServiceProvider(notifyServiceFactory), + platform: new CanvasServiceProvider(platformServiceFactory), }; export interface CanvasServices { @@ -70,4 +72,4 @@ export const stopServices = () => { Object.entries(services).forEach(([key, provider]) => provider.stop()); }; -export const { notify: notifyService } = services; +export const { notify: notifyService, platform: platformService } = services; diff --git a/x-pack/legacy/plugins/canvas/public/services/platform.ts b/x-pack/legacy/plugins/canvas/public/services/platform.ts new file mode 100644 index 0000000000000..440e9523044c1 --- /dev/null +++ b/x-pack/legacy/plugins/canvas/public/services/platform.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { CanvasServiceFactory } from '.'; +import { CoreStart, CoreSetup, CanvasSetupDeps, CanvasStartDeps } from '../plugin'; + +interface PlatformService { + coreSetup: CoreSetup; + coreStart: CoreStart; + setupPlugins: CanvasSetupDeps; + startPlugins: CanvasStartDeps; +} + +export const platformServiceFactory: CanvasServiceFactory = ( + coreSetup, + coreStart, + setupPlugins, + startPlugins +) => { + return { coreSetup, coreStart, setupPlugins, startPlugins }; +}; diff --git a/x-pack/legacy/plugins/canvas/public/state/initial_state.js b/x-pack/legacy/plugins/canvas/public/state/initial_state.js index 40c017543147f..bfa68b33908e0 100644 --- a/x-pack/legacy/plugins/canvas/public/state/initial_state.js +++ b/x-pack/legacy/plugins/canvas/public/state/initial_state.js @@ -5,7 +5,7 @@ */ import { get } from 'lodash'; -import { getCoreStart } from '../legacy'; +import { platformService } from '../services'; import { getDefaultWorkpad } from './defaults'; export const getInitialState = path => { @@ -13,7 +13,7 @@ export const getInitialState = path => { app: {}, // Kibana stuff in here assets: {}, // assets end up here transient: { - canUserWrite: getCoreStart().application.capabilities.canvas.save, + canUserWrite: platformService.getService().coreStart.application.capabilities.canvas.save, zoomScale: 1, elementStats: { total: 0, diff --git a/x-pack/legacy/plugins/canvas/public/state/reducers/workpad.js b/x-pack/legacy/plugins/canvas/public/state/reducers/workpad.js index 12733680ed32d..30f9c638a054f 100644 --- a/x-pack/legacy/plugins/canvas/public/state/reducers/workpad.js +++ b/x-pack/legacy/plugins/canvas/public/state/reducers/workpad.js @@ -5,7 +5,7 @@ */ import { handleActions } from 'redux-actions'; -import { getCoreStart } from '../../legacy'; +import { platformService } from '../../services'; import { getDefaultWorkpad } from '../defaults'; import { setWorkpad, @@ -22,11 +22,13 @@ import { APP_ROUTE_WORKPAD } from '../../../common/lib/constants'; export const workpadReducer = handleActions( { [setWorkpad]: (workpadState, { payload }) => { - getCoreStart().chrome.recentlyAccessed.add( - `${APP_ROUTE_WORKPAD}/${payload.id}`, - payload.name, - payload.id - ); + platformService + .getService() + .coreStart.chrome.recentlyAccessed.add( + `${APP_ROUTE_WORKPAD}/${payload.id}`, + payload.name, + payload.id + ); return payload; }, @@ -39,11 +41,13 @@ export const workpadReducer = handleActions( }, [setName]: (workpadState, { payload }) => { - getCoreStart().chrome.recentlyAccessed.add( - `${APP_ROUTE_WORKPAD}/${workpadState.id}`, - payload, - workpadState.id - ); + platformService + .getService() + .coreStart.chrome.recentlyAccessed.add( + `${APP_ROUTE_WORKPAD}/${workpadState.id}`, + payload, + workpadState.id + ); return { ...workpadState, name: payload }; }, diff --git a/x-pack/legacy/plugins/maps/index.js b/x-pack/legacy/plugins/maps/index.js index d1e8892fa2c98..a1186e04ee27a 100644 --- a/x-pack/legacy/plugins/maps/index.js +++ b/x-pack/legacy/plugins/maps/index.js @@ -54,7 +54,7 @@ export function maps(kibana) { emsLandingPageUrl: mapConfig.emsLandingPageUrl, kbnPkgVersion: serverConfig.get('pkg.version'), regionmapLayers: _.get(mapConfig, 'regionmap.layers', []), - tilemap: _.get(mapConfig, 'tilemap', []), + tilemap: _.get(mapConfig, 'tilemap', {}), }; }, styleSheetPaths: `${__dirname}/public/index.scss`, diff --git a/x-pack/legacy/plugins/monitoring/common/constants.ts b/x-pack/legacy/plugins/monitoring/common/constants.ts index 3a4c7b71dcd03..36030e1fa7f2a 100644 --- a/x-pack/legacy/plugins/monitoring/common/constants.ts +++ b/x-pack/legacy/plugins/monitoring/common/constants.ts @@ -251,7 +251,7 @@ export const ALERT_TYPES = [ALERT_TYPE_LICENSE_EXPIRATION, ALERT_TYPE_CLUSTER_ST /** * Matches the id for the built-in in email action type - * See x-pack/legacy/plugins/actions/server/builtin_action_types/email.ts + * See x-pack/plugins/actions/server/builtin_action_types/email.ts */ export const ALERT_ACTION_TYPE_EMAIL = '.email'; diff --git a/x-pack/legacy/plugins/monitoring/public/np_imports/angular/modules.ts b/x-pack/legacy/plugins/monitoring/public/np_imports/angular/modules.ts index a047c25c2b1d7..c6031cb220334 100644 --- a/x-pack/legacy/plugins/monitoring/public/np_imports/angular/modules.ts +++ b/x-pack/legacy/plugins/monitoring/public/np_imports/angular/modules.ts @@ -5,6 +5,8 @@ */ import angular, { IWindowService } from 'angular'; +// required for `ngSanitize` angular module +import 'angular-sanitize'; import { i18nDirective, i18nFilter, I18nProvider } from '@kbn/i18n/angular'; import { AppMountContext } from 'kibana/public'; diff --git a/x-pack/legacy/plugins/security/index.ts b/x-pack/legacy/plugins/security/index.ts index 5b2218af1fd52..b1dec2ce82c52 100644 --- a/x-pack/legacy/plugins/security/index.ts +++ b/x-pack/legacy/plugins/security/index.ts @@ -78,9 +78,7 @@ export const security = (kibana: Record) => // features are up to date. xpackInfo .feature(this.id) - .registerLicenseCheckResultsGenerator(() => - securityPlugin.__legacyCompat.license.getFeatures() - ); + .registerLicenseCheckResultsGenerator(() => securityPlugin.license.getFeatures()); server.expose({ getUser: async (request: LegacyRequest) => diff --git a/x-pack/legacy/plugins/task_manager/server/index.ts b/x-pack/legacy/plugins/task_manager/server/index.ts index 3ea687f7003f4..a3167920efa06 100644 --- a/x-pack/legacy/plugins/task_manager/server/index.ts +++ b/x-pack/legacy/plugins/task_manager/server/index.ts @@ -6,8 +6,6 @@ import { Root } from 'joi'; import { Legacy } from 'kibana'; -import mappings from './mappings.json'; -import { migrations } from './migrations'; import { createLegacyApi, getTaskManagerSetup } from './legacy'; export { LegacyTaskManagerApi, getTaskManagerSetup, getTaskManagerStart } from './legacy'; @@ -21,19 +19,6 @@ import { ArrayOrItem, } from '../../../../../src/legacy/plugin_discovery/types'; -const savedObjectSchemas = { - task: { - hidden: true, - isNamespaceAgnostic: true, - convertToAliasScript: `ctx._id = ctx._source.type + ':' + ctx._id`, - // legacy config is marked as any in core, no choice here - // eslint-disable-next-line @typescript-eslint/no-explicit-any - indexPattern(config: any) { - return config.get('xpack.task_manager.index'); - }, - }, -}; - export function taskManager(kibana: LegacyPluginApi): ArrayOrItem { return new kibana.Plugin({ id: 'task_manager', @@ -58,7 +43,7 @@ export function taskManager(kibana: LegacyPluginApi): ArrayOrItem { // we can't tell the Kibana Platform Task Manager plugin to // to wait to `start` as that happens before legacy plugins @@ -77,10 +62,5 @@ export function taskManager(kibana: LegacyPluginApi): ArrayOrItem - new kibana.Plugin({ - configPrefix: 'xpack.uptime', - id: PLUGIN.ID, - publicDir: resolve(__dirname, 'public'), - require: ['alerting', 'kibana', 'elasticsearch', 'xpack_main'], - uiExports: { - app: { - description: i18n.translate('xpack.uptime.pluginDescription', { - defaultMessage: 'Uptime monitoring', - description: 'The description text that will be shown to users in Kibana', - }), - icon: 'plugins/uptime/icons/heartbeat_white.svg', - euiIconType: 'uptimeApp', - title: i18n.translate('xpack.uptime.uptimeFeatureCatalogueTitle', { - defaultMessage: 'Uptime', - }), - main: 'plugins/uptime/app', - order: 8900, - url: '/app/uptime#/', - category: DEFAULT_APP_CATEGORIES.observability, - }, - home: ['plugins/uptime/register_feature'], - }, - }); diff --git a/x-pack/legacy/plugins/uptime/public/apps/index.ts b/x-pack/legacy/plugins/uptime/public/apps/index.ts deleted file mode 100644 index d58bf8398fcde..0000000000000 --- a/x-pack/legacy/plugins/uptime/public/apps/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { npSetup } from 'ui/new_platform'; -import { Plugin } from './plugin'; -import 'uiExports/embeddableFactories'; - -const plugin = new Plugin({ - opaqueId: Symbol('uptime'), - env: {} as any, - config: { get: () => ({} as any) }, -}); -plugin.setup(npSetup); diff --git a/x-pack/legacy/plugins/uptime/public/apps/plugin.ts b/x-pack/legacy/plugins/uptime/public/apps/plugin.ts deleted file mode 100644 index e73598c44c9f0..0000000000000 --- a/x-pack/legacy/plugins/uptime/public/apps/plugin.ts +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { LegacyCoreSetup, PluginInitializerContext, AppMountParameters } from 'src/core/public'; -import { PluginsSetup } from 'ui/new_platform/new_platform'; -import { FeatureCatalogueCategory } from '../../../../../../src/plugins/home/public'; -import { UMFrontendLibs } from '../lib/lib'; -import { PLUGIN } from '../../common/constants'; -import { getKibanaFrameworkAdapter } from '../lib/adapters/framework/new_platform_adapter'; - -export interface SetupObject { - core: LegacyCoreSetup; - plugins: PluginsSetup; -} - -export class Plugin { - constructor( - // @ts-ignore this is added to satisfy the New Platform typing constraint, - // but we're not leveraging any of its functionality yet. - private readonly initializerContext: PluginInitializerContext - ) {} - - public setup(setup: SetupObject) { - const { core, plugins } = setup; - const { home } = plugins; - - home.featureCatalogue.register({ - category: FeatureCatalogueCategory.DATA, - description: PLUGIN.DESCRIPTION, - icon: 'uptimeApp', - id: PLUGIN.ID, - path: '/app/uptime#/', - showOnHomePage: true, - title: PLUGIN.TITLE, - }); - - core.application.register({ - id: PLUGIN.ID, - euiIconType: 'uptimeApp', - order: 8900, - title: 'Uptime', - async mount(params: AppMountParameters) { - const [coreStart] = await core.getStartServices(); - const { element } = params; - const libs: UMFrontendLibs = { - framework: getKibanaFrameworkAdapter(coreStart, plugins), - }; - libs.framework.render(element); - return () => {}; - }, - }); - } -} diff --git a/x-pack/legacy/plugins/uptime/public/register_feature.ts b/x-pack/legacy/plugins/uptime/public/register_feature.ts deleted file mode 100644 index 2f83fa33ba4bc..0000000000000 --- a/x-pack/legacy/plugins/uptime/public/register_feature.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { i18n } from '@kbn/i18n'; -import { npSetup } from 'ui/new_platform'; -import { FeatureCatalogueCategory } from '../../../../../src/plugins/home/public'; - -const { - plugins: { home }, -} = npSetup; - -home.featureCatalogue.register({ - id: 'uptime', - title: i18n.translate('xpack.uptime.uptimeFeatureCatalogueTitle', { defaultMessage: 'Uptime' }), - description: i18n.translate('xpack.uptime.featureCatalogueDescription', { - defaultMessage: 'Perform endpoint health checks and uptime monitoring.', - }), - icon: 'uptimeApp', - path: `uptime#/`, - showOnHomePage: true, - category: FeatureCatalogueCategory.DATA, -}); diff --git a/x-pack/legacy/plugins/uptime/tsconfig.json b/x-pack/legacy/plugins/uptime/tsconfig.json deleted file mode 100644 index 53425909db3e8..0000000000000 --- a/x-pack/legacy/plugins/uptime/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "../../../tsconfig.json", - "exclude": ["**/node_modules/**"], - "paths": { - "react": ["../../../node_modules/@types/react"] - } -} \ No newline at end of file diff --git a/x-pack/package.json b/x-pack/package.json index 604889c6094b9..dcc9b8c61cb96 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -105,6 +105,7 @@ "@types/recompose": "^0.30.6", "@types/reduce-reducers": "^1.0.0", "@types/redux-actions": "^2.6.1", + "@types/set-value": "^2.0.0", "@types/sinon": "^7.0.13", "@types/styled-components": "^4.4.2", "@types/supertest": "^2.0.5", @@ -344,6 +345,7 @@ "rison-node": "0.3.1", "rxjs": "^6.5.3", "semver": "5.7.0", + "set-value": "^3.0.2", "squel": "^5.13.0", "stats-lite": "^2.2.0", "style-it": "^2.1.3", diff --git a/x-pack/plugins/actions/server/plugin.ts b/x-pack/plugins/actions/server/plugin.ts index 10e4d64584340..a6cc1fb5463bb 100644 --- a/x-pack/plugins/actions/server/plugin.ts +++ b/x-pack/plugins/actions/server/plugin.ts @@ -53,6 +53,7 @@ import { } from './routes'; import { IEventLogger, IEventLogService } from '../../event_log/server'; import { initializeActionsTelemetry, scheduleActionsTelemetry } from './usage/task'; +import { setupSavedObjects } from './saved_objects'; const EVENT_LOG_PROVIDER = 'actions'; export const EVENT_LOG_ACTIONS = { @@ -133,19 +134,7 @@ export class ActionsPlugin implements Plugin, Plugi ); } - // Encrypted attributes - // - `secrets` properties will be encrypted - // - `config` will be included in AAD - // - everything else excluded from AAD - plugins.encryptedSavedObjects.registerType({ - type: 'action', - attributesToEncrypt: new Set(['secrets']), - attributesToExcludeFromAAD: new Set(['name']), - }); - plugins.encryptedSavedObjects.registerType({ - type: 'action_task_params', - attributesToEncrypt: new Set(['apiKey']), - }); + setupSavedObjects(core.savedObjects, plugins.encryptedSavedObjects); plugins.eventLog.registerProviderActions(EVENT_LOG_PROVIDER, Object.values(EVENT_LOG_ACTIONS)); this.eventLogger = plugins.eventLog.getLogger({ diff --git a/x-pack/plugins/actions/server/saved_objects/index.ts b/x-pack/plugins/actions/server/saved_objects/index.ts new file mode 100644 index 0000000000000..dbd7925f96871 --- /dev/null +++ b/x-pack/plugins/actions/server/saved_objects/index.ts @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { SavedObjectsServiceSetup } from 'kibana/server'; +import mappings from './mappings.json'; +import { EncryptedSavedObjectsPluginSetup } from '../../../encrypted_saved_objects/server'; + +export function setupSavedObjects( + savedObjects: SavedObjectsServiceSetup, + encryptedSavedObjects: EncryptedSavedObjectsPluginSetup +) { + savedObjects.registerType({ + name: 'action', + hidden: false, + namespaceType: 'single', + mappings: mappings.action, + }); + + // Encrypted attributes + // - `secrets` properties will be encrypted + // - `config` will be included in AAD + // - everything else excluded from AAD + encryptedSavedObjects.registerType({ + type: 'action', + attributesToEncrypt: new Set(['secrets']), + attributesToExcludeFromAAD: new Set(['name']), + }); + + savedObjects.registerType({ + name: 'action_task_params', + hidden: false, + namespaceType: 'single', + mappings: mappings.action_task_params, + }); + encryptedSavedObjects.registerType({ + type: 'action_task_params', + attributesToEncrypt: new Set(['apiKey']), + }); +} diff --git a/x-pack/legacy/plugins/actions/server/mappings.json b/x-pack/plugins/actions/server/saved_objects/mappings.json similarity index 100% rename from x-pack/legacy/plugins/actions/server/mappings.json rename to x-pack/plugins/actions/server/saved_objects/mappings.json diff --git a/x-pack/plugins/alerting/server/plugin.ts b/x-pack/plugins/alerting/server/plugin.ts index c03d3506a051d..8cdde2eeb9877 100644 --- a/x-pack/plugins/alerting/server/plugin.ts +++ b/x-pack/plugins/alerting/server/plugin.ts @@ -58,6 +58,7 @@ import { Services } from './types'; import { registerAlertsUsageCollector } from './usage'; import { initializeAlertingTelemetry, scheduleAlertingTelemetry } from './usage/task'; import { IEventLogger, IEventLogService } from '../../event_log/server'; +import { setupSavedObjects } from './saved_objects'; const EVENT_LOG_PROVIDER = 'alerting'; export const EVENT_LOG_ACTIONS = { @@ -134,17 +135,7 @@ export class AlertingPlugin { ); } - // Encrypted attributes - plugins.encryptedSavedObjects.registerType({ - type: 'alert', - attributesToEncrypt: new Set(['apiKey']), - attributesToExcludeFromAAD: new Set([ - 'scheduledTaskId', - 'muteAll', - 'mutedInstanceIds', - 'updatedBy', - ]), - }); + setupSavedObjects(core.savedObjects, plugins.encryptedSavedObjects); plugins.eventLog.registerProviderActions(EVENT_LOG_PROVIDER, Object.values(EVENT_LOG_ACTIONS)); this.eventLogger = plugins.eventLog.getLogger({ diff --git a/x-pack/plugins/alerting/server/saved_objects/index.ts b/x-pack/plugins/alerting/server/saved_objects/index.ts new file mode 100644 index 0000000000000..4efec2fe55ef0 --- /dev/null +++ b/x-pack/plugins/alerting/server/saved_objects/index.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { SavedObjectsServiceSetup } from 'kibana/server'; +import mappings from './mappings.json'; +import { EncryptedSavedObjectsPluginSetup } from '../../../encrypted_saved_objects/server'; + +export function setupSavedObjects( + savedObjects: SavedObjectsServiceSetup, + encryptedSavedObjects: EncryptedSavedObjectsPluginSetup +) { + savedObjects.registerType({ + name: 'alert', + hidden: false, + namespaceType: 'single', + mappings: mappings.alert, + }); + + // Encrypted attributes + encryptedSavedObjects.registerType({ + type: 'alert', + attributesToEncrypt: new Set(['apiKey']), + attributesToExcludeFromAAD: new Set([ + 'scheduledTaskId', + 'muteAll', + 'mutedInstanceIds', + 'updatedBy', + ]), + }); +} diff --git a/x-pack/legacy/plugins/alerting/server/mappings.json b/x-pack/plugins/alerting/server/saved_objects/mappings.json similarity index 100% rename from x-pack/legacy/plugins/alerting/server/mappings.json rename to x-pack/plugins/alerting/server/saved_objects/mappings.json diff --git a/x-pack/plugins/graph/public/application.ts b/x-pack/plugins/graph/public/application.ts index 35ec0bb2bf6ce..fa479b1b06d5e 100644 --- a/x-pack/plugins/graph/public/application.ts +++ b/x-pack/plugins/graph/public/application.ts @@ -10,7 +10,7 @@ import angular from 'angular'; import { i18nDirective, i18nFilter, I18nProvider } from '@kbn/i18n/angular'; import '../../../../webpackShims/ace'; -// required for i18nIdDirective +// required for i18nIdDirective and `ngSanitize` angular module import 'angular-sanitize'; // required for ngRoute import 'angular-route'; diff --git a/x-pack/plugins/infra/public/plugin.ts b/x-pack/plugins/infra/public/plugin.ts index 26f206c06203b..40366b2a54f24 100644 --- a/x-pack/plugins/infra/public/plugin.ts +++ b/x-pack/plugins/infra/public/plugin.ts @@ -21,6 +21,8 @@ import { UsageCollectionSetup } from '../../../../src/plugins/usage_collection/p import { DataEnhancedSetup, DataEnhancedStart } from '../../data_enhanced/public'; import { TriggersAndActionsUIPublicPluginSetup } from '../../../plugins/triggers_actions_ui/public'; +import { getAlertType as getMetricsAlertType } from './components/alerting/metrics/metric_threshold_alert_type'; +import { getAlertType as getLogsAlertType } from './components/alerting/logs/log_threshold_alert_type'; export type ClientSetup = void; export type ClientStart = void; @@ -51,6 +53,9 @@ export class Plugin setup(core: CoreSetup, pluginsSetup: ClientPluginsSetup) { registerFeatures(pluginsSetup.home); + pluginsSetup.triggers_actions_ui.alertTypeRegistry.register(getMetricsAlertType()); + pluginsSetup.triggers_actions_ui.alertTypeRegistry.register(getLogsAlertType()); + core.application.register({ id: 'logs', title: i18n.translate('xpack.infra.logs.pluginTitle', { @@ -65,8 +70,6 @@ export class Plugin const plugins = getMergedPlugins(pluginsSetup, pluginsStart as ClientPluginsStart); const { startApp, composeLibs, LogsRouter } = await this.downloadAssets(); - await this.registerLogsAlertType(pluginsSetup); - return startApp( composeLibs(coreStart), coreStart, @@ -92,8 +95,6 @@ export class Plugin const plugins = getMergedPlugins(pluginsSetup, pluginsStart as ClientPluginsStart); const { startApp, composeLibs, MetricsRouter } = await this.downloadAssets(); - await this.registerMetricsAlertType(pluginsSetup); - return startApp( composeLibs(coreStart), coreStart, @@ -137,24 +138,4 @@ export class Plugin MetricsRouter, }; } - - // NOTE: apm is importing from `infra/public` and async importing that - // allow us to reduce the apm bundle size - private async registerLogsAlertType(pluginsSetup: ClientPluginsSetup) { - const { getAlertType } = await import('./components/alerting/logs/log_threshold_alert_type'); - - if (!pluginsSetup.triggers_actions_ui.alertTypeRegistry.has(getAlertType().id)) { - pluginsSetup.triggers_actions_ui.alertTypeRegistry.register(getAlertType()); - } - } - - private async registerMetricsAlertType(pluginsSetup: ClientPluginsSetup) { - const { getAlertType } = await import( - './components/alerting/metrics/metric_threshold_alert_type' - ); - - if (!pluginsSetup.triggers_actions_ui.alertTypeRegistry.has(getAlertType().id)) { - pluginsSetup.triggers_actions_ui.alertTypeRegistry.register(getAlertType()); - } - } } diff --git a/x-pack/plugins/ingest_manager/common/services/package_to_config.test.ts b/x-pack/plugins/ingest_manager/common/services/package_to_config.test.ts index cb290e61b17e5..a977a1a66e059 100644 --- a/x-pack/plugins/ingest_manager/common/services/package_to_config.test.ts +++ b/x-pack/plugins/ingest_manager/common/services/package_to_config.test.ts @@ -11,6 +11,7 @@ describe('Ingest Manager - packageToConfig', () => { name: 'mock-package', title: 'Mock package', version: '0.0.0', + latestVersion: '0.0.0', description: 'description', type: 'mock', categories: [], diff --git a/x-pack/plugins/ingest_manager/common/types/models/epm.ts b/x-pack/plugins/ingest_manager/common/types/models/epm.ts index fb6bf235d1e26..f8779a879a049 100644 --- a/x-pack/plugins/ingest_manager/common/types/models/epm.ts +++ b/x-pack/plugins/ingest_manager/common/types/models/epm.ts @@ -97,6 +97,7 @@ export interface RegistryStream { description?: string; enabled?: boolean; vars?: RegistryVarsEntry[]; + template?: string; } export type RequirementVersion = string; @@ -203,6 +204,8 @@ export interface RegistryVarsEntry { // internal until we need them interface PackageAdditions { title: string; + latestVersion: string; + installedVersion?: string; assets: AssetsGroupedByServiceByType; } diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/components/icons.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/components/icons.tsx new file mode 100644 index 0000000000000..64223efefaab8 --- /dev/null +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/components/icons.tsx @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { EuiIcon } from '@elastic/eui'; +import React from 'react'; +import styled from 'styled-components'; + +export const StyledAlert = styled(EuiIcon)` + color: ${props => props.theme.eui.euiColorWarning}; + padding: 0 5px; +`; + +export const UpdateIcon = () => ; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/components/package_card.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/components/package_card.tsx index 8ad081cbbabe4..ab7e87b3ad06c 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/components/package_card.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/components/package_card.tsx @@ -30,9 +30,15 @@ export function PackageCard({ showInstalledBadge, status, icons, + ...restProps }: PackageCardProps) { const { toDetailView } = useLinks(); - const url = toDetailView({ name, version }); + let urlVersion = version; + // if this is an installed package, link to the version installed + if ('savedObject' in restProps) { + urlVersion = restProps.savedObject.attributes.version || version; + } + const url = toDetailView({ name, version: urlVersion }); return ( ; +type InstallPackageProps = Pick & { + fromUpdate?: boolean; +}; +type SetPackageInstallStatusProps = Pick & PackageInstallItem; function usePackageInstall({ notifications }: { notifications: NotificationsStart }) { + const { toDetailView } = useLinks(); const [packages, setPackage] = useState({}); const setPackageInstallStatus = useCallback( - ({ name, status }: { name: PackageInfo['name']; status: InstallStatus }) => { + ({ name, status, version }: SetPackageInstallStatusProps) => { + const packageProps: PackageInstallItem = { + status, + version, + }; setPackage((prev: PackagesInstall) => ({ ...prev, - [name]: { status }, + [name]: packageProps, })); }, [] ); + const getPackageInstallStatus = useCallback( + (pkg: string): PackageInstallItem => { + return packages[pkg]; + }, + [packages] + ); + const installPackage = useCallback( - async ({ name, version, title }: InstallPackageProps) => { - setPackageInstallStatus({ name, status: InstallStatus.installing }); + async ({ name, version, title, fromUpdate = false }: InstallPackageProps) => { + const currStatus = getPackageInstallStatus(name); + const newStatus = { ...currStatus, name, status: InstallStatus.installing }; + setPackageInstallStatus(newStatus); const pkgkey = `${name}-${version}`; const res = await sendInstallPackage(pkgkey); if (res.error) { - setPackageInstallStatus({ name, status: InstallStatus.notInstalled }); + if (fromUpdate) { + // if there is an error during update, set it back to the previous version + // as handling of bad update is not implemented yet + setPackageInstallStatus({ ...currStatus, name }); + } else { + setPackageInstallStatus({ name, status: InstallStatus.notInstalled, version }); + } notifications.toasts.addWarning({ title: toMountPoint( { - return packages[pkg].status; - }, - [packages] + [getPackageInstallStatus, notifications.toasts, setPackageInstallStatus, toDetailView] ); const uninstallPackage = useCallback( async ({ name, version, title }: Pick) => { - setPackageInstallStatus({ name, status: InstallStatus.uninstalling }); + setPackageInstallStatus({ name, status: InstallStatus.uninstalling, version }); const pkgkey = `${name}-${version}`; const res = await sendRemovePackage(pkgkey); if (res.error) { - setPackageInstallStatus({ name, status: InstallStatus.installed }); + setPackageInstallStatus({ name, status: InstallStatus.installed, version }); notifications.toasts.addWarning({ title: toMountPoint( ; export function ContentPanel(props: ContentPanelProps) { - const { panel, name, version, assets, title, removable } = props; + const { panel, name, version, assets, title, removable, latestVersion } = props; switch (panel) { case 'settings': return ( @@ -60,6 +60,7 @@ export function ContentPanel(props: ContentPanelProps) { assets={assets} title={title} removable={removable} + latestVersion={latestVersion} /> ); case 'data-sources': diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/data_sources_panel.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/data_sources_panel.tsx index fa3245aec02c5..c82b7ed2297a7 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/data_sources_panel.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/data_sources_panel.tsx @@ -20,7 +20,7 @@ export const DataSourcesPanel = ({ name, version }: DataSourcesPanelProps) => { const packageInstallStatus = getPackageInstallStatus(name); // if they arrive at this page and the package is not installed, send them to overview // this happens if they arrive with a direct url or they uninstall while on this tab - if (packageInstallStatus !== InstallStatus.installed) + if (packageInstallStatus.status !== InstallStatus.installed) return ( props.theme.eui.euiSizeM}; `; -const StyledVersion = styled(Version)` - font-size: ${props => props.theme.eui.euiFontSizeS}; - color: ${props => props.theme.eui.euiColorDarkShade}; -`; - type HeaderProps = PackageInfo & { iconType?: IconType }; export function Header(props: HeaderProps) { - const { iconType, name, title, version } = props; + const { iconType, name, title, version, installedVersion, latestVersion } = props; const hasWriteCapabilites = useCapabilities().write; const { toListView } = useLinks(); const ADD_DATASOURCE_URI = useLink(`${EPM_PATH}/${name}-${version}/add-datasource`); - + const updateAvailable = installedVersion && installedVersion < latestVersion ? true : false; return ( @@ -59,7 +54,11 @@ export function Header(props: HeaderProps) {

{title} - + + + {version} {updateAvailable && } + +

diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/index.tsx index 3239d7b90e3c3..1f3eb2cc9362e 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/index.tsx @@ -32,11 +32,12 @@ export function Detail() { const packageInfo = response.data?.response; const title = packageInfo?.title; const name = packageInfo?.name; + const installedVersion = packageInfo?.installedVersion; const status: InstallStatus = packageInfo?.status as any; // track install status state if (name) { - setPackageInstallStatus({ name, status }); + setPackageInstallStatus({ name, status, version: installedVersion || null }); } if (packageInfo) { setInfo({ ...packageInfo, title: title || '' }); @@ -64,7 +65,6 @@ type LayoutProps = PackageInfo & Pick & Pick diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/installation_button.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/installation_button.tsx index cbbf1ce53c4ea..cdad67fd87548 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/installation_button.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/installation_button.tsx @@ -13,19 +13,21 @@ import { ConfirmPackageUninstall } from './confirm_package_uninstall'; import { ConfirmPackageInstall } from './confirm_package_install'; type InstallationButtonProps = Pick & { - disabled: boolean; + disabled?: boolean; + isUpdate?: boolean; }; export function InstallationButton(props: InstallationButtonProps) { - const { assets, name, title, version, disabled = true } = props; + const { assets, name, title, version, disabled = true, isUpdate = false } = props; const hasWriteCapabilites = useCapabilities().write; const installPackage = useInstallPackage(); const uninstallPackage = useUninstallPackage(); const getPackageInstallStatus = useGetPackageInstallStatus(); - const installationStatus = getPackageInstallStatus(name); + const { status: installationStatus } = getPackageInstallStatus(name); const isInstalling = installationStatus === InstallStatus.installing; const isRemoving = installationStatus === InstallStatus.uninstalling; const isInstalled = installationStatus === InstallStatus.installed; + const showUninstallButton = isInstalled || isRemoving; const [isModalVisible, setModalVisible] = useState(false); const toggleModal = useCallback(() => { setModalVisible(!isModalVisible); @@ -36,6 +38,10 @@ export function InstallationButton(props: InstallationButtonProps) { toggleModal(); }, [installPackage, name, title, toggleModal, version]); + const handleClickUpdate = useCallback(() => { + installPackage({ name, version, title, fromUpdate: true }); + }, [installPackage, name, title, version]); + const handleClickUninstall = useCallback(() => { uninstallPackage({ name, version, title }); toggleModal(); @@ -78,6 +84,15 @@ export function InstallationButton(props: InstallationButtonProps) { ); + const updateButton = ( + + + + ); + const uninstallButton = ( - {isInstalled || isRemoving ? uninstallButton : installButton} + {isUpdate ? updateButton : showUninstallButton ? uninstallButton : installButton} {isModalVisible && (isInstalled ? uninstallModal : installModal)} ) : null; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/settings_panel.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/settings_panel.tsx index 3589a1a9444e1..4d4dba2a64e5a 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/settings_panel.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/settings_panel.tsx @@ -8,11 +8,22 @@ import React from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiTitle, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; import { EuiSpacer } from '@elastic/eui'; +import styled from 'styled-components'; import { InstallStatus, PackageInfo } from '../../../../types'; import { useGetDatasources } from '../../../../hooks'; import { DATASOURCE_SAVED_OBJECT_TYPE } from '../../../../constants'; import { useGetPackageInstallStatus } from '../../hooks'; import { InstallationButton } from './installation_button'; +import { UpdateIcon } from '../../components/icons'; + +const SettingsTitleCell = styled.td` + padding-right: ${props => props.theme.eui.spacerSizes.xl}; + padding-bottom: ${props => props.theme.eui.spacerSizes.m}; +`; + +const UpdatesAvailableMsgContainer = styled.span` + padding-left: ${props => props.theme.eui.spacerSizes.s}; +`; const NoteLabel = () => ( ( defaultMessage="Note:" /> ); +const UpdatesAvailableMsg = () => ( + + + + +); + export const SettingsPanel = ( - props: Pick + props: Pick ) => { + const { name, title, removable, latestVersion, version } = props; const getPackageInstallStatus = useGetPackageInstallStatus(); const { data: datasourcesData } = useGetDatasources({ perPage: 0, page: 1, kuery: `${DATASOURCE_SAVED_OBJECT_TYPE}.package.name:${props.name}`, }); - const { name, title, removable } = props; - const packageInstallStatus = getPackageInstallStatus(name); + const { status: installationStatus, version: installedVersion } = getPackageInstallStatus(name); const packageHasDatasources = !!datasourcesData?.total; + const updateAvailable = installedVersion && installedVersion < latestVersion ? true : false; + const isViewingOldPackage = version < latestVersion; + // hide install/remove options if the user has version of the package is installed + // and this package is out of date or if they do have a version installed but it's not this one + const hideInstallOptions = + (installationStatus === InstallStatus.notInstalled && isViewingOldPackage) || + (installationStatus === InstallStatus.installed && installedVersion !== version); + + const isUpdating = installationStatus === InstallStatus.installing && installedVersion; return ( @@ -43,14 +73,13 @@ export const SettingsPanel = ( - {packageInstallStatus === InstallStatus.notInstalled || - packageInstallStatus === InstallStatus.installing ? ( + {installedVersion !== null && (

-

- -

+ + + + + + + + + + + + + + + +
+ + {installedVersion} + + {updateAvailable && } +
+ + {latestVersion} + +
+ {updateAvailable && ( +

+ +

+ )}

- ) : ( + )} + {!hideInstallOptions && !isUpdating && (
- -

+ + {installationStatus === InstallStatus.notInstalled || + installationStatus === InstallStatus.installing ? ( +
+ +

+ +

+
+ +

+ +

+
+ ) : ( +
+ +

+ +

+
+ +

+ +

+
+ )} + + +

+ +

+
+
+ {packageHasDatasources && removable === true && ( +

+ + + ), }} /> -

-
- -

- -

+

+ )} + {removable === false && ( +

+ + + + ), + }} + /> +

+ )}
)} - - -

- -

-
-
- {packageHasDatasources && removable === true && ( -

- - - - ), - }} - /> -

- )} - {removable === false && ( -

- - - - ), - }} - /> -

- )}
); }; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/side_nav_links.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/side_nav_links.tsx index 05729ccfc1af4..ab168ef1530bd 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/side_nav_links.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/side_nav_links.tsx @@ -37,7 +37,7 @@ export function SideNavLinks({ name, version, active }: NavLinkProps) { : p.theme.eui.euiFontWeightRegular}; `; // don't display Data Sources tab if the package is not installed - if (packageInstallStatus !== InstallStatus.installed && panel === 'data-sources') + if (packageInstallStatus.status !== InstallStatus.installed && panel === 'data-sources') return null; return ( diff --git a/x-pack/plugins/ingest_manager/server/routes/datasource/handlers.ts b/x-pack/plugins/ingest_manager/server/routes/datasource/handlers.ts index 56d6053a1451b..8f07e3ed1de02 100644 --- a/x-pack/plugins/ingest_manager/server/routes/datasource/handlers.ts +++ b/x-pack/plugins/ingest_manager/server/routes/datasource/handlers.ts @@ -7,7 +7,7 @@ import { TypeOf } from '@kbn/config-schema'; import Boom from 'boom'; import { RequestHandler } from 'src/core/server'; import { appContextService, datasourceService } from '../../services'; -import { ensureInstalledPackage } from '../../services/epm/packages'; +import { ensureInstalledPackage, getPackageInfo } from '../../services/epm/packages'; import { GetDatasourcesRequestSchema, GetOneDatasourceRequestSchema, @@ -85,12 +85,13 @@ export const createDatasourceHandler: RequestHandler< pkgName: request.body.package.name, callCluster, }); - + const pkgInfo = await getPackageInfo({ + savedObjectsClient: soClient, + pkgName: request.body.package.name, + pkgVersion: request.body.package.version, + }); newData.inputs = (await datasourceService.assignPackageStream( - { - pkgName: request.body.package.name, - pkgVersion: request.body.package.version, - }, + pkgInfo, request.body.inputs )) as TypeOf['inputs']; } @@ -127,13 +128,14 @@ export const updateDatasourceHandler: RequestHandler< const pkg = newData.package || datasource.package; const inputs = newData.inputs || datasource.inputs; if (pkg && (newData.inputs || newData.package)) { - newData.inputs = (await datasourceService.assignPackageStream( - { - pkgName: pkg.name, - pkgVersion: pkg.version, - }, - inputs - )) as TypeOf['inputs']; + const pkgInfo = await getPackageInfo({ + savedObjectsClient: soClient, + pkgName: pkg.name, + pkgVersion: pkg.version, + }); + newData.inputs = (await datasourceService.assignPackageStream(pkgInfo, inputs)) as TypeOf< + typeof CreateDatasourceRequestSchema.body + >['inputs']; } const updatedDatasource = await datasourceService.update( diff --git a/x-pack/plugins/ingest_manager/server/services/datasource.test.ts b/x-pack/plugins/ingest_manager/server/services/datasource.test.ts index 4cbbadce7f5bb..3682ae6d1167b 100644 --- a/x-pack/plugins/ingest_manager/server/services/datasource.test.ts +++ b/x-pack/plugins/ingest_manager/server/services/datasource.test.ts @@ -5,39 +5,38 @@ */ import { datasourceService } from './datasource'; +import { PackageInfo } from '../types'; -async function mockedGetAssetsData(_a: any, _b: any, dataset: string) { - if (dataset === 'dataset1') { - return [ - { - buffer: Buffer.from(` +const TEMPLATE = ` type: log metricset: ["dataset1"] paths: {{#each paths}} - {{this}} {{/each}} -`), - }, - ]; - } - return []; -} - -jest.mock('./epm/packages/assets', () => { - return { - getAssetsDataForPackageKey: mockedGetAssetsData, - }; -}); +`; describe('Datasource service', () => { describe('assignPackageStream', () => { - it('should work with cofig variables from the stream', async () => { + it('should work with config variables from the stream', async () => { const inputs = await datasourceService.assignPackageStream( - { - pkgName: 'package', - pkgVersion: '1.0.0', - }, + ({ + datasources: [ + { + inputs: [ + { + type: 'log', + streams: [ + { + dataset: 'package.dataset1', + template: TEMPLATE, + }, + ], + }, + ], + }, + ], + } as unknown) as PackageInfo, [ { type: 'log', @@ -85,10 +84,23 @@ describe('Datasource service', () => { it('should work with config variables at the input level', async () => { const inputs = await datasourceService.assignPackageStream( - { - pkgName: 'package', - pkgVersion: '1.0.0', - }, + ({ + datasources: [ + { + inputs: [ + { + type: 'log', + streams: [ + { + dataset: 'package.dataset1', + template: TEMPLATE, + }, + ], + }, + ], + }, + ], + } as unknown) as PackageInfo, [ { type: 'log', diff --git a/x-pack/plugins/ingest_manager/server/services/datasource.ts b/x-pack/plugins/ingest_manager/server/services/datasource.ts index 804039cf508ba..0a5ba43e40fba 100644 --- a/x-pack/plugins/ingest_manager/server/services/datasource.ts +++ b/x-pack/plugins/ingest_manager/server/services/datasource.ts @@ -4,20 +4,19 @@ * you may not use this file except in compliance with the Elastic License. */ import { SavedObjectsClientContract } from 'src/core/server'; -import { safeLoad } from 'js-yaml'; import { AuthenticatedUser } from '../../../security/server'; import { DeleteDatasourcesResponse, packageToConfigDatasource, DatasourceInput, DatasourceInputStream, + PackageInfo, } from '../../common'; import { DATASOURCE_SAVED_OBJECT_TYPE } from '../constants'; import { NewDatasource, Datasource, ListWithKuery } from '../types'; import { agentConfigService } from './agent_config'; import { getPackageInfo, getInstallation } from './epm/packages'; import { outputService } from './output'; -import { getAssetsDataForPackageKey } from './epm/packages/assets'; import { createStream } from './epm/agent/agent'; const SAVED_OBJECT_TYPE = DATASOURCE_SAVED_OBJECT_TYPE; @@ -201,20 +200,16 @@ class DatasourceService { } public async assignPackageStream( - pkgInfo: { pkgName: string; pkgVersion: string }, + pkgInfo: PackageInfo, inputs: DatasourceInput[] ): Promise { const inputsPromises = inputs.map(input => _assignPackageStreamToInput(pkgInfo, input)); + return Promise.all(inputsPromises); } } -const _isAgentStream = (p: string) => !!p.match(/agent\/stream\/stream\.yml/); - -async function _assignPackageStreamToInput( - pkgInfo: { pkgName: string; pkgVersion: string }, - input: DatasourceInput -) { +async function _assignPackageStreamToInput(pkgInfo: PackageInfo, input: DatasourceInput) { const streamsPromises = input.streams.map(stream => _assignPackageStreamToStream(pkgInfo, input, stream) ); @@ -224,7 +219,7 @@ async function _assignPackageStreamToInput( } async function _assignPackageStreamToStream( - pkgInfo: { pkgName: string; pkgVersion: string }, + pkgInfo: PackageInfo, input: DatasourceInput, stream: DatasourceInputStream ) { @@ -232,27 +227,35 @@ async function _assignPackageStreamToStream( return { ...stream, agent_stream: undefined }; } const dataset = getDataset(stream.dataset); - const assetsData = await getAssetsDataForPackageKey(pkgInfo, _isAgentStream, dataset); + const datasource = pkgInfo.datasources?.[0]; + if (!datasource) { + throw new Error('Stream template not found, no datasource'); + } - const [pkgStream] = assetsData; - if (!pkgStream || !pkgStream.buffer) { - throw new Error(`Stream template not found for dataset ${dataset}`); + const inputFromPkg = datasource.inputs.find(pkgInput => pkgInput.type === input.type); + if (!inputFromPkg) { + throw new Error(`Stream template not found, unable to found input ${input.type}`); } - // Populate template variables from input config and stream config - const data: { [k: string]: string | string[] } = {}; - if (input.vars) { - for (const key of Object.keys(input.vars)) { - data[key] = input.vars[key].value; - } + const streamFromPkg = inputFromPkg.streams.find( + pkgStream => pkgStream.dataset === stream.dataset + ); + if (!streamFromPkg) { + throw new Error(`Stream template not found, unable to found stream ${stream.dataset}`); } - if (stream.vars) { - for (const key of Object.keys(stream.vars)) { - data[key] = stream.vars[key].value; - } + + if (!streamFromPkg.template) { + throw new Error(`Stream template not found for dataset ${dataset}`); } - const yaml = safeLoad(createStream(data, pkgStream.buffer.toString())); + + const yaml = createStream( + // Populate template variables from input vars and stream vars + Object.assign({}, input.vars, stream.vars), + streamFromPkg.template + ); + stream.agent_stream = yaml; + return { ...stream }; } diff --git a/x-pack/plugins/ingest_manager/server/services/epm/agent/agent.test.ts b/x-pack/plugins/ingest_manager/server/services/epm/agent/agent.test.ts index 21de625532f03..db2e4fe474640 100644 --- a/x-pack/plugins/ingest_manager/server/services/epm/agent/agent.test.ts +++ b/x-pack/plugins/ingest_manager/server/services/epm/agent/agent.test.ts @@ -6,29 +6,61 @@ import { createStream } from './agent'; -test('Test creating a stream from template', () => { - const streamTemplate = ` -input: log -paths: -{{#each paths}} - - {{this}} -{{/each}} -exclude_files: [".gz$"] -processors: - - add_locale: ~ - `; - const vars = { - paths: ['/usr/local/var/log/nginx/access.log'], - }; +describe('createStream', () => { + it('should work', () => { + const streamTemplate = ` + input: log + paths: + {{#each paths}} + - {{this}} + {{/each}} + exclude_files: [".gz$"] + processors: + - add_locale: ~ + `; + const vars = { + paths: { value: ['/usr/local/var/log/nginx/access.log'] }, + }; - const output = createStream(vars, streamTemplate); + const output = createStream(vars, streamTemplate); + expect(output).toEqual({ + input: 'log', + paths: ['/usr/local/var/log/nginx/access.log'], + exclude_files: ['.gz$'], + processors: [{ add_locale: null }], + }); + }); - expect(output).toBe(` -input: log -paths: - - /usr/local/var/log/nginx/access.log -exclude_files: [".gz$"] -processors: - - add_locale: ~ - `); + it('should support yaml values', () => { + const streamTemplate = ` + input: redis/metrics + metricsets: ["key"] + test: null + {{#if key.patterns}} + key.patterns: {{key.patterns}} + {{/if}} + `; + const vars = { + 'key.patterns': { + type: 'yaml', + value: ` + - limit: 20 + pattern: '*' + `, + }, + }; + + const output = createStream(vars, streamTemplate); + expect(output).toEqual({ + input: 'redis/metrics', + metricsets: ['key'], + test: null, + 'key.patterns': [ + { + limit: 20, + pattern: '*', + }, + ], + }); + }); }); diff --git a/x-pack/plugins/ingest_manager/server/services/epm/agent/agent.ts b/x-pack/plugins/ingest_manager/server/services/epm/agent/agent.ts index 5d9a6d409aa1a..8254c0d8aaa37 100644 --- a/x-pack/plugins/ingest_manager/server/services/epm/agent/agent.ts +++ b/x-pack/plugins/ingest_manager/server/services/epm/agent/agent.ts @@ -5,12 +5,71 @@ */ import Handlebars from 'handlebars'; +import { safeLoad } from 'js-yaml'; +import { DatasourceConfigRecord } from '../../../../common'; -interface StreamVars { - [k: string]: string | string[]; +function isValidKey(key: string) { + return key !== '__proto__' && key !== 'constructor' && key !== 'prototype'; } -export function createStream(vars: StreamVars, streamTemplate: string) { - const template = Handlebars.compile(streamTemplate); - return template(vars); +function replaceVariablesInYaml(yamlVariables: { [k: string]: any }, yaml: any) { + if (Object.keys(yamlVariables).length === 0 || !yaml) { + return yaml; + } + + Object.entries(yaml).forEach(([key, value]: [string, any]) => { + if (typeof value === 'object') { + yaml[key] = replaceVariablesInYaml(yamlVariables, value); + } + if (typeof value === 'string' && value in yamlVariables) { + yaml[key] = yamlVariables[value]; + } + }); + + return yaml; +} + +function buildTemplateVariables(variables: DatasourceConfigRecord) { + const yamlValues: { [k: string]: any } = {}; + const vars = Object.entries(variables).reduce((acc, [key, recordEntry]) => { + // support variables with . like key.patterns + const keyParts = key.split('.'); + const lastKeyPart = keyParts.pop(); + + if (!lastKeyPart || !isValidKey(lastKeyPart)) { + throw new Error('Invalid key'); + } + + let varPart = acc; + for (const keyPart of keyParts) { + if (!isValidKey(keyPart)) { + throw new Error('Invalid key'); + } + if (!varPart[keyPart]) { + varPart[keyPart] = {}; + } + varPart = varPart[keyPart]; + } + + if (recordEntry.type && recordEntry.type === 'yaml') { + const yamlKeyPlaceholder = `##${key}##`; + varPart[lastKeyPart] = `"${yamlKeyPlaceholder}"`; + yamlValues[yamlKeyPlaceholder] = recordEntry.value ? safeLoad(recordEntry.value) : null; + } else { + varPart[lastKeyPart] = recordEntry.value; + } + return acc; + }, {} as { [k: string]: any }); + + return { vars, yamlValues }; +} + +export function createStream(variables: DatasourceConfigRecord, streamTemplate: string) { + const { vars, yamlValues } = buildTemplateVariables(variables); + + const template = Handlebars.compile(streamTemplate, { noEscape: true }); + const stream = template(vars); + const yamlFromStream = safeLoad(stream, {}); + + return replaceVariablesInYaml(yamlValues, yamlFromStream); } diff --git a/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/template/template.test.ts b/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/template/template.test.ts index 1a73c9581a2de..3679c577ee571 100644 --- a/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/template/template.test.ts +++ b/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/template/template.test.ts @@ -259,3 +259,53 @@ test('tests processing object field with dynamic set to strict', () => { const mappings = generateMappings(processedFields); expect(JSON.stringify(mappings)).toEqual(JSON.stringify(objectFieldDynamicStrictMapping)); }); + +test('tests processing object field with property', () => { + const objectFieldWithPropertyLiteralYml = ` +- name: a + type: object +- name: a.b + type: keyword + `; + const objectFieldWithPropertyMapping = { + properties: { + a: { + properties: { + b: { + ignore_above: 1024, + type: 'keyword', + }, + }, + }, + }, + }; + const fields: Field[] = safeLoad(objectFieldWithPropertyLiteralYml); + const processedFields = processFields(fields); + const mappings = generateMappings(processedFields); + expect(JSON.stringify(mappings)).toEqual(JSON.stringify(objectFieldWithPropertyMapping)); +}); + +test('tests processing object field with property, reverse order', () => { + const objectFieldWithPropertyReversedLiteralYml = ` +- name: a.b + type: keyword +- name: a + type: object + `; + const objectFieldWithPropertyReversedMapping = { + properties: { + a: { + properties: { + b: { + ignore_above: 1024, + type: 'keyword', + }, + }, + }, + }, + }; + const fields: Field[] = safeLoad(objectFieldWithPropertyReversedLiteralYml); + const processedFields = processFields(fields); + const mappings = generateMappings(processedFields); + expect(JSON.stringify(mappings)).toEqual(JSON.stringify(objectFieldWithPropertyReversedMapping)); +}); diff --git a/x-pack/plugins/ingest_manager/server/services/epm/fields/field.test.ts b/x-pack/plugins/ingest_manager/server/services/epm/fields/field.test.ts index e3aef6077dbc3..42989bb1e3ac9 100644 --- a/x-pack/plugins/ingest_manager/server/services/epm/fields/field.test.ts +++ b/x-pack/plugins/ingest_manager/server/services/epm/fields/field.test.ts @@ -179,4 +179,35 @@ describe('processFields', () => { JSON.stringify(mixedFieldsExpanded) ); }); + + const objectFieldWithProperty = [ + { + name: 'a', + type: 'object', + dynamic: true, + }, + { + name: 'a.b', + type: 'keyword', + }, + ]; + + const objectFieldWithPropertyExpanded = [ + { + name: 'a', + type: 'group', + dynamic: true, + fields: [ + { + name: 'b', + type: 'keyword', + }, + ], + }, + ]; + test('correctly handles properties of object type fields', () => { + expect(JSON.stringify(processFields(objectFieldWithProperty))).toEqual( + JSON.stringify(objectFieldWithPropertyExpanded) + ); + }); }); diff --git a/x-pack/plugins/ingest_manager/server/services/epm/fields/field.ts b/x-pack/plugins/ingest_manager/server/services/epm/fields/field.ts index 9c9843e0454ab..edf7624d3f0d5 100644 --- a/x-pack/plugins/ingest_manager/server/services/epm/fields/field.ts +++ b/x-pack/plugins/ingest_manager/server/services/epm/fields/field.ts @@ -108,7 +108,15 @@ function dedupFields(fields: Fields): Fields { return f.name === field.name; }); if (found) { - if (found.type === 'group' && field.type === 'group' && found.fields && field.fields) { + if ( + (found.type === 'group' || found.type === 'object') && + field.type === 'group' && + field.fields + ) { + if (!found.fields) { + found.fields = []; + } + found.type = 'group'; found.fields = dedupFields(found.fields.concat(field.fields)); } else { // only 'group' fields can be merged in this way diff --git a/x-pack/plugins/ingest_manager/server/services/epm/packages/get.ts b/x-pack/plugins/ingest_manager/server/services/epm/packages/get.ts index d76584225877c..da8d79a04b97c 100644 --- a/x-pack/plugins/ingest_manager/server/services/epm/packages/get.ts +++ b/x-pack/plugins/ingest_manager/server/services/epm/packages/get.ts @@ -67,9 +67,10 @@ export async function getPackageInfo(options: { pkgVersion: string; }): Promise { const { savedObjectsClient, pkgName, pkgVersion } = options; - const [item, savedObject, assets] = await Promise.all([ + const [item, savedObject, latestPackage, assets] = await Promise.all([ Registry.fetchInfo(pkgName, pkgVersion), getInstallationObject({ savedObjectsClient, pkgName }), + Registry.fetchFindLatestPackage(pkgName), Registry.getArchiveInfo(pkgName, pkgVersion), ] as const); // adding `as const` due to regression in TS 3.7.2 @@ -79,6 +80,7 @@ export async function getPackageInfo(options: { // add properties that aren't (or aren't yet) on Registry response const updated = { ...item, + latestVersion: latestPackage.version, title: item.title || nameAsTitle(item.name), assets: Registry.groupPathsByService(assets || []), }; diff --git a/x-pack/plugins/ingest_manager/server/services/epm/packages/index.ts b/x-pack/plugins/ingest_manager/server/services/epm/packages/index.ts index d49e0e661440f..c67cccd044bf5 100644 --- a/x-pack/plugins/ingest_manager/server/services/epm/packages/index.ts +++ b/x-pack/plugins/ingest_manager/server/services/epm/packages/index.ts @@ -43,6 +43,7 @@ export function createInstallableFrom( ? { ...from, status: InstallationStatus.installed, + installedVersion: savedObject.attributes.version, savedObject, } : { diff --git a/x-pack/plugins/ingest_manager/server/services/epm/packages/install.ts b/x-pack/plugins/ingest_manager/server/services/epm/packages/install.ts index 06f3decdbbe6f..8f51c4d78305c 100644 --- a/x-pack/plugins/ingest_manager/server/services/epm/packages/install.ts +++ b/x-pack/plugins/ingest_manager/server/services/epm/packages/install.ts @@ -106,7 +106,7 @@ export async function installPackage(options: { try { await deleteKibanaSavedObjectsAssets(savedObjectsClient, installedPkg.attributes.installed); } catch (err) { - // some assets may not exist if deleting during a failed update + // log these errors, some assets may not exist if deleted during a failed update } } diff --git a/x-pack/plugins/ingest_manager/server/services/epm/packages/remove.ts b/x-pack/plugins/ingest_manager/server/services/epm/packages/remove.ts index ac2c869f3b9e9..befb4722b6504 100644 --- a/x-pack/plugins/ingest_manager/server/services/epm/packages/remove.ts +++ b/x-pack/plugins/ingest_manager/server/services/epm/packages/remove.ts @@ -121,8 +121,12 @@ export async function deleteKibanaSavedObjectsAssets( const deletePromises = installedObjects.map(({ id, type }) => { const assetType = type as AssetType; if (savedObjectTypes.includes(assetType)) { - savedObjectsClient.delete(assetType, id); + return savedObjectsClient.delete(assetType, id); } }); - await Promise.all(deletePromises); + try { + await Promise.all(deletePromises); + } catch (err) { + throw new Error('error deleting saved object asset'); + } } diff --git a/x-pack/plugins/ingest_manager/server/services/setup.ts b/x-pack/plugins/ingest_manager/server/services/setup.ts index 206ad76703cf5..390e240841611 100644 --- a/x-pack/plugins/ingest_manager/server/services/setup.ts +++ b/x-pack/plugins/ingest_manager/server/services/setup.ts @@ -145,7 +145,7 @@ async function addPackageToConfig( config.namespace ); newDatasource.inputs = await datasourceService.assignPackageStream( - { pkgName: packageToInstall.name, pkgVersion: packageToInstall.version }, + packageInfo, newDatasource.inputs ); diff --git a/x-pack/plugins/lens/public/xy_visualization/index.ts b/x-pack/plugins/lens/public/xy_visualization/index.ts index 5dfae097be834..3a280fb045b06 100644 --- a/x-pack/plugins/lens/public/xy_visualization/index.ts +++ b/x-pack/plugins/lens/public/xy_visualization/index.ts @@ -53,6 +53,7 @@ export class XyVisualization { ? EUI_CHARTS_THEME_DARK.theme : EUI_CHARTS_THEME_LIGHT.theme, timeZone: getTimeZone(core.uiSettings), + histogramBarTarget: core.uiSettings.get('histogram:barTarget'), }) ); diff --git a/x-pack/plugins/lens/public/xy_visualization/xy_expression.test.tsx b/x-pack/plugins/lens/public/xy_visualization/xy_expression.test.tsx index e75e5fe763d6a..8db00aba0e36d 100644 --- a/x-pack/plugins/lens/public/xy_visualization/xy_expression.test.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/xy_expression.test.tsx @@ -40,7 +40,7 @@ const createSampleDatatableWithRows = (rows: KibanaDatatableRow[]): KibanaDatata id: 'c', name: 'c', formatHint: { id: 'string' }, - meta: { type: 'date-histogram', aggConfigParams: { interval: '10s' } }, + meta: { type: 'date-histogram', aggConfigParams: { interval: 'auto' } }, }, { id: 'd', name: 'ColD', formatHint: { id: 'string' } }, ], @@ -156,6 +156,7 @@ describe('xy_expression', () => { formatFactory={getFormatSpy} timeZone="UTC" chartTheme={{}} + histogramBarTarget={50} executeTriggerActions={executeTriggerActions} /> ); @@ -203,6 +204,7 @@ describe('xy_expression', () => { formatFactory={getFormatSpy} timeZone="UTC" chartTheme={{}} + histogramBarTarget={50} executeTriggerActions={executeTriggerActions} /> ); @@ -237,15 +239,17 @@ describe('xy_expression', () => { formatFactory={getFormatSpy} timeZone="UTC" chartTheme={{}} + histogramBarTarget={50} executeTriggerActions={executeTriggerActions} /> ); + // real auto interval is 30mins = 1800000 expect(component.find(Settings).prop('xDomain')).toMatchInlineSnapshot(` Object { "max": 1546491600000, "min": 1546405200000, - "minInterval": 10000, + "minInterval": 1728000, } `); }); @@ -271,6 +275,7 @@ describe('xy_expression', () => { formatFactory={getFormatSpy} timeZone="UTC" chartTheme={{}} + histogramBarTarget={50} executeTriggerActions={executeTriggerActions} /> ); @@ -279,7 +284,7 @@ describe('xy_expression', () => { Object { "max": 1546491600000, "min": 1546405200000, - "minInterval": 10000, + "minInterval": 1728000, } `); }); @@ -307,6 +312,7 @@ describe('xy_expression', () => { formatFactory={getFormatSpy} timeZone="UTC" chartTheme={{}} + histogramBarTarget={50} executeTriggerActions={executeTriggerActions} /> ); @@ -350,6 +356,7 @@ describe('xy_expression', () => { formatFactory={getFormatSpy} timeZone="UTC" chartTheme={{}} + histogramBarTarget={50} executeTriggerActions={executeTriggerActions} /> ); @@ -383,6 +390,7 @@ describe('xy_expression', () => { formatFactory={getFormatSpy} timeZone="UTC" chartTheme={{}} + histogramBarTarget={50} executeTriggerActions={executeTriggerActions} /> ); @@ -398,6 +406,7 @@ describe('xy_expression', () => { formatFactory={getFormatSpy} timeZone="UTC" chartTheme={{}} + histogramBarTarget={50} executeTriggerActions={executeTriggerActions} /> ); @@ -414,6 +423,7 @@ describe('xy_expression', () => { formatFactory={getFormatSpy} timeZone="UTC" chartTheme={{}} + histogramBarTarget={50} executeTriggerActions={executeTriggerActions} /> ); @@ -430,6 +440,7 @@ describe('xy_expression', () => { formatFactory={getFormatSpy} timeZone="UTC" chartTheme={{}} + histogramBarTarget={50} executeTriggerActions={executeTriggerActions} /> ); @@ -472,6 +483,7 @@ describe('xy_expression', () => { formatFactory={getFormatSpy} timeZone="UTC" chartTheme={{}} + histogramBarTarget={50} executeTriggerActions={executeTriggerActions} /> ); @@ -510,6 +522,7 @@ describe('xy_expression', () => { formatFactory={getFormatSpy} timeZone="UTC" chartTheme={{}} + histogramBarTarget={50} executeTriggerActions={executeTriggerActions} /> ); @@ -527,6 +540,7 @@ describe('xy_expression', () => { formatFactory={getFormatSpy} timeZone="UTC" chartTheme={{}} + histogramBarTarget={50} executeTriggerActions={executeTriggerActions} /> ); @@ -547,6 +561,7 @@ describe('xy_expression', () => { formatFactory={getFormatSpy} timeZone="UTC" chartTheme={{}} + histogramBarTarget={50} executeTriggerActions={executeTriggerActions} /> ); @@ -565,6 +580,7 @@ describe('xy_expression', () => { formatFactory={getFormatSpy} timeZone="CEST" chartTheme={{}} + histogramBarTarget={50} executeTriggerActions={executeTriggerActions} /> ); @@ -582,6 +598,7 @@ describe('xy_expression', () => { formatFactory={getFormatSpy} timeZone="UTC" chartTheme={{}} + histogramBarTarget={50} executeTriggerActions={executeTriggerActions} /> ); @@ -606,6 +623,7 @@ describe('xy_expression', () => { formatFactory={getFormatSpy} timeZone="UTC" chartTheme={{}} + histogramBarTarget={50} executeTriggerActions={executeTriggerActions} /> ); @@ -624,6 +642,7 @@ describe('xy_expression', () => { formatFactory={getFormatSpy} timeZone="UTC" chartTheme={{}} + histogramBarTarget={50} executeTriggerActions={executeTriggerActions} /> ); @@ -684,6 +703,7 @@ describe('xy_expression', () => { formatFactory={getFormatSpy} timeZone="UTC" chartTheme={{}} + histogramBarTarget={50} executeTriggerActions={executeTriggerActions} /> ); @@ -878,6 +898,7 @@ describe('xy_expression', () => { formatFactory={getFormatSpy} timeZone="UTC" chartTheme={{}} + histogramBarTarget={50} executeTriggerActions={executeTriggerActions} /> ); @@ -894,6 +915,7 @@ describe('xy_expression', () => { formatFactory={getFormatSpy} timeZone="UTC" chartTheme={{}} + histogramBarTarget={50} executeTriggerActions={executeTriggerActions} /> ); @@ -910,6 +932,7 @@ describe('xy_expression', () => { formatFactory={getFormatSpy} timeZone="UTC" chartTheme={{}} + histogramBarTarget={50} executeTriggerActions={executeTriggerActions} /> ); @@ -927,6 +950,7 @@ describe('xy_expression', () => { formatFactory={getFormatSpy} timeZone="UTC" chartTheme={{}} + histogramBarTarget={50} executeTriggerActions={executeTriggerActions} /> ); @@ -943,6 +967,7 @@ describe('xy_expression', () => { args={{ ...args, layers: [{ ...args.layers[0], accessors: ['a'] }] }} formatFactory={getFormatSpy} chartTheme={{}} + histogramBarTarget={50} timeZone="UTC" executeTriggerActions={executeTriggerActions} /> @@ -963,6 +988,7 @@ describe('xy_expression', () => { formatFactory={getFormatSpy} timeZone="UTC" chartTheme={{}} + histogramBarTarget={50} executeTriggerActions={executeTriggerActions} /> ); diff --git a/x-pack/plugins/lens/public/xy_visualization/xy_expression.tsx b/x-pack/plugins/lens/public/xy_visualization/xy_expression.tsx index d6b6de479acfb..85cf5753befd7 100644 --- a/x-pack/plugins/lens/public/xy_visualization/xy_expression.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/xy_expression.tsx @@ -6,6 +6,7 @@ import React, { useState, useEffect } from 'react'; import ReactDOM from 'react-dom'; +import moment from 'moment'; import { Chart, Settings, @@ -35,8 +36,8 @@ import { XYArgs, SeriesType, visualizationTypes } from './types'; import { VisualizationContainer } from '../visualization_container'; import { isHorizontalChart } from './state_helpers'; import { UiActionsStart } from '../../../../../src/plugins/ui_actions/public'; -import { parseInterval } from '../../../../../src/plugins/data/common'; import { getExecuteTriggerActions } from './services'; +import { parseInterval } from '../../../../../src/plugins/data/common'; type InferPropType = T extends React.FunctionComponent ? P : T; type SeriesSpec = InferPropType & @@ -58,6 +59,7 @@ type XYChartRenderProps = XYChartProps & { chartTheme: PartialTheme; formatFactory: FormatFactory; timeZone: string; + histogramBarTarget: number; executeTriggerActions: UiActionsStart['executeTriggerActions']; }; @@ -110,6 +112,7 @@ export const xyChart: ExpressionFunctionDefinition< export const getXyChartRenderer = (dependencies: { formatFactory: Promise; chartTheme: PartialTheme; + histogramBarTarget: number; timeZone: string; }): ExpressionRenderDefinition => ({ name: 'lens_xy_chart_renderer', @@ -130,6 +133,7 @@ export const getXyChartRenderer = (dependencies: { formatFactory={formatFactory} chartTheme={dependencies.chartTheme} timeZone={dependencies.timeZone} + histogramBarTarget={dependencies.histogramBarTarget} executeTriggerActions={executeTriggerActions} /> , @@ -169,6 +173,7 @@ export function XYChart({ formatFactory, timeZone, chartTheme, + histogramBarTarget, executeTriggerActions, }: XYChartRenderProps) { const { legend, layers } = args; @@ -212,18 +217,26 @@ export function XYChart({ const xTitle = (xAxisColumn && xAxisColumn.name) || args.xTitle; - // add minInterval only for single row value as it cannot be determined from dataset + function calculateMinInterval() { + // add minInterval only for single row value as it cannot be determined from dataset + if (data.dateRange && layers.every(layer => data.tables[layer.layerId].rows.length <= 1)) { + if (xAxisColumn?.meta?.aggConfigParams?.interval !== 'auto') + return parseInterval(xAxisColumn?.meta?.aggConfigParams?.interval)?.asMilliseconds(); - const minInterval = layers.every(layer => data.tables[layer.layerId].rows.length <= 1) - ? parseInterval(xAxisColumn?.meta?.aggConfigParams?.interval)?.asMilliseconds() - : undefined; + const { fromDate, toDate } = data.dateRange; + const duration = moment(toDate).diff(moment(fromDate)); + const targetMs = duration / histogramBarTarget; + return isNaN(targetMs) ? 0 : Math.max(Math.floor(targetMs), 1); + } + return undefined; + } const xDomain = data.dateRange && layers.every(l => l.xScaleType === 'time') ? { min: data.dateRange.fromDate.getTime(), max: data.dateRange.toDate.getTime(), - minInterval, + minInterval: calculateMinInterval(), } : undefined; return ( diff --git a/x-pack/plugins/maps/public/layers/layer_wizard_registry.ts b/x-pack/plugins/maps/public/layers/layer_wizard_registry.ts index 633e8c86d8c94..7715541b1c52d 100644 --- a/x-pack/plugins/maps/public/layers/layer_wizard_registry.ts +++ b/x-pack/plugins/maps/public/layers/layer_wizard_registry.ts @@ -20,6 +20,7 @@ export type RenderWizardArguments = { }; export type LayerWizard = { + checkVisibility?: () => boolean; description: string; icon: string; isIndexingSource?: boolean; @@ -34,5 +35,7 @@ export function registerLayerWizard(layerWizard: LayerWizard) { } export function getLayerWizards(): LayerWizard[] { - return [...registry]; + return registry.filter(layerWizard => { + return layerWizard.checkVisibility ? layerWizard.checkVisibility() : true; + }); } diff --git a/x-pack/plugins/maps/public/layers/sources/ems_file_source/ems_boundaries_layer_wizard.tsx b/x-pack/plugins/maps/public/layers/sources/ems_file_source/ems_boundaries_layer_wizard.tsx index f31e770df2d95..a6e2e7f42657c 100644 --- a/x-pack/plugins/maps/public/layers/sources/ems_file_source/ems_boundaries_layer_wizard.tsx +++ b/x-pack/plugins/maps/public/layers/sources/ems_file_source/ems_boundaries_layer_wizard.tsx @@ -12,8 +12,13 @@ import { LayerWizard, RenderWizardArguments } from '../../layer_wizard_registry' import { EMSFileCreateSourceEditor } from './create_source_editor'; // @ts-ignore import { EMSFileSource, sourceTitle } from './ems_file_source'; +// @ts-ignore +import { isEmsEnabled } from '../../../meta'; export const emsBoundariesLayerWizardConfig: LayerWizard = { + checkVisibility: () => { + return isEmsEnabled(); + }, description: i18n.translate('xpack.maps.source.emsFileDescription', { defaultMessage: 'Administrative boundaries from Elastic Maps Service', }), diff --git a/x-pack/plugins/maps/public/layers/sources/ems_tms_source/ems_base_map_layer_wizard.tsx b/x-pack/plugins/maps/public/layers/sources/ems_tms_source/ems_base_map_layer_wizard.tsx index ced33a0bcf84a..fc745edbabee8 100644 --- a/x-pack/plugins/maps/public/layers/sources/ems_tms_source/ems_base_map_layer_wizard.tsx +++ b/x-pack/plugins/maps/public/layers/sources/ems_tms_source/ems_base_map_layer_wizard.tsx @@ -12,8 +12,13 @@ import { EMSTMSSource, sourceTitle } from './ems_tms_source'; import { VectorTileLayer } from '../../vector_tile_layer'; // @ts-ignore import { TileServiceSelect } from './tile_service_select'; +// @ts-ignore +import { isEmsEnabled } from '../../../meta'; export const emsBaseMapLayerWizardConfig: LayerWizard = { + checkVisibility: () => { + return isEmsEnabled(); + }, description: i18n.translate('xpack.maps.source.emsTileDescription', { defaultMessage: 'Tile map service from Elastic Maps Service', }), diff --git a/x-pack/plugins/maps/public/layers/sources/kibana_regionmap_source/kibana_regionmap_layer_wizard.tsx b/x-pack/plugins/maps/public/layers/sources/kibana_regionmap_source/kibana_regionmap_layer_wizard.tsx index 4321501760faf..a9adec2bda2c8 100644 --- a/x-pack/plugins/maps/public/layers/sources/kibana_regionmap_source/kibana_regionmap_layer_wizard.tsx +++ b/x-pack/plugins/maps/public/layers/sources/kibana_regionmap_source/kibana_regionmap_layer_wizard.tsx @@ -12,8 +12,14 @@ import { KibanaRegionmapSource, sourceTitle } from './kibana_regionmap_source'; import { VectorLayer } from '../../vector_layer'; // @ts-ignore import { CreateSourceEditor } from './create_source_editor'; +// @ts-ignore +import { getKibanaRegionList } from '../../../meta'; export const kibanaRegionMapLayerWizardConfig: LayerWizard = { + checkVisibility: () => { + const regions = getKibanaRegionList(); + return regions.length; + }, description: i18n.translate('xpack.maps.source.kbnRegionMapDescription', { defaultMessage: 'Vector data from hosted GeoJSON configured in kibana.yml', }), diff --git a/x-pack/plugins/maps/public/layers/sources/kibana_tilemap_source/kibana_base_map_layer_wizard.tsx b/x-pack/plugins/maps/public/layers/sources/kibana_tilemap_source/kibana_base_map_layer_wizard.tsx index aeea2d6084f84..141fabeedd3e5 100644 --- a/x-pack/plugins/maps/public/layers/sources/kibana_tilemap_source/kibana_base_map_layer_wizard.tsx +++ b/x-pack/plugins/maps/public/layers/sources/kibana_tilemap_source/kibana_base_map_layer_wizard.tsx @@ -12,8 +12,14 @@ import { CreateSourceEditor } from './create_source_editor'; // @ts-ignore import { KibanaTilemapSource, sourceTitle } from './kibana_tilemap_source'; import { TileLayer } from '../../tile_layer'; +// @ts-ignore +import { getKibanaTileMap } from '../../../meta'; export const kibanaBasemapLayerWizardConfig: LayerWizard = { + checkVisibility: () => { + const tilemap = getKibanaTileMap(); + return !!tilemap.url; + }, description: i18n.translate('xpack.maps.source.kbnTMSDescription', { defaultMessage: 'Tile map service configured in kibana.yml', }), diff --git a/x-pack/plugins/maps/public/meta.js b/x-pack/plugins/maps/public/meta.js index d4612554cf00b..c3245e8e98db2 100644 --- a/x-pack/plugins/maps/public/meta.js +++ b/x-pack/plugins/maps/public/meta.js @@ -36,12 +36,15 @@ function fetchFunction(...args) { return fetch(...args); } +export function isEmsEnabled() { + return getInjectedVarFunc()('isEmsEnabled', true); +} + let emsClient = null; let latestLicenseId = null; export function getEMSClient() { if (!emsClient) { - const isEmsEnabled = getInjectedVarFunc()('isEmsEnabled', true); - if (isEmsEnabled) { + if (isEmsEnabled()) { const proxyElasticMapsServiceInMaps = getInjectedVarFunc()( 'proxyElasticMapsServiceInMaps', false @@ -86,7 +89,7 @@ export function getEMSClient() { } export function getGlyphUrl() { - if (!getInjectedVarFunc()('isEmsEnabled', true)) { + if (!isEmsEnabled()) { return ''; } return getInjectedVarFunc()('proxyElasticMapsServiceInMaps', false) diff --git a/x-pack/plugins/ml/common/types/capabilities.ts b/x-pack/plugins/ml/common/types/capabilities.ts index 2a449c95faa5b..da5fd3ac25209 100644 --- a/x-pack/plugins/ml/common/types/capabilities.ts +++ b/x-pack/plugins/ml/common/types/capabilities.ts @@ -7,6 +7,7 @@ import { KibanaRequest } from 'kibana/server'; export const userMlCapabilities = { + canAccessML: false, // Anomaly Detection canGetJobs: false, canGetDatafeeds: false, @@ -18,6 +19,10 @@ export const userMlCapabilities = { canGetFilters: false, // Data Frame Analytics canGetDataFrameAnalytics: false, + // Annotations + canGetAnnotations: false, + canCreateAnnotation: false, + canDeleteAnnotation: false, }; export const adminMlCapabilities = { @@ -26,9 +31,11 @@ export const adminMlCapabilities = { canDeleteJob: false, canOpenJob: false, canCloseJob: false, + canUpdateJob: false, canForecastJob: false, + canCreateDatafeed: false, + canDeleteDatafeed: false, canStartStopDatafeed: false, - canUpdateJob: false, canUpdateDatafeed: false, canPreviewDatafeed: false, // Calendars @@ -38,8 +45,8 @@ export const adminMlCapabilities = { canCreateFilter: false, canDeleteFilter: false, // Data Frame Analytics - canDeleteDataFrameAnalytics: false, canCreateDataFrameAnalytics: false, + canDeleteDataFrameAnalytics: false, canStartStopDataFrameAnalytics: false, }; @@ -47,7 +54,9 @@ export type UserMlCapabilities = typeof userMlCapabilities; export type AdminMlCapabilities = typeof adminMlCapabilities; export type MlCapabilities = UserMlCapabilities & AdminMlCapabilities; -export const basicLicenseMlCapabilities = ['canFindFileStructure'] as Array; +export const basicLicenseMlCapabilities = ['canAccessML', 'canFindFileStructure'] as Array< + keyof MlCapabilities +>; export function getDefaultCapabilities(): MlCapabilities { return { @@ -56,6 +65,23 @@ export function getDefaultCapabilities(): MlCapabilities { }; } +export function getPluginPrivileges() { + const userMlCapabilitiesKeys = Object.keys(userMlCapabilities); + const adminMlCapabilitiesKeys = Object.keys(adminMlCapabilities); + const allMlCapabilities = [...adminMlCapabilitiesKeys, ...userMlCapabilitiesKeys]; + + return { + user: { + ui: userMlCapabilitiesKeys, + api: userMlCapabilitiesKeys.map(k => `ml:${k}`), + }, + admin: { + ui: allMlCapabilities, + api: allMlCapabilities.map(k => `ml:${k}`), + }, + }; +} + export interface MlCapabilitiesResponse { capabilities: MlCapabilities; upgradeInProgress: boolean; diff --git a/x-pack/plugins/ml/public/application/overview/components/analytics_panel/analytics_panel.tsx b/x-pack/plugins/ml/public/application/overview/components/analytics_panel/analytics_panel.tsx index b2eda12abc578..c379cd702daee 100644 --- a/x-pack/plugins/ml/public/application/overview/components/analytics_panel/analytics_panel.tsx +++ b/x-pack/plugins/ml/public/application/overview/components/analytics_panel/analytics_panel.tsx @@ -82,14 +82,14 @@ export const AnalyticsPanel: FC = ({ jobCreationDisabled }) => { title={

{i18n.translate('xpack.ml.overview.analyticsList.createFirstJobMessage', { - defaultMessage: 'Create your first analytics job', + defaultMessage: 'Create your first data frame analytics job', })}

} body={

{i18n.translate('xpack.ml.overview.analyticsList.emptyPromptText', { - defaultMessage: `Data frame analytics enable you to perform different analyses of your data and annotate it with the results. The analytics job stores the annotated data, as well as a copy of the source data, in a new index.`, + defaultMessage: `Data frame analytics enable you to perform different analyses of your data and annotates it with the results. The job puts the annotated data and a copy of the source data in a new index.`, })}

} diff --git a/x-pack/plugins/ml/public/application/overview/components/anomaly_detection_panel/anomaly_detection_panel.tsx b/x-pack/plugins/ml/public/application/overview/components/anomaly_detection_panel/anomaly_detection_panel.tsx index 5f5c3f7c28670..dac39b1a2071d 100644 --- a/x-pack/plugins/ml/public/application/overview/components/anomaly_detection_panel/anomaly_detection_panel.tsx +++ b/x-pack/plugins/ml/public/application/overview/components/anomaly_detection_panel/anomaly_detection_panel.tsx @@ -172,7 +172,7 @@ export const AnomalyDetectionPanel: FC = ({ jobCreationDisabled }) => {

{i18n.translate('xpack.ml.overview.anomalyDetection.emptyPromptText', { - defaultMessage: `Machine learning makes it easy to detect anomalies in time series data stored in Elasticsearch. Track one metric from a single machine or hundreds of metrics across thousands of machines. Start automatically spotting the anomalies hiding in your data and resolve issues faster.`, + defaultMessage: `Anomaly detection enables you to find unusual behavior in time series data. Start automatically spotting the anomalies hiding in your data and resolve issues faster.`, })}

diff --git a/x-pack/plugins/ml/public/application/overview/components/sidebar.tsx b/x-pack/plugins/ml/public/application/overview/components/sidebar.tsx index 219c195bab111..3e4e9cfbd2b66 100644 --- a/x-pack/plugins/ml/public/application/overview/components/sidebar.tsx +++ b/x-pack/plugins/ml/public/application/overview/components/sidebar.tsx @@ -11,7 +11,6 @@ import { useMlKibana } from '../../contexts/kibana'; const createJobLink = '#/jobs/new_job/step/index_or_search'; const feedbackLink = 'https://www.elastic.co/community/'; -const whatIsMachineLearningLink = 'https://www.elastic.co/what-is/elasticsearch-machine-learning'; interface Props { createAnomalyDetectionJobDisabled: boolean; @@ -60,7 +59,7 @@ export const OverviewSideBar: FC = ({ createAnomalyDetectionJobDisabled }

@@ -79,14 +78,6 @@ export const OverviewSideBar: FC = ({ createAnomalyDetectionJobDisabled } /> ), - whatIsMachineLearning: ( - - - - ), }} />

@@ -96,7 +87,7 @@ export const OverviewSideBar: FC = ({ createAnomalyDetectionJobDisabled }

diff --git a/x-pack/plugins/ml/server/lib/capabilities/check_capabilities.test.ts b/x-pack/plugins/ml/server/lib/capabilities/check_capabilities.test.ts index 5093801d2d184..b6e95ae8373ee 100644 --- a/x-pack/plugins/ml/server/lib/capabilities/check_capabilities.test.ts +++ b/x-pack/plugins/ml/server/lib/capabilities/check_capabilities.test.ts @@ -36,7 +36,7 @@ describe('check_capabilities', () => { ); const { capabilities } = await getCapabilities(); const count = Object.keys(capabilities).length; - expect(count).toBe(22); + expect(count).toBe(28); done(); }); }); @@ -49,28 +49,42 @@ describe('check_capabilities', () => { mlLicense, mlIsEnabled ); - const { capabilities, upgradeInProgress, mlFeatureEnabledInSpace } = await getCapabilities(); + const { + capabilities, + upgradeInProgress, + mlFeatureEnabledInSpace, + isPlatinumOrTrialLicense, + } = await getCapabilities(); expect(upgradeInProgress).toBe(false); expect(mlFeatureEnabledInSpace).toBe(true); + expect(isPlatinumOrTrialLicense).toBe(true); + + expect(capabilities.canAccessML).toBe(true); expect(capabilities.canGetJobs).toBe(true); + expect(capabilities.canGetDatafeeds).toBe(true); + expect(capabilities.canGetCalendars).toBe(true); + expect(capabilities.canFindFileStructure).toBe(true); + expect(capabilities.canGetFilters).toBe(true); + expect(capabilities.canGetDataFrameAnalytics).toBe(true); + expect(capabilities.canGetAnnotations).toBe(true); + expect(capabilities.canCreateAnnotation).toBe(true); + expect(capabilities.canDeleteAnnotation).toBe(true); + expect(capabilities.canCreateJob).toBe(false); expect(capabilities.canDeleteJob).toBe(false); expect(capabilities.canOpenJob).toBe(false); expect(capabilities.canCloseJob).toBe(false); expect(capabilities.canForecastJob).toBe(false); - expect(capabilities.canGetDatafeeds).toBe(true); expect(capabilities.canStartStopDatafeed).toBe(false); expect(capabilities.canUpdateJob).toBe(false); + expect(capabilities.canCreateDatafeed).toBe(false); + expect(capabilities.canDeleteDatafeed).toBe(false); expect(capabilities.canUpdateDatafeed).toBe(false); expect(capabilities.canPreviewDatafeed).toBe(false); - expect(capabilities.canGetCalendars).toBe(true); expect(capabilities.canCreateCalendar).toBe(false); expect(capabilities.canDeleteCalendar).toBe(false); - expect(capabilities.canGetFilters).toBe(true); expect(capabilities.canCreateFilter).toBe(false); expect(capabilities.canDeleteFilter).toBe(false); - expect(capabilities.canFindFileStructure).toBe(true); - expect(capabilities.canGetDataFrameAnalytics).toBe(true); expect(capabilities.canDeleteDataFrameAnalytics).toBe(false); expect(capabilities.canCreateDataFrameAnalytics).toBe(false); expect(capabilities.canStartStopDataFrameAnalytics).toBe(false); @@ -84,28 +98,42 @@ describe('check_capabilities', () => { mlLicense, mlIsEnabled ); - const { capabilities, upgradeInProgress, mlFeatureEnabledInSpace } = await getCapabilities(); + const { + capabilities, + upgradeInProgress, + mlFeatureEnabledInSpace, + isPlatinumOrTrialLicense, + } = await getCapabilities(); expect(upgradeInProgress).toBe(false); expect(mlFeatureEnabledInSpace).toBe(true); + expect(isPlatinumOrTrialLicense).toBe(true); + + expect(capabilities.canAccessML).toBe(true); expect(capabilities.canGetJobs).toBe(true); + expect(capabilities.canGetDatafeeds).toBe(true); + expect(capabilities.canGetCalendars).toBe(true); + expect(capabilities.canFindFileStructure).toBe(true); + expect(capabilities.canGetFilters).toBe(true); + expect(capabilities.canGetDataFrameAnalytics).toBe(true); + expect(capabilities.canGetAnnotations).toBe(true); + expect(capabilities.canCreateAnnotation).toBe(true); + expect(capabilities.canDeleteAnnotation).toBe(true); + expect(capabilities.canCreateJob).toBe(true); expect(capabilities.canDeleteJob).toBe(true); expect(capabilities.canOpenJob).toBe(true); expect(capabilities.canCloseJob).toBe(true); expect(capabilities.canForecastJob).toBe(true); - expect(capabilities.canGetDatafeeds).toBe(true); expect(capabilities.canStartStopDatafeed).toBe(true); expect(capabilities.canUpdateJob).toBe(true); + expect(capabilities.canCreateDatafeed).toBe(true); + expect(capabilities.canDeleteDatafeed).toBe(true); expect(capabilities.canUpdateDatafeed).toBe(true); expect(capabilities.canPreviewDatafeed).toBe(true); - expect(capabilities.canGetCalendars).toBe(true); expect(capabilities.canCreateCalendar).toBe(true); expect(capabilities.canDeleteCalendar).toBe(true); - expect(capabilities.canGetFilters).toBe(true); expect(capabilities.canCreateFilter).toBe(true); expect(capabilities.canDeleteFilter).toBe(true); - expect(capabilities.canFindFileStructure).toBe(true); - expect(capabilities.canGetDataFrameAnalytics).toBe(true); expect(capabilities.canDeleteDataFrameAnalytics).toBe(true); expect(capabilities.canCreateDataFrameAnalytics).toBe(true); expect(capabilities.canStartStopDataFrameAnalytics).toBe(true); @@ -119,28 +147,42 @@ describe('check_capabilities', () => { mlLicense, mlIsEnabled ); - const { capabilities, upgradeInProgress, mlFeatureEnabledInSpace } = await getCapabilities(); + const { + capabilities, + upgradeInProgress, + mlFeatureEnabledInSpace, + isPlatinumOrTrialLicense, + } = await getCapabilities(); expect(upgradeInProgress).toBe(true); expect(mlFeatureEnabledInSpace).toBe(true); + expect(isPlatinumOrTrialLicense).toBe(true); + + expect(capabilities.canAccessML).toBe(true); expect(capabilities.canGetJobs).toBe(true); + expect(capabilities.canGetDatafeeds).toBe(true); + expect(capabilities.canGetCalendars).toBe(true); + expect(capabilities.canFindFileStructure).toBe(true); + expect(capabilities.canGetFilters).toBe(true); + expect(capabilities.canGetDataFrameAnalytics).toBe(true); + expect(capabilities.canGetAnnotations).toBe(true); + expect(capabilities.canCreateAnnotation).toBe(false); + expect(capabilities.canDeleteAnnotation).toBe(false); + expect(capabilities.canCreateJob).toBe(false); expect(capabilities.canDeleteJob).toBe(false); expect(capabilities.canOpenJob).toBe(false); expect(capabilities.canCloseJob).toBe(false); expect(capabilities.canForecastJob).toBe(false); - expect(capabilities.canGetDatafeeds).toBe(true); expect(capabilities.canStartStopDatafeed).toBe(false); expect(capabilities.canUpdateJob).toBe(false); + expect(capabilities.canCreateDatafeed).toBe(false); + expect(capabilities.canDeleteDatafeed).toBe(false); expect(capabilities.canUpdateDatafeed).toBe(false); expect(capabilities.canPreviewDatafeed).toBe(false); - expect(capabilities.canGetCalendars).toBe(true); expect(capabilities.canCreateCalendar).toBe(false); expect(capabilities.canDeleteCalendar).toBe(false); - expect(capabilities.canGetFilters).toBe(true); expect(capabilities.canCreateFilter).toBe(false); expect(capabilities.canDeleteFilter).toBe(false); - expect(capabilities.canFindFileStructure).toBe(true); - expect(capabilities.canGetDataFrameAnalytics).toBe(true); expect(capabilities.canDeleteDataFrameAnalytics).toBe(false); expect(capabilities.canCreateDataFrameAnalytics).toBe(false); expect(capabilities.canStartStopDataFrameAnalytics).toBe(false); @@ -154,28 +196,42 @@ describe('check_capabilities', () => { mlLicense, mlIsEnabled ); - const { capabilities, upgradeInProgress, mlFeatureEnabledInSpace } = await getCapabilities(); + const { + capabilities, + upgradeInProgress, + mlFeatureEnabledInSpace, + isPlatinumOrTrialLicense, + } = await getCapabilities(); expect(upgradeInProgress).toBe(true); expect(mlFeatureEnabledInSpace).toBe(true); + expect(isPlatinumOrTrialLicense).toBe(true); + + expect(capabilities.canAccessML).toBe(true); expect(capabilities.canGetJobs).toBe(true); + expect(capabilities.canGetDatafeeds).toBe(true); + expect(capabilities.canGetCalendars).toBe(true); + expect(capabilities.canFindFileStructure).toBe(true); + expect(capabilities.canGetFilters).toBe(true); + expect(capabilities.canGetDataFrameAnalytics).toBe(true); + expect(capabilities.canGetAnnotations).toBe(true); + expect(capabilities.canCreateAnnotation).toBe(false); + expect(capabilities.canDeleteAnnotation).toBe(false); + expect(capabilities.canCreateJob).toBe(false); expect(capabilities.canDeleteJob).toBe(false); expect(capabilities.canOpenJob).toBe(false); expect(capabilities.canCloseJob).toBe(false); expect(capabilities.canForecastJob).toBe(false); - expect(capabilities.canGetDatafeeds).toBe(true); expect(capabilities.canStartStopDatafeed).toBe(false); expect(capabilities.canUpdateJob).toBe(false); + expect(capabilities.canCreateDatafeed).toBe(false); + expect(capabilities.canDeleteDatafeed).toBe(false); expect(capabilities.canUpdateDatafeed).toBe(false); expect(capabilities.canPreviewDatafeed).toBe(false); - expect(capabilities.canGetCalendars).toBe(true); expect(capabilities.canCreateCalendar).toBe(false); expect(capabilities.canDeleteCalendar).toBe(false); - expect(capabilities.canGetFilters).toBe(true); expect(capabilities.canCreateFilter).toBe(false); expect(capabilities.canDeleteFilter).toBe(false); - expect(capabilities.canFindFileStructure).toBe(true); - expect(capabilities.canGetDataFrameAnalytics).toBe(true); expect(capabilities.canDeleteDataFrameAnalytics).toBe(false); expect(capabilities.canCreateDataFrameAnalytics).toBe(false); expect(capabilities.canStartStopDataFrameAnalytics).toBe(false); @@ -189,28 +245,42 @@ describe('check_capabilities', () => { mlLicense, mlIsNotEnabled ); - const { capabilities, upgradeInProgress, mlFeatureEnabledInSpace } = await getCapabilities(); + const { + capabilities, + upgradeInProgress, + mlFeatureEnabledInSpace, + isPlatinumOrTrialLicense, + } = await getCapabilities(); expect(upgradeInProgress).toBe(false); expect(mlFeatureEnabledInSpace).toBe(false); + expect(isPlatinumOrTrialLicense).toBe(true); + + expect(capabilities.canAccessML).toBe(false); expect(capabilities.canGetJobs).toBe(false); + expect(capabilities.canGetDatafeeds).toBe(false); + expect(capabilities.canGetCalendars).toBe(false); + expect(capabilities.canFindFileStructure).toBe(false); + expect(capabilities.canGetFilters).toBe(false); + expect(capabilities.canGetDataFrameAnalytics).toBe(false); + expect(capabilities.canGetAnnotations).toBe(false); + expect(capabilities.canCreateAnnotation).toBe(false); + expect(capabilities.canDeleteAnnotation).toBe(false); + expect(capabilities.canCreateJob).toBe(false); expect(capabilities.canDeleteJob).toBe(false); expect(capabilities.canOpenJob).toBe(false); expect(capabilities.canCloseJob).toBe(false); expect(capabilities.canForecastJob).toBe(false); - expect(capabilities.canGetDatafeeds).toBe(false); expect(capabilities.canStartStopDatafeed).toBe(false); expect(capabilities.canUpdateJob).toBe(false); + expect(capabilities.canCreateDatafeed).toBe(false); + expect(capabilities.canDeleteDatafeed).toBe(false); expect(capabilities.canUpdateDatafeed).toBe(false); expect(capabilities.canPreviewDatafeed).toBe(false); - expect(capabilities.canGetCalendars).toBe(false); expect(capabilities.canCreateCalendar).toBe(false); expect(capabilities.canDeleteCalendar).toBe(false); - expect(capabilities.canGetFilters).toBe(false); expect(capabilities.canCreateFilter).toBe(false); expect(capabilities.canDeleteFilter).toBe(false); - expect(capabilities.canFindFileStructure).toBe(false); - expect(capabilities.canGetDataFrameAnalytics).toBe(false); expect(capabilities.canDeleteDataFrameAnalytics).toBe(false); expect(capabilities.canCreateDataFrameAnalytics).toBe(false); expect(capabilities.canStartStopDataFrameAnalytics).toBe(false); @@ -225,28 +295,43 @@ describe('check_capabilities', () => { mlLicenseBasic, mlIsNotEnabled ); - const { capabilities, upgradeInProgress, mlFeatureEnabledInSpace } = await getCapabilities(); + const { + capabilities, + upgradeInProgress, + mlFeatureEnabledInSpace, + isPlatinumOrTrialLicense, + } = await getCapabilities(); + expect(upgradeInProgress).toBe(false); expect(mlFeatureEnabledInSpace).toBe(false); + expect(isPlatinumOrTrialLicense).toBe(false); + + expect(capabilities.canAccessML).toBe(false); expect(capabilities.canGetJobs).toBe(false); + expect(capabilities.canGetDatafeeds).toBe(false); + expect(capabilities.canGetCalendars).toBe(false); + expect(capabilities.canFindFileStructure).toBe(false); + expect(capabilities.canGetFilters).toBe(false); + expect(capabilities.canGetDataFrameAnalytics).toBe(false); + expect(capabilities.canGetAnnotations).toBe(false); + expect(capabilities.canCreateAnnotation).toBe(false); + expect(capabilities.canDeleteAnnotation).toBe(false); + expect(capabilities.canCreateJob).toBe(false); expect(capabilities.canDeleteJob).toBe(false); expect(capabilities.canOpenJob).toBe(false); expect(capabilities.canCloseJob).toBe(false); expect(capabilities.canForecastJob).toBe(false); - expect(capabilities.canGetDatafeeds).toBe(false); expect(capabilities.canStartStopDatafeed).toBe(false); expect(capabilities.canUpdateJob).toBe(false); + expect(capabilities.canCreateDatafeed).toBe(false); + expect(capabilities.canDeleteDatafeed).toBe(false); expect(capabilities.canUpdateDatafeed).toBe(false); expect(capabilities.canPreviewDatafeed).toBe(false); - expect(capabilities.canGetCalendars).toBe(false); expect(capabilities.canCreateCalendar).toBe(false); expect(capabilities.canDeleteCalendar).toBe(false); - expect(capabilities.canGetFilters).toBe(false); expect(capabilities.canCreateFilter).toBe(false); expect(capabilities.canDeleteFilter).toBe(false); - expect(capabilities.canFindFileStructure).toBe(false); - expect(capabilities.canGetDataFrameAnalytics).toBe(false); expect(capabilities.canDeleteDataFrameAnalytics).toBe(false); expect(capabilities.canCreateDataFrameAnalytics).toBe(false); expect(capabilities.canStartStopDataFrameAnalytics).toBe(false); diff --git a/x-pack/plugins/ml/server/lib/capabilities/check_capabilities.ts b/x-pack/plugins/ml/server/lib/capabilities/check_capabilities.ts index a2ad83c5522de..d955cf981faca 100644 --- a/x-pack/plugins/ml/server/lib/capabilities/check_capabilities.ts +++ b/x-pack/plugins/ml/server/lib/capabilities/check_capabilities.ts @@ -44,4 +44,6 @@ function disableAdminPrivileges(capabilities: MlCapabilities) { Object.keys(adminMlCapabilities).forEach(k => { capabilities[k as keyof MlCapabilities] = false; }); + capabilities.canCreateAnnotation = false; + capabilities.canDeleteAnnotation = false; } diff --git a/x-pack/plugins/ml/server/plugin.ts b/x-pack/plugins/ml/server/plugin.ts index 64f8eb4b0acd3..969b74194148b 100644 --- a/x-pack/plugins/ml/server/plugin.ts +++ b/x-pack/plugins/ml/server/plugin.ts @@ -45,7 +45,7 @@ import { systemRoutes } from './routes/system'; import { MlLicense } from '../common/license'; import { MlServerLicense } from './lib/license'; import { createSharedServices, SharedServices } from './shared_services'; -import { userMlCapabilities, adminMlCapabilities } from '../common/types/capabilities'; +import { getPluginPrivileges } from '../common/types/capabilities'; import { setupCapabilitiesSwitcher } from './lib/capabilities'; import { registerKibanaSettings } from './lib/register_settings'; @@ -75,8 +75,7 @@ export class MlServerPlugin implements Plugin { try { @@ -86,6 +89,9 @@ export function annotationRoutes( validate: { body: indexAnnotationSchema, }, + options: { + tags: ['access:ml:canCreateAnnotation'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -130,6 +136,9 @@ export function annotationRoutes( validate: { params: deleteAnnotationSchema, }, + options: { + tags: ['access:ml:canDeleteAnnotation'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { diff --git a/x-pack/plugins/ml/server/routes/anomaly_detectors.ts b/x-pack/plugins/ml/server/routes/anomaly_detectors.ts index ca63d69f403f6..63cd5498231af 100644 --- a/x-pack/plugins/ml/server/routes/anomaly_detectors.ts +++ b/x-pack/plugins/ml/server/routes/anomaly_detectors.ts @@ -37,6 +37,9 @@ export function jobRoutes({ router, mlLicense }: RouteInitialization) { { path: '/api/ml/anomaly_detectors', validate: false, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -65,6 +68,9 @@ export function jobRoutes({ router, mlLicense }: RouteInitialization) { validate: { params: jobIdSchema, }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -93,6 +99,9 @@ export function jobRoutes({ router, mlLicense }: RouteInitialization) { { path: '/api/ml/anomaly_detectors/_stats', validate: false, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -121,6 +130,9 @@ export function jobRoutes({ router, mlLicense }: RouteInitialization) { validate: { params: jobIdSchema, }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -154,6 +166,9 @@ export function jobRoutes({ router, mlLicense }: RouteInitialization) { params: jobIdSchema, body: schema.object(anomalyDetectionJobSchema), }, + options: { + tags: ['access:ml:canCreateJob'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -188,6 +203,9 @@ export function jobRoutes({ router, mlLicense }: RouteInitialization) { params: jobIdSchema, body: anomalyDetectionUpdateJobSchema, }, + options: { + tags: ['access:ml:canUpdateJob'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -220,6 +238,9 @@ export function jobRoutes({ router, mlLicense }: RouteInitialization) { validate: { params: jobIdSchema, }, + options: { + tags: ['access:ml:canOpenJob'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -251,6 +272,9 @@ export function jobRoutes({ router, mlLicense }: RouteInitialization) { validate: { params: jobIdSchema, }, + options: { + tags: ['access:ml:canCloseJob'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -286,6 +310,9 @@ export function jobRoutes({ router, mlLicense }: RouteInitialization) { validate: { params: jobIdSchema, }, + options: { + tags: ['access:ml:canDeleteJob'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -319,6 +346,9 @@ export function jobRoutes({ router, mlLicense }: RouteInitialization) { validate: { body: schema.any(), }, + options: { + tags: ['access:ml:canCreateJob'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -351,6 +381,9 @@ export function jobRoutes({ router, mlLicense }: RouteInitialization) { params: jobIdSchema, body: forecastAnomalyDetector, }, + options: { + tags: ['access:ml:canForecastJob'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -389,6 +422,9 @@ export function jobRoutes({ router, mlLicense }: RouteInitialization) { params: jobIdSchema, body: getRecordsSchema, }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -425,6 +461,9 @@ export function jobRoutes({ router, mlLicense }: RouteInitialization) { params: getBucketParamsSchema, body: getBucketsSchema, }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -462,6 +501,9 @@ export function jobRoutes({ router, mlLicense }: RouteInitialization) { params: jobIdSchema, body: getOverallBucketsSchema, }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -496,6 +538,9 @@ export function jobRoutes({ router, mlLicense }: RouteInitialization) { validate: { params: getCategoriesSchema, }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { diff --git a/x-pack/plugins/ml/server/routes/calendars.ts b/x-pack/plugins/ml/server/routes/calendars.ts index a17601f74ae93..9c80651a13999 100644 --- a/x-pack/plugins/ml/server/routes/calendars.ts +++ b/x-pack/plugins/ml/server/routes/calendars.ts @@ -52,6 +52,9 @@ export function calendars({ router, mlLicense }: RouteInitialization) { { path: '/api/ml/calendars', validate: false, + options: { + tags: ['access:ml:canGetCalendars'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -81,6 +84,9 @@ export function calendars({ router, mlLicense }: RouteInitialization) { validate: { params: calendarIdsSchema, }, + options: { + tags: ['access:ml:canGetCalendars'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { let returnValue; @@ -117,6 +123,9 @@ export function calendars({ router, mlLicense }: RouteInitialization) { validate: { body: calendarSchema, }, + options: { + tags: ['access:ml:canCreateCalendar'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -149,6 +158,9 @@ export function calendars({ router, mlLicense }: RouteInitialization) { params: calendarIdSchema, body: calendarSchema, }, + options: { + tags: ['access:ml:canCreateCalendar'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -180,6 +192,9 @@ export function calendars({ router, mlLicense }: RouteInitialization) { validate: { params: calendarIdSchema, }, + options: { + tags: ['access:ml:canDeleteCalendar'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { diff --git a/x-pack/plugins/ml/server/routes/data_frame_analytics.ts b/x-pack/plugins/ml/server/routes/data_frame_analytics.ts index dd9e0ea66aa9d..32cb2b343f876 100644 --- a/x-pack/plugins/ml/server/routes/data_frame_analytics.ts +++ b/x-pack/plugins/ml/server/routes/data_frame_analytics.ts @@ -33,6 +33,9 @@ export function dataFrameAnalyticsRoutes({ router, mlLicense }: RouteInitializat { path: '/api/ml/data_frame/analytics', validate: false, + options: { + tags: ['access:ml:canGetDataFrameAnalytics'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -61,6 +64,9 @@ export function dataFrameAnalyticsRoutes({ router, mlLicense }: RouteInitializat validate: { params: analyticsIdSchema, }, + options: { + tags: ['access:ml:canGetDataFrameAnalytics'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -88,6 +94,9 @@ export function dataFrameAnalyticsRoutes({ router, mlLicense }: RouteInitializat { path: '/api/ml/data_frame/analytics/_stats', validate: false, + options: { + tags: ['access:ml:canGetDataFrameAnalytics'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -118,6 +127,9 @@ export function dataFrameAnalyticsRoutes({ router, mlLicense }: RouteInitializat validate: { params: analyticsIdSchema, }, + options: { + tags: ['access:ml:canGetDataFrameAnalytics'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -155,6 +167,9 @@ export function dataFrameAnalyticsRoutes({ router, mlLicense }: RouteInitializat params: analyticsIdSchema, body: dataAnalyticsJobConfigSchema, }, + options: { + tags: ['access:ml:canCreateDataFrameAnalytics'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -190,6 +205,9 @@ export function dataFrameAnalyticsRoutes({ router, mlLicense }: RouteInitializat validate: { body: dataAnalyticsEvaluateSchema, }, + options: { + tags: ['access:ml:canCreateDataFrameAnalytics'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -224,6 +242,9 @@ export function dataFrameAnalyticsRoutes({ router, mlLicense }: RouteInitializat validate: { body: dataAnalyticsExplainSchema, }, + options: { + tags: ['access:ml:canCreateDataFrameAnalytics'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -257,6 +278,9 @@ export function dataFrameAnalyticsRoutes({ router, mlLicense }: RouteInitializat validate: { params: analyticsIdSchema, }, + options: { + tags: ['access:ml:canDeleteDataFrameAnalytics'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -291,6 +315,9 @@ export function dataFrameAnalyticsRoutes({ router, mlLicense }: RouteInitializat validate: { params: analyticsIdSchema, }, + options: { + tags: ['access:ml:canStartStopDataFrameAnalytics'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -324,6 +351,9 @@ export function dataFrameAnalyticsRoutes({ router, mlLicense }: RouteInitializat params: analyticsIdSchema, query: stopsDataFrameAnalyticsJobQuerySchema, }, + options: { + tags: ['access:ml:canStartStopDataFrameAnalytics'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -364,6 +394,9 @@ export function dataFrameAnalyticsRoutes({ router, mlLicense }: RouteInitializat validate: { params: analyticsIdSchema, }, + options: { + tags: ['access:ml:canGetDataFrameAnalytics'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { diff --git a/x-pack/plugins/ml/server/routes/data_visualizer.ts b/x-pack/plugins/ml/server/routes/data_visualizer.ts index 20029fbd8d1a6..04008a896a1a2 100644 --- a/x-pack/plugins/ml/server/routes/data_visualizer.ts +++ b/x-pack/plugins/ml/server/routes/data_visualizer.ts @@ -88,6 +88,9 @@ export function dataVisualizerRoutes({ router, mlLicense }: RouteInitialization) params: indexPatternTitleSchema, body: dataVisualizerFieldStatsSchema, }, + options: { + tags: ['access:ml:canAccessML'], + }, }, mlLicense.basicLicenseAPIGuard(async (context, request, response) => { try { @@ -150,6 +153,9 @@ export function dataVisualizerRoutes({ router, mlLicense }: RouteInitialization) params: indexPatternTitleSchema, body: dataVisualizerOverallStatsSchema, }, + options: { + tags: ['access:ml:canAccessML'], + }, }, mlLicense.basicLicenseAPIGuard(async (context, request, response) => { try { diff --git a/x-pack/plugins/ml/server/routes/datafeeds.ts b/x-pack/plugins/ml/server/routes/datafeeds.ts index ec667e1d305f5..1fa1d408372da 100644 --- a/x-pack/plugins/ml/server/routes/datafeeds.ts +++ b/x-pack/plugins/ml/server/routes/datafeeds.ts @@ -28,6 +28,9 @@ export function dataFeedRoutes({ router, mlLicense }: RouteInitialization) { { path: '/api/ml/datafeeds', validate: false, + options: { + tags: ['access:ml:canGetDatafeeds'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -57,6 +60,9 @@ export function dataFeedRoutes({ router, mlLicense }: RouteInitialization) { validate: { params: datafeedIdSchema, }, + options: { + tags: ['access:ml:canGetDatafeeds'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -83,6 +89,9 @@ export function dataFeedRoutes({ router, mlLicense }: RouteInitialization) { { path: '/api/ml/datafeeds/_stats', validate: false, + options: { + tags: ['access:ml:canGetDatafeeds'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -112,6 +121,9 @@ export function dataFeedRoutes({ router, mlLicense }: RouteInitialization) { validate: { params: datafeedIdSchema, }, + options: { + tags: ['access:ml:canGetDatafeeds'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -146,6 +158,9 @@ export function dataFeedRoutes({ router, mlLicense }: RouteInitialization) { params: datafeedIdSchema, body: datafeedConfigSchema, }, + options: { + tags: ['access:ml:canCreateDatafeed'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -181,6 +196,9 @@ export function dataFeedRoutes({ router, mlLicense }: RouteInitialization) { params: datafeedIdSchema, body: datafeedConfigSchema, }, + options: { + tags: ['access:ml:canUpdateDatafeed'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -216,6 +234,9 @@ export function dataFeedRoutes({ router, mlLicense }: RouteInitialization) { params: datafeedIdSchema, query: deleteDatafeedQuerySchema, }, + options: { + tags: ['access:ml:canDeleteDatafeed'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -255,6 +276,9 @@ export function dataFeedRoutes({ router, mlLicense }: RouteInitialization) { params: datafeedIdSchema, body: startDatafeedSchema, }, + options: { + tags: ['access:ml:canStartStopDatafeed'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -291,6 +315,9 @@ export function dataFeedRoutes({ router, mlLicense }: RouteInitialization) { validate: { params: datafeedIdSchema, }, + options: { + tags: ['access:ml:canStartStopDatafeed'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -324,6 +351,9 @@ export function dataFeedRoutes({ router, mlLicense }: RouteInitialization) { validate: { params: datafeedIdSchema, }, + options: { + tags: ['access:ml:canPreviewDatafeed'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { diff --git a/x-pack/plugins/ml/server/routes/fields_service.ts b/x-pack/plugins/ml/server/routes/fields_service.ts index 577e8e0161342..b0f13df294145 100644 --- a/x-pack/plugins/ml/server/routes/fields_service.ts +++ b/x-pack/plugins/ml/server/routes/fields_service.ts @@ -46,8 +46,10 @@ export function fieldsService({ router, mlLicense }: RouteInitialization) { validate: { body: getCardinalityOfFieldsSchema, }, + options: { + tags: ['access:ml:canAccessML'], + }, }, - mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { const resp = await getCardinalityOfFields(context, request.body); @@ -79,6 +81,9 @@ export function fieldsService({ router, mlLicense }: RouteInitialization) { validate: { body: getTimeFieldRangeSchema, }, + options: { + tags: ['access:ml:canAccessML'], + }, }, mlLicense.basicLicenseAPIGuard(async (context, request, response) => { try { diff --git a/x-pack/plugins/ml/server/routes/file_data_visualizer.ts b/x-pack/plugins/ml/server/routes/file_data_visualizer.ts index 3f3fc3f547b6a..0f389f9505943 100644 --- a/x-pack/plugins/ml/server/routes/file_data_visualizer.ts +++ b/x-pack/plugins/ml/server/routes/file_data_visualizer.ts @@ -71,6 +71,7 @@ export function fileDataVisualizerRoutes({ router, mlLicense }: RouteInitializat accepts: ['text/*', 'application/json'], maxBytes: MAX_FILE_SIZE_BYTES, }, + tags: ['access:ml:canFindFileStructure'], }, }, mlLicense.basicLicenseAPIGuard(async (context, request, response) => { @@ -105,6 +106,7 @@ export function fileDataVisualizerRoutes({ router, mlLicense }: RouteInitializat accepts: ['application/json'], maxBytes: MAX_FILE_SIZE_BYTES, }, + tags: ['access:ml:canFindFileStructure'], }, }, mlLicense.basicLicenseAPIGuard(async (context, request, response) => { diff --git a/x-pack/plugins/ml/server/routes/filters.ts b/x-pack/plugins/ml/server/routes/filters.ts index 738c25070358d..d5287c349a8fc 100644 --- a/x-pack/plugins/ml/server/routes/filters.ts +++ b/x-pack/plugins/ml/server/routes/filters.ts @@ -57,6 +57,9 @@ export function filtersRoutes({ router, mlLicense }: RouteInitialization) { { path: '/api/ml/filters', validate: false, + options: { + tags: ['access:ml:canGetFilters'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -89,6 +92,9 @@ export function filtersRoutes({ router, mlLicense }: RouteInitialization) { validate: { params: filterIdSchema, }, + options: { + tags: ['access:ml:canGetFilters'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -120,6 +126,9 @@ export function filtersRoutes({ router, mlLicense }: RouteInitialization) { validate: { body: createFilterSchema, }, + options: { + tags: ['access:ml:canCreateFilter'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -155,6 +164,9 @@ export function filtersRoutes({ router, mlLicense }: RouteInitialization) { params: filterIdSchema, body: updateFilterSchema, }, + options: { + tags: ['access:ml:canCreateFilter'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -186,6 +198,9 @@ export function filtersRoutes({ router, mlLicense }: RouteInitialization) { validate: { params: filterIdSchema, }, + options: { + tags: ['access:ml:canDeleteFilter'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -216,6 +231,9 @@ export function filtersRoutes({ router, mlLicense }: RouteInitialization) { { path: '/api/ml/filters/_stats', validate: false, + options: { + tags: ['access:ml:canGetFilters'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { diff --git a/x-pack/plugins/ml/server/routes/indices.ts b/x-pack/plugins/ml/server/routes/indices.ts index e434936beba63..fb3ef7fc41c76 100644 --- a/x-pack/plugins/ml/server/routes/indices.ts +++ b/x-pack/plugins/ml/server/routes/indices.ts @@ -27,6 +27,9 @@ export function indicesRoutes({ router, mlLicense }: RouteInitialization) { validate: { body: indicesSchema, }, + options: { + tags: ['access:ml:canAccessML'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { diff --git a/x-pack/plugins/ml/server/routes/job_audit_messages.ts b/x-pack/plugins/ml/server/routes/job_audit_messages.ts index 1fe5a7af95d4f..5acc89e7d13be 100644 --- a/x-pack/plugins/ml/server/routes/job_audit_messages.ts +++ b/x-pack/plugins/ml/server/routes/job_audit_messages.ts @@ -33,6 +33,9 @@ export function jobAuditMessagesRoutes({ router, mlLicense }: RouteInitializatio params: jobAuditMessagesJobIdSchema, query: jobAuditMessagesQuerySchema, }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -67,6 +70,9 @@ export function jobAuditMessagesRoutes({ router, mlLicense }: RouteInitializatio validate: { query: jobAuditMessagesQuerySchema, }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { diff --git a/x-pack/plugins/ml/server/routes/job_service.ts b/x-pack/plugins/ml/server/routes/job_service.ts index 149ca2591fd76..05c44e1da9757 100644 --- a/x-pack/plugins/ml/server/routes/job_service.ts +++ b/x-pack/plugins/ml/server/routes/job_service.ts @@ -4,11 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import Boom from 'boom'; import { schema } from '@kbn/config-schema'; -import { KibanaRequest } from 'kibana/server'; import { wrapError } from '../client/error_wrapper'; -import { RouteInitialization, JobServiceRouteDeps } from '../types'; +import { RouteInitialization } from '../types'; import { categorizationFieldExamplesSchema, chartSchema, @@ -27,19 +25,7 @@ import { categorizationExamplesProvider } from '../models/job_service/new_job'; /** * Routes for job service */ -export function jobServiceRoutes( - { router, mlLicense }: RouteInitialization, - { resolveMlCapabilities }: JobServiceRouteDeps -) { - async function hasPermissionToCreateJobs(request: KibanaRequest) { - const mlCapabilities = await resolveMlCapabilities(request); - if (mlCapabilities === null) { - throw new Error('resolveMlCapabilities is not defined'); - } - - return mlCapabilities.canCreateJob; - } - +export function jobServiceRoutes({ router, mlLicense }: RouteInitialization) { /** * @apiGroup JobService * @@ -55,6 +41,9 @@ export function jobServiceRoutes( validate: { body: forceStartDatafeedSchema, }, + options: { + tags: ['access:ml:canStartStopDatafeed'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -86,6 +75,9 @@ export function jobServiceRoutes( validate: { body: datafeedIdsSchema, }, + options: { + tags: ['access:ml:canStartStopDatafeed'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -117,6 +109,9 @@ export function jobServiceRoutes( validate: { body: jobIdsSchema, }, + options: { + tags: ['access:ml:canDeleteJob'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -148,6 +143,9 @@ export function jobServiceRoutes( validate: { body: jobIdsSchema, }, + options: { + tags: ['access:ml:canCloseJob'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -184,6 +182,9 @@ export function jobServiceRoutes( validate: { body: jobIdsSchema, }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -215,6 +216,9 @@ export function jobServiceRoutes( validate: { body: schema.object(jobsWithTimerangeSchema), }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -245,6 +249,9 @@ export function jobServiceRoutes( validate: { body: jobIdsSchema, }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -272,6 +279,9 @@ export function jobServiceRoutes( { path: '/api/ml/jobs/groups', validate: false, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -302,6 +312,9 @@ export function jobServiceRoutes( validate: { body: schema.object(updateGroupsSchema), }, + options: { + tags: ['access:ml:canUpdateJob'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -329,6 +342,9 @@ export function jobServiceRoutes( { path: '/api/ml/jobs/deleting_jobs_tasks', validate: false, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -359,6 +375,9 @@ export function jobServiceRoutes( validate: { body: jobIdsSchema, }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -389,6 +408,9 @@ export function jobServiceRoutes( params: schema.object({ indexPattern: schema.string() }), query: schema.maybe(schema.object({ rollup: schema.maybe(schema.string()) })), }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -422,6 +444,9 @@ export function jobServiceRoutes( validate: { body: schema.object(chartSchema), }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -474,6 +499,9 @@ export function jobServiceRoutes( validate: { body: schema.object(chartSchema), }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -522,6 +550,9 @@ export function jobServiceRoutes( { path: '/api/ml/jobs/all_jobs_and_group_ids', validate: false, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -552,6 +583,9 @@ export function jobServiceRoutes( validate: { body: schema.object(lookBackProgressSchema), }, + options: { + tags: ['access:ml:canCreateJob'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -583,17 +617,12 @@ export function jobServiceRoutes( validate: { body: schema.object(categorizationFieldExamplesSchema), }, + options: { + tags: ['access:ml:canCreateJob'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { - // due to the use of the _analyze endpoint which is called by the kibana user, - // basic job creation privileges are required to use this endpoint - if ((await hasPermissionToCreateJobs(request)) === false) { - throw Boom.forbidden( - 'Insufficient privileges, the machine_learning_admin role is required.' - ); - } - const { validateCategoryExamples } = categorizationExamplesProvider( context.ml!.mlClient.callAsCurrentUser, context.ml!.mlClient.callAsInternalUser @@ -644,6 +673,9 @@ export function jobServiceRoutes( validate: { body: schema.object(topCategoriesSchema), }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { diff --git a/x-pack/plugins/ml/server/routes/job_validation.ts b/x-pack/plugins/ml/server/routes/job_validation.ts index dd2bd9deadf43..632166d6d5fb8 100644 --- a/x-pack/plugins/ml/server/routes/job_validation.ts +++ b/x-pack/plugins/ml/server/routes/job_validation.ts @@ -57,6 +57,9 @@ export function jobValidationRoutes({ router, mlLicense }: RouteInitialization, validate: { body: estimateBucketSpanSchema, }, + options: { + tags: ['access:ml:canCreateJob'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -106,6 +109,9 @@ export function jobValidationRoutes({ router, mlLicense }: RouteInitialization, validate: { body: modelMemoryLimitSchema, }, + options: { + tags: ['access:ml:canCreateJob'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -135,6 +141,9 @@ export function jobValidationRoutes({ router, mlLicense }: RouteInitialization, validate: { body: validateCardinalitySchema, }, + options: { + tags: ['access:ml:canCreateJob'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -167,6 +176,9 @@ export function jobValidationRoutes({ router, mlLicense }: RouteInitialization, validate: { body: validateJobSchema, }, + options: { + tags: ['access:ml:canCreateJob'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { diff --git a/x-pack/plugins/ml/server/routes/modules.ts b/x-pack/plugins/ml/server/routes/modules.ts index 2891144fc4574..622ae66ede426 100644 --- a/x-pack/plugins/ml/server/routes/modules.ts +++ b/x-pack/plugins/ml/server/routes/modules.ts @@ -97,6 +97,9 @@ export function dataRecognizer({ router, mlLicense }: RouteInitialization) { indexPatternTitle: schema.string(), }), }, + options: { + tags: ['access:ml:canCreateJob'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -127,6 +130,9 @@ export function dataRecognizer({ router, mlLicense }: RouteInitialization) { ...getModuleIdParamSchema(true), }), }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -161,6 +167,9 @@ export function dataRecognizer({ router, mlLicense }: RouteInitialization) { params: schema.object(getModuleIdParamSchema()), body: setupModuleBodySchema, }, + options: { + tags: ['access:ml:canCreateJob'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -218,6 +227,9 @@ export function dataRecognizer({ router, mlLicense }: RouteInitialization) { validate: { params: schema.object(getModuleIdParamSchema()), }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { diff --git a/x-pack/plugins/ml/server/routes/notification_settings.ts b/x-pack/plugins/ml/server/routes/notification_settings.ts index 59458b1e486db..e4a9abb0784be 100644 --- a/x-pack/plugins/ml/server/routes/notification_settings.ts +++ b/x-pack/plugins/ml/server/routes/notification_settings.ts @@ -22,6 +22,9 @@ export function notificationRoutes({ router, mlLicense }: RouteInitialization) { { path: '/api/ml/notification_settings', validate: false, + options: { + tags: ['access:ml:canAccessML'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { diff --git a/x-pack/plugins/ml/server/routes/results_service.ts b/x-pack/plugins/ml/server/routes/results_service.ts index 89c267340fe52..94ca0827ccfa5 100644 --- a/x-pack/plugins/ml/server/routes/results_service.ts +++ b/x-pack/plugins/ml/server/routes/results_service.ts @@ -88,6 +88,9 @@ export function resultsServiceRoutes({ router, mlLicense }: RouteInitialization) validate: { body: anomaliesTableDataSchema, }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -117,6 +120,9 @@ export function resultsServiceRoutes({ router, mlLicense }: RouteInitialization) validate: { body: categoryDefinitionSchema, }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -146,6 +152,9 @@ export function resultsServiceRoutes({ router, mlLicense }: RouteInitialization) validate: { body: maxAnomalyScoreSchema, }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -175,6 +184,9 @@ export function resultsServiceRoutes({ router, mlLicense }: RouteInitialization) validate: { body: categoryExamplesSchema, }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { @@ -204,6 +216,9 @@ export function resultsServiceRoutes({ router, mlLicense }: RouteInitialization) validate: { body: partitionFieldValuesSchema, }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { diff --git a/x-pack/plugins/ml/server/routes/system.ts b/x-pack/plugins/ml/server/routes/system.ts index d5fe45728c56c..7ae7dd8eef065 100644 --- a/x-pack/plugins/ml/server/routes/system.ts +++ b/x-pack/plugins/ml/server/routes/system.ts @@ -54,6 +54,9 @@ export function systemRoutes( validate: { body: schema.maybe(schema.any()), }, + options: { + tags: ['access:ml:canAccessML'], + }, }, mlLicense.basicLicenseAPIGuard(async (context, request, response) => { try { @@ -110,6 +113,9 @@ export function systemRoutes( { path: '/api/ml/ml_capabilities', validate: false, + options: { + tags: ['access:ml:canAccessML'], + }, }, mlLicense.basicLicenseAPIGuard(async (context, request, response) => { try { @@ -150,7 +156,11 @@ export function systemRoutes( { path: '/api/ml/ml_node_count', validate: false, + options: { + tags: ['access:ml:canGetJobs'], + }, }, + mlLicense.basicLicenseAPIGuard(async (context, request, response) => { try { // check for basic license first for consistency with other @@ -201,6 +211,9 @@ export function systemRoutes( { path: '/api/ml/info', validate: false, + options: { + tags: ['access:ml:canAccessML'], + }, }, mlLicense.basicLicenseAPIGuard(async (context, request, response) => { try { @@ -229,6 +242,9 @@ export function systemRoutes( validate: { body: schema.maybe(schema.any()), }, + options: { + tags: ['access:ml:canGetJobs'], + }, }, mlLicense.fullLicenseAPIGuard(async (context, request, response) => { try { diff --git a/x-pack/plugins/ml/server/types.ts b/x-pack/plugins/ml/server/types.ts index d4cd61a7fa4f7..678e81d3526ac 100644 --- a/x-pack/plugins/ml/server/types.ts +++ b/x-pack/plugins/ml/server/types.ts @@ -30,10 +30,6 @@ export interface SystemRouteDeps { resolveMlCapabilities: ResolveMlCapabilities; } -export interface JobServiceRouteDeps { - resolveMlCapabilities: ResolveMlCapabilities; -} - export interface PluginsSetup { cloud: CloudSetup; features: FeaturesPluginSetup; diff --git a/x-pack/plugins/monitoring/common/constants.ts b/x-pack/plugins/monitoring/common/constants.ts index edd6142455dfb..eeed7b4d5acf6 100644 --- a/x-pack/plugins/monitoring/common/constants.ts +++ b/x-pack/plugins/monitoring/common/constants.ts @@ -245,7 +245,7 @@ export const ALERT_TYPES = [ALERT_TYPE_LICENSE_EXPIRATION, ALERT_TYPE_CLUSTER_ST /** * Matches the id for the built-in in email action type - * See x-pack/legacy/plugins/actions/server/builtin_action_types/email.ts + * See x-pack/plugins/actions/server/builtin_action_types/email.ts */ export const ALERT_ACTION_TYPE_EMAIL = '.email'; diff --git a/x-pack/plugins/security/public/account_management/account_management_app.ts b/x-pack/plugins/security/public/account_management/account_management_app.ts index cd3ef34858b19..41567a04fe030 100644 --- a/x-pack/plugins/security/public/account_management/account_management_app.ts +++ b/x-pack/plugins/security/public/account_management/account_management_app.ts @@ -7,7 +7,6 @@ import { i18n } from '@kbn/i18n'; import { StartServicesAccessor, ApplicationSetup, AppMountParameters } from 'src/core/public'; import { AuthenticationServiceSetup } from '../authentication'; -import { UserAPIClient } from '../management'; interface CreateDeps { application: ApplicationSetup; @@ -28,9 +27,14 @@ export const accountManagementApp = Object.freeze({ navLinkStatus: 3, appRoute: '/security/account', async mount({ element }: AppMountParameters) { - const [[coreStart], { renderAccountManagementPage }] = await Promise.all([ + const [ + [coreStart], + { renderAccountManagementPage }, + { UserAPIClient }, + ] = await Promise.all([ getStartServices(), import('./account_management_page'), + import('../management'), ]); coreStart.chrome.setBreadcrumbs([{ text: title }]); diff --git a/x-pack/plugins/security/public/authentication/access_agreement/_index.scss b/x-pack/plugins/security/public/authentication/access_agreement/_index.scss deleted file mode 100644 index dbab8347b096f..0000000000000 --- a/x-pack/plugins/security/public/authentication/access_agreement/_index.scss +++ /dev/null @@ -1 +0,0 @@ -@import './access_agreement_page'; diff --git a/x-pack/plugins/security/public/authentication/access_agreement/_access_agreement_page.scss b/x-pack/plugins/security/public/authentication/access_agreement/access_agreement_page.scss similarity index 100% rename from x-pack/plugins/security/public/authentication/access_agreement/_access_agreement_page.scss rename to x-pack/plugins/security/public/authentication/access_agreement/access_agreement_page.scss diff --git a/x-pack/plugins/security/public/authentication/access_agreement/access_agreement_page.tsx b/x-pack/plugins/security/public/authentication/access_agreement/access_agreement_page.tsx index 0315e229c678b..a34dcb18d2b9c 100644 --- a/x-pack/plugins/security/public/authentication/access_agreement/access_agreement_page.tsx +++ b/x-pack/plugins/security/public/authentication/access_agreement/access_agreement_page.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import './_index.scss'; +import './access_agreement_page.scss'; import React, { FormEvent, MouseEvent, useCallback, useEffect, useState } from 'react'; import ReactDOM from 'react-dom'; diff --git a/x-pack/plugins/security/public/authentication/components/authentication_state_page/_authentication_state_page.scss b/x-pack/plugins/security/public/authentication/components/authentication_state_page/authentication_state_page.scss similarity index 100% rename from x-pack/plugins/security/public/authentication/components/authentication_state_page/_authentication_state_page.scss rename to x-pack/plugins/security/public/authentication/components/authentication_state_page/authentication_state_page.scss diff --git a/x-pack/plugins/security/public/authentication/components/authentication_state_page/authentication_state_page.tsx b/x-pack/plugins/security/public/authentication/components/authentication_state_page/authentication_state_page.tsx index 7567f455bcca6..35be650d127fb 100644 --- a/x-pack/plugins/security/public/authentication/components/authentication_state_page/authentication_state_page.tsx +++ b/x-pack/plugins/security/public/authentication/components/authentication_state_page/authentication_state_page.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import './_authentication_state_page.scss'; +import './authentication_state_page.scss'; import { EuiIcon, EuiSpacer, EuiTitle } from '@elastic/eui'; import React from 'react'; diff --git a/x-pack/plugins/security/public/authentication/login/_login_page.scss b/x-pack/plugins/security/public/authentication/login/login_page.scss similarity index 100% rename from x-pack/plugins/security/public/authentication/login/_login_page.scss rename to x-pack/plugins/security/public/authentication/login/login_page.scss diff --git a/x-pack/plugins/security/public/authentication/login/login_page.tsx b/x-pack/plugins/security/public/authentication/login/login_page.tsx index b7ac70f2aaf89..d24a301ed24ec 100644 --- a/x-pack/plugins/security/public/authentication/login/login_page.tsx +++ b/x-pack/plugins/security/public/authentication/login/login_page.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import './_login_page.scss'; +import './login_page.scss'; import React, { Component } from 'react'; import ReactDOM from 'react-dom'; diff --git a/x-pack/plugins/security/public/index.scss b/x-pack/plugins/security/public/index.scss deleted file mode 100644 index 1bdb8cc178fdf..0000000000000 --- a/x-pack/plugins/security/public/index.scss +++ /dev/null @@ -1,4 +0,0 @@ -$secFormWidth: 460px; - -// Management styles -@import './management/index'; diff --git a/x-pack/plugins/security/public/index.ts b/x-pack/plugins/security/public/index.ts index fc4e158652a0a..8016c94224060 100644 --- a/x-pack/plugins/security/public/index.ts +++ b/x-pack/plugins/security/public/index.ts @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import './index.scss'; import { PluginInitializer, PluginInitializerContext } from 'src/core/public'; import { SecurityPlugin, diff --git a/x-pack/plugins/security/public/management/_index.scss b/x-pack/plugins/security/public/management/_index.scss deleted file mode 100644 index 5d419b5323079..0000000000000 --- a/x-pack/plugins/security/public/management/_index.scss +++ /dev/null @@ -1,3 +0,0 @@ -@import './roles/index'; -@import './users/index'; -@import './role_mappings/index'; diff --git a/x-pack/plugins/security/public/management/api_keys/api_keys_management_app.tsx b/x-pack/plugins/security/public/management/api_keys/api_keys_management_app.tsx index 272fc9cfc2fe6..b9ec5b35b3f9d 100644 --- a/x-pack/plugins/security/public/management/api_keys/api_keys_management_app.tsx +++ b/x-pack/plugins/security/public/management/api_keys/api_keys_management_app.tsx @@ -10,8 +10,6 @@ import { i18n } from '@kbn/i18n'; import { StartServicesAccessor } from 'src/core/public'; import { RegisterManagementAppArgs } from '../../../../../../src/plugins/management/public'; import { PluginStartDependencies } from '../../plugin'; -import { APIKeysGridPage } from './api_keys_grid'; -import { APIKeysAPIClient } from './api_keys_api_client'; import { DocumentationLinksService } from './documentation_links'; interface CreateParams { @@ -28,7 +26,6 @@ export const apiKeysManagementApp = Object.freeze({ defaultMessage: 'API Keys', }), async mount({ basePath, element, setBreadcrumbs }) { - const [{ docLinks, http, notifications, i18n: i18nStart }] = await getStartServices(); setBreadcrumbs([ { text: i18n.translate('xpack.security.apiKeys.breadcrumb', { @@ -38,6 +35,16 @@ export const apiKeysManagementApp = Object.freeze({ }, ]); + const [ + [{ docLinks, http, notifications, i18n: i18nStart }], + { APIKeysGridPage }, + { APIKeysAPIClient }, + ] = await Promise.all([ + getStartServices(), + import('./api_keys_grid'), + import('./api_keys_api_client'), + ]); + render( ; @@ -31,7 +27,6 @@ export const roleMappingsManagementApp = Object.freeze({ defaultMessage: 'Role Mappings', }), async mount({ basePath, element, setBreadcrumbs }) { - const [{ docLinks, http, notifications, i18n: i18nStart }] = await getStartServices(); const roleMappingsBreadcrumbs = [ { text: i18n.translate('xpack.security.roleMapping.breadcrumb', { @@ -41,6 +36,20 @@ export const roleMappingsManagementApp = Object.freeze({ }, ]; + const [ + [{ docLinks, http, notifications, i18n: i18nStart }], + { RoleMappingsGridPage }, + { EditRoleMappingPage }, + { RoleMappingsAPIClient }, + { RolesAPIClient }, + ] = await Promise.all([ + getStartServices(), + import('./role_mappings_grid'), + import('./edit_role_mapping'), + import('./role_mappings_api_client'), + import('../roles'), + ]); + const roleMappingsAPIClient = new RoleMappingsAPIClient(http); const dockLinksService = new DocumentationLinksService(docLinks); const RoleMappingsGridPageWithBreadcrumbs = () => { diff --git a/x-pack/plugins/security/public/management/roles/_index.scss b/x-pack/plugins/security/public/management/roles/_index.scss deleted file mode 100644 index 5256c79f01f10..0000000000000 --- a/x-pack/plugins/security/public/management/roles/_index.scss +++ /dev/null @@ -1 +0,0 @@ -@import './edit_role/index'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/_index.scss b/x-pack/plugins/security/public/management/roles/edit_role/_index.scss deleted file mode 100644 index 0153b1734ceba..0000000000000 --- a/x-pack/plugins/security/public/management/roles/edit_role/_index.scss +++ /dev/null @@ -1,3 +0,0 @@ -@import './collapsible_panel/index'; -@import './spaces_popover_list/index'; -@import './privileges/index'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/collapsible_panel/_index.scss b/x-pack/plugins/security/public/management/roles/edit_role/collapsible_panel/_index.scss deleted file mode 100644 index c0f4f8ab9a870..0000000000000 --- a/x-pack/plugins/security/public/management/roles/edit_role/collapsible_panel/_index.scss +++ /dev/null @@ -1 +0,0 @@ -@import './collapsible_panel'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/collapsible_panel/_collapsible_panel.scss b/x-pack/plugins/security/public/management/roles/edit_role/collapsible_panel/collapsible_panel.scss similarity index 100% rename from x-pack/plugins/security/public/management/roles/edit_role/collapsible_panel/_collapsible_panel.scss rename to x-pack/plugins/security/public/management/roles/edit_role/collapsible_panel/collapsible_panel.scss diff --git a/x-pack/plugins/security/public/management/roles/edit_role/collapsible_panel/collapsible_panel.tsx b/x-pack/plugins/security/public/management/roles/edit_role/collapsible_panel/collapsible_panel.tsx index 01af7cb4509f6..eb1417600e19b 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/collapsible_panel/collapsible_panel.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/collapsible_panel/collapsible_panel.tsx @@ -4,6 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ +import './collapsible_panel.scss'; + import { EuiFlexGroup, EuiFlexItem, diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/_index.scss b/x-pack/plugins/security/public/management/roles/edit_role/privileges/_index.scss deleted file mode 100644 index a1a9d038065e6..0000000000000 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/_index.scss +++ /dev/null @@ -1,2 +0,0 @@ -@import './privilege_feature_icon'; -@import './kibana/index'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/_index.scss b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/_index.scss deleted file mode 100644 index 19547c0e1953e..0000000000000 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/_index.scss +++ /dev/null @@ -1,2 +0,0 @@ -@import './feature_table/index'; -@import './space_aware_privilege_section/index'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/_index.scss b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/_index.scss deleted file mode 100644 index 6a96553742819..0000000000000 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/_index.scss +++ /dev/null @@ -1 +0,0 @@ -@import './change_all_privileges'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/_change_all_privileges.scss b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/change_all_privileges.scss similarity index 100% rename from x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/_change_all_privileges.scss rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/change_all_privileges.scss diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/change_all_privileges.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/change_all_privileges.tsx index 2083778e53998..5d7b13acf79da 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/change_all_privileges.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/change_all_privileges.tsx @@ -3,6 +3,9 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ + +import './change_all_privileges.scss'; + import { EuiContextMenuItem, EuiContextMenuPanel, EuiLink, EuiPopover } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import _ from 'lodash'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/_privilege_feature_icon.scss b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table_cell/feature_table_cell.scss similarity index 100% rename from x-pack/plugins/security/public/management/roles/edit_role/privileges/_privilege_feature_icon.scss rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table_cell/feature_table_cell.scss diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table_cell/feature_table_cell.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table_cell/feature_table_cell.tsx index 9e4a3a8a99b56..77445952f3d69 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table_cell/feature_table_cell.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table_cell/feature_table_cell.tsx @@ -4,6 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ +import './feature_table_cell.scss'; + import React from 'react'; import { EuiText, EuiIconTip, EuiIcon, IconType } from '@elastic/eui'; import { SecuredFeature } from '../../../../model'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/_index.scss b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/_index.scss deleted file mode 100644 index 3f40f21e102a1..0000000000000 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/_index.scss +++ /dev/null @@ -1 +0,0 @@ -@import './privilege_matrix'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/_privilege_matrix.scss b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/_privilege_matrix.scss deleted file mode 100644 index 8f47727fdf8d6..0000000000000 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/_privilege_matrix.scss +++ /dev/null @@ -1,14 +0,0 @@ -/** - * 1. Allow table to scroll both directions - */ - -.secPrivilegeMatrix__modal, -.secPrivilegeMatrix__modal .euiModal__flex { - overflow: hidden; /* 1 */ -} - -.secPrivilegeMatrix__row--isBasePrivilege, -.secPrivilegeMatrix__cell--isGlobalPrivilege, -.secPrivilegeTable__row--isGlobalSpace { - background-color: $euiColorLightestShade; -} diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_table.scss b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_table.scss new file mode 100644 index 0000000000000..8e2a3b0512afb --- /dev/null +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_table.scss @@ -0,0 +1,3 @@ +.secPrivilegeTable__row--isGlobalSpace { + background-color: $euiColorLightestShade; +} diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_table.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_table.tsx index ccb5398a11b23..30a275876fdc7 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_table.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_table.tsx @@ -3,6 +3,9 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ + +import './privilege_space_table.scss'; + import { EuiBadge, EuiBadgeProps, diff --git a/x-pack/plugins/security/public/management/roles/edit_role/spaces_popover_list/_index.scss b/x-pack/plugins/security/public/management/roles/edit_role/spaces_popover_list/_index.scss deleted file mode 100644 index b40a32cb8df96..0000000000000 --- a/x-pack/plugins/security/public/management/roles/edit_role/spaces_popover_list/_index.scss +++ /dev/null @@ -1 +0,0 @@ -@import './spaces_popover_list'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/spaces_popover_list/_spaces_popover_list.scss b/x-pack/plugins/security/public/management/roles/edit_role/spaces_popover_list/spaces_popover_list.scss similarity index 100% rename from x-pack/plugins/security/public/management/roles/edit_role/spaces_popover_list/_spaces_popover_list.scss rename to x-pack/plugins/security/public/management/roles/edit_role/spaces_popover_list/spaces_popover_list.scss diff --git a/x-pack/plugins/security/public/management/roles/edit_role/spaces_popover_list/spaces_popover_list.tsx b/x-pack/plugins/security/public/management/roles/edit_role/spaces_popover_list/spaces_popover_list.tsx index 92e42ec811afc..63ee311f3155e 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/spaces_popover_list/spaces_popover_list.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/spaces_popover_list/spaces_popover_list.tsx @@ -4,6 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ +import './spaces_popover_list.scss'; + import { EuiButtonEmpty, EuiContextMenuItem, diff --git a/x-pack/plugins/security/public/management/roles/roles_management_app.tsx b/x-pack/plugins/security/public/management/roles/roles_management_app.tsx index e1a10fdc2b8c3..9aaa3b47f3b19 100644 --- a/x-pack/plugins/security/public/management/roles/roles_management_app.tsx +++ b/x-pack/plugins/security/public/management/roles/roles_management_app.tsx @@ -12,13 +12,7 @@ import { StartServicesAccessor, FatalErrorsSetup } from 'src/core/public'; import { RegisterManagementAppArgs } from '../../../../../../src/plugins/management/public'; import { SecurityLicense } from '../../../common/licensing'; import { PluginStartDependencies } from '../../plugin'; -import { UserAPIClient } from '../users'; -import { RolesAPIClient } from './roles_api_client'; -import { RolesGridPage } from './roles_grid'; -import { EditRolePage } from './edit_role'; import { DocumentationLinksService } from './documentation_links'; -import { IndicesAPIClient } from './indices_api_client'; -import { PrivilegesAPIClient } from './privileges_api_client'; interface CreateParams { fatalErrors: FatalErrorsSetup; @@ -34,11 +28,6 @@ export const rolesManagementApp = Object.freeze({ order: 20, title: i18n.translate('xpack.security.management.rolesTitle', { defaultMessage: 'Roles' }), async mount({ basePath, element, setBreadcrumbs }) { - const [ - { application, docLinks, http, i18n: i18nStart, injectedMetadata, notifications }, - { data, features }, - ] = await getStartServices(); - const rolesBreadcrumbs = [ { text: i18n.translate('xpack.security.roles.breadcrumb', { defaultMessage: 'Roles' }), @@ -46,6 +35,27 @@ export const rolesManagementApp = Object.freeze({ }, ]; + const [ + [ + { application, docLinks, http, i18n: i18nStart, injectedMetadata, notifications }, + { data, features }, + ], + { RolesGridPage }, + { EditRolePage }, + { RolesAPIClient }, + { IndicesAPIClient }, + { PrivilegesAPIClient }, + { UserAPIClient }, + ] = await Promise.all([ + getStartServices(), + import('./roles_grid'), + import('./edit_role'), + import('./roles_api_client'), + import('./indices_api_client'), + import('./privileges_api_client'), + import('../users'), + ]); + const rolesAPIClient = new RolesAPIClient(http); const RolesGridPageWithBreadcrumbs = () => { setBreadcrumbs(rolesBreadcrumbs); diff --git a/x-pack/plugins/security/public/management/users/_index.scss b/x-pack/plugins/security/public/management/users/_index.scss deleted file mode 100644 index 35df0c1b96583..0000000000000 --- a/x-pack/plugins/security/public/management/users/_index.scss +++ /dev/null @@ -1 +0,0 @@ -@import './edit_user/index'; diff --git a/x-pack/plugins/security/public/management/users/edit_user/_index.scss b/x-pack/plugins/security/public/management/users/edit_user/_index.scss deleted file mode 100644 index 734ba7882ba72..0000000000000 --- a/x-pack/plugins/security/public/management/users/edit_user/_index.scss +++ /dev/null @@ -1 +0,0 @@ -@import './edit_user_page'; diff --git a/x-pack/plugins/security/public/management/users/edit_user/_edit_user_page.scss b/x-pack/plugins/security/public/management/users/edit_user/edit_user_page.scss similarity index 76% rename from x-pack/plugins/security/public/management/users/edit_user/_edit_user_page.scss rename to x-pack/plugins/security/public/management/users/edit_user/edit_user_page.scss index 7b24b74aceba0..727fac4782752 100644 --- a/x-pack/plugins/security/public/management/users/edit_user/_edit_user_page.scss +++ b/x-pack/plugins/security/public/management/users/edit_user/edit_user_page.scss @@ -1,5 +1,5 @@ .secUsersEditPage__content { - max-width: $secFormWidth; + max-width: 460px; margin-left: auto; margin-right: auto; flex-grow: 0; diff --git a/x-pack/plugins/security/public/management/users/edit_user/edit_user_page.tsx b/x-pack/plugins/security/public/management/users/edit_user/edit_user_page.tsx index 6417ce81b647d..1c8130029bb50 100644 --- a/x-pack/plugins/security/public/management/users/edit_user/edit_user_page.tsx +++ b/x-pack/plugins/security/public/management/users/edit_user/edit_user_page.tsx @@ -3,6 +3,9 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ + +import './edit_user_page.scss'; + import { get } from 'lodash'; import React, { Component, Fragment, ChangeEvent } from 'react'; import { diff --git a/x-pack/plugins/security/public/management/users/users_management_app.tsx b/x-pack/plugins/security/public/management/users/users_management_app.tsx index 82a2b8d2a98ad..9d337c1508ad4 100644 --- a/x-pack/plugins/security/public/management/users/users_management_app.tsx +++ b/x-pack/plugins/security/public/management/users/users_management_app.tsx @@ -12,10 +12,6 @@ import { StartServicesAccessor } from 'src/core/public'; import { RegisterManagementAppArgs } from '../../../../../../src/plugins/management/public'; import { AuthenticationServiceSetup } from '../../authentication'; import { PluginStartDependencies } from '../../plugin'; -import { RolesAPIClient } from '../roles'; -import { UserAPIClient } from './user_api_client'; -import { UsersGridPage } from './users_grid'; -import { EditUserPage } from './edit_user'; interface CreateParams { authc: AuthenticationServiceSetup; @@ -30,7 +26,6 @@ export const usersManagementApp = Object.freeze({ order: 10, title: i18n.translate('xpack.security.management.usersTitle', { defaultMessage: 'Users' }), async mount({ basePath, element, setBreadcrumbs }) { - const [{ http, notifications, i18n: i18nStart }] = await getStartServices(); const usersBreadcrumbs = [ { text: i18n.translate('xpack.security.users.breadcrumb', { defaultMessage: 'Users' }), @@ -38,6 +33,20 @@ export const usersManagementApp = Object.freeze({ }, ]; + const [ + [{ http, notifications, i18n: i18nStart }], + { UsersGridPage }, + { EditUserPage }, + { UserAPIClient }, + { RolesAPIClient }, + ] = await Promise.all([ + getStartServices(), + import('./users_grid'), + import('./edit_user'), + import('./user_api_client'), + import('../roles'), + ]); + const userAPIClient = new UserAPIClient(http); const rolesAPIClient = new RolesAPIClient(http); const UsersGridPageWithBreadcrumbs = () => { diff --git a/x-pack/plugins/security/server/mocks.ts b/x-pack/plugins/security/server/mocks.ts index ababf12c2be60..a6407366bbd3b 100644 --- a/x-pack/plugins/security/server/mocks.ts +++ b/x-pack/plugins/security/server/mocks.ts @@ -8,6 +8,7 @@ import { SecurityPluginSetup } from './plugin'; import { authenticationMock } from './authentication/index.mock'; import { authorizationMock } from './authorization/index.mock'; +import { licenseMock } from '../common/licensing/index.mock'; function createSetupMock() { const mockAuthz = authorizationMock.create(); @@ -19,6 +20,7 @@ function createSetupMock() { mode: mockAuthz.mode, }, registerSpacesService: jest.fn(), + license: licenseMock.create(), __legacyCompat: {} as SecurityPluginSetup['__legacyCompat'], }; } diff --git a/x-pack/plugins/security/server/plugin.test.ts b/x-pack/plugins/security/server/plugin.test.ts index 22a30f03c646a..d58c999ddccdf 100644 --- a/x-pack/plugins/security/server/plugin.test.ts +++ b/x-pack/plugins/security/server/plugin.test.ts @@ -50,21 +50,6 @@ describe('Security Plugin', () => { await expect(plugin.setup(mockCoreSetup, mockDependencies)).resolves.toMatchInlineSnapshot(` Object { "__legacyCompat": Object { - "license": Object { - "features$": Observable { - "_isScalar": false, - "operator": MapOperator { - "project": [Function], - "thisArg": undefined, - }, - "source": Observable { - "_isScalar": false, - "_subscribe": [Function], - }, - }, - "getFeatures": [Function], - "isEnabled": [Function], - }, "registerLegacyAPI": [Function], "registerPrivilegesWithCluster": [Function], }, @@ -103,6 +88,21 @@ describe('Security Plugin', () => { "useRbacForRequest": [Function], }, }, + "license": Object { + "features$": Observable { + "_isScalar": false, + "operator": MapOperator { + "project": [Function], + "thisArg": undefined, + }, + "source": Observable { + "_isScalar": false, + "_subscribe": [Function], + }, + }, + "getFeatures": [Function], + "isEnabled": [Function], + }, "registerSpacesService": [Function], } `); diff --git a/x-pack/plugins/security/server/plugin.ts b/x-pack/plugins/security/server/plugin.ts index e30b0caf76ddc..97f5aea888dc7 100644 --- a/x-pack/plugins/security/server/plugin.ts +++ b/x-pack/plugins/security/server/plugin.ts @@ -59,6 +59,7 @@ export interface SecurityPluginSetup { | 'invalidateAPIKeyAsInternalUser' >; authz: Pick; + license: SecurityLicense; /** * If Spaces plugin is available it's supposed to register its SpacesService with Security plugin @@ -73,7 +74,6 @@ export interface SecurityPluginSetup { __legacyCompat: { registerLegacyAPI: (legacyAPI: LegacyAPI) => void; registerPrivilegesWithCluster: () => void; - license: SecurityLicense; }; } @@ -194,6 +194,8 @@ export class Plugin { mode: authz.mode, }, + license, + registerSpacesService: service => { if (this.wasSpacesServiceAccessed()) { throw new Error('Spaces service has been accessed before registration.'); @@ -206,8 +208,6 @@ export class Plugin { registerLegacyAPI: (legacyAPI: LegacyAPI) => (this.legacyAPI = legacyAPI), registerPrivilegesWithCluster: async () => await authz.registerPrivilegesWithCluster(), - - license, }, }); } diff --git a/x-pack/plugins/siem/server/lib/timeline/types.ts b/x-pack/plugins/siem/common/types/timeline/index.ts similarity index 85% rename from x-pack/plugins/siem/server/lib/timeline/types.ts rename to x-pack/plugins/siem/common/types/timeline/index.ts index 0bce3300591c2..55b4f9c6aca4d 100644 --- a/x-pack/plugins/siem/server/lib/timeline/types.ts +++ b/x-pack/plugins/siem/common/types/timeline/index.ts @@ -7,14 +7,11 @@ /* eslint-disable @typescript-eslint/no-empty-interface */ import * as runtimeTypes from 'io-ts'; +import { SavedObjectsClient } from 'kibana/server'; -import { unionWithNullType } from '../framework'; -import { NoteSavedObjectToReturnRuntimeType, NoteSavedObject } from '../note/types'; -import { - PinnedEventToReturnSavedObjectRuntimeType, - PinnedEventSavedObject, -} from '../pinned_event/types'; -import { SavedObjectsClient } from '../../../../../../src/core/server'; +import { unionWithNullType } from '../../utility_types'; +import { NoteSavedObject, NoteSavedObjectToReturnRuntimeType } from './note'; +import { PinnedEventToReturnSavedObjectRuntimeType, PinnedEventSavedObject } from './pinned_event'; /* * ColumnHeader Types @@ -136,6 +133,17 @@ const SavedSortRuntimeType = runtimeTypes.partial({ /* * Timeline Types */ + +export enum TimelineType { + default = 'default', + template = 'template', +} + +export const TimelineTypeLiteralRt = runtimeTypes.union([ + runtimeTypes.literal(TimelineType.template), + runtimeTypes.literal(TimelineType.default), +]); + export const SavedTimelineRuntimeType = runtimeTypes.partial({ columns: unionWithNullType(runtimeTypes.array(SavedColumnHeaderRuntimeType)), dataProviders: unionWithNullType(runtimeTypes.array(SavedDataProviderRuntimeType)), @@ -146,6 +154,9 @@ export const SavedTimelineRuntimeType = runtimeTypes.partial({ kqlMode: unionWithNullType(runtimeTypes.string), kqlQuery: unionWithNullType(SavedFilterQueryQueryRuntimeType), title: unionWithNullType(runtimeTypes.string), + templateTimelineId: unionWithNullType(runtimeTypes.string), + templateTimelineVersion: unionWithNullType(runtimeTypes.number), + timelineType: unionWithNullType(TimelineTypeLiteralRt), dateRange: unionWithNullType(SavedDateRangePickerRuntimeType), savedQueryId: unionWithNullType(runtimeTypes.string), sort: unionWithNullType(SavedSortRuntimeType), @@ -192,6 +203,25 @@ export const TimelineSavedToReturnObjectRuntimeType = runtimeTypes.intersection( export interface TimelineSavedObject extends runtimeTypes.TypeOf {} +/** + * All Timeline Saved object type with metadata + */ +export const TimelineResponseType = runtimeTypes.type({ + data: runtimeTypes.type({ + persistTimeline: runtimeTypes.intersection([ + runtimeTypes.partial({ + code: unionWithNullType(runtimeTypes.number), + message: unionWithNullType(runtimeTypes.string), + }), + runtimeTypes.type({ + timeline: TimelineSavedToReturnObjectRuntimeType, + }), + ]), + }), +}); + +export interface TimelineResponse extends runtimeTypes.TypeOf {} + /** * All Timeline Saved object type with metadata */ @@ -234,6 +264,11 @@ export type ExportedTimelines = TimelineSavedObject & pinnedEventIds: string[]; }; +export interface ExportTimelineNotFoundError { + statusCode: number; + message: string; +} + export interface BulkGetInput { type: string; id: string; diff --git a/x-pack/plugins/siem/server/lib/note/types.ts b/x-pack/plugins/siem/common/types/timeline/note/index.ts similarity index 90% rename from x-pack/plugins/siem/server/lib/note/types.ts rename to x-pack/plugins/siem/common/types/timeline/note/index.ts index f7a10317bd84d..c8e674997c19c 100644 --- a/x-pack/plugins/siem/server/lib/note/types.ts +++ b/x-pack/plugins/siem/common/types/timeline/note/index.ts @@ -8,7 +8,7 @@ import * as runtimeTypes from 'io-ts'; -import { unionWithNullType } from '../framework'; +import { unionWithNullType } from '../../../utility_types'; /* * Note Types @@ -56,11 +56,7 @@ export const NoteSavedObjectToReturnRuntimeType = runtimeTypes.intersection([ version: runtimeTypes.string, }), runtimeTypes.partial({ - timelineVersion: runtimeTypes.union([ - runtimeTypes.string, - runtimeTypes.null, - runtimeTypes.undefined, - ]), + timelineVersion: unionWithNullType(runtimeTypes.string), }), ]); diff --git a/x-pack/plugins/siem/server/lib/pinned_event/types.ts b/x-pack/plugins/siem/common/types/timeline/pinned_event/index.ts similarity index 83% rename from x-pack/plugins/siem/server/lib/pinned_event/types.ts rename to x-pack/plugins/siem/common/types/timeline/pinned_event/index.ts index e598f03935047..89a619598f7c1 100644 --- a/x-pack/plugins/siem/server/lib/pinned_event/types.ts +++ b/x-pack/plugins/siem/common/types/timeline/pinned_event/index.ts @@ -8,7 +8,7 @@ import * as runtimeTypes from 'io-ts'; -import { unionWithNullType } from '../framework'; +import { unionWithNullType } from '../../../utility_types'; /* * Note Types @@ -40,11 +40,7 @@ export const PinnedEventSavedObjectRuntimeType = runtimeTypes.intersection([ }), runtimeTypes.partial({ pinnedEventId: unionWithNullType(runtimeTypes.string), - timelineVersion: runtimeTypes.union([ - runtimeTypes.string, - runtimeTypes.null, - runtimeTypes.undefined, - ]), + timelineVersion: unionWithNullType(runtimeTypes.string), }), ]); @@ -55,11 +51,7 @@ export const PinnedEventToReturnSavedObjectRuntimeType = runtimeTypes.intersecti }), SavedPinnedEventRuntimeType, runtimeTypes.partial({ - timelineVersion: runtimeTypes.union([ - runtimeTypes.string, - runtimeTypes.null, - runtimeTypes.undefined, - ]), + timelineVersion: unionWithNullType(runtimeTypes.string), }), ]); diff --git a/x-pack/plugins/siem/common/utility_types.ts b/x-pack/plugins/siem/common/utility_types.ts index b46ccdbbe3d05..a12dd926a9181 100644 --- a/x-pack/plugins/siem/common/utility_types.ts +++ b/x-pack/plugins/siem/common/utility_types.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import * as runtimeTypes from 'io-ts'; import { ReactNode } from 'react'; // This type is for typing EuiDescriptionList @@ -11,3 +12,6 @@ export interface DescriptionList { title: NonNullable; description: NonNullable; } + +export const unionWithNullType = (type: T) => + runtimeTypes.union([type, runtimeTypes.null]); diff --git a/x-pack/plugins/siem/public/components/matrix_histogram/__snapshots__/index.test.tsx.snap b/x-pack/plugins/siem/public/components/matrix_histogram/__snapshots__/index.test.tsx.snap index 5aa846d15b684..c4bdff7ea649a 100644 --- a/x-pack/plugins/siem/public/components/matrix_histogram/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/siem/public/components/matrix_histogram/__snapshots__/index.test.tsx.snap @@ -1,5 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Matrix Histogram Component not initial load it renders no MatrixLoader 1`] = `"

"`; +exports[`Matrix Histogram Component not initial load it renders no MatrixLoader 1`] = `"
"`; -exports[`Matrix Histogram Component on initial load it renders MatrixLoader 1`] = `"
"`; +exports[`Matrix Histogram Component on initial load it renders MatrixLoader 1`] = `"
"`; diff --git a/x-pack/plugins/siem/public/components/open_timeline/export_timeline/index.tsx b/x-pack/plugins/siem/public/components/open_timeline/export_timeline/index.tsx index 946c4b3a612dd..12cf952bb1ff8 100644 --- a/x-pack/plugins/siem/public/components/open_timeline/export_timeline/index.tsx +++ b/x-pack/plugins/siem/public/components/open_timeline/export_timeline/index.tsx @@ -9,7 +9,7 @@ import { DeleteTimelines } from '../types'; import { TimelineDownloader } from './export_timeline'; import { DeleteTimelineModalOverlay } from '../delete_timeline_modal'; -import { exportSelectedTimeline } from '../../../containers/timeline/all/api'; +import { exportSelectedTimeline } from '../../../containers/timeline/api'; export interface ExportTimeline { disableExportTimelineDownloader: () => void; diff --git a/x-pack/plugins/siem/public/components/open_timeline/index.test.tsx b/x-pack/plugins/siem/public/components/open_timeline/index.test.tsx index 04f0abe0d00d1..ea28bc06ef915 100644 --- a/x-pack/plugins/siem/public/components/open_timeline/index.test.tsx +++ b/x-pack/plugins/siem/public/components/open_timeline/index.test.tsx @@ -15,15 +15,34 @@ import { TestProviderWithoutDragAndDrop, apolloClient } from '../../mock/test_pr import { mockOpenTimelineQueryResults } from '../../mock/timeline_results'; import { DEFAULT_SEARCH_RESULTS_PER_PAGE } from '../../pages/timelines/timelines_page'; -import { StatefulOpenTimeline } from '.'; import { NotePreviews } from './note_previews'; import { OPEN_TIMELINE_CLASS_NAME } from './helpers'; - +import { StatefulOpenTimeline } from '.'; +import { useGetAllTimeline, getAllTimeline } from '../../containers/timeline/all'; jest.mock('../../lib/kibana'); +jest.mock('../../containers/timeline/all', () => { + const originalModule = jest.requireActual('../../containers/timeline/all'); + return { + useGetAllTimeline: jest.fn(), + getAllTimeline: originalModule.getAllTimeline, + }; +}); describe('StatefulOpenTimeline', () => { const theme = () => ({ eui: euiDarkVars, darkMode: true }); const title = 'All Timelines / Open Timelines'; + beforeEach(() => { + ((useGetAllTimeline as unknown) as jest.Mock).mockReturnValue({ + fetchAllTimeline: jest.fn(), + timelines: getAllTimeline( + '', + mockOpenTimelineQueryResults[0].result.data?.getAllTimeline?.timeline ?? [] + ), + loading: false, + totalCount: mockOpenTimelineQueryResults[0].result.data.getAllTimeline.totalCount, + refetch: jest.fn(), + }); + }); test('it has the expected initial state', () => { const wrapper = mount( @@ -459,6 +478,8 @@ describe('StatefulOpenTimeline', () => { .find('[data-test-subj="expand-notes"]') .first() .simulate('click'); + expect(wrapper.find('[data-test-subj="note-previews-container"]').exists()).toEqual(true); + expect(wrapper.find('[data-test-subj="updated-by"]').exists()).toEqual(true); expect( wrapper @@ -532,7 +553,7 @@ describe('StatefulOpenTimeline', () => { test('it renders the expected count of matching timelines when no query has been entered', async () => { const wrapper = mount( - + ( /** The requested field to sort on */ const [sortField, setSortField] = useState(DEFAULT_SORT_FIELD); + const { fetchAllTimeline, timelines, loading, totalCount, refetch } = useGetAllTimeline(); + /** Invoked when the user presses enters to submit the text in the search input */ const onQueryChange: OnQueryChange = useCallback((query: EuiSearchBarQuery) => { setSearch(query.queryText.trim()); @@ -133,45 +134,41 @@ export const StatefulOpenTimelineComponent = React.memo( // } // }; - const onDeleteOneTimeline: OnDeleteOneTimeline = useCallback( - (timelineIds: string[]) => { - deleteTimelines(timelineIds, { - search, - pageInfo: { - pageIndex: pageIndex + 1, - pageSize, - }, - sort: { - sortField: sortField as SortFieldTimeline, - sortOrder: sortDirection as Direction, - }, - onlyUserFavorite: onlyFavorites, + const deleteTimelines: DeleteTimelines = useCallback( + async (timelineIds: string[]) => { + if (timelineIds.includes(timeline.savedObjectId || '')) { + createNewTimeline({ id: 'timeline-1', columns: defaultHeaders, show: false }); + } + await apolloClient.mutate< + DeleteTimelineMutation.Mutation, + DeleteTimelineMutation.Variables + >({ + mutation: deleteTimelineMutation, + fetchPolicy: 'no-cache', + variables: { id: timelineIds }, }); + refetch(); + }, + [apolloClient, createNewTimeline, refetch, timeline] + ); + + const onDeleteOneTimeline: OnDeleteOneTimeline = useCallback( + async (timelineIds: string[]) => { + await deleteTimelines(timelineIds); }, - [search, pageIndex, pageSize, sortField, sortDirection, onlyFavorites] + [deleteTimelines] ); /** Invoked when the user clicks the action to delete the selected timelines */ - const onDeleteSelected: OnDeleteSelected = useCallback(() => { - deleteTimelines(getSelectedTimelineIds(selectedItems), { - search, - pageInfo: { - pageIndex: pageIndex + 1, - pageSize, - }, - sort: { - sortField: sortField as SortFieldTimeline, - sortOrder: sortDirection as Direction, - }, - onlyUserFavorite: onlyFavorites, - }); + const onDeleteSelected: OnDeleteSelected = useCallback(async () => { + await deleteTimelines(getSelectedTimelineIds(selectedItems)); // NOTE: we clear the selection state below, but if the server fails to // delete a timeline, it will remain selected in the table: resetSelectionState(); // TODO: the query must re-execute to show the results of the deletion - }, [selectedItems, search, pageIndex, pageSize, sortField, sortDirection, onlyFavorites]); + }, [selectedItems, deleteTimelines]); /** Invoked when the user selects (or de-selects) timelines */ const onSelectionChange: OnSelectionChange = useCallback( @@ -227,99 +224,88 @@ export const StatefulOpenTimelineComponent = React.memo( [apolloClient, updateIsLoading, updateTimeline] ); - const deleteTimelines: DeleteTimelines = useCallback( - (timelineIds: string[], variables?: AllTimelinesVariables) => { - if (timelineIds.includes(timeline.savedObjectId || '')) { - createNewTimeline({ id: 'timeline-1', columns: defaultHeaders, show: false }); - } - apolloClient.mutate({ - mutation: deleteTimelineMutation, - fetchPolicy: 'no-cache', - variables: { id: timelineIds }, - refetchQueries: [ - { - query: allTimelinesQuery, - variables, - }, - ], - }); - }, - [apolloClient, createNewTimeline, timeline] - ); - useEffect(() => { focusInput(); }, []); - return ( - { + fetchAllTimeline({ + pageInfo: { pageIndex: pageIndex + 1, pageSize, - }} - search={search} - sort={{ sortField: sortField as SortFieldTimeline, sortOrder: sortDirection as Direction }} - onlyUserFavorite={onlyFavorites} - > - {({ timelines, loading, totalCount, refetch }) => { - return !isModal ? ( - - ) : ( - - ); - }} - + }, + search, + sort: { sortField: sortField as SortFieldTimeline, sortOrder: sortDirection as Direction }, + onlyUserFavorite: onlyFavorites, + timelines, + totalCount, + }); + }, [ + pageIndex, + pageSize, + search, + sortField, + sortDirection, + timelines, + totalCount, + onlyFavorites, + ]); + + return !isModal ? ( + + ) : ( + ); } ); @@ -328,7 +314,6 @@ const makeMapStateToProps = () => { const getTimeline = timelineSelectors.getTimelineByIdSelector(); const mapStateToProps = (state: State) => { const timeline = getTimeline(state, 'timeline-1') ?? timelineDefaults; - return { timeline, }; diff --git a/x-pack/plugins/siem/public/components/open_timeline/open_timeline.tsx b/x-pack/plugins/siem/public/components/open_timeline/open_timeline.tsx index 6b2f953b82de4..26aeab87e3510 100644 --- a/x-pack/plugins/siem/public/components/open_timeline/open_timeline.tsx +++ b/x-pack/plugins/siem/public/components/open_timeline/open_timeline.tsx @@ -14,7 +14,7 @@ import { TimelinesTable } from './timelines_table'; import { TitleRow } from './title_row'; import { ImportDataModal } from '../import_data_modal'; import * as i18n from './translations'; -import { importTimelines } from '../../containers/timeline/all/api'; +import { importTimelines } from '../../containers/timeline/api'; import { UtilityBarGroup, diff --git a/x-pack/plugins/siem/public/components/open_timeline/open_timeline_modal/index.test.tsx b/x-pack/plugins/siem/public/components/open_timeline/open_timeline_modal/index.test.tsx index ca8fa50c572fe..46a0d46c1e0d1 100644 --- a/x-pack/plugins/siem/public/components/open_timeline/open_timeline_modal/index.test.tsx +++ b/x-pack/plugins/siem/public/components/open_timeline/open_timeline_modal/index.test.tsx @@ -13,6 +13,7 @@ import { ThemeProvider } from 'styled-components'; import { wait } from '../../../lib/helpers'; import { TestProviderWithoutDragAndDrop } from '../../../mock/test_providers'; import { mockOpenTimelineQueryResults } from '../../../mock/timeline_results'; +import { useGetAllTimeline, getAllTimeline } from '../../../containers/timeline/all'; import { OpenTimelineModal } from '.'; @@ -20,9 +21,28 @@ jest.mock('../../../lib/kibana'); jest.mock('../../../utils/apollo_context', () => ({ useApolloClient: () => ({}), })); +jest.mock('../../../containers/timeline/all', () => { + const originalModule = jest.requireActual('../../../containers/timeline/all'); + return { + useGetAllTimeline: jest.fn(), + getAllTimeline: originalModule.getAllTimeline, + }; +}); describe('OpenTimelineModal', () => { const theme = () => ({ eui: euiDarkVars, darkMode: true }); + beforeEach(() => { + ((useGetAllTimeline as unknown) as jest.Mock).mockReturnValue({ + fetchAllTimeline: jest.fn(), + timelines: getAllTimeline( + '', + mockOpenTimelineQueryResults[0].result.data?.getAllTimeline?.timeline ?? [] + ), + loading: false, + totalCount: mockOpenTimelineQueryResults[0].result.data.getAllTimeline.totalCount, + refetch: jest.fn(), + }); + }); test('it renders the expected modal', async () => { const wrapper = mount( diff --git a/x-pack/plugins/siem/public/components/open_timeline/types.ts b/x-pack/plugins/siem/public/components/open_timeline/types.ts index b7cc92ebd183f..41999c6249277 100644 --- a/x-pack/plugins/siem/public/components/open_timeline/types.ts +++ b/x-pack/plugins/siem/public/components/open_timeline/types.ts @@ -9,6 +9,7 @@ import { AllTimelinesVariables } from '../../containers/timeline/all'; import { TimelineModel } from '../../store/timeline/model'; import { NoteResult } from '../../graphql/types'; import { Refetch } from '../../store/inputs/model'; +import { TimelineType } from '../../../common/types/timeline'; /** The users who added a timeline to favorites */ export interface FavoriteTimelineResult { @@ -47,6 +48,8 @@ export interface OpenTimelineResult { pinnedEventIds?: Readonly> | null; savedObjectId?: string | null; title?: string | null; + templateTimelineId?: string | null; + type?: TimelineType.template | TimelineType.default; updated?: number | null; updatedBy?: string | null; } diff --git a/x-pack/plugins/siem/public/components/recent_timelines/index.tsx b/x-pack/plugins/siem/public/components/recent_timelines/index.tsx index 5b851701b973c..b641038f35ba6 100644 --- a/x-pack/plugins/siem/public/components/recent_timelines/index.tsx +++ b/x-pack/plugins/siem/public/components/recent_timelines/index.tsx @@ -6,11 +6,11 @@ import ApolloClient from 'apollo-client'; import { EuiHorizontalRule, EuiLink, EuiText } from '@elastic/eui'; -import React, { useCallback, useMemo } from 'react'; +import React, { useCallback, useMemo, useEffect } from 'react'; import { connect, ConnectedProps } from 'react-redux'; import { Dispatch } from 'redux'; -import { AllTimelinesQuery } from '../../containers/timeline/all'; +import { useGetAllTimeline } from '../../containers/timeline/all'; import { SortFieldTimeline, Direction } from '../../graphql/types'; import { queryTimelineById, dispatchUpdateTimeline } from '../open_timeline/helpers'; import { OnOpenTimeline } from '../open_timeline/types'; @@ -62,35 +62,39 @@ const StatefulRecentTimelinesComponent = React.memo( [filterBy] ); - return ( - { + fetchAllTimeline({ + pageInfo: { pageIndex: 1, pageSize: PAGE_SIZE, - }} - search={''} - sort={{ + }, + search: '', + sort: { sortField: SortFieldTimeline.updated, sortOrder: Direction.desc, - }} - onlyUserFavorite={filterBy === 'favorites'} - > - {({ timelines, loading }) => ( - <> - {loading ? ( - loadingPlaceholders - ) : ( - - )} - - {linkAllTimelines} - + }, + onlyUserFavorite: filterBy === 'favorites', + timelines, + totalCount, + }); + }, [filterBy, timelines, totalCount]); + + return ( + <> + {loading ? ( + loadingPlaceholders + ) : ( + )} - + + {linkAllTimelines} + ); } ); diff --git a/x-pack/plugins/siem/public/components/timeline/selectable_timeline/index.tsx b/x-pack/plugins/siem/public/components/timeline/selectable_timeline/index.tsx index 639d30bbe7bb9..4cc89e5bdba73 100644 --- a/x-pack/plugins/siem/public/components/timeline/selectable_timeline/index.tsx +++ b/x-pack/plugins/siem/public/components/timeline/selectable_timeline/index.tsx @@ -17,11 +17,11 @@ import { EuiFilterButton, } from '@elastic/eui'; import { isEmpty } from 'lodash/fp'; -import React, { memo, useCallback, useMemo, useState } from 'react'; +import React, { memo, useCallback, useMemo, useState, useEffect } from 'react'; import { ListProps } from 'react-virtualized'; import styled from 'styled-components'; -import { AllTimelinesQuery } from '../../../containers/timeline/all'; +import { useGetAllTimeline } from '../../../containers/timeline/all'; import { SortFieldTimeline, Direction } from '../../../graphql/types'; import { isUntitled } from '../../open_timeline/helpers'; import * as i18nTimeline from '../../open_timeline/translations'; @@ -96,6 +96,7 @@ const SelectableTimelineComponent: React.FC = ({ const [searchTimelineValue, setSearchTimelineValue] = useState(''); const [onlyFavorites, setOnlyFavorites] = useState(false); const [searchRef, setSearchRef] = useState(null); + const { fetchAllTimeline, timelines, loading, totalCount: timelineCount } = useGetAllTimeline(); const onSearchTimeline = useCallback(val => { setSearchTimelineValue(val); @@ -215,61 +216,64 @@ const SelectableTimelineComponent: React.FC = ({ [searchRef, onlyFavorites, handleOnToggleOnlyFavorites] ); + useEffect(() => { + fetchAllTimeline({ + pageInfo: { + pageIndex: 1, + pageSize, + }, + search: searchTimelineValue, + sort: { + sortField: SortFieldTimeline.updated, + sortOrder: Direction.desc, + }, + onlyUserFavorite: onlyFavorites, + timelines, + totalCount: timelineCount, + }); + }, [onlyFavorites, pageSize, searchTimelineValue, timelines, timelineCount]); + return ( - <> - + !hideUntitled || t.title !== '').length, + timelineCount + ), + } as unknown) as ListProps, + }} + renderOption={renderTimelineOption} + onChange={handleTimelineChange} + searchable + searchProps={{ + 'data-test-subj': 'timeline-super-select-search-box', + isLoading: loading, + placeholder: i18n.SEARCH_BOX_TIMELINE_PLACEHOLDER, + onSearch: onSearchTimeline, + incremental: false, + inputRef: (ref: HTMLElement) => { + setSearchRef(ref); + }, }} - search={searchTimelineValue} - sort={{ sortField: SortFieldTimeline.updated, sortOrder: Direction.desc }} - onlyUserFavorite={onlyFavorites} + singleSelection={true} + options={getSelectableOptions({ timelines, onlyFavorites, searchTimelineValue })} > - {({ timelines, loading, totalCount }) => ( - - !hideUntitled || t.title !== '').length, - totalCount - ), - } as unknown) as ListProps, - }} - renderOption={renderTimelineOption} - onChange={handleTimelineChange} - searchable - searchProps={{ - 'data-test-subj': 'timeline-super-select-search-box', - isLoading: loading, - placeholder: i18n.SEARCH_BOX_TIMELINE_PLACEHOLDER, - onSearch: onSearchTimeline, - incremental: false, - inputRef: (ref: HTMLElement) => { - setSearchRef(ref); - }, - }} - singleSelection={true} - options={getSelectableOptions({ timelines, onlyFavorites, searchTimelineValue })} - > - {(list, search) => ( - <> - {search} - {favoritePortal} - {list} - - )} - - + {(list, search) => ( + <> + {search} + {favoritePortal} + {list} + )} - - + + ); }; diff --git a/x-pack/plugins/siem/public/containers/timeline/all/api.ts b/x-pack/plugins/siem/public/containers/timeline/all/api.ts deleted file mode 100644 index 09c8374bad113..0000000000000 --- a/x-pack/plugins/siem/public/containers/timeline/all/api.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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { TIMELINE_IMPORT_URL, TIMELINE_EXPORT_URL } from '../../../../common/constants'; -import { ImportDataProps, ImportDataResponse } from '../../detection_engine/rules'; -import { KibanaServices } from '../../../lib/kibana'; -import { ExportSelectedData } from '../../../components/generic_downloader'; - -export const importTimelines = async ({ - fileToImport, - overwrite = false, - signal, -}: ImportDataProps): Promise => { - const formData = new FormData(); - formData.append('file', fileToImport); - - return KibanaServices.get().http.fetch(`${TIMELINE_IMPORT_URL}`, { - method: 'POST', - headers: { 'Content-Type': undefined }, - query: { overwrite }, - body: formData, - signal, - }); -}; - -export const exportSelectedTimeline: ExportSelectedData = async ({ - excludeExportDetails = false, - filename = `timelines_export.ndjson`, - ids = [], - signal, -}): Promise => { - const body = ids.length > 0 ? JSON.stringify({ ids }) : undefined; - const response = await KibanaServices.get().http.fetch(`${TIMELINE_EXPORT_URL}`, { - method: 'POST', - body, - query: { - exclude_export_details: excludeExportDetails, - file_name: filename, - }, - signal, - asResponse: true, - }); - - return response.body!; -}; diff --git a/x-pack/plugins/siem/public/containers/timeline/all/index.gql_query.ts b/x-pack/plugins/siem/public/containers/timeline/all/index.gql_query.ts index e380e46e77070..7d30b6c22a110 100644 --- a/x-pack/plugins/siem/public/containers/timeline/all/index.gql_query.ts +++ b/x-pack/plugins/siem/public/containers/timeline/all/index.gql_query.ts @@ -55,6 +55,9 @@ export const allTimelinesQuery = gql` noteIds pinnedEventIds title + timelineType + templateTimelineId + templateTimelineVersion created createdBy updated diff --git a/x-pack/plugins/siem/public/containers/timeline/all/index.tsx b/x-pack/plugins/siem/public/containers/timeline/all/index.tsx index b5c91ca287f0b..62c8d21a2e944 100644 --- a/x-pack/plugins/siem/public/containers/timeline/all/index.tsx +++ b/x-pack/plugins/siem/public/containers/timeline/all/index.tsx @@ -3,23 +3,28 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import React, { useCallback } from 'react'; -import { getOr } from 'lodash/fp'; -import memoizeOne from 'memoize-one'; -import { Query } from 'react-apollo'; +import { getOr, noop } from 'lodash/fp'; +import memoizeOne from 'memoize-one'; +import { useCallback, useState, useRef, useEffect } from 'react'; +import { useDispatch } from 'react-redux'; -import { ApolloQueryResult } from 'apollo-client'; import { OpenTimelineResult } from '../../../components/open_timeline/types'; +import { errorToToaster, useStateToaster } from '../../../components/toasters'; import { GetAllTimeline, PageInfoTimeline, SortTimeline, TimelineResult, } from '../../../graphql/types'; +import { inputsModel, inputsActions } from '../../../store/inputs'; +import { useApolloClient } from '../../../utils/apollo_context'; + import { allTimelinesQuery } from './index.gql_query'; +import * as i18n from '../../../pages/timelines/translations'; export interface AllTimelinesArgs { + fetchAllTimeline: ({ onlyUserFavorite, pageInfo, search, sort }: AllTimelinesVariables) => void; timelines: OpenTimelineResult[]; loading: boolean; totalCount: number; @@ -31,17 +36,13 @@ export interface AllTimelinesVariables { pageInfo: PageInfoTimeline; search: string; sort: SortTimeline; + timelines: OpenTimelineResult[]; + totalCount: number; } -interface OwnProps extends AllTimelinesVariables { - children?: (args: AllTimelinesArgs) => React.ReactNode; -} - -type Refetch = ( - variables: GetAllTimeline.Variables | undefined -) => Promise>; +export const ALL_TIMELINE_QUERY_ID = 'FETCH_ALL_TIMELINES'; -const getAllTimeline = memoizeOne( +export const getAllTimeline = memoizeOne( (variables: string, timelines: TimelineResult[]): OpenTimelineResult[] => timelines.map(timeline => ({ created: timeline.created, @@ -76,41 +77,117 @@ const getAllTimeline = memoizeOne( })) ); -const AllTimelinesQueryComponent: React.FC = ({ - children, - onlyUserFavorite, - pageInfo, - search, - sort, -}) => { - const variables: GetAllTimeline.Variables = { - onlyUserFavorite, - pageInfo, - search, - sort, - }; - const handleRefetch = useCallback((refetch: Refetch) => refetch(variables), [variables]); +export const useGetAllTimeline = (): AllTimelinesArgs => { + const dispatch = useDispatch(); + const apolloClient = useApolloClient(); + const refetch = useRef(); + const [, dispatchToaster] = useStateToaster(); + const [allTimelines, setAllTimelines] = useState({ + fetchAllTimeline: noop, + loading: false, + refetch: refetch.current ?? noop, + totalCount: 0, + timelines: [], + }); + + const fetchAllTimeline = useCallback( + async ({ + onlyUserFavorite, + pageInfo, + search, + sort, + timelines, + totalCount, + }: AllTimelinesVariables) => { + let didCancel = false; + const abortCtrl = new AbortController(); - return ( - - query={allTimelinesQuery} - fetchPolicy="network-only" - notifyOnNetworkStatusChange - variables={variables} - > - {({ data, loading, refetch }) => - children!({ - loading, - refetch: handleRefetch.bind(null, refetch), - totalCount: getOr(0, 'getAllTimeline.totalCount', data), - timelines: getAllTimeline( - JSON.stringify(variables), - getOr([], 'getAllTimeline.timeline', data) - ), - }) - } - + const fetchData = async () => { + try { + if (apolloClient != null) { + setAllTimelines({ + ...allTimelines, + timelines: timelines ?? allTimelines.timelines, + totalCount: totalCount ?? allTimelines.totalCount, + loading: true, + }); + const variables: GetAllTimeline.Variables = { + onlyUserFavorite, + pageInfo, + search, + sort, + }; + const response = await apolloClient.query< + GetAllTimeline.Query, + GetAllTimeline.Variables + >({ + query: allTimelinesQuery, + fetchPolicy: 'network-only', + variables, + context: { + fetchOptions: { + abortSignal: abortCtrl.signal, + }, + }, + }); + if (!didCancel) { + dispatch( + inputsActions.setQuery({ + inputId: 'global', + id: ALL_TIMELINE_QUERY_ID, + loading: false, + refetch: refetch.current ?? noop, + inspect: null, + }) + ); + setAllTimelines({ + fetchAllTimeline, + loading: false, + refetch: refetch.current ?? noop, + totalCount: getOr(0, 'getAllTimeline.totalCount', response.data), + timelines: getAllTimeline( + JSON.stringify(variables), + getOr([], 'getAllTimeline.timeline', response.data) + ), + }); + } + } + } catch (error) { + if (!didCancel) { + errorToToaster({ + title: i18n.ERROR_FETCHING_TIMELINES_TITLE, + error: error.body && error.body.message ? new Error(error.body.message) : error, + dispatchToaster, + }); + setAllTimelines({ + fetchAllTimeline, + loading: false, + refetch: noop, + totalCount: 0, + timelines: [], + }); + } + } + }; + refetch.current = fetchData; + fetchData(); + return () => { + didCancel = true; + abortCtrl.abort(); + }; + }, + [apolloClient, allTimelines] ); -}; -export const AllTimelinesQuery = React.memo(AllTimelinesQueryComponent); + useEffect(() => { + return () => { + dispatch(inputsActions.deleteOneQuery({ inputId: 'global', id: ALL_TIMELINE_QUERY_ID })); + }; + }, [dispatch]); + + return { + ...allTimelines, + fetchAllTimeline, + refetch: refetch.current ?? noop, + }; +}; diff --git a/x-pack/plugins/siem/public/containers/timeline/api.ts b/x-pack/plugins/siem/public/containers/timeline/api.ts new file mode 100644 index 0000000000000..023e2e6af9f88 --- /dev/null +++ b/x-pack/plugins/siem/public/containers/timeline/api.ts @@ -0,0 +1,115 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { fold } from 'fp-ts/lib/Either'; +import { identity } from 'fp-ts/lib/function'; +import { pipe } from 'fp-ts/lib/pipeable'; + +import { throwErrors } from '../../../../case/common/api'; +import { + SavedTimeline, + TimelineResponse, + TimelineResponseType, +} from '../../../common/types/timeline'; +import { TIMELINE_URL, TIMELINE_IMPORT_URL, TIMELINE_EXPORT_URL } from '../../../common/constants'; + +import { KibanaServices } from '../../lib/kibana'; +import { ExportSelectedData } from '../../components/generic_downloader'; + +import { createToasterPlainError } from '../case/utils'; +import { ImportDataProps, ImportDataResponse } from '../detection_engine/rules'; + +interface RequestPostTimeline { + timeline: SavedTimeline; + signal?: AbortSignal; +} + +interface RequestPatchTimeline extends RequestPostTimeline { + timelineId: T; + version: T; +} + +type RequestPersistTimeline = RequestPostTimeline & Partial>; + +const decodeTimelineResponse = (respTimeline?: TimelineResponse) => + pipe( + TimelineResponseType.decode(respTimeline), + fold(throwErrors(createToasterPlainError), identity) + ); + +const postTimeline = async ({ timeline }: RequestPostTimeline): Promise => { + const response = await KibanaServices.get().http.post(TIMELINE_URL, { + method: 'POST', + body: JSON.stringify({ timeline }), + }); + + return decodeTimelineResponse(response); +}; + +const patchTimeline = async ({ + timelineId, + timeline, + version, +}: RequestPatchTimeline): Promise => { + const response = await KibanaServices.get().http.patch(TIMELINE_URL, { + method: 'PATCH', + body: JSON.stringify({ timeline, timelineId, version }), + }); + + return decodeTimelineResponse(response); +}; + +export const persistTimeline = async ({ + timelineId, + timeline, + version, +}: RequestPersistTimeline): Promise => { + if (timelineId == null) { + return postTimeline({ timeline }); + } + return patchTimeline({ + timelineId, + timeline, + version: version ?? '', + }); +}; + +export const importTimelines = async ({ + fileToImport, + overwrite = false, + signal, +}: ImportDataProps): Promise => { + const formData = new FormData(); + formData.append('file', fileToImport); + + return KibanaServices.get().http.fetch(`${TIMELINE_IMPORT_URL}`, { + method: 'POST', + headers: { 'Content-Type': undefined }, + query: { overwrite }, + body: formData, + signal, + }); +}; + +export const exportSelectedTimeline: ExportSelectedData = async ({ + excludeExportDetails = false, + filename = `timelines_export.ndjson`, + ids = [], + signal, +}): Promise => { + const body = ids.length > 0 ? JSON.stringify({ ids }) : undefined; + const response = await KibanaServices.get().http.fetch(`${TIMELINE_EXPORT_URL}`, { + method: 'POST', + body, + query: { + exclude_export_details: excludeExportDetails, + file_name: filename, + }, + signal, + asResponse: true, + }); + + return response.body!; +}; diff --git a/x-pack/plugins/siem/public/graphql/introspection.json b/x-pack/plugins/siem/public/graphql/introspection.json index 2a9dd8f2aacfe..4026a043c7778 100644 --- a/x-pack/plugins/siem/public/graphql/introspection.json +++ b/x-pack/plugins/siem/public/graphql/introspection.json @@ -9728,6 +9728,30 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "templateTimelineId", + "description": "", + "args": [], + "type": { "kind": "SCALAR", "name": "String", "ofType": null }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "templateTimelineVersion", + "description": "", + "args": [], + "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "timelineType", + "description": "", + "args": [], + "type": { "kind": "ENUM", "name": "TimelineType", "ofType": null }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "updated", "description": "", @@ -10323,6 +10347,39 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "SCALAR", + "name": "Int", + "description": "The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1. ", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "ENUM", + "name": "TimelineType", + "description": "", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": [ + { + "name": "default", + "description": "", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "template", + "description": "", + "isDeprecated": false, + "deprecationReason": null + } + ], + "possibleTypes": null + }, { "kind": "INPUT_OBJECT", "name": "PageInfoTimeline", @@ -10863,6 +10920,24 @@ "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, + { + "name": "templateTimelineId", + "description": "", + "type": { "kind": "SCALAR", "name": "String", "ofType": null }, + "defaultValue": null + }, + { + "name": "templateTimelineVersion", + "description": "", + "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, + "defaultValue": null + }, + { + "name": "timelineType", + "description": "", + "type": { "kind": "ENUM", "name": "TimelineType", "ofType": null }, + "defaultValue": null + }, { "name": "dateRange", "description": "", diff --git a/x-pack/plugins/siem/public/graphql/types.ts b/x-pack/plugins/siem/public/graphql/types.ts index e15c099a007ad..8c39d5e58b99e 100644 --- a/x-pack/plugins/siem/public/graphql/types.ts +++ b/x-pack/plugins/siem/public/graphql/types.ts @@ -132,6 +132,12 @@ export interface TimelineInput { title?: Maybe; + templateTimelineId?: Maybe; + + templateTimelineVersion?: Maybe; + + timelineType?: Maybe; + dateRange?: Maybe; savedQueryId?: Maybe; @@ -334,6 +340,11 @@ export enum TlsFields { _id = '_id', } +export enum TimelineType { + default = 'default', + template = 'template', +} + export enum SortFieldTimeline { title = 'title', description = 'description', @@ -1944,6 +1955,12 @@ export interface TimelineResult { title?: Maybe; + templateTimelineId?: Maybe; + + templateTimelineVersion?: Maybe; + + timelineType?: Maybe; + updated?: Maybe; updatedBy?: Maybe; @@ -4030,6 +4047,12 @@ export namespace GetAllTimeline { title: Maybe; + timelineType: Maybe; + + templateTimelineId: Maybe; + + templateTimelineVersion: Maybe; + created: Maybe; createdBy: Maybe; diff --git a/x-pack/plugins/siem/public/lib/telemetry/middleware.ts b/x-pack/plugins/siem/public/lib/telemetry/middleware.ts index 59c6cb3566907..ca889e20e695f 100644 --- a/x-pack/plugins/siem/public/lib/telemetry/middleware.ts +++ b/x-pack/plugins/siem/public/lib/telemetry/middleware.ts @@ -7,7 +7,7 @@ import { Action, Dispatch, MiddlewareAPI } from 'redux'; import { track, METRIC_TYPE, TELEMETRY_EVENT } from './'; -import { timelineActions } from '../../store/actions'; +import * as timelineActions from '../../store/timeline/actions'; export const telemetryMiddleware = (api: MiddlewareAPI) => (next: Dispatch) => (action: Action) => { if (timelineActions.endTimelineSaving.match(action)) { diff --git a/x-pack/plugins/siem/public/mock/timeline_results.ts b/x-pack/plugins/siem/public/mock/timeline_results.ts index 0e61457873bfd..edd1c73771829 100644 --- a/x-pack/plugins/siem/public/mock/timeline_results.ts +++ b/x-pack/plugins/siem/public/mock/timeline_results.ts @@ -168,6 +168,9 @@ export const mockOpenTimelineQueryResults: MockedProvidedQuery[] = [ 'ZF0W12oB9v5HJNSHwY6L', ], title: 'test 1', + timelineType: null, + templateTimelineId: null, + templateTimelineVersion: null, created: 1558386787614, createdBy: 'elastic', updated: 1558390951234, @@ -294,6 +297,9 @@ export const mockOpenTimelineQueryResults: MockedProvidedQuery[] = [ 'ZF0W12oB9v5HJNSHwY6L', ], title: 'test 2', + timelineType: null, + templateTimelineId: null, + templateTimelineVersion: null, created: 1558386787614, createdBy: 'elastic', updated: 1558390951234, @@ -420,6 +426,9 @@ export const mockOpenTimelineQueryResults: MockedProvidedQuery[] = [ 'ZF0W12oB9v5HJNSHwY6L', ], title: 'test 2', + timelineType: null, + templateTimelineId: null, + templateTimelineVersion: null, created: 1558386787614, createdBy: 'elastic', updated: 1558390951234, @@ -546,6 +555,9 @@ export const mockOpenTimelineQueryResults: MockedProvidedQuery[] = [ 'ZF0W12oB9v5HJNSHwY6L', ], title: 'test 3', + timelineType: null, + templateTimelineId: null, + templateTimelineVersion: null, created: 1558386787614, createdBy: 'elastic', updated: 1558390951234, @@ -672,6 +684,9 @@ export const mockOpenTimelineQueryResults: MockedProvidedQuery[] = [ 'ZF0W12oB9v5HJNSHwY6L', ], title: 'test 4', + timelineType: null, + templateTimelineId: null, + templateTimelineVersion: null, created: 1558386787614, createdBy: 'elastic', updated: 1558390951234, @@ -798,6 +813,9 @@ export const mockOpenTimelineQueryResults: MockedProvidedQuery[] = [ 'ZF0W12oB9v5HJNSHwY6L', ], title: 'test 5', + timelineType: null, + templateTimelineId: null, + templateTimelineVersion: null, created: 1558386787614, createdBy: 'elastic', updated: 1558390951234, @@ -924,6 +942,9 @@ export const mockOpenTimelineQueryResults: MockedProvidedQuery[] = [ 'ZF0W12oB9v5HJNSHwY6L', ], title: 'test 6', + timelineType: null, + templateTimelineId: null, + templateTimelineVersion: null, created: 1558386787614, createdBy: 'elastic', updated: 1558390951234, @@ -1050,6 +1071,9 @@ export const mockOpenTimelineQueryResults: MockedProvidedQuery[] = [ 'ZF0W12oB9v5HJNSHwY6L', ], title: 'test 7', + timelineType: null, + templateTimelineId: null, + templateTimelineVersion: null, created: 1558386787614, createdBy: 'elastic', updated: 1558390951234, @@ -1176,6 +1200,9 @@ export const mockOpenTimelineQueryResults: MockedProvidedQuery[] = [ 'ZF0W12oB9v5HJNSHwY6L', ], title: 'test 7', + timelineType: null, + templateTimelineId: null, + templateTimelineVersion: null, created: 1558386787614, createdBy: 'elastic', updated: 1558390951234, @@ -1302,6 +1329,9 @@ export const mockOpenTimelineQueryResults: MockedProvidedQuery[] = [ 'ZF0W12oB9v5HJNSHwY6L', ], title: 'test 7', + timelineType: null, + templateTimelineId: null, + templateTimelineVersion: null, created: 1558386787614, createdBy: 'elastic', updated: 1558390951234, @@ -1428,6 +1458,9 @@ export const mockOpenTimelineQueryResults: MockedProvidedQuery[] = [ 'ZF0W12oB9v5HJNSHwY6L', ], title: 'test 7', + timelineType: null, + templateTimelineId: null, + templateTimelineVersion: null, created: 1558386787614, createdBy: 'elastic', updated: 1558390951234, @@ -1554,6 +1587,9 @@ export const mockOpenTimelineQueryResults: MockedProvidedQuery[] = [ 'ZF0W12oB9v5HJNSHwY6L', ], title: 'test 7', + timelineType: null, + templateTimelineId: null, + templateTimelineVersion: null, created: 1558386787614, createdBy: 'elastic', updated: 1558390951234, @@ -1680,6 +1716,9 @@ export const mockOpenTimelineQueryResults: MockedProvidedQuery[] = [ 'ZF0W12oB9v5HJNSHwY6L', ], title: 'test 7', + timelineType: null, + templateTimelineId: null, + templateTimelineVersion: null, created: 1558386787614, createdBy: 'elastic', updated: 1558390951234, diff --git a/x-pack/plugins/siem/public/pages/timelines/translations.ts b/x-pack/plugins/siem/public/pages/timelines/translations.ts index 723d164ad2cdd..304474bbff2c5 100644 --- a/x-pack/plugins/siem/public/pages/timelines/translations.ts +++ b/x-pack/plugins/siem/public/pages/timelines/translations.ts @@ -23,3 +23,10 @@ export const ALL_TIMELINES_IMPORT_TIMELINE_TITLE = i18n.translate( defaultMessage: 'Import Timeline', } ); + +export const ERROR_FETCHING_TIMELINES_TITLE = i18n.translate( + 'xpack.siem.timelines.allTimelines.errorFetchingTimelinesTitle', + { + defaultMessage: 'Failed to query all timelines data', + } +); diff --git a/x-pack/plugins/siem/public/store/model.ts b/x-pack/plugins/siem/public/store/model.ts index 9e9e663a59fe0..686dc096e61b0 100644 --- a/x-pack/plugins/siem/public/store/model.ts +++ b/x-pack/plugins/siem/public/store/model.ts @@ -9,15 +9,4 @@ export { dragAndDropModel } from './drag_and_drop'; export { hostsModel } from './hosts'; export { inputsModel } from './inputs'; export { networkModel } from './network'; - -export type KueryFilterQueryKind = 'kuery' | 'lucene'; - -export interface KueryFilterQuery { - kind: KueryFilterQueryKind; - expression: string; -} - -export interface SerializedFilterQuery { - kuery: KueryFilterQuery | null; - serializedQuery: string; -} +export * from './types'; diff --git a/x-pack/plugins/siem/public/store/store.ts b/x-pack/plugins/siem/public/store/store.ts index d3559e7a7adde..2af0f87b4494d 100644 --- a/x-pack/plugins/siem/public/store/store.ts +++ b/x-pack/plugins/siem/public/store/store.ts @@ -32,6 +32,7 @@ export const createStore = ( const middlewareDependencies = { apolloClient$: apolloClient, + selectAllTimelineQuery: inputsSelectors.globalQueryByIdSelector, selectNotesByIdSelector: appSelectors.selectNotesByIdSelector, timelineByIdSelector: timelineSelectors.timelineByIdSelector, timelineTimeRangeSelector: inputsSelectors.timelineTimeRangeSelector, diff --git a/x-pack/plugins/siem/public/store/timeline/actions.ts b/x-pack/plugins/siem/public/store/timeline/actions.ts index a03cc2643e014..12155decf40d4 100644 --- a/x-pack/plugins/siem/public/store/timeline/actions.ts +++ b/x-pack/plugins/siem/public/store/timeline/actions.ts @@ -12,7 +12,7 @@ import { DataProvider, QueryOperator, } from '../../components/timeline/data_providers/data_provider'; -import { KueryFilterQuery, SerializedFilterQuery } from '../model'; +import { KueryFilterQuery, SerializedFilterQuery } from '../types'; import { EventType, KqlMode, TimelineModel, ColumnHeaderOptions } from './model'; import { TimelineNonEcsData } from '../../graphql/types'; diff --git a/x-pack/plugins/siem/public/store/timeline/epic.ts b/x-pack/plugins/siem/public/store/timeline/epic.ts index 4fece0572274f..6812d8d8aa672 100644 --- a/x-pack/plugins/siem/public/store/timeline/epic.ts +++ b/x-pack/plugins/siem/public/store/timeline/epic.ts @@ -29,17 +29,11 @@ import { } from 'rxjs/operators'; import { esFilters, Filter, MatchAllFilter } from '../../../../../../src/plugins/data/public'; -import { persistTimelineMutation } from '../../containers/timeline/persist.gql_query'; -import { - PersistTimelineMutation, - TimelineInput, - ResponseTimeline, - TimelineResult, -} from '../../graphql/types'; +import { TimelineInput, ResponseTimeline, TimelineResult } from '../../graphql/types'; import { AppApolloClient } from '../../lib/lib'; import { addError } from '../app/actions'; import { NotesById } from '../app/model'; -import { TimeRange } from '../inputs/model'; +import { inputsModel } from '../inputs'; import { applyKqlFilterQuery, @@ -75,13 +69,15 @@ import { epicPersistPinnedEvent, timelinePinnedEventActionsType } from './epic_p import { epicPersistTimelineFavorite, timelineFavoriteActionsType } from './epic_favorite'; import { isNotNull } from './helpers'; import { dispatcherTimelinePersistQueue } from './epic_dispatcher_timeline_persistence_queue'; -import { refetchQueries } from './refetch_queries'; import { myEpicTimelineId } from './my_epic_timeline_id'; import { ActionTimeline, TimelineById } from './types'; +import { persistTimeline } from '../../containers/timeline/api'; +import { ALL_TIMELINE_QUERY_ID } from '../../containers/timeline/all'; interface TimelineEpicDependencies { timelineByIdSelector: (state: State) => TimelineById; - timelineTimeRangeSelector: (state: State) => TimeRange; + timelineTimeRangeSelector: (state: State) => inputsModel.TimeRange; + selectAllTimelineQuery: () => (state: State, id: string) => inputsModel.GlobalQuery; selectNotesByIdSelector: (state: State) => NotesById; apolloClient$: Observable; } @@ -119,10 +115,24 @@ export const createTimelineEpic = (): Epic< > => ( action$, state$, - { selectNotesByIdSelector, timelineByIdSelector, timelineTimeRangeSelector, apolloClient$ } + { + selectAllTimelineQuery, + selectNotesByIdSelector, + timelineByIdSelector, + timelineTimeRangeSelector, + apolloClient$, + } ) => { const timeline$ = state$.pipe(map(timelineByIdSelector), filter(isNotNull)); + const allTimelineQuery$ = state$.pipe( + map(state => { + const getQuery = selectAllTimelineQuery(); + return getQuery(state, ALL_TIMELINE_QUERY_ID); + }), + filter(isNotNull) + ); + const notes$ = state$.pipe(map(selectNotesByIdSelector), filter(isNotNull)); const timelineTimeRange$ = state$.pipe(map(timelineTimeRangeSelector), filter(isNotNull)); @@ -168,33 +178,52 @@ export const createTimelineEpic = (): Epic< const version = myEpicTimelineId.getTimelineVersion(); if (timelineNoteActionsType.includes(action.type)) { - return epicPersistNote(apolloClient, action, timeline, notes, action$, timeline$, notes$); + return epicPersistNote( + apolloClient, + action, + timeline, + notes, + action$, + timeline$, + notes$, + allTimelineQuery$ + ); } else if (timelinePinnedEventActionsType.includes(action.type)) { - return epicPersistPinnedEvent(apolloClient, action, timeline, action$, timeline$); + return epicPersistPinnedEvent( + apolloClient, + action, + timeline, + action$, + timeline$, + allTimelineQuery$ + ); } else if (timelineFavoriteActionsType.includes(action.type)) { - return epicPersistTimelineFavorite(apolloClient, action, timeline, action$, timeline$); + return epicPersistTimelineFavorite( + apolloClient, + action, + timeline, + action$, + timeline$, + allTimelineQuery$ + ); } else if (timelineActionsType.includes(action.type)) { return from( - apolloClient.mutate< - PersistTimelineMutation.Mutation, - PersistTimelineMutation.Variables - >({ - mutation: persistTimelineMutation, - fetchPolicy: 'no-cache', - variables: { - timelineId, - version, - timeline: convertTimelineAsInput(timeline[action.payload.id], timelineTimeRange), - }, - refetchQueries, + persistTimeline({ + timelineId, + version, + timeline: convertTimelineAsInput(timeline[action.payload.id], timelineTimeRange), }) ).pipe( - withLatestFrom(timeline$), - mergeMap(([result, recentTimeline]) => { + withLatestFrom(timeline$, allTimelineQuery$), + mergeMap(([result, recentTimeline, allTimelineQuery]) => { const savedTimeline = recentTimeline[action.payload.id]; const response: ResponseTimeline = get('data.persistTimeline', result); const callOutMsg = response.code === 403 ? [showCallOutUnauthorizedMsg()] : []; + if (allTimelineQuery.refetch != null) { + (allTimelineQuery.refetch as inputsModel.Refetch)(); + } + return [ response.code === 409 ? updateAutoSaveMsg({ @@ -261,7 +290,7 @@ const timelineInput: TimelineInput = { export const convertTimelineAsInput = ( timeline: TimelineModel, - timelineTimeRange: TimeRange + timelineTimeRange: inputsModel.TimeRange ): TimelineInput => Object.keys(timelineInput).reduce((acc, key) => { if (has(key, timeline)) { diff --git a/x-pack/plugins/siem/public/store/timeline/epic_favorite.ts b/x-pack/plugins/siem/public/store/timeline/epic_favorite.ts index 4d1b73aa70a6e..6a1dadb8a59f5 100644 --- a/x-pack/plugins/siem/public/store/timeline/epic_favorite.ts +++ b/x-pack/plugins/siem/public/store/timeline/epic_favorite.ts @@ -26,6 +26,7 @@ import { dispatcherTimelinePersistQueue } from './epic_dispatcher_timeline_persi import { refetchQueries } from './refetch_queries'; import { myEpicTimelineId } from './my_epic_timeline_id'; import { ActionTimeline, TimelineById } from './types'; +import { inputsModel } from '../inputs'; export const timelineFavoriteActionsType = [updateIsFavorite.type]; @@ -34,7 +35,8 @@ export const epicPersistTimelineFavorite = ( action: ActionTimeline, timeline: TimelineById, action$: Observable, - timeline$: Observable + timeline$: Observable, + allTimelineQuery$: Observable // eslint-disable-next-line @typescript-eslint/no-explicit-any ): Observable => from( @@ -50,12 +52,16 @@ export const epicPersistTimelineFavorite = ( refetchQueries, }) ).pipe( - withLatestFrom(timeline$), - mergeMap(([result, recentTimelines]) => { + withLatestFrom(timeline$, allTimelineQuery$), + mergeMap(([result, recentTimelines, allTimelineQuery]) => { const savedTimeline = recentTimelines[action.payload.id]; const response: ResponseFavoriteTimeline = get('data.persistFavorite', result); const callOutMsg = response.code === 403 ? [showCallOutUnauthorizedMsg()] : []; + if (allTimelineQuery.refetch != null) { + (allTimelineQuery.refetch as inputsModel.Refetch)(); + } + return [ ...callOutMsg, updateTimeline({ diff --git a/x-pack/plugins/siem/public/store/timeline/epic_note.ts b/x-pack/plugins/siem/public/store/timeline/epic_note.ts index e5a712fe2c666..3722a6ad8036c 100644 --- a/x-pack/plugins/siem/public/store/timeline/epic_note.ts +++ b/x-pack/plugins/siem/public/store/timeline/epic_note.ts @@ -16,6 +16,7 @@ import { persistTimelineNoteMutation } from '../../containers/timeline/notes/per import { PersistTimelineNoteMutation, ResponseNote } from '../../graphql/types'; import { updateNote, addError } from '../app/actions'; import { NotesById } from '../app/model'; +import { inputsModel } from '../inputs'; import { addNote, @@ -39,7 +40,8 @@ export const epicPersistNote = ( notes: NotesById, action$: Observable, timeline$: Observable, - notes$: Observable + notes$: Observable, + allTimelineQuery$: Observable // eslint-disable-next-line @typescript-eslint/no-explicit-any ): Observable => from( @@ -61,12 +63,16 @@ export const epicPersistNote = ( refetchQueries, }) ).pipe( - withLatestFrom(timeline$, notes$), - mergeMap(([result, recentTimeline, recentNotes]) => { + withLatestFrom(timeline$, notes$, allTimelineQuery$), + mergeMap(([result, recentTimeline, recentNotes, allTimelineQuery]) => { const noteIdRedux = action.payload.noteId; const response: ResponseNote = get('data.persistNote', result); const callOutMsg = response.code === 403 ? [showCallOutUnauthorizedMsg()] : []; + if (allTimelineQuery.refetch != null) { + (allTimelineQuery.refetch as inputsModel.Refetch)(); + } + return [ ...callOutMsg, recentTimeline[action.payload.id].savedObjectId == null diff --git a/x-pack/plugins/siem/public/store/timeline/epic_pinned_event.ts b/x-pack/plugins/siem/public/store/timeline/epic_pinned_event.ts index 2260999a91e7b..a1281250ba72a 100644 --- a/x-pack/plugins/siem/public/store/timeline/epic_pinned_event.ts +++ b/x-pack/plugins/siem/public/store/timeline/epic_pinned_event.ts @@ -15,6 +15,8 @@ import { filter, mergeMap, startWith, withLatestFrom, takeUntil } from 'rxjs/ope import { persistTimelinePinnedEventMutation } from '../../containers/timeline/pinned_event/persist.gql_query'; import { PersistTimelinePinnedEventMutation, PinnedEvent } from '../../graphql/types'; import { addError } from '../app/actions'; +import { inputsModel } from '../inputs'; + import { pinEvent, endTimelineSaving, @@ -35,7 +37,8 @@ export const epicPersistPinnedEvent = ( action: ActionTimeline, timeline: TimelineById, action$: Observable, - timeline$: Observable + timeline$: Observable, + allTimelineQuery$: Observable // eslint-disable-next-line @typescript-eslint/no-explicit-any ): Observable => from( @@ -57,12 +60,16 @@ export const epicPersistPinnedEvent = ( refetchQueries, }) ).pipe( - withLatestFrom(timeline$), - mergeMap(([result, recentTimeline]) => { + withLatestFrom(timeline$, allTimelineQuery$), + mergeMap(([result, recentTimeline, allTimelineQuery]) => { const savedTimeline = recentTimeline[action.payload.id]; const response: PinnedEvent = get('data.persistPinnedEventOnTimeline', result); const callOutMsg = response && response.code === 403 ? [showCallOutUnauthorizedMsg()] : []; + if (allTimelineQuery.refetch != null) { + (allTimelineQuery.refetch as inputsModel.Refetch)(); + } + return [ response != null ? updateTimeline({ diff --git a/x-pack/plugins/siem/public/store/types.ts b/x-pack/plugins/siem/public/store/types.ts new file mode 100644 index 0000000000000..2c679ba41116e --- /dev/null +++ b/x-pack/plugins/siem/public/store/types.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export type KueryFilterQueryKind = 'kuery' | 'lucene'; + +export interface KueryFilterQuery { + kind: KueryFilterQueryKind; + expression: string; +} + +export interface SerializedFilterQuery { + kuery: KueryFilterQuery | null; + serializedQuery: string; +} diff --git a/x-pack/plugins/siem/server/graphql/timeline/schema.gql.ts b/x-pack/plugins/siem/server/graphql/timeline/schema.gql.ts index 9dd04247b7f47..bc2b3a53d85f3 100644 --- a/x-pack/plugins/siem/server/graphql/timeline/schema.gql.ts +++ b/x-pack/plugins/siem/server/graphql/timeline/schema.gql.ts @@ -125,6 +125,11 @@ export const timelineSchema = gql` script: String } + enum TimelineType { + default + template + } + input TimelineInput { columns: [ColumnHeaderInput!] dataProviders: [DataProviderInput!] @@ -134,6 +139,9 @@ export const timelineSchema = gql` kqlMode: String kqlQuery: SerializedFilterQueryInput title: String + templateTimelineId: String + templateTimelineVersion: Int + timelineType: TimelineType dateRange: DateRangePickerInput savedQueryId: String sort: SortTimelineInput @@ -237,6 +245,9 @@ export const timelineSchema = gql` savedObjectId: String! sort: SortTimelineResult title: String + templateTimelineId: String + templateTimelineVersion: Int + timelineType: TimelineType updated: Float updatedBy: String version: String! diff --git a/x-pack/plugins/siem/server/graphql/types.ts b/x-pack/plugins/siem/server/graphql/types.ts index d272b7ff59b79..6a35ba08f8e43 100644 --- a/x-pack/plugins/siem/server/graphql/types.ts +++ b/x-pack/plugins/siem/server/graphql/types.ts @@ -134,6 +134,12 @@ export interface TimelineInput { title?: Maybe; + templateTimelineId?: Maybe; + + templateTimelineVersion?: Maybe; + + timelineType?: Maybe; + dateRange?: Maybe; savedQueryId?: Maybe; @@ -336,6 +342,11 @@ export enum TlsFields { _id = '_id', } +export enum TimelineType { + default = 'default', + template = 'template', +} + export enum SortFieldTimeline { title = 'title', description = 'description', @@ -1946,6 +1957,12 @@ export interface TimelineResult { title?: Maybe; + templateTimelineId?: Maybe; + + templateTimelineVersion?: Maybe; + + timelineType?: Maybe; + updated?: Maybe; updatedBy?: Maybe; @@ -8023,6 +8040,12 @@ export namespace TimelineResultResolvers { title?: TitleResolver, TypeParent, TContext>; + templateTimelineId?: TemplateTimelineIdResolver, TypeParent, TContext>; + + templateTimelineVersion?: TemplateTimelineVersionResolver, TypeParent, TContext>; + + timelineType?: TimelineTypeResolver, TypeParent, TContext>; + updated?: UpdatedResolver, TypeParent, TContext>; updatedBy?: UpdatedByResolver, TypeParent, TContext>; @@ -8130,6 +8153,21 @@ export namespace TimelineResultResolvers { Parent = TimelineResult, TContext = SiemContext > = Resolver; + export type TemplateTimelineIdResolver< + R = Maybe, + Parent = TimelineResult, + TContext = SiemContext + > = Resolver; + export type TemplateTimelineVersionResolver< + R = Maybe, + Parent = TimelineResult, + TContext = SiemContext + > = Resolver; + export type TimelineTypeResolver< + R = Maybe, + Parent = TimelineResult, + TContext = SiemContext + > = Resolver; export type UpdatedResolver< R = Maybe, Parent = TimelineResult, diff --git a/x-pack/plugins/siem/server/lib/compose/kibana.ts b/x-pack/plugins/siem/server/lib/compose/kibana.ts index 9c46f3320e37e..4a595032e43eb 100644 --- a/x-pack/plugins/siem/server/lib/compose/kibana.ts +++ b/x-pack/plugins/siem/server/lib/compose/kibana.ts @@ -27,9 +27,9 @@ import { ElasticsearchSourceStatusAdapter, SourceStatus } from '../source_status import { ConfigurationSourcesAdapter, Sources } from '../sources'; import { AppBackendLibs, AppDomainLibs } from '../types'; import { ElasticsearchUncommonProcessesAdapter, UncommonProcesses } from '../uncommon_processes'; -import { Note } from '../note/saved_object'; -import { PinnedEvent } from '../pinned_event/saved_object'; -import { Timeline } from '../timeline/saved_object'; +import * as note from '../note/saved_object'; +import * as pinnedEvent from '../pinned_event/saved_object'; +import * as timeline from '../timeline/saved_object'; import { ElasticsearchMatrixHistogramAdapter, MatrixHistogram } from '../matrix_histogram'; export function compose( @@ -41,10 +41,6 @@ export function compose( const sources = new Sources(new ConfigurationSourcesAdapter()); const sourceStatus = new SourceStatus(new ElasticsearchSourceStatusAdapter(framework)); - const timeline = new Timeline(); - const note = new Note(); - const pinnedEvent = new PinnedEvent(); - const domainLibs: AppDomainLibs = { authentications: new Authentications(new ElasticsearchAuthenticationAdapter(framework)), events: new Events(new ElasticsearchEventsAdapter(framework)), diff --git a/x-pack/plugins/siem/server/lib/detection_engine/scripts/get_action_instances.sh b/x-pack/plugins/siem/server/lib/detection_engine/scripts/get_action_instances.sh index 750c5574f4a72..2028216e6770f 100755 --- a/x-pack/plugins/siem/server/lib/detection_engine/scripts/get_action_instances.sh +++ b/x-pack/plugins/siem/server/lib/detection_engine/scripts/get_action_instances.sh @@ -10,7 +10,7 @@ set -e ./check_env_variables.sh # Example: ./get_action_instances.sh -# https://github.com/elastic/kibana/blob/master/x-pack/legacy/plugins/actions/README.md#get-apiaction_find-find-actions +# https://github.com/elastic/kibana/blob/master/x-pack/plugins/actions/README.md#get-apiaction_find-find-actions curl -s -k \ -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ -X GET ${KIBANA_URL}${SPACE_URL}/api/action/_getAll \ diff --git a/x-pack/plugins/siem/server/lib/detection_engine/scripts/get_action_types.sh b/x-pack/plugins/siem/server/lib/detection_engine/scripts/get_action_types.sh index 8d8cbdd70a803..c587e9a204182 100755 --- a/x-pack/plugins/siem/server/lib/detection_engine/scripts/get_action_types.sh +++ b/x-pack/plugins/siem/server/lib/detection_engine/scripts/get_action_types.sh @@ -10,7 +10,7 @@ set -e ./check_env_variables.sh # Example: ./get_action_types.sh -# https://github.com/elastic/kibana/blob/master/x-pack/legacy/plugins/actions/README.md +# https://github.com/elastic/kibana/blob/master/x-pack/plugins/actions/README.md curl -s -k \ -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ -X GET ${KIBANA_URL}${SPACE_URL}/api/action/types \ diff --git a/x-pack/plugins/siem/server/lib/detection_engine/signals/bulk_create_ml_signals.ts b/x-pack/plugins/siem/server/lib/detection_engine/signals/bulk_create_ml_signals.ts index d298f1cc7cbc6..a8cc6dc680410 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/signals/bulk_create_ml_signals.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/signals/bulk_create_ml_signals.ts @@ -4,7 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { flow, set, omit } from 'lodash/fp'; +import { flow, omit } from 'lodash/fp'; +import set from 'set-value'; import { SearchResponse } from 'elasticsearch'; import { Logger } from '../../../../../../../src/core/server'; @@ -55,8 +56,11 @@ export const transformAnomalyFieldsToEcs = (anomaly: Anomaly): EcsAnomaly => { } const omitDottedFields = omit(errantFields.map(field => field.name)); - const setNestedFields = errantFields.map(field => set(field.name, field.value)); - const setTimestamp = set('@timestamp', new Date(timestamp).toISOString()); + const setNestedFields = errantFields.map(field => (_anomaly: Anomaly) => + set(_anomaly, field.name, field.value) + ); + const setTimestamp = (_anomaly: Anomaly) => + set(_anomaly, '@timestamp', new Date(timestamp).toISOString()); return flow(omitDottedFields, setNestedFields, setTimestamp)(anomaly); }; diff --git a/x-pack/plugins/siem/server/lib/note/saved_object.ts b/x-pack/plugins/siem/server/lib/note/saved_object.ts index 3eae30625e422..219465f551457 100644 --- a/x-pack/plugins/siem/server/lib/note/saved_object.ts +++ b/x-pack/plugins/siem/server/lib/note/saved_object.ts @@ -15,6 +15,11 @@ import { identity } from 'fp-ts/lib/function'; import { SavedObjectsFindOptions } from '../../../../../../src/core/server'; import { AuthenticatedUser } from '../../../../security/common/model'; import { UNAUTHENTICATED_USER } from '../../../common/constants'; +import { + SavedNote, + NoteSavedObjectRuntimeType, + NoteSavedObject, +} from '../../../common/types/timeline/note'; import { PageInfoNote, ResponseNote, @@ -23,178 +28,198 @@ import { NoteResult, } from '../../graphql/types'; import { FrameworkRequest } from '../framework'; -import { SavedNote, NoteSavedObjectRuntimeType, NoteSavedObject } from './types'; import { noteSavedObjectType } from './saved_object_mappings'; import { pickSavedTimeline } from '../timeline/pick_saved_timeline'; import { convertSavedObjectToSavedTimeline } from '../timeline/convert_saved_object_to_savedtimeline'; import { timelineSavedObjectType } from '../timeline/saved_object_mappings'; -export class Note { - public async deleteNote(request: FrameworkRequest, noteIds: string[]) { - const savedObjectsClient = request.context.core.savedObjects.client; - - await Promise.all( - noteIds.map(noteId => savedObjectsClient.delete(noteSavedObjectType, noteId)) - ); - } - - public async deleteNoteByTimelineId(request: FrameworkRequest, timelineId: string) { - const options: SavedObjectsFindOptions = { - type: noteSavedObjectType, - search: timelineId, - searchFields: ['timelineId'], - }; - const notesToBeDeleted = await this.getAllSavedNote(request, options); - const savedObjectsClient = request.context.core.savedObjects.client; - - await Promise.all( - notesToBeDeleted.notes.map(note => - savedObjectsClient.delete(noteSavedObjectType, note.noteId) - ) - ); - } - - public async getNote(request: FrameworkRequest, noteId: string): Promise { - return this.getSavedNote(request, noteId); - } - - public async getNotesByEventId( - request: FrameworkRequest, - eventId: string - ): Promise { - const options: SavedObjectsFindOptions = { - type: noteSavedObjectType, - search: eventId, - searchFields: ['eventId'], - }; - const notesByEventId = await this.getAllSavedNote(request, options); - return notesByEventId.notes; - } - - public async getNotesByTimelineId( - request: FrameworkRequest, - timelineId: string - ): Promise { - const options: SavedObjectsFindOptions = { - type: noteSavedObjectType, - search: timelineId, - searchFields: ['timelineId'], - }; - const notesByTimelineId = await this.getAllSavedNote(request, options); - return notesByTimelineId.notes; - } - - public async getAllNotes( +export interface Note { + deleteNote: (request: FrameworkRequest, noteIds: string[]) => Promise; + deleteNoteByTimelineId: (request: FrameworkRequest, noteIds: string) => Promise; + getNote: (request: FrameworkRequest, noteId: string) => Promise; + getNotesByEventId: (request: FrameworkRequest, noteId: string) => Promise; + getNotesByTimelineId: (request: FrameworkRequest, noteId: string) => Promise; + getAllNotes: ( request: FrameworkRequest, pageInfo: PageInfoNote | null, search: string | null, sort: SortNote | null - ): Promise { - const options: SavedObjectsFindOptions = { - type: noteSavedObjectType, - perPage: pageInfo != null ? pageInfo.pageSize : undefined, - page: pageInfo != null ? pageInfo.pageIndex : undefined, - search: search != null ? search : undefined, - searchFields: ['note'], - sortField: sort != null ? sort.sortField : undefined, - sortOrder: sort != null ? sort.sortOrder : undefined, - }; - return this.getAllSavedNote(request, options); - } - - public async persistNote( + ) => Promise; + persistNote: ( request: FrameworkRequest, noteId: string | null, version: string | null, note: SavedNote - ): Promise { - try { - const savedObjectsClient = request.context.core.savedObjects.client; - - if (noteId == null) { - const timelineVersionSavedObject = - note.timelineId == null - ? await (async () => { - const timelineResult = convertSavedObjectToSavedTimeline( - await savedObjectsClient.create( - timelineSavedObjectType, - pickSavedTimeline(null, {}, request.user) - ) - ); - note.timelineId = timelineResult.savedObjectId; - return timelineResult.version; - })() - : null; - - // Create new note - return { - code: 200, - message: 'success', - note: convertSavedObjectToSavedNote( - await savedObjectsClient.create( - noteSavedObjectType, - pickSavedNote(noteId, note, request.user) - ), - timelineVersionSavedObject != null ? timelineVersionSavedObject : undefined - ), - }; - } + ) => Promise; + convertSavedObjectToSavedNote: ( + savedObject: unknown, + timelineVersion?: string | undefined | null + ) => NoteSavedObject; +} + +export const deleteNote = async (request: FrameworkRequest, noteIds: string[]) => { + const savedObjectsClient = request.context.core.savedObjects.client; + + await Promise.all(noteIds.map(noteId => savedObjectsClient.delete(noteSavedObjectType, noteId))); +}; + +export const deleteNoteByTimelineId = async (request: FrameworkRequest, timelineId: string) => { + const options: SavedObjectsFindOptions = { + type: noteSavedObjectType, + search: timelineId, + searchFields: ['timelineId'], + }; + const notesToBeDeleted = await getAllSavedNote(request, options); + const savedObjectsClient = request.context.core.savedObjects.client; + + await Promise.all( + notesToBeDeleted.notes.map(note => savedObjectsClient.delete(noteSavedObjectType, note.noteId)) + ); +}; + +export const getNote = async ( + request: FrameworkRequest, + noteId: string +): Promise => { + return getSavedNote(request, noteId); +}; + +export const getNotesByEventId = async ( + request: FrameworkRequest, + eventId: string +): Promise => { + const options: SavedObjectsFindOptions = { + type: noteSavedObjectType, + search: eventId, + searchFields: ['eventId'], + }; + const notesByEventId = await getAllSavedNote(request, options); + return notesByEventId.notes; +}; + +export const getNotesByTimelineId = async ( + request: FrameworkRequest, + timelineId: string +): Promise => { + const options: SavedObjectsFindOptions = { + type: noteSavedObjectType, + search: timelineId, + searchFields: ['timelineId'], + }; + const notesByTimelineId = await getAllSavedNote(request, options); + return notesByTimelineId.notes; +}; + +export const getAllNotes = async ( + request: FrameworkRequest, + pageInfo: PageInfoNote | null, + search: string | null, + sort: SortNote | null +): Promise => { + const options: SavedObjectsFindOptions = { + type: noteSavedObjectType, + perPage: pageInfo != null ? pageInfo.pageSize : undefined, + page: pageInfo != null ? pageInfo.pageIndex : undefined, + search: search != null ? search : undefined, + searchFields: ['note'], + sortField: sort != null ? sort.sortField : undefined, + sortOrder: sort != null ? sort.sortOrder : undefined, + }; + return getAllSavedNote(request, options); +}; + +export const persistNote = async ( + request: FrameworkRequest, + noteId: string | null, + version: string | null, + note: SavedNote +): Promise => { + try { + const savedObjectsClient = request.context.core.savedObjects.client; - // Update new note + if (noteId == null) { + const timelineVersionSavedObject = + note.timelineId == null + ? await (async () => { + const timelineResult = convertSavedObjectToSavedTimeline( + await savedObjectsClient.create( + timelineSavedObjectType, + pickSavedTimeline(null, {}, request.user) + ) + ); + note.timelineId = timelineResult.savedObjectId; + return timelineResult.version; + })() + : null; - const existingNote = await this.getSavedNote(request, noteId); + // Create new note return { code: 200, message: 'success', note: convertSavedObjectToSavedNote( - await savedObjectsClient.update( + await savedObjectsClient.create( noteSavedObjectType, - noteId, - pickSavedNote(noteId, note, request.user), - { - version: existingNote.version || undefined, - } - ) + pickSavedNote(noteId, note, request.user) + ), + timelineVersionSavedObject != null ? timelineVersionSavedObject : undefined ), }; - } catch (err) { - if (getOr(null, 'output.statusCode', err) === 403) { - const noteToReturn: NoteResult = { - ...note, - noteId: uuid.v1(), - version: '', - timelineId: '', - timelineVersion: '', - }; - return { - code: 403, - message: err.message, - note: noteToReturn, - }; - } - throw err; } - } - private async getSavedNote(request: FrameworkRequest, NoteId: string) { - const savedObjectsClient = request.context.core.savedObjects.client; - const savedObject = await savedObjectsClient.get(noteSavedObjectType, NoteId); - - return convertSavedObjectToSavedNote(savedObject); - } - - private async getAllSavedNote(request: FrameworkRequest, options: SavedObjectsFindOptions) { - const savedObjectsClient = request.context.core.savedObjects.client; - const savedObjects = await savedObjectsClient.find(options); + // Update new note + const existingNote = await getSavedNote(request, noteId); return { - totalCount: savedObjects.total, - notes: savedObjects.saved_objects.map(savedObject => - convertSavedObjectToSavedNote(savedObject) + code: 200, + message: 'success', + note: convertSavedObjectToSavedNote( + await savedObjectsClient.update( + noteSavedObjectType, + noteId, + pickSavedNote(noteId, note, request.user), + { + version: existingNote.version || undefined, + } + ) ), }; + } catch (err) { + if (getOr(null, 'output.statusCode', err) === 403) { + const noteToReturn: NoteResult = { + ...note, + noteId: uuid.v1(), + version: '', + timelineId: '', + timelineVersion: '', + }; + return { + code: 403, + message: err.message, + note: noteToReturn, + }; + } + throw err; } -} +}; + +const getSavedNote = async (request: FrameworkRequest, NoteId: string) => { + const savedObjectsClient = request.context.core.savedObjects.client; + const savedObject = await savedObjectsClient.get(noteSavedObjectType, NoteId); + + return convertSavedObjectToSavedNote(savedObject); +}; + +const getAllSavedNote = async (request: FrameworkRequest, options: SavedObjectsFindOptions) => { + const savedObjectsClient = request.context.core.savedObjects.client; + const savedObjects = await savedObjectsClient.find(options); + + return { + totalCount: savedObjects.total, + notes: savedObjects.saved_objects.map(savedObject => + convertSavedObjectToSavedNote(savedObject) + ), + }; +}; export const convertSavedObjectToSavedNote = ( savedObject: unknown, diff --git a/x-pack/plugins/siem/server/lib/pinned_event/saved_object.ts b/x-pack/plugins/siem/server/lib/pinned_event/saved_object.ts index 1e3a481e17106..c653f23d5c149 100644 --- a/x-pack/plugins/siem/server/lib/pinned_event/saved_object.ts +++ b/x-pack/plugins/siem/server/lib/pinned_event/saved_object.ts @@ -13,174 +13,224 @@ import { identity } from 'fp-ts/lib/function'; import { SavedObjectsFindOptions } from '../../../../../../src/core/server'; import { AuthenticatedUser } from '../../../../security/common/model'; import { UNAUTHENTICATED_USER } from '../../../common/constants'; -import { FrameworkRequest } from '../framework'; import { PinnedEventSavedObject, PinnedEventSavedObjectRuntimeType, SavedPinnedEvent, -} from './types'; +} from '../../../common/types/timeline/pinned_event'; +import { FrameworkRequest } from '../framework'; + import { PageInfoNote, SortNote, PinnedEvent as PinnedEventResponse } from '../../graphql/types'; import { pickSavedTimeline } from '../timeline/pick_saved_timeline'; import { convertSavedObjectToSavedTimeline } from '../timeline/convert_saved_object_to_savedtimeline'; import { pinnedEventSavedObjectType } from './saved_object_mappings'; import { timelineSavedObjectType } from '../timeline/saved_object_mappings'; -export class PinnedEvent { - public async deletePinnedEventOnTimeline(request: FrameworkRequest, pinnedEventIds: string[]) { - const savedObjectsClient = request.context.core.savedObjects.client; - - await Promise.all( - pinnedEventIds.map(pinnedEventId => - savedObjectsClient.delete(pinnedEventSavedObjectType, pinnedEventId) - ) - ); - } +export interface PinnedEvent { + deletePinnedEventOnTimeline: ( + request: FrameworkRequest, + pinnedEventIds: string[] + ) => Promise; - public async deleteAllPinnedEventsOnTimeline(request: FrameworkRequest, timelineId: string) { - const savedObjectsClient = request.context.core.savedObjects.client; - const options: SavedObjectsFindOptions = { - type: pinnedEventSavedObjectType, - search: timelineId, - searchFields: ['timelineId'], - }; - const pinnedEventToBeDeleted = await this.getAllSavedPinnedEvents(request, options); - await Promise.all( - pinnedEventToBeDeleted.map(pinnedEvent => - savedObjectsClient.delete(pinnedEventSavedObjectType, pinnedEvent.pinnedEventId) - ) - ); - } + deleteAllPinnedEventsOnTimeline: (request: FrameworkRequest, timelineId: string) => Promise; - public async getPinnedEvent( + getPinnedEvent: ( request: FrameworkRequest, pinnedEventId: string - ): Promise { - return this.getSavedPinnedEvent(request, pinnedEventId); - } + ) => Promise; - public async getAllPinnedEventsByTimelineId( + getAllPinnedEventsByTimelineId: ( request: FrameworkRequest, timelineId: string - ): Promise { - const options: SavedObjectsFindOptions = { - type: pinnedEventSavedObjectType, - search: timelineId, - searchFields: ['timelineId'], - }; - return this.getAllSavedPinnedEvents(request, options); - } + ) => Promise; - public async getAllPinnedEvents( + getAllPinnedEvents: ( request: FrameworkRequest, pageInfo: PageInfoNote | null, search: string | null, sort: SortNote | null - ): Promise { - const options: SavedObjectsFindOptions = { - type: pinnedEventSavedObjectType, - perPage: pageInfo != null ? pageInfo.pageSize : undefined, - page: pageInfo != null ? pageInfo.pageIndex : undefined, - search: search != null ? search : undefined, - searchFields: ['timelineId', 'eventId'], - sortField: sort != null ? sort.sortField : undefined, - sortOrder: sort != null ? sort.sortOrder : undefined, - }; - return this.getAllSavedPinnedEvents(request, options); - } + ) => Promise; - public async persistPinnedEventOnTimeline( + persistPinnedEventOnTimeline: ( request: FrameworkRequest, pinnedEventId: string | null, // pinned event saved object id eventId: string, timelineId: string | null - ): Promise { - const savedObjectsClient = request.context.core.savedObjects.client; - - try { - if (pinnedEventId == null) { - const timelineVersionSavedObject = - timelineId == null - ? await (async () => { - const timelineResult = convertSavedObjectToSavedTimeline( - await savedObjectsClient.create( - timelineSavedObjectType, - pickSavedTimeline(null, {}, request.user || null) - ) - ); - timelineId = timelineResult.savedObjectId; // eslint-disable-line no-param-reassign - return timelineResult.version; - })() - : null; - - if (timelineId != null) { - const allPinnedEventId = await this.getAllPinnedEventsByTimelineId(request, timelineId); - const isPinnedAlreadyExisting = allPinnedEventId.filter( - pinnedEvent => pinnedEvent.eventId === eventId - ); + ) => Promise; - if (isPinnedAlreadyExisting.length === 0) { - const savedPinnedEvent: SavedPinnedEvent = { - eventId, - timelineId, - }; - // create Pinned Event on Timeline - return convertSavedObjectToSavedPinnedEvent( - await savedObjectsClient.create( - pinnedEventSavedObjectType, - pickSavedPinnedEvent(pinnedEventId, savedPinnedEvent, request.user || null) - ), - timelineVersionSavedObject != null ? timelineVersionSavedObject : undefined - ); - } - return isPinnedAlreadyExisting[0]; + convertSavedObjectToSavedPinnedEvent: ( + savedObject: unknown, + timelineVersion?: string | undefined | null + ) => PinnedEventSavedObject; + + pickSavedPinnedEvent: ( + pinnedEventId: string | null, + savedPinnedEvent: SavedPinnedEvent, + userInfo: AuthenticatedUser | null + ) => // eslint-disable-next-line @typescript-eslint/no-explicit-any + any; +} + +export const deletePinnedEventOnTimeline = async ( + request: FrameworkRequest, + pinnedEventIds: string[] +) => { + const savedObjectsClient = request.context.core.savedObjects.client; + + await Promise.all( + pinnedEventIds.map(pinnedEventId => + savedObjectsClient.delete(pinnedEventSavedObjectType, pinnedEventId) + ) + ); +}; + +export const deleteAllPinnedEventsOnTimeline = async ( + request: FrameworkRequest, + timelineId: string +) => { + const savedObjectsClient = request.context.core.savedObjects.client; + const options: SavedObjectsFindOptions = { + type: pinnedEventSavedObjectType, + search: timelineId, + searchFields: ['timelineId'], + }; + const pinnedEventToBeDeleted = await getAllSavedPinnedEvents(request, options); + await Promise.all( + pinnedEventToBeDeleted.map(pinnedEvent => + savedObjectsClient.delete(pinnedEventSavedObjectType, pinnedEvent.pinnedEventId) + ) + ); +}; + +export const getPinnedEvent = async ( + request: FrameworkRequest, + pinnedEventId: string +): Promise => { + return getSavedPinnedEvent(request, pinnedEventId); +}; + +export const getAllPinnedEventsByTimelineId = async ( + request: FrameworkRequest, + timelineId: string +): Promise => { + const options: SavedObjectsFindOptions = { + type: pinnedEventSavedObjectType, + search: timelineId, + searchFields: ['timelineId'], + }; + return getAllSavedPinnedEvents(request, options); +}; + +export const getAllPinnedEvents = async ( + request: FrameworkRequest, + pageInfo: PageInfoNote | null, + search: string | null, + sort: SortNote | null +): Promise => { + const options: SavedObjectsFindOptions = { + type: pinnedEventSavedObjectType, + perPage: pageInfo != null ? pageInfo.pageSize : undefined, + page: pageInfo != null ? pageInfo.pageIndex : undefined, + search: search != null ? search : undefined, + searchFields: ['timelineId', 'eventId'], + sortField: sort != null ? sort.sortField : undefined, + sortOrder: sort != null ? sort.sortOrder : undefined, + }; + return getAllSavedPinnedEvents(request, options); +}; + +export const persistPinnedEventOnTimeline = async ( + request: FrameworkRequest, + pinnedEventId: string | null, // pinned event saved object id + eventId: string, + timelineId: string | null +): Promise => { + const savedObjectsClient = request.context.core.savedObjects.client; + + try { + if (pinnedEventId == null) { + const timelineVersionSavedObject = + timelineId == null + ? await (async () => { + const timelineResult = convertSavedObjectToSavedTimeline( + await savedObjectsClient.create( + timelineSavedObjectType, + pickSavedTimeline(null, {}, request.user || null) + ) + ); + timelineId = timelineResult.savedObjectId; // eslint-disable-line no-param-reassign + return timelineResult.version; + })() + : null; + + if (timelineId != null) { + const allPinnedEventId = await getAllPinnedEventsByTimelineId(request, timelineId); + const isPinnedAlreadyExisting = allPinnedEventId.filter( + pinnedEvent => pinnedEvent.eventId === eventId + ); + + if (isPinnedAlreadyExisting.length === 0) { + const savedPinnedEvent: SavedPinnedEvent = { + eventId, + timelineId, + }; + // create Pinned Event on Timeline + return convertSavedObjectToSavedPinnedEvent( + await savedObjectsClient.create( + pinnedEventSavedObjectType, + pickSavedPinnedEvent(pinnedEventId, savedPinnedEvent, request.user || null) + ), + timelineVersionSavedObject != null ? timelineVersionSavedObject : undefined + ); } - throw new Error('You can NOT pinned event without a timelineID'); + return isPinnedAlreadyExisting[0]; } - // Delete Pinned Event on Timeline - await this.deletePinnedEventOnTimeline(request, [pinnedEventId]); + throw new Error('You can NOT pinned event without a timelineID'); + } + // Delete Pinned Event on Timeline + await deletePinnedEventOnTimeline(request, [pinnedEventId]); + return null; + } catch (err) { + if (getOr(null, 'output.statusCode', err) === 404) { + /* + * Why we are doing that, because if it is not found for sure that it will be unpinned + * There is no need to bring back this error since we can assume that it is unpinned + */ return null; - } catch (err) { - if (getOr(null, 'output.statusCode', err) === 404) { - /* - * Why we are doing that, because if it is not found for sure that it will be unpinned - * There is no need to bring back this error since we can assume that it is unpinned - */ - return null; - } - if (getOr(null, 'output.statusCode', err) === 403) { - return pinnedEventId != null - ? { - code: 403, - message: err.message, - pinnedEventId: eventId, - timelineId: '', - timelineVersion: '', - } - : null; - } - throw err; } + if (getOr(null, 'output.statusCode', err) === 403) { + return pinnedEventId != null + ? { + code: 403, + message: err.message, + pinnedEventId: eventId, + timelineId: '', + timelineVersion: '', + } + : null; + } + throw err; } +}; - private async getSavedPinnedEvent(request: FrameworkRequest, pinnedEventId: string) { - const savedObjectsClient = request.context.core.savedObjects.client; - const savedObject = await savedObjectsClient.get(pinnedEventSavedObjectType, pinnedEventId); +const getSavedPinnedEvent = async (request: FrameworkRequest, pinnedEventId: string) => { + const savedObjectsClient = request.context.core.savedObjects.client; + const savedObject = await savedObjectsClient.get(pinnedEventSavedObjectType, pinnedEventId); - return convertSavedObjectToSavedPinnedEvent(savedObject); - } + return convertSavedObjectToSavedPinnedEvent(savedObject); +}; - private async getAllSavedPinnedEvents( - request: FrameworkRequest, - options: SavedObjectsFindOptions - ) { - const savedObjectsClient = request.context.core.savedObjects.client; - const savedObjects = await savedObjectsClient.find(options); - - return savedObjects.saved_objects.map(savedObject => - convertSavedObjectToSavedPinnedEvent(savedObject) - ); - } -} +const getAllSavedPinnedEvents = async ( + request: FrameworkRequest, + options: SavedObjectsFindOptions +) => { + const savedObjectsClient = request.context.core.savedObjects.client; + const savedObjects = await savedObjectsClient.find(options); + + return savedObjects.saved_objects.map(savedObject => + convertSavedObjectToSavedPinnedEvent(savedObject) + ); +}; export const convertSavedObjectToSavedPinnedEvent = ( savedObject: unknown, diff --git a/x-pack/plugins/siem/server/lib/timeline/convert_saved_object_to_savedtimeline.ts b/x-pack/plugins/siem/server/lib/timeline/convert_saved_object_to_savedtimeline.ts index ea5db565483c8..bde24a338ec84 100644 --- a/x-pack/plugins/siem/server/lib/timeline/convert_saved_object_to_savedtimeline.ts +++ b/x-pack/plugins/siem/server/lib/timeline/convert_saved_object_to_savedtimeline.ts @@ -8,16 +8,21 @@ import { failure } from 'io-ts/lib/PathReporter'; import { pipe } from 'fp-ts/lib/pipeable'; import { map, fold } from 'fp-ts/lib/Either'; import { identity } from 'fp-ts/lib/function'; -import { TimelineSavedObjectRuntimeType, TimelineSavedObject } from './types'; +import { + TimelineSavedObjectRuntimeType, + TimelineSavedObject, +} from '../../../common/types/timeline'; export const convertSavedObjectToSavedTimeline = (savedObject: unknown): TimelineSavedObject => { const timeline = pipe( TimelineSavedObjectRuntimeType.decode(savedObject), - map(savedTimeline => ({ - savedObjectId: savedTimeline.id, - version: savedTimeline.version, - ...savedTimeline.attributes, - })), + map(savedTimeline => { + return { + savedObjectId: savedTimeline.id, + version: savedTimeline.version, + ...savedTimeline.attributes, + }; + }), fold(errors => { throw new Error(failure(errors).join('\n')); }, identity) diff --git a/x-pack/plugins/siem/server/lib/timeline/create_timelines_stream_from_ndjson.ts b/x-pack/plugins/siem/server/lib/timeline/create_timelines_stream_from_ndjson.ts index abe8de9bf5b94..6b4017b5e4d5c 100644 --- a/x-pack/plugins/siem/server/lib/timeline/create_timelines_stream_from_ndjson.ts +++ b/x-pack/plugins/siem/server/lib/timeline/create_timelines_stream_from_ndjson.ts @@ -22,6 +22,7 @@ import { import { ImportTimelineResponse } from './routes/utils/import_timelines'; import { ImportTimelinesSchemaRt } from './routes/schemas/import_timelines_schema'; +import { BadRequestError } from '../detection_engine/errors/bad_request_error'; type ErrorFactory = (message: string) => Error; @@ -38,8 +39,11 @@ export const decodeOrThrow = ( pipe(runtimeType.decode(inputValue), fold(throwErrors(createError), identity)); export const validateTimelines = (): Transform => - createMapStream((obj: ImportTimelineResponse) => decodeOrThrow(ImportTimelinesSchemaRt)(obj)); - + createMapStream((obj: ImportTimelineResponse) => + obj instanceof Error + ? new BadRequestError(obj.message) + : decodeOrThrow(ImportTimelinesSchemaRt)(obj) + ); export const createTimelinesStreamFromNdJson = (ruleLimit: number) => { return [ createSplitStream('\n'), diff --git a/x-pack/plugins/siem/server/lib/timeline/pick_saved_timeline.ts b/x-pack/plugins/siem/server/lib/timeline/pick_saved_timeline.ts index 19adb7ac1045a..eeded1cc2532d 100644 --- a/x-pack/plugins/siem/server/lib/timeline/pick_saved_timeline.ts +++ b/x-pack/plugins/siem/server/lib/timeline/pick_saved_timeline.ts @@ -4,9 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ +import uuid from 'uuid'; import { AuthenticatedUser } from '../../../../security/common/model'; import { UNAUTHENTICATED_USER } from '../../../common/constants'; -import { SavedTimeline } from './types'; +import { SavedTimeline, TimelineType } from '../../../common/types/timeline'; export const pickSavedTimeline = ( timelineId: string | null, @@ -24,5 +25,21 @@ export const pickSavedTimeline = ( savedTimeline.updated = dateNow; savedTimeline.updatedBy = userInfo?.username ?? UNAUTHENTICATED_USER; } + + if (savedTimeline.timelineType === TimelineType.template) { + savedTimeline.timelineType = TimelineType.template; + if (savedTimeline.templateTimelineId == null) { + savedTimeline.templateTimelineId = uuid.v4(); + } + + if (savedTimeline.templateTimelineVersion == null) { + savedTimeline.templateTimelineVersion = 1; + } + } else { + savedTimeline.timelineType = TimelineType.default; + savedTimeline.templateTimelineId = null; + savedTimeline.templateTimelineVersion = null; + } + return savedTimeline; }; diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/README.md b/x-pack/plugins/siem/server/lib/timeline/routes/README.md new file mode 100644 index 0000000000000..2c5547e39fc4e --- /dev/null +++ b/x-pack/plugins/siem/server/lib/timeline/routes/README.md @@ -0,0 +1,326 @@ +**Timeline apis** + + 1. Create timeline api + 2. Update timeline api + 3. Create template timeline api + 4. Update template timeline api + + +## Create timeline api +#### POST /api/timeline +##### Authorization +Type: Basic Auth +username: Your Kibana username +password: Your Kibana password + + +##### Request header +``` +Content-Type: application/json +kbn-version: 8.0.0 +``` +##### Request body +```json +{ + "timeline": { + "columns": [ + { + "columnHeaderType": "not-filtered", + "id": "@timestamp" + }, + { + "columnHeaderType": "not-filtered", + "id": "message" + }, + { + "columnHeaderType": "not-filtered", + "id": "event.category" + }, + { + "columnHeaderType": "not-filtered", + "id": "event.action" + }, + { + "columnHeaderType": "not-filtered", + "id": "host.name" + }, + { + "columnHeaderType": "not-filtered", + "id": "source.ip" + }, + { + "columnHeaderType": "not-filtered", + "id": "destination.ip" + }, + { + "columnHeaderType": "not-filtered", + "id": "user.name" + } + ], + "dataProviders": [], + "description": "", + "eventType": "all", + "filters": [], + "kqlMode": "filter", + "kqlQuery": { + "filterQuery": null + }, + "title": "abd", + "dateRange": { + "start": 1587370079200, + "end": 1587456479201 + }, + "savedQueryId": null, + "sort": { + "columnId": "@timestamp", + "sortDirection": "desc" + } + }, + "timelineId":null, // Leave this as null + "version":null // Leave this as null +} +``` + + +## Update timeline api +#### PATCH /api/timeline +##### Authorization +Type: Basic Auth +username: Your Kibana username +password: Your Kibana password + + +##### Request header +``` +Content-Type: application/json +kbn-version: 8.0.0 +``` +##### Request body +```json +{ + "timeline": { + "columns": [ + { + "columnHeaderType": "not-filtered", + "id": "@timestamp" + }, + { + "columnHeaderType": "not-filtered", + "id": "message" + }, + { + "columnHeaderType": "not-filtered", + "id": "event.category" + }, + { + "columnHeaderType": "not-filtered", + "id": "event.action" + }, + { + "columnHeaderType": "not-filtered", + "id": "host.name" + }, + { + "columnHeaderType": "not-filtered", + "id": "source.ip" + }, + { + "columnHeaderType": "not-filtered", + "id": "destination.ip" + }, + { + "columnHeaderType": "not-filtered", + "id": "user.name" + } + ], + "dataProviders": [], + "description": "", + "eventType": "all", + "filters": [], + "kqlMode": "filter", + "kqlQuery": { + "filterQuery": null + }, + "title": "abd", + "dateRange": { + "start": 1587370079200, + "end": 1587456479201 + }, + "savedQueryId": null, + "sort": { + "columnId": "@timestamp", + "sortDirection": "desc" + }, + "created": 1587468588922, + "createdBy": "casetester", + "updated": 1587468588922, + "updatedBy": "casetester", + "timelineType": "default" + }, + "timelineId":"68ea5330-83c3-11ea-bff9-ab01dd7cb6cc", // Have to match the existing timeline savedObject id + "version":"WzYwLDFd" // Have to match the existing timeline version +} +``` + +## Create template timeline api +#### POST /api/timeline +##### Authorization +Type: Basic Auth +username: Your Kibana username +password: Your Kibana password + + +##### Request header +``` +Content-Type: application/json +kbn-version: 8.0.0 +``` +##### Request body +```json +{ + "timeline": { + "columns": [ + { + "columnHeaderType": "not-filtered", + "id": "@timestamp" + }, + { + "columnHeaderType": "not-filtered", + "id": "message" + }, + { + "columnHeaderType": "not-filtered", + "id": "event.category" + }, + { + "columnHeaderType": "not-filtered", + "id": "event.action" + }, + { + "columnHeaderType": "not-filtered", + "id": "host.name" + }, + { + "columnHeaderType": "not-filtered", + "id": "source.ip" + }, + { + "columnHeaderType": "not-filtered", + "id": "destination.ip" + }, + { + "columnHeaderType": "not-filtered", + "id": "user.name" + } + ], + "dataProviders": [ + + ], + "description": "", + "eventType": "all", + "filters": [ + + ], + "kqlMode": "filter", + "kqlQuery": { + "filterQuery": null + }, + "title": "abd", + "dateRange": { + "start": 1587370079200, + "end": 1587456479201 + }, + "savedQueryId": null, + "sort": { + "columnId": "@timestamp", + "sortDirection": "desc" + }, + "timelineType": "template" // This is the difference between create timeline + }, + "timelineId":null, // Leave this as null + "version":null // Leave this as null +} +``` + + +## Update template timeline api +#### PATCH /api/timeline +##### Authorization +Type: Basic Auth +username: Your Kibana username +password: Your Kibana password + + +##### Request header +``` +Content-Type: application/json +kbn-version: 8.0.0 +``` +##### Request body +```json +{ + "timeline": { + "columns": [ + { + "columnHeaderType": "not-filtered", + "id": "@timestamp" + }, + { + "columnHeaderType": "not-filtered", + "id": "message" + }, + { + "columnHeaderType": "not-filtered", + "id": "event.category" + }, + { + "columnHeaderType": "not-filtered", + "id": "event.action" + }, + { + "columnHeaderType": "not-filtered", + "id": "host.name" + }, + { + "columnHeaderType": "not-filtered", + "id": "source.ip" + }, + { + "columnHeaderType": "not-filtered", + "id": "destination.ip" + }, + { + "columnHeaderType": "not-filtered", + "id": "user.name" + } + ], + "dataProviders": [], + "description": "", + "eventType": "all", + "filters": [], + "kqlMode": "filter", + "kqlQuery": { + "filterQuery": null + }, + "title": "abd", + "dateRange": { + "start": 1587370079200, + "end": 1587456479201 + }, + "savedQueryId": null, + "sort": { + "columnId": "@timestamp", + "sortDirection": "desc" + }, + "timelineType": "template", + "created": 1587473119992, + "createdBy": "casetester", + "updated": 1587473119992, + "updatedBy": "casetester", + "templateTimelineId": "745d0316-6af7-43bf-afd6-9747119754fb", // Please provide the existing template timeline version + "templateTimelineVersion": 2 // Please provide a template timeline version grater than existing one + }, + "timelineId":"f5a4bd10-83cd-11ea-bf78-0547a65f1281", // This is a must as well + "version":"Wzg2LDFd" // Please provide the existing timeline version +} +``` \ No newline at end of file diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/__mocks__/import_timelines.ts b/x-pack/plugins/siem/server/lib/timeline/routes/__mocks__/import_timelines.ts index 686f2b491cf88..a832c818d48b0 100644 --- a/x-pack/plugins/siem/server/lib/timeline/routes/__mocks__/import_timelines.ts +++ b/x-pack/plugins/siem/server/lib/timeline/routes/__mocks__/import_timelines.ts @@ -5,6 +5,7 @@ */ import { omit } from 'lodash/fp'; +import { TimelineType } from '../../../../../common/types/timeline'; export const mockDuplicateIdErrors = []; @@ -148,6 +149,13 @@ export const mockGetTimelineValue = { pinnedEventIds: ['k-gi8nABm-sIqJ_scOoS'], }; +export const mockGetTemplateTimelineValue = { + ...mockGetTimelineValue, + timelineType: TimelineType.template, + templateTimelineId: '79deb4c0-6bc1-11ea-a90b-f5341fb7a189', + templateTimelineVersion: 1, +}; + export const mockParsedTimelineObject = omit( [ 'globalNotes', diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/__mocks__/request_responses.ts b/x-pack/plugins/siem/server/lib/timeline/routes/__mocks__/request_responses.ts index a83c443773302..304ca309775ff 100644 --- a/x-pack/plugins/siem/server/lib/timeline/routes/__mocks__/request_responses.ts +++ b/x-pack/plugins/siem/server/lib/timeline/routes/__mocks__/request_responses.ts @@ -3,10 +3,18 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - -import { TIMELINE_EXPORT_URL, TIMELINE_IMPORT_URL } from '../../../../../common/constants'; -import { requestMock } from '../../../detection_engine/routes/__mocks__'; +import * as rt from 'io-ts'; +import { + TIMELINE_EXPORT_URL, + TIMELINE_IMPORT_URL, + TIMELINE_URL, +} from '../../../../../common/constants'; import stream from 'stream'; +import { requestMock } from '../../../detection_engine/routes/__mocks__'; +import { SavedTimeline, TimelineType } from '../../../../../common/types/timeline'; +import { updateTimelineSchema } from '../schemas/update_timelines_schema'; +import { createTimelineSchema } from '../schemas/create_timelines_schema'; + const readable = new stream.Readable(); export const getExportTimelinesRequest = () => requestMock.create({ @@ -31,6 +39,96 @@ export const getImportTimelinesRequest = (filename?: string) => }, }); +export const inputTimeline: SavedTimeline = { + columns: [ + { columnHeaderType: 'not-filtered', id: '@timestamp' }, + { columnHeaderType: 'not-filtered', id: 'message' }, + { columnHeaderType: 'not-filtered', id: 'event.category' }, + { columnHeaderType: 'not-filtered', id: 'event.action' }, + { columnHeaderType: 'not-filtered', id: 'host.name' }, + { columnHeaderType: 'not-filtered', id: 'source.ip' }, + { columnHeaderType: 'not-filtered', id: 'destination.ip' }, + { columnHeaderType: 'not-filtered', id: 'user.name' }, + ], + dataProviders: [], + description: '', + eventType: 'all', + filters: [], + kqlMode: 'filter', + kqlQuery: { filterQuery: null }, + title: 't', + timelineType: TimelineType.default, + templateTimelineId: null, + templateTimelineVersion: null, + dateRange: { start: 1585227005527, end: 1585313405527 }, + savedQueryId: null, + sort: { columnId: '@timestamp', sortDirection: 'desc' }, +}; + +export const inputTemplateTimeline = { + ...inputTimeline, + timelineType: TimelineType.template, + templateTimelineId: null, + templateTimelineVersion: null, +}; + +export const createTimelineWithoutTimelineId = { + templateTimelineId: null, + timeline: inputTimeline, + timelineId: null, + version: null, + timelineType: TimelineType.default, +}; + +export const createTemplateTimelineWithoutTimelineId = { + templateTimelineId: null, + timeline: inputTemplateTimeline, + timelineId: null, + version: null, + timelineType: TimelineType.template, +}; + +export const createTimelineWithTimelineId = { + ...createTimelineWithoutTimelineId, + timelineId: '79deb4c0-6bc1-11ea-a90b-f5341fb7a189', +}; + +export const createTemplateTimelineWithTimelineId = { + ...createTemplateTimelineWithoutTimelineId, + timelineId: '79deb4c0-6bc1-11ea-a90b-f5341fb7a189', + templateTimelineId: 'existing template timeline id', +}; + +export const updateTimelineWithTimelineId = { + timeline: inputTimeline, + timelineId: '79deb4c0-6bc1-11ea-a90b-f5341fb7a189', + version: 'WzEyMjUsMV0=', +}; + +export const updateTemplateTimelineWithTimelineId = { + timeline: { + ...inputTemplateTimeline, + templateTimelineId: '79deb4c0-6bc1-11ea-a90b-f5341fb7a189', + templateTimelineVersion: 2, + }, + timelineId: '79deb4c0-6bc1-11ea-a90b-f5341fb7a189', + version: 'WzEyMjUsMV0=', +}; + +export const getCreateTimelinesRequest = (mockBody: rt.TypeOf) => + requestMock.create({ + method: 'post', + path: TIMELINE_URL, + body: mockBody, + }); + +export const getUpdateTimelinesRequest = (mockBody: rt.TypeOf) => + requestMock.create({ + method: 'patch', + path: TIMELINE_URL, + body: mockBody, + }); + export const getImportTimelinesRequestEnableOverwrite = (filename?: string) => requestMock.create({ method: 'post', diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/create_timelines_route.test.ts b/x-pack/plugins/siem/server/lib/timeline/routes/create_timelines_route.test.ts new file mode 100644 index 0000000000000..70ee1532395a5 --- /dev/null +++ b/x-pack/plugins/siem/server/lib/timeline/routes/create_timelines_route.test.ts @@ -0,0 +1,272 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { SecurityPluginSetup } from '../../../../../../plugins/security/server'; + +import { + serverMock, + requestContextMock, + createMockConfig, +} from '../../detection_engine/routes/__mocks__'; + +import { + mockGetCurrentUser, + mockGetTimelineValue, + mockGetTemplateTimelineValue, +} from './__mocks__/import_timelines'; +import { + getCreateTimelinesRequest, + inputTimeline, + createTimelineWithoutTimelineId, + createTimelineWithTimelineId, + createTemplateTimelineWithoutTimelineId, + createTemplateTimelineWithTimelineId, +} from './__mocks__/request_responses'; +import { + CREATE_TEMPLATE_TIMELINE_ERROR_MESSAGE, + CREATE_TIMELINE_ERROR_MESSAGE, +} from './utils/create_timelines'; + +describe('create timelines', () => { + let server: ReturnType; + let securitySetup: SecurityPluginSetup; + let { context } = requestContextMock.createTools(); + let mockGetTimeline: jest.Mock; + let mockPersistTimeline: jest.Mock; + let mockPersistPinnedEventOnTimeline: jest.Mock; + let mockPersistNote: jest.Mock; + + beforeEach(() => { + jest.resetModules(); + jest.resetAllMocks(); + jest.restoreAllMocks(); + jest.clearAllMocks(); + + server = serverMock.create(); + context = requestContextMock.createTools().context; + + securitySetup = ({ + authc: { + getCurrentUser: jest.fn().mockReturnValue(mockGetCurrentUser), + }, + authz: {}, + } as unknown) as SecurityPluginSetup; + + mockGetTimeline = jest.fn(); + mockPersistTimeline = jest.fn(); + mockPersistPinnedEventOnTimeline = jest.fn(); + mockPersistNote = jest.fn(); + }); + + describe('Manipulate timeline', () => { + describe('Create a new timeline', () => { + beforeEach(async () => { + jest.doMock('../saved_object', () => { + return { + getTimeline: mockGetTimeline.mockReturnValue(null), + persistTimeline: mockPersistTimeline.mockReturnValue({ + timeline: createTimelineWithTimelineId, + }), + }; + }); + + jest.doMock('../../pinned_event/saved_object', () => { + return { + persistPinnedEventOnTimeline: mockPersistPinnedEventOnTimeline, + }; + }); + + jest.doMock('../../note/saved_object', () => { + return { + persistNote: mockPersistNote, + }; + }); + + const createTimelinesRoute = jest.requireActual('./create_timelines_route') + .createTimelinesRoute; + createTimelinesRoute(server.router, createMockConfig(), securitySetup); + + const mockRequest = getCreateTimelinesRequest(createTimelineWithoutTimelineId); + await server.inject(mockRequest, context); + }); + + test('should Create a new timeline savedObject', async () => { + expect(mockPersistTimeline).toHaveBeenCalled(); + }); + + test('should Create a new timeline savedObject without timelineId', async () => { + expect(mockPersistTimeline.mock.calls[0][1]).toBeNull(); + }); + + test('should Create a new timeline savedObject without timeline version', async () => { + expect(mockPersistTimeline.mock.calls[0][2]).toBeNull(); + }); + + test('should Create a new timeline savedObject witn given timeline', async () => { + expect(mockPersistTimeline.mock.calls[0][3]).toEqual(inputTimeline); + }); + + test('should NOT Create new pinned events', async () => { + expect(mockPersistPinnedEventOnTimeline).not.toBeCalled(); + }); + + test('should NOT Create notes', async () => { + expect(mockPersistNote).not.toBeCalled(); + }); + + test('returns 200 when create timeline successfully', async () => { + const response = await server.inject( + getCreateTimelinesRequest(createTimelineWithoutTimelineId), + context + ); + expect(response.status).toEqual(200); + }); + }); + + describe('Import a timeline already exist', () => { + beforeEach(() => { + jest.doMock('../saved_object', () => { + return { + getTimeline: mockGetTimeline.mockReturnValue(mockGetTimelineValue), + persistTimeline: mockPersistTimeline, + }; + }); + + jest.doMock('../../pinned_event/saved_object', () => { + return { + persistPinnedEventOnTimeline: mockPersistPinnedEventOnTimeline, + }; + }); + + jest.doMock('../../note/saved_object', () => { + return { + persistNote: mockPersistNote, + }; + }); + + const createTimelinesRoute = jest.requireActual('./create_timelines_route') + .createTimelinesRoute; + createTimelinesRoute(server.router, createMockConfig(), securitySetup); + }); + + test('returns error message', async () => { + const response = await server.inject( + getCreateTimelinesRequest(createTimelineWithTimelineId), + context + ); + expect(response.body).toEqual({ + message: CREATE_TIMELINE_ERROR_MESSAGE, + status_code: 405, + }); + }); + }); + }); + + describe('Manipulate template timeline', () => { + describe('Create a new template timeline', () => { + beforeEach(async () => { + jest.doMock('../saved_object', () => { + return { + getTimeline: mockGetTimeline.mockReturnValue(null), + persistTimeline: mockPersistTimeline.mockReturnValue({ + timeline: createTemplateTimelineWithTimelineId, + }), + }; + }); + + jest.doMock('../../pinned_event/saved_object', () => { + return { + persistPinnedEventOnTimeline: mockPersistPinnedEventOnTimeline, + }; + }); + + jest.doMock('../../note/saved_object', () => { + return { + persistNote: mockPersistNote, + }; + }); + + const createTimelinesRoute = jest.requireActual('./create_timelines_route') + .createTimelinesRoute; + createTimelinesRoute(server.router, createMockConfig(), securitySetup); + + const mockRequest = getCreateTimelinesRequest(createTemplateTimelineWithoutTimelineId); + await server.inject(mockRequest, context); + }); + + test('should Create a new template timeline savedObject', async () => { + expect(mockPersistTimeline).toHaveBeenCalled(); + }); + + test('should Create a new template timeline savedObject without timelineId', async () => { + expect(mockPersistTimeline.mock.calls[0][1]).toBeNull(); + }); + + test('should Create a new template timeline savedObject without template timeline version', async () => { + expect(mockPersistTimeline.mock.calls[0][2]).toBeNull(); + }); + + test('should Create a new template timeline savedObject witn given template timeline', async () => { + expect(mockPersistTimeline.mock.calls[0][3]).toEqual( + createTemplateTimelineWithTimelineId.timeline + ); + }); + + test('should NOT Create new pinned events', async () => { + expect(mockPersistPinnedEventOnTimeline).not.toBeCalled(); + }); + + test('should NOT Create notes', async () => { + expect(mockPersistNote).not.toBeCalled(); + }); + + test('returns 200 when create timeline successfully', async () => { + const response = await server.inject( + getCreateTimelinesRequest(createTimelineWithoutTimelineId), + context + ); + expect(response.status).toEqual(200); + }); + }); + + describe('Import a template timeline already exist', () => { + beforeEach(() => { + jest.doMock('../saved_object', () => { + return { + getTimeline: mockGetTimeline.mockReturnValue(mockGetTemplateTimelineValue), + persistTimeline: mockPersistTimeline, + }; + }); + + jest.doMock('../../pinned_event/saved_object', () => { + return { + persistPinnedEventOnTimeline: mockPersistPinnedEventOnTimeline, + }; + }); + + jest.doMock('../../note/saved_object', () => { + return { + persistNote: mockPersistNote, + }; + }); + + const createTimelinesRoute = jest.requireActual('./create_timelines_route') + .createTimelinesRoute; + createTimelinesRoute(server.router, createMockConfig(), securitySetup); + }); + + test('returns error message', async () => { + const response = await server.inject( + getCreateTimelinesRequest(createTemplateTimelineWithTimelineId), + context + ); + expect(response.body).toEqual({ + message: CREATE_TEMPLATE_TIMELINE_ERROR_MESSAGE, + status_code: 405, + }); + }); + }); + }); +}); diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/create_timelines_route.ts b/x-pack/plugins/siem/server/lib/timeline/routes/create_timelines_route.ts new file mode 100644 index 0000000000000..c456ae31fb7da --- /dev/null +++ b/x-pack/plugins/siem/server/lib/timeline/routes/create_timelines_route.ts @@ -0,0 +1,90 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { IRouter } from '../../../../../../../src/core/server'; + +import { TIMELINE_URL } from '../../../../common/constants'; +import { TimelineType } from '../../../../common/types/timeline'; + +import { ConfigType } from '../../..'; +import { SetupPlugins } from '../../../plugin'; +import { buildRouteValidation } from '../../../utils/build_validation/route_validation'; + +import { transformError, buildSiemResponse } from '../../detection_engine/routes/utils'; + +import { createTimelineSchema } from './schemas/create_timelines_schema'; +import { buildFrameworkRequest } from './utils/common'; +import { + createTimelines, + getTimeline, + getTemplateTimeline, + CREATE_TEMPLATE_TIMELINE_ERROR_MESSAGE, + CREATE_TIMELINE_ERROR_MESSAGE, +} from './utils/create_timelines'; + +export const createTimelinesRoute = ( + router: IRouter, + config: ConfigType, + security: SetupPlugins['security'] +) => { + router.post( + { + path: TIMELINE_URL, + validate: { + body: buildRouteValidation(createTimelineSchema), + }, + options: { + tags: ['access:siem'], + }, + }, + async (context, request, response) => { + const siemResponse = buildSiemResponse(response); + + try { + const frameworkRequest = await buildFrameworkRequest(context, security, request); + + const { timelineId, timeline, version } = request.body; + const { templateTimelineId, timelineType } = timeline; + const isHandlingTemplateTimeline = timelineType === TimelineType.template; + + const existTimeline = + timelineId != null ? await getTimeline(frameworkRequest, timelineId) : null; + const existTemplateTimeline = + templateTimelineId != null + ? await getTemplateTimeline(frameworkRequest, templateTimelineId) + : null; + + if ( + (!isHandlingTemplateTimeline && existTimeline != null) || + (isHandlingTemplateTimeline && (existTemplateTimeline != null || existTimeline != null)) + ) { + return siemResponse.error({ + body: isHandlingTemplateTimeline + ? CREATE_TEMPLATE_TIMELINE_ERROR_MESSAGE + : CREATE_TIMELINE_ERROR_MESSAGE, + statusCode: 405, + }); + } + + // Create timeline + const newTimeline = await createTimelines(frameworkRequest, timeline, null, version); + return response.ok({ + body: { + data: { + persistTimeline: newTimeline, + }, + }, + }); + } catch (err) { + const error = transformError(err); + + return siemResponse.error({ + body: error.message, + statusCode: error.statusCode, + }); + } + } + ); +}; diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/import_timelines_route.test.ts b/x-pack/plugins/siem/server/lib/timeline/routes/import_timelines_route.test.ts index 9f41943cfa27f..56c152d02ae98 100644 --- a/x-pack/plugins/siem/server/lib/timeline/routes/import_timelines_route.test.ts +++ b/x-pack/plugins/siem/server/lib/timeline/routes/import_timelines_route.test.ts @@ -6,13 +6,13 @@ import { getImportTimelinesRequest } from './__mocks__/request_responses'; import { - createMockConfig, serverMock, requestContextMock, requestMock, + createMockConfig, } from '../../detection_engine/routes/__mocks__'; import { TIMELINE_EXPORT_URL } from '../../../../common/constants'; -import { SecurityPluginSetup } from '../../../../../security/server'; +import { SecurityPluginSetup } from '../../../../../../plugins/security/server'; import { mockUniqueParsedObjects, @@ -24,7 +24,6 @@ import { } from './__mocks__/import_timelines'; describe('import timelines', () => { - let config: ReturnType; let server: ReturnType; let request: ReturnType; let securitySetup: SecurityPluginSetup; @@ -43,7 +42,6 @@ describe('import timelines', () => { server = serverMock.create(); context = requestContextMock.createTools().context; - config = createMockConfig(); securitySetup = ({ authc: { @@ -84,40 +82,28 @@ describe('import timelines', () => { beforeEach(() => { jest.doMock('../saved_object', () => { return { - Timeline: jest.fn().mockImplementation(() => { - return { - getTimeline: mockGetTimeline.mockReturnValue(null), - persistTimeline: mockPersistTimeline.mockReturnValue({ - timeline: { savedObjectId: newTimelineSavedObjectId, version: newTimelineVersion }, - }), - }; + getTimeline: mockGetTimeline.mockReturnValue(null), + persistTimeline: mockPersistTimeline.mockReturnValue({ + timeline: { savedObjectId: newTimelineSavedObjectId, version: newTimelineVersion }, }), }; }); jest.doMock('../../pinned_event/saved_object', () => { return { - PinnedEvent: jest.fn().mockImplementation(() => { - return { - persistPinnedEventOnTimeline: mockPersistPinnedEventOnTimeline, - }; - }), + persistPinnedEventOnTimeline: mockPersistPinnedEventOnTimeline, }; }); jest.doMock('../../note/saved_object', () => { return { - Note: jest.fn().mockImplementation(() => { - return { - persistNote: mockPersistNote, - }; - }), + persistNote: mockPersistNote, }; }); const importTimelinesRoute = jest.requireActual('./import_timelines_route') .importTimelinesRoute; - importTimelinesRoute(server.router, config, securitySetup); + importTimelinesRoute(server.router, createMockConfig(), securitySetup); }); test('should use given timelineId to check if the timeline savedObject already exist', async () => { @@ -230,38 +216,26 @@ describe('import timelines', () => { beforeEach(() => { jest.doMock('../saved_object', () => { return { - Timeline: jest.fn().mockImplementation(() => { - return { - getTimeline: mockGetTimeline.mockReturnValue(mockGetTimelineValue), - persistTimeline: mockPersistTimeline, - }; - }), + getTimeline: mockGetTimeline.mockReturnValue(mockGetTimelineValue), + persistTimeline: mockPersistTimeline, }; }); jest.doMock('../../pinned_event/saved_object', () => { return { - PinnedEvent: jest.fn().mockImplementation(() => { - return { - persistPinnedEventOnTimeline: mockPersistPinnedEventOnTimeline, - }; - }), + persistPinnedEventOnTimeline: mockPersistPinnedEventOnTimeline, }; }); jest.doMock('../../note/saved_object', () => { return { - Note: jest.fn().mockImplementation(() => { - return { - persistNote: mockPersistNote, - }; - }), + persistNote: mockPersistNote, }; }); const importTimelinesRoute = jest.requireActual('./import_timelines_route') .importTimelinesRoute; - importTimelinesRoute(server.router, config, securitySetup); + importTimelinesRoute(server.router, createMockConfig(), securitySetup); }); test('returns error message', async () => { @@ -286,36 +260,24 @@ describe('import timelines', () => { beforeEach(() => { jest.doMock('../saved_object', () => { return { - Timeline: jest.fn().mockImplementation(() => { - return { - getTimeline: mockGetTimeline.mockReturnValue(null), - persistTimeline: mockPersistTimeline.mockReturnValue({ - timeline: { savedObjectId: '79deb4c0-6bc1-11ea-9999-f5341fb7a189' }, - }), - }; + getTimeline: mockGetTimeline.mockReturnValue(null), + persistTimeline: mockPersistTimeline.mockReturnValue({ + timeline: { savedObjectId: '79deb4c0-6bc1-11ea-9999-f5341fb7a189' }, }), }; }); jest.doMock('../../pinned_event/saved_object', () => { return { - PinnedEvent: jest.fn().mockImplementation(() => { - return { - persistPinnedEventOnTimeline: mockPersistPinnedEventOnTimeline.mockReturnValue( - new Error('Test error') - ), - }; - }), + persistPinnedEventOnTimeline: mockPersistPinnedEventOnTimeline.mockReturnValue( + new Error('Test error') + ), }; }); jest.doMock('../../note/saved_object', () => { return { - Note: jest.fn().mockImplementation(() => { - return { - persistNote: mockPersistNote, - }; - }), + persistNote: mockPersistNote, }; }); }); @@ -328,11 +290,14 @@ describe('import timelines', () => { const importTimelinesRoute = jest.requireActual('./import_timelines_route') .importTimelinesRoute; - importTimelinesRoute(server.router, config, securitySetup); + importTimelinesRoute(server.router, createMockConfig(), securitySetup); const result = server.validate(request); expect(result.badRequest).toHaveBeenCalledWith( - 'Invalid value "undefined" supplied to "file",Invalid value "undefined" supplied to "file"' + [ + 'Invalid value "undefined" supplied to "file"', + 'Invalid value "undefined" supplied to "file"', + ].join(',') ); }); }); diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/import_timelines_route.ts b/x-pack/plugins/siem/server/lib/timeline/routes/import_timelines_route.ts index 9d148abf82cdd..bff89bdf9b5b2 100644 --- a/x-pack/plugins/siem/server/lib/timeline/routes/import_timelines_route.ts +++ b/x-pack/plugins/siem/server/lib/timeline/routes/import_timelines_route.ts @@ -5,9 +5,19 @@ */ import { extname } from 'path'; -import { chunk, omit, set } from 'lodash/fp'; +import { chunk, omit } from 'lodash/fp'; + +import { createPromiseFromStreams } from '../../../../../../../src/legacy/utils'; +import { IRouter } from '../../../../../../../src/core/server'; import { TIMELINE_IMPORT_URL } from '../../../../common/constants'; + +import { SetupPlugins } from '../../../plugin'; +import { ConfigType } from '../../../config'; +import { buildRouteValidation } from '../../../utils/build_validation/route_validation'; + +import { importRulesSchema } from '../../detection_engine/routes/schemas/response/import_rules_schema'; +import { validate } from '../../detection_engine/routes/rules/validate'; import { buildSiemResponse, createBulkErrorObject, @@ -16,32 +26,22 @@ import { } from '../../detection_engine/routes/utils'; import { createTimelinesStreamFromNdJson } from '../create_timelines_stream_from_ndjson'; -import { createPromiseFromStreams } from '../../../../../../../src/legacy/utils'; +import { ImportTimelinesPayloadSchemaRt } from './schemas/import_timelines_schema'; +import { buildFrameworkRequest } from './utils/common'; import { - createTimelines, getTupleDuplicateErrorsAndUniqueTimeline, isBulkError, isImportRegular, ImportTimelineResponse, ImportTimelinesSchema, PromiseFromStreams, + timelineSavedObjectOmittedFields, } from './utils/import_timelines'; +import { createTimelines, getTimeline } from './utils/create_timelines'; -import { IRouter } from '../../../../../../../src/core/server'; -import { SetupPlugins } from '../../../plugin'; -import { ImportTimelinesPayloadSchemaRt } from './schemas/import_timelines_schema'; -import { importRulesSchema } from '../../detection_engine/routes/schemas/response/import_rules_schema'; -import { ConfigType } from '../../../config'; - -import { Timeline } from '../saved_object'; -import { validate } from '../../detection_engine/routes/rules/validate'; -import { FrameworkRequest } from '../../framework'; -import { buildRouteValidation } from '../../../utils/build_validation/route_validation'; const CHUNK_PARSED_OBJECT_SIZE = 10; -const timelineLib = new Timeline(); - export const importTimelinesRoute = ( router: IRouter, config: ConfigType, @@ -95,9 +95,7 @@ export const importTimelinesRoute = ( const chunkParseObjects = chunk(CHUNK_PARSED_OBJECT_SIZE, uniqueParsedObjects); let importTimelineResponse: ImportTimelineResponse[] = []; - const user = await security?.authc.getCurrentUser(request); - let frameworkRequest = set('context.core.savedObjects.client', savedObjectsClient, request); - frameworkRequest = set('user', user, frameworkRequest); + const frameworkRequest = await buildFrameworkRequest(context, security, request); while (chunkParseObjects.length) { const batchParseObjects = chunkParseObjects.shift() ?? []; @@ -125,32 +123,16 @@ export const importTimelinesRoute = ( eventNotes, } = parsedTimeline; const parsedTimelineObject = omit( - [ - 'globalNotes', - 'eventNotes', - 'pinnedEventIds', - 'version', - 'savedObjectId', - 'created', - 'createdBy', - 'updated', - 'updatedBy', - ], + timelineSavedObjectOmittedFields, parsedTimeline ); + let newTimeline = null; try { - let timeline = null; - try { - timeline = await timelineLib.getTimeline( - (frameworkRequest as unknown) as FrameworkRequest, - savedObjectId - ); - // eslint-disable-next-line no-empty - } catch (e) {} + const timeline = await getTimeline(frameworkRequest, savedObjectId); if (timeline == null) { - const newSavedObjectId = await createTimelines( - (frameworkRequest as unknown) as FrameworkRequest, + newTimeline = await createTimelines( + frameworkRequest, parsedTimelineObject, null, // timelineSavedObjectId null, // timelineVersion @@ -159,7 +141,10 @@ export const importTimelinesRoute = ( [] // existing note ids ); - resolve({ timeline_id: newSavedObjectId, status_code: 200 }); + resolve({ + timeline_id: newTimeline.timeline.savedObjectId, + status_code: 200, + }); } else { resolve( createBulkErrorObject({ diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/schemas/create_timelines_schema.ts b/x-pack/plugins/siem/server/lib/timeline/routes/schemas/create_timelines_schema.ts new file mode 100644 index 0000000000000..241d266a14c78 --- /dev/null +++ b/x-pack/plugins/siem/server/lib/timeline/routes/schemas/create_timelines_schema.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import * as rt from 'io-ts'; + +import { SavedTimelineRuntimeType } from '../../../../../common/types/timeline'; +import { unionWithNullType } from '../../../../../common/utility_types'; + +export const createTimelineSchema = rt.intersection([ + rt.type({ + timeline: SavedTimelineRuntimeType, + }), + rt.partial({ + timelineId: unionWithNullType(rt.string), + version: unionWithNullType(rt.string), + }), +]); diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/schemas/import_timelines_schema.ts b/x-pack/plugins/siem/server/lib/timeline/routes/schemas/import_timelines_schema.ts index 056fdaf0d2515..3b340b1c15359 100644 --- a/x-pack/plugins/siem/server/lib/timeline/routes/schemas/import_timelines_schema.ts +++ b/x-pack/plugins/siem/server/lib/timeline/routes/schemas/import_timelines_schema.ts @@ -7,14 +7,17 @@ import * as rt from 'io-ts'; import { Readable } from 'stream'; import { either } from 'fp-ts/lib/Either'; + +import { SavedTimelineRuntimeType } from '../../../../../common/types/timeline'; + import { eventNotes, globalNotes, pinnedEventIds } from './schemas'; -import { SavedTimelineRuntimeType } from '../../types'; +import { unionWithNullType } from '../../../../../common/utility_types'; export const ImportTimelinesSchemaRt = rt.intersection([ SavedTimelineRuntimeType, rt.type({ - savedObjectId: rt.string, - version: rt.string, + savedObjectId: unionWithNullType(rt.string), + version: unionWithNullType(rt.string), }), rt.type({ globalNotes, diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/schemas/schemas.ts b/x-pack/plugins/siem/server/lib/timeline/routes/schemas/schemas.ts index 71627363ef0f8..1fd3a3554dc15 100644 --- a/x-pack/plugins/siem/server/lib/timeline/routes/schemas/schemas.ts +++ b/x-pack/plugins/siem/server/lib/timeline/routes/schemas/schemas.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ import * as runtimeTypes from 'io-ts'; -import { unionWithNullType } from '../../../framework'; -import { SavedNoteRuntimeType } from '../../../note/types'; +import { unionWithNullType } from '../../../../../common/utility_types'; +import { SavedNoteRuntimeType } from '../../../../../common/types/timeline/note'; -export const eventNotes = runtimeTypes.array(unionWithNullType(SavedNoteRuntimeType)); -export const globalNotes = runtimeTypes.array(unionWithNullType(SavedNoteRuntimeType)); -export const pinnedEventIds = runtimeTypes.array(unionWithNullType(runtimeTypes.string)); +export const eventNotes = unionWithNullType(runtimeTypes.array(SavedNoteRuntimeType)); +export const globalNotes = unionWithNullType(runtimeTypes.array(SavedNoteRuntimeType)); +export const pinnedEventIds = unionWithNullType(runtimeTypes.array(runtimeTypes.string)); diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/schemas/update_timelines_schema.ts b/x-pack/plugins/siem/server/lib/timeline/routes/schemas/update_timelines_schema.ts new file mode 100644 index 0000000000000..43f4208947aa5 --- /dev/null +++ b/x-pack/plugins/siem/server/lib/timeline/routes/schemas/update_timelines_schema.ts @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import * as rt from 'io-ts'; + +import { SavedTimelineRuntimeType } from '../../../../../common/types/timeline'; +import { unionWithNullType } from '../../../../../common/utility_types'; + +export const updateTimelineSchema = rt.type({ + timeline: SavedTimelineRuntimeType, + timelineId: unionWithNullType(rt.string), + version: unionWithNullType(rt.string), +}); diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/update_timelines_route.test.ts b/x-pack/plugins/siem/server/lib/timeline/routes/update_timelines_route.test.ts new file mode 100644 index 0000000000000..9c47488d47159 --- /dev/null +++ b/x-pack/plugins/siem/server/lib/timeline/routes/update_timelines_route.test.ts @@ -0,0 +1,288 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { SecurityPluginSetup } from '../../../../../../plugins/security/server'; + +import { + serverMock, + requestContextMock, + createMockConfig, +} from '../../detection_engine/routes/__mocks__'; + +import { + getUpdateTimelinesRequest, + inputTimeline, + updateTimelineWithTimelineId, + updateTemplateTimelineWithTimelineId, +} from './__mocks__/request_responses'; +import { + mockGetCurrentUser, + mockGetTimelineValue, + mockGetTemplateTimelineValue, +} from './__mocks__/import_timelines'; +import { + UPDATE_TIMELINE_ERROR_MESSAGE, + UPDATE_TEMPLATE_TIMELINE_ERROR_MESSAGE, +} from './utils/update_timelines'; + +describe('update timelines', () => { + let server: ReturnType; + let securitySetup: SecurityPluginSetup; + let { context } = requestContextMock.createTools(); + let mockGetTimeline: jest.Mock; + let mockGetTemplateTimeline: jest.Mock; + let mockPersistTimeline: jest.Mock; + let mockPersistPinnedEventOnTimeline: jest.Mock; + let mockPersistNote: jest.Mock; + + beforeEach(() => { + jest.resetModules(); + jest.resetAllMocks(); + jest.restoreAllMocks(); + jest.clearAllMocks(); + + server = serverMock.create(); + context = requestContextMock.createTools().context; + + securitySetup = ({ + authc: { + getCurrentUser: jest.fn().mockReturnValue(mockGetCurrentUser), + }, + authz: {}, + } as unknown) as SecurityPluginSetup; + + mockGetTimeline = jest.fn(); + mockGetTemplateTimeline = jest.fn(); + mockPersistTimeline = jest.fn(); + mockPersistPinnedEventOnTimeline = jest.fn(); + mockPersistNote = jest.fn(); + }); + + describe('Manipulate timeline', () => { + describe('Update an existing timeline', () => { + beforeEach(async () => { + jest.doMock('../saved_object', () => { + return { + getTimeline: mockGetTimeline.mockReturnValue(mockGetTimelineValue), + persistTimeline: mockPersistTimeline.mockReturnValue({ + timeline: updateTimelineWithTimelineId.timeline, + }), + }; + }); + + jest.doMock('../../pinned_event/saved_object', () => { + return { + persistPinnedEventOnTimeline: mockPersistPinnedEventOnTimeline, + }; + }); + + jest.doMock('../../note/saved_object', () => { + return { + persistNote: mockPersistNote, + }; + }); + + const updateTimelinesRoute = jest.requireActual('./update_timelines_route') + .updateTimelinesRoute; + updateTimelinesRoute(server.router, createMockConfig(), securitySetup); + + const mockRequest = getUpdateTimelinesRequest(updateTimelineWithTimelineId); + await server.inject(mockRequest, context); + }); + + test('should Check a if given timeline id exist', async () => { + expect(mockGetTimeline.mock.calls[0][1]).toEqual(updateTimelineWithTimelineId.timelineId); + }); + + test('should Update existing timeline savedObject with timelineId', async () => { + expect(mockPersistTimeline.mock.calls[0][1]).toEqual( + updateTimelineWithTimelineId.timelineId + ); + }); + + test('should Update existing timeline savedObject with timeline version', async () => { + expect(mockPersistTimeline.mock.calls[0][2]).toEqual(updateTimelineWithTimelineId.version); + }); + + test('should Update existing timeline savedObject witn given timeline', async () => { + expect(mockPersistTimeline.mock.calls[0][3]).toEqual(inputTimeline); + }); + + test('should NOT Update new pinned events', async () => { + expect(mockPersistPinnedEventOnTimeline).not.toBeCalled(); + }); + + test('should NOT Update notes', async () => { + expect(mockPersistNote).not.toBeCalled(); + }); + + test('returns 200 when create timeline successfully', async () => { + const response = await server.inject( + getUpdateTimelinesRequest(updateTimelineWithTimelineId), + context + ); + expect(response.status).toEqual(200); + }); + }); + + describe("Update a timeline that doesn't exist", () => { + beforeEach(() => { + jest.doMock('../saved_object', () => { + return { + getTimeline: mockGetTimeline.mockReturnValue(null), + getTimelineByTemplateTimelineId: mockGetTemplateTimeline.mockReturnValue(null), + persistTimeline: mockPersistTimeline, + }; + }); + + jest.doMock('../../pinned_event/saved_object', () => { + return { + persistPinnedEventOnTimeline: mockPersistPinnedEventOnTimeline, + }; + }); + + jest.doMock('../../note/saved_object', () => { + return { + persistNote: mockPersistNote, + }; + }); + + const updateTimelinesRoute = jest.requireActual('./update_timelines_route') + .updateTimelinesRoute; + updateTimelinesRoute(server.router, createMockConfig(), securitySetup); + }); + + test('returns error message', async () => { + const response = await server.inject( + getUpdateTimelinesRequest(updateTimelineWithTimelineId), + context + ); + expect(response.body).toEqual({ + message: UPDATE_TIMELINE_ERROR_MESSAGE, + status_code: 405, + }); + }); + }); + }); + + describe('Manipulate template timeline', () => { + describe('Update an existing template timeline', () => { + beforeEach(async () => { + jest.doMock('../saved_object', () => { + return { + getTimeline: mockGetTimeline.mockReturnValue(mockGetTemplateTimelineValue), + getTimelineByTemplateTimelineId: mockGetTemplateTimeline.mockReturnValue({ + timeline: [mockGetTemplateTimelineValue], + }), + persistTimeline: mockPersistTimeline.mockReturnValue({ + timeline: updateTimelineWithTimelineId.timeline, + }), + }; + }); + + jest.doMock('../../pinned_event/saved_object', () => { + return { + persistPinnedEventOnTimeline: mockPersistPinnedEventOnTimeline, + }; + }); + + jest.doMock('../../note/saved_object', () => { + return { + persistNote: mockPersistNote, + }; + }); + + const updateTimelinesRoute = jest.requireActual('./update_timelines_route') + .updateTimelinesRoute; + updateTimelinesRoute(server.router, createMockConfig(), securitySetup); + + const mockRequest = getUpdateTimelinesRequest(updateTemplateTimelineWithTimelineId); + await server.inject(mockRequest, context); + }); + + test('should Check if given timeline id exist', async () => { + expect(mockGetTimeline.mock.calls[0][1]).toEqual( + updateTemplateTimelineWithTimelineId.timelineId + ); + }); + + test('should Update existing template timeline with template timelineId', async () => { + expect(mockGetTemplateTimeline.mock.calls[0][1]).toEqual( + updateTemplateTimelineWithTimelineId.timelineId + ); + }); + + test('should Update existing template timeline with timeline version', async () => { + expect(mockPersistTimeline.mock.calls[0][2]).toEqual( + updateTemplateTimelineWithTimelineId.version + ); + }); + + test('should Update existing template timeline witn given timeline', async () => { + expect(mockPersistTimeline.mock.calls[0][3]).toEqual( + updateTemplateTimelineWithTimelineId.timeline + ); + }); + + test('should NOT Update new pinned events', async () => { + expect(mockPersistPinnedEventOnTimeline).not.toBeCalled(); + }); + + test('should NOT Update notes', async () => { + expect(mockPersistNote).not.toBeCalled(); + }); + + test('returns 200 when create template timeline successfully', async () => { + const response = await server.inject( + getUpdateTimelinesRequest(updateTemplateTimelineWithTimelineId), + context + ); + expect(response.status).toEqual(200); + }); + }); + + describe("Update a template timeline that doesn't exist", () => { + beforeEach(() => { + jest.doMock('../saved_object', () => { + return { + getTimeline: mockGetTimeline.mockReturnValue(null), + getTimelineByTemplateTimelineId: mockGetTemplateTimeline.mockReturnValue({ + timeline: [], + }), + persistTimeline: mockPersistTimeline, + }; + }); + + jest.doMock('../../pinned_event/saved_object', () => { + return { + persistPinnedEventOnTimeline: mockPersistPinnedEventOnTimeline, + }; + }); + + jest.doMock('../../note/saved_object', () => { + return { + persistNote: mockPersistNote, + }; + }); + + const updateTimelinesRoute = jest.requireActual('./update_timelines_route') + .updateTimelinesRoute; + updateTimelinesRoute(server.router, createMockConfig(), securitySetup); + }); + + test('returns error message', async () => { + const response = await server.inject( + getUpdateTimelinesRequest(updateTemplateTimelineWithTimelineId), + context + ); + expect(response.body).toEqual({ + message: UPDATE_TEMPLATE_TIMELINE_ERROR_MESSAGE, + status_code: 405, + }); + }); + }); + }); +}); diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/update_timelines_route.ts b/x-pack/plugins/siem/server/lib/timeline/routes/update_timelines_route.ts new file mode 100644 index 0000000000000..a0f3d11a1533d --- /dev/null +++ b/x-pack/plugins/siem/server/lib/timeline/routes/update_timelines_route.ts @@ -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; + * you may not use this file except in compliance with the Elastic License. + */ + +import { IRouter } from '../../../../../../../src/core/server'; + +import { TIMELINE_URL } from '../../../../common/constants'; +import { TimelineType } from '../../../../common/types/timeline'; + +import { SetupPlugins } from '../../../plugin'; +import { buildRouteValidation } from '../../../utils/build_validation/route_validation'; +import { ConfigType } from '../../..'; + +import { transformError, buildSiemResponse } from '../../detection_engine/routes/utils'; +import { FrameworkRequest } from '../../framework'; + +import { updateTimelineSchema } from './schemas/update_timelines_schema'; +import { buildFrameworkRequest } from './utils/common'; +import { createTimelines, getTimeline, getTemplateTimeline } from './utils/create_timelines'; +import { checkIsFailureCases } from './utils/update_timelines'; + +export const updateTimelinesRoute = ( + router: IRouter, + config: ConfigType, + security: SetupPlugins['security'] +) => { + router.patch( + { + path: TIMELINE_URL, + validate: { + body: buildRouteValidation(updateTimelineSchema), + }, + options: { + tags: ['access:siem'], + }, + }, + // eslint-disable-next-line complexity + async (context, request, response) => { + const siemResponse = buildSiemResponse(response); + + try { + const frameworkRequest = await buildFrameworkRequest(context, security, request); + const { timelineId, timeline, version } = request.body; + const { templateTimelineId, templateTimelineVersion, timelineType } = timeline; + const isHandlingTemplateTimeline = timelineType === TimelineType.template; + const existTimeline = + timelineId != null ? await getTimeline(frameworkRequest, timelineId) : null; + + const existTemplateTimeline = + templateTimelineId != null + ? await getTemplateTimeline(frameworkRequest, templateTimelineId) + : null; + const errorObj = checkIsFailureCases( + isHandlingTemplateTimeline, + version, + templateTimelineVersion ?? null, + existTimeline, + existTemplateTimeline + ); + if (errorObj != null) { + return siemResponse.error(errorObj); + } + const updatedTimeline = await createTimelines( + (frameworkRequest as unknown) as FrameworkRequest, + timeline, + timelineId, + version + ); + return response.ok({ + body: { + data: { + persistTimeline: updatedTimeline, + }, + }, + }); + } catch (err) { + const error = transformError(err); + return siemResponse.error({ + body: error.message, + statusCode: error.statusCode, + }); + } + } + ); +}; diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/utils/common.ts b/x-pack/plugins/siem/server/lib/timeline/routes/utils/common.ts new file mode 100644 index 0000000000000..1036a74b74a03 --- /dev/null +++ b/x-pack/plugins/siem/server/lib/timeline/routes/utils/common.ts @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { set } from 'lodash/fp'; + +import { SetupPlugins } from '../../../../plugin'; +import { KibanaRequest } from '../../../../../../../../src/core/server'; +import { RequestHandlerContext } from '../../../../../../../../target/types/core/server'; +import { FrameworkRequest } from '../../../framework'; + +export const buildFrameworkRequest = async ( + context: RequestHandlerContext, + security: SetupPlugins['security'], + request: KibanaRequest +): Promise => { + const savedObjectsClient = context.core.savedObjects.client; + const user = await security?.authc.getCurrentUser(request); + + return set( + 'user', + user, + set( + 'context.core.savedObjects.client', + savedObjectsClient, + request + ) + ); +}; diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/utils/create_timelines.ts b/x-pack/plugins/siem/server/lib/timeline/routes/utils/create_timelines.ts new file mode 100644 index 0000000000000..2c67a514cdf97 --- /dev/null +++ b/x-pack/plugins/siem/server/lib/timeline/routes/utils/create_timelines.ts @@ -0,0 +1,150 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { isEmpty } from 'lodash/fp'; + +import * as timelineLib from '../../saved_object'; +import * as pinnedEventLib from '../../../pinned_event/saved_object'; +import * as noteLib from '../../../note/saved_object'; +import { FrameworkRequest } from '../../../framework'; +import { SavedTimeline, TimelineSavedObject } from '../../../../../common/types/timeline'; +import { SavedNote } from '../../../../../common/types/timeline/note'; +import { NoteResult, ResponseTimeline } from '../../../../graphql/types'; +export const CREATE_TIMELINE_ERROR_MESSAGE = + 'UPDATE timeline with POST is not allowed, please use PATCH instead'; +export const CREATE_TEMPLATE_TIMELINE_ERROR_MESSAGE = + 'UPDATE template timeline with POST is not allowed, please use PATCH instead'; + +export const saveTimelines = ( + frameworkRequest: FrameworkRequest, + timeline: SavedTimeline, + timelineSavedObjectId?: string | null, + timelineVersion?: string | null +): Promise => { + return timelineLib.persistTimeline( + frameworkRequest, + timelineSavedObjectId ?? null, + timelineVersion ?? null, + timeline + ); +}; + +export const savePinnedEvents = ( + frameworkRequest: FrameworkRequest, + timelineSavedObjectId: string, + pinnedEventIds: string[] +) => + Promise.all( + pinnedEventIds.map(eventId => + pinnedEventLib.persistPinnedEventOnTimeline( + frameworkRequest, + null, // pinnedEventSavedObjectId + eventId, + timelineSavedObjectId + ) + ) + ); + +export const saveNotes = ( + frameworkRequest: FrameworkRequest, + timelineSavedObjectId: string, + timelineVersion?: string | null, + existingNoteIds?: string[], + newNotes?: NoteResult[] +) => { + return Promise.all( + newNotes?.map(note => { + const newNote: SavedNote = { + eventId: note.eventId, + note: note.note, + timelineId: timelineSavedObjectId, + }; + + return noteLib.persistNote( + frameworkRequest, + existingNoteIds?.find(nId => nId === note.noteId) ?? null, + timelineVersion ?? null, + newNote + ); + }) ?? [] + ); +}; + +export const createTimelines = async ( + frameworkRequest: FrameworkRequest, + timeline: SavedTimeline, + timelineSavedObjectId?: string | null, + timelineVersion?: string | null, + pinnedEventIds?: string[] | null, + notes?: NoteResult[], + existingNoteIds?: string[] +): Promise => { + const responseTimeline = await saveTimelines( + frameworkRequest, + timeline, + timelineSavedObjectId, + timelineVersion + ); + const newTimelineSavedObjectId = responseTimeline.timeline.savedObjectId; + const newTimelineVersion = responseTimeline.timeline.version; + + let myPromises: unknown[] = []; + if (pinnedEventIds != null && !isEmpty(pinnedEventIds)) { + myPromises = [ + ...myPromises, + savePinnedEvents( + frameworkRequest, + timelineSavedObjectId ?? newTimelineSavedObjectId, + pinnedEventIds + ), + ]; + } + if (!isEmpty(notes)) { + myPromises = [ + ...myPromises, + saveNotes( + frameworkRequest, + timelineSavedObjectId ?? newTimelineSavedObjectId, + newTimelineVersion, + existingNoteIds, + notes + ), + ]; + } + + if (myPromises.length > 0) { + await Promise.all(myPromises); + } + + return responseTimeline; +}; + +export const getTimeline = async ( + frameworkRequest: FrameworkRequest, + savedObjectId: string +): Promise => { + let timeline = null; + try { + timeline = await timelineLib.getTimeline(frameworkRequest, savedObjectId); + // eslint-disable-next-line no-empty + } catch (e) {} + return timeline; +}; + +export const getTemplateTimeline = async ( + frameworkRequest: FrameworkRequest, + templateTimelineId: string +): Promise => { + let templateTimeline = null; + try { + templateTimeline = await timelineLib.getTimelineByTemplateTimelineId( + frameworkRequest, + templateTimelineId + ); + } catch (e) { + return null; + } + return templateTimeline.timeline[0]; +}; diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/utils/export_timelines.ts b/x-pack/plugins/siem/server/lib/timeline/routes/utils/export_timelines.ts index 677891fa16c02..ea9a5fab66805 100644 --- a/x-pack/plugins/siem/server/lib/timeline/routes/utils/export_timelines.ts +++ b/x-pack/plugins/siem/server/lib/timeline/routes/utils/export_timelines.ts @@ -4,13 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { NoteSavedObject } from '../../../note/types'; -import { PinnedEventSavedObject } from '../../../pinned_event/types'; -import { convertSavedObjectToSavedTimeline } from '../../convert_saved_object_to_savedtimeline'; - -import { convertSavedObjectToSavedPinnedEvent } from '../../../pinned_event/saved_object'; -import { convertSavedObjectToSavedNote } from '../../../note/saved_object'; - import { SavedObjectsClient, SavedObjectsFindOptions, @@ -22,11 +15,20 @@ import { ExportTimelineSavedObjectsClient, ExportedNotes, TimelineSavedObject, -} from '../../types'; + ExportTimelineNotFoundError, +} from '../../../../../common/types/timeline'; +import { NoteSavedObject } from '../../../../../common/types/timeline/note'; +import { PinnedEventSavedObject } from '../../../../../common/types/timeline/pinned_event'; + import { transformDataToNdjson } from '../../../../utils/read_stream/create_stream_from_ndjson'; + +import { convertSavedObjectToSavedPinnedEvent } from '../../../pinned_event/saved_object'; +import { convertSavedObjectToSavedNote } from '../../../note/saved_object'; import { pinnedEventSavedObjectType } from '../../../pinned_event/saved_object_mappings'; import { noteSavedObjectType } from '../../../note/saved_object_mappings'; + import { timelineSavedObjectType } from '../../saved_object_mappings'; +import { convertSavedObjectToSavedTimeline } from '../../convert_saved_object_to_savedtimeline'; export type TimelineSavedObjectsClient = Pick< SavedObjectsClient, @@ -126,12 +128,23 @@ const getTimelines = async ( ) ); - const timelineObjects: TimelineSavedObject[] | undefined = - savedObjects != null - ? savedObjects.saved_objects.map((savedObject: unknown) => { - return convertSavedObjectToSavedTimeline(savedObject); - }) - : []; + const timelineObjects: { + timelines: TimelineSavedObject[]; + errors: ExportTimelineNotFoundError[]; + } = savedObjects.saved_objects.reduce( + (acc, savedObject) => { + return savedObject.error == null + ? { + errors: acc.errors, + timelines: [...acc.timelines, convertSavedObjectToSavedTimeline(savedObject)], + } + : { errors: [...acc.errors, savedObject.error], timelines: acc.timelines }; + }, + { + timelines: [] as TimelineSavedObject[], + errors: [] as ExportTimelineNotFoundError[], + } + ); return timelineObjects; }; @@ -139,12 +152,8 @@ const getTimelines = async ( const getTimelinesFromObjects = async ( savedObjectsClient: ExportTimelineSavedObjectsClient, ids: string[] -): Promise => { - const timelines: TimelineSavedObject[] = await getTimelines(savedObjectsClient, ids); - // To Do for feature freeze - // if (timelines.length !== request.body.ids.length) { - // //figure out which is missing to tell user - // } +): Promise> => { + const { timelines, errors } = await getTimelines(savedObjectsClient, ids); const [notes, pinnedEventIds] = await Promise.all([ Promise.all(ids.map(timelineId => getNotesByTimelineId(savedObjectsClient, timelineId))), @@ -178,7 +187,7 @@ const getTimelinesFromObjects = async ( return acc; }, []); - return myResponse ?? []; + return [...myResponse, ...errors] ?? []; }; export const getExportTimelineByObjectIds = async ({ diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/utils/import_timelines.ts b/x-pack/plugins/siem/server/lib/timeline/routes/utils/import_timelines.ts index f69a715f9b2c9..9e120cdc023dc 100644 --- a/x-pack/plugins/siem/server/lib/timeline/routes/utils/import_timelines.ts +++ b/x-pack/plugins/siem/server/lib/timeline/routes/utils/import_timelines.ts @@ -7,20 +7,10 @@ import uuid from 'uuid'; import { has } from 'lodash/fp'; import { createBulkErrorObject, BulkError } from '../../../detection_engine/routes/utils'; -import { PinnedEvent } from '../../../pinned_event/saved_object'; -import { Note } from '../../../note/saved_object'; - -import { Timeline } from '../../saved_object'; -import { SavedTimeline } from '../../types'; -import { FrameworkRequest } from '../../../framework'; -import { SavedNote } from '../../../note/types'; +import { SavedTimeline } from '../../../../../common/types/timeline'; import { NoteResult } from '../../../../graphql/types'; import { HapiReadableStream } from '../../../detection_engine/rules/types'; -const pinnedEventLib = new PinnedEvent(); -const timelineLib = new Timeline(); -const noteLib = new Note(); - export interface ImportTimelinesSchema { success: boolean; success_count: number; @@ -84,100 +74,6 @@ export const getTupleDuplicateErrorsAndUniqueTimeline = ( return [Array.from(errors.values()), Array.from(timelinesAcc.values())]; }; -export const saveTimelines = async ( - frameworkRequest: FrameworkRequest, - timeline: SavedTimeline, - timelineSavedObjectId?: string | null, - timelineVersion?: string | null -) => { - const newTimelineRes = await timelineLib.persistTimeline( - frameworkRequest, - timelineSavedObjectId ?? null, - timelineVersion ?? null, - timeline - ); - - return { - newTimelineSavedObjectId: newTimelineRes?.timeline?.savedObjectId ?? null, - newTimelineVersion: newTimelineRes?.timeline?.version ?? null, - }; -}; - -export const savePinnedEvents = ( - frameworkRequest: FrameworkRequest, - timelineSavedObjectId: string, - pinnedEventIds?: string[] | null -) => { - return ( - pinnedEventIds?.map(eventId => { - return pinnedEventLib.persistPinnedEventOnTimeline( - frameworkRequest, - null, // pinnedEventSavedObjectId - eventId, - timelineSavedObjectId - ); - }) ?? [] - ); -}; - -export const saveNotes = ( - frameworkRequest: FrameworkRequest, - timelineSavedObjectId: string, - timelineVersion?: string | null, - existingNoteIds?: string[], - newNotes?: NoteResult[] -) => { - return Promise.all( - newNotes?.map(note => { - const newNote: SavedNote = { - eventId: note.eventId, - note: note.note, - timelineId: timelineSavedObjectId, - }; - - return noteLib.persistNote( - frameworkRequest, - existingNoteIds?.find(nId => nId === note.noteId) ?? null, - timelineVersion ?? null, - newNote - ); - }) ?? [] - ); -}; - -export const createTimelines = async ( - frameworkRequest: FrameworkRequest, - timeline: SavedTimeline, - timelineSavedObjectId?: string | null, - timelineVersion?: string | null, - pinnedEventIds?: string[] | null, - notes?: NoteResult[], - existingNoteIds?: string[] -) => { - const { newTimelineSavedObjectId, newTimelineVersion } = await saveTimelines( - frameworkRequest, - timeline, - timelineSavedObjectId, - timelineVersion - ); - await Promise.all([ - savePinnedEvents( - frameworkRequest, - timelineSavedObjectId ?? newTimelineSavedObjectId, - pinnedEventIds - ), - saveNotes( - frameworkRequest, - timelineSavedObjectId ?? newTimelineSavedObjectId, - newTimelineVersion, - existingNoteIds, - notes - ), - ]); - - return newTimelineSavedObjectId; -}; - export const isImportRegular = ( importTimelineResponse: ImportTimelineResponse ): importTimelineResponse is ImportRegular => { @@ -189,3 +85,15 @@ export const isBulkError = ( ): importRuleResponse is BulkError => { return has('error', importRuleResponse); }; + +export const timelineSavedObjectOmittedFields = [ + 'globalNotes', + 'eventNotes', + 'pinnedEventIds', + 'version', + 'savedObjectId', + 'created', + 'createdBy', + 'updated', + 'updatedBy', +]; diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/utils/update_timelines.ts b/x-pack/plugins/siem/server/lib/timeline/routes/utils/update_timelines.ts new file mode 100644 index 0000000000000..6a25d8def9116 --- /dev/null +++ b/x-pack/plugins/siem/server/lib/timeline/routes/utils/update_timelines.ts @@ -0,0 +1,81 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { TimelineSavedObject } from '../../../../../common/types/timeline'; + +export const UPDATE_TIMELINE_ERROR_MESSAGE = + 'CREATE timeline with PATCH is not allowed, please use POST instead'; +export const UPDATE_TEMPLATE_TIMELINE_ERROR_MESSAGE = + 'CREATE template timeline with PATCH is not allowed, please use POST instead'; +export const NO_MATCH_VERSION_ERROR_MESSAGE = + 'TimelineVersion conflict: The given version doesn not match with existing timeline'; +export const NO_MATCH_ID_ERROR_MESSAGE = + "Timeline id doesn't match with existing template timeline"; +export const OLDER_VERSION_ERROR_MESSAGE = + 'Template timelineVersion conflict: The given version is older then existing version'; + +export const checkIsFailureCases = ( + isHandlingTemplateTimeline: boolean, + version: string | null, + templateTimelineVersion: number | null, + existTimeline: TimelineSavedObject | null, + existTemplateTimeline: TimelineSavedObject | null +) => { + if (!isHandlingTemplateTimeline && existTimeline == null) { + return { + body: UPDATE_TIMELINE_ERROR_MESSAGE, + statusCode: 405, + }; + } else if (isHandlingTemplateTimeline && existTemplateTimeline == null) { + // Throw error to create template timeline in patch + return { + body: UPDATE_TEMPLATE_TIMELINE_ERROR_MESSAGE, + statusCode: 405, + }; + } else if ( + isHandlingTemplateTimeline && + existTimeline != null && + existTemplateTimeline != null && + existTimeline.savedObjectId !== existTemplateTimeline.savedObjectId + ) { + // Throw error you can not have a no matching between your timeline and your template timeline during an update + return { + body: NO_MATCH_ID_ERROR_MESSAGE, + statusCode: 409, + }; + } else if (!isHandlingTemplateTimeline && existTimeline?.version !== version) { + // throw error 409 conflict timeline + return { + body: NO_MATCH_VERSION_ERROR_MESSAGE, + statusCode: 409, + }; + } else if ( + isHandlingTemplateTimeline && + existTemplateTimeline != null && + existTemplateTimeline.templateTimelineVersion == null && + existTemplateTimeline.version !== version + ) { + // throw error 409 conflict timeline + return { + body: NO_MATCH_VERSION_ERROR_MESSAGE, + statusCode: 409, + }; + } else if ( + isHandlingTemplateTimeline && + templateTimelineVersion != null && + existTemplateTimeline != null && + existTemplateTimeline.templateTimelineVersion != null && + existTemplateTimeline.templateTimelineVersion >= templateTimelineVersion + ) { + // Throw error you can not update a template timeline version with an old version + return { + body: OLDER_VERSION_ERROR_MESSAGE, + statusCode: 409, + }; + } else { + return null; + } +}; diff --git a/x-pack/plugins/siem/server/lib/timeline/saved_object.ts b/x-pack/plugins/siem/server/lib/timeline/saved_object.ts index e8cd27947589f..d2df7589f3c4a 100644 --- a/x-pack/plugins/siem/server/lib/timeline/saved_object.ts +++ b/x-pack/plugins/siem/server/lib/timeline/saved_object.ts @@ -8,260 +8,308 @@ import { getOr } from 'lodash/fp'; import { SavedObjectsFindOptions } from '../../../../../../src/core/server'; import { UNAUTHENTICATED_USER } from '../../../common/constants'; +import { NoteSavedObject } from '../../../common/types/timeline/note'; +import { PinnedEventSavedObject } from '../../../common/types/timeline/pinned_event'; +import { SavedTimeline, TimelineSavedObject, TimelineType } from '../../../common/types/timeline'; import { ResponseTimeline, PageInfoTimeline, SortTimeline, ResponseFavoriteTimeline, TimelineResult, + Maybe, } from '../../graphql/types'; import { FrameworkRequest } from '../framework'; -import { Note } from '../note/saved_object'; -import { NoteSavedObject } from '../note/types'; -import { PinnedEventSavedObject } from '../pinned_event/types'; -import { PinnedEvent } from '../pinned_event/saved_object'; +import * as note from '../note/saved_object'; +import * as pinnedEvent from '../pinned_event/saved_object'; import { convertSavedObjectToSavedTimeline } from './convert_saved_object_to_savedtimeline'; import { pickSavedTimeline } from './pick_saved_timeline'; import { timelineSavedObjectType } from './saved_object_mappings'; -import { SavedTimeline, TimelineSavedObject } from './types'; interface ResponseTimelines { timeline: TimelineSavedObject[]; totalCount: number; } -export class Timeline { - private readonly note = new Note(); - private readonly pinnedEvent = new PinnedEvent(); +export interface ResponseTemplateTimeline { + code?: Maybe; - public async getTimeline( - request: FrameworkRequest, - timelineId: string - ): Promise { - return this.getSavedTimeline(request, timelineId); - } + message?: Maybe; + + templateTimeline: TimelineResult; +} - public async getAllTimeline( +export interface Timeline { + getTimeline: (request: FrameworkRequest, timelineId: string) => Promise; + + getAllTimeline: ( request: FrameworkRequest, onlyUserFavorite: boolean | null, pageInfo: PageInfoTimeline | null, search: string | null, sort: SortTimeline | null - ): Promise { - const options: SavedObjectsFindOptions = { - type: timelineSavedObjectType, - perPage: pageInfo != null ? pageInfo.pageSize : undefined, - page: pageInfo != null ? pageInfo.pageIndex : undefined, - search: search != null ? search : undefined, - searchFields: onlyUserFavorite - ? ['title', 'description', 'favorite.keySearch'] - : ['title', 'description'], - sortField: sort != null ? sort.sortField : undefined, - sortOrder: sort != null ? sort.sortOrder : undefined, - }; - - return this.getAllSavedTimeline(request, options); - } + ) => Promise; - public async persistFavorite( + persistFavorite: ( request: FrameworkRequest, timelineId: string | null - ): Promise { - const userName = request.user?.username ?? UNAUTHENTICATED_USER; - const fullName = request.user?.full_name ?? ''; - try { - let timeline: SavedTimeline = {}; - if (timelineId != null) { - const { - eventIdToNoteIds, - notes, - noteIds, - pinnedEventIds, - pinnedEventsSaveObject, - savedObjectId, - version, - ...savedTimeline - } = await this.getBasicSavedTimeline(request, timelineId); - timelineId = savedObjectId; // eslint-disable-line no-param-reassign - timeline = savedTimeline; - } + ) => Promise; - const userFavoriteTimeline = { - keySearch: userName != null ? convertStringToBase64(userName) : null, - favoriteDate: new Date().valueOf(), - fullName, - userName, - }; - if (timeline.favorite != null) { - const alreadyExistsTimelineFavoriteByUser = timeline.favorite.findIndex( - user => user.userName === userName - ); - - timeline.favorite = - alreadyExistsTimelineFavoriteByUser > -1 - ? [ - ...timeline.favorite.slice(0, alreadyExistsTimelineFavoriteByUser), - ...timeline.favorite.slice(alreadyExistsTimelineFavoriteByUser + 1), - ] - : [...timeline.favorite, userFavoriteTimeline]; - } else if (timeline.favorite == null) { - timeline.favorite = [userFavoriteTimeline]; - } + persistTimeline: ( + request: FrameworkRequest, + timelineId: string | null, + version: string | null, + timeline: SavedTimeline, + timelineType?: TimelineType | null + ) => Promise; - const persistResponse = await this.persistTimeline(request, timelineId, null, timeline); + deleteTimeline: (request: FrameworkRequest, timelineIds: string[]) => Promise; + convertStringToBase64: (text: string) => string; + timelineWithReduxProperties: ( + notes: NoteSavedObject[], + pinnedEvents: PinnedEventSavedObject[], + timeline: TimelineSavedObject, + userName: string + ) => TimelineSavedObject; +} + +export const getTimeline = async ( + request: FrameworkRequest, + timelineId: string +): Promise => { + return getSavedTimeline(request, timelineId); +}; + +export const getTimelineByTemplateTimelineId = async ( + request: FrameworkRequest, + templateTimelineId: string +): Promise<{ + totalCount: number; + timeline: TimelineSavedObject[]; +}> => { + const options: SavedObjectsFindOptions = { + type: timelineSavedObjectType, + filter: `siem-ui-timeline.attributes.templateTimelineId: ${templateTimelineId}`, + }; + return getAllSavedTimeline(request, options); +}; + +export const getAllTimeline = async ( + request: FrameworkRequest, + onlyUserFavorite: boolean | null, + pageInfo: PageInfoTimeline | null, + search: string | null, + sort: SortTimeline | null +): Promise => { + const options: SavedObjectsFindOptions = { + type: timelineSavedObjectType, + perPage: pageInfo != null ? pageInfo.pageSize : undefined, + page: pageInfo != null ? pageInfo.pageIndex : undefined, + search: search != null ? search : undefined, + searchFields: onlyUserFavorite + ? ['title', 'description', 'favorite.keySearch'] + : ['title', 'description'], + sortField: sort != null ? sort.sortField : undefined, + sortOrder: sort != null ? sort.sortOrder : undefined, + }; + return getAllSavedTimeline(request, options); +}; + +export const persistFavorite = async ( + request: FrameworkRequest, + timelineId: string | null +): Promise => { + const userName = request.user?.username ?? UNAUTHENTICATED_USER; + const fullName = request.user?.full_name ?? ''; + try { + let timeline: SavedTimeline = {}; + if (timelineId != null) { + const { + eventIdToNoteIds, + notes, + noteIds, + pinnedEventIds, + pinnedEventsSaveObject, + savedObjectId, + version, + ...savedTimeline + } = await getBasicSavedTimeline(request, timelineId); + timelineId = savedObjectId; // eslint-disable-line no-param-reassign + timeline = savedTimeline; + } + + const userFavoriteTimeline = { + keySearch: userName != null ? convertStringToBase64(userName) : null, + favoriteDate: new Date().valueOf(), + fullName, + userName, + }; + if (timeline.favorite != null) { + const alreadyExistsTimelineFavoriteByUser = timeline.favorite.findIndex( + user => user.userName === userName + ); + + timeline.favorite = + alreadyExistsTimelineFavoriteByUser > -1 + ? [ + ...timeline.favorite.slice(0, alreadyExistsTimelineFavoriteByUser), + ...timeline.favorite.slice(alreadyExistsTimelineFavoriteByUser + 1), + ] + : [...timeline.favorite, userFavoriteTimeline]; + } else if (timeline.favorite == null) { + timeline.favorite = [userFavoriteTimeline]; + } + + const persistResponse = await persistTimeline(request, timelineId, null, timeline); + return { + savedObjectId: persistResponse.timeline.savedObjectId, + version: persistResponse.timeline.version, + favorite: + persistResponse.timeline.favorite != null + ? persistResponse.timeline.favorite.filter(fav => fav.userName === userName) + : [], + }; + } catch (err) { + if (getOr(null, 'output.statusCode', err) === 403) { return { - savedObjectId: persistResponse.timeline.savedObjectId, - version: persistResponse.timeline.version, - favorite: - persistResponse.timeline.favorite != null - ? persistResponse.timeline.favorite.filter(fav => fav.userName === userName) - : [], + savedObjectId: '', + version: '', + favorite: [], + code: 403, + message: err.message, }; - } catch (err) { - if (getOr(null, 'output.statusCode', err) === 403) { - return { - savedObjectId: '', - version: '', - favorite: [], - code: 403, - message: err.message, - }; - } - throw err; } + throw err; } +}; - public async persistTimeline( - request: FrameworkRequest, - timelineId: string | null, - version: string | null, - timeline: SavedTimeline - ): Promise { - const savedObjectsClient = request.context.core.savedObjects.client; - try { - if (timelineId == null) { - // Create new timeline - const newTimeline = convertSavedObjectToSavedTimeline( - await savedObjectsClient.create( - timelineSavedObjectType, - pickSavedTimeline(timelineId, timeline, request.user) - ) - ); - return { - code: 200, - message: 'success', - timeline: newTimeline, - }; - } - // Update Timeline - await savedObjectsClient.update( - timelineSavedObjectType, - timelineId, - pickSavedTimeline(timelineId, timeline, request.user), - { - version: version || undefined, - } +export const persistTimeline = async ( + request: FrameworkRequest, + timelineId: string | null, + version: string | null, + timeline: SavedTimeline +): Promise => { + const savedObjectsClient = request.context.core.savedObjects.client; + try { + if (timelineId == null) { + // Create new timeline + const newTimeline = convertSavedObjectToSavedTimeline( + await savedObjectsClient.create( + timelineSavedObjectType, + pickSavedTimeline(timelineId, timeline, request.user) + ) ); - return { code: 200, message: 'success', - timeline: await this.getSavedTimeline(request, timelineId), + timeline: newTimeline, }; - } catch (err) { - if (timelineId != null && savedObjectsClient.errors.isConflictError(err)) { - return { - code: 409, - message: err.message, - timeline: await this.getSavedTimeline(request, timelineId), - }; - } else if (getOr(null, 'output.statusCode', err) === 403) { - const timelineToReturn: TimelineResult = { - ...timeline, - savedObjectId: '', - version: '', - }; - return { - code: 403, - message: err.message, - timeline: timelineToReturn, - }; + } + // Update Timeline + await savedObjectsClient.update( + timelineSavedObjectType, + timelineId, + pickSavedTimeline(timelineId, timeline, request.user), + { + version: version || undefined, } - throw err; + ); + + return { + code: 200, + message: 'success', + timeline: await getSavedTimeline(request, timelineId), + }; + } catch (err) { + if (timelineId != null && savedObjectsClient.errors.isConflictError(err)) { + return { + code: 409, + message: err.message, + timeline: await getSavedTimeline(request, timelineId), + }; + } else if (getOr(null, 'output.statusCode', err) === 403) { + const timelineToReturn: TimelineResult = { + ...timeline, + savedObjectId: '', + version: '', + }; + return { + code: 403, + message: err.message, + timeline: timelineToReturn, + }; } + throw err; } +}; - public async deleteTimeline(request: FrameworkRequest, timelineIds: string[]) { - const savedObjectsClient = request.context.core.savedObjects.client; - - await Promise.all( - timelineIds.map(timelineId => - Promise.all([ - savedObjectsClient.delete(timelineSavedObjectType, timelineId), - this.note.deleteNoteByTimelineId(request, timelineId), - this.pinnedEvent.deleteAllPinnedEventsOnTimeline(request, timelineId), - ]) - ) - ); - } +export const deleteTimeline = async (request: FrameworkRequest, timelineIds: string[]) => { + const savedObjectsClient = request.context.core.savedObjects.client; - private async getBasicSavedTimeline(request: FrameworkRequest, timelineId: string) { - const savedObjectsClient = request.context.core.savedObjects.client; - const savedObject = await savedObjectsClient.get(timelineSavedObjectType, timelineId); + await Promise.all( + timelineIds.map(timelineId => + Promise.all([ + savedObjectsClient.delete(timelineSavedObjectType, timelineId), + note.deleteNoteByTimelineId(request, timelineId), + pinnedEvent.deleteAllPinnedEventsOnTimeline(request, timelineId), + ]) + ) + ); +}; - return convertSavedObjectToSavedTimeline(savedObject); - } +const getBasicSavedTimeline = async (request: FrameworkRequest, timelineId: string) => { + const savedObjectsClient = request.context.core.savedObjects.client; + const savedObject = await savedObjectsClient.get(timelineSavedObjectType, timelineId); + + return convertSavedObjectToSavedTimeline(savedObject); +}; - private async getSavedTimeline(request: FrameworkRequest, timelineId: string) { - const userName = request.user?.username ?? UNAUTHENTICATED_USER; +const getSavedTimeline = async (request: FrameworkRequest, timelineId: string) => { + const userName = request.user?.username ?? UNAUTHENTICATED_USER; - const savedObjectsClient = request.context.core.savedObjects.client; - const savedObject = await savedObjectsClient.get(timelineSavedObjectType, timelineId); - const timelineSaveObject = convertSavedObjectToSavedTimeline(savedObject); - const timelineWithNotesAndPinnedEvents = await Promise.all([ - this.note.getNotesByTimelineId(request, timelineSaveObject.savedObjectId), - this.pinnedEvent.getAllPinnedEventsByTimelineId(request, timelineSaveObject.savedObjectId), - Promise.resolve(timelineSaveObject), - ]); + const savedObjectsClient = request.context.core.savedObjects.client; + const savedObject = await savedObjectsClient.get(timelineSavedObjectType, timelineId); + const timelineSaveObject = convertSavedObjectToSavedTimeline(savedObject); + const timelineWithNotesAndPinnedEvents = await Promise.all([ + note.getNotesByTimelineId(request, timelineSaveObject.savedObjectId), + pinnedEvent.getAllPinnedEventsByTimelineId(request, timelineSaveObject.savedObjectId), + Promise.resolve(timelineSaveObject), + ]); - const [notes, pinnedEvents, timeline] = timelineWithNotesAndPinnedEvents; + const [notes, pinnedEvents, timeline] = timelineWithNotesAndPinnedEvents; - return timelineWithReduxProperties(notes, pinnedEvents, timeline, userName); + return timelineWithReduxProperties(notes, pinnedEvents, timeline, userName); +}; + +const getAllSavedTimeline = async (request: FrameworkRequest, options: SavedObjectsFindOptions) => { + const userName = request.user?.username ?? UNAUTHENTICATED_USER; + const savedObjectsClient = request.context.core.savedObjects.client; + if (options.searchFields != null && options.searchFields.includes('favorite.keySearch')) { + options.search = `${options.search != null ? options.search : ''} ${ + userName != null ? convertStringToBase64(userName) : null + }`; } - private async getAllSavedTimeline(request: FrameworkRequest, options: SavedObjectsFindOptions) { - const userName = request.user?.username ?? UNAUTHENTICATED_USER; - const savedObjectsClient = request.context.core.savedObjects.client; - if (options.searchFields != null && options.searchFields.includes('favorite.keySearch')) { - options.search = `${options.search != null ? options.search : ''} ${ - userName != null ? convertStringToBase64(userName) : null - }`; - } + const savedObjects = await savedObjectsClient.find(options); - const savedObjects = await savedObjectsClient.find(options); - - const timelinesWithNotesAndPinnedEvents = await Promise.all( - savedObjects.saved_objects.map(async savedObject => { - const timelineSaveObject = convertSavedObjectToSavedTimeline(savedObject); - return Promise.all([ - this.note.getNotesByTimelineId(request, timelineSaveObject.savedObjectId), - this.pinnedEvent.getAllPinnedEventsByTimelineId( - request, - timelineSaveObject.savedObjectId - ), - Promise.resolve(timelineSaveObject), - ]); - }) - ); + const timelinesWithNotesAndPinnedEvents = await Promise.all( + savedObjects.saved_objects.map(async savedObject => { + const timelineSaveObject = convertSavedObjectToSavedTimeline(savedObject); + return Promise.all([ + note.getNotesByTimelineId(request, timelineSaveObject.savedObjectId), + pinnedEvent.getAllPinnedEventsByTimelineId(request, timelineSaveObject.savedObjectId), + Promise.resolve(timelineSaveObject), + ]); + }) + ); - return { - totalCount: savedObjects.total, - timeline: timelinesWithNotesAndPinnedEvents.map(([notes, pinnedEvents, timeline]) => - timelineWithReduxProperties(notes, pinnedEvents, timeline, userName) - ), - }; - } -} + return { + totalCount: savedObjects.total, + timeline: timelinesWithNotesAndPinnedEvents.map(([notes, pinnedEvents, timeline]) => + timelineWithReduxProperties(notes, pinnedEvents, timeline, userName) + ), + }; +}; export const convertStringToBase64 = (text: string): string => Buffer.from(text).toString('base64'); @@ -283,11 +331,9 @@ export const timelineWithReduxProperties = ( timeline.favorite != null && userName != null ? timeline.favorite.filter(fav => fav.userName === userName) : [], - eventIdToNoteIds: notes.filter(note => note.eventId != null), - noteIds: notes - .filter(note => note.eventId == null && note.noteId != null) - .map(note => note.noteId), + eventIdToNoteIds: notes.filter(n => n.eventId != null), + noteIds: notes.filter(n => n.eventId == null && n.noteId != null).map(n => n.noteId), notes, - pinnedEventIds: pinnedEvents.map(pinnedEvent => pinnedEvent.eventId), + pinnedEventIds: pinnedEvents.map(e => e.eventId), pinnedEventsSaveObject: pinnedEvents, }); diff --git a/x-pack/plugins/siem/server/lib/timeline/saved_object_mappings.ts b/x-pack/plugins/siem/server/lib/timeline/saved_object_mappings.ts index b956e0f98fcb6..1cab24d0879ff 100644 --- a/x-pack/plugins/siem/server/lib/timeline/saved_object_mappings.ts +++ b/x-pack/plugins/siem/server/lib/timeline/saved_object_mappings.ts @@ -231,6 +231,15 @@ export const timelineSavedObjectMappings = { title: { type: 'text', }, + templateTimelineId: { + type: 'text', + }, + templateTimelineVersion: { + type: 'integer', + }, + timelineType: { + type: 'keyword', + }, dateRange: { properties: { start: { diff --git a/x-pack/plugins/siem/server/routes/index.ts b/x-pack/plugins/siem/server/routes/index.ts index 1c03823e85fd7..ffad86a09cee7 100644 --- a/x-pack/plugins/siem/server/routes/index.ts +++ b/x-pack/plugins/siem/server/routes/index.ts @@ -30,6 +30,8 @@ import { findRulesStatusesRoute } from '../lib/detection_engine/routes/rules/fin import { getPrepackagedRulesStatusRoute } from '../lib/detection_engine/routes/rules/get_prepackaged_rules_status_route'; import { importTimelinesRoute } from '../lib/timeline/routes/import_timelines_route'; import { exportTimelinesRoute } from '../lib/timeline/routes/export_timelines_route'; +import { createTimelinesRoute } from '../lib/timeline/routes/create_timelines_route'; +import { updateTimelinesRoute } from '../lib/timeline/routes/update_timelines_route'; import { SetupPlugins } from '../plugin'; import { ConfigType } from '../config'; @@ -55,6 +57,8 @@ export const initRoutes = ( patchRulesBulkRoute(router); deleteRulesBulkRoute(router); + createTimelinesRoute(router, config, security); + updateTimelinesRoute(router, config, security); importRulesRoute(router, config); exportRulesRoute(router, config); diff --git a/x-pack/plugins/siem/server/utils/typed_resolvers.ts b/x-pack/plugins/siem/server/utils/typed_resolvers.ts index da38e8a1e1bf2..4f19bd54b01f0 100644 --- a/x-pack/plugins/siem/server/utils/typed_resolvers.ts +++ b/x-pack/plugins/siem/server/utils/typed_resolvers.ts @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import * as runtimeTypes from 'io-ts'; import { GraphQLResolveInfo } from 'graphql'; // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -106,6 +105,3 @@ export type ChildResolverOf = ResolverWithParent< Resolver_, ResultOf >; - -export const unionWithNullType = (type: T) => - runtimeTypes.union([type, runtimeTypes.null]); diff --git a/x-pack/plugins/task_manager/server/plugin.ts b/x-pack/plugins/task_manager/server/plugin.ts index a70fbdb18c30b..0f6e3fc31d96d 100644 --- a/x-pack/plugins/task_manager/server/plugin.ts +++ b/x-pack/plugins/task_manager/server/plugin.ts @@ -12,11 +12,10 @@ import { TaskManager } from './task_manager'; import { createTaskManager } from './create_task_manager'; import { TaskManagerConfig } from './config'; import { Middleware } from './lib/middleware'; +import { setupSavedObjects } from './saved_objects'; -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface PluginLegacyDependencies {} export type TaskManagerSetupContract = { - registerLegacyAPI: (legacyDependencies: PluginLegacyDependencies) => Promise; + registerLegacyAPI: () => Promise; } & Pick; export type TaskManagerStartContract = Pick< @@ -35,12 +34,18 @@ export class TaskManagerPlugin this.currentConfig = {} as TaskManagerConfig; } - public setup(core: CoreSetup, plugins: unknown): TaskManagerSetupContract { + public async setup(core: CoreSetup, plugins: unknown): Promise { const logger = this.initContext.logger.get('taskManager'); - const config$ = this.initContext.config.create(); + const config = await this.initContext.config + .create() + .pipe(first()) + .toPromise(); + + setupSavedObjects(core.savedObjects, config); + return { - registerLegacyAPI: once((__LEGACY: PluginLegacyDependencies) => { - config$.subscribe(async config => { + registerLegacyAPI: once(() => { + (async () => { const [{ savedObjects, elasticsearch }] = await core.getStartServices(); const savedObjectsRepository = savedObjects.createInternalRepository(['task']); this.legacyTaskManager$.next( @@ -53,7 +58,7 @@ export class TaskManagerPlugin }) ); this.legacyTaskManager$.complete(); - }); + })(); return this.taskManager; }), addMiddleware: (middleware: Middleware) => { diff --git a/x-pack/plugins/task_manager/server/saved_objects/index.ts b/x-pack/plugins/task_manager/server/saved_objects/index.ts new file mode 100644 index 0000000000000..0ad9021cd7f39 --- /dev/null +++ b/x-pack/plugins/task_manager/server/saved_objects/index.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { SavedObjectsServiceSetup } from 'kibana/server'; +import mappings from './mappings.json'; +import { TaskManagerConfig } from '../config.js'; + +export function setupSavedObjects( + savedObjects: SavedObjectsServiceSetup, + config: TaskManagerConfig +) { + savedObjects.registerType({ + name: 'task', + namespaceType: 'agnostic', + hidden: true, + convertToAliasScript: `ctx._id = ctx._source.type + ':' + ctx._id`, + mappings: mappings.task, + indexPattern: config.index, + }); +} diff --git a/x-pack/legacy/plugins/task_manager/server/mappings.json b/x-pack/plugins/task_manager/server/saved_objects/mappings.json similarity index 100% rename from x-pack/legacy/plugins/task_manager/server/mappings.json rename to x-pack/plugins/task_manager/server/saved_objects/mappings.json diff --git a/x-pack/legacy/plugins/task_manager/server/migrations.ts b/x-pack/plugins/task_manager/server/saved_objects/migrations.ts similarity index 100% rename from x-pack/legacy/plugins/task_manager/server/migrations.ts rename to x-pack/plugins/task_manager/server/saved_objects/migrations.ts diff --git a/x-pack/plugins/task_manager/server/task_manager.ts b/x-pack/plugins/task_manager/server/task_manager.ts index 24ceea0fe71ef..2a45a599120dd 100644 --- a/x-pack/plugins/task_manager/server/task_manager.ts +++ b/x-pack/plugins/task_manager/server/task_manager.ts @@ -240,7 +240,7 @@ export class TaskManager { * @param taskDefinitions - The Kibana task definitions dictionary */ public registerTaskDefinitions(taskDefinitions: TaskDictionary) { - this.assertUninitialized('register task definitions'); + this.assertUninitialized('register task definitions', Object.keys(taskDefinitions).join(', ')); const duplicate = Object.keys(taskDefinitions).find(k => !!this.definitions[k]); if (duplicate) { throw new Error(`Task ${duplicate} is already defined!`); @@ -360,9 +360,11 @@ export class TaskManager { * @param {string} message shown if task manager is already initialized * @returns void */ - private assertUninitialized(message: string) { + private assertUninitialized(message: string, context?: string) { if (this.isStarted) { - throw new Error(`Cannot ${message} after the task manager is initialized!`); + throw new Error( + `${context ? `[${context}] ` : ''}Cannot ${message} after the task manager is initialized` + ); } } } diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index aa8e3fc9b6fd2..81dc44f3a4cb4 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -10500,10 +10500,9 @@ "xpack.ml.overview.feedbackSectionTitle": "フィードバック", "xpack.ml.overview.gettingStartedSectionCreateJob": "新規ジョブを作成中", "xpack.ml.overview.gettingStartedSectionDocs": "ドキュメンテーション", - "xpack.ml.overview.gettingStartedSectionText": "機械学習へようこそ。はじめに{docs}や{createJob}をご参照ください。Elastic Stackの機械学習の詳細については、{whatIsMachineLearning}をご覧ください。{transforms}を使用して、分析ジョブの機能インデックスを作成することをお勧めします。", + "xpack.ml.overview.gettingStartedSectionText": "機械学習へようこそ。はじめに{docs}や{createJob}をご参照ください。{transforms}を使用して、分析ジョブの機能インデックスを作成することをお勧めします。", "xpack.ml.overview.gettingStartedSectionTitle": "はじめて使う", "xpack.ml.overview.gettingStartedSectionTransforms": "Elasticsearchの変換", - "xpack.ml.overview.gettingStartedSectionWhatIsMachineLearning": "こちら", "xpack.ml.overview.overviewLabel": "概要", "xpack.ml.overview.statsBar.failedAnalyticsLabel": "失敗", "xpack.ml.overview.statsBar.runningAnalyticsLabel": "実行中", @@ -16107,7 +16106,6 @@ "xpack.uptime.emptyStateError.notAuthorized": "アップタイムデータの表示が承認されていません。システム管理者にお問い合わせください。", "xpack.uptime.emptyStateError.notFoundPage": "ページが見つかりません", "xpack.uptime.emptyStateError.title": "エラー", - "xpack.uptime.featureCatalogueDescription": "エンドポイントヘルスチェックとアップタイム監視を行います。", "xpack.uptime.featureRegistry.uptimeFeatureName": "アップタイム", "xpack.uptime.filterBar.ariaLabel": "概要ページのインプットフィルター基準", "xpack.uptime.filterBar.filterDownLabel": "ダウン", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 83e9489d447c5..e06edb45de8fa 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -10503,10 +10503,9 @@ "xpack.ml.overview.feedbackSectionTitle": "反馈", "xpack.ml.overview.gettingStartedSectionCreateJob": "创建新作业", "xpack.ml.overview.gettingStartedSectionDocs": "文档", - "xpack.ml.overview.gettingStartedSectionText": "欢迎使用 Machine Learning。首先阅读我们的{docs}或{createJob}。有关 Elastic Stack 中的机器学习的详情,请参阅{whatIsMachineLearning}。建议使用 {transforms}为分析作业创建功能索引。", + "xpack.ml.overview.gettingStartedSectionText": "欢迎使用 Machine Learning。首先阅读我们的{docs}或{createJob}。建议使用 {transforms}为分析作业创建功能索引。", "xpack.ml.overview.gettingStartedSectionTitle": "入门", "xpack.ml.overview.gettingStartedSectionTransforms": "Elasticsearch 的转换", - "xpack.ml.overview.gettingStartedSectionWhatIsMachineLearning": "此处", "xpack.ml.overview.overviewLabel": "概览", "xpack.ml.overview.statsBar.failedAnalyticsLabel": "失败", "xpack.ml.overview.statsBar.runningAnalyticsLabel": "正在运行", @@ -16112,7 +16111,6 @@ "xpack.uptime.emptyStateError.notAuthorized": "您无权查看 Uptime 数据,请联系系统管理员。", "xpack.uptime.emptyStateError.notFoundPage": "未找到页面", "xpack.uptime.emptyStateError.title": "错误", - "xpack.uptime.featureCatalogueDescription": "执行终端节点运行状况检查和运行时间监测。", "xpack.uptime.featureRegistry.uptimeFeatureName": "运行时间", "xpack.uptime.filterBar.ariaLabel": "概览页面的输入筛选条件", "xpack.uptime.filterBar.filterDownLabel": "关闭", diff --git a/x-pack/legacy/plugins/uptime/README.md b/x-pack/plugins/uptime/README.md similarity index 100% rename from x-pack/legacy/plugins/uptime/README.md rename to x-pack/plugins/uptime/README.md diff --git a/x-pack/legacy/plugins/uptime/common/constants/alerts.ts b/x-pack/plugins/uptime/common/constants/alerts.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/common/constants/alerts.ts rename to x-pack/plugins/uptime/common/constants/alerts.ts diff --git a/x-pack/legacy/plugins/uptime/common/constants/capabilities.ts b/x-pack/plugins/uptime/common/constants/capabilities.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/common/constants/capabilities.ts rename to x-pack/plugins/uptime/common/constants/capabilities.ts diff --git a/x-pack/legacy/plugins/uptime/common/constants/chart_format_limits.ts b/x-pack/plugins/uptime/common/constants/chart_format_limits.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/common/constants/chart_format_limits.ts rename to x-pack/plugins/uptime/common/constants/chart_format_limits.ts diff --git a/x-pack/legacy/plugins/uptime/common/constants/client_defaults.ts b/x-pack/plugins/uptime/common/constants/client_defaults.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/common/constants/client_defaults.ts rename to x-pack/plugins/uptime/common/constants/client_defaults.ts diff --git a/x-pack/legacy/plugins/uptime/common/constants/context_defaults.ts b/x-pack/plugins/uptime/common/constants/context_defaults.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/common/constants/context_defaults.ts rename to x-pack/plugins/uptime/common/constants/context_defaults.ts diff --git a/x-pack/legacy/plugins/uptime/common/constants/index.ts b/x-pack/plugins/uptime/common/constants/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/common/constants/index.ts rename to x-pack/plugins/uptime/common/constants/index.ts diff --git a/x-pack/legacy/plugins/uptime/common/constants/plugin.ts b/x-pack/plugins/uptime/common/constants/plugin.ts similarity index 64% rename from x-pack/legacy/plugins/uptime/common/constants/plugin.ts rename to x-pack/plugins/uptime/common/constants/plugin.ts index 00781726941d5..6064524872a0a 100644 --- a/x-pack/legacy/plugins/uptime/common/constants/plugin.ts +++ b/x-pack/plugins/uptime/common/constants/plugin.ts @@ -8,12 +8,17 @@ import { i18n } from '@kbn/i18n'; export const PLUGIN = { APP_ROOT_ID: 'react-uptime-root', - DESCRIPTION: 'Uptime monitoring', + DESCRIPTION: i18n.translate('xpack.uptime.pluginDescription', { + defaultMessage: 'Uptime monitoring', + description: 'The description text that will appear in the feature catalogue.', + }), ID: 'uptime', LOCAL_STORAGE_KEY: 'xpack.uptime', NAME: i18n.translate('xpack.uptime.featureRegistry.uptimeFeatureName', { defaultMessage: 'Uptime', }), ROUTER_BASE_NAME: '/app/uptime#', - TITLE: 'uptime', + TITLE: i18n.translate('xpack.uptime.uptimeFeatureCatalogueTitle', { + defaultMessage: 'Uptime', + }), }; diff --git a/x-pack/legacy/plugins/uptime/common/constants/query.ts b/x-pack/plugins/uptime/common/constants/query.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/common/constants/query.ts rename to x-pack/plugins/uptime/common/constants/query.ts diff --git a/x-pack/legacy/plugins/uptime/common/constants/rest_api.ts b/x-pack/plugins/uptime/common/constants/rest_api.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/common/constants/rest_api.ts rename to x-pack/plugins/uptime/common/constants/rest_api.ts diff --git a/x-pack/legacy/plugins/uptime/common/constants/settings_defaults.ts b/x-pack/plugins/uptime/common/constants/settings_defaults.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/common/constants/settings_defaults.ts rename to x-pack/plugins/uptime/common/constants/settings_defaults.ts diff --git a/x-pack/legacy/plugins/uptime/common/constants/ui.ts b/x-pack/plugins/uptime/common/constants/ui.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/common/constants/ui.ts rename to x-pack/plugins/uptime/common/constants/ui.ts diff --git a/x-pack/legacy/plugins/uptime/common/runtime_types/alerts/index.ts b/x-pack/plugins/uptime/common/runtime_types/alerts/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/common/runtime_types/alerts/index.ts rename to x-pack/plugins/uptime/common/runtime_types/alerts/index.ts diff --git a/x-pack/legacy/plugins/uptime/common/runtime_types/alerts/status_check.ts b/x-pack/plugins/uptime/common/runtime_types/alerts/status_check.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/common/runtime_types/alerts/status_check.ts rename to x-pack/plugins/uptime/common/runtime_types/alerts/status_check.ts diff --git a/x-pack/legacy/plugins/uptime/common/runtime_types/certs.ts b/x-pack/plugins/uptime/common/runtime_types/certs.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/common/runtime_types/certs.ts rename to x-pack/plugins/uptime/common/runtime_types/certs.ts diff --git a/x-pack/legacy/plugins/uptime/common/runtime_types/common.ts b/x-pack/plugins/uptime/common/runtime_types/common.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/common/runtime_types/common.ts rename to x-pack/plugins/uptime/common/runtime_types/common.ts diff --git a/x-pack/legacy/plugins/uptime/common/runtime_types/dynamic_settings.ts b/x-pack/plugins/uptime/common/runtime_types/dynamic_settings.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/common/runtime_types/dynamic_settings.ts rename to x-pack/plugins/uptime/common/runtime_types/dynamic_settings.ts diff --git a/x-pack/legacy/plugins/uptime/common/runtime_types/index.ts b/x-pack/plugins/uptime/common/runtime_types/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/common/runtime_types/index.ts rename to x-pack/plugins/uptime/common/runtime_types/index.ts index 78aab3806ae04..e80471bf8b56f 100644 --- a/x-pack/legacy/plugins/uptime/common/runtime_types/index.ts +++ b/x-pack/plugins/uptime/common/runtime_types/index.ts @@ -7,8 +7,8 @@ export * from './alerts'; export * from './certs'; export * from './common'; +export * from './dynamic_settings'; export * from './monitor'; export * from './overview_filters'; export * from './ping'; export * from './snapshot'; -export * from './dynamic_settings'; diff --git a/x-pack/legacy/plugins/uptime/common/runtime_types/monitor/details.ts b/x-pack/plugins/uptime/common/runtime_types/monitor/details.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/common/runtime_types/monitor/details.ts rename to x-pack/plugins/uptime/common/runtime_types/monitor/details.ts diff --git a/x-pack/legacy/plugins/uptime/common/runtime_types/monitor/index.ts b/x-pack/plugins/uptime/common/runtime_types/monitor/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/common/runtime_types/monitor/index.ts rename to x-pack/plugins/uptime/common/runtime_types/monitor/index.ts diff --git a/x-pack/legacy/plugins/uptime/common/runtime_types/monitor/locations.ts b/x-pack/plugins/uptime/common/runtime_types/monitor/locations.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/common/runtime_types/monitor/locations.ts rename to x-pack/plugins/uptime/common/runtime_types/monitor/locations.ts diff --git a/x-pack/legacy/plugins/uptime/common/runtime_types/monitor/state.ts b/x-pack/plugins/uptime/common/runtime_types/monitor/state.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/common/runtime_types/monitor/state.ts rename to x-pack/plugins/uptime/common/runtime_types/monitor/state.ts diff --git a/x-pack/legacy/plugins/uptime/common/runtime_types/overview_filters/index.ts b/x-pack/plugins/uptime/common/runtime_types/overview_filters/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/common/runtime_types/overview_filters/index.ts rename to x-pack/plugins/uptime/common/runtime_types/overview_filters/index.ts diff --git a/x-pack/legacy/plugins/uptime/common/runtime_types/overview_filters/overview_filters.ts b/x-pack/plugins/uptime/common/runtime_types/overview_filters/overview_filters.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/common/runtime_types/overview_filters/overview_filters.ts rename to x-pack/plugins/uptime/common/runtime_types/overview_filters/overview_filters.ts diff --git a/x-pack/legacy/plugins/uptime/common/runtime_types/ping/histogram.ts b/x-pack/plugins/uptime/common/runtime_types/ping/histogram.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/common/runtime_types/ping/histogram.ts rename to x-pack/plugins/uptime/common/runtime_types/ping/histogram.ts diff --git a/x-pack/legacy/plugins/uptime/common/runtime_types/ping/index.ts b/x-pack/plugins/uptime/common/runtime_types/ping/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/common/runtime_types/ping/index.ts rename to x-pack/plugins/uptime/common/runtime_types/ping/index.ts diff --git a/x-pack/legacy/plugins/uptime/common/runtime_types/ping/ping.ts b/x-pack/plugins/uptime/common/runtime_types/ping/ping.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/common/runtime_types/ping/ping.ts rename to x-pack/plugins/uptime/common/runtime_types/ping/ping.ts diff --git a/x-pack/legacy/plugins/uptime/common/runtime_types/snapshot/index.ts b/x-pack/plugins/uptime/common/runtime_types/snapshot/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/common/runtime_types/snapshot/index.ts rename to x-pack/plugins/uptime/common/runtime_types/snapshot/index.ts diff --git a/x-pack/legacy/plugins/uptime/common/runtime_types/snapshot/snapshot_count.ts b/x-pack/plugins/uptime/common/runtime_types/snapshot/snapshot_count.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/common/runtime_types/snapshot/snapshot_count.ts rename to x-pack/plugins/uptime/common/runtime_types/snapshot/snapshot_count.ts diff --git a/x-pack/legacy/plugins/uptime/common/types/index.ts b/x-pack/plugins/uptime/common/types/index.ts similarity index 69% rename from x-pack/legacy/plugins/uptime/common/types/index.ts rename to x-pack/plugins/uptime/common/types/index.ts index a32eabd49a3e5..71ccd54dd3cdc 100644 --- a/x-pack/legacy/plugins/uptime/common/types/index.ts +++ b/x-pack/plugins/uptime/common/types/index.ts @@ -4,18 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -/** Represents a bucket of monitor status information. */ -export interface StatusData { - /** The timeseries point for this status data. */ - x: number; - /** The value of up counts for this point. */ - up?: number | null; - /** The value for down counts for this point. */ - down?: number | null; - /** The total down counts for this point. */ - total?: number | null; -} - /** Represents the average monitor duration ms at a point in time. */ export interface MonitorDurationAveragePoint { /** The timeseries value for this point. */ diff --git a/x-pack/plugins/uptime/kibana.json b/x-pack/plugins/uptime/kibana.json index 6ec8a755ebea0..ce8b64ce07254 100644 --- a/x-pack/plugins/uptime/kibana.json +++ b/x-pack/plugins/uptime/kibana.json @@ -2,8 +2,16 @@ "configPath": ["xpack", "uptime"], "id": "uptime", "kibanaVersion": "kibana", - "requiredPlugins": ["alerting", "features", "licensing", "usageCollection"], + "optionalPlugins": ["capabilities", "data", "home"], + "requiredPlugins": [ + "alerting", + "embeddable", + "features", + "licensing", + "triggers_actions_ui", + "usageCollection" + ], "server": true, - "ui": false, + "ui": true, "version": "8.0.0" } diff --git a/x-pack/legacy/plugins/uptime/public/app.ts b/x-pack/plugins/uptime/public/app.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/app.ts rename to x-pack/plugins/uptime/public/app.ts diff --git a/x-pack/legacy/plugins/actions/index.ts b/x-pack/plugins/uptime/public/apps/index.ts similarity index 85% rename from x-pack/legacy/plugins/actions/index.ts rename to x-pack/plugins/uptime/public/apps/index.ts index 276d1ea3accea..65b80d08d4f20 100644 --- a/x-pack/legacy/plugins/actions/index.ts +++ b/x-pack/plugins/uptime/public/apps/index.ts @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export * from './server/'; +export { UptimePlugin } from './plugin'; diff --git a/x-pack/plugins/uptime/public/apps/plugin.ts b/x-pack/plugins/uptime/public/apps/plugin.ts new file mode 100644 index 0000000000000..719dac022dada --- /dev/null +++ b/x-pack/plugins/uptime/public/apps/plugin.ts @@ -0,0 +1,72 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { LegacyCoreStart, AppMountParameters } from 'src/core/public'; +import { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from 'kibana/public'; +import { UMFrontendLibs } from '../lib/lib'; +import { PLUGIN } from '../../common/constants'; +import { FeatureCatalogueCategory } from '../../../../../src/plugins/home/public'; +import { getKibanaFrameworkAdapter } from '../lib/adapters/framework/new_platform_adapter'; +import { HomePublicPluginSetup } from '../../../../../src/plugins/home/public'; +import { EmbeddableStart } from '../../../../../src/plugins/embeddable/public'; +import { TriggersAndActionsUIPublicPluginSetup } from '../../../triggers_actions_ui/public'; +import { DataPublicPluginSetup } from '../../../../../src/plugins/data/public'; + +export interface StartObject { + core: LegacyCoreStart; + plugins: any; +} + +export interface ClientPluginsSetup { + data: DataPublicPluginSetup; + home: HomePublicPluginSetup; + triggers_actions_ui: TriggersAndActionsUIPublicPluginSetup; +} + +export interface ClientPluginsStart { + embeddable: EmbeddableStart; +} + +export class UptimePlugin implements Plugin { + constructor(_context: PluginInitializerContext) {} + + public async setup( + core: CoreSetup, + plugins: ClientPluginsSetup + ): Promise { + if (plugins.home) { + plugins.home.featureCatalogue.register({ + id: PLUGIN.ID, + title: PLUGIN.TITLE, + description: PLUGIN.DESCRIPTION, + icon: 'uptimeApp', + path: '/app/uptime#/', + showOnHomePage: true, + category: FeatureCatalogueCategory.DATA, + }); + } + + core.application.register({ + appRoute: '/app/uptime#/', + id: PLUGIN.ID, + euiIconType: 'uptimeApp', + order: 8900, + title: PLUGIN.TITLE, + async mount(params: AppMountParameters) { + const [coreStart, corePlugins] = await core.getStartServices(); + const { element } = params; + const libs: UMFrontendLibs = { + framework: getKibanaFrameworkAdapter(coreStart, plugins, corePlugins), + }; + libs.framework.render(element); + return () => {}; + }, + }); + } + + public start(_start: CoreStart, _plugins: {}): void {} + + public stop(): void {} +} diff --git a/x-pack/legacy/plugins/uptime/public/apps/template.html b/x-pack/plugins/uptime/public/apps/template.html similarity index 100% rename from x-pack/legacy/plugins/uptime/public/apps/template.html rename to x-pack/plugins/uptime/public/apps/template.html diff --git a/x-pack/legacy/plugins/uptime/public/badge.ts b/x-pack/plugins/uptime/public/badge.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/badge.ts rename to x-pack/plugins/uptime/public/badge.ts diff --git a/x-pack/legacy/plugins/uptime/public/breadcrumbs.ts b/x-pack/plugins/uptime/public/breadcrumbs.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/breadcrumbs.ts rename to x-pack/plugins/uptime/public/breadcrumbs.ts diff --git a/x-pack/legacy/plugins/uptime/public/components/common/__tests__/__snapshots__/location_link.test.tsx.snap b/x-pack/plugins/uptime/public/components/common/__tests__/__snapshots__/location_link.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/__tests__/__snapshots__/location_link.test.tsx.snap rename to x-pack/plugins/uptime/public/components/common/__tests__/__snapshots__/location_link.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/common/__tests__/__snapshots__/uptime_date_picker.test.tsx.snap b/x-pack/plugins/uptime/public/components/common/__tests__/__snapshots__/uptime_date_picker.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/__tests__/__snapshots__/uptime_date_picker.test.tsx.snap rename to x-pack/plugins/uptime/public/components/common/__tests__/__snapshots__/uptime_date_picker.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/common/__tests__/location_link.test.tsx b/x-pack/plugins/uptime/public/components/common/__tests__/location_link.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/__tests__/location_link.test.tsx rename to x-pack/plugins/uptime/public/components/common/__tests__/location_link.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/common/__tests__/uptime_date_picker.test.tsx b/x-pack/plugins/uptime/public/components/common/__tests__/uptime_date_picker.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/__tests__/uptime_date_picker.test.tsx rename to x-pack/plugins/uptime/public/components/common/__tests__/uptime_date_picker.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/common/charts/__tests__/__snapshots__/chart_empty_state.test.tsx.snap b/x-pack/plugins/uptime/public/components/common/charts/__tests__/__snapshots__/chart_empty_state.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/charts/__tests__/__snapshots__/chart_empty_state.test.tsx.snap rename to x-pack/plugins/uptime/public/components/common/charts/__tests__/__snapshots__/chart_empty_state.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/common/charts/__tests__/__snapshots__/chart_wrapper.test.tsx.snap b/x-pack/plugins/uptime/public/components/common/charts/__tests__/__snapshots__/chart_wrapper.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/charts/__tests__/__snapshots__/chart_wrapper.test.tsx.snap rename to x-pack/plugins/uptime/public/components/common/charts/__tests__/__snapshots__/chart_wrapper.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/common/charts/__tests__/__snapshots__/donut_chart.test.tsx.snap b/x-pack/plugins/uptime/public/components/common/charts/__tests__/__snapshots__/donut_chart.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/charts/__tests__/__snapshots__/donut_chart.test.tsx.snap rename to x-pack/plugins/uptime/public/components/common/charts/__tests__/__snapshots__/donut_chart.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/common/charts/__tests__/__snapshots__/donut_chart_legend.test.tsx.snap b/x-pack/plugins/uptime/public/components/common/charts/__tests__/__snapshots__/donut_chart_legend.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/charts/__tests__/__snapshots__/donut_chart_legend.test.tsx.snap rename to x-pack/plugins/uptime/public/components/common/charts/__tests__/__snapshots__/donut_chart_legend.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/common/charts/__tests__/__snapshots__/donut_chart_legend_row.test.tsx.snap b/x-pack/plugins/uptime/public/components/common/charts/__tests__/__snapshots__/donut_chart_legend_row.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/charts/__tests__/__snapshots__/donut_chart_legend_row.test.tsx.snap rename to x-pack/plugins/uptime/public/components/common/charts/__tests__/__snapshots__/donut_chart_legend_row.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/common/charts/__tests__/__snapshots__/duration_charts.test.tsx.snap b/x-pack/plugins/uptime/public/components/common/charts/__tests__/__snapshots__/duration_charts.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/charts/__tests__/__snapshots__/duration_charts.test.tsx.snap rename to x-pack/plugins/uptime/public/components/common/charts/__tests__/__snapshots__/duration_charts.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/common/charts/__tests__/__snapshots__/monitor_bar_series.test.tsx.snap b/x-pack/plugins/uptime/public/components/common/charts/__tests__/__snapshots__/monitor_bar_series.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/charts/__tests__/__snapshots__/monitor_bar_series.test.tsx.snap rename to x-pack/plugins/uptime/public/components/common/charts/__tests__/__snapshots__/monitor_bar_series.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/common/charts/__tests__/__snapshots__/ping_histogram.test.tsx.snap b/x-pack/plugins/uptime/public/components/common/charts/__tests__/__snapshots__/ping_histogram.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/charts/__tests__/__snapshots__/ping_histogram.test.tsx.snap rename to x-pack/plugins/uptime/public/components/common/charts/__tests__/__snapshots__/ping_histogram.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/common/charts/__tests__/chart_empty_state.test.tsx b/x-pack/plugins/uptime/public/components/common/charts/__tests__/chart_empty_state.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/charts/__tests__/chart_empty_state.test.tsx rename to x-pack/plugins/uptime/public/components/common/charts/__tests__/chart_empty_state.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/common/charts/__tests__/chart_wrapper.test.tsx b/x-pack/plugins/uptime/public/components/common/charts/__tests__/chart_wrapper.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/charts/__tests__/chart_wrapper.test.tsx rename to x-pack/plugins/uptime/public/components/common/charts/__tests__/chart_wrapper.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/common/charts/__tests__/donut_chart.test.tsx b/x-pack/plugins/uptime/public/components/common/charts/__tests__/donut_chart.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/charts/__tests__/donut_chart.test.tsx rename to x-pack/plugins/uptime/public/components/common/charts/__tests__/donut_chart.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/common/charts/__tests__/donut_chart_legend.test.tsx b/x-pack/plugins/uptime/public/components/common/charts/__tests__/donut_chart_legend.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/charts/__tests__/donut_chart_legend.test.tsx rename to x-pack/plugins/uptime/public/components/common/charts/__tests__/donut_chart_legend.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/common/charts/__tests__/donut_chart_legend_row.test.tsx b/x-pack/plugins/uptime/public/components/common/charts/__tests__/donut_chart_legend_row.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/charts/__tests__/donut_chart_legend_row.test.tsx rename to x-pack/plugins/uptime/public/components/common/charts/__tests__/donut_chart_legend_row.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/common/charts/__tests__/duration_charts.test.tsx b/x-pack/plugins/uptime/public/components/common/charts/__tests__/duration_charts.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/charts/__tests__/duration_charts.test.tsx rename to x-pack/plugins/uptime/public/components/common/charts/__tests__/duration_charts.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/common/charts/__tests__/get_tick_format.test.ts b/x-pack/plugins/uptime/public/components/common/charts/__tests__/get_tick_format.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/charts/__tests__/get_tick_format.test.ts rename to x-pack/plugins/uptime/public/components/common/charts/__tests__/get_tick_format.test.ts diff --git a/x-pack/legacy/plugins/uptime/public/components/common/charts/__tests__/monitor_bar_series.test.tsx b/x-pack/plugins/uptime/public/components/common/charts/__tests__/monitor_bar_series.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/charts/__tests__/monitor_bar_series.test.tsx rename to x-pack/plugins/uptime/public/components/common/charts/__tests__/monitor_bar_series.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/common/charts/__tests__/ping_histogram.test.tsx b/x-pack/plugins/uptime/public/components/common/charts/__tests__/ping_histogram.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/charts/__tests__/ping_histogram.test.tsx rename to x-pack/plugins/uptime/public/components/common/charts/__tests__/ping_histogram.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/common/charts/annotation_tooltip.tsx b/x-pack/plugins/uptime/public/components/common/charts/annotation_tooltip.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/charts/annotation_tooltip.tsx rename to x-pack/plugins/uptime/public/components/common/charts/annotation_tooltip.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/common/charts/chart_empty_state.tsx b/x-pack/plugins/uptime/public/components/common/charts/chart_empty_state.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/charts/chart_empty_state.tsx rename to x-pack/plugins/uptime/public/components/common/charts/chart_empty_state.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/common/charts/chart_wrapper/chart_wrapper.tsx b/x-pack/plugins/uptime/public/components/common/charts/chart_wrapper/chart_wrapper.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/charts/chart_wrapper/chart_wrapper.tsx rename to x-pack/plugins/uptime/public/components/common/charts/chart_wrapper/chart_wrapper.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/common/charts/chart_wrapper/index.ts b/x-pack/plugins/uptime/public/components/common/charts/chart_wrapper/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/charts/chart_wrapper/index.ts rename to x-pack/plugins/uptime/public/components/common/charts/chart_wrapper/index.ts diff --git a/x-pack/legacy/plugins/uptime/public/components/common/charts/donut_chart.tsx b/x-pack/plugins/uptime/public/components/common/charts/donut_chart.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/charts/donut_chart.tsx rename to x-pack/plugins/uptime/public/components/common/charts/donut_chart.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/common/charts/donut_chart_legend.tsx b/x-pack/plugins/uptime/public/components/common/charts/donut_chart_legend.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/charts/donut_chart_legend.tsx rename to x-pack/plugins/uptime/public/components/common/charts/donut_chart_legend.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/common/charts/donut_chart_legend_row.tsx b/x-pack/plugins/uptime/public/components/common/charts/donut_chart_legend_row.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/charts/donut_chart_legend_row.tsx rename to x-pack/plugins/uptime/public/components/common/charts/donut_chart_legend_row.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/common/charts/duration_chart.tsx b/x-pack/plugins/uptime/public/components/common/charts/duration_chart.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/charts/duration_chart.tsx rename to x-pack/plugins/uptime/public/components/common/charts/duration_chart.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/common/charts/duration_line_bar_list.tsx b/x-pack/plugins/uptime/public/components/common/charts/duration_line_bar_list.tsx similarity index 94% rename from x-pack/legacy/plugins/uptime/public/components/common/charts/duration_line_bar_list.tsx rename to x-pack/plugins/uptime/public/components/common/charts/duration_line_bar_list.tsx index a31a143b71fd2..ceb1e700f293e 100644 --- a/x-pack/legacy/plugins/uptime/public/components/common/charts/duration_line_bar_list.tsx +++ b/x-pack/plugins/uptime/public/components/common/charts/duration_line_bar_list.tsx @@ -9,11 +9,11 @@ import moment from 'moment'; import { AnnotationTooltipFormatter, RectAnnotation } from '@elastic/charts'; import { RectAnnotationDatum } from '@elastic/charts/dist/chart_types/xy_chart/utils/specs'; import { AnnotationTooltip } from './annotation_tooltip'; -import { ANOMALY_SEVERITY } from '../../../../../../../plugins/ml/common/constants/anomalies'; +import { ANOMALY_SEVERITY } from '../../../../../../plugins/ml/common/constants/anomalies'; import { getSeverityColor, getSeverityType, -} from '../../../../../../../plugins/ml/common/util/anomaly_utils'; +} from '../../../../../../plugins/ml/common/util/anomaly_utils'; interface Props { anomalies: any; diff --git a/x-pack/legacy/plugins/uptime/public/components/common/charts/duration_line_series_list.tsx b/x-pack/plugins/uptime/public/components/common/charts/duration_line_series_list.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/charts/duration_line_series_list.tsx rename to x-pack/plugins/uptime/public/components/common/charts/duration_line_series_list.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/common/charts/get_tick_format.ts b/x-pack/plugins/uptime/public/components/common/charts/get_tick_format.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/charts/get_tick_format.ts rename to x-pack/plugins/uptime/public/components/common/charts/get_tick_format.ts diff --git a/x-pack/legacy/plugins/uptime/public/components/common/charts/index.ts b/x-pack/plugins/uptime/public/components/common/charts/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/charts/index.ts rename to x-pack/plugins/uptime/public/components/common/charts/index.ts diff --git a/x-pack/legacy/plugins/uptime/public/components/common/charts/monitor_bar_series.tsx b/x-pack/plugins/uptime/public/components/common/charts/monitor_bar_series.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/charts/monitor_bar_series.tsx rename to x-pack/plugins/uptime/public/components/common/charts/monitor_bar_series.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/common/charts/ping_histogram.tsx b/x-pack/plugins/uptime/public/components/common/charts/ping_histogram.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/charts/ping_histogram.tsx rename to x-pack/plugins/uptime/public/components/common/charts/ping_histogram.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/common/higher_order/__tests__/__snapshots__/responsive_wrapper.test.tsx.snap b/x-pack/plugins/uptime/public/components/common/higher_order/__tests__/__snapshots__/responsive_wrapper.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/higher_order/__tests__/__snapshots__/responsive_wrapper.test.tsx.snap rename to x-pack/plugins/uptime/public/components/common/higher_order/__tests__/__snapshots__/responsive_wrapper.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/common/higher_order/__tests__/responsive_wrapper.test.tsx b/x-pack/plugins/uptime/public/components/common/higher_order/__tests__/responsive_wrapper.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/higher_order/__tests__/responsive_wrapper.test.tsx rename to x-pack/plugins/uptime/public/components/common/higher_order/__tests__/responsive_wrapper.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/common/higher_order/index.ts b/x-pack/plugins/uptime/public/components/common/higher_order/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/higher_order/index.ts rename to x-pack/plugins/uptime/public/components/common/higher_order/index.ts diff --git a/x-pack/legacy/plugins/uptime/public/components/common/higher_order/responsive_wrapper.tsx b/x-pack/plugins/uptime/public/components/common/higher_order/responsive_wrapper.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/higher_order/responsive_wrapper.tsx rename to x-pack/plugins/uptime/public/components/common/higher_order/responsive_wrapper.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/common/location_link.tsx b/x-pack/plugins/uptime/public/components/common/location_link.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/location_link.tsx rename to x-pack/plugins/uptime/public/components/common/location_link.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/common/uptime_date_picker.tsx b/x-pack/plugins/uptime/public/components/common/uptime_date_picker.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/common/uptime_date_picker.tsx rename to x-pack/plugins/uptime/public/components/common/uptime_date_picker.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/__tests__/__snapshots__/monitor_charts.test.tsx.snap b/x-pack/plugins/uptime/public/components/monitor/__tests__/__snapshots__/monitor_charts.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/__tests__/__snapshots__/monitor_charts.test.tsx.snap rename to x-pack/plugins/uptime/public/components/monitor/__tests__/__snapshots__/monitor_charts.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/__tests__/monitor_charts.test.tsx b/x-pack/plugins/uptime/public/components/monitor/__tests__/monitor_charts.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/__tests__/monitor_charts.test.tsx rename to x-pack/plugins/uptime/public/components/monitor/__tests__/monitor_charts.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/index.ts b/x-pack/plugins/uptime/public/components/monitor/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/index.ts rename to x-pack/plugins/uptime/public/components/monitor/index.ts diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/location_map/__tests__/__snapshots__/location_map.test.tsx.snap b/x-pack/plugins/uptime/public/components/monitor/location_map/__tests__/__snapshots__/location_map.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/location_map/__tests__/__snapshots__/location_map.test.tsx.snap rename to x-pack/plugins/uptime/public/components/monitor/location_map/__tests__/__snapshots__/location_map.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/location_map/__tests__/__snapshots__/location_missing.test.tsx.snap b/x-pack/plugins/uptime/public/components/monitor/location_map/__tests__/__snapshots__/location_missing.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/location_map/__tests__/__snapshots__/location_missing.test.tsx.snap rename to x-pack/plugins/uptime/public/components/monitor/location_map/__tests__/__snapshots__/location_missing.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/location_map/__tests__/__snapshots__/location_status_tags.test.tsx.snap b/x-pack/plugins/uptime/public/components/monitor/location_map/__tests__/__snapshots__/location_status_tags.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/location_map/__tests__/__snapshots__/location_status_tags.test.tsx.snap rename to x-pack/plugins/uptime/public/components/monitor/location_map/__tests__/__snapshots__/location_status_tags.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/location_map/__tests__/location_map.test.tsx b/x-pack/plugins/uptime/public/components/monitor/location_map/__tests__/location_map.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/location_map/__tests__/location_map.test.tsx rename to x-pack/plugins/uptime/public/components/monitor/location_map/__tests__/location_map.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/location_map/__tests__/location_missing.test.tsx b/x-pack/plugins/uptime/public/components/monitor/location_map/__tests__/location_missing.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/location_map/__tests__/location_missing.test.tsx rename to x-pack/plugins/uptime/public/components/monitor/location_map/__tests__/location_missing.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/location_map/__tests__/location_status_tags.test.tsx b/x-pack/plugins/uptime/public/components/monitor/location_map/__tests__/location_status_tags.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/location_map/__tests__/location_status_tags.test.tsx rename to x-pack/plugins/uptime/public/components/monitor/location_map/__tests__/location_status_tags.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/location_map/embeddables/__tests__/__mocks__/mock.ts b/x-pack/plugins/uptime/public/components/monitor/location_map/embeddables/__tests__/__mocks__/mock.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/location_map/embeddables/__tests__/__mocks__/mock.ts rename to x-pack/plugins/uptime/public/components/monitor/location_map/embeddables/__tests__/__mocks__/mock.ts diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/location_map/embeddables/__tests__/map_config.test.ts b/x-pack/plugins/uptime/public/components/monitor/location_map/embeddables/__tests__/map_config.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/location_map/embeddables/__tests__/map_config.test.ts rename to x-pack/plugins/uptime/public/components/monitor/location_map/embeddables/__tests__/map_config.test.ts diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/location_map/embeddables/embedded_map.tsx b/x-pack/plugins/uptime/public/components/monitor/location_map/embeddables/embedded_map.tsx similarity index 85% rename from x-pack/legacy/plugins/uptime/public/components/monitor/location_map/embeddables/embedded_map.tsx rename to x-pack/plugins/uptime/public/components/monitor/location_map/embeddables/embedded_map.tsx index 85d0b1b593704..06cdb07bd8bcd 100644 --- a/x-pack/legacy/plugins/uptime/public/components/monitor/location_map/embeddables/embedded_map.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/location_map/embeddables/embedded_map.tsx @@ -7,21 +7,17 @@ import React, { useEffect, useState, useContext, useRef } from 'react'; import uuid from 'uuid'; import styled from 'styled-components'; -import { npStart } from 'ui/new_platform'; - -import { - ViewMode, - EmbeddableOutput, - ErrorEmbeddable, - isErrorEmbeddable, -} from '../../../../../../../../../src/plugins/embeddable/public'; +import { MapEmbeddable, MapEmbeddableInput } from '../../../../../../../legacy/plugins/maps/public'; import * as i18n from './translations'; -import { MapEmbeddable, MapEmbeddableInput } from '../../../../../../maps/public'; -import { MAP_SAVED_OBJECT_TYPE } from '../../../../../../../../plugins/maps/public'; import { Location } from '../../../../../common/runtime_types'; - import { getLayerList } from './map_config'; -import { UptimeThemeContext } from '../../../../contexts'; +import { UptimeThemeContext, UptimeStartupPluginsContext } from '../../../../contexts'; +import { + isErrorEmbeddable, + ViewMode, + ErrorEmbeddable, +} from '../../../../../../../../src/plugins/embeddable/public'; +import { MAP_SAVED_OBJECT_TYPE } from '../../../../../../maps/public'; export interface EmbeddedMapProps { upPoints: LocationPoint[]; @@ -52,11 +48,11 @@ export const EmbeddedMap = React.memo(({ upPoints, downPoints }: EmbeddedMapProp const { colors } = useContext(UptimeThemeContext); const [embeddable, setEmbeddable] = useState(); const embeddableRoot: React.RefObject = useRef(null); - const factory = npStart.plugins.embeddable.getEmbeddableFactory< - MapEmbeddableInput, - EmbeddableOutput, - MapEmbeddable - >(MAP_SAVED_OBJECT_TYPE); + const { embeddable: embeddablePlugin } = useContext(UptimeStartupPluginsContext); + if (!embeddablePlugin) { + throw new Error('Embeddable start plugin not found'); + } + const factory: any = embeddablePlugin.getEmbeddableFactory(MAP_SAVED_OBJECT_TYPE); const input: MapEmbeddableInput = { id: uuid.v4(), @@ -88,7 +84,7 @@ export const EmbeddedMap = React.memo(({ upPoints, downPoints }: EmbeddedMapProp if (!factory) { throw new Error('Map embeddable not found.'); } - const embeddableObject = await factory.create({ + const embeddableObject: any = await factory.create({ ...input, title: i18n.MAP_TITLE, }); diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/location_map/embeddables/low_poly_layer.json b/x-pack/plugins/uptime/public/components/monitor/location_map/embeddables/low_poly_layer.json similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/location_map/embeddables/low_poly_layer.json rename to x-pack/plugins/uptime/public/components/monitor/location_map/embeddables/low_poly_layer.json diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/location_map/embeddables/map_config.ts b/x-pack/plugins/uptime/public/components/monitor/location_map/embeddables/map_config.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/location_map/embeddables/map_config.ts rename to x-pack/plugins/uptime/public/components/monitor/location_map/embeddables/map_config.ts diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/location_map/embeddables/translations.ts b/x-pack/plugins/uptime/public/components/monitor/location_map/embeddables/translations.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/location_map/embeddables/translations.ts rename to x-pack/plugins/uptime/public/components/monitor/location_map/embeddables/translations.ts diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/location_map/index.tsx b/x-pack/plugins/uptime/public/components/monitor/location_map/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/location_map/index.tsx rename to x-pack/plugins/uptime/public/components/monitor/location_map/index.ts diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/location_map/location_map.tsx b/x-pack/plugins/uptime/public/components/monitor/location_map/location_map.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/location_map/location_map.tsx rename to x-pack/plugins/uptime/public/components/monitor/location_map/location_map.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/location_map/location_missing.tsx b/x-pack/plugins/uptime/public/components/monitor/location_map/location_missing.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/location_map/location_missing.tsx rename to x-pack/plugins/uptime/public/components/monitor/location_map/location_missing.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/location_map/location_status_tags.tsx b/x-pack/plugins/uptime/public/components/monitor/location_map/location_status_tags.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/location_map/location_status_tags.tsx rename to x-pack/plugins/uptime/public/components/monitor/location_map/location_status_tags.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/ml/__tests__/__snapshots__/confirm_delete.test.tsx.snap b/x-pack/plugins/uptime/public/components/monitor/ml/__tests__/__snapshots__/confirm_delete.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/ml/__tests__/__snapshots__/confirm_delete.test.tsx.snap rename to x-pack/plugins/uptime/public/components/monitor/ml/__tests__/__snapshots__/confirm_delete.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/ml/__tests__/__snapshots__/license_info.test.tsx.snap b/x-pack/plugins/uptime/public/components/monitor/ml/__tests__/__snapshots__/license_info.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/ml/__tests__/__snapshots__/license_info.test.tsx.snap rename to x-pack/plugins/uptime/public/components/monitor/ml/__tests__/__snapshots__/license_info.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/ml/__tests__/__snapshots__/ml_flyout.test.tsx.snap b/x-pack/plugins/uptime/public/components/monitor/ml/__tests__/__snapshots__/ml_flyout.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/ml/__tests__/__snapshots__/ml_flyout.test.tsx.snap rename to x-pack/plugins/uptime/public/components/monitor/ml/__tests__/__snapshots__/ml_flyout.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/ml/__tests__/__snapshots__/ml_integerations.test.tsx.snap b/x-pack/plugins/uptime/public/components/monitor/ml/__tests__/__snapshots__/ml_integerations.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/ml/__tests__/__snapshots__/ml_integerations.test.tsx.snap rename to x-pack/plugins/uptime/public/components/monitor/ml/__tests__/__snapshots__/ml_integerations.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/ml/__tests__/__snapshots__/ml_job_link.test.tsx.snap b/x-pack/plugins/uptime/public/components/monitor/ml/__tests__/__snapshots__/ml_job_link.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/ml/__tests__/__snapshots__/ml_job_link.test.tsx.snap rename to x-pack/plugins/uptime/public/components/monitor/ml/__tests__/__snapshots__/ml_job_link.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/ml/__tests__/__snapshots__/ml_manage_job.test.tsx.snap b/x-pack/plugins/uptime/public/components/monitor/ml/__tests__/__snapshots__/ml_manage_job.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/ml/__tests__/__snapshots__/ml_manage_job.test.tsx.snap rename to x-pack/plugins/uptime/public/components/monitor/ml/__tests__/__snapshots__/ml_manage_job.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/ml/__tests__/confirm_delete.test.tsx b/x-pack/plugins/uptime/public/components/monitor/ml/__tests__/confirm_delete.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/ml/__tests__/confirm_delete.test.tsx rename to x-pack/plugins/uptime/public/components/monitor/ml/__tests__/confirm_delete.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/ml/__tests__/license_info.test.tsx b/x-pack/plugins/uptime/public/components/monitor/ml/__tests__/license_info.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/ml/__tests__/license_info.test.tsx rename to x-pack/plugins/uptime/public/components/monitor/ml/__tests__/license_info.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/ml/__tests__/ml_flyout.test.tsx b/x-pack/plugins/uptime/public/components/monitor/ml/__tests__/ml_flyout.test.tsx similarity index 97% rename from x-pack/legacy/plugins/uptime/public/components/monitor/ml/__tests__/ml_flyout.test.tsx rename to x-pack/plugins/uptime/public/components/monitor/ml/__tests__/ml_flyout.test.tsx index c0b02181dcce1..31cdcfac9feef 100644 --- a/x-pack/legacy/plugins/uptime/public/components/monitor/ml/__tests__/ml_flyout.test.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/ml/__tests__/ml_flyout.test.tsx @@ -9,7 +9,7 @@ import { renderWithIntl, shallowWithIntl } from 'test_utils/enzyme_helpers'; import { MLFlyoutView } from '../ml_flyout'; import { UptimeSettingsContext } from '../../../../contexts'; import { CLIENT_DEFAULTS } from '../../../../../common/constants'; -import { License } from '../../../../../../../../plugins/licensing/common/license'; +import { License } from '../../../../../../../plugins/licensing/common/license'; const expiredLicense = new License({ signature: 'test signature', diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/ml/__tests__/ml_integerations.test.tsx b/x-pack/plugins/uptime/public/components/monitor/ml/__tests__/ml_integerations.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/ml/__tests__/ml_integerations.test.tsx rename to x-pack/plugins/uptime/public/components/monitor/ml/__tests__/ml_integerations.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/ml/__tests__/ml_job_link.test.tsx b/x-pack/plugins/uptime/public/components/monitor/ml/__tests__/ml_job_link.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/ml/__tests__/ml_job_link.test.tsx rename to x-pack/plugins/uptime/public/components/monitor/ml/__tests__/ml_job_link.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/ml/__tests__/ml_manage_job.test.tsx b/x-pack/plugins/uptime/public/components/monitor/ml/__tests__/ml_manage_job.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/ml/__tests__/ml_manage_job.test.tsx rename to x-pack/plugins/uptime/public/components/monitor/ml/__tests__/ml_manage_job.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/ml/confirm_delete.tsx b/x-pack/plugins/uptime/public/components/monitor/ml/confirm_delete.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/ml/confirm_delete.tsx rename to x-pack/plugins/uptime/public/components/monitor/ml/confirm_delete.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/ml/index.ts b/x-pack/plugins/uptime/public/components/monitor/ml/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/ml/index.ts rename to x-pack/plugins/uptime/public/components/monitor/ml/index.ts diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/ml/license_info.tsx b/x-pack/plugins/uptime/public/components/monitor/ml/license_info.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/ml/license_info.tsx rename to x-pack/plugins/uptime/public/components/monitor/ml/license_info.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/ml/manage_ml_job.tsx b/x-pack/plugins/uptime/public/components/monitor/ml/manage_ml_job.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/ml/manage_ml_job.tsx rename to x-pack/plugins/uptime/public/components/monitor/ml/manage_ml_job.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/ml/ml_flyout.tsx b/x-pack/plugins/uptime/public/components/monitor/ml/ml_flyout.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/ml/ml_flyout.tsx rename to x-pack/plugins/uptime/public/components/monitor/ml/ml_flyout.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/ml/ml_flyout_container.tsx b/x-pack/plugins/uptime/public/components/monitor/ml/ml_flyout_container.tsx similarity index 98% rename from x-pack/legacy/plugins/uptime/public/components/monitor/ml/ml_flyout_container.tsx rename to x-pack/plugins/uptime/public/components/monitor/ml/ml_flyout_container.tsx index c3e8579ca4837..6eec30d405f76 100644 --- a/x-pack/legacy/plugins/uptime/public/components/monitor/ml/ml_flyout_container.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/ml/ml_flyout_container.tsx @@ -19,7 +19,7 @@ import * as labels from './translations'; import { useKibana, KibanaReactNotifications, -} from '../../../../../../../../src/plugins/kibana_react/public'; +} from '../../../../../../../src/plugins/kibana_react/public'; import { MLFlyoutView } from './ml_flyout'; import { ML_JOB_ID } from '../../../../common/constants'; import { UptimeRefreshContext, UptimeSettingsContext } from '../../../contexts'; diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/ml/ml_integeration.tsx b/x-pack/plugins/uptime/public/components/monitor/ml/ml_integeration.tsx similarity index 95% rename from x-pack/legacy/plugins/uptime/public/components/monitor/ml/ml_integeration.tsx rename to x-pack/plugins/uptime/public/components/monitor/ml/ml_integeration.tsx index 4963a901f0ecc..7f19885c15406 100644 --- a/x-pack/legacy/plugins/uptime/public/components/monitor/ml/ml_integeration.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/ml/ml_integeration.tsx @@ -18,9 +18,9 @@ import { ConfirmJobDeletion } from './confirm_delete'; import { UptimeRefreshContext } from '../../../contexts'; import { getMLJobId } from '../../../state/api/ml_anomaly'; import * as labels from './translations'; -import { useKibana } from '../../../../../../../../src/plugins/kibana_react/public'; +import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; import { ManageMLJobComponent } from './manage_ml_job'; -import { JobStat } from '../../../../../../../plugins/ml/common/types/data_recognizer'; +import { JobStat } from '../../../../../../plugins/ml/common/types/data_recognizer'; import { useMonitorId } from '../../../hooks'; export const MLIntegrationComponent = () => { diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/ml/ml_job_link.tsx b/x-pack/plugins/uptime/public/components/monitor/ml/ml_job_link.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/ml/ml_job_link.tsx rename to x-pack/plugins/uptime/public/components/monitor/ml/ml_job_link.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/ml/translations.tsx b/x-pack/plugins/uptime/public/components/monitor/ml/translations.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/ml/translations.tsx rename to x-pack/plugins/uptime/public/components/monitor/ml/translations.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/monitor_charts.tsx b/x-pack/plugins/uptime/public/components/monitor/monitor_charts.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/monitor_charts.tsx rename to x-pack/plugins/uptime/public/components/monitor/monitor_charts.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/monitor_duration/index.ts b/x-pack/plugins/uptime/public/components/monitor/monitor_duration/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/monitor_duration/index.ts rename to x-pack/plugins/uptime/public/components/monitor/monitor_duration/index.ts diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/monitor_duration/monitor_duration.tsx b/x-pack/plugins/uptime/public/components/monitor/monitor_duration/monitor_duration.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/monitor_duration/monitor_duration.tsx rename to x-pack/plugins/uptime/public/components/monitor/monitor_duration/monitor_duration.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/monitor_duration/monitor_duration_container.tsx b/x-pack/plugins/uptime/public/components/monitor/monitor_duration/monitor_duration_container.tsx similarity index 96% rename from x-pack/legacy/plugins/uptime/public/components/monitor/monitor_duration/monitor_duration_container.tsx rename to x-pack/plugins/uptime/public/components/monitor/monitor_duration/monitor_duration_container.tsx index 7e39b977f1271..52d4f620f84b3 100644 --- a/x-pack/legacy/plugins/uptime/public/components/monitor/monitor_duration/monitor_duration_container.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/monitor_duration/monitor_duration_container.tsx @@ -20,7 +20,7 @@ import { } from '../../../state/selectors'; import { UptimeRefreshContext } from '../../../contexts'; import { getMLJobId } from '../../../state/api/ml_anomaly'; -import { JobStat } from '../../../../../../../plugins/ml/common/types/data_recognizer'; +import { JobStat } from '../../../../../ml/common/types/data_recognizer'; import { MonitorDurationComponent } from './monitor_duration'; import { MonitorIdParam } from '../../../../common/types'; diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/monitor_status_details/__test__/__snapshots__/monitor_ssl_certificate.test.tsx.snap b/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/__snapshots__/monitor_ssl_certificate.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/monitor_status_details/__test__/__snapshots__/monitor_ssl_certificate.test.tsx.snap rename to x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/__snapshots__/monitor_ssl_certificate.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/monitor_status_details/__test__/__snapshots__/monitor_status.bar.test.tsx.snap b/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/__snapshots__/monitor_status.bar.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/monitor_status_details/__test__/__snapshots__/monitor_status.bar.test.tsx.snap rename to x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/__snapshots__/monitor_status.bar.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/monitor_status_details/__test__/__snapshots__/status_by_location.test.tsx.snap b/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/__snapshots__/status_by_location.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/monitor_status_details/__test__/__snapshots__/status_by_location.test.tsx.snap rename to x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/__snapshots__/status_by_location.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/monitor_status_details/__test__/monitor_ssl_certificate.test.tsx b/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/monitor_ssl_certificate.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/monitor_status_details/__test__/monitor_ssl_certificate.test.tsx rename to x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/monitor_ssl_certificate.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/monitor_status_details/__test__/monitor_status.bar.test.tsx b/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/monitor_status.bar.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/monitor_status_details/__test__/monitor_status.bar.test.tsx rename to x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/monitor_status.bar.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/monitor_status_details/__test__/status_by_location.test.tsx b/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/status_by_location.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/monitor_status_details/__test__/status_by_location.test.tsx rename to x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/status_by_location.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/monitor_status_details/index.ts b/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/monitor_status_details/index.ts rename to x-pack/plugins/uptime/public/components/monitor/monitor_status_details/index.ts diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/index.ts b/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/index.ts rename to x-pack/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/index.ts diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/ssl_certificate.tsx b/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/ssl_certificate.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/ssl_certificate.tsx rename to x-pack/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/ssl_certificate.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/status_bar.tsx b/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/status_bar.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/status_bar.tsx rename to x-pack/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/status_bar.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/status_bar_container.tsx b/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/status_bar_container.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/status_bar_container.tsx rename to x-pack/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/status_bar_container.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/status_by_location.tsx b/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/status_by_location.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/status_by_location.tsx rename to x-pack/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/status_by_location.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/translations.ts b/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/translations.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/translations.ts rename to x-pack/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/translations.ts diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/monitor_status_details/status_details.tsx b/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/status_details.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/monitor_status_details/status_details.tsx rename to x-pack/plugins/uptime/public/components/monitor/monitor_status_details/status_details.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/monitor_status_details/status_details_container.tsx b/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/status_details_container.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/monitor_status_details/status_details_container.tsx rename to x-pack/plugins/uptime/public/components/monitor/monitor_status_details/status_details_container.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/monitor_status_details/translations.ts b/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/translations.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/monitor_status_details/translations.ts rename to x-pack/plugins/uptime/public/components/monitor/monitor_status_details/translations.ts diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/ping_histogram/index.ts b/x-pack/plugins/uptime/public/components/monitor/ping_histogram/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/ping_histogram/index.ts rename to x-pack/plugins/uptime/public/components/monitor/ping_histogram/index.ts diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/ping_histogram/ping_histogram_container.tsx b/x-pack/plugins/uptime/public/components/monitor/ping_histogram/ping_histogram_container.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/ping_histogram/ping_histogram_container.tsx rename to x-pack/plugins/uptime/public/components/monitor/ping_histogram/ping_histogram_container.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/ping_list/__tests__/__snapshots__/doc_link_body.test.tsx.snap b/x-pack/plugins/uptime/public/components/monitor/ping_list/__tests__/__snapshots__/doc_link_body.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/ping_list/__tests__/__snapshots__/doc_link_body.test.tsx.snap rename to x-pack/plugins/uptime/public/components/monitor/ping_list/__tests__/__snapshots__/doc_link_body.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/ping_list/__tests__/__snapshots__/expanded_row.test.tsx.snap b/x-pack/plugins/uptime/public/components/monitor/ping_list/__tests__/__snapshots__/expanded_row.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/ping_list/__tests__/__snapshots__/expanded_row.test.tsx.snap rename to x-pack/plugins/uptime/public/components/monitor/ping_list/__tests__/__snapshots__/expanded_row.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/ping_list/__tests__/__snapshots__/ping_list.test.tsx.snap b/x-pack/plugins/uptime/public/components/monitor/ping_list/__tests__/__snapshots__/ping_list.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/ping_list/__tests__/__snapshots__/ping_list.test.tsx.snap rename to x-pack/plugins/uptime/public/components/monitor/ping_list/__tests__/__snapshots__/ping_list.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/ping_list/__tests__/doc_link_body.test.tsx b/x-pack/plugins/uptime/public/components/monitor/ping_list/__tests__/doc_link_body.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/ping_list/__tests__/doc_link_body.test.tsx rename to x-pack/plugins/uptime/public/components/monitor/ping_list/__tests__/doc_link_body.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/ping_list/__tests__/expanded_row.test.tsx b/x-pack/plugins/uptime/public/components/monitor/ping_list/__tests__/expanded_row.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/ping_list/__tests__/expanded_row.test.tsx rename to x-pack/plugins/uptime/public/components/monitor/ping_list/__tests__/expanded_row.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/ping_list/__tests__/ping_list.test.tsx b/x-pack/plugins/uptime/public/components/monitor/ping_list/__tests__/ping_list.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/ping_list/__tests__/ping_list.test.tsx rename to x-pack/plugins/uptime/public/components/monitor/ping_list/__tests__/ping_list.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/ping_list/doc_link_body.tsx b/x-pack/plugins/uptime/public/components/monitor/ping_list/doc_link_body.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/ping_list/doc_link_body.tsx rename to x-pack/plugins/uptime/public/components/monitor/ping_list/doc_link_body.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/ping_list/expanded_row.tsx b/x-pack/plugins/uptime/public/components/monitor/ping_list/expanded_row.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/ping_list/expanded_row.tsx rename to x-pack/plugins/uptime/public/components/monitor/ping_list/expanded_row.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/ping_list/index.tsx b/x-pack/plugins/uptime/public/components/monitor/ping_list/index.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/ping_list/index.tsx rename to x-pack/plugins/uptime/public/components/monitor/ping_list/index.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/ping_list/location_name.tsx b/x-pack/plugins/uptime/public/components/monitor/ping_list/location_name.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/ping_list/location_name.tsx rename to x-pack/plugins/uptime/public/components/monitor/ping_list/location_name.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/ping_list/ping_list.tsx b/x-pack/plugins/uptime/public/components/monitor/ping_list/ping_list.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/ping_list/ping_list.tsx rename to x-pack/plugins/uptime/public/components/monitor/ping_list/ping_list.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/monitor/ping_list/ping_list_container.tsx b/x-pack/plugins/uptime/public/components/monitor/ping_list/ping_list_container.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/monitor/ping_list/ping_list_container.tsx rename to x-pack/plugins/uptime/public/components/monitor/ping_list/ping_list_container.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/__tests__/__snapshots__/parsing_error_callout.test.tsx.snap b/x-pack/plugins/uptime/public/components/overview/__tests__/__snapshots__/parsing_error_callout.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/__tests__/__snapshots__/parsing_error_callout.test.tsx.snap rename to x-pack/plugins/uptime/public/components/overview/__tests__/__snapshots__/parsing_error_callout.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/__tests__/__snapshots__/snapshot.test.tsx.snap b/x-pack/plugins/uptime/public/components/overview/__tests__/__snapshots__/snapshot.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/__tests__/__snapshots__/snapshot.test.tsx.snap rename to x-pack/plugins/uptime/public/components/overview/__tests__/__snapshots__/snapshot.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/__tests__/__snapshots__/snapshot_heading.test.tsx.snap b/x-pack/plugins/uptime/public/components/overview/__tests__/__snapshots__/snapshot_heading.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/__tests__/__snapshots__/snapshot_heading.test.tsx.snap rename to x-pack/plugins/uptime/public/components/overview/__tests__/__snapshots__/snapshot_heading.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/__tests__/parsing_error_callout.test.tsx b/x-pack/plugins/uptime/public/components/overview/__tests__/parsing_error_callout.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/__tests__/parsing_error_callout.test.tsx rename to x-pack/plugins/uptime/public/components/overview/__tests__/parsing_error_callout.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/__tests__/snapshot.test.tsx b/x-pack/plugins/uptime/public/components/overview/__tests__/snapshot.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/__tests__/snapshot.test.tsx rename to x-pack/plugins/uptime/public/components/overview/__tests__/snapshot.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/__tests__/snapshot_heading.test.tsx b/x-pack/plugins/uptime/public/components/overview/__tests__/snapshot_heading.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/__tests__/snapshot_heading.test.tsx rename to x-pack/plugins/uptime/public/components/overview/__tests__/snapshot_heading.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/alerts/__tests__/alert_monitor_status.test.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/__tests__/alert_monitor_status.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/alerts/__tests__/alert_monitor_status.test.tsx rename to x-pack/plugins/uptime/public/components/overview/alerts/__tests__/alert_monitor_status.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx rename to x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx rename to x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/alerts/alerts_containers/index.ts b/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/alerts/alerts_containers/index.ts rename to x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/index.ts diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/alerts/alerts_containers/toggle_alert_flyout_button.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/toggle_alert_flyout_button.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/alerts/alerts_containers/toggle_alert_flyout_button.tsx rename to x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/toggle_alert_flyout_button.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/alerts/alerts_containers/uptime_alerts_flyout_wrapper.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/uptime_alerts_flyout_wrapper.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/alerts/alerts_containers/uptime_alerts_flyout_wrapper.tsx rename to x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/uptime_alerts_flyout_wrapper.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/alerts/index.ts b/x-pack/plugins/uptime/public/components/overview/alerts/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/alerts/index.ts rename to x-pack/plugins/uptime/public/components/overview/alerts/index.ts diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/alerts/toggle_alert_flyout_button.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/toggle_alert_flyout_button.tsx similarity index 97% rename from x-pack/legacy/plugins/uptime/public/components/overview/alerts/toggle_alert_flyout_button.tsx rename to x-pack/plugins/uptime/public/components/overview/alerts/toggle_alert_flyout_button.tsx index 04dfe4b3e3509..92fc015a276d3 100644 --- a/x-pack/legacy/plugins/uptime/public/components/overview/alerts/toggle_alert_flyout_button.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/toggle_alert_flyout_button.tsx @@ -8,7 +8,7 @@ import { EuiButtonEmpty, EuiContextMenuItem, EuiContextMenuPanel, EuiPopover } f import React, { useState } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; -import { useKibana } from '../../../../../../../../src/plugins/kibana_react/public'; +import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; interface Props { setAlertFlyoutVisible: (value: boolean) => void; diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/alerts/uptime_alerts_context_provider.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/uptime_alerts_context_provider.tsx similarity index 83% rename from x-pack/legacy/plugins/uptime/public/components/overview/alerts/uptime_alerts_context_provider.tsx rename to x-pack/plugins/uptime/public/components/overview/alerts/uptime_alerts_context_provider.tsx index 09e6dc72b7f98..262e1552e3660 100644 --- a/x-pack/legacy/plugins/uptime/public/components/overview/alerts/uptime_alerts_context_provider.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/uptime_alerts_context_provider.tsx @@ -5,8 +5,8 @@ */ import React from 'react'; -import { AlertsContextProvider } from '../../../../../../../plugins/triggers_actions_ui/public'; -import { useKibana } from '../../../../../../../../src/plugins/kibana_react/public'; +import { AlertsContextProvider } from '../../../../../../plugins/triggers_actions_ui/public'; +import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; export const UptimeAlertsContextProvider: React.FC = ({ children }) => { const { diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/alerts/uptime_alerts_flyout_wrapper.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/uptime_alerts_flyout_wrapper.tsx similarity index 90% rename from x-pack/legacy/plugins/uptime/public/components/overview/alerts/uptime_alerts_flyout_wrapper.tsx rename to x-pack/plugins/uptime/public/components/overview/alerts/uptime_alerts_flyout_wrapper.tsx index 13705e7d19293..9b1d3a73dc661 100644 --- a/x-pack/legacy/plugins/uptime/public/components/overview/alerts/uptime_alerts_flyout_wrapper.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/uptime_alerts_flyout_wrapper.tsx @@ -5,7 +5,7 @@ */ import React from 'react'; -import { AlertAdd } from '../../../../../../../plugins/triggers_actions_ui/public'; +import { AlertAdd } from '../../../../../../plugins/triggers_actions_ui/public'; interface Props { alertFlyoutVisible: boolean; diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/empty_state/__tests__/__snapshots__/data_or_index_missing.test.tsx.snap b/x-pack/plugins/uptime/public/components/overview/empty_state/__tests__/__snapshots__/data_or_index_missing.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/empty_state/__tests__/__snapshots__/data_or_index_missing.test.tsx.snap rename to x-pack/plugins/uptime/public/components/overview/empty_state/__tests__/__snapshots__/data_or_index_missing.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/empty_state/__tests__/__snapshots__/empty_state.test.tsx.snap b/x-pack/plugins/uptime/public/components/overview/empty_state/__tests__/__snapshots__/empty_state.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/empty_state/__tests__/__snapshots__/empty_state.test.tsx.snap rename to x-pack/plugins/uptime/public/components/overview/empty_state/__tests__/__snapshots__/empty_state.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/empty_state/__tests__/data_or_index_missing.test.tsx b/x-pack/plugins/uptime/public/components/overview/empty_state/__tests__/data_or_index_missing.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/empty_state/__tests__/data_or_index_missing.test.tsx rename to x-pack/plugins/uptime/public/components/overview/empty_state/__tests__/data_or_index_missing.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/empty_state/__tests__/empty_state.test.tsx b/x-pack/plugins/uptime/public/components/overview/empty_state/__tests__/empty_state.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/empty_state/__tests__/empty_state.test.tsx rename to x-pack/plugins/uptime/public/components/overview/empty_state/__tests__/empty_state.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/empty_state/data_or_index_missing.tsx b/x-pack/plugins/uptime/public/components/overview/empty_state/data_or_index_missing.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/empty_state/data_or_index_missing.tsx rename to x-pack/plugins/uptime/public/components/overview/empty_state/data_or_index_missing.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/empty_state/empty_state.tsx b/x-pack/plugins/uptime/public/components/overview/empty_state/empty_state.tsx similarity index 96% rename from x-pack/legacy/plugins/uptime/public/components/overview/empty_state/empty_state.tsx rename to x-pack/plugins/uptime/public/components/overview/empty_state/empty_state.tsx index 651103a34bf21..d38f203739cea 100644 --- a/x-pack/legacy/plugins/uptime/public/components/overview/empty_state/empty_state.tsx +++ b/x-pack/plugins/uptime/public/components/overview/empty_state/empty_state.tsx @@ -10,7 +10,7 @@ import { EmptyStateError } from './empty_state_error'; import { EmptyStateLoading } from './empty_state_loading'; import { DataOrIndexMissing } from './data_or_index_missing'; import { DynamicSettings, StatesIndexStatus } from '../../../../common/runtime_types'; -import { IHttpFetchError } from '../../../../../../../../target/types/core/public/http'; +import { IHttpFetchError } from '../../../../../../../target/types/core/public/http'; interface EmptyStateProps { children: JSX.Element[] | JSX.Element; diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/empty_state/empty_state_container.tsx b/x-pack/plugins/uptime/public/components/overview/empty_state/empty_state_container.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/empty_state/empty_state_container.tsx rename to x-pack/plugins/uptime/public/components/overview/empty_state/empty_state_container.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/empty_state/empty_state_error.tsx b/x-pack/plugins/uptime/public/components/overview/empty_state/empty_state_error.tsx similarity index 95% rename from x-pack/legacy/plugins/uptime/public/components/overview/empty_state/empty_state_error.tsx rename to x-pack/plugins/uptime/public/components/overview/empty_state/empty_state_error.tsx index 1135b969018a1..aa4040e319e0f 100644 --- a/x-pack/legacy/plugins/uptime/public/components/overview/empty_state/empty_state_error.tsx +++ b/x-pack/plugins/uptime/public/components/overview/empty_state/empty_state_error.tsx @@ -7,7 +7,7 @@ import { EuiEmptyPrompt, EuiPanel, EuiTitle, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React, { Fragment } from 'react'; -import { IHttpFetchError } from '../../../../../../../../target/types/core/public/http'; +import { IHttpFetchError } from '../../../../../../../target/types/core/public/http'; interface EmptyStateErrorProps { errors: IHttpFetchError[]; diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/empty_state/empty_state_loading.tsx b/x-pack/plugins/uptime/public/components/overview/empty_state/empty_state_loading.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/empty_state/empty_state_loading.tsx rename to x-pack/plugins/uptime/public/components/overview/empty_state/empty_state_loading.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/empty_state/index.ts b/x-pack/plugins/uptime/public/components/overview/empty_state/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/empty_state/index.ts rename to x-pack/plugins/uptime/public/components/overview/empty_state/index.ts diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/filter_group/__tests__/__snapshots__/filter_popover.test.tsx.snap b/x-pack/plugins/uptime/public/components/overview/filter_group/__tests__/__snapshots__/filter_popover.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/filter_group/__tests__/__snapshots__/filter_popover.test.tsx.snap rename to x-pack/plugins/uptime/public/components/overview/filter_group/__tests__/__snapshots__/filter_popover.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/filter_group/__tests__/__snapshots__/filter_status_button.test.tsx.snap b/x-pack/plugins/uptime/public/components/overview/filter_group/__tests__/__snapshots__/filter_status_button.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/filter_group/__tests__/__snapshots__/filter_status_button.test.tsx.snap rename to x-pack/plugins/uptime/public/components/overview/filter_group/__tests__/__snapshots__/filter_status_button.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/filter_group/__tests__/__snapshots__/parse_filter_map.test.ts.snap b/x-pack/plugins/uptime/public/components/overview/filter_group/__tests__/__snapshots__/parse_filter_map.test.ts.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/filter_group/__tests__/__snapshots__/parse_filter_map.test.ts.snap rename to x-pack/plugins/uptime/public/components/overview/filter_group/__tests__/__snapshots__/parse_filter_map.test.ts.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/filter_group/__tests__/filter_popover.test.tsx b/x-pack/plugins/uptime/public/components/overview/filter_group/__tests__/filter_popover.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/filter_group/__tests__/filter_popover.test.tsx rename to x-pack/plugins/uptime/public/components/overview/filter_group/__tests__/filter_popover.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/filter_group/__tests__/filter_status_button.test.tsx b/x-pack/plugins/uptime/public/components/overview/filter_group/__tests__/filter_status_button.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/filter_group/__tests__/filter_status_button.test.tsx rename to x-pack/plugins/uptime/public/components/overview/filter_group/__tests__/filter_status_button.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/filter_group/__tests__/parse_filter_map.test.ts b/x-pack/plugins/uptime/public/components/overview/filter_group/__tests__/parse_filter_map.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/filter_group/__tests__/parse_filter_map.test.ts rename to x-pack/plugins/uptime/public/components/overview/filter_group/__tests__/parse_filter_map.test.ts diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/filter_group/__tests__/toggle_selected_item.test.ts b/x-pack/plugins/uptime/public/components/overview/filter_group/__tests__/toggle_selected_item.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/filter_group/__tests__/toggle_selected_item.test.ts rename to x-pack/plugins/uptime/public/components/overview/filter_group/__tests__/toggle_selected_item.test.ts diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/filter_group/filter_group.tsx b/x-pack/plugins/uptime/public/components/overview/filter_group/filter_group.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/filter_group/filter_group.tsx rename to x-pack/plugins/uptime/public/components/overview/filter_group/filter_group.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/filter_group/filter_group_container.tsx b/x-pack/plugins/uptime/public/components/overview/filter_group/filter_group_container.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/filter_group/filter_group_container.tsx rename to x-pack/plugins/uptime/public/components/overview/filter_group/filter_group_container.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/filter_group/filter_popover.tsx b/x-pack/plugins/uptime/public/components/overview/filter_group/filter_popover.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/filter_group/filter_popover.tsx rename to x-pack/plugins/uptime/public/components/overview/filter_group/filter_popover.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/filter_group/filter_status_button.tsx b/x-pack/plugins/uptime/public/components/overview/filter_group/filter_status_button.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/filter_group/filter_status_button.tsx rename to x-pack/plugins/uptime/public/components/overview/filter_group/filter_status_button.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/filter_group/index.ts b/x-pack/plugins/uptime/public/components/overview/filter_group/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/filter_group/index.ts rename to x-pack/plugins/uptime/public/components/overview/filter_group/index.ts diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/filter_group/parse_filter_map.ts b/x-pack/plugins/uptime/public/components/overview/filter_group/parse_filter_map.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/filter_group/parse_filter_map.ts rename to x-pack/plugins/uptime/public/components/overview/filter_group/parse_filter_map.ts diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/filter_group/toggle_selected_item.ts b/x-pack/plugins/uptime/public/components/overview/filter_group/toggle_selected_item.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/filter_group/toggle_selected_item.ts rename to x-pack/plugins/uptime/public/components/overview/filter_group/toggle_selected_item.ts diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/filter_group/uptime_filter_button.tsx b/x-pack/plugins/uptime/public/components/overview/filter_group/uptime_filter_button.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/filter_group/uptime_filter_button.tsx rename to x-pack/plugins/uptime/public/components/overview/filter_group/uptime_filter_button.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/index.ts b/x-pack/plugins/uptime/public/components/overview/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/index.ts rename to x-pack/plugins/uptime/public/components/overview/index.ts diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/kuery_bar/index.ts b/x-pack/plugins/uptime/public/components/overview/kuery_bar/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/kuery_bar/index.ts rename to x-pack/plugins/uptime/public/components/overview/kuery_bar/index.ts diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/kuery_bar/kuery_bar.tsx b/x-pack/plugins/uptime/public/components/overview/kuery_bar/kuery_bar.tsx similarity index 98% rename from x-pack/legacy/plugins/uptime/public/components/overview/kuery_bar/kuery_bar.tsx rename to x-pack/plugins/uptime/public/components/overview/kuery_bar/kuery_bar.tsx index 63aceed2be636..792fff4c7cdca 100644 --- a/x-pack/legacy/plugins/uptime/public/components/overview/kuery_bar/kuery_bar.tsx +++ b/x-pack/plugins/uptime/public/components/overview/kuery_bar/kuery_bar.tsx @@ -16,7 +16,7 @@ import { IIndexPattern, QuerySuggestion, DataPublicPluginSetup, -} from '../../../../../../../../src/plugins/data/public'; +} from '../../../../../../../src/plugins/data/public'; const Container = styled.div` margin-bottom: 10px; diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/kuery_bar/kuery_bar_container.tsx b/x-pack/plugins/uptime/public/components/overview/kuery_bar/kuery_bar_container.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/kuery_bar/kuery_bar_container.tsx rename to x-pack/plugins/uptime/public/components/overview/kuery_bar/kuery_bar_container.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/kuery_bar/typeahead/click_outside.js b/x-pack/plugins/uptime/public/components/overview/kuery_bar/typeahead/click_outside.js similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/kuery_bar/typeahead/click_outside.js rename to x-pack/plugins/uptime/public/components/overview/kuery_bar/typeahead/click_outside.js diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/kuery_bar/typeahead/index.d.ts b/x-pack/plugins/uptime/public/components/overview/kuery_bar/typeahead/index.d.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/kuery_bar/typeahead/index.d.ts rename to x-pack/plugins/uptime/public/components/overview/kuery_bar/typeahead/index.d.ts diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/kuery_bar/typeahead/index.js b/x-pack/plugins/uptime/public/components/overview/kuery_bar/typeahead/index.js similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/kuery_bar/typeahead/index.js rename to x-pack/plugins/uptime/public/components/overview/kuery_bar/typeahead/index.js diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/kuery_bar/typeahead/suggestion.js b/x-pack/plugins/uptime/public/components/overview/kuery_bar/typeahead/suggestion.js similarity index 97% rename from x-pack/legacy/plugins/uptime/public/components/overview/kuery_bar/typeahead/suggestion.js rename to x-pack/plugins/uptime/public/components/overview/kuery_bar/typeahead/suggestion.js index 2b5ad9b59e39f..936eae04ffa64 100644 --- a/x-pack/legacy/plugins/uptime/public/components/overview/kuery_bar/typeahead/suggestion.js +++ b/x-pack/plugins/uptime/public/components/overview/kuery_bar/typeahead/suggestion.js @@ -14,7 +14,7 @@ import { units, fontSizes, unit, -} from '../../../../../../apm/public/style/variables'; +} from '../../../../../../../legacy/plugins/apm/public/style/variables'; import { tint } from 'polished'; import theme from '@elastic/eui/dist/eui_theme_light.json'; diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/kuery_bar/typeahead/suggestions.js b/x-pack/plugins/uptime/public/components/overview/kuery_bar/typeahead/suggestions.js similarity index 95% rename from x-pack/legacy/plugins/uptime/public/components/overview/kuery_bar/typeahead/suggestions.js rename to x-pack/plugins/uptime/public/components/overview/kuery_bar/typeahead/suggestions.js index 7fbabe71bcdb5..ac6832050b9d3 100644 --- a/x-pack/legacy/plugins/uptime/public/components/overview/kuery_bar/typeahead/suggestions.js +++ b/x-pack/plugins/uptime/public/components/overview/kuery_bar/typeahead/suggestions.js @@ -9,7 +9,7 @@ import PropTypes from 'prop-types'; import styled from 'styled-components'; import { isEmpty } from 'lodash'; import Suggestion from './suggestion'; -import { units, px, unit } from '../../../../../../apm/public/style/variables'; +import { units, px, unit } from '../../../../../../../legacy/plugins/apm/public/style/variables'; import { tint } from 'polished'; import theme from '@elastic/eui/dist/eui_theme_light.json'; diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/__tests__/__snapshots__/monitor_list.test.tsx.snap b/x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/__snapshots__/monitor_list.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/__tests__/__snapshots__/monitor_list.test.tsx.snap rename to x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/__snapshots__/monitor_list.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/__tests__/__snapshots__/monitor_list_status_column.test.tsx.snap b/x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/__snapshots__/monitor_list_status_column.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/__tests__/__snapshots__/monitor_list_status_column.test.tsx.snap rename to x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/__snapshots__/monitor_list_status_column.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/__tests__/__snapshots__/monitor_page_link.test.tsx.snap b/x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/__snapshots__/monitor_page_link.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/__tests__/__snapshots__/monitor_page_link.test.tsx.snap rename to x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/__snapshots__/monitor_page_link.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/__tests__/monitor_list.test.tsx b/x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/monitor_list.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/__tests__/monitor_list.test.tsx rename to x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/monitor_list.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/__tests__/monitor_list_page_size_select.test.tsx b/x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/monitor_list_page_size_select.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/__tests__/monitor_list_page_size_select.test.tsx rename to x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/monitor_list_page_size_select.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/__tests__/monitor_list_status_column.test.tsx b/x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/monitor_list_status_column.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/__tests__/monitor_list_status_column.test.tsx rename to x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/monitor_list_status_column.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/__tests__/monitor_page_link.test.tsx b/x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/monitor_page_link.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/__tests__/monitor_page_link.test.tsx rename to x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/monitor_page_link.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/__tests__/parse_timestamp.test.ts b/x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/parse_timestamp.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/__tests__/parse_timestamp.test.ts rename to x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/parse_timestamp.test.ts diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/index.ts b/x-pack/plugins/uptime/public/components/overview/monitor_list/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/index.ts rename to x-pack/plugins/uptime/public/components/overview/monitor_list/index.ts diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list.tsx b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list.tsx similarity index 96% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list.tsx rename to x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list.tsx index 18e2e2437e147..7e9536689470e 100644 --- a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list.tsx +++ b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list.tsx @@ -202,13 +202,7 @@ export const MonitorListComponent: React.FC = ({ itemId="monitor_id" itemIdToExpandedRowMap={getExpandedRowMap()} items={items} - // TODO: not needed without sorting and pagination - // onChange={onChange} noItemsMessage={!!filters ? labels.NO_MONITOR_ITEM_SELECTED : labels.NO_DATA_MESSAGE} - // TODO: reintegrate pagination in future release - // pagination={pagination} - // TODO: reintegrate sorting in future release - // sorting={sorting} columns={columns} /> diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_container.tsx b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_container.tsx similarity index 95% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_container.tsx rename to x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_container.tsx index 5bfe6ff0c5b4f..6fb880e28c734 100644 --- a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_container.tsx +++ b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_container.tsx @@ -9,7 +9,7 @@ import { useSelector, useDispatch } from 'react-redux'; import { getMonitorList } from '../../../state/actions'; import { FetchMonitorStatesQueryArgs } from '../../../../common/runtime_types'; import { monitorListSelector } from '../../../state/selectors'; -import { MonitorListComponent } from './index'; +import { MonitorListComponent } from './monitor_list'; export interface MonitorListProps { filters?: string; diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/__snapshots__/integration_group.test.tsx.snap b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/__snapshots__/integration_group.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/__snapshots__/integration_group.test.tsx.snap rename to x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/__snapshots__/integration_group.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/__snapshots__/integration_link.test.tsx.snap b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/__snapshots__/integration_link.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/__snapshots__/integration_link.test.tsx.snap rename to x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/__snapshots__/integration_link.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/__snapshots__/monitor_list_drawer.test.tsx.snap b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/__snapshots__/monitor_list_drawer.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/__snapshots__/monitor_list_drawer.test.tsx.snap rename to x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/__snapshots__/monitor_list_drawer.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/__snapshots__/monitor_status_list.test.tsx.snap b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/__snapshots__/monitor_status_list.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/__snapshots__/monitor_status_list.test.tsx.snap rename to x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/__snapshots__/monitor_status_list.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/__snapshots__/monitor_status_row.test.tsx.snap b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/__snapshots__/monitor_status_row.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/__snapshots__/monitor_status_row.test.tsx.snap rename to x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/__snapshots__/monitor_status_row.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/__snapshots__/most_recent_error.test.tsx.snap b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/__snapshots__/most_recent_error.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/__snapshots__/most_recent_error.test.tsx.snap rename to x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/__snapshots__/most_recent_error.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/data.json b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/data.json similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/data.json rename to x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/data.json diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/integration_group.test.tsx b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/integration_group.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/integration_group.test.tsx rename to x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/integration_group.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/integration_link.test.tsx b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/integration_link.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/integration_link.test.tsx rename to x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/integration_link.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/monitor_list_drawer.test.tsx b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/monitor_list_drawer.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/monitor_list_drawer.test.tsx rename to x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/monitor_list_drawer.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/monitor_status_list.test.tsx b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/monitor_status_list.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/monitor_status_list.test.tsx rename to x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/monitor_status_list.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/monitor_status_row.test.tsx b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/monitor_status_row.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/monitor_status_row.test.tsx rename to x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/monitor_status_row.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/most_recent_error.test.tsx b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/most_recent_error.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/most_recent_error.test.tsx rename to x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/most_recent_error.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/actions_popover/actions_popover.tsx b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/actions_popover/actions_popover.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/actions_popover/actions_popover.tsx rename to x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/actions_popover/actions_popover.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/actions_popover/actions_popover_container.tsx b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/actions_popover/actions_popover_container.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/actions_popover/actions_popover_container.tsx rename to x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/actions_popover/actions_popover_container.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/actions_popover/integration_group.tsx b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/actions_popover/integration_group.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/actions_popover/integration_group.tsx rename to x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/actions_popover/integration_group.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/actions_popover/integration_link.tsx b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/actions_popover/integration_link.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/actions_popover/integration_link.tsx rename to x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/actions_popover/integration_link.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/index.ts b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/index.ts rename to x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/index.ts diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/list_drawer_container.tsx b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/list_drawer_container.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/list_drawer_container.tsx rename to x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/list_drawer_container.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/monitor_list_drawer.tsx b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/monitor_list_drawer.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/monitor_list_drawer.tsx rename to x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/monitor_list_drawer.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/monitor_status_list.tsx b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/monitor_status_list.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/monitor_status_list.tsx rename to x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/monitor_status_list.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/monitor_status_row.tsx b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/monitor_status_row.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/monitor_status_row.tsx rename to x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/monitor_status_row.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/most_recent_error.tsx b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/most_recent_error.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/most_recent_error.tsx rename to x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/most_recent_error.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_page_size_select.tsx b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_page_size_select.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_page_size_select.tsx rename to x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_page_size_select.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_status_column.tsx b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_status_column.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_list_status_column.tsx rename to x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_status_column.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_page_link.tsx b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_page_link.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/monitor_page_link.tsx rename to x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_page_link.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/overview_page_link.tsx b/x-pack/plugins/uptime/public/components/overview/monitor_list/overview_page_link.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/overview_page_link.tsx rename to x-pack/plugins/uptime/public/components/overview/monitor_list/overview_page_link.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/parse_timestamp.ts b/x-pack/plugins/uptime/public/components/overview/monitor_list/parse_timestamp.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/parse_timestamp.ts rename to x-pack/plugins/uptime/public/components/overview/monitor_list/parse_timestamp.ts diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/translations.ts b/x-pack/plugins/uptime/public/components/overview/monitor_list/translations.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/translations.ts rename to x-pack/plugins/uptime/public/components/overview/monitor_list/translations.ts diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/types.ts b/x-pack/plugins/uptime/public/components/overview/monitor_list/types.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/monitor_list/types.ts rename to x-pack/plugins/uptime/public/components/overview/monitor_list/types.ts diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/overview_container.tsx b/x-pack/plugins/uptime/public/components/overview/overview_container.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/overview_container.tsx rename to x-pack/plugins/uptime/public/components/overview/overview_container.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/parsing_error_callout.tsx b/x-pack/plugins/uptime/public/components/overview/parsing_error_callout.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/parsing_error_callout.tsx rename to x-pack/plugins/uptime/public/components/overview/parsing_error_callout.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/snapshot/index.ts b/x-pack/plugins/uptime/public/components/overview/snapshot/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/snapshot/index.ts rename to x-pack/plugins/uptime/public/components/overview/snapshot/index.ts diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/snapshot/snapshot.tsx b/x-pack/plugins/uptime/public/components/overview/snapshot/snapshot.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/snapshot/snapshot.tsx rename to x-pack/plugins/uptime/public/components/overview/snapshot/snapshot.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/snapshot/snapshot_container.tsx b/x-pack/plugins/uptime/public/components/overview/snapshot/snapshot_container.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/snapshot/snapshot_container.tsx rename to x-pack/plugins/uptime/public/components/overview/snapshot/snapshot_container.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/snapshot/snapshot_heading.tsx b/x-pack/plugins/uptime/public/components/overview/snapshot/snapshot_heading.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/snapshot/snapshot_heading.tsx rename to x-pack/plugins/uptime/public/components/overview/snapshot/snapshot_heading.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/overview/status_panel.tsx b/x-pack/plugins/uptime/public/components/overview/status_panel.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/overview/status_panel.tsx rename to x-pack/plugins/uptime/public/components/overview/status_panel.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/__snapshots__/certificate_form.test.tsx.snap b/x-pack/plugins/uptime/public/components/settings/__tests__/__snapshots__/certificate_form.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/settings/__tests__/__snapshots__/certificate_form.test.tsx.snap rename to x-pack/plugins/uptime/public/components/settings/__tests__/__snapshots__/certificate_form.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/__snapshots__/indices_form.test.tsx.snap b/x-pack/plugins/uptime/public/components/settings/__tests__/__snapshots__/indices_form.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/settings/__tests__/__snapshots__/indices_form.test.tsx.snap rename to x-pack/plugins/uptime/public/components/settings/__tests__/__snapshots__/indices_form.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/certificate_form.test.tsx b/x-pack/plugins/uptime/public/components/settings/__tests__/certificate_form.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/settings/__tests__/certificate_form.test.tsx rename to x-pack/plugins/uptime/public/components/settings/__tests__/certificate_form.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/indices_form.test.tsx b/x-pack/plugins/uptime/public/components/settings/__tests__/indices_form.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/settings/__tests__/indices_form.test.tsx rename to x-pack/plugins/uptime/public/components/settings/__tests__/indices_form.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/settings/certificate_form.tsx b/x-pack/plugins/uptime/public/components/settings/certificate_form.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/settings/certificate_form.tsx rename to x-pack/plugins/uptime/public/components/settings/certificate_form.tsx diff --git a/x-pack/legacy/plugins/uptime/public/components/settings/indices_form.tsx b/x-pack/plugins/uptime/public/components/settings/indices_form.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/components/settings/indices_form.tsx rename to x-pack/plugins/uptime/public/components/settings/indices_form.tsx diff --git a/x-pack/legacy/plugins/uptime/public/contexts/index.ts b/x-pack/plugins/uptime/public/contexts/index.ts similarity index 82% rename from x-pack/legacy/plugins/uptime/public/contexts/index.ts rename to x-pack/plugins/uptime/public/contexts/index.ts index 2b27fcfe907ab..243a25c26901a 100644 --- a/x-pack/legacy/plugins/uptime/public/contexts/index.ts +++ b/x-pack/plugins/uptime/public/contexts/index.ts @@ -11,3 +11,7 @@ export { UptimeSettingsContextProvider, } from './uptime_settings_context'; export { UptimeThemeContextProvider, UptimeThemeContext } from './uptime_theme_context'; +export { + UptimeStartupPluginsContext, + UptimeStartupPluginsContextProvider, +} from './uptime_startup_plugins_context'; diff --git a/x-pack/legacy/plugins/uptime/public/contexts/uptime_refresh_context.tsx b/x-pack/plugins/uptime/public/contexts/uptime_refresh_context.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/contexts/uptime_refresh_context.tsx rename to x-pack/plugins/uptime/public/contexts/uptime_refresh_context.tsx diff --git a/x-pack/legacy/plugins/uptime/public/contexts/uptime_settings_context.tsx b/x-pack/plugins/uptime/public/contexts/uptime_settings_context.tsx similarity index 96% rename from x-pack/legacy/plugins/uptime/public/contexts/uptime_settings_context.tsx rename to x-pack/plugins/uptime/public/contexts/uptime_settings_context.tsx index 137846de103b4..4fabf3f2ed497 100644 --- a/x-pack/legacy/plugins/uptime/public/contexts/uptime_settings_context.tsx +++ b/x-pack/plugins/uptime/public/contexts/uptime_settings_context.tsx @@ -9,7 +9,7 @@ import { UptimeAppProps } from '../uptime_app'; import { CLIENT_DEFAULTS, CONTEXT_DEFAULTS } from '../../common/constants'; import { CommonlyUsedRange } from '../components/common/uptime_date_picker'; import { useGetUrlParams } from '../hooks'; -import { ILicense } from '../../../../../plugins/licensing/common/types'; +import { ILicense } from '../../../../plugins/licensing/common/types'; export interface UptimeSettingsContextValues { basePath: string; diff --git a/x-pack/plugins/uptime/public/contexts/uptime_startup_plugins_context.tsx b/x-pack/plugins/uptime/public/contexts/uptime_startup_plugins_context.tsx new file mode 100644 index 0000000000000..e516ff44aa12a --- /dev/null +++ b/x-pack/plugins/uptime/public/contexts/uptime_startup_plugins_context.tsx @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { createContext } from 'react'; +import { ClientPluginsStart } from '../apps/plugin'; + +export const UptimeStartupPluginsContext = createContext>({}); + +export const UptimeStartupPluginsContextProvider: React.FC> = ({ + children, + ...props +}) => ; diff --git a/x-pack/legacy/plugins/uptime/public/contexts/uptime_theme_context.tsx b/x-pack/plugins/uptime/public/contexts/uptime_theme_context.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/contexts/uptime_theme_context.tsx rename to x-pack/plugins/uptime/public/contexts/uptime_theme_context.tsx diff --git a/x-pack/legacy/plugins/uptime/public/hooks/__tests__/__snapshots__/use_url_params.test.tsx.snap b/x-pack/plugins/uptime/public/hooks/__tests__/__snapshots__/use_url_params.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/hooks/__tests__/__snapshots__/use_url_params.test.tsx.snap rename to x-pack/plugins/uptime/public/hooks/__tests__/__snapshots__/use_url_params.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/hooks/__tests__/use_breadcrumbs.test.tsx b/x-pack/plugins/uptime/public/hooks/__tests__/use_breadcrumbs.test.tsx similarity index 95% rename from x-pack/legacy/plugins/uptime/public/hooks/__tests__/use_breadcrumbs.test.tsx rename to x-pack/plugins/uptime/public/hooks/__tests__/use_breadcrumbs.test.tsx index 1ce00fe7ce3af..306919015fcb1 100644 --- a/x-pack/legacy/plugins/uptime/public/hooks/__tests__/use_breadcrumbs.test.tsx +++ b/x-pack/plugins/uptime/public/hooks/__tests__/use_breadcrumbs.test.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { Route } from 'react-router-dom'; import { mountWithRouter } from '../../lib'; import { OVERVIEW_ROUTE } from '../../../common/constants'; -import { KibanaContextProvider } from '../../../../../../../src/plugins/kibana_react/public'; +import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_react/public'; import { UptimeUrlParams, getSupportedUrlParams } from '../../lib/helper'; import { makeBaseBreadcrumb, useBreadcrumbs } from '../use_breadcrumbs'; diff --git a/x-pack/legacy/plugins/uptime/public/hooks/__tests__/use_url_params.test.tsx b/x-pack/plugins/uptime/public/hooks/__tests__/use_url_params.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/hooks/__tests__/use_url_params.test.tsx rename to x-pack/plugins/uptime/public/hooks/__tests__/use_url_params.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/hooks/index.ts b/x-pack/plugins/uptime/public/hooks/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/hooks/index.ts rename to x-pack/plugins/uptime/public/hooks/index.ts diff --git a/x-pack/legacy/plugins/uptime/public/hooks/update_kuery_string.ts b/x-pack/plugins/uptime/public/hooks/update_kuery_string.ts similarity index 95% rename from x-pack/legacy/plugins/uptime/public/hooks/update_kuery_string.ts rename to x-pack/plugins/uptime/public/hooks/update_kuery_string.ts index ab4d6f75849e8..492d2bab5bb80 100644 --- a/x-pack/legacy/plugins/uptime/public/hooks/update_kuery_string.ts +++ b/x-pack/plugins/uptime/public/hooks/update_kuery_string.ts @@ -5,7 +5,7 @@ */ import { combineFiltersAndUserSearch, stringifyKueries } from '../lib/helper'; -import { esKuery, IIndexPattern } from '../../../../../../src/plugins/data/public'; +import { esKuery, IIndexPattern } from '../../../../../src/plugins/data/public'; const getKueryString = (urlFilters: string): string => { let kueryString = ''; diff --git a/x-pack/legacy/plugins/uptime/public/hooks/use_breadcrumbs.ts b/x-pack/plugins/uptime/public/hooks/use_breadcrumbs.ts similarity index 94% rename from x-pack/legacy/plugins/uptime/public/hooks/use_breadcrumbs.ts rename to x-pack/plugins/uptime/public/hooks/use_breadcrumbs.ts index d1cc8e1897386..182c6b0114128 100644 --- a/x-pack/legacy/plugins/uptime/public/hooks/use_breadcrumbs.ts +++ b/x-pack/plugins/uptime/public/hooks/use_breadcrumbs.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import { useEffect } from 'react'; import { UptimeUrlParams } from '../lib/helper'; import { stringifyUrlParams } from '../lib/helper/stringify_url_params'; -import { useKibana } from '../../../../../../src/plugins/kibana_react/public'; +import { useKibana } from '../../../../../src/plugins/kibana_react/public'; import { useUrlParams } from '.'; export const makeBaseBreadcrumb = (params?: UptimeUrlParams): ChromeBreadcrumb => { diff --git a/x-pack/legacy/plugins/uptime/public/hooks/use_monitor.ts b/x-pack/plugins/uptime/public/hooks/use_monitor.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/hooks/use_monitor.ts rename to x-pack/plugins/uptime/public/hooks/use_monitor.ts diff --git a/x-pack/legacy/plugins/uptime/public/hooks/use_telemetry.ts b/x-pack/plugins/uptime/public/hooks/use_telemetry.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/hooks/use_telemetry.ts rename to x-pack/plugins/uptime/public/hooks/use_telemetry.ts diff --git a/x-pack/legacy/plugins/uptime/public/hooks/use_url_params.ts b/x-pack/plugins/uptime/public/hooks/use_url_params.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/hooks/use_url_params.ts rename to x-pack/plugins/uptime/public/hooks/use_url_params.ts diff --git a/x-pack/legacy/plugins/uptime/public/icons/heartbeat_white.svg b/x-pack/plugins/uptime/public/icons/heartbeat_white.svg similarity index 100% rename from x-pack/legacy/plugins/uptime/public/icons/heartbeat_white.svg rename to x-pack/plugins/uptime/public/icons/heartbeat_white.svg diff --git a/x-pack/legacy/plugins/uptime/common/graphql/resolver_types.ts b/x-pack/plugins/uptime/public/index.ts similarity index 53% rename from x-pack/legacy/plugins/uptime/common/graphql/resolver_types.ts rename to x-pack/plugins/uptime/public/index.ts index 22df610d2d516..48cf2c90ad07b 100644 --- a/x-pack/legacy/plugins/uptime/common/graphql/resolver_types.ts +++ b/x-pack/plugins/uptime/public/index.ts @@ -4,10 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -type UMResolverResult = Promise | T; +import { PluginInitializerContext } from 'kibana/public'; +import { UptimePlugin } from './apps'; -export type UMResolver = ( - parent: Parent, - args: Args, - context: Context -) => UMResolverResult; +export const plugin = (initializerContext: PluginInitializerContext) => + new UptimePlugin(initializerContext); diff --git a/x-pack/legacy/plugins/uptime/public/lib/adapters/framework/capabilities_adapter.ts b/x-pack/plugins/uptime/public/lib/adapters/framework/capabilities_adapter.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/adapters/framework/capabilities_adapter.ts rename to x-pack/plugins/uptime/public/lib/adapters/framework/capabilities_adapter.ts diff --git a/x-pack/legacy/plugins/uptime/public/lib/adapters/framework/new_platform_adapter.tsx b/x-pack/plugins/uptime/public/lib/adapters/framework/new_platform_adapter.tsx similarity index 86% rename from x-pack/legacy/plugins/uptime/public/lib/adapters/framework/new_platform_adapter.tsx rename to x-pack/plugins/uptime/public/lib/adapters/framework/new_platform_adapter.tsx index 71c73bf5ba5d4..f7f9e056f41af 100644 --- a/x-pack/legacy/plugins/uptime/public/lib/adapters/framework/new_platform_adapter.tsx +++ b/x-pack/plugins/uptime/public/lib/adapters/framework/new_platform_adapter.tsx @@ -9,7 +9,6 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { get } from 'lodash'; import { i18n as i18nFormatter } from '@kbn/i18n'; -import { PluginsSetup } from 'ui/new_platform/new_platform'; import { alertTypeInitializers } from '../../alert_types'; import { UptimeApp, UptimeAppProps } from '../../../uptime_app'; import { getIntegratedAppAvailability } from './capabilities_adapter'; @@ -20,10 +19,12 @@ import { DEFAULT_TIMEPICKER_QUICK_RANGES, } from '../../../../common/constants'; import { UMFrameworkAdapter } from '../../lib'; +import { ClientPluginsStart, ClientPluginsSetup } from '../../../apps/plugin'; export const getKibanaFrameworkAdapter = ( core: CoreStart, - plugins: PluginsSetup + plugins: ClientPluginsSetup, + startPlugins: ClientPluginsStart ): UMFrameworkAdapter => { const { application: { capabilities }, @@ -35,14 +36,15 @@ export const getKibanaFrameworkAdapter = ( const { data: { autocomplete }, - // TODO: after NP migration we can likely fix this typing problem - // @ts-ignore we don't control this type triggers_actions_ui, } = plugins; - alertTypeInitializers.forEach(init => - triggers_actions_ui.alertTypeRegistry.register(init({ autocomplete })) - ); + alertTypeInitializers.forEach(init => { + const alertInitializer = init({ autocomplete }); + if (!triggers_actions_ui.alertTypeRegistry.has(alertInitializer.id)) { + triggers_actions_ui.alertTypeRegistry.register(init({ autocomplete })); + } + }); let breadcrumbs: ChromeBreadcrumb[] = []; core.chrome.getBreadcrumbs$().subscribe((nextBreadcrumbs?: ChromeBreadcrumb[]) => { @@ -68,6 +70,7 @@ export const getKibanaFrameworkAdapter = ( isLogsAvailable: logs, kibanaBreadcrumbs: breadcrumbs, plugins, + startPlugins, renderGlobalHelpControls: () => setHelpExtension({ appName: i18nFormatter.translate('xpack.uptime.header.appName', { diff --git a/x-pack/legacy/plugins/uptime/public/lib/alert_types/__tests__/monitor_status.test.ts b/x-pack/plugins/uptime/public/lib/alert_types/__tests__/monitor_status.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/alert_types/__tests__/monitor_status.test.ts rename to x-pack/plugins/uptime/public/lib/alert_types/__tests__/monitor_status.test.ts diff --git a/x-pack/legacy/plugins/uptime/public/lib/alert_types/index.ts b/x-pack/plugins/uptime/public/lib/alert_types/index.ts similarity index 67% rename from x-pack/legacy/plugins/uptime/public/lib/alert_types/index.ts rename to x-pack/plugins/uptime/public/lib/alert_types/index.ts index 74160577cb0b1..f7ab254ffe675 100644 --- a/x-pack/legacy/plugins/uptime/public/lib/alert_types/index.ts +++ b/x-pack/plugins/uptime/public/lib/alert_types/index.ts @@ -4,9 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -// TODO: after NP migration is complete we should be able to remove this lint ignore comment -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { AlertTypeModel } from '../../../../../../plugins/triggers_actions_ui/public'; +import { AlertTypeModel } from '../../../../triggers_actions_ui/public'; import { initMonitorStatusAlertType } from './monitor_status'; export type AlertTypeInitializer = (dependenies: { autocomplete: any }) => AlertTypeModel; diff --git a/x-pack/legacy/plugins/uptime/public/lib/alert_types/monitor_status.tsx b/x-pack/plugins/uptime/public/lib/alert_types/monitor_status.tsx similarity index 88% rename from x-pack/legacy/plugins/uptime/public/lib/alert_types/monitor_status.tsx rename to x-pack/plugins/uptime/public/lib/alert_types/monitor_status.tsx index 0624d20b197c0..e7695fb1cbb56 100644 --- a/x-pack/legacy/plugins/uptime/public/lib/alert_types/monitor_status.tsx +++ b/x-pack/plugins/uptime/public/lib/alert_types/monitor_status.tsx @@ -8,17 +8,12 @@ import { PathReporter } from 'io-ts/lib/PathReporter'; import React from 'react'; import DateMath from '@elastic/datemath'; import { isRight } from 'fp-ts/lib/Either'; -import { - AlertTypeModel, - ValidationResult, - // TODO: this typing issue should be resolved after NP migration - // eslint-disable-next-line @kbn/eslint/no-restricted-paths -} from '../../../../../../plugins/triggers_actions_ui/public/types'; +import { AlertTypeModel } from '../../../../triggers_actions_ui/public'; import { AlertTypeInitializer } from '.'; import { StatusCheckExecutorParamsType } from '../../../common/runtime_types'; import { AlertMonitorStatus } from '../../components/overview/alerts/alerts_containers'; -export const validate = (alertParams: any): ValidationResult => { +export const validate = (alertParams: any) => { const errors: Record = {}; const decoded = StatusCheckExecutorParamsType.decode(alertParams); diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/__tests__/__snapshots__/stringify_kueries.test.ts.snap b/x-pack/plugins/uptime/public/lib/helper/__tests__/__snapshots__/stringify_kueries.test.ts.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/helper/__tests__/__snapshots__/stringify_kueries.test.ts.snap rename to x-pack/plugins/uptime/public/lib/helper/__tests__/__snapshots__/stringify_kueries.test.ts.snap diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/__tests__/__snapshots__/stringify_url_params.test.ts.snap b/x-pack/plugins/uptime/public/lib/helper/__tests__/__snapshots__/stringify_url_params.test.ts.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/helper/__tests__/__snapshots__/stringify_url_params.test.ts.snap rename to x-pack/plugins/uptime/public/lib/helper/__tests__/__snapshots__/stringify_url_params.test.ts.snap diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/__tests__/combine_filters_and_user_search.test.ts b/x-pack/plugins/uptime/public/lib/helper/__tests__/combine_filters_and_user_search.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/helper/__tests__/combine_filters_and_user_search.test.ts rename to x-pack/plugins/uptime/public/lib/helper/__tests__/combine_filters_and_user_search.test.ts diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/__tests__/convert_measurements.test.ts b/x-pack/plugins/uptime/public/lib/helper/__tests__/convert_measurements.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/helper/__tests__/convert_measurements.test.ts rename to x-pack/plugins/uptime/public/lib/helper/__tests__/convert_measurements.test.ts diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/__tests__/series_has_down_values.test.ts b/x-pack/plugins/uptime/public/lib/helper/__tests__/series_has_down_values.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/helper/__tests__/series_has_down_values.test.ts rename to x-pack/plugins/uptime/public/lib/helper/__tests__/series_has_down_values.test.ts diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/__tests__/stringify_kueries.test.ts b/x-pack/plugins/uptime/public/lib/helper/__tests__/stringify_kueries.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/helper/__tests__/stringify_kueries.test.ts rename to x-pack/plugins/uptime/public/lib/helper/__tests__/stringify_kueries.test.ts diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/__tests__/stringify_url_params.test.ts b/x-pack/plugins/uptime/public/lib/helper/__tests__/stringify_url_params.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/helper/__tests__/stringify_url_params.test.ts rename to x-pack/plugins/uptime/public/lib/helper/__tests__/stringify_url_params.test.ts diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/charts/__tests__/get_label_format.test.ts b/x-pack/plugins/uptime/public/lib/helper/charts/__tests__/get_label_format.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/helper/charts/__tests__/get_label_format.test.ts rename to x-pack/plugins/uptime/public/lib/helper/charts/__tests__/get_label_format.test.ts diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/charts/__tests__/is_within_current_date.test.ts b/x-pack/plugins/uptime/public/lib/helper/charts/__tests__/is_within_current_date.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/helper/charts/__tests__/is_within_current_date.test.ts rename to x-pack/plugins/uptime/public/lib/helper/charts/__tests__/is_within_current_date.test.ts diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/charts/get_chart_date_label.ts b/x-pack/plugins/uptime/public/lib/helper/charts/get_chart_date_label.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/helper/charts/get_chart_date_label.ts rename to x-pack/plugins/uptime/public/lib/helper/charts/get_chart_date_label.ts diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/charts/get_label_format.ts b/x-pack/plugins/uptime/public/lib/helper/charts/get_label_format.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/helper/charts/get_label_format.ts rename to x-pack/plugins/uptime/public/lib/helper/charts/get_label_format.ts diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/charts/index.ts b/x-pack/plugins/uptime/public/lib/helper/charts/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/helper/charts/index.ts rename to x-pack/plugins/uptime/public/lib/helper/charts/index.ts diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/charts/is_within_current_date.ts b/x-pack/plugins/uptime/public/lib/helper/charts/is_within_current_date.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/helper/charts/is_within_current_date.ts rename to x-pack/plugins/uptime/public/lib/helper/charts/is_within_current_date.ts diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/combine_filters_and_user_search.ts b/x-pack/plugins/uptime/public/lib/helper/combine_filters_and_user_search.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/helper/combine_filters_and_user_search.ts rename to x-pack/plugins/uptime/public/lib/helper/combine_filters_and_user_search.ts diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/convert_measurements.ts b/x-pack/plugins/uptime/public/lib/helper/convert_measurements.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/helper/convert_measurements.ts rename to x-pack/plugins/uptime/public/lib/helper/convert_measurements.ts diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/get_title.ts b/x-pack/plugins/uptime/public/lib/helper/get_title.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/helper/get_title.ts rename to x-pack/plugins/uptime/public/lib/helper/get_title.ts diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/helper_with_router.tsx b/x-pack/plugins/uptime/public/lib/helper/helper_with_router.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/helper/helper_with_router.tsx rename to x-pack/plugins/uptime/public/lib/helper/helper_with_router.tsx diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/index.ts b/x-pack/plugins/uptime/public/lib/helper/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/helper/index.ts rename to x-pack/plugins/uptime/public/lib/helper/index.ts diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/observability_integration/__tests__/get_apm_href.test.ts b/x-pack/plugins/uptime/public/lib/helper/observability_integration/__tests__/get_apm_href.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/helper/observability_integration/__tests__/get_apm_href.test.ts rename to x-pack/plugins/uptime/public/lib/helper/observability_integration/__tests__/get_apm_href.test.ts diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/observability_integration/__tests__/get_infra_href.test.ts b/x-pack/plugins/uptime/public/lib/helper/observability_integration/__tests__/get_infra_href.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/helper/observability_integration/__tests__/get_infra_href.test.ts rename to x-pack/plugins/uptime/public/lib/helper/observability_integration/__tests__/get_infra_href.test.ts diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/observability_integration/__tests__/get_logging_href.test.ts b/x-pack/plugins/uptime/public/lib/helper/observability_integration/__tests__/get_logging_href.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/helper/observability_integration/__tests__/get_logging_href.test.ts rename to x-pack/plugins/uptime/public/lib/helper/observability_integration/__tests__/get_logging_href.test.ts diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/observability_integration/add_base_path.ts b/x-pack/plugins/uptime/public/lib/helper/observability_integration/add_base_path.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/helper/observability_integration/add_base_path.ts rename to x-pack/plugins/uptime/public/lib/helper/observability_integration/add_base_path.ts diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/observability_integration/build_href.ts b/x-pack/plugins/uptime/public/lib/helper/observability_integration/build_href.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/helper/observability_integration/build_href.ts rename to x-pack/plugins/uptime/public/lib/helper/observability_integration/build_href.ts diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/observability_integration/get_apm_href.ts b/x-pack/plugins/uptime/public/lib/helper/observability_integration/get_apm_href.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/helper/observability_integration/get_apm_href.ts rename to x-pack/plugins/uptime/public/lib/helper/observability_integration/get_apm_href.ts diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/observability_integration/get_infra_href.ts b/x-pack/plugins/uptime/public/lib/helper/observability_integration/get_infra_href.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/helper/observability_integration/get_infra_href.ts rename to x-pack/plugins/uptime/public/lib/helper/observability_integration/get_infra_href.ts diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/observability_integration/get_logging_href.ts b/x-pack/plugins/uptime/public/lib/helper/observability_integration/get_logging_href.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/helper/observability_integration/get_logging_href.ts rename to x-pack/plugins/uptime/public/lib/helper/observability_integration/get_logging_href.ts diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/observability_integration/index.ts b/x-pack/plugins/uptime/public/lib/helper/observability_integration/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/helper/observability_integration/index.ts rename to x-pack/plugins/uptime/public/lib/helper/observability_integration/index.ts diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/series_has_down_values.ts b/x-pack/plugins/uptime/public/lib/helper/series_has_down_values.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/helper/series_has_down_values.ts rename to x-pack/plugins/uptime/public/lib/helper/series_has_down_values.ts diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/stringify_kueries.ts b/x-pack/plugins/uptime/public/lib/helper/stringify_kueries.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/helper/stringify_kueries.ts rename to x-pack/plugins/uptime/public/lib/helper/stringify_kueries.ts diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/stringify_url_params.ts b/x-pack/plugins/uptime/public/lib/helper/stringify_url_params.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/helper/stringify_url_params.ts rename to x-pack/plugins/uptime/public/lib/helper/stringify_url_params.ts diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/url_params/__tests__/__snapshots__/get_supported_url_params.test.ts.snap b/x-pack/plugins/uptime/public/lib/helper/url_params/__tests__/__snapshots__/get_supported_url_params.test.ts.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/helper/url_params/__tests__/__snapshots__/get_supported_url_params.test.ts.snap rename to x-pack/plugins/uptime/public/lib/helper/url_params/__tests__/__snapshots__/get_supported_url_params.test.ts.snap diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/url_params/__tests__/get_supported_url_params.test.ts b/x-pack/plugins/uptime/public/lib/helper/url_params/__tests__/get_supported_url_params.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/helper/url_params/__tests__/get_supported_url_params.test.ts rename to x-pack/plugins/uptime/public/lib/helper/url_params/__tests__/get_supported_url_params.test.ts diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/url_params/__tests__/parse_absolute_date.test.ts b/x-pack/plugins/uptime/public/lib/helper/url_params/__tests__/parse_absolute_date.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/helper/url_params/__tests__/parse_absolute_date.test.ts rename to x-pack/plugins/uptime/public/lib/helper/url_params/__tests__/parse_absolute_date.test.ts diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/url_params/__tests__/parse_url_int.test.ts b/x-pack/plugins/uptime/public/lib/helper/url_params/__tests__/parse_autorefresh_interval.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/helper/url_params/__tests__/parse_url_int.test.ts rename to x-pack/plugins/uptime/public/lib/helper/url_params/__tests__/parse_autorefresh_interval.test.ts diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/url_params/__tests__/parse_is_paused.test.ts b/x-pack/plugins/uptime/public/lib/helper/url_params/__tests__/parse_is_paused.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/helper/url_params/__tests__/parse_is_paused.test.ts rename to x-pack/plugins/uptime/public/lib/helper/url_params/__tests__/parse_is_paused.test.ts diff --git a/x-pack/plugins/uptime/public/lib/helper/url_params/__tests__/parse_url_int.test.ts b/x-pack/plugins/uptime/public/lib/helper/url_params/__tests__/parse_url_int.test.ts new file mode 100644 index 0000000000000..a5c2168378089 --- /dev/null +++ b/x-pack/plugins/uptime/public/lib/helper/url_params/__tests__/parse_url_int.test.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { parseUrlInt } from '../parse_url_int'; + +describe('parseUrlInt', () => { + it('parses a number', () => { + const result = parseUrlInt('23', 50); + expect(result).toBe(23); + }); + + it('returns default value for empty string', () => { + const result = parseUrlInt('', 50); + expect(result).toBe(50); + }); + + it('returns default value for non-numeric string', () => { + const result = parseUrlInt('abc', 50); + expect(result).toBe(50); + }); +}); diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/url_params/get_supported_url_params.ts b/x-pack/plugins/uptime/public/lib/helper/url_params/get_supported_url_params.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/helper/url_params/get_supported_url_params.ts rename to x-pack/plugins/uptime/public/lib/helper/url_params/get_supported_url_params.ts diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/url_params/index.ts b/x-pack/plugins/uptime/public/lib/helper/url_params/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/helper/url_params/index.ts rename to x-pack/plugins/uptime/public/lib/helper/url_params/index.ts diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/url_params/parse_absolute_date.ts b/x-pack/plugins/uptime/public/lib/helper/url_params/parse_absolute_date.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/helper/url_params/parse_absolute_date.ts rename to x-pack/plugins/uptime/public/lib/helper/url_params/parse_absolute_date.ts diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/url_params/parse_is_paused.ts b/x-pack/plugins/uptime/public/lib/helper/url_params/parse_is_paused.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/helper/url_params/parse_is_paused.ts rename to x-pack/plugins/uptime/public/lib/helper/url_params/parse_is_paused.ts diff --git a/x-pack/legacy/plugins/uptime/public/lib/helper/url_params/parse_url_int.ts b/x-pack/plugins/uptime/public/lib/helper/url_params/parse_url_int.ts similarity index 87% rename from x-pack/legacy/plugins/uptime/public/lib/helper/url_params/parse_url_int.ts rename to x-pack/plugins/uptime/public/lib/helper/url_params/parse_url_int.ts index b1a4d0a2aba0d..0e5363527b516 100644 --- a/x-pack/legacy/plugins/uptime/public/lib/helper/url_params/parse_url_int.ts +++ b/x-pack/plugins/uptime/public/lib/helper/url_params/parse_url_int.ts @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -// TODO: add a comment explaining the purpose of this function export const parseUrlInt = (value: string | undefined, defaultValue: number): number => { const parsed = parseInt(value || '', 10); return isNaN(parsed) ? defaultValue : parsed; diff --git a/x-pack/legacy/plugins/uptime/public/lib/index.ts b/x-pack/plugins/uptime/public/lib/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/index.ts rename to x-pack/plugins/uptime/public/lib/index.ts diff --git a/x-pack/legacy/plugins/uptime/public/lib/lib.ts b/x-pack/plugins/uptime/public/lib/lib.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/lib/lib.ts rename to x-pack/plugins/uptime/public/lib/lib.ts diff --git a/x-pack/legacy/plugins/uptime/public/pages/__tests__/__snapshots__/monitor.test.tsx.snap b/x-pack/plugins/uptime/public/pages/__tests__/__snapshots__/monitor.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/pages/__tests__/__snapshots__/monitor.test.tsx.snap rename to x-pack/plugins/uptime/public/pages/__tests__/__snapshots__/monitor.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/pages/__tests__/__snapshots__/not_found.test.tsx.snap b/x-pack/plugins/uptime/public/pages/__tests__/__snapshots__/not_found.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/pages/__tests__/__snapshots__/not_found.test.tsx.snap rename to x-pack/plugins/uptime/public/pages/__tests__/__snapshots__/not_found.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/pages/__tests__/__snapshots__/overview.test.tsx.snap b/x-pack/plugins/uptime/public/pages/__tests__/__snapshots__/overview.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/pages/__tests__/__snapshots__/overview.test.tsx.snap rename to x-pack/plugins/uptime/public/pages/__tests__/__snapshots__/overview.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/pages/__tests__/__snapshots__/page_header.test.tsx.snap b/x-pack/plugins/uptime/public/pages/__tests__/__snapshots__/page_header.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/pages/__tests__/__snapshots__/page_header.test.tsx.snap rename to x-pack/plugins/uptime/public/pages/__tests__/__snapshots__/page_header.test.tsx.snap diff --git a/x-pack/legacy/plugins/uptime/public/pages/__tests__/monitor.test.tsx b/x-pack/plugins/uptime/public/pages/__tests__/monitor.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/pages/__tests__/monitor.test.tsx rename to x-pack/plugins/uptime/public/pages/__tests__/monitor.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/pages/__tests__/not_found.test.tsx b/x-pack/plugins/uptime/public/pages/__tests__/not_found.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/pages/__tests__/not_found.test.tsx rename to x-pack/plugins/uptime/public/pages/__tests__/not_found.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/pages/__tests__/overview.test.tsx b/x-pack/plugins/uptime/public/pages/__tests__/overview.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/pages/__tests__/overview.test.tsx rename to x-pack/plugins/uptime/public/pages/__tests__/overview.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/pages/__tests__/page_header.test.tsx b/x-pack/plugins/uptime/public/pages/__tests__/page_header.test.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/pages/__tests__/page_header.test.tsx rename to x-pack/plugins/uptime/public/pages/__tests__/page_header.test.tsx diff --git a/x-pack/legacy/plugins/uptime/public/pages/index.ts b/x-pack/plugins/uptime/public/pages/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/pages/index.ts rename to x-pack/plugins/uptime/public/pages/index.ts diff --git a/x-pack/legacy/plugins/uptime/public/pages/monitor.tsx b/x-pack/plugins/uptime/public/pages/monitor.tsx similarity index 87% rename from x-pack/legacy/plugins/uptime/public/pages/monitor.tsx rename to x-pack/plugins/uptime/public/pages/monitor.tsx index 4495be9b24dc1..8a309db75acd2 100644 --- a/x-pack/legacy/plugins/uptime/public/pages/monitor.tsx +++ b/x-pack/plugins/uptime/public/pages/monitor.tsx @@ -7,14 +7,13 @@ import { EuiSpacer } from '@elastic/eui'; import React from 'react'; import { useSelector } from 'react-redux'; -import { useTrackPageview } from '../../../../../plugins/observability/public'; import { monitorStatusSelector } from '../state/selectors'; import { PageHeader } from './page_header'; import { useBreadcrumbs } from '../hooks/use_breadcrumbs'; +import { useTrackPageview } from '../../../observability/public'; import { useMonitorId, useUptimeTelemetry, UptimePage } from '../hooks'; import { MonitorCharts } from '../components/monitor'; -import { MonitorStatusDetails } from '../components/monitor'; -import { PingList } from '../components/monitor'; +import { MonitorStatusDetails, PingList } from '../components/monitor'; export const MonitorPage: React.FC = () => { const monitorId = useMonitorId(); diff --git a/x-pack/legacy/plugins/uptime/public/pages/not_found.tsx b/x-pack/plugins/uptime/public/pages/not_found.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/pages/not_found.tsx rename to x-pack/plugins/uptime/public/pages/not_found.tsx diff --git a/x-pack/legacy/plugins/uptime/public/pages/overview.tsx b/x-pack/plugins/uptime/public/pages/overview.tsx similarity index 96% rename from x-pack/legacy/plugins/uptime/public/pages/overview.tsx rename to x-pack/plugins/uptime/public/pages/overview.tsx index adc36efa6f7db..fefd804cbfabf 100644 --- a/x-pack/legacy/plugins/uptime/public/pages/overview.tsx +++ b/x-pack/plugins/uptime/public/pages/overview.tsx @@ -10,11 +10,11 @@ import styled from 'styled-components'; import { i18n } from '@kbn/i18n'; import { useUptimeTelemetry, UptimePage, useGetUrlParams } from '../hooks'; import { stringifyUrlParams } from '../lib/helper/stringify_url_params'; -import { useTrackPageview } from '../../../../../plugins/observability/public'; -import { DataPublicPluginSetup, IIndexPattern } from '../../../../../../src/plugins/data/public'; -import { useUpdateKueryString } from '../hooks'; import { PageHeader } from './page_header'; +import { DataPublicPluginSetup, IIndexPattern } from '../../../../../src/plugins/data/public'; +import { useUpdateKueryString } from '../hooks'; import { useBreadcrumbs } from '../hooks/use_breadcrumbs'; +import { useTrackPageview } from '../../../observability/public'; import { MonitorList } from '../components/overview/monitor_list/monitor_list_container'; import { EmptyState, FilterGroup, KueryBar, ParsingErrorCallout } from '../components/overview'; import { StatusPanel } from '../components/overview/status_panel'; diff --git a/x-pack/legacy/plugins/uptime/public/pages/page_header.tsx b/x-pack/plugins/uptime/public/pages/page_header.tsx similarity index 100% rename from x-pack/legacy/plugins/uptime/public/pages/page_header.tsx rename to x-pack/plugins/uptime/public/pages/page_header.tsx diff --git a/x-pack/legacy/plugins/uptime/public/pages/settings.tsx b/x-pack/plugins/uptime/public/pages/settings.tsx similarity index 98% rename from x-pack/legacy/plugins/uptime/public/pages/settings.tsx rename to x-pack/plugins/uptime/public/pages/settings.tsx index d8c2a78092854..52096a49435d7 100644 --- a/x-pack/legacy/plugins/uptime/public/pages/settings.tsx +++ b/x-pack/plugins/uptime/public/pages/settings.tsx @@ -24,7 +24,7 @@ import { getDynamicSettings, setDynamicSettings } from '../state/actions/dynamic import { DynamicSettings } from '../../common/runtime_types'; import { useBreadcrumbs } from '../hooks/use_breadcrumbs'; import { OVERVIEW_ROUTE } from '../../common/constants'; -import { useKibana } from '../../../../../../src/plugins/kibana_react/public'; +import { useKibana } from '../../../../../src/plugins/kibana_react/public'; import { UptimePage, useUptimeTelemetry } from '../hooks'; import { IndicesForm } from '../components/settings/indices_form'; import { diff --git a/x-pack/legacy/plugins/uptime/public/pages/translations.ts b/x-pack/plugins/uptime/public/pages/translations.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/pages/translations.ts rename to x-pack/plugins/uptime/public/pages/translations.ts diff --git a/x-pack/legacy/plugins/uptime/public/routes.tsx b/x-pack/plugins/uptime/public/routes.tsx similarity index 93% rename from x-pack/legacy/plugins/uptime/public/routes.tsx rename to x-pack/plugins/uptime/public/routes.tsx index b5e20ef8a70a9..eb0587c0417a2 100644 --- a/x-pack/legacy/plugins/uptime/public/routes.tsx +++ b/x-pack/plugins/uptime/public/routes.tsx @@ -6,7 +6,7 @@ import React, { FC } from 'react'; import { Route, Switch } from 'react-router-dom'; -import { DataPublicPluginSetup } from '../../../../../src/plugins/data/public'; +import { DataPublicPluginSetup } from '../../../../src/plugins/data/public'; import { OverviewPage } from './components/overview/overview_container'; import { MONITOR_ROUTE, OVERVIEW_ROUTE, SETTINGS_ROUTE } from '../common/constants'; import { MonitorPage, NotFoundPage, SettingsPage } from './pages'; diff --git a/x-pack/legacy/plugins/uptime/public/state/actions/__tests__/__snapshots__/overview_filters.test.ts.snap b/x-pack/plugins/uptime/public/state/actions/__tests__/__snapshots__/overview_filters.test.ts.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/actions/__tests__/__snapshots__/overview_filters.test.ts.snap rename to x-pack/plugins/uptime/public/state/actions/__tests__/__snapshots__/overview_filters.test.ts.snap diff --git a/x-pack/legacy/plugins/uptime/public/state/actions/__tests__/overview_filters.test.ts b/x-pack/plugins/uptime/public/state/actions/__tests__/overview_filters.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/actions/__tests__/overview_filters.test.ts rename to x-pack/plugins/uptime/public/state/actions/__tests__/overview_filters.test.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/actions/dynamic_settings.ts b/x-pack/plugins/uptime/public/state/actions/dynamic_settings.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/actions/dynamic_settings.ts rename to x-pack/plugins/uptime/public/state/actions/dynamic_settings.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/actions/index.ts b/x-pack/plugins/uptime/public/state/actions/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/actions/index.ts rename to x-pack/plugins/uptime/public/state/actions/index.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/actions/index_patternts.ts b/x-pack/plugins/uptime/public/state/actions/index_patternts.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/actions/index_patternts.ts rename to x-pack/plugins/uptime/public/state/actions/index_patternts.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/actions/index_status.ts b/x-pack/plugins/uptime/public/state/actions/index_status.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/actions/index_status.ts rename to x-pack/plugins/uptime/public/state/actions/index_status.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/actions/ml_anomaly.ts b/x-pack/plugins/uptime/public/state/actions/ml_anomaly.ts similarity index 82% rename from x-pack/legacy/plugins/uptime/public/state/actions/ml_anomaly.ts rename to x-pack/plugins/uptime/public/state/actions/ml_anomaly.ts index 67c75314a7305..441a3cefdf204 100644 --- a/x-pack/legacy/plugins/uptime/public/state/actions/ml_anomaly.ts +++ b/x-pack/plugins/uptime/public/state/actions/ml_anomaly.ts @@ -6,15 +6,15 @@ import { createAction } from 'redux-actions'; import { createAsyncAction } from './utils'; -import { MlCapabilitiesResponse } from '../../../../../../plugins/ml/common/types/capabilities'; -import { AnomaliesTableRecord } from '../../../../../../plugins/ml/common/types/anomalies'; +import { MlCapabilitiesResponse } from '../../../../../plugins/ml/common/types/capabilities'; +import { AnomaliesTableRecord } from '../../../../../plugins/ml/common/types/anomalies'; import { CreateMLJobSuccess, DeleteJobResults, MonitorIdParam, HeartbeatIndicesParam, } from './types'; -import { JobExistResult } from '../../../../../../plugins/ml/common/types/data_recognizer'; +import { JobExistResult } from '../../../../../plugins/ml/common/types/data_recognizer'; export const resetMLState = createAction('RESET_ML_STATE'); diff --git a/x-pack/legacy/plugins/uptime/public/state/actions/monitor.ts b/x-pack/plugins/uptime/public/state/actions/monitor.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/actions/monitor.ts rename to x-pack/plugins/uptime/public/state/actions/monitor.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/actions/monitor_duration.ts b/x-pack/plugins/uptime/public/state/actions/monitor_duration.ts similarity index 90% rename from x-pack/legacy/plugins/uptime/public/state/actions/monitor_duration.ts rename to x-pack/plugins/uptime/public/state/actions/monitor_duration.ts index 9a2db5be60b12..524044f873687 100644 --- a/x-pack/legacy/plugins/uptime/public/state/actions/monitor_duration.ts +++ b/x-pack/plugins/uptime/public/state/actions/monitor_duration.ts @@ -7,7 +7,7 @@ import { createAction } from 'redux-actions'; import { QueryParams } from './types'; import { MonitorDurationResult } from '../../../common/types'; -import { IHttpFetchError } from '../../../../../../../target/types/core/public/http'; +import { IHttpFetchError } from '../../../../../../target/types/core/public/http'; type MonitorQueryParams = QueryParams & { monitorId: string }; diff --git a/x-pack/legacy/plugins/uptime/public/state/actions/monitor_list.ts b/x-pack/plugins/uptime/public/state/actions/monitor_list.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/actions/monitor_list.ts rename to x-pack/plugins/uptime/public/state/actions/monitor_list.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/actions/monitor_status.ts b/x-pack/plugins/uptime/public/state/actions/monitor_status.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/actions/monitor_status.ts rename to x-pack/plugins/uptime/public/state/actions/monitor_status.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/actions/overview_filters.ts b/x-pack/plugins/uptime/public/state/actions/overview_filters.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/actions/overview_filters.ts rename to x-pack/plugins/uptime/public/state/actions/overview_filters.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/actions/ping.ts b/x-pack/plugins/uptime/public/state/actions/ping.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/actions/ping.ts rename to x-pack/plugins/uptime/public/state/actions/ping.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/actions/snapshot.ts b/x-pack/plugins/uptime/public/state/actions/snapshot.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/actions/snapshot.ts rename to x-pack/plugins/uptime/public/state/actions/snapshot.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/actions/types.ts b/x-pack/plugins/uptime/public/state/actions/types.ts similarity index 94% rename from x-pack/legacy/plugins/uptime/public/state/actions/types.ts rename to x-pack/plugins/uptime/public/state/actions/types.ts index 41381afd31453..dee2df77707d2 100644 --- a/x-pack/legacy/plugins/uptime/public/state/actions/types.ts +++ b/x-pack/plugins/uptime/public/state/actions/types.ts @@ -5,7 +5,7 @@ */ import { Action } from 'redux-actions'; -import { IHttpFetchError } from '../../../../../../../target/types/core/public/http'; +import { IHttpFetchError } from '../../../../../../target/types/core/public/http'; export interface AsyncAction { get: (payload: Payload) => Action; diff --git a/x-pack/legacy/plugins/uptime/public/state/actions/ui.ts b/x-pack/plugins/uptime/public/state/actions/ui.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/actions/ui.ts rename to x-pack/plugins/uptime/public/state/actions/ui.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/actions/utils.ts b/x-pack/plugins/uptime/public/state/actions/utils.ts similarity index 90% rename from x-pack/legacy/plugins/uptime/public/state/actions/utils.ts rename to x-pack/plugins/uptime/public/state/actions/utils.ts index a5adb96731f33..8ce4cf011406b 100644 --- a/x-pack/legacy/plugins/uptime/public/state/actions/utils.ts +++ b/x-pack/plugins/uptime/public/state/actions/utils.ts @@ -6,7 +6,7 @@ import { createAction } from 'redux-actions'; import { AsyncAction, AsyncAction1 } from './types'; -import { IHttpFetchError } from '../../../../../../../target/types/core/public/http'; +import { IHttpFetchError } from '../../../../../../target/types/core/public/http'; export function createAsyncAction( actionStr: string diff --git a/x-pack/legacy/plugins/uptime/public/state/api/__tests__/__snapshots__/snapshot.test.ts.snap b/x-pack/plugins/uptime/public/state/api/__tests__/__snapshots__/snapshot.test.ts.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/api/__tests__/__snapshots__/snapshot.test.ts.snap rename to x-pack/plugins/uptime/public/state/api/__tests__/__snapshots__/snapshot.test.ts.snap diff --git a/x-pack/legacy/plugins/uptime/public/state/api/__tests__/ml_anomaly.test.ts b/x-pack/plugins/uptime/public/state/api/__tests__/ml_anomaly.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/api/__tests__/ml_anomaly.test.ts rename to x-pack/plugins/uptime/public/state/api/__tests__/ml_anomaly.test.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/api/__tests__/snapshot.test.ts b/x-pack/plugins/uptime/public/state/api/__tests__/snapshot.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/api/__tests__/snapshot.test.ts rename to x-pack/plugins/uptime/public/state/api/__tests__/snapshot.test.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/api/dynamic_settings.ts b/x-pack/plugins/uptime/public/state/api/dynamic_settings.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/api/dynamic_settings.ts rename to x-pack/plugins/uptime/public/state/api/dynamic_settings.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/api/index.ts b/x-pack/plugins/uptime/public/state/api/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/api/index.ts rename to x-pack/plugins/uptime/public/state/api/index.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/api/index_pattern.ts b/x-pack/plugins/uptime/public/state/api/index_pattern.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/api/index_pattern.ts rename to x-pack/plugins/uptime/public/state/api/index_pattern.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/api/index_status.ts b/x-pack/plugins/uptime/public/state/api/index_status.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/api/index_status.ts rename to x-pack/plugins/uptime/public/state/api/index_status.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/api/ml_anomaly.ts b/x-pack/plugins/uptime/public/state/api/ml_anomaly.ts similarity index 92% rename from x-pack/legacy/plugins/uptime/public/state/api/ml_anomaly.ts rename to x-pack/plugins/uptime/public/state/api/ml_anomaly.ts index ca324895c26db..c4ecb769abefc 100644 --- a/x-pack/legacy/plugins/uptime/public/state/api/ml_anomaly.ts +++ b/x-pack/plugins/uptime/public/state/api/ml_anomaly.ts @@ -8,15 +8,15 @@ import moment from 'moment'; import { apiService } from './utils'; import { AnomalyRecords, AnomalyRecordsParams } from '../actions'; import { API_URLS, ML_JOB_ID, ML_MODULE_ID } from '../../../common/constants'; -import { MlCapabilitiesResponse } from '../../../../../../plugins/ml/common/types/capabilities'; +import { MlCapabilitiesResponse } from '../../../../../plugins/ml/common/types/capabilities'; import { CreateMLJobSuccess, DeleteJobResults, MonitorIdParam, HeartbeatIndicesParam, } from '../actions/types'; -import { DataRecognizerConfigResponse } from '../../../../../../plugins/ml/common/types/modules'; -import { JobExistResult } from '../../../../../../plugins/ml/common/types/data_recognizer'; +import { DataRecognizerConfigResponse } from '../../../../../plugins/ml/common/types/modules'; +import { JobExistResult } from '../../../../../plugins/ml/common/types/data_recognizer'; const getJobPrefix = (monitorId: string) => { // ML App doesn't support upper case characters in job name diff --git a/x-pack/legacy/plugins/uptime/public/state/api/monitor.ts b/x-pack/plugins/uptime/public/state/api/monitor.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/api/monitor.ts rename to x-pack/plugins/uptime/public/state/api/monitor.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/api/monitor_duration.ts b/x-pack/plugins/uptime/public/state/api/monitor_duration.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/api/monitor_duration.ts rename to x-pack/plugins/uptime/public/state/api/monitor_duration.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/api/monitor_list.ts b/x-pack/plugins/uptime/public/state/api/monitor_list.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/api/monitor_list.ts rename to x-pack/plugins/uptime/public/state/api/monitor_list.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/api/monitor_status.ts b/x-pack/plugins/uptime/public/state/api/monitor_status.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/api/monitor_status.ts rename to x-pack/plugins/uptime/public/state/api/monitor_status.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/api/overview_filters.ts b/x-pack/plugins/uptime/public/state/api/overview_filters.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/api/overview_filters.ts rename to x-pack/plugins/uptime/public/state/api/overview_filters.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/api/ping.ts b/x-pack/plugins/uptime/public/state/api/ping.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/api/ping.ts rename to x-pack/plugins/uptime/public/state/api/ping.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/api/snapshot.ts b/x-pack/plugins/uptime/public/state/api/snapshot.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/api/snapshot.ts rename to x-pack/plugins/uptime/public/state/api/snapshot.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/api/types.ts b/x-pack/plugins/uptime/public/state/api/types.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/api/types.ts rename to x-pack/plugins/uptime/public/state/api/types.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/api/utils.ts b/x-pack/plugins/uptime/public/state/api/utils.ts similarity index 95% rename from x-pack/legacy/plugins/uptime/public/state/api/utils.ts rename to x-pack/plugins/uptime/public/state/api/utils.ts index e67efa8570c11..acd9bec5a74bc 100644 --- a/x-pack/legacy/plugins/uptime/public/state/api/utils.ts +++ b/x-pack/plugins/uptime/public/state/api/utils.ts @@ -6,7 +6,7 @@ import { PathReporter } from 'io-ts/lib/PathReporter'; import { isRight } from 'fp-ts/lib/Either'; -import { HttpFetchQuery, HttpSetup } from '../../../../../../../target/types/core/public'; +import { HttpFetchQuery, HttpSetup } from '../../../../../../target/types/core/public'; class ApiService { private static instance: ApiService; diff --git a/x-pack/legacy/plugins/uptime/public/state/effects/__tests__/fetch_effect.test.ts b/x-pack/plugins/uptime/public/state/effects/__tests__/fetch_effect.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/effects/__tests__/fetch_effect.test.ts rename to x-pack/plugins/uptime/public/state/effects/__tests__/fetch_effect.test.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/effects/dynamic_settings.ts b/x-pack/plugins/uptime/public/state/effects/dynamic_settings.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/effects/dynamic_settings.ts rename to x-pack/plugins/uptime/public/state/effects/dynamic_settings.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/effects/fetch_effect.ts b/x-pack/plugins/uptime/public/state/effects/fetch_effect.ts similarity index 94% rename from x-pack/legacy/plugins/uptime/public/state/effects/fetch_effect.ts rename to x-pack/plugins/uptime/public/state/effects/fetch_effect.ts index b0734cb5ccabb..0aa85609fe4f0 100644 --- a/x-pack/legacy/plugins/uptime/public/state/effects/fetch_effect.ts +++ b/x-pack/plugins/uptime/public/state/effects/fetch_effect.ts @@ -6,7 +6,7 @@ import { call, put } from 'redux-saga/effects'; import { Action } from 'redux-actions'; -import { IHttpFetchError } from '../../../../../../../target/types/core/public/http'; +import { IHttpFetchError } from '../../../../../../target/types/core/public/http'; /** * Factory function for a fetch effect. It expects three action creators, diff --git a/x-pack/legacy/plugins/uptime/public/state/effects/index.ts b/x-pack/plugins/uptime/public/state/effects/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/effects/index.ts rename to x-pack/plugins/uptime/public/state/effects/index.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/effects/index_pattern.ts b/x-pack/plugins/uptime/public/state/effects/index_pattern.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/effects/index_pattern.ts rename to x-pack/plugins/uptime/public/state/effects/index_pattern.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/effects/index_status.ts b/x-pack/plugins/uptime/public/state/effects/index_status.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/effects/index_status.ts rename to x-pack/plugins/uptime/public/state/effects/index_status.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/effects/ml_anomaly.ts b/x-pack/plugins/uptime/public/state/effects/ml_anomaly.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/effects/ml_anomaly.ts rename to x-pack/plugins/uptime/public/state/effects/ml_anomaly.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/effects/monitor.ts b/x-pack/plugins/uptime/public/state/effects/monitor.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/effects/monitor.ts rename to x-pack/plugins/uptime/public/state/effects/monitor.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/effects/monitor_duration.ts b/x-pack/plugins/uptime/public/state/effects/monitor_duration.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/effects/monitor_duration.ts rename to x-pack/plugins/uptime/public/state/effects/monitor_duration.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/effects/monitor_list.ts b/x-pack/plugins/uptime/public/state/effects/monitor_list.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/effects/monitor_list.ts rename to x-pack/plugins/uptime/public/state/effects/monitor_list.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/effects/monitor_status.ts b/x-pack/plugins/uptime/public/state/effects/monitor_status.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/effects/monitor_status.ts rename to x-pack/plugins/uptime/public/state/effects/monitor_status.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/effects/overview_filters.ts b/x-pack/plugins/uptime/public/state/effects/overview_filters.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/effects/overview_filters.ts rename to x-pack/plugins/uptime/public/state/effects/overview_filters.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/effects/ping.ts b/x-pack/plugins/uptime/public/state/effects/ping.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/effects/ping.ts rename to x-pack/plugins/uptime/public/state/effects/ping.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/effects/snapshot.ts b/x-pack/plugins/uptime/public/state/effects/snapshot.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/effects/snapshot.ts rename to x-pack/plugins/uptime/public/state/effects/snapshot.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/index.ts b/x-pack/plugins/uptime/public/state/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/index.ts rename to x-pack/plugins/uptime/public/state/index.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/kibana_service.ts b/x-pack/plugins/uptime/public/state/kibana_service.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/kibana_service.ts rename to x-pack/plugins/uptime/public/state/kibana_service.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/reducers/__tests__/__snapshots__/snapshot.test.ts.snap b/x-pack/plugins/uptime/public/state/reducers/__tests__/__snapshots__/snapshot.test.ts.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/reducers/__tests__/__snapshots__/snapshot.test.ts.snap rename to x-pack/plugins/uptime/public/state/reducers/__tests__/__snapshots__/snapshot.test.ts.snap diff --git a/x-pack/legacy/plugins/uptime/public/state/reducers/__tests__/__snapshots__/ui.test.ts.snap b/x-pack/plugins/uptime/public/state/reducers/__tests__/__snapshots__/ui.test.ts.snap similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/reducers/__tests__/__snapshots__/ui.test.ts.snap rename to x-pack/plugins/uptime/public/state/reducers/__tests__/__snapshots__/ui.test.ts.snap diff --git a/x-pack/legacy/plugins/uptime/public/state/reducers/__tests__/snapshot.test.ts b/x-pack/plugins/uptime/public/state/reducers/__tests__/snapshot.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/reducers/__tests__/snapshot.test.ts rename to x-pack/plugins/uptime/public/state/reducers/__tests__/snapshot.test.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/reducers/__tests__/ui.test.ts b/x-pack/plugins/uptime/public/state/reducers/__tests__/ui.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/reducers/__tests__/ui.test.ts rename to x-pack/plugins/uptime/public/state/reducers/__tests__/ui.test.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/reducers/dynamic_settings.ts b/x-pack/plugins/uptime/public/state/reducers/dynamic_settings.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/reducers/dynamic_settings.ts rename to x-pack/plugins/uptime/public/state/reducers/dynamic_settings.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/reducers/index.ts b/x-pack/plugins/uptime/public/state/reducers/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/reducers/index.ts rename to x-pack/plugins/uptime/public/state/reducers/index.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/reducers/index_pattern.ts b/x-pack/plugins/uptime/public/state/reducers/index_pattern.ts similarity index 92% rename from x-pack/legacy/plugins/uptime/public/state/reducers/index_pattern.ts rename to x-pack/plugins/uptime/public/state/reducers/index_pattern.ts index bc482e2f35c45..b357f5a904ea6 100644 --- a/x-pack/legacy/plugins/uptime/public/state/reducers/index_pattern.ts +++ b/x-pack/plugins/uptime/public/state/reducers/index_pattern.ts @@ -5,7 +5,7 @@ */ import { handleActions, Action } from 'redux-actions'; import { getIndexPattern, getIndexPatternSuccess, getIndexPatternFail } from '../actions'; -import { IIndexPattern } from '../../../../../../../src/plugins/data/common/index_patterns'; +import { IIndexPattern } from '../../../../../../src/plugins/data/common/index_patterns'; export interface IndexPatternState { index_pattern: IIndexPattern | null; diff --git a/x-pack/legacy/plugins/uptime/public/state/reducers/index_status.ts b/x-pack/plugins/uptime/public/state/reducers/index_status.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/reducers/index_status.ts rename to x-pack/plugins/uptime/public/state/reducers/index_status.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/reducers/ml_anomaly.ts b/x-pack/plugins/uptime/public/state/reducers/ml_anomaly.ts similarity index 88% rename from x-pack/legacy/plugins/uptime/public/state/reducers/ml_anomaly.ts rename to x-pack/plugins/uptime/public/state/reducers/ml_anomaly.ts index df5e825c3488b..61e03a9592921 100644 --- a/x-pack/legacy/plugins/uptime/public/state/reducers/ml_anomaly.ts +++ b/x-pack/plugins/uptime/public/state/reducers/ml_anomaly.ts @@ -15,11 +15,11 @@ import { getMLCapabilitiesAction, } from '../actions'; import { getAsyncInitialState, handleAsyncAction } from './utils'; -import { IHttpFetchError } from '../../../../../../../target/types/core/public/http'; +import { IHttpFetchError } from '../../../../../../target/types/core/public/http'; import { AsyncInitialState } from './types'; -import { MlCapabilitiesResponse } from '../../../../../../plugins/ml/common/types/capabilities'; +import { MlCapabilitiesResponse } from '../../../../../plugins/ml/common/types/capabilities'; import { CreateMLJobSuccess, DeleteJobResults } from '../actions/types'; -import { JobExistResult } from '../../../../../../plugins/ml/common/types/data_recognizer'; +import { JobExistResult } from '../../../../../plugins/ml/common/types/data_recognizer'; export interface MLJobState { mlJob: AsyncInitialState; diff --git a/x-pack/legacy/plugins/uptime/public/state/reducers/monitor.ts b/x-pack/plugins/uptime/public/state/reducers/monitor.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/reducers/monitor.ts rename to x-pack/plugins/uptime/public/state/reducers/monitor.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/reducers/monitor_duration.ts b/x-pack/plugins/uptime/public/state/reducers/monitor_duration.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/reducers/monitor_duration.ts rename to x-pack/plugins/uptime/public/state/reducers/monitor_duration.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/reducers/monitor_list.ts b/x-pack/plugins/uptime/public/state/reducers/monitor_list.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/reducers/monitor_list.ts rename to x-pack/plugins/uptime/public/state/reducers/monitor_list.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/reducers/monitor_status.ts b/x-pack/plugins/uptime/public/state/reducers/monitor_status.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/reducers/monitor_status.ts rename to x-pack/plugins/uptime/public/state/reducers/monitor_status.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/reducers/overview_filters.ts b/x-pack/plugins/uptime/public/state/reducers/overview_filters.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/reducers/overview_filters.ts rename to x-pack/plugins/uptime/public/state/reducers/overview_filters.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/reducers/ping.ts b/x-pack/plugins/uptime/public/state/reducers/ping.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/reducers/ping.ts rename to x-pack/plugins/uptime/public/state/reducers/ping.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/reducers/ping_list.ts b/x-pack/plugins/uptime/public/state/reducers/ping_list.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/reducers/ping_list.ts rename to x-pack/plugins/uptime/public/state/reducers/ping_list.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/reducers/snapshot.ts b/x-pack/plugins/uptime/public/state/reducers/snapshot.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/reducers/snapshot.ts rename to x-pack/plugins/uptime/public/state/reducers/snapshot.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/reducers/types.ts b/x-pack/plugins/uptime/public/state/reducers/types.ts similarity index 81% rename from x-pack/legacy/plugins/uptime/public/state/reducers/types.ts rename to x-pack/plugins/uptime/public/state/reducers/types.ts index 88995a2f5dd70..c81ee6875f305 100644 --- a/x-pack/legacy/plugins/uptime/public/state/reducers/types.ts +++ b/x-pack/plugins/uptime/public/state/reducers/types.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { IHttpFetchError } from '../../../../../../../target/types/core/public/http'; +import { IHttpFetchError } from '../../../../../../target/types/core/public/http'; export interface AsyncInitialState { data: ReduceStateType | null; diff --git a/x-pack/legacy/plugins/uptime/public/state/reducers/ui.ts b/x-pack/plugins/uptime/public/state/reducers/ui.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/reducers/ui.ts rename to x-pack/plugins/uptime/public/state/reducers/ui.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/reducers/utils.ts b/x-pack/plugins/uptime/public/state/reducers/utils.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/reducers/utils.ts rename to x-pack/plugins/uptime/public/state/reducers/utils.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/selectors/__tests__/index.test.ts b/x-pack/plugins/uptime/public/state/selectors/__tests__/index.test.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/selectors/__tests__/index.test.ts rename to x-pack/plugins/uptime/public/state/selectors/__tests__/index.test.ts diff --git a/x-pack/legacy/plugins/uptime/public/state/selectors/index.ts b/x-pack/plugins/uptime/public/state/selectors/index.ts similarity index 100% rename from x-pack/legacy/plugins/uptime/public/state/selectors/index.ts rename to x-pack/plugins/uptime/public/state/selectors/index.ts diff --git a/x-pack/legacy/plugins/uptime/public/uptime_app.tsx b/x-pack/plugins/uptime/public/uptime_app.tsx similarity index 75% rename from x-pack/legacy/plugins/uptime/public/uptime_app.tsx rename to x-pack/plugins/uptime/public/uptime_app.tsx index 92775a2663863..0d18f959230d1 100644 --- a/x-pack/legacy/plugins/uptime/public/uptime_app.tsx +++ b/x-pack/plugins/uptime/public/uptime_app.tsx @@ -10,13 +10,14 @@ import React, { useEffect } from 'react'; import { Provider as ReduxProvider } from 'react-redux'; import { BrowserRouter as Router } from 'react-router-dom'; import { I18nStart, ChromeBreadcrumb, CoreStart } from 'src/core/public'; -import { PluginsSetup } from 'ui/new_platform/new_platform'; -import { KibanaContextProvider } from '../../../../../src/plugins/kibana_react/public'; +import { KibanaContextProvider } from '../../../../src/plugins/kibana_react/public'; +import { ClientPluginsSetup, ClientPluginsStart } from './apps/plugin'; import { UMUpdateBadge } from './lib/lib'; import { UptimeRefreshContextProvider, UptimeSettingsContextProvider, UptimeThemeContextProvider, + UptimeStartupPluginsContextProvider, } from './contexts'; import { CommonlyUsedRange } from './components/common/uptime_date_picker'; import { store } from './state'; @@ -47,7 +48,8 @@ export interface UptimeAppProps { isInfraAvailable: boolean; isLogsAvailable: boolean; kibanaBreadcrumbs: ChromeBreadcrumb[]; - plugins: PluginsSetup; + plugins: ClientPluginsSetup; + startPlugins: ClientPluginsStart; routerBasename: string; setBadge: UMUpdateBadge; renderGlobalHelpControls(): void; @@ -66,6 +68,7 @@ const Application = (props: UptimeAppProps) => { renderGlobalHelpControls, routerBasename, setBadge, + startPlugins, } = props; useEffect(() => { @@ -87,7 +90,6 @@ const Application = (props: UptimeAppProps) => { kibanaService.core = core; - // @ts-ignore store.dispatch(setBasePath(basePath)); return ( @@ -99,17 +101,19 @@ const Application = (props: UptimeAppProps) => { - - -
- - -
-
-
+ + + +
+ + +
+
+
+
diff --git a/x-pack/plugins/uptime/server/kibana.index.ts b/x-pack/plugins/uptime/server/kibana.index.ts index 725b53aeca02d..d68bbabe82b86 100644 --- a/x-pack/plugins/uptime/server/kibana.index.ts +++ b/x-pack/plugins/uptime/server/kibana.index.ts @@ -5,7 +5,7 @@ */ import { Request, Server } from 'hapi'; -import { PLUGIN } from '../../../legacy/plugins/uptime/common/constants'; +import { PLUGIN } from '../common/constants'; import { compose } from './lib/compose/kibana'; import { initUptimeServer } from './uptime_server'; import { UptimeCorePlugins, UptimeCoreSetup } from './lib/adapters/framework'; diff --git a/x-pack/plugins/uptime/server/lib/adapters/framework/adapter_types.ts b/x-pack/plugins/uptime/server/lib/adapters/framework/adapter_types.ts index 98c6be5aa3c8e..f4d1c72770494 100644 --- a/x-pack/plugins/uptime/server/lib/adapters/framework/adapter_types.ts +++ b/x-pack/plugins/uptime/server/lib/adapters/framework/adapter_types.ts @@ -13,7 +13,7 @@ import { } from 'src/core/server'; import { UMKibanaRoute } from '../../../rest_api'; import { PluginSetupContract } from '../../../../../features/server'; -import { DynamicSettings } from '../../../../../../legacy/plugins/uptime/common/runtime_types'; +import { DynamicSettings } from '../../../../common/runtime_types'; export type APICaller = ( endpoint: string, @@ -31,7 +31,7 @@ export type UMSavedObjectsQueryFn = ( ) => Promise | T; export interface UptimeCoreSetup { - route: IRouter; + router: IRouter; } export interface UptimeCorePlugins { diff --git a/x-pack/plugins/uptime/server/lib/adapters/framework/kibana_framework_adapter.ts b/x-pack/plugins/uptime/server/lib/adapters/framework/kibana_framework_adapter.ts index 0176471aec1be..46f46720d4c04 100644 --- a/x-pack/plugins/uptime/server/lib/adapters/framework/kibana_framework_adapter.ts +++ b/x-pack/plugins/uptime/server/lib/adapters/framework/kibana_framework_adapter.ts @@ -21,10 +21,10 @@ export class UMKibanaBackendFrameworkAdapter implements UMBackendFrameworkAdapte }; switch (method) { case 'GET': - this.server.route.get(routeDefinition, handler); + this.server.router.get(routeDefinition, handler); break; case 'POST': - this.server.route.post(routeDefinition, handler); + this.server.router.post(routeDefinition, handler); break; default: throw new Error(`Handler for method ${method} is not defined`); diff --git a/x-pack/plugins/uptime/server/lib/alerts/__tests__/status_check.test.ts b/x-pack/plugins/uptime/server/lib/alerts/__tests__/status_check.test.ts index 4f4c6e3011ad1..24da3f3fa4d06 100644 --- a/x-pack/plugins/uptime/server/lib/alerts/__tests__/status_check.test.ts +++ b/x-pack/plugins/uptime/server/lib/alerts/__tests__/status_check.test.ts @@ -16,7 +16,7 @@ import { AlertType } from '../../../../../alerting/server'; import { IRouter } from 'kibana/server'; import { UMServerLibs } from '../../lib'; import { UptimeCoreSetup } from '../../adapters'; -import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../../../legacy/plugins/uptime/common/constants'; +import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../common/constants'; import { alertsMock, AlertServicesMock } from '../../../../../alerting/server/mocks'; /** @@ -27,10 +27,10 @@ import { alertsMock, AlertServicesMock } from '../../../../../alerting/server/mo * so we don't have to mock them all for each test. */ const bootstrapDependencies = (customRequests?: any) => { - const route: IRouter = {} as IRouter; + const router: IRouter = {} as IRouter; // these server/libs parameters don't have any functionality, which is fine // because we aren't testing them here - const server: UptimeCoreSetup = { route }; + const server: UptimeCoreSetup = { router }; const libs: UMServerLibs = { requests: {} } as UMServerLibs; libs.requests = { ...libs.requests, ...customRequests }; return { server, libs }; diff --git a/x-pack/plugins/uptime/server/lib/alerts/status_check.ts b/x-pack/plugins/uptime/server/lib/alerts/status_check.ts index 829e6f92d3702..f9df559a3977b 100644 --- a/x-pack/plugins/uptime/server/lib/alerts/status_check.ts +++ b/x-pack/plugins/uptime/server/lib/alerts/status_check.ts @@ -9,14 +9,14 @@ import { isRight } from 'fp-ts/lib/Either'; import { ThrowReporter } from 'io-ts/lib/ThrowReporter'; import { i18n } from '@kbn/i18n'; import { AlertExecutorOptions } from '../../../../alerting/server'; -import { ACTION_GROUP_DEFINITIONS } from '../../../../../legacy/plugins/uptime/common/constants'; import { UptimeAlertTypeFactory } from './types'; import { GetMonitorStatusResult } from '../requests'; import { StatusCheckExecutorParamsType, StatusCheckAlertStateType, StatusCheckAlertState, -} from '../../../../../legacy/plugins/uptime/common/runtime_types'; +} from '../../../common/runtime_types'; +import { ACTION_GROUP_DEFINITIONS } from '../../../common/constants'; import { savedObjectsAdapter } from '../saved_objects'; const { MONITOR_STATUS } = ACTION_GROUP_DEFINITIONS; diff --git a/x-pack/plugins/uptime/server/lib/helper/get_histogram_interval.ts b/x-pack/plugins/uptime/server/lib/helper/get_histogram_interval.ts index fb44f5727aab3..26515fb4b4c63 100644 --- a/x-pack/plugins/uptime/server/lib/helper/get_histogram_interval.ts +++ b/x-pack/plugins/uptime/server/lib/helper/get_histogram_interval.ts @@ -5,7 +5,7 @@ */ import DateMath from '@elastic/datemath'; -import { QUERY } from '../../../../../legacy/plugins/uptime/common/constants'; +import { QUERY } from '../../../common/constants'; export const parseRelativeDate = (dateStr: string, options = {}) => { // We need this this parsing because if user selects This week or this date diff --git a/x-pack/plugins/uptime/server/lib/requests/__tests__/get_certs.test.ts b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_certs.test.ts index b49a6b22ff976..894e2316dc927 100644 --- a/x-pack/plugins/uptime/server/lib/requests/__tests__/get_certs.test.ts +++ b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_certs.test.ts @@ -5,7 +5,7 @@ */ import { getCerts } from '../get_certs'; -import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../../../legacy/plugins/uptime/common/constants'; +import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../common/constants'; describe('getCerts', () => { let mockHits: any; diff --git a/x-pack/plugins/uptime/server/lib/requests/__tests__/get_latest_monitor.test.ts b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_latest_monitor.test.ts index 03e2bc7a44bd0..75bf5096bd997 100644 --- a/x-pack/plugins/uptime/server/lib/requests/__tests__/get_latest_monitor.test.ts +++ b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_latest_monitor.test.ts @@ -5,7 +5,7 @@ */ import { getLatestMonitor } from '../get_latest_monitor'; -import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../../../legacy/plugins/uptime/common/constants'; +import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../common/constants'; describe('getLatestMonitor', () => { let expectedGetLatestSearchParams: any; diff --git a/x-pack/plugins/uptime/server/lib/requests/__tests__/get_monitor_charts.test.ts b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_monitor_charts.test.ts index 5d3f9ce8d4ad9..45be1df3e8d3b 100644 --- a/x-pack/plugins/uptime/server/lib/requests/__tests__/get_monitor_charts.test.ts +++ b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_monitor_charts.test.ts @@ -7,7 +7,7 @@ import { set } from 'lodash'; import mockChartsData from './monitor_charts_mock.json'; import { getMonitorDurationChart } from '../get_monitor_duration'; -import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../../../legacy/plugins/uptime/common/constants'; +import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../common/constants'; describe('ElasticsearchMonitorsAdapter', () => { it('getMonitorChartsData will provide expected filters', async () => { diff --git a/x-pack/plugins/uptime/server/lib/requests/__tests__/get_monitor_status.test.ts b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_monitor_status.test.ts index e47be617d7c99..82e624221c301 100644 --- a/x-pack/plugins/uptime/server/lib/requests/__tests__/get_monitor_status.test.ts +++ b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_monitor_status.test.ts @@ -6,8 +6,8 @@ import { elasticsearchServiceMock } from '../../../../../../../src/core/server/mocks'; import { getMonitorStatus } from '../get_monitor_status'; -import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../../../legacy/plugins/uptime/common/constants'; import { ScopedClusterClient } from 'src/core/server'; +import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../common/constants'; interface BucketItemCriteria { monitor_id: string; diff --git a/x-pack/plugins/uptime/server/lib/requests/__tests__/get_ping_histogram.test.ts b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_ping_histogram.test.ts index 4de7d3ffd2a7d..e456670a5e68d 100644 --- a/x-pack/plugins/uptime/server/lib/requests/__tests__/get_ping_histogram.test.ts +++ b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_ping_histogram.test.ts @@ -5,7 +5,7 @@ */ import { getPingHistogram } from '../get_ping_histogram'; -import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../../../legacy/plugins/uptime/common/constants'; +import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../common/constants'; describe('getPingHistogram', () => { const standardMockResponse: any = { diff --git a/x-pack/plugins/uptime/server/lib/requests/__tests__/get_pings.test.ts b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_pings.test.ts index abd3655cc6402..fd890a30cf742 100644 --- a/x-pack/plugins/uptime/server/lib/requests/__tests__/get_pings.test.ts +++ b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_pings.test.ts @@ -6,7 +6,7 @@ import { getPings } from '../get_pings'; import { set } from 'lodash'; -import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../../../legacy/plugins/uptime/common/constants'; +import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../common/constants'; describe('getAll', () => { let mockEsSearchResult: any; diff --git a/x-pack/plugins/uptime/server/lib/requests/get_certs.ts b/x-pack/plugins/uptime/server/lib/requests/get_certs.ts index 4f99fbe94d54c..b427e7cae1a7e 100644 --- a/x-pack/plugins/uptime/server/lib/requests/get_certs.ts +++ b/x-pack/plugins/uptime/server/lib/requests/get_certs.ts @@ -5,7 +5,7 @@ */ import { UMElasticsearchQueryFn } from '../adapters'; -import { Cert, GetCertsParams } from '../../../../../legacy/plugins/uptime/common/runtime_types'; +import { Cert, GetCertsParams } from '../../../common/runtime_types'; export const getCerts: UMElasticsearchQueryFn = async ({ callES, diff --git a/x-pack/plugins/uptime/server/lib/requests/get_filter_bar.ts b/x-pack/plugins/uptime/server/lib/requests/get_filter_bar.ts index 95d23ddcbf466..dbe71cf689214 100644 --- a/x-pack/plugins/uptime/server/lib/requests/get_filter_bar.ts +++ b/x-pack/plugins/uptime/server/lib/requests/get_filter_bar.ts @@ -5,7 +5,7 @@ */ import { UMElasticsearchQueryFn } from '../adapters'; -import { OverviewFilters } from '../../../../../legacy/plugins/uptime/common/runtime_types'; +import { OverviewFilters } from '../../../common/runtime_types'; import { generateFilterAggs } from './generate_filter_aggs'; export interface GetFilterBarParams { diff --git a/x-pack/plugins/uptime/server/lib/requests/get_index_status.ts b/x-pack/plugins/uptime/server/lib/requests/get_index_status.ts index 6f7854d35b308..7688f04f1acd9 100644 --- a/x-pack/plugins/uptime/server/lib/requests/get_index_status.ts +++ b/x-pack/plugins/uptime/server/lib/requests/get_index_status.ts @@ -5,7 +5,7 @@ */ import { UMElasticsearchQueryFn } from '../adapters'; -import { StatesIndexStatus } from '../../../../../legacy/plugins/uptime/common/runtime_types'; +import { StatesIndexStatus } from '../../../common/runtime_types'; export const getIndexStatus: UMElasticsearchQueryFn<{}, StatesIndexStatus> = async ({ callES, diff --git a/x-pack/plugins/uptime/server/lib/requests/get_latest_monitor.ts b/x-pack/plugins/uptime/server/lib/requests/get_latest_monitor.ts index a8e9ccb875a08..98ce449002f21 100644 --- a/x-pack/plugins/uptime/server/lib/requests/get_latest_monitor.ts +++ b/x-pack/plugins/uptime/server/lib/requests/get_latest_monitor.ts @@ -5,7 +5,7 @@ */ import { UMElasticsearchQueryFn } from '../adapters'; -import { Ping } from '../../../../../legacy/plugins/uptime/common/runtime_types'; +import { Ping } from '../../../common/runtime_types'; export interface GetLatestMonitorParams { /** @member dateRangeStart timestamp bounds */ diff --git a/x-pack/plugins/uptime/server/lib/requests/get_monitor_details.ts b/x-pack/plugins/uptime/server/lib/requests/get_monitor_details.ts index 4ce7176b57b19..cf4ffa339ddfc 100644 --- a/x-pack/plugins/uptime/server/lib/requests/get_monitor_details.ts +++ b/x-pack/plugins/uptime/server/lib/requests/get_monitor_details.ts @@ -5,10 +5,7 @@ */ import { UMElasticsearchQueryFn } from '../adapters'; -import { - MonitorDetails, - MonitorError, -} from '../../../../../legacy/plugins/uptime/common/runtime_types'; +import { MonitorDetails, MonitorError } from '../../../common/runtime_types'; export interface GetMonitorDetailsParams { monitorId: string; diff --git a/x-pack/plugins/uptime/server/lib/requests/get_monitor_duration.ts b/x-pack/plugins/uptime/server/lib/requests/get_monitor_duration.ts index e9c745b0a8713..ea2a7e790652b 100644 --- a/x-pack/plugins/uptime/server/lib/requests/get_monitor_duration.ts +++ b/x-pack/plugins/uptime/server/lib/requests/get_monitor_duration.ts @@ -5,11 +5,8 @@ */ import { UMElasticsearchQueryFn } from '../adapters'; -import { QUERY } from '../../../../../legacy/plugins/uptime/common/constants'; -import { - LocationDurationLine, - MonitorDurationResult, -} from '../../../../../legacy/plugins/uptime/common/types'; +import { LocationDurationLine, MonitorDurationResult } from '../../../common/types'; +import { QUERY } from '../../../common/constants'; export interface GetMonitorChartsParams { /** @member monitorId ID value for the selected monitor */ diff --git a/x-pack/plugins/uptime/server/lib/requests/get_monitor_locations.ts b/x-pack/plugins/uptime/server/lib/requests/get_monitor_locations.ts index f49e404ffb084..c8d3ca043edc5 100644 --- a/x-pack/plugins/uptime/server/lib/requests/get_monitor_locations.ts +++ b/x-pack/plugins/uptime/server/lib/requests/get_monitor_locations.ts @@ -5,11 +5,8 @@ */ import { UMElasticsearchQueryFn } from '../adapters'; -import { UNNAMED_LOCATION } from '../../../../../legacy/plugins/uptime/common/constants'; -import { - MonitorLocations, - MonitorLocation, -} from '../../../../../legacy/plugins/uptime/common/runtime_types'; +import { MonitorLocations, MonitorLocation } from '../../../common/runtime_types'; +import { UNNAMED_LOCATION } from '../../../common/constants'; /** * Fetch data for the monitor page title. diff --git a/x-pack/plugins/uptime/server/lib/requests/get_monitor_states.ts b/x-pack/plugins/uptime/server/lib/requests/get_monitor_states.ts index 4b40943a85705..b1791dd04861c 100644 --- a/x-pack/plugins/uptime/server/lib/requests/get_monitor_states.ts +++ b/x-pack/plugins/uptime/server/lib/requests/get_monitor_states.ts @@ -4,15 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -import { CONTEXT_DEFAULTS } from '../../../../../legacy/plugins/uptime/common/constants'; +import { CONTEXT_DEFAULTS } from '../../../common/constants'; import { fetchPage } from './search'; import { UMElasticsearchQueryFn } from '../adapters'; -import { - SortOrder, - CursorDirection, - MonitorSummary, -} from '../../../../../legacy/plugins/uptime/common/runtime_types'; - +import { MonitorSummary, SortOrder, CursorDirection } from '../../../common/runtime_types'; import { QueryContext } from './search'; export interface CursorPagination { diff --git a/x-pack/plugins/uptime/server/lib/requests/get_ping_histogram.ts b/x-pack/plugins/uptime/server/lib/requests/get_ping_histogram.ts index 5a8927764ea5c..299913c8dff08 100644 --- a/x-pack/plugins/uptime/server/lib/requests/get_ping_histogram.ts +++ b/x-pack/plugins/uptime/server/lib/requests/get_ping_histogram.ts @@ -5,12 +5,9 @@ */ import { UMElasticsearchQueryFn } from '../adapters'; -import { QUERY } from '../../../../../legacy/plugins/uptime/common/constants'; import { getFilterClause } from '../helper'; -import { - HistogramResult, - HistogramQueryResult, -} from '../../../../../legacy/plugins/uptime/common/runtime_types'; +import { HistogramResult, HistogramQueryResult } from '../../../common/runtime_types'; +import { QUERY } from '../../../common/constants'; export interface GetPingHistogramParams { /** @member dateRangeStart timestamp bounds */ diff --git a/x-pack/plugins/uptime/server/lib/requests/get_pings.ts b/x-pack/plugins/uptime/server/lib/requests/get_pings.ts index 6eccfdb13cef7..a6a0e3c3d6542 100644 --- a/x-pack/plugins/uptime/server/lib/requests/get_pings.ts +++ b/x-pack/plugins/uptime/server/lib/requests/get_pings.ts @@ -10,7 +10,7 @@ import { HttpResponseBody, PingsResponse, Ping, -} from '../../../../../legacy/plugins/uptime/common/runtime_types'; +} from '../../../common/runtime_types'; const DEFAULT_PAGE_SIZE = 25; diff --git a/x-pack/plugins/uptime/server/lib/requests/get_snapshot_counts.ts b/x-pack/plugins/uptime/server/lib/requests/get_snapshot_counts.ts index 01f2ad88161cf..b57bc87d45418 100644 --- a/x-pack/plugins/uptime/server/lib/requests/get_snapshot_counts.ts +++ b/x-pack/plugins/uptime/server/lib/requests/get_snapshot_counts.ts @@ -5,8 +5,8 @@ */ import { UMElasticsearchQueryFn } from '../adapters'; -import { Snapshot } from '../../../../../legacy/plugins/uptime/common/runtime_types'; -import { CONTEXT_DEFAULTS } from '../../../../../legacy/plugins/uptime/common/constants'; +import { CONTEXT_DEFAULTS } from '../../../common/constants'; +import { Snapshot } from '../../../common/runtime_types'; import { QueryContext } from './search'; export interface GetSnapshotCountParams { diff --git a/x-pack/plugins/uptime/server/lib/requests/search/__tests__/fetch_page.test.ts b/x-pack/plugins/uptime/server/lib/requests/search/__tests__/fetch_page.test.ts index 2a8f681ab3453..d4ad80c85ec3d 100644 --- a/x-pack/plugins/uptime/server/lib/requests/search/__tests__/fetch_page.test.ts +++ b/x-pack/plugins/uptime/server/lib/requests/search/__tests__/fetch_page.test.ts @@ -12,7 +12,7 @@ import { MonitorGroupsPage, } from '../fetch_page'; import { QueryContext } from '../query_context'; -import { MonitorSummary } from '../../../../../../../legacy/plugins/uptime/common/runtime_types'; +import { MonitorSummary } from '../../../../../common/runtime_types'; import { nextPagination, prevPagination, simpleQueryContext } from './test_helpers'; const simpleFixture: MonitorGroups[] = [ diff --git a/x-pack/plugins/uptime/server/lib/requests/search/__tests__/query_context.test.ts b/x-pack/plugins/uptime/server/lib/requests/search/__tests__/query_context.test.ts index 84774cdeed856..e53fff429dd8d 100644 --- a/x-pack/plugins/uptime/server/lib/requests/search/__tests__/query_context.test.ts +++ b/x-pack/plugins/uptime/server/lib/requests/search/__tests__/query_context.test.ts @@ -6,10 +6,7 @@ import { QueryContext } from '../query_context'; import { CursorPagination } from '../types'; -import { - CursorDirection, - SortOrder, -} from '../../../../../../../legacy/plugins/uptime/common/runtime_types'; +import { CursorDirection, SortOrder } from '../../../../../common/runtime_types'; describe(QueryContext, () => { // 10 minute range diff --git a/x-pack/plugins/uptime/server/lib/requests/search/__tests__/test_helpers.ts b/x-pack/plugins/uptime/server/lib/requests/search/__tests__/test_helpers.ts index 47034c2130116..40775bde1c7f5 100644 --- a/x-pack/plugins/uptime/server/lib/requests/search/__tests__/test_helpers.ts +++ b/x-pack/plugins/uptime/server/lib/requests/search/__tests__/test_helpers.ts @@ -5,10 +5,7 @@ */ import { CursorPagination } from '../types'; -import { - CursorDirection, - SortOrder, -} from '../../../../../../../legacy/plugins/uptime/common/runtime_types'; +import { CursorDirection, SortOrder } from '../../../../../common/runtime_types'; import { QueryContext } from '../query_context'; export const prevPagination = (key: any): CursorPagination => { diff --git a/x-pack/plugins/uptime/server/lib/requests/search/enrich_monitor_groups.ts b/x-pack/plugins/uptime/server/lib/requests/search/enrich_monitor_groups.ts index 4739c804d24e7..d21259fad77a6 100644 --- a/x-pack/plugins/uptime/server/lib/requests/search/enrich_monitor_groups.ts +++ b/x-pack/plugins/uptime/server/lib/requests/search/enrich_monitor_groups.ts @@ -6,14 +6,14 @@ import { get, sortBy } from 'lodash'; import { QueryContext } from './query_context'; -import { QUERY, STATES } from '../../../../../../legacy/plugins/uptime/common/constants'; +import { QUERY, STATES } from '../../../../common/constants'; import { Check, Histogram, MonitorSummary, CursorDirection, SortOrder, -} from '../../../../../../legacy/plugins/uptime/common/runtime_types'; +} from '../../../../common/runtime_types'; import { MonitorEnricher } from './fetch_page'; export const enrichMonitorGroups: MonitorEnricher = async ( diff --git a/x-pack/plugins/uptime/server/lib/requests/search/fetch_page.ts b/x-pack/plugins/uptime/server/lib/requests/search/fetch_page.ts index 84167840d5d9b..bef8106ad1896 100644 --- a/x-pack/plugins/uptime/server/lib/requests/search/fetch_page.ts +++ b/x-pack/plugins/uptime/server/lib/requests/search/fetch_page.ts @@ -7,12 +7,8 @@ import { flatten } from 'lodash'; import { CursorPagination } from './types'; import { QueryContext } from './query_context'; -import { QUERY } from '../../../../../../legacy/plugins/uptime/common/constants'; -import { - CursorDirection, - MonitorSummary, - SortOrder, -} from '../../../../../../legacy/plugins/uptime/common/runtime_types'; +import { QUERY } from '../../../../common/constants'; +import { CursorDirection, MonitorSummary, SortOrder } from '../../../../common/runtime_types'; import { enrichMonitorGroups } from './enrich_monitor_groups'; import { MonitorGroupIterator } from './monitor_group_iterator'; diff --git a/x-pack/plugins/uptime/server/lib/requests/search/find_potential_matches.ts b/x-pack/plugins/uptime/server/lib/requests/search/find_potential_matches.ts index 3449febfa5b05..e60c52660915a 100644 --- a/x-pack/plugins/uptime/server/lib/requests/search/find_potential_matches.ts +++ b/x-pack/plugins/uptime/server/lib/requests/search/find_potential_matches.ts @@ -5,7 +5,7 @@ */ import { get, set } from 'lodash'; -import { CursorDirection } from '../../../../../../legacy/plugins/uptime/common/runtime_types'; +import { CursorDirection } from '../../../../common/runtime_types'; import { QueryContext } from './query_context'; // This is the first phase of the query. In it, we find the most recent check groups that matched the given query. diff --git a/x-pack/plugins/uptime/server/lib/requests/search/monitor_group_iterator.ts b/x-pack/plugins/uptime/server/lib/requests/search/monitor_group_iterator.ts index 31d9166eb1e73..2fb9562028258 100644 --- a/x-pack/plugins/uptime/server/lib/requests/search/monitor_group_iterator.ts +++ b/x-pack/plugins/uptime/server/lib/requests/search/monitor_group_iterator.ts @@ -6,7 +6,7 @@ import { QueryContext } from './query_context'; import { fetchChunk } from './fetch_chunk'; -import { CursorDirection } from '../../../../../../legacy/plugins/uptime/common/runtime_types'; +import { CursorDirection } from '../../../../common/runtime_types'; import { MonitorGroups } from './fetch_page'; import { CursorPagination } from './types'; diff --git a/x-pack/plugins/uptime/server/lib/requests/search/refine_potential_matches.ts b/x-pack/plugins/uptime/server/lib/requests/search/refine_potential_matches.ts index 43fc54fb25808..977c32ad1f984 100644 --- a/x-pack/plugins/uptime/server/lib/requests/search/refine_potential_matches.ts +++ b/x-pack/plugins/uptime/server/lib/requests/search/refine_potential_matches.ts @@ -5,7 +5,7 @@ */ import { QueryContext } from './query_context'; -import { CursorDirection } from '../../../../../../legacy/plugins/uptime/common/runtime_types'; +import { CursorDirection } from '../../../../common/runtime_types'; import { MonitorGroups, MonitorLocCheckGroup } from './fetch_page'; /** diff --git a/x-pack/plugins/uptime/server/lib/requests/search/types.ts b/x-pack/plugins/uptime/server/lib/requests/search/types.ts index 2ec52d400b597..35e9647196454 100644 --- a/x-pack/plugins/uptime/server/lib/requests/search/types.ts +++ b/x-pack/plugins/uptime/server/lib/requests/search/types.ts @@ -4,10 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { - CursorDirection, - SortOrder, -} from '../../../../../../legacy/plugins/uptime/common/runtime_types'; +import { CursorDirection, SortOrder } from '../../../../common/runtime_types'; export interface CursorPagination { cursorKey?: any; diff --git a/x-pack/plugins/uptime/server/lib/requests/uptime_requests.ts b/x-pack/plugins/uptime/server/lib/requests/uptime_requests.ts index 84154429b9188..69507d2950cd8 100644 --- a/x-pack/plugins/uptime/server/lib/requests/uptime_requests.ts +++ b/x-pack/plugins/uptime/server/lib/requests/uptime_requests.ts @@ -8,10 +8,17 @@ import { UMElasticsearchQueryFn } from '../adapters'; import { HistogramResult, Ping, - PingsResponse as PingResults, + PingsResponse, GetCertsParams, GetPingsParams, -} from '../../../../../legacy/plugins/uptime/common/runtime_types'; + Cert, + OverviewFilters, + MonitorDetails, + MonitorLocations, + Snapshot, + StatesIndexStatus, +} from '../../../common/runtime_types'; +import { MonitorDurationResult } from '../../../common/types'; import { GetFilterBarParams, GetLatestMonitorParams, @@ -23,17 +30,8 @@ import { GetMonitorStatusParams, GetMonitorStatusResult, } from '.'; -import { - OverviewFilters, - MonitorDetails, - MonitorLocations, - Snapshot, - StatesIndexStatus, - Cert, -} from '../../../../../legacy/plugins/uptime/common/runtime_types'; import { GetMonitorStatesResult } from './get_monitor_states'; import { GetSnapshotCountParams } from './get_snapshot_counts'; -import { MonitorDurationResult } from '../../../../../legacy/plugins/uptime/common/types'; type ESQ = UMElasticsearchQueryFn; @@ -47,7 +45,7 @@ export interface UptimeRequests { getMonitorLocations: ESQ; getMonitorStates: ESQ; getMonitorStatus: ESQ; - getPings: ESQ; + getPings: ESQ; getPingHistogram: ESQ; getSnapshotCount: ESQ; getIndexStatus: ESQ<{}, StatesIndexStatus>; diff --git a/x-pack/plugins/uptime/server/lib/saved_objects.ts b/x-pack/plugins/uptime/server/lib/saved_objects.ts index d849fbd8ce0a8..28b9eaad2cf6f 100644 --- a/x-pack/plugins/uptime/server/lib/saved_objects.ts +++ b/x-pack/plugins/uptime/server/lib/saved_objects.ts @@ -4,8 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { DynamicSettings } from '../../../../legacy/plugins/uptime/common/runtime_types'; -import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../legacy/plugins/uptime/common/constants'; +import { DYNAMIC_SETTINGS_DEFAULTS } from '../../common/constants'; +import { DynamicSettings } from '../../common/runtime_types'; import { SavedObjectsType, SavedObjectsErrorHelpers } from '../../../../../src/core/server'; import { UMSavedObjectsQueryFn } from './adapters'; diff --git a/x-pack/plugins/uptime/server/plugin.ts b/x-pack/plugins/uptime/server/plugin.ts index 7cc591a6b2db1..13d1ae216f204 100644 --- a/x-pack/plugins/uptime/server/plugin.ts +++ b/x-pack/plugins/uptime/server/plugin.ts @@ -8,19 +8,20 @@ import { PluginInitializerContext, CoreStart, CoreSetup, + Plugin as PluginType, ISavedObjectsRepository, } from '../../../../src/core/server'; import { initServerWithKibana } from './kibana.index'; import { KibanaTelemetryAdapter, UptimeCorePlugins } from './lib/adapters'; import { umDynamicSettings } from './lib/saved_objects'; -export class Plugin { +export class Plugin implements PluginType { private savedObjectsClient?: ISavedObjectsRepository; constructor(_initializerContext: PluginInitializerContext) {} public setup(core: CoreSetup, plugins: UptimeCorePlugins) { - initServerWithKibana({ route: core.http.createRouter() }, plugins); + initServerWithKibana({ router: core.http.createRouter() }, plugins); core.savedObjects.registerType(umDynamicSettings); KibanaTelemetryAdapter.registerUsageCollector( plugins.usageCollection, @@ -28,7 +29,9 @@ export class Plugin { ); } - public start(_core: CoreStart, _plugins: any) { - this.savedObjectsClient = _core.savedObjects.createInternalRepository(); + public start(core: CoreStart, _plugins: any) { + this.savedObjectsClient = core.savedObjects.createInternalRepository(); } + + public stop() {} } diff --git a/x-pack/plugins/uptime/server/rest_api/certs.ts b/x-pack/plugins/uptime/server/rest_api/certs.ts index 31fb3f4ab96a7..f2e1700b23e7d 100644 --- a/x-pack/plugins/uptime/server/rest_api/certs.ts +++ b/x-pack/plugins/uptime/server/rest_api/certs.ts @@ -7,7 +7,7 @@ import { schema } from '@kbn/config-schema'; import { UMServerLibs } from '../lib/lib'; import { UMRestApiRouteFactory } from '.'; -import { API_URLS } from '../../../../legacy/plugins/uptime/common/constants/rest_api'; +import { API_URLS } from '../../common/constants'; const DEFAULT_INDEX = 0; const DEFAULT_SIZE = 25; diff --git a/x-pack/plugins/uptime/server/rest_api/dynamic_settings.ts b/x-pack/plugins/uptime/server/rest_api/dynamic_settings.ts index 3f4e2fc345182..31833a25ee8ac 100644 --- a/x-pack/plugins/uptime/server/rest_api/dynamic_settings.ts +++ b/x-pack/plugins/uptime/server/rest_api/dynamic_settings.ts @@ -8,10 +8,7 @@ import { schema } from '@kbn/config-schema'; import { isRight } from 'fp-ts/lib/Either'; import { PathReporter } from 'io-ts/lib/PathReporter'; import { UMServerLibs } from '../lib/lib'; -import { - DynamicSettings, - DynamicSettingsType, -} from '../../../../legacy/plugins/uptime/common/runtime_types'; +import { DynamicSettings, DynamicSettingsType } from '../../common/runtime_types'; import { UMRestApiRouteFactory } from '.'; import { savedObjectsAdapter } from '../lib/saved_objects'; diff --git a/x-pack/plugins/uptime/server/rest_api/index_state/get_index_pattern.ts b/x-pack/plugins/uptime/server/rest_api/index_state/get_index_pattern.ts index 689a75c5903a6..26715f0ff37b6 100644 --- a/x-pack/plugins/uptime/server/rest_api/index_state/get_index_pattern.ts +++ b/x-pack/plugins/uptime/server/rest_api/index_state/get_index_pattern.ts @@ -6,7 +6,7 @@ import { UMServerLibs } from '../../lib/lib'; import { UMRestApiRouteFactory } from '../types'; -import { API_URLS } from '../../../../../legacy/plugins/uptime/common/constants/rest_api'; +import { API_URLS } from '../../../common/constants'; export const createGetIndexPatternRoute: UMRestApiRouteFactory = (libs: UMServerLibs) => ({ method: 'GET', diff --git a/x-pack/plugins/uptime/server/rest_api/index_state/get_index_status.ts b/x-pack/plugins/uptime/server/rest_api/index_state/get_index_status.ts index 8ed73d90b2389..9a4280efa98f9 100644 --- a/x-pack/plugins/uptime/server/rest_api/index_state/get_index_status.ts +++ b/x-pack/plugins/uptime/server/rest_api/index_state/get_index_status.ts @@ -6,7 +6,7 @@ import { UMServerLibs } from '../../lib/lib'; import { UMRestApiRouteFactory } from '../types'; -import { API_URLS } from '../../../../../legacy/plugins/uptime/common/constants'; +import { API_URLS } from '../../../common/constants'; export const createGetIndexStatusRoute: UMRestApiRouteFactory = (libs: UMServerLibs) => ({ method: 'GET', diff --git a/x-pack/plugins/uptime/server/rest_api/monitors/monitor_list.ts b/x-pack/plugins/uptime/server/rest_api/monitors/monitor_list.ts index 5cb4e8a6241b7..60b3eafaa765e 100644 --- a/x-pack/plugins/uptime/server/rest_api/monitors/monitor_list.ts +++ b/x-pack/plugins/uptime/server/rest_api/monitors/monitor_list.ts @@ -6,8 +6,7 @@ import { schema } from '@kbn/config-schema'; import { UMRestApiRouteFactory } from '../types'; -import { CONTEXT_DEFAULTS } from '../../../../../legacy/plugins/uptime/common/constants'; -import { API_URLS } from '../../../../../legacy/plugins/uptime/common/constants/rest_api'; +import { API_URLS, CONTEXT_DEFAULTS } from '../../../common/constants'; export const createMonitorListRoute: UMRestApiRouteFactory = libs => ({ method: 'GET', diff --git a/x-pack/plugins/uptime/server/rest_api/monitors/monitor_locations.ts b/x-pack/plugins/uptime/server/rest_api/monitors/monitor_locations.ts index 66ce9871506d4..a110209043a7e 100644 --- a/x-pack/plugins/uptime/server/rest_api/monitors/monitor_locations.ts +++ b/x-pack/plugins/uptime/server/rest_api/monitors/monitor_locations.ts @@ -7,7 +7,7 @@ import { schema } from '@kbn/config-schema'; import { UMServerLibs } from '../../lib/lib'; import { UMRestApiRouteFactory } from '../types'; -import { API_URLS } from '../../../../../legacy/plugins/uptime/common/constants/rest_api'; +import { API_URLS } from '../../../common/constants'; export const createGetMonitorLocationsRoute: UMRestApiRouteFactory = (libs: UMServerLibs) => ({ method: 'GET', diff --git a/x-pack/plugins/uptime/server/rest_api/monitors/monitor_status.ts b/x-pack/plugins/uptime/server/rest_api/monitors/monitor_status.ts index 9cf1340fb9409..bb002f8a8c286 100644 --- a/x-pack/plugins/uptime/server/rest_api/monitors/monitor_status.ts +++ b/x-pack/plugins/uptime/server/rest_api/monitors/monitor_status.ts @@ -7,7 +7,7 @@ import { schema } from '@kbn/config-schema'; import { UMServerLibs } from '../../lib/lib'; import { UMRestApiRouteFactory } from '../types'; -import { API_URLS } from '../../../../../legacy/plugins/uptime/common/constants'; +import { API_URLS } from '../../../common/constants'; export const createGetStatusBarRoute: UMRestApiRouteFactory = (libs: UMServerLibs) => ({ method: 'GET', diff --git a/x-pack/plugins/uptime/server/rest_api/monitors/monitors_details.ts b/x-pack/plugins/uptime/server/rest_api/monitors/monitors_details.ts index 1cc010781457e..69e719efb0719 100644 --- a/x-pack/plugins/uptime/server/rest_api/monitors/monitors_details.ts +++ b/x-pack/plugins/uptime/server/rest_api/monitors/monitors_details.ts @@ -7,7 +7,7 @@ import { schema } from '@kbn/config-schema'; import { UMServerLibs } from '../../lib/lib'; import { UMRestApiRouteFactory } from '../types'; -import { API_URLS } from '../../../../../legacy/plugins/uptime/common/constants/rest_api'; +import { API_URLS } from '../../../common/constants'; export const createGetMonitorDetailsRoute: UMRestApiRouteFactory = (libs: UMServerLibs) => ({ method: 'GET', diff --git a/x-pack/plugins/uptime/server/rest_api/monitors/monitors_durations.ts b/x-pack/plugins/uptime/server/rest_api/monitors/monitors_durations.ts index 9743ced13350a..34313211061b0 100644 --- a/x-pack/plugins/uptime/server/rest_api/monitors/monitors_durations.ts +++ b/x-pack/plugins/uptime/server/rest_api/monitors/monitors_durations.ts @@ -7,7 +7,7 @@ import { schema } from '@kbn/config-schema'; import { UMServerLibs } from '../../lib/lib'; import { UMRestApiRouteFactory } from '../types'; -import { API_URLS } from '../../../../../legacy/plugins/uptime/common/constants/rest_api'; +import { API_URLS } from '../../../common/constants'; export const createGetMonitorDurationRoute: UMRestApiRouteFactory = (libs: UMServerLibs) => ({ method: 'GET', diff --git a/x-pack/plugins/uptime/server/rest_api/overview_filters/get_overview_filters.ts b/x-pack/plugins/uptime/server/rest_api/overview_filters/get_overview_filters.ts index deac05f36c8dc..00cbaf0d16723 100644 --- a/x-pack/plugins/uptime/server/rest_api/overview_filters/get_overview_filters.ts +++ b/x-pack/plugins/uptime/server/rest_api/overview_filters/get_overview_filters.ts @@ -8,7 +8,7 @@ import { schema } from '@kbn/config-schema'; import { UMServerLibs } from '../../lib/lib'; import { UMRestApiRouteFactory } from '../types'; import { objectValuesToArrays } from '../../lib/helper'; -import { API_URLS } from '../../../../../legacy/plugins/uptime/common/constants/rest_api'; +import { API_URLS } from '../../../common/constants'; const arrayOrStringType = schema.maybe( schema.oneOf([schema.string(), schema.arrayOf(schema.string())]) diff --git a/x-pack/plugins/uptime/server/rest_api/pings/get_ping_histogram.ts b/x-pack/plugins/uptime/server/rest_api/pings/get_ping_histogram.ts index dceef5ecb7848..41078f735920b 100644 --- a/x-pack/plugins/uptime/server/rest_api/pings/get_ping_histogram.ts +++ b/x-pack/plugins/uptime/server/rest_api/pings/get_ping_histogram.ts @@ -7,7 +7,7 @@ import { schema } from '@kbn/config-schema'; import { UMServerLibs } from '../../lib/lib'; import { UMRestApiRouteFactory } from '../types'; -import { API_URLS } from '../../../../../legacy/plugins/uptime/common/constants/rest_api'; +import { API_URLS } from '../../../common/constants'; export const createGetPingHistogramRoute: UMRestApiRouteFactory = (libs: UMServerLibs) => ({ method: 'GET', diff --git a/x-pack/plugins/uptime/server/rest_api/pings/get_pings.ts b/x-pack/plugins/uptime/server/rest_api/pings/get_pings.ts index 80a887a7f64a9..d97195a7fe2b1 100644 --- a/x-pack/plugins/uptime/server/rest_api/pings/get_pings.ts +++ b/x-pack/plugins/uptime/server/rest_api/pings/get_pings.ts @@ -9,8 +9,8 @@ import { isLeft } from 'fp-ts/lib/Either'; import { PathReporter } from 'io-ts/lib/PathReporter'; import { UMServerLibs } from '../../lib/lib'; import { UMRestApiRouteFactory } from '../types'; -import { API_URLS } from '../../../../../legacy/plugins/uptime/common/constants/rest_api'; -import { GetPingsParamsType } from '../../../../../legacy/plugins/uptime/common/runtime_types'; +import { API_URLS } from '../../../common/constants'; +import { GetPingsParamsType } from '../../../common/runtime_types'; export const createGetPingsRoute: UMRestApiRouteFactory = (libs: UMServerLibs) => ({ method: 'GET', diff --git a/x-pack/plugins/uptime/server/rest_api/snapshot/get_snapshot_count.ts b/x-pack/plugins/uptime/server/rest_api/snapshot/get_snapshot_count.ts index d870f49280117..7809e102a499f 100644 --- a/x-pack/plugins/uptime/server/rest_api/snapshot/get_snapshot_count.ts +++ b/x-pack/plugins/uptime/server/rest_api/snapshot/get_snapshot_count.ts @@ -7,7 +7,7 @@ import { schema } from '@kbn/config-schema'; import { UMServerLibs } from '../../lib/lib'; import { UMRestApiRouteFactory } from '../types'; -import { API_URLS } from '../../../../../legacy/plugins/uptime/common/constants'; +import { API_URLS } from '../../../common/constants'; export const createGetSnapshotCount: UMRestApiRouteFactory = (libs: UMServerLibs) => ({ method: 'GET', diff --git a/x-pack/plugins/uptime/server/rest_api/telemetry/log_page_view.ts b/x-pack/plugins/uptime/server/rest_api/telemetry/log_page_view.ts index 4b2db71037071..d8387e79e9089 100644 --- a/x-pack/plugins/uptime/server/rest_api/telemetry/log_page_view.ts +++ b/x-pack/plugins/uptime/server/rest_api/telemetry/log_page_view.ts @@ -8,7 +8,7 @@ import { schema } from '@kbn/config-schema'; import { KibanaTelemetryAdapter } from '../../lib/adapters/telemetry'; import { UMRestApiRouteFactory } from '../types'; import { PageViewParams } from '../../lib/adapters/telemetry/types'; -import { API_URLS } from '../../../../../legacy/plugins/uptime/common/constants'; +import { API_URLS } from '../../../common/constants'; export const createLogPageViewRoute: UMRestApiRouteFactory = () => ({ method: 'POST', diff --git a/x-pack/plugins/uptime/server/rest_api/types.ts b/x-pack/plugins/uptime/server/rest_api/types.ts index e05e7a4d7faf1..8720b9dc60b12 100644 --- a/x-pack/plugins/uptime/server/rest_api/types.ts +++ b/x-pack/plugins/uptime/server/rest_api/types.ts @@ -15,8 +15,8 @@ import { KibanaRequest, KibanaResponseFactory, IKibanaResponse, -} from 'src/core/server'; -import { DynamicSettings } from '../../../../legacy/plugins/uptime/common/runtime_types'; +} from 'kibana/server'; +import { DynamicSettings } from '../../common/runtime_types'; import { UMServerLibs } from '../lib/lib'; /** diff --git a/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/servicenow.ts b/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/servicenow.ts index a7551ad7e2fad..1244657ed9988 100644 --- a/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/servicenow.ts +++ b/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/servicenow.ts @@ -9,7 +9,7 @@ import { FtrProviderContext } from '../../../../common/ftr_provider_context'; import { getExternalServiceSimulatorPath, ExternalServiceSimulator, -} from '../../../../common/fixtures/plugins/actions'; +} from '../../../../common/fixtures/plugins/actions_simulators'; // node ../scripts/functional_test_runner.js --grep "Actions.servicenddd" --config=test/alerting_api_integration/security_and_spaces/config.ts diff --git a/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/slack.ts b/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/slack.ts index 46258e41d5d69..4151deab45213 100644 --- a/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/slack.ts +++ b/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/slack.ts @@ -9,7 +9,7 @@ import { FtrProviderContext } from '../../../../common/ftr_provider_context'; import { getExternalServiceSimulatorPath, ExternalServiceSimulator, -} from '../../../../common/fixtures/plugins/actions'; +} from '../../../../common/fixtures/plugins/actions_simulators'; // eslint-disable-next-line import/no-default-export export default function slackTest({ getService }: FtrProviderContext) { diff --git a/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/webhook.ts b/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/webhook.ts index 338610e9243a4..bae6dada48fb7 100644 --- a/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/webhook.ts +++ b/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/webhook.ts @@ -8,7 +8,7 @@ import { FtrProviderContext } from '../../../../common/ftr_provider_context'; import { getExternalServiceSimulatorPath, ExternalServiceSimulator, -} from '../../../../common/fixtures/plugins/actions'; +} from '../../../../common/fixtures/plugins/actions_simulators'; // eslint-disable-next-line import/no-default-export export default function webhookTest({ getService }: FtrProviderContext) { diff --git a/x-pack/test/alerting_api_integration/common/config.ts b/x-pack/test/alerting_api_integration/common/config.ts index 457b7621e84bd..870ed3cf0cc0f 100644 --- a/x-pack/test/alerting_api_integration/common/config.ts +++ b/x-pack/test/alerting_api_integration/common/config.ts @@ -8,7 +8,7 @@ import path from 'path'; import { CA_CERT_PATH } from '@kbn/dev-utils'; import { FtrConfigProviderContext } from '@kbn/test/types/ftr'; import { services } from './services'; -import { getAllExternalServiceSimulatorPaths } from './fixtures/plugins/actions'; +import { getAllExternalServiceSimulatorPaths } from './fixtures/plugins/actions_simulators'; interface CreateTestConfigOptions { license: string; @@ -75,7 +75,6 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions) 'some.non.existent.com', ])}`, `--xpack.actions.enabledActionTypes=${JSON.stringify(enabledActionTypes)}`, - '--xpack.alerting.enabled=true', '--xpack.eventLog.logEntries=true', `--xpack.actions.preconfigured=${JSON.stringify([ { @@ -124,7 +123,7 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions) ])}`, ...disabledPlugins.map(key => `--xpack.${key}.enabled=false`), `--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'alerts')}`, - `--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'actions')}`, + `--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'actions_simulators')}`, `--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'task_manager')}`, `--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'aad')}`, `--server.xsrf.whitelist=${JSON.stringify(getAllExternalServiceSimulatorPaths())}`, diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/aad/index.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/aad/index.ts index 05139213b76b9..400aec7e11c8d 100644 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/aad/index.ts +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/aad/index.ts @@ -21,7 +21,7 @@ interface CheckAADRequest extends Hapi.Request { // eslint-disable-next-line import/no-default-export export default function(kibana: any) { return new kibana.Plugin({ - require: ['actions', 'alerting', 'encryptedSavedObjects'], + require: ['encryptedSavedObjects'], name: 'aad-fixtures', init(server: Legacy.Server) { const newPlatform = ((server as unknown) as KbnServer).newPlatform; diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions/README.md b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/README.md similarity index 100% rename from x-pack/test/alerting_api_integration/common/fixtures/plugins/actions/README.md rename to x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/README.md diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions/index.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/index.ts similarity index 98% rename from x-pack/test/alerting_api_integration/common/fixtures/plugins/actions/index.ts rename to x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/index.ts index 019b15cc1862a..45edd4c092da9 100644 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions/index.ts +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/index.ts @@ -36,7 +36,7 @@ export function getAllExternalServiceSimulatorPaths(): string[] { // eslint-disable-next-line import/no-default-export export default function(kibana: any) { return new kibana.Plugin({ - require: ['xpack_main', 'actions'], + require: ['xpack_main'], name: NAME, init: (server: Hapi.Server) => { // this action is specifically NOT enabled in ../../config.ts diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions/package.json b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/package.json similarity index 100% rename from x-pack/test/alerting_api_integration/common/fixtures/plugins/actions/package.json rename to x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/package.json diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions/pagerduty_simulation.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/pagerduty_simulation.ts similarity index 100% rename from x-pack/test/alerting_api_integration/common/fixtures/plugins/actions/pagerduty_simulation.ts rename to x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/pagerduty_simulation.ts diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions/servicenow_simulation.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/servicenow_simulation.ts similarity index 100% rename from x-pack/test/alerting_api_integration/common/fixtures/plugins/actions/servicenow_simulation.ts rename to x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/servicenow_simulation.ts diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions/slack_simulation.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/slack_simulation.ts similarity index 100% rename from x-pack/test/alerting_api_integration/common/fixtures/plugins/actions/slack_simulation.ts rename to x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/slack_simulation.ts diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions/webhook_simulation.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/webhook_simulation.ts similarity index 100% rename from x-pack/test/alerting_api_integration/common/fixtures/plugins/actions/webhook_simulation.ts rename to x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/webhook_simulation.ts diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/index.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/index.ts index 43d533ad3ae14..1a47addf36ab3 100644 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/index.ts +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/index.ts @@ -11,8 +11,8 @@ import { ActionTypeExecutorOptions, ActionType } from '../../../../../../plugins // eslint-disable-next-line import/no-default-export export default function(kibana: any) { return new kibana.Plugin({ - require: ['xpack_main', 'actions', 'alerting', 'elasticsearch'], - name: 'alerts', + require: ['xpack_main', 'elasticsearch'], + name: 'alerts-fixture', init(server: any) { const clusterClient = server.newPlatform.start.core.elasticsearch.legacy.client; server.plugins.xpack_main.registerFeature({ diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/task_manager/index.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/task_manager/index.ts index 29708f86b0a9b..ac32f05805e4a 100644 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/task_manager/index.ts +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/task_manager/index.ts @@ -31,7 +31,7 @@ const taskByIdQuery = (id: string) => ({ export default function(kibana: any) { return new kibana.Plugin({ name: 'taskManagerHelpers', - require: ['elasticsearch', 'task_manager'], + require: ['elasticsearch'], config(Joi: any) { return Joi.object({ diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/pagerduty.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/pagerduty.ts index eeb0818b5fbab..4c76ebfb93b0b 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/pagerduty.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/pagerduty.ts @@ -11,7 +11,7 @@ import { FtrProviderContext } from '../../../../common/ftr_provider_context'; import { getExternalServiceSimulatorPath, ExternalServiceSimulator, -} from '../../../../common/fixtures/plugins/actions'; +} from '../../../../common/fixtures/plugins/actions_simulators'; // eslint-disable-next-line import/no-default-export export default function pagerdutyTest({ getService }: FtrProviderContext) { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/servicenow.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/servicenow.ts index 054f8f6141817..399ae0f27f5b1 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/servicenow.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/servicenow.ts @@ -11,7 +11,7 @@ import { FtrProviderContext } from '../../../../common/ftr_provider_context'; import { getExternalServiceSimulatorPath, ExternalServiceSimulator, -} from '../../../../common/fixtures/plugins/actions'; +} from '../../../../common/fixtures/plugins/actions_simulators'; // node ../scripts/functional_test_runner.js --grep "servicenow" --config=test/alerting_api_integration/security_and_spaces/config.ts diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/slack.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/slack.ts index e00589b7e85b7..386254e49c19c 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/slack.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/slack.ts @@ -11,7 +11,7 @@ import { FtrProviderContext } from '../../../../common/ftr_provider_context'; import { getExternalServiceSimulatorPath, ExternalServiceSimulator, -} from '../../../../common/fixtures/plugins/actions'; +} from '../../../../common/fixtures/plugins/actions_simulators'; // eslint-disable-next-line import/no-default-export export default function slackTest({ getService }: FtrProviderContext) { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/webhook.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/webhook.ts index fd996ea4507ba..9b66326fa6157 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/webhook.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/webhook.ts @@ -10,7 +10,7 @@ import { FtrProviderContext } from '../../../../common/ftr_provider_context'; import { getExternalServiceSimulatorPath, ExternalServiceSimulator, -} from '../../../../common/fixtures/plugins/actions'; +} from '../../../../common/fixtures/plugins/actions_simulators'; const defaultValues: Record = { headers: null, diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/actions/builtin_action_types/webhook.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/actions/builtin_action_types/webhook.ts index 5122a74d53b72..112149a32649a 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/actions/builtin_action_types/webhook.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/actions/builtin_action_types/webhook.ts @@ -10,7 +10,7 @@ import { FtrProviderContext } from '../../../../common/ftr_provider_context'; import { getExternalServiceSimulatorPath, ExternalServiceSimulator, -} from '../../../../common/fixtures/plugins/actions'; +} from '../../../../common/fixtures/plugins/actions_simulators'; // eslint-disable-next-line import/no-default-export export default function webhookTest({ getService }: FtrProviderContext) { diff --git a/x-pack/test/api_integration/apis/ml/anomaly_detectors/create.ts b/x-pack/test/api_integration/apis/ml/anomaly_detectors/create.ts index bbc766df34dcf..10857caab98e2 100644 --- a/x-pack/test/api_integration/apis/ml/anomaly_detectors/create.ts +++ b/x-pack/test/api_integration/apis/ml/anomaly_detectors/create.ts @@ -91,12 +91,11 @@ export default ({ getService }: FtrProviderContext) => { model_plot_config: { enabled: true }, }, expected: { - responseCode: 403, + responseCode: 404, responseBody: { - statusCode: 403, - error: 'Forbidden', - message: - '[security_exception] action [cluster:admin/xpack/ml/job/put] is unauthorized for user [ml_viewer]', + statusCode: 404, + error: 'Not Found', + message: 'Not Found', }, }, }, diff --git a/x-pack/test/api_integration/apis/ml/jobs/jobs_summary.ts b/x-pack/test/api_integration/apis/ml/jobs/jobs_summary.ts index 6a57db1687868..a5cb68d782126 100644 --- a/x-pack/test/api_integration/apis/ml/jobs/jobs_summary.ts +++ b/x-pack/test/api_integration/apis/ml/jobs/jobs_summary.ts @@ -197,8 +197,8 @@ export default ({ getService }: FtrProviderContext) => { requestBody: {}, // Note that the jobs and datafeeds are loaded async so the actual error message is not deterministic. expected: { - responseCode: 403, - error: 'Forbidden', + responseCode: 404, + error: 'Not Found', }, }, ]; diff --git a/x-pack/test/api_integration/apis/ml/modules/setup_module.ts b/x-pack/test/api_integration/apis/ml/modules/setup_module.ts index 23ddd3b63a2ef..c42fc95c1bc7f 100644 --- a/x-pack/test/api_integration/apis/ml/modules/setup_module.ts +++ b/x-pack/test/api_integration/apis/ml/modules/setup_module.ts @@ -84,10 +84,9 @@ export default ({ getService }: FtrProviderContext) => { startDatafeed: false, }, expected: { - responseCode: 403, - error: 'Forbidden', - message: - '[security_exception] action [cluster:monitor/xpack/ml/info/get] is unauthorized for user [ml_unauthorized]', + responseCode: 404, + error: 'Not Found', + message: 'Not Found', }, }, ]; diff --git a/x-pack/test/api_integration/apis/uptime/feature_controls.ts b/x-pack/test/api_integration/apis/uptime/feature_controls.ts index 6d125807e169d..6c566ec7cb23b 100644 --- a/x-pack/test/api_integration/apis/uptime/feature_controls.ts +++ b/x-pack/test/api_integration/apis/uptime/feature_controls.ts @@ -7,7 +7,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../ftr_provider_context'; import { PINGS_DATE_RANGE_END, PINGS_DATE_RANGE_START } from './constants'; -import { API_URLS } from '../../../../legacy/plugins/uptime/common/constants'; +import { API_URLS } from '../../../../plugins/uptime/common/constants'; export default function featureControlsTests({ getService }: FtrProviderContext) { const supertest = getService('supertestWithoutAuth'); diff --git a/x-pack/test/api_integration/apis/uptime/rest/certs.ts b/x-pack/test/api_integration/apis/uptime/rest/certs.ts index 7510ea3f34d28..a3a15d8f8b014 100644 --- a/x-pack/test/api_integration/apis/uptime/rest/certs.ts +++ b/x-pack/test/api_integration/apis/uptime/rest/certs.ts @@ -8,8 +8,8 @@ import expect from '@kbn/expect'; import moment from 'moment'; import { isRight } from 'fp-ts/lib/Either'; import { FtrProviderContext } from '../../../ftr_provider_context'; -import { API_URLS } from '../../../../../legacy/plugins/uptime/common/constants'; -import { CertType } from '../../../../../legacy/plugins/uptime/common/runtime_types'; +import { API_URLS } from '../../../../../plugins/uptime/common/constants'; +import { CertType } from '../../../../../plugins/uptime/common/runtime_types'; import { makeChecksWithStatus } from './helper/make_checks'; export default function({ getService }: FtrProviderContext) { diff --git a/x-pack/test/api_integration/apis/uptime/rest/doc_count.ts b/x-pack/test/api_integration/apis/uptime/rest/doc_count.ts index 5258426cf193c..f343cd1da8788 100644 --- a/x-pack/test/api_integration/apis/uptime/rest/doc_count.ts +++ b/x-pack/test/api_integration/apis/uptime/rest/doc_count.ts @@ -5,7 +5,7 @@ */ import { FtrProviderContext } from '../../../ftr_provider_context'; import { expectFixtureEql } from './helper/expect_fixture_eql'; -import { API_URLS } from '../../../../../legacy/plugins/uptime/common/constants'; +import { API_URLS } from '../../../../../plugins/uptime/common/constants'; export default function({ getService }: FtrProviderContext) { describe('docCount query', () => { diff --git a/x-pack/test/api_integration/apis/uptime/rest/dynamic_settings.ts b/x-pack/test/api_integration/apis/uptime/rest/dynamic_settings.ts index ea980721b831b..95caf50d1ca7a 100644 --- a/x-pack/test/api_integration/apis/uptime/rest/dynamic_settings.ts +++ b/x-pack/test/api_integration/apis/uptime/rest/dynamic_settings.ts @@ -7,9 +7,8 @@ import expect from '@kbn/expect'; import { isRight } from 'fp-ts/lib/Either'; import { FtrProviderContext } from '../../../ftr_provider_context'; -import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../../legacy/plugins/uptime/common/constants'; -import { DynamicSettingsType } from '../../../../../legacy/plugins/uptime/common/runtime_types'; - +import { DynamicSettingsType } from '../../../../../plugins/uptime/common/runtime_types'; +import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../../plugins/uptime/common/constants'; export default function({ getService }: FtrProviderContext) { const supertest = getService('supertest'); diff --git a/x-pack/test/api_integration/apis/uptime/rest/monitor_states_generated.ts b/x-pack/test/api_integration/apis/uptime/rest/monitor_states_generated.ts index 3c17370532f91..c3d5849e028ab 100644 --- a/x-pack/test/api_integration/apis/uptime/rest/monitor_states_generated.ts +++ b/x-pack/test/api_integration/apis/uptime/rest/monitor_states_generated.ts @@ -7,8 +7,8 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; import { makeChecksWithStatus } from './helper/make_checks'; -import { API_URLS } from '../../../../../legacy/plugins/uptime/common/constants'; -import { MonitorSummary } from '../../../../../legacy/plugins/uptime/common/runtime_types'; +import { MonitorSummary } from '../../../../../plugins/uptime/common/runtime_types'; +import { API_URLS } from '../../../../../plugins/uptime/common/constants'; export default function({ getService }: FtrProviderContext) { const supertest = getService('supertest'); diff --git a/x-pack/test/api_integration/apis/uptime/rest/monitor_states_real_data.ts b/x-pack/test/api_integration/apis/uptime/rest/monitor_states_real_data.ts index f1e37bff405fd..c5a691312f525 100644 --- a/x-pack/test/api_integration/apis/uptime/rest/monitor_states_real_data.ts +++ b/x-pack/test/api_integration/apis/uptime/rest/monitor_states_real_data.ts @@ -7,8 +7,8 @@ import expect from '@kbn/expect'; import { isRight } from 'fp-ts/lib/Either'; import { FtrProviderContext } from '../../../ftr_provider_context'; -import { API_URLS } from '../../../../../legacy/plugins/uptime/common/constants'; -import { MonitorSummaryResultType } from '../../../../../legacy/plugins/uptime/common/runtime_types'; +import { MonitorSummaryResultType } from '../../../../../plugins/uptime/common/runtime_types'; +import { API_URLS } from '../../../../../plugins/uptime/common/constants'; interface ExpectedMonitorStatesPage { response: any; diff --git a/x-pack/test/api_integration/apis/uptime/rest/ping_list.ts b/x-pack/test/api_integration/apis/uptime/rest/ping_list.ts index a261763d5991f..3d754d89cf9be 100644 --- a/x-pack/test/api_integration/apis/uptime/rest/ping_list.ts +++ b/x-pack/test/api_integration/apis/uptime/rest/ping_list.ts @@ -7,7 +7,7 @@ import expect from '@kbn/expect'; import { isLeft } from 'fp-ts/lib/Either'; import { PathReporter } from 'io-ts/lib/PathReporter'; -import { PingsResponseType } from '../../../../../legacy/plugins/uptime/common/runtime_types'; +import { PingsResponseType } from '../../../../../plugins/uptime/common/runtime_types'; import { FtrProviderContext } from '../../../ftr_provider_context'; function decodePingsResponseData(response: any) { diff --git a/x-pack/test/api_integration/apis/uptime/rest/telemetry_collectors.ts b/x-pack/test/api_integration/apis/uptime/rest/telemetry_collectors.ts index 017ef02afe5ea..99e09aa5ce886 100644 --- a/x-pack/test/api_integration/apis/uptime/rest/telemetry_collectors.ts +++ b/x-pack/test/api_integration/apis/uptime/rest/telemetry_collectors.ts @@ -6,7 +6,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; -import { API_URLS } from '../../../../../legacy/plugins/uptime/common/constants'; +import { API_URLS } from '../../../../../plugins/uptime/common/constants'; import { makeChecksWithStatus } from './helper/make_checks'; export default function({ getService }: FtrProviderContext) { diff --git a/x-pack/test/detection_engine_api_integration/common/config.ts b/x-pack/test/detection_engine_api_integration/common/config.ts index e89352118990a..1e6600c7cd2c0 100644 --- a/x-pack/test/detection_engine_api_integration/common/config.ts +++ b/x-pack/test/detection_engine_api_integration/common/config.ts @@ -78,7 +78,6 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions) 'some.non.existent.com', ])}`, `--xpack.actions.enabledActionTypes=${JSON.stringify(enabledActionTypes)}`, - '--xpack.alerting.enabled=true', '--xpack.eventLog.logEntries=true', ...disabledPlugins.map(key => `--xpack.${key}.enabled=false`), `--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'alerts')}`, diff --git a/x-pack/test/functional/apps/dashboard/reporting/index.js b/x-pack/test/functional/apps/dashboard/reporting/index.ts similarity index 94% rename from x-pack/test/functional/apps/dashboard/reporting/index.js rename to x-pack/test/functional/apps/dashboard/reporting/index.ts index 99be084d80d74..796e15b4e270f 100644 --- a/x-pack/test/functional/apps/dashboard/reporting/index.js +++ b/x-pack/test/functional/apps/dashboard/reporting/index.ts @@ -5,9 +5,10 @@ */ import expect from '@kbn/expect'; -import path from 'path'; import fs from 'fs'; +import path from 'path'; import { promisify } from 'util'; +import { FtrProviderContext } from '../../../ftr_provider_context'; import { checkIfPngsMatch } from './lib/compare_pngs'; const writeFileAsync = promisify(fs.writeFile); @@ -15,7 +16,7 @@ const mkdirAsync = promisify(fs.mkdir); const REPORTS_FOLDER = path.resolve(__dirname, 'reports'); -export default function({ getService, getPageObjects }) { +export default function({ getService, getPageObjects }: FtrProviderContext) { const esArchiver = getService('esArchiver'); const browser = getService('browser'); const log = getService('log'); @@ -85,14 +86,14 @@ export default function({ getService, getPageObjects }) { describe('Preserve Layout', () => { it('matches baseline report', async function() { - const writeSessionReport = async (name, rawPdf, reportExt) => { + const writeSessionReport = async (name: string, rawPdf: Buffer, reportExt: string) => { const sessionDirectory = path.resolve(REPORTS_FOLDER, 'session'); await mkdirAsync(sessionDirectory, { recursive: true }); const sessionReportPath = path.resolve(sessionDirectory, `${name}.${reportExt}`); await writeFileAsync(sessionReportPath, rawPdf); return sessionReportPath; }; - const getBaselineReportPath = (fileName, reportExt) => { + const getBaselineReportPath = (fileName: string, reportExt: string) => { const baselineFolder = path.resolve(REPORTS_FOLDER, 'baseline'); const fullPath = path.resolve(baselineFolder, `${fileName}.${reportExt}`); log.debug(`getBaselineReportPath (${fullPath})`); diff --git a/x-pack/test/functional/apps/dashboard/reporting/lib/compare_pngs.js b/x-pack/test/functional/apps/dashboard/reporting/lib/compare_pngs.ts similarity index 90% rename from x-pack/test/functional/apps/dashboard/reporting/lib/compare_pngs.js rename to x-pack/test/functional/apps/dashboard/reporting/lib/compare_pngs.ts index 13c97a7fce785..b2eb645c8372c 100644 --- a/x-pack/test/functional/apps/dashboard/reporting/lib/compare_pngs.js +++ b/x-pack/test/functional/apps/dashboard/reporting/lib/compare_pngs.ts @@ -4,14 +4,19 @@ * you may not use this file except in compliance with the Elastic License. */ -import path from 'path'; -import fs from 'fs'; import { promisify } from 'bluebird'; +import fs from 'fs'; +import path from 'path'; import { comparePngs } from '../../../../../../../test/functional/services/lib/compare_pngs'; -const mkdirAsync = promisify(fs.mkdir); +const mkdirAsync = promisify(fs.mkdir); -export async function checkIfPngsMatch(actualpngPath, baselinepngPath, screenshotsDirectory, log) { +export async function checkIfPngsMatch( + actualpngPath: string, + baselinepngPath: string, + screenshotsDirectory: string, + log: any +) { log.debug(`checkIfpngsMatch: ${actualpngPath} vs ${baselinepngPath}`); // Copy the pngs into the screenshot session directory, as that's where the generated pngs will automatically be // stored. diff --git a/x-pack/test/functional/apps/discover/reporting.js b/x-pack/test/functional/apps/discover/reporting.ts similarity index 96% rename from x-pack/test/functional/apps/discover/reporting.js rename to x-pack/test/functional/apps/discover/reporting.ts index 4aa005fc2db55..7a33e7f5135d4 100644 --- a/x-pack/test/functional/apps/discover/reporting.js +++ b/x-pack/test/functional/apps/discover/reporting.ts @@ -5,8 +5,9 @@ */ import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../ftr_provider_context'; -export default function({ getService, getPageObjects }) { +export default function({ getService, getPageObjects }: FtrProviderContext) { const log = getService('log'); const esArchiver = getService('esArchiver'); const browser = getService('browser'); diff --git a/x-pack/test/functional/apps/uptime/settings.ts b/x-pack/test/functional/apps/uptime/settings.ts index 64b6300e0df63..7a813a5cdfb52 100644 --- a/x-pack/test/functional/apps/uptime/settings.ts +++ b/x-pack/test/functional/apps/uptime/settings.ts @@ -6,8 +6,8 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../ftr_provider_context'; -import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../legacy/plugins/uptime/common/constants'; -import { DynamicSettings } from '../../../../legacy/plugins/uptime/common/runtime_types'; +import { DynamicSettings } from '../../../../plugins/uptime/common/runtime_types'; +import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../plugins/uptime/common/constants'; import { makeChecks } from '../../../api_integration/apis/uptime/rest/helper/make_checks'; export default ({ getPageObjects, getService }: FtrProviderContext) => { diff --git a/x-pack/test/functional/apps/visualize/reporting.js b/x-pack/test/functional/apps/visualize/reporting.ts similarity index 94% rename from x-pack/test/functional/apps/visualize/reporting.js rename to x-pack/test/functional/apps/visualize/reporting.ts index bc252e1ad4134..5ef954e334d81 100644 --- a/x-pack/test/functional/apps/visualize/reporting.js +++ b/x-pack/test/functional/apps/visualize/reporting.ts @@ -5,8 +5,9 @@ */ import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../ftr_provider_context'; -export default function({ getService, getPageObjects }) { +export default function({ getService, getPageObjects }: FtrProviderContext) { const esArchiver = getService('esArchiver'); const browser = getService('browser'); const log = getService('log'); diff --git a/x-pack/test/functional/page_objects/index.ts b/x-pack/test/functional/page_objects/index.ts index 782d57adea770..4b8c2944ef190 100644 --- a/x-pack/test/functional/page_objects/index.ts +++ b/x-pack/test/functional/page_objects/index.ts @@ -19,7 +19,6 @@ import { GraphPageProvider } from './graph_page'; import { GrokDebuggerPageProvider } from './grok_debugger_page'; // @ts-ignore not ts yet import { WatcherPageProvider } from './watcher_page'; -// @ts-ignore not ts yet import { ReportingPageProvider } from './reporting_page'; // @ts-ignore not ts yet import { AccountSettingProvider } from './accountsetting_page'; diff --git a/x-pack/test/functional/page_objects/lens_page.ts b/x-pack/test/functional/page_objects/lens_page.ts index 1bf637c50b0ba..57b2847cc2e50 100644 --- a/x-pack/test/functional/page_objects/lens_page.ts +++ b/x-pack/test/functional/page_objects/lens_page.ts @@ -12,6 +12,7 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont const testSubjects = getService('testSubjects'); const retry = getService('retry'); const find = getService('find'); + const comboBox = getService('comboBox'); const PageObjects = getPageObjects([ 'header', 'common', @@ -107,20 +108,17 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont * @param opts.operation - the desired operation ID for the dimension * @param opts.field - the desired field for the dimension */ - async configureDimension(opts: { dimension: string; operation?: string; field?: string }) { + async configureDimension(opts: { dimension: string; operation: string; field: string }) { await find.clickByCssSelector(opts.dimension); - if (opts.operation) { - await find.clickByCssSelector( - `[data-test-subj="lns-indexPatternDimensionIncompatible-${opts.operation}"], - [data-test-subj="lns-indexPatternDimension-${opts.operation}"]` - ); - } + await find.clickByCssSelector( + `[data-test-subj="lns-indexPatternDimensionIncompatible-${opts.operation}"], + [data-test-subj="lns-indexPatternDimension-${opts.operation}"]` + ); - if (opts.field) { - await testSubjects.click('indexPattern-dimension-field'); - await testSubjects.click(`lns-fieldOption-${opts.field}`); - } + const target = await testSubjects.find('indexPattern-dimension-field'); + await comboBox.openOptionsList(target); + await comboBox.setElement(target, opts.field); }, /** diff --git a/x-pack/test/functional/page_objects/reporting_page.js b/x-pack/test/functional/page_objects/reporting_page.ts similarity index 84% rename from x-pack/test/functional/page_objects/reporting_page.js rename to x-pack/test/functional/page_objects/reporting_page.ts index b24ba8cf95d1c..2c20519a8d214 100644 --- a/x-pack/test/functional/page_objects/reporting_page.js +++ b/x-pack/test/functional/page_objects/reporting_page.ts @@ -4,25 +4,19 @@ * you may not use this file except in compliance with the Elastic License. */ +import http, { IncomingMessage } from 'http'; +import { FtrProviderContext } from 'test/functional/ftr_provider_context'; import { parse } from 'url'; -import http from 'http'; -/* - * NOTE: Reporting is a service, not an app. The page objects that are - * important for generating reports belong to the apps that integrate with the - * Reporting service. Eventually, this file should be dissolved across the - * apps that need it for testing their integration. - * Issue: https://github.com/elastic/kibana/issues/52927 - */ -export function ReportingPageProvider({ getService, getPageObjects }) { +export function ReportingPageProvider({ getService, getPageObjects }: FtrProviderContext) { const retry = getService('retry'); const log = getService('log'); const testSubjects = getService('testSubjects'); const browser = getService('browser'); - const PageObjects = getPageObjects(['common', 'security', 'share', 'timePicker']); + const PageObjects = getPageObjects(['common', 'security' as any, 'share', 'timePicker']); // FIXME: Security PageObject is not Typescript class ReportingPage { - async forceSharedItemsContainerSize({ width }) { + async forceSharedItemsContainerSize({ width }: { width: number }) { await browser.execute(` var el = document.querySelector('[data-shared-items-container]'); el.style.flex="none"; @@ -30,7 +24,7 @@ export function ReportingPageProvider({ getService, getPageObjects }) { `); } - async getReportURL(timeout) { + async getReportURL(timeout: number) { log.debug('getReportURL'); const url = await testSubjects.getAttribute('downloadCompletedReportButton', 'href', timeout); @@ -48,7 +42,7 @@ export function ReportingPageProvider({ getService, getPageObjects }) { `); } - getResponse(url) { + getResponse(url: string): Promise { log.debug(`getResponse for ${url}`); const auth = 'test_user:changeme'; // FIXME not sure why there is no config that can be read for this const headers = { @@ -62,29 +56,30 @@ export function ReportingPageProvider({ getService, getPageObjects }) { hostname: parsedUrl.hostname, path: parsedUrl.path, port: parsedUrl.port, - responseType: 'arraybuffer', headers, }, - res => { + (res: IncomingMessage) => { resolve(res); } ) - .on('error', e => { + .on('error', (e: Error) => { log.error(e); reject(e); }); }); } - async getRawPdfReportData(url) { - const data = []; // List of Buffer objects + async getRawPdfReportData(url: string): Promise { + const data: Buffer[] = []; // List of Buffer objects log.debug(`getRawPdfReportData for ${url}`); return new Promise(async (resolve, reject) => { const response = await this.getResponse(url).catch(reject); - response.on('data', chunk => data.push(chunk)); - response.on('end', () => resolve(Buffer.concat(data))); + if (response) { + response.on('data', (chunk: Buffer) => data.push(chunk)); + response.on('end', () => resolve(Buffer.concat(data))); + } }); } diff --git a/x-pack/test/functional/services/uptime/settings.ts b/x-pack/test/functional/services/uptime/settings.ts index 9719152b62d35..96f5e45ce2ca4 100644 --- a/x-pack/test/functional/services/uptime/settings.ts +++ b/x-pack/test/functional/services/uptime/settings.ts @@ -5,7 +5,7 @@ */ import { FtrProviderContext } from '../../ftr_provider_context'; -import { DynamicSettings } from '../../../../legacy/plugins/uptime/common/runtime_types'; +import { DynamicSettings } from '../../../../plugins/uptime/common/runtime_types'; export function UptimeSettingsProvider({ getService }: FtrProviderContext) { const testSubjects = getService('testSubjects'); diff --git a/x-pack/test/functional_with_es_ssl/config.ts b/x-pack/test/functional_with_es_ssl/config.ts index a620b1d953376..71b22a336f6b9 100644 --- a/x-pack/test/functional_with_es_ssl/config.ts +++ b/x-pack/test/functional_with_es_ssl/config.ts @@ -50,8 +50,6 @@ export default async function({ readConfigFile }: FtrConfigProviderContext) { `--elasticsearch.hosts=https://${servers.elasticsearch.hostname}:${servers.elasticsearch.port}`, `--elasticsearch.ssl.certificateAuthorities=${CA_CERT_PATH}`, `--plugin-path=${join(__dirname, 'fixtures', 'plugins', 'alerts')}`, - '--xpack.actions.enabled=true', - '--xpack.alerting.enabled=true', `--xpack.actions.preconfigured=${JSON.stringify([ { id: 'my-slack1', diff --git a/x-pack/test/plugin_api_integration/plugins/sample_task_plugin/kibana.json b/x-pack/test/plugin_api_integration/plugins/sample_task_plugin/kibana.json new file mode 100644 index 0000000000000..416ef7fa34591 --- /dev/null +++ b/x-pack/test/plugin_api_integration/plugins/sample_task_plugin/kibana.json @@ -0,0 +1,9 @@ +{ + "id": "sample_task_plugin", + "version": "1.0.0", + "kibanaVersion": "kibana", + "configPath": ["xpack"], + "requiredPlugins": ["taskManager"], + "server": true, + "ui": false +} diff --git a/x-pack/test/plugin_api_integration/plugins/sample_task_plugin/package.json b/x-pack/test/plugin_api_integration/plugins/sample_task_plugin/package.json new file mode 100644 index 0000000000000..c8d47decd94c1 --- /dev/null +++ b/x-pack/test/plugin_api_integration/plugins/sample_task_plugin/package.json @@ -0,0 +1,18 @@ +{ + "name": "sample_task_plugin", + "version": "1.0.0", + "kibana": { + "version": "kibana", + "templateVersion": "1.0.0" + }, + "main": "target/test/plugin_api_integration/plugins/sample_task_plugin", + "scripts": { + "kbn": "node ../../../../../scripts/kbn.js", + "build": "rm -rf './target' && tsc" + }, + "devDependencies": { + "typescript": "3.7.2" + }, + "license": "Apache-2.0", + "dependencies": {} +} diff --git a/x-pack/legacy/plugins/alerting/index.ts b/x-pack/test/plugin_api_integration/plugins/sample_task_plugin/server/index.ts similarity index 65% rename from x-pack/legacy/plugins/alerting/index.ts rename to x-pack/test/plugin_api_integration/plugins/sample_task_plugin/server/index.ts index 0d0a698841269..77233f463734a 100644 --- a/x-pack/legacy/plugins/alerting/index.ts +++ b/x-pack/test/plugin_api_integration/plugins/sample_task_plugin/server/index.ts @@ -4,4 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -export * from './server'; +import { SampleTaskManagerFixturePlugin } from './plugin'; + +export const plugin = () => new SampleTaskManagerFixturePlugin(); diff --git a/x-pack/test/plugin_api_integration/plugins/sample_task_plugin/server/init_routes.ts b/x-pack/test/plugin_api_integration/plugins/sample_task_plugin/server/init_routes.ts new file mode 100644 index 0000000000000..1fee2decbcba9 --- /dev/null +++ b/x-pack/test/plugin_api_integration/plugins/sample_task_plugin/server/init_routes.ts @@ -0,0 +1,252 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { schema } from '@kbn/config-schema'; +import { + RequestHandlerContext, + KibanaRequest, + KibanaResponseFactory, + IKibanaResponse, + IRouter, + CoreSetup, +} from 'kibana/server'; +import { EventEmitter } from 'events'; +import { TaskManagerStartContract } from '../../../../../plugins/task_manager/server'; + +const scope = 'testing'; +const taskManagerQuery = { + bool: { + filter: { + bool: { + must: [ + { + term: { + 'task.scope': scope, + }, + }, + ], + }, + }, + }, +}; + +export function initRoutes( + router: IRouter, + core: CoreSetup, + taskManagerStart: Promise, + taskTestingEvents: EventEmitter +) { + async function ensureIndexIsRefreshed() { + return await core.elasticsearch.adminClient.callAsInternalUser('indices.refresh', { + index: '.kibana_task_manager', + }); + } + + router.post( + { + path: `/api/sample_tasks/schedule`, + validate: { + body: schema.object({ + task: schema.object({ + taskType: schema.string(), + schedule: schema.maybe( + schema.object({ + interval: schema.string(), + }) + ), + interval: schema.maybe(schema.string()), + params: schema.recordOf(schema.string(), schema.any(), { defaultValue: {} }), + state: schema.recordOf(schema.string(), schema.any(), { defaultValue: {} }), + id: schema.maybe(schema.string()), + }), + }), + }, + }, + async function( + context: RequestHandlerContext, + req: KibanaRequest, + res: KibanaResponseFactory + ): Promise> { + try { + const taskManager = await taskManagerStart; + const { task: taskFields } = req.body; + const task = { + ...taskFields, + scope: [scope], + }; + + const taskResult = await taskManager.schedule(task, { req }); + + return res.ok({ body: taskResult }); + } catch (err) { + return res.internalError({ body: err }); + } + } + ); + + router.post( + { + path: `/api/sample_tasks/run_now`, + validate: { + body: schema.object({ + task: schema.object({ + id: schema.string({}), + }), + }), + }, + }, + async function( + context: RequestHandlerContext, + req: KibanaRequest, + res: KibanaResponseFactory + ): Promise> { + const { + task: { id }, + } = req.body; + try { + const taskManager = await taskManagerStart; + return res.ok({ body: await taskManager.runNow(id) }); + } catch (err) { + return res.ok({ body: { id, error: `${err}` } }); + } + } + ); + + router.post( + { + path: `/api/sample_tasks/ensure_scheduled`, + validate: { + body: schema.object({ + task: schema.object({ + taskType: schema.string(), + params: schema.object({}), + state: schema.maybe(schema.object({})), + id: schema.maybe(schema.string()), + }), + }), + }, + }, + async function( + context: RequestHandlerContext, + req: KibanaRequest, + res: KibanaResponseFactory + ): Promise> { + try { + const { task: taskFields } = req.body; + const task = { + ...taskFields, + scope: [scope], + }; + + const taskManager = await taskManagerStart; + const taskResult = await taskManager.ensureScheduled(task, { req }); + + return res.ok({ body: taskResult }); + } catch (err) { + return res.ok({ body: err }); + } + } + ); + + router.post( + { + path: `/api/sample_tasks/event`, + validate: { + body: schema.object({ + event: schema.string(), + data: schema.recordOf(schema.string(), schema.any(), { defaultValue: {} }), + }), + }, + }, + async function( + context: RequestHandlerContext, + req: KibanaRequest, + res: KibanaResponseFactory + ): Promise> { + try { + const { event, data } = req.body; + taskTestingEvents.emit(event, data); + return res.ok({ body: event }); + } catch (err) { + return res.ok({ body: err }); + } + } + ); + + router.get( + { + path: `/api/sample_tasks`, + validate: {}, + }, + async function( + context: RequestHandlerContext, + req: KibanaRequest, + res: KibanaResponseFactory + ): Promise> { + try { + const taskManager = await taskManagerStart; + return res.ok({ + body: await taskManager.fetch({ + query: taskManagerQuery, + }), + }); + } catch (err) { + return res.ok({ body: err }); + } + } + ); + + router.get( + { + path: `/api/sample_tasks/task/{taskId}`, + validate: { + params: schema.object({ + taskId: schema.string(), + }), + }, + }, + async function( + context: RequestHandlerContext, + req: KibanaRequest, + res: KibanaResponseFactory + ): Promise> { + try { + await ensureIndexIsRefreshed(); + const taskManager = await taskManagerStart; + return res.ok({ body: await taskManager.get(req.params.taskId) }); + } catch (err) { + return res.ok({ body: err }); + } + return res.ok({ body: {} }); + } + ); + + router.delete( + { + path: `/api/sample_tasks`, + validate: {}, + }, + async function( + context: RequestHandlerContext, + req: KibanaRequest, + res: KibanaResponseFactory + ): Promise> { + try { + let tasksFound = 0; + const taskManager = await taskManagerStart; + do { + const { docs: tasks } = await taskManager.fetch({ + query: taskManagerQuery, + }); + tasksFound = tasks.length; + await Promise.all(tasks.map(task => taskManager.remove(task.id))); + } while (tasksFound > 0); + return res.ok({ body: 'OK' }); + } catch (err) { + return res.ok({ body: err }); + } + } + ); +} diff --git a/x-pack/test/plugin_api_integration/plugins/sample_task_plugin/server/plugin.ts b/x-pack/test/plugin_api_integration/plugins/sample_task_plugin/server/plugin.ts new file mode 100644 index 0000000000000..508d58b8f0ca9 --- /dev/null +++ b/x-pack/test/plugin_api_integration/plugins/sample_task_plugin/server/plugin.ts @@ -0,0 +1,164 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { Plugin, CoreSetup, CoreStart } from 'kibana/server'; +import { EventEmitter } from 'events'; +import { Subject } from 'rxjs'; +import { first } from 'rxjs/operators'; +import { initRoutes } from './init_routes'; +import { + TaskManagerSetupContract, + TaskManagerStartContract, + ConcreteTaskInstance, +} from '../../../../../plugins/task_manager/server'; +import { DEFAULT_MAX_WORKERS } from '../../../../../plugins/task_manager/server/config'; + +// this plugin's dependendencies +export interface SampleTaskManagerFixtureSetupDeps { + taskManager: TaskManagerSetupContract; +} +export interface SampleTaskManagerFixtureStartDeps { + taskManager: TaskManagerStartContract; +} + +export class SampleTaskManagerFixturePlugin + implements + Plugin { + taskManagerStart$: Subject = new Subject(); + taskManagerStart: Promise = this.taskManagerStart$ + .pipe(first()) + .toPromise(); + + public setup(core: CoreSetup, { taskManager }: SampleTaskManagerFixtureSetupDeps) { + const taskTestingEvents = new EventEmitter(); + taskTestingEvents.setMaxListeners(DEFAULT_MAX_WORKERS * 2); + + const defaultSampleTaskConfig = { + timeout: '1m', + // This task allows tests to specify its behavior (whether it reschedules itself, whether it errors, etc) + // taskInstance.params has the following optional fields: + // nextRunMilliseconds: number - If specified, the run method will return a runAt that is now + nextRunMilliseconds + // failWith: string - If specified, the task will throw an error with the specified message + // failOn: number - If specified, the task will only throw the `failWith` error when `count` equals to the failOn value + // waitForParams : boolean - should the task stall ands wait to receive params asynchronously before using the default params + // waitForEvent : string - if provided, the task will stall (after completing the run) and wait for an asyn event before completing + createTaskRunner: ({ taskInstance }: { taskInstance: ConcreteTaskInstance }) => ({ + async run() { + const { params, state, id } = taskInstance; + const prevState = state || { count: 0 }; + + const count = (prevState.count || 0) + 1; + + const runParams = { + ...params, + // if this task requires custom params provided async - wait for them + ...(params.waitForParams ? await once(taskTestingEvents, id) : {}), + }; + + if (runParams.failWith) { + if (!runParams.failOn || (runParams.failOn && count === runParams.failOn)) { + throw new Error(runParams.failWith); + } + } + + await core.elasticsearch.adminClient.callAsInternalUser('index', { + index: '.kibana_task_manager_test_result', + body: { + type: 'task', + taskId: taskInstance.id, + params: JSON.stringify(runParams), + state: JSON.stringify(state), + ranAt: new Date(), + }, + refresh: true, + }); + + // Stall task run until a certain event is triggered + if (runParams.waitForEvent) { + await once(taskTestingEvents, runParams.waitForEvent); + } + + return { + state: { count }, + runAt: millisecondsFromNow(runParams.nextRunMilliseconds), + }; + }, + }), + }; + + taskManager.registerTaskDefinitions({ + sampleTask: { + ...defaultSampleTaskConfig, + type: 'sampleTask', + title: 'Sample Task', + description: 'A sample task for testing the task_manager.', + }, + singleAttemptSampleTask: { + ...defaultSampleTaskConfig, + type: 'singleAttemptSampleTask', + title: 'Failing Sample Task', + description: + 'A sample task for testing the task_manager that fails on the first attempt to run.', + // fail after the first failed run + maxAttempts: 1, + }, + }); + + taskManager.addMiddleware({ + async beforeSave({ taskInstance, ...opts }) { + const modifiedInstance = { + ...taskInstance, + params: { + originalParams: taskInstance.params, + superFly: 'My middleware param!', + }, + }; + + return { + ...opts, + taskInstance: modifiedInstance, + }; + }, + + async beforeRun({ taskInstance, ...opts }) { + return { + ...opts, + taskInstance: { + ...taskInstance, + params: taskInstance.params.originalParams, + }, + }; + }, + + async beforeMarkRunning(context) { + return context; + }, + }); + initRoutes(core.http.createRouter(), core, this.taskManagerStart, taskTestingEvents); + } + + public start(core: CoreStart, { taskManager }: SampleTaskManagerFixtureStartDeps) { + this.taskManagerStart$.next(taskManager); + this.taskManagerStart$.complete(); + } + public stop() {} +} + +function millisecondsFromNow(ms: number) { + if (!ms) { + return; + } + + const dt = new Date(); + dt.setTime(dt.getTime() + ms); + return dt; +} + +const once = function(emitter: EventEmitter, event: string): Promise> { + return new Promise(resolve => { + emitter.once(event, data => resolve(data || {})); + }); +}; diff --git a/x-pack/test/plugin_api_integration/plugins/task_manager/index.js b/x-pack/test/plugin_api_integration/plugins/task_manager/index.js deleted file mode 100644 index e5b645367b8b7..0000000000000 --- a/x-pack/test/plugin_api_integration/plugins/task_manager/index.js +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -const { DEFAULT_MAX_WORKERS } = require('../../../../plugins/task_manager/server/config.ts'); -const { EventEmitter } = require('events'); - -import { initRoutes } from './init_routes'; - -const once = function(emitter, event) { - return new Promise(resolve => { - emitter.once(event, data => resolve(data || {})); - }); -}; - -export default function TaskTestingAPI(kibana) { - const taskTestingEvents = new EventEmitter(); - taskTestingEvents.setMaxListeners(DEFAULT_MAX_WORKERS * 2); - - return new kibana.Plugin({ - name: 'sampleTask', - require: ['elasticsearch', 'task_manager'], - - config(Joi) { - return Joi.object({ - enabled: Joi.boolean().default(true), - }).default(); - }, - - init(server) { - const taskManager = { - ...server.newPlatform.setup.plugins.taskManager, - ...server.newPlatform.start.plugins.taskManager, - }; - const legacyTaskManager = server.plugins.task_manager; - - const defaultSampleTaskConfig = { - timeout: '1m', - // This task allows tests to specify its behavior (whether it reschedules itself, whether it errors, etc) - // taskInstance.params has the following optional fields: - // nextRunMilliseconds: number - If specified, the run method will return a runAt that is now + nextRunMilliseconds - // failWith: string - If specified, the task will throw an error with the specified message - // failOn: number - If specified, the task will only throw the `failWith` error when `count` equals to the failOn value - // waitForParams : boolean - should the task stall ands wait to receive params asynchronously before using the default params - // waitForEvent : string - if provided, the task will stall (after completing the run) and wait for an asyn event before completing - createTaskRunner: ({ taskInstance }) => ({ - async run() { - const { params, state, id } = taskInstance; - const prevState = state || { count: 0 }; - - const count = (prevState.count || 0) + 1; - - const runParams = { - ...params, - // if this task requires custom params provided async - wait for them - ...(params.waitForParams ? await once(taskTestingEvents, id) : {}), - }; - - if (runParams.failWith) { - if (!runParams.failOn || (runParams.failOn && count === runParams.failOn)) { - throw new Error(runParams.failWith); - } - } - - const callCluster = server.plugins.elasticsearch.getCluster('admin') - .callWithInternalUser; - await callCluster('index', { - index: '.kibana_task_manager_test_result', - body: { - type: 'task', - taskId: taskInstance.id, - params: JSON.stringify(runParams), - state: JSON.stringify(state), - ranAt: new Date(), - }, - refresh: true, - }); - - // Stall task run until a certain event is triggered - if (runParams.waitForEvent) { - await once(taskTestingEvents, runParams.waitForEvent); - } - - return { - state: { count }, - runAt: millisecondsFromNow(runParams.nextRunMilliseconds), - }; - }, - }), - }; - - taskManager.registerTaskDefinitions({ - sampleTask: { - ...defaultSampleTaskConfig, - title: 'Sample Task', - description: 'A sample task for testing the task_manager.', - }, - singleAttemptSampleTask: { - ...defaultSampleTaskConfig, - title: 'Failing Sample Task', - description: - 'A sample task for testing the task_manager that fails on the first attempt to run.', - // fail after the first failed run - maxAttempts: 1, - }, - }); - - taskManager.addMiddleware({ - async beforeSave({ taskInstance, ...opts }) { - const modifiedInstance = { - ...taskInstance, - params: { - originalParams: taskInstance.params, - superFly: 'My middleware param!', - }, - }; - - return { - ...opts, - taskInstance: modifiedInstance, - }; - }, - - async beforeRun({ taskInstance, ...opts }) { - return { - ...opts, - taskInstance: { - ...taskInstance, - params: taskInstance.params.originalParams, - }, - }; - }, - }); - - initRoutes(server, taskManager, legacyTaskManager, taskTestingEvents); - }, - }); -} - -function millisecondsFromNow(ms) { - if (!ms) { - return; - } - - const dt = new Date(); - dt.setTime(dt.getTime() + ms); - return dt; -} diff --git a/x-pack/test/plugin_api_integration/plugins/task_manager/init_routes.js b/x-pack/test/plugin_api_integration/plugins/task_manager/init_routes.js deleted file mode 100644 index 785fbed341423..0000000000000 --- a/x-pack/test/plugin_api_integration/plugins/task_manager/init_routes.js +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import Joi from 'joi'; - -const scope = 'testing'; -const taskManagerQuery = { - bool: { - filter: { - bool: { - must: [ - { - term: { - 'task.scope': scope, - }, - }, - ], - }, - }, - }, -}; - -export function initRoutes(server, taskManager, legacyTaskManager, taskTestingEvents) { - const callCluster = server.plugins.elasticsearch.getCluster('admin').callWithInternalUser; - - async function ensureIndexIsRefreshed() { - return await callCluster('indices.refresh', { - index: '.kibana_task_manager', - }); - } - - server.route({ - path: '/api/sample_tasks/schedule', - method: 'POST', - config: { - validate: { - payload: Joi.object({ - task: Joi.object({ - taskType: Joi.string().required(), - schedule: Joi.object({ - interval: Joi.string(), - }).optional(), - interval: Joi.string().optional(), - params: Joi.object().required(), - state: Joi.object().optional(), - id: Joi.string().optional(), - }), - }), - }, - }, - async handler(request) { - try { - const { task: taskFields } = request.payload; - const task = { - ...taskFields, - scope: [scope], - }; - - const taskResult = await taskManager.schedule(task, { request }); - - return taskResult; - } catch (err) { - return err; - } - }, - }); - - /* - Schedule using legacy Api - */ - server.route({ - path: '/api/sample_tasks/schedule_legacy', - method: 'POST', - config: { - validate: { - payload: Joi.object({ - task: Joi.object({ - taskType: Joi.string().required(), - schedule: Joi.object({ - interval: Joi.string(), - }).optional(), - interval: Joi.string().optional(), - params: Joi.object().required(), - state: Joi.object().optional(), - id: Joi.string().optional(), - }), - }), - }, - }, - async handler(request) { - try { - const { task: taskFields } = request.payload; - const task = { - ...taskFields, - scope: [scope], - }; - - const taskResult = await legacyTaskManager.schedule(task, { request }); - - return taskResult; - } catch (err) { - return err; - } - }, - }); - - server.route({ - path: '/api/sample_tasks/run_now', - method: 'POST', - config: { - validate: { - payload: Joi.object({ - task: Joi.object({ - id: Joi.string().optional(), - }), - }), - }, - }, - async handler(request) { - const { - task: { id }, - } = request.payload; - try { - return await taskManager.runNow(id); - } catch (err) { - return { id, error: `${err}` }; - } - }, - }); - - server.route({ - path: '/api/sample_tasks/ensure_scheduled', - method: 'POST', - config: { - validate: { - payload: Joi.object({ - task: Joi.object({ - taskType: Joi.string().required(), - params: Joi.object().required(), - state: Joi.object().optional(), - id: Joi.string().optional(), - }), - }), - }, - }, - async handler(request) { - try { - const { task: taskFields } = request.payload; - const task = { - ...taskFields, - scope: [scope], - }; - - const taskResult = await taskManager.ensureScheduled(task, { request }); - - return taskResult; - } catch (err) { - return err; - } - }, - }); - - server.route({ - path: '/api/sample_tasks/event', - method: 'POST', - config: { - validate: { - payload: Joi.object({ - event: Joi.string().required(), - data: Joi.object() - .optional() - .default({}), - }), - }, - }, - async handler(request) { - try { - const { event, data } = request.payload; - taskTestingEvents.emit(event, data); - return { event }; - } catch (err) { - return err; - } - }, - }); - - server.route({ - path: '/api/sample_tasks', - method: 'GET', - async handler() { - try { - return taskManager.fetch({ - query: taskManagerQuery, - }); - } catch (err) { - return err; - } - }, - }); - - server.route({ - path: '/api/sample_tasks/task/{taskId}', - method: 'GET', - async handler(request) { - try { - await ensureIndexIsRefreshed(); - return await taskManager.get(request.params.taskId); - } catch (err) { - return err; - } - }, - }); - - server.route({ - path: '/api/sample_tasks', - method: 'DELETE', - async handler() { - try { - let tasksFound = 0; - do { - const { docs: tasks } = await taskManager.fetch({ - query: taskManagerQuery, - }); - tasksFound = tasks.length; - await Promise.all(tasks.map(task => taskManager.remove(task.id))); - } while (tasksFound > 0); - return 'OK'; - } catch (err) { - return err; - } - }, - }); -} diff --git a/x-pack/test/plugin_api_integration/plugins/task_manager/package.json b/x-pack/test/plugin_api_integration/plugins/task_manager/package.json deleted file mode 100644 index ec63c512e9cd7..0000000000000 --- a/x-pack/test/plugin_api_integration/plugins/task_manager/package.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "sample_task_plugin", - "version": "1.0.0", - "kibana": { - "version": "kibana", - "templateVersion": "1.0.0" - }, - "license": "Apache-2.0", - "dependencies": { - "joi": "^13.5.2" - } -} diff --git a/x-pack/test/plugin_api_integration/test_suites/event_log/public_api_integration.ts b/x-pack/test/plugin_api_integration/test_suites/event_log/public_api_integration.ts index e5b840b335846..d7bbc29bd861e 100644 --- a/x-pack/test/plugin_api_integration/test_suites/event_log/public_api_integration.ts +++ b/x-pack/test/plugin_api_integration/test_suites/event_log/public_api_integration.ts @@ -19,7 +19,9 @@ export default function({ getService }: FtrProviderContext) { const log = getService('log'); const retry = getService('retry'); - describe('Event Log public API', () => { + // FLAKY: https://github.com/elastic/kibana/issues/64723 + // FLAKY: https://github.com/elastic/kibana/issues/64812 + describe.skip('Event Log public API', () => { it('should allow querying for events by Saved Object', async () => { const id = uuid.v4(); diff --git a/x-pack/test/plugin_api_integration/test_suites/task_manager/task_manager_integration.js b/x-pack/test/plugin_api_integration/test_suites/task_manager/task_manager_integration.js index e8f976d5ae6e3..00cefa42711c9 100644 --- a/x-pack/test/plugin_api_integration/test_suites/task_manager/task_manager_integration.js +++ b/x-pack/test/plugin_api_integration/test_suites/task_manager/task_manager_integration.js @@ -11,7 +11,7 @@ import supertestAsPromised from 'supertest-as-promised'; const { task: { properties: taskManagerIndexMapping }, -} = require('../../../../legacy/plugins/task_manager/server/mappings.json'); +} = require('../../../../plugins/task_manager/server/saved_objects/mappings.json'); const { DEFAULT_MAX_WORKERS, @@ -90,15 +90,6 @@ export default function({ getService }) { .then(response => response.body); } - function scheduleTaskUsingLegacyApi(task) { - return supertest - .post('/api/sample_tasks/schedule_legacy') - .set('kbn-xsrf', 'xxx') - .send({ task }) - .expect(200) - .then(response => response.body); - } - function runTaskNow(task) { return supertest .post('/api/sample_tasks/run_now') @@ -587,15 +578,5 @@ export default function({ getService }) { expect(getTaskById(tasks, longRunningTask.id).state.count).to.eql(1); }); }); - - it('should retain the legacy api until v8.0.0', async () => { - const result = await scheduleTaskUsingLegacyApi({ - id: 'task-with-legacy-api', - taskType: 'sampleTask', - params: {}, - }); - - expect(result.id).to.be('task-with-legacy-api'); - }); }); } diff --git a/yarn.lock b/yarn.lock index ee00ef283f07c..94e6a0a11aa99 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4798,6 +4798,11 @@ resolved "https://registry.yarnpkg.com/@types/semver/-/semver-5.5.0.tgz#146c2a29ee7d3bae4bf2fcb274636e264c813c45" integrity sha512-41qEJgBH/TWgo5NFSvBCJ1qkoi3Q6ONSF2avrHq1LVEZfYpdHmj0y9SuTK+u9ZhG1sYQKBL1AWXKyLWP4RaUoQ== +"@types/set-value@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@types/set-value/-/set-value-2.0.0.tgz#63d386b103926dcf49b50e16e0f6dd49983046be" + integrity sha512-k8dCJEC80F/mbsIOZ5Hj3YSzTVVVBwMdtP/M9Rtc2TM4F5etVd+2UG8QUiAUfbXm4fABedL2tBZnrBheY7UwpA== + "@types/shot@*": version "4.0.0" resolved "https://registry.yarnpkg.com/@types/shot/-/shot-4.0.0.tgz#7545500c489b65c69b5bc5446ba4fef3bd26af92" @@ -26910,6 +26915,13 @@ set-value@^2.0.0, set-value@^2.0.1: is-plain-object "^2.0.3" split-string "^3.0.1" +set-value@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-3.0.2.tgz#74e8ecd023c33d0f77199d415409a40f21e61b90" + integrity sha512-npjkVoz+ank0zjlV9F47Fdbjfj/PfXyVhZvGALWsyIYU/qrMzpi6avjKW3/7KeSU2Df3I46BrN1xOI1+6vW0hA== + dependencies: + is-plain-object "^2.0.4" + setimmediate@^1.0.4, setimmediate@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"