diff --git a/.ci/Jenkinsfile_security_cypress b/.ci/Jenkinsfile_security_cypress index d7f702a56563f..f7b02cd1c4ab1 100644 --- a/.ci/Jenkinsfile_security_cypress +++ b/.ci/Jenkinsfile_security_cypress @@ -10,7 +10,8 @@ kibanaPipeline(timeoutMinutes: 180) { ) { catchError { withEnv([ - 'CI_PARALLEL_PROCESS_NUMBER=1' + 'CI_PARALLEL_PROCESS_NUMBER=1', + 'IGNORE_SHIP_CI_STATS_ERROR=true', ]) { def job = 'xpack-securityCypress' diff --git a/.ci/es-snapshots/Jenkinsfile_verify_es b/.ci/es-snapshots/Jenkinsfile_verify_es index 11a39faa9aed0..736a71b73d14d 100644 --- a/.ci/es-snapshots/Jenkinsfile_verify_es +++ b/.ci/es-snapshots/Jenkinsfile_verify_es @@ -26,10 +26,12 @@ kibanaPipeline(timeoutMinutes: 150) { message: "[${SNAPSHOT_VERSION}] ES Snapshot Verification Failure", ) { retryable.enable(2) - withEnv(["ES_SNAPSHOT_MANIFEST=${SNAPSHOT_MANIFEST}"]) { + withEnv([ + "ES_SNAPSHOT_MANIFEST=${SNAPSHOT_MANIFEST}", + 'IGNORE_SHIP_CI_STATS_ERROR=true', + ]) { parallel([ 'kibana-intake-agent': workers.intake('kibana-intake', './test/scripts/jenkins_unit.sh'), - 'x-pack-intake-agent': workers.intake('x-pack-intake', './test/scripts/jenkins_xpack.sh'), 'kibana-oss-agent': workers.functional('kibana-oss-tests', { kibanaPipeline.buildOss() }, [ 'oss-ciGroup1': kibanaPipeline.ossCiGroupProcess(1), 'oss-ciGroup2': kibanaPipeline.ossCiGroupProcess(2), diff --git a/.ci/jobs.yml b/.ci/jobs.yml index b05e834f5a459..6aa93d4a1056a 100644 --- a/.ci/jobs.yml +++ b/.ci/jobs.yml @@ -2,7 +2,6 @@ JOB: - kibana-intake - - x-pack-intake - kibana-firefoxSmoke - kibana-ciGroup1 - kibana-ciGroup2 diff --git a/.eslintrc.js b/.eslintrc.js index 9430b9bf24466..7608bcb40a0b9 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1119,6 +1119,39 @@ module.exports = { // All files files: ['x-pack/plugins/enterprise_search/**/*.{ts,tsx}'], rules: { + 'import/order': [ + 'error', + { + groups: ['unknown', ['builtin', 'external'], 'internal', 'parent', 'sibling', 'index'], + pathGroups: [ + { + pattern: + '{../../../../../../,../../../../../,../../../../,../../../,../../,../}{common/,*}__mocks__{*,/**}', + group: 'unknown', + }, + { + pattern: '{**,.}/*.mock', + group: 'unknown', + }, + { + pattern: 'react*', + group: 'external', + position: 'before', + }, + { + pattern: '{@elastic/**,@kbn/**,src/**}', + group: 'internal', + }, + ], + pathGroupsExcludedImportTypes: [], + alphabetize: { + order: 'asc', + caseInsensitive: true, + }, + 'newlines-between': 'always-and-inside-groups', + }, + ], + 'import/newline-after-import': 'error', 'react-hooks/exhaustive-deps': 'off', 'react/jsx-boolean-value': ['error', 'never'], }, diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 34b449346ddf7..87dc99fa33749 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -26,6 +26,7 @@ /src/plugins/vis_type_xy/ @elastic/kibana-app /src/plugins/visualize/ @elastic/kibana-app /src/plugins/visualizations/ @elastic/kibana-app +/packages/kbn-tinymath/ @elastic/kibana-app # Application Services /examples/bfetch_explorer/ @elastic/kibana-app-services diff --git a/dev_docs/assets/applications.png b/dev_docs/assets/applications.png new file mode 100644 index 0000000000000..409f3416136ec Binary files /dev/null and b/dev_docs/assets/applications.png differ diff --git a/dev_docs/assets/platform_plugins_core.png b/dev_docs/assets/platform_plugins_core.png new file mode 100644 index 0000000000000..a1b7df4483c3f Binary files /dev/null and b/dev_docs/assets/platform_plugins_core.png differ diff --git a/dev_docs/kibana_platform_plugin_intro.mdx b/dev_docs/kibana_platform_plugin_intro.mdx index 3303561fae069..ce8b8b8b54756 100644 --- a/dev_docs/kibana_platform_plugin_intro.mdx +++ b/dev_docs/kibana_platform_plugin_intro.mdx @@ -11,45 +11,34 @@ From an end user perspective, Kibana is a tool for interacting with Elasticsearc to visualize and analyze data. From a developer perspective, Kibana is a platform that provides a set of tools to build not only the UI you see in Kibana today, but -a wide variety of applications that can be used to explore, visualize, and act upon data in Elasticsearch. The platform provides developers the ability to build applications, or inject extra functionality into +a wide variety of applications that can be used to explore, visualize, and act upon data in Elasticsearch. The platform provides developers the ability +to build applications, or inject extra functionality into already existing applications. Did you know that almost everything you see in the Kibana UI is built inside a plugin? If you removed all plugins from Kibana, you'd be left with an empty navigation menu, and a set of developer tools. The Kibana platform is a blank canvas, just waiting for a developer to come along and create something! ![Kibana personas](assets/kibana_platform_plugin_end_user.png) + +## Platform services -## Plugins vs The Platform +Plugins have access to three kinds of public services: -The core platform provides the most basic and fundamental tools neccessary for building a plugin, like creating saved objects, -routing, application registration, and notifications. The Core platform is not a plugin itself, although -there are some plugins that provide platform functionality. For example, the - provides basic utilities to search, query, and filter data in Elasticsearch. -This code is not part of Core, but is still fundamental for building a plugin, - and we strongly encourage using this service over querying Elasticsearch directly. - - -We currently have three kinds of public services: - - - platform services provided by `core` - - platform services provided by plugins, that can, and should, be used by every plugin (e.g. ) . - - shared services provided by plugins, that are only relevant for only a few, specific plugins (e.g. "presentation utils"). - -Two common questions we encounter are: + - Platform services provided by `core` () + - Platform services provided by plugins () + - Shared services provided by plugins, that are only relevant for only a few, specific plugins (e.g. "presentation utils"). -1. Which services are platform services? -2. What is the difference between platform code supplied by core, and platform code supplied by plugins? + The first two items are what make up "Platform services". -We don't have great answers to those questions today. Currently, the best answers we have are: + -1. Platform plugins are _usually_ plugins that are managed by the Platform Group, but we are starting to see some exceptions. -2. `core` code contains the most fundamental and stable services needed for plugin development. Everything else goes in a plugin. +We try to put only the most stable and fundamental code into `Core`, while more application focused functionality goes in a plugin, but the heuristic isn't +clear, and we haven't done a great job of sticking to it. For example, notifications and toasts are core services, but data and search are plugin services. -We will continue to focus on adding clarity around these types of services and what developers can expect from each. - - +Today it looks something like this. +![Core vs platform plugins vs plugins](assets/platform_plugins_core.png) + - When the Kibana platform and plugin infrastructure was built, we thought of two types of code: core services, and other plugin services. We planned to keep the most stable and fundamental code needed to build plugins inside core. @@ -70,125 +59,62 @@ Another side effect of having many small plugins is that common code often ends We recognize the need to better clarify the relationship between core functionality, platform-like plugin functionality, and functionality exposed by other plugins. It's something we will be working on! - -The main difference between core functionality and functionality supplied by plugins, is in how it is accessed. Core is -passed to plugins as the first parameter to their `start` and `setup` lifecycle functions, while plugin supplied functionality is passed as the -second parameter. Plugin dependencies must be declared explicitly inside the `kibana.json` file. Core functionality is always provided. Read the -section on for more information. - -## The anatomy of a plugin - -Plugins are defined as classes and present themselves to Kibana through a simple wrapper function. A plugin can have browser-side code, server-side code, -or both. There is no architectural difference between a plugin in the browser and a plugin on the server. In both places, you describe your plugin similarly, -and you interact with Core and other plugins in the same way. - -The basic file structure of a Kibana plugin named demo that has both client-side and server-side code would be: - -``` -plugins/ - demo - kibana.json [1] - public - index.ts [2] - plugin.ts [3] - server - index.ts [4] - plugin.ts [5] -``` - -### [1] kibana.json - -`kibana.json` is a static manifest file that is used to identify the plugin and to specify if this plugin has server-side code, browser-side code, or both: - -``` -{ - "id": "demo", - "version": "kibana", - "server": true, - "ui": true -} -``` - -### [2] public/index.ts - -`public/index.ts` is the entry point into the client-side code of this plugin. It must export a function named plugin, which will receive a standard set of - core capabilities as an argument. It should return an instance of its plugin class for Kibana to load. - -``` -import type { PluginInitializerContext } from 'kibana/server'; -import { DemoPlugin } from './plugin'; - -export function plugin(initializerContext: PluginInitializerContext) { - return new DemoPlugin(initializerContext); -} -``` - -### [3] public/plugin.ts - -`public/plugin.ts` is the client-side plugin definition itself. Technically speaking, it does not need to be a class or even a separate file from the entry - point, but all plugins at Elastic should be consistent in this way. - +We will continue to focus on adding clarity around these types of services and what developers can expect from each. - ```ts -import type { Plugin, PluginInitializerContext, CoreSetup, CoreStart } from 'kibana/server'; -export class DemoPlugin implements Plugin { - constructor(initializerContext: PluginInitializerContext) {} + - public setup(core: CoreSetup) { - // called when plugin is setting up during Kibana's startup sequence - } +### Core services - public start(core: CoreStart) { - // called after all plugins are set up - } +Sometimes referred to just as Core, Core services provide the most basic and fundamental tools neccessary for building a plugin, like creating saved objects, +routing, application registration, and notifications. The Core platform is not a plugin itself, although +there are some plugins that provide platform functionality. We call these . - public stop() { - // called when plugin is torn down during Kibana's shutdown sequence - } -} - ``` +### Platform plugins +Plugins that provide fundamental services and functionality to extend and customize Kibana, for example, the + plugin. There is no official way to tell if a plugin is a platform plugin or not. +Platform plugins are _usually_ plugins that are managed by the Platform Group, but we are starting to see some exceptions. -### [4] server/index.ts +## Plugins -`server/index.ts` is the entry-point into the server-side code of this plugin. It is identical in almost every way to the client-side entry-point: +Plugins are code that is written to extend and customize Kibana. Plugin's don't have to be part of the Kibana repo, though the Kibana +repo does contain many plugins! Plugins add customizations by +using provided by . +Sometimes people confuse the term "plugin" and "application". While often there is a 1:1 relationship between a plugin and an application, it is not always the case. +A plugin may register many applications, or none. -### [5] server/plugin.ts +### Applications -`server/plugin.ts` is the server-side plugin definition. The shape of this plugin is the same as it’s client-side counter-part: +Applications are top level pages in the Kibana UI. Dashboard, Canvas, Maps, App Search, etc, are all examples of applications: -```ts -import type { Plugin, PluginInitializerContext, CoreSetup, CoreStart } from 'kibana/server'; +![applications in kibana](./assets/applications.png) -export class DemoPlugin implements Plugin { - constructor(initializerContext: PluginInitializerContext) {} +A plugin can register an application by +adding it to core's application . - public setup(core: CoreSetup) { - // called when plugin is setting up during Kibana's startup sequence - } +### Public plugin API - public start(core: CoreStart) { - // called after all plugins are set up - } +A plugin's public API consists of everything exported from a plugin's , +as well as from the top level `index.ts` files that exist in the three "scope" folders: - public stop() { - // called when plugin is torn down during Kibana's shutdown sequence - } -} -``` +- common/index.ts +- public/index.ts +- server/index.ts -Kibana does not impose any technical restrictions on how the the internals of a plugin are architected, though there are certain -considerations related to how plugins integrate with core APIs and APIs exposed by other plugins that may greatly impact how they are built. +Any plugin that exports something from those files, or from the lifecycle methods, is exposing a public service. We sometimes call these things "plugin services" or +"shared services". -## Plugin lifecycles & Core services +## Lifecycle methods -The various independent domains that make up core are represented by a series of services. Those services expose public interfaces that are provided to all plugins. -Services expose different features at different parts of their lifecycle. We describe the lifecycle of core services and plugins with specifically-named functions on the service definition. +Core, and plugins, expose different features at different parts of their lifecycle. We describe the lifecycle of core services and plugins with + specifically-named functions on the service definition. -Kibana has three lifecycles: setup, start, and stop. Each plugin’s setup function is called sequentially while Kibana is setting up on the server or when it is being loaded in the browser. The start functions are called sequentially after setup has been completed for all plugins. The stop functions are called sequentially while Kibana is gracefully shutting down the server or when the browser tab or window is being closed. +Kibana has three lifecycles: setup, start, and stop. Each plugin’s setup function is called sequentially while Kibana is setting up + on the server or when it is being loaded in the browser. The start functions are called sequentially after setup has been completed for all plugins. + The stop functions are called sequentially while Kibana is gracefully shutting down the server or when the browser tab or window is being closed. The table below explains how each lifecycle relates to the state of Kibana. @@ -201,105 +127,18 @@ The table below explains how each lifecycle relates to the state of Kibana. Different service interfaces can and will be passed to setup, start, and stop because certain functionality makes sense in the context of a running plugin while other types of functionality may have restrictions or may only make sense in the context of a plugin that is stopping. -## How plugin's interact with each other, and Core - -The lifecycle-specific contracts exposed by core services are always passed as the first argument to the equivalent lifecycle function in a plugin. -For example, the core http service exposes a function createRouter to all plugin setup functions. To use this function to register an HTTP route handler, -a plugin just accesses it off of the first argument: - -```ts -import type { CoreSetup } from 'kibana/server'; - -export class DemoPlugin { - public setup(core: CoreSetup) { - const router = core.http.createRouter(); - // handler is called when '/path' resource is requested with `GET` method - router.get({ path: '/path', validate: false }, (context, req, res) => res.ok({ content: 'ok' })); - } -} -``` - -Unlike core, capabilities exposed by plugins are not automatically injected into all plugins. -Instead, if a plugin wishes to use the public interface provided by another plugin, it must first declare that plugin as a - dependency in it’s kibana.json manifest file. - -** foobar plugin.ts: ** - -``` -import type { Plugin } from 'kibana/server'; -export interface FoobarPluginSetup { [1] - getFoo(): string; -} - -export interface FoobarPluginStart { [1] - getBar(): string; -} - -export class MyPlugin implements Plugin { - public setup(): FoobarPluginSetup { - return { - getFoo() { - return 'foo'; - }, - }; - } - - public start(): FoobarPluginStart { - return { - getBar() { - return 'bar'; - }, - }; - } -} -``` -[1] We highly encourage plugin authors to explicitly declare public interfaces for their plugins. - - -** demo kibana.json** - -``` -{ - "id": "demo", - "requiredPlugins": ["foobar"], - "server": true, - "ui": true -} -``` - -With that specified in the plugin manifest, the appropriate interfaces are then available via the second argument of setup and/or start: - -```ts -import type { CoreSetup, CoreStart } from 'kibana/server'; -import type { FoobarPluginSetup, FoobarPluginStart } from '../../foobar/server'; - -interface DemoSetupPlugins { [1] - foobar: FoobarPluginSetup; -} - -interface DemoStartPlugins { - foobar: FoobarPluginStart; -} - -export class DemoPlugin { - public setup(core: CoreSetup, plugins: DemoSetupPlugins) { [2] - const { foobar } = plugins; - foobar.getFoo(); // 'foo' - foobar.getBar(); // throws because getBar does not exist - } - - public start(core: CoreStart, plugins: DemoStartPlugins) { [3] - const { foobar } = plugins; - foobar.getFoo(); // throws because getFoo does not exist - foobar.getBar(); // 'bar' - } - - public stop() {} -} -``` - -[1] The interface for plugin’s dependencies must be manually composed. You can do this by importing the appropriate type from the plugin and constructing an interface where the property name is the plugin’s ID. - -[2] These manually constructed types should then be used to specify the type of the second argument to the plugin. - -[3] Notice that the type for the setup and start lifecycles are different. Plugin lifecycle functions can only access the APIs that are exposed during that lifecycle. +## Extension points + +An extension point is a function provided by core, or a plugin's plugin API, that can be used by other +plugins to customize the Kibana experience. Examples of extension points are: + +- core.application.register (The extension point talked about above) +- core.notifications.toasts.addSuccess +- core.overlays.showModal +- embeddables.registerEmbeddableFactory +- uiActions.registerAction +- core.saedObjects.registerType + +## Follow up material + +Learn how to build your own plugin by following \ No newline at end of file diff --git a/dev_docs/tutorials/building_a_plugin.mdx b/dev_docs/tutorials/building_a_plugin.mdx new file mode 100644 index 0000000000000..cee5a9a399de5 --- /dev/null +++ b/dev_docs/tutorials/building_a_plugin.mdx @@ -0,0 +1,226 @@ +--- +id: kibDevTutorialBuildAPlugin +slug: /kibana-dev-docs/tutorials/build-a-plugin +title: Kibana plugin tutorial +summary: Anatomy of a Kibana plugin and how to build one +date: 2021-02-05 +tags: ['kibana','onboarding', 'dev', 'tutorials'] +--- + +Prereading material: + +- + +## The anatomy of a plugin + +Plugins are defined as classes and present themselves to Kibana through a simple wrapper function. A plugin can have browser-side code, server-side code, +or both. There is no architectural difference between a plugin in the browser and a plugin on the server. In both places, you describe your plugin similarly, +and you interact with Core and other plugins in the same way. + +The basic file structure of a Kibana plugin named demo that has both client-side and server-side code would be: + +``` +plugins/ + demo + kibana.json [1] + public + index.ts [2] + plugin.ts [3] + server + index.ts [4] + plugin.ts [5] + common + index.ts [6] +``` + +### [1] kibana.json + +`kibana.json` is a static manifest file that is used to identify the plugin and to specify if this plugin has server-side code, browser-side code, or both: + +``` +{ + "id": "demo", + "version": "kibana", + "server": true, + "ui": true +} +``` + +### [2] public/index.ts + +`public/index.ts` is the entry point into the client-side code of this plugin. It must export a function named plugin, which will receive a standard set of + core capabilities as an argument. It should return an instance of its plugin class for Kibana to load. + +``` +import type { PluginInitializerContext } from 'kibana/server'; +import { DemoPlugin } from './plugin'; + +export function plugin(initializerContext: PluginInitializerContext) { + return new DemoPlugin(initializerContext); +} +``` + +### [3] public/plugin.ts + +`public/plugin.ts` is the client-side plugin definition itself. Technically speaking, it does not need to be a class or even a separate file from the entry + point, but all plugins at Elastic should be consistent in this way. + + + ```ts +import type { Plugin, PluginInitializerContext, CoreSetup, CoreStart } from 'kibana/server'; + +export class DemoPlugin implements Plugin { + constructor(initializerContext: PluginInitializerContext) {} + + public setup(core: CoreSetup) { + // called when plugin is setting up during Kibana's startup sequence + } + + public start(core: CoreStart) { + // called after all plugins are set up + } + + public stop() { + // called when plugin is torn down during Kibana's shutdown sequence + } +} + ``` + + +### [4] server/index.ts + +`server/index.ts` is the entry-point into the server-side code of this plugin. It is identical in almost every way to the client-side entry-point: + +### [5] server/plugin.ts + +`server/plugin.ts` is the server-side plugin definition. The shape of this plugin is the same as it’s client-side counter-part: + +```ts +import type { Plugin, PluginInitializerContext, CoreSetup, CoreStart } from 'kibana/server'; + +export class DemoPlugin implements Plugin { + constructor(initializerContext: PluginInitializerContext) {} + + public setup(core: CoreSetup) { + // called when plugin is setting up during Kibana's startup sequence + } + + public start(core: CoreStart) { + // called after all plugins are set up + } + + public stop() { + // called when plugin is torn down during Kibana's shutdown sequence + } +} +``` + +Kibana does not impose any technical restrictions on how the the internals of a plugin are architected, though there are certain +considerations related to how plugins integrate with core APIs and APIs exposed by other plugins that may greatly impact how they are built. + +### [6] common/index.ts + +`common/index.ts` is the entry-point into code that can be used both server-side or client side. + +## How plugin's interact with each other, and Core + +The lifecycle-specific contracts exposed by core services are always passed as the first argument to the equivalent lifecycle function in a plugin. +For example, the core http service exposes a function createRouter to all plugin setup functions. To use this function to register an HTTP route handler, +a plugin just accesses it off of the first argument: + +```ts +import type { CoreSetup } from 'kibana/server'; + +export class DemoPlugin { + public setup(core: CoreSetup) { + const router = core.http.createRouter(); + // handler is called when '/path' resource is requested with `GET` method + router.get({ path: '/path', validate: false }, (context, req, res) => res.ok({ content: 'ok' })); + } +} +``` + +Unlike core, capabilities exposed by plugins are not automatically injected into all plugins. +Instead, if a plugin wishes to use the public interface provided by another plugin, it must first declare that plugin as a + dependency in it’s kibana.json manifest file. + +** foobar plugin.ts: ** + +``` +import type { Plugin } from 'kibana/server'; +export interface FoobarPluginSetup { [1] + getFoo(): string; +} + +export interface FoobarPluginStart { [1] + getBar(): string; +} + +export class MyPlugin implements Plugin { + public setup(): FoobarPluginSetup { + return { + getFoo() { + return 'foo'; + }, + }; + } + + public start(): FoobarPluginStart { + return { + getBar() { + return 'bar'; + }, + }; + } +} +``` +[1] We highly encourage plugin authors to explicitly declare public interfaces for their plugins. + + +** demo kibana.json** + +``` +{ + "id": "demo", + "requiredPlugins": ["foobar"], + "server": true, + "ui": true +} +``` + +With that specified in the plugin manifest, the appropriate interfaces are then available via the second argument of setup and/or start: + +```ts +import type { CoreSetup, CoreStart } from 'kibana/server'; +import type { FoobarPluginSetup, FoobarPluginStart } from '../../foobar/server'; + +interface DemoSetupPlugins { [1] + foobar: FoobarPluginSetup; +} + +interface DemoStartPlugins { + foobar: FoobarPluginStart; +} + +export class DemoPlugin { + public setup(core: CoreSetup, plugins: DemoSetupPlugins) { [2] + const { foobar } = plugins; + foobar.getFoo(); // 'foo' + foobar.getBar(); // throws because getBar does not exist + } + + public start(core: CoreStart, plugins: DemoStartPlugins) { [3] + const { foobar } = plugins; + foobar.getFoo(); // throws because getFoo does not exist + foobar.getBar(); // 'bar' + } + + public stop() {} +} +``` + +[1] The interface for plugin’s dependencies must be manually composed. You can do this by importing the appropriate type from the plugin and constructing an interface where the property name is the plugin’s ID. + +[2] These manually constructed types should then be used to specify the type of the second argument to the plugin. + +[3] Notice that the type for the setup and start lifecycles are different. Plugin lifecycle functions can only access the APIs that are exposed during that lifecycle. diff --git a/docs/developer/contributing/development-ci-metrics.asciidoc b/docs/developer/contributing/development-ci-metrics.asciidoc index 3e49686fb67f0..2efe4e7c60a7d 100644 --- a/docs/developer/contributing/development-ci-metrics.asciidoc +++ b/docs/developer/contributing/development-ci-metrics.asciidoc @@ -121,13 +121,20 @@ Changes to the {kib-repo}blob/{branch}/packages/kbn-optimizer/limits.yml[`limits [[ci-metric-validating-limits]] === Validating `page load bundle size` limits -Once you've fixed any issues discovered while diagnosing overages you probably should just push the changes to your PR and let CI validate them. +While you're trying to track down changes which will improve the bundle size, try running the following command locally: -If you have a pretty powerful dev machine, or the necessary patience/determination, you can validate the limits locally by running the following command: +[source,shell] +----------- +node scripts/build_kibana_platform_plugins --dist --watch --focus {pluginId} +----------- + +This will build the front-end bundles for your plugin and only the plugins your plugin depends on. Whenever you make changes the bundles are rebuilt and you can inspect the metrics of that build in the `target/public/metrics.json` file within your plugin. This file will be updated as you save changes to the source and should be helpful to determine if your changes are lowering the `page load asset size` enough. + +If you only want to run the build once you can run: [source,shell] ----------- -node scripts/build_kibana_platform_plugins --validate-limits +node scripts/build_kibana_platform_plugins --validate-limits --focus {pluginId} ----------- This command needs to apply production optimizations to get the right sizes, which means that the optimizer will take significantly longer to run and on most developmer machines will consume all of your machines resources for 20 minutes or more. If you'd like to multi-task while this is running you might need to limit the number of workers using the `--max-workers` flag. \ No newline at end of file diff --git a/docs/developer/plugin-list.asciidoc b/docs/developer/plugin-list.asciidoc index 6587d5dc422b4..263addc98ee62 100644 --- a/docs/developer/plugin-list.asciidoc +++ b/docs/developer/plugin-list.asciidoc @@ -443,10 +443,6 @@ using the CURL scripts in the scripts folder. |Visualize geo data from Elasticsearch or 3rd party geo-services. -|{kib-repo}blob/{branch}/x-pack/plugins/maps_file_upload/README.md[mapsFileUpload] -|Deprecated - plugin targeted for removal and will get merged into file_upload plugin - - |{kib-repo}blob/{branch}/x-pack/plugins/maps_legacy_licensing/README.md[mapsLegacyLicensing] |This plugin provides access to the detailed tile map services from Elastic. diff --git a/docs/migration/migrate_8_0.asciidoc b/docs/migration/migrate_8_0.asciidoc index 14eff4594c813..5452621440ed8 100644 --- a/docs/migration/migrate_8_0.asciidoc +++ b/docs/migration/migrate_8_0.asciidoc @@ -52,7 +52,18 @@ for example, `logstash-*`. ==== Default logging timezone is now the system's timezone *Details:* In prior releases the timezone used in logs defaulted to UTC. We now use the host machine's timezone by default. -*Impact:* To restore the previous behavior, in kibana.yml set `logging.timezone: UTC`. +*Impact:* To restore the previous behavior, in kibana.yml use the pattern layout, with a date modifier: +[source,yaml] +------------------- +logging: + appenders: + console: + kind: console + layout: + kind: pattern + pattern: "%date{ISO8601_TZ}{UTC}" +------------------- +See https://github.com/elastic/kibana/pull/90368 for more details. [float] ==== Responses are never logged by default diff --git a/docs/setup/settings.asciidoc b/docs/setup/settings.asciidoc index ecdb41c897b12..9b9c26fd0e1db 100644 --- a/docs/setup/settings.asciidoc +++ b/docs/setup/settings.asciidoc @@ -309,7 +309,8 @@ suppress all logging output. *Default: `false`* | Set to the canonical time zone ID (for example, `America/Los_Angeles`) to log events using that time zone. For possible values, refer to -https://en.wikipedia.org/wiki/List_of_tz_database_time_zones[database time zones]. *Default: `UTC`* +https://en.wikipedia.org/wiki/List_of_tz_database_time_zones[database time zones]. +When not set, log events use the host timezone | [[logging-verbose]] `logging.verbose:` {ess-icon} | Set to `true` to log all events, including system usage information and all diff --git a/docs/user/alerting/alert-types.asciidoc b/docs/user/alerting/alert-types.asciidoc index 279739e95b522..016ecc3167298 100644 --- a/docs/user/alerting/alert-types.asciidoc +++ b/docs/user/alerting/alert-types.asciidoc @@ -130,12 +130,13 @@ image::images/alert-types-es-query-select.png[Choosing an ES query alert type] [float] ==== Defining the conditions -The ES query alert has 4 clauses that define the condition to detect. +The ES query alert has 5 clauses that define the condition to detect. [role="screenshot"] image::images/alert-types-es-query-conditions.png[Four clauses define the condition to detect] Index:: This clause requires an *index or index pattern* and a *time field* that will be used for the *time window*. +Size:: This clause specifies the number of documents to pass to the configured actions when the the threshold condition is met. ES query:: This clause specifies the ES DSL query to execute. The number of documents that match this query will be evaulated against the threshold condition. Aggregations are not supported at this time. Threshold:: This clause defines a threshold value and a comparison operator (`is above`, `is above or equals`, `is below`, `is below or equals`, or `is between`). The number of documents that match the specified query is compared to this threshold. diff --git a/docs/user/alerting/images/alert-types-es-query-conditions.png b/docs/user/alerting/images/alert-types-es-query-conditions.png index ce2bd6a42a4b5..3cbba5eb4950e 100644 Binary files a/docs/user/alerting/images/alert-types-es-query-conditions.png and b/docs/user/alerting/images/alert-types-es-query-conditions.png differ diff --git a/jest.config.integration.js b/jest.config.integration.js index df9fa9029aaa3..50767932a52d7 100644 --- a/jest.config.integration.js +++ b/jest.config.integration.js @@ -17,6 +17,7 @@ module.exports = { testPathIgnorePatterns: preset.testPathIgnorePatterns.filter( (pattern) => !pattern.includes('integration_tests') ), + setupFilesAfterEnv: ['/packages/kbn-test/target/jest/setup/after_env.integration.js'], reporters: [ 'default', [ @@ -24,5 +25,7 @@ module.exports = { { reportName: 'Jest Integration Tests' }, ], ], - setupFilesAfterEnv: ['/packages/kbn-test/target/jest/setup/after_env.integration.js'], + coverageReporters: !!process.env.CI + ? [['json', { file: 'jest-integration.json' }]] + : ['html', 'text'], }; diff --git a/jest.config.js b/jest.config.js index 89f66b5ee462f..03dc832ba170c 100644 --- a/jest.config.js +++ b/jest.config.js @@ -7,6 +7,14 @@ */ module.exports = { + preset: '@kbn/test', rootDir: '.', - projects: [...require('./jest.config.oss').projects, ...require('./x-pack/jest.config').projects], + projects: [ + '/packages/*/jest.config.js', + '/src/*/jest.config.js', + '/src/legacy/*/jest.config.js', + '/src/plugins/*/jest.config.js', + '/test/*/jest.config.js', + '/x-pack/plugins/*/jest.config.js', + ], }; diff --git a/jest.config.oss.js b/jest.config.oss.js deleted file mode 100644 index fcd704382f39d..0000000000000 --- a/jest.config.oss.js +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -module.exports = { - preset: '@kbn/test', - rootDir: '.', - projects: [ - '/packages/*/jest.config.js', - '/src/*/jest.config.js', - '/src/legacy/*/jest.config.js', - '/src/plugins/*/jest.config.js', - '/test/*/jest.config.js', - ], -}; diff --git a/package.json b/package.json index 7144745f2ae35..aac576dbc3561 100644 --- a/package.json +++ b/package.json @@ -97,7 +97,7 @@ "@babel/runtime": "^7.12.5", "@elastic/datemath": "link:packages/elastic-datemath", "@elastic/elasticsearch": "npm:@elastic/elasticsearch-canary@^8.0.0-canary", - "@elastic/ems-client": "7.11.0", + "@elastic/ems-client": "7.12.0", "@elastic/eui": "31.4.0", "@elastic/filesaver": "1.1.2", "@elastic/good": "^9.0.1-kibana3", diff --git a/packages/kbn-dev-utils/src/ci_stats_reporter/ship_ci_stats_cli.ts b/packages/kbn-dev-utils/src/ci_stats_reporter/ship_ci_stats_cli.ts index 1ee78518bb801..4d07b54b8cf03 100644 --- a/packages/kbn-dev-utils/src/ci_stats_reporter/ship_ci_stats_cli.ts +++ b/packages/kbn-dev-utils/src/ci_stats_reporter/ship_ci_stats_cli.ts @@ -22,10 +22,18 @@ export function shipCiStatsCli() { throw createFlagError('expected --metrics to be a string'); } + const maybeFail = (message: string) => { + const error = createFailError(message); + if (process.env.IGNORE_SHIP_CI_STATS_ERROR === 'true') { + error.exitCode = 0; + } + return error; + }; + const reporter = CiStatsReporter.fromEnv(log); if (!reporter.isEnabled()) { - throw createFailError('unable to initilize the CI Stats reporter'); + throw maybeFail('unable to initilize the CI Stats reporter'); } for (const path of metricPaths) { @@ -35,7 +43,7 @@ export function shipCiStatsCli() { if (await reporter.metrics(JSON.parse(json))) { log.success('shipped metrics from', path); } else { - throw createFailError('failed to ship metrics'); + throw maybeFail('failed to ship metrics'); } } }, diff --git a/packages/kbn-optimizer/limits.yml b/packages/kbn-optimizer/limits.yml index 490c2ccc19d7d..a1e40c06f6fa1 100644 --- a/packages/kbn-optimizer/limits.yml +++ b/packages/kbn-optimizer/limits.yml @@ -104,4 +104,4 @@ pageLoadAssetSize: presentationUtil: 28545 spacesOss: 18817 osquery: 107090 - mapsFileUpload: 23775 + fileUpload: 25664 diff --git a/packages/kbn-std/src/promise.test.ts b/packages/kbn-std/src/promise.test.ts index f7c119acd0c7a..bf4f3951d5850 100644 --- a/packages/kbn-std/src/promise.test.ts +++ b/packages/kbn-std/src/promise.test.ts @@ -12,40 +12,36 @@ const delay = (ms: number, resolveValue?: any) => new Promise((resolve) => setTimeout(resolve, ms, resolveValue)); describe('withTimeout', () => { - it('resolves with a promise value if resolved in given timeout', async () => { + it('resolves with a promise value and "timedout: false" if resolved in given timeout', async () => { await expect( withTimeout({ promise: delay(10, 'value'), - timeout: 200, - errorMessage: 'error-message', + timeoutMs: 200, }) - ).resolves.toBe('value'); + ).resolves.toStrictEqual({ value: 'value', timedout: false }); }); - it('rejects with errorMessage if not resolved in given time', async () => { + it('resolves with "timedout: false" if not resolved in given time', async () => { await expect( withTimeout({ promise: delay(200, 'value'), - timeout: 10, - errorMessage: 'error-message', + timeoutMs: 10, }) - ).rejects.toMatchInlineSnapshot(`[Error: error-message]`); + ).resolves.toStrictEqual({ timedout: true }); await expect( withTimeout({ promise: new Promise((i) => i), - timeout: 10, - errorMessage: 'error-message', + timeoutMs: 10, }) - ).rejects.toMatchInlineSnapshot(`[Error: error-message]`); + ).resolves.toStrictEqual({ timedout: true }); }); it('does not swallow promise error', async () => { await expect( withTimeout({ promise: Promise.reject(new Error('from-promise')), - timeout: 10, - errorMessage: 'error-message', + timeoutMs: 10, }) ).rejects.toMatchInlineSnapshot(`[Error: from-promise]`); }); diff --git a/packages/kbn-std/src/promise.ts b/packages/kbn-std/src/promise.ts index 9d8f7703c026d..9209c2ce372c6 100644 --- a/packages/kbn-std/src/promise.ts +++ b/packages/kbn-std/src/promise.ts @@ -6,19 +6,26 @@ * Side Public License, v 1. */ -export function withTimeout({ +export async function withTimeout({ promise, - timeout, - errorMessage, + timeoutMs, }: { promise: Promise; - timeout: number; - errorMessage: string; -}) { - return Promise.race([ - promise, - new Promise((resolve, reject) => setTimeout(() => reject(new Error(errorMessage)), timeout)), - ]) as Promise; + timeoutMs: number; +}): Promise<{ timedout: true } | { timedout: false; value: T }> { + let timeout: NodeJS.Timeout | undefined; + try { + return (await Promise.race([ + promise.then((v) => ({ value: v, timedout: false })), + new Promise((resolve) => { + timeout = setTimeout(() => resolve({ timedout: true }), timeoutMs); + }), + ])) as Promise<{ timedout: true } | { timedout: false; value: T }>; + } finally { + if (timeout !== undefined) { + clearTimeout(timeout); + } + } } export function isPromise(maybePromise: T | Promise): maybePromise is Promise { diff --git a/packages/kbn-test/jest-preset.js b/packages/kbn-test/jest-preset.js index 9ed11c4fe5fdd..717be8f413b48 100644 --- a/packages/kbn-test/jest-preset.js +++ b/packages/kbn-test/jest-preset.js @@ -19,7 +19,9 @@ module.exports = { coveragePathIgnorePatterns: ['/node_modules/', '.*\\.d\\.ts'], // A list of reporter names that Jest uses when writing coverage reports - coverageReporters: !!process.env.CODE_COVERAGE ? ['json'] : ['html', 'text'], + coverageReporters: !!process.env.CODE_COVERAGE + ? [['json', { file: 'jest.json' }]] + : ['html', 'text'], // An array of file extensions your modules use moduleFileExtensions: ['js', 'mjs', 'json', 'ts', 'tsx', 'node'], diff --git a/packages/kbn-tinymath/package.json b/packages/kbn-tinymath/package.json index 13b77b1482af9..cc4fa0a64d9c3 100644 --- a/packages/kbn-tinymath/package.json +++ b/packages/kbn-tinymath/package.json @@ -4,6 +4,7 @@ "license": "SSPL-1.0 OR Elastic License 2.0", "private": true, "main": "src/index.js", + "types": "tinymath.d.ts", "scripts": { "kbn:bootstrap": "yarn build", "build": "../../node_modules/.bin/pegjs -o src/grammar.js src/grammar.pegjs" diff --git a/packages/kbn-tinymath/src/grammar.js b/packages/kbn-tinymath/src/grammar.js index 60dfcf4800631..5454143530c39 100644 --- a/packages/kbn-tinymath/src/grammar.js +++ b/packages/kbn-tinymath/src/grammar.js @@ -156,11 +156,21 @@ function peg$parse(input, options) { peg$c12 = function(literal) { return literal; }, - peg$c13 = function(first, rest) { // We can open this up later. Strict for now. - return first + rest.join(''); + peg$c13 = function(chars) { + return { + type: 'variable', + value: chars.join(''), + location: simpleLocation(location()), + text: text() + }; }, - peg$c14 = function(first, mid) { - return first + mid.map(m => m[0].join('') + m[1].join('')).join('') + peg$c14 = function(rest) { + return { + type: 'variable', + value: rest.join(''), + location: simpleLocation(location()), + text: text() + }; }, peg$c15 = "+", peg$c16 = peg$literalExpectation("+", false), @@ -168,8 +178,11 @@ function peg$parse(input, options) { peg$c18 = peg$literalExpectation("-", false), peg$c19 = function(left, rest) { return rest.reduce((acc, curr) => ({ + type: 'function', name: curr[0] === '+' ? 'add' : 'subtract', - args: [acc, curr[1]] + args: [acc, curr[1]], + location: simpleLocation(location()), + text: text() }), left) }, peg$c20 = "*", @@ -178,8 +191,11 @@ function peg$parse(input, options) { peg$c23 = peg$literalExpectation("/", false), peg$c24 = function(left, rest) { return rest.reduce((acc, curr) => ({ + type: 'function', name: curr[0] === '*' ? 'multiply' : 'divide', - args: [acc, curr[1]] + args: [acc, curr[1]], + location: simpleLocation(location()), + text: text() }), left) }, peg$c25 = "(", @@ -196,25 +212,51 @@ function peg$parse(input, options) { peg$c34 = function(first, rest) { return [first].concat(rest); }, - peg$c35 = peg$otherExpectation("function"), - peg$c36 = /^[a-z]/, - peg$c37 = peg$classExpectation([["a", "z"]], false, false), - peg$c38 = function(name, args) { - return {name: name.join(''), args: args || []}; + peg$c35 = /^["]/, + peg$c36 = peg$classExpectation(["\""], false, false), + peg$c37 = function(value) { return value.join(''); }, + peg$c38 = /^[']/, + peg$c39 = peg$classExpectation(["'"], false, false), + peg$c40 = /^[a-zA-Z_]/, + peg$c41 = peg$classExpectation([["a", "z"], ["A", "Z"], "_"], false, false), + peg$c42 = "=", + peg$c43 = peg$literalExpectation("=", false), + peg$c44 = function(name, value) { + return { + type: 'namedArgument', + name: name.join(''), + value: value, + location: simpleLocation(location()), + text: text() + }; + }, + peg$c45 = peg$otherExpectation("function"), + peg$c46 = /^[a-zA-Z_\-]/, + peg$c47 = peg$classExpectation([["a", "z"], ["A", "Z"], "_", "-"], false, false), + peg$c48 = function(name, args) { + return { + type: 'function', + name: name.join(''), + args: args || [], + location: simpleLocation(location()), + text: text() + }; }, - peg$c39 = peg$otherExpectation("number"), - peg$c40 = function() { return parseFloat(text()); }, - peg$c41 = /^[eE]/, - peg$c42 = peg$classExpectation(["e", "E"], false, false), - peg$c43 = peg$otherExpectation("exponent"), - peg$c44 = ".", - peg$c45 = peg$literalExpectation(".", false), - peg$c46 = "0", - peg$c47 = peg$literalExpectation("0", false), - peg$c48 = /^[1-9]/, - peg$c49 = peg$classExpectation([["1", "9"]], false, false), - peg$c50 = /^[0-9]/, - peg$c51 = peg$classExpectation([["0", "9"]], false, false), + peg$c49 = peg$otherExpectation("number"), + peg$c50 = function() { + return parseFloat(text()); + }, + peg$c51 = /^[eE]/, + peg$c52 = peg$classExpectation(["e", "E"], false, false), + peg$c53 = peg$otherExpectation("exponent"), + peg$c54 = ".", + peg$c55 = peg$literalExpectation(".", false), + peg$c56 = "0", + peg$c57 = peg$literalExpectation("0", false), + peg$c58 = /^[1-9]/, + peg$c59 = peg$classExpectation([["1", "9"]], false, false), + peg$c60 = /^[0-9]/, + peg$c61 = peg$classExpectation([["0", "9"]], false, false), peg$currPos = 0, peg$savedPos = 0, @@ -456,10 +498,7 @@ function peg$parse(input, options) { if (s1 !== peg$FAILED) { s2 = peg$parseNumber(); if (s2 === peg$FAILED) { - s2 = peg$parseVariableWithQuote(); - if (s2 === peg$FAILED) { - s2 = peg$parseVariable(); - } + s2 = peg$parseVariable(); } if (s2 !== peg$FAILED) { s3 = peg$parse_(); @@ -489,25 +528,37 @@ function peg$parse(input, options) { } function peg$parseVariable() { - var s0, s1, s2, s3, s4; + var s0, s1, s2, s3, s4, s5; s0 = peg$currPos; s1 = peg$parse_(); if (s1 !== peg$FAILED) { - s2 = peg$parseStartChar(); + s2 = peg$parseQuote(); if (s2 !== peg$FAILED) { s3 = []; s4 = peg$parseValidChar(); + if (s4 === peg$FAILED) { + s4 = peg$parseSpace(); + } while (s4 !== peg$FAILED) { s3.push(s4); s4 = peg$parseValidChar(); + if (s4 === peg$FAILED) { + s4 = peg$parseSpace(); + } } if (s3 !== peg$FAILED) { - s4 = peg$parse_(); + s4 = peg$parseQuote(); if (s4 !== peg$FAILED) { - peg$savedPos = s0; - s1 = peg$c13(s2, s3); - s0 = s1; + s5 = peg$parse_(); + if (s5 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c13(s3); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } } else { peg$currPos = s0; s0 = peg$FAILED; @@ -524,98 +575,26 @@ function peg$parse(input, options) { peg$currPos = s0; s0 = peg$FAILED; } - - return s0; - } - - function peg$parseVariableWithQuote() { - var s0, s1, s2, s3, s4, s5, s6, s7, s8; - - s0 = peg$currPos; - s1 = peg$parse_(); - if (s1 !== peg$FAILED) { - s2 = peg$parseQuote(); - if (s2 !== peg$FAILED) { - s3 = peg$parseStartChar(); + if (s0 === peg$FAILED) { + s0 = peg$currPos; + s1 = peg$parse_(); + if (s1 !== peg$FAILED) { + s2 = []; + s3 = peg$parseValidChar(); if (s3 !== peg$FAILED) { - s4 = []; - s5 = peg$currPos; - s6 = []; - s7 = peg$parseSpace(); - while (s7 !== peg$FAILED) { - s6.push(s7); - s7 = peg$parseSpace(); + while (s3 !== peg$FAILED) { + s2.push(s3); + s3 = peg$parseValidChar(); } - if (s6 !== peg$FAILED) { - s7 = []; - s8 = peg$parseValidChar(); - if (s8 !== peg$FAILED) { - while (s8 !== peg$FAILED) { - s7.push(s8); - s8 = peg$parseValidChar(); - } - } else { - s7 = peg$FAILED; - } - if (s7 !== peg$FAILED) { - s6 = [s6, s7]; - s5 = s6; - } else { - peg$currPos = s5; - s5 = peg$FAILED; - } - } else { - peg$currPos = s5; - s5 = peg$FAILED; - } - while (s5 !== peg$FAILED) { - s4.push(s5); - s5 = peg$currPos; - s6 = []; - s7 = peg$parseSpace(); - while (s7 !== peg$FAILED) { - s6.push(s7); - s7 = peg$parseSpace(); - } - if (s6 !== peg$FAILED) { - s7 = []; - s8 = peg$parseValidChar(); - if (s8 !== peg$FAILED) { - while (s8 !== peg$FAILED) { - s7.push(s8); - s8 = peg$parseValidChar(); - } - } else { - s7 = peg$FAILED; - } - if (s7 !== peg$FAILED) { - s6 = [s6, s7]; - s5 = s6; - } else { - peg$currPos = s5; - s5 = peg$FAILED; - } - } else { - peg$currPos = s5; - s5 = peg$FAILED; - } - } - if (s4 !== peg$FAILED) { - s5 = peg$parseQuote(); - if (s5 !== peg$FAILED) { - s6 = peg$parse_(); - if (s6 !== peg$FAILED) { - peg$savedPos = s0; - s1 = peg$c14(s3, s4); - s0 = s1; - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } + } else { + s2 = peg$FAILED; + } + if (s2 !== peg$FAILED) { + s3 = peg$parse_(); + if (s3 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c14(s2); + s0 = s1; } else { peg$currPos = s0; s0 = peg$FAILED; @@ -628,9 +607,6 @@ function peg$parse(input, options) { peg$currPos = s0; s0 = peg$FAILED; } - } else { - peg$currPos = s0; - s0 = peg$FAILED; } return s0; @@ -911,105 +887,288 @@ function peg$parse(input, options) { return s0; } - function peg$parseArguments() { - var s0, s1, s2, s3, s4, s5, s6, s7, s8; + function peg$parseArgument_List() { + var s0, s1, s2, s3, s4, s5, s6, s7; peg$silentFails++; s0 = peg$currPos; - s1 = peg$parse_(); + s1 = peg$parseArgument(); if (s1 !== peg$FAILED) { - s2 = peg$parseAddSubtract(); - if (s2 !== peg$FAILED) { - s3 = []; - s4 = peg$currPos; - s5 = peg$parse_(); + s2 = []; + s3 = peg$currPos; + s4 = peg$parse_(); + if (s4 !== peg$FAILED) { + if (input.charCodeAt(peg$currPos) === 44) { + s5 = peg$c31; + peg$currPos++; + } else { + s5 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c32); } + } if (s5 !== peg$FAILED) { - if (input.charCodeAt(peg$currPos) === 44) { - s6 = peg$c31; - peg$currPos++; - } else { - s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c32); } - } + s6 = peg$parse_(); if (s6 !== peg$FAILED) { - s7 = peg$parse_(); + s7 = peg$parseArgument(); if (s7 !== peg$FAILED) { - s8 = peg$parseAddSubtract(); - if (s8 !== peg$FAILED) { - peg$savedPos = s4; - s5 = peg$c33(s2, s8); - s4 = s5; - } else { - peg$currPos = s4; - s4 = peg$FAILED; - } + peg$savedPos = s3; + s4 = peg$c33(s1, s7); + s3 = s4; } else { - peg$currPos = s4; - s4 = peg$FAILED; + peg$currPos = s3; + s3 = peg$FAILED; } } else { - peg$currPos = s4; - s4 = peg$FAILED; + peg$currPos = s3; + s3 = peg$FAILED; } } else { - peg$currPos = s4; - s4 = peg$FAILED; + peg$currPos = s3; + s3 = peg$FAILED; } - while (s4 !== peg$FAILED) { - s3.push(s4); - s4 = peg$currPos; - s5 = peg$parse_(); + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + while (s3 !== peg$FAILED) { + s2.push(s3); + s3 = peg$currPos; + s4 = peg$parse_(); + if (s4 !== peg$FAILED) { + if (input.charCodeAt(peg$currPos) === 44) { + s5 = peg$c31; + peg$currPos++; + } else { + s5 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c32); } + } if (s5 !== peg$FAILED) { - if (input.charCodeAt(peg$currPos) === 44) { - s6 = peg$c31; - peg$currPos++; - } else { - s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c32); } - } + s6 = peg$parse_(); if (s6 !== peg$FAILED) { - s7 = peg$parse_(); + s7 = peg$parseArgument(); if (s7 !== peg$FAILED) { - s8 = peg$parseAddSubtract(); - if (s8 !== peg$FAILED) { - peg$savedPos = s4; - s5 = peg$c33(s2, s8); - s4 = s5; - } else { - peg$currPos = s4; - s4 = peg$FAILED; - } + peg$savedPos = s3; + s4 = peg$c33(s1, s7); + s3 = s4; } else { - peg$currPos = s4; - s4 = peg$FAILED; + peg$currPos = s3; + s3 = peg$FAILED; } } else { - peg$currPos = s4; - s4 = peg$FAILED; + peg$currPos = s3; + s3 = peg$FAILED; } } else { - peg$currPos = s4; + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } + if (s2 !== peg$FAILED) { + s3 = peg$parse_(); + if (s3 !== peg$FAILED) { + if (input.charCodeAt(peg$currPos) === 44) { + s4 = peg$c31; + peg$currPos++; + } else { s4 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c32); } + } + if (s4 === peg$FAILED) { + s4 = null; + } + if (s4 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c34(s1, s2); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + peg$silentFails--; + if (s0 === peg$FAILED) { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c30); } + } + + return s0; + } + + function peg$parseString() { + var s0, s1, s2, s3; + + s0 = peg$currPos; + if (peg$c35.test(input.charAt(peg$currPos))) { + s1 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c36); } + } + if (s1 !== peg$FAILED) { + s2 = []; + s3 = peg$parseValidChar(); + if (s3 !== peg$FAILED) { + while (s3 !== peg$FAILED) { + s2.push(s3); + s3 = peg$parseValidChar(); + } + } else { + s2 = peg$FAILED; + } + if (s2 !== peg$FAILED) { + if (peg$c35.test(input.charAt(peg$currPos))) { + s3 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c36); } + } + if (s3 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c37(s2); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + if (s0 === peg$FAILED) { + s0 = peg$currPos; + if (peg$c38.test(input.charAt(peg$currPos))) { + s1 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c39); } + } + if (s1 !== peg$FAILED) { + s2 = []; + s3 = peg$parseValidChar(); + if (s3 !== peg$FAILED) { + while (s3 !== peg$FAILED) { + s2.push(s3); + s3 = peg$parseValidChar(); + } + } else { + s2 = peg$FAILED; + } + if (s2 !== peg$FAILED) { + if (peg$c38.test(input.charAt(peg$currPos))) { + s3 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c39); } + } + if (s3 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c37(s2); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + if (s0 === peg$FAILED) { + s0 = peg$currPos; + s1 = []; + s2 = peg$parseValidChar(); + if (s2 !== peg$FAILED) { + while (s2 !== peg$FAILED) { + s1.push(s2); + s2 = peg$parseValidChar(); } + } else { + s1 = peg$FAILED; + } + if (s1 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c37(s1); + } + s0 = s1; + } + } + + return s0; + } + + function peg$parseArgument() { + var s0, s1, s2, s3, s4, s5, s6; + + s0 = peg$currPos; + s1 = []; + if (peg$c40.test(input.charAt(peg$currPos))) { + s2 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c41); } + } + if (s2 !== peg$FAILED) { + while (s2 !== peg$FAILED) { + s1.push(s2); + if (peg$c40.test(input.charAt(peg$currPos))) { + s2 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c41); } + } + } + } else { + s1 = peg$FAILED; + } + if (s1 !== peg$FAILED) { + s2 = peg$parse_(); + if (s2 !== peg$FAILED) { + if (input.charCodeAt(peg$currPos) === 61) { + s3 = peg$c42; + peg$currPos++; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c43); } } if (s3 !== peg$FAILED) { s4 = peg$parse_(); if (s4 !== peg$FAILED) { - if (input.charCodeAt(peg$currPos) === 44) { - s5 = peg$c31; - peg$currPos++; - } else { - s5 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c32); } - } + s5 = peg$parseNumber(); if (s5 === peg$FAILED) { - s5 = null; + s5 = peg$parseString(); } if (s5 !== peg$FAILED) { s6 = peg$parse_(); if (s6 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$c34(s2, s3); + s1 = peg$c44(s1, s5); s0 = s1; } else { peg$currPos = s0; @@ -1035,10 +1194,8 @@ function peg$parse(input, options) { peg$currPos = s0; s0 = peg$FAILED; } - peg$silentFails--; if (s0 === peg$FAILED) { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c30); } + s0 = peg$parseAddSubtract(); } return s0; @@ -1052,22 +1209,22 @@ function peg$parse(input, options) { s1 = peg$parse_(); if (s1 !== peg$FAILED) { s2 = []; - if (peg$c36.test(input.charAt(peg$currPos))) { + if (peg$c46.test(input.charAt(peg$currPos))) { s3 = input.charAt(peg$currPos); peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c37); } + if (peg$silentFails === 0) { peg$fail(peg$c47); } } if (s3 !== peg$FAILED) { while (s3 !== peg$FAILED) { s2.push(s3); - if (peg$c36.test(input.charAt(peg$currPos))) { + if (peg$c46.test(input.charAt(peg$currPos))) { s3 = input.charAt(peg$currPos); peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c37); } + if (peg$silentFails === 0) { peg$fail(peg$c47); } } } } else { @@ -1084,7 +1241,7 @@ function peg$parse(input, options) { if (s3 !== peg$FAILED) { s4 = peg$parse_(); if (s4 !== peg$FAILED) { - s5 = peg$parseArguments(); + s5 = peg$parseArgument_List(); if (s5 === peg$FAILED) { s5 = null; } @@ -1102,7 +1259,7 @@ function peg$parse(input, options) { s8 = peg$parse_(); if (s8 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$c38(s2, s5); + s1 = peg$c48(s2, s5); s0 = s1; } else { peg$currPos = s0; @@ -1139,7 +1296,7 @@ function peg$parse(input, options) { peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c35); } + if (peg$silentFails === 0) { peg$fail(peg$c45); } } return s0; @@ -1174,7 +1331,7 @@ function peg$parse(input, options) { } if (s4 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$c40(); + s1 = peg$c50(); s0 = s1; } else { peg$currPos = s0; @@ -1195,7 +1352,7 @@ function peg$parse(input, options) { peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c39); } + if (peg$silentFails === 0) { peg$fail(peg$c49); } } return s0; @@ -1204,12 +1361,12 @@ function peg$parse(input, options) { function peg$parseE() { var s0; - if (peg$c41.test(input.charAt(peg$currPos))) { + if (peg$c51.test(input.charAt(peg$currPos))) { s0 = input.charAt(peg$currPos); peg$currPos++; } else { s0 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c42); } + if (peg$silentFails === 0) { peg$fail(peg$c52); } } return s0; @@ -1261,7 +1418,7 @@ function peg$parse(input, options) { peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c43); } + if (peg$silentFails === 0) { peg$fail(peg$c53); } } return s0; @@ -1272,11 +1429,11 @@ function peg$parse(input, options) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 46) { - s1 = peg$c44; + s1 = peg$c54; peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c45); } + if (peg$silentFails === 0) { peg$fail(peg$c55); } } if (s1 !== peg$FAILED) { s2 = []; @@ -1308,20 +1465,20 @@ function peg$parse(input, options) { var s0, s1, s2, s3; if (input.charCodeAt(peg$currPos) === 48) { - s0 = peg$c46; + s0 = peg$c56; peg$currPos++; } else { s0 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c47); } + if (peg$silentFails === 0) { peg$fail(peg$c57); } } if (s0 === peg$FAILED) { s0 = peg$currPos; - if (peg$c48.test(input.charAt(peg$currPos))) { + if (peg$c58.test(input.charAt(peg$currPos))) { s1 = input.charAt(peg$currPos); peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c49); } + if (peg$silentFails === 0) { peg$fail(peg$c59); } } if (s1 !== peg$FAILED) { s2 = []; @@ -1349,17 +1506,30 @@ function peg$parse(input, options) { function peg$parseDigit() { var s0; - if (peg$c50.test(input.charAt(peg$currPos))) { + if (peg$c60.test(input.charAt(peg$currPos))) { s0 = input.charAt(peg$currPos); peg$currPos++; } else { s0 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c51); } + if (peg$silentFails === 0) { peg$fail(peg$c61); } } return s0; } + + function simpleLocation (location) { + // Returns an object representing the position of the function within the expression, + // demarcated by the position of its first character and last character. We calculate these values + // using the offset because the expression could span multiple lines, and we don't want to deal + // with column and line values. + return { + min: location.start.offset, + max: location.end.offset + } + } + + peg$result = peg$startRuleFunction(); if (peg$result !== peg$FAILED && peg$currPos === input.length) { diff --git a/packages/kbn-tinymath/src/grammar.pegjs b/packages/kbn-tinymath/src/grammar.pegjs index cab8e024e60b3..9cb92fa9374a2 100644 --- a/packages/kbn-tinymath/src/grammar.pegjs +++ b/packages/kbn-tinymath/src/grammar.pegjs @@ -1,5 +1,18 @@ // tinymath parsing grammar +{ + function simpleLocation (location) { + // Returns an object representing the position of the function within the expression, + // demarcated by the position of its first character and last character. We calculate these values + // using the offset because the expression could span multiple lines, and we don't want to deal + // with column and line values. + return { + min: location.start.offset, + max: location.end.offset + } + } +} + start = Expression @@ -23,18 +36,28 @@ ValidChar // literals and variables Literal "literal" - = _ literal:(Number / VariableWithQuote / Variable) _ { + = _ literal:(Number / Variable) _ { return literal; } +// Quoted variables are interpreted as strings +// but unquoted variables are more restrictive Variable - = _ first:StartChar rest:ValidChar* _ { // We can open this up later. Strict for now. - return first + rest.join(''); + = _ Quote chars:(ValidChar / Space)* Quote _ { + return { + type: 'variable', + value: chars.join(''), + location: simpleLocation(location()), + text: text() + }; } - -VariableWithQuote - = _ Quote first:StartChar mid:(Space* ValidChar+)* Quote _ { - return first + mid.map(m => m[0].join('') + m[1].join('')).join('') + / _ rest:ValidChar+ _ { + return { + type: 'variable', + value: rest.join(''), + location: simpleLocation(location()), + text: text() + }; } // expressions @@ -45,16 +68,22 @@ Expression AddSubtract = _ left:MultiplyDivide rest:(('+' / '-') MultiplyDivide)* _ { return rest.reduce((acc, curr) => ({ + type: 'function', name: curr[0] === '+' ? 'add' : 'subtract', - args: [acc, curr[1]] + args: [acc, curr[1]], + location: simpleLocation(location()), + text: text() }), left) } MultiplyDivide = _ left:Factor rest:(('*' / '/') Factor)* _ { return rest.reduce((acc, curr) => ({ + type: 'function', name: curr[0] === '*' ? 'multiply' : 'divide', - args: [acc, curr[1]] + args: [acc, curr[1]], + location: simpleLocation(location()), + text: text() }), left) } @@ -68,20 +97,46 @@ Group return expr } -Arguments "arguments" - = _ first:Expression rest:(_ ',' _ arg:Expression {return arg})* _ ','? _ { +Argument_List "arguments" + = first:Argument rest:(_ ',' _ arg:Argument {return arg})* _ ','? { return [first].concat(rest); } +String + = [\"] value:(ValidChar)+ [\"] { return value.join(''); } + / [\'] value:(ValidChar)+ [\'] { return value.join(''); } + / value:(ValidChar)+ { return value.join(''); } + + +Argument + = name:[a-zA-Z_]+ _ '=' _ value:(Number / String) _ { + return { + type: 'namedArgument', + name: name.join(''), + value: value, + location: simpleLocation(location()), + text: text() + }; + } + / arg:Expression + Function "function" - = _ name:[a-z]+ '(' _ args:Arguments? _ ')' _ { - return {name: name.join(''), args: args || []}; + = _ name:[a-zA-Z_-]+ '(' _ args:Argument_List? _ ')' _ { + return { + type: 'function', + name: name.join(''), + args: args || [], + location: simpleLocation(location()), + text: text() + }; } // Numbers. Lol. Number "number" - = '-'? Integer Fraction? Exp? { return parseFloat(text()); } + = '-'? Integer Fraction? Exp? { + return parseFloat(text()); + } E = [eE] diff --git a/packages/kbn-tinymath/src/index.js b/packages/kbn-tinymath/src/index.js index fd4d167bf04dc..4db7df9c57315 100644 --- a/packages/kbn-tinymath/src/index.js +++ b/packages/kbn-tinymath/src/index.js @@ -38,17 +38,22 @@ function interpret(node, scope, injectedFunctions) { return exec(node); function exec(node) { - const type = getType(node); + if (typeof node === 'number') { + return node; + } - if (type === 'function') return invoke(node); + if (node.type === 'function') return invoke(node); - if (type === 'string') { - const val = getValue(scope, node); - if (typeof val === 'undefined') throw new Error(`Unknown variable: ${node}`); + if (node.type === 'variable') { + const val = getValue(scope, node.value); + if (typeof val === 'undefined') throw new Error(`Unknown variable: ${node.value}`); return val; } - return node; // Can only be a number at this point + if (node.type === 'namedArgument') { + // We are ignoring named arguments in the interpreter + throw new Error(`Named arguments are not supported in tinymath itself, at ${node.name}`); + } } function invoke(node) { @@ -67,17 +72,6 @@ function getValue(scope, node) { return typeof val !== 'undefined' ? val : scope[node]; } -function getType(x) { - const type = typeof x; - if (type === 'object') { - const keys = Object.keys(x); - if (keys.length !== 2 || !x.name || !x.args) throw new Error('Invalid AST object'); - return 'function'; - } - if (type === 'string' || type === 'number') return type; - throw new Error(`Unknown AST property type: ${type}`); -} - function isOperable(args) { return args.every((arg) => { if (Array.isArray(arg)) return isOperable(arg); diff --git a/packages/kbn-tinymath/test/library.test.js b/packages/kbn-tinymath/test/library.test.js index 01b4aa3fbf7ae..d11822625b98f 100644 --- a/packages/kbn-tinymath/test/library.test.js +++ b/packages/kbn-tinymath/test/library.test.js @@ -11,7 +11,19 @@ Need tests for spacing, etc */ -const { evaluate, parse } = require('..'); +import { evaluate, parse } from '..'; + +function variableEqual(value) { + return expect.objectContaining({ type: 'variable', value }); +} + +function functionEqual(name, args) { + return expect.objectContaining({ type: 'function', name, args }); +} + +function namedArgumentEqual(name, value) { + return expect.objectContaining({ type: 'namedArgument', name, value }); +} describe('Parser', () => { describe('Numbers', () => { @@ -31,96 +43,144 @@ describe('Parser', () => { describe('Variables', () => { it('strings', () => { - expect(parse('f')).toEqual('f'); - expect(parse('foo')).toEqual('foo'); + expect(parse('f')).toEqual(variableEqual('f')); + expect(parse('foo')).toEqual(variableEqual('foo')); + expect(parse('foo1')).toEqual(variableEqual('foo1')); + expect(() => parse('1foo1')).toThrow('but "f" found'); + }); + + it('strings with spaces', () => { + expect(parse(' foo ')).toEqual(variableEqual('foo')); + expect(() => parse(' foo bar ')).toThrow('but "b" found'); }); it('allowed characters', () => { - expect(parse('_foo')).toEqual('_foo'); - expect(parse('@foo')).toEqual('@foo'); - expect(parse('.foo')).toEqual('.foo'); - expect(parse('-foo')).toEqual('-foo'); - expect(parse('_foo0')).toEqual('_foo0'); - expect(parse('@foo0')).toEqual('@foo0'); - expect(parse('.foo0')).toEqual('.foo0'); - expect(parse('-foo0')).toEqual('-foo0'); + expect(parse('_foo')).toEqual(variableEqual('_foo')); + expect(parse('@foo')).toEqual(variableEqual('@foo')); + expect(parse('.foo')).toEqual(variableEqual('.foo')); + expect(parse('-foo')).toEqual(variableEqual('-foo')); + expect(parse('_foo0')).toEqual(variableEqual('_foo0')); + expect(parse('@foo0')).toEqual(variableEqual('@foo0')); + expect(parse('.foo0')).toEqual(variableEqual('.foo0')); + expect(parse('-foo0')).toEqual(variableEqual('-foo0')); }); }); describe('quoted variables', () => { it('strings with double quotes', () => { - expect(parse('"foo"')).toEqual('foo'); - expect(parse('"f b"')).toEqual('f b'); - expect(parse('"foo bar"')).toEqual('foo bar'); - expect(parse('"foo bar fizz buzz"')).toEqual('foo bar fizz buzz'); - expect(parse('"foo bar baby"')).toEqual('foo bar baby'); + expect(parse('"foo"')).toEqual(variableEqual('foo')); + expect(parse('"f b"')).toEqual(variableEqual('f b')); + expect(parse('"foo bar"')).toEqual(variableEqual('foo bar')); + expect(parse('"foo bar fizz buzz"')).toEqual(variableEqual('foo bar fizz buzz')); + expect(parse('"foo bar baby"')).toEqual(variableEqual('foo bar baby')); }); it('strings with single quotes', () => { /* eslint-disable prettier/prettier */ - expect(parse("'foo'")).toEqual('foo'); - expect(parse("'f b'")).toEqual('f b'); - expect(parse("'foo bar'")).toEqual('foo bar'); - expect(parse("'foo bar fizz buzz'")).toEqual('foo bar fizz buzz'); - expect(parse("'foo bar baby'")).toEqual('foo bar baby'); + expect(parse("'foo'")).toEqual(variableEqual('foo')); + expect(parse("'f b'")).toEqual(variableEqual('f b')); + expect(parse("'foo bar'")).toEqual(variableEqual('foo bar')); + expect(parse("'foo bar fizz buzz'")).toEqual(variableEqual('foo bar fizz buzz')); + expect(parse("'foo bar baby'")).toEqual(variableEqual('foo bar baby')); + expect(parse("' foo bar'")).toEqual(variableEqual(" foo bar")); + expect(parse("'foo bar '")).toEqual(variableEqual("foo bar ")); + expect(parse("'0foo'")).toEqual(variableEqual("0foo")); + expect(parse("' foo bar'")).toEqual(variableEqual(" foo bar")); + expect(parse("'foo bar '")).toEqual(variableEqual("foo bar ")); + expect(parse("'0foo'")).toEqual(variableEqual("0foo")); /* eslint-enable prettier/prettier */ }); it('allowed characters', () => { - expect(parse('"_foo bar"')).toEqual('_foo bar'); - expect(parse('"@foo bar"')).toEqual('@foo bar'); - expect(parse('".foo bar"')).toEqual('.foo bar'); - expect(parse('"-foo bar"')).toEqual('-foo bar'); - expect(parse('"_foo0 bar1"')).toEqual('_foo0 bar1'); - expect(parse('"@foo0 bar1"')).toEqual('@foo0 bar1'); - expect(parse('".foo0 bar1"')).toEqual('.foo0 bar1'); - expect(parse('"-foo0 bar1"')).toEqual('-foo0 bar1'); - }); - - it('invalid characters in double quotes', () => { - const check = (str) => () => parse(str); - expect(check('" foo bar"')).toThrow('but "\\"" found'); - expect(check('"foo bar "')).toThrow('but "\\"" found'); - expect(check('"0foo"')).toThrow('but "\\"" found'); - expect(check('" foo bar"')).toThrow('but "\\"" found'); - expect(check('"foo bar "')).toThrow('but "\\"" found'); - expect(check('"0foo"')).toThrow('but "\\"" found'); - }); - - it('invalid characters in single quotes', () => { - const check = (str) => () => parse(str); - /* eslint-disable prettier/prettier */ - expect(check("' foo bar'")).toThrow('but "\'" found'); - expect(check("'foo bar '")).toThrow('but "\'" found'); - expect(check("'0foo'")).toThrow('but "\'" found'); - expect(check("' foo bar'")).toThrow('but "\'" found'); - expect(check("'foo bar '")).toThrow('but "\'" found'); - expect(check("'0foo'")).toThrow('but "\'" found'); - /* eslint-enable prettier/prettier */ + expect(parse('"_foo bar"')).toEqual(variableEqual('_foo bar')); + expect(parse('"@foo bar"')).toEqual(variableEqual('@foo bar')); + expect(parse('".foo bar"')).toEqual(variableEqual('.foo bar')); + expect(parse('"-foo bar"')).toEqual(variableEqual('-foo bar')); + expect(parse('"_foo0 bar1"')).toEqual(variableEqual('_foo0 bar1')); + expect(parse('"@foo0 bar1"')).toEqual(variableEqual('@foo0 bar1')); + expect(parse('".foo0 bar1"')).toEqual(variableEqual('.foo0 bar1')); + expect(parse('"-foo0 bar1"')).toEqual(variableEqual('-foo0 bar1')); + expect(parse('" foo bar"')).toEqual(variableEqual(' foo bar')); + expect(parse('"foo bar "')).toEqual(variableEqual('foo bar ')); + expect(parse('"0foo"')).toEqual(variableEqual('0foo')); + expect(parse('" foo bar"')).toEqual(variableEqual(' foo bar')); + expect(parse('"foo bar "')).toEqual(variableEqual('foo bar ')); + expect(parse('"0foo"')).toEqual(variableEqual('0foo')); }); }); describe('Functions', () => { it('no arguments', () => { - expect(parse('foo()')).toEqual({ name: 'foo', args: [] }); + expect(parse('foo()')).toEqual(functionEqual('foo', [])); }); it('arguments', () => { - expect(parse('foo(5,10)')).toEqual({ name: 'foo', args: [5, 10] }); + expect(parse('foo(5,10)')).toEqual(functionEqual('foo', [5, 10])); }); it('arguments with strings', () => { - expect(parse('foo("string with spaces")')).toEqual({ - name: 'foo', - args: ['string with spaces'], - }); + expect(parse('foo("string with spaces")')).toEqual( + functionEqual('foo', [variableEqual('string with spaces')]) + ); - /* eslint-disable prettier/prettier */ - expect(parse("foo('string with spaces')")).toEqual({ - name: 'foo', - args: ['string with spaces'], - }); - /* eslint-enable prettier/prettier */ + expect(parse("foo('string with spaces')")).toEqual( + functionEqual('foo', [variableEqual('string with spaces')]) + ); + }); + + it('named only', () => { + expect(parse('foo(q=10)')).toEqual(functionEqual('foo', [namedArgumentEqual('q', 10)])); + }); + + it('named argument is numeric', () => { + expect(parse('foo(q=10.1234e5)')).toEqual( + functionEqual('foo', [namedArgumentEqual('q', 10.1234e5)]) + ); + }); + + it('named and positional', () => { + expect(parse('foo(ref, q="bar")')).toEqual( + functionEqual('foo', [variableEqual('ref'), namedArgumentEqual('q', 'bar')]) + ); + }); + + it('numerically named', () => { + expect(() => parse('foo(1=2)')).toThrow('but "(" found'); + }); + + it('multiple named', () => { + expect(parse('foo(q_param="bar", offset="1d")')).toEqual( + functionEqual('foo', [ + namedArgumentEqual('q_param', 'bar'), + namedArgumentEqual('offset', '1d'), + ]) + ); + }); + + it('multiple named and positional', () => { + expect(parse('foo(q="bar", ref, offset="1d", 100)')).toEqual( + functionEqual('foo', [ + namedArgumentEqual('q', 'bar'), + variableEqual('ref'), + namedArgumentEqual('offset', '1d'), + 100, + ]) + ); + }); + + it('duplicate named', () => { + expect(parse('foo(q="bar", q="test")')).toEqual( + functionEqual('foo', [namedArgumentEqual('q', 'bar'), namedArgumentEqual('q', 'test')]) + ); + }); + + it('incomplete named', () => { + expect(() => parse('foo(a=)')).toThrow('but "(" found'); + expect(() => parse('foo(=a)')).toThrow('but "(" found'); + }); + + it('invalid named', () => { + expect(() => parse('foo(offset-type="1d")')).toThrow('but "(" found'); }); }); @@ -155,7 +215,7 @@ describe('Evaluate', () => { ); }); - it('valiables with dots', () => { + it('variables with dots', () => { expect(evaluate('foo.bar', { 'foo.bar': 20 })).toEqual(20); expect(evaluate('"is.null"', { 'is.null': null })).toEqual(null); expect(evaluate('"is.false"', { 'is.null': null, 'is.false': false })).toEqual(false); @@ -210,6 +270,10 @@ describe('Evaluate', () => { expect(evaluate('sum("space name")', { 'space name': [1, 2, 21] })).toEqual(24); }); + it('throws on named arguments', () => { + expect(() => evaluate('sum(invalid=a)')).toThrow('Named arguments are not supported'); + }); + it('equations with injected functions', () => { expect( evaluate( diff --git a/packages/kbn-tinymath/tinymath.d.ts b/packages/kbn-tinymath/tinymath.d.ts new file mode 100644 index 0000000000000..c3c32a59fa15a --- /dev/null +++ b/packages/kbn-tinymath/tinymath.d.ts @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export function parse(expression: string): TinymathAST; +export function evaluate( + expression: string | null, + context: Record +): number | number[]; + +// Named arguments are not top-level parts of the grammar, but can be nested +export type TinymathAST = number | TinymathVariable | TinymathFunction | TinymathNamedArgument; + +// Zero-indexed location +export interface TinymathLocation { + min: number; + max: number; +} + +export interface TinymathFunction { + type: 'function'; + name: string; + text: string; + args: TinymathAST[]; + location: TinymathLocation; +} + +export interface TinymathVariable { + type: 'variable'; + value: string; + text: string; + location: TinymathLocation; +} + +export interface TinymathNamedArgument { + type: 'namedArgument'; + name: string; + value: string; + text: string; + location: TinymathLocation; +} diff --git a/packages/kbn-tinymath/tsconfig.json b/packages/kbn-tinymath/tsconfig.json new file mode 100644 index 0000000000000..62a7376efdfa6 --- /dev/null +++ b/packages/kbn-tinymath/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "tsBuildInfoFile": "../../build/tsbuildinfo/packages/kbn-tinymath" + }, + "include": ["tinymath.d.ts"] +} diff --git a/src/core/public/plugins/plugins_service.ts b/src/core/public/plugins/plugins_service.ts index 57fbe4cbecd12..230a675b4cda6 100644 --- a/src/core/public/plugins/plugins_service.ts +++ b/src/core/public/plugins/plugins_service.ts @@ -111,11 +111,18 @@ export class PluginsService implements CoreService { expect(messages).toEqual([]); }); }); + + describe('logging.timezone', () => { + it('warns when ops events are used', () => { + const { messages } = applyCoreDeprecations({ + logging: { timezone: 'GMT' }, + }); + expect(messages).toMatchInlineSnapshot(` + Array [ + "\\"logging.timezone\\" has been deprecated and will be removed in 8.0. To set the timezone moving forward, please add a timezone date modifier to the log pattern in your logging configuration. For more details, see https://github.com/elastic/kibana/blob/master/src/core/server/logging/README.md", + ] + `); + }); + + it('does not warn when other events are configured', () => { + const { messages } = applyCoreDeprecations({ + logging: { events: { log: '*' } }, + }); + expect(messages).toEqual([]); + }); + }); }); diff --git a/src/core/server/config/deprecation/core_deprecations.ts b/src/core/server/config/deprecation/core_deprecations.ts index 0db53cdb2e8be..fbdbaeb14fd59 100644 --- a/src/core/server/config/deprecation/core_deprecations.ts +++ b/src/core/server/config/deprecation/core_deprecations.ts @@ -127,6 +127,18 @@ const requestLoggingEventDeprecation: ConfigDeprecation = (settings, fromPath, l return settings; }; +const timezoneLoggingDeprecation: ConfigDeprecation = (settings, fromPath, log) => { + if (has(settings, 'logging.timezone')) { + log( + '"logging.timezone" has been deprecated and will be removed ' + + 'in 8.0. To set the timezone moving forward, please add a timezone date modifier to the log pattern ' + + 'in your logging configuration. For more details, see ' + + 'https://github.com/elastic/kibana/blob/master/src/core/server/logging/README.md' + ); + } + return settings; +}; + export const coreDeprecationProvider: ConfigDeprecationProvider = ({ rename, unusedFromRoot }) => [ unusedFromRoot('savedObjects.indexCheckTimeout'), unusedFromRoot('server.xsrf.token'), @@ -163,4 +175,5 @@ export const coreDeprecationProvider: ConfigDeprecationProvider = ({ rename, unu mapManifestServiceUrlDeprecation, opsLoggingEventDeprecation, requestLoggingEventDeprecation, + timezoneLoggingDeprecation, ]; diff --git a/src/core/server/legacy/integration_tests/logging.test.ts b/src/core/server/legacy/integration_tests/logging.test.ts index 6588f4270fe18..321eb81708f1e 100644 --- a/src/core/server/legacy/integration_tests/logging.test.ts +++ b/src/core/server/legacy/integration_tests/logging.test.ts @@ -87,7 +87,7 @@ describe('logging service', () => { const loggedString = getPlatformLogsFromMock(mockConsoleLog); expect(loggedString).toMatchInlineSnapshot(` Array [ - "[xxxx-xx-xxTxx:xx:xx.xxxZ][INFO ][test-file] handled by NP", + "[xxxx-xx-xxTxx:xx:xx.xxx-xx:xx][INFO ][test-file] handled by NP", ] `); }); @@ -131,9 +131,9 @@ describe('logging service', () => { expect(getPlatformLogsFromMock(mockConsoleLog)).toMatchInlineSnapshot(` Array [ - "[xxxx-xx-xxTxx:xx:xx.xxxZ][INFO ][test-file] info", - "[xxxx-xx-xxTxx:xx:xx.xxxZ][WARN ][test-file] warn", - "[xxxx-xx-xxTxx:xx:xx.xxxZ][ERROR][test-file] error", + "[xxxx-xx-xxTxx:xx:xx.xxx-xx:xx][INFO ][test-file] info", + "[xxxx-xx-xxTxx:xx:xx.xxx-xx:xx][WARN ][test-file] warn", + "[xxxx-xx-xxTxx:xx:xx.xxx-xx:xx][ERROR][test-file] error", ] `); @@ -162,9 +162,9 @@ describe('logging service', () => { expect(getPlatformLogsFromMock(mockConsoleLog)).toMatchInlineSnapshot(` Array [ - "[xxxx-xx-xxTxx:xx:xx.xxxZ][INFO ][test-file] info", - "[xxxx-xx-xxTxx:xx:xx.xxxZ][WARN ][test-file] warn", - "[xxxx-xx-xxTxx:xx:xx.xxxZ][ERROR][test-file] error", + "[xxxx-xx-xxTxx:xx:xx.xxx-xx:xx][INFO ][test-file] info", + "[xxxx-xx-xxTxx:xx:xx.xxx-xx:xx][WARN ][test-file] warn", + "[xxxx-xx-xxTxx:xx:xx.xxx-xx:xx][ERROR][test-file] error", ] `); @@ -199,9 +199,9 @@ describe('logging service', () => { expect(getPlatformLogsFromMock(mockConsoleLog)).toMatchInlineSnapshot(` Array [ - "[xxxx-xx-xxTxx:xx:xx.xxxZ][INFO ][test-file] info", - "[xxxx-xx-xxTxx:xx:xx.xxxZ][WARN ][test-file] warn", - "[xxxx-xx-xxTxx:xx:xx.xxxZ][ERROR][test-file] error", + "[xxxx-xx-xxTxx:xx:xx.xxx-xx:xx][INFO ][test-file] info", + "[xxxx-xx-xxTxx:xx:xx.xxx-xx:xx][WARN ][test-file] warn", + "[xxxx-xx-xxTxx:xx:xx.xxx-xx:xx][ERROR][test-file] error", ] `); diff --git a/src/core/server/logging/README.md b/src/core/server/logging/README.md index b0759defb8803..9e3da1f3e0d71 100644 --- a/src/core/server/logging/README.md +++ b/src/core/server/logging/README.md @@ -110,7 +110,8 @@ Example of `%meta` output: ##### date Outputs the date of the logging event. The date conversion specifier may be followed by a set of braces containing a name of predefined date format and canonical timezone name. -Timezone name is expected to be one from [TZ database name](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) +Timezone name is expected to be one from [TZ database name](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). +Timezone defaults to the host timezone when not explicitly specified. Example of `%date` output: | Conversion pattern | Example | @@ -410,22 +411,22 @@ loggerWithNestedContext.debug('Message with `debug` log level.'); And assuming logger for `server` context with `console` appender and `trace` level was used, console output will look like this: ```bash -[2017-07-25T18:54:41.639Z][TRACE][server] Message with `trace` log level. -[2017-07-25T18:54:41.639Z][DEBUG][server] Message with `debug` log level. -[2017-07-25T18:54:41.639Z][INFO ][server] Message with `info` log level. -[2017-07-25T18:54:41.639Z][WARN ][server] Message with `warn` log level. -[2017-07-25T18:54:41.639Z][ERROR][server] Message with `error` log level. -[2017-07-25T18:54:41.639Z][FATAL][server] Message with `fatal` log level. - -[2017-07-25T18:54:41.639Z][TRACE][server.http] Message with `trace` log level. -[2017-07-25T18:54:41.639Z][DEBUG][server.http] Message with `debug` log level. +[2017-07-25T11:54:41.639-07:00][TRACE][server] Message with `trace` log level. +[2017-07-25T11:54:41.639-07:00][DEBUG][server] Message with `debug` log level. +[2017-07-25T11:54:41.639-07:00][INFO ][server] Message with `info` log level. +[2017-07-25T11:54:41.639-07:00][WARN ][server] Message with `warn` log level. +[2017-07-25T11:54:41.639-07:00][ERROR][server] Message with `error` log level. +[2017-07-25T11:54:41.639-07:00][FATAL][server] Message with `fatal` log level. + +[2017-07-25T11:54:41.639-07:00][TRACE][server.http] Message with `trace` log level. +[2017-07-25T11:54:41.639-07:00][DEBUG][server.http] Message with `debug` log level. ``` The log will be less verbose with `warn` level for the `server` context: ```bash -[2017-07-25T18:54:41.639Z][WARN ][server] Message with `warn` log level. -[2017-07-25T18:54:41.639Z][ERROR][server] Message with `error` log level. -[2017-07-25T18:54:41.639Z][FATAL][server] Message with `fatal` log level. +[2017-07-25T11:54:41.639-07:00][WARN ][server] Message with `warn` log level. +[2017-07-25T11:54:41.639-07:00][ERROR][server] Message with `error` log level. +[2017-07-25T11:54:41.639-07:00][FATAL][server] Message with `fatal` log level. ``` ### Logging config migration @@ -488,7 +489,7 @@ logging.root.level: all #### logging.timezone Set to the canonical timezone id to log events using that timezone. New logging config allows -to [specify timezone](#date) for `layout: pattern`. +to [specify timezone](#date) for `layout: pattern`. Defaults to host timezone when not specified. ```yaml logging: appenders: @@ -530,7 +531,7 @@ TBD | Parameter | Platform log record in **pattern** format | Legacy Platform log record **text** format | | --------------- | ------------------------------------------ | ------------------------------------------ | -| @timestamp | ISO8601 `2012-01-31T23:33:22.011Z` | Absolute `23:33:22.011` | +| @timestamp | ISO8601_TZ `2012-01-31T23:33:22.011-05:00` | Absolute `23:33:22.011` | | context | `parent.child` | `['parent', 'child']` | | level | `DEBUG` | `['debug']` | | meta | stringified JSON object `{"to": "v8"}` | N/A | diff --git a/src/core/server/logging/__snapshots__/logging_system.test.ts.snap b/src/core/server/logging/__snapshots__/logging_system.test.ts.snap index cbe0e352a0f3a..8013aec4a06fd 100644 --- a/src/core/server/logging/__snapshots__/logging_system.test.ts.snap +++ b/src/core/server/logging/__snapshots__/logging_system.test.ts.snap @@ -1,20 +1,20 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`appends records via multiple appenders.: console logs 1`] = `"[2012-01-31T23:33:22.011Z][INFO ][some-context] You know, just for your info."`; +exports[`appends records via multiple appenders.: console logs 1`] = `"[2012-01-31T18:33:22.011-05:00][INFO ][some-context] You know, just for your info."`; exports[`appends records via multiple appenders.: file logs 1`] = ` -"[2012-01-31T23:33:22.011Z][WARN ][tests] Config is not ready! +"[2012-01-31T13:33:22.011-05:00][WARN ][tests] Config is not ready! " `; exports[`appends records via multiple appenders.: file logs 2`] = ` -"[2012-01-31T23:33:22.011Z][ERROR][tests.child] Too bad that config is not ready :/ +"[2012-01-31T08:33:22.011-05:00][ERROR][tests.child] Too bad that config is not ready :/ " `; exports[`asLoggerFactory() only allows to create new loggers. 1`] = ` Object { - "@timestamp": "2012-01-31T18:33:22.011-05:00", + "@timestamp": "2012-01-30T22:33:22.011-05:00", "log": Object { "level": "TRACE", "logger": "test.context", @@ -28,7 +28,7 @@ Object { exports[`asLoggerFactory() only allows to create new loggers. 2`] = ` Object { - "@timestamp": "2012-01-31T13:33:22.011-05:00", + "@timestamp": "2012-01-30T17:33:22.011-05:00", "log": Object { "level": "INFO", "logger": "test.context", @@ -43,7 +43,7 @@ Object { exports[`asLoggerFactory() only allows to create new loggers. 3`] = ` Object { - "@timestamp": "2012-01-31T08:33:22.011-05:00", + "@timestamp": "2012-01-30T12:33:22.011-05:00", "log": Object { "level": "FATAL", "logger": "test.context", @@ -87,7 +87,7 @@ Object { exports[`uses \`root\` logger if context is not specified. 1`] = ` Array [ Array [ - "[2012-01-31T23:33:22.011Z][INFO ][root] This message goes to a root context.", + "[2012-01-31T03:33:22.011-05:00][INFO ][root] This message goes to a root context.", ], ] `; diff --git a/src/core/server/logging/layouts/__snapshots__/pattern_layout.test.ts.snap b/src/core/server/logging/layouts/__snapshots__/pattern_layout.test.ts.snap index 8988f3019d509..54e46ca7f520e 100644 --- a/src/core/server/logging/layouts/__snapshots__/pattern_layout.test.ts.snap +++ b/src/core/server/logging/layouts/__snapshots__/pattern_layout.test.ts.snap @@ -12,29 +12,29 @@ exports[`\`format()\` correctly formats record with custom pattern. 5`] = `"mock exports[`\`format()\` correctly formats record with custom pattern. 6`] = `"mock-message-6-context-6-message-6"`; -exports[`\`format()\` correctly formats record with full pattern. 1`] = `"[2012-02-01T14:30:22.011Z][FATAL][context-1] Some error stack"`; +exports[`\`format()\` correctly formats record with full pattern. 1`] = `"[2012-02-01T09:30:22.011-05:00][FATAL][context-1] Some error stack"`; -exports[`\`format()\` correctly formats record with full pattern. 2`] = `"[2012-02-01T14:30:22.011Z][ERROR][context-2] message-2"`; +exports[`\`format()\` correctly formats record with full pattern. 2`] = `"[2012-02-01T09:30:22.011-05:00][ERROR][context-2] message-2"`; -exports[`\`format()\` correctly formats record with full pattern. 3`] = `"[2012-02-01T14:30:22.011Z][WARN ][context-3] message-3"`; +exports[`\`format()\` correctly formats record with full pattern. 3`] = `"[2012-02-01T09:30:22.011-05:00][WARN ][context-3] message-3"`; -exports[`\`format()\` correctly formats record with full pattern. 4`] = `"[2012-02-01T14:30:22.011Z][DEBUG][context-4] message-4"`; +exports[`\`format()\` correctly formats record with full pattern. 4`] = `"[2012-02-01T09:30:22.011-05:00][DEBUG][context-4] message-4"`; -exports[`\`format()\` correctly formats record with full pattern. 5`] = `"[2012-02-01T14:30:22.011Z][INFO ][context-5] message-5"`; +exports[`\`format()\` correctly formats record with full pattern. 5`] = `"[2012-02-01T09:30:22.011-05:00][INFO ][context-5] message-5"`; -exports[`\`format()\` correctly formats record with full pattern. 6`] = `"[2012-02-01T14:30:22.011Z][TRACE][context-6] message-6"`; +exports[`\`format()\` correctly formats record with full pattern. 6`] = `"[2012-02-01T09:30:22.011-05:00][TRACE][context-6] message-6"`; -exports[`\`format()\` correctly formats record with highlighting. 1`] = `[2012-02-01T14:30:22.011Z][FATAL][context-1] Some error stack`; +exports[`\`format()\` correctly formats record with highlighting. 1`] = `[2012-02-01T09:30:22.011-05:00][FATAL][context-1] Some error stack`; -exports[`\`format()\` correctly formats record with highlighting. 2`] = `[2012-02-01T14:30:22.011Z][ERROR][context-2] message-2`; +exports[`\`format()\` correctly formats record with highlighting. 2`] = `[2012-02-01T09:30:22.011-05:00][ERROR][context-2] message-2`; -exports[`\`format()\` correctly formats record with highlighting. 3`] = `[2012-02-01T14:30:22.011Z][WARN ][context-3] message-3`; +exports[`\`format()\` correctly formats record with highlighting. 3`] = `[2012-02-01T09:30:22.011-05:00][WARN ][context-3] message-3`; -exports[`\`format()\` correctly formats record with highlighting. 4`] = `[2012-02-01T14:30:22.011Z][DEBUG][context-4] message-4`; +exports[`\`format()\` correctly formats record with highlighting. 4`] = `[2012-02-01T09:30:22.011-05:00][DEBUG][context-4] message-4`; -exports[`\`format()\` correctly formats record with highlighting. 5`] = `[2012-02-01T14:30:22.011Z][INFO ][context-5] message-5`; +exports[`\`format()\` correctly formats record with highlighting. 5`] = `[2012-02-01T09:30:22.011-05:00][INFO ][context-5] message-5`; -exports[`\`format()\` correctly formats record with highlighting. 6`] = `[2012-02-01T14:30:22.011Z][TRACE][context-6] message-6`; +exports[`\`format()\` correctly formats record with highlighting. 6`] = `[2012-02-01T09:30:22.011-05:00][TRACE][context-6] message-6`; exports[`allows specifying the PID in custom pattern 1`] = `"5355-context-1-Some error stack"`; diff --git a/src/core/server/logging/layouts/conversions/date.ts b/src/core/server/logging/layouts/conversions/date.ts index c1f871282c5de..66aad5b42354a 100644 --- a/src/core/server/logging/layouts/conversions/date.ts +++ b/src/core/server/logging/layouts/conversions/date.ts @@ -22,11 +22,14 @@ const formats = { UNIX_MILLIS: 'UNIX_MILLIS', }; -function formatDate(date: Date, dateFormat: string = formats.ISO8601, timezone?: string): string { +function formatDate( + date: Date, + dateFormat: string = formats.ISO8601_TZ, + timezone?: string +): string { const momentDate = moment(date); - if (timezone) { - momentDate.tz(timezone); - } + momentDate.tz(timezone ?? moment.tz.guess()); + switch (dateFormat) { case formats.ISO8601: return momentDate.toISOString(); diff --git a/src/core/server/logging/layouts/pattern_layout.test.ts b/src/core/server/logging/layouts/pattern_layout.test.ts index d291516524be0..7dd3c7c51f833 100644 --- a/src/core/server/logging/layouts/pattern_layout.test.ts +++ b/src/core/server/logging/layouts/pattern_layout.test.ts @@ -122,7 +122,9 @@ test('`format()` correctly formats record with meta data.', () => { to: 'v8', }, }) - ).toBe('[2012-02-01T14:30:22.011Z][DEBUG][context-meta]{"from":"v7","to":"v8"} message-meta'); + ).toBe( + '[2012-02-01T09:30:22.011-05:00][DEBUG][context-meta]{"from":"v7","to":"v8"} message-meta' + ); expect( layout.format({ @@ -133,7 +135,7 @@ test('`format()` correctly formats record with meta data.', () => { pid: 5355, meta: {}, }) - ).toBe('[2012-02-01T14:30:22.011Z][DEBUG][context-meta]{} message-meta'); + ).toBe('[2012-02-01T09:30:22.011-05:00][DEBUG][context-meta]{} message-meta'); expect( layout.format({ @@ -143,7 +145,7 @@ test('`format()` correctly formats record with meta data.', () => { timestamp, pid: 5355, }) - ).toBe('[2012-02-01T14:30:22.011Z][DEBUG][context-meta] message-meta'); + ).toBe('[2012-02-01T09:30:22.011-05:00][DEBUG][context-meta] message-meta'); }); test('`format()` correctly formats record with highlighting.', () => { @@ -187,10 +189,10 @@ describe('format', () => { timestamp, pid: 5355, }; - it('uses ISO8601 as default', () => { + it('uses ISO8601_TZ as default', () => { const layout = new PatternLayout(); - expect(layout.format(record)).toBe('[2012-02-01T14:30:22.011Z][DEBUG][context] message'); + expect(layout.format(record)).toBe('[2012-02-01T09:30:22.011-05:00][DEBUG][context] message'); }); describe('supports specifying a predefined format', () => { diff --git a/src/core/server/plugins/plugins_system.test.ts b/src/core/server/plugins/plugins_system.test.ts index 5c38deeb5cf6e..abcd00f4e2daf 100644 --- a/src/core/server/plugins/plugins_system.test.ts +++ b/src/core/server/plugins/plugins_system.test.ts @@ -621,3 +621,45 @@ describe('asynchronous plugins', () => { `); }); }); + +describe('stop', () => { + beforeAll(() => { + jest.useFakeTimers(); + }); + + afterAll(() => { + jest.useRealTimers(); + }); + + it('waits for 30 sec to finish "stop" and move on to the next plugin.', async () => { + const [plugin1, plugin2] = [createPlugin('timeout-stop-1'), createPlugin('timeout-stop-2')].map( + (plugin, index) => { + jest.spyOn(plugin, 'setup').mockResolvedValue(`setup-as-${index}`); + jest.spyOn(plugin, 'start').mockResolvedValue(`started-as-${index}`); + pluginsSystem.addPlugin(plugin); + return plugin; + } + ); + + const stopSpy1 = jest + .spyOn(plugin1, 'stop') + .mockImplementationOnce(() => new Promise((resolve) => resolve)); + const stopSpy2 = jest.spyOn(plugin2, 'stop').mockImplementationOnce(() => Promise.resolve()); + + mockCreatePluginSetupContext.mockImplementation(() => ({})); + + await pluginsSystem.setupPlugins(setupDeps); + const stopPromise = pluginsSystem.stopPlugins(); + + jest.runAllTimers(); + await stopPromise; + expect(stopSpy1).toHaveBeenCalledTimes(1); + expect(stopSpy2).toHaveBeenCalledTimes(1); + + expect(loggingSystemMock.collect(logger).warn.flat()).toEqual( + expect.arrayContaining([ + `"timeout-stop-1" plugin didn't stop in 30sec., move on to the next.`, + ]) + ); + }); +}); diff --git a/src/core/server/plugins/plugins_system.ts b/src/core/server/plugins/plugins_system.ts index b7b8c297ea571..0244254838fab 100644 --- a/src/core/server/plugins/plugins_system.ts +++ b/src/core/server/plugins/plugins_system.ts @@ -105,11 +105,18 @@ export class PluginsSystem { `Plugin ${pluginName} is using asynchronous setup lifecycle. Asynchronous plugins support will be removed in a later version.` ); } - contract = await withTimeout({ + const contractMaybe = await withTimeout({ promise: contractOrPromise, - timeout: 10 * Sec, - errorMessage: `Setup lifecycle of "${pluginName}" plugin wasn't completed in 10sec. Consider disabling the plugin and re-start.`, + timeoutMs: 10 * Sec, }); + + if (contractMaybe.timedout) { + throw new Error( + `Setup lifecycle of "${pluginName}" plugin wasn't completed in 10sec. Consider disabling the plugin and re-start.` + ); + } else { + contract = contractMaybe.value; + } } else { contract = contractOrPromise; } @@ -154,11 +161,18 @@ export class PluginsSystem { `Plugin ${pluginName} is using asynchronous start lifecycle. Asynchronous plugins support will be removed in a later version.` ); } - contract = await withTimeout({ + const contractMaybe = await withTimeout({ promise: contractOrPromise, - timeout: 10 * Sec, - errorMessage: `Start lifecycle of "${pluginName}" plugin wasn't completed in 10sec. Consider disabling the plugin and re-start.`, + timeoutMs: 10 * Sec, }); + + if (contractMaybe.timedout) { + throw new Error( + `Start lifecycle of "${pluginName}" plugin wasn't completed in 10sec. Consider disabling the plugin and re-start.` + ); + } else { + contract = contractMaybe.value; + } } else { contract = contractOrPromise; } @@ -181,7 +195,15 @@ export class PluginsSystem { const pluginName = this.satupPlugins.pop()!; this.log.debug(`Stopping plugin "${pluginName}"...`); - await this.plugins.get(pluginName)!.stop(); + + const resultMaybe = await withTimeout({ + promise: this.plugins.get(pluginName)!.stop(), + timeoutMs: 30 * Sec, + }); + + if (resultMaybe?.timedout) { + this.log.warn(`"${pluginName}" plugin didn't stop in 30sec., move on to the next.`); + } } } diff --git a/src/dev/code_coverage/shell_scripts/extract_archives.sh b/src/dev/code_coverage/shell_scripts/extract_archives.sh index 376467f9f2e55..14b35f8786d02 100644 --- a/src/dev/code_coverage/shell_scripts/extract_archives.sh +++ b/src/dev/code_coverage/shell_scripts/extract_archives.sh @@ -6,7 +6,7 @@ EXTRACT_DIR=/tmp/extracted_coverage mkdir -p $EXTRACT_DIR echo "### Extracting downloaded artifacts" -for x in kibana-intake x-pack-intake kibana-oss-tests kibana-xpack-tests; do +for x in kibana-intake kibana-oss-tests kibana-xpack-tests; do tar -xzf $DOWNLOAD_DIR/coverage/${x}/kibana-coverage.tar.gz -C $EXTRACT_DIR || echo "### Error 'tarring': ${x}" done diff --git a/src/dev/typescript/build_refs.ts b/src/dev/typescript/build_refs.ts index ff6a81843972c..77d6eb2abc612 100644 --- a/src/dev/typescript/build_refs.ts +++ b/src/dev/typescript/build_refs.ts @@ -7,12 +7,10 @@ */ import execa from 'execa'; -import Path from 'path'; import { run, ToolingLog } from '@kbn/dev-utils'; export async function buildAllRefs(log: ToolingLog) { await buildRefs(log, 'tsconfig.refs.json'); - await buildRefs(log, Path.join('x-pack', 'tsconfig.refs.json')); } async function buildRefs(log: ToolingLog, projectPath: string) { diff --git a/src/plugins/dashboard/public/application/listing/dashboard_listing.test.tsx b/src/plugins/dashboard/public/application/listing/dashboard_listing.test.tsx index ee731db0ced65..c7d5db970db42 100644 --- a/src/plugins/dashboard/public/application/listing/dashboard_listing.test.tsx +++ b/src/plugins/dashboard/public/application/listing/dashboard_listing.test.tsx @@ -49,11 +49,16 @@ function makeDefaultServices(): DashboardAppServices { hits, }); }; + const dashboardPanelStorage = ({ + getDashboardIdsWithUnsavedChanges: jest + .fn() + .mockResolvedValue(['dashboardUnsavedOne', 'dashboardUnsavedTwo']), + } as unknown) as DashboardPanelStorage; + return { savedObjects: savedObjectsPluginMock.createStartContract(), embeddable: embeddablePluginMock.createInstance().doStart(), dashboardCapabilities: {} as DashboardCapabilities, - dashboardPanelStorage: {} as DashboardPanelStorage, initializerContext: {} as PluginInitializerContext, chrome: chromeServiceMock.createStartContract(), navigation: {} as NavigationPublicPluginStart, @@ -68,6 +73,7 @@ function makeDefaultServices(): DashboardAppServices { restorePreviousUrl: () => {}, onAppLeave: (handler) => {}, allowByValueEmbeddables: true, + dashboardPanelStorage, savedDashboards, core, }; diff --git a/src/plugins/dashboard/public/application/listing/dashboard_listing.tsx b/src/plugins/dashboard/public/application/listing/dashboard_listing.tsx index 24d08ad06cc3b..c12385a29c4ec 100644 --- a/src/plugins/dashboard/public/application/listing/dashboard_listing.tsx +++ b/src/plugins/dashboard/public/application/listing/dashboard_listing.tsx @@ -8,7 +8,7 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { EuiLink, EuiButton, EuiEmptyPrompt } from '@elastic/eui'; -import React, { Fragment, useCallback, useEffect, useMemo } from 'react'; +import React, { Fragment, useCallback, useEffect, useMemo, useState } from 'react'; import { attemptLoadDashboardByTitle } from '../lib'; import { DashboardAppServices, DashboardRedirect } from '../types'; import { getDashboardBreadcrumb, dashboardListingTable } from '../../dashboard_strings'; @@ -48,6 +48,10 @@ export const DashboardListing = ({ }, } = useKibana(); + const [unsavedDashboardIds, setUnsavedDashboardIds] = useState( + dashboardPanelStorage.getDashboardIdsWithUnsavedChanges() + ); + // Set breadcrumbs useEffect useEffect(() => { setBreadcrumbs([ @@ -135,8 +139,12 @@ export const DashboardListing = ({ ); const deleteItems = useCallback( - (dashboards: Array<{ id: string }>) => savedDashboards.delete(dashboards.map((d) => d.id)), - [savedDashboards] + (dashboards: Array<{ id: string }>) => { + dashboards.map((d) => dashboardPanelStorage.clearPanels(d.id)); + setUnsavedDashboardIds(dashboardPanelStorage.getDashboardIdsWithUnsavedChanges()); + return savedDashboards.delete(dashboards.map((d) => d.id)); + }, + [savedDashboards, dashboardPanelStorage] ); const editItem = useCallback( @@ -179,7 +187,13 @@ export const DashboardListing = ({ tableColumns, }} > - + + setUnsavedDashboardIds(dashboardPanelStorage.getDashboardIdsWithUnsavedChanges()) + } + /> ); }; diff --git a/src/plugins/dashboard/public/application/listing/dashboard_unsaved_listing.test.tsx b/src/plugins/dashboard/public/application/listing/dashboard_unsaved_listing.test.tsx index 119b2d559b68a..13688b4061be9 100644 --- a/src/plugins/dashboard/public/application/listing/dashboard_unsaved_listing.test.tsx +++ b/src/plugins/dashboard/public/application/listing/dashboard_unsaved_listing.test.tsx @@ -17,8 +17,8 @@ import { KibanaContextProvider } from '../../services/kibana_react'; import { SavedObjectLoader } from '../../services/saved_objects'; import { DashboardPanelStorage } from '../lib'; import { DASHBOARD_PANELS_UNSAVED_ID } from '../lib/dashboard_panel_storage'; -import { DashboardAppServices, DashboardRedirect } from '../types'; -import { DashboardUnsavedListing } from './dashboard_unsaved_listing'; +import { DashboardAppServices } from '../types'; +import { DashboardUnsavedListing, DashboardUnsavedListingProps } from './dashboard_unsaved_listing'; const mockedDashboards: { [key: string]: DashboardSavedObject } = { dashboardUnsavedOne: { @@ -39,16 +39,11 @@ function makeDefaultServices(): DashboardAppServices { const core = coreMock.createStart(); core.overlays.openConfirm = jest.fn().mockResolvedValue(true); const savedDashboards = {} as SavedObjectLoader; - savedDashboards.get = jest.fn().mockImplementation((id: string) => mockedDashboards[id]); + savedDashboards.get = jest + .fn() + .mockImplementation((id: string) => Promise.resolve(mockedDashboards[id])); const dashboardPanelStorage = {} as DashboardPanelStorage; dashboardPanelStorage.clearPanels = jest.fn(); - dashboardPanelStorage.getDashboardIdsWithUnsavedChanges = jest - .fn() - .mockImplementation(() => [ - 'dashboardUnsavedOne', - 'dashboardUnsavedTwo', - 'dashboardUnsavedThree', - ]); return ({ dashboardPanelStorage, savedDashboards, @@ -56,14 +51,18 @@ function makeDefaultServices(): DashboardAppServices { } as unknown) as DashboardAppServices; } -const makeDefaultProps = () => ({ redirectTo: jest.fn() }); +const makeDefaultProps = (): DashboardUnsavedListingProps => ({ + redirectTo: jest.fn(), + unsavedDashboardIds: ['dashboardUnsavedOne', 'dashboardUnsavedTwo', 'dashboardUnsavedThree'], + refreshUnsavedDashboards: jest.fn(), +}); function mountWith({ services: incomingServices, props: incomingProps, }: { services?: DashboardAppServices; - props?: { redirectTo: DashboardRedirect }; + props?: DashboardUnsavedListingProps; }) { const services = incomingServices ?? makeDefaultServices(); const props = incomingProps ?? makeDefaultProps(); @@ -89,11 +88,9 @@ describe('Unsaved listing', () => { }); it('Does not attempt to get unsaved dashboard id', async () => { - const services = makeDefaultServices(); - services.dashboardPanelStorage.getDashboardIdsWithUnsavedChanges = jest - .fn() - .mockImplementation(() => ['dashboardUnsavedOne', DASHBOARD_PANELS_UNSAVED_ID]); - mountWith({ services }); + const props = makeDefaultProps(); + props.unsavedDashboardIds = ['dashboardUnsavedOne', DASHBOARD_PANELS_UNSAVED_ID]; + const { services } = mountWith({ props }); await waitFor(() => { expect(services.savedDashboards.get).toHaveBeenCalledTimes(1); }); @@ -115,11 +112,9 @@ describe('Unsaved listing', () => { }); it('Redirects to new dashboard when continue editing clicked', async () => { - const services = makeDefaultServices(); - services.dashboardPanelStorage.getDashboardIdsWithUnsavedChanges = jest - .fn() - .mockImplementation(() => [DASHBOARD_PANELS_UNSAVED_ID]); - const { props, component } = mountWith({ services }); + const props = makeDefaultProps(); + props.unsavedDashboardIds = [DASHBOARD_PANELS_UNSAVED_ID]; + const { component } = mountWith({ props }); const getEditButton = () => findTestSubject(component, `edit-unsaved-New-Dashboard`); await waitFor(() => { component.update(); @@ -150,4 +145,34 @@ describe('Unsaved listing', () => { ); }); }); + + it('removes unsaved changes from any dashboard which errors on fetch', async () => { + const services = makeDefaultServices(); + const props = makeDefaultProps(); + services.savedDashboards.get = jest.fn().mockImplementation((id: string) => { + if (id === 'failCase1' || id === 'failCase2') { + return Promise.reject(new Error()); + } + return Promise.resolve(mockedDashboards[id]); + }); + + props.unsavedDashboardIds = [ + 'dashboardUnsavedOne', + 'dashboardUnsavedTwo', + 'dashboardUnsavedThree', + 'failCase1', + 'failCase2', + ]; + const { component } = mountWith({ services, props }); + waitFor(() => { + component.update(); + expect(services.dashboardPanelStorage.clearPanels).toHaveBeenCalledWith('failCase1'); + expect(services.dashboardPanelStorage.clearPanels).toHaveBeenCalledWith('failCase2'); + + // clearing panels from dashboard with errors should cause getDashboardIdsWithUnsavedChanges to be called again. + expect( + services.dashboardPanelStorage.getDashboardIdsWithUnsavedChanges + ).toHaveBeenCalledTimes(2); + }); + }); }); diff --git a/src/plugins/dashboard/public/application/listing/dashboard_unsaved_listing.tsx b/src/plugins/dashboard/public/application/listing/dashboard_unsaved_listing.tsx index d7b9564d9d1e3..db50cfb638d64 100644 --- a/src/plugins/dashboard/public/application/listing/dashboard_unsaved_listing.tsx +++ b/src/plugins/dashboard/public/application/listing/dashboard_unsaved_listing.tsx @@ -106,7 +106,17 @@ interface UnsavedItemMap { [key: string]: DashboardSavedObject; } -export const DashboardUnsavedListing = ({ redirectTo }: { redirectTo: DashboardRedirect }) => { +export interface DashboardUnsavedListingProps { + refreshUnsavedDashboards: () => void; + redirectTo: DashboardRedirect; + unsavedDashboardIds: string[]; +} + +export const DashboardUnsavedListing = ({ + redirectTo, + unsavedDashboardIds, + refreshUnsavedDashboards, +}: DashboardUnsavedListingProps) => { const { services: { dashboardPanelStorage, @@ -116,9 +126,6 @@ export const DashboardUnsavedListing = ({ redirectTo }: { redirectTo: DashboardR } = useKibana(); const [items, setItems] = useState({}); - const [dashboardIds, setDashboardIds] = useState( - dashboardPanelStorage.getDashboardIdsWithUnsavedChanges() - ); const onOpen = useCallback( (id?: string) => { @@ -133,48 +140,63 @@ export const DashboardUnsavedListing = ({ redirectTo }: { redirectTo: DashboardR overlays, () => { dashboardPanelStorage.clearPanels(id); - setDashboardIds(dashboardPanelStorage.getDashboardIdsWithUnsavedChanges()); + refreshUnsavedDashboards(); }, createConfirmStrings.getCancelButtonText() ); }, - [overlays, dashboardPanelStorage] + [overlays, refreshUnsavedDashboards, dashboardPanelStorage] ); useEffect(() => { - if (dashboardIds?.length === 0) { + if (unsavedDashboardIds?.length === 0) { return; } let canceled = false; - const dashPromises = dashboardIds + const dashPromises = unsavedDashboardIds .filter((id) => id !== DASHBOARD_PANELS_UNSAVED_ID) - .map((dashboardId) => savedDashboards.get(dashboardId)); - Promise.all(dashPromises).then((dashboards: DashboardSavedObject[]) => { + .map((dashboardId) => { + return (savedDashboards.get(dashboardId) as Promise).catch( + () => dashboardId + ); + }); + Promise.all(dashPromises).then((dashboards: Array) => { const dashboardMap = {}; if (canceled) { return; } - setItems( - dashboards.reduce((map, dashboard) => { - return { - ...map, - [dashboard.id || DASHBOARD_PANELS_UNSAVED_ID]: dashboard, - }; - }, dashboardMap) - ); + let hasError = false; + const newItems = dashboards.reduce((map, dashboard) => { + if (typeof dashboard === 'string') { + hasError = true; + dashboardPanelStorage.clearPanels(dashboard); + return map; + } + return { + ...map, + [dashboard.id || DASHBOARD_PANELS_UNSAVED_ID]: dashboard, + }; + }, dashboardMap); + if (hasError) { + refreshUnsavedDashboards(); + return; + } + setItems(newItems); }); return () => { canceled = true; }; - }, [dashboardIds, savedDashboards]); + }, [savedDashboards, dashboardPanelStorage, refreshUnsavedDashboards, unsavedDashboardIds]); - return dashboardIds.length === 0 ? null : ( + return unsavedDashboardIds.length === 0 ? null : ( <> 1)} + title={dashboardUnsavedListingStrings.getUnsavedChangesTitle( + unsavedDashboardIds.length > 1 + )} > - {dashboardIds.map((dashboardId: string) => { + {unsavedDashboardIds.map((dashboardId: string) => { const title: string | undefined = dashboardId === DASHBOARD_PANELS_UNSAVED_ID ? getNewDashboardTitle() diff --git a/src/plugins/data/common/search/tabify/__snapshots__/tabify_docs.test.ts.snap b/src/plugins/data/common/search/tabify/__snapshots__/tabify_docs.test.ts.snap index 6cc191a67633c..22276335a0599 100644 --- a/src/plugins/data/common/search/tabify/__snapshots__/tabify_docs.test.ts.snap +++ b/src/plugins/data/common/search/tabify/__snapshots__/tabify_docs.test.ts.snap @@ -1,5 +1,113 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`tabifyDocs combines meta fields if meta option is set 1`] = ` +Object { + "columns": Array [ + Object { + "id": "fieldTest", + "meta": Object { + "field": "fieldTest", + "index": "test-index", + "params": Object { + "id": "number", + }, + "type": "number", + }, + "name": "fieldTest", + }, + Object { + "id": "invalidMapping", + "meta": Object { + "field": "invalidMapping", + "index": "test-index", + "params": undefined, + "type": "number", + }, + "name": "invalidMapping", + }, + Object { + "id": "nested", + "meta": Object { + "field": "nested", + "index": "test-index", + "params": undefined, + "type": "object", + }, + "name": "nested", + }, + Object { + "id": "sourceTest", + "meta": Object { + "field": "sourceTest", + "index": "test-index", + "params": Object { + "id": "number", + }, + "type": "number", + }, + "name": "sourceTest", + }, + Object { + "id": "_id", + "meta": Object { + "field": "_id", + "index": "test-index", + "params": undefined, + "type": "string", + }, + "name": "_id", + }, + Object { + "id": "_index", + "meta": Object { + "field": "_index", + "index": "test-index", + "params": undefined, + "type": "string", + }, + "name": "_index", + }, + Object { + "id": "_score", + "meta": Object { + "field": "_score", + "index": "test-index", + "params": undefined, + "type": "number", + }, + "name": "_score", + }, + Object { + "id": "_type", + "meta": Object { + "field": "_type", + "index": "test-index", + "params": undefined, + "type": "string", + }, + "name": "_type", + }, + ], + "rows": Array [ + Object { + "_id": "hit-id-value", + "_index": "hit-index-value", + "_score": 77, + "_type": "hit-type-value", + "fieldTest": 123, + "invalidMapping": 345, + "nested": Array [ + Object { + "field": 123, + }, + ], + "sourceTest": 123, + }, + ], + "type": "datatable", +} +`; + exports[`tabifyDocs converts fields by default 1`] = ` Object { "columns": Array [ @@ -47,9 +155,53 @@ Object { }, "name": "sourceTest", }, + Object { + "id": "_id", + "meta": Object { + "field": "_id", + "index": "test-index", + "params": undefined, + "type": "string", + }, + "name": "_id", + }, + Object { + "id": "_index", + "meta": Object { + "field": "_index", + "index": "test-index", + "params": undefined, + "type": "string", + }, + "name": "_index", + }, + Object { + "id": "_score", + "meta": Object { + "field": "_score", + "index": "test-index", + "params": undefined, + "type": "number", + }, + "name": "_score", + }, + Object { + "id": "_type", + "meta": Object { + "field": "_type", + "index": "test-index", + "params": undefined, + "type": "string", + }, + "name": "_type", + }, ], "rows": Array [ Object { + "_id": "hit-id-value", + "_index": "hit-index-value", + "_score": 77, + "_type": "hit-type-value", "fieldTest": 123, "invalidMapping": 345, "nested": Array [ @@ -111,9 +263,53 @@ Object { }, "name": "sourceTest", }, + Object { + "id": "_id", + "meta": Object { + "field": "_id", + "index": "test-index", + "params": undefined, + "type": "string", + }, + "name": "_id", + }, + Object { + "id": "_index", + "meta": Object { + "field": "_index", + "index": "test-index", + "params": undefined, + "type": "string", + }, + "name": "_index", + }, + Object { + "id": "_score", + "meta": Object { + "field": "_score", + "index": "test-index", + "params": undefined, + "type": "number", + }, + "name": "_score", + }, + Object { + "id": "_type", + "meta": Object { + "field": "_type", + "index": "test-index", + "params": undefined, + "type": "string", + }, + "name": "_type", + }, ], "rows": Array [ Object { + "_id": "hit-id-value", + "_index": "hit-index-value", + "_score": 77, + "_type": "hit-type-value", "fieldTest": 123, "invalidMapping": 345, "nested": Array [ @@ -175,9 +371,53 @@ Object { }, "name": "sourceTest", }, + Object { + "id": "_id", + "meta": Object { + "field": "_id", + "index": "test-index", + "params": undefined, + "type": "string", + }, + "name": "_id", + }, + Object { + "id": "_index", + "meta": Object { + "field": "_index", + "index": "test-index", + "params": undefined, + "type": "string", + }, + "name": "_index", + }, + Object { + "id": "_score", + "meta": Object { + "field": "_score", + "index": "test-index", + "params": undefined, + "type": "number", + }, + "name": "_score", + }, + Object { + "id": "_type", + "meta": Object { + "field": "_type", + "index": "test-index", + "params": undefined, + "type": "string", + }, + "name": "_type", + }, ], "rows": Array [ Object { + "_id": "hit-id-value", + "_index": "hit-index-value", + "_score": 77, + "_type": "hit-type-value", "fieldTest": 123, "invalidMapping": 345, "nested": Array [ @@ -235,9 +475,53 @@ Object { }, "name": "sourceTest", }, + Object { + "id": "_id", + "meta": Object { + "field": "_id", + "index": undefined, + "params": undefined, + "type": "string", + }, + "name": "_id", + }, + Object { + "id": "_index", + "meta": Object { + "field": "_index", + "index": undefined, + "params": undefined, + "type": "string", + }, + "name": "_index", + }, + Object { + "id": "_score", + "meta": Object { + "field": "_score", + "index": undefined, + "params": undefined, + "type": "number", + }, + "name": "_score", + }, + Object { + "id": "_type", + "meta": Object { + "field": "_type", + "index": undefined, + "params": undefined, + "type": "string", + }, + "name": "_type", + }, ], "rows": Array [ Object { + "_id": "hit-id-value", + "_index": "hit-index-value", + "_score": 77, + "_type": "hit-type-value", "fieldTest": 123, "invalidMapping": 345, "nested": Array [ diff --git a/src/plugins/data/common/search/tabify/tabify_docs.test.ts b/src/plugins/data/common/search/tabify/tabify_docs.test.ts index c81e39f4c156a..52e12aeee1ae6 100644 --- a/src/plugins/data/common/search/tabify/tabify_docs.test.ts +++ b/src/plugins/data/common/search/tabify/tabify_docs.test.ts @@ -37,6 +37,10 @@ describe('tabifyDocs', () => { hits: { hits: [ { + _id: 'hit-id-value', + _index: 'hit-index-value', + _type: 'hit-type-value', + _score: 77, _source: { sourceTest: 123 }, fields: { fieldTest: 123, invalidMapping: 345, nested: [{ field: 123 }] }, }, @@ -59,6 +63,11 @@ describe('tabifyDocs', () => { expect(table).toMatchSnapshot(); }); + it('combines meta fields if meta option is set', () => { + const table = tabifyDocs(response, index, { meta: true }); + expect(table).toMatchSnapshot(); + }); + it('works without provided index pattern', () => { const table = tabifyDocs(response); expect(table).toMatchSnapshot(); diff --git a/src/plugins/data/common/search/tabify/tabify_docs.ts b/src/plugins/data/common/search/tabify/tabify_docs.ts index eaf43d9fd6ff6..b4806283e63f2 100644 --- a/src/plugins/data/common/search/tabify/tabify_docs.ts +++ b/src/plugins/data/common/search/tabify/tabify_docs.ts @@ -11,6 +11,12 @@ import { isPlainObject } from 'lodash'; import { IndexPattern } from '../../index_patterns/index_patterns'; import { Datatable, DatatableColumn, DatatableColumnType } from '../../../../expressions/common'; +export interface TabifyDocsOptions { + shallow?: boolean; + source?: boolean; + meta?: boolean; +} + export function flattenHit( hit: SearchResponse['hits']['hits'][0], indexPattern?: IndexPattern, @@ -56,12 +62,13 @@ export function flattenHit( if (params?.source !== false && hit._source) { flatten(hit._source as Record); } - return flat; -} + if (params?.meta !== false) { + // combine the fields that Discover allows to add as columns + const { _id, _index, _type, _score } = hit; + flatten({ _id, _index, _score, _type }); + } -export interface TabifyDocsOptions { - shallow?: boolean; - source?: boolean; + return flat; } export const tabifyDocs = ( diff --git a/src/plugins/data/server/search/search_service.test.ts b/src/plugins/data/server/search/search_service.test.ts index d6589e88085a0..192c133c94a04 100644 --- a/src/plugins/data/server/search/search_service.test.ts +++ b/src/plugins/data/server/search/search_service.test.ts @@ -7,7 +7,7 @@ */ import type { MockedKeys } from '@kbn/utility-types/jest'; -import { CoreSetup, CoreStart } from '../../../../core/server'; +import { CoreSetup, CoreStart, SavedObject } from '../../../../core/server'; import { coreMock } from '../../../../core/server/mocks'; import { DataPluginStart } from '../plugin'; @@ -86,13 +86,22 @@ describe('Search service', () => { describe('asScopedProvider', () => { let mockScopedClient: IScopedSearchClient; let searcPluginStart: ISearchStart>; - let mockStrategy: jest.Mocked; + let mockStrategy: any; + let mockStrategyNoCancel: jest.Mocked; let mockSessionService: ISearchSessionService; let mockSessionClient: jest.Mocked; const sessionId = '1234'; beforeEach(() => { - mockStrategy = { search: jest.fn().mockReturnValue(of({})) }; + mockStrategy = { + search: jest.fn().mockReturnValue(of({})), + cancel: jest.fn(), + extend: jest.fn(), + }; + + mockStrategyNoCancel = { + search: jest.fn().mockReturnValue(of({})), + }; mockSessionClient = createSearchSessionsClientMock(); mockSessionService = { @@ -104,6 +113,7 @@ describe('Search service', () => { expressions: expressionsPluginMock.createSetupContract(), }); pluginSetup.registerSearchStrategy('es', mockStrategy); + pluginSetup.registerSearchStrategy('nocancel', mockStrategyNoCancel); pluginSetup.__enhance({ defaultStrategy: 'es', sessionService: mockSessionService, @@ -123,7 +133,7 @@ describe('Search service', () => { it('searches using the original request if not restoring, trackId is not called if there is no id in the response', async () => { const searchRequest = { params: {} }; const options = { sessionId, isStored: false, isRestore: false }; - mockSessionClient.trackId = jest.fn(); + mockSessionClient.trackId = jest.fn().mockResolvedValue(undefined); mockStrategy.search.mockReturnValue( of({ @@ -165,10 +175,27 @@ describe('Search service', () => { expect(request).toStrictEqual({ ...searchRequest, id: 'my_id' }); }); + it('does not fail if `trackId` throws', async () => { + const searchRequest = { params: {} }; + const options = { sessionId, isStored: false, isRestore: false }; + mockSessionClient.trackId = jest.fn().mockRejectedValue(undefined); + + mockStrategy.search.mockReturnValue( + of({ + id: 'my_id', + rawResponse: {} as any, + }) + ); + + await mockScopedClient.search(searchRequest, options).toPromise(); + + expect(mockSessionClient.trackId).toBeCalledTimes(1); + }); + it('calls `trackId` for every response, if the response contains an `id` and not restoring', async () => { const searchRequest = { params: {} }; const options = { sessionId, isStored: false, isRestore: false }; - mockSessionClient.trackId = jest.fn(); + mockSessionClient.trackId = jest.fn().mockResolvedValue(undefined); mockStrategy.search.mockReturnValue( of( @@ -195,7 +222,7 @@ describe('Search service', () => { const searchRequest = { params: {} }; const options = { sessionId, isStored: true, isRestore: true }; mockSessionClient.getId = jest.fn().mockResolvedValueOnce('my_id'); - mockSessionClient.trackId = jest.fn(); + mockSessionClient.trackId = jest.fn().mockResolvedValue(undefined); await mockScopedClient.search(searchRequest, options).toPromise(); @@ -206,12 +233,258 @@ describe('Search service', () => { const searchRequest = { params: {} }; const options = {}; mockSessionClient.getId = jest.fn().mockResolvedValueOnce('my_id'); - mockSessionClient.trackId = jest.fn(); + mockSessionClient.trackId = jest.fn().mockResolvedValue(undefined); await mockScopedClient.search(searchRequest, options).toPromise(); expect(mockSessionClient.trackId).not.toBeCalled(); }); }); + + describe('cancelSession', () => { + const mockSavedObject: SavedObject = { + id: 'd7170a35-7e2c-48d6-8dec-9a056721b489', + type: 'search-session', + attributes: { + name: 'my_name', + appId: 'my_app_id', + urlGeneratorId: 'my_url_generator_id', + idMapping: {}, + }, + references: [], + }; + + it('cancels a saved object with no search ids', async () => { + mockSessionClient.getSearchIdMapping = jest + .fn() + .mockResolvedValue(new Map()); + mockSessionClient.cancel = jest.fn().mockResolvedValue(mockSavedObject); + const cancelSpy = jest.spyOn(mockScopedClient, 'cancel'); + + await mockScopedClient.cancelSession('123'); + + expect(mockSessionClient.cancel).toHaveBeenCalledTimes(1); + expect(cancelSpy).not.toHaveBeenCalled(); + }); + + it('cancels a saved object and search ids', async () => { + const mockMap = new Map(); + mockMap.set('abc', 'es'); + mockSessionClient.getSearchIdMapping = jest.fn().mockResolvedValue(mockMap); + mockStrategy.cancel = jest.fn(); + mockSessionClient.cancel = jest.fn().mockResolvedValue(mockSavedObject); + + await mockScopedClient.cancelSession('123'); + + expect(mockSessionClient.cancel).toHaveBeenCalledTimes(1); + + const [searchId, options] = mockStrategy.cancel.mock.calls[0]; + expect(mockStrategy.cancel).toHaveBeenCalledTimes(1); + expect(searchId).toBe('abc'); + expect(options).toHaveProperty('strategy', 'es'); + }); + + it('cancels a saved object with some strategies that dont support cancellation, dont throw an error', async () => { + const mockMap = new Map(); + mockMap.set('abc', 'nocancel'); + mockMap.set('def', 'es'); + mockSessionClient.getSearchIdMapping = jest.fn().mockResolvedValue(mockMap); + mockStrategy.cancel = jest.fn(); + mockSessionClient.cancel = jest.fn().mockResolvedValue(mockSavedObject); + + await mockScopedClient.cancelSession('123'); + + expect(mockSessionClient.cancel).toHaveBeenCalledTimes(1); + + const [searchId, options] = mockStrategy.cancel.mock.calls[0]; + expect(mockStrategy.cancel).toHaveBeenCalledTimes(1); + expect(searchId).toBe('def'); + expect(options).toHaveProperty('strategy', 'es'); + }); + + it('cancels a saved object with some strategies that dont exist, dont throw an error', async () => { + const mockMap = new Map(); + mockMap.set('abc', 'notsupported'); + mockMap.set('def', 'es'); + mockSessionClient.getSearchIdMapping = jest.fn().mockResolvedValue(mockMap); + mockStrategy.cancel = jest.fn(); + mockSessionClient.cancel = jest.fn().mockResolvedValue(mockSavedObject); + + await mockScopedClient.cancelSession('123'); + + expect(mockSessionClient.cancel).toHaveBeenCalledTimes(1); + + const [searchId, options] = mockStrategy.cancel.mock.calls[0]; + expect(mockStrategy.cancel).toHaveBeenCalledTimes(1); + expect(searchId).toBe('def'); + expect(options).toHaveProperty('strategy', 'es'); + }); + }); + + describe('deleteSession', () => { + const mockSavedObject: SavedObject = { + id: 'd7170a35-7e2c-48d6-8dec-9a056721b489', + type: 'search-session', + attributes: { + name: 'my_name', + appId: 'my_app_id', + urlGeneratorId: 'my_url_generator_id', + idMapping: {}, + }, + references: [], + }; + + it('deletes a saved object with no search ids', async () => { + mockSessionClient.getSearchIdMapping = jest + .fn() + .mockResolvedValue(new Map()); + mockSessionClient.delete = jest.fn().mockResolvedValue(mockSavedObject); + const cancelSpy = jest.spyOn(mockScopedClient, 'cancel'); + + await mockScopedClient.deleteSession('123'); + + expect(mockSessionClient.delete).toHaveBeenCalledTimes(1); + expect(cancelSpy).not.toHaveBeenCalled(); + }); + + it('deletes a saved object and search ids', async () => { + const mockMap = new Map(); + mockMap.set('abc', 'es'); + mockSessionClient.getSearchIdMapping = jest.fn().mockResolvedValue(mockMap); + mockSessionClient.delete = jest.fn().mockResolvedValue(mockSavedObject); + mockStrategy.cancel = jest.fn(); + + await mockScopedClient.deleteSession('123'); + + expect(mockSessionClient.delete).toHaveBeenCalledTimes(1); + + const [searchId, options] = mockStrategy.cancel.mock.calls[0]; + expect(mockStrategy.cancel).toHaveBeenCalledTimes(1); + expect(searchId).toBe('abc'); + expect(options).toHaveProperty('strategy', 'es'); + }); + + it('deletes a saved object with some strategies that dont support cancellation, dont throw an error', async () => { + const mockMap = new Map(); + mockMap.set('abc', 'nocancel'); + mockMap.set('def', 'es'); + mockSessionClient.getSearchIdMapping = jest.fn().mockResolvedValue(mockMap); + mockSessionClient.delete = jest.fn().mockResolvedValue(mockSavedObject); + mockStrategy.cancel = jest.fn(); + + await mockScopedClient.deleteSession('123'); + + expect(mockSessionClient.delete).toHaveBeenCalledTimes(1); + + const [searchId, options] = mockStrategy.cancel.mock.calls[0]; + expect(mockStrategy.cancel).toHaveBeenCalledTimes(1); + expect(searchId).toBe('def'); + expect(options).toHaveProperty('strategy', 'es'); + }); + + it('deletes a saved object with some strategies that dont exist, dont throw an error', async () => { + const mockMap = new Map(); + mockMap.set('abc', 'notsupported'); + mockMap.set('def', 'es'); + mockSessionClient.getSearchIdMapping = jest.fn().mockResolvedValue(mockMap); + mockStrategy.cancel = jest.fn(); + mockSessionClient.delete = jest.fn().mockResolvedValue(mockSavedObject); + + await mockScopedClient.deleteSession('123'); + + expect(mockSessionClient.delete).toHaveBeenCalledTimes(1); + + const [searchId, options] = mockStrategy.cancel.mock.calls[0]; + expect(mockStrategy.cancel).toHaveBeenCalledTimes(1); + expect(searchId).toBe('def'); + expect(options).toHaveProperty('strategy', 'es'); + }); + }); + + describe('extendSession', () => { + const mockSavedObject: SavedObject = { + id: 'd7170a35-7e2c-48d6-8dec-9a056721b489', + type: 'search-session', + attributes: { + name: 'my_name', + appId: 'my_app_id', + urlGeneratorId: 'my_url_generator_id', + idMapping: {}, + }, + references: [], + }; + + it('extends a saved object with no search ids', async () => { + mockSessionClient.getSearchIdMapping = jest + .fn() + .mockResolvedValue(new Map()); + mockSessionClient.extend = jest.fn().mockResolvedValue(mockSavedObject); + mockStrategy.extend = jest.fn(); + + await mockScopedClient.extendSession('123', new Date('2020-01-01')); + + expect(mockSessionClient.extend).toHaveBeenCalledTimes(1); + expect(mockStrategy.extend).not.toHaveBeenCalled(); + }); + + it('extends a saved object and search ids', async () => { + const mockMap = new Map(); + mockMap.set('abc', 'es'); + mockSessionClient.getSearchIdMapping = jest.fn().mockResolvedValue(mockMap); + mockSessionClient.extend = jest.fn().mockResolvedValue(mockSavedObject); + mockStrategy.extend = jest.fn(); + + await mockScopedClient.extendSession('123', new Date('2020-01-01')); + + expect(mockSessionClient.extend).toHaveBeenCalledTimes(1); + expect(mockStrategy.extend).toHaveBeenCalledTimes(1); + const [searchId, keepAlive, options] = mockStrategy.extend.mock.calls[0]; + expect(searchId).toBe('abc'); + expect(keepAlive).toContain('ms'); + expect(options).toHaveProperty('strategy', 'es'); + }); + + it('doesnt extend the saved object with some strategies that dont support cancellation, throws an error', async () => { + const mockMap = new Map(); + mockMap.set('abc', 'nocancel'); + mockMap.set('def', 'es'); + mockSessionClient.getSearchIdMapping = jest.fn().mockResolvedValue(mockMap); + mockSessionClient.extend = jest.fn().mockResolvedValue(mockSavedObject); + mockStrategy.extend = jest.fn().mockResolvedValue({}); + + const extendRes = mockScopedClient.extendSession('123', new Date('2020-01-01')); + + await expect(extendRes).rejects.toThrowError( + 'Failed to extend the expiration of some searches' + ); + + expect(mockSessionClient.extend).not.toHaveBeenCalled(); + const [searchId, keepAlive, options] = mockStrategy.extend.mock.calls[0]; + expect(searchId).toBe('def'); + expect(keepAlive).toContain('ms'); + expect(options).toHaveProperty('strategy', 'es'); + }); + + it('doesnt extend the saved object with some strategies that dont exist, throws an error', async () => { + const mockMap = new Map(); + mockMap.set('abc', 'notsupported'); + mockMap.set('def', 'es'); + mockSessionClient.getSearchIdMapping = jest.fn().mockResolvedValue(mockMap); + mockSessionClient.extend = jest.fn().mockResolvedValue(mockSavedObject); + mockStrategy.extend = jest.fn().mockResolvedValue({}); + + const extendRes = mockScopedClient.extendSession('123', new Date('2020-01-01')); + + await expect(extendRes).rejects.toThrowError( + 'Failed to extend the expiration of some searches' + ); + + expect(mockSessionClient.extend).not.toHaveBeenCalled(); + const [searchId, keepAlive, options] = mockStrategy.extend.mock.calls[0]; + expect(searchId).toBe('def'); + expect(keepAlive).toContain('ms'); + expect(options).toHaveProperty('strategy', 'es'); + }); + }); }); }); diff --git a/src/plugins/data/server/search/search_service.ts b/src/plugins/data/server/search/search_service.ts index ce0771a1e9df8..6ece8ff945468 100644 --- a/src/plugins/data/server/search/search_service.ts +++ b/src/plugins/data/server/search/search_service.ts @@ -275,7 +275,10 @@ export class SearchService implements Plugin { switchMap((searchRequest) => strategy.search(searchRequest, options, deps)), tap((response) => { if (!options.sessionId || !response.id || options.isRestore) return; - deps.searchSessionsClient.trackId(request, response.id, options); + // intentionally swallow tracking error, as it shouldn't fail the search + deps.searchSessionsClient.trackId(request, response.id, options).catch((trackErr) => { + this.logger.error(trackErr); + }); }) ); } catch (e) { @@ -283,7 +286,11 @@ export class SearchService implements Plugin { } }; - private cancel = (deps: SearchStrategyDependencies, id: string, options: ISearchOptions = {}) => { + private cancel = async ( + deps: SearchStrategyDependencies, + id: string, + options: ISearchOptions = {} + ) => { const strategy = this.getSearchStrategy(options.strategy); if (!strategy.cancel) { throw new KbnServerError( @@ -294,7 +301,7 @@ export class SearchService implements Plugin { return strategy.cancel(id, options, deps); }; - private extend = ( + private extend = async ( deps: SearchStrategyDependencies, id: string, keepAlive: string, @@ -309,25 +316,26 @@ export class SearchService implements Plugin { private cancelSessionSearches = async (deps: SearchStrategyDependencies, sessionId: string) => { const searchIdMapping = await deps.searchSessionsClient.getSearchIdMapping(sessionId); - - for (const [searchId, strategyName] of searchIdMapping.entries()) { - const searchOptions = { - sessionId, - strategy: strategyName, - isStored: true, - }; - this.cancel(deps, searchId, searchOptions); - } + await Promise.allSettled( + Array.from(searchIdMapping).map(([searchId, strategyName]) => { + const searchOptions = { + sessionId, + strategy: strategyName, + isStored: true, + }; + return this.cancel(deps, searchId, searchOptions); + }) + ); }; private cancelSession = async (deps: SearchStrategyDependencies, sessionId: string) => { const response = await deps.searchSessionsClient.cancel(sessionId); - this.cancelSessionSearches(deps, sessionId); + await this.cancelSessionSearches(deps, sessionId); return response; }; private deleteSession = async (deps: SearchStrategyDependencies, sessionId: string) => { - this.cancelSessionSearches(deps, sessionId); + await this.cancelSessionSearches(deps, sessionId); return deps.searchSessionsClient.delete(sessionId); }; @@ -339,13 +347,19 @@ export class SearchService implements Plugin { const searchIdMapping = await deps.searchSessionsClient.getSearchIdMapping(sessionId); const keepAlive = `${moment(expires).diff(moment())}ms`; - for (const [searchId, strategyName] of searchIdMapping.entries()) { - const searchOptions = { - sessionId, - strategy: strategyName, - isStored: true, - }; - await this.extend(deps, searchId, keepAlive, searchOptions); + const result = await Promise.allSettled( + Array.from(searchIdMapping).map(([searchId, strategyName]) => { + const searchOptions = { + sessionId, + strategy: strategyName, + isStored: true, + }; + return this.extend(deps, searchId, keepAlive, searchOptions); + }) + ); + + if (result.some((extRes) => extRes.status === 'rejected')) { + throw new Error('Failed to extend the expiration of some searches'); } return deps.searchSessionsClient.extend(sessionId, expires); diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/math.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/math.test.js index 5376abbc1a088..1e30720d6e5b2 100644 --- a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/math.test.js +++ b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/math.test.js @@ -134,9 +134,7 @@ describe('math(resp, panel, series)', () => { series )(await mathAgg(resp, panel, series)((results) => results))([]); } catch (e) { - expect(e.message).toEqual( - 'Failed to parse expression. Expected "*", "+", "-", "/", or end of input but "(" found.' - ); + expect(e.message).toEqual('No such function: notExistingFn'); } }); diff --git a/test/api_integration/services/supertest.ts b/test/api_integration/services/supertest.ts index 1257a934da8be..a0268b78cb151 100644 --- a/test/api_integration/services/supertest.ts +++ b/test/api_integration/services/supertest.ts @@ -19,6 +19,14 @@ export function KibanaSupertestProvider({ getService }: FtrProviderContext) { export function ElasticsearchSupertestProvider({ getService }: FtrProviderContext) { const config = getService('config'); - const elasticSearchServerUrl = formatUrl(config.get('servers.elasticsearch')); - return supertestAsPromised(elasticSearchServerUrl); + const esServerConfig = config.get('servers.elasticsearch'); + const elasticSearchServerUrl = formatUrl(esServerConfig); + + let agentOptions = {}; + if ('certificateAuthorities' in esServerConfig) { + agentOptions = { ca: esServerConfig!.certificateAuthorities }; + } + + // @ts-ignore - supertestAsPromised doesn't like the agentOptions, but still passes it correctly to supertest + return supertestAsPromised.agent(elasticSearchServerUrl, agentOptions); } diff --git a/test/scripts/jenkins_unit.sh b/test/scripts/jenkins_unit.sh index 6e28f9c3ef56a..9e387f97a016e 100755 --- a/test/scripts/jenkins_unit.sh +++ b/test/scripts/jenkins_unit.sh @@ -2,12 +2,6 @@ source test/scripts/jenkins_test_setup.sh -rename_coverage_file() { - test -f target/kibana-coverage/jest/coverage-final.json \ - && mv target/kibana-coverage/jest/coverage-final.json \ - target/kibana-coverage/jest/$1-coverage-final.json -} - if [[ -z "$CODE_COVERAGE" ]] ; then # Lint ./test/scripts/lint/eslint.sh @@ -34,13 +28,8 @@ if [[ -z "$CODE_COVERAGE" ]] ; then ./test/scripts/checks/test_hardening.sh else echo " -> Running jest tests with coverage" - node scripts/jest --ci --verbose --coverage --config jest.config.oss.js || true; - rename_coverage_file "oss" - echo "" - echo "" + node scripts/jest --ci --verbose --maxWorkers=6 --coverage || true; + echo " -> Running jest integration tests with coverage" - node --max-old-space-size=8192 scripts/jest_integration --ci --verbose --coverage || true; - rename_coverage_file "oss-integration" - echo "" - echo "" + node scripts/jest_integration --ci --verbose --coverage || true; fi diff --git a/test/scripts/jenkins_xpack.sh b/test/scripts/jenkins_xpack.sh deleted file mode 100755 index 66fb5ae5370bc..0000000000000 --- a/test/scripts/jenkins_xpack.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env bash - -source test/scripts/jenkins_test_setup.sh - -if [[ -z "$CODE_COVERAGE" ]] ; then - echo " -> Running jest tests" - - ./test/scripts/test/xpack_jest_unit.sh -else - echo " -> Build runtime for canvas" - # build runtime for canvas - echo "NODE_ENV=$NODE_ENV" - node ./x-pack/plugins/canvas/scripts/shareable_runtime - echo " -> Running jest tests with coverage" - cd x-pack - node --max-old-space-size=6144 scripts/jest --ci --verbose --maxWorkers=5 --coverage --config jest.config.js || true; - # 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 \ - ../target/kibana-coverage/jest/xpack-coverage-final.json - echo "" - echo "" -fi diff --git a/test/scripts/test/jest_unit.sh b/test/scripts/test/jest_unit.sh index 88c0fe528b88c..1442a0f728727 100755 --- a/test/scripts/test/jest_unit.sh +++ b/test/scripts/test/jest_unit.sh @@ -2,5 +2,7 @@ source src/dev/ci_setup/setup_env.sh +export NODE_OPTIONS="--max-old-space-size=2048" + checks-reporter-with-killswitch "Jest Unit Tests" \ - node scripts/jest --config jest.config.oss.js --ci --verbose --maxWorkers=5 + node scripts/jest --ci --verbose --maxWorkers=8 diff --git a/test/scripts/test/xpack_jest_unit.sh b/test/scripts/test/xpack_jest_unit.sh deleted file mode 100755 index 33b1c8a2b5183..0000000000000 --- a/test/scripts/test/xpack_jest_unit.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env bash - -source src/dev/ci_setup/setup_env.sh - -checks-reporter-with-killswitch "X-Pack Jest" \ - node scripts/jest x-pack --ci --verbose --maxWorkers=5 diff --git a/tsconfig.refs.json b/tsconfig.refs.json index 17b1fc5dc1fe9..d5482a85856fe 100644 --- a/tsconfig.refs.json +++ b/tsconfig.refs.json @@ -55,5 +55,60 @@ { "path": "./src/plugins/visualizations/tsconfig.json" }, { "path": "./src/plugins/visualize/tsconfig.json" }, { "path": "./src/plugins/index_pattern_management/tsconfig.json" }, + { "path": "./x-pack/plugins/actions/tsconfig.json" }, + { "path": "./x-pack/plugins/alerts/tsconfig.json" }, + { "path": "./x-pack/plugins/beats_management/tsconfig.json" }, + { "path": "./x-pack/plugins/canvas/tsconfig.json" }, + { "path": "./x-pack/plugins/cloud/tsconfig.json" }, + { "path": "./x-pack/plugins/code/tsconfig.json" }, + { "path": "./x-pack/plugins/console_extensions/tsconfig.json" }, + { "path": "./x-pack/plugins/dashboard_enhanced/tsconfig.json" }, + { "path": "./x-pack/plugins/data_enhanced/tsconfig.json" }, + { "path": "./x-pack/plugins/dashboard_mode/tsconfig.json" }, + { "path": "./x-pack/plugins/discover_enhanced/tsconfig.json" }, + { "path": "./x-pack/plugins/embeddable_enhanced/tsconfig.json" }, + { "path": "./x-pack/plugins/encrypted_saved_objects/tsconfig.json" }, + { "path": "./x-pack/plugins/enterprise_search/tsconfig.json" }, + { "path": "./x-pack/plugins/event_log/tsconfig.json" }, + { "path": "./x-pack/plugins/features/tsconfig.json" }, + { "path": "./x-pack/plugins/file_upload/tsconfig.json" }, + { "path": "./x-pack/plugins/fleet/tsconfig.json" }, + { "path": "./x-pack/plugins/global_search_bar/tsconfig.json" }, + { "path": "./x-pack/plugins/global_search_providers/tsconfig.json" }, + { "path": "./x-pack/plugins/global_search/tsconfig.json" }, + { "path": "./x-pack/plugins/graph/tsconfig.json" }, + { "path": "./x-pack/plugins/grokdebugger/tsconfig.json" }, + { "path": "./x-pack/plugins/infra/tsconfig.json" }, + { "path": "./x-pack/plugins/ingest_pipelines/tsconfig.json" }, + { "path": "./x-pack/plugins/lens/tsconfig.json" }, + { "path": "./x-pack/plugins/license_management/tsconfig.json" }, + { "path": "./x-pack/plugins/licensing/tsconfig.json" }, + { "path": "./x-pack/plugins/maps_legacy_licensing/tsconfig.json" }, + { "path": "./x-pack/plugins/maps/tsconfig.json" }, + { "path": "./x-pack/plugins/ml/tsconfig.json" }, + { "path": "./x-pack/plugins/observability/tsconfig.json" }, + { "path": "./x-pack/plugins/painless_lab/tsconfig.json" }, + { "path": "./x-pack/plugins/reporting/tsconfig.json" }, + { "path": "./x-pack/plugins/saved_objects_tagging/tsconfig.json" }, + { "path": "./x-pack/plugins/searchprofiler/tsconfig.json" }, + { "path": "./x-pack/plugins/security/tsconfig.json" }, + { "path": "./x-pack/plugins/snapshot_restore/tsconfig.json" }, + { "path": "./x-pack/plugins/spaces/tsconfig.json" }, + { "path": "./x-pack/plugins/stack_alerts/tsconfig.json" }, + { "path": "./x-pack/plugins/task_manager/tsconfig.json" }, + { "path": "./x-pack/plugins/telemetry_collection_xpack/tsconfig.json" }, + { "path": "./x-pack/plugins/transform/tsconfig.json" }, + { "path": "./x-pack/plugins/translations/tsconfig.json" }, + { "path": "./x-pack/plugins/triggers_actions_ui/tsconfig.json" }, + { "path": "./x-pack/plugins/ui_actions_enhanced/tsconfig.json" }, + { "path": "./x-pack/plugins/upgrade_assistant/tsconfig.json" }, + { "path": "./x-pack/plugins/runtime_fields/tsconfig.json" }, + { "path": "./x-pack/plugins/index_management/tsconfig.json" }, + { "path": "./x-pack/plugins/watcher/tsconfig.json" }, + { "path": "./x-pack/plugins/rollup/tsconfig.json"}, + { "path": "./x-pack/plugins/remote_clusters/tsconfig.json"}, + { "path": "./x-pack/plugins/cross_cluster_replication/tsconfig.json"}, + { "path": "./x-pack/plugins/index_lifecycle_management/tsconfig.json"}, + { "path": "./x-pack/plugins/uptime/tsconfig.json" }, ] } diff --git a/vars/kibanaCoverage.groovy b/vars/kibanaCoverage.groovy index 609d8f78aeb96..e393f3a5d2150 100644 --- a/vars/kibanaCoverage.groovy +++ b/vars/kibanaCoverage.groovy @@ -197,13 +197,6 @@ def ingest(jobName, buildNumber, buildUrl, timestamp, previousSha, teamAssignmen def runTests() { parallel([ 'kibana-intake-agent': workers.intake('kibana-intake', './test/scripts/jenkins_unit.sh'), - 'x-pack-intake-agent': { - withEnv([ - 'NODE_ENV=test' // Needed for jest tests only - ]) { - workers.intake('x-pack-intake', './test/scripts/jenkins_xpack.sh')() - } - }, 'kibana-oss-agent' : workers.functional( 'kibana-oss-tests', { kibanaPipeline.buildOss() }, diff --git a/vars/kibanaPipeline.groovy b/vars/kibanaPipeline.groovy index 17349f6b566dc..5efcea3edb9bb 100644 --- a/vars/kibanaPipeline.groovy +++ b/vars/kibanaPipeline.groovy @@ -186,20 +186,21 @@ def uploadCoverageArtifacts(prefix, pattern) { def withGcsArtifactUpload(workerName, closure) { def uploadPrefix = "kibana-ci-artifacts/jobs/${env.JOB_NAME}/${BUILD_NUMBER}/${workerName}" def ARTIFACT_PATTERNS = [ + 'target/junit/**/*', 'target/kibana-*', - 'target/test-metrics/*', + 'target/kibana-coverage/**/*', 'target/kibana-security-solution/**/*.png', - 'target/junit/**/*', + 'target/test-metrics/*', 'target/test-suites-ci-plan.json', - 'test/**/screenshots/session/*.png', - 'test/**/screenshots/failure/*.png', 'test/**/screenshots/diff/*.png', + 'test/**/screenshots/failure/*.png', + 'test/**/screenshots/session/*.png', 'test/functional/failure_debug/html/*.html', - 'x-pack/test/**/screenshots/session/*.png', - 'x-pack/test/**/screenshots/failure/*.png', 'x-pack/test/**/screenshots/diff/*.png', - 'x-pack/test/functional/failure_debug/html/*.html', + 'x-pack/test/**/screenshots/failure/*.png', + 'x-pack/test/**/screenshots/session/*.png', 'x-pack/test/functional/apps/reporting/reports/session/*.pdf', + 'x-pack/test/functional/failure_debug/html/*.html', ] withEnv([ @@ -462,15 +463,10 @@ def allCiTasks() { } }, jest: { - workers.ci(name: 'jest', size: 'c2-8', ramDisk: true) { + workers.ci(name: 'jest', size: 'n2-standard-16', ramDisk: false) { scriptTask('Jest Unit Tests', 'test/scripts/test/jest_unit.sh')() } }, - xpackJest: { - workers.ci(name: 'xpack-jest', size: 'c2-8', ramDisk: true) { - scriptTask('X-Pack Jest Unit Tests', 'test/scripts/test/xpack_jest_unit.sh')() - } - }, ]) } diff --git a/vars/workers.groovy b/vars/workers.groovy index e1684f7aadb43..5d3328bc8a3c4 100644 --- a/vars/workers.groovy +++ b/vars/workers.groovy @@ -19,8 +19,8 @@ def label(size) { return 'docker && tests-xl-highmem' case 'xxl': return 'docker && tests-xxl && gobld/machineType:custom-64-270336' - case 'c2-8': - return 'docker && linux && immutable && gobld/machineType:c2-standard-8' + case 'n2-standard-16': + return 'docker && linux && immutable && gobld/machineType:n2-standard-16' } error "unknown size '${size}'" diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json index f95c4286b3f26..c09198b3874a1 100644 --- a/x-pack/.i18nrc.json +++ b/x-pack/.i18nrc.json @@ -20,7 +20,7 @@ "xpack.endpoint": "plugins/endpoint", "xpack.enterpriseSearch": "plugins/enterprise_search", "xpack.features": "plugins/features", - "xpack.fileUpload": "plugins/maps_file_upload", + "xpack.fileUpload": "plugins/file_upload", "xpack.globalSearch": ["plugins/global_search"], "xpack.globalSearchBar": ["plugins/global_search_bar"], "xpack.graph": ["plugins/graph"], diff --git a/x-pack/plugins/apm/public/plugin.ts b/x-pack/plugins/apm/public/plugin.ts index f585515f79b0c..a1b3af6a9f943 100644 --- a/x-pack/plugins/apm/public/plugin.ts +++ b/x-pack/plugins/apm/public/plugin.ts @@ -162,7 +162,24 @@ export class ApmPlugin implements Plugin { order: 8500, euiIconType: 'logoObservability', category: DEFAULT_APP_CATEGORIES.observability, - + meta: { + keywords: [ + 'RUM', + 'Real User Monitoring', + 'DEM', + 'Digital Experience Monitoring', + 'EUM', + 'End User Monitoring', + 'UX', + 'Javascript', + 'APM', + 'Mobile', + 'digital', + 'performance', + 'web performance', + 'web perf', + ], + }, async mount(params: AppMountParameters) { // Load application bundle and Get start service const [{ renderApp }, [coreStart, corePlugins]] = await Promise.all([ diff --git a/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/index.test.ts b/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/index.test.ts index 741f282b169ed..addd7391d782d 100644 --- a/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/index.test.ts +++ b/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_apm_event_client/index.test.ts @@ -69,10 +69,10 @@ describe('createApmEventClient', () => { incomingRequest.on('abort', () => { setTimeout(() => { resolve(undefined); - }, 0); + }, 100); }); incomingRequest.abort(); - }, 50); + }, 100); }); expect(abort).toHaveBeenCalled(); diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/common/math.ts b/x-pack/plugins/canvas/canvas_plugin_src/functions/common/math.ts index 15ca11c902280..af70fa729b7da 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/functions/common/math.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/functions/common/math.ts @@ -5,7 +5,6 @@ * 2.0. */ -// @ts-expect-error no @typed def; Elastic library import { evaluate } from '@kbn/tinymath'; import { pivotObjectArray } from '../../../common/lib/pivot_object_array'; import { Datatable, isDatatable, ExpressionFunctionDefinition } from '../../../types'; diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/server/get_expression_type.test.js b/x-pack/plugins/canvas/canvas_plugin_src/functions/server/get_expression_type.test.ts similarity index 96% rename from x-pack/plugins/canvas/canvas_plugin_src/functions/server/get_expression_type.test.js rename to x-pack/plugins/canvas/canvas_plugin_src/functions/server/get_expression_type.test.ts index 0345f05efa8ff..81b7517686b1c 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/functions/server/get_expression_type.test.js +++ b/x-pack/plugins/canvas/canvas_plugin_src/functions/server/get_expression_type.test.ts @@ -11,7 +11,7 @@ import { getExpressionType } from './pointseries/lib/get_expression_type'; describe('getExpressionType', () => { it('returns the result type of an evaluated math expression', () => { expect(getExpressionType(testTable.columns, '2')).toBe('number'); - expect(getExpressionType(testTable.colunns, '2 + 3')).toBe('number'); + expect(getExpressionType(testTable.columns, '2 + 3')).toBe('number'); expect(getExpressionType(testTable.columns, 'name')).toBe('string'); expect(getExpressionType(testTable.columns, 'time')).toBe('date'); expect(getExpressionType(testTable.columns, 'price')).toBe('number'); diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/server/get_field_names.test.ts b/x-pack/plugins/canvas/canvas_plugin_src/functions/server/get_field_names.test.ts index 136fbf2ac5d13..dc2b85c7393b4 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/functions/server/get_field_names.test.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/functions/server/get_field_names.test.ts @@ -5,7 +5,6 @@ * 2.0. */ -// @ts-expect-error untyped library import { parse } from '@kbn/tinymath'; import { getFieldNames } from './pointseries/lib/get_field_names'; diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/server/pointseries/index.ts b/x-pack/plugins/canvas/canvas_plugin_src/functions/server/pointseries/index.ts index a88a31388eeeb..38438ffb4ad66 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/functions/server/pointseries/index.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/functions/server/pointseries/index.ts @@ -5,7 +5,6 @@ * 2.0. */ -// @ts-expect-error Untyped Elastic library import { evaluate } from '@kbn/tinymath'; import { groupBy, zipObject, omit, uniqBy } from 'lodash'; import moment from 'moment'; @@ -20,7 +19,6 @@ import { import { pivotObjectArray } from '../../../../common/lib/pivot_object_array'; import { unquoteString } from '../../../../common/lib/unquote_string'; import { isColumnReference } from './lib/is_column_reference'; -// @ts-expect-error untyped local import { getExpressionType } from './lib/get_expression_type'; import { getFunctionHelp, getFunctionErrors } from '../../../../i18n'; @@ -132,16 +130,17 @@ export function pointseries(): ExpressionFunctionDefinition< [PRIMARY_KEY]: i, })); - function normalizeValue(expression: string, value: string) { + function normalizeValue(expression: string, value: number | number[], index: number) { + const numberValue = Array.isArray(value) ? value[index] : value; switch (getExpressionType(input.columns, expression)) { case 'string': - return String(value); + return String(numberValue); case 'number': - return Number(value); + return Number(numberValue); case 'date': - return moment(value).valueOf(); + return moment(numberValue).valueOf(); default: - return value; + return numberValue; } } @@ -153,7 +152,7 @@ export function pointseries(): ExpressionFunctionDefinition< (acc: Record, { name, value }) => { try { acc[name] = args[name] - ? normalizeValue(value, evaluate(value, mathScope)[i]) + ? normalizeValue(value, evaluate(value, mathScope), i) : '_all'; } catch (e) { // TODO: handle invalid column names... diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/server/pointseries/lib/get_expression_type.js b/x-pack/plugins/canvas/canvas_plugin_src/functions/server/pointseries/lib/get_expression_type.ts similarity index 82% rename from x-pack/plugins/canvas/canvas_plugin_src/functions/server/pointseries/lib/get_expression_type.js rename to x-pack/plugins/canvas/canvas_plugin_src/functions/server/pointseries/lib/get_expression_type.ts index 5ed10a084e34f..80ac627747318 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/functions/server/pointseries/lib/get_expression_type.js +++ b/x-pack/plugins/canvas/canvas_plugin_src/functions/server/pointseries/lib/get_expression_type.ts @@ -6,11 +6,12 @@ */ import { parse } from '@kbn/tinymath'; +import { DatatableColumn } from 'src/plugins/expressions/common'; import { getFieldType } from '../../../../../common/lib/get_field_type'; import { isColumnReference } from './is_column_reference'; import { getFieldNames } from './get_field_names'; -export function getExpressionType(columns, mathExpression) { +export function getExpressionType(columns: DatatableColumn[], mathExpression: string) { // if isColumnReference returns true, then mathExpression is just a string // referencing a column in a datatable if (isColumnReference(mathExpression)) { @@ -19,7 +20,7 @@ export function getExpressionType(columns, mathExpression) { const parsedMath = parse(mathExpression); - if (parsedMath.args) { + if (typeof parsedMath !== 'number' && parsedMath.type === 'function') { const fieldNames = parsedMath.args.reduce(getFieldNames, []); if (fieldNames.length > 0) { @@ -30,7 +31,7 @@ export function getExpressionType(columns, mathExpression) { } return types; - }, []); + }, [] as string[]); return fieldTypes.length === 1 ? fieldTypes[0] : 'string'; } diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/server/pointseries/lib/get_field_names.ts b/x-pack/plugins/canvas/canvas_plugin_src/functions/server/pointseries/lib/get_field_names.ts index 5ae27b27c66f2..550705fdddd7f 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/functions/server/pointseries/lib/get_field_names.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/functions/server/pointseries/lib/get_field_names.ts @@ -5,21 +5,19 @@ * 2.0. */ -type Arg = - | string - | number - | { - name: string; - args: Arg[]; - }; +import { TinymathAST } from '@kbn/tinymath'; -export function getFieldNames(names: string[], arg: Arg): string[] { - if (typeof arg === 'object' && arg.args !== undefined) { - return names.concat(arg.args.reduce(getFieldNames, [])); +export function getFieldNames(names: string[], ast: TinymathAST): string[] { + if (typeof ast === 'number') { + return names; } - if (typeof arg === 'string') { - return names.concat(arg); + if (ast.type === 'function') { + return names.concat(ast.args.reduce(getFieldNames, [])); + } + + if (ast.type === 'variable') { + return names.concat(ast.value); } return names; diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/server/pointseries/lib/is_column_reference.ts b/x-pack/plugins/canvas/canvas_plugin_src/functions/server/pointseries/lib/is_column_reference.ts index abcd953a4e123..4b9de8b90cb20 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/functions/server/pointseries/lib/is_column_reference.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/functions/server/pointseries/lib/is_column_reference.ts @@ -5,7 +5,6 @@ * 2.0. */ -// @ts-expect-error untyped library import { parse } from '@kbn/tinymath'; export function isColumnReference(mathExpression: string | null): boolean { @@ -13,5 +12,5 @@ export function isColumnReference(mathExpression: string | null): boolean { mathExpression = 'null'; } const parsedMath = parse(mathExpression); - return typeof parsedMath === 'string'; + return typeof parsedMath !== 'number' && parsedMath.type === 'variable'; } diff --git a/x-pack/plugins/canvas/canvas_plugin_src/uis/arguments/datacolumn/get_form_object.test.js b/x-pack/plugins/canvas/canvas_plugin_src/uis/arguments/datacolumn/get_form_object.test.ts similarity index 100% rename from x-pack/plugins/canvas/canvas_plugin_src/uis/arguments/datacolumn/get_form_object.test.js rename to x-pack/plugins/canvas/canvas_plugin_src/uis/arguments/datacolumn/get_form_object.test.ts diff --git a/x-pack/plugins/canvas/canvas_plugin_src/uis/arguments/datacolumn/get_form_object.js b/x-pack/plugins/canvas/canvas_plugin_src/uis/arguments/datacolumn/get_form_object.ts similarity index 71% rename from x-pack/plugins/canvas/canvas_plugin_src/uis/arguments/datacolumn/get_form_object.js rename to x-pack/plugins/canvas/canvas_plugin_src/uis/arguments/datacolumn/get_form_object.ts index 7e7930f39c9bd..015dca39402b5 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/uis/arguments/datacolumn/get_form_object.js +++ b/x-pack/plugins/canvas/canvas_plugin_src/uis/arguments/datacolumn/get_form_object.ts @@ -9,7 +9,7 @@ import { parse } from '@kbn/tinymath'; import { unquoteString } from '../../../../common/lib/unquote_string'; // break out into separate function, write unit tests first -export function getFormObject(argValue) { +export function getFormObject(argValue: string) { if (argValue === '') { return { fn: '', @@ -20,23 +20,28 @@ export function getFormObject(argValue) { // check if the value is a math expression, and set its type if it is const mathObj = parse(argValue); // A symbol node is a plain string, so we guess that they're looking for a column. - if (typeof mathObj === 'string') { + if (typeof mathObj === 'number') { + throw new Error(`Cannot render scalar values or complex math expressions`); + } + + if (mathObj.type === 'variable') { return { fn: '', - column: unquoteString(argValue), + column: unquoteString(mathObj.value), }; } // Check if its a simple function, eg a function wrapping a symbol node // check for only one arg of type string if ( - typeof mathObj === 'object' && + mathObj.type === 'function' && mathObj.args.length === 1 && - typeof mathObj.args[0] === 'string' + typeof mathObj.args[0] !== 'number' && + mathObj.args[0].type === 'variable' ) { return { fn: mathObj.name, - column: unquoteString(mathObj.args[0]), + column: unquoteString(mathObj.args[0].value), }; } diff --git a/x-pack/plugins/cross_cluster_replication/tsconfig.json b/x-pack/plugins/cross_cluster_replication/tsconfig.json new file mode 100644 index 0000000000000..9c7590b9c2553 --- /dev/null +++ b/x-pack/plugins/cross_cluster_replication/tsconfig.json @@ -0,0 +1,31 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "composite": true, + "outDir": "./target/types", + "emitDeclarationOnly": true, + "declaration": true, + "declarationMap": true + }, + "include": [ + "common/**/*", + "public/**/*", + "server/**/*", + ], + "references": [ + { "path": "../../../src/core/tsconfig.json" }, + // required plugins + { "path": "../../../src/plugins/home/tsconfig.json" }, + { "path": "../licensing/tsconfig.json" }, + { "path": "../../../src/plugins/management/tsconfig.json" }, + { "path": "../remote_clusters/tsconfig.json" }, + { "path": "../index_management/tsconfig.json" }, + { "path": "../features/tsconfig.json" }, + // optional plugins + { "path": "../../../src/plugins/usage_collection/tsconfig.json" }, + // required bundles + { "path": "../../../src/plugins/kibana_react/tsconfig.json" }, + { "path": "../../../src/plugins/es_ui_shared/tsconfig.json" }, + { "path": "../../../src/plugins/data/tsconfig.json" }, + ] +} diff --git a/x-pack/plugins/enterprise_search/public/applications/__mocks__/kea.mock.ts b/x-pack/plugins/enterprise_search/public/applications/__mocks__/kea.mock.ts index f284fef370f02..ecc7b991f0761 100644 --- a/x-pack/plugins/enterprise_search/public/applications/__mocks__/kea.mock.ts +++ b/x-pack/plugins/enterprise_search/public/applications/__mocks__/kea.mock.ts @@ -11,11 +11,11 @@ * NOTE: These variable names MUST start with 'mock*' in order for * Jest to accept its use within a jest.mock() */ +import { mockFlashMessagesValues, mockFlashMessagesActions } from './flash_messages_logic.mock'; +import { mockHttpValues } from './http_logic.mock'; import { mockKibanaValues } from './kibana_logic.mock'; import { mockLicensingValues } from './licensing_logic.mock'; -import { mockHttpValues } from './http_logic.mock'; import { mockTelemetryActions } from './telemetry_logic.mock'; -import { mockFlashMessagesValues, mockFlashMessagesActions } from './flash_messages_logic.mock'; export const mockAllValues = { ...mockKibanaValues, diff --git a/x-pack/plugins/enterprise_search/public/applications/__mocks__/kibana_logic.mock.ts b/x-pack/plugins/enterprise_search/public/applications/__mocks__/kibana_logic.mock.ts index a201a2b56c25c..d8d66e5ee1998 100644 --- a/x-pack/plugins/enterprise_search/public/applications/__mocks__/kibana_logic.mock.ts +++ b/x-pack/plugins/enterprise_search/public/applications/__mocks__/kibana_logic.mock.ts @@ -6,6 +6,7 @@ */ import { chartPluginMock } from '../../../../../../src/plugins/charts/public/mocks'; + import { mockHistory } from './'; export const mockKibanaValues = { diff --git a/x-pack/plugins/enterprise_search/public/applications/__mocks__/mount_async.mock.tsx b/x-pack/plugins/enterprise_search/public/applications/__mocks__/mount_async.mock.tsx index 27e8a1421f462..2b5c06df37e8c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/__mocks__/mount_async.mock.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/__mocks__/mount_async.mock.tsx @@ -6,8 +6,9 @@ */ import React from 'react'; -import { act } from 'react-dom/test-utils'; + import { mount, ReactWrapper } from 'enzyme'; +import { act } from 'react-dom/test-utils'; import { mountWithIntl } from './'; diff --git a/x-pack/plugins/enterprise_search/public/applications/__mocks__/mount_with_i18n.mock.tsx b/x-pack/plugins/enterprise_search/public/applications/__mocks__/mount_with_i18n.mock.tsx index a5a2891d3699c..3a98616082412 100644 --- a/x-pack/plugins/enterprise_search/public/applications/__mocks__/mount_with_i18n.mock.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/__mocks__/mount_with_i18n.mock.tsx @@ -6,7 +6,9 @@ */ import React from 'react'; + import { mount } from 'enzyme'; + import { I18nProvider } from '@kbn/i18n/react'; /** diff --git a/x-pack/plugins/enterprise_search/public/applications/__mocks__/shallow_with_i18n.mock.tsx b/x-pack/plugins/enterprise_search/public/applications/__mocks__/shallow_with_i18n.mock.tsx index 224d71ac579a0..0127804374163 100644 --- a/x-pack/plugins/enterprise_search/public/applications/__mocks__/shallow_with_i18n.mock.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/__mocks__/shallow_with_i18n.mock.tsx @@ -8,6 +8,7 @@ import React from 'react'; import { shallow, mount, ReactWrapper } from 'enzyme'; + import { I18nProvider, __IntlProvider } from '@kbn/i18n/react'; // Use fake component to extract `intl` property to use in tests. diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/app_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/app_logic.test.ts index 86f3993728e06..e5b0a702897bf 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/app_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/app_logic.test.ts @@ -5,9 +5,9 @@ * 2.0. */ +import { DEFAULT_INITIAL_APP_DATA } from '../../../common/__mocks__'; import { LogicMounter } from '../__mocks__'; -import { DEFAULT_INITIAL_APP_DATA } from '../../../common/__mocks__'; import { AppLogic } from './app_logic'; describe('AppLogic', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/app_logic.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/app_logic.ts index 8a55b7c0add94..c33a0e89d2aee 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/app_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/app_logic.ts @@ -8,6 +8,7 @@ import { kea, MakeLogicType } from 'kea'; import { InitialAppData } from '../../../common/types'; + import { ConfiguredLimits, Account, Role } from './types'; import { getRoleAbilities } from './utils/role'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/analytics_layout.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/analytics_layout.test.tsx index 5248833d827b2..1a4e05c04f319 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/analytics_layout.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/analytics_layout.test.tsx @@ -11,14 +11,15 @@ import { mockKibanaValues, setMockValues, setMockActions, rerender } from '../.. import React from 'react'; import { useParams } from 'react-router-dom'; + import { shallow } from 'enzyme'; -import { Loading } from '../../../shared/loading'; import { FlashMessages } from '../../../shared/flash_messages'; +import { Loading } from '../../../shared/loading'; import { LogRetentionCallout } from '../log_retention'; -import { AnalyticsHeader, AnalyticsUnavailable } from './components'; import { AnalyticsLayout } from './analytics_layout'; +import { AnalyticsHeader, AnalyticsUnavailable } from './components'; describe('AnalyticsLayout', () => { const { history } = mockKibanaValues; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/analytics_layout.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/analytics_layout.tsx index 88d0f77541166..0c90267c1dbad 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/analytics_layout.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/analytics_layout.tsx @@ -7,18 +7,21 @@ import React, { useEffect } from 'react'; import { useParams } from 'react-router-dom'; + import { useValues, useActions } from 'kea'; + import { EuiSpacer } from '@elastic/eui'; -import { KibanaLogic } from '../../../shared/kibana'; import { FlashMessages } from '../../../shared/flash_messages'; +import { KibanaLogic } from '../../../shared/kibana'; import { Loading } from '../../../shared/loading'; import { LogRetentionCallout, LogRetentionOptions } from '../log_retention'; -import { AnalyticsLogic } from './'; import { AnalyticsHeader, AnalyticsUnavailable } from './components'; +import { AnalyticsLogic } from './'; + interface Props { title: string; isQueryView?: boolean; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/analytics_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/analytics_logic.test.ts index 6ca9eb23c962b..ad612e48c770a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/analytics_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/analytics_logic.test.ts @@ -19,6 +19,7 @@ jest.mock('../engine', () => ({ import { nextTick } from '@kbn/test/jest'; import { DEFAULT_START_DATE, DEFAULT_END_DATE } from './constants'; + import { AnalyticsLogic } from './'; describe('AnalyticsLogic', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/analytics_logic.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/analytics_logic.ts index e978d2c65398e..de0828f6d71ea 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/analytics_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/analytics_logic.ts @@ -8,9 +8,9 @@ import { kea, MakeLogicType } from 'kea'; import queryString from 'query-string'; -import { KibanaLogic } from '../../../shared/kibana'; -import { HttpLogic } from '../../../shared/http'; import { flashAPIErrors } from '../../../shared/flash_messages'; +import { HttpLogic } from '../../../shared/http'; +import { KibanaLogic } from '../../../shared/kibana'; import { EngineLogic } from '../engine'; import { DEFAULT_START_DATE, DEFAULT_END_DATE } from './constants'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/analytics_router.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/analytics_router.test.tsx index 3f6bf77024c1e..3940151d3b7cd 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/analytics_router.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/analytics_router.test.tsx @@ -8,9 +8,11 @@ import '../../__mocks__/engine_logic.mock'; import React from 'react'; -import { shallow } from 'enzyme'; + import { Route, Switch } from 'react-router-dom'; +import { shallow } from 'enzyme'; + import { AnalyticsRouter } from './'; describe('AnalyticsRouter', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_cards.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_cards.test.tsx index 84ee392c2419e..8883d0d1ffcbd 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_cards.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_cards.test.tsx @@ -6,7 +6,9 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiStat } from '@elastic/eui'; import { AnalyticsCards } from './'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_cards.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_cards.tsx index 417fa0cc48f65..b08e391f845e6 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_cards.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_cards.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiStat } from '@elastic/eui'; interface Props { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_chart.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_chart.test.tsx index dcea1f81e53eb..51238d62bdac7 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_chart.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_chart.test.tsx @@ -8,7 +8,9 @@ import { mockKibanaValues } from '../../../../__mocks__'; import React from 'react'; + import { shallow } from 'enzyme'; + import { Chart, Settings, LineSeries, Axis } from '@elastic/charts'; import { AnalyticsChart } from './'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_chart.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_chart.tsx index 686cadda02f63..fa33389503beb 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_chart.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_chart.tsx @@ -6,9 +6,11 @@ */ import React from 'react'; + import { useValues } from 'kea'; import moment from 'moment'; + import { Chart, Settings, LineSeries, CurveType, Axis } from '@elastic/charts'; import { KibanaLogic } from '../../../../shared/kibana'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_header.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_header.test.tsx index 3faf2b03097f7..952c4c2517a0e 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_header.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_header.test.tsx @@ -8,13 +8,16 @@ import { setMockValues, mockKibanaValues } from '../../../../__mocks__'; import React, { ReactElement } from 'react'; + import { shallow, ShallowWrapper } from 'enzyme'; import moment, { Moment } from 'moment'; + import { EuiPageHeader, EuiSelect, EuiDatePickerRange, EuiButton } from '@elastic/eui'; import { LogRetentionTooltip } from '../../log_retention'; import { DEFAULT_START_DATE, DEFAULT_END_DATE } from '../constants'; + import { AnalyticsHeader } from './'; describe('AnalyticsHeader', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_header.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_header.tsx index 3986f7859bfd2..8a87a5e8c211c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_header.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_header.tsx @@ -6,12 +6,11 @@ */ import React, { useState } from 'react'; -import { useValues } from 'kea'; -import queryString from 'query-string'; +import { useValues } from 'kea'; import moment from 'moment'; +import queryString from 'query-string'; -import { i18n } from '@kbn/i18n'; import { EuiPageHeader, EuiPageHeaderSection, @@ -23,11 +22,12 @@ import { EuiDatePicker, EuiButton, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { AnalyticsLogic } from '../'; import { KibanaLogic } from '../../../../shared/kibana'; import { LogRetentionTooltip, LogRetentionOptions } from '../../log_retention'; -import { AnalyticsLogic } from '../'; import { DEFAULT_START_DATE, DEFAULT_END_DATE, SERVER_DATE_FORMAT } from '../constants'; import { convertTagsToSelectOptions } from '../utils'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_search.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_search.test.tsx index 4a3bbda5120bc..89fa5b4cc4b73 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_search.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_search.test.tsx @@ -9,7 +9,9 @@ import { mockKibanaValues } from '../../../../__mocks__'; import '../../../__mocks__/engine_logic.mock'; import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiFieldSearch } from '@elastic/eui'; import { AnalyticsSearch } from './'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_search.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_search.tsx index 922e096701e84..4f2b525aaa168 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_search.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_search.tsx @@ -6,10 +6,11 @@ */ import React, { useState } from 'react'; + import { useValues } from 'kea'; -import { i18n } from '@kbn/i18n'; import { EuiFlexGroup, EuiFlexItem, EuiFieldSearch, EuiButton, EuiSpacer } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { KibanaLogic } from '../../../../shared/kibana'; import { ENGINE_ANALYTICS_QUERY_DETAIL_PATH } from '../../../routes'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_section.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_section.test.tsx index 981173e2a915b..56e30e6061173 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_section.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_section.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; import { AnalyticsSection } from './'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/analytics_table.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/analytics_table.test.tsx index 0788edfdda427..2eac65fc21091 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/analytics_table.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/analytics_table.test.tsx @@ -9,6 +9,7 @@ import { mountWithIntl, mockKibanaValues } from '../../../../../__mocks__'; import '../../../../__mocks__/engine_logic.mock'; import React from 'react'; + import { EuiBasicTable, EuiBadge, EuiEmptyPrompt } from '@elastic/eui'; import { AnalyticsTable } from './'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/analytics_table.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/analytics_table.tsx index 8e9853233cbed..a580047f1f635 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/analytics_table.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/analytics_table.tsx @@ -6,10 +6,12 @@ */ import React from 'react'; -import { i18n } from '@kbn/i18n'; + import { EuiBasicTable, EuiBasicTableColumn, EuiEmptyPrompt } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { Query } from '../../types'; + import { TERM_COLUMN_PROPS, TAGS_COLUMN, diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/inline_tags_list.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/inline_tags_list.test.tsx index 9ad2cc32f99c5..9204fa6e75fa7 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/inline_tags_list.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/inline_tags_list.test.tsx @@ -6,7 +6,9 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiBadge, EuiToolTip } from '@elastic/eui'; import { InlineTagsList } from './inline_tags_list'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/inline_tags_list.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/inline_tags_list.tsx index 421ff1eedf278..908b096c80a9e 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/inline_tags_list.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/inline_tags_list.tsx @@ -6,8 +6,9 @@ */ import React from 'react'; -import { i18n } from '@kbn/i18n'; + import { EuiBadgeGroup, EuiBadge, EuiToolTip } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { Query } from '../../types'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/query_clicks_table.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/query_clicks_table.test.tsx index 4396f91136258..cc8f13299c57f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/query_clicks_table.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/query_clicks_table.test.tsx @@ -9,6 +9,7 @@ import { mountWithIntl } from '../../../../../__mocks__'; import '../../../../__mocks__/engine_logic.mock'; import React from 'react'; + import { EuiBasicTable, EuiLink, EuiBadge, EuiEmptyPrompt } from '@elastic/eui'; import { QueryClicksTable } from './'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/query_clicks_table.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/query_clicks_table.tsx index 7c333623df6c0..4a93724ff5245 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/query_clicks_table.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/query_clicks_table.tsx @@ -7,15 +7,16 @@ import React from 'react'; -import { i18n } from '@kbn/i18n'; import { EuiBasicTable, EuiBasicTableColumn, EuiEmptyPrompt } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { EuiLinkTo } from '../../../../../shared/react_router_helpers'; import { ENGINE_DOCUMENT_DETAIL_PATH } from '../../../../routes'; -import { generateEnginePath } from '../../../engine'; import { DOCUMENTS_TITLE } from '../../../documents'; +import { generateEnginePath } from '../../../engine'; import { QueryClick } from '../../types'; + import { FIRST_COLUMN_PROPS, TAGS_COLUMN, COUNT_COLUMN_PROPS } from './shared_columns'; interface Props { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/recent_queries_table.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/recent_queries_table.test.tsx index fdbbd326c47a1..a5a582d3747bc 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/recent_queries_table.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/recent_queries_table.test.tsx @@ -9,6 +9,7 @@ import { mountWithIntl, mockKibanaValues } from '../../../../../__mocks__'; import '../../../../__mocks__/engine_logic.mock'; import React from 'react'; + import { EuiBasicTable, EuiBadge, EuiEmptyPrompt } from '@elastic/eui'; import { RecentQueriesTable } from './'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/recent_queries_table.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/recent_queries_table.tsx index 20e50e633b321..7724ac5c393ec 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/recent_queries_table.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/recent_queries_table.tsx @@ -7,11 +7,12 @@ import React from 'react'; +import { EuiBasicTable, EuiBasicTableColumn, EuiEmptyPrompt } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedDate, FormattedTime } from '@kbn/i18n/react'; -import { EuiBasicTable, EuiBasicTableColumn, EuiEmptyPrompt } from '@elastic/eui'; import { RecentQuery } from '../../types'; + import { TERM_COLUMN_PROPS, TAGS_COLUMN, diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/shared_columns.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/shared_columns.tsx index 0612fac1c07ed..9d8365a2f7af1 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/shared_columns.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/shared_columns.tsx @@ -6,14 +6,15 @@ */ import React from 'react'; + import { i18n } from '@kbn/i18n'; -import { EuiLinkTo } from '../../../../../shared/react_router_helpers'; import { KibanaLogic } from '../../../../../shared/kibana'; +import { EuiLinkTo } from '../../../../../shared/react_router_helpers'; import { ENGINE_ANALYTICS_QUERY_DETAIL_PATH } from '../../../../routes'; import { generateEnginePath } from '../../../engine'; - import { Query, RecentQuery } from '../../types'; + import { InlineTagsList } from './inline_tags_list'; /** diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_unavailable.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_unavailable.test.tsx index ddc0e4636b3ad..e2ff440615dfc 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_unavailable.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_unavailable.test.tsx @@ -6,7 +6,9 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiEmptyPrompt } from '@elastic/eui'; import { FlashMessages } from '../../../../shared/flash_messages'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_unavailable.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_unavailable.tsx index 2ef020d2f4992..388570b32b6d2 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_unavailable.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_unavailable.tsx @@ -6,8 +6,9 @@ */ import React from 'react'; -import { i18n } from '@kbn/i18n'; + import { EuiEmptyPrompt } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { FlashMessages } from '../../../../shared/flash_messages'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/constants.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/constants.ts index a04a9474ce5ae..75001f5bc86d6 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/constants.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/constants.ts @@ -6,6 +6,7 @@ */ import moment from 'moment'; + import { i18n } from '@kbn/i18n'; export const ANALYTICS_TITLE = i18n.translate( diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/utils.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/utils.ts index 2d00c906b2aec..db679b0f387e8 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/utils.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/utils.ts @@ -6,11 +6,12 @@ */ import moment from 'moment'; -import { i18n } from '@kbn/i18n'; + import { EuiSelectProps } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; -import { SERVER_DATE_FORMAT } from './constants'; import { ChartData } from './components/analytics_chart'; +import { SERVER_DATE_FORMAT } from './constants'; interface ConvertToChartData { data: number[]; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/analytics.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/analytics.test.tsx index 065b2208648bf..d8921ff0d3723 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/analytics.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/analytics.test.tsx @@ -9,6 +9,7 @@ import { setMockValues } from '../../../../__mocks__'; import '../../../__mocks__/engine_logic.mock'; import React from 'react'; + import { shallow } from 'enzyme'; import { @@ -18,6 +19,7 @@ import { AnalyticsTable, RecentQueriesTable, } from '../components'; + import { Analytics, ViewAllButton } from './analytics'; describe('Analytics overview', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/analytics.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/analytics.tsx index 09b1ff45c6122..a4f0bc356ac78 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/analytics.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/analytics.tsx @@ -6,10 +6,11 @@ */ import React from 'react'; + import { useValues } from 'kea'; -import { i18n } from '@kbn/i18n'; import { EuiSpacer, EuiTitle } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { EuiButtonTo } from '../../../../shared/react_router_helpers'; import { @@ -21,6 +22,8 @@ import { } from '../../../routes'; import { generateEnginePath } from '../../engine'; +import { AnalyticsLayout } from '../analytics_layout'; +import { AnalyticsSection, AnalyticsTable, RecentQueriesTable } from '../components'; import { ANALYTICS_TITLE, TOTAL_QUERIES, @@ -32,9 +35,7 @@ import { TOP_QUERIES_NO_CLICKS, RECENT_QUERIES, } from '../constants'; -import { AnalyticsLayout } from '../analytics_layout'; -import { AnalyticsSection, AnalyticsTable, RecentQueriesTable } from '../components'; -import { AnalyticsLogic, AnalyticsCards, AnalyticsChart, convertToChartData } from '../'; +import { AnalyticsLogic, AnalyticsCards, AnalyticsChart, convertToChartData } from '../index'; export const Analytics: React.FC = () => { const { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/query_detail.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/query_detail.test.tsx index 050770944edcd..978f11ddfd5cd 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/query_detail.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/query_detail.test.tsx @@ -10,12 +10,14 @@ import { setMockValues } from '../../../../__mocks__'; import React from 'react'; import { useParams } from 'react-router-dom'; + import { shallow } from 'enzyme'; import { SetAppSearchChrome as SetPageChrome } from '../../../../shared/kibana_chrome'; import { AnalyticsLayout } from '../analytics_layout'; import { AnalyticsCards, AnalyticsChart, QueryClicksTable } from '../components'; + import { QueryDetail } from './'; describe('QueryDetail', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/query_detail.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/query_detail.tsx index 96587eb528710..f00c4e29a7190 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/query_detail.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/query_detail.tsx @@ -6,10 +6,11 @@ */ import React from 'react'; + import { useValues } from 'kea'; -import { i18n } from '@kbn/i18n'; import { EuiSpacer } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { SetAppSearchChrome as SetPageChrome } from '../../../../shared/kibana_chrome'; import { BreadcrumbTrail } from '../../../../shared/kibana_chrome/generate_breadcrumbs'; @@ -17,7 +18,7 @@ import { useDecodedParams } from '../../../utils/encode_path_params'; import { AnalyticsLayout } from '../analytics_layout'; import { AnalyticsSection, QueryClicksTable } from '../components'; -import { AnalyticsLogic, AnalyticsCards, AnalyticsChart, convertToChartData } from '../'; +import { AnalyticsLogic, AnalyticsCards, AnalyticsChart, convertToChartData } from '../index'; const QUERY_DETAIL_TITLE = i18n.translate( 'xpack.enterpriseSearch.appSearch.engine.analytics.queryDetail.title', diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/recent_queries.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/recent_queries.test.tsx index 40577fb2d4447..21d515a7b9795 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/recent_queries.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/recent_queries.test.tsx @@ -8,9 +8,11 @@ import { setMockValues } from '../../../../__mocks__'; import React from 'react'; + import { shallow } from 'enzyme'; import { RecentQueriesTable } from '../components'; + import { RecentQueries } from './'; describe('RecentQueries', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/recent_queries.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/recent_queries.tsx index e5380258894ae..bb0c3c4d32244 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/recent_queries.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/recent_queries.tsx @@ -6,12 +6,13 @@ */ import React from 'react'; + import { useValues } from 'kea'; -import { RECENT_QUERIES } from '../constants'; +import { AnalyticsLogic } from '../'; import { AnalyticsLayout } from '../analytics_layout'; import { AnalyticsSearch, RecentQueriesTable } from '../components'; -import { AnalyticsLogic } from '../'; +import { RECENT_QUERIES } from '../constants'; export const RecentQueries: React.FC = () => { const { recentQueries } = useValues(AnalyticsLogic); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/top_queries.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/top_queries.test.tsx index b037e6bf1d64e..46b2b37958435 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/top_queries.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/top_queries.test.tsx @@ -8,9 +8,11 @@ import { setMockValues } from '../../../../__mocks__'; import React from 'react'; + import { shallow } from 'enzyme'; import { AnalyticsTable } from '../components'; + import { TopQueries } from './'; describe('TopQueries', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/top_queries.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/top_queries.tsx index 76d523d16ee11..6459126560b3a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/top_queries.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/top_queries.tsx @@ -6,12 +6,13 @@ */ import React from 'react'; + import { useValues } from 'kea'; -import { TOP_QUERIES } from '../constants'; +import { AnalyticsLogic } from '../'; import { AnalyticsLayout } from '../analytics_layout'; import { AnalyticsSearch, AnalyticsTable } from '../components'; -import { AnalyticsLogic } from '../'; +import { TOP_QUERIES } from '../constants'; export const TopQueries: React.FC = () => { const { topQueries } = useValues(AnalyticsLogic); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/top_queries_no_clicks.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/top_queries_no_clicks.test.tsx index 1248a49fc5a9c..83212160d1350 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/top_queries_no_clicks.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/top_queries_no_clicks.test.tsx @@ -8,9 +8,11 @@ import { setMockValues } from '../../../../__mocks__'; import React from 'react'; + import { shallow } from 'enzyme'; import { AnalyticsTable } from '../components'; + import { TopQueriesNoClicks } from './'; describe('TopQueriesNoClicks', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/top_queries_no_clicks.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/top_queries_no_clicks.tsx index 604ab96b871e7..8e2591697feaa 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/top_queries_no_clicks.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/top_queries_no_clicks.tsx @@ -6,12 +6,13 @@ */ import React from 'react'; + import { useValues } from 'kea'; -import { TOP_QUERIES_NO_CLICKS } from '../constants'; +import { AnalyticsLogic } from '../'; import { AnalyticsLayout } from '../analytics_layout'; import { AnalyticsSearch, AnalyticsTable } from '../components'; -import { AnalyticsLogic } from '../'; +import { TOP_QUERIES_NO_CLICKS } from '../constants'; export const TopQueriesNoClicks: React.FC = () => { const { topQueriesNoClicks } = useValues(AnalyticsLogic); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/top_queries_no_results.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/top_queries_no_results.test.tsx index 3cb77b3c7afbc..dfc5b9c93ab64 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/top_queries_no_results.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/top_queries_no_results.test.tsx @@ -8,9 +8,11 @@ import { setMockValues } from '../../../../__mocks__'; import React from 'react'; + import { shallow } from 'enzyme'; import { AnalyticsTable } from '../components'; + import { TopQueriesNoResults } from './'; describe('TopQueriesNoResults', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/top_queries_no_results.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/top_queries_no_results.tsx index 425fdf8e88559..e093a5130d204 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/top_queries_no_results.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/top_queries_no_results.tsx @@ -6,12 +6,13 @@ */ import React from 'react'; + import { useValues } from 'kea'; -import { TOP_QUERIES_NO_RESULTS } from '../constants'; +import { AnalyticsLogic } from '../'; import { AnalyticsLayout } from '../analytics_layout'; import { AnalyticsSearch, AnalyticsTable } from '../components'; -import { AnalyticsLogic } from '../'; +import { TOP_QUERIES_NO_RESULTS } from '../constants'; export const TopQueriesNoResults: React.FC = () => { const { topQueriesNoResults } = useValues(AnalyticsLogic); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/top_queries_with_clicks.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/top_queries_with_clicks.test.tsx index 83be03e95d2cf..fb967ca06b387 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/top_queries_with_clicks.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/top_queries_with_clicks.test.tsx @@ -8,9 +8,11 @@ import { setMockValues } from '../../../../__mocks__'; import React from 'react'; + import { shallow } from 'enzyme'; import { AnalyticsTable } from '../components'; + import { TopQueriesWithClicks } from './'; describe('TopQueriesWithClicks', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/top_queries_with_clicks.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/top_queries_with_clicks.tsx index bec096019035b..87e276a8382c3 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/top_queries_with_clicks.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/top_queries_with_clicks.tsx @@ -6,12 +6,13 @@ */ import React from 'react'; + import { useValues } from 'kea'; -import { TOP_QUERIES_WITH_CLICKS } from '../constants'; +import { AnalyticsLogic } from '../'; import { AnalyticsLayout } from '../analytics_layout'; import { AnalyticsSearch, AnalyticsTable } from '../components'; -import { AnalyticsLogic } from '../'; +import { TOP_QUERIES_WITH_CLICKS } from '../constants'; export const TopQueriesWithClicks: React.FC = () => { const { topQueriesWithClicks } = useValues(AnalyticsLogic); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/constants.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/constants.ts index 2e28e5a272643..0fb118548a67b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/constants.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/constants.ts @@ -6,6 +6,7 @@ */ import { i18n } from '@kbn/i18n'; + import { DOCS_PREFIX } from '../../routes'; export const CREDENTIALS_TITLE = i18n.translate( diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials.test.tsx index cc783e7c056e2..48fcf4b8c5b66 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials.test.tsx @@ -9,12 +9,15 @@ import { setMockValues, setMockActions } from '../../../__mocks__/kea.mock'; import { unmountHandler } from '../../../__mocks__/shallow_useeffect.mock'; import React from 'react'; + import { shallow } from 'enzyme'; -import { Credentials } from './credentials'; import { EuiCopy, EuiLoadingContent, EuiPageContentBody } from '@elastic/eui'; import { externalUrl } from '../../../shared/enterprise_search_url'; + +import { Credentials } from './credentials'; + import { CredentialsFlyout } from './credentials_flyout'; describe('Credentials', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials.tsx index 0266b64f97104..266e9467c300d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials.tsx @@ -6,6 +6,7 @@ */ import React, { useEffect } from 'react'; + import { useActions, useValues } from 'kea'; import { @@ -24,14 +25,14 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; +import { externalUrl } from '../../../shared/enterprise_search_url/external_url'; import { FlashMessages } from '../../../shared/flash_messages'; +import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; -import { CredentialsLogic } from './credentials_logic'; -import { externalUrl } from '../../../shared/enterprise_search_url/external_url'; import { CREDENTIALS_TITLE } from './constants'; -import { CredentialsList } from './credentials_list'; import { CredentialsFlyout } from './credentials_flyout'; +import { CredentialsList } from './credentials_list'; +import { CredentialsLogic } from './credentials_logic'; export const Credentials: React.FC = () => { const { initializeCredentialsData, resetCredentials, showCredentialsForm } = useActions( diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/body.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/body.test.tsx index 8b5a59b82c19b..595bc1bcbb828 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/body.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/body.test.tsx @@ -8,12 +8,15 @@ import { setMockValues, setMockActions } from '../../../../__mocks__/kea.mock'; import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiFlyoutBody, EuiForm } from '@elastic/eui'; import { ApiTokenTypes } from '../constants'; import { defaultApiToken } from '../credentials_logic'; +import { CredentialsFlyoutBody } from './body'; import { FormKeyName, FormKeyType, @@ -21,7 +24,6 @@ import { FormKeyEngineAccess, FormKeyUpdateWarning, } from './form_components'; -import { CredentialsFlyoutBody } from './body'; describe('CredentialsFlyoutBody', () => { const values = { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/body.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/body.tsx index f3de25fe0a25d..def165f3f82a2 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/body.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/body.tsx @@ -6,12 +6,14 @@ */ import React from 'react'; + import { useValues, useActions } from 'kea'; + import { EuiFlyoutBody, EuiForm } from '@elastic/eui'; import { FlashMessages } from '../../../../shared/flash_messages'; -import { CredentialsLogic } from '../credentials_logic'; import { ApiTokenTypes } from '../constants'; +import { CredentialsLogic } from '../credentials_logic'; import { FormKeyName, diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/footer.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/footer.test.tsx index 036fe881c7d0d..23e85b92bb8b4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/footer.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/footer.test.tsx @@ -8,7 +8,9 @@ import { setMockValues, setMockActions } from '../../../../__mocks__/kea.mock'; import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiFlyoutFooter, EuiButtonEmpty } from '@elastic/eui'; import { CredentialsFlyoutFooter } from './footer'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/footer.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/footer.tsx index dc2d52a073b36..c05bd82c6206e 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/footer.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/footer.tsx @@ -6,7 +6,9 @@ */ import React from 'react'; + import { useValues, useActions } from 'kea'; + import { EuiFlyoutFooter, EuiFlexGroup, diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_engine_access.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_engine_access.test.tsx index 51a737ce8c826..7247deb09f12b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_engine_access.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_engine_access.test.tsx @@ -8,7 +8,9 @@ import { setMockValues, setMockActions, rerender } from '../../../../../__mocks__'; import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiRadio, EuiCheckbox } from '@elastic/eui'; import { FormKeyEngineAccess, EngineSelection } from './key_engine_access'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_engine_access.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_engine_access.tsx index 2a9e8cf153dca..0d6ebfe437927 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_engine_access.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_engine_access.tsx @@ -6,7 +6,9 @@ */ import React from 'react'; + import { useValues, useActions } from 'kea'; + import { EuiFormRow, EuiRadio, diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_name.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_name.test.tsx index 27f95f2ba7cd8..d54d0c89c90cb 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_name.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_name.test.tsx @@ -8,7 +8,9 @@ import { setMockValues, setMockActions } from '../../../../../__mocks__/kea.mock'; import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiFieldText, EuiFormRow } from '@elastic/eui'; import { FormKeyName } from './'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_name.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_name.tsx index cb4dce76dfcc1..f4f4f5f0aaaaa 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_name.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_name.tsx @@ -6,7 +6,9 @@ */ import React from 'react'; + import { useValues, useActions } from 'kea'; + import { EuiFormRow, EuiFieldText } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_read_write_access.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_read_write_access.test.tsx index 8cfa5b3c4571a..cf45576d691cf 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_read_write_access.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_read_write_access.test.tsx @@ -8,7 +8,9 @@ import { setMockValues, setMockActions } from '../../../../../__mocks__/kea.mock'; import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiCheckbox } from '@elastic/eui'; import { FormKeyReadWriteAccess } from './'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_read_write_access.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_read_write_access.tsx index f9653159b4403..0b631089c3984 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_read_write_access.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_read_write_access.tsx @@ -6,7 +6,9 @@ */ import React from 'react'; + import { useValues, useActions } from 'kea'; + import { EuiCheckbox, EuiText, EuiTitle, EuiSpacer, EuiPanel } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_type.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_type.test.tsx index 9cf6c82184579..5de2c7fda53ca 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_type.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_type.test.tsx @@ -8,10 +8,13 @@ import { setMockValues, setMockActions } from '../../../../../__mocks__/kea.mock'; import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiSelect } from '@elastic/eui'; import { ApiTokenTypes, TOKEN_TYPE_INFO } from '../../constants'; + import { FormKeyType } from './'; describe('FormKeyType', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_type.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_type.tsx index a8cc16b3b30e7..60308274fbb76 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_type.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_type.tsx @@ -6,13 +6,15 @@ */ import React from 'react'; + import { useValues, useActions } from 'kea'; + import { EuiFormRow, EuiSelect, EuiText, EuiLink } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { AppLogic } from '../../../../app_logic'; -import { CredentialsLogic } from '../../credentials_logic'; import { TOKEN_TYPE_DESCRIPTION, TOKEN_TYPE_INFO, DOCS_HREF } from '../../constants'; +import { CredentialsLogic } from '../../credentials_logic'; export const FormKeyType: React.FC = () => { const { myRole } = useValues(AppLogic); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_update_warning.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_update_warning.test.tsx index 073c4ec1c92bf..38eec0b371576 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_update_warning.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_update_warning.test.tsx @@ -6,7 +6,9 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiCallOut } from '@elastic/eui'; import { FormKeyUpdateWarning } from './'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_update_warning.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_update_warning.tsx index 87cda9590f5cb..c24eebea9178b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_update_warning.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/form_components/key_update_warning.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { EuiSpacer, EuiCallOut } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/header.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/header.test.tsx index 0772a395dbe71..8ee7f810c1fa5 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/header.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/header.test.tsx @@ -8,7 +8,9 @@ import { setMockValues } from '../../../../__mocks__/kea.mock'; import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiFlyoutHeader } from '@elastic/eui'; import { ApiTokenTypes } from '../constants'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/header.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/header.tsx index a9efcbe371c4f..586ddc5c22b97 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/header.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/header.tsx @@ -6,12 +6,14 @@ */ import React from 'react'; + import { useValues } from 'kea'; + import { EuiFlyoutHeader, EuiTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { CredentialsLogic } from '../credentials_logic'; import { FLYOUT_ARIA_LABEL_ID } from '../constants'; +import { CredentialsLogic } from '../credentials_logic'; export const CredentialsFlyoutHeader: React.FC = () => { const { activeApiToken } = useValues(CredentialsLogic); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/index.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/index.test.tsx index 1f7408857857a..9932b8ca227b0 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/index.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/index.test.tsx @@ -8,7 +8,9 @@ import { setMockActions } from '../../../../__mocks__/kea.mock'; import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiFlyout } from '@elastic/eui'; import { CredentialsFlyout } from './'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/index.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/index.tsx index 1335a3cdeea18..2ee73a6b80b5a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_flyout/index.tsx @@ -6,14 +6,17 @@ */ import React from 'react'; + import { useActions } from 'kea'; + import { EuiPortal, EuiFlyout } from '@elastic/eui'; -import { CredentialsLogic } from '../credentials_logic'; import { FLYOUT_ARIA_LABEL_ID } from '../constants'; -import { CredentialsFlyoutHeader } from './header'; +import { CredentialsLogic } from '../credentials_logic'; + import { CredentialsFlyoutBody } from './body'; import { CredentialsFlyoutFooter } from './footer'; +import { CredentialsFlyoutHeader } from './header'; export const CredentialsFlyout: React.FC = () => { const { hideCredentialsForm } = useActions(CredentialsLogic); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_list/credentials_list.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_list/credentials_list.test.tsx index dd3d8ef8069ba..8c52df30bfc67 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_list/credentials_list.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_list/credentials_list.test.tsx @@ -8,15 +8,18 @@ import { setMockValues, setMockActions } from '../../../../__mocks__/kea.mock'; import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiBasicTable, EuiCopy, EuiEmptyPrompt } from '@elastic/eui'; -import { ApiToken } from '../types'; +import { HiddenText } from '../../../../shared/hidden_text'; import { ApiTokenTypes } from '../constants'; +import { ApiToken } from '../types'; -import { HiddenText } from '../../../../shared/hidden_text'; import { Key } from './key'; -import { CredentialsList } from './credentials_list'; + +import { CredentialsList } from './'; describe('Credentials', () => { const apiToken: ApiToken = { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_list/credentials_list.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_list/credentials_list.tsx index 9d220469347f2..f23479017a680 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_list/credentials_list.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_list/credentials_list.tsx @@ -6,19 +6,21 @@ */ import React, { useMemo } from 'react'; -import { EuiBasicTable, EuiBasicTableColumn, EuiCopy, EuiEmptyPrompt } from '@elastic/eui'; -import { CriteriaWithPagination } from '@elastic/eui/src/components/basic_table/basic_table'; + import { useActions, useValues } from 'kea'; +import { EuiBasicTable, EuiBasicTableColumn, EuiCopy, EuiEmptyPrompt } from '@elastic/eui'; +import { CriteriaWithPagination } from '@elastic/eui/src/components/basic_table/basic_table'; import { i18n } from '@kbn/i18n'; -import { CredentialsLogic } from '../credentials_logic'; -import { Key } from './key'; import { HiddenText } from '../../../../shared/hidden_text'; -import { ApiToken } from '../types'; import { TOKEN_TYPE_DISPLAY_NAMES } from '../constants'; -import { apiTokenSort } from '../utils/api_token_sort'; +import { CredentialsLogic } from '../credentials_logic'; +import { ApiToken } from '../types'; import { getModeDisplayText, getEnginesDisplayText } from '../utils'; +import { apiTokenSort } from '../utils/api_token_sort'; + +import { Key } from './key'; export const CredentialsList: React.FC = () => { const { deleteApiKey, fetchCredentials, showCredentialsForm } = useActions(CredentialsLogic); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_list/key.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_list/key.test.tsx index c18302db9ddfd..5e042319ae613 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_list/key.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_list/key.test.tsx @@ -6,7 +6,9 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiButtonIcon } from '@elastic/eui'; import { Key } from './key'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_list/key.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_list/key.tsx index 940453c83a1fe..ff14379b9aecc 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_list/key.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_list/key.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { EuiButtonIcon } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_logic.test.ts index 005f487772d80..c9d6a43ebbbae 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_logic.test.ts @@ -17,6 +17,7 @@ jest.mock('../../app_logic', () => ({ import { nextTick } from '@kbn/test/jest'; import { AppLogic } from '../../app_logic'; + import { ApiTokenTypes } from './constants'; import { CredentialsLogic } from './credentials_logic'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_logic.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_logic.ts index 25cd1be93836d..ff4600872c589 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials_logic.ts @@ -7,19 +7,19 @@ import { kea, MakeLogicType } from 'kea'; -import { formatApiName } from '../../utils/format_api_name'; -import { ApiTokenTypes, CREATE_MESSAGE, UPDATE_MESSAGE, DELETE_MESSAGE } from './constants'; - -import { HttpLogic } from '../../../shared/http'; +import { Meta } from '../../../../../common/types'; import { clearFlashMessages, setSuccessMessage, flashAPIErrors, } from '../../../shared/flash_messages'; +import { HttpLogic } from '../../../shared/http'; import { AppLogic } from '../../app_logic'; - -import { Meta } from '../../../../../common/types'; import { Engine } from '../../types'; +import { formatApiName } from '../../utils/format_api_name'; + +import { ApiTokenTypes, CREATE_MESSAGE, UPDATE_MESSAGE, DELETE_MESSAGE } from './constants'; + import { ApiToken, CredentialsDetails, TokenReadWrite } from './types'; export const defaultApiToken: ApiToken = { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/types.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/types.ts index ddc81658eed2c..0427d25add49b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/types.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/types.ts @@ -6,6 +6,7 @@ */ import { Engine } from '../../types'; + import { ApiTokenTypes } from './constants'; export interface CredentialsDetails { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/utils/api_token_sort.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/utils/api_token_sort.test.ts index 1f84caa7e1ef7..70277d6cb7f22 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/utils/api_token_sort.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/utils/api_token_sort.test.ts @@ -5,11 +5,12 @@ * 2.0. */ -import { apiTokenSort } from '.'; import { ApiTokenTypes } from '../constants'; import { ApiToken } from '../types'; +import { apiTokenSort } from '.'; + describe('apiTokenSort', () => { const apiToken: ApiToken = { name: '', diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/utils/get_engines_display_text.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/utils/get_engines_display_text.test.tsx index e92957405a524..71d00efa2a868 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/utils/get_engines_display_text.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/utils/get_engines_display_text.test.tsx @@ -6,22 +6,24 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; -import { getEnginesDisplayText } from './get_engines_display_text'; -import { ApiToken } from '../types'; import { ApiTokenTypes } from '../constants'; +import { ApiToken } from '../types'; -const apiToken: ApiToken = { - name: '', - type: ApiTokenTypes.Private, - read: true, - write: true, - access_all_engines: true, - engines: ['engine1', 'engine2', 'engine3'], -}; +import { getEnginesDisplayText } from './get_engines_display_text'; describe('getEnginesDisplayText', () => { + const apiToken: ApiToken = { + name: '', + type: ApiTokenTypes.Private, + read: true, + write: true, + access_all_engines: true, + engines: ['engine1', 'engine2', 'engine3'], + }; + it('returns "--" when the token is an admin token', () => { const wrapper = shallow(
{getEnginesDisplayText({ ...apiToken, type: ApiTokenTypes.Admin })}
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/utils/get_engines_display_text.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/utils/get_engines_display_text.tsx index 34089cacbf180..d3577ec14fec9 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/utils/get_engines_display_text.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/utils/get_engines_display_text.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { ApiTokenTypes, ALL } from '../constants'; import { ApiToken } from '../types'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/api_code_example.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/api_code_example.test.tsx index 7203cf6982086..34afa9d1e39ed 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/api_code_example.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/api_code_example.test.tsx @@ -9,7 +9,9 @@ import '../../../../__mocks__/enterprise_search_url.mock'; import { setMockValues, setMockActions } from '../../../../__mocks__/kea.mock'; import React from 'react'; + import { shallow, ShallowWrapper } from 'enzyme'; + import { EuiCode, EuiCodeBlock, EuiButtonEmpty } from '@elastic/eui'; import { ApiCodeExample, FlyoutHeader, FlyoutBody, FlyoutFooter } from './api_code_example'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/api_code_example.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/api_code_example.tsx index 9167df25f75b5..88e9df5c2bbf5 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/api_code_example.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/api_code_example.tsx @@ -5,12 +5,12 @@ * 2.0. */ -import dedent from 'dedent'; import React from 'react'; + +import dedent from 'dedent'; + import { useValues, useActions } from 'kea'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; import { EuiFlyoutHeader, EuiTitle, @@ -27,18 +27,19 @@ import { EuiFlexGroup, EuiFlexItem, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; import { getEnterpriseSearchUrl } from '../../../../shared/enterprise_search_url'; +import { DOCS_PREFIX } from '../../../routes'; import { EngineLogic } from '../../engine'; import { EngineDetails } from '../../engine/types'; - -import { DOCS_PREFIX } from '../../../routes'; import { DOCUMENTS_API_JSON_EXAMPLE, FLYOUT_ARIA_LABEL_ID, FLYOUT_CANCEL_BUTTON, } from '../constants'; -import { DocumentCreationLogic } from '../'; +import { DocumentCreationLogic } from '../index'; export const ApiCodeExample: React.FC = () => ( <> diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/paste_json_text.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/paste_json_text.test.tsx index c1c0a554b4794..8b5b36094fbc6 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/paste_json_text.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/paste_json_text.test.tsx @@ -8,10 +8,13 @@ import { setMockValues, setMockActions, rerender } from '../../../../__mocks__'; import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiTextArea, EuiButtonEmpty, EuiButton } from '@elastic/eui'; import { Errors } from '../creation_response_components'; + import { PasteJsonText, FlyoutHeader, FlyoutBody, FlyoutFooter } from './paste_json_text'; describe('PasteJsonText', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/paste_json_text.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/paste_json_text.tsx index 377d795413714..2d4a6de26333f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/paste_json_text.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/paste_json_text.tsx @@ -6,9 +6,9 @@ */ import React from 'react'; + import { useValues, useActions } from 'kea'; -import { i18n } from '@kbn/i18n'; import { EuiFlyoutHeader, EuiTitle, @@ -22,12 +22,13 @@ import { EuiSpacer, EuiText, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { AppLogic } from '../../../app_logic'; import { FLYOUT_ARIA_LABEL_ID, FLYOUT_CANCEL_BUTTON, FLYOUT_CONTINUE_BUTTON } from '../constants'; import { Errors } from '../creation_response_components'; -import { DocumentCreationLogic } from '../'; +import { DocumentCreationLogic } from '../index'; import './paste_json_text.scss'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/show_creation_modes.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/show_creation_modes.test.tsx index 2c66ae56dd3ce..739580d039a36 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/show_creation_modes.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/show_creation_modes.test.tsx @@ -8,10 +8,13 @@ import { setMockActions } from '../../../../__mocks__/kea.mock'; import React from 'react'; + import { shallow, ShallowWrapper } from 'enzyme'; + import { EuiButtonEmpty } from '@elastic/eui'; import { DocumentCreationButtons } from '../'; + import { ShowCreationModes } from './'; describe('ShowCreationModes', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/show_creation_modes.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/show_creation_modes.tsx index b67c7689d816f..d46b9acbb63d7 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/show_creation_modes.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/show_creation_modes.tsx @@ -6,9 +6,9 @@ */ import React from 'react'; + import { useActions } from 'kea'; -import { i18n } from '@kbn/i18n'; import { EuiFlyoutHeader, EuiTitle, @@ -16,9 +16,10 @@ import { EuiFlyoutFooter, EuiButtonEmpty, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { FLYOUT_ARIA_LABEL_ID, FLYOUT_CANCEL_BUTTON } from '../constants'; -import { DocumentCreationLogic, DocumentCreationButtons } from '../'; +import { DocumentCreationLogic, DocumentCreationButtons } from '../index'; export const ShowCreationModes: React.FC = () => { const { closeDocumentCreation } = useActions(DocumentCreationLogic); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/upload_json_file.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/upload_json_file.test.tsx index cee76ebe6857e..7dc8952a18688 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/upload_json_file.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/upload_json_file.test.tsx @@ -8,10 +8,13 @@ import { setMockValues, setMockActions, rerender } from '../../../../__mocks__'; import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiFilePicker, EuiButtonEmpty, EuiButton } from '@elastic/eui'; import { Errors } from '../creation_response_components'; + import { UploadJsonFile, FlyoutHeader, FlyoutBody, FlyoutFooter } from './upload_json_file'; describe('UploadJsonFile', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/upload_json_file.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/upload_json_file.tsx index cab79a929f7b9..5d50ae55fcd10 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/upload_json_file.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/upload_json_file.tsx @@ -6,9 +6,9 @@ */ import React from 'react'; + import { useValues, useActions } from 'kea'; -import { i18n } from '@kbn/i18n'; import { EuiFlyoutHeader, EuiTitle, @@ -22,12 +22,13 @@ import { EuiSpacer, EuiText, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { AppLogic } from '../../../app_logic'; import { FLYOUT_ARIA_LABEL_ID, FLYOUT_CANCEL_BUTTON, FLYOUT_CONTINUE_BUTTON } from '../constants'; import { Errors } from '../creation_response_components'; -import { DocumentCreationLogic } from '../'; +import { DocumentCreationLogic } from '../index'; export const UploadJsonFile: React.FC = () => ( <> diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_response_components/errors.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_response_components/errors.test.tsx index 7ac97ae81b6ca..f03989aeaf5a3 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_response_components/errors.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_response_components/errors.test.tsx @@ -8,7 +8,9 @@ import { setMockValues } from '../../../../__mocks__/kea.mock'; import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiCallOut } from '@elastic/eui'; import { Errors } from './'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_response_components/errors.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_response_components/errors.tsx index 618828182e67d..3564d8ad088ee 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_response_components/errors.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_response_components/errors.tsx @@ -6,12 +6,13 @@ */ import React from 'react'; + import { useValues } from 'kea'; import { EuiCallOut } from '@elastic/eui'; import { DOCUMENT_CREATION_ERRORS, DOCUMENT_CREATION_WARNINGS } from '../constants'; -import { DocumentCreationLogic } from '../'; +import { DocumentCreationLogic } from '../index'; export const Errors: React.FC = () => { const { errors, warnings } = useValues(DocumentCreationLogic); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_response_components/summary.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_response_components/summary.test.tsx index 9558d23fa3a77..f53f94322879c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_response_components/summary.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_response_components/summary.test.tsx @@ -8,15 +8,19 @@ import { setMockValues, setMockActions } from '../../../../__mocks__/kea.mock'; import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiFlyoutBody, EuiCallOut, EuiButton } from '@elastic/eui'; +import { FlyoutHeader, FlyoutBody, FlyoutFooter } from './summary'; import { InvalidDocumentsSummary, ValidDocumentsSummary, SchemaFieldsSummary, } from './summary_sections'; -import { Summary, FlyoutHeader, FlyoutBody, FlyoutFooter } from './summary'; + +import { Summary } from './'; describe('Summary', () => { const values = { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_response_components/summary.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_response_components/summary.tsx index 673c6726afb5d..8361afe62e1ca 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_response_components/summary.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_response_components/summary.tsx @@ -6,9 +6,9 @@ */ import React from 'react'; + import { useValues, useActions } from 'kea'; -import { i18n } from '@kbn/i18n'; import { EuiFlyoutHeader, EuiTitle, @@ -19,10 +19,11 @@ import { EuiFlexItem, EuiButton, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { DocumentCreationLogic } from '../'; import { FLYOUT_ARIA_LABEL_ID, FLYOUT_CLOSE_BUTTON, DOCUMENT_CREATION_ERRORS } from '../constants'; import { DocumentCreationStep } from '../types'; -import { DocumentCreationLogic } from '../'; import { InvalidDocumentsSummary, diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_response_components/summary_documents.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_response_components/summary_documents.test.tsx index 0704d465bbac4..cd8209bafed3f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_response_components/summary_documents.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_response_components/summary_documents.test.tsx @@ -6,7 +6,9 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiCodeBlock, EuiCallOut } from '@elastic/eui'; import { ExampleDocumentJson, MoreDocumentsText } from './summary_documents'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_response_components/summary_documents.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_response_components/summary_documents.tsx index be19a7677a1ab..0dad75cb1f98f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_response_components/summary_documents.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_response_components/summary_documents.tsx @@ -7,8 +7,8 @@ import React, { Fragment } from 'react'; -import { i18n } from '@kbn/i18n'; import { EuiCodeBlock, EuiCallOut, EuiTitle, EuiText, EuiSpacer } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; interface ExampleDocumentJsonProps { document: object; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_response_components/summary_section.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_response_components/summary_section.test.tsx index 41028d61c55f2..24fa2766cb15d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_response_components/summary_section.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_response_components/summary_section.test.tsx @@ -6,7 +6,9 @@ */ import React, { ReactElement } from 'react'; + import { shallow } from 'enzyme'; + import { EuiAccordion, EuiIcon } from '@elastic/eui'; import { SummarySectionAccordion, SummarySectionEmpty } from './summary_section'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_response_components/summary_sections.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_response_components/summary_sections.test.tsx index 9ead42f33521f..7eb9f3f46036d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_response_components/summary_sections.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_response_components/summary_sections.test.tsx @@ -8,11 +8,13 @@ import { setMockValues } from '../../../../__mocks__/kea.mock'; import React from 'react'; + import { shallow } from 'enzyme'; import { EuiBadge } from '@elastic/eui'; -import { SummarySectionAccordion, SummarySectionEmpty } from './summary_section'; + import { ExampleDocumentJson, MoreDocumentsText } from './summary_documents'; +import { SummarySectionAccordion, SummarySectionEmpty } from './summary_section'; import { InvalidDocumentsSummary, diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_response_components/summary_sections.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_response_components/summary_sections.tsx index 637188132d6bc..f2e863c2a9983 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_response_components/summary_sections.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_response_components/summary_sections.tsx @@ -6,15 +6,16 @@ */ import React from 'react'; + import { useValues } from 'kea'; -import { i18n } from '@kbn/i18n'; import { EuiFlexGroup, EuiFlexItem, EuiBadge } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { DocumentCreationLogic } from '../'; -import { SummarySectionAccordion, SummarySectionEmpty } from './summary_section'; import { ExampleDocumentJson, MoreDocumentsText } from './summary_documents'; +import { SummarySectionAccordion, SummarySectionEmpty } from './summary_section'; export const InvalidDocumentsSummary: React.FC = () => { const { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/document_creation_buttons.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/document_creation_buttons.test.tsx index 4b90acfbc37a8..7cbcc6b17e047 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/document_creation_buttons.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/document_creation_buttons.test.tsx @@ -9,8 +9,11 @@ import { setMockActions } from '../../../__mocks__/kea.mock'; import '../../__mocks__/engine_logic.mock'; import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiCard } from '@elastic/eui'; + import { EuiCardTo } from '../../../shared/react_router_helpers'; import { DocumentCreationButtons } from './'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/document_creation_buttons.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/document_creation_buttons.tsx index ec9c6615f5b8c..6d3caca87dcc3 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/document_creation_buttons.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/document_creation_buttons.tsx @@ -6,10 +6,9 @@ */ import React from 'react'; + import { useActions } from 'kea'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; import { EuiText, EuiCode, @@ -20,6 +19,8 @@ import { EuiCard, EuiIcon, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; import { EuiCardTo } from '../../../shared/react_router_helpers'; import { DOCS_PREFIX, ENGINE_CRAWLER_PATH } from '../../routes'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/document_creation_flyout.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/document_creation_flyout.test.tsx index 4c5375d78f95f..66995b8d20dfe 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/document_creation_flyout.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/document_creation_flyout.test.tsx @@ -8,7 +8,9 @@ import { setMockValues, setMockActions } from '../../../__mocks__/kea.mock'; import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiFlyout } from '@elastic/eui'; import { @@ -18,9 +20,8 @@ import { UploadJsonFile, } from './creation_mode_components'; import { Summary } from './creation_response_components'; -import { DocumentCreationStep } from './types'; - import { DocumentCreationFlyout, FlyoutContent } from './document_creation_flyout'; +import { DocumentCreationStep } from './types'; describe('DocumentCreationFlyout', () => { const values = { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/document_creation_flyout.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/document_creation_flyout.tsx index 16f805d7e86fd..159f3403d3740 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/document_creation_flyout.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/document_creation_flyout.tsx @@ -6,14 +6,12 @@ */ import React from 'react'; + import { useValues, useActions } from 'kea'; import { EuiPortal, EuiFlyout } from '@elastic/eui'; -import { DocumentCreationLogic } from './'; -import { DocumentCreationStep } from './types'; import { FLYOUT_ARIA_LABEL_ID } from './constants'; - import { ShowCreationModes, ApiCodeExample, @@ -21,6 +19,9 @@ import { UploadJsonFile, } from './creation_mode_components'; import { Summary } from './creation_response_components'; +import { DocumentCreationStep } from './types'; + +import { DocumentCreationLogic } from './'; export const DocumentCreationFlyout: React.FC = () => { const { closeDocumentCreation } = useActions(DocumentCreationLogic); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/document_creation_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/document_creation_logic.test.ts index 63c59343580d3..37d3d1577767f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/document_creation_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/document_creation_logic.test.ts @@ -7,13 +7,9 @@ import { LogicMounter, mockHttpValues } from '../../../__mocks__'; -import { nextTick } from '@kbn/test/jest'; import dedent from 'dedent'; -jest.mock('./utils', () => ({ - readUploadedFileAsText: jest.fn(), -})); -import { readUploadedFileAsText } from './utils'; +import { nextTick } from '@kbn/test/jest'; jest.mock('../engine', () => ({ EngineLogic: { values: { engineName: 'test-engine' } }, @@ -21,6 +17,12 @@ jest.mock('../engine', () => ({ import { DOCUMENTS_API_JSON_EXAMPLE } from './constants'; import { DocumentCreationStep } from './types'; + +jest.mock('./utils', () => ({ + readUploadedFileAsText: jest.fn(), +})); +import { readUploadedFileAsText } from './utils'; + import { DocumentCreationLogic } from './'; describe('DocumentCreationLogic', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/document_creation_logic.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/document_creation_logic.ts index 13d2618bcd31f..a0ef73bbcea21 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/document_creation_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/document_creation_logic.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { kea, MakeLogicType } from 'kea'; import dedent from 'dedent'; +import { kea, MakeLogicType } from 'kea'; import { isPlainObject, chunk, uniq } from 'lodash'; import { HttpLogic } from '../../../shared/http'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/document_creation_button.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/document_creation_button.test.tsx index ab1679c455c6e..82fa9d3c82ce9 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/document_creation_button.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/document_creation_button.test.tsx @@ -8,10 +8,13 @@ import { setMockActions } from '../../../__mocks__/kea.mock'; import React from 'react'; + import { shallow, ShallowWrapper } from 'enzyme'; + import { EuiButton } from '@elastic/eui'; import { DocumentCreationFlyout } from '../document_creation'; + import { DocumentCreationButton } from './document_creation_button'; describe('DocumentCreationButton', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/document_creation_button.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/document_creation_button.tsx index a05005fefa082..687f589d37594 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/document_creation_button.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/document_creation_button.tsx @@ -6,10 +6,11 @@ */ import React from 'react'; + import { useActions } from 'kea'; -import { i18n } from '@kbn/i18n'; import { EuiButton } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { DocumentCreationLogic, DocumentCreationFlyout } from '../document_creation'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/document_detail.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/document_detail.test.tsx index 55613077efdba..ba060b7497270 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/document_detail.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/document_detail.test.tsx @@ -10,14 +10,17 @@ import { setMockValues, setMockActions } from '../../../__mocks__/kea.mock'; import { unmountHandler } from '../../../__mocks__/shallow_useeffect.mock'; import React from 'react'; -import { shallow } from 'enzyme'; import { useParams } from 'react-router-dom'; + +import { shallow } from 'enzyme'; + import { EuiPageContent, EuiBasicTable } from '@elastic/eui'; import { Loading } from '../../../shared/loading'; -import { DocumentDetail } from '.'; import { ResultFieldValue } from '../result'; +import { DocumentDetail } from '.'; + describe('DocumentDetail', () => { const values = { dataLoading: false, diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/document_detail.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/document_detail.tsx index ca6af345de7ed..8f80978c29002 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/document_detail.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/document_detail.tsx @@ -6,9 +6,10 @@ */ import React, { useEffect } from 'react'; -import { useActions, useValues } from 'kea'; import { useParams } from 'react-router-dom'; +import { useActions, useValues } from 'kea'; + import { EuiButton, EuiPageHeader, @@ -21,15 +22,15 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { Loading } from '../../../shared/loading'; -import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; import { FlashMessages } from '../../../shared/flash_messages'; +import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; +import { Loading } from '../../../shared/loading'; import { useDecodedParams } from '../../utils/encode_path_params'; import { ResultFieldValue } from '../result'; +import { DOCUMENTS_TITLE } from './constants'; import { DocumentDetailLogic } from './document_detail_logic'; import { FieldDetails } from './types'; -import { DOCUMENTS_TITLE } from './constants'; const DOCUMENT_DETAIL_TITLE = (documentId: string) => i18n.translate('xpack.enterpriseSearch.appSearch.documentDetail.title', { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/document_detail_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/document_detail_logic.test.ts index ef5ebad3aea13..d2683fac649a0 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/document_detail_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/document_detail_logic.test.ts @@ -15,9 +15,10 @@ import { mockEngineValues } from '../../__mocks__'; import { nextTick } from '@kbn/test/jest'; -import { DocumentDetailLogic } from './document_detail_logic'; import { InternalSchemaTypes } from '../../../shared/types'; +import { DocumentDetailLogic } from './document_detail_logic'; + describe('DocumentDetailLogic', () => { const { mount } = new LogicMounter(DocumentDetailLogic); const { http } = mockHttpValues; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/document_detail_logic.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/document_detail_logic.ts index 8b023fb585f86..17c2c788523d0 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/document_detail_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/document_detail_logic.ts @@ -6,11 +6,12 @@ */ import { kea, MakeLogicType } from 'kea'; + import { i18n } from '@kbn/i18n'; import { flashAPIErrors, setQueuedSuccessMessage } from '../../../shared/flash_messages'; -import { KibanaLogic } from '../../../shared/kibana'; import { HttpLogic } from '../../../shared/http'; +import { KibanaLogic } from '../../../shared/kibana'; import { ENGINE_DOCUMENTS_PATH } from '../../routes'; import { EngineLogic, generateEnginePath } from '../engine'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/documents.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/documents.test.tsx index 43bbc6cc67895..ace76ae55c046 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/documents.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/documents.test.tsx @@ -8,10 +8,12 @@ import { setMockValues } from '../../../__mocks__/kea.mock'; import React from 'react'; + import { shallow } from 'enzyme'; import { DocumentCreationButton } from './document_creation_button'; import { SearchExperience } from './search_experience'; + import { Documents } from '.'; describe('Documents', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/documents.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/documents.tsx index 7223900911512..8c3ae7fd24f6d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/documents.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/documents.tsx @@ -7,16 +7,19 @@ import React from 'react'; -import { EuiPageHeader, EuiPageHeaderSection, EuiTitle, EuiCallOut, EuiSpacer } from '@elastic/eui'; import { useValues } from 'kea'; + +import { EuiPageHeader, EuiPageHeaderSection, EuiTitle, EuiCallOut, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { DocumentCreationButton } from './document_creation_button'; -import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; import { FlashMessages } from '../../../shared/flash_messages'; -import { DOCUMENTS_TITLE } from './constants'; -import { EngineLogic } from '../engine'; +import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; + import { AppLogic } from '../../app_logic'; +import { EngineLogic } from '../engine'; + +import { DOCUMENTS_TITLE } from './constants'; +import { DocumentCreationButton } from './document_creation_button'; import { SearchExperience } from './search_experience'; interface Props { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/build_search_ui_config.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/build_search_ui_config.ts index b9577d9d0f07d..9fac068555db5 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/build_search_ui_config.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/build_search_ui_config.ts @@ -6,6 +6,7 @@ */ import { Schema } from '../../../../shared/types'; + import { Fields } from './types'; export const buildSearchUIConfig = (apiConnector: object, schema: Schema, fields: Fields) => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/build_sort_options.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/build_sort_options.ts index ab3a943ef2f55..54cf2bdd4f257 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/build_sort_options.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/build_sort_options.ts @@ -7,8 +7,8 @@ import { flatten } from 'lodash'; -import { Fields, SortOption, SortDirection } from './types'; import { ASCENDING, DESCENDING } from './constants'; +import { Fields, SortOption, SortDirection } from './types'; const fieldNameToSortOptions = (fieldName: string): SortOption[] => ['asc', 'desc'].map((direction) => ({ diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/customization_callout.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/customization_callout.test.tsx index e62e4521927dc..6ed2d7edc9639 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/customization_callout.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/customization_callout.test.tsx @@ -8,6 +8,7 @@ import React from 'react'; import { shallow, ShallowWrapper } from 'enzyme'; + import { EuiButton } from '@elastic/eui'; import { CustomizationCallout } from './customization_callout'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/customization_callout.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/customization_callout.tsx index 8954549f74651..48a9fcdeaa878 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/customization_callout.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/customization_callout.tsx @@ -6,9 +6,9 @@ */ import React from 'react'; -import { i18n } from '@kbn/i18n'; import { EuiButton, EuiFlexGroup, EuiIcon, EuiSpacer, EuiText } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; interface Props { onClick(): void; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/customization_modal.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/customization_modal.test.tsx index 11e13f4222abb..332c5b822eb6d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/customization_modal.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/customization_modal.test.tsx @@ -8,7 +8,9 @@ import { setMockValues, setMockActions } from '../../../../__mocks__'; import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiButton, EuiButtonEmpty } from '@elastic/eui'; import { CustomizationModal } from './customization_modal'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/customization_modal.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/customization_modal.tsx index 2d3604b2ba279..e05fc10053ff1 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/customization_modal.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/customization_modal.tsx @@ -7,6 +7,8 @@ import React, { useState, useMemo } from 'react'; +import { useValues } from 'kea'; + import { EuiButton, EuiButtonEmpty, @@ -21,7 +23,6 @@ import { EuiOverlayMask, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { useValues } from 'kea'; import { EngineLogic } from '../../engine'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/hooks.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/hooks.test.tsx index aecb4cc154117..028a9af21311f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/hooks.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/hooks.test.tsx @@ -25,8 +25,9 @@ jest.mock('react', () => ({ })); import React from 'react'; -import { act } from 'react-dom/test-utils'; + import { mount, ReactWrapper } from 'enzyme'; +import { act } from 'react-dom/test-utils'; import { useSearchContextState, useSearchContextActions } from './hooks'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/pagination.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/pagination.test.tsx index 5fe47d5942ab8..b55163ca9843a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/pagination.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/pagination.test.tsx @@ -8,6 +8,7 @@ import React from 'react'; import { shallow } from 'enzyme'; + // @ts-expect-error types are not available for this package yet import { Paging, ResultsPerPage } from '@elastic/react-search-ui'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/pagination.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/pagination.tsx index 846671c62de82..d81b056842642 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/pagination.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/pagination.tsx @@ -10,6 +10,7 @@ import React from 'react'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; // @ts-expect-error types are not available for this package yet import { Paging, ResultsPerPage } from '@elastic/react-search-ui'; + import { PagingView, ResultsPerPageView } from './views'; export const Pagination: React.FC<{ 'aria-label': string }> = ({ 'aria-label': ariaLabel }) => ( diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/search_experience.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/search_experience.test.tsx index b0dccf0583e2f..bfa5c8264fece 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/search_experience.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/search_experience.test.tsx @@ -8,21 +8,24 @@ import '../../../../__mocks__/enterprise_search_url.mock'; import { setMockValues } from '../../../../__mocks__'; +import React from 'react'; + +import { shallow, ShallowWrapper } from 'enzyme'; + +// @ts-expect-error types are not available for this package yet +import { SearchProvider, Facet } from '@elastic/react-search-ui'; + jest.mock('../../../../shared/use_local_storage', () => ({ useLocalStorage: jest.fn(), })); import { useLocalStorage } from '../../../../shared/use_local_storage'; -import React from 'react'; -// @ts-expect-error types are not available for this package yet -import { SearchProvider, Facet } from '@elastic/react-search-ui'; -import { shallow, ShallowWrapper } from 'enzyme'; - import { CustomizationCallout } from './customization_callout'; import { CustomizationModal } from './customization_modal'; + import { Fields } from './types'; -import { SearchExperience } from './search_experience'; +import { SearchExperience } from './'; describe('SearchExperience', () => { const values = { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/search_experience.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/search_experience.tsx index 6ae4f264d7c74..6fbc6305edb25 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/search_experience.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/search_experience.tsx @@ -7,13 +7,14 @@ import React, { useState } from 'react'; -import { i18n } from '@kbn/i18n'; import { useValues } from 'kea'; + import { EuiButton, EuiSpacer, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; // @ts-expect-error types are not available for this package yet; import { SearchProvider, SearchBox, Sorting, Facet } from '@elastic/react-search-ui'; // @ts-expect-error types are not available for this package yet import AppSearchAPIConnector from '@elastic/search-ui-app-search-connector'; +import { i18n } from '@kbn/i18n'; import './search_experience.scss'; @@ -21,14 +22,14 @@ import { externalUrl } from '../../../../shared/enterprise_search_url'; import { useLocalStorage } from '../../../../shared/use_local_storage'; import { EngineLogic } from '../../engine'; -import { Fields, SortOption } from './types'; -import { SearchBoxView, SortingView, MultiCheckboxFacetsView } from './views'; -import { SearchExperienceContent } from './search_experience_content'; import { buildSearchUIConfig } from './build_search_ui_config'; -import { CustomizationCallout } from './customization_callout'; -import { CustomizationModal } from './customization_modal'; import { buildSortOptions } from './build_sort_options'; import { ASCENDING, DESCENDING } from './constants'; +import { CustomizationCallout } from './customization_callout'; +import { CustomizationModal } from './customization_modal'; +import { SearchExperienceContent } from './search_experience_content'; +import { Fields, SortOption } from './types'; +import { SearchBoxView, SortingView, MultiCheckboxFacetsView } from './views'; const RECENTLY_UPLOADED = i18n.translate( 'xpack.enterpriseSearch.appSearch.documents.search.sortBy.option.recentlyUploaded', diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/search_experience_content.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/search_experience_content.test.tsx index 737e3ea1b2999..49f51c2010e3a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/search_experience_content.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/search_experience_content.test.tsx @@ -6,18 +6,20 @@ */ import { setMockValues } from '../../../../__mocks__/kea.mock'; -import { setMockSearchContextState } from './__mocks__/hooks.mock'; import React from 'react'; import { shallow, mount } from 'enzyme'; + // @ts-expect-error types are not available for this package yet import { Results } from '@elastic/react-search-ui'; -import { ResultView } from './views'; -import { Pagination } from './pagination'; import { SchemaTypes } from '../../../../shared/types'; + +import { setMockSearchContextState } from './__mocks__/hooks.mock'; +import { Pagination } from './pagination'; import { SearchExperienceContent } from './search_experience_content'; +import { ResultView } from './views'; describe('SearchExperienceContent', () => { const searchState = { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/search_experience_content.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/search_experience_content.tsx index 45c20d8ffce2c..91db26ac676c9 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/search_experience_content.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/search_experience_content.tsx @@ -7,20 +7,22 @@ import React from 'react'; -import { i18n } from '@kbn/i18n'; +import { useValues } from 'kea'; + import { EuiFlexGroup, EuiSpacer, EuiButton, EuiEmptyPrompt } from '@elastic/eui'; // @ts-expect-error types are not available for this package yet import { Results, Paging, ResultsPerPage } from '@elastic/react-search-ui'; -import { useValues } from 'kea'; +import { i18n } from '@kbn/i18n'; -import { ResultView } from './views'; -import { Pagination } from './pagination'; -import { useSearchContextState } from './hooks'; -import { DocumentCreationButton } from '../document_creation_button'; import { AppLogic } from '../../../app_logic'; -import { EngineLogic } from '../../engine'; import { DOCS_PREFIX } from '../../../routes'; +import { EngineLogic } from '../../engine'; import { Result } from '../../result/types'; +import { DocumentCreationButton } from '../document_creation_button'; + +import { useSearchContextState } from './hooks'; +import { Pagination } from './pagination'; +import { ResultView } from './views'; export const SearchExperienceContent: React.FC = () => { const { resultSearchTerm, totalResults, wasSearched } = useSearchContextState(); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/views/paging_view.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/views/paging_view.test.tsx index 03b9e33f89fef..28cd126e5c004 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/views/paging_view.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/views/paging_view.test.tsx @@ -8,6 +8,7 @@ import React from 'react'; import { shallow } from 'enzyme'; + import { EuiPagination } from '@elastic/eui'; import { PagingView } from './paging_view'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/views/result_view.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/views/result_view.test.tsx index e06603894c288..24685aef71078 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/views/result_view.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/views/result_view.test.tsx @@ -9,10 +9,11 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { ResultView } from '.'; import { SchemaTypes } from '../../../../../shared/types'; import { Result } from '../../../result/result'; +import { ResultView } from '.'; + describe('ResultView', () => { const result = { id: { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/views/result_view.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/views/result_view.tsx index 9dd3fcea5f754..b133780310a4c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/views/result_view.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/views/result_view.tsx @@ -7,9 +7,9 @@ import React from 'react'; -import { Result as ResultType } from '../../../result/types'; import { Schema } from '../../../../../shared/types'; import { Result } from '../../../result/result'; +import { Result as ResultType } from '../../../result/types'; export interface Props { result: ResultType; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/views/results_per_page_view.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/views/results_per_page_view.test.tsx index 70e4d7e4e1878..24db762e26e32 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/views/results_per_page_view.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/views/results_per_page_view.test.tsx @@ -8,6 +8,7 @@ import React from 'react'; import { shallow } from 'enzyme'; + import { EuiSelect } from '@elastic/eui'; import { ResultsPerPageView } from '.'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/views/results_per_page_view.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/views/results_per_page_view.tsx index b57944042e67f..5056d56d1f3d0 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/views/results_per_page_view.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/views/results_per_page_view.tsx @@ -7,8 +7,8 @@ import React from 'react'; -import { i18n } from '@kbn/i18n'; import { EuiSelect, EuiSelectOption } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; const wrapResultsPerPageOptionForEuiSelect: (option: number) => EuiSelectOption = (option) => ({ text: option, diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/views/search_box_view.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/views/search_box_view.test.tsx index 182e2ea222f90..a35fcefb30ac6 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/views/search_box_view.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/views/search_box_view.test.tsx @@ -8,6 +8,7 @@ import React from 'react'; import { shallow } from 'enzyme'; + import { EuiFieldSearch } from '@elastic/eui'; import { SearchBoxView } from './search_box_view'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/views/sorting_view.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/views/sorting_view.test.tsx index 4f7317a2bf5d0..a147f45feef14 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/views/sorting_view.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/views/sorting_view.test.tsx @@ -8,6 +8,7 @@ import React from 'react'; import { shallow } from 'enzyme'; + import { EuiSelect } from '@elastic/eui'; import { SortingView } from '.'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/views/sorting_view.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/views/sorting_view.tsx index 047caf6ca1e3b..e3f21b67a6530 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/views/sorting_view.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/views/sorting_view.tsx @@ -7,8 +7,8 @@ import React from 'react'; -import { i18n } from '@kbn/i18n'; import { EuiSelect, EuiSelectOption } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; interface Option { label: string; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_logic.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_logic.ts index fbe08cbeb939f..664a3006cfa2c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_logic.ts @@ -10,6 +10,7 @@ import { kea, MakeLogicType } from 'kea'; import { HttpLogic } from '../../../shared/http'; import { IIndexingStatus } from '../../../shared/types'; + import { EngineDetails } from './types'; interface EngineValues { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.test.tsx index 8ed36ad5ab006..1781883aa6532 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.test.tsx @@ -9,7 +9,9 @@ import { setMockValues, rerender } from '../../../__mocks__'; import { mockEngineValues } from '../../__mocks__'; import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiBadge, EuiIcon } from '@elastic/eui'; import { EngineNav } from './engine_nav'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.tsx index b1b31c245eb99..447e4d678bcdb 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.tsx @@ -6,11 +6,13 @@ */ import React from 'react'; + import { useValues } from 'kea'; import { EuiText, EuiBadge, EuiIcon, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { getAppSearchUrl } from '../../../shared/enterprise_search_url'; import { SideNavLink, SideNavItem } from '../../../shared/layout'; import { AppLogic } from '../../app_logic'; import { @@ -27,23 +29,23 @@ import { ENGINE_SEARCH_UI_PATH, ENGINE_API_LOGS_PATH, } from '../../routes'; -import { getAppSearchUrl } from '../../../shared/enterprise_search_url'; -import { ENGINES_TITLE } from '../engines'; -import { OVERVIEW_TITLE } from '../engine_overview'; import { ANALYTICS_TITLE } from '../analytics'; -import { DOCUMENTS_TITLE } from '../documents'; -import { SCHEMA_TITLE } from '../schema'; +import { API_LOGS_TITLE } from '../api_logs'; import { CRAWLER_TITLE } from '../crawler'; -import { RELEVANCE_TUNING_TITLE } from '../relevance_tuning'; -import { SYNONYMS_TITLE } from '../synonyms'; import { CURATIONS_TITLE } from '../curations'; +import { DOCUMENTS_TITLE } from '../documents'; +import { OVERVIEW_TITLE } from '../engine_overview'; +import { ENGINES_TITLE } from '../engines'; +import { RELEVANCE_TUNING_TITLE } from '../relevance_tuning'; import { RESULT_SETTINGS_TITLE } from '../result_settings'; +import { SCHEMA_TITLE } from '../schema'; import { SEARCH_UI_TITLE } from '../search_ui'; -import { API_LOGS_TITLE } from '../api_logs'; +import { SYNONYMS_TITLE } from '../synonyms'; -import { EngineLogic, generateEnginePath } from './'; import { EngineDetails } from './types'; +import { EngineLogic, generateEnginePath } from './'; + import './engine_nav.scss'; export const EngineNav: React.FC = () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.test.tsx index cff05b296846b..3740882dee3db 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.test.tsx @@ -6,17 +6,18 @@ */ import '../../../__mocks__/react_router_history.mock'; -import { unmountHandler } from '../../../__mocks__/shallow_useeffect.mock'; import { mockFlashMessageHelpers, setMockValues, setMockActions } from '../../../__mocks__'; +import { unmountHandler } from '../../../__mocks__/shallow_useeffect.mock'; import { mockEngineValues } from '../../__mocks__'; import React from 'react'; -import { shallow } from 'enzyme'; import { Switch, Redirect, useParams } from 'react-router-dom'; +import { shallow } from 'enzyme'; + import { Loading } from '../../../shared/loading'; -import { EngineOverview } from '../engine_overview'; import { AnalyticsRouter } from '../analytics'; +import { EngineOverview } from '../engine_overview'; import { RelevanceTuning } from '../relevance_tuning'; import { EngineRouter } from './engine_router'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.tsx index 257bb1e69ad7f..2f1c3bc57d331 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.tsx @@ -7,12 +7,14 @@ import React, { useEffect } from 'react'; import { Route, Switch, Redirect, useParams } from 'react-router-dom'; + import { useValues, useActions } from 'kea'; import { i18n } from '@kbn/i18n'; -import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; import { setQueuedErrorMessage } from '../../../shared/flash_messages'; +import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; +import { Loading } from '../../../shared/loading'; import { AppLogic } from '../../app_logic'; // TODO: Uncomment and add more routes as we migrate them @@ -31,13 +33,11 @@ import { // ENGINE_SEARCH_UI_PATH, // ENGINE_API_LOGS_PATH, } from '../../routes'; -import { ENGINES_TITLE } from '../engines'; -import { OVERVIEW_TITLE } from '../engine_overview'; - -import { Loading } from '../../../shared/loading'; -import { EngineOverview } from '../engine_overview'; import { AnalyticsRouter } from '../analytics'; import { DocumentDetail, Documents } from '../documents'; +import { OVERVIEW_TITLE } from '../engine_overview'; +import { EngineOverview } from '../engine_overview'; +import { ENGINES_TITLE } from '../engines'; import { RelevanceTuning } from '../relevance_tuning'; import { EngineLogic } from './'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/types.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/types.ts index d20f9890cd4db..b50e8eb555dc9 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/types.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/types.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { ApiToken } from '../credentials/types'; import { Schema, SchemaConflicts, IIndexingStatus } from '../../../shared/types'; +import { ApiToken } from '../credentials/types'; export interface Engine { name: string; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/recent_api_logs.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/recent_api_logs.test.tsx index 7b52a04d07958..42fa9777563db 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/recent_api_logs.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/recent_api_logs.test.tsx @@ -8,6 +8,7 @@ import '../../../__mocks__/engine_logic.mock'; import React from 'react'; + import { shallow, ShallowWrapper } from 'enzyme'; import { EuiButtonTo } from '../../../../shared/react_router_helpers'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/recent_api_logs.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/recent_api_logs.tsx index d7290533f4f7b..625ba2e905840 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/recent_api_logs.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/recent_api_logs.tsx @@ -17,9 +17,9 @@ import { import { EuiButtonTo } from '../../../../shared/react_router_helpers'; import { ENGINE_API_LOGS_PATH } from '../../../routes'; +import { RECENT_API_EVENTS } from '../../api_logs/constants'; import { generateEnginePath } from '../../engine'; -import { RECENT_API_EVENTS } from '../../api_logs/constants'; import { VIEW_API_LOGS } from '../constants'; export const RecentApiLogs: React.FC = () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/total_charts.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/total_charts.test.tsx index 867b78f859a22..a2f35b4709939 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/total_charts.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/total_charts.test.tsx @@ -9,6 +9,7 @@ import { setMockValues } from '../../../../__mocks__/kea.mock'; import '../../../__mocks__/engine_logic.mock'; import React from 'react'; + import { shallow, ShallowWrapper } from 'enzyme'; import { EuiButtonTo } from '../../../../shared/react_router_helpers'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/total_charts.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/total_charts.tsx index 4fa2246ee6170..6bd973ae142a8 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/total_charts.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/total_charts.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { useValues } from 'kea'; import { @@ -21,12 +22,12 @@ import { import { EuiButtonTo } from '../../../../shared/react_router_helpers'; import { ENGINE_ANALYTICS_PATH, ENGINE_API_LOGS_PATH } from '../../../routes'; +import { AnalyticsChart, convertToChartData } from '../../analytics'; +import { TOTAL_QUERIES, TOTAL_API_OPERATIONS } from '../../analytics/constants'; import { generateEnginePath } from '../../engine'; -import { TOTAL_QUERIES, TOTAL_API_OPERATIONS } from '../../analytics/constants'; import { VIEW_ANALYTICS, VIEW_API_LOGS, LAST_7_DAYS } from '../constants'; -import { AnalyticsChart, convertToChartData } from '../../analytics'; -import { EngineOverviewLogic } from '../'; +import { EngineOverviewLogic } from '../index'; export const TotalCharts: React.FC = () => { const { startDate, queriesPerDay, operationsPerDay } = useValues(EngineOverviewLogic); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/total_stats.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/total_stats.test.tsx index a897c635eeadd..7fcda61073c5b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/total_stats.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/total_stats.test.tsx @@ -8,9 +8,11 @@ import { setMockValues } from '../../../../__mocks__/kea.mock'; import React from 'react'; + import { shallow } from 'enzyme'; import { AnalyticsCards } from '../../analytics'; + import { TotalStats } from './total_stats'; describe('TotalStats', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/total_stats.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/total_stats.tsx index 3eb208fa86504..35c6fa439a416 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/total_stats.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/total_stats.tsx @@ -6,12 +6,12 @@ */ import React from 'react'; + import { useValues } from 'kea'; -import { TOTAL_QUERIES, TOTAL_DOCUMENTS, TOTAL_CLICKS } from '../../analytics/constants'; import { AnalyticsCards } from '../../analytics'; - -import { EngineOverviewLogic } from '../'; +import { TOTAL_QUERIES, TOTAL_DOCUMENTS, TOTAL_CLICKS } from '../../analytics/constants'; +import { EngineOverviewLogic } from '../index'; export const TotalStats: React.FC = () => { const { totalQueries, documentCount, totalClicks } = useValues(EngineOverviewLogic); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/unavailable_prompt.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/unavailable_prompt.test.tsx index 7cd042a646e73..4c61a713b3793 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/unavailable_prompt.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/unavailable_prompt.test.tsx @@ -6,7 +6,9 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiEmptyPrompt } from '@elastic/eui'; import { UnavailablePrompt } from './unavailable_prompt'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/unavailable_prompt.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/unavailable_prompt.tsx index 2916be92ead99..69e79ecfc580d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/unavailable_prompt.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/unavailable_prompt.tsx @@ -7,8 +7,8 @@ import React from 'react'; -import { i18n } from '@kbn/i18n'; import { EuiEmptyPrompt } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; export const UnavailablePrompt: React.FC = () => ( { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.tsx index 9e673d48a7e5b..77552b36af239 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.tsx @@ -6,16 +6,19 @@ */ import React, { useEffect } from 'react'; + import { useActions, useValues } from 'kea'; +import { Loading } from '../../../shared/loading'; import { AppLogic } from '../../app_logic'; import { EngineLogic } from '../engine'; -import { Loading } from '../../../shared/loading'; -import { EngineOverviewLogic } from './'; import { EmptyEngineOverview } from './engine_overview_empty'; + import { EngineOverviewMetrics } from './engine_overview_metrics'; +import { EngineOverviewLogic } from './'; + export const EngineOverview: React.FC = () => { const { myRole: { canManageEngineDocuments, canViewEngineCredentials }, diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_empty.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_empty.test.tsx index 5947618e59c16..9066283229a04 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_empty.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_empty.test.tsx @@ -6,12 +6,15 @@ */ import React from 'react'; + import { shallow, ShallowWrapper } from 'enzyme'; + import { EuiButton } from '@elastic/eui'; import { docLinks } from '../../../shared/doc_links'; import { DocumentCreationButtons, DocumentCreationFlyout } from '../document_creation'; + import { EmptyEngineOverview } from './engine_overview_empty'; describe('EmptyEngineOverview', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_empty.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_empty.tsx index 6a0c46286907d..81bf3716edfb8 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_empty.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_empty.tsx @@ -7,7 +7,6 @@ import React from 'react'; -import { i18n } from '@kbn/i18n'; import { EuiPageHeader, EuiPageHeaderSection, @@ -15,6 +14,7 @@ import { EuiTitle, EuiButton, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { DOCS_PREFIX } from '../../routes'; import { DocumentCreationButtons, DocumentCreationFlyout } from '../document_creation'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_metrics.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_metrics.test.tsx index ebcdbaf1f7f09..638c8b0da87ce 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_metrics.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_metrics.test.tsx @@ -8,6 +8,7 @@ import { setMockValues } from '../../../__mocks__/kea.mock'; import React from 'react'; + import { shallow } from 'enzyme'; import { UnavailablePrompt, TotalStats, TotalCharts, RecentApiLogs } from './components'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_metrics.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_metrics.tsx index ffb1a25d21cae..34a154ca83741 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_metrics.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_metrics.tsx @@ -6,15 +6,16 @@ */ import React from 'react'; + import { useValues } from 'kea'; -import { i18n } from '@kbn/i18n'; import { EuiPageHeader, EuiTitle, EuiSpacer } from '@elastic/eui'; - -import { EngineOverviewLogic } from './'; +import { i18n } from '@kbn/i18n'; import { UnavailablePrompt, TotalStats, TotalCharts, RecentApiLogs } from './components'; +import { EngineOverviewLogic } from './'; + export const EngineOverviewMetrics: React.FC = () => { const { apiLogsUnavailable } = useValues(EngineOverviewLogic); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/assets/icons.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/assets/icons.test.tsx index 9c2818f9907a4..33ca5bd8248c9 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/assets/icons.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/assets/icons.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; import { EngineIcon } from './engine_icon'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/empty_state.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/empty_state.test.tsx index b04226b6b1dfb..ac540eec3ff91 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/empty_state.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/empty_state.test.tsx @@ -9,7 +9,9 @@ import '../../../../__mocks__/kea.mock'; import { mockTelemetryActions } from '../../../../__mocks__'; import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiEmptyPrompt, EuiButton } from '@elastic/eui'; import { EmptyState } from './'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/empty_state.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/empty_state.tsx index 60a454a5707c9..5419a175c9eff 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/empty_state.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/empty_state.tsx @@ -6,13 +6,15 @@ */ import React from 'react'; + import { useActions } from 'kea'; + import { EuiPageContent, EuiEmptyPrompt, EuiButton } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { TelemetryLogic } from '../../../../shared/telemetry'; import { getAppSearchUrl } from '../../../../shared/enterprise_search_url'; import { SetAppSearchChrome as SetPageChrome } from '../../../../shared/kibana_chrome'; +import { TelemetryLogic } from '../../../../shared/telemetry'; import { CREATE_ENGINES_PATH } from '../../../routes'; import { EnginesOverviewHeader } from './header'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/header.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/header.test.tsx index 6dedb90690ace..5ccd2c552ef02 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/header.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/header.test.tsx @@ -10,6 +10,7 @@ import '../../../../__mocks__/enterprise_search_url.mock'; import { mockTelemetryActions } from '../../../../__mocks__'; import React from 'react'; + import { shallow } from 'enzyme'; import { EnginesOverviewHeader } from './'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/header.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/header.tsx index 8a8227821b492..290270c08258c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/header.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/header.tsx @@ -6,7 +6,9 @@ */ import React from 'react'; + import { useActions } from 'kea'; + import { EuiPageHeader, EuiPageHeaderSection, @@ -17,8 +19,8 @@ import { } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { TelemetryLogic } from '../../../../shared/telemetry'; import { getAppSearchUrl } from '../../../../shared/enterprise_search_url'; +import { TelemetryLogic } from '../../../../shared/telemetry'; export const EnginesOverviewHeader: React.FC = () => { const { sendAppSearchTelemetry } = useActions(TelemetryLogic); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/loading_state.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/loading_state.test.tsx index 4adc8c11fa0dd..f7ccfea4bb4d4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/loading_state.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/loading_state.test.tsx @@ -6,7 +6,9 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiLoadingContent } from '@elastic/eui'; import { LoadingState } from './'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/loading_state.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/loading_state.tsx index 48160602106cd..155d8263c484d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/loading_state.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/loading_state.tsx @@ -6,9 +6,11 @@ */ import React from 'react'; + import { EuiPageContent, EuiSpacer, EuiLoadingContent } from '@elastic/eui'; import { SetAppSearchChrome as SetPageChrome } from '../../../../shared/kibana_chrome'; + import { EnginesOverviewHeader } from './header'; export const LoadingState: React.FC = () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_logic.test.ts index c25f60e47598e..9e9bfc4973124 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_logic.test.ts @@ -10,6 +10,7 @@ import { LogicMounter, mockHttpValues } from '../../../__mocks__'; import { nextTick } from '@kbn/test/jest'; import { EngineDetails } from '../engine/types'; + import { EnginesLogic } from './'; describe('EnginesLogic', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.test.tsx index f4aeb60a88250..cdc06dbbe3921 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.test.tsx @@ -9,6 +9,7 @@ import '../../../__mocks__/shallow_useeffect.mock'; import { setMockValues, setMockActions, rerender } from '../../../__mocks__'; import React from 'react'; + import { shallow, ShallowWrapper } from 'enzyme'; import { LoadingState, EmptyState } from './components'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.tsx index c13db688fc2b6..2835c8b7cb3c4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.tsx @@ -6,7 +6,9 @@ */ import React, { useEffect } from 'react'; + import { useValues, useActions } from 'kea'; + import { EuiPageContent, EuiPageContentHeader, @@ -15,17 +17,17 @@ import { EuiSpacer, } from '@elastic/eui'; -import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; -import { SendAppSearchTelemetry as SendTelemetry } from '../../../shared/telemetry'; import { FlashMessages } from '../../../shared/flash_messages'; +import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; import { LicensingLogic } from '../../../shared/licensing'; +import { SendAppSearchTelemetry as SendTelemetry } from '../../../shared/telemetry'; import { EngineIcon } from './assets/engine_icon'; import { MetaEngineIcon } from './assets/meta_engine_icon'; -import { ENGINES_TITLE, META_ENGINES_TITLE } from './constants'; import { EnginesOverviewHeader, LoadingState, EmptyState } from './components'; -import { EnginesTable } from './engines_table'; +import { ENGINES_TITLE, META_ENGINES_TITLE } from './constants'; import { EnginesLogic } from './engines_logic'; +import { EnginesTable } from './engines_table'; import './engines_overview.scss'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_table.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_table.test.tsx index 65b96035eaaee..d6f0946164ea4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_table.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_table.test.tsx @@ -9,10 +9,13 @@ import '../../../__mocks__/enterprise_search_url.mock'; import { mockTelemetryActions, mountWithIntl } from '../../../__mocks__'; import React from 'react'; + import { EuiBasicTable, EuiPagination, EuiButtonEmpty } from '@elastic/eui'; + import { EuiLinkTo } from '../../../shared/react_router_helpers'; import { EngineDetails } from '../engine/types'; + import { EnginesTable } from './engines_table'; describe('EnginesTable', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_table.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_table.tsx index b439d7e6bdf33..d41c5c908c08f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_table.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_table.tsx @@ -6,18 +6,19 @@ */ import React from 'react'; + import { useActions } from 'kea'; + import { EuiBasicTable, EuiBasicTableColumn } from '@elastic/eui'; -import { FormattedMessage, FormattedDate, FormattedNumber } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; - -import { TelemetryLogic } from '../../../shared/telemetry'; -import { EuiLinkTo } from '../../../shared/react_router_helpers'; -import { generateEncodedPath } from '../../utils/encode_path_params'; -import { ENGINE_PATH } from '../../routes'; +import { FormattedMessage, FormattedDate, FormattedNumber } from '@kbn/i18n/react'; import { ENGINES_PAGE_SIZE } from '../../../../../common/constants'; +import { EuiLinkTo } from '../../../shared/react_router_helpers'; +import { TelemetryLogic } from '../../../shared/telemetry'; import { UNIVERSAL_LANGUAGE } from '../../constants'; +import { ENGINE_PATH } from '../../routes'; +import { generateEncodedPath } from '../../utils/encode_path_params'; import { EngineDetails } from '../engine/types'; interface EnginesTablePagination { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/error_connecting/error_connecting.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/error_connecting/error_connecting.test.tsx index 6ff33385df9a5..9ec3fdda63656 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/error_connecting/error_connecting.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/error_connecting/error_connecting.test.tsx @@ -6,9 +6,11 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; import { ErrorStatePrompt } from '../../../shared/error_state'; + import { ErrorConnecting } from './'; describe('ErrorConnecting', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/error_connecting/error_connecting.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/error_connecting/error_connecting.tsx index ad5eff6c4dacf..d7fde0cd5dd25 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/error_connecting/error_connecting.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/error_connecting/error_connecting.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { EuiPageContent } from '@elastic/eui'; import { ErrorStatePrompt } from '../../../shared/error_state'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/library/library.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/library/library.tsx index 2d39b5a9aa05c..f76ad78c847d1 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/library/library.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/library/library.tsx @@ -5,6 +5,8 @@ * 2.0. */ +import React from 'react'; + import { EuiSpacer, EuiPageHeader, @@ -13,7 +15,6 @@ import { EuiPageContentBody, EuiPageContent, } from '@elastic/eui'; -import React from 'react'; import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; import { Schema } from '../../../shared/types'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/components/log_retention_callout.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/components/log_retention_callout.test.tsx index d0bc1c9a88c5f..124edb6871453 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/components/log_retention_callout.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/components/log_retention_callout.test.tsx @@ -6,14 +6,16 @@ */ import '../../../../__mocks__/shallow_useeffect.mock'; -import { setMockValues, setMockActions } from '../../../../__mocks__/kea.mock'; -import { mountWithIntl } from '../../../../__mocks__'; +import { setMockValues, setMockActions, mountWithIntl } from '../../../../__mocks__'; import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiCallOut, EuiLink } from '@elastic/eui'; import { LogRetentionOptions } from '../'; + import { LogRetentionCallout } from './'; describe('LogRetentionCallout', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/components/log_retention_callout.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/components/log_retention_callout.tsx index 0252a788f75ef..235d977793161 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/components/log_retention_callout.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/components/log_retention_callout.tsx @@ -6,11 +6,12 @@ */ import React, { useEffect } from 'react'; + import { useValues, useActions } from 'kea'; +import { EuiCallOut, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiCallOut, EuiSpacer } from '@elastic/eui'; import { EuiLinkTo } from '../../../../shared/react_router_helpers'; @@ -19,7 +20,7 @@ import { SETTINGS_PATH } from '../../../routes'; import { ANALYTICS_TITLE } from '../../analytics'; import { API_LOGS_TITLE } from '../../api_logs'; -import { LogRetentionLogic, LogRetentionOptions, renderLogRetentionDate } from '../'; +import { LogRetentionLogic, LogRetentionOptions, renderLogRetentionDate } from '../index'; const TITLE_MAP = { [LogRetentionOptions.Analytics]: ANALYTICS_TITLE, diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/components/log_retention_tooltip.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/components/log_retention_tooltip.test.tsx index 14615f6ac2dd9..854a9f1d8d162 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/components/log_retention_tooltip.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/components/log_retention_tooltip.test.tsx @@ -9,10 +9,13 @@ import '../../../../__mocks__/shallow_useeffect.mock'; import { setMockValues, setMockActions } from '../../../../__mocks__/kea.mock'; import React from 'react'; + import { shallow, mount } from 'enzyme'; + import { EuiIconTip } from '@elastic/eui'; import { LogRetentionOptions, LogRetentionMessage } from '../'; + import { LogRetentionTooltip } from './'; describe('LogRetentionTooltip', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/components/log_retention_tooltip.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/components/log_retention_tooltip.tsx index e3b428baa6d9a..bf074ba0272f2 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/components/log_retention_tooltip.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/components/log_retention_tooltip.tsx @@ -6,10 +6,11 @@ */ import React, { useEffect } from 'react'; + import { useValues, useActions } from 'kea'; -import { i18n } from '@kbn/i18n'; import { EuiIconTip } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { LogRetentionLogic, LogRetentionMessage, LogRetentionOptions } from '../'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/log_retention_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/log_retention_logic.test.ts index 9615aba5fdef4..19bd2af50aad9 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/log_retention_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/log_retention_logic.test.ts @@ -10,7 +10,8 @@ import { LogicMounter, mockHttpValues, mockFlashMessageHelpers } from '../../../ import { nextTick } from '@kbn/test/jest'; import { LogRetentionOptions } from './types'; -import { LogRetentionLogic } from './log_retention_logic'; + +import { LogRetentionLogic } from './'; describe('LogRetentionLogic', () => { const { mount } = new LogicMounter(LogRetentionLogic); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/log_retention_logic.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/log_retention_logic.ts index 77d4cf395196a..ec078842dab55 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/log_retention_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/log_retention_logic.ts @@ -7,8 +7,8 @@ import { kea, MakeLogicType } from 'kea'; -import { HttpLogic } from '../../../shared/http'; import { flashAPIErrors } from '../../../shared/flash_messages'; +import { HttpLogic } from '../../../shared/http'; import { LogRetentionOptions, LogRetention, LogRetentionServer } from './types'; import { convertLogRetentionFromServerToClient } from './utils/convert_log_retention'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/messaging/constants.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/messaging/constants.tsx index 0f231092a36e2..c7c4d90d91ce8 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/messaging/constants.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/messaging/constants.tsx @@ -6,8 +6,9 @@ */ import React from 'react'; -import { FormattedDate, FormattedMessage } from '@kbn/i18n/react'; + import { i18n } from '@kbn/i18n'; +import { FormattedDate, FormattedMessage } from '@kbn/i18n/react'; import { LogRetentionOptions, LogRetentionSettings, LogRetentionPolicy } from '../types'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/messaging/log_retention_message.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/messaging/log_retention_message.test.tsx index be95261a35c25..cd71e37108927 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/messaging/log_retention_message.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/messaging/log_retention_message.test.tsx @@ -5,13 +5,14 @@ * 2.0. */ -import { setMockValues } from '../../../../__mocks__/kea.mock'; -import { mountWithIntl } from '../../../../__mocks__'; +import { setMockValues, mountWithIntl } from '../../../../__mocks__'; import React from 'react'; + import { shallow } from 'enzyme'; import { LogRetentionOptions } from '../types'; + import { LogRetentionMessage } from './'; describe('LogRetentionMessage', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/messaging/log_retention_message.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/messaging/log_retention_message.tsx index 62bac44b122af..7d34a2567ba14 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/messaging/log_retention_message.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/log_retention/messaging/log_retention_message.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { useValues } from 'kea'; import { AppLogic } from '../../../app_logic'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/relevance_tuning.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/relevance_tuning.tsx index 56e31ec6bf970..83e83c0f9ea43 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/relevance_tuning.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/relevance_tuning.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { EuiPageHeader, EuiPageHeaderSection, @@ -14,8 +15,8 @@ import { EuiPageContent, } from '@elastic/eui'; -import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; import { FlashMessages } from '../../../shared/flash_messages'; +import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; import { RELEVANCE_TUNING_TITLE } from './constants'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/relevance_tuning_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/relevance_tuning_logic.test.ts index 586a845ce382a..7f7bce1b7ba95 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/relevance_tuning_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/relevance_tuning_logic.test.ts @@ -9,7 +9,7 @@ import { LogicMounter } from '../../../__mocks__'; import { BoostType } from './types'; -import { RelevanceTuningLogic } from './relevance_tuning_logic'; +import { RelevanceTuningLogic } from './'; describe('RelevanceTuningLogic', () => { const { mount } = new LogicMounter(RelevanceTuningLogic); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result.test.tsx index 0c3749d1ccb3d..41428999b1e40 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result.test.tsx @@ -6,15 +6,17 @@ */ import React from 'react'; + import { shallow, ShallowWrapper } from 'enzyme'; + import { EuiPanel } from '@elastic/eui'; -import { ResultField } from './result_field'; -import { ResultHeader } from './result_header'; import { ReactRouterHelper } from '../../../shared/react_router_helpers/eui_components'; import { SchemaTypes } from '../../../shared/types'; import { Result } from './result'; +import { ResultField } from './result_field'; +import { ResultHeader } from './result_header'; describe('Result', () => { const props = { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result.tsx index d84b079ea9d72..7288fdf39f3ff 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result.tsx @@ -6,6 +6,7 @@ */ import React, { useState, useMemo } from 'react'; + import classNames from 'classnames'; import './result.scss'; @@ -14,13 +15,14 @@ import { EuiPanel, EuiIcon } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { ReactRouterHelper } from '../../../shared/react_router_helpers/eui_components'; -import { generateEncodedPath } from '../../utils/encode_path_params'; -import { ENGINE_DOCUMENT_DETAIL_PATH } from '../../routes'; import { Schema } from '../../../shared/types'; -import { FieldValue, Result as ResultType } from './types'; +import { ENGINE_DOCUMENT_DETAIL_PATH } from '../../routes'; +import { generateEncodedPath } from '../../utils/encode_path_params'; + import { ResultField } from './result_field'; import { ResultHeader } from './result_header'; +import { FieldValue, Result as ResultType } from './types'; interface Props { result: ResultType; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result_field.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result_field.test.tsx index 6869708627b8d..1e79266dd7e7d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result_field.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result_field.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; import { ResultField } from './result_field'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result_field.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result_field.tsx index a1c3ccd93622a..003810ec40a8d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result_field.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result_field.tsx @@ -6,9 +6,11 @@ */ import React from 'react'; -import { ResultFieldValue } from '.'; + import { FieldType, Raw, Snippet } from './types'; +import { ResultFieldValue } from '.'; + import './result_field.scss'; interface Props { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result_field_value.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result_field_value.test.tsx index e1cefa1d79469..c732c9c8216c0 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result_field_value.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result_field_value.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { shallow, ShallowWrapper } from 'enzyme'; import { ResultFieldValue } from '.'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result_header.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result_header.test.tsx index 9d90b3ae35a8f..dcefd0f6bc0b0 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result_header.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result_header.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; import { ResultHeader } from './result_header'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result_header_item.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result_header_item.test.tsx index e8cc8796440a9..52fa81943bb2e 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result_header_item.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result_header_item.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { mount } from 'enzyme'; import { ResultHeaderItem } from './result_header_item'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/generic_confirmation_modal.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/generic_confirmation_modal.test.tsx index 3e450b7a7bb70..8477f0e8e2ce2 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/generic_confirmation_modal.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/generic_confirmation_modal.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; import { GenericConfirmationModal } from './generic_confirmation_modal'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/generic_confirmation_modal.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/generic_confirmation_modal.tsx index b792ace4dac3f..eb64fe6421d80 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/generic_confirmation_modal.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/generic_confirmation_modal.tsx @@ -6,7 +6,6 @@ */ import React, { ReactNode, useState } from 'react'; -import { i18n } from '@kbn/i18n'; import { EuiButton, @@ -21,6 +20,7 @@ import { EuiSpacer, EuiText, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; interface GenericConfirmationModalProps { description: ReactNode; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_confirmation_modal.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_confirmation_modal.test.tsx index a6d0cab532729..494517a438372 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_confirmation_modal.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_confirmation_modal.test.tsx @@ -8,9 +8,11 @@ import { setMockActions, setMockValues } from '../../../../__mocks__'; import React from 'react'; + import { shallow } from 'enzyme'; import { LogRetentionOptions } from '../../log_retention'; + import { GenericConfirmationModal } from './generic_confirmation_modal'; import { LogRetentionConfirmationModal } from './log_retention_confirmation_modal'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_confirmation_modal.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_confirmation_modal.tsx index 52a2478d7158e..ca1fa9a8d0737 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_confirmation_modal.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_confirmation_modal.tsx @@ -6,12 +6,14 @@ */ import React from 'react'; -import { i18n } from '@kbn/i18n'; -import { EuiTextColor, EuiOverlayMask } from '@elastic/eui'; import { useActions, useValues } from 'kea'; +import { EuiTextColor, EuiOverlayMask } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + import { LogRetentionLogic, LogRetentionOptions } from '../../log_retention'; + import { GenericConfirmationModal } from './generic_confirmation_modal'; export const LogRetentionConfirmationModal: React.FC = () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_panel.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_panel.test.tsx index 882b82979a511..aee23e61e76fe 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_panel.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_panel.test.tsx @@ -9,9 +9,11 @@ import '../../../../__mocks__/shallow_useeffect.mock'; import { setMockActions, setMockValues } from '../../../../__mocks__'; import React from 'react'; + import { shallow } from 'enzyme'; import { LogRetention } from '../../log_retention/types'; + import { LogRetentionPanel } from './log_retention_panel'; describe('', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_panel.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_panel.tsx index 3a40be9efd5db..76fdcdac58ad4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_panel.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_panel.tsx @@ -6,11 +6,12 @@ */ import React, { useEffect } from 'react'; -import { i18n } from '@kbn/i18n'; -import { EuiLink, EuiSpacer, EuiSwitch, EuiText, EuiTextColor, EuiTitle } from '@elastic/eui'; import { useActions, useValues } from 'kea'; +import { EuiLink, EuiSpacer, EuiSwitch, EuiText, EuiTextColor, EuiTitle } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + import { DOCS_PREFIX } from '../../../routes'; import { LogRetentionLogic, LogRetentionOptions, LogRetentionMessage } from '../../log_retention'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/settings.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/settings.test.tsx index fead8cda0c0e2..41d446b8e36fc 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/settings.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/settings.test.tsx @@ -6,7 +6,9 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiPageContentBody } from '@elastic/eui'; import { Settings } from './settings'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/settings.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/settings.tsx index c029cf344f18b..510075eba4abf 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/settings.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/settings.tsx @@ -15,10 +15,11 @@ import { EuiTitle, } from '@elastic/eui'; -import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; import { FlashMessages } from '../../../shared/flash_messages'; +import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; import { LogRetentionPanel, LogRetentionConfirmationModal } from './log_retention'; + import { SETTINGS_TITLE } from './'; export const Settings: React.FC = () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/setup_guide/setup_guide.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/setup_guide/setup_guide.test.tsx index e8dcb6ff98358..0b4a86870a69d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/setup_guide/setup_guide.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/setup_guide/setup_guide.test.tsx @@ -6,10 +6,12 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; import { SetupGuideLayout } from '../../../shared/setup_guide'; + import { SetupGuide } from './'; describe('SetupGuide', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/setup_guide/setup_guide.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/setup_guide/setup_guide.tsx index befb06c719a39..3d96b22859fad 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/setup_guide/setup_guide.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/setup_guide/setup_guide.tsx @@ -6,15 +6,17 @@ */ import React from 'react'; + import { EuiSpacer, EuiTitle, EuiText } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; import { APP_SEARCH_PLUGIN } from '../../../../../common/constants'; -import { SetupGuideLayout, SETUP_GUIDE_TITLE } from '../../../shared/setup_guide'; import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; +import { SetupGuideLayout, SETUP_GUIDE_TITLE } from '../../../shared/setup_guide'; import { SendAppSearchTelemetry as SendTelemetry } from '../../../shared/telemetry'; import { DOCS_PREFIX } from '../../routes'; + import GettingStarted from './assets/getting_started.png'; export const SetupGuide: React.FC = () => ( diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx index dc3c0b03148d9..0e8220266d613 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx @@ -11,13 +11,16 @@ import { setMockValues, setMockActions } from '../__mocks__'; import React from 'react'; import { Redirect } from 'react-router-dom'; + import { shallow } from 'enzyme'; import { Layout, SideNav, SideNavLink } from '../shared/layout'; -import { SetupGuide } from './components/setup_guide'; -import { ErrorConnecting } from './components/error_connecting'; -import { EnginesOverview } from './components/engines'; + import { EngineRouter } from './components/engine'; +import { EnginesOverview } from './components/engines'; +import { ErrorConnecting } from './components/error_connecting'; +import { SetupGuide } from './components/setup_guide'; + import { AppSearch, AppSearchUnconfigured, AppSearchConfigured, AppSearchNav } from './'; describe('AppSearch', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx index 918697422af6b..36ac3fb4dbc5b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx @@ -7,18 +7,26 @@ import React, { useEffect } from 'react'; import { Route, Redirect, Switch } from 'react-router-dom'; + import { useActions, useValues } from 'kea'; +import { APP_SEARCH_PLUGIN } from '../../../common/constants'; +import { InitialAppData } from '../../../common/types'; import { getAppSearchUrl } from '../shared/enterprise_search_url'; -import { KibanaLogic } from '../shared/kibana'; import { HttpLogic } from '../shared/http'; -import { AppLogic } from './app_logic'; -import { InitialAppData } from '../../../common/types'; - -import { APP_SEARCH_PLUGIN } from '../../../common/constants'; +import { KibanaLogic } from '../shared/kibana'; import { Layout, SideNav, SideNavLink } from '../shared/layout'; -import { EngineNav, EngineRouter } from './components/engine'; +import { NotFound } from '../shared/not_found'; +import { AppLogic } from './app_logic'; +import { Credentials, CREDENTIALS_TITLE } from './components/credentials'; +import { EngineNav, EngineRouter } from './components/engine'; +import { EnginesOverview, ENGINES_TITLE } from './components/engines'; +import { ErrorConnecting } from './components/error_connecting'; +import { Library } from './components/library'; +import { ROLE_MAPPINGS_TITLE } from './components/role_mappings'; +import { Settings, SETTINGS_TITLE } from './components/settings'; +import { SetupGuide } from './components/setup_guide'; import { ROOT_PATH, SETUP_GUIDE_PATH, @@ -30,15 +38,6 @@ import { LIBRARY_PATH, } from './routes'; -import { SetupGuide } from './components/setup_guide'; -import { ErrorConnecting } from './components/error_connecting'; -import { NotFound } from '../shared/not_found'; -import { EnginesOverview, ENGINES_TITLE } from './components/engines'; -import { Settings, SETTINGS_TITLE } from './components/settings'; -import { Credentials, CREDENTIALS_TITLE } from './components/credentials'; -import { ROLE_MAPPINGS_TITLE } from './components/role_mappings'; -import { Library } from './components/library'; - export const AppSearch: React.FC = (props) => { const { config } = useValues(KibanaLogic); return !config.host ? : ; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/error_connecting/error_connecting.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/error_connecting/error_connecting.test.tsx index 6ff33385df9a5..9ec3fdda63656 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/error_connecting/error_connecting.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/error_connecting/error_connecting.test.tsx @@ -6,9 +6,11 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; import { ErrorStatePrompt } from '../../../shared/error_state'; + import { ErrorConnecting } from './'; describe('ErrorConnecting', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/error_connecting/error_connecting.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/error_connecting/error_connecting.tsx index cb1abc275d37f..afee20df106e8 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/error_connecting/error_connecting.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/error_connecting/error_connecting.tsx @@ -6,10 +6,11 @@ */ import React from 'react'; + import { EuiPage, EuiPageContent } from '@elastic/eui'; -import { SendEnterpriseSearchTelemetry as SendTelemetry } from '../../../shared/telemetry'; import { ErrorStatePrompt } from '../../../shared/error_state'; +import { SendEnterpriseSearchTelemetry as SendTelemetry } from '../../../shared/telemetry'; export const ErrorConnecting: React.FC = () => ( diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/product_card/product_card.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/product_card/product_card.test.tsx index a9098689b3d0e..8631e6e2a51d4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/product_card/product_card.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/product_card/product_card.test.tsx @@ -8,11 +8,13 @@ import { setMockValues, mockTelemetryActions } from '../../../__mocks__'; import React from 'react'; + import { shallow } from 'enzyme'; import { EuiCard } from '@elastic/eui'; -import { EuiButtonTo } from '../../../shared/react_router_helpers'; + import { APP_SEARCH_PLUGIN, WORKPLACE_SEARCH_PLUGIN } from '../../../../../common/constants'; +import { EuiButtonTo } from '../../../shared/react_router_helpers'; import { ProductCard } from './'; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/product_card/product_card.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/product_card/product_card.tsx index d31daeef54de9..20727e37460f1 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/product_card/product_card.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/product_card/product_card.tsx @@ -6,14 +6,16 @@ */ import React from 'react'; + import { useValues, useActions } from 'kea'; import { snakeCase } from 'lodash'; -import { i18n } from '@kbn/i18n'; + import { EuiCard, EuiTextColor } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { KibanaLogic } from '../../../shared/kibana'; import { EuiButtonTo } from '../../../shared/react_router_helpers'; import { TelemetryLogic } from '../../../shared/telemetry'; -import { KibanaLogic } from '../../../shared/kibana'; import './product_card.scss'; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/product_selector/product_selector.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/product_selector/product_selector.test.tsx index 0d55e2ce21c74..9ee34634e3797 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/product_selector/product_selector.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/product_selector/product_selector.test.tsx @@ -8,11 +8,13 @@ import { setMockValues } from '../../../__mocks__/kea.mock'; import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiPage } from '@elastic/eui'; -import { SetupGuideCta } from '../setup_guide'; import { ProductCard } from '../product_card'; +import { SetupGuideCta } from '../setup_guide'; import { ProductSelector } from './'; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/product_selector/product_selector.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/product_selector/product_selector.tsx index 910840f023bb2..f2476a5770c25 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/product_selector/product_selector.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/product_selector/product_selector.tsx @@ -6,7 +6,9 @@ */ import React from 'react'; + import { useValues } from 'kea'; + import { EuiPage, EuiPageBody, @@ -25,11 +27,10 @@ import { KibanaLogic } from '../../../shared/kibana'; import { SetEnterpriseSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; import { SendEnterpriseSearchTelemetry as SendTelemetry } from '../../../shared/telemetry'; -import { ProductCard } from '../product_card'; -import { SetupGuideCta } from '../setup_guide'; - import AppSearchImage from '../../assets/app_search.png'; import WorkplaceSearchImage from '../../assets/workplace_search.png'; +import { ProductCard } from '../product_card'; +import { SetupGuideCta } from '../setup_guide'; interface ProductSelectorProps { access: { diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/setup_guide/setup_guide.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/setup_guide/setup_guide.test.tsx index e2f3595d26974..44f06de7ff137 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/setup_guide/setup_guide.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/setup_guide/setup_guide.test.tsx @@ -6,10 +6,12 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; import { SetEnterpriseSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; import { SetupGuideLayout } from '../../../shared/setup_guide'; + import { SetupGuide } from './'; describe('SetupGuide', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/setup_guide/setup_guide.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/setup_guide/setup_guide.tsx index 02327e01c5ede..c59742d7ccbea 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/setup_guide/setup_guide.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/setup_guide/setup_guide.tsx @@ -6,14 +6,16 @@ */ import React from 'react'; + import { EuiSpacer, EuiTitle, EuiText } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; import { ENTERPRISE_SEARCH_PLUGIN } from '../../../../../common/constants'; -import { SetupGuideLayout, SETUP_GUIDE_TITLE } from '../../../shared/setup_guide'; import { SetEnterpriseSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; +import { SetupGuideLayout, SETUP_GUIDE_TITLE } from '../../../shared/setup_guide'; import { SendEnterpriseSearchTelemetry as SendTelemetry } from '../../../shared/telemetry'; + import GettingStarted from './assets/getting_started.png'; export const SetupGuide: React.FC = () => ( diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/setup_guide/setup_guide_cta.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/setup_guide/setup_guide_cta.test.tsx index 140e779df55d2..659af6d23c6d0 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/setup_guide/setup_guide_cta.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/setup_guide/setup_guide_cta.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; import { SetupGuideCta } from './'; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/setup_guide/setup_guide_cta.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/setup_guide/setup_guide_cta.tsx index 7d32b11ba7ae8..17260cc15793a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/setup_guide/setup_guide_cta.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/setup_guide/setup_guide_cta.tsx @@ -6,8 +6,10 @@ */ import React from 'react'; -import { i18n } from '@kbn/i18n'; + import { EuiFlexGroup, EuiFlexItem, EuiTitle, EuiText } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + import { EuiPanelTo } from '../../../shared/react_router_helpers'; import CtaImage from './assets/getting_started.png'; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/index.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/index.test.tsx index e4508f4e99276..2d8dbd55f4366 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/index.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/index.test.tsx @@ -5,15 +5,17 @@ * 2.0. */ +import { setMockValues, rerender } from '../__mocks__'; + import React from 'react'; -import { shallow } from 'enzyme'; -import { setMockValues, rerender } from '../__mocks__'; +import { shallow } from 'enzyme'; -import { EnterpriseSearch } from './'; -import { SetupGuide } from './components/setup_guide'; import { ErrorConnecting } from './components/error_connecting'; import { ProductSelector } from './components/product_selector'; +import { SetupGuide } from './components/setup_guide'; + +import { EnterpriseSearch } from './'; describe('EnterpriseSearch', () => { it('renders the Setup Guide and Product Selector', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/index.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/index.tsx index 50ed0bce75cf8..b21e46429672a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/index.tsx @@ -7,18 +7,17 @@ import React from 'react'; import { Route, Switch } from 'react-router-dom'; + import { useValues } from 'kea'; -import { KibanaLogic } from '../shared/kibana'; import { InitialAppData } from '../../../common/types'; - import { HttpLogic } from '../shared/http'; - -import { ROOT_PATH, SETUP_GUIDE_PATH } from './routes'; +import { KibanaLogic } from '../shared/kibana'; import { ErrorConnecting } from './components/error_connecting'; import { ProductSelector } from './components/product_selector'; import { SetupGuide } from './components/setup_guide'; +import { ROOT_PATH, SETUP_GUIDE_PATH } from './routes'; import './index.scss'; diff --git a/x-pack/plugins/enterprise_search/public/applications/index.test.tsx b/x-pack/plugins/enterprise_search/public/applications/index.test.tsx index f36561787eb69..2e0940b9c4af2 100644 --- a/x-pack/plugins/enterprise_search/public/applications/index.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/index.test.tsx @@ -6,17 +6,19 @@ */ import React from 'react'; + import { getContext } from 'kea'; -import { coreMock } from 'src/core/public/mocks'; -import { licensingMock } from '../../../licensing/public/mocks'; +import { coreMock } from '../../../../../src/core/public/mocks'; import { chartPluginMock } from '../../../../../src/plugins/charts/public/mocks'; +import { licensingMock } from '../../../licensing/public/mocks'; -import { renderApp, renderHeaderActions } from './'; -import { EnterpriseSearch } from './enterprise_search'; import { AppSearch } from './app_search'; -import { WorkplaceSearch } from './workplace_search'; +import { EnterpriseSearch } from './enterprise_search'; import { KibanaLogic } from './shared/kibana'; +import { WorkplaceSearch } from './workplace_search'; + +import { renderApp, renderHeaderActions } from './'; describe('renderApp', () => { const kibanaDeps = { diff --git a/x-pack/plugins/enterprise_search/public/applications/index.tsx b/x-pack/plugins/enterprise_search/public/applications/index.tsx index 97e43f758e5b8..155ff5b92ba27 100644 --- a/x-pack/plugins/enterprise_search/public/applications/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/index.tsx @@ -7,21 +7,23 @@ import React from 'react'; import ReactDOM from 'react-dom'; -import { Router } from 'react-router-dom'; import { Provider } from 'react-redux'; -import { Store } from 'redux'; +import { Router } from 'react-router-dom'; + import { getContext, resetContext } from 'kea'; +import { Store } from 'redux'; + import { I18nProvider } from '@kbn/i18n/react'; -import { AppMountParameters, CoreStart } from 'src/core/public'; -import { PluginsStart, ClientConfigType, ClientData } from '../plugin'; +import { AppMountParameters, CoreStart } from '../../../../../src/core/public'; import { InitialAppData } from '../../common/types'; +import { PluginsStart, ClientConfigType, ClientData } from '../plugin'; +import { externalUrl } from './shared/enterprise_search_url'; +import { mountFlashMessagesLogic } from './shared/flash_messages'; +import { mountHttpLogic } from './shared/http'; import { mountKibanaLogic } from './shared/kibana'; import { mountLicensingLogic } from './shared/licensing'; -import { mountHttpLogic } from './shared/http'; -import { mountFlashMessagesLogic } from './shared/flash_messages'; -import { externalUrl } from './shared/enterprise_search_url'; /** * This file serves as a reusable wrapper to share Kibana-level context and other helpers diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/error_state/error_state_prompt.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/error_state/error_state_prompt.test.tsx index 9870264eb1c2f..d9d31f5a45d4b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/error_state/error_state_prompt.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/error_state/error_state_prompt.test.tsx @@ -8,7 +8,9 @@ import '../../__mocks__/kea.mock'; import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiEmptyPrompt } from '@elastic/eui'; import { ErrorStatePrompt } from './'; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/error_state/error_state_prompt.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/error_state/error_state_prompt.tsx index cf8b234442002..f855c7b67dc6e 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/error_state/error_state_prompt.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/error_state/error_state_prompt.tsx @@ -6,12 +6,14 @@ */ import React from 'react'; + import { useValues } from 'kea'; + import { EuiEmptyPrompt, EuiCode } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiButtonTo } from '../react_router_helpers'; import { KibanaLogic } from '../../shared/kibana'; +import { EuiButtonTo } from '../react_router_helpers'; import './error_state_prompt.scss'; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/flash_messages.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/flash_messages.test.tsx index 2a31c0ecd66a8..aa45ce58af86a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/flash_messages.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/flash_messages.test.tsx @@ -8,7 +8,9 @@ import { setMockValues } from '../../__mocks__/kea.mock'; import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiCallOut } from '@elastic/eui'; import { FlashMessages } from './flash_messages'; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/flash_messages.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/flash_messages.tsx index 5f38961b8a341..60d80487a2593 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/flash_messages.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/flash_messages.tsx @@ -6,7 +6,9 @@ */ import React, { Fragment } from 'react'; + import { useValues } from 'kea'; + import { EuiCallOut, EuiCallOutProps, EuiSpacer } from '@elastic/eui'; import { FlashMessagesLogic } from './flash_messages_logic'; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/flash_messages_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/flash_messages_logic.test.ts index 61f667719e3e6..7fc78c99fb242 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/flash_messages_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/flash_messages_logic.test.ts @@ -5,12 +5,14 @@ * 2.0. */ +import { mockKibanaValues } from '../../__mocks__/kibana_logic.mock'; + import { resetContext } from 'kea'; -import { mockKibanaValues } from '../../__mocks__/kibana_logic.mock'; const { history } = mockKibanaValues; -import { FlashMessagesLogic, mountFlashMessagesLogic, IFlashMessage } from './flash_messages_logic'; +import { FlashMessagesLogic, mountFlashMessagesLogic } from './flash_messages_logic'; +import { IFlashMessage } from './types'; describe('FlashMessagesLogic', () => { const mount = () => mountFlashMessagesLogic(); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/flash_messages_logic.ts b/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/flash_messages_logic.ts index 26af4103aada1..5993e67b28a39 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/flash_messages_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/flash_messages_logic.ts @@ -6,15 +6,10 @@ */ import { kea, MakeLogicType } from 'kea'; -import { ReactNode } from 'react'; import { KibanaLogic } from '../kibana'; -export interface IFlashMessage { - type: 'success' | 'info' | 'warning' | 'error'; - message: ReactNode; - description?: ReactNode; -} +import { IFlashMessage } from './types'; interface FlashMessagesValues { messages: IFlashMessage[]; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/handle_api_errors.test.ts b/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/handle_api_errors.test.ts index 1df1c6a7a680e..b6b0e23ce7d6a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/handle_api_errors.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/handle_api_errors.test.ts @@ -8,6 +8,7 @@ import '../../__mocks__/kibana_logic.mock'; import { FlashMessagesLogic } from './flash_messages_logic'; + import { flashAPIErrors } from './handle_api_errors'; describe('flashAPIErrors', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/handle_api_errors.ts b/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/handle_api_errors.ts index 5fb824ebde9a0..11003d0fcc171 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/handle_api_errors.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/handle_api_errors.ts @@ -7,7 +7,8 @@ import { HttpResponse } from 'src/core/public'; -import { FlashMessagesLogic, IFlashMessage } from './flash_messages_logic'; +import { FlashMessagesLogic } from './flash_messages_logic'; +import { IFlashMessage } from './types'; /** * The API errors we are handling can come from one of two ways: diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/index.ts b/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/index.ts index 8d3605a19c22c..40317eb390547 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/index.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/index.ts @@ -6,7 +6,8 @@ */ export { FlashMessages } from './flash_messages'; -export { FlashMessagesLogic, IFlashMessage, mountFlashMessagesLogic } from './flash_messages_logic'; +export { FlashMessagesLogic, mountFlashMessagesLogic } from './flash_messages_logic'; +export { IFlashMessage } from './types'; export { flashAPIErrors } from './handle_api_errors'; export { setSuccessMessage, diff --git a/x-pack/plugins/maps_file_upload/server/client/errors.js b/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/types.ts similarity index 60% rename from x-pack/plugins/maps_file_upload/server/client/errors.js rename to x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/types.ts index 8f8516158b303..c1d2f8420198d 100644 --- a/x-pack/plugins/maps_file_upload/server/client/errors.js +++ b/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/types.ts @@ -5,8 +5,10 @@ * 2.0. */ -import { boomify } from '@hapi/boom'; +import { ReactNode } from 'react'; -export function wrapError(error) { - return boomify(error, { statusCode: error.status }); +export interface IFlashMessage { + type: 'success' | 'info' | 'warning' | 'error'; + message: ReactNode; + description?: ReactNode; } diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/hidden_text/hidden_text.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/hidden_text/hidden_text.test.tsx index 1888edca53034..af63b9a801edd 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/hidden_text/hidden_text.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/hidden_text/hidden_text.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; import { HiddenText } from '.'; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/hidden_text/hidden_text.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/hidden_text/hidden_text.tsx index 5503baf0bdae4..35901496c5fbd 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/hidden_text/hidden_text.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/hidden_text/hidden_text.tsx @@ -6,6 +6,7 @@ */ import React, { useState, ReactElement } from 'react'; + import { i18n } from '@kbn/i18n'; interface ChildrenProps { diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/indexing_status/indexing_status.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/indexing_status/indexing_status.test.tsx index d8f02be60ef92..44bd8b78320d6 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/indexing_status/indexing_status.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/indexing_status/indexing_status.test.tsx @@ -9,13 +9,14 @@ import '../../__mocks__/shallow_useeffect.mock'; import { setMockActions, setMockValues } from '../../__mocks__'; import React from 'react'; + import { shallow } from 'enzyme'; import { EuiPanel } from '@elastic/eui'; +import { IndexingStatus } from './indexing_status'; import { IndexingStatusContent } from './indexing_status_content'; import { IndexingStatusErrors } from './indexing_status_errors'; -import { IndexingStatus } from './indexing_status'; describe('IndexingStatus', () => { const getItemDetailPath = jest.fn(); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/indexing_status/indexing_status.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/indexing_status/indexing_status.tsx index 3898eda126415..ee0557e15396c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/indexing_status/indexing_status.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/indexing_status/indexing_status.tsx @@ -11,12 +11,12 @@ import { useValues, useActions } from 'kea'; import { EuiPanel, EuiSpacer } from '@elastic/eui'; +import { IIndexingStatus } from '../types'; + import { IndexingStatusContent } from './indexing_status_content'; import { IndexingStatusErrors } from './indexing_status_errors'; import { IndexingStatusLogic } from './indexing_status_logic'; -import { IIndexingStatus } from '../types'; - export interface IIndexingStatusProps { viewLinkPath: string; itemId: string; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/indexing_status/indexing_status_content.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/indexing_status/indexing_status_content.test.tsx index a744ddf8b5290..8998e640d6c35 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/indexing_status/indexing_status_content.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/indexing_status/indexing_status_content.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; import { EuiProgress, EuiTitle } from '@elastic/eui'; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/indexing_status/indexing_status_errors.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/indexing_status/indexing_status_errors.test.tsx index 3747fe020af20..eb5fa9d70f026 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/indexing_status/indexing_status_errors.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/indexing_status/indexing_status_errors.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; import { EuiCallOut } from '@elastic/eui'; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/indexing_status/indexing_status_logic.ts b/x-pack/plugins/enterprise_search/public/applications/shared/indexing_status/indexing_status_logic.ts index 11ba1304d0a22..a436b669bcbe5 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/indexing_status/indexing_status_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/indexing_status/indexing_status_logic.ts @@ -7,9 +7,9 @@ import { kea, MakeLogicType } from 'kea'; +import { flashAPIErrors } from '../flash_messages'; import { HttpLogic } from '../http'; import { IIndexingStatus } from '../types'; -import { flashAPIErrors } from '../flash_messages'; interface IndexingStatusProps { statusPath: string; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.test.ts index 10b550fc93eb3..a5f54d16b2fad 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.test.ts @@ -5,10 +5,10 @@ * 2.0. */ -import { resetContext } from 'kea'; - import { mockKibanaValues } from '../../__mocks__'; +import { resetContext } from 'kea'; + import { KibanaLogic, mountKibanaLogic } from './kibana_logic'; describe('KibanaLogic', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.ts b/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.ts index 4bb1859df09ea..8015d22f7c44a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.ts @@ -5,12 +5,13 @@ * 2.0. */ -import { kea, MakeLogicType } from 'kea'; - import { FC } from 'react'; + import { History } from 'history'; -import { ApplicationStart, ChromeBreadcrumb } from 'src/core/public'; -import { ChartsPluginStart } from 'src/plugins/charts/public'; +import { kea, MakeLogicType } from 'kea'; + +import { ApplicationStart, ChromeBreadcrumb } from '../../../../../../../src/core/public'; +import { ChartsPluginStart } from '../../../../../../../src/plugins/charts/public'; import { CloudSetup } from '../../../../../cloud/public'; import { HttpLogic } from '../http'; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/generate_breadcrumbs.ts b/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/generate_breadcrumbs.ts index 64f53c767b17c..908cc0601ab9c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/generate_breadcrumbs.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/generate_breadcrumbs.ts @@ -6,10 +6,8 @@ */ import { useValues } from 'kea'; -import { EuiBreadcrumb } from '@elastic/eui'; -import { KibanaLogic } from '../kibana'; -import { HttpLogic } from '../http'; +import { EuiBreadcrumb } from '@elastic/eui'; import { ENTERPRISE_SEARCH_PLUGIN, @@ -18,6 +16,8 @@ import { } from '../../../../common/constants'; import { stripLeadingSlash } from '../../../../common/strip_slashes'; +import { HttpLogic } from '../http'; +import { KibanaLogic } from '../kibana'; import { letBrowserHandleEvent, createHref } from '../react_router_helpers'; /** diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/set_chrome.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/set_chrome.test.tsx index 5b1aa64c42d64..c9743e6824018 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/set_chrome.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/set_chrome.test.tsx @@ -9,6 +9,7 @@ import '../../__mocks__/shallow_useeffect.mock'; import { setMockValues, mockKibanaValues, mockHistory } from '../../__mocks__'; import React from 'react'; + import { shallow } from 'enzyme'; jest.mock('./generate_breadcrumbs', () => ({ diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/set_chrome.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/set_chrome.tsx index fa127566b1b02..e639f9d22fb4b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/set_chrome.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/set_chrome.tsx @@ -6,6 +6,7 @@ */ import React, { useEffect } from 'react'; + import { useValues } from 'kea'; import { KibanaLogic } from '../kibana'; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/layout/layout.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/layout/layout.test.tsx index c67518e977de2..28092f75cdede 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/layout/layout.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/layout/layout.test.tsx @@ -6,7 +6,9 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiPageSideBar, EuiButton, EuiPageBody, EuiCallOut } from '@elastic/eui'; import { Layout, INavContext } from './layout'; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/layout/layout.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/layout/layout.tsx index 1af85905e6ccb..9cf5fccddbd5b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/layout/layout.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/layout/layout.tsx @@ -6,6 +6,7 @@ */ import React, { useState } from 'react'; + import classNames from 'classnames'; import { EuiPage, EuiPageSideBar, EuiPageBody, EuiButton, EuiCallOut } from '@elastic/eui'; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/layout/side_nav.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/layout/side_nav.test.tsx index ceb5f21ce056f..451b49738029d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/layout/side_nav.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/layout/side_nav.test.tsx @@ -9,11 +9,13 @@ import '../../__mocks__/react_router_history.mock'; import React from 'react'; import { useLocation } from 'react-router-dom'; + import { shallow } from 'enzyme'; import { EuiLink } from '@elastic/eui'; -import { EuiLinkTo } from '../react_router_helpers'; + import { ENTERPRISE_SEARCH_PLUGIN, APP_SEARCH_PLUGIN } from '../../../../common/constants'; +import { EuiLinkTo } from '../react_router_helpers'; import { SideNav, SideNavLink, SideNavItem } from './'; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/layout/side_nav.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/layout/side_nav.tsx index 605d3940a8cc7..58a5c7bbb229f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/layout/side_nav.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/layout/side_nav.tsx @@ -7,14 +7,15 @@ import React, { useContext } from 'react'; import { useLocation } from 'react-router-dom'; + import classNames from 'classnames'; -import { i18n } from '@kbn/i18n'; import { EuiIcon, EuiTitle, EuiText, EuiLink } from '@elastic/eui'; // TODO: Remove EuiLink after full Kibana transition -import { EuiLinkTo } from '../react_router_helpers'; +import { i18n } from '@kbn/i18n'; import { ENTERPRISE_SEARCH_PLUGIN } from '../../../../common/constants'; import { stripTrailingSlash } from '../../../../common/strip_slashes'; +import { EuiLinkTo } from '../react_router_helpers'; import { NavContext, INavContext } from './layout'; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/loading/loading.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/loading/loading.test.tsx index c443467d5cb32..eab5694a27968 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/loading/loading.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/loading/loading.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; import { EuiLoadingSpinner } from '@elastic/eui'; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/loading/loading.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/loading/loading.tsx index cfcbeaee72095..27a4dfdec0c07 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/loading/loading.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/loading/loading.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { EuiLoadingSpinner } from '@elastic/eui'; import './loading.scss'; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/not_found/not_found.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/not_found/not_found.test.tsx index 0bda848bc8d6c..7e75b2b47bb7a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/not_found/not_found.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/not_found/not_found.test.tsx @@ -8,12 +8,14 @@ import { setMockValues } from '../../__mocks__/kea.mock'; import React from 'react'; + import { shallow } from 'enzyme'; import { EuiButton as EuiButtonExternal, EuiEmptyPrompt } from '@elastic/eui'; import { APP_SEARCH_PLUGIN, WORKPLACE_SEARCH_PLUGIN } from '../../../../common/constants'; import { SetAppSearchChrome } from '../kibana_chrome'; + import { AppSearchLogo } from './assets/app_search_logo'; import { WorkplaceSearchLogo } from './assets/workplace_search_logo'; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/not_found/not_found.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/not_found/not_found.tsx index 6102987464f55..5699568c40558 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/not_found/not_found.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/not_found/not_found.tsx @@ -6,8 +6,9 @@ */ import React from 'react'; + import { useValues } from 'kea'; -import { i18n } from '@kbn/i18n'; + import { EuiPageContent, EuiEmptyPrompt, @@ -16,6 +17,7 @@ import { EuiFlexItem, EuiButton, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { APP_SEARCH_PLUGIN, @@ -23,11 +25,11 @@ import { LICENSED_SUPPORT_URL, } from '../../../../common/constants'; -import { EuiButtonTo } from '../react_router_helpers'; -import { BreadcrumbTrail } from '../kibana_chrome/generate_breadcrumbs'; import { SetAppSearchChrome, SetWorkplaceSearchChrome } from '../kibana_chrome'; -import { SendAppSearchTelemetry, SendWorkplaceSearchTelemetry } from '../telemetry'; +import { BreadcrumbTrail } from '../kibana_chrome/generate_breadcrumbs'; import { LicensingLogic } from '../licensing'; +import { EuiButtonTo } from '../react_router_helpers'; +import { SendAppSearchTelemetry, SendWorkplaceSearchTelemetry } from '../telemetry'; import { AppSearchLogo } from './assets/app_search_logo'; import { WorkplaceSearchLogo } from './assets/workplace_search_logo'; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/create_href.test.ts b/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/create_href.test.ts index 0619dab19e2bd..fe2973cfdee32 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/create_href.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/create_href.test.ts @@ -5,9 +5,10 @@ * 2.0. */ -import { httpServiceMock } from 'src/core/public/mocks'; import { mockHistory } from '../../__mocks__'; +import { httpServiceMock } from 'src/core/public/mocks'; + import { createHref } from './'; describe('createHref', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/create_href.ts b/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/create_href.ts index e36a65c2457db..ea28fc4d440c5 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/create_href.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/create_href.ts @@ -6,6 +6,7 @@ */ import { History } from 'history'; + import { HttpSetup } from 'src/core/public'; /** diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/eui_components.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/eui_components.test.tsx index 4de43ce997b48..75639ffeb9d6b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/eui_components.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/eui_components.test.tsx @@ -7,11 +7,13 @@ import '../../__mocks__/kea.mock'; +import { mockKibanaValues, mockHistory } from '../../__mocks__'; + import React from 'react'; + import { shallow, mount } from 'enzyme'; -import { EuiLink, EuiButton, EuiButtonEmpty, EuiPanel, EuiCard } from '@elastic/eui'; -import { mockKibanaValues, mockHistory } from '../../__mocks__'; +import { EuiLink, EuiButton, EuiButtonEmpty, EuiPanel, EuiCard } from '@elastic/eui'; import { EuiLinkTo, EuiButtonTo, EuiButtonEmptyTo, EuiPanelTo, EuiCardTo } from './eui_components'; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/eui_components.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/eui_components.tsx index 384eb79c993c1..b9fee9d16273b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/eui_components.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/eui_components.tsx @@ -6,7 +6,9 @@ */ import React from 'react'; + import { useValues } from 'kea'; + import { EuiLink, EuiButton, @@ -20,8 +22,9 @@ import { } from '@elastic/eui'; import { EuiPanelProps } from '@elastic/eui/src/components/panel/panel'; -import { KibanaLogic } from '../kibana'; import { HttpLogic } from '../http'; +import { KibanaLogic } from '../kibana'; + import { letBrowserHandleEvent, createHref } from './'; /** diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/schema/schema_add_field_modal.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/schema/schema_add_field_modal.test.tsx index c0bd1f3671f15..88c170b059d9c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/schema/schema_add_field_modal.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/schema/schema_add_field_modal.test.tsx @@ -6,16 +6,17 @@ */ import React from 'react'; + import { shallow, mount } from 'enzyme'; +import { EuiFieldText, EuiModal, EuiSelect } from '@elastic/eui'; + import { NUMBER } from '../constants/field_types'; import { FIELD_NAME_CORRECTED_PREFIX } from './constants'; import { SchemaAddFieldModal } from './'; -import { EuiFieldText, EuiModal, EuiSelect } from '@elastic/eui'; - describe('SchemaAddFieldModal', () => { const addNewField = jest.fn(); const closeAddFieldModal = jest.fn(); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/schema/schema_errors_accordion.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/schema/schema_errors_accordion.test.tsx index b1fde05906d44..a82f9e9b6113b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/schema/schema_errors_accordion.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/schema/schema_errors_accordion.test.tsx @@ -6,11 +6,13 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; import { EuiAccordion, EuiTableRow } from '@elastic/eui'; import { EuiLinkTo } from '../react_router_helpers'; + import { SchemaErrorsAccordion } from './schema_errors_accordion'; describe('SchemaErrorsAccordion', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/schema/schema_existing_field.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/schema/schema_existing_field.test.tsx index 62f66bc95a5eb..5e89dce24bd4a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/schema/schema_existing_field.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/schema/schema_existing_field.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; import { EuiSelect } from '@elastic/eui'; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/setup_guide/cloud/instructions.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/setup_guide/cloud/instructions.test.tsx index 5d69a8ea84acf..0136f9745c322 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/setup_guide/cloud/instructions.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/setup_guide/cloud/instructions.test.tsx @@ -5,11 +5,13 @@ * 2.0. */ +import { mountWithIntl } from '../../../__mocks__'; + import React from 'react'; + import { shallow } from 'enzyme'; -import { EuiSteps, EuiLink } from '@elastic/eui'; -import { mountWithIntl } from '../../../__mocks__'; +import { EuiSteps, EuiLink } from '@elastic/eui'; import { CloudSetupInstructions } from './instructions'; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/setup_guide/cloud/instructions.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/setup_guide/cloud/instructions.tsx index 24ba5bd4e5d0a..b355c88943a54 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/setup_guide/cloud/instructions.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/setup_guide/cloud/instructions.tsx @@ -6,9 +6,10 @@ */ import React from 'react'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { i18n } from '@kbn/i18n'; + import { EuiPageContent, EuiSteps, EuiText, EuiLink, EuiCallOut } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; import { docLinks } from '../../doc_links'; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/setup_guide/instructions.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/setup_guide/instructions.test.tsx index 74fb74ce8cf70..fd31ca720b82b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/setup_guide/instructions.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/setup_guide/instructions.test.tsx @@ -5,11 +5,13 @@ * 2.0. */ +import { mountWithIntl } from '../../__mocks__'; + import React from 'react'; + import { shallow } from 'enzyme'; -import { EuiSteps, EuiLink } from '@elastic/eui'; -import { mountWithIntl } from '../../__mocks__'; +import { EuiSteps, EuiLink } from '@elastic/eui'; import { SetupInstructions } from './instructions'; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/setup_guide/instructions.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/setup_guide/instructions.tsx index 83c244ea24ff1..5e39d1acdf189 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/setup_guide/instructions.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/setup_guide/instructions.tsx @@ -6,8 +6,7 @@ */ import React from 'react'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { i18n } from '@kbn/i18n'; + import { EuiPageContent, EuiSpacer, @@ -18,6 +17,8 @@ import { EuiAccordion, EuiLink, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; interface Props { productName: string; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/setup_guide/setup_guide.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/setup_guide/setup_guide.test.tsx index 0b70bb70f8441..90ddddd7d20aa 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/setup_guide/setup_guide.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/setup_guide/setup_guide.test.tsx @@ -8,11 +8,13 @@ import { setMockValues, rerender } from '../../__mocks__'; import React from 'react'; + import { shallow, ShallowWrapper } from 'enzyme'; + import { EuiIcon } from '@elastic/eui'; -import { SetupInstructions } from './instructions'; import { CloudSetupInstructions } from './cloud/instructions'; +import { SetupInstructions } from './instructions'; import { SetupGuideLayout } from './'; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/setup_guide/setup_guide.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/setup_guide/setup_guide.tsx index a0e89bfd8e57d..2140b3392abae 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/setup_guide/setup_guide.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/setup_guide/setup_guide.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { useValues } from 'kea'; import { @@ -22,9 +23,9 @@ import { import { KibanaLogic } from '../kibana'; -import { SetupInstructions } from './instructions'; import { CloudSetupInstructions } from './cloud/instructions'; import { SETUP_GUIDE_TITLE } from './constants'; +import { SetupInstructions } from './instructions'; import './setup_guide.scss'; /** diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/table_header/table_header.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/table_header/table_header.test.tsx index d2588ed8d4aca..a481f22095aa3 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/table_header/table_header.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/table_header/table_header.test.tsx @@ -6,7 +6,9 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiTableHeader, EuiTableHeaderCell } from '@elastic/eui'; import { TableHeader } from './table_header'; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/telemetry/send_telemetry.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/telemetry/send_telemetry.test.tsx index 60f4d404a917a..5fc8074d0a4d7 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/telemetry/send_telemetry.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/telemetry/send_telemetry.test.tsx @@ -9,6 +9,7 @@ import '../../__mocks__/shallow_useeffect.mock'; import { mockTelemetryActions } from '../../__mocks__'; import React from 'react'; + import { shallow } from 'enzyme'; import { diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/telemetry/send_telemetry.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/telemetry/send_telemetry.tsx index e0f54a9e421bf..1759b4075deca 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/telemetry/send_telemetry.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/telemetry/send_telemetry.tsx @@ -6,6 +6,7 @@ */ import React, { useEffect } from 'react'; + import { useActions } from 'kea'; import { TelemetryLogic, SendTelemetryHelper } from './telemetry_logic'; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/telemetry/telemetry_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/shared/telemetry/telemetry_logic.test.ts index 52aec2c384adb..e516daedc1ba6 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/telemetry/telemetry_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/telemetry/telemetry_logic.test.ts @@ -5,9 +5,10 @@ * 2.0. */ -import { JSON_HEADER as headers } from '../../../../common/constants'; import { LogicMounter, mockHttpValues } from '../../__mocks__'; +import { JSON_HEADER as headers } from '../../../../common/constants'; + import { TelemetryLogic } from './telemetry_logic'; describe('Telemetry logic', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/truncate/truncate.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/truncate/truncate.test.tsx index 71ed60cbd1c93..f9bf55b4fe800 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/truncate/truncate.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/truncate/truncate.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; import { TruncatedContent } from './'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/__mocks__/content_sources.mock.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/__mocks__/content_sources.mock.ts index c249f5ee20588..ce92f62d3a017 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/__mocks__/content_sources.mock.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/__mocks__/content_sources.mock.ts @@ -5,10 +5,11 @@ * 2.0. */ -import { mergeServerAndStaticData } from '../views/content_sources/sources_logic'; -import { staticSourceData } from '../views/content_sources/source_data'; import { groups } from './groups.mock'; +import { staticSourceData } from '../views/content_sources/source_data'; +import { mergeServerAndStaticData } from '../views/content_sources/sources_logic'; + export const contentSources = [ { id: '123', diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/app_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/app_logic.test.ts index f1e6ca237681f..8ba94e83d26cf 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/app_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/app_logic.test.ts @@ -5,9 +5,9 @@ * 2.0. */ +import { DEFAULT_INITIAL_APP_DATA } from '../../../common/__mocks__'; import { LogicMounter } from '../__mocks__'; -import { DEFAULT_INITIAL_APP_DATA } from '../../../common/__mocks__'; import { AppLogic } from './app_logic'; describe('AppLogic', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/layout/kibana_header_actions.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/layout/kibana_header_actions.test.tsx index c2c645ebe439a..a7a788b48789a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/layout/kibana_header_actions.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/layout/kibana_header_actions.test.tsx @@ -5,12 +5,14 @@ * 2.0. */ -import { externalUrl } from '../../../shared/enterprise_search_url'; - import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiButtonEmpty } from '@elastic/eui'; +import { externalUrl } from '../../../shared/enterprise_search_url'; + import { WorkplaceSearchHeaderActions } from './'; describe('WorkplaceSearchHeaderActions', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/layout/kibana_header_actions.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/layout/kibana_header_actions.tsx index c1912deb8d40a..c79865d25ecd7 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/layout/kibana_header_actions.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/layout/kibana_header_actions.tsx @@ -6,10 +6,10 @@ */ import React from 'react'; + import { EuiButtonEmpty, EuiText } from '@elastic/eui'; import { externalUrl, getWorkplaceSearchUrl } from '../../../shared/enterprise_search_url'; - import { NAV } from '../../constants'; export const WorkplaceSearchHeaderActions: React.FC = () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/layout/nav.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/layout/nav.test.tsx index d2b2da1a48176..8f37f608f4e28 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/layout/nav.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/layout/nav.test.tsx @@ -8,9 +8,11 @@ import '../../../__mocks__/enterprise_search_url.mock'; import React from 'react'; + import { shallow } from 'enzyme'; import { SideNav, SideNavLink } from '../../../shared/layout'; + import { WorkplaceSearchNav } from './'; describe('WorkplaceSearchNav', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/layout/nav.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/layout/nav.tsx index 2696e5acf1c12..c184247b253d6 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/layout/nav.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/layout/nav.tsx @@ -12,9 +12,7 @@ import { EuiSpacer } from '@elastic/eui'; import { WORKPLACE_SEARCH_PLUGIN } from '../../../../../common/constants'; import { getWorkplaceSearchUrl } from '../../../shared/enterprise_search_url'; import { SideNav, SideNavLink } from '../../../shared/layout'; - import { NAV } from '../../constants'; - import { SOURCES_PATH, SECURITY_PATH, diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/api_key/api_key.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/api_key/api_key.test.tsx index 66e9ac9ed7a8b..32f21c158736f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/api_key/api_key.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/api_key/api_key.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; import { EuiCodeBlock, EuiFormLabel } from '@elastic/eui'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/component_loader/component_loader.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/component_loader/component_loader.test.tsx index cb3fc32432999..991c7a061b4bb 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/component_loader/component_loader.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/component_loader/component_loader.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; import { EuiLoadingSpinner, EuiTextColor } from '@elastic/eui'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/content_section/content_section.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/content_section/content_section.test.tsx index c21e8b8d3449f..21280926d7aae 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/content_section/content_section.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/content_section/content_section.test.tsx @@ -6,12 +6,15 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiSpacer } from '@elastic/eui'; -import { ContentSection } from './'; import { ViewContentHeader } from '../view_content_header'; +import { ContentSection } from './'; + const props = { children:
, testSubj: 'contentSection', diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/content_section/content_section.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/content_section/content_section.tsx index b0ab18bbfde95..e606263ac6f1c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/content_section/content_section.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/content_section/content_section.tsx @@ -10,7 +10,6 @@ import React from 'react'; import { EuiSpacer } from '@elastic/eui'; import { SpacerSizeTypes } from '../../../types'; - import { ViewContentHeader } from '../view_content_header'; import './content_section.scss'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/credential_item/credential_item.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/credential_item/credential_item.test.tsx index 79c4abdf2e223..13e2a229b3a76 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/credential_item/credential_item.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/credential_item/credential_item.test.tsx @@ -6,6 +6,7 @@ */ import * as React from 'react'; + import { shallow } from 'enzyme'; import { EuiCopy, EuiButtonIcon, EuiFieldText } from '@elastic/eui'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/license_badge/license_badge.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/license_badge/license_badge.test.tsx index 4e38894766d86..6deb37d850076 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/license_badge/license_badge.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/license_badge/license_badge.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; import { EuiBadge } from '@elastic/eui'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/license_callout/license_callout.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/license_callout/license_callout.test.tsx index d8266127a0f42..6a69178ad07da 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/license_callout/license_callout.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/license_callout/license_callout.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; import { EuiLink, EuiText } from '@elastic/eui'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/product_button/product_button.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/product_button/product_button.test.tsx index 5ef191d0d0fe8..0bced6a7fc4e0 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/product_button/product_button.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/product_button/product_button.test.tsx @@ -9,7 +9,9 @@ import '../../../../__mocks__/kea.mock'; import { mockTelemetryActions } from '../../../../__mocks__'; import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiButton } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/product_button/product_button.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/product_button/product_button.tsx index ded4278c35e14..3611bfb2a3f69 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/product_button/product_button.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/product_button/product_button.tsx @@ -6,13 +6,14 @@ */ import React from 'react'; + import { useActions } from 'kea'; import { EuiButton, EuiButtonProps, EuiLinkProps } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { TelemetryLogic } from '../../../../shared/telemetry'; import { getWorkplaceSearchUrl } from '../../../../shared/enterprise_search_url'; +import { TelemetryLogic } from '../../../../shared/telemetry'; export const ProductButton: React.FC = () => { const { sendWorkplaceSearchTelemetry } = useActions(TelemetryLogic); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/source_config_fields/source_config_fields.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/source_config_fields/source_config_fields.test.tsx index e5cd2bb2e0461..9af91107d7304 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/source_config_fields/source_config_fields.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/source_config_fields/source_config_fields.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; import { ApiKey } from '../api_key'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/source_config_fields/source_config_fields.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/source_config_fields/source_config_fields.tsx index 8c6e2b0174eb0..236d475b8f687 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/source_config_fields/source_config_fields.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/source_config_fields/source_config_fields.tsx @@ -16,7 +16,6 @@ import { CLIENT_ID_LABEL, CLIENT_SECRET_LABEL, } from '../../../constants'; - import { ApiKey } from '../api_key'; import { CredentialItem } from '../credential_item'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/source_icon/source_icon.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/source_icon/source_icon.test.tsx index f8cf9d63915d6..3bea6f224dc2b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/source_icon/source_icon.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/source_icon/source_icon.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; import { EuiIcon } from '@elastic/eui'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/source_row/source_row.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/source_row/source_row.test.tsx index cfac7148bf88a..9661471bb1dd7 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/source_row/source_row.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/source_row/source_row.test.tsx @@ -5,11 +5,13 @@ * 2.0. */ +import { contentSources } from '../../../__mocks__/content_sources.mock'; + import React from 'react'; + import { shallow } from 'enzyme'; import { EuiTableRow, EuiSwitch, EuiIcon } from '@elastic/eui'; -import { contentSources } from '../../../__mocks__/content_sources.mock'; import { SourceIcon } from '../source_icon'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/source_row/source_row.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/source_row/source_row.tsx index 11d71481751b0..6cfc68b45ee3c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/source_row/source_row.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/source_row/source_row.tsx @@ -26,14 +26,13 @@ import { import { EuiLinkTo } from '../../../../shared/react_router_helpers'; import { SOURCE_STATUSES as statuses } from '../../../constants'; -import { ContentSourceDetails } from '../../../types'; import { ADD_SOURCE_PATH, SOURCE_DETAILS_PATH, getContentSourcePath, getSourcesPath, } from '../../../routes'; - +import { ContentSourceDetails } from '../../../types'; import { SourceIcon } from '../source_icon'; import './source_row.scss'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/sources_table/sources_table.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/sources_table/sources_table.test.tsx index efe529bcfb289..f54f7ccdf24bd 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/sources_table/sources_table.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/sources_table/sources_table.test.tsx @@ -5,13 +5,15 @@ * 2.0. */ +import { contentSources } from '../../../__mocks__/content_sources.mock'; + import React from 'react'; + import { shallow } from 'enzyme'; import { EuiTable } from '@elastic/eui'; -import { TableHeader } from '../../../../shared/table_header/table_header'; -import { contentSources } from '../../../__mocks__/content_sources.mock'; +import { TableHeader } from '../../../../shared/table_header/table_header'; import { SourceRow } from '../source_row'; import { SourcesTable } from './'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/sources_table/sources_table.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/sources_table/sources_table.tsx index a0aba097d17f4..66e7e2e752a1e 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/sources_table/sources_table.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/sources_table/sources_table.tsx @@ -10,8 +10,8 @@ import React from 'react'; import { EuiTable, EuiTableBody } from '@elastic/eui'; import { TableHeader } from '../../../../shared/table_header/table_header'; -import { SourceRow, ISourceRow } from '../source_row'; import { ContentSourceDetails } from '../../../types'; +import { SourceRow, ISourceRow } from '../source_row'; interface SourcesTableProps extends ISourceRow { sources: ContentSourceDetails[]; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/table_pagination_bar/table_pagination_bar.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/table_pagination_bar/table_pagination_bar.test.tsx index 343c9b68bc834..d22ddcce49dc4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/table_pagination_bar/table_pagination_bar.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/table_pagination_bar/table_pagination_bar.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; import { EuiFlexGroup, EuiTablePagination } from '@elastic/eui'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/user_icon/user_icon.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/user_icon/user_icon.test.tsx index d8046bd88cf4a..5ce83b641cf8f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/user_icon/user_icon.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/user_icon/user_icon.test.tsx @@ -5,10 +5,11 @@ * 2.0. */ +import { users } from '../../../__mocks__/users.mock'; + import React from 'react'; -import { shallow } from 'enzyme'; -import { users } from '../../../__mocks__/users.mock'; +import { shallow } from 'enzyme'; import { UserIcon } from './user_icon'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/user_row/user_row.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/user_row/user_row.test.tsx index fe2bfd27db55a..f15c74ed1054b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/user_row/user_row.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/user_row/user_row.test.tsx @@ -5,13 +5,14 @@ * 2.0. */ +import { users } from '../../../__mocks__/users.mock'; + import React from 'react'; + import { shallow } from 'enzyme'; import { EuiTableRow } from '@elastic/eui'; -import { users } from '../../../__mocks__/users.mock'; - import { UserRow } from './'; describe('SourcesTable', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/view_content_header/view_content_header.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/view_content_header/view_content_header.test.tsx index 01a05a5d94c75..fda1a27e103c2 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/view_content_header/view_content_header.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/view_content_header/view_content_header.test.tsx @@ -6,7 +6,9 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiFlexGroup } from '@elastic/eui'; import { ViewContentHeader } from './'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/view_content_header/view_content_header.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/view_content_header/view_content_header.tsx index ed2989de5ce3c..fa3a1d3ccb2e4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/view_content_header/view_content_header.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/view_content_header/view_content_header.tsx @@ -8,7 +8,6 @@ import React from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiText, EuiTitle, EuiSpacer } from '@elastic/eui'; - import { FlexGroupAlignItems } from '@elastic/eui/src/components/flex/flex_group'; interface ViewContentHeaderProps { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.test.tsx index 73ee7662888bb..5678ad545d50d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.test.tsx @@ -10,13 +10,15 @@ import { setMockValues, setMockActions, mockKibanaValues } from '../__mocks__'; import React from 'react'; import { Redirect } from 'react-router-dom'; + import { shallow } from 'enzyme'; import { Layout } from '../shared/layout'; + import { WorkplaceSearchHeaderActions } from './components/layout'; -import { SetupGuide } from './views/setup_guide'; import { ErrorState } from './views/error_state'; import { Overview } from './views/overview'; +import { SetupGuide } from './views/setup_guide'; import { WorkplaceSearch, WorkplaceSearchUnconfigured, WorkplaceSearchConfigured } from './'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.tsx index a4c12f1d71d4e..d690dee4dc98c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.tsx @@ -7,16 +7,18 @@ import React, { useEffect } from 'react'; import { Route, Redirect, Switch, useLocation } from 'react-router-dom'; + import { useActions, useValues } from 'kea'; import { WORKPLACE_SEARCH_PLUGIN } from '../../../common/constants'; import { InitialAppData } from '../../../common/types'; -import { KibanaLogic } from '../shared/kibana'; import { HttpLogic } from '../shared/http'; -import { AppLogic } from './app_logic'; +import { KibanaLogic } from '../shared/kibana'; import { Layout } from '../shared/layout'; -import { WorkplaceSearchNav, WorkplaceSearchHeaderActions } from './components/layout'; +import { NotFound } from '../shared/not_found'; +import { AppLogic } from './app_logic'; +import { WorkplaceSearchNav, WorkplaceSearchHeaderActions } from './components/layout'; import { GROUPS_PATH, SETUP_GUIDE_PATH, @@ -25,19 +27,16 @@ import { ORG_SETTINGS_PATH, SECURITY_PATH, } from './routes'; - -import { SetupGuide } from './views/setup_guide'; +import { SourcesRouter } from './views/content_sources'; +import { SourceSubNav } from './views/content_sources/components/source_sub_nav'; import { ErrorState } from './views/error_state'; -import { NotFound } from '../shared/not_found'; -import { Overview } from './views/overview'; import { GroupsRouter } from './views/groups'; +import { GroupSubNav } from './views/groups/components/group_sub_nav'; +import { Overview } from './views/overview'; import { Security } from './views/security'; -import { SourcesRouter } from './views/content_sources'; import { SettingsRouter } from './views/settings'; - -import { GroupSubNav } from './views/groups/components/group_sub_nav'; -import { SourceSubNav } from './views/content_sources/components/source_sub_nav'; import { SettingsSubNav } from './views/settings/components/settings_sub_nav'; +import { SetupGuide } from './views/setup_guide'; export const WorkplaceSearch: React.FC = (props) => { const { config } = useValues(KibanaLogic); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/routes.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/routes.test.tsx index d9c1dbeefad92..68bec94270a01 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/routes.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/routes.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; import { EuiLink } from '@elastic/eui'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source.test.tsx index aa219a475406f..41f53523bca4e 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source.test.tsx @@ -7,10 +7,10 @@ import '../../../../../__mocks__/shallow_useeffect.mock'; import { mockKibanaValues, setMockActions, setMockValues } from '../../../../../__mocks__'; - import { sourceConfigData } from '../../../../__mocks__/content_sources.mock'; import React from 'react'; + import { shallow } from 'enzyme'; import { Loading } from '../../../../../shared/loading'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source.tsx index 0664c930775bc..b00f9807f0acd 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source.tsx @@ -9,16 +9,16 @@ import React, { useEffect } from 'react'; import { useActions, useValues } from 'kea'; -import { AppLogic } from '../../../../app_logic'; import { KibanaLogic } from '../../../../../shared/kibana'; import { Loading } from '../../../../../shared/loading'; +import { AppLogic } from '../../../../app_logic'; import { CUSTOM_SERVICE_TYPE } from '../../../../constants'; -import { staticSourceData } from '../../source_data'; -import { AddSourceLogic, AddSourceProps, AddSourceSteps } from './add_source_logic'; -import { SourceDataItem } from '../../../../types'; import { SOURCE_ADDED_PATH, getSourcesPath } from '../../../../routes'; +import { SourceDataItem } from '../../../../types'; +import { staticSourceData } from '../../source_data'; import { AddSourceHeader } from './add_source_header'; +import { AddSourceLogic, AddSourceProps, AddSourceSteps } from './add_source_logic'; import { ConfigCompleted } from './config_completed'; import { ConfigurationIntro } from './configuration_intro'; import { ConfigureCustom } from './configure_custom'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_header.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_header.test.tsx index 7167fcf3bc252..879f7993f3dc1 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_header.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_header.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; import { EuiText, EuiTextColor } from '@elastic/eui'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_list.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_list.test.tsx index fe24eeb5c7cb5..90da349ea4f27 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_list.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_list.test.tsx @@ -14,23 +14,23 @@ import { } from '../../../../__mocks__/content_sources.mock'; import React from 'react'; + import { shallow } from 'enzyme'; import { EuiEmptyPrompt, EuiFieldSearch } from '@elastic/eui'; -import { Loading } from '../../../../../../applications/shared/loading'; +import { Loading } from '../../../../../shared/loading'; import { ViewContentHeader } from '../../../../components/shared/view_content_header'; +import { AddSourceList } from './add_source_list'; +import { AvailableSourcesList } from './available_sources_list'; +import { ConfiguredSourcesList } from './configured_sources_list'; import { ADD_SOURCE_NEW_SOURCE_DESCRIPTION, ADD_SOURCE_ORG_SOURCE_DESCRIPTION, ADD_SOURCE_PRIVATE_SOURCE_DESCRIPTION, } from './constants'; -import { AddSourceList } from './add_source_list'; -import { AvailableSourcesList } from './available_sources_list'; -import { ConfiguredSourcesList } from './configured_sources_list'; - describe('AddSourceList', () => { const initializeSources = jest.fn(); const resetSourcesState = jest.fn(); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_list.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_list.tsx index 3a0db0f44047d..372187485f277 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_list.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_list.tsx @@ -18,15 +18,18 @@ import { EuiPanel, EuiEmptyPrompt, } from '@elastic/eui'; -import noSharedSourcesIcon from '../../../../assets/share_circle.svg'; +import { Loading } from '../../../../../shared/loading'; import { AppLogic } from '../../../../app_logic'; +import noSharedSourcesIcon from '../../../../assets/share_circle.svg'; import { ContentSection } from '../../../../components/shared/content_section'; import { ViewContentHeader } from '../../../../components/shared/view_content_header'; -import { Loading } from '../../../../../../applications/shared/loading'; import { CUSTOM_SERVICE_TYPE } from '../../../../constants'; import { SourceDataItem } from '../../../../types'; +import { SourcesLogic } from '../../sources_logic'; +import { AvailableSourcesList } from './available_sources_list'; +import { ConfiguredSourcesList } from './configured_sources_list'; import { ADD_SOURCE_NEW_SOURCE_DESCRIPTION, ADD_SOURCE_ORG_SOURCE_DESCRIPTION, @@ -39,10 +42,6 @@ import { ADD_SOURCE_EMPTY_BODY, } from './constants'; -import { SourcesLogic } from '../../sources_logic'; -import { AvailableSourcesList } from './available_sources_list'; -import { ConfiguredSourcesList } from './configured_sources_list'; - export const AddSourceList: React.FC = () => { const { contentSources, dataLoading, availableSources, configuredSources } = useValues( SourcesLogic diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_logic.test.ts index a3fd35503ea0d..ed67eb9994bc8 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_logic.test.ts @@ -11,20 +11,18 @@ import { mockHttpValues, mockKibanaValues, } from '../../../../../__mocks__'; +import { sourceConfigData } from '../../../../__mocks__/content_sources.mock'; + +import { nextTick } from '@kbn/test/jest'; -import { AppLogic } from '../../../../app_logic'; jest.mock('../../../../app_logic', () => ({ AppLogic: { values: { isOrganization: true } }, })); +import { AppLogic } from '../../../../app_logic'; -import { SourcesLogic } from '../../sources_logic'; - -import { nextTick } from '@kbn/test/jest'; - -import { CustomSource } from '../../../../types'; import { SOURCES_PATH, getSourcesPath } from '../../../../routes'; - -import { sourceConfigData } from '../../../../__mocks__/content_sources.mock'; +import { CustomSource } from '../../../../types'; +import { SourcesLogic } from '../../sources_logic'; import { AddSourceLogic, diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_logic.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_logic.ts index f10e81487567e..4e996aff6f5b0 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_logic.ts @@ -5,33 +5,27 @@ * 2.0. */ -import { keys, pickBy } from 'lodash'; - -import { kea, MakeLogicType } from 'kea'; - import { Search } from 'history'; +import { kea, MakeLogicType } from 'kea'; +import { keys, pickBy } from 'lodash'; import { i18n } from '@kbn/i18n'; - import { HttpFetchQuery } from 'src/core/public'; -import { HttpLogic } from '../../../../../shared/http'; -import { KibanaLogic } from '../../../../../shared/kibana'; -import { parseQueryParams } from '../../../../../shared/query_params'; - import { flashAPIErrors, setSuccessMessage, clearFlashMessages, } from '../../../../../shared/flash_messages'; - -import { staticSourceData } from '../../source_data'; -import { SOURCES_PATH, getSourcesPath } from '../../../../routes'; -import { CUSTOM_SERVICE_TYPE, WORKPLACE_SEARCH_URL_PREFIX } from '../../../../constants'; - +import { HttpLogic } from '../../../../../shared/http'; +import { KibanaLogic } from '../../../../../shared/kibana'; +import { parseQueryParams } from '../../../../../shared/query_params'; import { AppLogic } from '../../../../app_logic'; -import { SourcesLogic } from '../../sources_logic'; +import { CUSTOM_SERVICE_TYPE, WORKPLACE_SEARCH_URL_PREFIX } from '../../../../constants'; +import { SOURCES_PATH, getSourcesPath } from '../../../../routes'; import { CustomSource } from '../../../../types'; +import { staticSourceData } from '../../source_data'; +import { SourcesLogic } from '../../sources_logic'; export interface AddSourceProps { sourceIndex: number; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/available_sources_list.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/available_sources_list.test.tsx index 43f1486644c72..fcb55f24ddb03 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/available_sources_list.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/available_sources_list.test.tsx @@ -7,10 +7,10 @@ import '../../../../../__mocks__/shallow_useeffect.mock'; import { setMockValues } from '../../../../../__mocks__'; - import { mergedAvailableSources } from '../../../../__mocks__/content_sources.mock'; import React from 'react'; + import { shallow } from 'enzyme'; import { EuiCard, EuiToolTip, EuiTitle } from '@elastic/eui'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/available_sources_list.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/available_sources_list.tsx index 8060f765a91b0..fafc1ea54a6cf 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/available_sources_list.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/available_sources_list.tsx @@ -7,7 +7,7 @@ import React from 'react'; -import { i18n } from '@kbn/i18n'; +import { useValues } from 'kea'; import { EuiCard, @@ -18,15 +18,13 @@ import { EuiText, EuiToolTip, } from '@elastic/eui'; - -import { useValues } from 'kea'; +import { i18n } from '@kbn/i18n'; import { LicensingLogic } from '../../../../../shared/licensing'; import { EuiLinkTo } from '../../../../../shared/react_router_helpers'; - import { SourceIcon } from '../../../../components/shared/source_icon'; -import { SourceDataItem } from '../../../../types'; import { ADD_CUSTOM_PATH, getSourcesPath } from '../../../../routes'; +import { SourceDataItem } from '../../../../types'; import { AVAILABLE_SOURCE_EMPTY_STATE, diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_completed.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_completed.test.tsx index cd40da7f6b376..163da5297e370 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_completed.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_completed.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; import { ConfigCompleted } from './config_completed'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_completed.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_completed.tsx index bd85b3c7c2dd5..1d4f1f2fca980 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_completed.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_completed.tsx @@ -7,9 +7,6 @@ import React from 'react'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; - import { EuiButton, EuiFlexGroup, @@ -20,7 +17,10 @@ import { EuiText, EuiTextAlign, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiLinkTo, EuiButtonTo } from '../../../../../shared/react_router_helpers'; import { getSourcesPath, ADD_SOURCE_PATH, @@ -28,8 +28,6 @@ import { PRIVATE_SOURCES_DOCS_URL, } from '../../../../routes'; -import { EuiLinkTo, EuiButtonTo } from '../../../../../shared/react_router_helpers'; - import { CONFIG_COMPLETED_PRIVATE_SOURCES_DOCS_LINK, CONFIG_COMPLETED_CONFIGURE_NEW_BUTTON, diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_docs_links.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_docs_links.test.tsx index b56f36df5486e..914eca94ad6f3 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_docs_links.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_docs_links.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; import { EuiButtonEmpty } from '@elastic/eui'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_docs_links.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_docs_links.tsx index 259e911d6d54f..043d28e9dba03 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_docs_links.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_docs_links.tsx @@ -7,9 +7,8 @@ import React from 'react'; -import { i18n } from '@kbn/i18n'; - import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { DOCUMENTATION_LINK_TITLE } from '../../../../constants'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configuration_intro.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configuration_intro.test.tsx index 2d26982cbc2f5..2ebc021925abf 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configuration_intro.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configuration_intro.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; import { EuiText, EuiTitle } from '@elastic/eui'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configuration_intro.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configuration_intro.tsx index ff1caafb91bdb..914eee74dfc4e 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configuration_intro.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configuration_intro.tsx @@ -7,9 +7,6 @@ import React from 'react'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; - import { EuiBadge, EuiButton, @@ -20,6 +17,10 @@ import { EuiText, EuiTitle, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; + +import connectionIllustration from '../../../../assets/connection_illustration.svg'; import { CONFIG_INTRO_ALT_TEXT, @@ -31,8 +32,6 @@ import { CONFIG_INTRO_STEP2_TEXT, } from './constants'; -import connectionIllustration from '../../../../assets/connection_illustration.svg'; - interface ConfigurationIntroProps { header: React.ReactNode; name: string; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_custom.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_custom.test.tsx index a3b572737bdeb..099989255bf47 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_custom.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_custom.test.tsx @@ -9,6 +9,7 @@ import '../../../../../__mocks__/shallow_useeffect.mock'; import { setMockActions, setMockValues } from '../../../../../__mocks__'; import React from 'react'; + import { shallow } from 'enzyme'; import { EuiForm, EuiFieldText } from '@elastic/eui'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_custom.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_custom.tsx index 2d0113f1d0e7d..36242f5523e77 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_custom.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_custom.tsx @@ -9,8 +9,6 @@ import React, { ChangeEvent, FormEvent } from 'react'; import { useActions, useValues } from 'kea'; -import { FormattedMessage } from '@kbn/i18n/react'; - import { EuiButton, EuiFieldText, @@ -20,8 +18,10 @@ import { EuiSpacer, EuiText, } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; import { CUSTOM_SOURCE_DOCS_URL } from '../../../../routes'; + import { AddSourceLogic } from './add_source_logic'; import { CONFIG_CUSTOM_BUTTON } from './constants'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_oauth.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_oauth.test.tsx index a57ff390150ea..533dfcda70db1 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_oauth.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_oauth.test.tsx @@ -9,11 +9,12 @@ import '../../../../../__mocks__/shallow_useeffect.mock'; import { setMockActions, setMockValues } from '../../../../../__mocks__'; import React from 'react'; + import { shallow } from 'enzyme'; import { EuiCheckboxGroup } from '@elastic/eui'; -import { Loading } from '../../../../../../applications/shared/loading'; +import { Loading } from '../../../../../shared/loading'; import { ConfigureOauth } from './configure_oauth'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_oauth.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_oauth.tsx index 3eae438eb960c..69a2fbd1495c7 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_oauth.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_oauth.tsx @@ -6,10 +6,10 @@ */ import React, { useEffect, useState, FormEvent } from 'react'; +import { useLocation } from 'react-router-dom'; import { Location } from 'history'; import { useActions, useValues } from 'kea'; -import { useLocation } from 'react-router-dom'; import { EuiButton, @@ -19,13 +19,12 @@ import { EuiFormRow, EuiSpacer, } from '@elastic/eui'; - import { EuiCheckboxGroupIdToSelectedMap } from '@elastic/eui/src/components/form/checkbox/checkbox_group'; -import { parseQueryParams } from '../../../../../../applications/shared/query_params'; -import { Loading } from '../../../../../../applications/shared/loading'; -import { AddSourceLogic } from './add_source_logic'; +import { Loading } from '../../../../../shared/loading'; +import { parseQueryParams } from '../../../../../shared/query_params'; +import { AddSourceLogic } from './add_source_logic'; import { CONFIG_OAUTH_LABEL, CONFIG_OAUTH_BUTTON } from './constants'; interface OauthQueryParams { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configured_sources_list.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configured_sources_list.test.tsx index 3bb7d42748f25..2e2e04556cdb7 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configured_sources_list.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configured_sources_list.test.tsx @@ -5,13 +5,14 @@ * 2.0. */ +import { mergedConfiguredSources } from '../../../../__mocks__/content_sources.mock'; + import React from 'react'; + import { shallow } from 'enzyme'; import { EuiPanel } from '@elastic/eui'; -import { mergedConfiguredSources } from '../../../../__mocks__/content_sources.mock'; - import { ConfiguredSourcesList } from './configured_sources_list'; describe('ConfiguredSourcesList', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configured_sources_list.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configured_sources_list.tsx index cb5e96a4019a1..5f64913410d4c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configured_sources_list.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configured_sources_list.tsx @@ -21,8 +21,8 @@ import { import { EuiButtonEmptyTo } from '../../../../../shared/react_router_helpers'; import { SourceIcon } from '../../../../components/shared/source_icon'; -import { SourceDataItem } from '../../../../types'; import { getSourcesPath } from '../../../../routes'; +import { SourceDataItem } from '../../../../types'; import { CONFIGURED_SOURCES_LIST_UNCONNECTED_TOOLTIP, diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/connect_instance.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/connect_instance.test.tsx index cff95136968db..b795b0af09944 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/connect_instance.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/connect_instance.test.tsx @@ -9,12 +9,14 @@ import '../../../../../__mocks__/shallow_useeffect.mock'; import { setMockActions, setMockValues } from '../../../../../__mocks__'; import React from 'react'; + import { shallow } from 'enzyme'; import { EuiBadge, EuiCallOut, EuiSwitch } from '@elastic/eui'; import { FeatureIds } from '../../../../types'; import { staticSourceData } from '../../source_data'; + import { ConnectInstance } from './connect_instance'; describe('ConnectInstance', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/connect_instance.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/connect_instance.tsx index ea5d556350759..08b29075f3d0d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/connect_instance.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/connect_instance.tsx @@ -8,8 +8,6 @@ import React, { useState, useEffect, FormEvent } from 'react'; import { useActions, useValues } from 'kea'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; import { EuiButton, @@ -27,16 +25,16 @@ import { EuiBadge, EuiBadgeGroup, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; -import { LicensingLogic } from '../../../../../../applications/shared/licensing'; - +import { LicensingLogic } from '../../../../../shared/licensing'; import { AppLogic } from '../../../../app_logic'; -import { AddSourceLogic } from './add_source_logic'; -import { FeatureIds, Configuration, Features } from '../../../../types'; import { DOCUMENT_PERMISSIONS_DOCS_URL } from '../../../../routes'; -import { SourceFeatures } from './source_features'; - +import { FeatureIds, Configuration, Features } from '../../../../types'; import { LEARN_MORE_LINK } from '../../constants'; + +import { AddSourceLogic } from './add_source_logic'; import { CONNECT_REMOTE, CONNECT_PRIVATE, @@ -47,6 +45,7 @@ import { CONNECT_NOT_SYNCED_TITLE, CONNECT_NOT_SYNCED_TEXT, } from './constants'; +import { SourceFeatures } from './source_features'; interface ConnectInstanceProps { header: React.ReactNode; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/re_authenticate.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/re_authenticate.test.tsx index 94c2e734751ee..38b6925008181 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/re_authenticate.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/re_authenticate.test.tsx @@ -9,6 +9,7 @@ import '../../../../../__mocks__/shallow_useeffect.mock'; import { setMockActions, setMockValues } from '../../../../../__mocks__'; import React from 'react'; + import { shallow } from 'enzyme'; import { ReAuthenticate } from './re_authenticate'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/re_authenticate.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/re_authenticate.tsx index 0cdf461f2d64c..eb6736d84a197 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/re_authenticate.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/re_authenticate.tsx @@ -6,14 +6,15 @@ */ import React, { useEffect, useState, FormEvent } from 'react'; +import { useLocation } from 'react-router-dom'; import { Location } from 'history'; import { useActions, useValues } from 'kea'; -import { useLocation } from 'react-router-dom'; -import { i18n } from '@kbn/i18n'; import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiSpacer } from '@elastic/eui'; -import { parseQueryParams } from '../../../../../../applications/shared/query_params'; +import { i18n } from '@kbn/i18n'; + +import { parseQueryParams } from '../../../../../shared/query_params'; import { AddSourceLogic } from './add_source_logic'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_config.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_config.test.tsx index 4d1955d7928a8..c0f7f1139cb73 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_config.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_config.test.tsx @@ -7,18 +7,18 @@ import '../../../../../__mocks__/shallow_useeffect.mock'; import { setMockActions, setMockValues } from '../../../../../__mocks__'; +import { sourceConfigData } from '../../../../__mocks__/content_sources.mock'; import React from 'react'; + import { shallow } from 'enzyme'; import { EuiSteps, EuiButton, EuiButtonEmpty } from '@elastic/eui'; -import { sourceConfigData } from '../../../../__mocks__/content_sources.mock'; +import { ApiKey } from '../../../../components/shared/api_key'; import { staticSourceData } from '../../source_data'; -import { ApiKey } from '../../../../components/shared/api_key'; import { ConfigDocsLinks } from './config_docs_links'; - import { SaveConfig } from './save_config'; describe('SaveConfig', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_config.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_config.tsx index f6d5d0f4066ab..956d5143ef2c5 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_config.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_config.tsx @@ -8,7 +8,6 @@ import React, { FormEvent } from 'react'; import { useActions, useValues } from 'kea'; -import { i18n } from '@kbn/i18n'; import { EuiButton, @@ -21,7 +20,10 @@ import { EuiSpacer, EuiSteps, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { LicensingLogic } from '../../../../../shared/licensing'; +import { ApiKey } from '../../../../components/shared/api_key'; import { PUBLIC_KEY_LABEL, CONSUMER_KEY_LABEL, @@ -31,16 +33,11 @@ import { CLIENT_SECRET_LABEL, REMOVE_BUTTON, } from '../../../../constants'; - -import { OAUTH_SAVE_CONFIG_BUTTON, OAUTH_BACK_BUTTON, OAUTH_STEP_2 } from './constants'; - -import { LicensingLogic } from '../../../../../../applications/shared/licensing'; - -import { ApiKey } from '../../../../components/shared/api_key'; -import { AddSourceLogic } from './add_source_logic'; import { Configuration } from '../../../../types'; +import { AddSourceLogic } from './add_source_logic'; import { ConfigDocsLinks } from './config_docs_links'; +import { OAUTH_SAVE_CONFIG_BUTTON, OAUTH_BACK_BUTTON, OAUTH_STEP_2 } from './constants'; interface SaveConfigProps { header: React.ReactNode; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_custom.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_custom.test.tsx index 551bd7f1bb006..5ed777322cc08 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_custom.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_custom.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; import { EuiLink, EuiPanel, EuiTitle } from '@elastic/eui'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_custom.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_custom.tsx index a61ad1aeb728a..b42bd674109fe 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_custom.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_custom.tsx @@ -7,9 +7,6 @@ import React from 'react'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; - import { EuiFlexGroup, EuiFlexItem, @@ -22,12 +19,12 @@ import { EuiLink, EuiPanel, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; import { EuiLinkTo } from '../../../../../shared/react_router_helpers'; import { CredentialItem } from '../../../../components/shared/credential_item'; import { LicenseBadge } from '../../../../components/shared/license_badge'; - -import { CustomSource } from '../../../../types'; import { SOURCES_PATH, SOURCE_DISPLAY_SETTINGS_PATH, @@ -36,7 +33,7 @@ import { getContentSourcePath, getSourcesPath, } from '../../../../routes'; - +import { CustomSource } from '../../../../types'; import { ACCESS_TOKEN_LABEL, ID_LABEL, LEARN_CUSTOM_FEATURES_BUTTON } from '../../constants'; import { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/source_features.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/source_features.test.tsx index ccc6d05df5f9a..cd8ba37695ac6 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/source_features.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/source_features.test.tsx @@ -11,10 +11,10 @@ import React from 'react'; import { EuiPanel } from '@elastic/eui'; -import { SourceFeatures } from './source_features'; - import { staticSourceData } from '../../source_data'; +import { SourceFeatures } from './source_features'; + describe('SourceFeatures', () => { const { features, objTypes } = staticSourceData[0]; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/source_features.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/source_features.tsx index 186e8fcdc3790..0838ab2ccdae2 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/source_features.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/source_features.tsx @@ -8,7 +8,6 @@ import React from 'react'; import { useValues } from 'kea'; -import { FormattedMessage } from '@kbn/i18n/react'; import { EuiFlexGroup, @@ -19,13 +18,13 @@ import { EuiText, EuiTitle, } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; -import { LicensingLogic } from '../../../../../../applications/shared/licensing'; - +import { LicensingLogic } from '../../../../../shared/licensing'; import { AppLogic } from '../../../../app_logic'; import { LicenseBadge } from '../../../../components/shared/license_badge'; -import { Features, FeatureIds } from '../../../../types'; import { ENT_SEARCH_LICENSE_MANAGEMENT } from '../../../../routes'; +import { Features, FeatureIds } from '../../../../types'; import { SOURCE_FEATURES_SEARCHABLE, diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/custom_source_icon.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/custom_source_icon.test.tsx index 6567f74bd8790..fcce69d70ad50 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/custom_source_icon.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/custom_source_icon.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; import { CustomSourceIcon } from './custom_source_icon'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings.test.tsx index 72744690baf30..feebc7f8d445e 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings.test.tsx @@ -8,24 +8,21 @@ import '../../../../../__mocks__/shallow_useeffect.mock'; import { mockKibanaValues } from '../../../../../__mocks__'; - import { setMockValues, setMockActions } from '../../../../../__mocks__'; import { unmountHandler } from '../../../../../__mocks__/shallow_useeffect.mock'; - -import { shallow } from 'enzyme'; +import { exampleResult } from '../../../../__mocks__/content_sources.mock'; import React from 'react'; -import { EuiButton, EuiTabbedContent } from '@elastic/eui'; +import { shallow } from 'enzyme'; -import { exampleResult } from '../../../../__mocks__/content_sources.mock'; +import { EuiButton, EuiTabbedContent } from '@elastic/eui'; import { Loading } from '../../../../../shared/loading'; import { ViewContentHeader } from '../../../../components/shared/view_content_header'; -import { FieldEditorModal } from './field_editor_modal'; - import { DisplaySettings } from './display_settings'; +import { FieldEditorModal } from './field_editor_modal'; describe('DisplaySettings', () => { const { navigateToUrl } = mockKibanaValues; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings.tsx index 62beb4e40793b..29266cdefe584 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings.tsx @@ -19,21 +19,18 @@ import { EuiTabbedContentTab, } from '@elastic/eui'; +import { clearFlashMessages } from '../../../../../shared/flash_messages'; +import { KibanaLogic } from '../../../../../shared/kibana'; +import { Loading } from '../../../../../shared/loading'; +import { AppLogic } from '../../../../app_logic'; +import { ViewContentHeader } from '../../../../components/shared/view_content_header'; +import { SAVE_BUTTON } from '../../../../constants'; import { DISPLAY_SETTINGS_RESULT_DETAIL_PATH, DISPLAY_SETTINGS_SEARCH_RESULT_PATH, getContentSourcePath, } from '../../../../routes'; -import { clearFlashMessages } from '../../../../../shared/flash_messages'; - -import { KibanaLogic } from '../../../../../shared/kibana'; -import { AppLogic } from '../../../../app_logic'; - -import { Loading } from '../../../../../shared/loading'; -import { ViewContentHeader } from '../../../../components/shared/view_content_header'; - -import { SAVE_BUTTON } from '../../../../constants'; import { UNSAVED_MESSAGE, DISPLAY_SETTINGS_TITLE, @@ -43,9 +40,7 @@ import { SEARCH_RESULTS_LABEL, RESULT_DETAIL_LABEL, } from './constants'; - import { DisplaySettingsLogic } from './display_settings_logic'; - import { FieldEditorModal } from './field_editor_modal'; import { ResultDetail } from './result_detail'; import { SearchResults } from './search_results'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_logic.test.ts index c51f3e97bf155..73df0298ecd19 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_logic.test.ts @@ -5,25 +5,22 @@ * 2.0. */ -import { LogicMounter } from '../../../../../__mocks__/kea.mock'; +import { LogicMounter, mockFlashMessageHelpers, mockHttpValues } from '../../../../../__mocks__'; +import { exampleResult } from '../../../../__mocks__/content_sources.mock'; -import { mockFlashMessageHelpers, mockHttpValues } from '../../../../../__mocks__'; +import { nextTick } from '@kbn/test/jest'; const contentSource = { id: 'source123' }; jest.mock('../../source_logic', () => ({ SourceLogic: { values: { contentSource } }, })); -import { AppLogic } from '../../../../app_logic'; jest.mock('../../../../app_logic', () => ({ AppLogic: { values: { isOrganization: true } }, })); +import { AppLogic } from '../../../../app_logic'; -import { nextTick } from '@kbn/test/jest'; - -import { exampleResult } from '../../../../__mocks__/content_sources.mock'; import { LEAVE_UNASSIGNED_FIELD } from './constants'; - import { DisplaySettingsLogic, defaultSearchResultConfig } from './display_settings_logic'; describe('DisplaySettingsLogic', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_logic.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_logic.ts index 7c5946d08292c..62d959083af59 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_logic.ts @@ -5,24 +5,23 @@ * 2.0. */ -import { cloneDeep, isEqual, differenceBy } from 'lodash'; import { DropResult } from 'react-beautiful-dnd'; import { kea, MakeLogicType } from 'kea'; - -import { HttpLogic } from '../../../../../shared/http'; +import { cloneDeep, isEqual, differenceBy } from 'lodash'; import { setSuccessMessage, clearFlashMessages, flashAPIErrors, } from '../../../../../shared/flash_messages'; - +import { HttpLogic } from '../../../../../shared/http'; import { AppLogic } from '../../../../app_logic'; +import { DetailField, SearchResultConfig, OptionValue, Result } from '../../../../types'; import { SourceLogic } from '../../source_logic'; -import { DetailField, SearchResultConfig, OptionValue, Result } from '../../../../types'; import { LEAVE_UNASSIGNED_FIELD, SUCCESS_MESSAGE } from './constants'; + export interface DisplaySettingsResponseProps { sourceName: string; searchResultConfig: SearchResultConfig; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_router.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_router.test.tsx index f216cbf286b94..f04afe60aa49d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_router.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_router.test.tsx @@ -10,12 +10,11 @@ import '../../../../../__mocks__/shallow_useeffect.mock'; import { setMockValues } from '../../../../../__mocks__'; import React from 'react'; -import { shallow } from 'enzyme'; - import { Route, Switch } from 'react-router-dom'; -import { DisplaySettings } from './display_settings'; +import { shallow } from 'enzyme'; +import { DisplaySettings } from './display_settings'; import { DisplaySettingsRouter } from './display_settings_router'; describe('DisplaySettingsRouter', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_router.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_router.tsx index fa9817494ee09..bd753631ed48c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_router.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_router.tsx @@ -6,12 +6,11 @@ */ import React from 'react'; +import { Route, Switch } from 'react-router-dom'; import { useValues } from 'kea'; -import { Route, Switch } from 'react-router-dom'; import { AppLogic } from '../../../../app_logic'; - import { DISPLAY_SETTINGS_RESULT_DETAIL_PATH, DISPLAY_SETTINGS_SEARCH_RESULT_PATH, diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_result_detail_card.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_result_detail_card.test.tsx index 381e4fe4c0b25..15e1fe0ed417c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_result_detail_card.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_result_detail_card.test.tsx @@ -8,11 +8,11 @@ import '../../../../../__mocks__/shallow_useeffect.mock'; import { setMockValues } from '../../../../../__mocks__'; -import { shallow } from 'enzyme'; +import { exampleResult } from '../../../../__mocks__/content_sources.mock'; import React from 'react'; -import { exampleResult } from '../../../../__mocks__/content_sources.mock'; +import { shallow } from 'enzyme'; import { ExampleResultDetailCard } from './example_result_detail_card'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_result_detail_card.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_result_detail_card.tsx index 46c06f28af6d6..93a7d660215f0 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_result_detail_card.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_result_detail_card.tsx @@ -14,9 +14,8 @@ import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiText, EuiTitle } from '@elasti import { URL_LABEL } from '../../../../constants'; -import { DisplaySettingsLogic } from './display_settings_logic'; - import { CustomSourceIcon } from './custom_source_icon'; +import { DisplaySettingsLogic } from './display_settings_logic'; import { TitleField } from './title_field'; export const ExampleResultDetailCard: React.FC = () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_search_result_group.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_search_result_group.test.tsx index d08195f3e83bc..6f90c1045ae31 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_search_result_group.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_search_result_group.test.tsx @@ -8,14 +8,13 @@ import '../../../../../__mocks__/shallow_useeffect.mock'; import { setMockValues } from '../../../../../__mocks__'; -import { shallow } from 'enzyme'; +import { exampleResult } from '../../../../__mocks__/content_sources.mock'; import React from 'react'; -import { exampleResult } from '../../../../__mocks__/content_sources.mock'; +import { shallow } from 'enzyme'; import { CustomSourceIcon } from './custom_source_icon'; - import { ExampleSearchResultGroup } from './example_search_result_group'; describe('ExampleSearchResultGroup', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_search_result_group.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_search_result_group.tsx index 5d5f73467f82c..df89eed38ae92 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_search_result_group.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_search_result_group.tsx @@ -7,15 +7,15 @@ import React from 'react'; -import { isColorDark, hexToRgb } from '@elastic/eui'; import classNames from 'classnames'; import { useValues } from 'kea'; -import { DESCRIPTION_LABEL } from '../../../../constants'; +import { isColorDark, hexToRgb } from '@elastic/eui'; -import { DisplaySettingsLogic } from './display_settings_logic'; +import { DESCRIPTION_LABEL } from '../../../../constants'; import { CustomSourceIcon } from './custom_source_icon'; +import { DisplaySettingsLogic } from './display_settings_logic'; import { SubtitleField } from './subtitle_field'; import { TitleField } from './title_field'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_standout_result.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_standout_result.test.tsx index 6241bcf05fbff..49845e79d86aa 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_standout_result.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_standout_result.test.tsx @@ -8,14 +8,13 @@ import '../../../../../__mocks__/shallow_useeffect.mock'; import { setMockValues } from '../../../../../__mocks__'; -import { shallow } from 'enzyme'; +import { exampleResult } from '../../../../__mocks__/content_sources.mock'; import React from 'react'; -import { exampleResult } from '../../../../__mocks__/content_sources.mock'; +import { shallow } from 'enzyme'; import { CustomSourceIcon } from './custom_source_icon'; - import { ExampleStandoutResult } from './example_standout_result'; describe('ExampleStandoutResult', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_standout_result.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_standout_result.tsx index 3c139001d3ea2..48c3149e622bd 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_standout_result.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_standout_result.tsx @@ -14,9 +14,8 @@ import { isColorDark, hexToRgb } from '@elastic/eui'; import { DESCRIPTION_LABEL } from '../../../../constants'; -import { DisplaySettingsLogic } from './display_settings_logic'; - import { CustomSourceIcon } from './custom_source_icon'; +import { DisplaySettingsLogic } from './display_settings_logic'; import { SubtitleField } from './subtitle_field'; import { TitleField } from './title_field'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/field_editor_modal.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/field_editor_modal.test.tsx index 82687165d0535..fe7bced843841 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/field_editor_modal.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/field_editor_modal.test.tsx @@ -8,13 +8,13 @@ import '../../../../../__mocks__/shallow_useeffect.mock'; import { setMockValues, setMockActions } from '../../../../../__mocks__'; -import { shallow } from 'enzyme'; +import { exampleResult } from '../../../../__mocks__/content_sources.mock'; import React from 'react'; -import { EuiModal, EuiSelect, EuiFieldText } from '@elastic/eui'; +import { shallow } from 'enzyme'; -import { exampleResult } from '../../../../__mocks__/content_sources.mock'; +import { EuiModal, EuiSelect, EuiFieldText } from '@elastic/eui'; import { FieldEditorModal } from './field_editor_modal'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/result_detail.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/result_detail.test.tsx index 217a8142af5d5..768573ce80fee 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/result_detail.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/result_detail.test.tsx @@ -6,9 +6,8 @@ */ import '../../../../../__mocks__/shallow_useeffect.mock'; - import { setMockValues, setMockActions } from '../../../../../__mocks__'; -import { shallow, mount } from 'enzyme'; +import { exampleResult } from '../../../../__mocks__/content_sources.mock'; /** * Mocking necessary due to console warnings from react d-n-d, which EUI uses @@ -40,12 +39,11 @@ jest.mock('react-beautiful-dnd', () => ({ import React from 'react'; -import { EuiTextColor } from '@elastic/eui'; +import { shallow, mount } from 'enzyme'; -import { exampleResult } from '../../../../__mocks__/content_sources.mock'; +import { EuiTextColor } from '@elastic/eui'; import { ExampleResultDetailCard } from './example_result_detail_card'; - import { ResultDetail } from './result_detail'; describe('ResultDetail', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/result_detail.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/result_detail.tsx index 8382ddc9e82b3..6832f075476e7 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/result_detail.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/result_detail.tsx @@ -28,10 +28,9 @@ import { } from '@elastic/eui'; import { ADD_FIELD_LABEL, EDIT_FIELD_LABEL, REMOVE_FIELD_LABEL } from '../../../../constants'; -import { VISIBLE_FIELDS_TITLE, EMPTY_FIELDS_DESCRIPTION, PREVIEW_TITLE } from './constants'; +import { VISIBLE_FIELDS_TITLE, EMPTY_FIELDS_DESCRIPTION, PREVIEW_TITLE } from './constants'; import { DisplaySettingsLogic } from './display_settings_logic'; - import { ExampleResultDetailCard } from './example_result_detail_card'; export const ResultDetail: React.FC = () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/search_results.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/search_results.test.tsx index 26116a7e736bc..28de0006f162f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/search_results.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/search_results.test.tsx @@ -8,16 +8,15 @@ import '../../../../../__mocks__/shallow_useeffect.mock'; import { setMockValues, setMockActions } from '../../../../../__mocks__'; -import { shallow } from 'enzyme'; +import { exampleResult } from '../../../../__mocks__/content_sources.mock'; import React from 'react'; -import { exampleResult } from '../../../../__mocks__/content_sources.mock'; +import { shallow } from 'enzyme'; +import { LEAVE_UNASSIGNED_FIELD } from './constants'; import { ExampleSearchResultGroup } from './example_search_result_group'; import { ExampleStandoutResult } from './example_standout_result'; - -import { LEAVE_UNASSIGNED_FIELD } from './constants'; import { SearchResults } from './search_results'; describe('SearchResults', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/search_results.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/search_results.tsx index b2ba2b13e5ec3..859fb2d5d2a20 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/search_results.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/search_results.tsx @@ -21,9 +21,8 @@ import { EuiTitle, } from '@elastic/eui'; -import { DisplaySettingsLogic } from './display_settings_logic'; - import { DESCRIPTION_LABEL } from '../../../../constants'; + import { LEAVE_UNASSIGNED_FIELD, SEARCH_RESULTS_TITLE, @@ -34,7 +33,7 @@ import { STANDARD_RESULTS_TITLE, STANDARD_RESULTS_DESCRIPTION, } from './constants'; - +import { DisplaySettingsLogic } from './display_settings_logic'; import { ExampleSearchResultGroup } from './example_search_result_group'; import { ExampleStandoutResult } from './example_standout_result'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/subtitle_field.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/subtitle_field.test.tsx index 812af1b1fd26b..76c28ae3d4060 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/subtitle_field.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/subtitle_field.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; import { SubtitleField } from './subtitle_field'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/title_field.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/title_field.test.tsx index f2a82f058c0de..2ed4aa0b0fad1 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/title_field.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/title_field.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; import { TitleField } from './title_field'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/overview.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/overview.test.tsx index 0e91d2a3a4a28..a30f1bfbd596a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/overview.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/overview.test.tsx @@ -8,14 +8,14 @@ import '../../../../__mocks__/shallow_useeffect.mock'; import { setMockValues } from '../../../../__mocks__'; +import { fullContentSources } from '../../../__mocks__/content_sources.mock'; import React from 'react'; + import { shallow } from 'enzyme'; import { EuiEmptyPrompt, EuiPanel, EuiTable } from '@elastic/eui'; -import { fullContentSources } from '../../../__mocks__/content_sources.mock'; - import { Loading } from '../../../../shared/loading'; import { ComponentLoader } from '../../../components/shared/component_loader'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/overview.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/overview.tsx index a67adfdd3802a..34d7edd99c376 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/overview.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/overview.tsx @@ -9,8 +9,6 @@ import React from 'react'; import { useValues } from 'kea'; -import { FormattedMessage } from '@kbn/i18n/react'; - import { EuiEmptyPrompt, EuiFlexGroup, @@ -30,7 +28,21 @@ import { EuiTextColor, EuiTitle, } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { Loading } from '../../../../shared/loading'; +import { EuiPanelTo } from '../../../../shared/react_router_helpers'; +import { AppLogic } from '../../../app_logic'; +import aclImage from '../../../assets/supports_acl.svg'; +import { ComponentLoader } from '../../../components/shared/component_loader'; +import { CredentialItem } from '../../../components/shared/credential_item'; +import { LicenseBadge } from '../../../components/shared/license_badge'; +import { ViewContentHeader } from '../../../components/shared/view_content_header'; +import { + RECENT_ACTIVITY_TITLE, + CREDENTIALS_TITLE, + DOCUMENTATION_LINK_TITLE, +} from '../../../constants'; import { CUSTOM_SOURCE_DOCS_URL, DOCUMENT_PERMISSIONS_DOCS_URL, @@ -38,12 +50,6 @@ import { EXTERNAL_IDENTITIES_DOCS_URL, getGroupPath, } from '../../../routes'; - -import { - RECENT_ACTIVITY_TITLE, - CREDENTIALS_TITLE, - DOCUMENTATION_LINK_TITLE, -} from '../../../constants'; import { SOURCES_NO_CONTENT_TITLE, CONTENT_SUMMARY_TITLE, @@ -70,17 +76,6 @@ import { DOC_PERMISSIONS_DESCRIPTION, CUSTOM_CALLOUT_TITLE, } from '../constants'; - -import { AppLogic } from '../../../app_logic'; - -import { ComponentLoader } from '../../../components/shared/component_loader'; -import { CredentialItem } from '../../../components/shared/credential_item'; -import { ViewContentHeader } from '../../../components/shared/view_content_header'; -import { LicenseBadge } from '../../../components/shared/license_badge'; -import { Loading } from '../../../../shared/loading'; -import { EuiPanelTo } from '../../../../shared/react_router_helpers'; - -import aclImage from '../../../assets/supports_acl.svg'; import { SourceLogic } from '../source_logic'; export const Overview: React.FC = () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/schema/schema.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/schema/schema.test.tsx index b30c5d78fd42f..ccf3275ffd96f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/schema/schema.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/schema/schema.test.tsx @@ -8,21 +8,20 @@ import '../../../../../__mocks__/shallow_useeffect.mock'; import { setMockValues, setMockActions } from '../../../../../__mocks__'; +import { mostRecentIndexJob } from '../../../../__mocks__/content_sources.mock'; import React from 'react'; + import { shallow } from 'enzyme'; import { EuiEmptyPrompt, EuiFieldSearch } from '@elastic/eui'; -import { mostRecentIndexJob } from '../../../../__mocks__/content_sources.mock'; - import { IndexingStatus } from '../../../../../shared/indexing_status'; import { Loading } from '../../../../../shared/loading'; import { SchemaAddFieldModal } from '../../../../../shared/schema/schema_add_field_modal'; -import { SchemaFieldsTable } from './schema_fields_table'; - import { Schema } from './schema'; +import { SchemaFieldsTable } from './schema_fields_table'; describe('Schema', () => { const initializeSchema = jest.fn(); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/schema/schema.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/schema/schema.tsx index fe48e1c14ff41..77d1002a9ad26 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/schema/schema.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/schema/schema.tsx @@ -20,17 +20,12 @@ import { EuiPanel, } from '@elastic/eui'; -import { getReindexJobRoute } from '../../../../routes'; -import { AppLogic } from '../../../../app_logic'; - +import { IndexingStatus } from '../../../../../shared/indexing_status'; import { Loading } from '../../../../../shared/loading'; -import { ViewContentHeader } from '../../../../components/shared/view_content_header'; - import { SchemaAddFieldModal } from '../../../../../shared/schema/schema_add_field_modal'; -import { IndexingStatus } from '../../../../../shared/indexing_status'; - -import { SchemaFieldsTable } from './schema_fields_table'; -import { SchemaLogic } from './schema_logic'; +import { AppLogic } from '../../../../app_logic'; +import { ViewContentHeader } from '../../../../components/shared/view_content_header'; +import { getReindexJobRoute } from '../../../../routes'; import { SCHEMA_ADD_FIELD_BUTTON, @@ -42,6 +37,8 @@ import { SCHEMA_EMPTY_SCHEMA_TITLE, SCHEMA_EMPTY_SCHEMA_DESCRIPTION, } from './constants'; +import { SchemaFieldsTable } from './schema_fields_table'; +import { SchemaLogic } from './schema_logic'; export const Schema: React.FC = () => { const { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/schema/schema_change_errors.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/schema/schema_change_errors.test.tsx index 421aa04692bd7..e9276b8ec3878 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/schema/schema_change_errors.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/schema/schema_change_errors.test.tsx @@ -10,9 +10,10 @@ import '../../../../../__mocks__/shallow_useeffect.mock'; import { setMockValues, setMockActions } from '../../../../../__mocks__'; import React from 'react'; -import { shallow } from 'enzyme'; import { useParams } from 'react-router-dom'; +import { shallow } from 'enzyme'; + import { SchemaErrorsAccordion } from '../../../../../shared/schema/schema_errors_accordion'; import { SchemaChangeErrors } from './schema_change_errors'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/schema/schema_change_errors.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/schema/schema_change_errors.tsx index a212052e1beba..29cb2b7589220 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/schema/schema_change_errors.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/schema/schema_change_errors.tsx @@ -14,8 +14,9 @@ import { EuiSpacer } from '@elastic/eui'; import { SchemaErrorsAccordion } from '../../../../../shared/schema/schema_errors_accordion'; import { ViewContentHeader } from '../../../../components/shared/view_content_header'; -import { SchemaLogic } from './schema_logic'; + import { SCHEMA_ERRORS_HEADING } from './constants'; +import { SchemaLogic } from './schema_logic'; export const SchemaChangeErrors: React.FC = () => { const { activeReindexJobId, sourceId } = useParams() as { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/schema/schema_fields_table.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/schema/schema_fields_table.test.tsx index a9d6494dcee00..bc0363d55da69 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/schema/schema_fields_table.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/schema/schema_fields_table.test.tsx @@ -10,6 +10,7 @@ import '../../../../../__mocks__/shallow_useeffect.mock'; import { setMockValues, setMockActions } from '../../../../../__mocks__'; import React from 'react'; + import { shallow } from 'enzyme'; import { SchemaExistingField } from '../../../../../shared/schema/schema_existing_field'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/schema/schema_fields_table.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/schema/schema_fields_table.tsx index a683d9384f636..3f56a2cfc745b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/schema/schema_fields_table.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/schema/schema_fields_table.tsx @@ -9,8 +9,6 @@ import React from 'react'; import { useActions, useValues } from 'kea'; -import { i18n } from '@kbn/i18n'; - import { EuiFlexGroup, EuiFlexItem, @@ -21,13 +19,15 @@ import { EuiTableRow, EuiTableRowCell, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { SchemaExistingField } from '../../../../../shared/schema/schema_existing_field'; -import { SchemaLogic } from './schema_logic'; + import { SCHEMA_ERRORS_TABLE_FIELD_NAME_HEADER, SCHEMA_ERRORS_TABLE_DATA_TYPE_HEADER, } from './constants'; +import { SchemaLogic } from './schema_logic'; export const SchemaFieldsTable: React.FC = () => { const { updateExistingFieldType } = useActions(SchemaLogic); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/schema/schema_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/schema/schema_logic.test.ts index 5957822eb8d49..af650d95efaf6 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/schema/schema_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/schema/schema_logic.test.ts @@ -6,6 +6,7 @@ */ import { LogicMounter, mockFlashMessageHelpers, mockHttpValues } from '../../../../../__mocks__'; +import { mostRecentIndexJob } from '../../../../__mocks__/content_sources.mock'; import { nextTick } from '@kbn/test/jest'; @@ -14,7 +15,6 @@ jest.mock('../../source_logic', () => ({ SourceLogic: { values: { contentSource } }, })); -import { AppLogic } from '../../../../app_logic'; jest.mock('../../../../app_logic', () => ({ AppLogic: { values: { isOrganization: true } }, })); @@ -22,16 +22,15 @@ jest.mock('../../../../app_logic', () => ({ const spyScrollTo = jest.fn(); Object.defineProperty(global.window, 'scrollTo', { value: spyScrollTo }); -import { mostRecentIndexJob } from '../../../../__mocks__/content_sources.mock'; import { TEXT } from '../../../../../shared/constants/field_types'; import { ADD, UPDATE } from '../../../../../shared/constants/operations'; +import { AppLogic } from '../../../../app_logic'; import { SCHEMA_FIELD_ERRORS_ERROR_MESSAGE, SCHEMA_FIELD_ADDED_MESSAGE, SCHEMA_UPDATED_MESSAGE, } from './constants'; - import { SchemaLogic, dataTypeOptions } from './schema_logic'; describe('SchemaLogic', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/schema/schema_logic.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/schema/schema_logic.ts index 09b608af43536..9906efe707d85 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/schema/schema_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/schema/schema_logic.ts @@ -5,23 +5,20 @@ * 2.0. */ -import { cloneDeep, isEqual } from 'lodash'; import { kea, MakeLogicType } from 'kea'; - -import { HttpLogic } from '../../../../../shared/http'; +import { cloneDeep, isEqual } from 'lodash'; import { TEXT } from '../../../../../shared/constants/field_types'; import { ADD, UPDATE } from '../../../../../shared/constants/operations'; -import { IndexJob, TOperation, Schema, SchemaTypes } from '../../../../../shared/types'; -import { OptionValue } from '../../../../types'; - import { flashAPIErrors, setSuccessMessage, clearFlashMessages, } from '../../../../../shared/flash_messages'; - +import { HttpLogic } from '../../../../../shared/http'; +import { IndexJob, TOperation, Schema, SchemaTypes } from '../../../../../shared/types'; import { AppLogic } from '../../../../app_logic'; +import { OptionValue } from '../../../../types'; import { SourceLogic } from '../../source_logic'; import { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_added.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_added.test.tsx index d3256a86baebc..ddf89159b2675 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_added.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_added.test.tsx @@ -10,10 +10,10 @@ import '../../../../__mocks__/shallow_useeffect.mock'; import { setMockActions } from '../../../../__mocks__'; import React from 'react'; -import { shallow } from 'enzyme'; - import { useLocation } from 'react-router-dom'; +import { shallow } from 'enzyme'; + import { Loading } from '../../../../shared/loading'; import { SourceAdded } from './source_added'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_added.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_added.tsx index 5901c06b3f66c..5f1d2ed0c81c3 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_added.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_added.tsx @@ -6,10 +6,10 @@ */ import React, { useEffect } from 'react'; +import { useLocation } from 'react-router-dom'; import { Location } from 'history'; import { useActions } from 'kea'; -import { useLocation } from 'react-router-dom'; import { Loading } from '../../../../shared/loading'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_content.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_content.test.tsx index 6a773b81909a3..12399d4822a13 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_content.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_content.test.tsx @@ -8,8 +8,11 @@ import '../../../../__mocks__/shallow_useeffect.mock'; import { setMockValues, setMockActions } from '../../../../__mocks__'; +import { fullContentSources, contentItems } from '../../../__mocks__/content_sources.mock'; +import { meta } from '../../../__mocks__/meta.mock'; import React from 'react'; + import { shallow } from 'enzyme'; import { @@ -21,12 +24,9 @@ import { EuiLink, } from '@elastic/eui'; -import { meta } from '../../../__mocks__/meta.mock'; -import { fullContentSources, contentItems } from '../../../__mocks__/content_sources.mock'; - import { DEFAULT_META } from '../../../../shared/constants'; +import { Loading } from '../../../../shared/loading'; import { ComponentLoader } from '../../../components/shared/component_loader'; -import { Loading } from '../../../../../applications/shared/loading'; import { TablePaginationBar } from '../../../components/shared/table_pagination_bar'; import { SourceContent } from './source_content'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_content.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_content.tsx index 61676279ada03..3dd8ad1dc7899 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_content.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_content.tsx @@ -11,9 +11,6 @@ import { useActions, useValues } from 'kea'; import { startCase } from 'lodash'; import moment from 'moment'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; - import { EuiButton, EuiButtonEmpty, @@ -31,20 +28,17 @@ import { EuiTableRowCell, EuiLink, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; -import { CUSTOM_SOURCE_DOCS_URL } from '../../../routes'; -import { SourceContentItem } from '../../../types'; - +import { Loading } from '../../../../shared/loading'; import { TruncatedContent } from '../../../../shared/truncate'; - -const MAX_LENGTH = 28; - import { ComponentLoader } from '../../../components/shared/component_loader'; -import { Loading } from '../../../../../applications/shared/loading'; import { TablePaginationBar } from '../../../components/shared/table_pagination_bar'; import { ViewContentHeader } from '../../../components/shared/view_content_header'; - import { CUSTOM_SERVICE_TYPE } from '../../../constants'; +import { CUSTOM_SOURCE_DOCS_URL } from '../../../routes'; +import { SourceContentItem } from '../../../types'; import { NO_CONTENT_MESSAGE, CUSTOM_DOCUMENTATION_LINK, @@ -55,9 +49,10 @@ import { SOURCE_CONTENT_TITLE, CONTENT_LOADING_TEXT, } from '../constants'; - import { SourceLogic } from '../source_logic'; +const MAX_LENGTH = 28; + export const SourceContent: React.FC = () => { const [searchTerm, setSearchTerm] = useState(''); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_info_card.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_info_card.test.tsx index 7a8a932f391e1..7c4c02cdc9819 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_info_card.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_info_card.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; import { EuiBadge, EuiHealth, EuiText, EuiTitle } from '@elastic/eui'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_info_card.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_info_card.tsx index 8334c34d6c615..765836191ff00 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_info_card.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_info_card.tsx @@ -18,7 +18,6 @@ import { } from '@elastic/eui'; import { SourceIcon } from '../../../components/shared/source_icon'; - import { REMOTE_SOURCE_LABEL, CREATED_LABEL, STATUS_LABEL, READY_TEXT } from '../constants'; interface SourceInfoCardProps { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_settings.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_settings.test.tsx index d73da79375ffe..f13189afe8252 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_settings.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_settings.test.tsx @@ -8,14 +8,14 @@ import '../../../../__mocks__/shallow_useeffect.mock'; import { setMockValues, setMockActions } from '../../../../__mocks__'; +import { fullContentSources, sourceConfigData } from '../../../__mocks__/content_sources.mock'; import React from 'react'; + import { shallow } from 'enzyme'; import { EuiConfirmModal } from '@elastic/eui'; -import { fullContentSources, sourceConfigData } from '../../../__mocks__/content_sources.mock'; - import { SourceConfigFields } from '../../../components/shared/source_config_fields'; import { SourceSettings } from './source_settings'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_settings.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_settings.tsx index 2fa00c7f029f1..75a1779a1fda8 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_settings.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_settings.tsx @@ -6,12 +6,10 @@ */ import React, { useEffect, useState, ChangeEvent, FormEvent } from 'react'; +import { Link } from 'react-router-dom'; import { useActions, useValues } from 'kea'; import { isEmpty } from 'lodash'; -import { Link } from 'react-router-dom'; - -import { FormattedMessage } from '@kbn/i18n/react'; import { EuiButton, @@ -23,7 +21,12 @@ import { EuiFlexItem, EuiFormRow, } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { AppLogic } from '../../../app_logic'; +import { ContentSection } from '../../../components/shared/content_section'; +import { SourceConfigFields } from '../../../components/shared/source_config_fields'; +import { ViewContentHeader } from '../../../components/shared/view_content_header'; import { CANCEL_BUTTON, OK_BUTTON, @@ -31,6 +34,8 @@ import { SAVE_CHANGES_BUTTON, REMOVE_BUTTON, } from '../../../constants'; +import { SourceDataItem } from '../../../types'; +import { AddSourceLogic } from '../components/add_source/add_source_logic'; import { SOURCE_SETTINGS_TITLE, SOURCE_SETTINGS_DESCRIPTION, @@ -41,16 +46,7 @@ import { SOURCE_REMOVE_TITLE, SOURCE_REMOVE_DESCRIPTION, } from '../constants'; - -import { ContentSection } from '../../../components/shared/content_section'; -import { SourceConfigFields } from '../../../components/shared/source_config_fields'; -import { ViewContentHeader } from '../../../components/shared/view_content_header'; - -import { SourceDataItem } from '../../../types'; -import { AppLogic } from '../../../app_logic'; -import { AddSourceLogic } from '../components/add_source/add_source_logic'; import { staticSourceData } from '../source_data'; - import { SourceLogic } from '../source_logic'; export const SourceSettings: React.FC = () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_sub_nav.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_sub_nav.test.tsx index fe5545668e4ce..59f3bfb0a5611 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_sub_nav.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_sub_nav.test.tsx @@ -8,12 +8,13 @@ import { setMockValues } from '../../../../__mocks__'; import React from 'react'; + import { shallow } from 'enzyme'; +import { SideNavLink } from '../../../../shared/layout'; import { CUSTOM_SERVICE_TYPE } from '../../../constants'; -import { SourceSubNav } from './source_sub_nav'; -import { SideNavLink } from '../../../../shared/layout'; +import { SourceSubNav } from './source_sub_nav'; describe('SourceSubNav', () => { it('renders empty when no group id present', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_sub_nav.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_sub_nav.tsx index 739b9ec138f29..99cebd5ded585 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_sub_nav.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/source_sub_nav.tsx @@ -6,15 +6,12 @@ */ import React from 'react'; + import { useValues } from 'kea'; +import { SideNavLink } from '../../../../shared/layout'; import { AppLogic } from '../../../app_logic'; import { NAV, CUSTOM_SERVICE_TYPE } from '../../../constants'; - -import { SourceLogic } from '../source_logic'; - -import { SideNavLink } from '../../../../shared/layout'; - import { getContentSourcePath, SOURCE_DETAILS_PATH, @@ -23,6 +20,7 @@ import { SOURCE_DISPLAY_SETTINGS_PATH, SOURCE_SETTINGS_PATH, } from '../../../routes'; +import { SourceLogic } from '../source_logic'; export const SourceSubNav: React.FC = () => { const { isOrganization } = useValues(AppLogic); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/organization_sources.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/organization_sources.test.tsx index 68addbacc5a23..b986658f19fb3 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/organization_sources.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/organization_sources.test.tsx @@ -8,18 +8,16 @@ import '../../../__mocks__/shallow_useeffect.mock'; import { setMockValues, setMockActions } from '../../../__mocks__'; - -import { shallow } from 'enzyme'; +import { contentSources } from '../../__mocks__/content_sources.mock'; import React from 'react'; import { Redirect } from 'react-router-dom'; -import { contentSources } from '../../__mocks__/content_sources.mock'; +import { shallow } from 'enzyme'; import { Loading } from '../../../shared/loading'; import { SourcesTable } from '../../components/shared/sources_table'; import { ViewContentHeader } from '../../components/shared/view_content_header'; - import { ADD_SOURCE_PATH, getSourcesPath } from '../../routes'; import { OrganizationSources } from './organization_sources'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/organization_sources.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/organization_sources.tsx index 24c1f130da50d..4559003b4597f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/organization_sources.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/organization_sources.tsx @@ -6,11 +6,16 @@ */ import React, { useEffect } from 'react'; +import { Link, Redirect } from 'react-router-dom'; import { useActions, useValues } from 'kea'; -import { Link, Redirect } from 'react-router-dom'; import { EuiButton } from '@elastic/eui'; + +import { Loading } from '../../../shared/loading'; +import { ContentSection } from '../../components/shared/content_section'; +import { SourcesTable } from '../../components/shared/sources_table'; +import { ViewContentHeader } from '../../components/shared/view_content_header'; import { ADD_SOURCE_PATH, getSourcesPath } from '../../routes'; import { @@ -18,14 +23,7 @@ import { ORG_SOURCES_HEADER_TITLE, ORG_SOURCES_HEADER_DESCRIPTION, } from './constants'; - -import { Loading } from '../../../shared/loading'; -import { ContentSection } from '../../components/shared/content_section'; -import { SourcesTable } from '../../components/shared/sources_table'; -import { ViewContentHeader } from '../../components/shared/view_content_header'; - import { SourcesLogic } from './sources_logic'; - import { SourcesView } from './sources_view'; export const OrganizationSources: React.FC = () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/private_sources.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/private_sources.tsx index d68b451ffa6f5..087681fa89603 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/private_sources.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/private_sources.tsx @@ -12,11 +12,15 @@ import { useActions, useValues } from 'kea'; import { EuiCallOut, EuiEmptyPrompt, EuiSpacer, EuiPanel } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { LicensingLogic } from '../../../../applications/shared/licensing'; - -import { ADD_SOURCE_PATH, getSourcesPath } from '../../routes'; - +import { LicensingLogic } from '../../../shared/licensing'; +import { Loading } from '../../../shared/loading'; +import { EuiButtonTo } from '../../../shared/react_router_helpers'; +import { AppLogic } from '../../app_logic'; import noSharedSourcesIcon from '../../assets/share_circle.svg'; +import { ContentSection } from '../../components/shared/content_section'; +import { SourcesTable } from '../../components/shared/sources_table'; +import { ViewContentHeader } from '../../components/shared/view_content_header'; +import { ADD_SOURCE_PATH, getSourcesPath } from '../../routes'; import { AND, @@ -34,16 +38,8 @@ import { LICENSE_CALLOUT_TITLE, LICENSE_CALLOUT_DESCRIPTION, } from './constants'; - -import { Loading } from '../../../shared/loading'; -import { EuiButtonTo } from '../../../shared/react_router_helpers'; -import { ContentSection } from '../../components/shared/content_section'; -import { SourcesTable } from '../../components/shared/sources_table'; -import { ViewContentHeader } from '../../components/shared/view_content_header'; - -import { AppLogic } from '../../app_logic'; -import { SourcesView } from './sources_view'; import { SourcesLogic } from './sources_logic'; +import { SourcesView } from './sources_view'; // TODO: Remove this after links in Kibana sidenav interface SidebarLink { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/source_data.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/source_data.tsx index 5b34603bca68f..cdad8e07a88be 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/source_data.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/source_data.tsx @@ -7,6 +7,7 @@ import { i18n } from '@kbn/i18n'; +import { SOURCE_NAMES, SOURCE_OBJ_TYPES, GITHUB_LINK_TITLE } from '../../constants'; import { ADD_BOX_PATH, ADD_CONFLUENCE_PATH, @@ -62,11 +63,8 @@ import { ZENDESK_DOCS_URL, CUSTOM_SOURCE_DOCS_URL, } from '../../routes'; - import { FeatureIds, SourceDataItem } from '../../types'; -import { SOURCE_NAMES, SOURCE_OBJ_TYPES, GITHUB_LINK_TITLE } from '../../constants'; - const connectStepDescription = { attachments: i18n.translate( 'xpack.enterpriseSearch.workplaceSearch.sources.connectStepDescription.attachments', diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/source_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/source_logic.test.ts index 15df7ddc99395..d20d0576d11ce 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/source_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/source_logic.test.ts @@ -12,16 +12,16 @@ import { mockKibanaValues, expectedAsyncError, } from '../../../__mocks__'; +import { fullContentSources, contentItems } from '../../__mocks__/content_sources.mock'; +import { meta } from '../../__mocks__/meta.mock'; + +import { DEFAULT_META } from '../../../shared/constants'; -import { AppLogic } from '../../app_logic'; jest.mock('../../app_logic', () => ({ AppLogic: { values: { isOrganization: true } }, })); +import { AppLogic } from '../../app_logic'; -import { fullContentSources, contentItems } from '../../__mocks__/content_sources.mock'; -import { meta } from '../../__mocks__/meta.mock'; - -import { DEFAULT_META } from '../../../shared/constants'; import { NOT_FOUND_PATH } from '../../routes'; import { SourceLogic } from './source_logic'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/source_logic.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/source_logic.ts index c1f5d6033543f..72700ce42c75d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/source_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/source_logic.ts @@ -9,17 +9,15 @@ import { kea, MakeLogicType } from 'kea'; import { i18n } from '@kbn/i18n'; -import { HttpLogic } from '../../../shared/http'; -import { KibanaLogic } from '../../../shared/kibana'; - +import { DEFAULT_META } from '../../../shared/constants'; import { flashAPIErrors, setSuccessMessage, setQueuedSuccessMessage, clearFlashMessages, } from '../../../shared/flash_messages'; - -import { DEFAULT_META } from '../../../shared/constants'; +import { HttpLogic } from '../../../shared/http'; +import { KibanaLogic } from '../../../shared/kibana'; import { AppLogic } from '../../app_logic'; import { NOT_FOUND_PATH, SOURCES_PATH, getSourcesPath } from '../../routes'; import { ContentSourceFullData, Meta, DocumentSummaryItem, SourceContentItem } from '../../types'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/source_router.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/source_router.test.tsx index cf3c075d0c1e9..004f7e5e45bfa 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/source_router.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/source_router.test.tsx @@ -8,20 +8,17 @@ import '../../../__mocks__/shallow_useeffect.mock'; import { setMockValues, setMockActions } from '../../../__mocks__'; +import { contentSources } from '../../__mocks__/content_sources.mock'; import React from 'react'; -import { shallow } from 'enzyme'; import { useParams } from 'react-router-dom'; - import { Route, Switch } from 'react-router-dom'; -import { contentSources } from '../../__mocks__/content_sources.mock'; +import { shallow } from 'enzyme'; import { SetWorkplaceSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; - -import { NAV } from '../../constants'; - import { Loading } from '../../../shared/loading'; +import { NAV } from '../../constants'; import { DisplaySettingsRouter } from './components/display_settings'; import { Overview } from './components/overview'; @@ -29,7 +26,6 @@ import { Schema } from './components/schema'; import { SchemaChangeErrors } from './components/schema/schema_change_errors'; import { SourceContent } from './components/source_content'; import { SourceSettings } from './components/source_settings'; - import { SourceRouter } from './source_router'; describe('SourceRouter', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/source_router.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/source_router.tsx index ac450441f8783..ef9788efbdaf2 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/source_router.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/source_router.tsx @@ -6,24 +6,19 @@ */ import React, { useEffect } from 'react'; +import { Route, Switch, useParams } from 'react-router-dom'; import { useActions, useValues } from 'kea'; import moment from 'moment'; -import { Route, Switch, useParams } from 'react-router-dom'; import { EuiButton, EuiCallOut, EuiHorizontalRule, EuiSpacer } from '@elastic/eui'; import { SetWorkplaceSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; +import { Loading } from '../../../shared/loading'; import { SendWorkplaceSearchTelemetry as SendTelemetry } from '../../../shared/telemetry'; - +import { AppLogic } from '../../app_logic'; import { NAV } from '../../constants'; - -import { - SOURCE_DISABLED_CALLOUT_TITLE, - SOURCE_DISABLED_CALLOUT_DESCRIPTION, - SOURCE_DISABLED_CALLOUT_BUTTON, -} from './constants'; - +import { CUSTOM_SERVICE_TYPE } from '../../constants'; import { ENT_SEARCH_LICENSE_MANAGEMENT, REINDEX_JOB_PATH, @@ -36,13 +31,6 @@ import { getSourcesPath, } from '../../routes'; -import { AppLogic } from '../../app_logic'; - -import { Loading } from '../../../shared/loading'; - -import { CUSTOM_SERVICE_TYPE } from '../../constants'; -import { SourceLogic } from './source_logic'; - import { DisplaySettingsRouter } from './components/display_settings'; import { Overview } from './components/overview'; import { Schema } from './components/schema'; @@ -50,6 +38,12 @@ import { SchemaChangeErrors } from './components/schema/schema_change_errors'; import { SourceContent } from './components/source_content'; import { SourceInfoCard } from './components/source_info_card'; import { SourceSettings } from './components/source_settings'; +import { + SOURCE_DISABLED_CALLOUT_TITLE, + SOURCE_DISABLED_CALLOUT_DESCRIPTION, + SOURCE_DISABLED_CALLOUT_BUTTON, +} from './constants'; +import { SourceLogic } from './source_logic'; export const SourceRouter: React.FC = () => { const { sourceId } = useParams() as { sourceId: string }; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_logic.test.ts index b7db569eb704c..13844f51b2319 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_logic.test.ts @@ -11,13 +11,12 @@ import { mockHttpValues, expectedAsyncError, } from '../../../__mocks__'; +import { configuredSources, contentSources } from '../../__mocks__/content_sources.mock'; -import { AppLogic } from '../../app_logic'; jest.mock('../../app_logic', () => ({ AppLogic: { values: { isOrganization: true } }, })); - -import { configuredSources, contentSources } from '../../__mocks__/content_sources.mock'; +import { AppLogic } from '../../app_logic'; import { SourcesLogic, fetchSourceStatuses, POLLING_INTERVAL } from './sources_logic'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_logic.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_logic.ts index 5108ed45501f7..9de2b447619a6 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_logic.ts @@ -5,22 +5,18 @@ * 2.0. */ -import { cloneDeep, findIndex } from 'lodash'; - import { kea, MakeLogicType } from 'kea'; +import { cloneDeep, findIndex } from 'lodash'; import { i18n } from '@kbn/i18n'; -import { HttpLogic } from '../../../shared/http'; - import { flashAPIErrors, setQueuedSuccessMessage } from '../../../shared/flash_messages'; - +import { HttpLogic } from '../../../shared/http'; +import { AppLogic } from '../../app_logic'; import { Connector, ContentSourceDetails, ContentSourceStatus, SourceDataItem } from '../../types'; import { staticSourceData } from './source_data'; -import { AppLogic } from '../../app_logic'; - interface ServerStatuses { [key: string]: string; } diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_router.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_router.test.tsx index b1a6ea128ac8c..2438061c67759 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_router.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_router.test.tsx @@ -10,10 +10,10 @@ import '../../../__mocks__/shallow_useeffect.mock'; import { setMockValues, setMockActions } from '../../../__mocks__'; import React from 'react'; -import { shallow } from 'enzyme'; - import { Route, Switch, Redirect } from 'react-router-dom'; +import { shallow } from 'enzyme'; + import { ADD_SOURCE_PATH, PERSONAL_SOURCES_PATH, SOURCES_PATH, getSourcesPath } from '../../routes'; import { SourcesRouter } from './sources_router'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_router.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_router.tsx index 28ad2fe3a3965..b7857cf4612a2 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_router.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_router.tsx @@ -6,16 +6,16 @@ */ import React, { useEffect } from 'react'; +import { Redirect, Route, Switch, useLocation } from 'react-router-dom'; import { Location } from 'history'; import { useActions, useValues } from 'kea'; -import { Redirect, Route, Switch, useLocation } from 'react-router-dom'; +import { FlashMessages } from '../../../shared/flash_messages'; import { SetWorkplaceSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; +import { LicensingLogic } from '../../../shared/licensing'; import { SendWorkplaceSearchTelemetry as SendTelemetry } from '../../../shared/telemetry'; - -import { LicensingLogic } from '../../../../applications/shared/licensing'; - +import { AppLogic } from '../../app_logic'; import { NAV } from '../../constants'; import { ADD_SOURCE_PATH, @@ -26,17 +26,13 @@ import { getSourcesPath, } from '../../routes'; -import { FlashMessages } from '../../../shared/flash_messages'; - -import { AppLogic } from '../../app_logic'; -import { staticSourceData } from './source_data'; -import { SourcesLogic } from './sources_logic'; - import { AddSource, AddSourceList } from './components/add_source'; import { SourceAdded } from './components/source_added'; import { OrganizationSources } from './organization_sources'; import { PrivateSources } from './private_sources'; +import { staticSourceData } from './source_data'; import { SourceRouter } from './source_router'; +import { SourcesLogic } from './sources_logic'; import './sources.scss'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_view.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_view.test.tsx index 742d19ebbd156..06d7ecff50299 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_view.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_view.test.tsx @@ -9,10 +9,10 @@ import '../../../__mocks__/shallow_useeffect.mock'; import { setMockValues, setMockActions } from '../../../__mocks__'; -import { shallow } from 'enzyme'; - import React from 'react'; +import { shallow } from 'enzyme'; + import { EuiModal } from '@elastic/eui'; import { Loading } from '../../../shared/loading'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_view.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_view.tsx index ac70d74cc3d78..c62f0b00258d6 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_view.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_view.tsx @@ -9,9 +9,6 @@ import React from 'react'; import { useActions, useValues } from 'kea'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; - import { EuiButton, EuiLink, @@ -25,10 +22,11 @@ import { EuiOverlayMask, EuiText, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; import { Loading } from '../../../shared/loading'; import { SourceIcon } from '../../components/shared/source_icon'; - import { EXTERNAL_IDENTITIES_DOCS_URL, DOCUMENT_PERMISSIONS_DOCS_URL } from '../../routes'; import { @@ -36,7 +34,6 @@ import { DOCUMENT_PERMISSIONS_LINK, UNDERSTAND_BUTTON, } from './constants'; - import { SourcesLogic } from './sources_logic'; interface SourcesViewProps { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/error_state/error_state.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/error_state/error_state.test.tsx index 0408bbf3e7e84..a8fcdfd7cb257 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/error_state/error_state.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/error_state/error_state.test.tsx @@ -6,9 +6,11 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; import { ErrorStatePrompt } from '../../../shared/error_state'; + import { ErrorState } from './'; describe('ErrorState', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/error_state/error_state.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/error_state/error_state.tsx index 74e52912b551b..8116d55542820 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/error_state/error_state.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/error_state/error_state.tsx @@ -8,6 +8,7 @@ // TODO: Remove EuiPage & EuiPageBody before exposing full app import React from 'react'; + import { EuiPage, EuiPageBody, EuiPageContent } from '@elastic/eui'; import { WORKPLACE_SEARCH_PLUGIN } from '../../../../../common/constants'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/__mocks__/groups_logic.mock.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/__mocks__/groups_logic.mock.ts index 3df7fbb5a0596..0e072210d2489 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/__mocks__/groups_logic.mock.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/__mocks__/groups_logic.mock.ts @@ -5,9 +5,8 @@ * 2.0. */ -import { ContentSource, User, Group } from '../../../types'; - import { DEFAULT_META } from '../../../../shared/constants'; +import { ContentSource, User, Group } from '../../../types'; export const mockGroupsValues = { groups: [] as Group[], diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/add_group_modal.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/add_group_modal.test.tsx index 1065c2c2df4c3..26ac5e484f0d7 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/add_group_modal.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/add_group_modal.test.tsx @@ -8,12 +8,13 @@ import { setMockValues, setMockActions } from '../../../../__mocks__'; import React from 'react'; -import { shallow } from 'enzyme'; -import { AddGroupModal } from './add_group_modal'; +import { shallow } from 'enzyme'; import { EuiModal, EuiOverlayMask } from '@elastic/eui'; +import { AddGroupModal } from './add_group_modal'; + describe('AddGroupModal', () => { const closeNewGroupModal = jest.fn(); const saveNewGroup = jest.fn(); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/add_group_modal.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/add_group_modal.tsx index f49c978d06e90..fb82e9393f2a2 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/add_group_modal.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/add_group_modal.tsx @@ -8,7 +8,6 @@ import React from 'react'; import { useActions, useValues } from 'kea'; -import { i18n } from '@kbn/i18n'; import { EuiButton, @@ -22,9 +21,9 @@ import { EuiModalHeaderTitle, EuiOverlayMask, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { CANCEL_BUTTON } from '../../../constants'; - import { GroupsLogic } from '../groups_logic'; const ADD_GROUP_HEADER = i18n.translate( diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/clear_filters_link.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/clear_filters_link.test.tsx index 2dffe89f38569..9118bc5e7adf3 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/clear_filters_link.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/clear_filters_link.test.tsx @@ -8,12 +8,13 @@ import { setMockActions } from '../../../../__mocks__'; import React from 'react'; -import { shallow } from 'enzyme'; -import { ClearFiltersLink } from './clear_filters_link'; +import { shallow } from 'enzyme'; import { EuiLink } from '@elastic/eui'; +import { ClearFiltersLink } from './clear_filters_link'; + describe('ClearFiltersLink', () => { const resetGroupsFilters = jest.fn(); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/clear_filters_link.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/clear_filters_link.tsx index 3734148ea3afa..6aeb2241bca61 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/clear_filters_link.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/clear_filters_link.tsx @@ -8,9 +8,9 @@ import React from 'react'; import { useActions } from 'kea'; -import { i18n } from '@kbn/i18n'; import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiLink } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { GroupsLogic } from '../groups_logic'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/filterable_users_list.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/filterable_users_list.test.tsx index 965a4887f4359..a460070772d1f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/filterable_users_list.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/filterable_users_list.test.tsx @@ -8,14 +8,15 @@ import { users } from '../../../__mocks__/users.mock'; import React from 'react'; + import { shallow } from 'enzyme'; import { EuiFieldSearch, EuiFilterSelectItem, EuiCard, EuiPopoverTitle } from '@elastic/eui'; -import { FilterableUsersList } from './filterable_users_list'; - import { User } from '../../../types'; +import { FilterableUsersList } from './filterable_users_list'; + const mockSetState = jest.fn(); const useStateMock: any = (initState: any) => [initState, mockSetState]; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/filterable_users_list.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/filterable_users_list.tsx index ef222e934260b..8a7875b5e8310 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/filterable_users_list.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/filterable_users_list.tsx @@ -7,8 +7,6 @@ import React, { useState } from 'react'; -import { i18n } from '@kbn/i18n'; - import { EuiCard, EuiFieldSearch, @@ -17,6 +15,7 @@ import { EuiPopoverTitle, EuiSpacer, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { User } from '../../../types'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/filterable_users_popover.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/filterable_users_popover.test.tsx index 36a99425c9793..1813b766b9875 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/filterable_users_popover.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/filterable_users_popover.test.tsx @@ -9,13 +9,14 @@ import { setMockActions } from '../../../../__mocks__'; import { users } from '../../../__mocks__/users.mock'; import React from 'react'; -import { shallow } from 'enzyme'; -import { FilterableUsersPopover } from './filterable_users_popover'; -import { FilterableUsersList } from './filterable_users_list'; +import { shallow } from 'enzyme'; import { EuiFilterGroup, EuiPopover } from '@elastic/eui'; +import { FilterableUsersList } from './filterable_users_list'; +import { FilterableUsersPopover } from './filterable_users_popover'; + const closePopover = jest.fn(); const addFilteredUser = jest.fn(); const removeFilteredUser = jest.fn(); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/filterable_users_popover.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/filterable_users_popover.tsx index b47232197c47f..3cf4d97c781d9 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/filterable_users_popover.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/filterable_users_popover.tsx @@ -12,8 +12,8 @@ import { useActions } from 'kea'; import { EuiFilterGroup, EuiPopover } from '@elastic/eui'; import { User } from '../../../types'; - import { GroupsLogic } from '../groups_logic'; + import { FilterableUsersList } from './filterable_users_list'; interface FilterableUsersPopoverProps { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_manager_modal.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_manager_modal.test.tsx index 8ee14b7c82cc4..949ae9d502e73 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_manager_modal.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_manager_modal.test.tsx @@ -6,16 +6,17 @@ */ import { setMockValues } from '../../../../__mocks__'; -import { groups } from '../../../__mocks__/groups.mock'; import { contentSources } from '../../../__mocks__/content_sources.mock'; +import { groups } from '../../../__mocks__/groups.mock'; import React from 'react'; -import { shallow } from 'enzyme'; -import { GroupManagerModal } from './group_manager_modal'; +import { shallow } from 'enzyme'; import { EuiOverlayMask, EuiModal, EuiEmptyPrompt } from '@elastic/eui'; +import { GroupManagerModal } from './group_manager_modal'; + const hideModal = jest.fn(); const selectAll = jest.fn(); const saveItems = jest.fn(); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_manager_modal.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_manager_modal.tsx index ae5c042fc27dc..b4317ed9bd417 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_manager_modal.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_manager_modal.tsx @@ -9,8 +9,6 @@ import React from 'react'; import { useValues } from 'kea'; -import { i18n } from '@kbn/i18n'; - import { EuiButton, EuiButtonEmpty, @@ -26,15 +24,13 @@ import { EuiOverlayMask, EuiSpacer, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { EuiButtonTo } from '../../../../shared/react_router_helpers'; - -import { Group } from '../../../types'; +import noSharedSourcesIcon from '../../../assets/share_circle.svg'; import { CANCEL_BUTTON } from '../../../constants'; import { SOURCES_PATH } from '../../../routes'; - -import noSharedSourcesIcon from '../../../assets/share_circle.svg'; - +import { Group } from '../../../types'; import { GroupLogic } from '../group_logic'; import { GroupsLogic } from '../groups_logic'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_overview.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_overview.test.tsx index ea49ae09f3a25..e39d72a861b6f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_overview.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_overview.test.tsx @@ -9,21 +9,22 @@ import { setMockActions, setMockValues } from '../../../../__mocks__'; import { groups } from '../../../__mocks__/groups.mock'; import React from 'react'; + import { shallow } from 'enzyme'; +import { EuiFieldText } from '@elastic/eui'; + +import { Loading } from '../../../../shared/loading'; +import { ContentSection } from '../../../components/shared/content_section'; +import { SourcesTable } from '../../../components/shared/sources_table'; +import { ViewContentHeader } from '../../../components/shared/view_content_header'; + import { GroupOverview, EMPTY_SOURCES_DESCRIPTION, EMPTY_USERS_DESCRIPTION, } from './group_overview'; -import { ContentSection } from '../../../components/shared/content_section'; -import { ViewContentHeader } from '../../../components/shared/view_content_header'; -import { SourcesTable } from '../../../components/shared/sources_table'; -import { Loading } from '../../../../shared/loading'; - -import { EuiFieldText } from '@elastic/eui'; - const deleteGroup = jest.fn(); const showSharedSourcesModal = jest.fn(); const showManageUsersModal = jest.fn(); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_overview.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_overview.tsx index ca67c2aac98ad..df9c0b5db9b7d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_overview.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_overview.tsx @@ -9,8 +9,6 @@ import React from 'react'; import { useActions, useValues } from 'kea'; -import { i18n } from '@kbn/i18n'; - import { EuiButton, EuiConfirmModal, @@ -22,20 +20,19 @@ import { EuiSpacer, EuiHorizontalRule, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; -import { CANCEL_BUTTON } from '../../../constants'; - -import { AppLogic } from '../../../app_logic'; +import { Loading } from '../../../../shared/loading'; import { TruncatedContent } from '../../../../shared/truncate'; +import { AppLogic } from '../../../app_logic'; import { ContentSection } from '../../../components/shared/content_section'; -import { ViewContentHeader } from '../../../components/shared/view_content_header'; -import { Loading } from '../../../../shared/loading'; import { SourcesTable } from '../../../components/shared/sources_table'; +import { ViewContentHeader } from '../../../components/shared/view_content_header'; +import { CANCEL_BUTTON } from '../../../constants'; +import { GroupLogic, MAX_NAME_LENGTH } from '../group_logic'; import { GroupUsersTable } from './group_users_table'; -import { GroupLogic, MAX_NAME_LENGTH } from '../group_logic'; - export const EMPTY_SOURCES_DESCRIPTION = i18n.translate( 'xpack.enterpriseSearch.workplaceSearch.groups.overview.emptySourcesDescription', { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row.test.tsx index 19898172fb4e7..205eafd69cd10 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row.test.tsx @@ -9,14 +9,15 @@ import { setMockValues } from '../../../../__mocks__'; import { groups } from '../../../__mocks__/groups.mock'; import React from 'react'; + import { shallow } from 'enzyme'; import moment from 'moment'; +import { EuiTableRow } from '@elastic/eui'; + import { GroupRow, NO_USERS_MESSAGE, NO_SOURCES_MESSAGE } from './group_row'; import { GroupUsers } from './group_users'; -import { EuiTableRow } from '@elastic/eui'; - describe('GroupRow', () => { beforeEach(() => { setMockValues({ isFederatedAuth: true }); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row.tsx index 1a085aea93cc6..5e89d4491d597 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row.tsx @@ -6,21 +6,20 @@ */ import React from 'react'; -import moment from 'moment'; -import { useValues } from 'kea'; -import { i18n } from '@kbn/i18n'; +import { useValues } from 'kea'; +import moment from 'moment'; import { EuiTableRow, EuiTableRowCell, EuiIcon } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; -import { TruncatedContent } from '../../../../shared/truncate'; import { EuiLinkTo } from '../../../../shared/react_router_helpers'; - -import { Group } from '../../../types'; - +import { TruncatedContent } from '../../../../shared/truncate'; import { AppLogic } from '../../../app_logic'; import { getGroupPath } from '../../../routes'; +import { Group } from '../../../types'; import { MAX_NAME_LENGTH } from '../group_logic'; + import { GroupSources } from './group_sources'; import { GroupUsers } from './group_users'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row_sources_dropdown.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row_sources_dropdown.test.tsx index e4c626a28c1a6..23c00d0fa209e 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row_sources_dropdown.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row_sources_dropdown.test.tsx @@ -8,13 +8,14 @@ import { contentSources } from '../../../__mocks__/content_sources.mock'; import React from 'react'; + import { shallow } from 'enzyme'; +import { EuiFilterGroup } from '@elastic/eui'; + import { GroupRowSourcesDropdown } from './group_row_sources_dropdown'; import { SourceOptionItem } from './source_option_item'; -import { EuiFilterGroup } from '@elastic/eui'; - const onButtonClick = jest.fn(); const closePopover = jest.fn(); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row_sources_dropdown.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row_sources_dropdown.tsx index a8f8c18cc6f38..77d7de91caf7c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row_sources_dropdown.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row_sources_dropdown.tsx @@ -7,9 +7,8 @@ import React from 'react'; -import { i18n } from '@kbn/i18n'; - import { EuiFilterGroup, EuiPopover, EuiPopoverTitle, EuiButtonEmpty } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { ContentSource } from '../../../types'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row_users_dropdown.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row_users_dropdown.test.tsx index 7dae74155d0d6..e75b325a4eae9 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row_users_dropdown.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row_users_dropdown.test.tsx @@ -9,12 +9,13 @@ import { setMockActions, setMockValues } from '../../../../__mocks__'; import { users } from '../../../__mocks__/users.mock'; import React from 'react'; + import { shallow, mount } from 'enzyme'; import { EuiLoadingContent, EuiButtonEmpty } from '@elastic/eui'; -import { GroupRowUsersDropdown } from './group_row_users_dropdown'; import { FilterableUsersPopover } from './filterable_users_popover'; +import { GroupRowUsersDropdown } from './group_row_users_dropdown'; const fetchGroupUsers = jest.fn(); const onButtonClick = jest.fn(); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row_users_dropdown.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row_users_dropdown.tsx index 9ca9c8339ba6a..aaf715fc71615 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row_users_dropdown.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row_users_dropdown.tsx @@ -12,6 +12,7 @@ import { useActions, useValues } from 'kea'; import { EuiLoadingContent, EuiButtonEmpty } from '@elastic/eui'; import { GroupsLogic } from '../groups_logic'; + import { FilterableUsersPopover } from './filterable_users_popover'; interface GroupRowUsersDropdownProps { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_source_prioritization.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_source_prioritization.test.tsx index 49305ec33d228..4a9244486bf30 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_source_prioritization.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_source_prioritization.test.tsx @@ -9,14 +9,15 @@ import { setMockActions, setMockValues } from '../../../../__mocks__'; import { groups } from '../../../__mocks__/groups.mock'; import React from 'react'; + import { shallow } from 'enzyme'; +import { EuiTable, EuiEmptyPrompt, EuiRange } from '@elastic/eui'; + import { Loading } from '../../../../shared/loading'; import { GroupSourcePrioritization } from './group_source_prioritization'; -import { EuiTable, EuiEmptyPrompt, EuiRange } from '@elastic/eui'; - const updatePriority = jest.fn(); const saveGroupSourcePrioritization = jest.fn(); const showSharedSourcesModal = jest.fn(); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_source_prioritization.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_source_prioritization.tsx index 6907618e40b46..9b131e730b937 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_source_prioritization.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_source_prioritization.tsx @@ -9,8 +9,6 @@ import React, { ChangeEvent, MouseEvent } from 'react'; import { useActions, useValues } from 'kea'; -import { i18n } from '@kbn/i18n'; - import { EuiButton, EuiEmptyPrompt, @@ -26,14 +24,13 @@ import { EuiTableRow, EuiTableRowCell, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { Loading } from '../../../../shared/loading'; -import { ViewContentHeader } from '../../../components/shared/view_content_header'; import { SourceIcon } from '../../../components/shared/source_icon'; - -import { GroupLogic } from '../group_logic'; - +import { ViewContentHeader } from '../../../components/shared/view_content_header'; import { ContentSource } from '../../../types'; +import { GroupLogic } from '../group_logic'; const HEADER_TITLE = i18n.translate( 'xpack.enterpriseSearch.workplaceSearch.groups.sourceProioritization.headerTitle', diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_sources.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_sources.test.tsx index fd2a5e2bc6d9a..a245f0a768b0e 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_sources.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_sources.test.tsx @@ -8,15 +8,15 @@ import { contentSources } from '../../../__mocks__/content_sources.mock'; import React from 'react'; -import { shallow } from 'enzyme'; -import { GroupSources } from './group_sources'; -import { GroupRowSourcesDropdown } from './group_row_sources_dropdown'; +import { shallow } from 'enzyme'; import { SourceIcon } from '../../../components/shared/source_icon'; - import { ContentSourceDetails } from '../../../types'; +import { GroupRowSourcesDropdown } from './group_row_sources_dropdown'; +import { GroupSources } from './group_sources'; + describe('GroupSources', () => { it('renders', () => { const wrapper = shallow(); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_sources.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_sources.tsx index ae3b5000941b1..97739e46caba4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_sources.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_sources.tsx @@ -9,7 +9,6 @@ import React, { useState } from 'react'; import { SourceIcon } from '../../../components/shared/source_icon'; import { MAX_TABLE_ROW_ICONS } from '../../../constants'; - import { ContentSource } from '../../../types'; import { GroupRowSourcesDropdown } from './group_row_sources_dropdown'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_sub_nav.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_sub_nav.test.tsx index ead4af451ee7a..e4dde81949bfa 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_sub_nav.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_sub_nav.test.tsx @@ -8,12 +8,13 @@ import { setMockValues } from '../../../../__mocks__'; import React from 'react'; -import { shallow } from 'enzyme'; -import { GroupSubNav } from './group_sub_nav'; +import { shallow } from 'enzyme'; import { SideNavLink } from '../../../../shared/layout'; +import { GroupSubNav } from './group_sub_nav'; + describe('GroupSubNav', () => { it('renders empty when no group id present', () => { setMockValues({ group: {} }); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_sub_nav.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_sub_nav.tsx index e2bd6e8ae91f2..c5fc0717d1105 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_sub_nav.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_sub_nav.tsx @@ -6,14 +6,13 @@ */ import React from 'react'; -import { useValues } from 'kea'; -import { GroupLogic } from '../group_logic'; -import { NAV } from '../../../constants'; +import { useValues } from 'kea'; import { SideNavLink } from '../../../../shared/layout'; - +import { NAV } from '../../../constants'; import { getGroupPath, getGroupSourcePrioritizationPath } from '../../../routes'; +import { GroupLogic } from '../group_logic'; export const GroupSubNav: React.FC = () => { const { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_users.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_users.test.tsx index f1bc063e1a223..eba79ea70177d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_users.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_users.test.tsx @@ -8,14 +8,14 @@ import { users } from '../../../__mocks__/users.mock'; import React from 'react'; + import { shallow } from 'enzyme'; +import { UserIcon } from '../../../components/shared/user_icon'; import { User } from '../../../types'; -import { GroupUsers } from './group_users'; import { GroupRowUsersDropdown } from './group_row_users_dropdown'; - -import { UserIcon } from '../../../components/shared/user_icon'; +import { GroupUsers } from './group_users'; const props = { groupUsers: users, diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_users.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_users.tsx index 850910428c4b2..6e60df15ed30a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_users.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_users.tsx @@ -9,7 +9,6 @@ import React, { useState } from 'react'; import { UserIcon } from '../../../components/shared/user_icon'; import { MAX_TABLE_ROW_ICONS } from '../../../constants'; - import { User } from '../../../types'; import { GroupRowUsersDropdown } from './group_row_users_dropdown'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_users_table.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_users_table.test.tsx index 83e945547438f..a6376d7653627 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_users_table.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_users_table.test.tsx @@ -9,14 +9,15 @@ import { setMockValues } from '../../../../__mocks__'; import { groups } from '../../../__mocks__/groups.mock'; import React from 'react'; + import { shallow } from 'enzyme'; -import { User } from '../../../types'; +import { EuiTable, EuiTablePagination } from '@elastic/eui'; -import { GroupUsersTable } from './group_users_table'; import { TableHeader } from '../../../../shared/table_header'; +import { User } from '../../../types'; -import { EuiTable, EuiTablePagination } from '@elastic/eui'; +import { GroupUsersTable } from './group_users_table'; const group = groups[0]; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_users_table.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_users_table.tsx index 4b337fda9143d..5d070b1a21b7d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_users_table.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_users_table.tsx @@ -9,17 +9,14 @@ import React, { useState } from 'react'; import { useValues } from 'kea'; -import { i18n } from '@kbn/i18n'; - import { EuiTable, EuiTableBody, EuiTablePagination } from '@elastic/eui'; import { Pager } from '@elastic/eui'; - -import { User } from '../../../types'; +import { i18n } from '@kbn/i18n'; import { TableHeader } from '../../../../shared/table_header'; -import { UserRow } from '../../../components/shared/user_row'; - import { AppLogic } from '../../../app_logic'; +import { UserRow } from '../../../components/shared/user_row'; +import { User } from '../../../types'; import { GroupLogic } from '../group_logic'; const USERS_PER_PAGE = 10; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/groups_table.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/groups_table.test.tsx index d6724499490cf..f60a13ec296d5 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/groups_table.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/groups_table.test.tsx @@ -8,18 +8,18 @@ import { setMockActions, setMockValues } from '../../../../__mocks__'; import { groups } from '../../../__mocks__/groups.mock'; -import { DEFAULT_META } from '../../../../shared/constants'; - import React from 'react'; + import { shallow } from 'enzyme'; +import { EuiTable, EuiTableHeaderCell } from '@elastic/eui'; + +import { DEFAULT_META } from '../../../../shared/constants'; import { TablePaginationBar } from '../../../components/shared/table_pagination_bar'; -import { GroupsTable } from './groups_table'; -import { GroupRow } from './group_row'; import { ClearFiltersLink } from './clear_filters_link'; - -import { EuiTable, EuiTableHeaderCell } from '@elastic/eui'; +import { GroupRow } from './group_row'; +import { GroupsTable } from './groups_table'; const setActivePage = jest.fn(); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/groups_table.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/groups_table.tsx index 31f549c3e2065..95292116cba05 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/groups_table.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/groups_table.tsx @@ -9,8 +9,6 @@ import React from 'react'; import { useActions, useValues } from 'kea'; -import { i18n } from '@kbn/i18n'; - import { EuiSpacer, EuiTable, @@ -18,14 +16,14 @@ import { EuiTableHeader, EuiTableHeaderCell, } from '@elastic/eui'; - -import { TablePaginationBar } from '../../../components/shared/table_pagination_bar'; +import { i18n } from '@kbn/i18n'; import { AppLogic } from '../../../app_logic'; +import { TablePaginationBar } from '../../../components/shared/table_pagination_bar'; import { GroupsLogic } from '../groups_logic'; -import { GroupRow } from './group_row'; import { ClearFiltersLink } from './clear_filters_link'; +import { GroupRow } from './group_row'; const GROUP_TABLE_HEADER = i18n.translate( 'xpack.enterpriseSearch.workplaceSearch.groups.groupsTable.groupTableHeader', diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/manage_users_modal.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/manage_users_modal.test.tsx index 059dff969aee3..49d51dfc7254c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/manage_users_modal.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/manage_users_modal.test.tsx @@ -9,11 +9,12 @@ import { setMockActions, setMockValues } from '../../../../__mocks__'; import { users } from '../../../__mocks__/users.mock'; import React from 'react'; + import { shallow } from 'enzyme'; -import { ManageUsersModal } from './manage_users_modal'; import { FilterableUsersList } from './filterable_users_list'; import { GroupManagerModal } from './group_manager_modal'; +import { ManageUsersModal } from './manage_users_modal'; const addGroupUser = jest.fn(); const removeGroupUser = jest.fn(); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/shared_sources_modal.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/shared_sources_modal.test.tsx index f937ded7d4918..dd72850a06ad9 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/shared_sources_modal.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/shared_sources_modal.test.tsx @@ -9,10 +9,11 @@ import { setMockActions, setMockValues } from '../../../../__mocks__'; import { groups } from '../../../__mocks__/groups.mock'; import React from 'react'; + import { shallow } from 'enzyme'; -import { SharedSourcesModal } from './shared_sources_modal'; import { GroupManagerModal } from './group_manager_modal'; +import { SharedSourcesModal } from './shared_sources_modal'; import { SourcesList } from './sources_list'; const group = groups[0]; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/source_option_item.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/source_option_item.test.tsx index d037a49875a7e..bad60e15ed2d0 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/source_option_item.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/source_option_item.test.tsx @@ -8,14 +8,14 @@ import { contentSources } from '../../../__mocks__/content_sources.mock'; import React from 'react'; -import { shallow } from 'enzyme'; -import { SourceOptionItem } from './source_option_item'; +import { shallow } from 'enzyme'; import { TruncatedContent } from '../../../../shared/truncate'; - import { SourceIcon } from '../../../components/shared/source_icon'; +import { SourceOptionItem } from './source_option_item'; + describe('SourceOptionItem', () => { it('renders', () => { const wrapper = shallow(); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/source_option_item.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/source_option_item.tsx index a87980415bd1f..e2da597a83598 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/source_option_item.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/source_option_item.tsx @@ -10,7 +10,6 @@ import React from 'react'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { TruncatedContent } from '../../../../shared/truncate'; - import { SourceIcon } from '../../../components/shared/source_icon'; import { ContentSource } from '../../../types'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/sources_list.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/sources_list.test.tsx index 56e700c10e04c..05fe2c92f9f72 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/sources_list.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/sources_list.test.tsx @@ -8,12 +8,13 @@ import { contentSources } from '../../../__mocks__/content_sources.mock'; import React from 'react'; -import { shallow } from 'enzyme'; -import { SourcesList } from './sources_list'; +import { shallow } from 'enzyme'; import { EuiFilterSelectItem } from '@elastic/eui'; +import { SourcesList } from './sources_list'; + const addFilteredSource = jest.fn(); const removeFilteredSource = jest.fn(); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/table_filter_sources_dropdown.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/table_filter_sources_dropdown.test.tsx index b7efe84df180c..1e2a57da9ad2e 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/table_filter_sources_dropdown.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/table_filter_sources_dropdown.test.tsx @@ -9,11 +9,11 @@ import { setMockActions, setMockValues } from '../../../../__mocks__'; import { contentSources } from '../../../__mocks__/content_sources.mock'; import React from 'react'; -import { shallow } from 'enzyme'; -import { TableFilterSourcesDropdown } from './table_filter_sources_dropdown'; +import { shallow } from 'enzyme'; import { SourcesList } from './sources_list'; +import { TableFilterSourcesDropdown } from './table_filter_sources_dropdown'; const addFilteredSource = jest.fn(); const removeFilteredSource = jest.fn(); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/table_filter_sources_dropdown.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/table_filter_sources_dropdown.tsx index b38d5fc55b6f8..5f75340d562ef 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/table_filter_sources_dropdown.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/table_filter_sources_dropdown.tsx @@ -9,11 +9,11 @@ import React from 'react'; import { useActions, useValues } from 'kea'; -import { i18n } from '@kbn/i18n'; - import { EuiFilterButton, EuiFilterGroup, EuiPopover } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { GroupsLogic } from '../groups_logic'; + import { SourcesList } from './sources_list'; const FILTER_SOURCES_BUTTON_TEXT = i18n.translate( diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/table_filter_users_dropdown.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/table_filter_users_dropdown.test.tsx index 9eaaa64b1c4e4..e472563862015 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/table_filter_users_dropdown.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/table_filter_users_dropdown.test.tsx @@ -9,10 +9,11 @@ import { setMockActions, setMockValues } from '../../../../__mocks__'; import { users } from '../../../__mocks__/users.mock'; import React from 'react'; + import { shallow } from 'enzyme'; -import { TableFilterUsersDropdown } from './table_filter_users_dropdown'; import { FilterableUsersPopover } from './filterable_users_popover'; +import { TableFilterUsersDropdown } from './table_filter_users_dropdown'; const closeFilterUsersDropdown = jest.fn(); const toggleFilterUsersDropdown = jest.fn(); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/table_filter_users_dropdown.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/table_filter_users_dropdown.tsx index 9ddb955767c14..c09e1e3cf87cc 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/table_filter_users_dropdown.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/table_filter_users_dropdown.tsx @@ -9,11 +9,11 @@ import React from 'react'; import { useActions, useValues } from 'kea'; -import { i18n } from '@kbn/i18n'; - import { EuiFilterButton } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { GroupsLogic } from '../groups_logic'; + import { FilterableUsersPopover } from './filterable_users_popover'; const FILTER_USERS_BUTTON_TEXT = i18n.translate( diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/table_filters.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/table_filters.test.tsx index 0fdaf74376494..bcc58c394b516 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/table_filters.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/table_filters.test.tsx @@ -8,13 +8,14 @@ import { setMockActions, setMockValues } from '../../../../__mocks__'; import React from 'react'; -import { shallow } from 'enzyme'; -import { TableFilters } from './table_filters'; +import { shallow } from 'enzyme'; import { EuiFieldSearch } from '@elastic/eui'; + import { TableFilterSourcesDropdown } from './table_filter_sources_dropdown'; import { TableFilterUsersDropdown } from './table_filter_users_dropdown'; +import { TableFilters } from './table_filters'; const setFilterValue = jest.fn(); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/table_filters.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/table_filters.tsx index cfd40e1a0df4e..e9ea6a7c6b4aa 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/table_filters.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/table_filters.tsx @@ -9,9 +9,8 @@ import React, { ChangeEvent } from 'react'; import { useActions, useValues } from 'kea'; -import { i18n } from '@kbn/i18n'; - import { EuiFieldSearch, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { AppLogic } from '../../../app_logic'; import { GroupsLogic } from '../groups_logic'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/user_option_item.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/user_option_item.test.tsx index 01f67cc910afd..6c8dbbde2e69f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/user_option_item.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/user_option_item.test.tsx @@ -8,12 +8,14 @@ import { users } from '../../../__mocks__/users.mock'; import React from 'react'; + import { shallow } from 'enzyme'; -import { UserOptionItem } from './user_option_item'; +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; + import { UserIcon } from '../../../components/shared/user_icon'; -import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { UserOptionItem } from './user_option_item'; const user = users[0]; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/group_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/group_logic.test.ts index d8d41b5e2888a..836efa82995fc 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/group_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/group_logic.test.ts @@ -11,15 +11,15 @@ import { mockFlashMessageHelpers, mockHttpValues, } from '../../../__mocks__'; +import { groups } from '../../__mocks__/groups.mock'; import { nextTick } from '@kbn/test/jest'; -import { groups } from '../../__mocks__/groups.mock'; +import { GROUPS_PATH } from '../../routes'; + import { mockGroupValues } from './__mocks__/group_logic.mock'; import { GroupLogic } from './group_logic'; -import { GROUPS_PATH } from '../../routes'; - describe('GroupLogic', () => { const { mount } = new LogicMounter(GroupLogic); const { http } = mockHttpValues; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/group_logic.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/group_logic.ts index 7e7ce838434f5..f23b182b98649 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/group_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/group_logic.ts @@ -7,10 +7,9 @@ import { kea, MakeLogicType } from 'kea'; import { isEqual } from 'lodash'; + import { i18n } from '@kbn/i18n'; -import { HttpLogic } from '../../../shared/http'; -import { KibanaLogic } from '../../../shared/kibana'; import { clearFlashMessages, flashAPIErrors, @@ -18,9 +17,9 @@ import { setQueuedSuccessMessage, setQueuedErrorMessage, } from '../../../shared/flash_messages'; - +import { HttpLogic } from '../../../shared/http'; +import { KibanaLogic } from '../../../shared/kibana'; import { GROUPS_PATH } from '../../routes'; - import { ContentSourceDetails, GroupDetails, User, SourcePriority } from '../../types'; export const MAX_NAME_LENGTH = 40; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/group_router.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/group_router.test.tsx index a04fc4c744790..0b218f2496154 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/group_router.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/group_router.test.tsx @@ -7,25 +7,21 @@ import '../../../__mocks__/shallow_useeffect.mock'; import { setMockValues, setMockActions } from '../../../__mocks__'; +import { groups } from '../../__mocks__/groups.mock'; import React from 'react'; -import { shallow } from 'enzyme'; - import { Route, Switch } from 'react-router-dom'; -import { groups } from '../../__mocks__/groups.mock'; +import { shallow } from 'enzyme'; +import { FlashMessages } from '../../../shared/flash_messages'; import { SetWorkplaceSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; import { GroupOverview } from './components/group_overview'; import { GroupSourcePrioritization } from './components/group_source_prioritization'; - -import { GroupRouter } from './group_router'; - -import { FlashMessages } from '../../../shared/flash_messages'; - import { ManageUsersModal } from './components/manage_users_modal'; import { SharedSourcesModal } from './components/shared_sources_modal'; +import { GroupRouter } from './group_router'; describe('GroupRouter', () => { const initializeGroup = jest.fn(); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/group_router.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/group_router.tsx index 82eb7931dfcdc..a5b8bd138d0c8 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/group_router.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/group_router.tsx @@ -6,23 +6,21 @@ */ import React, { useEffect } from 'react'; +import { Route, Switch, useParams } from 'react-router-dom'; import { useActions, useValues } from 'kea'; -import { Route, Switch, useParams } from 'react-router-dom'; import { FlashMessages } from '../../../shared/flash_messages'; import { SetWorkplaceSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; import { SendWorkplaceSearchTelemetry as SendTelemetry } from '../../../shared/telemetry'; - -import { GROUP_SOURCE_PRIORITIZATION_PATH, GROUP_PATH } from '../../routes'; import { NAV } from '../../constants'; -import { GroupLogic } from './group_logic'; - -import { ManageUsersModal } from './components/manage_users_modal'; -import { SharedSourcesModal } from './components/shared_sources_modal'; +import { GROUP_SOURCE_PRIORITIZATION_PATH, GROUP_PATH } from '../../routes'; import { GroupOverview } from './components/group_overview'; import { GroupSourcePrioritization } from './components/group_source_prioritization'; +import { ManageUsersModal } from './components/manage_users_modal'; +import { SharedSourcesModal } from './components/shared_sources_modal'; +import { GroupLogic } from './group_logic'; export const GroupRouter: React.FC = () => { const { groupId } = useParams() as { groupId: string }; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/groups.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/groups.test.tsx index d67dd5857561e..8470c5d3e0f66 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/groups.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/groups.test.tsx @@ -11,23 +11,22 @@ import { groups } from '../../__mocks__/groups.mock'; import { meta } from '../../__mocks__/meta.mock'; import React from 'react'; + import { shallow } from 'enzyme'; -import { Groups } from './groups'; +import { EuiFieldSearch, EuiLoadingSpinner } from '@elastic/eui'; -import { ViewContentHeader } from '../../components/shared/view_content_header'; -import { Loading } from '../../../shared/loading'; +import { DEFAULT_META } from '../../../shared/constants'; import { FlashMessages } from '../../../shared/flash_messages'; +import { Loading } from '../../../shared/loading'; +import { EuiButtonTo } from '../../../shared/react_router_helpers'; +import { ViewContentHeader } from '../../components/shared/view_content_header'; import { AddGroupModal } from './components/add_group_modal'; import { ClearFiltersLink } from './components/clear_filters_link'; import { GroupsTable } from './components/groups_table'; import { TableFilters } from './components/table_filters'; - -import { DEFAULT_META } from '../../../shared/constants'; - -import { EuiFieldSearch, EuiLoadingSpinner } from '@elastic/eui'; -import { EuiButtonTo } from '../../../shared/react_router_helpers'; +import { Groups } from './groups'; const getSearchResults = jest.fn(); const openNewGroupModal = jest.fn(); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/groups.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/groups.tsx index 7a8b9343691f9..b2bf0364b2d1f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/groups.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/groups.tsx @@ -8,26 +8,22 @@ import React, { useEffect } from 'react'; import { useActions, useValues } from 'kea'; -import { i18n } from '@kbn/i18n'; import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner, EuiSpacer } from '@elastic/eui'; -import { EuiButtonTo } from '../../../shared/react_router_helpers'; - -import { AppLogic } from '../../app_logic'; +import { i18n } from '@kbn/i18n'; +import { FlashMessages, FlashMessagesLogic } from '../../../shared/flash_messages'; import { Loading } from '../../../shared/loading'; +import { EuiButtonTo } from '../../../shared/react_router_helpers'; +import { AppLogic } from '../../app_logic'; import { ViewContentHeader } from '../../components/shared/view_content_header'; - import { getGroupPath, USERS_PATH } from '../../routes'; -import { FlashMessages, FlashMessagesLogic } from '../../../shared/flash_messages'; - -import { GroupsLogic } from './groups_logic'; - import { AddGroupModal } from './components/add_group_modal'; import { ClearFiltersLink } from './components/clear_filters_link'; import { GroupsTable } from './components/groups_table'; import { TableFilters } from './components/table_filters'; +import { GroupsLogic } from './groups_logic'; export const Groups: React.FC = () => { const { messages } = useValues(FlashMessagesLogic); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/groups_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/groups_logic.test.ts index 26d7f9784cc6e..806c6e1c69f84 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/groups_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/groups_logic.test.ts @@ -6,15 +6,15 @@ */ import { LogicMounter, mockFlashMessageHelpers, mockHttpValues } from '../../../__mocks__'; +import { contentSources } from '../../__mocks__/content_sources.mock'; +import { groups } from '../../__mocks__/groups.mock'; +import { users } from '../../__mocks__/users.mock'; import { nextTick } from '@kbn/test/jest'; -import { DEFAULT_META } from '../../../shared/constants'; import { JSON_HEADER as headers } from '../../../../../common/constants'; +import { DEFAULT_META } from '../../../shared/constants'; -import { groups } from '../../__mocks__/groups.mock'; -import { contentSources } from '../../__mocks__/content_sources.mock'; -import { users } from '../../__mocks__/users.mock'; import { mockGroupsValues } from './__mocks__/groups_logic.mock'; import { GroupsLogic } from './groups_logic'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/groups_logic.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/groups_logic.ts index 68a6eb7bdf344..a036cdda3d68e 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/groups_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/groups_logic.ts @@ -6,22 +6,20 @@ */ import { kea, MakeLogicType } from 'kea'; -import { i18n } from '@kbn/i18n'; -import { HttpLogic } from '../../../shared/http'; +import { i18n } from '@kbn/i18n'; +import { JSON_HEADER as headers } from '../../../../../common/constants'; +import { Meta } from '../../../../../common/types'; +import { DEFAULT_META } from '../../../shared/constants'; import { clearFlashMessages, flashAPIErrors, setSuccessMessage, } from '../../../shared/flash_messages'; - +import { HttpLogic } from '../../../shared/http'; import { ContentSource, Group, User } from '../../types'; -import { JSON_HEADER as headers } from '../../../../../common/constants'; -import { DEFAULT_META } from '../../../shared/constants'; -import { Meta } from '../../../../../common/types'; - export const MAX_NAME_LENGTH = 40; interface GroupsServerData { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/groups_router.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/groups_router.test.tsx index 43c31038a45c6..0295605eddd4d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/groups_router.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/groups_router.test.tsx @@ -9,14 +9,13 @@ import '../../../__mocks__/shallow_useeffect.mock'; import { setMockActions } from '../../../__mocks__'; import React from 'react'; -import { shallow } from 'enzyme'; - import { Route, Switch } from 'react-router-dom'; -import { GroupsRouter } from './groups_router'; +import { shallow } from 'enzyme'; import { GroupRouter } from './group_router'; import { Groups } from './groups'; +import { GroupsRouter } from './groups_router'; describe('GroupsRouter', () => { const initializeGroups = jest.fn(); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/groups_router.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/groups_router.tsx index e835a2668f3d3..d8c4f4801ba24 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/groups_router.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/groups_router.tsx @@ -6,21 +6,18 @@ */ import React, { useEffect } from 'react'; +import { Route, Switch } from 'react-router-dom'; import { useActions } from 'kea'; -import { Route, Switch } from 'react-router-dom'; - import { SetWorkplaceSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; import { SendWorkplaceSearchTelemetry as SendTelemetry } from '../../../shared/telemetry'; - -import { GROUP_PATH, GROUPS_PATH } from '../../routes'; import { NAV } from '../../constants'; - -import { GroupsLogic } from './groups_logic'; +import { GROUP_PATH, GROUPS_PATH } from '../../routes'; import { GroupRouter } from './group_router'; import { Groups } from './groups'; +import { GroupsLogic } from './groups_logic'; import './groups.scss'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/__mocks__/overview_logic.mock.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/__mocks__/overview_logic.mock.ts index f03dcfe98ddd0..787354974cb31 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/__mocks__/overview_logic.mock.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/__mocks__/overview_logic.mock.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { setMockValues as setMockKeaValues, setMockActions } from '../../../../__mocks__/kea.mock'; import { DEFAULT_INITIAL_APP_DATA } from '../../../../../../common/__mocks__'; +import { setMockValues as setMockKeaValues, setMockActions } from '../../../../__mocks__/kea.mock'; const { workplaceSearch: mockAppValues } = DEFAULT_INITIAL_APP_DATA; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/onboarding_card.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/onboarding_card.test.tsx index 8f962ec4cf665..68dece976a09c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/onboarding_card.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/onboarding_card.test.tsx @@ -10,6 +10,7 @@ import '../../../__mocks__/enterprise_search_url.mock'; import { mockTelemetryActions } from '../../../__mocks__'; import React from 'react'; + import { shallow } from 'enzyme'; import { EuiEmptyPrompt, EuiButton, EuiButtonEmpty } from '@elastic/eui'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/onboarding_card.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/onboarding_card.tsx index 68a4c4dc10f4f..2f8d06b71fc27 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/onboarding_card.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/onboarding_card.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { useActions } from 'kea'; import { @@ -20,8 +21,8 @@ import { EuiLinkProps, } from '@elastic/eui'; -import { TelemetryLogic } from '../../../shared/telemetry'; import { getWorkplaceSearchUrl } from '../../../shared/enterprise_search_url'; +import { TelemetryLogic } from '../../../shared/telemetry'; interface OnboardingCardProps { title: React.ReactNode; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/onboarding_steps.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/onboarding_steps.test.tsx index 7f676ce2faac2..7a368e7d384ea 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/onboarding_steps.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/onboarding_steps.test.tsx @@ -6,16 +6,18 @@ */ import { mockTelemetryActions } from '../../../__mocks__'; + import './__mocks__/overview_logic.mock'; -import { setMockValues } from './__mocks__'; import React from 'react'; + import { shallow } from 'enzyme'; import { SOURCES_PATH, USERS_PATH } from '../../routes'; -import { OnboardingSteps, OrgNameOnboarding } from './onboarding_steps'; +import { setMockValues } from './__mocks__'; import { OnboardingCard } from './onboarding_card'; +import { OnboardingSteps, OrgNameOnboarding } from './onboarding_steps'; const account = { id: '1', diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/onboarding_steps.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/onboarding_steps.tsx index ae30a52c1541c..fc3998fcdfeec 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/onboarding_steps.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/onboarding_steps.tsx @@ -6,8 +6,7 @@ */ import React from 'react'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; + import { useValues, useActions } from 'kea'; import { @@ -22,17 +21,18 @@ import { EuiButtonEmptyProps, EuiLinkProps, } from '@elastic/eui'; -import sharedSourcesIcon from '../../components/shared/assets/source_icons/share_circle.svg'; -import { TelemetryLogic } from '../../../shared/telemetry'; -import { getWorkplaceSearchUrl } from '../../../shared/enterprise_search_url'; -import { SOURCES_PATH, USERS_PATH, ORG_SETTINGS_PATH } from '../../routes'; - -import { ContentSection } from '../../components/shared/content_section'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { getWorkplaceSearchUrl } from '../../../shared/enterprise_search_url'; +import { TelemetryLogic } from '../../../shared/telemetry'; import { AppLogic } from '../../app_logic'; -import { OverviewLogic } from './overview_logic'; +import sharedSourcesIcon from '../../components/shared/assets/source_icons/share_circle.svg'; +import { ContentSection } from '../../components/shared/content_section'; +import { SOURCES_PATH, USERS_PATH, ORG_SETTINGS_PATH } from '../../routes'; import { OnboardingCard } from './onboarding_card'; +import { OverviewLogic } from './overview_logic'; const SOURCES_TITLE = i18n.translate( 'xpack.enterpriseSearch.workplaceSearch.overviewOnboardingSourcesCard.title', diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/organization_stats.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/organization_stats.test.tsx index cf4f96f6b788b..412977f18fadf 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/organization_stats.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/organization_stats.test.tsx @@ -6,12 +6,14 @@ */ import './__mocks__/overview_logic.mock'; -import { setMockValues } from './__mocks__'; import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiFlexGrid } from '@elastic/eui'; +import { setMockValues } from './__mocks__'; import { OrganizationStats } from './organization_stats'; import { StatisticCard } from './statistic_card'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/organization_stats.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/organization_stats.tsx index 52c370caac989..525035030b8cc 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/organization_stats.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/organization_stats.tsx @@ -6,18 +6,18 @@ */ import React from 'react'; -import { EuiFlexGrid } from '@elastic/eui'; + import { useValues } from 'kea'; -import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiFlexGrid } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { AppLogic } from '../../app_logic'; import { ContentSection } from '../../components/shared/content_section'; import { SOURCES_PATH, USERS_PATH } from '../../routes'; -import { AppLogic } from '../../app_logic'; import { OverviewLogic } from './overview_logic'; - import { StatisticCard } from './statistic_card'; export const OrganizationStats: React.FC = () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/overview.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/overview.test.tsx index fc70a07e339e4..2ec2d949ff491 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/overview.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/overview.test.tsx @@ -7,18 +7,19 @@ import '../../../__mocks__/react_router_history.mock'; import './__mocks__/overview_logic.mock'; -import { mockActions, setMockValues } from './__mocks__'; import React from 'react'; + import { shallow, mount } from 'enzyme'; import { Loading } from '../../../shared/loading'; import { ViewContentHeader } from '../../components/shared/view_content_header'; +import { mockActions, setMockValues } from './__mocks__'; import { OnboardingSteps } from './onboarding_steps'; import { OrganizationStats } from './organization_stats'; -import { RecentActivity } from './recent_activity'; import { Overview } from './overview'; +import { RecentActivity } from './recent_activity'; describe('Overview', () => { describe('non-happy-path states', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/overview.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/overview.tsx index 07bc999922661..6bf84b585da80 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/overview.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/overview.tsx @@ -8,22 +8,22 @@ // TODO: Remove EuiPage & EuiPageBody before exposing full app import React, { useEffect } from 'react'; + +import { useActions, useValues } from 'kea'; + import { EuiPage, EuiPageBody, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { useActions, useValues } from 'kea'; import { SetWorkplaceSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; +import { Loading } from '../../../shared/loading'; import { SendWorkplaceSearchTelemetry as SendTelemetry } from '../../../shared/telemetry'; - import { AppLogic } from '../../app_logic'; -import { OverviewLogic } from './overview_logic'; - -import { Loading } from '../../../shared/loading'; import { ProductButton } from '../../components/shared/product_button'; import { ViewContentHeader } from '../../components/shared/view_content_header'; import { OnboardingSteps } from './onboarding_steps'; import { OrganizationStats } from './organization_stats'; +import { OverviewLogic } from './overview_logic'; import { RecentActivity } from './recent_activity'; const ONBOARDING_HEADER_TITLE = i18n.translate( diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/overview_logic.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/overview_logic.ts index 6d0beb638cd52..75513cfba3a09 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/overview_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/overview_logic.ts @@ -6,6 +6,7 @@ */ import { kea, MakeLogicType } from 'kea'; + import { HttpLogic } from '../../../shared/http'; import { FeedActivity } from './recent_activity'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/recent_activity.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/recent_activity.test.tsx index 9c571bd8bc169..0b62207afc520 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/recent_activity.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/recent_activity.test.tsx @@ -6,15 +6,17 @@ */ import { mockTelemetryActions } from '../../../__mocks__'; + import './__mocks__/overview_logic.mock'; -import { setMockValues } from './__mocks__'; import React from 'react'; + import { shallow } from 'enzyme'; import { EuiEmptyPrompt, EuiLink } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; +import { setMockValues } from './__mocks__'; import { RecentActivity, RecentActivityItem } from './recent_activity'; const organization = { name: 'foo', defaultOrgName: 'bar' }; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/recent_activity.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/recent_activity.tsx index 1dcec989a94c7..43d3f880feef4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/recent_activity.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/recent_activity.tsx @@ -7,19 +7,19 @@ import React from 'react'; -import moment from 'moment'; import { useValues, useActions } from 'kea'; +import moment from 'moment'; import { EuiEmptyPrompt, EuiLink, EuiPanel, EuiSpacer, EuiLinkProps } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { ContentSection } from '../../components/shared/content_section'; -import { TelemetryLogic } from '../../../shared/telemetry'; import { getWorkplaceSearchUrl } from '../../../shared/enterprise_search_url'; -import { SOURCE_DETAILS_PATH, getContentSourcePath } from '../../routes'; +import { TelemetryLogic } from '../../../shared/telemetry'; +import { AppLogic } from '../../app_logic'; +import { ContentSection } from '../../components/shared/content_section'; import { RECENT_ACTIVITY_TITLE } from '../../constants'; +import { SOURCE_DETAILS_PATH, getContentSourcePath } from '../../routes'; -import { AppLogic } from '../../app_logic'; import { OverviewLogic } from './overview_logic'; import './recent_activity.scss'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/statistic_card.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/statistic_card.test.tsx index 2893c3630393e..ff1d69e406830 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/statistic_card.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/statistic_card.test.tsx @@ -8,6 +8,7 @@ import '../../../__mocks__/enterprise_search_url.mock'; import React from 'react'; + import { shallow } from 'enzyme'; import { EuiCard } from '@elastic/eui'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/statistic_card.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/statistic_card.tsx index 83e6c2012a046..346debb1c5251 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/statistic_card.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/overview/statistic_card.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { EuiCard, EuiFlexItem, EuiTitle, EuiTextColor } from '@elastic/eui'; import { getWorkplaceSearchUrl } from '../../../shared/enterprise_search_url'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/security/components/private_sources_table.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/security/components/private_sources_table.test.tsx index fb28fba9b3aea..4f7160ba631f1 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/security/components/private_sources_table.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/security/components/private_sources_table.test.tsx @@ -8,7 +8,9 @@ import { setMockValues } from '../../../../__mocks__'; import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiSwitch } from '@elastic/eui'; import { PrivateSourcesTable } from './private_sources_table'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/security/components/private_sources_table.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/security/components/private_sources_table.tsx index 8ba29e5986e04..559b2fe3edbd1 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/security/components/private_sources_table.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/security/components/private_sources_table.tsx @@ -24,11 +24,10 @@ import { EuiTableRowCell, EuiSpacer, } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; import { LicensingLogic } from '../../../../shared/licensing'; -import { SecurityLogic, PrivateSourceSection } from '../security_logic'; import { REMOTE_SOURCES_TOGGLE_TEXT, REMOTE_SOURCES_TABLE_DESCRIPTION, @@ -38,6 +37,7 @@ import { STANDARD_SOURCES_EMPTY_TABLE_TITLE, SOURCE, } from '../../../constants'; +import { SecurityLogic, PrivateSourceSection } from '../security_logic'; interface PrivateSourcesTableProps { sourceType: 'remote' | 'standard'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/security/security.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/security/security.test.tsx index 24e6e5808355a..4eed6a6fefe68 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/security/security.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/security/security.test.tsx @@ -9,11 +9,14 @@ import { setMockValues, setMockActions } from '../../../__mocks__'; import { unmountHandler } from '../../../__mocks__/shallow_useeffect.mock'; import React from 'react'; + import { shallow } from 'enzyme'; + import { EuiSwitch, EuiConfirmModal } from '@elastic/eui'; -import { Loading } from '../../../shared/loading'; +import { Loading } from '../../../shared/loading'; import { ViewContentHeader } from '../../components/shared/view_content_header'; + import { Security } from './security'; describe('Security', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/security/security.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/security/security.tsx index 818dd34447c73..ba1ffb66f4691 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/security/security.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/security/security.tsx @@ -23,15 +23,11 @@ import { EuiOverlayMask, } from '@elastic/eui'; -import { LicensingLogic } from '../../../shared/licensing'; import { FlashMessages } from '../../../shared/flash_messages'; -import { LicenseCallout } from '../../components/shared/license_callout'; +import { LicensingLogic } from '../../../shared/licensing'; import { Loading } from '../../../shared/loading'; +import { LicenseCallout } from '../../components/shared/license_callout'; import { ViewContentHeader } from '../../components/shared/view_content_header'; -import { SecurityLogic } from './security_logic'; - -import { PrivateSourcesTable } from './components/private_sources_table'; - import { SECURITY_UNSAVED_CHANGES_MESSAGE, RESET_BUTTON, @@ -46,6 +42,9 @@ import { PRIVATE_SOURCES_UPDATE_CONFIRMATION_TEXT, } from '../../constants'; +import { PrivateSourcesTable } from './components/private_sources_table'; +import { SecurityLogic } from './security_logic'; + export const Security: React.FC = () => { const [confirmModalVisible, setConfirmModalVisibility] = useState(false); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/security/security_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/security/security_logic.test.ts index c2bd1be390592..02d8fdd3c30e4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/security/security_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/security/security_logic.test.ts @@ -5,11 +5,13 @@ * 2.0. */ -import { LogicMounter } from '../../../__mocks__/kea.mock'; import { mockHttpValues, mockFlashMessageHelpers } from '../../../__mocks__'; -import { SecurityLogic } from './security_logic'; +import { LogicMounter } from '../../../__mocks__/kea.mock'; + import { nextTick } from '@kbn/test/jest'; +import { SecurityLogic } from './security_logic'; + describe('SecurityLogic', () => { const { http } = mockHttpValues; const { flashAPIErrors } = mockFlashMessageHelpers; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/security/security_logic.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/security/security_logic.ts index 8689cec037848..07ebec41366b2 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/security/security_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/security/security_logic.ts @@ -5,11 +5,10 @@ * 2.0. */ +import { kea, MakeLogicType } from 'kea'; import { cloneDeep } from 'lodash'; import { isEqual } from 'lodash'; -import { kea, MakeLogicType } from 'kea'; - import { clearFlashMessages, setSuccessMessage, @@ -17,7 +16,6 @@ import { } from '../../../shared/flash_messages'; import { HttpLogic } from '../../../shared/http'; import { AppLogic } from '../../app_logic'; - import { SOURCE_RESTRICTIONS_SUCCESS_MESSAGE } from '../../constants'; export interface PrivateSource { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/connectors.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/connectors.test.tsx index d1dd9e64c4d2d..13ef86a21a208 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/connectors.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/connectors.test.tsx @@ -8,10 +8,10 @@ import '../../../../__mocks__/shallow_useeffect.mock'; import { setMockValues, setMockActions } from '../../../../__mocks__'; - import { configuredSources } from '../../../__mocks__/content_sources.mock'; import React from 'react'; + import { shallow } from 'enzyme'; import { Loading } from '../../../../shared/loading'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/connectors.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/connectors.tsx index 5b74f6d1d2806..9387cd4602255 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/connectors.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/connectors.tsx @@ -19,12 +19,11 @@ import { EuiSpacer, } from '@elastic/eui'; -import { EuiButtonEmptyTo } from '../../../../shared/react_router_helpers'; import { Loading } from '../../../../shared/loading'; -import { SourceIcon } from '../../../components/shared/source_icon'; +import { EuiButtonEmptyTo } from '../../../../shared/react_router_helpers'; import { LicenseCallout } from '../../../components/shared/license_callout'; +import { SourceIcon } from '../../../components/shared/source_icon'; import { ViewContentHeader } from '../../../components/shared/view_content_header'; - import { CONFIGURE_BUTTON, CONNECTORS_HEADER_TITLE, @@ -36,9 +35,7 @@ import { } from '../../../constants'; import { getSourcesPath } from '../../../routes'; import { SourceDataItem } from '../../../types'; - import { staticSourceData } from '../../content_sources/source_data'; - import { SettingsLogic } from '../settings_logic'; export const Connectors: React.FC = () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/customize.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/customize.test.tsx index 8f77c229ad6f8..ed05829d9e082 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/customize.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/customize.test.tsx @@ -10,6 +10,7 @@ import '../../../../__mocks__/shallow_useeffect.mock'; import { setMockValues, setMockActions } from '../../../../__mocks__'; import React from 'react'; + import { shallow } from 'enzyme'; import { EuiFieldText } from '@elastic/eui'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/customize.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/customize.tsx index d57621bd397db..37f9e288f7f3d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/customize.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/customize.tsx @@ -11,16 +11,14 @@ import { useActions, useValues } from 'kea'; import { EuiButton, EuiFieldText, EuiFlexGroup, EuiFlexItem, EuiFormRow } from '@elastic/eui'; +import { ContentSection } from '../../../components/shared/content_section'; +import { ViewContentHeader } from '../../../components/shared/view_content_header'; import { CUSTOMIZE_HEADER_TITLE, CUSTOMIZE_HEADER_DESCRIPTION, CUSTOMIZE_NAME_LABEL, CUSTOMIZE_NAME_BUTTON, } from '../../../constants'; - -import { ContentSection } from '../../../components/shared/content_section'; -import { ViewContentHeader } from '../../../components/shared/view_content_header'; - import { SettingsLogic } from '../settings_logic'; export const Customize: React.FC = () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/oauth_application.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/oauth_application.test.tsx index 6fc9d51f42a86..55a58610e0ed6 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/oauth_application.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/oauth_application.test.tsx @@ -8,17 +8,18 @@ import '../../../../__mocks__/shallow_useeffect.mock'; import { setMockValues, setMockActions } from '../../../../__mocks__'; +import { oauthApplication } from '../../../__mocks__/content_sources.mock'; import React from 'react'; + import { shallow } from 'enzyme'; import { EuiModal, EuiForm } from '@elastic/eui'; -import { oauthApplication } from '../../../__mocks__/content_sources.mock'; -import { OAUTH_DESCRIPTION, REDIRECT_INSECURE_ERROR_TEXT } from '../../../constants'; - import { CredentialItem } from '../../../components/shared/credential_item'; import { ViewContentHeader } from '../../../components/shared/view_content_header'; +import { OAUTH_DESCRIPTION, REDIRECT_INSECURE_ERROR_TEXT } from '../../../constants'; + import { OauthApplication } from './oauth_application'; describe('OauthApplication', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/oauth_application.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/oauth_application.tsx index 04759e4f5fdd0..28e7e2a33eaa1 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/oauth_application.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/oauth_application.tsx @@ -26,7 +26,11 @@ import { EuiText, } from '@elastic/eui'; -import { ENT_SEARCH_LICENSE_MANAGEMENT } from '../../../routes'; +import { LicensingLogic } from '../../../../shared/licensing'; +import { ContentSection } from '../../../components/shared/content_section'; +import { CredentialItem } from '../../../components/shared/credential_item'; +import { LicenseBadge } from '../../../components/shared/license_badge'; +import { ViewContentHeader } from '../../../components/shared/view_content_header'; import { CLIENT_ID_LABEL, CLIENT_SECRET_LABEL, @@ -48,12 +52,7 @@ import { LICENSE_MODAL_DESCRIPTION, LICENSE_MODAL_LINK, } from '../../../constants'; - -import { LicensingLogic } from '../../../../shared/licensing'; -import { ContentSection } from '../../../components/shared/content_section'; -import { LicenseBadge } from '../../../components/shared/license_badge'; -import { ViewContentHeader } from '../../../components/shared/view_content_header'; -import { CredentialItem } from '../../../components/shared/credential_item'; +import { ENT_SEARCH_LICENSE_MANAGEMENT } from '../../../routes'; import { SettingsLogic } from '../settings_logic'; export const OauthApplication: React.FC = () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/settings_sub_nav.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/settings_sub_nav.test.tsx index f00bb7d897e25..5cd8a3fc1cf03 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/settings_sub_nav.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/settings_sub_nav.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; import { SideNavLink } from '../../../../shared/layout'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/settings_sub_nav.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/settings_sub_nav.tsx index 20a6e349c1272..3f68997a17b8b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/settings_sub_nav.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/settings_sub_nav.tsx @@ -7,10 +7,8 @@ import React from 'react'; -import { NAV } from '../../../constants'; - import { SideNavLink } from '../../../../shared/layout'; - +import { NAV } from '../../../constants'; import { ORG_SETTINGS_CUSTOMIZE_PATH, ORG_SETTINGS_CONNECTORS_PATH, diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/source_config.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/source_config.test.tsx index 73ea92117c6df..ed9f715fd6916 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/source_config.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/source_config.test.tsx @@ -8,16 +8,17 @@ import '../../../../__mocks__/shallow_useeffect.mock'; import { setMockValues, setMockActions } from '../../../../__mocks__'; +import { sourceConfigData } from '../../../__mocks__/content_sources.mock'; import React from 'react'; + import { shallow } from 'enzyme'; import { EuiConfirmModal } from '@elastic/eui'; -import { sourceConfigData } from '../../../__mocks__/content_sources.mock'; - import { Loading } from '../../../../shared/loading'; import { SaveConfig } from '../../content_sources/components/add_source/save_config'; + import { SourceConfig } from './source_config'; describe('SourceConfig', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/source_config.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/source_config.tsx index 4b59e0f3401c5..4ed223931d6a4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/source_config.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/components/source_config.tsx @@ -8,18 +8,16 @@ import React, { useEffect, useState } from 'react'; import { useActions, useValues } from 'kea'; -import { i18n } from '@kbn/i18n'; import { EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { Loading } from '../../../../shared/loading'; import { SourceDataItem } from '../../../types'; -import { staticSourceData } from '../../content_sources/source_data'; -import { AddSourceLogic } from '../../content_sources/components/add_source/add_source_logic'; - import { AddSourceHeader } from '../../content_sources/components/add_source/add_source_header'; +import { AddSourceLogic } from '../../content_sources/components/add_source/add_source_logic'; import { SaveConfig } from '../../content_sources/components/add_source/save_config'; - +import { staticSourceData } from '../../content_sources/source_data'; import { SettingsLogic } from '../settings_logic'; interface SourceConfigProps { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/settings_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/settings_logic.test.ts index b8b08b8658372..a57c2c1f9ad44 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/settings_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/settings_logic.test.ts @@ -5,15 +5,14 @@ * 2.0. */ -import { LogicMounter } from '../../../__mocks__/kea.mock'; - import { mockFlashMessageHelpers, mockHttpValues, mockKibanaValues } from '../../../__mocks__'; +import { LogicMounter } from '../../../__mocks__/kea.mock'; +import { configuredSources, oauthApplication } from '../../__mocks__/content_sources.mock'; import { nextTick } from '@kbn/test/jest'; -import { configuredSources, oauthApplication } from '../../__mocks__/content_sources.mock'; - import { ORG_UPDATED_MESSAGE, OAUTH_APP_UPDATED_MESSAGE } from '../../constants'; + import { SettingsLogic } from './settings_logic'; describe('SettingsLogic', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/settings_logic.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/settings_logic.ts index 5a4f366c737d5..ad552ff8f5a41 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/settings_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/settings_logic.ts @@ -6,6 +6,7 @@ */ import { kea, MakeLogicType } from 'kea'; + import { i18n } from '@kbn/i18n'; import { @@ -14,13 +15,11 @@ import { setSuccessMessage, flashAPIErrors, } from '../../../shared/flash_messages'; -import { KibanaLogic } from '../../../shared/kibana'; import { HttpLogic } from '../../../shared/http'; - -import { Connector } from '../../types'; +import { KibanaLogic } from '../../../shared/kibana'; import { ORG_UPDATED_MESSAGE, OAUTH_APP_UPDATED_MESSAGE } from '../../constants'; - import { ORG_SETTINGS_CONNECTORS_PATH } from '../../routes'; +import { Connector } from '../../types'; interface IOauthApplication { name: string; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/settings_router.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/settings_router.test.tsx index 7f3ba0a8f34b3..411414fb33eaf 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/settings_router.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/settings_router.test.tsx @@ -10,19 +10,17 @@ import '../../../__mocks__/shallow_useeffect.mock'; import { setMockActions } from '../../../__mocks__'; import React from 'react'; -import { shallow } from 'enzyme'; - import { Route, Redirect, Switch } from 'react-router-dom'; -import { staticSourceData } from '../content_sources/source_data'; +import { shallow } from 'enzyme'; import { FlashMessages } from '../../../shared/flash_messages'; +import { staticSourceData } from '../content_sources/source_data'; import { Connectors } from './components/connectors'; import { Customize } from './components/customize'; import { OauthApplication } from './components/oauth_application'; import { SourceConfig } from './components/source_config'; - import { SettingsRouter } from './settings_router'; describe('SettingsRouter', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/settings_router.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/settings_router.tsx index ee9122b015eff..34dcc48621a2e 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/settings_router.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/settings/settings_router.tsx @@ -6,26 +6,23 @@ */ import React, { useEffect } from 'react'; +import { Redirect, Route, Switch } from 'react-router-dom'; import { useActions } from 'kea'; -import { Redirect, Route, Switch } from 'react-router-dom'; +import { FlashMessages } from '../../../shared/flash_messages'; import { ORG_SETTINGS_PATH, ORG_SETTINGS_CUSTOMIZE_PATH, ORG_SETTINGS_CONNECTORS_PATH, ORG_SETTINGS_OAUTH_APPLICATION_PATH, } from '../../routes'; - -import { FlashMessages } from '../../../shared/flash_messages'; +import { staticSourceData } from '../content_sources/source_data'; import { Connectors } from './components/connectors'; import { Customize } from './components/customize'; import { OauthApplication } from './components/oauth_application'; import { SourceConfig } from './components/source_config'; - -import { staticSourceData } from '../content_sources/source_data'; - import { SettingsLogic } from './settings_logic'; export const SettingsRouter: React.FC = () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/setup_guide/setup_guide.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/setup_guide/setup_guide.test.tsx index 8bec56603cd80..6b03e86080402 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/setup_guide/setup_guide.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/setup_guide/setup_guide.test.tsx @@ -6,10 +6,12 @@ */ import React from 'react'; + import { shallow } from 'enzyme'; import { SetWorkplaceSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; import { SetupGuideLayout } from '../../../shared/setup_guide'; + import { SetupGuide } from './'; describe('SetupGuide', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/setup_guide/setup_guide.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/setup_guide/setup_guide.tsx index 810125fc931a6..13191f42bc566 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/setup_guide/setup_guide.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/setup_guide/setup_guide.tsx @@ -6,18 +6,19 @@ */ import React from 'react'; + import { EuiSpacer, EuiTitle, EuiText, EuiButton, EuiLink } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; import { WORKPLACE_SEARCH_PLUGIN } from '../../../../../common/constants'; -import { SetupGuideLayout, SETUP_GUIDE_TITLE } from '../../../shared/setup_guide'; import { SetWorkplaceSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; +import { SetupGuideLayout, SETUP_GUIDE_TITLE } from '../../../shared/setup_guide'; import { SendWorkplaceSearchTelemetry as SendTelemetry } from '../../../shared/telemetry'; +import { DOCS_PREFIX } from '../../routes'; import GettingStarted from './assets/getting_started.png'; -import { DOCS_PREFIX } from '../../routes'; const GETTING_STARTED_LINK_URL = `${DOCS_PREFIX}/workplace-search-getting-started.html`; export const SetupGuide: React.FC = () => { diff --git a/x-pack/plugins/enterprise_search/public/index.ts b/x-pack/plugins/enterprise_search/public/index.ts index da343728b7d41..b7131e70fec07 100644 --- a/x-pack/plugins/enterprise_search/public/index.ts +++ b/x-pack/plugins/enterprise_search/public/index.ts @@ -6,6 +6,7 @@ */ import { PluginInitializerContext } from 'src/core/public'; + import { EnterpriseSearchPlugin } from './plugin'; export const plugin = (initializerContext: PluginInitializerContext) => { diff --git a/x-pack/plugins/enterprise_search/public/plugin.ts b/x-pack/plugins/enterprise_search/public/plugin.ts index c10eb74f47720..f00e81a5accf7 100644 --- a/x-pack/plugins/enterprise_search/public/plugin.ts +++ b/x-pack/plugins/enterprise_search/public/plugin.ts @@ -12,15 +12,15 @@ import { HttpSetup, Plugin, PluginInitializerContext, -} from 'src/core/public'; -import { DEFAULT_APP_CATEGORIES } from '../../../../src/core/public'; + DEFAULT_APP_CATEGORIES, +} from '../../../../src/core/public'; +import { ChartsPluginStart } from '../../../../src/plugins/charts/public'; import { FeatureCatalogueCategory, HomePublicPluginSetup, } from '../../../../src/plugins/home/public'; import { CloudSetup } from '../../cloud/public'; import { LicensingPluginStart } from '../../licensing/public'; -import { ChartsPluginStart } from '../../../../src/plugins/charts/public'; import { APP_SEARCH_PLUGIN, diff --git a/x-pack/plugins/enterprise_search/server/__mocks__/router.mock.ts b/x-pack/plugins/enterprise_search/server/__mocks__/router.mock.ts index 88cf30bb2a549..5c19ca7062b65 100644 --- a/x-pack/plugins/enterprise_search/server/__mocks__/router.mock.ts +++ b/x-pack/plugins/enterprise_search/server/__mocks__/router.mock.ts @@ -5,13 +5,13 @@ * 2.0. */ -import { httpServiceMock, httpServerMock } from 'src/core/server/mocks'; import { IRouter, KibanaRequest, RequestHandlerContext, RouteValidatorConfig, } from 'src/core/server'; +import { httpServiceMock, httpServerMock } from 'src/core/server/mocks'; /** * Test helper that mocks Kibana's router and DRYs out various helper (callRoute, schema validation) diff --git a/x-pack/plugins/enterprise_search/server/__mocks__/routerDependencies.mock.ts b/x-pack/plugins/enterprise_search/server/__mocks__/routerDependencies.mock.ts index c84254660a728..50ff082858fc8 100644 --- a/x-pack/plugins/enterprise_search/server/__mocks__/routerDependencies.mock.ts +++ b/x-pack/plugins/enterprise_search/server/__mocks__/routerDependencies.mock.ts @@ -6,6 +6,7 @@ */ import { loggingSystemMock } from 'src/core/server/mocks'; + import { ConfigType } from '../'; export const mockLogger = loggingSystemMock.createLogger().get(); diff --git a/x-pack/plugins/enterprise_search/server/collectors/app_search/telemetry.ts b/x-pack/plugins/enterprise_search/server/collectors/app_search/telemetry.ts index 537e1b77f3e84..36ba2976f929a 100644 --- a/x-pack/plugins/enterprise_search/server/collectors/app_search/telemetry.ts +++ b/x-pack/plugins/enterprise_search/server/collectors/app_search/telemetry.ts @@ -6,6 +6,7 @@ */ import { get } from 'lodash'; + import { SavedObjectsServiceStart, Logger } from 'src/core/server'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; diff --git a/x-pack/plugins/enterprise_search/server/collectors/enterprise_search/telemetry.ts b/x-pack/plugins/enterprise_search/server/collectors/enterprise_search/telemetry.ts index 732dfbd02c10b..f71c8a5444c9c 100644 --- a/x-pack/plugins/enterprise_search/server/collectors/enterprise_search/telemetry.ts +++ b/x-pack/plugins/enterprise_search/server/collectors/enterprise_search/telemetry.ts @@ -6,6 +6,7 @@ */ import { get } from 'lodash'; + import { SavedObjectsServiceStart, Logger } from 'src/core/server'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; diff --git a/x-pack/plugins/enterprise_search/server/collectors/workplace_search/telemetry.ts b/x-pack/plugins/enterprise_search/server/collectors/workplace_search/telemetry.ts index 01210eba95368..e36ce94066789 100644 --- a/x-pack/plugins/enterprise_search/server/collectors/workplace_search/telemetry.ts +++ b/x-pack/plugins/enterprise_search/server/collectors/workplace_search/telemetry.ts @@ -6,6 +6,7 @@ */ import { get } from 'lodash'; + import { SavedObjectsServiceStart, Logger } from 'src/core/server'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; diff --git a/x-pack/plugins/enterprise_search/server/index.ts b/x-pack/plugins/enterprise_search/server/index.ts index ac012077fdf84..c4552b9134eae 100644 --- a/x-pack/plugins/enterprise_search/server/index.ts +++ b/x-pack/plugins/enterprise_search/server/index.ts @@ -5,8 +5,9 @@ * 2.0. */ -import { PluginInitializerContext, PluginConfigDescriptor } from 'src/core/server'; import { schema, TypeOf } from '@kbn/config-schema'; +import { PluginInitializerContext, PluginConfigDescriptor } from 'src/core/server'; + import { EnterpriseSearchPlugin } from './plugin'; export const plugin = (initializerContext: PluginInitializerContext) => { diff --git a/x-pack/plugins/enterprise_search/server/lib/check_access.test.ts b/x-pack/plugins/enterprise_search/server/lib/check_access.test.ts index 4a978c66b16d6..3c5d33fa74d3b 100644 --- a/x-pack/plugins/enterprise_search/server/lib/check_access.test.ts +++ b/x-pack/plugins/enterprise_search/server/lib/check_access.test.ts @@ -5,14 +5,15 @@ * 2.0. */ +import { spacesMock } from '../../../spaces/server/mocks'; + +import { checkAccess } from './check_access'; + jest.mock('./enterprise_search_config_api', () => ({ callEnterpriseSearchConfigAPI: jest.fn(), })); import { callEnterpriseSearchConfigAPI } from './enterprise_search_config_api'; -import { checkAccess } from './check_access'; -import { spacesMock } from '../../../spaces/server/mocks'; - const enabledSpace = { id: 'space', name: 'space', diff --git a/x-pack/plugins/enterprise_search/server/lib/check_access.ts b/x-pack/plugins/enterprise_search/server/lib/check_access.ts index 25c92d62c1203..0a5e0c9e2b832 100644 --- a/x-pack/plugins/enterprise_search/server/lib/check_access.ts +++ b/x-pack/plugins/enterprise_search/server/lib/check_access.ts @@ -6,9 +6,10 @@ */ import { KibanaRequest, Logger } from 'src/core/server'; -import { SpacesPluginStart } from '../../../spaces/server'; + import { SecurityPluginSetup } from '../../../security/server'; -import { ConfigType } from '../'; +import { SpacesPluginStart } from '../../../spaces/server'; +import { ConfigType } from '../index'; import { callEnterpriseSearchConfigAPI } from './enterprise_search_config_api'; diff --git a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts index 61aeffd99db00..6c6744ef3e32b 100644 --- a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts +++ b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts @@ -5,14 +5,15 @@ * 2.0. */ +import { DEFAULT_INITIAL_APP_DATA } from '../../common/__mocks__'; + jest.mock('node-fetch'); -// eslint-disable-next-line @typescript-eslint/no-var-requires -const fetchMock = require('node-fetch') as jest.Mock; +import fetch from 'node-fetch'; + const { Response } = jest.requireActual('node-fetch'); import { loggingSystemMock } from 'src/core/server/mocks'; -import { DEFAULT_INITIAL_APP_DATA } from '../../common/__mocks__'; import { callEnterpriseSearchConfigAPI } from './enterprise_search_config_api'; describe('callEnterpriseSearchConfigAPI', () => { @@ -101,7 +102,7 @@ describe('callEnterpriseSearchConfigAPI', () => { }); it('calls the config API endpoint', async () => { - fetchMock.mockImplementationOnce((url: string) => { + ((fetch as unknown) as jest.Mock).mockImplementationOnce((url: string) => { expect(url).toEqual('http://localhost:3002/api/ent/v2/internal/client_config'); return Promise.resolve(new Response(JSON.stringify(mockResponse))); }); @@ -117,7 +118,7 @@ describe('callEnterpriseSearchConfigAPI', () => { }); it('falls back without error when data is unavailable', async () => { - fetchMock.mockImplementationOnce((url: string) => Promise.resolve(new Response('{}'))); + ((fetch as unknown) as jest.Mock).mockReturnValueOnce(Promise.resolve(new Response('{}'))); expect(await callEnterpriseSearchConfigAPI(mockDependencies)).toEqual({ access: { @@ -180,21 +181,17 @@ describe('callEnterpriseSearchConfigAPI', () => { const config = { host: '' }; expect(await callEnterpriseSearchConfigAPI({ ...mockDependencies, config })).toEqual({}); - expect(fetchMock).not.toHaveBeenCalled(); + expect(fetch).not.toHaveBeenCalled(); }); it('handles server errors', async () => { - fetchMock.mockImplementationOnce(() => { - return Promise.reject('500'); - }); + ((fetch as unknown) as jest.Mock).mockReturnValueOnce(Promise.reject('500')); expect(await callEnterpriseSearchConfigAPI(mockDependencies)).toEqual({}); expect(mockDependencies.log.error).toHaveBeenCalledWith( 'Could not perform access check to Enterprise Search: 500' ); - fetchMock.mockImplementationOnce(() => { - return Promise.resolve('Bad Data'); - }); + ((fetch as unknown) as jest.Mock).mockReturnValueOnce(Promise.resolve('Bad Data')); expect(await callEnterpriseSearchConfigAPI(mockDependencies)).toEqual({}); expect(mockDependencies.log.error).toHaveBeenCalledWith( 'Could not perform access check to Enterprise Search: TypeError: response.json is not a function' @@ -212,7 +209,7 @@ describe('callEnterpriseSearchConfigAPI', () => { ); // Timeout - fetchMock.mockImplementationOnce(async () => { + ((fetch as unknown) as jest.Mock).mockImplementationOnce(async () => { jest.advanceTimersByTime(250); return Promise.reject({ name: 'AbortError' }); }); diff --git a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.ts b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.ts index 9f207361cef91..0ed4ad257f30b 100644 --- a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.ts +++ b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.ts @@ -9,11 +9,12 @@ import AbortController from 'abort-controller'; import fetch from 'node-fetch'; import { KibanaRequest, Logger } from 'src/core/server'; -import { ConfigType } from '../'; -import { Access } from './check_access'; -import { InitialAppData } from '../../common/types'; import { stripTrailingSlash } from '../../common/strip_slashes'; +import { InitialAppData } from '../../common/types'; +import { ConfigType } from '../index'; + +import { Access } from './check_access'; interface Params { request: KibanaRequest; diff --git a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_request_handler.test.ts b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_request_handler.test.ts index 8d47ba0ec77ba..7199067a2c8f4 100644 --- a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_request_handler.test.ts +++ b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_request_handler.test.ts @@ -6,6 +6,7 @@ */ import { mockConfig, mockLogger } from '../__mocks__'; + import { JSON_HEADER, READ_ONLY_MODE_HEADER } from '../../common/constants'; import { EnterpriseSearchRequestHandler } from './enterprise_search_request_handler'; @@ -13,6 +14,7 @@ import { EnterpriseSearchRequestHandler } from './enterprise_search_request_hand jest.mock('node-fetch'); // eslint-disable-next-line @typescript-eslint/no-var-requires const fetchMock = require('node-fetch') as jest.Mock; + const { Response } = jest.requireActual('node-fetch'); const responseMock = { diff --git a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_request_handler.ts b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_request_handler.ts index 39590b310fc26..f47df58c4eca1 100644 --- a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_request_handler.ts +++ b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_request_handler.ts @@ -7,6 +7,7 @@ import fetch, { Response } from 'node-fetch'; import querystring from 'querystring'; + import { RequestHandler, RequestHandlerContext, @@ -14,8 +15,9 @@ import { KibanaResponseFactory, Logger, } from 'src/core/server'; -import { ConfigType } from '../index'; + import { JSON_HEADER, READ_ONLY_MODE_HEADER } from '../../common/constants'; +import { ConfigType } from '../index'; interface ConstructorDependencies { config: ConfigType; diff --git a/x-pack/plugins/enterprise_search/server/plugin.ts b/x-pack/plugins/enterprise_search/server/plugin.ts index 569479f921cdd..1b9659899097d 100644 --- a/x-pack/plugins/enterprise_search/server/plugin.ts +++ b/x-pack/plugins/enterprise_search/server/plugin.ts @@ -13,37 +13,39 @@ import { SavedObjectsServiceStart, IRouter, KibanaRequest, -} from 'src/core/server'; -import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; -import { SpacesPluginStart } from '../../spaces/server'; -import { DEFAULT_APP_CATEGORIES } from '../../../../src/core/server'; -import { SecurityPluginSetup } from '../../security/server'; + DEFAULT_APP_CATEGORIES, +} from '../../../../src/core/server'; +import { UsageCollectionSetup } from '../../../../src/plugins/usage_collection/server'; import { PluginSetupContract as FeaturesPluginSetup } from '../../features/server'; +import { SecurityPluginSetup } from '../../security/server'; +import { SpacesPluginStart } from '../../spaces/server'; import { ENTERPRISE_SEARCH_PLUGIN, APP_SEARCH_PLUGIN, WORKPLACE_SEARCH_PLUGIN, } from '../common/constants'; -import { ConfigType } from './'; + +import { registerTelemetryUsageCollector as registerASTelemetryUsageCollector } from './collectors/app_search/telemetry'; +import { registerTelemetryUsageCollector as registerESTelemetryUsageCollector } from './collectors/enterprise_search/telemetry'; +import { registerTelemetryUsageCollector as registerWSTelemetryUsageCollector } from './collectors/workplace_search/telemetry'; + import { checkAccess } from './lib/check_access'; import { EnterpriseSearchRequestHandler, IEnterpriseSearchRequestHandler, } from './lib/enterprise_search_request_handler'; -import { enterpriseSearchTelemetryType } from './saved_objects/enterprise_search/telemetry'; -import { registerTelemetryUsageCollector as registerESTelemetryUsageCollector } from './collectors/enterprise_search/telemetry'; -import { registerTelemetryRoute } from './routes/enterprise_search/telemetry'; +import { registerAppSearchRoutes } from './routes/app_search'; import { registerConfigDataRoute } from './routes/enterprise_search/config_data'; +import { registerTelemetryRoute } from './routes/enterprise_search/telemetry'; +import { registerWorkplaceSearchRoutes } from './routes/workplace_search'; import { appSearchTelemetryType } from './saved_objects/app_search/telemetry'; -import { registerTelemetryUsageCollector as registerASTelemetryUsageCollector } from './collectors/app_search/telemetry'; -import { registerAppSearchRoutes } from './routes/app_search'; - +import { enterpriseSearchTelemetryType } from './saved_objects/enterprise_search/telemetry'; import { workplaceSearchTelemetryType } from './saved_objects/workplace_search/telemetry'; -import { registerTelemetryUsageCollector as registerWSTelemetryUsageCollector } from './collectors/workplace_search/telemetry'; -import { registerWorkplaceSearchRoutes } from './routes/workplace_search'; + +import { ConfigType } from './'; interface PluginsSetup { usageCollection?: UsageCollectionSetup; diff --git a/x-pack/plugins/enterprise_search/server/routes/app_search/engines.ts b/x-pack/plugins/enterprise_search/server/routes/app_search/engines.ts index 49ff0353bef03..0070680985a34 100644 --- a/x-pack/plugins/enterprise_search/server/routes/app_search/engines.ts +++ b/x-pack/plugins/enterprise_search/server/routes/app_search/engines.ts @@ -7,8 +7,8 @@ import { schema } from '@kbn/config-schema'; -import { RouteDependencies } from '../../plugin'; import { ENGINES_PAGE_SIZE } from '../../../common/constants'; +import { RouteDependencies } from '../../plugin'; interface EnginesResponse { results: object[]; diff --git a/x-pack/plugins/enterprise_search/server/routes/app_search/index.ts b/x-pack/plugins/enterprise_search/server/routes/app_search/index.ts index 233e728a3010a..92fdcb689db1d 100644 --- a/x-pack/plugins/enterprise_search/server/routes/app_search/index.ts +++ b/x-pack/plugins/enterprise_search/server/routes/app_search/index.ts @@ -7,12 +7,12 @@ import { RouteDependencies } from '../../plugin'; -import { registerEnginesRoutes } from './engines'; -import { registerCredentialsRoutes } from './credentials'; -import { registerSettingsRoutes } from './settings'; import { registerAnalyticsRoutes } from './analytics'; +import { registerCredentialsRoutes } from './credentials'; import { registerDocumentsRoutes, registerDocumentRoutes } from './documents'; +import { registerEnginesRoutes } from './engines'; import { registerSearchSettingsRoutes } from './search_settings'; +import { registerSettingsRoutes } from './settings'; export const registerAppSearchRoutes = (dependencies: RouteDependencies) => { registerEnginesRoutes(dependencies); diff --git a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/config_data.ts b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/config_data.ts index f9c65eedbb13a..e2cbd409bd396 100644 --- a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/config_data.ts +++ b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/config_data.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { RouteDependencies } from '../../plugin'; import { callEnterpriseSearchConfigAPI } from '../../lib/enterprise_search_config_api'; +import { RouteDependencies } from '../../plugin'; export function registerConfigDataRoute({ router, config, log }: RouteDependencies) { router.get( diff --git a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/telemetry.test.ts b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/telemetry.test.ts index 08c398ba3eb0d..62f68748fcea1 100644 --- a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/telemetry.test.ts +++ b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/telemetry.test.ts @@ -5,9 +5,10 @@ * 2.0. */ -import { loggingSystemMock, savedObjectsServiceMock } from 'src/core/server/mocks'; import { MockRouter, mockLogger, mockDependencies } from '../../__mocks__'; +import { loggingSystemMock, savedObjectsServiceMock } from 'src/core/server/mocks'; + jest.mock('../../collectors/lib/telemetry', () => ({ incrementUICounter: jest.fn(), })); diff --git a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/telemetry.ts b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/telemetry.ts index c8750bdff5d38..90afba414c044 100644 --- a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/telemetry.ts +++ b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/telemetry.ts @@ -7,12 +7,13 @@ import { schema } from '@kbn/config-schema'; -import { RouteDependencies } from '../../plugin'; -import { incrementUICounter } from '../../collectors/lib/telemetry'; - -import { ES_TELEMETRY_NAME } from '../../collectors/enterprise_search/telemetry'; import { AS_TELEMETRY_NAME } from '../../collectors/app_search/telemetry'; +import { ES_TELEMETRY_NAME } from '../../collectors/enterprise_search/telemetry'; +import { incrementUICounter } from '../../collectors/lib/telemetry'; import { WS_TELEMETRY_NAME } from '../../collectors/workplace_search/telemetry'; + +import { RouteDependencies } from '../../plugin'; + const productToTelemetryMap = { enterprise_search: ES_TELEMETRY_NAME, app_search: AS_TELEMETRY_NAME, diff --git a/x-pack/plugins/enterprise_search/server/routes/workplace_search/index.ts b/x-pack/plugins/enterprise_search/server/routes/workplace_search/index.ts index c4819c3579adc..cc6226e340653 100644 --- a/x-pack/plugins/enterprise_search/server/routes/workplace_search/index.ts +++ b/x-pack/plugins/enterprise_search/server/routes/workplace_search/index.ts @@ -7,11 +7,11 @@ import { RouteDependencies } from '../../plugin'; -import { registerOverviewRoute } from './overview'; import { registerGroupsRoutes } from './groups'; -import { registerSourcesRoutes } from './sources'; -import { registerSettingsRoutes } from './settings'; +import { registerOverviewRoute } from './overview'; import { registerSecurityRoutes } from './security'; +import { registerSettingsRoutes } from './settings'; +import { registerSourcesRoutes } from './sources'; export const registerWorkplaceSearchRoutes = (dependencies: RouteDependencies) => { registerOverviewRoute(dependencies); diff --git a/x-pack/plugins/enterprise_search/server/saved_objects/app_search/telemetry.ts b/x-pack/plugins/enterprise_search/server/saved_objects/app_search/telemetry.ts index 29b1ce8182f52..ab873b6678885 100644 --- a/x-pack/plugins/enterprise_search/server/saved_objects/app_search/telemetry.ts +++ b/x-pack/plugins/enterprise_search/server/saved_objects/app_search/telemetry.ts @@ -8,6 +8,7 @@ /* istanbul ignore file */ import { SavedObjectsType } from 'src/core/server'; + import { AS_TELEMETRY_NAME } from '../../collectors/app_search/telemetry'; export const appSearchTelemetryType: SavedObjectsType = { diff --git a/x-pack/plugins/enterprise_search/server/saved_objects/enterprise_search/telemetry.ts b/x-pack/plugins/enterprise_search/server/saved_objects/enterprise_search/telemetry.ts index 07659299ef87f..e2edff1b6a213 100644 --- a/x-pack/plugins/enterprise_search/server/saved_objects/enterprise_search/telemetry.ts +++ b/x-pack/plugins/enterprise_search/server/saved_objects/enterprise_search/telemetry.ts @@ -8,6 +8,7 @@ /* istanbul ignore file */ import { SavedObjectsType } from 'src/core/server'; + import { ES_TELEMETRY_NAME } from '../../collectors/enterprise_search/telemetry'; export const enterpriseSearchTelemetryType: SavedObjectsType = { diff --git a/x-pack/plugins/enterprise_search/server/saved_objects/workplace_search/telemetry.ts b/x-pack/plugins/enterprise_search/server/saved_objects/workplace_search/telemetry.ts index a466d69cf8343..af4d5908dec67 100644 --- a/x-pack/plugins/enterprise_search/server/saved_objects/workplace_search/telemetry.ts +++ b/x-pack/plugins/enterprise_search/server/saved_objects/workplace_search/telemetry.ts @@ -8,6 +8,7 @@ /* istanbul ignore file */ import { SavedObjectsType } from 'src/core/server'; + import { WS_TELEMETRY_NAME } from '../../collectors/workplace_search/telemetry'; export const workplaceSearchTelemetryType: SavedObjectsType = { diff --git a/x-pack/plugins/file_upload/kibana.json b/x-pack/plugins/file_upload/kibana.json index 7ca024174ec6a..7676a01d0b0f9 100644 --- a/x-pack/plugins/file_upload/kibana.json +++ b/x-pack/plugins/file_upload/kibana.json @@ -3,6 +3,6 @@ "version": "8.0.0", "kibanaVersion": "kibana", "server": true, - "ui": false, - "requiredPlugins": ["usageCollection"] + "ui": true, + "requiredPlugins": ["data", "usageCollection"] } diff --git a/x-pack/plugins/maps_file_upload/public/components/index_settings.js b/x-pack/plugins/file_upload/public/components/index_settings.js similarity index 100% rename from x-pack/plugins/maps_file_upload/public/components/index_settings.js rename to x-pack/plugins/file_upload/public/components/index_settings.js diff --git a/x-pack/plugins/maps_file_upload/public/components/json_import_progress.js b/x-pack/plugins/file_upload/public/components/json_import_progress.js similarity index 96% rename from x-pack/plugins/maps_file_upload/public/components/json_import_progress.js rename to x-pack/plugins/file_upload/public/components/json_import_progress.js index 535142bc3500e..1f9293e77d33c 100644 --- a/x-pack/plugins/maps_file_upload/public/components/json_import_progress.js +++ b/x-pack/plugins/file_upload/public/components/json_import_progress.js @@ -118,9 +118,7 @@ export class JsonImportProgress extends Component { {i18n.translate('xpack.fileUpload.jsonImport.indexMgmtLink', { defaultMessage: 'Index Management', diff --git a/x-pack/plugins/maps_file_upload/public/components/json_index_file_picker.js b/x-pack/plugins/file_upload/public/components/json_index_file_picker.js similarity index 99% rename from x-pack/plugins/maps_file_upload/public/components/json_index_file_picker.js rename to x-pack/plugins/file_upload/public/components/json_index_file_picker.js index 8721b5b60f039..a92412ae9d697 100644 --- a/x-pack/plugins/maps_file_upload/public/components/json_index_file_picker.js +++ b/x-pack/plugins/file_upload/public/components/json_index_file_picker.js @@ -10,8 +10,8 @@ import { EuiFilePicker, EuiFormRow, EuiProgress } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; import { parseFile } from '../util/file_parser'; -import { MAX_FILE_SIZE } from '../../common/constants/file_import'; +const MAX_FILE_SIZE = 52428800; const ACCEPTABLE_FILETYPES = ['json', 'geojson']; const acceptedFileTypeString = ACCEPTABLE_FILETYPES.map((type) => `.${type}`).join(','); const acceptedFileTypeStringMessage = ACCEPTABLE_FILETYPES.map((type) => `.${type}`).join(', '); diff --git a/x-pack/plugins/maps_file_upload/public/components/json_upload_and_parse.js b/x-pack/plugins/file_upload/public/components/json_upload_and_parse.js similarity index 100% rename from x-pack/plugins/maps_file_upload/public/components/json_upload_and_parse.js rename to x-pack/plugins/file_upload/public/components/json_upload_and_parse.js diff --git a/x-pack/plugins/maps_file_upload/public/get_file_upload_component.ts b/x-pack/plugins/file_upload/public/get_file_upload_component.ts similarity index 100% rename from x-pack/plugins/maps_file_upload/public/get_file_upload_component.ts rename to x-pack/plugins/file_upload/public/get_file_upload_component.ts diff --git a/x-pack/plugins/maps_file_upload/public/index.ts b/x-pack/plugins/file_upload/public/index.ts similarity index 94% rename from x-pack/plugins/maps_file_upload/public/index.ts rename to x-pack/plugins/file_upload/public/index.ts index 95553685cbbdd..efabc984e0220 100644 --- a/x-pack/plugins/maps_file_upload/public/index.ts +++ b/x-pack/plugins/file_upload/public/index.ts @@ -11,5 +11,7 @@ export function plugin() { return new FileUploadPlugin(); } +export * from '../common'; + export { StartContract } from './plugin'; export { FileUploadComponentProps } from './get_file_upload_component'; diff --git a/x-pack/plugins/maps_file_upload/public/kibana_services.js b/x-pack/plugins/file_upload/public/kibana_services.js similarity index 100% rename from x-pack/plugins/maps_file_upload/public/kibana_services.js rename to x-pack/plugins/file_upload/public/kibana_services.js diff --git a/x-pack/plugins/maps_file_upload/public/plugin.ts b/x-pack/plugins/file_upload/public/plugin.ts similarity index 100% rename from x-pack/plugins/maps_file_upload/public/plugin.ts rename to x-pack/plugins/file_upload/public/plugin.ts diff --git a/x-pack/plugins/maps_file_upload/public/util/file_parser.js b/x-pack/plugins/file_upload/public/util/file_parser.js similarity index 100% rename from x-pack/plugins/maps_file_upload/public/util/file_parser.js rename to x-pack/plugins/file_upload/public/util/file_parser.js diff --git a/x-pack/plugins/maps_file_upload/public/util/file_parser.test.js b/x-pack/plugins/file_upload/public/util/file_parser.test.js similarity index 100% rename from x-pack/plugins/maps_file_upload/public/util/file_parser.test.js rename to x-pack/plugins/file_upload/public/util/file_parser.test.js diff --git a/x-pack/plugins/maps_file_upload/public/util/geo_json_clean_and_validate.js b/x-pack/plugins/file_upload/public/util/geo_json_clean_and_validate.js similarity index 100% rename from x-pack/plugins/maps_file_upload/public/util/geo_json_clean_and_validate.js rename to x-pack/plugins/file_upload/public/util/geo_json_clean_and_validate.js diff --git a/x-pack/plugins/maps_file_upload/public/util/geo_json_clean_and_validate.test.js b/x-pack/plugins/file_upload/public/util/geo_json_clean_and_validate.test.js similarity index 100% rename from x-pack/plugins/maps_file_upload/public/util/geo_json_clean_and_validate.test.js rename to x-pack/plugins/file_upload/public/util/geo_json_clean_and_validate.test.js diff --git a/x-pack/plugins/maps_file_upload/public/util/geo_processing.js b/x-pack/plugins/file_upload/public/util/geo_processing.js similarity index 76% rename from x-pack/plugins/maps_file_upload/public/util/geo_processing.js rename to x-pack/plugins/file_upload/public/util/geo_processing.js index d6f9651496aca..c90c55c2b49ac 100644 --- a/x-pack/plugins/maps_file_upload/public/util/geo_processing.js +++ b/x-pack/plugins/file_upload/public/util/geo_processing.js @@ -6,26 +6,12 @@ */ import _ from 'lodash'; -import { ES_GEO_FIELD_TYPE } from '../../common/constants/file_import'; -const DEFAULT_SETTINGS = { - number_of_shards: 1, +export const ES_GEO_FIELD_TYPE = { + GEO_POINT: 'geo_point', + GEO_SHAPE: 'geo_shape', }; -const DEFAULT_GEO_SHAPE_MAPPINGS = { - coordinates: { - type: ES_GEO_FIELD_TYPE.GEO_SHAPE, - }, -}; - -const DEFAULT_GEO_POINT_MAPPINGS = { - coordinates: { - type: ES_GEO_FIELD_TYPE.GEO_POINT, - }, -}; - -const DEFAULT_INGEST_PIPELINE = {}; - export function getGeoIndexTypesForFeatures(featureTypes) { const hasNoFeatureType = !featureTypes || !featureTypes.length; if (hasNoFeatureType) { @@ -77,11 +63,16 @@ export function geoJsonToEs(parsedGeojson, datatype) { export function getGeoJsonIndexingDetails(parsedGeojson, dataType) { return { data: geoJsonToEs(parsedGeojson, dataType), - ingestPipeline: DEFAULT_INGEST_PIPELINE, - mappings: - dataType === ES_GEO_FIELD_TYPE.GEO_POINT - ? DEFAULT_GEO_POINT_MAPPINGS - : DEFAULT_GEO_SHAPE_MAPPINGS, - settings: DEFAULT_SETTINGS, + ingestPipeline: {}, + mappings: { + properties: { + coordinates: { + type: dataType, + }, + }, + }, + settings: { + number_of_shards: 1, + }, }; } diff --git a/x-pack/plugins/maps_file_upload/public/util/geo_processing.test.js b/x-pack/plugins/file_upload/public/util/geo_processing.test.js similarity index 97% rename from x-pack/plugins/maps_file_upload/public/util/geo_processing.test.js rename to x-pack/plugins/file_upload/public/util/geo_processing.test.js index 75da5bae015af..37b665c0a3e16 100644 --- a/x-pack/plugins/maps_file_upload/public/util/geo_processing.test.js +++ b/x-pack/plugins/file_upload/public/util/geo_processing.test.js @@ -5,8 +5,7 @@ * 2.0. */ -import { geoJsonToEs } from './geo_processing'; -import { ES_GEO_FIELD_TYPE } from '../../common/constants/file_import'; +import { ES_GEO_FIELD_TYPE, geoJsonToEs } from './geo_processing'; describe('geo_processing', () => { describe('getGeoJsonToEs', () => { diff --git a/x-pack/plugins/maps_file_upload/public/util/http_service.js b/x-pack/plugins/file_upload/public/util/http_service.js similarity index 100% rename from x-pack/plugins/maps_file_upload/public/util/http_service.js rename to x-pack/plugins/file_upload/public/util/http_service.js diff --git a/x-pack/plugins/maps_file_upload/public/util/indexing_service.js b/x-pack/plugins/file_upload/public/util/indexing_service.js similarity index 96% rename from x-pack/plugins/maps_file_upload/public/util/indexing_service.js rename to x-pack/plugins/file_upload/public/util/indexing_service.js index c29e9685162bc..253681dad6a7d 100644 --- a/x-pack/plugins/maps_file_upload/public/util/indexing_service.js +++ b/x-pack/plugins/file_upload/public/util/indexing_service.js @@ -11,8 +11,6 @@ import { getGeoJsonIndexingDetails } from './geo_processing'; import { sizeLimitedChunking } from './size_limited_chunking'; import { i18n } from '@kbn/i18n'; -const fileType = 'json'; - export async function indexData(parsedFile, transformDetails, indexName, dataType, appName) { if (!parsedFile) { throw i18n.translate('xpack.fileUpload.indexingService.noFileImported', { @@ -117,10 +115,10 @@ function transformDataByFormatForIndexing(transform, parsedFile, dataType) { async function writeToIndex(indexingDetails) { const query = indexingDetails.id ? { id: indexingDetails.id } : null; - const { appName, index, data, settings, mappings, ingestPipeline } = indexingDetails; + const { index, data, settings, mappings, ingestPipeline } = indexingDetails; return await httpService({ - url: `/api/maps/fileupload/import`, + url: `/api/file_upload/import`, method: 'POST', ...(query ? { query } : {}), data: { @@ -129,8 +127,6 @@ async function writeToIndex(indexingDetails) { settings, mappings, ingestPipeline, - fileType, - ...(appName ? { app: appName } : {}), }, }); } diff --git a/x-pack/plugins/maps_file_upload/public/util/indexing_service.test.js b/x-pack/plugins/file_upload/public/util/indexing_service.test.js similarity index 100% rename from x-pack/plugins/maps_file_upload/public/util/indexing_service.test.js rename to x-pack/plugins/file_upload/public/util/indexing_service.test.js diff --git a/x-pack/plugins/maps_file_upload/public/util/size_limited_chunking.js b/x-pack/plugins/file_upload/public/util/size_limited_chunking.js similarity index 95% rename from x-pack/plugins/maps_file_upload/public/util/size_limited_chunking.js rename to x-pack/plugins/file_upload/public/util/size_limited_chunking.js index e42e11d0f27f0..09d4e8ca8e3a2 100644 --- a/x-pack/plugins/maps_file_upload/public/util/size_limited_chunking.js +++ b/x-pack/plugins/file_upload/public/util/size_limited_chunking.js @@ -5,7 +5,7 @@ * 2.0. */ -import { MAX_BYTES } from '../../common/constants/file_import'; +const MAX_BYTES = 31457280; // MAX_BYTES is a good guideline for splitting up posts, but this logic // occasionally sizes chunks so closely to the limit, that the remaining content diff --git a/x-pack/plugins/maps_file_upload/public/util/size_limited_chunking.test.js b/x-pack/plugins/file_upload/public/util/size_limited_chunking.test.js similarity index 100% rename from x-pack/plugins/maps_file_upload/public/util/size_limited_chunking.test.js rename to x-pack/plugins/file_upload/public/util/size_limited_chunking.test.js diff --git a/x-pack/plugins/file_upload/server/routes.ts b/x-pack/plugins/file_upload/server/routes.ts index 425e5551f2147..d7b7b8f99edd9 100644 --- a/x-pack/plugins/file_upload/server/routes.ts +++ b/x-pack/plugins/file_upload/server/routes.ts @@ -52,7 +52,7 @@ export function fileUploadRoutes(router: IRouter) { accepts: ['application/json'], maxBytes: MAX_FILE_SIZE_BYTES, }, - tags: ['access:ml:canFindFileStructure'], + tags: ['access:fileUpload:import'], }, }, async (context, request, response) => { diff --git a/x-pack/plugins/file_upload/tsconfig.json b/x-pack/plugins/file_upload/tsconfig.json index f985a4599d5fe..bebb08e6dd5e3 100644 --- a/x-pack/plugins/file_upload/tsconfig.json +++ b/x-pack/plugins/file_upload/tsconfig.json @@ -10,6 +10,7 @@ "include": ["common/**/*", "public/**/*", "server/**/*"], "references": [ { "path": "../../../src/core/tsconfig.json" }, + { "path": "../../../src/plugins/data/tsconfig.json" }, { "path": "../../../src/plugins/usage_collection/tsconfig.json" } ] } diff --git a/x-pack/plugins/fleet/server/services/agents/enroll.ts b/x-pack/plugins/fleet/server/services/agents/enroll.ts index c984a84ceea01..6ca19bf884cca 100644 --- a/x-pack/plugins/fleet/server/services/agents/enroll.ts +++ b/x-pack/plugins/fleet/server/services/agents/enroll.ts @@ -11,11 +11,13 @@ import semverParse from 'semver/functions/parse'; import semverDiff from 'semver/functions/diff'; import semverLte from 'semver/functions/lte'; -import { SavedObjectsClientContract } from 'src/core/server'; -import { AgentType, Agent, AgentSOAttributes, FleetServerAgent } from '../../types'; +import type { SavedObjectsClientContract } from 'src/core/server'; +import type { AgentType, Agent, AgentSOAttributes, FleetServerAgent } from '../../types'; import { savedObjectToAgent } from './saved_objects'; import { AGENT_SAVED_OBJECT_TYPE, AGENTS_INDEX } from '../../constants'; +import { IngestManagerError } from '../../errors'; import * as APIKeyService from '../api_keys'; +import { agentPolicyService } from '../../services'; import { appContextService } from '../app_context'; export async function enroll( @@ -27,6 +29,11 @@ export async function enroll( const agentVersion = metadata?.local?.elastic?.agent?.version; validateAgentVersion(agentVersion); + const agentPolicy = await agentPolicyService.get(soClient, agentPolicyId, false); + if (agentPolicy?.is_managed) { + throw new IngestManagerError(`Cannot enroll in managed policy ${agentPolicyId}`); + } + if (appContextService.getConfig()?.agents?.fleetServerEnabled) { const esClient = appContextService.getInternalUserESClient(); diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.helpers.tsx b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.helpers.tsx index dc375f6370048..38049dd7c6cfa 100644 --- a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.helpers.tsx +++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.helpers.tsx @@ -278,7 +278,6 @@ export const setup = async (arg?: { appServicesContext: Partial exists('policyFormErrorsCallout'), timeline: { - hasRolloverIndicator: () => exists('timelineHotPhaseRolloverToolTip'), hasHotPhase: () => exists('ilmTimelineHotPhase'), hasWarmPhase: () => exists('ilmTimelineWarmPhase'), hasColdPhase: () => exists('ilmTimelineColdPhase'), diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.test.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.test.ts index f2266741ec7d1..282daf780b86c 100644 --- a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.test.ts +++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.test.ts @@ -845,14 +845,6 @@ describe('', () => { expect(actions.timeline.hasColdPhase()).toBe(true); expect(actions.timeline.hasDeletePhase()).toBe(true); }); - - test('show and hide rollover indicator on timeline', async () => { - const { actions } = testBed; - expect(actions.timeline.hasRolloverIndicator()).toBe(true); - await actions.hot.toggleDefaultRollover(false); - await actions.hot.toggleRollover(false); - expect(actions.timeline.hasRolloverIndicator()).toBe(false); - }); }); describe('policy error notifications', () => { diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/hot_phase/hot_phase.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/hot_phase/hot_phase.tsx index 74809965a52d9..c77493476b929 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/hot_phase/hot_phase.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/hot_phase/hot_phase.tsx @@ -17,7 +17,7 @@ import { EuiTextColor, EuiSwitch, EuiIconTip, - EuiIcon, + EuiText, } from '@elastic/eui'; import { useFormData, SelectField, NumericField } from '../../../../../../shared_imports'; @@ -68,8 +68,20 @@ export const HotPhase: FunctionComponent = () => {

{' '} + defaultMessage="Start writing to a new index when the current index reaches a certain size, document count, or age. Enables you to optimize performance and manage resource usage when working with time series data." + /> +

+ + + +

+ + {i18n.translate( + 'xpack.indexLifecycleMgmt.rollover.rolloverOffsetsPhaseTimingDescriptionNote', + { defaultMessage: 'Note: ' } + )} + + {i18nTexts.editPolicy.rolloverOffsetsHotPhaseTiming}{' '} {

- -   - {i18nTexts.editPolicy.rolloverOffsetsHotPhaseTiming} - path={isUsingDefaultRolloverPath}> {(field) => ( <> - field.setValue(e.target.checked)} - data-test-subj="useDefaultRolloverSwitch" - /> -   - - } + + field.setValue(e.target.checked)} + data-test-subj="useDefaultRolloverSwitch" + /> + + + )} diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/forcemerge_field.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/forcemerge_field.tsx index bbdcbbf4759ef..8cb566ceae25a 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/forcemerge_field.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/forcemerge_field.tsx @@ -45,7 +45,7 @@ export const ForcemergeField: React.FunctionComponent = ({ phase }) => { <> {' '} diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/searchable_snapshot_field/searchable_snapshot_field.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/searchable_snapshot_field/searchable_snapshot_field.tsx index 9251b08742476..c85201f708a2b 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/searchable_snapshot_field/searchable_snapshot_field.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/searchable_snapshot_field/searchable_snapshot_field.tsx @@ -342,7 +342,7 @@ export const SearchableSnapshotField: FunctionComponent = ({ phase }) => , }} diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/shrink_field.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/shrink_field.tsx index b5fb79811ee2d..8ac387ba106b7 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/shrink_field.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/shrink_field.tsx @@ -38,7 +38,7 @@ export const ShrinkField: FunctionComponent = ({ phase }) => { {' '} diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/timeline/components/timeline_phase_text.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/timeline/components/timeline_phase_text.tsx index 3a9f33fa3d169..62b100b85cbe2 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/timeline/components/timeline_phase_text.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/timeline/components/timeline_phase_text.tsx @@ -12,8 +12,8 @@ export const TimelinePhaseText: FunctionComponent<{ phaseName: ReactNode | string; durationInPhase?: ReactNode | string; }> = ({ phaseName, durationInPhase }) => ( - - + + {phaseName} diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/timeline/timeline.scss b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/timeline/timeline.scss index 7d65d2cd6b212..de49e665ed933 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/timeline/timeline.scss +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/timeline/timeline.scss @@ -1,11 +1,5 @@ $ilmTimelineBarHeight: $euiSizeS; -/* -* For theming we need to shade or tint to get the right color from the base EUI color -*/ -$ilmDeletePhaseBackgroundColor: tintOrShade($euiColorVis5_behindText, 80%,80%); -$ilmDeletePhaseColor: shadeOrTint($euiColorVis5, 40%, 40%); - .ilmTimeline { overflow: hidden; width: 100%; @@ -49,14 +43,16 @@ $ilmDeletePhaseColor: shadeOrTint($euiColorVis5, 40%, 40%); */ padding: $euiSizeM; margin-left: $euiSizeM; - background-color: $ilmDeletePhaseBackgroundColor; - color: $ilmDeletePhaseColor; - border-radius: calc(#{$euiSizeS} / 2); + background-color: $euiColorLightestShade; + color: $euiColorDarkShade; + border-radius: 50%; } &__colorBar { display: inline-block; height: $ilmTimelineBarHeight; + margin-top: $euiSizeS; + margin-bottom: $euiSizeXS; border-radius: calc(#{$ilmTimelineBarHeight} / 2); width: 100%; } @@ -84,8 +80,4 @@ $ilmDeletePhaseColor: shadeOrTint($euiColorVis5, 40%, 40%); background-color: $euiColorVis1; } } - - &__rolloverIcon { - display: inline-block; - } } diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/timeline/timeline.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/timeline/timeline.tsx index 2d83009bd4df4..8097ab51eb59e 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/timeline/timeline.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/timeline/timeline.tsx @@ -8,14 +8,12 @@ import { i18n } from '@kbn/i18n'; import React, { FunctionComponent, memo } from 'react'; - -import { EuiFlexGroup, EuiFlexItem, EuiTitle, EuiIconTip } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiTitle, EuiText, EuiIconTip } from '@elastic/eui'; import { PhasesExceptDelete } from '../../../../../../common/types'; import { calculateRelativeFromAbsoluteMilliseconds, - normalizeTimingsToHumanReadable, PhaseAgeInMilliseconds, AbsoluteTimings, } from '../../lib'; @@ -48,6 +46,12 @@ const msTimeToOverallPercent = (ms: number, totalMs: number) => { const SCORE_BUFFER_AMOUNT = 50; const i18nTexts = { + title: i18n.translate('xpack.indexLifecycleMgmt.timeline.title', { + defaultMessage: 'Policy Summary', + }), + description: i18n.translate('xpack.indexLifecycleMgmt.timeline.description', { + defaultMessage: 'This policy moves data through the following phases.', + }), hotPhase: i18n.translate('xpack.indexLifecycleMgmt.timeline.hotPhaseSectionTitle', { defaultMessage: 'Hot phase', }), @@ -69,6 +73,11 @@ const i18nTexts = { defaultMessage: 'Policy deletes the index after lifecycle phases complete.', }), }, + foreverIcon: { + ariaLabel: i18n.translate('xpack.indexLifecycleMgmt.timeline.foreverIconToolTipContent', { + defaultMessage: 'Forever', + }), + }, }; const calculateWidths = (inputs: PhaseAgeInMilliseconds) => { @@ -118,27 +127,23 @@ export const Timeline: FunctionComponent = memo( }; const phaseAgeInMilliseconds = calculateRelativeFromAbsoluteMilliseconds(absoluteTimings); - const humanReadableTimings = normalizeTimingsToHumanReadable(phaseAgeInMilliseconds); const widths = calculateWidths(phaseAgeInMilliseconds); const getDurationInPhaseContent = (phase: PhasesExceptDelete): string | React.ReactNode => phaseAgeInMilliseconds.phases[phase] === Infinity ? ( - - ) : ( - humanReadableTimings[phase] - ); + + ) : null; return ( -

- {i18n.translate('xpack.indexLifecycleMgmt.timeline.title', { - defaultMessage: 'Policy Timeline', - })} -

+

{i18nTexts.title}

+ + {i18nTexts.description} +
= memo( >
- {i18nTexts.hotPhase} -   -
- -
- - ) : ( - i18nTexts.hotPhase - ) - } + phaseName={i18nTexts.hotPhase} durationInPhase={getDurationInPhaseContent('hot')} />
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/i18n_texts.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/i18n_texts.ts index 5deba8607cd52..3923cf93cd0d3 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/i18n_texts.ts +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/i18n_texts.ts @@ -16,7 +16,7 @@ export const i18nTexts = { 'xpack.indexLifecycleMgmt.rollover.rolloverOffsetsPhaseTimingDescription', { defaultMessage: - 'How long it takes to reach the rollover criteria in the hot phase can vary. Data moves to the next phase when the time since rollover reaches the minimum age.', + 'How long it takes to reach the rollover criteria in the hot phase can vary.', } ), searchableSnapshotInHotPhase: { @@ -195,7 +195,7 @@ export const i18nTexts = { descriptions: { hot: i18n.translate('xpack.indexLifecycleMgmt.editPolicy.hotPhase.hotPhaseDescription', { defaultMessage: - 'This phase is required. You are actively querying and writing to your index. For faster updates, you can roll over the index when it gets too big or too old.', + 'You actively store and query data in the hot phase. All policies have a hot phase.', }), warm: i18n.translate('xpack.indexLifecycleMgmt.editPolicy.warmPhase.warmPhaseDescription', { defaultMessage: diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/lib/absolute_timing_to_relative_timing.test.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/lib/absolute_timing_to_relative_timing.test.ts index 7ec20cc2a5966..8a9635e2db219 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/lib/absolute_timing_to_relative_timing.test.ts +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/lib/absolute_timing_to_relative_timing.test.ts @@ -11,7 +11,6 @@ import { deserializer } from '../form'; import { formDataToAbsoluteTimings, calculateRelativeFromAbsoluteMilliseconds, - absoluteTimingToRelativeTiming, } from './absolute_timing_to_relative_timing'; export const calculateRelativeTimingMs = flow( @@ -273,243 +272,4 @@ describe('Conversion of absolute policy timing to relative timing', () => { }); }); }); - - describe('absoluteTimingToRelativeTiming', () => { - describe('policy that never deletes data (keep forever)', () => { - test('always hot', () => { - expect( - absoluteTimingToRelativeTiming( - deserializer({ - name: 'test', - phases: { - hot: { - min_age: '0ms', - actions: {}, - }, - }, - }) - ) - ).toEqual({ total: 'forever', hot: 'forever', warm: undefined, cold: undefined }); - }); - - test('hot, then always warm', () => { - expect( - absoluteTimingToRelativeTiming( - deserializer({ - name: 'test', - phases: { - hot: { - min_age: '0ms', - actions: {}, - }, - warm: { - actions: {}, - }, - }, - }) - ) - ).toEqual({ total: 'forever', hot: 'less than a day', warm: 'forever', cold: undefined }); - }); - - test('hot, then warm, then always cold', () => { - expect( - absoluteTimingToRelativeTiming( - deserializer({ - name: 'test', - phases: { - hot: { - min_age: '0ms', - actions: {}, - }, - warm: { - min_age: '1M', - actions: {}, - }, - cold: { - min_age: '34d', - actions: {}, - }, - }, - }) - ) - ).toEqual({ - total: 'forever', - hot: '30 days', - warm: '4 days', - cold: 'forever', - }); - }); - - test('hot, then always cold', () => { - expect( - absoluteTimingToRelativeTiming( - deserializer({ - name: 'test', - phases: { - hot: { - min_age: '0ms', - actions: {}, - }, - cold: { - min_age: '34d', - actions: {}, - }, - }, - }) - ) - ).toEqual({ total: 'forever', hot: '34 days', warm: undefined, cold: 'forever' }); - }); - }); - - describe('policy that deletes data', () => { - test('hot, then delete', () => { - expect( - absoluteTimingToRelativeTiming( - deserializer({ - name: 'test', - phases: { - hot: { - min_age: '0ms', - actions: {}, - }, - delete: { - min_age: '1M', - actions: {}, - }, - }, - }) - ) - ).toEqual({ - total: '30 days', - hot: '30 days', - warm: undefined, - cold: undefined, - }); - }); - - test('hot, then warm, then delete', () => { - expect( - absoluteTimingToRelativeTiming( - deserializer({ - name: 'test', - phases: { - hot: { - min_age: '0ms', - actions: {}, - }, - warm: { - min_age: '24d', - actions: {}, - }, - delete: { - min_age: '1M', - actions: {}, - }, - }, - }) - ) - ).toEqual({ - total: '30 days', - hot: '24 days', - warm: '6 days', - cold: undefined, - }); - }); - - test('hot, then warm, then cold, then delete', () => { - expect( - absoluteTimingToRelativeTiming( - deserializer({ - name: 'test', - phases: { - hot: { - min_age: '0ms', - actions: {}, - }, - warm: { - min_age: '24d', - actions: {}, - }, - cold: { - min_age: '2M', - actions: {}, - }, - delete: { - min_age: '2d', - actions: {}, - }, - }, - }) - ) - ).toEqual({ - total: '61 days', - hot: '24 days', - warm: '37 days', - cold: 'less than a day', - }); - }); - - test('hot, then cold, then delete', () => { - expect( - absoluteTimingToRelativeTiming( - deserializer({ - name: 'test', - phases: { - hot: { - min_age: '0ms', - actions: {}, - }, - cold: { - min_age: '2M', - actions: {}, - }, - delete: { - min_age: '2d', - actions: {}, - }, - }, - }) - ) - ).toEqual({ - total: '61 days', - hot: '61 days', - warm: undefined, - cold: 'less than a day', - }); - }); - - test('hot, then long warm, then short cold, then delete', () => { - expect( - absoluteTimingToRelativeTiming( - deserializer({ - name: 'test', - phases: { - hot: { - min_age: '0ms', - actions: {}, - }, - warm: { - min_age: '2M', - actions: {}, - }, - cold: { - min_age: '1d', - actions: {}, - }, - delete: { - min_age: '2d', - actions: {}, - }, - }, - }) - ) - ).toEqual({ - total: '61 days', - hot: '61 days', - warm: 'less than a day', - cold: 'less than a day', - }); - }); - }); - }); }); diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/lib/absolute_timing_to_relative_timing.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/lib/absolute_timing_to_relative_timing.ts index 73ff8c76b9233..2974a88c22343 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/lib/absolute_timing_to_relative_timing.ts +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/lib/absolute_timing_to_relative_timing.ts @@ -21,8 +21,6 @@ */ import moment from 'moment'; -import { i18n } from '@kbn/i18n'; -import { flow } from 'fp-ts/function'; import { splitSizeAndUnits } from '../../../lib/policies'; @@ -34,21 +32,6 @@ type MinAgePhase = 'warm' | 'cold' | 'delete'; type Phase = 'hot' | MinAgePhase; -const i18nTexts = { - forever: i18n.translate('xpack.indexLifecycleMgmt.relativeTiming.forever', { - defaultMessage: 'forever', - }), - lessThanADay: i18n.translate('xpack.indexLifecycleMgmt.relativeTiming.lessThanADay', { - defaultMessage: 'less than a day', - }), - day: i18n.translate('xpack.indexLifecycleMgmt.relativeTiming.day', { - defaultMessage: 'day', - }), - days: i18n.translate('xpack.indexLifecycleMgmt.relativeTiming.days', { - defaultMessage: 'days', - }), -}; - const phaseOrder: Phase[] = ['hot', 'warm', 'cold', 'delete']; const getMinAge = (phase: MinAgePhase, formData: FormInternal) => ({ @@ -162,38 +145,3 @@ export const calculateRelativeFromAbsoluteMilliseconds = ( }; export type RelativePhaseTimingInMs = ReturnType; - -const millisecondsToDays = (milliseconds?: number): string | undefined => { - if (milliseconds == null) { - return; - } - if (!isFinite(milliseconds)) { - return i18nTexts.forever; - } - const days = milliseconds / 8.64e7; - return days < 1 - ? i18nTexts.lessThanADay - : `${Math.floor(days)} ${days === 1 ? i18nTexts.day : i18nTexts.days}`; -}; - -export const normalizeTimingsToHumanReadable = ({ - total, - phases, -}: PhaseAgeInMilliseconds): { total?: string; hot?: string; warm?: string; cold?: string } => { - return { - total: millisecondsToDays(total), - hot: millisecondsToDays(phases.hot), - warm: millisecondsToDays(phases.warm), - cold: millisecondsToDays(phases.cold), - }; -}; - -/** - * Given {@link FormInternal}, extract the min_age values for each phase and calculate - * human readable strings for communicating how long data will remain in a phase. - */ -export const absoluteTimingToRelativeTiming = flow( - formDataToAbsoluteTimings, - calculateRelativeFromAbsoluteMilliseconds, - normalizeTimingsToHumanReadable -); diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/lib/index.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/lib/index.ts index 396318a1d78cf..af4757a7b7105 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/lib/index.ts +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/lib/index.ts @@ -6,9 +6,7 @@ */ export { - absoluteTimingToRelativeTiming, calculateRelativeFromAbsoluteMilliseconds, - normalizeTimingsToHumanReadable, formDataToAbsoluteTimings, AbsoluteTimings, PhaseAgeInMilliseconds, diff --git a/x-pack/plugins/index_lifecycle_management/tsconfig.json b/x-pack/plugins/index_lifecycle_management/tsconfig.json new file mode 100644 index 0000000000000..73dcc62132cbf --- /dev/null +++ b/x-pack/plugins/index_lifecycle_management/tsconfig.json @@ -0,0 +1,32 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "composite": true, + "outDir": "./target/types", + "emitDeclarationOnly": true, + "declaration": true, + "declarationMap": true + }, + "include": [ + "__jest__/**/*", + "common/**/*", + "public/**/*", + "server/**/*", + "../../typings/**/*", + ], + "references": [ + { "path": "../../../src/core/tsconfig.json" }, + // required plugins + { "path": "../licensing/tsconfig.json" }, + { "path": "../../../src/plugins/management/tsconfig.json" }, + { "path": "../features/tsconfig.json" }, + { "path": "../../../src/plugins/share/tsconfig.json" }, + // optional plugins + { "path": "../cloud/tsconfig.json" }, + { "path": "../../../src/plugins/usage_collection/tsconfig.json" }, + { "path": "../index_management/tsconfig.json" }, + { "path": "../../../src/plugins/home/tsconfig.json" }, + // required bundles + { "path": "../../../src/plugins/kibana_react/tsconfig.json" }, + ] +} diff --git a/x-pack/plugins/infra/common/alerting/metrics/index.ts b/x-pack/plugins/infra/common/alerting/metrics/index.ts index 5151a40c7e8b1..2c66638711cd0 100644 --- a/x-pack/plugins/infra/common/alerting/metrics/index.ts +++ b/x-pack/plugins/infra/common/alerting/metrics/index.ts @@ -10,8 +10,8 @@ export const INFRA_ALERT_PREVIEW_PATH = '/api/infra/alerting/preview'; export const TOO_MANY_BUCKETS_PREVIEW_EXCEPTION = 'TOO_MANY_BUCKETS_PREVIEW_EXCEPTION'; export interface TooManyBucketsPreviewExceptionMetadata { - TOO_MANY_BUCKETS_PREVIEW_EXCEPTION: any; - maxBuckets: number; + TOO_MANY_BUCKETS_PREVIEW_EXCEPTION: boolean; + maxBuckets: any; } export const isTooManyBucketsPreviewException = ( value: any diff --git a/x-pack/plugins/infra/common/alerting/metrics/types.ts b/x-pack/plugins/infra/common/alerting/metrics/types.ts index 47a5202cc7275..7a4edb8f49189 100644 --- a/x-pack/plugins/infra/common/alerting/metrics/types.ts +++ b/x-pack/plugins/infra/common/alerting/metrics/types.ts @@ -4,14 +4,15 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - import * as rt from 'io-ts'; +import { ANOMALY_THRESHOLD } from '../../infra_ml'; import { ItemTypeRT } from '../../inventory_models/types'; // TODO: Have threshold and inventory alerts import these types from this file instead of from their // local directories export const METRIC_THRESHOLD_ALERT_TYPE_ID = 'metrics.alert.threshold'; export const METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID = 'metrics.alert.inventory.threshold'; +export const METRIC_ANOMALY_ALERT_TYPE_ID = 'metrics.alert.anomaly'; export enum Comparator { GT = '>', @@ -34,6 +35,26 @@ export enum Aggregators { P99 = 'p99', } +const metricAnomalyNodeTypeRT = rt.union([rt.literal('hosts'), rt.literal('k8s')]); +const metricAnomalyMetricRT = rt.union([ + rt.literal('memory_usage'), + rt.literal('network_in'), + rt.literal('network_out'), +]); +const metricAnomalyInfluencerFilterRT = rt.type({ + fieldName: rt.string, + fieldValue: rt.string, +}); + +export interface MetricAnomalyParams { + nodeType: rt.TypeOf; + metric: rt.TypeOf; + alertInterval?: string; + sourceId?: string; + threshold: Exclude; + influencerFilter: rt.TypeOf | undefined; +} + // Alert Preview API const baseAlertRequestParamsRT = rt.intersection([ rt.partial({ @@ -51,7 +72,6 @@ const baseAlertRequestParamsRT = rt.intersection([ rt.literal('M'), rt.literal('y'), ]), - criteria: rt.array(rt.any), alertInterval: rt.string, alertThrottle: rt.string, alertOnNoData: rt.boolean, @@ -65,6 +85,7 @@ const metricThresholdAlertPreviewRequestParamsRT = rt.intersection([ }), rt.type({ alertType: rt.literal(METRIC_THRESHOLD_ALERT_TYPE_ID), + criteria: rt.array(rt.any), }), ]); export type MetricThresholdAlertPreviewRequestParams = rt.TypeOf< @@ -76,26 +97,49 @@ const inventoryAlertPreviewRequestParamsRT = rt.intersection([ rt.type({ nodeType: ItemTypeRT, alertType: rt.literal(METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID), + criteria: rt.array(rt.any), }), ]); export type InventoryAlertPreviewRequestParams = rt.TypeOf< typeof inventoryAlertPreviewRequestParamsRT >; +const metricAnomalyAlertPreviewRequestParamsRT = rt.intersection([ + baseAlertRequestParamsRT, + rt.type({ + nodeType: metricAnomalyNodeTypeRT, + metric: metricAnomalyMetricRT, + threshold: rt.number, + alertType: rt.literal(METRIC_ANOMALY_ALERT_TYPE_ID), + }), + rt.partial({ + influencerFilter: metricAnomalyInfluencerFilterRT, + }), +]); +export type MetricAnomalyAlertPreviewRequestParams = rt.TypeOf< + typeof metricAnomalyAlertPreviewRequestParamsRT +>; + export const alertPreviewRequestParamsRT = rt.union([ metricThresholdAlertPreviewRequestParamsRT, inventoryAlertPreviewRequestParamsRT, + metricAnomalyAlertPreviewRequestParamsRT, ]); export type AlertPreviewRequestParams = rt.TypeOf; export const alertPreviewSuccessResponsePayloadRT = rt.type({ numberOfGroups: rt.number, - resultTotals: rt.type({ - fired: rt.number, - noData: rt.number, - error: rt.number, - notifications: rt.number, - }), + resultTotals: rt.intersection([ + rt.type({ + fired: rt.number, + noData: rt.number, + error: rt.number, + notifications: rt.number, + }), + rt.partial({ + warning: rt.number, + }), + ]), }); export type AlertPreviewSuccessResponsePayload = rt.TypeOf< typeof alertPreviewSuccessResponsePayloadRT diff --git a/x-pack/plugins/infra/common/http_api/infra_ml/results/metrics_hosts_anomalies.ts b/x-pack/plugins/infra/common/http_api/infra_ml/results/metrics_hosts_anomalies.ts index 27574d01be898..0b70b65b7069e 100644 --- a/x-pack/plugins/infra/common/http_api/infra_ml/results/metrics_hosts_anomalies.ts +++ b/x-pack/plugins/infra/common/http_api/infra_ml/results/metrics_hosts_anomalies.ts @@ -62,6 +62,7 @@ export const getMetricsHostsAnomaliesRequestPayloadRT = rt.type({ rt.type({ // the ID of the source configuration sourceId: rt.string, + anomalyThreshold: rt.number, // the time range to fetch the log entry anomalies from timeRange: timeRangeRT, }), diff --git a/x-pack/plugins/infra/common/http_api/infra_ml/results/metrics_k8s_anomalies.ts b/x-pack/plugins/infra/common/http_api/infra_ml/results/metrics_k8s_anomalies.ts index 3c2615a447b07..3ee6189dcbf9a 100644 --- a/x-pack/plugins/infra/common/http_api/infra_ml/results/metrics_k8s_anomalies.ts +++ b/x-pack/plugins/infra/common/http_api/infra_ml/results/metrics_k8s_anomalies.ts @@ -62,6 +62,7 @@ export const getMetricsK8sAnomaliesRequestPayloadRT = rt.type({ rt.type({ // the ID of the source configuration sourceId: rt.string, + anomalyThreshold: rt.number, // the time range to fetch the log entry anomalies from timeRange: timeRangeRT, }), diff --git a/x-pack/plugins/infra/common/http_api/log_analysis/results/index.ts b/x-pack/plugins/infra/common/http_api/log_analysis/results/index.ts index d50495689e9d8..23c2ce5f0c21f 100644 --- a/x-pack/plugins/infra/common/http_api/log_analysis/results/index.ts +++ b/x-pack/plugins/infra/common/http_api/log_analysis/results/index.ts @@ -9,7 +9,6 @@ export * from './log_entry_categories'; export * from './log_entry_category_datasets'; export * from './log_entry_category_datasets_stats'; export * from './log_entry_category_examples'; -export * from './log_entry_rate'; export * from './log_entry_examples'; export * from './log_entry_anomalies'; export * from './log_entry_anomalies_datasets'; diff --git a/x-pack/plugins/infra/common/http_api/log_analysis/results/log_entry_rate.ts b/x-pack/plugins/infra/common/http_api/log_analysis/results/log_entry_rate.ts deleted file mode 100644 index 943e1df70c0ba..0000000000000 --- a/x-pack/plugins/infra/common/http_api/log_analysis/results/log_entry_rate.ts +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import * as rt from 'io-ts'; - -import { badRequestErrorRT, conflictErrorRT, forbiddenErrorRT, timeRangeRT } from '../../shared'; - -export const LOG_ANALYSIS_GET_LOG_ENTRY_RATE_PATH = - '/api/infra/log_analysis/results/log_entry_rate'; - -/** - * request - */ - -export const getLogEntryRateRequestPayloadRT = rt.type({ - data: rt.intersection([ - rt.type({ - bucketDuration: rt.number, - sourceId: rt.string, - timeRange: timeRangeRT, - }), - rt.partial({ - datasets: rt.array(rt.string), - }), - ]), -}); - -export type GetLogEntryRateRequestPayload = rt.TypeOf; - -/** - * response - */ - -export const logEntryRateAnomalyRT = rt.type({ - id: rt.string, - actualLogEntryRate: rt.number, - anomalyScore: rt.number, - duration: rt.number, - startTime: rt.number, - typicalLogEntryRate: rt.number, -}); - -export type LogEntryRateAnomaly = rt.TypeOf; - -export const logEntryRatePartitionRT = rt.type({ - analysisBucketCount: rt.number, - anomalies: rt.array(logEntryRateAnomalyRT), - averageActualLogEntryRate: rt.number, - maximumAnomalyScore: rt.number, - numberOfLogEntries: rt.number, - partitionId: rt.string, -}); - -export type LogEntryRatePartition = rt.TypeOf; - -export const logEntryRateHistogramBucketRT = rt.type({ - partitions: rt.array(logEntryRatePartitionRT), - startTime: rt.number, -}); - -export type LogEntryRateHistogramBucket = rt.TypeOf; - -export const getLogEntryRateSuccessReponsePayloadRT = rt.type({ - data: rt.type({ - bucketDuration: rt.number, - histogramBuckets: rt.array(logEntryRateHistogramBucketRT), - totalNumberOfLogEntries: rt.number, - }), -}); - -export type GetLogEntryRateSuccessResponsePayload = rt.TypeOf< - typeof getLogEntryRateSuccessReponsePayloadRT ->; - -export const getLogEntryRateResponsePayloadRT = rt.union([ - getLogEntryRateSuccessReponsePayloadRT, - badRequestErrorRT, - conflictErrorRT, - forbiddenErrorRT, -]); - -export type GetLogEntryRateReponsePayload = rt.TypeOf; diff --git a/x-pack/plugins/infra/common/http_api/source_api.ts b/x-pack/plugins/infra/common/http_api/source_api.ts index 257383be859aa..f14151531ba35 100644 --- a/x-pack/plugins/infra/common/http_api/source_api.ts +++ b/x-pack/plugins/infra/common/http_api/source_api.ts @@ -90,6 +90,7 @@ export const SavedSourceConfigurationRuntimeType = rt.partial({ metricsExplorerDefaultView: rt.string, fields: SavedSourceConfigurationFieldsRuntimeType, logColumns: rt.array(SavedSourceConfigurationColumnRuntimeType), + anomalyThreshold: rt.number, }); export interface InfraSavedSourceConfiguration @@ -107,6 +108,7 @@ export const pickSavedSourceConfiguration = ( inventoryDefaultView, metricsExplorerDefaultView, logColumns, + anomalyThreshold, } = value; const { container, host, pod, tiebreaker, timestamp } = fields; @@ -119,6 +121,7 @@ export const pickSavedSourceConfiguration = ( metricsExplorerDefaultView, fields: { container, host, pod, tiebreaker, timestamp }, logColumns, + anomalyThreshold, }; }; @@ -140,6 +143,7 @@ export const StaticSourceConfigurationRuntimeType = rt.partial({ metricsExplorerDefaultView: rt.string, fields: StaticSourceConfigurationFieldsRuntimeType, logColumns: rt.array(SavedSourceConfigurationColumnRuntimeType), + anomalyThreshold: rt.number, }); export interface InfraStaticSourceConfiguration diff --git a/x-pack/plugins/infra/common/infra_ml/anomaly_results.ts b/x-pack/plugins/infra/common/infra_ml/anomaly_results.ts index 589e57a1388b5..81e46d85ba220 100644 --- a/x-pack/plugins/infra/common/infra_ml/anomaly_results.ts +++ b/x-pack/plugins/infra/common/infra_ml/anomaly_results.ts @@ -5,36 +5,44 @@ * 2.0. */ -export const ML_SEVERITY_SCORES = { - warning: 3, - minor: 25, - major: 50, - critical: 75, -}; +export enum ANOMALY_SEVERITY { + CRITICAL = 'critical', + MAJOR = 'major', + MINOR = 'minor', + WARNING = 'warning', + LOW = 'low', + UNKNOWN = 'unknown', +} -export type MLSeverityScoreCategories = keyof typeof ML_SEVERITY_SCORES; +export enum ANOMALY_THRESHOLD { + CRITICAL = 75, + MAJOR = 50, + MINOR = 25, + WARNING = 3, + LOW = 0, +} -export const ML_SEVERITY_COLORS = { - critical: 'rgb(228, 72, 72)', - major: 'rgb(229, 113, 0)', - minor: 'rgb(255, 221, 0)', - warning: 'rgb(125, 180, 226)', +export const SEVERITY_COLORS = { + CRITICAL: '#fe5050', + MAJOR: '#fba740', + MINOR: '#fdec25', + WARNING: '#8bc8fb', + LOW: '#d2e9f7', + BLANK: '#ffffff', }; -export const getSeverityCategoryForScore = ( - score: number -): MLSeverityScoreCategories | undefined => { - if (score >= ML_SEVERITY_SCORES.critical) { - return 'critical'; - } else if (score >= ML_SEVERITY_SCORES.major) { - return 'major'; - } else if (score >= ML_SEVERITY_SCORES.minor) { - return 'minor'; - } else if (score >= ML_SEVERITY_SCORES.warning) { - return 'warning'; +export const getSeverityCategoryForScore = (score: number): ANOMALY_SEVERITY | undefined => { + if (score >= ANOMALY_THRESHOLD.CRITICAL) { + return ANOMALY_SEVERITY.CRITICAL; + } else if (score >= ANOMALY_THRESHOLD.MAJOR) { + return ANOMALY_SEVERITY.MAJOR; + } else if (score >= ANOMALY_THRESHOLD.MINOR) { + return ANOMALY_SEVERITY.MINOR; + } else if (score >= ANOMALY_THRESHOLD.WARNING) { + return ANOMALY_SEVERITY.WARNING; } else { // Category is too low to include - return undefined; + return ANOMALY_SEVERITY.LOW; } }; diff --git a/x-pack/plugins/infra/common/log_analysis/log_analysis_results.ts b/x-pack/plugins/infra/common/log_analysis/log_analysis_results.ts index f460747f8b142..113e8ff8c34e6 100644 --- a/x-pack/plugins/infra/common/log_analysis/log_analysis_results.ts +++ b/x-pack/plugins/infra/common/log_analysis/log_analysis_results.ts @@ -40,10 +40,6 @@ export const getSeverityCategoryForScore = ( } }; -export const formatAnomalyScore = (score: number) => { - return Math.round(score); -}; - export const formatOneDecimalPlace = (number: number) => { return Math.round(number * 10) / 10; }; diff --git a/x-pack/plugins/infra/kibana.json b/x-pack/plugins/infra/kibana.json index 327cb674de00b..c892f7017da33 100644 --- a/x-pack/plugins/infra/kibana.json +++ b/x-pack/plugins/infra/kibana.json @@ -13,9 +13,17 @@ "alerts", "triggersActionsUi" ], - "optionalPlugins": ["ml", "observability", "home"], + "optionalPlugins": ["ml", "observability", "home", "embeddable"], "server": true, "ui": true, "configPath": ["xpack", "infra"], - "requiredBundles": ["observability", "licenseManagement", "kibanaUtils", "kibanaReact", "home"] + "requiredBundles": [ + "observability", + "licenseManagement", + "kibanaUtils", + "kibanaReact", + "home", + "ml", + "embeddable" + ] } diff --git a/x-pack/plugins/infra/public/alerting/common/components/alert_preview.tsx b/x-pack/plugins/infra/public/alerting/common/components/alert_preview.tsx index cfe1579b5f408..57c6f695453ef 100644 --- a/x-pack/plugins/infra/public/alerting/common/components/alert_preview.tsx +++ b/x-pack/plugins/infra/public/alerting/common/components/alert_preview.tsx @@ -37,7 +37,7 @@ interface Props { alertInterval: string; alertThrottle: string; alertType: PreviewableAlertTypes; - alertParams: { criteria: any[]; sourceId: string } & Record; + alertParams: { criteria?: any[]; sourceId: string } & Record; validate: (params: any) => ValidationResult; showNoDataResults?: boolean; groupByDisplayName?: string; @@ -109,6 +109,7 @@ export const AlertPreview: React.FC = (props) => { }, [previewLookbackInterval, alertInterval]); const isPreviewDisabled = useMemo(() => { + if (!alertParams.criteria) return false; const validationResult = validate({ criteria: alertParams.criteria } as any); const hasValidationErrors = Object.values(validationResult.errors).some((result) => Object.values(result).some((arr) => Array.isArray(arr) && arr.length) @@ -123,6 +124,11 @@ export const AlertPreview: React.FC = (props) => { return unthrottledNotifications > notifications; }, [previewResult, showNoDataResults]); + const hasWarningThreshold = useMemo( + () => alertParams.criteria?.some((c) => Reflect.has(c, 'warningThreshold')) ?? false, + [alertParams] + ); + return ( = (props) => { - - - - ), - }} - />{' '} - {previewResult.groupByDisplayName ? ( - <> - {' '} - - - {' '} - - ) : null} - e.value === previewResult.previewLookbackInterval - )?.shortText, - }} - /> - + } > {showNoDataResults && previewResult.resultTotals.noData ? ( + ), boldedResultsNumber: ( {i18n.translate( 'xpack.infra.metrics.alertFlyout.alertPreviewNoDataResultNumber', { - defaultMessage: - '{noData, plural, one {was # result} other {were # results}}', + defaultMessage: '{noData, plural, one {# result} other {# results}}', values: { noData: previewResult.resultTotals.noData, }, @@ -361,6 +333,145 @@ export const AlertPreview: React.FC = (props) => { ); }; +const PreviewTextString = ({ + previewResult, + hasWarningThreshold, +}: { + previewResult: AlertPreviewSuccessResponsePayload & Record; + hasWarningThreshold: boolean; +}) => { + const instanceCount = hasWarningThreshold ? ( + + ), + criticalInstances: ( + + + + ), + warningInstances: ( + + + + ), + boldCritical: ( + + + + ), + boldWarning: ( + + + + ), + }} + /> + ) : ( + + ), + firedTimes: ( + + + + ), + }} + /> + ); + + const groupByText = previewResult.groupByDisplayName ? ( + <> + + + + ), + }} + />{' '} + + ) : ( + <> + ); + + const lookbackText = ( + e.value === previewResult.previewLookbackInterval) + ?.shortText, + }} + /> + ); + + return ( + + ); +}; + const previewOptions = [ { value: 'h', diff --git a/x-pack/plugins/infra/public/alerting/common/components/get_alert_preview.ts b/x-pack/plugins/infra/public/alerting/common/components/get_alert_preview.ts index a1cee1361a18f..2bb98e83cbe70 100644 --- a/x-pack/plugins/infra/public/alerting/common/components/get_alert_preview.ts +++ b/x-pack/plugins/infra/public/alerting/common/components/get_alert_preview.ts @@ -10,13 +10,15 @@ import { INFRA_ALERT_PREVIEW_PATH, METRIC_THRESHOLD_ALERT_TYPE_ID, METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID, + METRIC_ANOMALY_ALERT_TYPE_ID, AlertPreviewRequestParams, AlertPreviewSuccessResponsePayload, } from '../../../../common/alerting/metrics'; export type PreviewableAlertTypes = | typeof METRIC_THRESHOLD_ALERT_TYPE_ID - | typeof METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID; + | typeof METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID + | typeof METRIC_ANOMALY_ALERT_TYPE_ID; export async function getAlertPreview({ fetch, diff --git a/x-pack/plugins/infra/public/alerting/common/components/metrics_alert_dropdown.tsx b/x-pack/plugins/infra/public/alerting/common/components/metrics_alert_dropdown.tsx new file mode 100644 index 0000000000000..f1236c4fc2c2b --- /dev/null +++ b/x-pack/plugins/infra/public/alerting/common/components/metrics_alert_dropdown.tsx @@ -0,0 +1,151 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +import React, { useState, useCallback, useMemo } from 'react'; +import { + EuiPopover, + EuiButtonEmpty, + EuiContextMenu, + EuiContextMenuPanelDescriptor, +} from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { useInfraMLCapabilities } from '../../../containers/ml/infra_ml_capabilities'; +import { PrefilledInventoryAlertFlyout } from '../../inventory/components/alert_flyout'; +import { PrefilledThresholdAlertFlyout } from '../../metric_threshold/components/alert_flyout'; +import { PrefilledAnomalyAlertFlyout } from '../../metric_anomaly/components/alert_flyout'; +import { useLinkProps } from '../../../hooks/use_link_props'; + +type VisibleFlyoutType = 'inventory' | 'threshold' | 'anomaly' | null; + +export const MetricsAlertDropdown = () => { + const [popoverOpen, setPopoverOpen] = useState(false); + const [visibleFlyoutType, setVisibleFlyoutType] = useState(null); + const { hasInfraMLCapabilities } = useInfraMLCapabilities(); + + const closeFlyout = useCallback(() => setVisibleFlyoutType(null), [setVisibleFlyoutType]); + + const manageAlertsLinkProps = useLinkProps({ + app: 'management', + pathname: '/insightsAndAlerting/triggersActions/alerts', + }); + + const panels: EuiContextMenuPanelDescriptor[] = useMemo( + () => [ + { + id: 0, + title: i18n.translate('xpack.infra.alerting.alertDropdownTitle', { + defaultMessage: 'Alerts', + }), + items: [ + { + name: i18n.translate('xpack.infra.alerting.infrastructureDropdownMenu', { + defaultMessage: 'Infrastructure', + }), + panel: 1, + }, + { + name: i18n.translate('xpack.infra.alerting.metricsDropdownMenu', { + defaultMessage: 'Metrics', + }), + panel: 2, + }, + { + name: i18n.translate('xpack.infra.alerting.manageAlerts', { + defaultMessage: 'Manage alerts', + }), + icon: 'tableOfContents', + onClick: manageAlertsLinkProps.onClick, + }, + ], + }, + { + id: 1, + title: i18n.translate('xpack.infra.alerting.infrastructureDropdownTitle', { + defaultMessage: 'Infrastructure alerts', + }), + items: [ + { + name: i18n.translate('xpack.infra.alerting.createInventoryAlertButton', { + defaultMessage: 'Create inventory alert', + }), + onClick: () => setVisibleFlyoutType('inventory'), + }, + ].concat( + hasInfraMLCapabilities + ? { + name: i18n.translate('xpack.infra.alerting.createAnomalyAlertButton', { + defaultMessage: 'Create anomaly alert', + }), + onClick: () => setVisibleFlyoutType('anomaly'), + } + : [] + ), + }, + { + id: 2, + title: i18n.translate('xpack.infra.alerting.metricsDropdownTitle', { + defaultMessage: 'Metrics alerts', + }), + items: [ + { + name: i18n.translate('xpack.infra.alerting.createThresholdAlertButton', { + defaultMessage: 'Create threshold alert', + }), + onClick: () => setVisibleFlyoutType('threshold'), + }, + ], + }, + ], + [manageAlertsLinkProps, setVisibleFlyoutType, hasInfraMLCapabilities] + ); + + const closePopover = useCallback(() => { + setPopoverOpen(false); + }, [setPopoverOpen]); + + const openPopover = useCallback(() => { + setPopoverOpen(true); + }, [setPopoverOpen]); + + return ( + <> + + + + } + isOpen={popoverOpen} + closePopover={closePopover} + > + + + + + ); +}; + +interface AlertFlyoutProps { + visibleFlyoutType: VisibleFlyoutType; + onClose(): void; +} + +const AlertFlyout = ({ visibleFlyoutType, onClose }: AlertFlyoutProps) => { + switch (visibleFlyoutType) { + case 'inventory': + return ; + case 'threshold': + return ; + case 'anomaly': + return ; + default: + return null; + } +}; diff --git a/x-pack/plugins/infra/public/alerting/inventory/components/alert_dropdown.tsx b/x-pack/plugins/infra/public/alerting/inventory/components/alert_dropdown.tsx deleted file mode 100644 index a7b6c9fb7104c..0000000000000 --- a/x-pack/plugins/infra/public/alerting/inventory/components/alert_dropdown.tsx +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useState, useCallback } from 'react'; -import { EuiPopover, EuiButtonEmpty, EuiContextMenuItem, EuiContextMenuPanel } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { useAlertPrefillContext } from '../../../alerting/use_alert_prefill'; -import { AlertFlyout } from './alert_flyout'; -import { ManageAlertsContextMenuItem } from './manage_alerts_context_menu_item'; - -export const InventoryAlertDropdown = () => { - const [popoverOpen, setPopoverOpen] = useState(false); - const [flyoutVisible, setFlyoutVisible] = useState(false); - - const { inventoryPrefill } = useAlertPrefillContext(); - const { nodeType, metric, filterQuery } = inventoryPrefill; - - const closePopover = useCallback(() => { - setPopoverOpen(false); - }, [setPopoverOpen]); - - const openPopover = useCallback(() => { - setPopoverOpen(true); - }, [setPopoverOpen]); - - const menuItems = [ - setFlyoutVisible(true)}> - - , - , - ]; - - return ( - <> - - - - } - isOpen={popoverOpen} - closePopover={closePopover} - > - - - - - ); -}; diff --git a/x-pack/plugins/infra/public/alerting/inventory/components/alert_flyout.tsx b/x-pack/plugins/infra/public/alerting/inventory/components/alert_flyout.tsx index 815e1f2be33f2..33fe3c7af30c7 100644 --- a/x-pack/plugins/infra/public/alerting/inventory/components/alert_flyout.tsx +++ b/x-pack/plugins/infra/public/alerting/inventory/components/alert_flyout.tsx @@ -8,8 +8,7 @@ import React, { useCallback, useContext, useMemo } from 'react'; import { TriggerActionsContext } from '../../../utils/triggers_actions_context'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID } from '../../../../server/lib/alerting/inventory_metric_threshold/types'; +import { METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID } from '../../../../common/alerting/metrics'; import { InfraWaffleMapOptions } from '../../../lib/lib'; import { InventoryItemType } from '../../../../common/inventory_models/types'; import { useAlertPrefillContext } from '../../../alerting/use_alert_prefill'; @@ -49,3 +48,18 @@ export const AlertFlyout = ({ options, nodeType, filter, visible, setVisible }: return <>{visible && AddAlertFlyout}; }; + +export const PrefilledInventoryAlertFlyout = ({ onClose }: { onClose(): void }) => { + const { inventoryPrefill } = useAlertPrefillContext(); + const { nodeType, metric, filterQuery } = inventoryPrefill; + + return ( + + ); +}; diff --git a/x-pack/plugins/infra/public/alerting/inventory/components/expression.tsx b/x-pack/plugins/infra/public/alerting/inventory/components/expression.tsx index d403c254f2bd0..4a05521e9fc87 100644 --- a/x-pack/plugins/infra/public/alerting/inventory/components/expression.tsx +++ b/x-pack/plugins/infra/public/alerting/inventory/components/expression.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { debounce, pick } from 'lodash'; +import { debounce, pick, omit } from 'lodash'; import { Unit } from '@elastic/datemath'; import React, { useCallback, useMemo, useEffect, useState, ChangeEvent } from 'react'; import { IFieldType } from 'src/plugins/data/public'; @@ -21,6 +21,7 @@ import { EuiCheckbox, EuiToolTip, EuiIcon, + EuiHealth, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; @@ -423,9 +424,24 @@ const StyledExpression = euiStyled.div` padding: 0 4px; `; +const StyledHealth = euiStyled(EuiHealth)` + margin-left: 4px; +`; + export const ExpressionRow: React.FC = (props) => { const { setAlertParams, expression, errors, expressionId, remove, canDelete, fields } = props; - const { metric, comparator = Comparator.GT, threshold = [], customMetric } = expression; + const { + metric, + comparator = Comparator.GT, + threshold = [], + customMetric, + warningThreshold = [], + warningComparator, + } = expression; + + const [displayWarningThreshold, setDisplayWarningThreshold] = useState( + Boolean(warningThreshold?.length) + ); const updateMetric = useCallback( (m?: SnapshotMetricType | string) => { @@ -452,6 +468,13 @@ export const ExpressionRow: React.FC = (props) => { [expressionId, expression, setAlertParams] ); + const updateWarningComparator = useCallback( + (c?: string) => { + setAlertParams(expressionId, { ...expression, warningComparator: c as Comparator }); + }, + [expressionId, expression, setAlertParams] + ); + const updateThreshold = useCallback( (t) => { if (t.join() !== expression.threshold.join()) { @@ -461,6 +484,58 @@ export const ExpressionRow: React.FC = (props) => { [expressionId, expression, setAlertParams] ); + const updateWarningThreshold = useCallback( + (t) => { + if (t.join() !== expression.warningThreshold?.join()) { + setAlertParams(expressionId, { ...expression, warningThreshold: t }); + } + }, + [expressionId, expression, setAlertParams] + ); + + const toggleWarningThreshold = useCallback(() => { + if (!displayWarningThreshold) { + setDisplayWarningThreshold(true); + setAlertParams(expressionId, { + ...expression, + warningComparator: comparator, + warningThreshold: [], + }); + } else { + setDisplayWarningThreshold(false); + setAlertParams(expressionId, omit(expression, 'warningComparator', 'warningThreshold')); + } + }, [ + displayWarningThreshold, + setDisplayWarningThreshold, + setAlertParams, + comparator, + expression, + expressionId, + ]); + + const criticalThresholdExpression = ( + + ); + + const warningThresholdExpression = displayWarningThreshold && ( + + ); + const ofFields = useMemo(() => { let myMetrics = hostMetricTypes; @@ -515,25 +590,62 @@ export const ExpressionRow: React.FC = (props) => { fields={fields} /> - - - - {metric && ( -
- {metricUnit[metric]?.label || ''} -
- )} + {!displayWarningThreshold && criticalThresholdExpression} + {displayWarningThreshold && ( + <> + + {criticalThresholdExpression} + + + + + + {warningThresholdExpression} + + + + + + + )} + {!displayWarningThreshold && ( + <> + {' '} + + + + + + + + )} {canDelete && ( @@ -553,6 +665,38 @@ export const ExpressionRow: React.FC = (props) => { ); }; +const ThresholdElement: React.FC<{ + updateComparator: (c?: string) => void; + updateThreshold: (t?: number[]) => void; + threshold: InventoryMetricConditions['threshold']; + comparator: InventoryMetricConditions['comparator']; + errors: IErrorObject; + metric?: SnapshotMetricType; +}> = ({ updateComparator, updateThreshold, threshold, metric, comparator, errors }) => { + return ( + <> + + + + {metric && ( +
+ {metricUnit[metric]?.label || ''} +
+ )} + + ); +}; + const getDisplayNameForType = (type: InventoryItemType) => { const inventoryModel = findInventoryModel(type); return inventoryModel.displayName; diff --git a/x-pack/plugins/infra/public/alerting/inventory/components/node_type.tsx b/x-pack/plugins/infra/public/alerting/inventory/components/node_type.tsx index f02f98c49f01a..bd7812acac678 100644 --- a/x-pack/plugins/infra/public/alerting/inventory/components/node_type.tsx +++ b/x-pack/plugins/infra/public/alerting/inventory/components/node_type.tsx @@ -68,7 +68,7 @@ export const NodeTypeExpression = ({ setAggTypePopoverOpen(false)}> { - if (!isNumber(v)) { - const key = i === 0 ? 'threshold0' : 'threshold1'; - errors[id][key].push( - i18n.translate('xpack.infra.metrics.alertFlyout.error.thresholdTypeRequired', { - defaultMessage: 'Thresholds must contain a valid number.', - }) - ); - } - }); - } - - if (c.comparator === 'between' && (!c.threshold || c.threshold.length < 2)) { - errors[id].threshold1.push( + if (c.warningThreshold && !c.warningThreshold.length) { + errors[id].warning.threshold0.push( i18n.translate('xpack.infra.metrics.alertFlyout.error.thresholdRequired', { defaultMessage: 'Threshold is required.', }) ); } + for (const props of [ + { comparator: c.comparator, threshold: c.threshold, type: 'critical' }, + { comparator: c.warningComparator, threshold: c.warningThreshold, type: 'warning' }, + ]) { + // The Threshold component returns an empty array with a length ([empty]) because it's using delete newThreshold[i]. + // We need to use [...c.threshold] to convert it to an array with an undefined value ([undefined]) so we can test each element. + const { comparator, threshold, type } = props as { + comparator?: Comparator; + threshold?: number[]; + type: 'critical' | 'warning'; + }; + if (threshold && threshold.length && ![...threshold].every(isNumber)) { + [...threshold].forEach((v, i) => { + if (!isNumber(v)) { + const key = i === 0 ? 'threshold0' : 'threshold1'; + errors[id][type][key].push( + i18n.translate('xpack.infra.metrics.alertFlyout.error.thresholdTypeRequired', { + defaultMessage: 'Thresholds must contain a valid number.', + }) + ); + } + }); + } + + if (comparator === Comparator.BETWEEN && (!threshold || threshold.length < 2)) { + errors[id][type].threshold1.push( + i18n.translate('xpack.infra.metrics.alertFlyout.error.thresholdRequired', { + defaultMessage: 'Threshold is required.', + }) + ); + } + } if (!c.timeSize) { errors[id].timeWindowSize.push( diff --git a/x-pack/plugins/infra/public/alerting/metric_anomaly/components/alert_flyout.tsx b/x-pack/plugins/infra/public/alerting/metric_anomaly/components/alert_flyout.tsx new file mode 100644 index 0000000000000..9d467e1df7e36 --- /dev/null +++ b/x-pack/plugins/infra/public/alerting/metric_anomaly/components/alert_flyout.tsx @@ -0,0 +1,53 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useCallback, useContext, useMemo } from 'react'; + +import { TriggerActionsContext } from '../../../utils/triggers_actions_context'; +import { METRIC_ANOMALY_ALERT_TYPE_ID } from '../../../../common/alerting/metrics'; +import { InfraWaffleMapOptions } from '../../../lib/lib'; +import { InventoryItemType } from '../../../../common/inventory_models/types'; +import { useAlertPrefillContext } from '../../../alerting/use_alert_prefill'; + +interface Props { + visible?: boolean; + metric?: InfraWaffleMapOptions['metric']; + nodeType?: InventoryItemType; + filter?: string; + setVisible(val: boolean): void; +} + +export const AlertFlyout = ({ metric, nodeType, visible, setVisible }: Props) => { + const { triggersActionsUI } = useContext(TriggerActionsContext); + + const onCloseFlyout = useCallback(() => setVisible(false), [setVisible]); + const AddAlertFlyout = useMemo( + () => + triggersActionsUI && + triggersActionsUI.getAddAlertFlyout({ + consumer: 'infrastructure', + onClose: onCloseFlyout, + canChangeTrigger: false, + alertTypeId: METRIC_ANOMALY_ALERT_TYPE_ID, + metadata: { + metric, + nodeType, + }, + }), + // eslint-disable-next-line react-hooks/exhaustive-deps + [triggersActionsUI, visible] + ); + + return <>{visible && AddAlertFlyout}; +}; + +export const PrefilledAnomalyAlertFlyout = ({ onClose }: { onClose(): void }) => { + const { inventoryPrefill } = useAlertPrefillContext(); + const { nodeType, metric } = inventoryPrefill; + + return ; +}; diff --git a/x-pack/plugins/infra/public/alerting/metric_anomaly/components/expression.test.tsx b/x-pack/plugins/infra/public/alerting/metric_anomaly/components/expression.test.tsx new file mode 100644 index 0000000000000..ae2c6ed81badb --- /dev/null +++ b/x-pack/plugins/infra/public/alerting/metric_anomaly/components/expression.test.tsx @@ -0,0 +1,74 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { mountWithIntl, nextTick } from '@kbn/test/jest'; +// We are using this inside a `jest.mock` call. Jest requires dynamic dependencies to be prefixed with `mock` +import { coreMock as mockCoreMock } from 'src/core/public/mocks'; +import React from 'react'; +import { Expression, AlertContextMeta } from './expression'; +import { act } from 'react-dom/test-utils'; + +jest.mock('../../../containers/source/use_source_via_http', () => ({ + useSourceViaHttp: () => ({ + source: { id: 'default' }, + createDerivedIndexPattern: () => ({ fields: [], title: 'metricbeat-*' }), + }), +})); + +jest.mock('../../../hooks/use_kibana', () => ({ + useKibanaContextForPlugin: () => ({ + services: mockCoreMock.createStart(), + }), +})); + +jest.mock('../../../containers/ml/infra_ml_capabilities', () => ({ + useInfraMLCapabilities: () => ({ + isLoading: false, + hasInfraMLCapabilities: true, + }), +})); + +describe('Expression', () => { + async function setup(currentOptions: AlertContextMeta) { + const alertParams = { + metric: undefined, + nodeType: undefined, + threshold: 50, + }; + const wrapper = mountWithIntl( + Reflect.set(alertParams, key, value)} + setAlertProperty={() => {}} + metadata={currentOptions} + /> + ); + + const update = async () => + await act(async () => { + await nextTick(); + wrapper.update(); + }); + + await update(); + + return { wrapper, update, alertParams }; + } + + it('should prefill the alert using the context metadata', async () => { + const currentOptions = { + nodeType: 'pod', + metric: { type: 'tx' }, + }; + const { alertParams } = await setup(currentOptions as AlertContextMeta); + expect(alertParams.nodeType).toBe('k8s'); + expect(alertParams.metric).toBe('network_out'); + }); +}); diff --git a/x-pack/plugins/infra/public/alerting/metric_anomaly/components/expression.tsx b/x-pack/plugins/infra/public/alerting/metric_anomaly/components/expression.tsx new file mode 100644 index 0000000000000..5938c7119616f --- /dev/null +++ b/x-pack/plugins/infra/public/alerting/metric_anomaly/components/expression.tsx @@ -0,0 +1,320 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { pick } from 'lodash'; +import React, { useCallback, useState, useMemo, useEffect } from 'react'; +import { EuiFlexGroup, EuiSpacer, EuiText, EuiLoadingContent } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { i18n } from '@kbn/i18n'; +import { useInfraMLCapabilities } from '../../../containers/ml/infra_ml_capabilities'; +import { SubscriptionSplashContent } from '../../../components/subscription_splash_content'; +import { AlertPreview } from '../../common'; +import { + METRIC_ANOMALY_ALERT_TYPE_ID, + MetricAnomalyParams, +} from '../../../../common/alerting/metrics'; +import { euiStyled, EuiThemeProvider } from '../../../../../../../src/plugins/kibana_react/common'; +import { + WhenExpression, + // eslint-disable-next-line @kbn/eslint/no-restricted-paths +} from '../../../../../triggers_actions_ui/public/common'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { IErrorObject } from '../../../../../triggers_actions_ui/public/types'; +import { useSourceViaHttp } from '../../../containers/source/use_source_via_http'; +import { findInventoryModel } from '../../../../common/inventory_models'; +import { InventoryItemType, SnapshotMetricType } from '../../../../common/inventory_models/types'; +import { NodeTypeExpression } from './node_type'; +import { SeverityThresholdExpression } from './severity_threshold'; +import { InfraWaffleMapOptions } from '../../../lib/lib'; +import { ANOMALY_THRESHOLD } from '../../../../common/infra_ml'; + +import { validateMetricAnomaly } from './validation'; +import { InfluencerFilter } from './influencer_filter'; +import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; + +export interface AlertContextMeta { + metric?: InfraWaffleMapOptions['metric']; + nodeType?: InventoryItemType; +} + +interface Props { + errors: IErrorObject[]; + alertParams: MetricAnomalyParams & { + sourceId: string; + }; + alertInterval: string; + alertThrottle: string; + setAlertParams(key: string, value: any): void; + setAlertProperty(key: string, value: any): void; + metadata: AlertContextMeta; +} + +export const defaultExpression = { + metric: 'memory_usage' as MetricAnomalyParams['metric'], + threshold: ANOMALY_THRESHOLD.MAJOR, + nodeType: 'hosts', + influencerFilter: undefined, +}; + +export const Expression: React.FC = (props) => { + const { hasInfraMLCapabilities, isLoading: isLoadingMLCapabilities } = useInfraMLCapabilities(); + const { http, notifications } = useKibanaContextForPlugin().services; + const { setAlertParams, alertParams, alertInterval, alertThrottle, metadata } = props; + const { source, createDerivedIndexPattern } = useSourceViaHttp({ + sourceId: 'default', + type: 'metrics', + fetch: http.fetch, + toastWarning: notifications.toasts.addWarning, + }); + + const derivedIndexPattern = useMemo(() => createDerivedIndexPattern('metrics'), [ + createDerivedIndexPattern, + ]); + + const [influencerFieldName, updateInfluencerFieldName] = useState( + alertParams.influencerFilter?.fieldName ?? 'host.name' + ); + + useEffect(() => { + setAlertParams('hasInfraMLCapabilities', hasInfraMLCapabilities); + }, [setAlertParams, hasInfraMLCapabilities]); + + useEffect(() => { + if (alertParams.influencerFilter) { + setAlertParams('influencerFilter', { + ...alertParams.influencerFilter, + fieldName: influencerFieldName, + }); + } + }, [influencerFieldName, alertParams, setAlertParams]); + const updateInfluencerFieldValue = useCallback( + (value: string) => { + if (value) { + setAlertParams('influencerFilter', { + ...alertParams.influencerFilter, + fieldValue: value, + }); + } else { + setAlertParams('influencerFilter', undefined); + } + }, + [setAlertParams, alertParams] + ); + + useEffect(() => { + setAlertParams('alertInterval', alertInterval); + }, [setAlertParams, alertInterval]); + + const updateNodeType = useCallback( + (nt: any) => { + setAlertParams('nodeType', nt); + }, + [setAlertParams] + ); + + const updateMetric = useCallback( + (metric: string) => { + setAlertParams('metric', metric); + }, + [setAlertParams] + ); + + const updateSeverityThreshold = useCallback( + (threshold: any) => { + setAlertParams('threshold', threshold); + }, + [setAlertParams] + ); + + const prefillNodeType = useCallback(() => { + const md = metadata; + if (md && md.nodeType) { + setAlertParams( + 'nodeType', + getMLNodeTypeFromInventoryNodeType(md.nodeType) ?? defaultExpression.nodeType + ); + } else { + setAlertParams('nodeType', defaultExpression.nodeType); + } + }, [metadata, setAlertParams]); + + const prefillMetric = useCallback(() => { + const md = metadata; + if (md && md.metric) { + setAlertParams( + 'metric', + getMLMetricFromInventoryMetric(md.metric.type) ?? defaultExpression.metric + ); + } else { + setAlertParams('metric', defaultExpression.metric); + } + }, [metadata, setAlertParams]); + + useEffect(() => { + if (!alertParams.nodeType) { + prefillNodeType(); + } + + if (!alertParams.threshold) { + setAlertParams('threshold', defaultExpression.threshold); + } + + if (!alertParams.metric) { + prefillMetric(); + } + + if (!alertParams.sourceId) { + setAlertParams('sourceId', source?.id || 'default'); + } + }, [metadata, derivedIndexPattern, defaultExpression, source]); // eslint-disable-line react-hooks/exhaustive-deps + + if (isLoadingMLCapabilities) return ; + if (!hasInfraMLCapabilities) return ; + + return ( + // https://github.com/elastic/kibana/issues/89506 + + +

+ +

+
+ + + + + + + + + + + + + + + + + + + +
+ ); +}; + +// required for dynamic import +// eslint-disable-next-line import/no-default-export +export default Expression; + +const StyledExpressionRow = euiStyled(EuiFlexGroup)` + display: flex; + flex-wrap: wrap; + margin: 0 -4px; +`; + +const StyledExpression = euiStyled.div` + padding: 0 4px; +`; + +const getDisplayNameForType = (type: InventoryItemType) => { + const inventoryModel = findInventoryModel(type); + return inventoryModel.displayName; +}; + +export const nodeTypes: { [key: string]: any } = { + hosts: { + text: getDisplayNameForType('host'), + value: 'hosts', + }, + k8s: { + text: getDisplayNameForType('pod'), + value: 'k8s', + }, +}; + +const getMLMetricFromInventoryMetric = (metric: SnapshotMetricType) => { + switch (metric) { + case 'memory': + return 'memory_usage'; + case 'tx': + return 'network_out'; + case 'rx': + return 'network_in'; + default: + return null; + } +}; + +const getMLNodeTypeFromInventoryNodeType = (nodeType: InventoryItemType) => { + switch (nodeType) { + case 'host': + return 'hosts'; + case 'pod': + return 'k8s'; + default: + return null; + } +}; diff --git a/x-pack/plugins/infra/public/alerting/metric_anomaly/components/influencer_filter.tsx b/x-pack/plugins/infra/public/alerting/metric_anomaly/components/influencer_filter.tsx new file mode 100644 index 0000000000000..34a917a77dcf5 --- /dev/null +++ b/x-pack/plugins/infra/public/alerting/metric_anomaly/components/influencer_filter.tsx @@ -0,0 +1,193 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { debounce } from 'lodash'; +import { i18n } from '@kbn/i18n'; +import React, { useState, useCallback, useEffect, useMemo } from 'react'; +import { first } from 'lodash'; +import { EuiFlexGroup, EuiFormRow, EuiCheckbox, EuiFlexItem, EuiSelect } from '@elastic/eui'; +import { + MetricsExplorerKueryBar, + CurryLoadSuggestionsType, +} from '../../../pages/metrics/metrics_explorer/components/kuery_bar'; +import { MetricAnomalyParams } from '../../../../common/alerting/metrics'; + +interface Props { + fieldName: string; + fieldValue: string; + nodeType: MetricAnomalyParams['nodeType']; + onChangeFieldName: (v: string) => void; + onChangeFieldValue: (v: string) => void; + derivedIndexPattern: Parameters[0]['derivedIndexPattern']; +} + +const FILTER_TYPING_DEBOUNCE_MS = 500; + +export const InfluencerFilter = ({ + fieldName, + fieldValue, + nodeType, + onChangeFieldName, + onChangeFieldValue, + derivedIndexPattern, +}: Props) => { + const fieldNameOptions = useMemo(() => (nodeType === 'k8s' ? k8sFieldNames : hostFieldNames), [ + nodeType, + ]); + + // If initial props contain a fieldValue, assume it was passed in from loaded alertParams, + // and enable the UI element + const [isEnabled, updateIsEnabled] = useState(fieldValue ? true : false); + const [storedFieldValue, updateStoredFieldValue] = useState(fieldValue); + + useEffect( + () => + nodeType === 'k8s' + ? onChangeFieldName(first(k8sFieldNames)!.value) + : onChangeFieldName(first(hostFieldNames)!.value), + [nodeType, onChangeFieldName] + ); + + const onSelectFieldName = useCallback((e) => onChangeFieldName(e.target.value), [ + onChangeFieldName, + ]); + const onUpdateFieldValue = useCallback( + (value) => { + updateStoredFieldValue(value); + onChangeFieldValue(value); + }, + [onChangeFieldValue] + ); + + const toggleEnabled = useCallback(() => { + const nextState = !isEnabled; + updateIsEnabled(nextState); + if (!nextState) { + onChangeFieldValue(''); + } else { + onChangeFieldValue(storedFieldValue); + } + }, [isEnabled, updateIsEnabled, onChangeFieldValue, storedFieldValue]); + + /* eslint-disable-next-line react-hooks/exhaustive-deps */ + const debouncedOnUpdateFieldValue = useCallback( + debounce(onUpdateFieldValue, FILTER_TYPING_DEBOUNCE_MS), + [onUpdateFieldValue] + ); + + const affixFieldNameToQuery: CurryLoadSuggestionsType = (fn) => ( + expression, + cursorPosition, + maxSuggestions + ) => { + // Add the field name to the front of the passed-in query + const prefix = `${fieldName}:`; + // Trim whitespace to prevent AND/OR suggestions + const modifiedExpression = `${prefix}${expression}`.trim(); + // Move the cursor position forward by the length of the field name + const modifiedPosition = cursorPosition + prefix.length; + return fn(modifiedExpression, modifiedPosition, maxSuggestions, (suggestions) => + suggestions + .map((s) => ({ + ...s, + // Remove quotes from suggestions + text: s.text.replace(/\"/g, '').trim(), + // Offset the returned suggestions' cursor positions so that they can be autocompleted accurately + start: s.start - prefix.length, + end: s.end - prefix.length, + })) + // Removing quotes can lead to an already-selected suggestion still coming up in the autocomplete list, + // so filter these out + .filter((s) => !expression.startsWith(s.text)) + ); + }; + + return ( + + } + helpText={ + isEnabled ? ( + <> + {i18n.translate('xpack.infra.metrics.alertFlyout.anomalyFilterHelpText', { + defaultMessage: + 'Limit the scope of your alert trigger to anomalies influenced by certain node(s).', + })} +
+ {i18n.translate('xpack.infra.metrics.alertFlyout.anomalyFilterHelpTextExample', { + defaultMessage: 'For example: "my-node-1" or "my-node-*"', + })} + + ) : null + } + fullWidth + display="rowCompressed" + > + {isEnabled ? ( + + + + + + + + + ) : ( + <> + )} +
+ ); +}; + +const hostFieldNames = [ + { + value: 'host.name', + text: 'host.name', + }, +]; + +const k8sFieldNames = [ + { + value: 'kubernetes.pod.uid', + text: 'kubernetes.pod.uid', + }, + { + value: 'kubernetes.node.name', + text: 'kubernetes.node.name', + }, + { + value: 'kubernetes.namespace', + text: 'kubernetes.namespace', + }, +]; + +const filterByNodeLabel = i18n.translate('xpack.infra.metrics.alertFlyout.filterByNodeLabel', { + defaultMessage: 'Filter by node', +}); diff --git a/x-pack/plugins/infra/public/alerting/metric_anomaly/components/node_type.tsx b/x-pack/plugins/infra/public/alerting/metric_anomaly/components/node_type.tsx new file mode 100644 index 0000000000000..6ddcf8fd5cb65 --- /dev/null +++ b/x-pack/plugins/infra/public/alerting/metric_anomaly/components/node_type.tsx @@ -0,0 +1,117 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useState } from 'react'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiExpression, EuiPopover, EuiFlexGroup, EuiFlexItem, EuiSelect } from '@elastic/eui'; +import { EuiPopoverTitle, EuiButtonIcon } from '@elastic/eui'; +import { MetricAnomalyParams } from '../../../../common/alerting/metrics'; + +type Node = MetricAnomalyParams['nodeType']; + +interface WhenExpressionProps { + value: Node; + options: { [key: string]: { text: string; value: Node } }; + onChange: (value: Node) => void; + popupPosition?: + | 'upCenter' + | 'upLeft' + | 'upRight' + | 'downCenter' + | 'downLeft' + | 'downRight' + | 'leftCenter' + | 'leftUp' + | 'leftDown' + | 'rightCenter' + | 'rightUp' + | 'rightDown'; +} + +export const NodeTypeExpression = ({ + value, + options, + onChange, + popupPosition, +}: WhenExpressionProps) => { + const [aggTypePopoverOpen, setAggTypePopoverOpen] = useState(false); + + return ( + { + setAggTypePopoverOpen(true); + }} + /> + } + isOpen={aggTypePopoverOpen} + closePopover={() => { + setAggTypePopoverOpen(false); + }} + ownFocus + anchorPosition={popupPosition ?? 'downLeft'} + > +
+ setAggTypePopoverOpen(false)}> + + + { + onChange(e.target.value as Node); + setAggTypePopoverOpen(false); + }} + options={Object.values(options).map((o) => o)} + /> +
+
+ ); +}; + +interface ClosablePopoverTitleProps { + children: JSX.Element; + onClose: () => void; +} + +export const ClosablePopoverTitle = ({ children, onClose }: ClosablePopoverTitleProps) => { + return ( + + + {children} + + onClose()} + /> + + + + ); +}; diff --git a/x-pack/plugins/infra/public/alerting/metric_anomaly/components/severity_threshold.tsx b/x-pack/plugins/infra/public/alerting/metric_anomaly/components/severity_threshold.tsx new file mode 100644 index 0000000000000..2dc561ff172b9 --- /dev/null +++ b/x-pack/plugins/infra/public/alerting/metric_anomaly/components/severity_threshold.tsx @@ -0,0 +1,140 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useState } from 'react'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiExpression, EuiPopover, EuiFlexGroup, EuiFlexItem, EuiSelect } from '@elastic/eui'; +import { EuiPopoverTitle, EuiButtonIcon } from '@elastic/eui'; +import { ANOMALY_THRESHOLD } from '../../../../common/infra_ml'; + +interface WhenExpressionProps { + value: Exclude; + onChange: (value: ANOMALY_THRESHOLD) => void; + popupPosition?: + | 'upCenter' + | 'upLeft' + | 'upRight' + | 'downCenter' + | 'downLeft' + | 'downRight' + | 'leftCenter' + | 'leftUp' + | 'leftDown' + | 'rightCenter' + | 'rightUp' + | 'rightDown'; +} + +const options = { + [ANOMALY_THRESHOLD.CRITICAL]: { + text: i18n.translate('xpack.infra.metrics.alertFlyout.expression.severityScore.criticalLabel', { + defaultMessage: 'Critical', + }), + value: ANOMALY_THRESHOLD.CRITICAL, + }, + [ANOMALY_THRESHOLD.MAJOR]: { + text: i18n.translate('xpack.infra.metrics.alertFlyout.expression.severityScore.majorLabel', { + defaultMessage: 'Major', + }), + value: ANOMALY_THRESHOLD.MAJOR, + }, + [ANOMALY_THRESHOLD.MINOR]: { + text: i18n.translate('xpack.infra.metrics.alertFlyout.expression.severityScore.minorLabel', { + defaultMessage: 'Minor', + }), + value: ANOMALY_THRESHOLD.MINOR, + }, + [ANOMALY_THRESHOLD.WARNING]: { + text: i18n.translate('xpack.infra.metrics.alertFlyout.expression.severityScore.warningLabel', { + defaultMessage: 'Warning', + }), + value: ANOMALY_THRESHOLD.WARNING, + }, +}; + +export const SeverityThresholdExpression = ({ + value, + onChange, + popupPosition, +}: WhenExpressionProps) => { + const [aggTypePopoverOpen, setAggTypePopoverOpen] = useState(false); + + return ( + { + setAggTypePopoverOpen(true); + }} + /> + } + isOpen={aggTypePopoverOpen} + closePopover={() => { + setAggTypePopoverOpen(false); + }} + ownFocus + anchorPosition={popupPosition ?? 'downLeft'} + > +
+ setAggTypePopoverOpen(false)}> + + + { + onChange(Number(e.target.value) as ANOMALY_THRESHOLD); + setAggTypePopoverOpen(false); + }} + options={Object.values(options).map((o) => o)} + /> +
+
+ ); +}; + +interface ClosablePopoverTitleProps { + children: JSX.Element; + onClose: () => void; +} + +export const ClosablePopoverTitle = ({ children, onClose }: ClosablePopoverTitleProps) => { + return ( + + + {children} + + onClose()} + /> + + + + ); +}; diff --git a/x-pack/plugins/infra/public/alerting/metric_anomaly/components/validation.tsx b/x-pack/plugins/infra/public/alerting/metric_anomaly/components/validation.tsx new file mode 100644 index 0000000000000..8e254fb2b67a8 --- /dev/null +++ b/x-pack/plugins/infra/public/alerting/metric_anomaly/components/validation.tsx @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { ValidationResult } from '../../../../../triggers_actions_ui/public/types'; + +export function validateMetricAnomaly({ + hasInfraMLCapabilities, +}: { + hasInfraMLCapabilities: boolean; +}): ValidationResult { + const validationResult = { errors: {} }; + const errors: { + hasInfraMLCapabilities: string[]; + } = { + hasInfraMLCapabilities: [], + }; + + validationResult.errors = errors; + + if (!hasInfraMLCapabilities) { + errors.hasInfraMLCapabilities.push( + i18n.translate('xpack.infra.metrics.alertFlyout.error.mlCapabilitiesRequired', { + defaultMessage: 'Cannot create an anomaly alert when machine learning is disabled.', + }) + ); + } + + return validationResult; +} diff --git a/x-pack/plugins/infra/public/alerting/metric_anomaly/index.ts b/x-pack/plugins/infra/public/alerting/metric_anomaly/index.ts new file mode 100644 index 0000000000000..31fed514bdacc --- /dev/null +++ b/x-pack/plugins/infra/public/alerting/metric_anomaly/index.ts @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +import React from 'react'; +import { METRIC_ANOMALY_ALERT_TYPE_ID } from '../../../common/alerting/metrics'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { AlertTypeModel } from '../../../../triggers_actions_ui/public/types'; +import { AlertTypeParams } from '../../../../alerts/common'; +import { validateMetricAnomaly } from './components/validation'; + +interface MetricAnomalyAlertTypeParams extends AlertTypeParams { + hasInfraMLCapabilities: boolean; +} + +export function createMetricAnomalyAlertType(): AlertTypeModel { + return { + id: METRIC_ANOMALY_ALERT_TYPE_ID, + description: i18n.translate('xpack.infra.metrics.anomaly.alertFlyout.alertDescription', { + defaultMessage: 'Alert when the anomaly score exceeds a defined threshold.', + }), + iconClass: 'bell', + documentationUrl(docLinks) { + return `${docLinks.ELASTIC_WEBSITE_URL}guide/en/observability/${docLinks.DOC_LINK_VERSION}/metric-anomaly-alert.html`; + }, + alertParamsExpression: React.lazy(() => import('./components/expression')), + validate: validateMetricAnomaly, + defaultActionMessage: i18n.translate( + 'xpack.infra.metrics.alerting.anomaly.defaultActionMessage', + { + defaultMessage: `\\{\\{alertName\\}\\} is in a state of \\{\\{context.alertState\\}\\} + +\\{\\{context.metric\\}\\} was \\{\\{context.summary\\}\\} than normal at \\{\\{context.timestamp\\}\\} + +Typical value: \\{\\{context.typical\\}\\} +Actual value: \\{\\{context.actual\\}\\} +`, + } + ), + requiresAppContext: false, + }; +} diff --git a/x-pack/plugins/infra/public/alerting/metric_threshold/components/alert_dropdown.tsx b/x-pack/plugins/infra/public/alerting/metric_threshold/components/alert_dropdown.tsx deleted file mode 100644 index 3bbe811225825..0000000000000 --- a/x-pack/plugins/infra/public/alerting/metric_threshold/components/alert_dropdown.tsx +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useState, useCallback } from 'react'; -import { EuiPopover, EuiButtonEmpty, EuiContextMenuItem, EuiContextMenuPanel } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { useAlertPrefillContext } from '../../use_alert_prefill'; -import { AlertFlyout } from './alert_flyout'; -import { ManageAlertsContextMenuItem } from '../../inventory/components/manage_alerts_context_menu_item'; - -export const MetricsAlertDropdown = () => { - const [popoverOpen, setPopoverOpen] = useState(false); - const [flyoutVisible, setFlyoutVisible] = useState(false); - - const { metricThresholdPrefill } = useAlertPrefillContext(); - const { groupBy, filterQuery, metrics } = metricThresholdPrefill; - - const closePopover = useCallback(() => { - setPopoverOpen(false); - }, [setPopoverOpen]); - - const openPopover = useCallback(() => { - setPopoverOpen(true); - }, [setPopoverOpen]); - - const menuItems = [ - setFlyoutVisible(true)}> - - , - , - ]; - - return ( - <> - - - - } - isOpen={popoverOpen} - closePopover={closePopover} - > - - - - - ); -}; diff --git a/x-pack/plugins/infra/public/alerting/metric_threshold/components/alert_flyout.tsx b/x-pack/plugins/infra/public/alerting/metric_threshold/components/alert_flyout.tsx index 929654ecb4693..e7e4ade5257fc 100644 --- a/x-pack/plugins/infra/public/alerting/metric_threshold/components/alert_flyout.tsx +++ b/x-pack/plugins/infra/public/alerting/metric_threshold/components/alert_flyout.tsx @@ -7,10 +7,10 @@ import React, { useCallback, useContext, useMemo } from 'react'; import { TriggerActionsContext } from '../../../utils/triggers_actions_context'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { METRIC_THRESHOLD_ALERT_TYPE_ID } from '../../../../server/lib/alerting/metric_threshold/types'; +import { METRIC_THRESHOLD_ALERT_TYPE_ID } from '../../../../common/alerting/metrics'; import { MetricsExplorerSeries } from '../../../../common/http_api/metrics_explorer'; import { MetricsExplorerOptions } from '../../../pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options'; +import { useAlertPrefillContext } from '../../../alerting/use_alert_prefill'; interface Props { visible?: boolean; @@ -42,3 +42,10 @@ export const AlertFlyout = (props: Props) => { return <>{visible && AddAlertFlyout}; }; + +export const PrefilledThresholdAlertFlyout = ({ onClose }: { onClose(): void }) => { + const { metricThresholdPrefill } = useAlertPrefillContext(); + const { groupBy, filterQuery, metrics } = metricThresholdPrefill; + + return ; +}; diff --git a/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression_chart.test.tsx b/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression_chart.test.tsx index 939834fa7c4a8..7e4209e4253d7 100644 --- a/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression_chart.test.tsx +++ b/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression_chart.test.tsx @@ -64,6 +64,7 @@ describe('ExpressionChart', () => { pod: 'kubernetes.pod.uid', tiebreaker: '_doc', }, + anomalyThreshold: 20, }, }; diff --git a/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression_chart.tsx b/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression_chart.tsx index 65842089863f3..c98984b5475cd 100644 --- a/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression_chart.tsx +++ b/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression_chart.tsx @@ -111,7 +111,9 @@ export const ExpressionChart: React.FC = ({ ); } - const thresholds = expression.threshold.slice().sort(); + const criticalThresholds = expression.threshold.slice().sort(); + const warningThresholds = expression.warningThreshold?.slice().sort() ?? []; + const thresholds = [...criticalThresholds, ...warningThresholds].sort(); // Creating a custom series where the ID is changed to 0 // so that we can get a proper domian @@ -145,108 +147,70 @@ export const ExpressionChart: React.FC = ({ const dataDomain = calculateDomain(series, [metric], false); const domain = { max: Math.max(dataDomain.max, last(thresholds) || dataDomain.max) * 1.1, // add 10% headroom. - min: Math.min(dataDomain.min, first(thresholds) || dataDomain.min), + min: Math.min(dataDomain.min, first(thresholds) || dataDomain.min) * 0.9, // add 10% floor, }; if (domain.min === first(expression.threshold)) { domain.min = domain.min * 0.9; } - const isAbove = [Comparator.GT, Comparator.GT_OR_EQ].includes(expression.comparator); - const isBelow = [Comparator.LT, Comparator.LT_OR_EQ].includes(expression.comparator); const opacity = 0.3; const { timeSize, timeUnit } = expression; const timeLabel = TIME_LABELS[timeUnit as keyof typeof TIME_LABELS]; - return ( - <> - - - - ({ - dataValue: threshold, - }))} - style={{ - line: { - strokeWidth: 2, - stroke: colorTransformer(Color.color1), - opacity: 1, - }, - }} - /> - {thresholds.length === 2 && expression.comparator === Comparator.BETWEEN ? ( - <> - - - ) : null} - {thresholds.length === 2 && expression.comparator === Comparator.OUTSIDE_RANGE ? ( - <> - - & { sortedThresholds: number[]; color: Color; id: string }) => { + if (!comparator || !threshold) return null; + const isAbove = [Comparator.GT, Comparator.GT_OR_EQ].includes(comparator); + const isBelow = [Comparator.LT, Comparator.LT_OR_EQ].includes(comparator); + return ( + <> + ({ + dataValue: t, + }))} + style={{ + line: { + strokeWidth: 2, + stroke: colorTransformer(color), + opacity: 1, + }, + }} + /> + {sortedThresholds.length === 2 && comparator === Comparator.BETWEEN ? ( + <> + - - ) : null} - {isBelow && first(expression.threshold) != null ? ( + }, + ]} + /> + + ) : null} + {sortedThresholds.length === 2 && comparator === Comparator.OUTSIDE_RANGE ? ( + <> = ({ x0: firstTimestamp, x1: lastTimestamp, y0: domain.min, - y1: first(expression.threshold), + y1: first(threshold), }, }, ]} /> - ) : null} - {isAbove && first(expression.threshold) != null ? ( = ({ coordinates: { x0: firstTimestamp, x1: lastTimestamp, - y0: first(expression.threshold), + y0: last(threshold), y1: domain.max, }, }, ]} /> - ) : null} + + ) : null} + {isBelow && first(threshold) != null ? ( + + ) : null} + {isAbove && first(threshold) != null ? ( + + ) : null} + + ); + }; + + return ( + <> + + + + + {expression.warningComparator && expression.warningThreshold && ( + + )} = (props) => { const [isExpanded, setRowState] = useState(true); const toggleRowState = useCallback(() => setRowState(!isExpanded), [isExpanded]); @@ -85,9 +92,14 @@ export const ExpressionRow: React.FC = (props) => { metric, comparator = Comparator.GT, threshold = [], + warningThreshold = [], + warningComparator, } = expression; + const [displayWarningThreshold, setDisplayWarningThreshold] = useState( + Boolean(warningThreshold?.length) + ); - const isMetricPct = useMemo(() => metric && metric.endsWith('.pct'), [metric]); + const isMetricPct = useMemo(() => Boolean(metric && metric.endsWith('.pct')), [metric]); const updateAggType = useCallback( (at: string) => { @@ -114,22 +126,81 @@ export const ExpressionRow: React.FC = (props) => { [expressionId, expression, setAlertParams] ); + const updateWarningComparator = useCallback( + (c?: string) => { + setAlertParams(expressionId, { ...expression, warningComparator: c as Comparator }); + }, + [expressionId, expression, setAlertParams] + ); + + const convertThreshold = useCallback( + (enteredThreshold) => + isMetricPct ? enteredThreshold.map((v: number) => pctToDecimal(v)) : enteredThreshold, + [isMetricPct] + ); + const updateThreshold = useCallback( (enteredThreshold) => { - const t = isMetricPct - ? enteredThreshold.map((v: number) => pctToDecimal(v)) - : enteredThreshold; + const t = convertThreshold(enteredThreshold); if (t.join() !== expression.threshold.join()) { setAlertParams(expressionId, { ...expression, threshold: t }); } }, - [expressionId, expression, isMetricPct, setAlertParams] + [expressionId, expression, convertThreshold, setAlertParams] ); - const displayedThreshold = useMemo(() => { - if (isMetricPct) return threshold.map((v) => decimalToPct(v)); - return threshold; - }, [threshold, isMetricPct]); + const updateWarningThreshold = useCallback( + (enteredThreshold) => { + const t = convertThreshold(enteredThreshold); + if (t.join() !== expression.warningThreshold?.join()) { + setAlertParams(expressionId, { ...expression, warningThreshold: t }); + } + }, + [expressionId, expression, convertThreshold, setAlertParams] + ); + + const toggleWarningThreshold = useCallback(() => { + if (!displayWarningThreshold) { + setDisplayWarningThreshold(true); + setAlertParams(expressionId, { + ...expression, + warningComparator: comparator, + warningThreshold: [], + }); + } else { + setDisplayWarningThreshold(false); + setAlertParams(expressionId, omit(expression, 'warningComparator', 'warningThreshold')); + } + }, [ + displayWarningThreshold, + setDisplayWarningThreshold, + setAlertParams, + comparator, + expression, + expressionId, + ]); + + const criticalThresholdExpression = ( + + ); + + const warningThresholdExpression = displayWarningThreshold && ( + + ); return ( <> @@ -187,26 +258,62 @@ export const ExpressionRow: React.FC = (props) => { /> )} - - - - {isMetricPct && ( -
- % -
- )} + {!displayWarningThreshold && criticalThresholdExpression} + {displayWarningThreshold && ( + <> + + {criticalThresholdExpression} + + + + + + {warningThresholdExpression} + + + + + + + )} + {!displayWarningThreshold && ( + <> + {' '} + + + + + + + + )}
{canDelete && ( @@ -227,6 +334,44 @@ export const ExpressionRow: React.FC = (props) => { ); }; +const ThresholdElement: React.FC<{ + updateComparator: (c?: string) => void; + updateThreshold: (t?: number[]) => void; + threshold: MetricExpression['threshold']; + isMetricPct: boolean; + comparator: MetricExpression['comparator']; + errors: IErrorObject; +}> = ({ updateComparator, updateThreshold, threshold, isMetricPct, comparator, errors }) => { + const displayedThreshold = useMemo(() => { + if (isMetricPct) return threshold.map((v) => decimalToPct(v)); + return threshold; + }, [threshold, isMetricPct]); + + return ( + <> + + + + {isMetricPct && ( +
+ % +
+ )} + + ); +}; + export const aggregationType: { [key: string]: any } = { avg: { text: i18n.translate('xpack.infra.metrics.alertFlyout.aggregationText.avg', { diff --git a/x-pack/plugins/infra/public/alerting/metric_threshold/components/validation.tsx b/x-pack/plugins/infra/public/alerting/metric_threshold/components/validation.tsx index bab396df9da0d..69b2f1d1bcc8f 100644 --- a/x-pack/plugins/infra/public/alerting/metric_threshold/components/validation.tsx +++ b/x-pack/plugins/infra/public/alerting/metric_threshold/components/validation.tsx @@ -25,8 +25,14 @@ export function validateMetricThreshold({ aggField: string[]; timeSizeUnit: string[]; timeWindowSize: string[]; - threshold0: string[]; - threshold1: string[]; + critical: { + threshold0: string[]; + threshold1: string[]; + }; + warning: { + threshold0: string[]; + threshold1: string[]; + }; metric: string[]; }; } = {}; @@ -44,8 +50,14 @@ export function validateMetricThreshold({ aggField: [], timeSizeUnit: [], timeWindowSize: [], - threshold0: [], - threshold1: [], + critical: { + threshold0: [], + threshold1: [], + }, + warning: { + threshold0: [], + threshold1: [], + }, metric: [], }; if (!c.aggType) { @@ -57,36 +69,54 @@ export function validateMetricThreshold({ } if (!c.threshold || !c.threshold.length) { - errors[id].threshold0.push( + errors[id].critical.threshold0.push( i18n.translate('xpack.infra.metrics.alertFlyout.error.thresholdRequired', { defaultMessage: 'Threshold is required.', }) ); } - // The Threshold component returns an empty array with a length ([empty]) because it's using delete newThreshold[i]. - // We need to use [...c.threshold] to convert it to an array with an undefined value ([undefined]) so we can test each element. - if (c.threshold && c.threshold.length && ![...c.threshold].every(isNumber)) { - [...c.threshold].forEach((v, i) => { - if (!isNumber(v)) { - const key = i === 0 ? 'threshold0' : 'threshold1'; - errors[id][key].push( - i18n.translate('xpack.infra.metrics.alertFlyout.error.thresholdTypeRequired', { - defaultMessage: 'Thresholds must contain a valid number.', - }) - ); - } - }); - } - - if (c.comparator === Comparator.BETWEEN && (!c.threshold || c.threshold.length < 2)) { - errors[id].threshold1.push( + if (c.warningThreshold && !c.warningThreshold.length) { + errors[id].warning.threshold0.push( i18n.translate('xpack.infra.metrics.alertFlyout.error.thresholdRequired', { defaultMessage: 'Threshold is required.', }) ); } + for (const props of [ + { comparator: c.comparator, threshold: c.threshold, type: 'critical' }, + { comparator: c.warningComparator, threshold: c.warningThreshold, type: 'warning' }, + ]) { + // The Threshold component returns an empty array with a length ([empty]) because it's using delete newThreshold[i]. + // We need to use [...c.threshold] to convert it to an array with an undefined value ([undefined]) so we can test each element. + const { comparator, threshold, type } = props as { + comparator?: Comparator; + threshold?: number[]; + type: 'critical' | 'warning'; + }; + if (threshold && threshold.length && ![...threshold].every(isNumber)) { + [...threshold].forEach((v, i) => { + if (!isNumber(v)) { + const key = i === 0 ? 'threshold0' : 'threshold1'; + errors[id][type][key].push( + i18n.translate('xpack.infra.metrics.alertFlyout.error.thresholdTypeRequired', { + defaultMessage: 'Thresholds must contain a valid number.', + }) + ); + } + }); + } + + if (comparator === Comparator.BETWEEN && (!threshold || threshold.length < 2)) { + errors[id][type].threshold1.push( + i18n.translate('xpack.infra.metrics.alertFlyout.error.thresholdRequired', { + defaultMessage: 'Threshold is required.', + }) + ); + } + } + if (!c.timeSize) { errors[id].timeWindowSize.push( i18n.translate('xpack.infra.metrics.alertFlyout.error.timeRequred', { diff --git a/x-pack/plugins/infra/public/components/logging/log_analysis_results/anomaly_severity_indicator.tsx b/x-pack/plugins/infra/public/components/logging/log_analysis_results/anomaly_severity_indicator.tsx index 6fcbb0f6ffd4c..20fe816d1dab2 100644 --- a/x-pack/plugins/infra/public/components/logging/log_analysis_results/anomaly_severity_indicator.tsx +++ b/x-pack/plugins/infra/public/components/logging/log_analysis_results/anomaly_severity_indicator.tsx @@ -7,18 +7,15 @@ import { EuiHealth } from '@elastic/eui'; import React, { useMemo } from 'react'; -import { - formatAnomalyScore, - getSeverityCategoryForScore, - ML_SEVERITY_COLORS, -} from '../../../../common/log_analysis'; +import { getFormattedSeverityScore } from '../../../../../ml/public'; +import { getSeverityCategoryForScore, ML_SEVERITY_COLORS } from '../../../../common/log_analysis'; export const AnomalySeverityIndicator: React.FunctionComponent<{ anomalyScore: number; }> = ({ anomalyScore }) => { const severityColor = useMemo(() => getColorForAnomalyScore(anomalyScore), [anomalyScore]); - return {formatAnomalyScore(anomalyScore)}; + return {getFormattedSeverityScore(anomalyScore)}; }; const getColorForAnomalyScore = (anomalyScore: number) => { diff --git a/x-pack/plugins/infra/public/components/logging/log_analysis_setup/index.ts b/x-pack/plugins/infra/public/components/logging/log_analysis_setup/index.ts index 1bcc9e7157a51..db5a996c604fc 100644 --- a/x-pack/plugins/infra/public/components/logging/log_analysis_setup/index.ts +++ b/x-pack/plugins/infra/public/components/logging/log_analysis_setup/index.ts @@ -14,4 +14,3 @@ export * from './missing_results_privileges_prompt'; export * from './missing_setup_privileges_prompt'; export * from './ml_unavailable_prompt'; export * from './setup_status_unknown_prompt'; -export * from './subscription_splash_content'; diff --git a/x-pack/plugins/infra/public/components/logging/log_analysis_setup/process_step/process_step.tsx b/x-pack/plugins/infra/public/components/logging/log_analysis_setup/process_step/process_step.tsx index ed26bd5b2077c..987ae87423fda 100644 --- a/x-pack/plugins/infra/public/components/logging/log_analysis_setup/process_step/process_step.tsx +++ b/x-pack/plugins/infra/public/components/logging/log_analysis_setup/process_step/process_step.tsx @@ -75,7 +75,7 @@ export const ProcessStep: React.FunctionComponent = ({ defaultMessage="Something went wrong creating the necessary ML jobs. Please ensure all selected log indices exist." /> - {errorMessages.map((errorMessage, i) => ( + {setupStatus.reasons.map((errorMessage, i) => ( {errorMessage} diff --git a/x-pack/plugins/infra/public/components/logging/log_analysis_setup/subscription_splash_content.tsx b/x-pack/plugins/infra/public/components/logging/log_analysis_setup/subscription_splash_content.tsx deleted file mode 100644 index c91c1d82afe9b..0000000000000 --- a/x-pack/plugins/infra/public/components/logging/log_analysis_setup/subscription_splash_content.tsx +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useEffect } from 'react'; -import { i18n } from '@kbn/i18n'; -import { - EuiPage, - EuiPageBody, - EuiPageContent, - EuiFlexGroup, - EuiFlexItem, - EuiSpacer, - EuiTitle, - EuiText, - EuiButton, - EuiButtonEmpty, - EuiImage, -} from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { HttpStart } from 'src/core/public'; -import { LoadingPage } from '../../loading_page'; - -import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; -import { euiStyled } from '../../../../../../../src/plugins/kibana_react/common'; -import { useTrialStatus } from '../../../hooks/use_trial_status'; - -export const SubscriptionSplashContent: React.FC = () => { - const { services } = useKibana<{ http: HttpStart }>(); - const { loadState, isTrialAvailable, checkTrialAvailability } = useTrialStatus(); - - useEffect(() => { - checkTrialAvailability(); - }, [checkTrialAvailability]); - - if (loadState === 'pending') { - return ( - - ); - } - - const canStartTrial = isTrialAvailable && loadState === 'resolved'; - - let title; - let description; - let cta; - - if (canStartTrial) { - title = ( - - ); - - description = ( - - ); - - cta = ( - - - - ); - } else { - title = ( - - ); - - description = ( - - ); - - cta = ( - - - - ); - } - - return ( - - - - - - -

{title}

-
- - -

{description}

-
- -
{cta}
-
- - - -
- - -

- -

-
- - - -
-
-
-
- ); -}; - -const SubscriptionPage = euiStyled(EuiPage)` - height: 100% -`; - -const SubscriptionPageContent = euiStyled(EuiPageContent)` - max-width: 768px !important; -`; - -const SubscriptionPageFooter = euiStyled.div` - background: ${(props) => props.theme.eui.euiColorLightestShade}; - margin: 0 -${(props) => props.theme.eui.paddingSizes.l} -${(props) => - props.theme.eui.paddingSizes.l}; - padding: ${(props) => props.theme.eui.paddingSizes.l}; -`; diff --git a/x-pack/plugins/infra/public/components/missing_embeddable_factory_callout.tsx b/x-pack/plugins/infra/public/components/missing_embeddable_factory_callout.tsx new file mode 100644 index 0000000000000..8afd8cde32ef3 --- /dev/null +++ b/x-pack/plugins/infra/public/components/missing_embeddable_factory_callout.tsx @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiCallOut } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +export const MissingEmbeddableFactoryCallout: React.FC<{ embeddableType: string }> = ({ + embeddableType, +}) => { + return ( + + ); +}; diff --git a/x-pack/plugins/infra/public/components/source_configuration/indices_configuration_form_state.ts b/x-pack/plugins/infra/public/components/source_configuration/indices_configuration_form_state.ts index 794048a8b3a3a..b4dede79d11f2 100644 --- a/x-pack/plugins/infra/public/components/source_configuration/indices_configuration_form_state.ts +++ b/x-pack/plugins/infra/public/components/source_configuration/indices_configuration_form_state.ts @@ -7,7 +7,11 @@ import { ReactNode, useCallback, useMemo, useState } from 'react'; -import { createInputFieldProps, validateInputFieldNotEmpty } from './input_fields'; +import { + createInputFieldProps, + createInputRangeFieldProps, + validateInputFieldNotEmpty, +} from './input_fields'; interface FormState { name: string; @@ -20,6 +24,7 @@ interface FormState { podField: string; tiebreakerField: string; timestampField: string; + anomalyThreshold: number; } type FormStateChanges = Partial; @@ -124,6 +129,17 @@ export const useIndicesConfigurationFormState = ({ }), [formState.timestampField] ); + const anomalyThresholdFieldProps = useMemo( + () => + createInputRangeFieldProps({ + errors: validateInputFieldNotEmpty(formState.anomalyThreshold), + name: 'anomalyThreshold', + onChange: (anomalyThreshold) => + setFormStateChanges((changes) => ({ ...changes, anomalyThreshold })), + value: formState.anomalyThreshold, + }), + [formState.anomalyThreshold] + ); const fieldProps = useMemo( () => ({ @@ -135,6 +151,7 @@ export const useIndicesConfigurationFormState = ({ podField: podFieldFieldProps, tiebreakerField: tiebreakerFieldFieldProps, timestampField: timestampFieldFieldProps, + anomalyThreshold: anomalyThresholdFieldProps, }), [ nameFieldProps, @@ -145,6 +162,7 @@ export const useIndicesConfigurationFormState = ({ podFieldFieldProps, tiebreakerFieldFieldProps, timestampFieldFieldProps, + anomalyThresholdFieldProps, ] ); @@ -183,4 +201,5 @@ const defaultFormState: FormState = { podField: '', tiebreakerField: '', timestampField: '', + anomalyThreshold: 0, }; diff --git a/x-pack/plugins/infra/public/components/source_configuration/input_fields.tsx b/x-pack/plugins/infra/public/components/source_configuration/input_fields.tsx index b8832d27a0a4d..a7a842417ebc2 100644 --- a/x-pack/plugins/infra/public/components/source_configuration/input_fields.tsx +++ b/x-pack/plugins/infra/public/components/source_configuration/input_fields.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React from 'react'; +import React, { ReactText } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -43,7 +43,47 @@ export const createInputFieldProps = < value, }); -export const validateInputFieldNotEmpty = (value: string) => +export interface InputRangeFieldProps< + Value extends ReactText = ReactText, + FieldElement extends HTMLInputElement = HTMLInputElement, + ButtonElement extends HTMLButtonElement = HTMLButtonElement +> { + error: React.ReactNode[]; + isInvalid: boolean; + name: string; + onChange?: ( + evt: React.ChangeEvent | React.MouseEvent, + isValid: boolean + ) => void; + value: Value; +} + +export const createInputRangeFieldProps = < + Value extends ReactText = ReactText, + FieldElement extends HTMLInputElement = HTMLInputElement, + ButtonElement extends HTMLButtonElement = HTMLButtonElement +>({ + errors, + name, + onChange, + value, +}: { + errors: FieldErrorMessage[]; + name: string; + onChange: (newValue: number, isValid: boolean) => void; + value: Value; +}): InputRangeFieldProps => ({ + error: errors, + isInvalid: errors.length > 0, + name, + onChange: ( + evt: React.ChangeEvent | React.MouseEvent, + isValid: boolean + ) => onChange(+evt.currentTarget.value, isValid), + value, +}); + +export const validateInputFieldNotEmpty = (value: React.ReactText) => value === '' ? [ { + return ( + + +

+ +

+
+ + + + + } + description={ + + } + > + + } + > + + + +
+ ); +}; diff --git a/x-pack/plugins/infra/public/components/source_configuration/source_configuration_form_state.tsx b/x-pack/plugins/infra/public/components/source_configuration/source_configuration_form_state.tsx index 3f947bdb40677..c80235137eea6 100644 --- a/x-pack/plugins/infra/public/components/source_configuration/source_configuration_form_state.tsx +++ b/x-pack/plugins/infra/public/components/source_configuration/source_configuration_form_state.tsx @@ -27,6 +27,7 @@ export const useSourceConfigurationFormState = (configuration?: InfraSourceConfi podField: configuration.fields.pod, tiebreakerField: configuration.fields.tiebreaker, timestampField: configuration.fields.timestamp, + anomalyThreshold: configuration.anomalyThreshold, } : undefined, [configuration] @@ -79,6 +80,7 @@ export const useSourceConfigurationFormState = (configuration?: InfraSourceConfi timestamp: indicesConfigurationFormState.formState.timestampField, }, logColumns: logColumnsConfigurationFormState.formState.logColumns, + anomalyThreshold: indicesConfigurationFormState.formState.anomalyThreshold, }), [indicesConfigurationFormState.formState, logColumnsConfigurationFormState.formState] ); @@ -97,6 +99,7 @@ export const useSourceConfigurationFormState = (configuration?: InfraSourceConfi timestamp: indicesConfigurationFormState.formStateChanges.timestampField, }, logColumns: logColumnsConfigurationFormState.formStateChanges.logColumns, + anomalyThreshold: indicesConfigurationFormState.formStateChanges.anomalyThreshold, }), [ indicesConfigurationFormState.formStateChanges, diff --git a/x-pack/plugins/infra/public/components/source_configuration/source_configuration_settings.tsx b/x-pack/plugins/infra/public/components/source_configuration/source_configuration_settings.tsx index bdf4584bc6287..e63f43470497d 100644 --- a/x-pack/plugins/infra/public/components/source_configuration/source_configuration_settings.tsx +++ b/x-pack/plugins/infra/public/components/source_configuration/source_configuration_settings.tsx @@ -26,6 +26,8 @@ import { NameConfigurationPanel } from './name_configuration_panel'; import { useSourceConfigurationFormState } from './source_configuration_form_state'; import { SourceLoadingPage } from '../source_loading_page'; import { Prompt } from '../../utils/navigation_warning_prompt'; +import { MLConfigurationPanel } from './ml_configuration_panel'; +import { useInfraMLCapabilitiesContext } from '../../containers/ml/infra_ml_capabilities'; interface SourceConfigurationSettingsProps { shouldAllowEdit: boolean; @@ -52,7 +54,6 @@ export const SourceConfigurationSettings = ({ formState, formStateChanges, } = useSourceConfigurationFormState(source && source.configuration); - const persistUpdates = useCallback(async () => { if (sourceExists) { await updateSourceConfiguration(formStateChanges); @@ -74,6 +75,8 @@ export const SourceConfigurationSettings = ({ source, ]); + const { hasInfraMLCapabilities } = useInfraMLCapabilitiesContext(); + if ((isLoading || isUninitialized) && !source) { return ; } @@ -125,6 +128,18 @@ export const SourceConfigurationSettings = ({ /> + {hasInfraMLCapabilities && ( + <> + + + + + + )} {errors.length > 0 ? ( <> diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/ml/anomaly_detection/subscription_splash_content.tsx b/x-pack/plugins/infra/public/components/subscription_splash_content.tsx similarity index 58% rename from x-pack/plugins/infra/public/pages/metrics/inventory_view/components/ml/anomaly_detection/subscription_splash_content.tsx rename to x-pack/plugins/infra/public/components/subscription_splash_content.tsx index e05759ab57dd5..a6477dfc7d172 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/ml/anomaly_detection/subscription_splash_content.tsx +++ b/x-pack/plugins/infra/public/components/subscription_splash_content.tsx @@ -22,11 +22,11 @@ import { } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { LoadingPage } from '../../../../../../components/loading_page'; -import { useTrialStatus } from '../../../../../../hooks/use_trial_status'; -import { useKibana } from '../../../../../../../../../../src/plugins/kibana_react/public'; -import { euiStyled } from '../../../../../../../../../../src/plugins/kibana_react/common'; -import { HttpStart } from '../../../../../../../../../../src/core/public'; +import { useKibana } from '../../../../../src/plugins/kibana_react/public'; +import { euiStyled, EuiThemeProvider } from '../../../../../src/plugins/kibana_react/common'; +import { HttpStart } from '../../../../../src/core/public'; +import { useTrialStatus } from '../hooks/use_trial_status'; +import { LoadingPage } from '../components/loading_page'; export const SubscriptionSplashContent: React.FC = () => { const { services } = useKibana<{ http: HttpStart }>(); @@ -102,58 +102,60 @@ export const SubscriptionSplashContent: React.FC = () => { } return ( - - - - - - -

{title}

+ + + + + + + +

{title}

+
+ + +

{description}

+
+ +
{cta}
+
+ + + +
+ + +

+ +

- - -

{description}

-
- -
{cta}
-
- - - -
- - -

+ -

-
- - - -
-
-
-
+ + + + + + ); }; diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/api/ml_setup_module_api.ts b/x-pack/plugins/infra/public/containers/logs/log_analysis/api/ml_setup_module_api.ts index 69846e1f51482..ea1567d6056f1 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/api/ml_setup_module_api.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/api/ml_setup_module_api.ts @@ -91,8 +91,19 @@ const setupMlModuleRequestPayloadRT = rt.intersection([ setupMlModuleRequestParamsRT, ]); +const setupErrorRT = rt.type({ + reason: rt.string, + type: rt.string, +}); + const setupErrorResponseRT = rt.type({ - msg: rt.string, + status: rt.number, + error: rt.intersection([ + setupErrorRT, + rt.type({ + root_cause: rt.array(setupErrorRT), + }), + ]), }); const datafeedSetupResponseRT = rt.intersection([ diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module.tsx b/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module.tsx index 72b74d5f99719..00a6c3c2a72fb 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module.tsx +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module.tsx @@ -11,6 +11,7 @@ import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; import { useTrackedPromise } from '../../../utils/use_tracked_promise'; import { useModuleStatus } from './log_analysis_module_status'; import { ModuleDescriptor, ModuleSourceConfiguration } from './log_analysis_module_types'; +import { useUiTracker } from '../../../../../observability/public'; export const useLogAnalysisModule = ({ sourceConfiguration, @@ -23,6 +24,8 @@ export const useLogAnalysisModule = ({ const { spaceId, sourceId, timestampField } = sourceConfiguration; const [moduleStatus, dispatchModuleStatus] = useModuleStatus(moduleDescriptor.jobTypes); + const trackMetric = useUiTracker({ app: 'infra_logs' }); + const [, fetchJobStatus] = useTrackedPromise( { cancelPreviousOn: 'resolution', @@ -75,6 +78,25 @@ export const useLogAnalysisModule = ({ return { setupResult, jobSummaries }; }, onResolve: ({ setupResult: { datafeeds, jobs }, jobSummaries }) => { + // Track failures + if ( + [...datafeeds, ...jobs] + .reduce((acc, resource) => [...acc, ...Object.keys(resource)], []) + .some((key) => key === 'error') + ) { + const reasons = [...datafeeds, ...jobs] + .filter((resource) => resource.error !== undefined) + .map((resource) => resource.error?.error?.reason ?? ''); + // NOTE: Lack of indices and a missing field mapping have the same error + if ( + reasons.filter((reason) => reason.includes('because it has no mappings')).length > 0 + ) { + trackMetric({ metric: 'logs_ml_setup_error_bad_indices_or_mappings' }); + } else { + trackMetric({ metric: 'logs_ml_setup_error_unknown_cause' }); + } + } + dispatchModuleStatus({ type: 'finishedSetup', datafeedSetupResults: datafeeds, @@ -84,8 +106,11 @@ export const useLogAnalysisModule = ({ sourceId, }); }, - onReject: () => { + onReject: (e: any) => { dispatchModuleStatus({ type: 'failedSetup' }); + if (e?.body?.statusCode === 403) { + trackMetric({ metric: 'logs_ml_setup_error_lack_of_privileges' }); + } }, }, [moduleDescriptor.setUpModule, spaceId, sourceId, timestampField] diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_status.tsx b/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_status.tsx index 1fec67228aa22..c3117c9326d1e 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_status.tsx +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_module_status.tsx @@ -105,10 +105,10 @@ const createStatusReducer = (jobTypes: JobType[]) => ( reasons: [ ...Object.values(datafeedSetupResults) .filter(hasError) - .map((datafeed) => datafeed.error.msg), + .map((datafeed) => datafeed.error.error?.reason), ...Object.values(jobSetupResults) .filter(hasError) - .map((job) => job.error.msg), + .map((job) => job.error.error?.reason), ], }; diff --git a/x-pack/plugins/infra/public/containers/ml/infra_ml_capabilities.tsx b/x-pack/plugins/infra/public/containers/ml/infra_ml_capabilities.tsx index 72dc4da01d867..661ce8f8a253c 100644 --- a/x-pack/plugins/infra/public/containers/ml/infra_ml_capabilities.tsx +++ b/x-pack/plugins/infra/public/containers/ml/infra_ml_capabilities.tsx @@ -52,11 +52,11 @@ export const useInfraMLCapabilities = () => { const hasInfraMLSetupCapabilities = mlCapabilities.capabilities.canCreateJob; const hasInfraMLReadCapabilities = mlCapabilities.capabilities.canGetJobs; - const hasInfraMLCapabilites = + const hasInfraMLCapabilities = mlCapabilities.isPlatinumOrTrialLicense && mlCapabilities.mlFeatureEnabledInSpace; return { - hasInfraMLCapabilites, + hasInfraMLCapabilities, hasInfraMLReadCapabilities, hasInfraMLSetupCapabilities, isLoading, diff --git a/x-pack/plugins/infra/public/containers/with_kuery_autocompletion.tsx b/x-pack/plugins/infra/public/containers/with_kuery_autocompletion.tsx index 379ac9774c242..1a759950f640d 100644 --- a/x-pack/plugins/infra/public/containers/with_kuery_autocompletion.tsx +++ b/x-pack/plugins/infra/public/containers/with_kuery_autocompletion.tsx @@ -56,7 +56,8 @@ class WithKueryAutocompletionComponent extends React.Component< private loadSuggestions = async ( expression: string, cursorPosition: number, - maxSuggestions?: number + maxSuggestions?: number, + transformSuggestions?: (s: QuerySuggestion[]) => QuerySuggestion[] ) => { const { indexPattern } = this.props; const language = 'kuery'; @@ -86,6 +87,10 @@ class WithKueryAutocompletionComponent extends React.Component< boolFilter: [], })) || []; + const transformedSuggestions = transformSuggestions + ? transformSuggestions(suggestions) + : suggestions; + this.setState((state) => state.currentRequest && state.currentRequest.expression !== expression && @@ -94,7 +99,9 @@ class WithKueryAutocompletionComponent extends React.Component< : { ...state, currentRequest: null, - suggestions: maxSuggestions ? suggestions.slice(0, maxSuggestions) : suggestions, + suggestions: maxSuggestions + ? transformedSuggestions.slice(0, maxSuggestions) + : transformedSuggestions, } ); }; diff --git a/x-pack/plugins/infra/public/hooks/use_kibana_timefilter_time.tsx b/x-pack/plugins/infra/public/hooks/use_kibana_timefilter_time.tsx index 12b0cb06d8682..15eb525dca734 100644 --- a/x-pack/plugins/infra/public/hooks/use_kibana_timefilter_time.tsx +++ b/x-pack/plugins/infra/public/hooks/use_kibana_timefilter_time.tsx @@ -5,11 +5,10 @@ * 2.0. */ -import { useCallback } from 'react'; +import { useCallback, useEffect } from 'react'; import useUpdateEffect from 'react-use/lib/useUpdateEffect'; import useMount from 'react-use/lib/useMount'; - import { useKibanaContextForPlugin } from './use_kibana'; import { TimeRange, TimefilterContract } from '../../../../../src/plugins/data/public'; @@ -29,8 +28,24 @@ export const useKibanaTimefilterTime = ({ return [getTime, services.data.query.timefilter.timefilter.setTime]; }; -export const useSyncKibanaTimeFilterTime = (defaults: TimeRange, currentTimeRange: TimeRange) => { - const [, setTime] = useKibanaTimefilterTime(defaults); +/** + * Handles one or two way syncing with the Kibana time filter service. + * + * For one way syncing the time range will be synced back to the time filter service + * on mount *if* it differs from the defaults, e.g. a URL param. + * Future updates, after mount, will also be synced back to the time filter service. + * + * For two way syncing, in addition to the above, changes *from* the time filter service + * will be sycned to the solution, e.g. there might be an embeddable on the page that + * fires an action that hooks into the time filter service. + */ +export const useSyncKibanaTimeFilterTime = ( + defaults: TimeRange, + currentTimeRange: TimeRange, + setTimeRange?: (timeRange: TimeRange) => void +) => { + const { services } = useKibanaContextForPlugin(); + const [getTime, setTime] = useKibanaTimefilterTime(defaults); // On first mount we only want to sync time with Kibana if the derived currentTimeRange (e.g. from URL params) // differs from our defaults. @@ -40,8 +55,22 @@ export const useSyncKibanaTimeFilterTime = (defaults: TimeRange, currentTimeRang } }); - // Sync explicit changes *after* mount back to Kibana + // Sync explicit changes *after* mount from the solution back to Kibana useUpdateEffect(() => { setTime({ from: currentTimeRange.from, to: currentTimeRange.to }); }, [currentTimeRange.from, currentTimeRange.to, setTime]); + + // *Optionally* sync time filter service changes back to the solution. + // For example, an embeddable might have a time range action that hooks into + // the time filter service. + useEffect(() => { + const sub = services.data.query.timefilter.timefilter.getTimeUpdate$().subscribe(() => { + if (setTimeRange) { + const timeRange = getTime(); + setTimeRange(timeRange); + } + }); + + return () => sub.unsubscribe(); + }, [getTime, setTimeRange, services.data.query.timefilter.timefilter]); }; diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/page_content.tsx b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/page_content.tsx index f0fdd79bcd93d..628df397998ee 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_categories/page_content.tsx +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_categories/page_content.tsx @@ -7,13 +7,13 @@ import { i18n } from '@kbn/i18n'; import React, { useCallback, useEffect } from 'react'; +import { SubscriptionSplashContent } from '../../../components/subscription_splash_content'; import { isJobStatusWithResults } from '../../../../common/log_analysis'; import { LoadingPage } from '../../../components/loading_page'; import { LogAnalysisSetupStatusUnknownPrompt, MissingResultsPrivilegesPrompt, MissingSetupPrivilegesPrompt, - SubscriptionSplashContent, } from '../../../components/logging/log_analysis_setup'; import { LogAnalysisSetupFlyout, diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/page_content.tsx b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/page_content.tsx index 4d06d23ef93ef..5fd00527b8b70 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/page_content.tsx +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/page_content.tsx @@ -7,13 +7,13 @@ import { i18n } from '@kbn/i18n'; import React, { memo, useEffect, useCallback } from 'react'; +import { SubscriptionSplashContent } from '../../../components/subscription_splash_content'; import { isJobStatusWithResults } from '../../../../common/log_analysis'; import { LoadingPage } from '../../../components/loading_page'; import { LogAnalysisSetupStatusUnknownPrompt, MissingResultsPrivilegesPrompt, MissingSetupPrivilegesPrompt, - SubscriptionSplashContent, } from '../../../components/logging/log_analysis_setup'; import { LogAnalysisSetupFlyout, diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/page_results_content.tsx b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/page_results_content.tsx index a8660e1ce8013..54617d025652b 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/page_results_content.tsx +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/page_results_content.tsx @@ -5,17 +5,14 @@ * 2.0. */ -import datemath from '@elastic/datemath'; import { EuiFlexGroup, EuiFlexItem, EuiPage, EuiPanel, EuiSuperDatePicker } from '@elastic/eui'; import moment from 'moment'; import { stringify } from 'query-string'; -import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import React, { useCallback, useMemo } from 'react'; import { encode, RisonValue } from 'rison-node'; -import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; import { euiStyled } from '../../../../../../../src/plugins/kibana_react/common'; +import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; import { useTrackPageview } from '../../../../../observability/public'; -import { TimeRange } from '../../../../common/time/time_range'; -import { bucketSpan } from '../../../../common/log_analysis'; import { TimeKey } from '../../../../common/time'; import { CategoryJobNoticesSection, @@ -29,14 +26,11 @@ import { useLogEntryCategoriesModuleContext } from '../../../containers/logs/log import { useLogEntryRateModuleContext } from '../../../containers/logs/log_analysis/modules/log_entry_rate'; import { useLogEntryFlyoutContext } from '../../../containers/logs/log_flyout'; import { useLogSourceContext } from '../../../containers/logs/log_source'; -import { useInterval } from '../../../hooks/use_interval'; import { AnomaliesResults } from './sections/anomalies'; import { useLogEntryAnomaliesResults } from './use_log_entry_anomalies_results'; -import { useLogEntryRateResults } from './use_log_entry_rate_results'; -import { - StringTimeRange, - useLogAnalysisResultsUrlState, -} from './use_log_entry_rate_results_url_state'; +import { useDatasetFiltering } from './use_dataset_filtering'; +import { useLogAnalysisResultsUrlState } from './use_log_entry_rate_results_url_state'; +import { isJobStatusWithResults } from '../../../../common/log_analysis'; export const SORT_DEFAULTS = { direction: 'desc' as const, @@ -62,6 +56,8 @@ export const LogEntryRateResultsContent: React.FunctionComponent = () => { hasStoppedJobs: hasStoppedLogEntryRateJobs, moduleDescriptor: logEntryRateModuleDescriptor, setupStatus: logEntryRateSetupStatus, + jobStatus: logEntryRateJobStatus, + jobIds: logEntryRateJobIds, } = useLogEntryRateModuleContext(); const { @@ -71,10 +67,29 @@ export const LogEntryRateResultsContent: React.FunctionComponent = () => { hasStoppedJobs: hasStoppedLogEntryCategoriesJobs, moduleDescriptor: logEntryCategoriesModuleDescriptor, setupStatus: logEntryCategoriesSetupStatus, + jobStatus: logEntryCategoriesJobStatus, + jobIds: logEntryCategoriesJobIds, } = useLogEntryCategoriesModuleContext(); + const jobIds = useMemo(() => { + return [ + ...(isJobStatusWithResults(logEntryRateJobStatus['log-entry-rate']) + ? [logEntryRateJobIds['log-entry-rate']] + : []), + ...(isJobStatusWithResults(logEntryCategoriesJobStatus['log-entry-categories-count']) + ? [logEntryCategoriesJobIds['log-entry-categories-count']] + : []), + ]; + }, [ + logEntryRateJobIds, + logEntryCategoriesJobIds, + logEntryRateJobStatus, + logEntryCategoriesJobStatus, + ]); + const { - timeRange: selectedTimeRange, + timeRange, + friendlyTimeRange, setTimeRange: setSelectedTimeRange, autoRefresh, setAutoRefresh, @@ -86,21 +101,13 @@ export const LogEntryRateResultsContent: React.FunctionComponent = () => { logEntryId: flyoutLogEntryId, } = useLogEntryFlyoutContext(); - const [queryTimeRange, setQueryTimeRange] = useState<{ - value: TimeRange; - lastChangedTime: number; - }>(() => ({ - value: stringToNumericTimeRange(selectedTimeRange), - lastChangedTime: Date.now(), - })); - const linkToLogStream = useCallback( (filter: string, id: string, timeKey?: TimeKey) => { const params = { logPosition: encode({ - end: moment(queryTimeRange.value.endTime).format('YYYY-MM-DDTHH:mm:ss.SSSZ'), + end: moment(timeRange.value.endTime).format('YYYY-MM-DDTHH:mm:ss.SSSZ'), position: timeKey as RisonValue, - start: moment(queryTimeRange.value.startTime).format('YYYY-MM-DDTHH:mm:ss.SSSZ'), + start: moment(timeRange.value.startTime).format('YYYY-MM-DDTHH:mm:ss.SSSZ'), streamLive: false, }), flyoutOptions: encode({ @@ -114,23 +121,10 @@ export const LogEntryRateResultsContent: React.FunctionComponent = () => { navigateToApp?.('logs', { path: `/stream?${stringify(params)}` }); }, - [queryTimeRange, navigateToApp] - ); - - const bucketDuration = useMemo( - () => getBucketDuration(queryTimeRange.value.startTime, queryTimeRange.value.endTime), - [queryTimeRange.value.endTime, queryTimeRange.value.startTime] + [timeRange, navigateToApp] ); - const [selectedDatasets, setSelectedDatasets] = useState([]); - - const { getLogEntryRate, isLoading, logEntryRate } = useLogEntryRateResults({ - sourceId, - startTime: queryTimeRange.value.startTime, - endTime: queryTimeRange.value.endTime, - bucketDuration, - filteredDatasets: selectedDatasets, - }); + const { selectedDatasets, setSelectedDatasets } = useDatasetFiltering(); const { isLoadingLogEntryAnomalies, @@ -146,48 +140,13 @@ export const LogEntryRateResultsContent: React.FunctionComponent = () => { isLoadingDatasets, } = useLogEntryAnomaliesResults({ sourceId, - startTime: queryTimeRange.value.startTime, - endTime: queryTimeRange.value.endTime, + startTime: timeRange.value.startTime, + endTime: timeRange.value.endTime, defaultSortOptions: SORT_DEFAULTS, defaultPaginationOptions: PAGINATION_DEFAULTS, filteredDatasets: selectedDatasets, }); - const handleQueryTimeRangeChange = useCallback( - ({ start: startTime, end: endTime }: { start: string; end: string }) => { - setQueryTimeRange({ - value: stringToNumericTimeRange({ startTime, endTime }), - lastChangedTime: Date.now(), - }); - }, - [setQueryTimeRange] - ); - - const handleSelectedTimeRangeChange = useCallback( - (selectedTime: { start: string; end: string; isInvalid: boolean }) => { - if (selectedTime.isInvalid) { - return; - } - setSelectedTimeRange({ - startTime: selectedTime.start, - endTime: selectedTime.end, - }); - handleQueryTimeRangeChange(selectedTime); - }, - [setSelectedTimeRange, handleQueryTimeRangeChange] - ); - - const handleChartTimeRangeChange = useCallback( - ({ startTime, endTime }: TimeRange) => { - handleSelectedTimeRangeChange({ - end: new Date(endTime).toISOString(), - isInvalid: false, - start: new Date(startTime).toISOString(), - }); - }, - [handleSelectedTimeRangeChange] - ); - const handleAutoRefreshChange = useCallback( ({ isPaused, refreshInterval: interval }: { isPaused: boolean; refreshInterval: number }) => { setAutoRefresh({ @@ -207,7 +166,6 @@ export const LogEntryRateResultsContent: React.FunctionComponent = () => { showModuleSetup, ]); - const hasLogRateResults = (logEntryRate?.histogramBuckets?.length ?? 0) > 0; const hasAnomalyResults = logEntryAnomalies.length > 0; const isFirstUse = useMemo( @@ -217,22 +175,18 @@ export const LogEntryRateResultsContent: React.FunctionComponent = () => { logEntryCategoriesSetupStatus.type === 'succeeded' || (logEntryRateSetupStatus.type === 'skipped' && !!logEntryRateSetupStatus.newlyCreated) || logEntryRateSetupStatus.type === 'succeeded') && - !(hasLogRateResults || hasAnomalyResults), - [hasAnomalyResults, hasLogRateResults, logEntryCategoriesSetupStatus, logEntryRateSetupStatus] + !hasAnomalyResults, + [hasAnomalyResults, logEntryCategoriesSetupStatus, logEntryRateSetupStatus] ); - useEffect(() => { - getLogEntryRate(); - }, [getLogEntryRate, selectedDatasets, queryTimeRange.lastChangedTime]); - - useInterval( - () => { - handleQueryTimeRangeChange({ - start: selectedTimeRange.startTime, - end: selectedTimeRange.endTime, - }); + const handleSelectedTimeRangeChange = useCallback( + (selectedTime: { start: string; end: string; isInvalid: boolean }) => { + if (selectedTime.isInvalid) { + return; + } + setSelectedTimeRange(selectedTime); }, - autoRefresh.isPaused ? null : autoRefresh.interval + [setSelectedTimeRange] ); return ( @@ -251,8 +205,8 @@ export const LogEntryRateResultsContent: React.FunctionComponent = () => {
{ { changePaginationOptions={changePaginationOptions} sortOptions={sortOptions} paginationOptions={paginationOptions} + selectedDatasets={selectedDatasets} + jobIds={jobIds} + autoRefresh={autoRefresh} /> @@ -318,37 +272,6 @@ export const LogEntryRateResultsContent: React.FunctionComponent = () => { ); }; -const stringToNumericTimeRange = (timeRange: StringTimeRange): TimeRange => ({ - startTime: moment( - datemath.parse(timeRange.startTime, { - momentInstance: moment, - }) - ).valueOf(), - endTime: moment( - datemath.parse(timeRange.endTime, { - momentInstance: moment, - roundUp: true, - }) - ).valueOf(), -}); - -/** - * This function takes the current time range in ms, - * works out the bucket interval we'd need to always - * display 100 data points, and then takes that new - * value and works out the nearest multiple of - * 900000 (15 minutes) to it, so that we don't end up with - * jaggy bucket boundaries between the ML buckets and our - * aggregation buckets. - */ -const getBucketDuration = (startTime: number, endTime: number) => { - const msRange = moment(endTime).diff(moment(startTime)); - const bucketIntervalInMs = msRange / 100; - const result = bucketSpan * Math.round(bucketIntervalInMs / bucketSpan); - const roundedResult = parseInt(Number(result).toFixed(0), 10); - return roundedResult < bucketSpan ? bucketSpan : roundedResult; -}; - // This is needed due to the flex-basis: 100% !important; rule that // kicks in on small screens via media queries breaking when using direction="column" export const ResultsContentPage = euiStyled(EuiPage)` diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/sections/anomalies/anomalies_swimlane_visualisation.tsx b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/sections/anomalies/anomalies_swimlane_visualisation.tsx new file mode 100644 index 0000000000000..b0e85a4648d6e --- /dev/null +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/sections/anomalies/anomalies_swimlane_visualisation.tsx @@ -0,0 +1,70 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useMemo } from 'react'; +import moment from 'moment'; +import { AutoRefresh } from '../../use_log_entry_rate_results_url_state'; +import { useKibanaContextForPlugin } from '../../../../../hooks/use_kibana'; +import { + ANOMALY_SWIMLANE_EMBEDDABLE_TYPE, + AnomalySwimlaneEmbeddableInput, +} from '../../../../../../../ml/public'; +import { EmbeddableRenderer } from '../../../../../../../../../src/plugins/embeddable/public'; +import { partitionField } from '../../../../../../common/infra_ml'; +import { MissingEmbeddableFactoryCallout } from '../../../../../components/missing_embeddable_factory_callout'; +import { TimeRange } from '../../../../../../common/time/time_range'; + +interface Props { + timeRange: TimeRange; + jobIds: string[]; + selectedDatasets: string[]; + autoRefresh: AutoRefresh; +} + +// Disable refresh, allow our timerange changes to refresh the embeddable. +const REFRESH_CONFIG = { + pause: true, + value: 0, +}; + +export const AnomaliesSwimlaneVisualisation: React.FC = (props) => { + const { embeddable: embeddablePlugin } = useKibanaContextForPlugin().services; + if (!embeddablePlugin) return null; + return ; +}; + +export const VisualisationContent: React.FC = ({ timeRange, jobIds, selectedDatasets }) => { + const { embeddable: embeddablePlugin } = useKibanaContextForPlugin().services; + const factory = embeddablePlugin?.getEmbeddableFactory(ANOMALY_SWIMLANE_EMBEDDABLE_TYPE); + + const embeddableInput: AnomalySwimlaneEmbeddableInput = useMemo(() => { + return { + id: 'LOG_ENTRY_ANOMALIES_EMBEDDABLE_INSTANCE', // NOTE: This is the only embeddable on the anomalies page, a static string will do. + jobIds, + swimlaneType: 'viewBy', + timeRange: { + from: moment(timeRange.startTime).format('YYYY-MM-DDTHH:mm:ss.SSSZ'), + to: moment(timeRange.endTime).format('YYYY-MM-DDTHH:mm:ss.SSSZ'), + }, + refreshConfig: REFRESH_CONFIG, + viewBy: partitionField, + filters: [], + query: { + language: 'kuery', + query: selectedDatasets + .map((dataset) => `${partitionField} : ${dataset !== '' ? dataset : '""'}`) + .join(' or '), // Ensure unknown (those with an empty "" string) datasets are handled correctly. + }, + }; + }, [jobIds, timeRange.startTime, timeRange.endTime, selectedDatasets]); + + if (!factory) { + return ; + } + + return ; +}; diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/sections/anomalies/chart.tsx b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/sections/anomalies/chart.tsx deleted file mode 100644 index dd9c2dd707044..0000000000000 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/sections/anomalies/chart.tsx +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiEmptyPrompt } from '@elastic/eui'; -import { RectAnnotationDatum, AnnotationId } from '@elastic/charts'; -import { - Axis, - BarSeries, - Chart, - niceTimeFormatter, - Settings, - TooltipValue, - LIGHT_THEME, - DARK_THEME, - RectAnnotation, - BrushEndListener, -} from '@elastic/charts'; -import numeral from '@elastic/numeral'; -import { i18n } from '@kbn/i18n'; -import moment from 'moment'; -import React, { useCallback, useMemo } from 'react'; -import { LoadingOverlayWrapper } from '../../../../../components/loading_overlay_wrapper'; - -import { TimeRange } from '../../../../../../common/time/time_range'; -import { - MLSeverityScoreCategories, - ML_SEVERITY_COLORS, -} from '../../../../../../common/log_analysis'; -import { useKibanaUiSetting } from '../../../../../utils/use_kibana_ui_setting'; - -export const AnomaliesChart: React.FunctionComponent<{ - chartId: string; - setTimeRange: (timeRange: TimeRange) => void; - timeRange: TimeRange; - series: Array<{ time: number; value: number }>; - annotations: Record; - renderAnnotationTooltip?: (details?: string) => JSX.Element; - isLoading: boolean; -}> = ({ - chartId, - series, - annotations, - setTimeRange, - timeRange, - renderAnnotationTooltip, - isLoading, -}) => { - const [dateFormat] = useKibanaUiSetting('dateFormat', 'Y-MM-DD HH:mm:ss.SSS'); - const [isDarkMode] = useKibanaUiSetting('theme:darkMode'); - - const chartDateFormatter = useMemo( - () => niceTimeFormatter([timeRange.startTime, timeRange.endTime]), - [timeRange] - ); - - const logEntryRateSpecId = 'averageValues'; - - const tooltipProps = useMemo( - () => ({ - headerFormatter: (tooltipData: TooltipValue) => moment(tooltipData.value).format(dateFormat), - }), - [dateFormat] - ); - - const handleBrushEnd = useCallback( - ({ x }) => { - if (!x) { - return; - } - const [startTime, endTime] = x; - setTimeRange({ - endTime, - startTime, - }); - }, - [setTimeRange] - ); - - return !isLoading && !series.length ? ( - - {i18n.translate('xpack.infra.logs.analysis.anomalySectionLogRateChartNoData', { - defaultMessage: 'There is no log rate data to display.', - })} - - } - titleSize="m" - /> - ) : ( - -
- {series.length ? ( - - - numeral(value.toPrecision(3)).format('0[.][00]a')} // https://github.com/adamwdraper/Numeral-js/issues/194 - /> - - {renderAnnotations(annotations, chartId, renderAnnotationTooltip)} - - - ) : null} -
-
- ); -}; - -interface SeverityConfig { - id: AnnotationId; - style: { - fill: string; - opacity: number; - }; -} - -const severityConfigs: Record = { - warning: { - id: `anomalies-warning`, - style: { fill: ML_SEVERITY_COLORS.warning, opacity: 0.7 }, - }, - minor: { - id: `anomalies-minor`, - style: { fill: ML_SEVERITY_COLORS.minor, opacity: 0.7 }, - }, - major: { - id: `anomalies-major`, - style: { fill: ML_SEVERITY_COLORS.major, opacity: 0.7 }, - }, - critical: { - id: `anomalies-critical`, - style: { fill: ML_SEVERITY_COLORS.critical, opacity: 0.7 }, - }, -}; - -const renderAnnotations = ( - annotations: Record, - chartId: string, - renderAnnotationTooltip?: (details?: string) => JSX.Element -) => { - return Object.entries(annotations).map((entry, index) => { - return ( - - ); - }); -}; - -const barSeriesStyle = { rect: { fill: '#D3DAE6', opacity: 0.6 } }; // TODO: Acquire this from "theme" as euiColorLightShade diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/sections/anomalies/index.tsx b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/sections/anomalies/index.tsx index 75d7c4212bbc3..3bc206e9ad7bb 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/sections/anomalies/index.tsx +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/sections/anomalies/index.tsx @@ -14,12 +14,9 @@ import { EuiLoadingSpinner, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import React, { useMemo } from 'react'; -import { euiStyled } from '../../../../../../../../../src/plugins/kibana_react/common'; -import { LogEntryRateResults } from '../../use_log_entry_rate_results'; +import React from 'react'; import { TimeRange } from '../../../../../../common/time/time_range'; -import { getAnnotationsForAll, getLogEntryRateCombinedSeries } from '../helpers/data_formatters'; -import { AnomaliesChart } from './chart'; +import { AnomaliesSwimlaneVisualisation } from './anomalies_swimlane_visualisation'; import { AnomaliesTable } from './table'; import { ManageJobsButton } from '../../../../../components/logging/log_analysis_setup/manage_jobs_button'; import { @@ -33,13 +30,11 @@ import { SortOptions, } from '../../use_log_entry_anomalies_results'; import { LoadingOverlayWrapper } from '../../../../../components/loading_overlay_wrapper'; +import { AutoRefresh } from '../../use_log_entry_rate_results_url_state'; export const AnomaliesResults: React.FunctionComponent<{ - isLoadingLogRateResults: boolean; isLoadingAnomaliesResults: boolean; - logEntryRateResults: LogEntryRateResults | null; anomalies: LogEntryAnomalies; - setTimeRange: (timeRange: TimeRange) => void; timeRange: TimeRange; onViewModuleList: () => void; page: Page; @@ -49,11 +44,11 @@ export const AnomaliesResults: React.FunctionComponent<{ changePaginationOptions: ChangePaginationOptions; sortOptions: SortOptions; paginationOptions: PaginationOptions; + selectedDatasets: string[]; + jobIds: string[]; + autoRefresh: AutoRefresh; }> = ({ - isLoadingLogRateResults, isLoadingAnomaliesResults, - logEntryRateResults, - setTimeRange, timeRange, onViewModuleList, anomalies, @@ -64,27 +59,10 @@ export const AnomaliesResults: React.FunctionComponent<{ fetchNextPage, fetchPreviousPage, page, + selectedDatasets, + jobIds, + autoRefresh, }) => { - const logEntryRateSeries = useMemo( - () => - logEntryRateResults && logEntryRateResults.histogramBuckets - ? getLogEntryRateCombinedSeries(logEntryRateResults) - : [], - [logEntryRateResults] - ); - const anomalyAnnotations = useMemo( - () => - logEntryRateResults && logEntryRateResults.histogramBuckets - ? getAnnotationsForAll(logEntryRateResults) - : { - warning: [], - minor: [], - major: [], - critical: [], - }, - [logEntryRateResults] - ); - return ( <> @@ -98,52 +76,44 @@ export const AnomaliesResults: React.FunctionComponent<{
- {(!logEntryRateResults || - (logEntryRateResults && - logEntryRateResults.histogramBuckets && - !logEntryRateResults.histogramBuckets.length)) && - (!anomalies || anomalies.length === 0) ? ( - } - > - - {i18n.translate('xpack.infra.logs.analysis.anomalySectionNoDataTitle', { - defaultMessage: 'There is no data to display.', - })} - - } - titleSize="m" - body={ -

- {i18n.translate('xpack.infra.logs.analysis.anomalySectionNoDataBody', { - defaultMessage: 'You may want to adjust your time range.', - })} -

- } + + + -
- ) : ( - <> - - - - - - + + + + <> + {!anomalies || anomalies.length === 0 ? ( + } + > + + {i18n.translate('xpack.infra.logs.analysis.anomalySectionNoDataTitle', { + defaultMessage: 'There is no data to display.', + })} + + } + titleSize="m" + body={ +

+ {i18n.translate('xpack.infra.logs.analysis.anomalySectionNoDataBody', { + defaultMessage: 'You may want to adjust your time range.', + })} +

+ } + /> +
+ ) : ( - - )} + )} + ); }; @@ -164,52 +134,6 @@ const title = i18n.translate('xpack.infra.logs.analysis.anomaliesSectionTitle', defaultMessage: 'Anomalies', }); -interface ParsedAnnotationDetails { - anomalyScoresByPartition: Array<{ partitionName: string; maximumAnomalyScore: number }>; -} - -const overallAnomalyScoreLabel = i18n.translate( - 'xpack.infra.logs.analysis.overallAnomalyChartMaxScoresLabel', - { - defaultMessage: 'Max anomaly scores:', - } -); - -const AnnotationTooltip: React.FunctionComponent<{ details: string }> = ({ details }) => { - const parsedDetails: ParsedAnnotationDetails = JSON.parse(details); - return ( - - - {overallAnomalyScoreLabel} - -
    - {parsedDetails.anomalyScoresByPartition.map(({ partitionName, maximumAnomalyScore }) => { - return ( -
  • - - {`${partitionName}: `} - {maximumAnomalyScore} - -
  • - ); - })} -
-
- ); -}; - -const renderAnnotationTooltip = (details?: string) => { - // Note: Seems to be necessary to get things typed correctly all the way through to elastic-charts components - if (!details) { - return
; - } - return ; -}; - -const TooltipWrapper = euiStyled('div')` - white-space: nowrap; -`; - const loadingAriaLabel = i18n.translate( 'xpack.infra.logs.analysis.anomaliesSectionLoadingAriaLabel', { defaultMessage: 'Loading anomalies' } diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/sections/anomalies/table.tsx b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/sections/anomalies/table.tsx index d80f9d04e72a8..c208c72558362 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/sections/anomalies/table.tsx +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/sections/anomalies/table.tsx @@ -22,7 +22,6 @@ import useSet from 'react-use/lib/useSet'; import { TimeRange } from '../../../../../../common/time/time_range'; import { AnomalyType, - formatAnomalyScore, getFriendlyNameForPartitionId, formatOneDecimalPlace, isCategoryAnomaly, @@ -47,7 +46,6 @@ import { LoadingOverlayWrapper } from '../../../../../components/loading_overlay interface TableItem { id: string; dataset: string; - datasetName: string; anomalyScore: number; startTime: number; typical: number; @@ -86,7 +84,6 @@ const datasetColumnName = i18n.translate( export const AnomaliesTable: React.FunctionComponent<{ results: LogEntryAnomalies; - setTimeRange: (timeRange: TimeRange) => void; timeRange: TimeRange; changeSortOptions: ChangeSortOptions; changePaginationOptions: ChangePaginationOptions; @@ -99,7 +96,6 @@ export const AnomaliesTable: React.FunctionComponent<{ }> = ({ results, timeRange, - setTimeRange, changeSortOptions, sortOptions, changePaginationOptions, @@ -122,8 +118,7 @@ export const AnomaliesTable: React.FunctionComponent<{ return { id: anomaly.id, dataset: anomaly.dataset, - datasetName: getFriendlyNameForPartitionId(anomaly.dataset), - anomalyScore: formatAnomalyScore(anomaly.anomalyScore), + anomalyScore: anomaly.anomalyScore, startTime: anomaly.startTime, type: anomaly.type, typical: anomaly.typical, @@ -182,11 +177,12 @@ export const AnomaliesTable: React.FunctionComponent<{ render: (startTime: number) => moment(startTime).format(dateFormat), }, { - field: 'datasetName', + field: 'dataset', name: datasetColumnName, sortable: true, truncateText: true, width: '200px', + render: (dataset: string) => getFriendlyNameForPartitionId(dataset), }, { align: RIGHT_ALIGNMENT, diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/sections/helpers/data_formatters.tsx b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/sections/helpers/data_formatters.tsx deleted file mode 100644 index 8041ad1458546..0000000000000 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/sections/helpers/data_formatters.tsx +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { RectAnnotationDatum } from '@elastic/charts'; -import { i18n } from '@kbn/i18n'; - -import { - formatAnomalyScore, - getFriendlyNameForPartitionId, - getSeverityCategoryForScore, - MLSeverityScoreCategories, -} from '../../../../../../common/log_analysis'; -import { LogEntryRateResults } from '../../use_log_entry_rate_results'; - -export const getLogEntryRatePartitionedSeries = (results: LogEntryRateResults) => { - return results.histogramBuckets.reduce>( - (buckets, bucket) => { - return [ - ...buckets, - ...bucket.partitions.map((partition) => ({ - group: getFriendlyNameForPartitionId(partition.partitionId), - time: bucket.startTime, - value: partition.averageActualLogEntryRate, - })), - ]; - }, - [] - ); -}; - -export const getLogEntryRateCombinedSeries = (results: LogEntryRateResults) => { - return results.histogramBuckets.reduce>( - (buckets, bucket) => { - return [ - ...buckets, - { - time: bucket.startTime, - value: bucket.partitions.reduce((accumulatedValue, partition) => { - return accumulatedValue + partition.averageActualLogEntryRate; - }, 0), - }, - ]; - }, - [] - ); -}; - -export const getLogEntryRateSeriesForPartition = ( - results: LogEntryRateResults, - partitionId: string -) => { - return results.partitionBuckets[partitionId].buckets.reduce< - Array<{ time: number; value: number }> - >((buckets, bucket) => { - return [ - ...buckets, - { - time: bucket.startTime, - value: bucket.averageActualLogEntryRate, - }, - ]; - }, []); -}; - -export const getAnnotationsForPartition = (results: LogEntryRateResults, partitionId: string) => { - return results.partitionBuckets[partitionId].buckets.reduce< - Record - >( - (annotatedBucketsBySeverity, bucket) => { - const severityCategory = getSeverityCategoryForScore(bucket.maximumAnomalyScore); - if (!severityCategory) { - return annotatedBucketsBySeverity; - } - - return { - ...annotatedBucketsBySeverity, - [severityCategory]: [ - ...annotatedBucketsBySeverity[severityCategory], - { - coordinates: { - x0: bucket.startTime, - x1: bucket.startTime + results.bucketDuration, - }, - details: i18n.translate( - 'xpack.infra.logs.analysis.partitionMaxAnomalyScoreAnnotationLabel', - { - defaultMessage: 'Max anomaly score: {maxAnomalyScore}', - values: { - maxAnomalyScore: formatAnomalyScore(bucket.maximumAnomalyScore), - }, - } - ), - }, - ], - }; - }, - { - warning: [], - minor: [], - major: [], - critical: [], - } - ); -}; - -export const getTotalNumberOfLogEntriesForPartition = ( - results: LogEntryRateResults, - partitionId: string -) => { - return results.partitionBuckets[partitionId].totalNumberOfLogEntries; -}; - -export const getAnnotationsForAll = (results: LogEntryRateResults) => { - return results.histogramBuckets.reduce>( - (annotatedBucketsBySeverity, bucket) => { - const maxAnomalyScoresByPartition = bucket.partitions.reduce< - Array<{ partitionName: string; maximumAnomalyScore: number }> - >((bucketMaxAnomalyScoresByPartition, partition) => { - if (!getSeverityCategoryForScore(partition.maximumAnomalyScore)) { - return bucketMaxAnomalyScoresByPartition; - } - return [ - ...bucketMaxAnomalyScoresByPartition, - { - partitionName: getFriendlyNameForPartitionId(partition.partitionId), - maximumAnomalyScore: formatAnomalyScore(partition.maximumAnomalyScore), - }, - ]; - }, []); - - if (maxAnomalyScoresByPartition.length === 0) { - return annotatedBucketsBySeverity; - } - const severityCategory = getSeverityCategoryForScore( - Math.max( - ...maxAnomalyScoresByPartition.map((partitionScore) => partitionScore.maximumAnomalyScore) - ) - ); - if (!severityCategory) { - return annotatedBucketsBySeverity; - } - const sortedMaxAnomalyScoresByPartition = maxAnomalyScoresByPartition.sort( - (a, b) => b.maximumAnomalyScore - a.maximumAnomalyScore - ); - return { - ...annotatedBucketsBySeverity, - [severityCategory]: [ - ...annotatedBucketsBySeverity[severityCategory], - { - coordinates: { - x0: bucket.startTime, - x1: bucket.startTime + results.bucketDuration, - }, - details: JSON.stringify({ - anomalyScoresByPartition: sortedMaxAnomalyScoresByPartition, - }), - }, - ], - }; - }, - { - warning: [], - minor: [], - major: [], - critical: [], - } - ); -}; - -export const getTopAnomalyScoreAcrossAllPartitions = (results: LogEntryRateResults) => { - const allTopScores = Object.values(results.partitionBuckets).reduce( - (scores: number[], partition) => { - return [...scores, partition.topAnomalyScore]; - }, - [] - ); - return Math.max(...allTopScores); -}; diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/service_calls/get_log_entry_rate.ts b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/service_calls/get_log_entry_rate.ts deleted file mode 100644 index 4b677140e2a7a..0000000000000 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/service_calls/get_log_entry_rate.ts +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { HttpHandler } from 'src/core/public'; -import { - getLogEntryRateRequestPayloadRT, - getLogEntryRateSuccessReponsePayloadRT, - LOG_ANALYSIS_GET_LOG_ENTRY_RATE_PATH, -} from '../../../../../common/http_api/log_analysis'; -import { decodeOrThrow } from '../../../../../common/runtime_types'; - -interface RequestArgs { - sourceId: string; - startTime: number; - endTime: number; - bucketDuration: number; - datasets?: string[]; -} - -export const callGetLogEntryRateAPI = async (requestArgs: RequestArgs, fetch: HttpHandler) => { - const { sourceId, startTime, endTime, bucketDuration, datasets } = requestArgs; - const response = await fetch(LOG_ANALYSIS_GET_LOG_ENTRY_RATE_PATH, { - method: 'POST', - body: JSON.stringify( - getLogEntryRateRequestPayloadRT.encode({ - data: { - sourceId, - timeRange: { - startTime, - endTime, - }, - bucketDuration, - datasets, - }, - }) - ), - }); - return decodeOrThrow(getLogEntryRateSuccessReponsePayloadRT)(response); -}; diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/use_dataset_filtering.ts b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/use_dataset_filtering.ts new file mode 100644 index 0000000000000..9bd1e42779a36 --- /dev/null +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/use_dataset_filtering.ts @@ -0,0 +1,99 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useEffect, useReducer, useCallback } from 'react'; +import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; +import { Filter } from '../../../../../../../src/plugins/data/common'; +import { CONTROLLED_BY_SWIM_LANE_FILTER } from '../../../../../ml/public'; + +interface ReducerState { + selectedDatasets: string[]; + selectedDatasetsFilters: Filter[]; +} + +type ReducerAction = + | { type: 'changeSelectedDatasets'; payload: { datasets: string[] } } + | { type: 'updateDatasetsFilters'; payload: { filters: Filter[] } }; + +const initialState: ReducerState = { + selectedDatasets: [], + selectedDatasetsFilters: [], +}; + +function reducer(state: ReducerState, action: ReducerAction) { + switch (action.type) { + case 'changeSelectedDatasets': + return { + ...state, + selectedDatasets: action.payload.datasets, + }; + case 'updateDatasetsFilters': + const datasetsToAdd = action.payload.filters + .filter((filter) => !state.selectedDatasets.includes(filter.meta.params.query)) + .map((filter) => filter.meta.params.query); + return { + ...state, + selectedDatasets: [...state.selectedDatasets, ...datasetsToAdd], + selectedDatasetsFilters: action.payload.filters, + }; + default: + throw new Error('Unknown action'); + } +} + +export const useDatasetFiltering = () => { + const { services } = useKibanaContextForPlugin(); + const [reducerState, dispatch] = useReducer(reducer, initialState); + + const handleSetSelectedDatasets = useCallback( + (datasets: string[]) => { + dispatch({ type: 'changeSelectedDatasets', payload: { datasets } }); + }, + [dispatch] + ); + + // NOTE: The anomaly swimlane embeddable will communicate it's filter action + // changes via the filterManager service. + useEffect(() => { + const sub = services.data.query.filterManager.getUpdates$().subscribe(() => { + const filters = services.data.query.filterManager + .getFilters() + .filter( + (filter) => + filter.meta.controlledBy && filter.meta.controlledBy === CONTROLLED_BY_SWIM_LANE_FILTER + ); + dispatch({ type: 'updateDatasetsFilters', payload: { filters } }); + }); + + return () => sub.unsubscribe(); + }, [services.data.query.filterManager, dispatch]); + + // NOTE: When filters are removed via the UI we need to make sure these are also tidied up + // within the FilterManager service, otherwise a scenario can occur where that filter can't + // be re-added via the embeddable as it will be seen as a duplicate to the FilterManager, + // and no update will be emitted. + useEffect(() => { + const filtersToRemove = reducerState.selectedDatasetsFilters.filter( + (filter) => !reducerState.selectedDatasets.includes(filter.meta.params.query) + ); + if (filtersToRemove.length > 0) { + filtersToRemove.forEach((filter) => { + services.data.query.filterManager.removeFilter(filter); + }); + } + }, [ + reducerState.selectedDatasets, + reducerState.selectedDatasetsFilters, + services.data.query.filterManager, + ]); + + return { + selectedDatasets: reducerState.selectedDatasets, + setSelectedDatasets: handleSetSelectedDatasets, + selectedDatasetsFilters: reducerState.selectedDatasetsFilters, + }; +}; diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/use_log_entry_rate_results.ts b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/use_log_entry_rate_results.ts deleted file mode 100644 index a226977a30c57..0000000000000 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/use_log_entry_rate_results.ts +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { useMemo, useState } from 'react'; - -import { - GetLogEntryRateSuccessResponsePayload, - LogEntryRateHistogramBucket, - LogEntryRatePartition, - LogEntryRateAnomaly, -} from '../../../../common/http_api/log_analysis'; -import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; -import { useTrackedPromise } from '../../../utils/use_tracked_promise'; -import { callGetLogEntryRateAPI } from './service_calls/get_log_entry_rate'; - -type PartitionBucket = LogEntryRatePartition & { - startTime: number; -}; - -type PartitionRecord = Record< - string, - { buckets: PartitionBucket[]; topAnomalyScore: number; totalNumberOfLogEntries: number } ->; - -export type AnomalyRecord = LogEntryRateAnomaly & { - partitionId: string; -}; - -export interface LogEntryRateResults { - bucketDuration: number; - totalNumberOfLogEntries: number; - histogramBuckets: LogEntryRateHistogramBucket[]; - partitionBuckets: PartitionRecord; - anomalies: AnomalyRecord[]; -} - -export const useLogEntryRateResults = ({ - sourceId, - startTime, - endTime, - bucketDuration = 15 * 60 * 1000, - filteredDatasets, -}: { - sourceId: string; - startTime: number; - endTime: number; - bucketDuration: number; - filteredDatasets?: string[]; -}) => { - const { services } = useKibanaContextForPlugin(); - const [logEntryRate, setLogEntryRate] = useState(null); - - const [getLogEntryRateRequest, getLogEntryRate] = useTrackedPromise( - { - cancelPreviousOn: 'resolution', - createPromise: async () => { - return await callGetLogEntryRateAPI( - { - sourceId, - startTime, - endTime, - bucketDuration, - datasets: filteredDatasets, - }, - services.http.fetch - ); - }, - onResolve: ({ data }) => { - setLogEntryRate({ - bucketDuration: data.bucketDuration, - totalNumberOfLogEntries: data.totalNumberOfLogEntries, - histogramBuckets: data.histogramBuckets, - partitionBuckets: formatLogEntryRateResultsByPartition(data), - anomalies: formatLogEntryRateResultsByAllAnomalies(data), - }); - }, - onReject: () => { - setLogEntryRate(null); - }, - }, - [sourceId, startTime, endTime, bucketDuration, filteredDatasets] - ); - - const isLoading = useMemo(() => getLogEntryRateRequest.state === 'pending', [ - getLogEntryRateRequest.state, - ]); - - return { - getLogEntryRate, - isLoading, - logEntryRate, - }; -}; - -const formatLogEntryRateResultsByPartition = ( - results: GetLogEntryRateSuccessResponsePayload['data'] -): PartitionRecord => { - const partitionedBuckets = results.histogramBuckets.reduce< - Record - >((partitionResults, bucket) => { - return bucket.partitions.reduce>( - (_partitionResults, partition) => { - return { - ..._partitionResults, - [partition.partitionId]: { - buckets: _partitionResults[partition.partitionId] - ? [ - ..._partitionResults[partition.partitionId].buckets, - { startTime: bucket.startTime, ...partition }, - ] - : [{ startTime: bucket.startTime, ...partition }], - }, - }; - }, - partitionResults - ); - }, {}); - - const resultsByPartition: PartitionRecord = {}; - - Object.entries(partitionedBuckets).map(([key, value]) => { - const anomalyScores = value.buckets.reduce((scores: number[], bucket) => { - return [...scores, bucket.maximumAnomalyScore]; - }, []); - const totalNumberOfLogEntries = value.buckets.reduce((total, bucket) => { - return (total += bucket.numberOfLogEntries); - }, 0); - resultsByPartition[key] = { - topAnomalyScore: Math.max(...anomalyScores), - totalNumberOfLogEntries, - buckets: value.buckets, - }; - }); - - return resultsByPartition; -}; - -const formatLogEntryRateResultsByAllAnomalies = ( - results: GetLogEntryRateSuccessResponsePayload['data'] -): AnomalyRecord[] => { - return results.histogramBuckets.reduce((anomalies, bucket) => { - return bucket.partitions.reduce((_anomalies, partition) => { - if (partition.anomalies.length > 0) { - partition.anomalies.forEach((anomaly) => { - _anomalies.push({ - partitionId: partition.partitionId, - ...anomaly, - }); - }); - return _anomalies; - } else { - return _anomalies; - } - }, anomalies); - }, []); -}; diff --git a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/use_log_entry_rate_results_url_state.tsx b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/use_log_entry_rate_results_url_state.tsx index fdbde1acb83ad..ccfae14fd4a59 100644 --- a/x-pack/plugins/infra/public/pages/logs/log_entry_rate/use_log_entry_rate_results_url_state.tsx +++ b/x-pack/plugins/infra/public/pages/logs/log_entry_rate/use_log_entry_rate_results_url_state.tsx @@ -5,24 +5,32 @@ * 2.0. */ -import { fold } from 'fp-ts/lib/Either'; -import { constant, identity } from 'fp-ts/lib/function'; -import { pipe } from 'fp-ts/lib/pipeable'; +import { useCallback, useMemo, useState } from 'react'; +import datemath from '@elastic/datemath'; +import moment from 'moment'; import * as rt from 'io-ts'; - +import { TimeRange as KibanaTimeRange } from '../../../../../../../src/plugins/data/public'; +import { TimeRange } from '../../../../common/time/time_range'; import { useUrlState } from '../../../utils/use_url_state'; +import { useInterval } from '../../../hooks/use_interval'; import { useKibanaTimefilterTime, useSyncKibanaTimeFilterTime, } from '../../../hooks/use_kibana_timefilter_time'; +import { decodeOrThrow } from '../../../../common/runtime_types'; -const autoRefreshRT = rt.union([ - rt.type({ - interval: rt.number, - isPaused: rt.boolean, - }), - rt.undefined, -]); +const autoRefreshRT = rt.type({ + interval: rt.number, + isPaused: rt.boolean, +}); + +export type AutoRefresh = rt.TypeOf; +const urlAutoRefreshRT = rt.union([autoRefreshRT, rt.undefined]); +const decodeAutoRefreshUrlState = decodeOrThrow(urlAutoRefreshRT); +const defaultAutoRefreshState = { + isPaused: false, + interval: 30000, +}; export const stringTimeRangeRT = rt.type({ startTime: rt.string, @@ -31,6 +39,7 @@ export const stringTimeRangeRT = rt.type({ export type StringTimeRange = rt.TypeOf; const urlTimeRangeRT = rt.union([stringTimeRangeRT, rt.undefined]); +const decodeTimeRangeUrlState = decodeOrThrow(urlTimeRangeRT); const TIME_RANGE_URL_STATE_KEY = 'timeRange'; const AUTOREFRESH_URL_STATE_KEY = 'autoRefresh'; @@ -40,36 +49,102 @@ export const useLogAnalysisResultsUrlState = () => { const [getTime] = useKibanaTimefilterTime(TIME_DEFAULTS); const { from: start, to: end } = getTime(); - const [timeRange, setTimeRange] = useUrlState({ - defaultState: { + const defaultTimeRangeState = useMemo(() => { + return { startTime: start, endTime: end, - }, - decodeUrlState: (value: unknown) => - pipe(urlTimeRangeRT.decode(value), fold(constant(undefined), identity)), + }; + }, [start, end]); + + const [urlTimeRange, setUrlTimeRange] = useUrlState({ + defaultState: defaultTimeRangeState, + decodeUrlState: decodeTimeRangeUrlState, encodeUrlState: urlTimeRangeRT.encode, urlStateKey: TIME_RANGE_URL_STATE_KEY, writeDefaultState: true, }); - useSyncKibanaTimeFilterTime(TIME_DEFAULTS, { from: timeRange.startTime, to: timeRange.endTime }); + // Numeric time range for querying APIs + const [queryTimeRange, setQueryTimeRange] = useState<{ + value: TimeRange; + lastChangedTime: number; + }>(() => ({ + value: stringToNumericTimeRange({ start: urlTimeRange.startTime, end: urlTimeRange.endTime }), + lastChangedTime: Date.now(), + })); - const [autoRefresh, setAutoRefresh] = useUrlState({ - defaultState: { - isPaused: false, - interval: 30000, + const handleQueryTimeRangeChange = useCallback( + ({ start: startTime, end: endTime }: { start: string; end: string }) => { + setQueryTimeRange({ + value: stringToNumericTimeRange({ start: startTime, end: endTime }), + lastChangedTime: Date.now(), + }); + }, + [setQueryTimeRange] + ); + + const setTimeRange = useCallback( + (selectedTime: { start: string; end: string }) => { + setUrlTimeRange({ + startTime: selectedTime.start, + endTime: selectedTime.end, + }); + handleQueryTimeRangeChange(selectedTime); }, - decodeUrlState: (value: unknown) => - pipe(autoRefreshRT.decode(value), fold(constant(undefined), identity)), - encodeUrlState: autoRefreshRT.encode, + [setUrlTimeRange, handleQueryTimeRangeChange] + ); + + const handleTimeFilterChange = useCallback( + (newTimeRange: KibanaTimeRange) => { + const { from, to } = newTimeRange; + setTimeRange({ start: from, end: to }); + }, + [setTimeRange] + ); + + useSyncKibanaTimeFilterTime( + TIME_DEFAULTS, + { from: urlTimeRange.startTime, to: urlTimeRange.endTime }, + handleTimeFilterChange + ); + + const [autoRefresh, setAutoRefresh] = useUrlState({ + defaultState: defaultAutoRefreshState, + decodeUrlState: decodeAutoRefreshUrlState, + encodeUrlState: urlAutoRefreshRT.encode, urlStateKey: AUTOREFRESH_URL_STATE_KEY, writeDefaultState: true, }); + useInterval( + () => { + handleQueryTimeRangeChange({ + start: urlTimeRange.startTime, + end: urlTimeRange.endTime, + }); + }, + autoRefresh.isPaused ? null : autoRefresh.interval + ); + return { - timeRange, + timeRange: queryTimeRange, + friendlyTimeRange: urlTimeRange, setTimeRange, autoRefresh, setAutoRefresh, }; }; + +const stringToNumericTimeRange = (timeRange: { start: string; end: string }): TimeRange => ({ + startTime: moment( + datemath.parse(timeRange.start, { + momentInstance: moment, + }) + ).valueOf(), + endTime: moment( + datemath.parse(timeRange.end, { + momentInstance: moment, + roundUp: true, + }) + ).valueOf(), +}); diff --git a/x-pack/plugins/infra/public/pages/metrics/index.tsx b/x-pack/plugins/infra/public/pages/metrics/index.tsx index 52c2a70f2d359..8fd32bda7fbc8 100644 --- a/x-pack/plugins/infra/public/pages/metrics/index.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/index.tsx @@ -35,12 +35,11 @@ import { WaffleOptionsProvider } from './inventory_view/hooks/use_waffle_options import { WaffleTimeProvider } from './inventory_view/hooks/use_waffle_time'; import { WaffleFiltersProvider } from './inventory_view/hooks/use_waffle_filters'; -import { InventoryAlertDropdown } from '../../alerting/inventory/components/alert_dropdown'; -import { MetricsAlertDropdown } from '../../alerting/metric_threshold/components/alert_dropdown'; +import { MetricsAlertDropdown } from '../../alerting/common/components/metrics_alert_dropdown'; import { SavedView } from '../../containers/saved_view/saved_view'; import { AlertPrefillProvider } from '../../alerting/use_alert_prefill'; import { InfraMLCapabilitiesProvider } from '../../containers/ml/infra_ml_capabilities'; -import { AnomalyDetectionFlyout } from './inventory_view/components/ml/anomaly_detection/anomoly_detection_flyout'; +import { AnomalyDetectionFlyout } from './inventory_view/components/ml/anomaly_detection/anomaly_detection_flyout'; import { HeaderMenuPortal } from '../../../../observability/public'; import { HeaderActionMenuContext } from '../../utils/header_action_menu_provider'; @@ -83,8 +82,7 @@ export const InfrastructurePage = ({ match }: RouteComponentProps) => { - - + { jobSummaries: k8sJobSummaries, } = useMetricK8sModuleContext(); const { - hasInfraMLCapabilites, + hasInfraMLCapabilities, hasInfraMLReadCapabilities, hasInfraMLSetupCapabilities, } = useInfraMLCapabilitiesContext(); @@ -69,7 +69,7 @@ export const FlyoutHome = (props: Props) => { } }, [fetchK8sJobStatus, fetchHostJobStatus, hasInfraMLReadCapabilities]); - if (!hasInfraMLCapabilites) { + if (!hasInfraMLCapabilities) { return ; } else if (!hasInfraMLReadCapabilities) { return ; diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/timeline/timeline.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/timeline/timeline.tsx index a6a296f7d5725..0248241d616dc 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/timeline/timeline.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/timeline/timeline.tsx @@ -51,7 +51,7 @@ interface Props { } export const Timeline: React.FC = ({ interval, yAxisFormatter, isVisible }) => { - const { sourceId } = useSourceContext(); + const { sourceId, source } = useSourceContext(); const { metric, nodeType, accountId, region } = useWaffleOptionsContext(); const { currentTime, jumpToTime, stopAutoReload } = useWaffleTimeContext(); const { filterQueryAsJson } = useWaffleFiltersContext(); @@ -70,6 +70,7 @@ export const Timeline: React.FC = ({ interval, yAxisFormatter, isVisible const anomalyParams = { sourceId: 'default', + anomalyThreshold: source?.configuration.anomalyThreshold || 0, startTime, endTime, defaultSortOptions: { diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_metrics_hosts_anomalies.ts b/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_metrics_hosts_anomalies.ts index c3732fb22cb63..25afd05633fa5 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_metrics_hosts_anomalies.ts +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_metrics_hosts_anomalies.ts @@ -138,6 +138,7 @@ export const useMetricsHostsAnomaliesResults = ({ endTime, startTime, sourceId, + anomalyThreshold, defaultSortOptions, defaultPaginationOptions, onGetMetricsHostsAnomaliesDatasetsError, @@ -146,6 +147,7 @@ export const useMetricsHostsAnomaliesResults = ({ endTime: number; startTime: number; sourceId: string; + anomalyThreshold: number; defaultSortOptions: Sort; defaultPaginationOptions: Pick; onGetMetricsHostsAnomaliesDatasetsError?: (error: Error) => void; @@ -182,6 +184,7 @@ export const useMetricsHostsAnomaliesResults = ({ return await callGetMetricHostsAnomaliesAPI( { sourceId, + anomalyThreshold, startTime: queryStartTime, endTime: queryEndTime, metric, @@ -215,6 +218,7 @@ export const useMetricsHostsAnomaliesResults = ({ }, [ sourceId, + anomalyThreshold, dispatch, reducerState.timeRange, reducerState.sortOptions, @@ -296,6 +300,7 @@ export const useMetricsHostsAnomaliesResults = ({ interface RequestArgs { sourceId: string; + anomalyThreshold: number; startTime: number; endTime: number; metric: Metric; @@ -307,13 +312,14 @@ export const callGetMetricHostsAnomaliesAPI = async ( requestArgs: RequestArgs, fetch: HttpHandler ) => { - const { sourceId, startTime, endTime, metric, sort, pagination } = requestArgs; + const { sourceId, anomalyThreshold, startTime, endTime, metric, sort, pagination } = requestArgs; const response = await fetch(INFA_ML_GET_METRICS_HOSTS_ANOMALIES_PATH, { method: 'POST', body: JSON.stringify( getMetricsHostsAnomaliesRequestPayloadRT.encode({ data: { sourceId, + anomalyThreshold, timeRange: { startTime, endTime, diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_metrics_k8s_anomalies.ts b/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_metrics_k8s_anomalies.ts index 2a8beeaa814fc..c135a2c5e6661 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_metrics_k8s_anomalies.ts +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_metrics_k8s_anomalies.ts @@ -138,6 +138,7 @@ export const useMetricsK8sAnomaliesResults = ({ endTime, startTime, sourceId, + anomalyThreshold, defaultSortOptions, defaultPaginationOptions, onGetMetricsHostsAnomaliesDatasetsError, @@ -146,6 +147,7 @@ export const useMetricsK8sAnomaliesResults = ({ endTime: number; startTime: number; sourceId: string; + anomalyThreshold: number; defaultSortOptions: Sort; defaultPaginationOptions: Pick; onGetMetricsHostsAnomaliesDatasetsError?: (error: Error) => void; @@ -183,6 +185,7 @@ export const useMetricsK8sAnomaliesResults = ({ return await callGetMetricsK8sAnomaliesAPI( { sourceId, + anomalyThreshold, startTime: queryStartTime, endTime: queryEndTime, metric, @@ -217,6 +220,7 @@ export const useMetricsK8sAnomaliesResults = ({ }, [ sourceId, + anomalyThreshold, dispatch, reducerState.timeRange, reducerState.sortOptions, @@ -298,6 +302,7 @@ export const useMetricsK8sAnomaliesResults = ({ interface RequestArgs { sourceId: string; + anomalyThreshold: number; startTime: number; endTime: number; metric: Metric; @@ -310,13 +315,23 @@ export const callGetMetricsK8sAnomaliesAPI = async ( requestArgs: RequestArgs, fetch: HttpHandler ) => { - const { sourceId, startTime, endTime, metric, sort, pagination, datasets } = requestArgs; + const { + sourceId, + anomalyThreshold, + startTime, + endTime, + metric, + sort, + pagination, + datasets, + } = requestArgs; const response = await fetch(INFA_ML_GET_METRICS_K8S_ANOMALIES_PATH, { method: 'POST', body: JSON.stringify( getMetricsK8sAnomaliesRequestPayloadRT.encode({ data: { sourceId, + anomalyThreshold, timeRange: { startTime, endTime, diff --git a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/kuery_bar.tsx b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/kuery_bar.tsx index 44391568741f3..e22c6fa661181 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/kuery_bar.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/kuery_bar.tsx @@ -10,7 +10,19 @@ import { i18n } from '@kbn/i18n'; import React, { useEffect, useState } from 'react'; import { WithKueryAutocompletion } from '../../../../containers/with_kuery_autocompletion'; import { AutocompleteField } from '../../../../components/autocomplete_field'; -import { esKuery, IIndexPattern } from '../../../../../../../../src/plugins/data/public'; +import { + esKuery, + IIndexPattern, + QuerySuggestion, +} from '../../../../../../../../src/plugins/data/public'; + +type LoadSuggestionsFn = ( + e: string, + p: number, + m?: number, + transform?: (s: QuerySuggestion[]) => QuerySuggestion[] +) => void; +export type CurryLoadSuggestionsType = (loadSuggestions: LoadSuggestionsFn) => LoadSuggestionsFn; interface Props { derivedIndexPattern: IIndexPattern; @@ -18,6 +30,7 @@ interface Props { onChange?: (query: string) => void; value?: string | null; placeholder?: string; + curryLoadSuggestions?: CurryLoadSuggestionsType; } function validateQuery(query: string) { @@ -35,6 +48,7 @@ export const MetricsExplorerKueryBar = ({ onChange, value, placeholder, + curryLoadSuggestions = defaultCurryLoadSuggestions, }: Props) => { const [draftQuery, setDraftQuery] = useState(value || ''); const [isValid, setValidation] = useState(true); @@ -73,7 +87,7 @@ export const MetricsExplorerKueryBar = ({ aria-label={placeholder} isLoadingSuggestions={isLoadingSuggestions} isValid={isValid} - loadSuggestions={loadSuggestions} + loadSuggestions={curryLoadSuggestions(loadSuggestions)} onChange={handleChange} onSubmit={onSubmit} placeholder={placeholder || defaultPlaceholder} @@ -84,3 +98,6 @@ export const MetricsExplorerKueryBar = ({ ); }; + +const defaultCurryLoadSuggestions: CurryLoadSuggestionsType = (loadSuggestions) => (...args) => + loadSuggestions(...args); diff --git a/x-pack/plugins/infra/public/plugin.ts b/x-pack/plugins/infra/public/plugin.ts index 8e7d165f8a535..d4bb83e8668ba 100644 --- a/x-pack/plugins/infra/public/plugin.ts +++ b/x-pack/plugins/infra/public/plugin.ts @@ -10,6 +10,7 @@ import { AppMountParameters, PluginInitializerContext } from 'kibana/public'; import { DEFAULT_APP_CATEGORIES } from '../../../../src/core/public'; import { createMetricThresholdAlertType } from './alerting/metric_threshold'; import { createInventoryMetricAlertType } from './alerting/inventory'; +import { createMetricAnomalyAlertType } from './alerting/metric_anomaly'; import { getAlertType as getLogsAlertType } from './alerting/log_threshold'; import { registerFeatures } from './register_feature'; import { @@ -35,6 +36,7 @@ export class Plugin implements InfraClientPluginClass { pluginsSetup.triggersActionsUi.alertTypeRegistry.register(createInventoryMetricAlertType()); pluginsSetup.triggersActionsUi.alertTypeRegistry.register(getLogsAlertType()); pluginsSetup.triggersActionsUi.alertTypeRegistry.register(createMetricThresholdAlertType()); + pluginsSetup.triggersActionsUi.alertTypeRegistry.register(createMetricAnomalyAlertType()); if (pluginsSetup.observability) { pluginsSetup.observability.dashboard.register({ diff --git a/x-pack/plugins/infra/public/types.ts b/x-pack/plugins/infra/public/types.ts index b78912bfba3ac..4d70676d25e40 100644 --- a/x-pack/plugins/infra/public/types.ts +++ b/x-pack/plugins/infra/public/types.ts @@ -23,7 +23,8 @@ import type { ObservabilityPluginStart, } from '../../observability/public'; import type { SpacesPluginStart } from '../../spaces/public'; -import { MlPluginStart } from '../../ml/public'; +import { MlPluginStart, MlPluginSetup } from '../../ml/public'; +import type { EmbeddableStart } from '../../../../src/plugins/embeddable/public'; // Our own setup and start contract values export type InfraClientSetupExports = void; @@ -35,6 +36,7 @@ export interface InfraClientSetupDeps { observability: ObservabilityPluginSetup; triggersActionsUi: TriggersAndActionsUIPublicPluginSetup; usageCollection: UsageCollectionSetup; + ml: MlPluginSetup; embeddable: EmbeddableSetup; } @@ -46,6 +48,7 @@ export interface InfraClientStartDeps { triggersActionsUi: TriggersAndActionsUIPublicPluginStart; usageCollection: UsageCollectionStart; ml: MlPluginStart; + embeddable?: EmbeddableStart; } export type InfraClientCoreSetup = CoreSetup; diff --git a/x-pack/plugins/infra/public/utils/fixtures/metrics_explorer.ts b/x-pack/plugins/infra/public/utils/fixtures/metrics_explorer.ts index 6d8f9ae476044..27648b6d7b193 100644 --- a/x-pack/plugins/infra/public/utils/fixtures/metrics_explorer.ts +++ b/x-pack/plugins/infra/public/utils/fixtures/metrics_explorer.ts @@ -40,6 +40,7 @@ export const source = { message: ['message'], tiebreaker: '@timestamp', }, + anomalyThreshold: 20, }; export const chartOptions: MetricsExplorerChartOptions = { diff --git a/x-pack/plugins/infra/public/utils/use_url_state.ts b/x-pack/plugins/infra/public/utils/use_url_state.ts index fd927bb5ef662..970b3a20b2951 100644 --- a/x-pack/plugins/infra/public/utils/use_url_state.ts +++ b/x-pack/plugins/infra/public/utils/use_url_state.ts @@ -38,15 +38,13 @@ export const useUrlState = ({ return getParamFromQueryString(queryString, urlStateKey); }, [queryString, urlStateKey]); - const decodedState = useMemo(() => decodeUrlState(decodeRisonUrlState(urlStateString)), [ - decodeUrlState, - urlStateString, - ]); - - const state = useMemo(() => (typeof decodedState !== 'undefined' ? decodedState : defaultState), [ - defaultState, - decodedState, - ]); + const decodedState = useMemo(() => { + return decodeUrlState(decodeRisonUrlState(urlStateString)); + }, [decodeUrlState, urlStateString]); + + const state = useMemo(() => { + return typeof decodedState !== 'undefined' ? decodedState : defaultState; + }, [defaultState, decodedState]); const setState = useCallback( (newState: State | undefined) => { diff --git a/x-pack/plugins/infra/server/infra_server.ts b/x-pack/plugins/infra/server/infra_server.ts index 00ec36d866624..8a6f22d55750e 100644 --- a/x-pack/plugins/infra/server/infra_server.ts +++ b/x-pack/plugins/infra/server/infra_server.ts @@ -12,7 +12,6 @@ import { initGetLogEntryCategoryDatasetsRoute, initGetLogEntryCategoryDatasetsStatsRoute, initGetLogEntryCategoryExamplesRoute, - initGetLogEntryRateRoute, initGetLogEntryExamplesRoute, initValidateLogAnalysisDatasetsRoute, initValidateLogAnalysisIndicesRoute, @@ -46,7 +45,6 @@ export const initInfraServer = (libs: InfraBackendLibs) => { initGetLogEntryCategoryDatasetsRoute(libs); initGetLogEntryCategoryDatasetsStatsRoute(libs); initGetLogEntryCategoryExamplesRoute(libs); - initGetLogEntryRateRoute(libs); initGetLogEntryAnomaliesRoute(libs); initGetLogEntryAnomaliesDatasetsRoute(libs); initGetK8sAnomaliesRoute(libs); diff --git a/x-pack/plugins/infra/server/lib/alerting/common/messages.ts b/x-pack/plugins/infra/server/lib/alerting/common/messages.ts index 9f0be1679448f..b692629209849 100644 --- a/x-pack/plugins/infra/server/lib/alerting/common/messages.ts +++ b/x-pack/plugins/infra/server/lib/alerting/common/messages.ts @@ -19,6 +19,9 @@ export const stateToAlertMessage = { [AlertStates.ALERT]: i18n.translate('xpack.infra.metrics.alerting.threshold.alertState', { defaultMessage: 'ALERT', }), + [AlertStates.WARNING]: i18n.translate('xpack.infra.metrics.alerting.threshold.warningState', { + defaultMessage: 'WARNING', + }), [AlertStates.NO_DATA]: i18n.translate('xpack.infra.metrics.alerting.threshold.noDataState', { defaultMessage: 'NO DATA', }), diff --git a/x-pack/plugins/infra/server/lib/alerting/common/types.ts b/x-pack/plugins/infra/server/lib/alerting/common/types.ts index e4db2600e316d..0b809429de0d2 100644 --- a/x-pack/plugins/infra/server/lib/alerting/common/types.ts +++ b/x-pack/plugins/infra/server/lib/alerting/common/types.ts @@ -29,6 +29,15 @@ export enum Aggregators { export enum AlertStates { OK, ALERT, + WARNING, NO_DATA, ERROR, } + +export interface PreviewResult { + fired: number; + warning: number; + noData: number; + error: number; + notifications: number; +} diff --git a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/evaluate_condition.ts b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/evaluate_condition.ts index 16f74d579969a..ea37f7adda7c4 100644 --- a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/evaluate_condition.ts +++ b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/evaluate_condition.ts @@ -26,6 +26,7 @@ import { getNodes } from '../../../routes/snapshot/lib/get_nodes'; type ConditionResult = InventoryMetricConditions & { shouldFire: boolean[]; + shouldWarn: boolean[]; currentValue: number; isNoData: boolean[]; isError: boolean; @@ -39,8 +40,8 @@ export const evaluateCondition = async ( filterQuery?: string, lookbackSize?: number ): Promise> => { - const { comparator, metric, customMetric } = condition; - let { threshold } = condition; + const { comparator, warningComparator, metric, customMetric } = condition; + let { threshold, warningThreshold } = condition; const timerange = { to: Date.now(), @@ -62,19 +63,22 @@ export const evaluateCondition = async ( ); threshold = threshold.map((n) => convertMetricValue(metric, n)); - - const comparisonFunction = comparatorMap[comparator]; + warningThreshold = warningThreshold?.map((n) => convertMetricValue(metric, n)); + + const valueEvaluator = (value?: DataValue, t?: number[], c?: Comparator) => { + if (value === undefined || value === null || !t || !c) return [false]; + const comparisonFunction = comparatorMap[c]; + return Array.isArray(value) + ? value.map((v) => comparisonFunction(Number(v), t)) + : [comparisonFunction(value as number, t)]; + }; const result = mapValues(currentValues, (value) => { if (isTooManyBucketsPreviewException(value)) throw value; return { ...condition, - shouldFire: - value !== undefined && - value !== null && - (Array.isArray(value) - ? value.map((v) => comparisonFunction(Number(v), threshold)) - : [comparisonFunction(value as number, threshold)]), + shouldFire: valueEvaluator(value, threshold, comparator), + shouldWarn: valueEvaluator(value, warningThreshold, warningComparator), isNoData: Array.isArray(value) ? value.map((v) => v === null) : [value === null], isError: value === undefined, currentValue: getCurrentValue(value), @@ -90,6 +94,7 @@ const getCurrentValue: (value: any) => number = (value) => { return NaN; }; +type DataValue = number | null | Array; const getData = async ( callCluster: AlertServices['callCluster'], nodeType: InventoryItemType, diff --git a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/inventory_metric_threshold_executor.ts b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/inventory_metric_threshold_executor.ts index 2658fa6820274..a15f1010194a5 100644 --- a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/inventory_metric_threshold_executor.ts +++ b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/inventory_metric_threshold_executor.ts @@ -81,6 +81,7 @@ export const createInventoryMetricThresholdExecutor = (libs: InfraBackendLibs) = // Grab the result of the most recent bucket last(result[item].shouldFire) ); + const shouldAlertWarn = results.every((result) => last(result[item].shouldWarn)); // AND logic; because we need to evaluate all criteria, if one of them reports no data then the // whole alert is in a No Data/Error state @@ -93,12 +94,20 @@ export const createInventoryMetricThresholdExecutor = (libs: InfraBackendLibs) = ? AlertStates.NO_DATA : shouldAlertFire ? AlertStates.ALERT + : shouldAlertWarn + ? AlertStates.WARNING : AlertStates.OK; let reason; - if (nextState === AlertStates.ALERT) { + if (nextState === AlertStates.ALERT || nextState === AlertStates.WARNING) { reason = results - .map((result) => buildReasonWithVerboseMetricName(result[item], buildFiredAlertReason)) + .map((result) => + buildReasonWithVerboseMetricName( + result[item], + buildFiredAlertReason, + nextState === AlertStates.WARNING + ) + ) .join('\n'); } else if (nextState === AlertStates.OK && prevState?.alertState === AlertStates.ALERT) { /* @@ -125,7 +134,11 @@ export const createInventoryMetricThresholdExecutor = (libs: InfraBackendLibs) = } if (reason) { const actionGroupId = - nextState === AlertStates.OK ? RecoveredActionGroup.id : FIRED_ACTIONS_ID; + nextState === AlertStates.OK + ? RecoveredActionGroup.id + : nextState === AlertStates.WARNING + ? WARNING_ACTIONS.id + : FIRED_ACTIONS.id; alertInstance.scheduleActions( /** * TODO: We're lying to the compiler here as explicitly calling `scheduleActions` on @@ -152,7 +165,11 @@ export const createInventoryMetricThresholdExecutor = (libs: InfraBackendLibs) = } }; -const buildReasonWithVerboseMetricName = (resultItem: any, buildReason: (r: any) => string) => { +const buildReasonWithVerboseMetricName = ( + resultItem: any, + buildReason: (r: any) => string, + useWarningThreshold?: boolean +) => { if (!resultItem) return ''; const resultWithVerboseMetricName = { ...resultItem, @@ -162,6 +179,8 @@ const buildReasonWithVerboseMetricName = (resultItem: any, buildReason: (r: any) ? getCustomMetricLabel(resultItem.customMetric) : resultItem.metric), currentValue: formatMetric(resultItem.metric, resultItem.currentValue), + threshold: useWarningThreshold ? resultItem.warningThreshold! : resultItem.threshold, + comparator: useWarningThreshold ? resultItem.warningComparator! : resultItem.comparator, }; return buildReason(resultWithVerboseMetricName); }; @@ -177,11 +196,18 @@ const mapToConditionsLookup = ( {} ); -export const FIRED_ACTIONS_ID = 'metrics.invenotry_threshold.fired'; +export const FIRED_ACTIONS_ID = 'metrics.inventory_threshold.fired'; export const FIRED_ACTIONS: ActionGroup = { id: FIRED_ACTIONS_ID, name: i18n.translate('xpack.infra.metrics.alerting.inventory.threshold.fired', { - defaultMessage: 'Fired', + defaultMessage: 'Alert', + }), +}; +export const WARNING_ACTIONS_ID = 'metrics.inventory_threshold.warning'; +export const WARNING_ACTIONS = { + id: WARNING_ACTIONS_ID, + name: i18n.translate('xpack.infra.metrics.alerting.threshold.warning', { + defaultMessage: 'Warning', }), }; diff --git a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/preview_inventory_metric_threshold_alert.ts b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/preview_inventory_metric_threshold_alert.ts index 528c0f92d20e7..5fff76260e5c6 100644 --- a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/preview_inventory_metric_threshold_alert.ts +++ b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/preview_inventory_metric_threshold_alert.ts @@ -7,6 +7,7 @@ import { Unit } from '@elastic/datemath'; import { first } from 'lodash'; +import { PreviewResult } from '../common/types'; import { InventoryMetricConditions } from './types'; import { TOO_MANY_BUCKETS_PREVIEW_EXCEPTION, @@ -35,7 +36,9 @@ interface PreviewInventoryMetricThresholdAlertParams { alertOnNoData: boolean; } -export const previewInventoryMetricThresholdAlert = async ({ +export const previewInventoryMetricThresholdAlert: ( + params: PreviewInventoryMetricThresholdAlertParams +) => Promise = async ({ callCluster, params, source, @@ -43,7 +46,7 @@ export const previewInventoryMetricThresholdAlert = async ({ alertInterval, alertThrottle, alertOnNoData, -}: PreviewInventoryMetricThresholdAlertParams) => { +}) => { const { criteria, filterQuery, nodeType } = params as InventoryMetricThresholdParams; if (criteria.length === 0) throw new Error('Cannot execute an alert with 0 conditions'); @@ -74,6 +77,7 @@ export const previewInventoryMetricThresholdAlert = async ({ const numberOfResultBuckets = lookbackSize; const numberOfExecutionBuckets = Math.floor(numberOfResultBuckets / alertResultsPerExecution); let numberOfTimesFired = 0; + let numberOfTimesWarned = 0; let numberOfNoDataResults = 0; let numberOfErrors = 0; let numberOfNotifications = 0; @@ -88,6 +92,9 @@ export const previewInventoryMetricThresholdAlert = async ({ const shouldFire = result[item].shouldFire as boolean[]; return shouldFire[mappedBucketIndex]; }); + const allConditionsWarnInMappedBucket = + !allConditionsFiredInMappedBucket && + results.every((result) => result[item].shouldWarn[mappedBucketIndex]); const someConditionsNoDataInMappedBucket = results.some((result) => { const hasNoData = result[item].isNoData as boolean[]; return hasNoData[mappedBucketIndex]; @@ -108,6 +115,9 @@ export const previewInventoryMetricThresholdAlert = async ({ } else if (allConditionsFiredInMappedBucket) { numberOfTimesFired++; notifyWithThrottle(); + } else if (allConditionsWarnInMappedBucket) { + numberOfTimesWarned++; + notifyWithThrottle(); } else if (throttleTracker > 0) { throttleTracker++; } @@ -115,7 +125,13 @@ export const previewInventoryMetricThresholdAlert = async ({ throttleTracker = 0; } } - return [numberOfTimesFired, numberOfNoDataResults, numberOfErrors, numberOfNotifications]; + return { + fired: numberOfTimesFired, + warning: numberOfTimesWarned, + noData: numberOfNoDataResults, + error: numberOfErrors, + notifications: numberOfNotifications, + }; }); return previewResults; diff --git a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/register_inventory_metric_threshold_alert_type.ts b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/register_inventory_metric_threshold_alert_type.ts index 4ae1a0e4d5d49..6c439225d9d00 100644 --- a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/register_inventory_metric_threshold_alert_type.ts +++ b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/register_inventory_metric_threshold_alert_type.ts @@ -7,11 +7,17 @@ import { schema } from '@kbn/config-schema'; import { i18n } from '@kbn/i18n'; -import { AlertType, AlertInstanceState, AlertInstanceContext } from '../../../../../alerts/server'; +import { + AlertType, + AlertInstanceState, + AlertInstanceContext, + ActionGroupIdsOf, +} from '../../../../../alerts/server'; import { createInventoryMetricThresholdExecutor, FIRED_ACTIONS, FIRED_ACTIONS_ID, + WARNING_ACTIONS, } from './inventory_metric_threshold_executor'; import { METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID, Comparator } from './types'; import { InfraBackendLibs } from '../../infra_types'; @@ -25,7 +31,6 @@ import { metricActionVariableDescription, thresholdActionVariableDescription, } from '../common/messages'; -import { RecoveredActionGroupId } from '../../../../../alerts/common'; const condition = schema.object({ threshold: schema.arrayOf(schema.number()), @@ -33,6 +38,8 @@ const condition = schema.object({ timeUnit: schema.string(), timeSize: schema.number(), metric: schema.string(), + warningThreshold: schema.maybe(schema.arrayOf(schema.number())), + warningComparator: schema.maybe(oneOfLiterals(Object.values(Comparator))), customMetric: schema.maybe( schema.object({ type: schema.literal('custom'), @@ -44,7 +51,9 @@ const condition = schema.object({ ), }); -export type InventoryMetricThresholdAllowedActionGroups = typeof FIRED_ACTIONS_ID; +export type InventoryMetricThresholdAllowedActionGroups = ActionGroupIdsOf< + typeof FIRED_ACTIONS | typeof WARNING_ACTIONS +>; export const registerMetricInventoryThresholdAlertType = ( libs: InfraBackendLibs @@ -56,8 +65,7 @@ export const registerMetricInventoryThresholdAlertType = ( Record, AlertInstanceState, AlertInstanceContext, - InventoryMetricThresholdAllowedActionGroups, - RecoveredActionGroupId + InventoryMetricThresholdAllowedActionGroups > => ({ id: METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID, name: i18n.translate('xpack.infra.metrics.inventory.alertName', { @@ -78,7 +86,7 @@ export const registerMetricInventoryThresholdAlertType = ( ), }, defaultActionGroupId: FIRED_ACTIONS_ID, - actionGroups: [FIRED_ACTIONS], + actionGroups: [FIRED_ACTIONS, WARNING_ACTIONS], producer: 'infrastructure', minimumLicenseRequired: 'basic', executor: createInventoryMetricThresholdExecutor(libs), diff --git a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/types.ts b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/types.ts index 28c41de9b10d6..120fa47c079ab 100644 --- a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/types.ts +++ b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/types.ts @@ -22,4 +22,6 @@ export interface InventoryMetricConditions { threshold: number[]; comparator: Comparator; customMetric?: SnapshotCustomMetricInput; + warningThreshold?: number[]; + warningComparator?: Comparator; } diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_anomaly/evaluate_condition.ts b/x-pack/plugins/infra/server/lib/alerting/metric_anomaly/evaluate_condition.ts new file mode 100644 index 0000000000000..b7ef8ec7d2312 --- /dev/null +++ b/x-pack/plugins/infra/server/lib/alerting/metric_anomaly/evaluate_condition.ts @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { MetricAnomalyParams } from '../../../../common/alerting/metrics'; +import { getMetricsHostsAnomalies, getMetricK8sAnomalies } from '../../infra_ml'; +import { MlSystem, MlAnomalyDetectors } from '../../../types'; + +type ConditionParams = Omit & { + spaceId: string; + startTime: number; + endTime: number; + mlSystem: MlSystem; + mlAnomalyDetectors: MlAnomalyDetectors; +}; + +export const evaluateCondition = async ({ + nodeType, + spaceId, + sourceId, + mlSystem, + mlAnomalyDetectors, + startTime, + endTime, + metric, + threshold, + influencerFilter, +}: ConditionParams) => { + const getAnomalies = nodeType === 'k8s' ? getMetricK8sAnomalies : getMetricsHostsAnomalies; + + const result = await getAnomalies( + { + spaceId, + mlSystem, + mlAnomalyDetectors, + }, + sourceId ?? 'default', + threshold, + startTime, + endTime, + metric, + { field: 'anomalyScore', direction: 'desc' }, + { pageSize: 100 }, + influencerFilter + ); + + return result; +}; diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_anomaly/metric_anomaly_executor.ts b/x-pack/plugins/infra/server/lib/alerting/metric_anomaly/metric_anomaly_executor.ts new file mode 100644 index 0000000000000..ec95aac7268ad --- /dev/null +++ b/x-pack/plugins/infra/server/lib/alerting/metric_anomaly/metric_anomaly_executor.ts @@ -0,0 +1,142 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +import { first } from 'lodash'; +import moment from 'moment'; +import { stateToAlertMessage } from '../common/messages'; +import { MetricAnomalyParams } from '../../../../common/alerting/metrics'; +import { MappedAnomalyHit } from '../../infra_ml'; +import { AlertStates } from '../common/types'; +import { + ActionGroup, + AlertInstanceContext, + AlertInstanceState, +} from '../../../../../alerts/common'; +import { AlertExecutorOptions } from '../../../../../alerts/server'; +import { getIntervalInSeconds } from '../../../utils/get_interval_in_seconds'; +import { MetricAnomalyAllowedActionGroups } from './register_metric_anomaly_alert_type'; +import { MlPluginSetup } from '../../../../../ml/server'; +import { KibanaRequest } from '../../../../../../../src/core/server'; +import { InfraBackendLibs } from '../../infra_types'; +import { evaluateCondition } from './evaluate_condition'; + +export const createMetricAnomalyExecutor = (libs: InfraBackendLibs, ml?: MlPluginSetup) => async ({ + services, + params, + startedAt, +}: AlertExecutorOptions< + /** + * TODO: Remove this use of `any` by utilizing a proper type + */ + Record, + Record, + AlertInstanceState, + AlertInstanceContext, + MetricAnomalyAllowedActionGroups +>) => { + if (!ml) { + return; + } + const request = {} as KibanaRequest; + const mlSystem = ml.mlSystemProvider(request, services.savedObjectsClient); + const mlAnomalyDetectors = ml.anomalyDetectorsProvider(request, services.savedObjectsClient); + + const { + metric, + alertInterval, + influencerFilter, + sourceId, + nodeType, + threshold, + } = params as MetricAnomalyParams; + + const alertInstance = services.alertInstanceFactory(`${nodeType}-${metric}`); + + const bucketInterval = getIntervalInSeconds('15m') * 1000; + const alertIntervalInMs = getIntervalInSeconds(alertInterval ?? '1m') * 1000; + + const endTime = startedAt.getTime(); + // Anomalies are bucketed at :00, :15, :30, :45 minutes every hour + const previousBucketStartTime = endTime - (endTime % bucketInterval); + + // If the alert interval is less than 15m, make sure that it actually queries an anomaly bucket + const startTime = Math.min(endTime - alertIntervalInMs, previousBucketStartTime); + + const { data } = await evaluateCondition({ + sourceId: sourceId ?? 'default', + spaceId: 'default', + mlSystem, + mlAnomalyDetectors, + startTime, + endTime, + metric, + threshold, + nodeType, + influencerFilter, + }); + + const shouldAlertFire = data.length > 0; + + if (shouldAlertFire) { + const { startTime: anomalyStartTime, anomalyScore, actual, typical, influencers } = first( + data as MappedAnomalyHit[] + )!; + + alertInstance.scheduleActions(FIRED_ACTIONS_ID, { + alertState: stateToAlertMessage[AlertStates.ALERT], + timestamp: moment(anomalyStartTime).toISOString(), + anomalyScore, + actual, + typical, + metric: metricNameMap[metric], + summary: generateSummaryMessage(actual, typical), + influencers: influencers.join(', '), + }); + } +}; + +export const FIRED_ACTIONS_ID = 'metrics.anomaly.fired'; +export const FIRED_ACTIONS: ActionGroup = { + id: FIRED_ACTIONS_ID, + name: i18n.translate('xpack.infra.metrics.alerting.anomaly.fired', { + defaultMessage: 'Fired', + }), +}; + +const generateSummaryMessage = (actual: number, typical: number) => { + const differential = (Math.max(actual, typical) / Math.min(actual, typical)) + .toFixed(1) + .replace('.0', ''); + if (actual > typical) { + return i18n.translate('xpack.infra.metrics.alerting.anomaly.summaryHigher', { + defaultMessage: '{differential}x higher', + values: { + differential, + }, + }); + } else { + return i18n.translate('xpack.infra.metrics.alerting.anomaly.summaryLower', { + defaultMessage: '{differential}x lower', + values: { + differential, + }, + }); + } +}; + +const metricNameMap = { + memory_usage: i18n.translate('xpack.infra.metrics.alerting.anomaly.memoryUsage', { + defaultMessage: 'Memory usage', + }), + network_in: i18n.translate('xpack.infra.metrics.alerting.anomaly.networkIn', { + defaultMessage: 'Network in', + }), + network_out: i18n.translate('xpack.infra.metrics.alerting.anomaly.networkOut', { + defaultMessage: 'Network out', + }), +}; diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_anomaly/preview_metric_anomaly_alert.ts b/x-pack/plugins/infra/server/lib/alerting/metric_anomaly/preview_metric_anomaly_alert.ts new file mode 100644 index 0000000000000..98992701e3bb4 --- /dev/null +++ b/x-pack/plugins/infra/server/lib/alerting/metric_anomaly/preview_metric_anomaly_alert.ts @@ -0,0 +1,120 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Unit } from '@elastic/datemath'; +import { countBy } from 'lodash'; +import { MappedAnomalyHit } from '../../infra_ml'; +import { MlSystem, MlAnomalyDetectors } from '../../../types'; +import { MetricAnomalyParams } from '../../../../common/alerting/metrics'; +import { + TOO_MANY_BUCKETS_PREVIEW_EXCEPTION, + isTooManyBucketsPreviewException, +} from '../../../../common/alerting/metrics'; +import { getIntervalInSeconds } from '../../../utils/get_interval_in_seconds'; +import { evaluateCondition } from './evaluate_condition'; + +interface PreviewMetricAnomalyAlertParams { + mlSystem: MlSystem; + mlAnomalyDetectors: MlAnomalyDetectors; + spaceId: string; + params: MetricAnomalyParams; + sourceId: string; + lookback: Unit; + alertInterval: string; + alertThrottle: string; + alertOnNoData: boolean; +} + +export const previewMetricAnomalyAlert = async ({ + mlSystem, + mlAnomalyDetectors, + spaceId, + params, + sourceId, + lookback, + alertInterval, + alertThrottle, +}: PreviewMetricAnomalyAlertParams) => { + const { metric, threshold, influencerFilter, nodeType } = params as MetricAnomalyParams; + + const alertIntervalInSeconds = getIntervalInSeconds(alertInterval); + const throttleIntervalInSeconds = getIntervalInSeconds(alertThrottle); + const executionsPerThrottle = Math.floor(throttleIntervalInSeconds / alertIntervalInSeconds); + + const lookbackInterval = `1${lookback}`; + const lookbackIntervalInSeconds = getIntervalInSeconds(lookbackInterval); + const endTime = Date.now(); + const startTime = endTime - lookbackIntervalInSeconds * 1000; + + const numberOfExecutions = Math.floor(lookbackIntervalInSeconds / alertIntervalInSeconds); + const bucketIntervalInSeconds = getIntervalInSeconds('15m'); + const bucketsPerExecution = Math.max( + 1, + Math.floor(alertIntervalInSeconds / bucketIntervalInSeconds) + ); + + try { + let anomalies: MappedAnomalyHit[] = []; + const { data } = await evaluateCondition({ + nodeType, + spaceId, + sourceId, + mlSystem, + mlAnomalyDetectors, + startTime, + endTime, + metric, + threshold, + influencerFilter, + }); + anomalies = [...anomalies, ...data]; + + const anomaliesByTime = countBy(anomalies, ({ startTime: anomStartTime }) => anomStartTime); + + let numberOfTimesFired = 0; + let numberOfNotifications = 0; + let throttleTracker = 0; + const notifyWithThrottle = () => { + if (throttleTracker === 0) numberOfNotifications++; + throttleTracker++; + }; + // Mock each alert evaluation + for (let i = 0; i < numberOfExecutions; i++) { + const executionTime = startTime + alertIntervalInSeconds * 1000 * i; + // Get an array of bucket times this mock alert evaluation will be looking at + // Anomalies are bucketed at :00, :15, :30, :45 minutes every hour, + // so this is an array of how many of those times occurred between this evaluation + // and the previous one + const bucketsLookedAt = Array.from(Array(bucketsPerExecution), (_, idx) => { + const previousBucketStartTime = + executionTime - + (executionTime % (bucketIntervalInSeconds * 1000)) - + idx * bucketIntervalInSeconds * 1000; + return previousBucketStartTime; + }); + const anomaliesDetectedInBuckets = bucketsLookedAt.some((bucketTime) => + Reflect.has(anomaliesByTime, bucketTime) + ); + + if (anomaliesDetectedInBuckets) { + numberOfTimesFired++; + notifyWithThrottle(); + } else if (throttleTracker > 0) { + throttleTracker++; + } + if (throttleTracker === executionsPerThrottle) { + throttleTracker = 0; + } + } + + return { fired: numberOfTimesFired, notifications: numberOfNotifications }; + } catch (e) { + if (!isTooManyBucketsPreviewException(e)) throw e; + const { maxBuckets } = e; + throw new Error(`${TOO_MANY_BUCKETS_PREVIEW_EXCEPTION}:${maxBuckets}`); + } +}; diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_anomaly/register_metric_anomaly_alert_type.ts b/x-pack/plugins/infra/server/lib/alerting/metric_anomaly/register_metric_anomaly_alert_type.ts new file mode 100644 index 0000000000000..8ac62c125515a --- /dev/null +++ b/x-pack/plugins/infra/server/lib/alerting/metric_anomaly/register_metric_anomaly_alert_type.ts @@ -0,0 +1,110 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { schema } from '@kbn/config-schema'; +import { i18n } from '@kbn/i18n'; +import { MlPluginSetup } from '../../../../../ml/server'; +import { AlertType, AlertInstanceState, AlertInstanceContext } from '../../../../../alerts/server'; +import { + createMetricAnomalyExecutor, + FIRED_ACTIONS, + FIRED_ACTIONS_ID, +} from './metric_anomaly_executor'; +import { METRIC_ANOMALY_ALERT_TYPE_ID } from '../../../../common/alerting/metrics'; +import { InfraBackendLibs } from '../../infra_types'; +import { oneOfLiterals, validateIsStringElasticsearchJSONFilter } from '../common/utils'; +import { alertStateActionVariableDescription } from '../common/messages'; +import { RecoveredActionGroupId } from '../../../../../alerts/common'; + +export type MetricAnomalyAllowedActionGroups = typeof FIRED_ACTIONS_ID; + +export const registerMetricAnomalyAlertType = ( + libs: InfraBackendLibs, + ml?: MlPluginSetup +): AlertType< + /** + * TODO: Remove this use of `any` by utilizing a proper type + */ + Record, + Record, + AlertInstanceState, + AlertInstanceContext, + MetricAnomalyAllowedActionGroups, + RecoveredActionGroupId +> => ({ + id: METRIC_ANOMALY_ALERT_TYPE_ID, + name: i18n.translate('xpack.infra.metrics.anomaly.alertName', { + defaultMessage: 'Infrastructure anomaly', + }), + validate: { + params: schema.object( + { + nodeType: oneOfLiterals(['hosts', 'k8s']), + alertInterval: schema.string(), + metric: oneOfLiterals(['memory_usage', 'network_in', 'network_out']), + threshold: schema.number(), + filterQuery: schema.maybe( + schema.string({ validate: validateIsStringElasticsearchJSONFilter }) + ), + sourceId: schema.string(), + }, + { unknowns: 'allow' } + ), + }, + defaultActionGroupId: FIRED_ACTIONS_ID, + actionGroups: [FIRED_ACTIONS], + producer: 'infrastructure', + minimumLicenseRequired: 'basic', + executor: createMetricAnomalyExecutor(libs, ml), + actionVariables: { + context: [ + { name: 'alertState', description: alertStateActionVariableDescription }, + { + name: 'metric', + description: i18n.translate('xpack.infra.metrics.alerting.anomalyMetricDescription', { + defaultMessage: 'The metric name in the specified condition.', + }), + }, + { + name: 'timestamp', + description: i18n.translate('xpack.infra.metrics.alerting.anomalyTimestampDescription', { + defaultMessage: 'A timestamp of when the anomaly was detected.', + }), + }, + { + name: 'anomalyScore', + description: i18n.translate('xpack.infra.metrics.alerting.anomalyScoreDescription', { + defaultMessage: 'The exact severity score of the detected anomaly.', + }), + }, + { + name: 'actual', + description: i18n.translate('xpack.infra.metrics.alerting.anomalyActualDescription', { + defaultMessage: 'The actual value of the monitored metric at the time of the anomaly.', + }), + }, + { + name: 'typical', + description: i18n.translate('xpack.infra.metrics.alerting.anomalyTypicalDescription', { + defaultMessage: 'The typical value of the monitored metric at the time of the anomaly.', + }), + }, + { + name: 'summary', + description: i18n.translate('xpack.infra.metrics.alerting.anomalySummaryDescription', { + defaultMessage: 'A description of the anomaly, e.g. "2x higher."', + }), + }, + { + name: 'influencers', + description: i18n.translate('xpack.infra.metrics.alerting.anomalyInfluencersDescription', { + defaultMessage: 'A list of node names that influenced the anomaly.', + }), + }, + ], + }, +}); diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/evaluate_alert.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/evaluate_alert.ts index f9661e2cd56bb..029445a441eea 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/evaluate_alert.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/evaluate_alert.ts @@ -60,8 +60,17 @@ export const evaluateAlert = { + if (!t || !c) return [false]; + const comparisonFunction = comparatorMap[c]; + return Array.isArray(points) + ? points.map( + (point) => t && typeof point.value === 'number' && comparisonFunction(point.value, t) + ) + : [false]; + }; + return mapValues(currentValues, (points: any[] | typeof NaN | null) => { if (isTooManyBucketsPreviewException(points)) throw points; return { @@ -69,12 +78,8 @@ export const evaluateAlert = - typeof point.value === 'number' && comparisonFunction(point.value, threshold) - ) - : [false], + shouldFire: pointsEvaluator(points, threshold, comparator), + shouldWarn: pointsEvaluator(points, warningThreshold, warningComparator), isNoData: Array.isArray(points) ? points.map((point) => point?.value === null || point === null) : [points === null], diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.ts index 17b9ab1cab907..b822d71b3f812 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.ts @@ -18,7 +18,7 @@ import { stateToAlertMessage, } from '../common/messages'; import { createFormatter } from '../../../../common/formatters'; -import { AlertStates } from './types'; +import { AlertStates, Comparator } from './types'; import { evaluateAlert, EvaluatedAlertParams } from './lib/evaluate_alert'; import { MetricThresholdAlertExecutorOptions, @@ -60,6 +60,7 @@ export const createMetricThresholdExecutor = ( // Grab the result of the most recent bucket last(result[group].shouldFire) ); + const shouldAlertWarn = alertResults.every((result) => last(result[group].shouldWarn)); // AND logic; because we need to evaluate all criteria, if one of them reports no data then the // whole alert is in a No Data/Error state const isNoData = alertResults.some((result) => last(result[group].isNoData)); @@ -71,12 +72,18 @@ export const createMetricThresholdExecutor = ( ? AlertStates.NO_DATA : shouldAlertFire ? AlertStates.ALERT + : shouldAlertWarn + ? AlertStates.WARNING : AlertStates.OK; let reason; - if (nextState === AlertStates.ALERT) { + if (nextState === AlertStates.ALERT || nextState === AlertStates.WARNING) { reason = alertResults - .map((result) => buildFiredAlertReason(formatAlertResult(result[group]))) + .map((result) => + buildFiredAlertReason( + formatAlertResult(result[group], nextState === AlertStates.WARNING) + ) + ) .join('\n'); } else if (nextState === AlertStates.OK && prevState?.alertState === AlertStates.ALERT) { /* @@ -105,7 +112,11 @@ export const createMetricThresholdExecutor = ( const firstResult = first(alertResults); const timestamp = (firstResult && firstResult[group].timestamp) ?? moment().toISOString(); const actionGroupId = - nextState === AlertStates.OK ? RecoveredActionGroup.id : FIRED_ACTIONS.id; + nextState === AlertStates.OK + ? RecoveredActionGroup.id + : nextState === AlertStates.WARNING + ? WARNING_ACTIONS.id + : FIRED_ACTIONS.id; alertInstance.scheduleActions(actionGroupId, { group, alertState: stateToAlertMessage[nextState], @@ -132,7 +143,14 @@ export const createMetricThresholdExecutor = ( export const FIRED_ACTIONS = { id: 'metrics.threshold.fired', name: i18n.translate('xpack.infra.metrics.alerting.threshold.fired', { - defaultMessage: 'Fired', + defaultMessage: 'Alert', + }), +}; + +export const WARNING_ACTIONS = { + id: 'metrics.threshold.warning', + name: i18n.translate('xpack.infra.metrics.alerting.threshold.warning', { + defaultMessage: 'Warning', }), }; @@ -152,9 +170,20 @@ const formatAlertResult = ( metric: string; currentValue: number; threshold: number[]; - } & AlertResult + comparator: Comparator; + warningThreshold?: number[]; + warningComparator?: Comparator; + } & AlertResult, + useWarningThreshold?: boolean ) => { - const { metric, currentValue, threshold } = alertResult; + const { + metric, + currentValue, + threshold, + comparator, + warningThreshold, + warningComparator, + } = alertResult; const noDataValue = i18n.translate( 'xpack.infra.metrics.alerting.threshold.noDataFormattedValue', { @@ -167,12 +196,17 @@ const formatAlertResult = ( currentValue: currentValue ?? noDataValue, }; const formatter = createFormatter('percent'); + const thresholdToFormat = useWarningThreshold ? warningThreshold! : threshold; + const comparatorToFormat = useWarningThreshold ? warningComparator! : comparator; return { ...alertResult, currentValue: currentValue !== null && typeof currentValue !== 'undefined' ? formatter(currentValue) : noDataValue, - threshold: Array.isArray(threshold) ? threshold.map((v: number) => formatter(v)) : threshold, + threshold: Array.isArray(thresholdToFormat) + ? thresholdToFormat.map((v: number) => formatter(v)) + : thresholdToFormat, + comparator: comparatorToFormat, }; }; diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/preview_metric_threshold_alert.test.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/preview_metric_threshold_alert.test.ts index 8576fd7b59299..1adca25504b1f 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/preview_metric_threshold_alert.test.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/preview_metric_threshold_alert.test.ts @@ -20,10 +20,10 @@ describe('Previewing the metric threshold alert type', () => { alertThrottle: '1m', alertOnNoData: true, }); - const [firedResults, noDataResults, errorResults, notifications] = ungroupedResult; - expect(firedResults).toBe(30); - expect(noDataResults).toBe(0); - expect(errorResults).toBe(0); + const { fired, noData, error, notifications } = ungroupedResult; + expect(fired).toBe(30); + expect(noData).toBe(0); + expect(error).toBe(0); expect(notifications).toBe(30); }); @@ -35,10 +35,10 @@ describe('Previewing the metric threshold alert type', () => { alertThrottle: '3m', alertOnNoData: true, }); - const [firedResults, noDataResults, errorResults, notifications] = ungroupedResult; - expect(firedResults).toBe(10); - expect(noDataResults).toBe(0); - expect(errorResults).toBe(0); + const { fired, noData, error, notifications } = ungroupedResult; + expect(fired).toBe(10); + expect(noData).toBe(0); + expect(error).toBe(0); expect(notifications).toBe(10); }); test('returns the expected results using a bucket interval longer than the alert interval', async () => { @@ -49,10 +49,10 @@ describe('Previewing the metric threshold alert type', () => { alertThrottle: '30s', alertOnNoData: true, }); - const [firedResults, noDataResults, errorResults, notifications] = ungroupedResult; - expect(firedResults).toBe(60); - expect(noDataResults).toBe(0); - expect(errorResults).toBe(0); + const { fired, noData, error, notifications } = ungroupedResult; + expect(fired).toBe(60); + expect(noData).toBe(0); + expect(error).toBe(0); expect(notifications).toBe(60); }); test('returns the expected results using a throttle interval longer than the alert interval', async () => { @@ -63,10 +63,10 @@ describe('Previewing the metric threshold alert type', () => { alertThrottle: '3m', alertOnNoData: true, }); - const [firedResults, noDataResults, errorResults, notifications] = ungroupedResult; - expect(firedResults).toBe(30); - expect(noDataResults).toBe(0); - expect(errorResults).toBe(0); + const { fired, noData, error, notifications } = ungroupedResult; + expect(fired).toBe(30); + expect(noData).toBe(0); + expect(error).toBe(0); expect(notifications).toBe(15); }); }); @@ -83,15 +83,25 @@ describe('Previewing the metric threshold alert type', () => { alertThrottle: '1m', alertOnNoData: true, }); - const [firedResultsA, noDataResultsA, errorResultsA, notificationsA] = resultA; - expect(firedResultsA).toBe(30); - expect(noDataResultsA).toBe(0); - expect(errorResultsA).toBe(0); + const { + fired: firedA, + noData: noDataA, + error: errorA, + notifications: notificationsA, + } = resultA; + expect(firedA).toBe(30); + expect(noDataA).toBe(0); + expect(errorA).toBe(0); expect(notificationsA).toBe(30); - const [firedResultsB, noDataResultsB, errorResultsB, notificationsB] = resultB; - expect(firedResultsB).toBe(60); - expect(noDataResultsB).toBe(0); - expect(errorResultsB).toBe(0); + const { + fired: firedB, + noData: noDataB, + error: errorB, + notifications: notificationsB, + } = resultB; + expect(firedB).toBe(60); + expect(noDataB).toBe(0); + expect(errorB).toBe(0); expect(notificationsB).toBe(60); }); }); @@ -113,10 +123,10 @@ describe('Previewing the metric threshold alert type', () => { alertThrottle: '1m', alertOnNoData: true, }); - const [firedResults, noDataResults, errorResults, notifications] = ungroupedResult; - expect(firedResults).toBe(25); - expect(noDataResults).toBe(10); - expect(errorResults).toBe(0); + const { fired, noData, error, notifications } = ungroupedResult; + expect(fired).toBe(25); + expect(noData).toBe(10); + expect(error).toBe(0); expect(notifications).toBe(35); }); }); diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/preview_metric_threshold_alert.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/preview_metric_threshold_alert.ts index ac6372a94b1fe..b9fa6659d5fcd 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/preview_metric_threshold_alert.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/preview_metric_threshold_alert.ts @@ -14,6 +14,7 @@ import { import { ILegacyScopedClusterClient } from '../../../../../../../src/core/server'; import { InfraSource } from '../../../../common/http_api/source_api'; import { getIntervalInSeconds } from '../../../utils/get_interval_in_seconds'; +import { PreviewResult } from '../common/types'; import { MetricExpressionParams } from './types'; import { evaluateAlert } from './lib/evaluate_alert'; @@ -39,7 +40,7 @@ export const previewMetricThresholdAlert: ( params: PreviewMetricThresholdAlertParams, iterations?: number, precalculatedNumberOfGroups?: number -) => Promise = async ( +) => Promise = async ( { callCluster, params, @@ -98,6 +99,7 @@ export const previewMetricThresholdAlert: ( numberOfResultBuckets / alertResultsPerExecution ); let numberOfTimesFired = 0; + let numberOfTimesWarned = 0; let numberOfNoDataResults = 0; let numberOfErrors = 0; let numberOfNotifications = 0; @@ -111,6 +113,9 @@ export const previewMetricThresholdAlert: ( const allConditionsFiredInMappedBucket = alertResults.every( (alertResult) => alertResult[group].shouldFire[mappedBucketIndex] ); + const allConditionsWarnInMappedBucket = + !allConditionsFiredInMappedBucket && + alertResults.every((alertResult) => alertResult[group].shouldWarn[mappedBucketIndex]); const someConditionsNoDataInMappedBucket = alertResults.some((alertResult) => { const hasNoData = alertResult[group].isNoData as boolean[]; return hasNoData[mappedBucketIndex]; @@ -131,6 +136,9 @@ export const previewMetricThresholdAlert: ( } else if (allConditionsFiredInMappedBucket) { numberOfTimesFired++; notifyWithThrottle(); + } else if (allConditionsWarnInMappedBucket) { + numberOfTimesWarned++; + notifyWithThrottle(); } else if (throttleTracker > 0) { throttleTracker += alertIntervalInSeconds; } @@ -138,7 +146,13 @@ export const previewMetricThresholdAlert: ( throttleTracker = 0; } } - return [numberOfTimesFired, numberOfNoDataResults, numberOfErrors, numberOfNotifications]; + return { + fired: numberOfTimesFired, + warning: numberOfTimesWarned, + noData: numberOfNoDataResults, + error: numberOfErrors, + notifications: numberOfNotifications, + }; }) ); return previewResults; @@ -199,7 +213,12 @@ export const previewMetricThresholdAlert: ( .reduce((a, b) => { if (!a) return b; if (!b) return a; - return [a[0] + b[0], a[1] + b[1], a[2] + b[2], a[3] + b[3]]; + const res = { ...a }; + const entries = (Object.entries(b) as unknown) as Array<[keyof PreviewResult, number]>; + for (const [key, value] of entries) { + res[key] += value; + } + return res; }) ); return zippedResult; diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/register_metric_threshold_alert_type.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/register_metric_threshold_alert_type.ts index 6d8790f4f430c..e5e3a7bff329e 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/register_metric_threshold_alert_type.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/register_metric_threshold_alert_type.ts @@ -15,7 +15,11 @@ import { ActionGroupIdsOf, } from '../../../../../alerts/server'; import { METRIC_EXPLORER_AGGREGATIONS } from '../../../../common/http_api/metrics_explorer'; -import { createMetricThresholdExecutor, FIRED_ACTIONS } from './metric_threshold_executor'; +import { + createMetricThresholdExecutor, + FIRED_ACTIONS, + WARNING_ACTIONS, +} from './metric_threshold_executor'; import { METRIC_THRESHOLD_ALERT_TYPE_ID, Comparator } from './types'; import { InfraBackendLibs } from '../../infra_types'; import { oneOfLiterals, validateIsStringElasticsearchJSONFilter } from '../common/utils'; @@ -37,7 +41,7 @@ export type MetricThresholdAlertType = AlertType< Record, AlertInstanceState, AlertInstanceContext, - ActionGroupIdsOf + ActionGroupIdsOf >; export type MetricThresholdAlertExecutorOptions = AlertExecutorOptions< /** @@ -47,7 +51,7 @@ export type MetricThresholdAlertExecutorOptions = AlertExecutorOptions< Record, AlertInstanceState, AlertInstanceContext, - ActionGroupIdsOf + ActionGroupIdsOf >; export function registerMetricThresholdAlertType(libs: InfraBackendLibs): MetricThresholdAlertType { @@ -56,6 +60,8 @@ export function registerMetricThresholdAlertType(libs: InfraBackendLibs): Metric comparator: oneOfLiterals(Object.values(Comparator)), timeUnit: schema.string(), timeSize: schema.number(), + warningThreshold: schema.maybe(schema.arrayOf(schema.number())), + warningComparator: schema.maybe(oneOfLiterals(Object.values(Comparator))), }; const nonCountCriterion = schema.object({ @@ -92,7 +98,7 @@ export function registerMetricThresholdAlertType(libs: InfraBackendLibs): Metric ), }, defaultActionGroupId: FIRED_ACTIONS.id, - actionGroups: [FIRED_ACTIONS], + actionGroups: [FIRED_ACTIONS, WARNING_ACTIONS], minimumLicenseRequired: 'basic', executor: createMetricThresholdExecutor(libs), actionVariables: { diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/types.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/types.ts index f876e40d9cd1f..37f21022f183d 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/types.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/types.ts @@ -29,6 +29,8 @@ interface BaseMetricExpressionParams { sourceId?: string; threshold: number[]; comparator: Comparator; + warningComparator?: Comparator; + warningThreshold?: number[]; } interface NonCountMetricExpressionParams extends BaseMetricExpressionParams { diff --git a/x-pack/plugins/infra/server/lib/alerting/register_alert_types.ts b/x-pack/plugins/infra/server/lib/alerting/register_alert_types.ts index 0b4df6805759e..11fbe269b854d 100644 --- a/x-pack/plugins/infra/server/lib/alerting/register_alert_types.ts +++ b/x-pack/plugins/infra/server/lib/alerting/register_alert_types.ts @@ -8,13 +8,21 @@ import { PluginSetupContract } from '../../../../alerts/server'; import { registerMetricThresholdAlertType } from './metric_threshold/register_metric_threshold_alert_type'; import { registerMetricInventoryThresholdAlertType } from './inventory_metric_threshold/register_inventory_metric_threshold_alert_type'; +import { registerMetricAnomalyAlertType } from './metric_anomaly/register_metric_anomaly_alert_type'; + import { registerLogThresholdAlertType } from './log_threshold/register_log_threshold_alert_type'; import { InfraBackendLibs } from '../infra_types'; +import { MlPluginSetup } from '../../../../ml/server'; -const registerAlertTypes = (alertingPlugin: PluginSetupContract, libs: InfraBackendLibs) => { +const registerAlertTypes = ( + alertingPlugin: PluginSetupContract, + libs: InfraBackendLibs, + ml?: MlPluginSetup +) => { if (alertingPlugin) { alertingPlugin.registerType(registerMetricThresholdAlertType(libs)); alertingPlugin.registerType(registerMetricInventoryThresholdAlertType(libs)); + alertingPlugin.registerType(registerMetricAnomalyAlertType(libs, ml)); const registerFns = [registerLogThresholdAlertType]; registerFns.forEach((fn) => { diff --git a/x-pack/plugins/infra/server/lib/infra_ml/common.ts b/x-pack/plugins/infra/server/lib/infra_ml/common.ts index 0182cb0e4099a..686f27d714cc1 100644 --- a/x-pack/plugins/infra/server/lib/infra_ml/common.ts +++ b/x-pack/plugins/infra/server/lib/infra_ml/common.ts @@ -17,6 +17,23 @@ import { import { decodeOrThrow } from '../../../common/runtime_types'; import { startTracingSpan, TracingSpan } from '../../../common/performance_tracing'; +export interface MappedAnomalyHit { + id: string; + anomalyScore: number; + typical: number; + actual: number; + jobId: string; + startTime: number; + duration: number; + influencers: string[]; + categoryId?: string; +} + +export interface InfluencerFilter { + fieldName: string; + fieldValue: string; +} + export async function fetchMlJob(mlAnomalyDetectors: MlAnomalyDetectors, jobId: string) { const finalizeMlGetJobSpan = startTracingSpan('Fetch ml job from ES'); const { diff --git a/x-pack/plugins/infra/server/lib/infra_ml/index.ts b/x-pack/plugins/infra/server/lib/infra_ml/index.ts index d346b71d76aa8..82093b1a359d0 100644 --- a/x-pack/plugins/infra/server/lib/infra_ml/index.ts +++ b/x-pack/plugins/infra/server/lib/infra_ml/index.ts @@ -8,3 +8,4 @@ export * from './errors'; export * from './metrics_hosts_anomalies'; export * from './metrics_k8s_anomalies'; +export { MappedAnomalyHit } from './common'; diff --git a/x-pack/plugins/infra/server/lib/infra_ml/metrics_hosts_anomalies.ts b/x-pack/plugins/infra/server/lib/infra_ml/metrics_hosts_anomalies.ts index 072f07dfaffdb..f6e11f5294191 100644 --- a/x-pack/plugins/infra/server/lib/infra_ml/metrics_hosts_anomalies.ts +++ b/x-pack/plugins/infra/server/lib/infra_ml/metrics_hosts_anomalies.ts @@ -5,11 +5,10 @@ * 2.0. */ -import type { InfraPluginRequestHandlerContext } from '../../types'; import { InfraRequestHandlerContext } from '../../types'; import { TracingSpan, startTracingSpan } from '../../../common/performance_tracing'; -import { fetchMlJob } from './common'; -import { getJobId, metricsHostsJobTypes } from '../../../common/infra_ml'; +import { fetchMlJob, MappedAnomalyHit, InfluencerFilter } from './common'; +import { getJobId, metricsHostsJobTypes, ANOMALY_THRESHOLD } from '../../../common/infra_ml'; import { Sort, Pagination } from '../../../common/http_api/infra_ml'; import type { MlSystem, MlAnomalyDetectors } from '../../types'; import { InsufficientAnomalyMlJobsConfigured, isMlPrivilegesError } from './errors'; @@ -19,18 +18,6 @@ import { createMetricsHostsAnomaliesQuery, } from './queries/metrics_hosts_anomalies'; -interface MappedAnomalyHit { - id: string; - anomalyScore: number; - typical: number; - actual: number; - jobId: string; - startTime: number; - duration: number; - influencers: string[]; - categoryId?: string; -} - async function getCompatibleAnomaliesJobIds( spaceId: string, sourceId: string, @@ -74,13 +61,15 @@ async function getCompatibleAnomaliesJobIds( } export async function getMetricsHostsAnomalies( - context: InfraPluginRequestHandlerContext & { infra: Required }, + context: Required, sourceId: string, + anomalyThreshold: ANOMALY_THRESHOLD, startTime: number, endTime: number, metric: 'memory_usage' | 'network_in' | 'network_out' | undefined, sort: Sort, - pagination: Pagination + pagination: Pagination, + influencerFilter?: InfluencerFilter ) { const finalizeMetricsHostsAnomaliesSpan = startTracingSpan('get metrics hosts entry anomalies'); @@ -88,10 +77,10 @@ export async function getMetricsHostsAnomalies( jobIds, timing: { spans: jobSpans }, } = await getCompatibleAnomaliesJobIds( - context.infra.spaceId, + context.spaceId, sourceId, metric, - context.infra.mlAnomalyDetectors + context.mlAnomalyDetectors ); if (jobIds.length === 0) { @@ -107,12 +96,14 @@ export async function getMetricsHostsAnomalies( hasMoreEntries, timing: { spans: fetchLogEntryAnomaliesSpans }, } = await fetchMetricsHostsAnomalies( - context.infra.mlSystem, + context.mlSystem, + anomalyThreshold, jobIds, startTime, endTime, sort, - pagination + pagination, + influencerFilter ); const data = anomalies.map((anomaly) => { @@ -162,11 +153,13 @@ const parseAnomalyResult = (anomaly: MappedAnomalyHit, jobId: string) => { async function fetchMetricsHostsAnomalies( mlSystem: MlSystem, + anomalyThreshold: ANOMALY_THRESHOLD, jobIds: string[], startTime: number, endTime: number, sort: Sort, - pagination: Pagination + pagination: Pagination, + influencerFilter?: InfluencerFilter ) { // We'll request 1 extra entry on top of our pageSize to determine if there are // more entries to be fetched. This avoids scenarios where the client side can't @@ -178,7 +171,15 @@ async function fetchMetricsHostsAnomalies( const results = decodeOrThrow(metricsHostsAnomaliesResponseRT)( await mlSystem.mlAnomalySearch( - createMetricsHostsAnomaliesQuery(jobIds, startTime, endTime, sort, expandedPagination), + createMetricsHostsAnomaliesQuery({ + jobIds, + anomalyThreshold, + startTime, + endTime, + sort, + pagination: expandedPagination, + influencerFilter, + }), jobIds ) ); diff --git a/x-pack/plugins/infra/server/lib/infra_ml/metrics_k8s_anomalies.ts b/x-pack/plugins/infra/server/lib/infra_ml/metrics_k8s_anomalies.ts index 44837d88ddb43..34039e9107f00 100644 --- a/x-pack/plugins/infra/server/lib/infra_ml/metrics_k8s_anomalies.ts +++ b/x-pack/plugins/infra/server/lib/infra_ml/metrics_k8s_anomalies.ts @@ -5,11 +5,10 @@ * 2.0. */ -import type { InfraPluginRequestHandlerContext } from '../../types'; import { InfraRequestHandlerContext } from '../../types'; import { TracingSpan, startTracingSpan } from '../../../common/performance_tracing'; -import { fetchMlJob } from './common'; -import { getJobId, metricsK8SJobTypes } from '../../../common/infra_ml'; +import { fetchMlJob, MappedAnomalyHit, InfluencerFilter } from './common'; +import { getJobId, metricsK8SJobTypes, ANOMALY_THRESHOLD } from '../../../common/infra_ml'; import { Sort, Pagination } from '../../../common/http_api/infra_ml'; import type { MlSystem, MlAnomalyDetectors } from '../../types'; import { InsufficientAnomalyMlJobsConfigured, isMlPrivilegesError } from './errors'; @@ -19,18 +18,6 @@ import { createMetricsK8sAnomaliesQuery, } from './queries/metrics_k8s_anomalies'; -interface MappedAnomalyHit { - id: string; - anomalyScore: number; - typical: number; - actual: number; - jobId: string; - startTime: number; - influencers: string[]; - duration: number; - categoryId?: string; -} - async function getCompatibleAnomaliesJobIds( spaceId: string, sourceId: string, @@ -74,13 +61,15 @@ async function getCompatibleAnomaliesJobIds( } export async function getMetricK8sAnomalies( - context: InfraPluginRequestHandlerContext & { infra: Required }, + context: Required, sourceId: string, + anomalyThreshold: ANOMALY_THRESHOLD, startTime: number, endTime: number, metric: 'memory_usage' | 'network_in' | 'network_out' | undefined, sort: Sort, - pagination: Pagination + pagination: Pagination, + influencerFilter?: InfluencerFilter ) { const finalizeMetricsK8sAnomaliesSpan = startTracingSpan('get metrics k8s entry anomalies'); @@ -88,10 +77,10 @@ export async function getMetricK8sAnomalies( jobIds, timing: { spans: jobSpans }, } = await getCompatibleAnomaliesJobIds( - context.infra.spaceId, + context.spaceId, sourceId, metric, - context.infra.mlAnomalyDetectors + context.mlAnomalyDetectors ); if (jobIds.length === 0) { @@ -106,12 +95,14 @@ export async function getMetricK8sAnomalies( hasMoreEntries, timing: { spans: fetchLogEntryAnomaliesSpans }, } = await fetchMetricK8sAnomalies( - context.infra.mlSystem, + context.mlSystem, + anomalyThreshold, jobIds, startTime, endTime, sort, - pagination + pagination, + influencerFilter ); const data = anomalies.map((anomaly) => { @@ -158,11 +149,13 @@ const parseAnomalyResult = (anomaly: MappedAnomalyHit, jobId: string) => { async function fetchMetricK8sAnomalies( mlSystem: MlSystem, + anomalyThreshold: ANOMALY_THRESHOLD, jobIds: string[], startTime: number, endTime: number, sort: Sort, - pagination: Pagination + pagination: Pagination, + influencerFilter?: InfluencerFilter | undefined ) { // We'll request 1 extra entry on top of our pageSize to determine if there are // more entries to be fetched. This avoids scenarios where the client side can't @@ -174,7 +167,15 @@ async function fetchMetricK8sAnomalies( const results = decodeOrThrow(metricsK8sAnomaliesResponseRT)( await mlSystem.mlAnomalySearch( - createMetricsK8sAnomaliesQuery(jobIds, startTime, endTime, sort, expandedPagination), + createMetricsK8sAnomaliesQuery({ + jobIds, + anomalyThreshold, + startTime, + endTime, + sort, + pagination: expandedPagination, + influencerFilter, + }), jobIds ) ); diff --git a/x-pack/plugins/infra/server/lib/infra_ml/queries/common.ts b/x-pack/plugins/infra/server/lib/infra_ml/queries/common.ts index b3676fc54aeaa..6f996a672a44a 100644 --- a/x-pack/plugins/infra/server/lib/infra_ml/queries/common.ts +++ b/x-pack/plugins/infra/server/lib/infra_ml/queries/common.ts @@ -77,3 +77,35 @@ export const createDatasetsFilters = (datasets?: string[]) => }, ] : []; + +export const createInfluencerFilter = ({ + fieldName, + fieldValue, +}: { + fieldName: string; + fieldValue: string; +}) => [ + { + nested: { + path: 'influencers', + query: { + bool: { + must: [ + { + match: { + 'influencers.influencer_field_name': fieldName, + }, + }, + { + query_string: { + fields: ['influencers.influencer_field_values'], + query: fieldValue, + minimum_should_match: 1, + }, + }, + ], + }, + }, + }, + }, +]; diff --git a/x-pack/plugins/infra/server/lib/infra_ml/queries/metrics_host_anomalies.test.ts b/x-pack/plugins/infra/server/lib/infra_ml/queries/metrics_host_anomalies.test.ts new file mode 100644 index 0000000000000..4c3e0ca8bc26f --- /dev/null +++ b/x-pack/plugins/infra/server/lib/infra_ml/queries/metrics_host_anomalies.test.ts @@ -0,0 +1,63 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createMetricsHostsAnomaliesQuery } from './metrics_hosts_anomalies'; +import { Sort, Pagination } from '../../../../common/http_api/infra_ml'; + +describe('createMetricsHostAnomaliesQuery', () => { + const jobIds = ['kibana-metrics-ui-default-default-hosts_memory_usage']; + const anomalyThreshold = 30; + const startTime = 1612454527112; + const endTime = 1612541227112; + const sort: Sort = { field: 'anomalyScore', direction: 'desc' }; + const pagination: Pagination = { pageSize: 101 }; + + test('returns the correct query', () => { + expect( + createMetricsHostsAnomaliesQuery({ + jobIds, + anomalyThreshold, + startTime, + endTime, + sort, + pagination, + }) + ).toMatchObject({ + allowNoIndices: true, + ignoreUnavailable: true, + trackScores: false, + trackTotalHits: false, + body: { + query: { + bool: { + filter: [ + { terms: { job_id: ['kibana-metrics-ui-default-default-hosts_memory_usage'] } }, + { range: { record_score: { gte: 30 } } }, + { range: { timestamp: { gte: 1612454527112, lte: 1612541227112 } } }, + { terms: { result_type: ['record'] } }, + ], + }, + }, + sort: [{ record_score: 'desc' }, { _doc: 'desc' }], + size: 101, + _source: [ + 'job_id', + 'record_score', + 'typical', + 'actual', + 'partition_field_value', + 'timestamp', + 'bucket_span', + 'by_field_value', + 'host.name', + 'influencers.influencer_field_name', + 'influencers.influencer_field_values', + ], + }, + }); + }); +}); diff --git a/x-pack/plugins/infra/server/lib/infra_ml/queries/metrics_hosts_anomalies.ts b/x-pack/plugins/infra/server/lib/infra_ml/queries/metrics_hosts_anomalies.ts index 07b25931d838e..7808851508a7c 100644 --- a/x-pack/plugins/infra/server/lib/infra_ml/queries/metrics_hosts_anomalies.ts +++ b/x-pack/plugins/infra/server/lib/infra_ml/queries/metrics_hosts_anomalies.ts @@ -6,6 +6,7 @@ */ import * as rt from 'io-ts'; +import { ANOMALY_THRESHOLD } from '../../../../common/infra_ml'; import { commonSearchSuccessResponseFieldsRT } from '../../../utils/elasticsearch_runtime_types'; import { createJobIdsFilters, @@ -13,7 +14,9 @@ import { createResultTypeFilters, defaultRequestParameters, createAnomalyScoreFilter, + createInfluencerFilter, } from './common'; +import { InfluencerFilter } from '../common'; import { Sort, Pagination } from '../../../../common/http_api/infra_ml'; // TODO: Reassess validity of this against ML docs @@ -25,23 +28,37 @@ const sortToMlFieldMap = { startTime: 'timestamp', }; -export const createMetricsHostsAnomaliesQuery = ( - jobIds: string[], - startTime: number, - endTime: number, - sort: Sort, - pagination: Pagination -) => { +export const createMetricsHostsAnomaliesQuery = ({ + jobIds, + anomalyThreshold, + startTime, + endTime, + sort, + pagination, + influencerFilter, +}: { + jobIds: string[]; + anomalyThreshold: ANOMALY_THRESHOLD; + startTime: number; + endTime: number; + sort: Sort; + pagination: Pagination; + influencerFilter?: InfluencerFilter; +}) => { const { field } = sort; const { pageSize } = pagination; const filters = [ ...createJobIdsFilters(jobIds), - ...createAnomalyScoreFilter(50), + ...createAnomalyScoreFilter(anomalyThreshold), ...createTimeRangeFilters(startTime, endTime), ...createResultTypeFilters(['record']), ]; + const influencerQuery = influencerFilter + ? { must: createInfluencerFilter(influencerFilter) } + : {}; + const sourceFields = [ 'job_id', 'record_score', @@ -69,6 +86,7 @@ export const createMetricsHostsAnomaliesQuery = ( query: { bool: { filter: filters, + ...influencerQuery, }, }, search_after: queryCursor, diff --git a/x-pack/plugins/infra/server/lib/infra_ml/queries/metrics_k8s_anomalies.test.ts b/x-pack/plugins/infra/server/lib/infra_ml/queries/metrics_k8s_anomalies.test.ts new file mode 100644 index 0000000000000..81dcb390dff56 --- /dev/null +++ b/x-pack/plugins/infra/server/lib/infra_ml/queries/metrics_k8s_anomalies.test.ts @@ -0,0 +1,62 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createMetricsK8sAnomaliesQuery } from './metrics_k8s_anomalies'; +import { Sort, Pagination } from '../../../../common/http_api/infra_ml'; + +describe('createMetricsK8sAnomaliesQuery', () => { + const jobIds = ['kibana-metrics-ui-default-default-k8s_memory_usage']; + const anomalyThreshold = 30; + const startTime = 1612454527112; + const endTime = 1612541227112; + const sort: Sort = { field: 'anomalyScore', direction: 'desc' }; + const pagination: Pagination = { pageSize: 101 }; + + test('returns the correct query', () => { + expect( + createMetricsK8sAnomaliesQuery({ + jobIds, + anomalyThreshold, + startTime, + endTime, + sort, + pagination, + }) + ).toMatchObject({ + allowNoIndices: true, + ignoreUnavailable: true, + trackScores: false, + trackTotalHits: false, + body: { + query: { + bool: { + filter: [ + { terms: { job_id: ['kibana-metrics-ui-default-default-k8s_memory_usage'] } }, + { range: { record_score: { gte: 30 } } }, + { range: { timestamp: { gte: 1612454527112, lte: 1612541227112 } } }, + { terms: { result_type: ['record'] } }, + ], + }, + }, + sort: [{ record_score: 'desc' }, { _doc: 'desc' }], + size: 101, + _source: [ + 'job_id', + 'record_score', + 'typical', + 'actual', + 'partition_field_value', + 'timestamp', + 'bucket_span', + 'by_field_value', + 'influencers.influencer_field_name', + 'influencers.influencer_field_values', + ], + }, + }); + }); +}); diff --git a/x-pack/plugins/infra/server/lib/infra_ml/queries/metrics_k8s_anomalies.ts b/x-pack/plugins/infra/server/lib/infra_ml/queries/metrics_k8s_anomalies.ts index 8a6e9396fb098..54eea067177ed 100644 --- a/x-pack/plugins/infra/server/lib/infra_ml/queries/metrics_k8s_anomalies.ts +++ b/x-pack/plugins/infra/server/lib/infra_ml/queries/metrics_k8s_anomalies.ts @@ -6,6 +6,7 @@ */ import * as rt from 'io-ts'; +import { ANOMALY_THRESHOLD } from '../../../../common/infra_ml'; import { commonSearchSuccessResponseFieldsRT } from '../../../utils/elasticsearch_runtime_types'; import { createJobIdsFilters, @@ -13,7 +14,9 @@ import { createResultTypeFilters, defaultRequestParameters, createAnomalyScoreFilter, + createInfluencerFilter, } from './common'; +import { InfluencerFilter } from '../common'; import { Sort, Pagination } from '../../../../common/http_api/infra_ml'; // TODO: Reassess validity of this against ML docs @@ -25,23 +28,37 @@ const sortToMlFieldMap = { startTime: 'timestamp', }; -export const createMetricsK8sAnomaliesQuery = ( - jobIds: string[], - startTime: number, - endTime: number, - sort: Sort, - pagination: Pagination -) => { +export const createMetricsK8sAnomaliesQuery = ({ + jobIds, + anomalyThreshold, + startTime, + endTime, + sort, + pagination, + influencerFilter, +}: { + jobIds: string[]; + anomalyThreshold: ANOMALY_THRESHOLD; + startTime: number; + endTime: number; + sort: Sort; + pagination: Pagination; + influencerFilter?: InfluencerFilter; +}) => { const { field } = sort; const { pageSize } = pagination; const filters = [ ...createJobIdsFilters(jobIds), - ...createAnomalyScoreFilter(50), + ...createAnomalyScoreFilter(anomalyThreshold), ...createTimeRangeFilters(startTime, endTime), ...createResultTypeFilters(['record']), ]; + const influencerQuery = influencerFilter + ? { must: createInfluencerFilter(influencerFilter) } + : {}; + const sourceFields = [ 'job_id', 'record_score', @@ -68,6 +85,7 @@ export const createMetricsK8sAnomaliesQuery = ( query: { bool: { filter: filters, + ...influencerQuery, }, }, search_after: queryCursor, diff --git a/x-pack/plugins/infra/server/lib/log_analysis/log_entry_anomalies.ts b/x-pack/plugins/infra/server/lib/log_analysis/log_entry_anomalies.ts index 3fc098bcf8846..f5465a967f2a5 100644 --- a/x-pack/plugins/infra/server/lib/log_analysis/log_entry_anomalies.ts +++ b/x-pack/plugins/infra/server/lib/log_analysis/log_entry_anomalies.ts @@ -281,7 +281,6 @@ async function fetchLogEntryAnomalies( nextPageCursor: hits[hits.length - 1].sort, } : undefined; - const anomalies = hits.map((result) => { const { // eslint-disable-next-line @typescript-eslint/naming-convention diff --git a/x-pack/plugins/infra/server/lib/sources/defaults.ts b/x-pack/plugins/infra/server/lib/sources/defaults.ts index ce7c4410baca9..1b924619a905c 100644 --- a/x-pack/plugins/infra/server/lib/sources/defaults.ts +++ b/x-pack/plugins/infra/server/lib/sources/defaults.ts @@ -45,4 +45,5 @@ export const defaultSourceConfiguration: InfraSourceConfiguration = { }, }, ], + anomalyThreshold: 50, }; diff --git a/x-pack/plugins/infra/server/lib/sources/errors.ts b/x-pack/plugins/infra/server/lib/sources/errors.ts index fb0dc3b031511..082dfc611cc5b 100644 --- a/x-pack/plugins/infra/server/lib/sources/errors.ts +++ b/x-pack/plugins/infra/server/lib/sources/errors.ts @@ -4,10 +4,17 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - +/* eslint-disable max-classes-per-file */ export class NotFoundError extends Error { constructor(message?: string) { super(message); Object.setPrototypeOf(this, new.target.prototype); } } + +export class AnomalyThresholdRangeError extends Error { + constructor(message?: string) { + super(message); + Object.setPrototypeOf(this, new.target.prototype); + } +} diff --git a/x-pack/plugins/infra/server/lib/sources/migrations/7_9_0_add_new_indexing_strategy_index_names.test.ts b/x-pack/plugins/infra/server/lib/sources/migrations/7_9_0_add_new_indexing_strategy_index_names.test.ts index 4cea6cbe32cfb..21b7643ca6a7f 100644 --- a/x-pack/plugins/infra/server/lib/sources/migrations/7_9_0_add_new_indexing_strategy_index_names.test.ts +++ b/x-pack/plugins/infra/server/lib/sources/migrations/7_9_0_add_new_indexing_strategy_index_names.test.ts @@ -126,6 +126,7 @@ const createTestSourceConfiguration = (logAlias: string, metricAlias: string) => ], logAlias, metricAlias, + anomalyThreshold: 20, }, id: 'TEST_ID', type: infraSourceConfigurationSavedObjectName, diff --git a/x-pack/plugins/infra/server/lib/sources/sources.ts b/x-pack/plugins/infra/server/lib/sources/sources.ts index aad877a077acf..fe005b04978da 100644 --- a/x-pack/plugins/infra/server/lib/sources/sources.ts +++ b/x-pack/plugins/infra/server/lib/sources/sources.ts @@ -10,9 +10,10 @@ import { failure } from 'io-ts/lib/PathReporter'; import { identity, constant } from 'fp-ts/lib/function'; import { pipe } from 'fp-ts/lib/pipeable'; import { map, fold } from 'fp-ts/lib/Either'; +import { inRange } from 'lodash'; import { SavedObjectsClientContract } from 'src/core/server'; import { defaultSourceConfiguration } from './defaults'; -import { NotFoundError } from './errors'; +import { AnomalyThresholdRangeError, NotFoundError } from './errors'; import { infraSourceConfigurationSavedObjectName } from './saved_object_type'; import { InfraSavedSourceConfiguration, @@ -104,6 +105,9 @@ export class InfraSources { source: InfraSavedSourceConfiguration ) { const staticDefaultSourceConfiguration = await this.getStaticDefaultSourceConfiguration(); + const { anomalyThreshold } = source; + if (anomalyThreshold && !inRange(anomalyThreshold, 0, 101)) + throw new AnomalyThresholdRangeError('anomalyThreshold must be 1-100'); const newSourceConfiguration = mergeSourceConfiguration( staticDefaultSourceConfiguration, @@ -140,6 +144,10 @@ export class InfraSources { sourceProperties: InfraSavedSourceConfiguration ) { const staticDefaultSourceConfiguration = await this.getStaticDefaultSourceConfiguration(); + const { anomalyThreshold } = sourceProperties; + + if (anomalyThreshold && !inRange(anomalyThreshold, 0, 101)) + throw new AnomalyThresholdRangeError('anomalyThreshold must be 1-100'); const { configuration, version } = await this.getSourceConfiguration( savedObjectsClient, diff --git a/x-pack/plugins/infra/server/plugin.ts b/x-pack/plugins/infra/server/plugin.ts index 99555fa56acd5..0ac49e05b36b9 100644 --- a/x-pack/plugins/infra/server/plugin.ts +++ b/x-pack/plugins/infra/server/plugin.ts @@ -137,7 +137,7 @@ export class InfraServerPlugin implements Plugin { ]); initInfraServer(this.libs); - registerAlertTypes(plugins.alerts, this.libs); + registerAlertTypes(plugins.alerts, this.libs, plugins.ml); core.http.registerRouteHandlerContext( 'infra', diff --git a/x-pack/plugins/infra/server/routes/alerting/preview.ts b/x-pack/plugins/infra/server/routes/alerting/preview.ts index ba16221108958..3da560135eaf4 100644 --- a/x-pack/plugins/infra/server/routes/alerting/preview.ts +++ b/x-pack/plugins/infra/server/routes/alerting/preview.ts @@ -5,20 +5,25 @@ * 2.0. */ +import { PreviewResult } from '../../lib/alerting/common/types'; import { METRIC_THRESHOLD_ALERT_TYPE_ID, METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID, + METRIC_ANOMALY_ALERT_TYPE_ID, INFRA_ALERT_PREVIEW_PATH, TOO_MANY_BUCKETS_PREVIEW_EXCEPTION, alertPreviewRequestParamsRT, alertPreviewSuccessResponsePayloadRT, MetricThresholdAlertPreviewRequestParams, InventoryAlertPreviewRequestParams, + MetricAnomalyAlertPreviewRequestParams, } from '../../../common/alerting/metrics'; import { createValidationFunction } from '../../../common/runtime_types'; import { previewInventoryMetricThresholdAlert } from '../../lib/alerting/inventory_metric_threshold/preview_inventory_metric_threshold_alert'; import { previewMetricThresholdAlert } from '../../lib/alerting/metric_threshold/preview_metric_threshold_alert'; +import { previewMetricAnomalyAlert } from '../../lib/alerting/metric_anomaly/preview_metric_anomaly_alert'; import { InfraBackendLibs } from '../../lib/infra_types'; +import { assertHasInfraMlPlugins } from '../../utils/request_context'; export const initAlertPreviewRoute = ({ framework, sources }: InfraBackendLibs) => { const { callWithRequest } = framework; @@ -32,8 +37,6 @@ export const initAlertPreviewRoute = ({ framework, sources }: InfraBackendLibs) }, framework.router.handleLegacyErrors(async (requestContext, request, response) => { const { - criteria, - filterQuery, lookback, sourceId, alertType, @@ -54,7 +57,11 @@ export const initAlertPreviewRoute = ({ framework, sources }: InfraBackendLibs) try { switch (alertType) { case METRIC_THRESHOLD_ALERT_TYPE_ID: { - const { groupBy } = request.body as MetricThresholdAlertPreviewRequestParams; + const { + groupBy, + criteria, + filterQuery, + } = request.body as MetricThresholdAlertPreviewRequestParams; const previewResult = await previewMetricThresholdAlert({ callCluster, params: { criteria, filterQuery, groupBy }, @@ -65,33 +72,17 @@ export const initAlertPreviewRoute = ({ framework, sources }: InfraBackendLibs) alertOnNoData, }); - const numberOfGroups = previewResult.length; - const resultTotals = previewResult.reduce( - (totals, [firedResult, noDataResult, errorResult, notifications]) => { - return { - ...totals, - fired: totals.fired + firedResult, - noData: totals.noData + noDataResult, - error: totals.error + errorResult, - notifications: totals.notifications + notifications, - }; - }, - { - fired: 0, - noData: 0, - error: 0, - notifications: 0, - } - ); + const payload = processPreviewResults(previewResult); return response.ok({ - body: alertPreviewSuccessResponsePayloadRT.encode({ - numberOfGroups, - resultTotals, - }), + body: alertPreviewSuccessResponsePayloadRT.encode(payload), }); } case METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID: { - const { nodeType } = request.body as InventoryAlertPreviewRequestParams; + const { + nodeType, + criteria, + filterQuery, + } = request.body as InventoryAlertPreviewRequestParams; const previewResult = await previewInventoryMetricThresholdAlert({ callCluster, params: { criteria, filterQuery, nodeType }, @@ -102,29 +93,42 @@ export const initAlertPreviewRoute = ({ framework, sources }: InfraBackendLibs) alertOnNoData, }); - const numberOfGroups = previewResult.length; - const resultTotals = previewResult.reduce( - (totals, [firedResult, noDataResult, errorResult, notifications]) => { - return { - ...totals, - fired: totals.fired + firedResult, - noData: totals.noData + noDataResult, - error: totals.error + errorResult, - notifications: totals.notifications + notifications, - }; - }, - { - fired: 0, - noData: 0, - error: 0, - notifications: 0, - } - ); + const payload = processPreviewResults(previewResult); + + return response.ok({ + body: alertPreviewSuccessResponsePayloadRT.encode(payload), + }); + } + case METRIC_ANOMALY_ALERT_TYPE_ID: { + assertHasInfraMlPlugins(requestContext); + const { + nodeType, + metric, + threshold, + influencerFilter, + } = request.body as MetricAnomalyAlertPreviewRequestParams; + const { mlAnomalyDetectors, mlSystem, spaceId } = requestContext.infra; + + const previewResult = await previewMetricAnomalyAlert({ + mlAnomalyDetectors, + mlSystem, + spaceId, + params: { nodeType, metric, threshold, influencerFilter }, + lookback, + sourceId: source.id, + alertInterval, + alertThrottle, + alertOnNoData, + }); return response.ok({ body: alertPreviewSuccessResponsePayloadRT.encode({ - numberOfGroups, - resultTotals, + numberOfGroups: 1, + resultTotals: { + ...previewResult, + error: 0, + noData: 0, + }, }), }); } @@ -150,3 +154,27 @@ export const initAlertPreviewRoute = ({ framework, sources }: InfraBackendLibs) }) ); }; + +const processPreviewResults = (previewResult: PreviewResult[]) => { + const numberOfGroups = previewResult.length; + const resultTotals = previewResult.reduce( + (totals, { fired, warning, noData, error, notifications }) => { + return { + ...totals, + fired: totals.fired + fired, + warning: totals.warning + warning, + noData: totals.noData + noData, + error: totals.error + error, + notifications: totals.notifications + notifications, + }; + }, + { + fired: 0, + warning: 0, + noData: 0, + error: 0, + notifications: 0, + } + ); + return { numberOfGroups, resultTotals }; +}; diff --git a/x-pack/plugins/infra/server/routes/infra_ml/results/metrics_hosts_anomalies.ts b/x-pack/plugins/infra/server/routes/infra_ml/results/metrics_hosts_anomalies.ts index 215ebf3280c03..6e227cfc12d11 100644 --- a/x-pack/plugins/infra/server/routes/infra_ml/results/metrics_hosts_anomalies.ts +++ b/x-pack/plugins/infra/server/routes/infra_ml/results/metrics_hosts_anomalies.ts @@ -34,6 +34,7 @@ export const initGetHostsAnomaliesRoute = ({ framework }: InfraBackendLibs) => { const { data: { sourceId, + anomalyThreshold, timeRange: { startTime, endTime }, sort: sortParam, pagination: paginationParam, @@ -52,8 +53,9 @@ export const initGetHostsAnomaliesRoute = ({ framework }: InfraBackendLibs) => { hasMoreEntries, timing, } = await getMetricsHostsAnomalies( - requestContext, + requestContext.infra, sourceId, + anomalyThreshold, startTime, endTime, metric, diff --git a/x-pack/plugins/infra/server/routes/infra_ml/results/metrics_k8s_anomalies.ts b/x-pack/plugins/infra/server/routes/infra_ml/results/metrics_k8s_anomalies.ts index 906278be657d3..1c2c4947a02ea 100644 --- a/x-pack/plugins/infra/server/routes/infra_ml/results/metrics_k8s_anomalies.ts +++ b/x-pack/plugins/infra/server/routes/infra_ml/results/metrics_k8s_anomalies.ts @@ -33,6 +33,7 @@ export const initGetK8sAnomaliesRoute = ({ framework }: InfraBackendLibs) => { const { data: { sourceId, + anomalyThreshold, timeRange: { startTime, endTime }, sort: sortParam, pagination: paginationParam, @@ -51,8 +52,9 @@ export const initGetK8sAnomaliesRoute = ({ framework }: InfraBackendLibs) => { hasMoreEntries, timing, } = await getMetricK8sAnomalies( - requestContext, + requestContext.infra, sourceId, + anomalyThreshold, startTime, endTime, metric, diff --git a/x-pack/plugins/infra/server/routes/log_analysis/results/index.ts b/x-pack/plugins/infra/server/routes/log_analysis/results/index.ts index d50495689e9d8..23c2ce5f0c21f 100644 --- a/x-pack/plugins/infra/server/routes/log_analysis/results/index.ts +++ b/x-pack/plugins/infra/server/routes/log_analysis/results/index.ts @@ -9,7 +9,6 @@ export * from './log_entry_categories'; export * from './log_entry_category_datasets'; export * from './log_entry_category_datasets_stats'; export * from './log_entry_category_examples'; -export * from './log_entry_rate'; export * from './log_entry_examples'; export * from './log_entry_anomalies'; export * from './log_entry_anomalies_datasets'; diff --git a/x-pack/plugins/infra/server/routes/log_analysis/results/log_entry_rate.ts b/x-pack/plugins/infra/server/routes/log_analysis/results/log_entry_rate.ts deleted file mode 100644 index c1762f88a6cdd..0000000000000 --- a/x-pack/plugins/infra/server/routes/log_analysis/results/log_entry_rate.ts +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import Boom from '@hapi/boom'; -import { InfraBackendLibs } from '../../../lib/infra_types'; -import { - LOG_ANALYSIS_GET_LOG_ENTRY_RATE_PATH, - getLogEntryRateRequestPayloadRT, - getLogEntryRateSuccessReponsePayloadRT, - GetLogEntryRateSuccessResponsePayload, -} from '../../../../common/http_api/log_analysis'; -import { createValidationFunction } from '../../../../common/runtime_types'; -import { getLogEntryRateBuckets } from '../../../lib/log_analysis'; -import { assertHasInfraMlPlugins } from '../../../utils/request_context'; -import { isMlPrivilegesError } from '../../../lib/log_analysis/errors'; - -export const initGetLogEntryRateRoute = ({ framework }: InfraBackendLibs) => { - framework.registerRoute( - { - method: 'post', - path: LOG_ANALYSIS_GET_LOG_ENTRY_RATE_PATH, - validate: { - body: createValidationFunction(getLogEntryRateRequestPayloadRT), - }, - }, - framework.router.handleLegacyErrors(async (requestContext, request, response) => { - const { - data: { sourceId, timeRange, bucketDuration, datasets }, - } = request.body; - - try { - assertHasInfraMlPlugins(requestContext); - - const logEntryRateBuckets = await getLogEntryRateBuckets( - requestContext, - sourceId, - timeRange.startTime, - timeRange.endTime, - bucketDuration, - datasets - ); - - return response.ok({ - body: getLogEntryRateSuccessReponsePayloadRT.encode({ - data: { - bucketDuration, - histogramBuckets: logEntryRateBuckets, - totalNumberOfLogEntries: getTotalNumberOfLogEntries(logEntryRateBuckets), - }, - }), - }); - } catch (error) { - if (Boom.isBoom(error)) { - throw error; - } - - if (isMlPrivilegesError(error)) { - return response.customError({ - statusCode: 403, - body: { - message: error.message, - }, - }); - } - - return response.customError({ - statusCode: error.statusCode ?? 500, - body: { - message: error.message ?? 'An unexpected error occurred', - }, - }); - } - }) - ); -}; - -const getTotalNumberOfLogEntries = ( - logEntryRateBuckets: GetLogEntryRateSuccessResponsePayload['data']['histogramBuckets'] -) => { - return logEntryRateBuckets.reduce((sumNumberOfLogEntries, bucket) => { - const sumPartitions = bucket.partitions.reduce((partitionsTotal, partition) => { - return (partitionsTotal += partition.numberOfLogEntries); - }, 0); - return (sumNumberOfLogEntries += sumPartitions); - }, 0); -}; diff --git a/x-pack/plugins/infra/server/routes/source/index.ts b/x-pack/plugins/infra/server/routes/source/index.ts index f1132049bd03c..5c3827e56ce79 100644 --- a/x-pack/plugins/infra/server/routes/source/index.ts +++ b/x-pack/plugins/infra/server/routes/source/index.ts @@ -16,6 +16,7 @@ import { import { InfraBackendLibs } from '../../lib/infra_types'; import { hasData } from '../../lib/sources/has_data'; import { createSearchClient } from '../../lib/create_search_client'; +import { AnomalyThresholdRangeError } from '../../lib/sources/errors'; const typeToInfraIndexType = (value: string | undefined) => { switch (value) { @@ -137,6 +138,15 @@ export const initSourceRoute = (libs: InfraBackendLibs) => { throw error; } + if (error instanceof AnomalyThresholdRangeError) { + return response.customError({ + statusCode: 400, + body: { + message: error.message, + }, + }); + } + return response.customError({ statusCode: error.statusCode ?? 500, body: { diff --git a/x-pack/plugins/infra/server/services/log_entries/log_entries_search_strategy.test.ts b/x-pack/plugins/infra/server/services/log_entries/log_entries_search_strategy.test.ts index 16a45dc6489ee..bc4976a068f4d 100644 --- a/x-pack/plugins/infra/server/services/log_entries/log_entries_search_strategy.test.ts +++ b/x-pack/plugins/infra/server/services/log_entries/log_entries_search_strategy.test.ts @@ -279,6 +279,7 @@ const createSourceConfigurationMock = (): InfraSource => ({ timestamp: 'TIMESTAMP_FIELD', tiebreaker: 'TIEBREAKER_FIELD', }, + anomalyThreshold: 20, }, }); diff --git a/x-pack/plugins/infra/server/services/log_entries/log_entry_search_strategy.test.ts b/x-pack/plugins/infra/server/services/log_entries/log_entry_search_strategy.test.ts index 6bcc61f2be4a6..7ac8b71c04b2a 100644 --- a/x-pack/plugins/infra/server/services/log_entries/log_entry_search_strategy.test.ts +++ b/x-pack/plugins/infra/server/services/log_entries/log_entry_search_strategy.test.ts @@ -216,6 +216,7 @@ const createSourceConfigurationMock = () => ({ timestamp: 'TIMESTAMP_FIELD', tiebreaker: 'TIEBREAKER_FIELD', }, + anomalyThreshold: 20, }, }); diff --git a/x-pack/plugins/maps/common/descriptor_types/layer_descriptor_types.ts b/x-pack/plugins/maps/common/descriptor_types/layer_descriptor_types.ts index 62de8baa66d5f..7a21599605b52 100644 --- a/x-pack/plugins/maps/common/descriptor_types/layer_descriptor_types.ts +++ b/x-pack/plugins/maps/common/descriptor_types/layer_descriptor_types.ts @@ -8,7 +8,11 @@ /* eslint-disable @typescript-eslint/consistent-type-definitions */ import { Query } from 'src/plugins/data/public'; -import { StyleDescriptor, VectorStyleDescriptor } from './style_property_descriptor_types'; +import { + HeatmapStyleDescriptor, + StyleDescriptor, + VectorStyleDescriptor, +} from './style_property_descriptor_types'; import { DataRequestDescriptor } from './data_request_descriptor_types'; import { AbstractSourceDescriptor, TermJoinSourceDescriptor } from './source_descriptor_types'; @@ -40,3 +44,7 @@ export type LayerDescriptor = { export type VectorLayerDescriptor = LayerDescriptor & { style: VectorStyleDescriptor; }; + +export type HeatmapLayerDescriptor = LayerDescriptor & { + style: HeatmapStyleDescriptor; +}; diff --git a/x-pack/plugins/maps/kibana.json b/x-pack/plugins/maps/kibana.json index 744cc18c36f3e..1d4f76db79751 100644 --- a/x-pack/plugins/maps/kibana.json +++ b/x-pack/plugins/maps/kibana.json @@ -11,7 +11,7 @@ "features", "inspector", "data", - "mapsFileUpload", + "fileUpload", "uiActions", "navigation", "visualizations", @@ -25,7 +25,8 @@ ], "optionalPlugins": [ "home", - "savedObjectsTagging" + "savedObjectsTagging", + "charts" ], "ui": true, "server": true, diff --git a/x-pack/plugins/maps/public/actions/data_request_actions.ts b/x-pack/plugins/maps/public/actions/data_request_actions.ts index 2e6a8098e5c21..5e8a18348ac5a 100644 --- a/x-pack/plugins/maps/public/actions/data_request_actions.ts +++ b/x-pack/plugins/maps/public/actions/data_request_actions.ts @@ -40,7 +40,7 @@ import { UPDATE_SOURCE_DATA_REQUEST, } from './map_action_constants'; import { ILayer } from '../classes/layers/layer'; -import { IVectorLayer } from '../classes/layers/vector_layer/vector_layer'; +import { IVectorLayer } from '../classes/layers/vector_layer'; import { DataMeta, MapExtent, MapFilters } from '../../common/descriptor_types'; import { DataRequestAbortError } from '../classes/util/data_request'; import { scaleBounds, turfBboxToBounds } from '../../common/elasticsearch_util'; diff --git a/x-pack/plugins/maps/public/actions/layer_actions.ts b/x-pack/plugins/maps/public/actions/layer_actions.ts index 16aa44af4460f..d68e4744975f1 100644 --- a/x-pack/plugins/maps/public/actions/layer_actions.ts +++ b/x-pack/plugins/maps/public/actions/layer_actions.ts @@ -42,7 +42,7 @@ import { clearDataRequests, syncDataForLayerId, updateStyleMeta } from './data_r import { cleanTooltipStateForLayer } from './tooltip_actions'; import { JoinDescriptor, LayerDescriptor, StyleDescriptor } from '../../common/descriptor_types'; import { ILayer } from '../classes/layers/layer'; -import { IVectorLayer } from '../classes/layers/vector_layer/vector_layer'; +import { IVectorLayer } from '../classes/layers/vector_layer'; import { LAYER_STYLE_TYPE, LAYER_TYPE } from '../../common/constants'; import { IVectorStyle } from '../classes/styles/vector/vector_style'; import { notifyLicensedFeatureUsage } from '../licensed_features'; diff --git a/x-pack/plugins/maps/public/classes/joins/inner_join.test.js b/x-pack/plugins/maps/public/classes/joins/inner_join.test.js index 749745530af7e..67fbf94fd1787 100644 --- a/x-pack/plugins/maps/public/classes/joins/inner_join.test.js +++ b/x-pack/plugins/maps/public/classes/joins/inner_join.test.js @@ -9,7 +9,7 @@ import { InnerJoin } from './inner_join'; import { SOURCE_TYPES } from '../../../common/constants'; jest.mock('../../kibana_services', () => {}); -jest.mock('../layers/vector_layer/vector_layer', () => {}); +jest.mock('../layers/vector_layer', () => {}); const rightSource = { type: SOURCE_TYPES.ES_TERM_SOURCE, diff --git a/x-pack/plugins/maps/public/classes/layers/blended_vector_layer/blended_vector_layer.ts b/x-pack/plugins/maps/public/classes/layers/blended_vector_layer/blended_vector_layer.ts index efd022292f90b..d3a4fa4101ac9 100644 --- a/x-pack/plugins/maps/public/classes/layers/blended_vector_layer/blended_vector_layer.ts +++ b/x-pack/plugins/maps/public/classes/layers/blended_vector_layer/blended_vector_layer.ts @@ -6,7 +6,7 @@ */ import { i18n } from '@kbn/i18n'; -import { VectorLayer } from '../vector_layer/vector_layer'; +import { IVectorLayer, VectorLayer } from '../vector_layer'; import { IVectorStyle, VectorStyle } from '../../styles/vector/vector_style'; import { getDefaultDynamicProperties } from '../../styles/vector/vector_style_defaults'; import { IDynamicStyleProperty } from '../../styles/vector/properties/dynamic_style_property'; @@ -24,7 +24,6 @@ import { } from '../../../../common/constants'; import { ESGeoGridSource } from '../../sources/es_geo_grid_source/es_geo_grid_source'; import { canSkipSourceUpdate } from '../../util/can_skip_fetch'; -import { IVectorLayer } from '../vector_layer/vector_layer'; import { IESSource } from '../../sources/es_source'; import { ISource } from '../../sources/source'; import { DataRequestContext } from '../../../actions'; @@ -169,6 +168,7 @@ function getClusterStyleDescriptor( } export interface BlendedVectorLayerArguments { + chartsPaletteServiceGetColor?: (value: string) => string | null; source: IVectorSource; layerDescriptor: VectorLayerDescriptor; } @@ -205,7 +205,12 @@ export class BlendedVectorLayer extends VectorLayer implements IVectorLayer { this._documentStyle, this._clusterSource ); - this._clusterStyle = new VectorStyle(clusterStyleDescriptor, this._clusterSource, this); + this._clusterStyle = new VectorStyle( + clusterStyleDescriptor, + this._clusterSource, + this, + options.chartsPaletteServiceGetColor + ); let isClustered = false; const countDataRequest = this.getDataRequest(ACTIVE_COUNT_DATA_ID); diff --git a/x-pack/plugins/maps/public/classes/layers/choropleth_layer_wizard/create_choropleth_layer_descriptor.ts b/x-pack/plugins/maps/public/classes/layers/choropleth_layer_wizard/create_choropleth_layer_descriptor.ts index a85ba041c4351..a4955a965d77c 100644 --- a/x-pack/plugins/maps/public/classes/layers/choropleth_layer_wizard/create_choropleth_layer_descriptor.ts +++ b/x-pack/plugins/maps/public/classes/layers/choropleth_layer_wizard/create_choropleth_layer_descriptor.ts @@ -23,7 +23,7 @@ import { ESSearchSourceDescriptor, } from '../../../../common/descriptor_types'; import { VectorStyle } from '../../styles/vector/vector_style'; -import { VectorLayer } from '../vector_layer/vector_layer'; +import { VectorLayer } from '../vector_layer'; import { EMSFileSource } from '../../sources/ems_file_source'; // @ts-ignore import { ESSearchSource } from '../../sources/es_search_source'; diff --git a/x-pack/plugins/maps/public/classes/layers/create_region_map_layer_descriptor.ts b/x-pack/plugins/maps/public/classes/layers/create_region_map_layer_descriptor.ts index 8e0d234445355..658a093321500 100644 --- a/x-pack/plugins/maps/public/classes/layers/create_region_map_layer_descriptor.ts +++ b/x-pack/plugins/maps/public/classes/layers/create_region_map_layer_descriptor.ts @@ -22,8 +22,7 @@ import { } from '../../../common/constants'; import { VectorStyle } from '../styles/vector/vector_style'; import { EMSFileSource } from '../sources/ems_file_source'; -// @ts-ignore -import { VectorLayer } from './vector_layer/vector_layer'; +import { VectorLayer } from './vector_layer'; import { getDefaultDynamicProperties } from '../styles/vector/vector_style_defaults'; import { NUMERICAL_COLOR_PALETTES } from '../styles/color_palettes'; import { getJoinAggKey } from '../../../common/get_agg_key'; diff --git a/x-pack/plugins/maps/public/classes/layers/create_tile_map_layer_descriptor.ts b/x-pack/plugins/maps/public/classes/layers/create_tile_map_layer_descriptor.ts index a9de8c98ee557..e3e5f3878ee56 100644 --- a/x-pack/plugins/maps/public/classes/layers/create_tile_map_layer_descriptor.ts +++ b/x-pack/plugins/maps/public/classes/layers/create_tile_map_layer_descriptor.ts @@ -23,11 +23,9 @@ import { VECTOR_STYLES, } from '../../../common/constants'; import { VectorStyle } from '../styles/vector/vector_style'; -// @ts-ignore import { ESGeoGridSource } from '../sources/es_geo_grid_source'; -import { VectorLayer } from './vector_layer/vector_layer'; -// @ts-ignore -import { HeatmapLayer } from './heatmap_layer/heatmap_layer'; +import { VectorLayer } from './vector_layer'; +import { HeatmapLayer } from './heatmap_layer'; import { getDefaultDynamicProperties } from '../styles/vector/vector_style_defaults'; import { NUMERICAL_COLOR_PALETTES } from '../styles/color_palettes'; import { getSourceAggKey } from '../../../common/get_agg_key'; diff --git a/x-pack/plugins/maps/public/classes/layers/file_upload_wizard/wizard.tsx b/x-pack/plugins/maps/public/classes/layers/file_upload_wizard/wizard.tsx index a61ea4ce713a8..44a22f1529f18 100644 --- a/x-pack/plugins/maps/public/classes/layers/file_upload_wizard/wizard.tsx +++ b/x-pack/plugins/maps/public/classes/layers/file_upload_wizard/wizard.tsx @@ -16,10 +16,10 @@ import { } from '../../../../common/constants'; import { getFileUploadComponent } from '../../../kibana_services'; import { GeoJsonFileSource } from '../../sources/geojson_file_source'; -import { VectorLayer } from '../../layers/vector_layer/vector_layer'; +import { VectorLayer } from '../../layers/vector_layer'; import { createDefaultLayerDescriptor } from '../../sources/es_search_source'; import { RenderWizardArguments } from '../../layers/layer_wizard_registry'; -import { FileUploadComponentProps } from '../../../../../maps_file_upload/public'; +import { FileUploadComponentProps } from '../../../../../file_upload/public'; export const INDEX_SETUP_STEP_ID = 'INDEX_SETUP_STEP_ID'; export const INDEXING_STEP_ID = 'INDEXING_STEP_ID'; diff --git a/x-pack/plugins/maps/public/classes/layers/heatmap_layer/heatmap_layer.js b/x-pack/plugins/maps/public/classes/layers/heatmap_layer/heatmap_layer.js deleted file mode 100644 index 97cc7151112bf..0000000000000 --- a/x-pack/plugins/maps/public/classes/layers/heatmap_layer/heatmap_layer.js +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { AbstractLayer } from '../layer'; -import { VectorLayer } from '../vector_layer/vector_layer'; -import { HeatmapStyle } from '../../styles/heatmap/heatmap_style'; -import { EMPTY_FEATURE_COLLECTION, LAYER_TYPE } from '../../../../common/constants'; - -const SCALED_PROPERTY_NAME = '__kbn_heatmap_weight__'; //unique name to store scaled value for weighting - -export class HeatmapLayer extends VectorLayer { - static type = LAYER_TYPE.HEATMAP; - - static createDescriptor(options) { - const heatmapLayerDescriptor = super.createDescriptor(options); - heatmapLayerDescriptor.type = HeatmapLayer.type; - heatmapLayerDescriptor.style = HeatmapStyle.createDescriptor(); - return heatmapLayerDescriptor; - } - - constructor({ layerDescriptor, source }) { - super({ layerDescriptor, source }); - if (!layerDescriptor.style) { - const defaultStyle = HeatmapStyle.createDescriptor(); - this._style = new HeatmapStyle(defaultStyle); - } else { - this._style = new HeatmapStyle(layerDescriptor.style); - } - } - - getStyleForEditing() { - return this._style; - } - - getStyle() { - return this._style; - } - - getCurrentStyle() { - return this._style; - } - - _getPropKeyOfSelectedMetric() { - const metricfields = this.getSource().getMetricFields(); - return metricfields[0].getName(); - } - - _getHeatmapLayerId() { - return this.makeMbLayerId('heatmap'); - } - - getMbLayerIds() { - return [this._getHeatmapLayerId()]; - } - - ownsMbLayerId(mbLayerId) { - return this._getHeatmapLayerId() === mbLayerId; - } - - syncLayerWithMB(mbMap) { - super._syncSourceBindingWithMb(mbMap); - - const heatmapLayerId = this._getHeatmapLayerId(); - if (!mbMap.getLayer(heatmapLayerId)) { - mbMap.addLayer({ - id: heatmapLayerId, - type: 'heatmap', - source: this.getId(), - paint: {}, - }); - } - - const mbSourceAfter = mbMap.getSource(this.getId()); - const sourceDataRequest = this.getSourceDataRequest(); - const featureCollection = sourceDataRequest ? sourceDataRequest.getData() : null; - if (!featureCollection) { - mbSourceAfter.setData(EMPTY_FEATURE_COLLECTION); - return; - } - - const propertyKey = this._getPropKeyOfSelectedMetric(); - const dataBoundToMap = AbstractLayer.getBoundDataForSource(mbMap, this.getId()); - if (featureCollection !== dataBoundToMap) { - let max = 1; //max will be at least one, since counts or sums will be at least one. - for (let i = 0; i < featureCollection.features.length; i++) { - max = Math.max(featureCollection.features[i].properties[propertyKey], max); - } - for (let i = 0; i < featureCollection.features.length; i++) { - featureCollection.features[i].properties[SCALED_PROPERTY_NAME] = - featureCollection.features[i].properties[propertyKey] / max; - } - mbSourceAfter.setData(featureCollection); - } - - this.syncVisibilityWithMb(mbMap, heatmapLayerId); - this.getCurrentStyle().setMBPaintProperties({ - mbMap, - layerId: heatmapLayerId, - propertyName: SCALED_PROPERTY_NAME, - resolution: this.getSource().getGridResolution(), - }); - mbMap.setPaintProperty(heatmapLayerId, 'heatmap-opacity', this.getAlpha()); - mbMap.setLayerZoomRange(heatmapLayerId, this.getMinZoom(), this.getMaxZoom()); - } - - getLayerTypeIconName() { - return 'heatmap'; - } - - async hasLegendDetails() { - return true; - } - - renderLegendDetails() { - const metricFields = this.getSource().getMetricFields(); - return this.getCurrentStyle().renderLegendDetails(metricFields[0]); - } -} diff --git a/x-pack/plugins/maps/public/classes/layers/heatmap_layer/heatmap_layer.ts b/x-pack/plugins/maps/public/classes/layers/heatmap_layer/heatmap_layer.ts new file mode 100644 index 0000000000000..8eebd7c57afd7 --- /dev/null +++ b/x-pack/plugins/maps/public/classes/layers/heatmap_layer/heatmap_layer.ts @@ -0,0 +1,182 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Map as MbMap, GeoJSONSource as MbGeoJSONSource } from 'mapbox-gl'; +import { FeatureCollection } from 'geojson'; +import { AbstractLayer } from '../layer'; +import { HeatmapStyle } from '../../styles/heatmap/heatmap_style'; +import { EMPTY_FEATURE_COLLECTION, LAYER_TYPE } from '../../../../common/constants'; +import { HeatmapLayerDescriptor, MapQuery } from '../../../../common/descriptor_types'; +import { ESGeoGridSource } from '../../sources/es_geo_grid_source'; +import { addGeoJsonMbSource, syncVectorSource } from '../vector_layer'; +import { DataRequestContext } from '../../../actions'; +import { DataRequestAbortError } from '../../util/data_request'; + +const SCALED_PROPERTY_NAME = '__kbn_heatmap_weight__'; // unique name to store scaled value for weighting + +export class HeatmapLayer extends AbstractLayer { + static type = LAYER_TYPE.HEATMAP; + + private readonly _style: HeatmapStyle; + + static createDescriptor(options: Partial) { + const heatmapLayerDescriptor = super.createDescriptor(options); + heatmapLayerDescriptor.type = HeatmapLayer.type; + heatmapLayerDescriptor.style = HeatmapStyle.createDescriptor(); + return heatmapLayerDescriptor; + } + + constructor({ + layerDescriptor, + source, + }: { + layerDescriptor: HeatmapLayerDescriptor; + source: ESGeoGridSource; + }) { + super({ layerDescriptor, source }); + if (!layerDescriptor.style) { + const defaultStyle = HeatmapStyle.createDescriptor(); + this._style = new HeatmapStyle(defaultStyle); + } else { + this._style = new HeatmapStyle(layerDescriptor.style); + } + } + + getSource(): ESGeoGridSource { + return super.getSource() as ESGeoGridSource; + } + + getStyleForEditing() { + return this._style; + } + + getStyle() { + return this._style; + } + + getCurrentStyle() { + return this._style; + } + + _getPropKeyOfSelectedMetric() { + const metricfields = this.getSource().getMetricFields(); + return metricfields[0].getName(); + } + + _getHeatmapLayerId() { + return this.makeMbLayerId('heatmap'); + } + + getMbLayerIds() { + return [this._getHeatmapLayerId()]; + } + + ownsMbLayerId(mbLayerId: string) { + return this._getHeatmapLayerId() === mbLayerId; + } + + ownsMbSourceId(mbSourceId: string) { + return this.getId() === mbSourceId; + } + + async syncData(syncContext: DataRequestContext) { + if (this.isLoadingBounds()) { + return; + } + + const sourceQuery = this.getQuery() as MapQuery; + try { + await syncVectorSource({ + layerId: this.getId(), + layerName: await this.getDisplayName(this.getSource()), + prevDataRequest: this.getSourceDataRequest(), + requestMeta: { + ...syncContext.dataFilters, + fieldNames: this.getSource().getFieldNames(), + geogridPrecision: this.getSource().getGeoGridPrecision(syncContext.dataFilters.zoom), + sourceQuery: sourceQuery ? sourceQuery : undefined, + applyGlobalQuery: this.getSource().getApplyGlobalQuery(), + applyGlobalTime: this.getSource().getApplyGlobalTime(), + sourceMeta: this.getSource().getSyncMeta(), + }, + syncContext, + source: this.getSource(), + }); + } catch (error) { + if (!(error instanceof DataRequestAbortError)) { + throw error; + } + } + } + + syncLayerWithMB(mbMap: MbMap) { + addGeoJsonMbSource(this._getMbSourceId(), this.getMbLayerIds(), mbMap); + + const heatmapLayerId = this._getHeatmapLayerId(); + if (!mbMap.getLayer(heatmapLayerId)) { + mbMap.addLayer({ + id: heatmapLayerId, + type: 'heatmap', + source: this.getId(), + paint: {}, + }); + } + + const mbGeoJSONSource = mbMap.getSource(this.getId()) as MbGeoJSONSource; + const sourceDataRequest = this.getSourceDataRequest(); + const featureCollection = sourceDataRequest + ? (sourceDataRequest.getData() as FeatureCollection) + : null; + if (!featureCollection) { + mbGeoJSONSource.setData(EMPTY_FEATURE_COLLECTION); + return; + } + + const propertyKey = this._getPropKeyOfSelectedMetric(); + const dataBoundToMap = AbstractLayer.getBoundDataForSource(mbMap, this.getId()); + if (featureCollection !== dataBoundToMap) { + let max = 1; // max will be at least one, since counts or sums will be at least one. + for (let i = 0; i < featureCollection.features.length; i++) { + max = Math.max(featureCollection.features[i].properties?.[propertyKey], max); + } + for (let i = 0; i < featureCollection.features.length; i++) { + if (featureCollection.features[i].properties) { + featureCollection.features[i].properties![SCALED_PROPERTY_NAME] = + featureCollection.features[i].properties![propertyKey] / max; + } + } + mbGeoJSONSource.setData(featureCollection); + } + + this.syncVisibilityWithMb(mbMap, heatmapLayerId); + this.getCurrentStyle().setMBPaintProperties({ + mbMap, + layerId: heatmapLayerId, + propertyName: SCALED_PROPERTY_NAME, + resolution: this.getSource().getGridResolution(), + }); + mbMap.setPaintProperty(heatmapLayerId, 'heatmap-opacity', this.getAlpha()); + mbMap.setLayerZoomRange(heatmapLayerId, this.getMinZoom(), this.getMaxZoom()); + } + + getLayerTypeIconName() { + return 'heatmap'; + } + + async getFields() { + return this.getSource().getFields(); + } + + async hasLegendDetails() { + return true; + } + + renderLegendDetails() { + const metricFields = this.getSource().getMetricFields(); + return this.getCurrentStyle().renderLegendDetails(metricFields[0]); + } +} diff --git a/x-pack/plugins/maps_file_upload/server/models/import_data/index.js b/x-pack/plugins/maps/public/classes/layers/heatmap_layer/index.ts similarity index 83% rename from x-pack/plugins/maps_file_upload/server/models/import_data/index.js rename to x-pack/plugins/maps/public/classes/layers/heatmap_layer/index.ts index c1ba4b84975e5..ba15d97a39219 100644 --- a/x-pack/plugins/maps_file_upload/server/models/import_data/index.js +++ b/x-pack/plugins/maps/public/classes/layers/heatmap_layer/index.ts @@ -5,4 +5,4 @@ * 2.0. */ -export { importDataProvider } from './import_data'; +export { HeatmapLayer } from './heatmap_layer'; diff --git a/x-pack/plugins/maps/public/classes/layers/layer.tsx b/x-pack/plugins/maps/public/classes/layers/layer.tsx index aedf7af08b2c8..89c6d70a217c9 100644 --- a/x-pack/plugins/maps/public/classes/layers/layer.tsx +++ b/x-pack/plugins/maps/public/classes/layers/layer.tsx @@ -21,6 +21,7 @@ import { MAX_ZOOM, MB_SOURCE_ID_LAYER_ID_PREFIX_DELIMITER, MIN_ZOOM, + SOURCE_BOUNDS_DATA_REQUEST_ID, SOURCE_DATA_REQUEST_ID, SOURCE_TYPES, STYLE_TYPE, @@ -66,6 +67,7 @@ export interface ILayer { getImmutableSourceProperties(): Promise; renderSourceSettingsEditor({ onChange }: SourceEditorArgs): ReactElement | null; isLayerLoading(): boolean; + isLoadingBounds(): boolean; isFilteredByGlobalTime(): Promise; hasErrors(): boolean; getErrors(): string; @@ -401,6 +403,11 @@ export class AbstractLayer implements ILayer { return this._dataRequests.some((dataRequest) => dataRequest.isLoading()); } + isLoadingBounds() { + const boundsDataRequest = this.getDataRequest(SOURCE_BOUNDS_DATA_REQUEST_ID); + return !!boundsDataRequest && boundsDataRequest.isLoading(); + } + hasErrors(): boolean { return _.get(this._descriptor, '__isInErrorState', false); } diff --git a/x-pack/plugins/maps/public/classes/layers/load_layer_wizards.ts b/x-pack/plugins/maps/public/classes/layers/load_layer_wizards.ts index a32ae15405fac..bed7599f89073 100644 --- a/x-pack/plugins/maps/public/classes/layers/load_layer_wizards.ts +++ b/x-pack/plugins/maps/public/classes/layers/load_layer_wizards.ts @@ -9,7 +9,6 @@ import { registerLayerWizard } from './layer_wizard_registry'; import { uploadLayerWizardConfig } from './file_upload_wizard'; // @ts-ignore import { esDocumentsLayerWizardConfig } from '../sources/es_search_source'; -// @ts-ignore import { clustersLayerWizardConfig, heatmapLayerWizardConfig } from '../sources/es_geo_grid_source'; import { geoLineLayerWizardConfig } from '../sources/es_geo_line_source'; // @ts-ignore diff --git a/x-pack/plugins/maps/public/classes/layers/solution_layers/observability/create_layer_descriptor.test.ts b/x-pack/plugins/maps/public/classes/layers/solution_layers/observability/create_layer_descriptor.test.ts index c312ddec42572..b9cfb0067abd2 100644 --- a/x-pack/plugins/maps/public/classes/layers/solution_layers/observability/create_layer_descriptor.test.ts +++ b/x-pack/plugins/maps/public/classes/layers/solution_layers/observability/create_layer_descriptor.test.ts @@ -176,7 +176,6 @@ describe('createLayerDescriptor', () => { __dataRequests: [], alpha: 0.75, id: '12345', - joins: [], label: '[Performance] Duration', maxZoom: 24, minZoom: 0, diff --git a/x-pack/plugins/maps/public/classes/layers/solution_layers/observability/create_layer_descriptor.ts b/x-pack/plugins/maps/public/classes/layers/solution_layers/observability/create_layer_descriptor.ts index fd9147d62cc26..03870e7668189 100644 --- a/x-pack/plugins/maps/public/classes/layers/solution_layers/observability/create_layer_descriptor.ts +++ b/x-pack/plugins/maps/public/classes/layers/solution_layers/observability/create_layer_descriptor.ts @@ -31,11 +31,9 @@ import { OBSERVABILITY_METRIC_TYPE } from './metric_select'; import { DISPLAY } from './display_select'; import { VectorStyle } from '../../../styles/vector/vector_style'; import { EMSFileSource } from '../../../sources/ems_file_source'; -// @ts-ignore import { ESGeoGridSource } from '../../../sources/es_geo_grid_source'; -import { VectorLayer } from '../../vector_layer/vector_layer'; -// @ts-ignore -import { HeatmapLayer } from '../../heatmap_layer/heatmap_layer'; +import { VectorLayer } from '../../vector_layer'; +import { HeatmapLayer } from '../../heatmap_layer'; import { getDefaultDynamicProperties } from '../../../styles/vector/vector_style_defaults'; // redefining APM constant to avoid making maps app depend on APM plugin diff --git a/x-pack/plugins/maps/public/classes/layers/solution_layers/security/create_layer_descriptors.ts b/x-pack/plugins/maps/public/classes/layers/solution_layers/security/create_layer_descriptors.ts index 74a66276459c7..b2283196a41dd 100644 --- a/x-pack/plugins/maps/public/classes/layers/solution_layers/security/create_layer_descriptors.ts +++ b/x-pack/plugins/maps/public/classes/layers/solution_layers/security/create_layer_descriptors.ts @@ -22,7 +22,7 @@ import { SYMBOLIZE_AS_TYPES, VECTOR_STYLES, } from '../../../../../common/constants'; -import { VectorLayer } from '../../vector_layer/vector_layer'; +import { VectorLayer } from '../../vector_layer'; import { VectorStyle } from '../../../styles/vector/vector_style'; // @ts-ignore import { ESSearchSource } from '../../../sources/es_search_source'; diff --git a/x-pack/plugins/maps/public/classes/layers/tiled_vector_layer/tiled_vector_layer.tsx b/x-pack/plugins/maps/public/classes/layers/tiled_vector_layer/tiled_vector_layer.tsx index d98396b960cbd..477b17ae03d7b 100644 --- a/x-pack/plugins/maps/public/classes/layers/tiled_vector_layer/tiled_vector_layer.tsx +++ b/x-pack/plugins/maps/public/classes/layers/tiled_vector_layer/tiled_vector_layer.tsx @@ -15,7 +15,7 @@ import { EuiIcon } from '@elastic/eui'; import { Feature } from 'geojson'; import { IVectorStyle, VectorStyle } from '../../styles/vector/vector_style'; import { SOURCE_DATA_REQUEST_ID, LAYER_TYPE } from '../../../../common/constants'; -import { VectorLayer, VectorLayerArguments } from '../vector_layer/vector_layer'; +import { VectorLayer, VectorLayerArguments } from '../vector_layer'; import { ITiledSingleLayerVectorSource } from '../../sources/vector_source'; import { DataRequestContext } from '../../../actions'; import { diff --git a/x-pack/plugins/maps/public/classes/util/assign_feature_ids.test.ts b/x-pack/plugins/maps/public/classes/layers/vector_layer/assign_feature_ids.test.ts similarity index 97% rename from x-pack/plugins/maps/public/classes/util/assign_feature_ids.test.ts rename to x-pack/plugins/maps/public/classes/layers/vector_layer/assign_feature_ids.test.ts index 4fe3804968b81..137d443b39b91 100644 --- a/x-pack/plugins/maps/public/classes/util/assign_feature_ids.test.ts +++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/assign_feature_ids.test.ts @@ -6,7 +6,7 @@ */ import { assignFeatureIds } from './assign_feature_ids'; -import { FEATURE_ID_PROPERTY_NAME } from '../../../common/constants'; +import { FEATURE_ID_PROPERTY_NAME } from '../../../../common/constants'; import { FeatureCollection, Feature, Point } from 'geojson'; const featureId = 'myFeature1'; diff --git a/x-pack/plugins/maps/public/classes/util/assign_feature_ids.ts b/x-pack/plugins/maps/public/classes/layers/vector_layer/assign_feature_ids.ts similarity index 96% rename from x-pack/plugins/maps/public/classes/util/assign_feature_ids.ts rename to x-pack/plugins/maps/public/classes/layers/vector_layer/assign_feature_ids.ts index f6b7851159586..c40c8299ad04c 100644 --- a/x-pack/plugins/maps/public/classes/util/assign_feature_ids.ts +++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/assign_feature_ids.ts @@ -7,7 +7,7 @@ import _ from 'lodash'; import { FeatureCollection, Feature } from 'geojson'; -import { FEATURE_ID_PROPERTY_NAME } from '../../../common/constants'; +import { FEATURE_ID_PROPERTY_NAME } from '../../../../common/constants'; let idCounter = 0; diff --git a/x-pack/plugins/maps_file_upload/server/telemetry/index.ts b/x-pack/plugins/maps/public/classes/layers/vector_layer/index.ts similarity index 63% rename from x-pack/plugins/maps_file_upload/server/telemetry/index.ts rename to x-pack/plugins/maps/public/classes/layers/vector_layer/index.ts index 83cd64c3f0e6f..4b509ba5dff00 100644 --- a/x-pack/plugins/maps_file_upload/server/telemetry/index.ts +++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/index.ts @@ -5,5 +5,5 @@ * 2.0. */ -export { registerFileUploadUsageCollector } from './file_upload_usage_collector'; -export { fileUploadTelemetryMappingsType } from './mappings'; +export { addGeoJsonMbSource, syncVectorSource } from './utils'; +export { IVectorLayer, VectorLayer, VectorLayerArguments } from './vector_layer'; diff --git a/x-pack/plugins/maps/public/classes/layers/vector_layer/utils.tsx b/x-pack/plugins/maps/public/classes/layers/vector_layer/utils.tsx new file mode 100644 index 0000000000000..a3754b20de818 --- /dev/null +++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/utils.tsx @@ -0,0 +1,114 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FeatureCollection } from 'geojson'; +import { Map as MbMap } from 'mapbox-gl'; +import { + EMPTY_FEATURE_COLLECTION, + SOURCE_DATA_REQUEST_ID, + VECTOR_SHAPE_TYPE, +} from '../../../../common/constants'; +import { VectorSourceRequestMeta } from '../../../../common/descriptor_types'; +import { DataRequestContext } from '../../../actions'; +import { IVectorSource } from '../../sources/vector_source'; +import { DataRequestAbortError } from '../../util/data_request'; +import { DataRequest } from '../../util/data_request'; +import { getCentroidFeatures } from '../../../../common/get_centroid_features'; +import { canSkipSourceUpdate } from '../../util/can_skip_fetch'; +import { assignFeatureIds } from './assign_feature_ids'; + +export function addGeoJsonMbSource(mbSourceId: string, mbLayerIds: string[], mbMap: MbMap) { + const mbSource = mbMap.getSource(mbSourceId); + if (!mbSource) { + mbMap.addSource(mbSourceId, { + type: 'geojson', + data: EMPTY_FEATURE_COLLECTION, + }); + } else if (mbSource.type !== 'geojson') { + // Recreate source when existing source is not geojson. This can occur when layer changes from tile layer to vector layer. + mbLayerIds.forEach((mbLayerId) => { + if (mbMap.getLayer(mbLayerId)) { + mbMap.removeLayer(mbLayerId); + } + }); + + mbMap.removeSource(mbSourceId); + mbMap.addSource(mbSourceId, { + type: 'geojson', + data: EMPTY_FEATURE_COLLECTION, + }); + } +} + +export async function syncVectorSource({ + layerId, + layerName, + prevDataRequest, + requestMeta, + syncContext, + source, +}: { + layerId: string; + layerName: string; + prevDataRequest: DataRequest | undefined; + requestMeta: VectorSourceRequestMeta; + syncContext: DataRequestContext; + source: IVectorSource; +}): Promise<{ refreshed: boolean; featureCollection: FeatureCollection }> { + const { + startLoading, + stopLoading, + onLoadError, + registerCancelCallback, + isRequestStillActive, + } = syncContext; + const dataRequestId = SOURCE_DATA_REQUEST_ID; + const requestToken = Symbol(`${layerId}-${dataRequestId}`); + const canSkipFetch = await canSkipSourceUpdate({ + source, + prevDataRequest, + nextMeta: requestMeta, + }); + if (canSkipFetch) { + return { + refreshed: false, + featureCollection: prevDataRequest + ? (prevDataRequest.getData() as FeatureCollection) + : EMPTY_FEATURE_COLLECTION, + }; + } + + try { + startLoading(dataRequestId, requestToken, requestMeta); + const { data: sourceFeatureCollection, meta } = await source.getGeoJsonWithMeta( + layerName, + requestMeta, + registerCancelCallback.bind(null, requestToken), + () => { + return isRequestStillActive(dataRequestId, requestToken); + } + ); + const layerFeatureCollection = assignFeatureIds(sourceFeatureCollection); + const supportedShapes = await source.getSupportedShapeTypes(); + if ( + supportedShapes.includes(VECTOR_SHAPE_TYPE.LINE) || + supportedShapes.includes(VECTOR_SHAPE_TYPE.POLYGON) + ) { + layerFeatureCollection.features.push(...getCentroidFeatures(layerFeatureCollection)); + } + stopLoading(dataRequestId, requestToken, layerFeatureCollection, meta); + return { + refreshed: true, + featureCollection: layerFeatureCollection, + }; + } catch (error) { + if (!(error instanceof DataRequestAbortError)) { + onLoadError(dataRequestId, requestToken, error.message); + } + throw error; + } +} diff --git a/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx b/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx index ee1cda6eaee43..7e87d99fd4f93 100644 --- a/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx +++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx @@ -13,10 +13,8 @@ import { EuiIcon } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { AbstractLayer } from '../layer'; import { IVectorStyle, VectorStyle } from '../../styles/vector/vector_style'; -import { getCentroidFeatures } from '../../../../common/get_centroid_features'; import { FEATURE_ID_PROPERTY_NAME, - SOURCE_DATA_REQUEST_ID, SOURCE_META_DATA_REQUEST_ID, SOURCE_FORMATTERS_DATA_REQUEST_ID, SOURCE_BOUNDS_DATA_REQUEST_ID, @@ -25,10 +23,8 @@ import { KBN_TOO_MANY_FEATURES_PROPERTY, LAYER_TYPE, FIELD_ORIGIN, - LAYER_STYLE_TYPE, KBN_TOO_MANY_FEATURES_IMAGE_ID, FieldFormatter, - VECTOR_SHAPE_TYPE, } from '../../../../common/constants'; import { JoinTooltipProperty } from '../../tooltips/join_tooltip_property'; import { DataRequestAbortError } from '../../util/data_request'; @@ -37,7 +33,6 @@ import { canSkipStyleMetaUpdate, canSkipFormattersUpdate, } from '../../util/can_skip_fetch'; -import { assignFeatureIds } from '../../util/assign_feature_ids'; import { getFeatureCollectionBounds } from '../../util/get_feature_collection_bounds'; import { getCentroidFilterExpression, @@ -65,6 +60,7 @@ import { IDynamicStyleProperty } from '../../styles/vector/properties/dynamic_st import { IESSource } from '../../sources/es_source'; import { PropertiesMap } from '../../../../common/elasticsearch_util'; import { ITermJoinSource } from '../../sources/term_join_source'; +import { addGeoJsonMbSource, syncVectorSource } from './utils'; interface SourceResult { refreshed: boolean; @@ -81,6 +77,7 @@ export interface VectorLayerArguments { source: IVectorSource; joins?: InnerJoin[]; layerDescriptor: VectorLayerDescriptor; + chartsPaletteServiceGetColor?: (value: string) => string | null; } export interface IVectorLayer extends ILayer { @@ -94,7 +91,7 @@ export interface IVectorLayer extends ILayer { hasJoins(): boolean; } -export class VectorLayer extends AbstractLayer { +export class VectorLayer extends AbstractLayer implements IVectorLayer { static type = LAYER_TYPE.VECTOR; protected readonly _style: IVectorStyle; @@ -119,13 +116,23 @@ export class VectorLayer extends AbstractLayer { return layerDescriptor as VectorLayerDescriptor; } - constructor({ layerDescriptor, source, joins = [] }: VectorLayerArguments) { + constructor({ + layerDescriptor, + source, + joins = [], + chartsPaletteServiceGetColor, + }: VectorLayerArguments) { super({ layerDescriptor, source, }); this._joins = joins; - this._style = new VectorStyle(layerDescriptor.style, source, this); + this._style = new VectorStyle( + layerDescriptor.style, + source, + this, + chartsPaletteServiceGetColor + ); } getSource(): IVectorSource { @@ -277,11 +284,6 @@ export class VectorLayer extends AbstractLayer { return bounds; } - isLoadingBounds() { - const boundsDataRequest = this.getDataRequest(SOURCE_BOUNDS_DATA_REQUEST_ID); - return !!boundsDataRequest && boundsDataRequest.isLoading(); - } - async getLeftJoinFields() { return await this.getSource().getLeftJoinFields(); } @@ -409,11 +411,9 @@ export class VectorLayer extends AbstractLayer { source: IVectorSource, style: IVectorStyle ): VectorSourceRequestMeta { - const styleFieldNames = - style.getType() === LAYER_STYLE_TYPE.VECTOR ? style.getSourceFieldNames() : []; const fieldNames = [ ...source.getFieldNames(), - ...styleFieldNames, + ...style.getSourceFieldNames(), ...this.getValidJoins().map((join) => join.getLeftField().getName()), ]; @@ -474,82 +474,11 @@ export class VectorLayer extends AbstractLayer { } } - async _syncSource( - syncContext: DataRequestContext, - source: IVectorSource, - style: IVectorStyle - ): Promise { - const { - startLoading, - stopLoading, - onLoadError, - registerCancelCallback, - dataFilters, - isRequestStillActive, - } = syncContext; - const dataRequestId = SOURCE_DATA_REQUEST_ID; - const requestToken = Symbol(`layer-${this.getId()}-${dataRequestId}`); - const searchFilters: VectorSourceRequestMeta = this._getSearchFilters( - dataFilters, - source, - style - ); - const prevDataRequest = this.getSourceDataRequest(); - const canSkipFetch = await canSkipSourceUpdate({ - source, - prevDataRequest, - nextMeta: searchFilters, - }); - if (canSkipFetch) { - return { - refreshed: false, - featureCollection: prevDataRequest - ? (prevDataRequest.getData() as FeatureCollection) - : EMPTY_FEATURE_COLLECTION, - }; - } - - try { - startLoading(dataRequestId, requestToken, searchFilters); - const layerName = await this.getDisplayName(source); - const { data: sourceFeatureCollection, meta } = await source.getGeoJsonWithMeta( - layerName, - searchFilters, - registerCancelCallback.bind(null, requestToken), - () => { - return isRequestStillActive(dataRequestId, requestToken); - } - ); - const layerFeatureCollection = assignFeatureIds(sourceFeatureCollection); - const supportedShapes = await source.getSupportedShapeTypes(); - if ( - supportedShapes.includes(VECTOR_SHAPE_TYPE.LINE) || - supportedShapes.includes(VECTOR_SHAPE_TYPE.POLYGON) - ) { - layerFeatureCollection.features.push(...getCentroidFeatures(layerFeatureCollection)); - } - stopLoading(dataRequestId, requestToken, layerFeatureCollection, meta); - return { - refreshed: true, - featureCollection: layerFeatureCollection, - }; - } catch (error) { - if (!(error instanceof DataRequestAbortError)) { - onLoadError(dataRequestId, requestToken, error.message); - } - throw error; - } - } - async _syncSourceStyleMeta( syncContext: DataRequestContext, source: IVectorSource, style: IVectorStyle ) { - if (this.getCurrentStyle().getType() !== LAYER_STYLE_TYPE.VECTOR) { - return; - } - const sourceQuery = this.getQuery() as MapQuery; return this._syncStyleMeta({ source, @@ -654,10 +583,6 @@ export class VectorLayer extends AbstractLayer { source: IVectorSource, style: IVectorStyle ) { - if (style.getType() !== LAYER_STYLE_TYPE.VECTOR) { - return; - } - return this._syncFormatters({ source, dataRequestId: SOURCE_FORMATTERS_DATA_REQUEST_ID, @@ -762,7 +687,14 @@ export class VectorLayer extends AbstractLayer { try { await this._syncSourceStyleMeta(syncContext, source, style); await this._syncSourceFormatters(syncContext, source, style); - const sourceResult = await this._syncSource(syncContext, source, style); + const sourceResult = await syncVectorSource({ + layerId: this.getId(), + layerName: await this.getDisplayName(source), + prevDataRequest: this.getSourceDataRequest(), + requestMeta: this._getSearchFilters(syncContext.dataFilters, source, style), + syncContext, + source, + }); if ( !sourceResult.featureCollection || !sourceResult.featureCollection.features.length || @@ -1050,31 +982,8 @@ export class VectorLayer extends AbstractLayer { this._setMbCentroidProperties(mbMap); } - _syncSourceBindingWithMb(mbMap: MbMap) { - const mbSource = mbMap.getSource(this._getMbSourceId()); - if (!mbSource) { - mbMap.addSource(this._getMbSourceId(), { - type: 'geojson', - data: EMPTY_FEATURE_COLLECTION, - }); - } else if (mbSource.type !== 'geojson') { - // Recreate source when existing source is not geojson. This can occur when layer changes from tile layer to vector layer. - this.getMbLayerIds().forEach((mbLayerId) => { - if (mbMap.getLayer(mbLayerId)) { - mbMap.removeLayer(mbLayerId); - } - }); - - mbMap.removeSource(this._getMbSourceId()); - mbMap.addSource(this._getMbSourceId(), { - type: 'geojson', - data: EMPTY_FEATURE_COLLECTION, - }); - } - } - syncLayerWithMB(mbMap: MbMap) { - this._syncSourceBindingWithMb(mbMap); + addGeoJsonMbSource(this._getMbSourceId(), this.getMbLayerIds(), mbMap); this._syncFeatureCollectionWithMb(mbMap); this._syncStylePropertiesWithMb(mbMap); } diff --git a/x-pack/plugins/maps/public/classes/sources/ems_file_source/ems_boundaries_layer_wizard.tsx b/x-pack/plugins/maps/public/classes/sources/ems_file_source/ems_boundaries_layer_wizard.tsx index 3acc3c59e5930..d4cf4dbee7943 100644 --- a/x-pack/plugins/maps/public/classes/sources/ems_file_source/ems_boundaries_layer_wizard.tsx +++ b/x-pack/plugins/maps/public/classes/sources/ems_file_source/ems_boundaries_layer_wizard.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; -import { VectorLayer } from '../../layers/vector_layer/vector_layer'; +import { VectorLayer } from '../../layers/vector_layer'; import { LayerWizard, RenderWizardArguments } from '../../layers/layer_wizard_registry'; import { EMSFileCreateSourceEditor } from './create_source_editor'; import { EMSFileSource, getSourceTitle } from './ems_file_source'; diff --git a/x-pack/plugins/maps/public/classes/sources/ems_file_source/ems_file_source.test.tsx b/x-pack/plugins/maps/public/classes/sources/ems_file_source/ems_file_source.test.tsx index 5a0a3ed8df596..e711fb900e39a 100644 --- a/x-pack/plugins/maps/public/classes/sources/ems_file_source/ems_file_source.test.tsx +++ b/x-pack/plugins/maps/public/classes/sources/ems_file_source/ems_file_source.test.tsx @@ -7,7 +7,7 @@ import { EMSFileSource } from './ems_file_source'; -jest.mock('../../layers/vector_layer/vector_layer', () => {}); +jest.mock('../../layers/vector_layer', () => {}); function makeEMSFileSource(tooltipProperties: string[]) { const emsFileSource = new EMSFileSource({ tooltipProperties }); diff --git a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/clusters_layer_wizard.tsx b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/clusters_layer_wizard.tsx index 8951b7b278459..36dd28cb5bbf1 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/clusters_layer_wizard.tsx +++ b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/clusters_layer_wizard.tsx @@ -9,10 +9,9 @@ import { i18n } from '@kbn/i18n'; import React from 'react'; // @ts-ignore import { CreateSourceEditor } from './create_source_editor'; -// @ts-ignore import { ESGeoGridSource, clustersTitle } from './es_geo_grid_source'; import { LayerWizard, RenderWizardArguments } from '../../layers/layer_wizard_registry'; -import { VectorLayer } from '../../layers/vector_layer/vector_layer'; +import { VectorLayer } from '../../layers/vector_layer'; import { ESGeoGridSourceDescriptor, ColorDynamicOptions, diff --git a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/heatmap_layer_wizard.tsx b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/heatmap_layer_wizard.tsx index 83a7e02383f77..8fc26f3593750 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/heatmap_layer_wizard.tsx +++ b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/heatmap_layer_wizard.tsx @@ -9,11 +9,9 @@ import { i18n } from '@kbn/i18n'; import React from 'react'; // @ts-ignore import { CreateSourceEditor } from './create_source_editor'; -// @ts-ignore import { ESGeoGridSource, heatmapTitle } from './es_geo_grid_source'; import { LayerWizard, RenderWizardArguments } from '../../layers/layer_wizard_registry'; -// @ts-ignore -import { HeatmapLayer } from '../../layers/heatmap_layer/heatmap_layer'; +import { HeatmapLayer } from '../../layers/heatmap_layer'; import { ESGeoGridSourceDescriptor } from '../../../../common/descriptor_types'; import { LAYER_WIZARD_CATEGORY, RENDER_AS } from '../../../../common/constants'; import { HeatmapLayerIcon } from '../../layers/icons/heatmap_layer_icon'; diff --git a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/index.js b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/index.ts similarity index 100% rename from x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/index.js rename to x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/index.ts diff --git a/x-pack/plugins/maps/public/classes/sources/es_geo_line_source/layer_wizard.tsx b/x-pack/plugins/maps/public/classes/sources/es_geo_line_source/layer_wizard.tsx index 6a1dfc74271d8..8da7037a5a34c 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_geo_line_source/layer_wizard.tsx +++ b/x-pack/plugins/maps/public/classes/sources/es_geo_line_source/layer_wizard.tsx @@ -12,7 +12,7 @@ import { ESGeoLineSource, geoLineTitle, REQUIRES_GOLD_LICENSE_MSG } from './es_g import { LayerWizard, RenderWizardArguments } from '../../layers/layer_wizard_registry'; import { LAYER_WIZARD_CATEGORY, STYLE_TYPE, VECTOR_STYLES } from '../../../../common/constants'; import { VectorStyle } from '../../styles/vector/vector_style'; -import { VectorLayer } from '../../layers/vector_layer/vector_layer'; +import { VectorLayer } from '../../layers/vector_layer'; import { getIsGoldPlus } from '../../../licensed_features'; import { TracksLayerIcon } from '../../layers/icons/tracks_layer_icon'; diff --git a/x-pack/plugins/maps/public/classes/sources/es_pew_pew_source/point_2_point_layer_wizard.tsx b/x-pack/plugins/maps/public/classes/sources/es_pew_pew_source/point_2_point_layer_wizard.tsx index 49b161711481c..c94c7859a85e7 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_pew_pew_source/point_2_point_layer_wizard.tsx +++ b/x-pack/plugins/maps/public/classes/sources/es_pew_pew_source/point_2_point_layer_wizard.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { getDefaultDynamicProperties } from '../../styles/vector/vector_style_defaults'; -import { VectorLayer } from '../../layers/vector_layer/vector_layer'; +import { VectorLayer } from '../../layers/vector_layer'; // @ts-ignore import { ESPewPewSource, sourceTitle } from './es_pew_pew_source'; import { VectorStyle } from '../../styles/vector/vector_style'; diff --git a/x-pack/plugins/maps/public/classes/sources/es_search_source/create_layer_descriptor.ts b/x-pack/plugins/maps/public/classes/sources/es_search_source/create_layer_descriptor.ts index 2734af5742dbb..41b4e8d7a318a 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_search_source/create_layer_descriptor.ts +++ b/x-pack/plugins/maps/public/classes/sources/es_search_source/create_layer_descriptor.ts @@ -9,7 +9,7 @@ import { Query } from 'src/plugins/data/public'; import { LayerDescriptor } from '../../../../common/descriptor_types'; import { ES_GEO_FIELD_TYPE, SCALING_TYPES } from '../../../../common/constants'; import { ESSearchSource } from './es_search_source'; -import { VectorLayer } from '../../layers/vector_layer/vector_layer'; +import { VectorLayer } from '../../layers/vector_layer'; import { getIsGoldPlus } from '../../../licensed_features'; export interface CreateLayerDescriptorParams { diff --git a/x-pack/plugins/maps/public/classes/sources/es_search_source/es_documents_layer_wizard.tsx b/x-pack/plugins/maps/public/classes/sources/es_search_source/es_documents_layer_wizard.tsx index d01ed459e3171..c0606b5f4aec6 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_search_source/es_documents_layer_wizard.tsx +++ b/x-pack/plugins/maps/public/classes/sources/es_search_source/es_documents_layer_wizard.tsx @@ -13,7 +13,7 @@ import { LayerWizard, RenderWizardArguments } from '../../layers/layer_wizard_re // @ts-ignore import { ESSearchSource, sourceTitle } from './es_search_source'; import { BlendedVectorLayer } from '../../layers/blended_vector_layer/blended_vector_layer'; -import { VectorLayer } from '../../layers/vector_layer/vector_layer'; +import { VectorLayer } from '../../layers/vector_layer'; import { LAYER_WIZARD_CATEGORY, SCALING_TYPES } from '../../../../common/constants'; import { TiledVectorLayer } from '../../layers/tiled_vector_layer/tiled_vector_layer'; import { DocumentsLayerIcon } from '../../layers/icons/documents_layer_icon'; diff --git a/x-pack/plugins/maps/public/classes/sources/es_term_source/es_term_source.test.js b/x-pack/plugins/maps/public/classes/sources/es_term_source/es_term_source.test.js index a7994db286112..1f4a1ab7c9afa 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_term_source/es_term_source.test.js +++ b/x-pack/plugins/maps/public/classes/sources/es_term_source/es_term_source.test.js @@ -7,7 +7,7 @@ import { ESTermSource, extractPropertiesMap } from './es_term_source'; -jest.mock('../../layers/vector_layer/vector_layer', () => {}); +jest.mock('../../layers/vector_layer', () => {}); const indexPatternTitle = 'myIndex'; const termFieldName = 'myTermField'; diff --git a/x-pack/plugins/maps/public/classes/sources/kibana_regionmap_source/kibana_regionmap_layer_wizard.tsx b/x-pack/plugins/maps/public/classes/sources/kibana_regionmap_source/kibana_regionmap_layer_wizard.tsx index b41f599ac3d75..907b80e6405a6 100644 --- a/x-pack/plugins/maps/public/classes/sources/kibana_regionmap_source/kibana_regionmap_layer_wizard.tsx +++ b/x-pack/plugins/maps/public/classes/sources/kibana_regionmap_source/kibana_regionmap_layer_wizard.tsx @@ -10,7 +10,7 @@ import { i18n } from '@kbn/i18n'; import { LayerWizard, RenderWizardArguments } from '../../layers/layer_wizard_registry'; // @ts-ignore import { KibanaRegionmapSource, sourceTitle } from './kibana_regionmap_source'; -import { VectorLayer } from '../../layers/vector_layer/vector_layer'; +import { VectorLayer } from '../../layers/vector_layer'; // @ts-ignore import { CreateSourceEditor } from './create_source_editor'; import { getKibanaRegionList } from '../../../meta'; diff --git a/x-pack/plugins/maps/public/classes/styles/heatmap/heatmap_style.tsx b/x-pack/plugins/maps/public/classes/styles/heatmap/heatmap_style.tsx index f30040cf93b57..fe581a1807b28 100644 --- a/x-pack/plugins/maps/public/classes/styles/heatmap/heatmap_style.tsx +++ b/x-pack/plugins/maps/public/classes/styles/heatmap/heatmap_style.tsx @@ -31,7 +31,7 @@ export class HeatmapStyle implements IStyle { this._descriptor = HeatmapStyle.createDescriptor(descriptor.colorRampName); } - static createDescriptor(colorRampName: string) { + static createDescriptor(colorRampName?: string) { return { type: LAYER_STYLE_TYPE.HEATMAP, colorRampName: colorRampName ? colorRampName : DEFAULT_HEATMAP_COLOR_RAMP_NAME, diff --git a/x-pack/plugins/maps/public/classes/styles/vector/components/vector_style_editor.test.tsx b/x-pack/plugins/maps/public/classes/styles/vector/components/vector_style_editor.test.tsx index 3cfae4a836042..d0d3a7c2abe06 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/components/vector_style_editor.test.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/components/vector_style_editor.test.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { shallow } from 'enzyme'; import { StyleProperties, VectorStyleEditor } from './vector_style_editor'; import { getDefaultStaticProperties } from '../vector_style_defaults'; -import { IVectorLayer } from '../../../layers/vector_layer/vector_layer'; +import { IVectorLayer } from '../../../layers/vector_layer'; import { IVectorSource } from '../../../sources/vector_source'; import { FIELD_ORIGIN, diff --git a/x-pack/plugins/maps/public/classes/styles/vector/components/vector_style_editor.tsx b/x-pack/plugins/maps/public/classes/styles/vector/components/vector_style_editor.tsx index b36f3a38e2783..91bcc2dc06859 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/components/vector_style_editor.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/components/vector_style_editor.tsx @@ -49,7 +49,7 @@ import { SymbolizeAsProperty } from '../properties/symbolize_as_property'; import { LabelBorderSizeProperty } from '../properties/label_border_size_property'; import { StaticTextProperty } from '../properties/static_text_property'; import { StaticSizeProperty } from '../properties/static_size_property'; -import { IVectorLayer } from '../../../layers/vector_layer/vector_layer'; +import { IVectorLayer } from '../../../layers/vector_layer'; export interface StyleProperties { [key: string]: IStyleProperty; diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.test.tsx b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.test.tsx index 03b7ce17063c3..b7e0133881ee1 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.test.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.test.tsx @@ -24,7 +24,7 @@ import { } from '../../../../../common/constants'; import { mockField, MockLayer, MockStyle } from './test_helpers/test_util'; import { ColorDynamicOptions } from '../../../../../common/descriptor_types'; -import { IVectorLayer } from '../../../layers/vector_layer/vector_layer'; +import { IVectorLayer } from '../../../layers/vector_layer'; import { IField } from '../../../fields/field'; const makeProperty = (options: ColorDynamicOptions, style?: MockStyle, field?: IField) => { diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.tsx b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.tsx index cac56ad1c8a57..d654cdc6bff51 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.tsx @@ -16,7 +16,12 @@ import { getPercentilesMbColorRampStops, getColorPalette, } from '../../color_palettes'; -import { COLOR_MAP_TYPE, DATA_MAPPING_FUNCTION } from '../../../../../common/constants'; +import { + COLOR_MAP_TYPE, + DATA_MAPPING_FUNCTION, + FieldFormatter, + VECTOR_STYLES, +} from '../../../../../common/constants'; import { isCategoricalStopsInvalid, getOtherCategoryLabel, @@ -26,6 +31,8 @@ import { Break, BreakedLegend } from '../components/legend/breaked_legend'; import { ColorDynamicOptions, OrdinalColorStop } from '../../../../../common/descriptor_types'; import { LegendProps } from './style_property'; import { getOrdinalSuffix } from '../../../util/ordinal_suffix'; +import { IField } from '../../../fields/field'; +import { IVectorLayer } from '../../../layers/vector_layer/vector_layer'; const UP_TO = i18n.translate('xpack.maps.legend.upto', { defaultMessage: 'up to', @@ -34,6 +41,20 @@ const EMPTY_STOPS = { stops: [], defaultColor: null }; const RGBA_0000 = 'rgba(0,0,0,0)'; export class DynamicColorProperty extends DynamicStyleProperty { + private readonly _chartsPaletteServiceGetColor?: (value: string) => string | null; + + constructor( + options: ColorDynamicOptions, + styleName: VECTOR_STYLES, + field: IField | null, + vectorLayer: IVectorLayer, + getFieldFormatter: (fieldName: string) => null | FieldFormatter, + chartsPaletteServiceGetColor?: (value: string) => string | null + ) { + super(options, styleName, field, vectorLayer, getFieldFormatter); + this._chartsPaletteServiceGetColor = chartsPaletteServiceGetColor; + } + syncCircleColorWithMb(mbLayerId: string, mbMap: MbMap, alpha: number) { const color = this._getMbColor(); mbMap.setPaintProperty(mbLayerId, 'circle-color', color); @@ -260,12 +281,16 @@ export class DynamicColorProperty extends DynamicStyleProperty { - if (stop !== null) { + stops.forEach(({ stop, color }: { stop: string | number | null; color: string | null }) => { + if (stop !== null && color != null) { breaks.push({ color, symbolId, diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_icon_property.test.tsx b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_icon_property.test.tsx index fc4d495f1e40a..46339c5a4a20d 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_icon_property.test.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_icon_property.test.tsx @@ -20,7 +20,7 @@ import { DynamicIconProperty } from './dynamic_icon_property'; import { mockField, MockLayer } from './test_helpers/test_util'; import { IconDynamicOptions } from '../../../../../common/descriptor_types'; import { IField } from '../../../fields/field'; -import { IVectorLayer } from '../../../layers/vector_layer/vector_layer'; +import { IVectorLayer } from '../../../layers/vector_layer'; const makeProperty = (options: Partial, field: IField = mockField) => { const defaultOptions: IconDynamicOptions = { diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_size_property.test.tsx b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_size_property.test.tsx index 40d72a357218f..64a3e0cf0e322 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_size_property.test.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_size_property.test.tsx @@ -21,7 +21,7 @@ import { IField } from '../../../fields/field'; import { Map as MbMap } from 'mapbox-gl'; import { SizeDynamicOptions } from '../../../../../common/descriptor_types'; import { mockField, MockLayer, MockStyle } from './test_helpers/test_util'; -import { IVectorLayer } from '../../../layers/vector_layer/vector_layer'; +import { IVectorLayer } from '../../../layers/vector_layer'; export class MockMbMap { _paintPropertyCalls: unknown[]; diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_size_property.tsx b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_size_property.tsx index 52b78b4211a2d..7076775dcce31 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_size_property.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_size_property.tsx @@ -20,7 +20,7 @@ import { import { FieldFormatter, MB_LOOKUP_FUNCTION, VECTOR_STYLES } from '../../../../../common/constants'; import { SizeDynamicOptions } from '../../../../../common/descriptor_types'; import { IField } from '../../../fields/field'; -import { IVectorLayer } from '../../../layers/vector_layer/vector_layer'; +import { IVectorLayer } from '../../../layers/vector_layer'; export class DynamicSizeProperty extends DynamicStyleProperty { private readonly _isSymbolizedAsIcon: boolean; diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.tsx b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.tsx index f62b17ee05ad6..9ffd9a0f1b345 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.tsx @@ -34,7 +34,7 @@ import { StyleMetaData, } from '../../../../../common/descriptor_types'; import { IField } from '../../../fields/field'; -import { IVectorLayer } from '../../../layers/vector_layer/vector_layer'; +import { IVectorLayer } from '../../../layers/vector_layer'; import { InnerJoin } from '../../../joins/inner_join'; import { IVectorStyle } from '../vector_style'; import { getComputedFieldName } from '../style_util'; diff --git a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx index cef5f5048e9af..692be08d07bc6 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx @@ -70,7 +70,7 @@ import { DataRequest } from '../../util/data_request'; import { IStyle } from '../style'; import { IStyleProperty } from './properties/style_property'; import { IField } from '../../fields/field'; -import { IVectorLayer } from '../../layers/vector_layer/vector_layer'; +import { IVectorLayer } from '../../layers/vector_layer'; import { IVectorSource } from '../../sources/vector_source'; import { createStyleFieldsHelper, StyleFieldsHelper } from './style_fields_helper'; import { IESAggField } from '../../fields/agg'; @@ -178,7 +178,8 @@ export class VectorStyle implements IVectorStyle { constructor( descriptor: VectorStyleDescriptor | null, source: IVectorSource, - layer: IVectorLayer + layer: IVectorLayer, + chartsPaletteServiceGetColor?: (value: string) => string | null ) { this._source = source; this._layer = layer; @@ -197,11 +198,13 @@ export class VectorStyle implements IVectorStyle { ); this._lineColorStyleProperty = this._makeColorProperty( this._descriptor.properties[VECTOR_STYLES.LINE_COLOR], - VECTOR_STYLES.LINE_COLOR + VECTOR_STYLES.LINE_COLOR, + chartsPaletteServiceGetColor ); this._fillColorStyleProperty = this._makeColorProperty( this._descriptor.properties[VECTOR_STYLES.FILL_COLOR], - VECTOR_STYLES.FILL_COLOR + VECTOR_STYLES.FILL_COLOR, + chartsPaletteServiceGetColor ); this._lineWidthStyleProperty = this._makeSizeProperty( this._descriptor.properties[VECTOR_STYLES.LINE_WIDTH], @@ -230,11 +233,13 @@ export class VectorStyle implements IVectorStyle { ); this._labelColorStyleProperty = this._makeColorProperty( this._descriptor.properties[VECTOR_STYLES.LABEL_COLOR], - VECTOR_STYLES.LABEL_COLOR + VECTOR_STYLES.LABEL_COLOR, + chartsPaletteServiceGetColor ); this._labelBorderColorStyleProperty = this._makeColorProperty( this._descriptor.properties[VECTOR_STYLES.LABEL_BORDER_COLOR], - VECTOR_STYLES.LABEL_BORDER_COLOR + VECTOR_STYLES.LABEL_BORDER_COLOR, + chartsPaletteServiceGetColor ); this._labelBorderSizeStyleProperty = new LabelBorderSizeProperty( this._descriptor.properties[VECTOR_STYLES.LABEL_BORDER_SIZE].options, @@ -890,7 +895,8 @@ export class VectorStyle implements IVectorStyle { _makeColorProperty( descriptor: ColorStylePropertyDescriptor | undefined, - styleName: VECTOR_STYLES + styleName: VECTOR_STYLES, + chartsPaletteServiceGetColor?: (value: string) => string | null ) { if (!descriptor || !descriptor.options) { return new StaticColorProperty({ color: '' }, styleName); @@ -904,7 +910,8 @@ export class VectorStyle implements IVectorStyle { styleName, field, this._layer, - this._getFieldFormatter + this._getFieldFormatter, + chartsPaletteServiceGetColor ); } else { throw new Error(`${descriptor} not implemented`); diff --git a/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx b/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx index a1d65bf08c458..b769ac489f565 100644 --- a/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx +++ b/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx @@ -37,6 +37,7 @@ import { import { getIsLayerTOCOpen, getOpenTOCDetails } from '../selectors/ui_selectors'; import { getInspectorAdapters, + setChartsPaletteServiceGetColor, setEventHandlers, EventHandlers, } from '../reducers/non_serializable_instances'; @@ -54,7 +55,12 @@ import { RawValue, } from '../../common/constants'; import { RenderToolTipContent } from '../classes/tooltips/tooltip_property'; -import { getUiActions, getCoreI18n, getHttp } from '../kibana_services'; +import { + getUiActions, + getCoreI18n, + getHttp, + getChartsPaletteServiceGetColor, +} from '../kibana_services'; import { LayerDescriptor } from '../../common/descriptor_types'; import { MapContainer } from '../connected_components/map_container'; import { SavedMap } from '../routes/map_page'; @@ -83,6 +89,7 @@ export class MapEmbeddable private _prevQuery?: Query; private _prevRefreshConfig?: RefreshInterval; private _prevFilters?: Filter[]; + private _prevSyncColors?: boolean; private _prevSearchSessionId?: string; private _domNode?: HTMLElement; private _unsubscribeFromStore?: Unsubscribe; @@ -126,6 +133,8 @@ export class MapEmbeddable } private _initializeStore() { + this._dispatchSetChartsPaletteServiceGetColor(this.input.syncColors); + const store = this._savedMap.getStore(); store.dispatch(setReadOnly(true)); store.dispatch(disableScrollZoom()); @@ -221,6 +230,10 @@ export class MapEmbeddable if (this.input.refreshConfig && !_.isEqual(this.input.refreshConfig, this._prevRefreshConfig)) { this._dispatchSetRefreshConfig(this.input.refreshConfig); } + + if (this.input.syncColors !== this._prevSyncColors) { + this._dispatchSetChartsPaletteServiceGetColor(this.input.syncColors); + } } _dispatchSetQuery({ @@ -261,6 +274,19 @@ export class MapEmbeddable ); } + async _dispatchSetChartsPaletteServiceGetColor(syncColors?: boolean) { + this._prevSyncColors = syncColors; + const chartsPaletteServiceGetColor = syncColors + ? await getChartsPaletteServiceGetColor() + : null; + if (syncColors !== this._prevSyncColors) { + return; + } + this._savedMap + .getStore() + .dispatch(setChartsPaletteServiceGetColor(chartsPaletteServiceGetColor)); + } + /** * * @param {HTMLElement} domNode diff --git a/x-pack/plugins/maps/public/kibana_services.ts b/x-pack/plugins/maps/public/kibana_services.ts index 632a5f5382f73..1fbca669b0d8e 100644 --- a/x-pack/plugins/maps/public/kibana_services.ts +++ b/x-pack/plugins/maps/public/kibana_services.ts @@ -11,6 +11,7 @@ import { MapsLegacyConfig } from '../../../../src/plugins/maps_legacy/config'; import { MapsConfigType } from '../config'; import { MapsPluginStartDependencies } from './plugin'; import { EMSSettings } from '../common/ems_settings'; +import { PaletteRegistry } from '../../../../src/plugins/charts/public'; let kibanaVersion: string; export const setKibanaVersion = (version: string) => (kibanaVersion = version); @@ -26,7 +27,7 @@ export const getIndexPatternService = () => pluginsStart.data.indexPatterns; export const getAutocompleteService = () => pluginsStart.data.autocomplete; export const getInspector = () => pluginsStart.inspector; export const getFileUploadComponent = async () => { - return await pluginsStart.mapsFileUpload.getFileUploadComponent(); + return await pluginsStart.fileUpload.getFileUploadComponent(); }; export const getUiSettings = () => coreStart.uiSettings; export const getIsDarkMode = () => getUiSettings().get('theme:darkMode', false); @@ -83,3 +84,22 @@ export const getShareService = () => pluginsStart.share; export const getIsAllowByValueEmbeddables = () => pluginsStart.dashboard.dashboardFeatureFlagConfig.allowByValueEmbeddables; + +export async function getChartsPaletteServiceGetColor(): Promise< + ((value: string) => string) | null +> { + const paletteRegistry: PaletteRegistry | null = pluginsStart.charts + ? await pluginsStart.charts.palettes.getPalettes() + : null; + if (!paletteRegistry) { + return null; + } + + const paletteDefinition = paletteRegistry.get('default'); + const chartConfiguration = { syncColors: true }; + return (value: string) => { + const series = [{ name: value, rankAtDepth: 0, totalSeriesAtDepth: 1 }]; + const color = paletteDefinition.getColor(series, chartConfiguration); + return color ? color : '#3d3d3d'; + }; +} diff --git a/x-pack/plugins/maps/public/plugin.ts b/x-pack/plugins/maps/public/plugin.ts index 8889d1d44f10f..12cff9edf55ff 100644 --- a/x-pack/plugins/maps/public/plugin.ts +++ b/x-pack/plugins/maps/public/plugin.ts @@ -54,7 +54,7 @@ import { EmbeddableStart } from '../../../../src/plugins/embeddable/public'; import { MapsLegacyConfig } from '../../../../src/plugins/maps_legacy/config'; import { DataPublicPluginStart } from '../../../../src/plugins/data/public'; import { LicensingPluginSetup, LicensingPluginStart } from '../../licensing/public'; -import { StartContract as FileUploadStartContract } from '../../maps_file_upload/public'; +import { StartContract as FileUploadStartContract } from '../../file_upload/public'; import { SavedObjectsStart } from '../../../../src/plugins/saved_objects/public'; import { PresentationUtilPluginStart } from '../../../../src/plugins/presentation_util/public'; import { @@ -64,6 +64,7 @@ import { } from './licensed_features'; import { EMSSettings } from '../common/ems_settings'; import { SavedObjectTaggingPluginStart } from '../../saved_objects_tagging/public'; +import { ChartsPluginStart } from '../../../../src/plugins/charts/public'; export interface MapsPluginSetupDependencies { inspector: InspectorSetupContract; @@ -76,9 +77,10 @@ export interface MapsPluginSetupDependencies { } export interface MapsPluginStartDependencies { + charts: ChartsPluginStart; data: DataPublicPluginStart; embeddable: EmbeddableStart; - mapsFileUpload: FileUploadStartContract; + fileUpload: FileUploadStartContract; inspector: InspectorStartContract; licensing: LicensingPluginStart; navigation: NavigationPublicPluginStart; diff --git a/x-pack/plugins/maps/public/reducers/non_serializable_instances.d.ts b/x-pack/plugins/maps/public/reducers/non_serializable_instances.d.ts index 54a90946a5a89..9808a5e09b8ab 100644 --- a/x-pack/plugins/maps/public/reducers/non_serializable_instances.d.ts +++ b/x-pack/plugins/maps/public/reducers/non_serializable_instances.d.ts @@ -15,6 +15,7 @@ export type NonSerializableState = { inspectorAdapters: Adapters; cancelRequestCallbacks: Map {}>; // key is request token, value is cancel callback eventHandlers: Partial; + chartsPaletteServiceGetColor: (value: string) => string | null; }; export interface ResultMeta { @@ -58,6 +59,14 @@ export function getInspectorAdapters(state: MapStoreState): Adapters; export function getEventHandlers(state: MapStoreState): Partial; +export function getChartsPaletteServiceGetColor( + state: MapStoreState +): (value: string) => string | null; + +export function setChartsPaletteServiceGetColor( + chartsPaletteServiceGetColor: ((value: string) => string) | null +): AnyAction; + export function cancelRequest(requestToken?: symbol): AnyAction; export function registerCancelCallback(requestToken: symbol, callback: () => void): AnyAction; diff --git a/x-pack/plugins/maps/public/reducers/non_serializable_instances.js b/x-pack/plugins/maps/public/reducers/non_serializable_instances.js index 46846a8df3f23..4cc4e91a308a5 100644 --- a/x-pack/plugins/maps/public/reducers/non_serializable_instances.js +++ b/x-pack/plugins/maps/public/reducers/non_serializable_instances.js @@ -12,6 +12,7 @@ import { getShowMapsInspectorAdapter } from '../kibana_services'; const REGISTER_CANCEL_CALLBACK = 'REGISTER_CANCEL_CALLBACK'; const UNREGISTER_CANCEL_CALLBACK = 'UNREGISTER_CANCEL_CALLBACK'; const SET_EVENT_HANDLERS = 'SET_EVENT_HANDLERS'; +const SET_CHARTS_PALETTE_SERVICE_GET_COLOR = 'SET_CHARTS_PALETTE_SERVICE_GET_COLOR'; function createInspectorAdapters() { const inspectorAdapters = { @@ -30,6 +31,7 @@ export function nonSerializableInstances(state, action = {}) { inspectorAdapters: createInspectorAdapters(), cancelRequestCallbacks: new Map(), // key is request token, value is cancel callback eventHandlers: {}, + chartsPaletteServiceGetColor: null, }; } @@ -50,6 +52,12 @@ export function nonSerializableInstances(state, action = {}) { eventHandlers: action.eventHandlers, }; } + case SET_CHARTS_PALETTE_SERVICE_GET_COLOR: { + return { + ...state, + chartsPaletteServiceGetColor: action.chartsPaletteServiceGetColor, + }; + } default: return state; } @@ -68,6 +76,11 @@ export const getEventHandlers = ({ nonSerializableInstances }) => { return nonSerializableInstances.eventHandlers; }; +export function getChartsPaletteServiceGetColor({ nonSerializableInstances }) { + console.log('getChartsPaletteServiceGetColor', nonSerializableInstances); + return nonSerializableInstances.chartsPaletteServiceGetColor; +} + // Actions export const registerCancelCallback = (requestToken, callback) => { return { @@ -104,3 +117,10 @@ export const setEventHandlers = (eventHandlers = {}) => { eventHandlers, }; }; + +export function setChartsPaletteServiceGetColor(chartsPaletteServiceGetColor) { + return { + type: SET_CHARTS_PALETTE_SERVICE_GET_COLOR, + chartsPaletteServiceGetColor, + }; +} diff --git a/x-pack/plugins/maps/public/reducers/store.js b/x-pack/plugins/maps/public/reducers/store.js index 3c9b5d1b98e29..4e355add59fee 100644 --- a/x-pack/plugins/maps/public/reducers/store.js +++ b/x-pack/plugins/maps/public/reducers/store.js @@ -15,6 +15,7 @@ import { MAP_DESTROYED } from '../actions'; export const DEFAULT_MAP_STORE_STATE = { ui: { ...DEFAULT_MAP_UI_STATE }, map: { ...DEFAULT_MAP_STATE }, + nonSerializableInstances: {}, }; export function createMapStore() { diff --git a/x-pack/plugins/maps/public/selectors/map_selectors.test.ts b/x-pack/plugins/maps/public/selectors/map_selectors.test.ts index eb11ee61d9deb..c2f5fc02c5df2 100644 --- a/x-pack/plugins/maps/public/selectors/map_selectors.test.ts +++ b/x-pack/plugins/maps/public/selectors/map_selectors.test.ts @@ -5,17 +5,12 @@ * 2.0. */ -jest.mock('../classes/layers/vector_layer/vector_layer', () => {}); +jest.mock('../classes/layers/vector_layer', () => {}); jest.mock('../classes/layers/tiled_vector_layer/tiled_vector_layer', () => {}); jest.mock('../classes/layers/blended_vector_layer/blended_vector_layer', () => {}); -jest.mock('../classes/layers/heatmap_layer/heatmap_layer', () => {}); +jest.mock('../classes/layers/heatmap_layer', () => {}); jest.mock('../classes/layers/vector_tile_layer/vector_tile_layer', () => {}); jest.mock('../classes/joins/inner_join', () => {}); -jest.mock('../reducers/non_serializable_instances', () => ({ - getInspectorAdapters: () => { - return {}; - }, -})); jest.mock('../kibana_services', () => ({ getTimeFilter: () => ({ getTime: () => { diff --git a/x-pack/plugins/maps/public/selectors/map_selectors.ts b/x-pack/plugins/maps/public/selectors/map_selectors.ts index 34af789f6834f..f53f39ad2fc0c 100644 --- a/x-pack/plugins/maps/public/selectors/map_selectors.ts +++ b/x-pack/plugins/maps/public/selectors/map_selectors.ts @@ -12,13 +12,15 @@ import { Adapters } from 'src/plugins/inspector/public'; import { TileLayer } from '../classes/layers/tile_layer/tile_layer'; // @ts-ignore import { VectorTileLayer } from '../classes/layers/vector_tile_layer/vector_tile_layer'; -import { IVectorLayer, VectorLayer } from '../classes/layers/vector_layer/vector_layer'; +import { IVectorLayer, VectorLayer } from '../classes/layers/vector_layer'; import { VectorStyle } from '../classes/styles/vector/vector_style'; -// @ts-ignore -import { HeatmapLayer } from '../classes/layers/heatmap_layer/heatmap_layer'; +import { HeatmapLayer } from '../classes/layers/heatmap_layer'; import { BlendedVectorLayer } from '../classes/layers/blended_vector_layer/blended_vector_layer'; import { getTimeFilter } from '../kibana_services'; -import { getInspectorAdapters } from '../reducers/non_serializable_instances'; +import { + getChartsPaletteServiceGetColor, + getInspectorAdapters, +} from '../reducers/non_serializable_instances'; import { TiledVectorLayer } from '../classes/layers/tiled_vector_layer/tiled_vector_layer'; import { copyPersistentState, TRACKED_LAYER_DESCRIPTOR } from '../reducers/util'; import { InnerJoin } from '../classes/joins/inner_join'; @@ -38,6 +40,7 @@ import { DataRequestDescriptor, DrawState, Goto, + HeatmapLayerDescriptor, LayerDescriptor, MapCenter, MapExtent, @@ -51,11 +54,13 @@ import { Filter, TimeRange } from '../../../../../src/plugins/data/public'; import { ISource } from '../classes/sources/source'; import { ITMSSource } from '../classes/sources/tms_source'; import { IVectorSource } from '../classes/sources/vector_source'; +import { ESGeoGridSource } from '../classes/sources/es_geo_grid_source'; import { ILayer } from '../classes/layers/layer'; export function createLayerInstance( layerDescriptor: LayerDescriptor, - inspectorAdapters?: Adapters + inspectorAdapters?: Adapters, + chartsPaletteServiceGetColor?: (value: string) => string | null ): ILayer { const source: ISource = createSourceInstance(layerDescriptor.sourceDescriptor, inspectorAdapters); @@ -75,15 +80,20 @@ export function createLayerInstance( layerDescriptor: vectorLayerDescriptor, source: source as IVectorSource, joins, + chartsPaletteServiceGetColor, }); case VectorTileLayer.type: return new VectorTileLayer({ layerDescriptor, source: source as ITMSSource }); case HeatmapLayer.type: - return new HeatmapLayer({ layerDescriptor, source }); + return new HeatmapLayer({ + layerDescriptor: layerDescriptor as HeatmapLayerDescriptor, + source: source as ESGeoGridSource, + }); case BlendedVectorLayer.type: return new BlendedVectorLayer({ layerDescriptor: layerDescriptor as VectorLayerDescriptor, source: source as IVectorSource, + chartsPaletteServiceGetColor, }); case TiledVectorLayer.type: return new TiledVectorLayer({ @@ -295,9 +305,10 @@ export const getSpatialFiltersLayer = createSelector( export const getLayerList = createSelector( getLayerListRaw, getInspectorAdapters, - (layerDescriptorList, inspectorAdapters) => { + getChartsPaletteServiceGetColor, + (layerDescriptorList, inspectorAdapters, chartsPaletteServiceGetColor) => { return layerDescriptorList.map((layerDescriptor) => - createLayerInstance(layerDescriptor, inspectorAdapters) + createLayerInstance(layerDescriptor, inspectorAdapters, chartsPaletteServiceGetColor) ); } ); diff --git a/x-pack/plugins/maps/server/plugin.ts b/x-pack/plugins/maps/server/plugin.ts index 7440b6ee1e1df..cb22a98b70aa8 100644 --- a/x-pack/plugins/maps/server/plugin.ts +++ b/x-pack/plugins/maps/server/plugin.ts @@ -177,6 +177,7 @@ export class MapsPlugin implements Plugin { catalogue: [APP_ID], privileges: { all: { + api: ['fileUpload:import'], app: [APP_ID, 'kibana'], catalogue: [APP_ID], savedObject: { diff --git a/x-pack/plugins/maps/tsconfig.json b/x-pack/plugins/maps/tsconfig.json index b70459c690c07..4a8bfe2ebae66 100644 --- a/x-pack/plugins/maps/tsconfig.json +++ b/x-pack/plugins/maps/tsconfig.json @@ -19,7 +19,7 @@ { "path": "../../../src/plugins/maps_legacy/tsconfig.json" }, { "path": "../features/tsconfig.json" }, { "path": "../licensing/tsconfig.json" }, - { "path": "../maps_file_upload/tsconfig.json" }, + { "path": "../file_upload/tsconfig.json" }, { "path": "../saved_objects_tagging/tsconfig.json" }, ] } diff --git a/x-pack/plugins/maps_file_upload/README.md b/x-pack/plugins/maps_file_upload/README.md deleted file mode 100644 index 1e3343664afb8..0000000000000 --- a/x-pack/plugins/maps_file_upload/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Maps File upload - -Deprecated - plugin targeted for removal and will get merged into file_upload plugin diff --git a/x-pack/plugins/maps_file_upload/common/constants/file_import.ts b/x-pack/plugins/maps_file_upload/common/constants/file_import.ts deleted file mode 100644 index 9e4763c2c8113..0000000000000 --- a/x-pack/plugins/maps_file_upload/common/constants/file_import.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export const MAX_BYTES = 31457280; - -export const MAX_FILE_SIZE = 52428800; - -// Value to use in the Elasticsearch index mapping metadata to identify the -// index as having been created by the File Upload Plugin. -export const INDEX_META_DATA_CREATED_BY = 'file-upload-plugin'; - -export const ES_GEO_FIELD_TYPE = { - GEO_POINT: 'geo_point', - GEO_SHAPE: 'geo_shape', -}; - -export const DEFAULT_KBN_VERSION = 'kbnVersion'; diff --git a/x-pack/plugins/maps_file_upload/jest.config.js b/x-pack/plugins/maps_file_upload/jest.config.js deleted file mode 100644 index e7b45a559df10..0000000000000 --- a/x-pack/plugins/maps_file_upload/jest.config.js +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -module.exports = { - preset: '@kbn/test', - rootDir: '../../..', - roots: ['/x-pack/plugins/maps_file_upload'], -}; diff --git a/x-pack/plugins/maps_file_upload/kibana.json b/x-pack/plugins/maps_file_upload/kibana.json deleted file mode 100644 index f544c56cba517..0000000000000 --- a/x-pack/plugins/maps_file_upload/kibana.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "id": "mapsFileUpload", - "version": "8.0.0", - "kibanaVersion": "kibana", - "server": true, - "ui": true, - "requiredPlugins": ["data", "usageCollection"] -} diff --git a/x-pack/plugins/maps_file_upload/mappings.ts b/x-pack/plugins/maps_file_upload/mappings.ts deleted file mode 100644 index b8b263409f814..0000000000000 --- a/x-pack/plugins/maps_file_upload/mappings.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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export const mappings = { - 'file-upload-telemetry': { - properties: { - filesUploadedTotalCount: { - type: 'long', - }, - }, - }, -}; diff --git a/x-pack/plugins/maps_file_upload/server/index.js b/x-pack/plugins/maps_file_upload/server/index.js deleted file mode 100644 index 4bf4e931c7eaa..0000000000000 --- a/x-pack/plugins/maps_file_upload/server/index.js +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { FileUploadPlugin } from './plugin'; - -export * from './plugin'; - -export const plugin = () => new FileUploadPlugin(); diff --git a/x-pack/plugins/maps_file_upload/server/kibana_server_services.js b/x-pack/plugins/maps_file_upload/server/kibana_server_services.js deleted file mode 100644 index 8a1278f433ab9..0000000000000 --- a/x-pack/plugins/maps_file_upload/server/kibana_server_services.js +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -let internalRepository; -export const setInternalRepository = (createInternalRepository) => { - internalRepository = createInternalRepository(); -}; -export const getInternalRepository = () => internalRepository; diff --git a/x-pack/plugins/maps_file_upload/server/models/import_data/import_data.js b/x-pack/plugins/maps_file_upload/server/models/import_data/import_data.js deleted file mode 100644 index 7ba491a8ea49e..0000000000000 --- a/x-pack/plugins/maps_file_upload/server/models/import_data/import_data.js +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { INDEX_META_DATA_CREATED_BY } from '../../../common/constants/file_import'; -import uuid from 'uuid'; - -export function importDataProvider(callWithRequest) { - async function importData(id, index, settings, mappings, ingestPipeline, data) { - let createdIndex; - let createdPipelineId; - const docCount = data.length; - - try { - const { id: pipelineId, pipeline } = ingestPipeline; - - if (!id) { - // first chunk of data, create the index and id to return - id = uuid.v1(); - - await createIndex(index, settings, mappings); - createdIndex = index; - - // create the pipeline if one has been supplied - if (pipelineId !== undefined) { - const success = await createPipeline(pipelineId, pipeline); - if (success.acknowledged !== true) { - throw success; - } - } - createdPipelineId = pipelineId; - } else { - createdIndex = index; - createdPipelineId = pipelineId; - } - - let failures = []; - if (data.length) { - const resp = await indexData(index, createdPipelineId, data); - if (resp.success === false) { - if (resp.ingestError) { - // all docs failed, abort - throw resp; - } else { - // some docs failed. - // still report success but with a list of failures - failures = resp.failures || []; - } - } - } - - return { - success: true, - id, - index: createdIndex, - pipelineId: createdPipelineId, - docCount, - failures, - }; - } catch (error) { - return { - success: false, - id, - index: createdIndex, - pipelineId: createdPipelineId, - error: error.error !== undefined ? error.error : error, - docCount, - ingestError: error.ingestError, - failures: error.failures || [], - }; - } - } - - async function createIndex(index, settings, mappings) { - const body = { - mappings: { - _meta: { - created_by: INDEX_META_DATA_CREATED_BY, - }, - properties: mappings, - }, - }; - - if (settings && Object.keys(settings).length) { - body.settings = settings; - } - - await callWithRequest('indices.create', { index, body }); - } - - async function indexData(index, pipelineId, data) { - try { - const body = []; - for (let i = 0; i < data.length; i++) { - body.push({ index: {} }); - body.push(data[i]); - } - - const settings = { index, body }; - if (pipelineId !== undefined) { - settings.pipeline = pipelineId; - } - - const resp = await callWithRequest('bulk', settings); - if (resp.errors) { - throw resp; - } else { - return { - success: true, - docs: data.length, - failures: [], - }; - } - } catch (error) { - let failures = []; - let ingestError = false; - if (error.errors !== undefined && Array.isArray(error.items)) { - // an expected error where some or all of the bulk request - // docs have failed to be ingested. - failures = getFailures(error.items, data); - } else { - // some other error has happened. - ingestError = true; - } - - return { - success: false, - error, - docCount: data.length, - failures, - ingestError, - }; - } - } - - async function createPipeline(id, pipeline) { - return await callWithRequest('ingest.putPipeline', { id, body: pipeline }); - } - - function getFailures(items, data) { - const failures = []; - for (let i = 0; i < items.length; i++) { - const item = items[i]; - if (item.index && item.index.error) { - failures.push({ - item: i, - reason: item.index.error.reason, - doc: data[i], - }); - } - } - return failures; - } - - return { - importData, - }; -} diff --git a/x-pack/plugins/maps_file_upload/server/plugin.js b/x-pack/plugins/maps_file_upload/server/plugin.js deleted file mode 100644 index 1072da863acc7..0000000000000 --- a/x-pack/plugins/maps_file_upload/server/plugin.js +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { initRoutes } from './routes/file_upload'; -import { setInternalRepository } from './kibana_server_services'; -import { registerFileUploadUsageCollector, fileUploadTelemetryMappingsType } from './telemetry'; - -export class FileUploadPlugin { - constructor() { - this.router = null; - } - - setup(core, plugins) { - core.savedObjects.registerType(fileUploadTelemetryMappingsType); - this.router = core.http.createRouter(); - registerFileUploadUsageCollector(plugins.usageCollection); - } - - start(core) { - initRoutes(this.router, core.savedObjects.getSavedObjectsRepository); - setInternalRepository(core.savedObjects.createInternalRepository); - } -} diff --git a/x-pack/plugins/maps_file_upload/server/routes/file_upload.js b/x-pack/plugins/maps_file_upload/server/routes/file_upload.js deleted file mode 100644 index 1b617c44113a2..0000000000000 --- a/x-pack/plugins/maps_file_upload/server/routes/file_upload.js +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { importDataProvider } from '../models/import_data'; -import { updateTelemetry } from '../telemetry/telemetry'; -import { MAX_BYTES } from '../../common/constants/file_import'; -import { schema } from '@kbn/config-schema'; - -export const IMPORT_ROUTE = '/api/maps/fileupload/import'; - -export const querySchema = schema.maybe( - schema.object({ - id: schema.nullable(schema.string()), - }) -); - -export const bodySchema = schema.object( - { - app: schema.maybe(schema.string()), - index: schema.string(), - fileType: schema.string(), - ingestPipeline: schema.maybe( - schema.object( - {}, - { - defaultValue: {}, - unknowns: 'allow', - } - ) - ), - }, - { unknowns: 'allow' } -); - -const options = { - body: { - maxBytes: MAX_BYTES, - accepts: ['application/json'], - }, -}; - -export const idConditionalValidation = (body, boolHasId) => - schema - .object( - { - data: boolHasId - ? schema.arrayOf(schema.object({}, { unknowns: 'allow' }), { minSize: 1 }) - : schema.any(), - settings: boolHasId - ? schema.any() - : schema.object( - {}, - { - defaultValue: { - number_of_shards: 1, - }, - unknowns: 'allow', - } - ), - mappings: boolHasId - ? schema.any() - : schema.object( - {}, - { - defaultValue: {}, - unknowns: 'allow', - } - ), - }, - { unknowns: 'allow' } - ) - .validate(body); - -const finishValidationAndProcessReq = () => { - return async (con, req, { ok, badRequest }) => { - const { - query: { id }, - body, - } = req; - const boolHasId = !!id; - - let resp; - try { - const validIdReqData = idConditionalValidation(body, boolHasId); - const callWithRequest = con.core.elasticsearch.legacy.client.callAsCurrentUser; - const { importData: importDataFunc } = importDataProvider(callWithRequest); - - const { index, settings, mappings, ingestPipeline, data } = validIdReqData; - const processedReq = await importDataFunc( - id, - index, - settings, - mappings, - ingestPipeline, - data - ); - - if (processedReq.success) { - resp = ok({ body: processedReq }); - // If no id's been established then this is a new index, update telemetry - if (!boolHasId) { - await updateTelemetry(); - } - } else { - resp = badRequest(`Error processing request 1: ${processedReq.error.message}`, ['body']); - } - } catch (e) { - resp = badRequest(`Error processing request 2: : ${e.message}`, ['body']); - } - return resp; - }; -}; - -export const initRoutes = (router) => { - router.post( - { - path: `${IMPORT_ROUTE}{id?}`, - validate: { - query: querySchema, - body: bodySchema, - }, - options, - }, - finishValidationAndProcessReq() - ); -}; diff --git a/x-pack/plugins/maps_file_upload/server/routes/file_upload.test.js b/x-pack/plugins/maps_file_upload/server/routes/file_upload.test.js deleted file mode 100644 index e893e103aad72..0000000000000 --- a/x-pack/plugins/maps_file_upload/server/routes/file_upload.test.js +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { querySchema, bodySchema, idConditionalValidation } from './file_upload'; - -const queryWithId = { - id: '123', -}; - -const bodyWithoutQueryId = { - index: 'islandofone', - data: [], - settings: { number_of_shards: 1 }, - mappings: { coordinates: { type: 'geo_point' } }, - ingestPipeline: {}, - fileType: 'json', - app: 'Maps', -}; - -const bodyWithQueryId = { - index: 'islandofone2', - data: [{ coordinates: [], name: 'islandofone2' }], - settings: {}, - mappings: {}, - ingestPipeline: {}, - fileType: 'json', -}; - -describe('route validation', () => { - it(`validates query with id`, async () => { - const validationResult = querySchema.validate(queryWithId); - expect(validationResult.id).toBe(queryWithId.id); - }); - - it(`validates query without id`, async () => { - const validationResult = querySchema.validate({}); - expect(validationResult.id).toBeNull(); - }); - - it(`throws when query contains content other than an id`, async () => { - expect(() => querySchema.validate({ notAnId: 123 })).toThrowError( - `[notAnId]: definition for this key is missing` - ); - }); - - it(`validates body with valid fields`, async () => { - const validationResult = bodySchema.validate(bodyWithoutQueryId); - expect(validationResult).toEqual(bodyWithoutQueryId); - }); - - it(`throws if an expected field is missing`, async () => { - /* eslint-disable no-unused-vars */ - const { index, ...bodyWithoutIndexField } = bodyWithoutQueryId; - expect(() => bodySchema.validate(bodyWithoutIndexField)).toThrowError( - `[index]: expected value of type [string] but got [undefined]` - ); - }); - - it(`validates conditional fields when id has been provided in query`, async () => { - const validationResult = idConditionalValidation(bodyWithQueryId, true); - expect(validationResult).toEqual(bodyWithQueryId); - }); - - it(`validates conditional fields when no id has been provided in query`, async () => { - const validationResultWhenIdPresent = idConditionalValidation(bodyWithoutQueryId, false); - expect(validationResultWhenIdPresent).toEqual(bodyWithoutQueryId); - // Conditions for no id are more strict since this query sets up the index, - // expect it to throw if expected fields aren't present - expect(() => idConditionalValidation(bodyWithoutQueryId, true)).toThrowError( - `[data]: array size is [0], but cannot be smaller than [1]` - ); - }); -}); diff --git a/x-pack/plugins/maps_file_upload/server/telemetry/file_upload_usage_collector.ts b/x-pack/plugins/maps_file_upload/server/telemetry/file_upload_usage_collector.ts deleted file mode 100644 index bf786aa830448..0000000000000 --- a/x-pack/plugins/maps_file_upload/server/telemetry/file_upload_usage_collector.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; -import { getTelemetry, initTelemetry, Telemetry } from './telemetry'; - -export function registerFileUploadUsageCollector(usageCollection: UsageCollectionSetup): void { - const fileUploadUsageCollector = usageCollection.makeUsageCollector({ - type: 'fileUploadTelemetry', - isReady: () => true, - fetch: async () => { - const fileUploadUsage = await getTelemetry(); - if (!fileUploadUsage) { - return initTelemetry(); - } - - return fileUploadUsage; - }, - schema: { - filesUploadedTotalCount: { type: 'long' }, - }, - }); - - usageCollection.registerCollector(fileUploadUsageCollector); -} diff --git a/x-pack/plugins/maps_file_upload/server/telemetry/mappings.ts b/x-pack/plugins/maps_file_upload/server/telemetry/mappings.ts deleted file mode 100644 index ee79e2f6c6d47..0000000000000 --- a/x-pack/plugins/maps_file_upload/server/telemetry/mappings.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { SavedObjectsType } from 'src/core/server'; -import { TELEMETRY_DOC_ID } from './telemetry'; - -export const fileUploadTelemetryMappingsType: SavedObjectsType = { - name: TELEMETRY_DOC_ID, - hidden: false, - namespaceType: 'agnostic', - mappings: { - properties: { - filesUploadedTotalCount: { - type: 'long', - }, - }, - }, -}; diff --git a/x-pack/plugins/maps_file_upload/server/telemetry/telemetry.test.ts b/x-pack/plugins/maps_file_upload/server/telemetry/telemetry.test.ts deleted file mode 100644 index 2ca01b03aa633..0000000000000 --- a/x-pack/plugins/maps_file_upload/server/telemetry/telemetry.test.ts +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { getTelemetry, updateTelemetry } from './telemetry'; - -const internalRepository = () => ({ - get: jest.fn(() => null), - create: jest.fn(() => ({ attributes: 'test' })), - update: jest.fn(() => ({ attributes: 'test' })), -}); - -function mockInit(getVal: any = { attributes: {} }): any { - return { - ...internalRepository(), - get: jest.fn(() => getVal), - }; -} - -describe('file upload plugin telemetry', () => { - describe('getTelemetry', () => { - it('should get existing telemetry', async () => { - const internalRepo = mockInit(); - await getTelemetry(internalRepo); - expect(internalRepo.update.mock.calls.length).toBe(0); - expect(internalRepo.get.mock.calls.length).toBe(1); - expect(internalRepo.create.mock.calls.length).toBe(0); - }); - }); - - describe('updateTelemetry', () => { - it('should update existing telemetry', async () => { - const internalRepo = mockInit({ - attributes: { - filesUploadedTotalCount: 2, - }, - }); - - await updateTelemetry(internalRepo); - expect(internalRepo.update.mock.calls.length).toBe(1); - expect(internalRepo.get.mock.calls.length).toBe(1); - expect(internalRepo.create.mock.calls.length).toBe(0); - }); - }); -}); diff --git a/x-pack/plugins/maps_file_upload/server/telemetry/telemetry.ts b/x-pack/plugins/maps_file_upload/server/telemetry/telemetry.ts deleted file mode 100644 index 0e53c2570e01b..0000000000000 --- a/x-pack/plugins/maps_file_upload/server/telemetry/telemetry.ts +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import _ from 'lodash'; -// @ts-ignore -import { getInternalRepository } from '../kibana_server_services'; - -export const TELEMETRY_DOC_ID = 'file-upload-telemetry'; - -export interface Telemetry { - filesUploadedTotalCount: number; -} - -export interface TelemetrySavedObject { - attributes: Telemetry; -} - -export function initTelemetry(): Telemetry { - return { - filesUploadedTotalCount: 0, - }; -} - -export async function getTelemetry(internalRepo?: object): Promise { - const internalRepository = internalRepo || getInternalRepository(); - let telemetrySavedObject; - - try { - telemetrySavedObject = await internalRepository.get(TELEMETRY_DOC_ID, TELEMETRY_DOC_ID); - } catch (e) { - // Fail silently - } - - return telemetrySavedObject ? telemetrySavedObject.attributes : null; -} - -export async function updateTelemetry(internalRepo?: any) { - const internalRepository = internalRepo || getInternalRepository(); - let telemetry = await getTelemetry(internalRepository); - // Create if doesn't exist - if (!telemetry || _.isEmpty(telemetry)) { - const newTelemetrySavedObject = await internalRepository.create( - TELEMETRY_DOC_ID, - initTelemetry(), - { id: TELEMETRY_DOC_ID } - ); - telemetry = newTelemetrySavedObject.attributes; - } - - await internalRepository.update(TELEMETRY_DOC_ID, TELEMETRY_DOC_ID, incrementCounts(telemetry)); -} - -export function incrementCounts({ filesUploadedTotalCount }: { filesUploadedTotalCount: number }) { - return { - // TODO: get telemetry for app, total file counts, file type - filesUploadedTotalCount: filesUploadedTotalCount + 1, - }; -} diff --git a/x-pack/plugins/maps_file_upload/tsconfig.json b/x-pack/plugins/maps_file_upload/tsconfig.json deleted file mode 100644 index f068d62b71739..0000000000000 --- a/x-pack/plugins/maps_file_upload/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "extends": "../../../tsconfig.base.json", - "compilerOptions": { - "composite": true, - "outDir": "./target/types", - "emitDeclarationOnly": true, - "declaration": true, - "declarationMap": true - }, - "include": ["common/**/*", "public/**/*", "server/**/*", "mappings.ts"], - "references": [ - { "path": "../../../src/plugins/data/tsconfig.json" }, - { "path": "../../../src/plugins/usage_collection/tsconfig.json" } - ] -} diff --git a/x-pack/plugins/ml/common/types/capabilities.ts b/x-pack/plugins/ml/common/types/capabilities.ts index eb7615c79a363..974a1f2243060 100644 --- a/x-pack/plugins/ml/common/types/capabilities.ts +++ b/x-pack/plugins/ml/common/types/capabilities.ts @@ -99,7 +99,7 @@ export function getPluginPrivileges() { return { admin: { ...privilege, - api: allMlCapabilitiesKeys.map((k) => `ml:${k}`), + api: ['fileUpload:import', ...allMlCapabilitiesKeys.map((k) => `ml:${k}`)], catalogue: [PLUGIN_ID, `${PLUGIN_ID}_file_data_visualizer`], ui: allMlCapabilitiesKeys, savedObject: { diff --git a/x-pack/plugins/ml/common/types/modules.ts b/x-pack/plugins/ml/common/types/modules.ts index faa9c700f95a4..7c9623d3e68ec 100644 --- a/x-pack/plugins/ml/common/types/modules.ts +++ b/x-pack/plugins/ml/common/types/modules.ts @@ -68,6 +68,7 @@ export interface KibanaObjectResponse extends ResultItem { export interface DatafeedResponse extends ResultItem { started: boolean; + awaitingMlNodeAllocation?: boolean; error?: ErrorType; } diff --git a/x-pack/plugins/ml/public/application/components/jobs_awaiting_node_warning/jobs_awaiting_node_warning.tsx b/x-pack/plugins/ml/public/application/components/jobs_awaiting_node_warning/jobs_awaiting_node_warning.tsx index bc216ce62a57c..2cc36b7a2adf7 100644 --- a/x-pack/plugins/ml/public/application/components/jobs_awaiting_node_warning/jobs_awaiting_node_warning.tsx +++ b/x-pack/plugins/ml/public/application/components/jobs_awaiting_node_warning/jobs_awaiting_node_warning.tsx @@ -9,14 +9,14 @@ import React, { Fragment, FC } from 'react'; import { EuiCallOut, EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { isCloud } from '../../services/ml_server_info'; +import { lazyMlNodesAvailable } from '../../ml_nodes_check'; interface Props { jobCount: number; } export const JobsAwaitingNodeWarning: FC = ({ jobCount }) => { - if (isCloud() === false || jobCount === 0) { + if (lazyMlNodesAvailable() === false || jobCount === 0) { return null; } @@ -26,7 +26,7 @@ export const JobsAwaitingNodeWarning: FC = ({ jobCount }) => { title={ } color="primary" @@ -35,7 +35,7 @@ export const JobsAwaitingNodeWarning: FC = ({ jobCount }) => {
= () => { + if (lazyMlNodesAvailable() === false) { + return null; + } + return ( } color="primary" @@ -31,7 +36,7 @@ export const NewJobAwaitingNodeWarning: FC = () => {
diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_clone/clone_action_name.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_clone/clone_action_name.tsx index 039a00afe52ee..ee66612de97ac 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_clone/clone_action_name.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_clone/clone_action_name.tsx @@ -117,6 +117,10 @@ const getAnalyticsJobMeta = (config: CloneDataFrameAnalyticsConfig): AnalyticsJo optional: true, defaultValue: 'maximize_minimum_recall', }, + early_stopping_enabled: { + optional: true, + ignore: true, + }, }, } : {}), @@ -207,6 +211,10 @@ const getAnalyticsJobMeta = (config: CloneDataFrameAnalyticsConfig): AnalyticsJo loss_function_parameter: { optional: true, }, + early_stopping_enabled: { + optional: true, + ignore: true, + }, }, } : {}), diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/state.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/state.ts index 8de4470b028f5..a70962c45ffcb 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/state.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/state.ts @@ -56,6 +56,7 @@ export interface State { destinationIndexNameEmpty: boolean; destinationIndexNameValid: boolean; destinationIndexPatternTitleExists: boolean; + earlyStoppingEnabled: undefined | boolean; eta: undefined | number; featureBagFraction: undefined | number; featureInfluenceThreshold: undefined | number; @@ -125,6 +126,7 @@ export const getInitialState = (): State => ({ destinationIndexNameEmpty: true, destinationIndexNameValid: false, destinationIndexPatternTitleExists: false, + earlyStoppingEnabled: undefined, eta: undefined, featureBagFraction: undefined, featureInfluenceThreshold: undefined, @@ -239,7 +241,10 @@ export const getJobConfigFromFormState = ( formState.gamma && { gamma: formState.gamma }, formState.lambda && { lambda: formState.lambda }, formState.maxTrees && { max_trees: formState.maxTrees }, - formState.randomizeSeed && { randomize_seed: formState.randomizeSeed } + formState.randomizeSeed && { randomize_seed: formState.randomizeSeed }, + formState.earlyStoppingEnabled !== undefined && { + early_stopping_enabled: formState.earlyStoppingEnabled, + } ); jobConfig.analysis = { diff --git a/x-pack/plugins/ml/public/application/datavisualizer/file_based/components/file_datavisualizer_view/file_error_callouts.tsx b/x-pack/plugins/ml/public/application/datavisualizer/file_based/components/file_datavisualizer_view/file_error_callouts.tsx index 0535b15912a9b..0fa7de4732c39 100644 --- a/x-pack/plugins/ml/public/application/datavisualizer/file_based/components/file_datavisualizer_view/file_error_callouts.tsx +++ b/x-pack/plugins/ml/public/application/datavisualizer/file_based/components/file_datavisualizer_view/file_error_callouts.tsx @@ -12,7 +12,7 @@ import { EuiCallOut, EuiSpacer, EuiButtonEmpty, EuiHorizontalRule } from '@elast import numeral from '@elastic/numeral'; import { ErrorResponse } from '../../../../../../common/types/errors'; -import { FILE_SIZE_DISPLAY_FORMAT } from '../../../../../../../file_upload/common'; +import { FILE_SIZE_DISPLAY_FORMAT } from '../../../../../../../file_upload/public'; interface FileTooLargeProps { fileSize: number; diff --git a/x-pack/plugins/ml/public/application/datavisualizer/file_based/components/utils/utils.ts b/x-pack/plugins/ml/public/application/datavisualizer/file_based/components/utils/utils.ts index 47f262ef45a18..4412390d62c1f 100644 --- a/x-pack/plugins/ml/public/application/datavisualizer/file_based/components/utils/utils.ts +++ b/x-pack/plugins/ml/public/application/datavisualizer/file_based/components/utils/utils.ts @@ -15,7 +15,7 @@ import { MAX_FILE_SIZE_BYTES, ABSOLUTE_MAX_FILE_SIZE_BYTES, FILE_SIZE_DISPLAY_FORMAT, -} from '../../../../../../../file_upload/common'; +} from '../../../../../../../file_upload/public'; import { getUiSettings } from '../../../../util/dependency_cache'; import { FILE_DATA_VISUALIZER_MAX_FILE_SIZE } from '../../../../../../common/constants/settings'; diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/recognize/components/job_item.tsx b/x-pack/plugins/ml/public/application/jobs/new_job/recognize/components/job_item.tsx index 760ff67d97b9d..311e291cf2519 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/recognize/components/job_item.tsx +++ b/x-pack/plugins/ml/public/application/jobs/new_job/recognize/components/job_item.tsx @@ -21,7 +21,7 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { ModuleJobUI } from '../page'; import { SETUP_RESULTS_WIDTH } from './module_jobs'; import { tabColor } from '../../../../../../common/util/group_color_utils'; -import { JobOverride } from '../../../../../../common/types/modules'; +import { JobOverride, DatafeedResponse } from '../../../../../../common/types/modules'; import { extractErrorMessage } from '../../../../../../common/util/errors'; interface JobItemProps { @@ -151,8 +151,8 @@ export const JobItem: FC = memo( = memo( ); } ); + +function getDatafeedStartedIcon({ + awaitingMlNodeAllocation, + success, +}: DatafeedResponse): { type: string; color: string } { + if (awaitingMlNodeAllocation === true) { + return { type: 'alert', color: 'warning' }; + } + + return success ? { type: 'check', color: 'secondary' } : { type: 'cross', color: 'danger' }; +} diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/recognize/page.tsx b/x-pack/plugins/ml/public/application/jobs/new_job/recognize/page.tsx index 14018d485e04c..271898654ca49 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/recognize/page.tsx +++ b/x-pack/plugins/ml/public/application/jobs/new_job/recognize/page.tsx @@ -43,6 +43,7 @@ import { TimeRange } from '../common/components'; import { JobId } from '../../../../../common/types/anomaly_detection_jobs'; import { ML_PAGES } from '../../../../../common/constants/ml_url_generator'; import { TIME_FORMAT } from '../../../../../common/constants/time_format'; +import { JobsAwaitingNodeWarning } from '../../../components/jobs_awaiting_node_warning'; export interface ModuleJobUI extends ModuleJob { datafeedResult?: DatafeedResponse; @@ -84,6 +85,7 @@ export const Page: FC = ({ moduleId, existingGroupIds }) => { const [saveState, setSaveState] = useState(SAVE_STATE.NOT_SAVED); const [resultsUrl, setResultsUrl] = useState(''); const [existingGroups, setExistingGroups] = useState(existingGroupIds); + const [jobsAwaitingNodeCount, setJobsAwaitingNodeCount] = useState(0); // #endregion const { @@ -204,9 +206,19 @@ export const Page: FC = ({ moduleId, existingGroupIds }) => { }); setResultsUrl(url); - const failedJobsCount = jobsResponse.reduce((count, { success }) => { - return success ? count : count + 1; - }, 0); + const failedJobsCount = jobsResponse.reduce( + (count, { success }) => (success ? count : count + 1), + 0 + ); + + const lazyJobsCount = datafeedsResponse.reduce( + (count, { awaitingMlNodeAllocation }) => + awaitingMlNodeAllocation === true ? count + 1 : count, + 0 + ); + + setJobsAwaitingNodeCount(lazyJobsCount); + setSaveState( failedJobsCount === 0 ? SAVE_STATE.SAVED @@ -291,6 +303,8 @@ export const Page: FC = ({ moduleId, existingGroupIds }) => { )} + {jobsAwaitingNodeCount > 0 && } + diff --git a/x-pack/plugins/ml/public/application/ml_nodes_check/check_ml_nodes.ts b/x-pack/plugins/ml/public/application/ml_nodes_check/check_ml_nodes.ts index 71aef2da312a6..551a5823c1f41 100644 --- a/x-pack/plugins/ml/public/application/ml_nodes_check/check_ml_nodes.ts +++ b/x-pack/plugins/ml/public/application/ml_nodes_check/check_ml_nodes.ts @@ -48,6 +48,14 @@ export function mlNodesAvailable() { return mlNodeCount !== 0 || lazyMlNodeCount !== 0; } +export function currentMlNodesAvailable() { + return mlNodeCount !== 0; +} + +export function lazyMlNodesAvailable() { + return lazyMlNodeCount !== 0; +} + export function permissionToViewMlNodeCount() { return userHasPermissionToViewMlNodeCount; } diff --git a/x-pack/plugins/ml/public/application/ml_nodes_check/index.ts b/x-pack/plugins/ml/public/application/ml_nodes_check/index.ts index 295ff1aca2ec7..8102f95c035b0 100644 --- a/x-pack/plugins/ml/public/application/ml_nodes_check/index.ts +++ b/x-pack/plugins/ml/public/application/ml_nodes_check/index.ts @@ -9,5 +9,6 @@ export { checkMlNodesAvailable, getMlNodeCount, mlNodesAvailable, + lazyMlNodesAvailable, permissionToViewMlNodeCount, } from './check_ml_nodes'; diff --git a/x-pack/plugins/ml/public/application/timeseriesexplorer/components/forecasting_modal/run_controls.js b/x-pack/plugins/ml/public/application/timeseriesexplorer/components/forecasting_modal/run_controls.js index a37ad5fd30517..b36acba8b4ba4 100644 --- a/x-pack/plugins/ml/public/application/timeseriesexplorer/components/forecasting_modal/run_controls.js +++ b/x-pack/plugins/ml/public/application/timeseriesexplorer/components/forecasting_modal/run_controls.js @@ -27,7 +27,7 @@ import { import { JOB_STATE } from '../../../../../common/constants/states'; import { FORECAST_DURATION_MAX_DAYS } from './forecasting_modal'; import { ForecastProgress } from './forecast_progress'; -import { mlNodesAvailable } from '../../../ml_nodes_check/check_ml_nodes'; +import { currentMlNodesAvailable } from '../../../ml_nodes_check/check_ml_nodes'; import { checkPermission, createPermissionFailureMessage, @@ -41,7 +41,7 @@ function getRunInputDisabledState(job, isForecastRequested) { // - No canForecastJob permission // - Job is not in an OPENED or CLOSED state // - A new forecast has been requested - if (mlNodesAvailable() === false) { + if (currentMlNodesAvailable() === false) { return { isDisabled: true, isDisabledToolTipText: i18n.translate( diff --git a/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/swimlane_input_resolver.ts b/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/swimlane_input_resolver.ts index 0d75db64a01b9..fa0cccda99d22 100644 --- a/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/swimlane_input_resolver.ts +++ b/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/swimlane_input_resolver.ts @@ -36,7 +36,7 @@ import { parseInterval } from '../../../common/util/parse_interval'; import { AnomalyDetectorService } from '../../application/services/anomaly_detector_service'; import { isViewBySwimLaneData } from '../../application/explorer/swimlane_container'; import { ViewMode } from '../../../../../../src/plugins/embeddable/public'; -import { CONTROLLED_BY_SWIM_LANE_FILTER } from '../../ui_actions/apply_influencer_filters_action'; +import { CONTROLLED_BY_SWIM_LANE_FILTER } from '../../ui_actions/constants'; import { AnomalySwimlaneEmbeddableInput, AnomalySwimlaneEmbeddableOutput, diff --git a/x-pack/plugins/ml/public/index.ts b/x-pack/plugins/ml/public/index.ts index 1c4aa4031171d..c88ce2d7f95d2 100755 --- a/x-pack/plugins/ml/public/index.ts +++ b/x-pack/plugins/ml/public/index.ts @@ -39,8 +39,18 @@ export type { RenderCellValue, } from './shared'; +export type { AnomalySwimlaneEmbeddableInput } from './embeddables'; + +export { ANOMALY_SWIMLANE_EMBEDDABLE_TYPE } from './embeddables/constants'; +export { CONTROLLED_BY_SWIM_LANE_FILTER } from './ui_actions/constants'; + // Static exports -export { getSeverityColor, getSeverityType } from '../common/util/anomaly_utils'; +export { + getSeverityColor, + getSeverityType, + getFormattedSeverityScore, +} from '../common/util/anomaly_utils'; + export { ANOMALY_SEVERITY } from '../common'; export { useMlHref, ML_PAGES, MlUrlGenerator } from './ml_url_generator'; diff --git a/x-pack/plugins/ml/public/ui_actions/apply_influencer_filters_action.tsx b/x-pack/plugins/ml/public/ui_actions/apply_influencer_filters_action.tsx index e9b70ee14aae6..e3d2ca4ce0de1 100644 --- a/x-pack/plugins/ml/public/ui_actions/apply_influencer_filters_action.tsx +++ b/x-pack/plugins/ml/public/ui_actions/apply_influencer_filters_action.tsx @@ -11,11 +11,10 @@ import { MlCoreSetup } from '../plugin'; import { SWIMLANE_TYPE, VIEW_BY_JOB_LABEL } from '../application/explorer/explorer_constants'; import { Filter, FilterStateStore } from '../../../../../src/plugins/data/common'; import { ANOMALY_SWIMLANE_EMBEDDABLE_TYPE, SwimLaneDrilldownContext } from '../embeddables'; +import { CONTROLLED_BY_SWIM_LANE_FILTER } from './constants'; export const APPLY_INFLUENCER_FILTERS_ACTION = 'applyInfluencerFiltersAction'; -export const CONTROLLED_BY_SWIM_LANE_FILTER = 'anomaly-swim-lane'; - export function createApplyInfluencerFiltersAction( getStartServices: MlCoreSetup['getStartServices'] ) { diff --git a/x-pack/jest.config.js b/x-pack/plugins/ml/public/ui_actions/constants.ts similarity index 67% rename from x-pack/jest.config.js rename to x-pack/plugins/ml/public/ui_actions/constants.ts index 231004359632b..6dc3f03d10fd9 100644 --- a/x-pack/jest.config.js +++ b/x-pack/plugins/ml/public/ui_actions/constants.ts @@ -5,8 +5,4 @@ * 2.0. */ -module.exports = { - preset: '@kbn/test', - rootDir: '..', - projects: ['/x-pack/plugins/*/jest.config.js'], -}; +export const CONTROLLED_BY_SWIM_LANE_FILTER = 'anomaly-swim-lane'; diff --git a/x-pack/plugins/ml/server/models/data_recognizer/data_recognizer.ts b/x-pack/plugins/ml/server/models/data_recognizer/data_recognizer.ts index 92dfe3aa0fbf9..a1fac92d45b4e 100644 --- a/x-pack/plugins/ml/server/models/data_recognizer/data_recognizer.ts +++ b/x-pack/plugins/ml/server/models/data_recognizer/data_recognizer.ts @@ -491,6 +491,7 @@ export class DataRecognizer { const startedDatafeed = startResults[df.id]; if (startedDatafeed !== undefined) { df.started = startedDatafeed.started; + df.awaitingMlNodeAllocation = startedDatafeed.awaitingMlNodeAllocation; if (startedDatafeed.error !== undefined) { df.error = startedDatafeed.error; } @@ -749,9 +750,20 @@ export class DataRecognizer { datafeeds.map(async (datafeed) => { try { await this.saveDatafeed(datafeed); - return { id: datafeed.id, success: true, started: false }; + return { + id: datafeed.id, + success: true, + started: false, + awaitingMlNodeAllocation: false, + }; } catch ({ body }) { - return { id: datafeed.id, success: false, started: false, error: body }; + return { + id: datafeed.id, + success: false, + started: false, + awaitingMlNodeAllocation: false, + error: body, + }; } }) ); @@ -811,11 +823,18 @@ export class DataRecognizer { duration.end = (end as unknown) as string; } - await this._mlClient.startDatafeed({ + const { + body: { started, node }, + } = await this._mlClient.startDatafeed<{ + started: boolean; + node: string; + }>({ datafeed_id: datafeed.id, ...duration, }); - result.started = true; + + result.started = started; + result.awaitingMlNodeAllocation = node?.length === 0; } catch ({ body }) { result.started = false; result.error = body; @@ -845,6 +864,7 @@ export class DataRecognizer { if (d.id === d2.id) { d.success = d2.success; d.started = d2.started; + d.awaitingMlNodeAllocation = d2.awaitingMlNodeAllocation; if (d2.error !== undefined) { d.error = d2.error; } diff --git a/x-pack/plugins/monitoring/server/es_client/monitoring_endpoint_disable_watches.ts b/x-pack/plugins/monitoring/server/es_client/monitoring_endpoint_disable_watches.ts index 454379d17848e..8e9e8d916e496 100644 --- a/x-pack/plugins/monitoring/server/es_client/monitoring_endpoint_disable_watches.ts +++ b/x-pack/plugins/monitoring/server/es_client/monitoring_endpoint_disable_watches.ts @@ -13,7 +13,7 @@ export function monitoringEndpointDisableWatches(Client: any, _config: any, comp params: {}, urls: [ { - fmt: '_monitoring/migrate/alerts', + fmt: '/_monitoring/migrate/alerts', }, ], method: 'POST', diff --git a/x-pack/plugins/remote_clusters/server/routes/api/add_route.test.ts b/x-pack/plugins/remote_clusters/server/routes/api/add_route.test.ts index 066a2d56cbeec..9348fd1eb20df 100644 --- a/x-pack/plugins/remote_clusters/server/routes/api/add_route.test.ts +++ b/x-pack/plugins/remote_clusters/server/routes/api/add_route.test.ts @@ -10,13 +10,26 @@ import { register } from './add_route'; import { API_BASE_PATH } from '../../../common/constants'; import { LicenseStatus } from '../../types'; -import { xpackMocks } from '../../../../../mocks'; +import { licensingMock } from '../../../../../plugins/licensing/server/mocks'; + import { elasticsearchServiceMock, httpServerMock, httpServiceMock, + coreMock, } from '../../../../../../src/core/server/mocks'; +// Re-implement the mock that was imported directly from `x-pack/mocks` +function createCoreRequestHandlerContextMock() { + return { + core: coreMock.createRequestHandlerContext(), + licensing: licensingMock.createRequestHandlerContext(), + }; +} + +const xpackMocks = { + createRequestHandlerContext: createCoreRequestHandlerContextMock, +}; interface TestOptions { licenseCheckResult?: LicenseStatus; apiResponses?: Array<() => Promise>; diff --git a/x-pack/plugins/remote_clusters/server/routes/api/delete_route.test.ts b/x-pack/plugins/remote_clusters/server/routes/api/delete_route.test.ts index 29d846314bd9b..ce94f45bb8443 100644 --- a/x-pack/plugins/remote_clusters/server/routes/api/delete_route.test.ts +++ b/x-pack/plugins/remote_clusters/server/routes/api/delete_route.test.ts @@ -10,13 +10,26 @@ import { register } from './delete_route'; import { API_BASE_PATH } from '../../../common/constants'; import { LicenseStatus } from '../../types'; -import { xpackMocks } from '../../../../../mocks'; +import { licensingMock } from '../../../../../plugins/licensing/server/mocks'; + import { elasticsearchServiceMock, httpServerMock, httpServiceMock, + coreMock, } from '../../../../../../src/core/server/mocks'; +// Re-implement the mock that was imported directly from `x-pack/mocks` +function createCoreRequestHandlerContextMock() { + return { + core: coreMock.createRequestHandlerContext(), + licensing: licensingMock.createRequestHandlerContext(), + }; +} + +const xpackMocks = { + createRequestHandlerContext: createCoreRequestHandlerContextMock, +}; interface TestOptions { licenseCheckResult?: LicenseStatus; apiResponses?: Array<() => Promise>; diff --git a/x-pack/plugins/remote_clusters/server/routes/api/get_route.test.ts b/x-pack/plugins/remote_clusters/server/routes/api/get_route.test.ts index 33a3142ddc105..25d17d796b0ee 100644 --- a/x-pack/plugins/remote_clusters/server/routes/api/get_route.test.ts +++ b/x-pack/plugins/remote_clusters/server/routes/api/get_route.test.ts @@ -12,13 +12,26 @@ import { register } from './get_route'; import { API_BASE_PATH } from '../../../common/constants'; import { LicenseStatus } from '../../types'; -import { xpackMocks } from '../../../../../mocks'; +import { licensingMock } from '../../../../../plugins/licensing/server/mocks'; + import { elasticsearchServiceMock, httpServerMock, httpServiceMock, + coreMock, } from '../../../../../../src/core/server/mocks'; +// Re-implement the mock that was imported directly from `x-pack/mocks` +function createCoreRequestHandlerContextMock() { + return { + core: coreMock.createRequestHandlerContext(), + licensing: licensingMock.createRequestHandlerContext(), + }; +} + +const xpackMocks = { + createRequestHandlerContext: createCoreRequestHandlerContextMock, +}; interface TestOptions { licenseCheckResult?: LicenseStatus; apiResponses?: Array<() => Promise>; diff --git a/x-pack/plugins/remote_clusters/server/routes/api/update_route.test.ts b/x-pack/plugins/remote_clusters/server/routes/api/update_route.test.ts index 31db362f7c953..22c87786a585c 100644 --- a/x-pack/plugins/remote_clusters/server/routes/api/update_route.test.ts +++ b/x-pack/plugins/remote_clusters/server/routes/api/update_route.test.ts @@ -10,13 +10,26 @@ import { register } from './update_route'; import { API_BASE_PATH } from '../../../common/constants'; import { LicenseStatus } from '../../types'; -import { xpackMocks } from '../../../../../mocks'; +import { licensingMock } from '../../../../../plugins/licensing/server/mocks'; + import { elasticsearchServiceMock, httpServerMock, httpServiceMock, + coreMock, } from '../../../../../../src/core/server/mocks'; +// Re-implement the mock that was imported directly from `x-pack/mocks` +function createCoreRequestHandlerContextMock() { + return { + core: coreMock.createRequestHandlerContext(), + licensing: licensingMock.createRequestHandlerContext(), + }; +} + +const xpackMocks = { + createRequestHandlerContext: createCoreRequestHandlerContextMock, +}; interface TestOptions { licenseCheckResult?: LicenseStatus; apiResponses?: Array<() => Promise>; diff --git a/x-pack/plugins/remote_clusters/tsconfig.json b/x-pack/plugins/remote_clusters/tsconfig.json new file mode 100644 index 0000000000000..0bee6300cf0b2 --- /dev/null +++ b/x-pack/plugins/remote_clusters/tsconfig.json @@ -0,0 +1,30 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "composite": true, + "outDir": "./target/types", + "emitDeclarationOnly": true, + "declaration": true, + "declarationMap": true + }, + "include": [ + "common/**/*", + "fixtures/**/*", + "public/**/*", + "server/**/*", + ], + "references": [ + { "path": "../../../src/core/tsconfig.json" }, + // required plugins + { "path": "../licensing/tsconfig.json" }, + { "path": "../../../src/plugins/management/tsconfig.json" }, + { "path": "../index_management/tsconfig.json" }, + { "path": "../features/tsconfig.json" }, + // optional plugins + { "path": "../../../src/plugins/usage_collection/tsconfig.json" }, + { "path": "../cloud/tsconfig.json" }, + // required bundles + { "path": "../../../src/plugins/kibana_react/tsconfig.json" }, + { "path": "../../../src/plugins/es_ui_shared/tsconfig.json" }, + ] +} diff --git a/x-pack/plugins/rollup/tsconfig.json b/x-pack/plugins/rollup/tsconfig.json new file mode 100644 index 0000000000000..9b994d1710ffc --- /dev/null +++ b/x-pack/plugins/rollup/tsconfig.json @@ -0,0 +1,35 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "composite": true, + "outDir": "./target/types", + "emitDeclarationOnly": true, + "declaration": true, + "declarationMap": true + }, + "include": [ + "common/**/*", + "fixtures/**/*", + "public/**/*", + "server/**/*", + ], + "references": [ + { "path": "../../../src/core/tsconfig.json" }, + // required plugins + { "path": "../../../src/plugins/index_pattern_management/tsconfig.json" }, + { "path": "../../../src/plugins/management/tsconfig.json" }, + { "path": "../licensing/tsconfig.json" }, + { "path": "../features/tsconfig.json" }, + // optional plugins + { "path": "../../../src/plugins/home/tsconfig.json" }, + { "path": "../index_management/tsconfig.json" }, + { "path": "../../../src/plugins/usage_collection/tsconfig.json" }, + { "path": "../../../src/plugins/vis_type_timeseries/tsconfig.json" }, + // required bundles + { "path": "../../../src/plugins/kibana_utils/tsconfig.json" }, + { "path": "../../../src/plugins/kibana_react/tsconfig.json" }, + { "path": "../../../src/plugins/es_ui_shared/tsconfig.json" }, + { "path": "../../../src/plugins/data/tsconfig.json" }, + + ] +} diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline_modal/open_timeline_modal_body.tsx b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline_modal/open_timeline_modal_body.tsx index 13b9c9ef4f519..1616c5e84247f 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline_modal/open_timeline_modal_body.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline_modal/open_timeline_modal_body.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { EuiModalBody, EuiModalHeader } from '@elastic/eui'; +import { EuiModalBody, EuiModalHeader, EuiSpacer } from '@elastic/eui'; import React, { Fragment, memo, useMemo } from 'react'; import styled from 'styled-components'; @@ -62,11 +62,10 @@ export const OpenTimelineModalBody = memo( const SearchRowContent = useMemo( () => ( - {!!timelineFilter && timelineFilter} {!!templateTimelineFilter && templateTimelineFilter} ), - [timelineFilter, templateTimelineFilter] + [templateTimelineFilter] ); return ( @@ -84,9 +83,14 @@ export const OpenTimelineModalBody = memo( <> + {!!timelineFilter && ( + <> + {timelineFilter} + + + )} & { */ export const TitleRow = React.memo( ({ children, onAddTimelinesToFavorites, selectedTimelinesCount, title }) => ( - + {onAddTimelinesToFavorites && ( diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/translations.ts b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/translations.ts index 84907c74cdace..ae743ad30eef1 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/translations.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/translations.ts @@ -146,7 +146,7 @@ export const OPEN_TIMELINE = i18n.translate( export const OPEN_TIMELINE_TITLE = i18n.translate( 'xpack.securitySolution.open.timeline.openTimelineTitle', { - defaultMessage: 'Open Timeline', + defaultMessage: 'Open', } ); @@ -274,12 +274,6 @@ export const SUCCESSFULLY_EXPORTED_TIMELINE_TEMPLATES = (totalTimelineTemplates: } ); -export const FILTER_TIMELINES = (timelineType: string) => - i18n.translate('xpack.securitySolution.open.timeline.filterByTimelineTypesTitle', { - values: { timelineType }, - defaultMessage: 'Only {timelineType}', - }); - export const TAB_TIMELINES = i18n.translate( 'xpack.securitySolution.timelines.components.tabs.timelinesTitle', { diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/types.ts b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/types.ts index ddf567edafe13..ad62bda4c9783 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/types.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/types.ts @@ -221,13 +221,11 @@ export enum TimelineTabsStyle { } export interface TimelineTab { - count: number | undefined; disabled: boolean; href: string; id: TimelineTypeLiteral; name: string; onClick: (ev: { preventDefault: () => void }) => void; - withNext: boolean; } export interface TemplateTimelineFilter { diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/use_timeline_types.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/use_timeline_types.test.tsx new file mode 100644 index 0000000000000..1d39dd169ffaa --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/use_timeline_types.test.tsx @@ -0,0 +1,193 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { fireEvent, render } from '@testing-library/react'; +import { renderHook, act } from '@testing-library/react-hooks'; +import { + useTimelineTypes, + UseTimelineTypesArgs, + UseTimelineTypesResult, +} from './use_timeline_types'; + +jest.mock('react-router-dom', () => { + return { + useParams: jest.fn().mockReturnValue('default'), + useHistory: jest.fn().mockReturnValue([]), + }; +}); + +jest.mock('../../../common/components/link_to', () => { + return { + getTimelineTabsUrl: jest.fn(), + useFormatUrl: jest.fn().mockReturnValue({ + formatUrl: jest.fn(), + search: '', + }), + }; +}); + +describe('useTimelineTypes', () => { + it('init', async () => { + await act(async () => { + const { result, waitForNextUpdate } = renderHook< + UseTimelineTypesArgs, + UseTimelineTypesResult + >(() => useTimelineTypes({ defaultTimelineCount: 0, templateTimelineCount: 3 })); + await waitForNextUpdate(); + expect(result.current).toEqual({ + timelineType: 'default', + timelineTabs: result.current.timelineTabs, + timelineFilters: result.current.timelineFilters, + }); + }); + }); + + describe('timelineTabs', () => { + it('render timelineTabs', async () => { + await act(async () => { + const { result, waitForNextUpdate } = renderHook< + UseTimelineTypesArgs, + UseTimelineTypesResult + >(() => useTimelineTypes({ defaultTimelineCount: 0, templateTimelineCount: 3 })); + await waitForNextUpdate(); + + const { container } = render(result.current.timelineTabs); + expect( + container.querySelector('[data-test-subj="timeline-tab-default"]') + ).toHaveTextContent('Timelines'); + expect( + container.querySelector('[data-test-subj="timeline-tab-template"]') + ).toHaveTextContent('Templates'); + }); + }); + + it('set timelineTypes correctly', async () => { + await act(async () => { + const { result, waitForNextUpdate } = renderHook< + UseTimelineTypesArgs, + UseTimelineTypesResult + >(() => useTimelineTypes({ defaultTimelineCount: 0, templateTimelineCount: 3 })); + await waitForNextUpdate(); + + const { container } = render(result.current.timelineTabs); + + fireEvent( + container.querySelector('[data-test-subj="timeline-tab-template"]')!, + new MouseEvent('click', { + bubbles: true, + cancelable: true, + }) + ); + + expect(result.current).toEqual({ + timelineType: 'template', + timelineTabs: result.current.timelineTabs, + timelineFilters: result.current.timelineFilters, + }); + }); + }); + + it('stays in the same tab if clicking again on current tab', async () => { + await act(async () => { + const { result, waitForNextUpdate } = renderHook< + UseTimelineTypesArgs, + UseTimelineTypesResult + >(() => useTimelineTypes({ defaultTimelineCount: 0, templateTimelineCount: 3 })); + await waitForNextUpdate(); + + const { container } = render(result.current.timelineTabs); + + fireEvent( + container.querySelector('[data-test-subj="timeline-tab-default"]')!, + new MouseEvent('click', { + bubbles: true, + cancelable: true, + }) + ); + + expect(result.current).toEqual({ + timelineType: 'default', + timelineTabs: result.current.timelineTabs, + timelineFilters: result.current.timelineFilters, + }); + }); + }); + }); + + describe('timelineFilters', () => { + it('render timelineFilters', async () => { + await act(async () => { + const { result, waitForNextUpdate } = renderHook< + UseTimelineTypesArgs, + UseTimelineTypesResult + >(() => useTimelineTypes({ defaultTimelineCount: 0, templateTimelineCount: 3 })); + await waitForNextUpdate(); + + const { container } = render(<>{result.current.timelineFilters}); + expect( + container.querySelector('[data-test-subj="open-timeline-modal-body-filter-default"]') + ).toHaveTextContent('Timelines'); + expect( + container.querySelector('[data-test-subj="open-timeline-modal-body-filter-template"]') + ).toHaveTextContent('Templates'); + }); + }); + + it('set timelineTypes correctly', async () => { + await act(async () => { + const { result, waitForNextUpdate } = renderHook< + UseTimelineTypesArgs, + UseTimelineTypesResult + >(() => useTimelineTypes({ defaultTimelineCount: 0, templateTimelineCount: 3 })); + await waitForNextUpdate(); + + const { container } = render(<>{result.current.timelineFilters}); + + fireEvent( + container.querySelector('[data-test-subj="open-timeline-modal-body-filter-template"]')!, + new MouseEvent('click', { + bubbles: true, + cancelable: true, + }) + ); + + expect(result.current).toEqual({ + timelineType: 'template', + timelineTabs: result.current.timelineTabs, + timelineFilters: result.current.timelineFilters, + }); + }); + }); + + it('stays in the same tab if clicking again on current tab', async () => { + await act(async () => { + const { result, waitForNextUpdate } = renderHook< + UseTimelineTypesArgs, + UseTimelineTypesResult + >(() => useTimelineTypes({ defaultTimelineCount: 0, templateTimelineCount: 3 })); + await waitForNextUpdate(); + + const { container } = render(<>{result.current.timelineFilters}); + + fireEvent( + container.querySelector('[data-test-subj="open-timeline-modal-body-filter-default"]')!, + new MouseEvent('click', { + bubbles: true, + cancelable: true, + }) + ); + + expect(result.current).toEqual({ + timelineType: 'default', + timelineTabs: result.current.timelineTabs, + timelineFilters: result.current.timelineFilters, + }); + }); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/use_timeline_types.tsx b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/use_timeline_types.tsx index 728d8b6eeb488..a66fe43d305f1 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/use_timeline_types.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/use_timeline_types.tsx @@ -7,7 +7,7 @@ import React, { useState, useCallback, useMemo } from 'react'; import { useParams, useHistory } from 'react-router-dom'; -import { EuiTabs, EuiTab, EuiSpacer, EuiFilterButton } from '@elastic/eui'; +import { EuiTabs, EuiTab, EuiSpacer } from '@elastic/eui'; import { noop } from 'lodash/fp'; import { TimelineTypeLiteralWithNull, TimelineType } from '../../../../common/types/timeline'; @@ -24,7 +24,7 @@ export interface UseTimelineTypesArgs { export interface UseTimelineTypesResult { timelineType: TimelineTypeLiteralWithNull; timelineTabs: JSX.Element; - timelineFilters: JSX.Element[]; + timelineFilters: JSX.Element; } export const useTimelineTypes = ({ @@ -59,51 +59,28 @@ export const useTimelineTypes = ({ (timelineTabsStyle: TimelineTabsStyle) => [ { id: TimelineType.default, - name: - timelineTabsStyle === TimelineTabsStyle.filter - ? i18n.FILTER_TIMELINES(i18n.TAB_TIMELINES) - : i18n.TAB_TIMELINES, + name: i18n.TAB_TIMELINES, href: formatUrl(getTimelineTabsUrl(TimelineType.default, urlSearch)), disabled: false, - withNext: true, - count: - timelineTabsStyle === TimelineTabsStyle.filter - ? defaultTimelineCount ?? undefined - : undefined, + onClick: timelineTabsStyle === TimelineTabsStyle.tab ? goToTimeline : noop, }, { id: TimelineType.template, - name: - timelineTabsStyle === TimelineTabsStyle.filter - ? i18n.FILTER_TIMELINES(i18n.TAB_TEMPLATES) - : i18n.TAB_TEMPLATES, + name: i18n.TAB_TEMPLATES, href: formatUrl(getTimelineTabsUrl(TimelineType.template, urlSearch)), disabled: false, - withNext: false, - count: - timelineTabsStyle === TimelineTabsStyle.filter - ? templateTimelineCount ?? undefined - : undefined, + onClick: timelineTabsStyle === TimelineTabsStyle.tab ? goToTemplateTimeline : noop, }, ], - [ - defaultTimelineCount, - templateTimelineCount, - urlSearch, - formatUrl, - goToTimeline, - goToTemplateTimeline, - ] + [urlSearch, formatUrl, goToTimeline, goToTemplateTimeline] ); const onFilterClicked = useCallback( (tabId, tabStyle: TimelineTabsStyle) => { setTimelineTypes((prevTimelineTypes) => { - if (tabId === prevTimelineTypes && tabStyle === TimelineTabsStyle.filter) { - return tabId === TimelineType.default ? TimelineType.template : TimelineType.default; - } else if (prevTimelineTypes !== tabId) { + if (prevTimelineTypes !== tabId) { setTimelineTypes(tabId); } return prevTimelineTypes; @@ -139,21 +116,23 @@ export const useTimelineTypes = ({ }, [tabName]); const timelineFilters = useMemo(() => { - return getFilterOrTabs(TimelineTabsStyle.filter).map((tab: TimelineTab) => ( - void }) => { - tab.onClick(ev); - onFilterClicked(tab.id, TimelineTabsStyle.filter); - }} - withNext={tab.withNext} - > - {tab.name} - - )); + return ( + + {getFilterOrTabs(TimelineTabsStyle.filter).map((tab: TimelineTab) => ( + void }) => { + tab.onClick(ev); + onFilterClicked(tab.id, TimelineTabsStyle.filter); + }} + > + {tab.name} + + ))} + + ); }, [timelineType, getFilterOrTabs, onFilterClicked]); return { diff --git a/x-pack/plugins/security_solution/server/lib/machine_learning/index.test.ts b/x-pack/plugins/security_solution/server/lib/machine_learning/index.test.ts index 86133d93e99c8..1f49ac7bf5019 100644 --- a/x-pack/plugins/security_solution/server/lib/machine_learning/index.test.ts +++ b/x-pack/plugins/security_solution/server/lib/machine_learning/index.test.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { ESFilter } from '../../../../../typings/elasticsearch'; import { getExceptionListItemSchemaMock } from '../../../../lists/common/schemas/response/exception_list_item_schema.mock'; import { getAnomalies, AnomaliesSearchParams } from '.'; @@ -13,8 +14,8 @@ const getFiltersFromMock = (mock: jest.Mock) => { return searchParams.body.query.bool.filter; }; -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const getBoolCriteriaFromFilters = (filters: any[]) => filters[1].bool.must; +const getBoolCriteriaFromFilters = (filters: ESFilter[]) => + filters.find((filter) => filter?.bool?.must)?.bool?.must; describe('getAnomalies', () => { let searchParams: AnomaliesSearchParams; @@ -104,4 +105,20 @@ describe('getAnomalies', () => { ]) ); }); + + it('ignores anomalies that do not have finalized scores', () => { + const mockMlAnomalySearch = jest.fn(); + getAnomalies(searchParams, mockMlAnomalySearch); + const filters = getFiltersFromMock(mockMlAnomalySearch); + + expect(filters).toEqual( + expect.arrayContaining([ + { + term: { + is_interim: false, + }, + }, + ]) + ); + }); }); diff --git a/x-pack/plugins/security_solution/server/lib/machine_learning/index.ts b/x-pack/plugins/security_solution/server/lib/machine_learning/index.ts index 962c44174d891..c3fea9f6d916f 100644 --- a/x-pack/plugins/security_solution/server/lib/machine_learning/index.ts +++ b/x-pack/plugins/security_solution/server/lib/machine_learning/index.ts @@ -47,6 +47,7 @@ export const getAnomalies = async ( analyze_wildcard: false, }, }, + { term: { is_interim: false } }, { bool: { must: boolCriteria, diff --git a/x-pack/plugins/stack_alerts/public/alert_types/components/index_select_popover.test.tsx b/x-pack/plugins/stack_alerts/public/alert_types/components/index_select_popover.test.tsx index 64c085a823478..3b7baac9b80e6 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/components/index_select_popover.test.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/components/index_select_popover.test.tsx @@ -9,54 +9,58 @@ import React from 'react'; import { act } from 'react-dom/test-utils'; import { mountWithIntl, nextTick } from '@kbn/test/jest'; import { IndexSelectPopover } from './index_select_popover'; +import { EuiComboBox } from '@elastic/eui'; -jest.mock('../../../../triggers_actions_ui/public', () => ({ - getIndexPatterns: () => { - return ['index1', 'index2']; - }, - firstFieldOption: () => { - return { text: 'Select a field', value: '' }; - }, - getTimeFieldOptions: () => { - return [ - { - text: '@timestamp', - value: '@timestamp', - }, - ]; - }, - getFields: () => { - return Promise.resolve([ - { - name: '@timestamp', - type: 'date', - }, - { - name: 'field', - type: 'text', - }, - ]); - }, - getIndexOptions: () => { - return Promise.resolve([ - { - label: 'indexOption', - options: [ - { - label: 'index1', - value: 'index1', - }, - { - label: 'index2', - value: 'index2', - }, - ], - }, - ]); - }, -})); +jest.mock('../../../../triggers_actions_ui/public', () => { + const original = jest.requireActual('../../../../triggers_actions_ui/public'); + return { + ...original, + getIndexPatterns: () => { + return ['index1', 'index2']; + }, + getTimeFieldOptions: () => { + return [ + { + text: '@timestamp', + value: '@timestamp', + }, + ]; + }, + getFields: () => { + return Promise.resolve([ + { + name: '@timestamp', + type: 'date', + }, + { + name: 'field', + type: 'text', + }, + ]); + }, + getIndexOptions: () => { + return Promise.resolve([ + { + label: 'indexOption', + options: [ + { + label: 'index1', + value: 'index1', + }, + { + label: 'index2', + value: 'index2', + }, + ], + }, + ]); + }, + }; +}); describe('IndexSelectPopover', () => { + const onIndexChange = jest.fn(); + const onTimeFieldChange = jest.fn(); const props = { index: [], esFields: [], @@ -65,8 +69,8 @@ describe('IndexSelectPopover', () => { index: [], timeField: [], }, - onIndexChange: jest.fn(), - onTimeFieldChange: jest.fn(), + onIndexChange, + onTimeFieldChange, }; beforeEach(() => { @@ -106,10 +110,62 @@ describe('IndexSelectPopover', () => { const indexComboBox = wrapper.find('#indexSelectSearchBox'); indexComboBox.first().simulate('click'); - const event = { target: { value: 'indexPattern1' } }; - indexComboBox.find('input').first().simulate('change', event); + + await act(async () => { + const event = { target: { value: 'indexPattern1' } }; + indexComboBox.find('input').first().simulate('change', event); + await nextTick(); + wrapper.update(); + }); const updatedIndexSearchValue = wrapper.find('[data-test-subj="comboBoxSearchInput"]'); expect(updatedIndexSearchValue.first().props().value).toEqual('indexPattern1'); + + const thresholdComboBox = wrapper + .find(EuiComboBox) + .filter('[data-test-subj="thresholdIndexesComboBox"]'); + const thresholdOptions = thresholdComboBox.prop('options'); + expect(thresholdOptions.length > 0).toBeTruthy(); + + await act(async () => { + thresholdComboBox.prop('onChange')!([thresholdOptions[0].options![0]]); + await nextTick(); + wrapper.update(); + }); + expect(onIndexChange).toHaveBeenCalledWith( + [thresholdOptions[0].options![0]].map((opt) => opt.value) + ); + + const timeFieldSelect = wrapper.find('select[data-test-subj="thresholdAlertTimeFieldSelect"]'); + await act(async () => { + timeFieldSelect.simulate('change', { target: { value: '@timestamp' } }); + await nextTick(); + wrapper.update(); + }); + expect(onTimeFieldChange).toHaveBeenCalledWith('@timestamp'); + }); + + test('renders index and timeField if defined', async () => { + const index = 'test-index'; + const timeField = '@timestamp'; + const indexSelectProps = { + ...props, + index: [index], + timeField, + }; + const wrapper = mountWithIntl(); + expect(wrapper.find('button[data-test-subj="selectIndexExpression"]').text()).toEqual( + `index ${index}` + ); + + wrapper.find('[data-test-subj="selectIndexExpression"]').first().simulate('click'); + await act(async () => { + await nextTick(); + wrapper.update(); + }); + + expect( + wrapper.find('EuiSelect[data-test-subj="thresholdAlertTimeFieldSelect"]').text() + ).toEqual(`Select a field${timeField}`); }); }); diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression.test.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression.test.tsx index 3349de086d982..27ddb28eed779 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression.test.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression.test.tsx @@ -58,9 +58,6 @@ jest.mock('../../../../triggers_actions_ui/public', () => { getIndexPatterns: () => { return ['index1', 'index2']; }, - firstFieldOption: () => { - return { text: 'Select a field', value: '' }; - }, getTimeFieldOptions: () => { return [ { @@ -129,6 +126,7 @@ describe('EsQueryAlertTypeExpression', () => { index: ['test-index'], timeField: '@timestamp', esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n}`, + size: 100, thresholdComparator: '>', threshold: [0], timeWindowSize: 15, @@ -140,6 +138,7 @@ describe('EsQueryAlertTypeExpression', () => { const errors = { index: [], esQuery: [], + size: [], timeField: [], timeWindowSize: [], }; @@ -172,6 +171,7 @@ describe('EsQueryAlertTypeExpression', () => { test('should render EsQueryAlertTypeExpression with expected components', async () => { const wrapper = await setup(getAlertParams()); expect(wrapper.find('[data-test-subj="indexSelectPopover"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="sizeValueExpression"]').exists()).toBeTruthy(); expect(wrapper.find('[data-test-subj="queryJsonEditor"]').exists()).toBeTruthy(); expect(wrapper.find('[data-test-subj="testQuerySuccess"]').exists()).toBeFalsy(); expect(wrapper.find('[data-test-subj="testQueryError"]').exists()).toBeFalsy(); diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression.tsx index 27f8071564c55..37c64688ec49a 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression.tsx @@ -30,6 +30,7 @@ import { COMPARATORS, ThresholdExpression, ForLastExpression, + ValueExpression, AlertTypeParamsExpressionProps, } from '../../../../triggers_actions_ui/public'; import { validateExpression } from './validation'; @@ -45,6 +46,7 @@ const DEFAULT_VALUES = { "match_all" : {} } }`, + SIZE: 100, TIME_WINDOW_SIZE: 5, TIME_WINDOW_UNIT: 'm', THRESHOLD: [1000], @@ -53,6 +55,7 @@ const DEFAULT_VALUES = { const expressionFieldsWithValidation = [ 'index', 'esQuery', + 'size', 'timeField', 'threshold0', 'threshold1', @@ -74,6 +77,7 @@ export const EsQueryAlertTypeExpression: React.FunctionComponent< index, timeField, esQuery, + size, thresholdComparator, threshold, timeWindowSize, @@ -83,6 +87,7 @@ export const EsQueryAlertTypeExpression: React.FunctionComponent< const getDefaultParams = () => ({ ...alertParams, esQuery: esQuery ?? DEFAULT_VALUES.QUERY, + size: size ?? DEFAULT_VALUES.SIZE, timeWindowSize: timeWindowSize ?? DEFAULT_VALUES.TIME_WINDOW_SIZE, timeWindowUnit: timeWindowUnit ?? DEFAULT_VALUES.TIME_WINDOW_UNIT, threshold: threshold ?? DEFAULT_VALUES.THRESHOLD, @@ -214,7 +219,7 @@ export const EsQueryAlertTypeExpression: React.FunctionComponent<
@@ -234,6 +239,7 @@ export const EsQueryAlertTypeExpression: React.FunctionComponent< ...alertParams, index: indices, esQuery: DEFAULT_VALUES.QUERY, + size: DEFAULT_VALUES.SIZE, thresholdComparator: DEFAULT_VALUES.THRESHOLD_COMPARATOR, timeWindowSize: DEFAULT_VALUES.TIME_WINDOW_SIZE, timeWindowUnit: DEFAULT_VALUES.TIME_WINDOW_UNIT, @@ -246,6 +252,19 @@ export const EsQueryAlertTypeExpression: React.FunctionComponent< }} onTimeFieldChange={(updatedTimeField: string) => setParam('timeField', updatedTimeField)} /> + { + setParam('size', updatedValue); + }} + />
diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/types.ts b/x-pack/plugins/stack_alerts/public/alert_types/es_query/types.ts index a22af7a7bc8a5..af34b88ba28c5 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/types.ts +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/types.ts @@ -17,6 +17,7 @@ export interface EsQueryAlertParams extends AlertTypeParams { index: string[]; timeField?: string; esQuery: string; + size: number; thresholdComparator?: string; threshold: number[]; timeWindowSize: number; diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/validation.test.ts b/x-pack/plugins/stack_alerts/public/alert_types/es_query/validation.test.ts index 7d604e964fb9d..52278b4576557 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/validation.test.ts +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/validation.test.ts @@ -13,6 +13,7 @@ describe('expression params validation', () => { const initialParams: EsQueryAlertParams = { index: [], esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n}`, + size: 100, timeWindowSize: 1, timeWindowUnit: 's', threshold: [0], @@ -25,6 +26,7 @@ describe('expression params validation', () => { const initialParams: EsQueryAlertParams = { index: ['test'], esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n}`, + size: 100, timeWindowSize: 1, timeWindowUnit: 's', threshold: [0], @@ -37,6 +39,7 @@ describe('expression params validation', () => { const initialParams: EsQueryAlertParams = { index: ['test'], esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n`, + size: 100, timeWindowSize: 1, timeWindowUnit: 's', threshold: [0], @@ -49,6 +52,7 @@ describe('expression params validation', () => { const initialParams: EsQueryAlertParams = { index: ['test'], esQuery: `{\n \"aggs\":{\n \"match_all\" : {}\n }\n}`, + size: 100, timeWindowSize: 1, timeWindowUnit: 's', threshold: [0], @@ -61,6 +65,7 @@ describe('expression params validation', () => { const initialParams: EsQueryAlertParams = { index: ['test'], esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n}`, + size: 100, threshold: [], timeWindowSize: 1, timeWindowUnit: 's', @@ -74,6 +79,7 @@ describe('expression params validation', () => { const initialParams: EsQueryAlertParams = { index: ['test'], esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n}`, + size: 100, threshold: [1], timeWindowSize: 1, timeWindowUnit: 's', @@ -87,6 +93,7 @@ describe('expression params validation', () => { const initialParams: EsQueryAlertParams = { index: ['test'], esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n}`, + size: 100, threshold: [10, 1], timeWindowSize: 1, timeWindowUnit: 's', @@ -97,4 +104,34 @@ describe('expression params validation', () => { 'Threshold 1 must be > Threshold 0.' ); }); + + test('if size property is < 0 should return proper error message', () => { + const initialParams: EsQueryAlertParams = { + index: ['test'], + esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n`, + size: -1, + timeWindowSize: 1, + timeWindowUnit: 's', + threshold: [0], + }; + expect(validateExpression(initialParams).errors.size.length).toBeGreaterThan(0); + expect(validateExpression(initialParams).errors.size[0]).toBe( + 'Size must be between 0 and 10,000.' + ); + }); + + test('if size property is > 10000 should return proper error message', () => { + const initialParams: EsQueryAlertParams = { + index: ['test'], + esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n`, + size: 25000, + timeWindowSize: 1, + timeWindowUnit: 's', + threshold: [0], + }; + expect(validateExpression(initialParams).errors.size.length).toBeGreaterThan(0); + expect(validateExpression(initialParams).errors.size[0]).toBe( + 'Size must be between 0 and 10,000.' + ); + }); }); diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/validation.ts b/x-pack/plugins/stack_alerts/public/alert_types/es_query/validation.ts index 8b402d63ae565..e6449dd4a6089 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/validation.ts +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/validation.ts @@ -10,12 +10,21 @@ import { EsQueryAlertParams } from './types'; import { ValidationResult, builtInComparators } from '../../../../triggers_actions_ui/public'; export const validateExpression = (alertParams: EsQueryAlertParams): ValidationResult => { - const { index, timeField, esQuery, threshold, timeWindowSize, thresholdComparator } = alertParams; + const { + index, + timeField, + esQuery, + size, + threshold, + timeWindowSize, + thresholdComparator, + } = alertParams; const validationResult = { errors: {} }; const errors = { index: new Array(), timeField: new Array(), esQuery: new Array(), + size: new Array(), threshold0: new Array(), threshold1: new Array(), thresholdComparator: new Array(), @@ -94,5 +103,20 @@ export const validateExpression = (alertParams: EsQueryAlertParams): ValidationR }) ); } + if (!size) { + errors.size.push( + i18n.translate('xpack.stackAlerts.esQuery.ui.validation.error.requiredSizeText', { + defaultMessage: 'Size is required.', + }) + ); + } + if ((size && size < 0) || size > 10000) { + errors.size.push( + i18n.translate('xpack.stackAlerts.esQuery.ui.validation.error.invalidSizeRangeText', { + defaultMessage: 'Size must be between 0 and {max, number}.', + values: { max: 10000 }, + }) + ); + } return validationResult; }; diff --git a/x-pack/plugins/stack_alerts/public/alert_types/threshold/expression.test.tsx b/x-pack/plugins/stack_alerts/public/alert_types/threshold/expression.test.tsx new file mode 100644 index 0000000000000..01c2bc18f35e8 --- /dev/null +++ b/x-pack/plugins/stack_alerts/public/alert_types/threshold/expression.test.tsx @@ -0,0 +1,218 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { mountWithIntl, nextTick } from '@kbn/test/jest'; +import { act } from 'react-dom/test-utils'; +import IndexThresholdAlertTypeExpression, { DEFAULT_VALUES } from './expression'; +import { dataPluginMock } from 'src/plugins/data/public/mocks'; +import { chartPluginMock } from 'src/plugins/charts/public/mocks'; +import { IndexThresholdAlertParams } from './types'; +import { validateExpression } from './validation'; +import { + builtInAggregationTypes, + builtInComparators, + getTimeUnitLabel, + TIME_UNITS, +} from '../../../../triggers_actions_ui/public'; + +jest.mock('../../../../triggers_actions_ui/public', () => { + const original = jest.requireActual('../../../../triggers_actions_ui/public'); + return { + ...original, + getIndexPatterns: () => { + return ['index1', 'index2']; + }, + getTimeFieldOptions: () => { + return [ + { + text: '@timestamp', + value: '@timestamp', + }, + ]; + }, + getFields: () => { + return Promise.resolve([ + { + name: '@timestamp', + type: 'date', + }, + { + name: 'field', + type: 'text', + }, + ]); + }, + getIndexOptions: () => { + return Promise.resolve([ + { + label: 'indexOption', + options: [ + { + label: 'index1', + value: 'index1', + }, + { + label: 'index2', + value: 'index2', + }, + ], + }, + ]); + }, + }; +}); + +const dataMock = dataPluginMock.createStartContract(); +const chartsStartMock = chartPluginMock.createStartContract(); + +describe('IndexThresholdAlertTypeExpression', () => { + function getAlertParams(overrides = {}) { + return { + index: 'test-index', + aggType: 'count', + thresholdComparator: '>', + threshold: [0], + timeWindowSize: 15, + timeWindowUnit: 's', + ...overrides, + }; + } + async function setup(alertParams: IndexThresholdAlertParams) { + const { errors } = validateExpression(alertParams); + + const wrapper = mountWithIntl( + {}} + setAlertProperty={() => {}} + errors={errors} + data={dataMock} + defaultActionGroupId="" + actionGroups={[]} + charts={chartsStartMock} + /> + ); + + await act(async () => { + await nextTick(); + wrapper.update(); + }); + return wrapper; + } + + test(`should render IndexThresholdAlertTypeExpression with expected components when aggType doesn't require field`, async () => { + const wrapper = await setup(getAlertParams()); + expect(wrapper.find('[data-test-subj="indexSelectPopover"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="whenExpression"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="groupByExpression"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="aggTypeExpression"]').exists()).toBeFalsy(); + expect(wrapper.find('[data-test-subj="thresholdExpression"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="forLastExpression"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="visualizationPlaceholder"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="thresholdVisualization"]').exists()).toBeFalsy(); + }); + + test(`should render IndexThresholdAlertTypeExpression with expected components when aggType does require field`, async () => { + const wrapper = await setup(getAlertParams({ aggType: 'avg' })); + expect(wrapper.find('[data-test-subj="indexSelectPopover"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="whenExpression"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="groupByExpression"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="aggTypeExpression"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="thresholdExpression"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="forLastExpression"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="visualizationPlaceholder"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="thresholdVisualization"]').exists()).toBeFalsy(); + }); + + test(`should render IndexThresholdAlertTypeExpression with visualization when there are no expression errors`, async () => { + const wrapper = await setup(getAlertParams({ timeField: '@timestamp' })); + expect(wrapper.find('[data-test-subj="visualizationPlaceholder"]').exists()).toBeFalsy(); + expect(wrapper.find('[data-test-subj="thresholdVisualization"]').exists()).toBeTruthy(); + }); + + test(`should set default alert params when params are undefined`, async () => { + const wrapper = await setup( + getAlertParams({ + aggType: undefined, + thresholdComparator: undefined, + timeWindowSize: undefined, + timeWindowUnit: undefined, + groupBy: undefined, + threshold: undefined, + }) + ); + + expect(wrapper.find('button[data-test-subj="selectIndexExpression"]').text()).toEqual( + 'index test-index' + ); + expect(wrapper.find('button[data-test-subj="whenExpression"]').text()).toEqual( + `when ${builtInAggregationTypes[DEFAULT_VALUES.AGGREGATION_TYPE].text}` + ); + expect(wrapper.find('button[data-test-subj="groupByExpression"]').text()).toEqual( + `over ${DEFAULT_VALUES.GROUP_BY} documents ` + ); + expect(wrapper.find('[data-test-subj="aggTypeExpression"]').exists()).toBeFalsy(); + expect(wrapper.find('button[data-test-subj="thresholdPopover"]').text()).toEqual( + `${builtInComparators[DEFAULT_VALUES.THRESHOLD_COMPARATOR].text} ` + ); + expect(wrapper.find('button[data-test-subj="forLastExpression"]').text()).toEqual( + `for the last ${DEFAULT_VALUES.TIME_WINDOW_SIZE} ${getTimeUnitLabel( + DEFAULT_VALUES.TIME_WINDOW_UNIT as TIME_UNITS, + DEFAULT_VALUES.TIME_WINDOW_SIZE.toString() + )}` + ); + expect( + wrapper.find('EuiEmptyPrompt[data-test-subj="visualizationPlaceholder"]').text() + ).toEqual(`Complete the expression to generate a preview.`); + }); + + test(`should use alert params when params are defined`, async () => { + const aggType = 'avg'; + const thresholdComparator = 'between'; + const timeWindowSize = 987; + const timeWindowUnit = 's'; + const threshold = [3, 1003]; + const groupBy = 'top'; + const termSize = '27'; + const termField = 'host.name'; + const wrapper = await setup( + getAlertParams({ + aggType, + thresholdComparator, + timeWindowSize, + timeWindowUnit, + termSize, + termField, + groupBy, + threshold, + }) + ); + + expect(wrapper.find('button[data-test-subj="whenExpression"]').text()).toEqual( + `when ${builtInAggregationTypes[aggType].text}` + ); + expect(wrapper.find('button[data-test-subj="groupByExpression"]').text()).toEqual( + `grouped over ${groupBy} ${termSize} '${termField}'` + ); + + expect(wrapper.find('button[data-test-subj="thresholdPopover"]').text()).toEqual( + `${builtInComparators[thresholdComparator].text} ${threshold[0]} AND ${threshold[1]}` + ); + expect(wrapper.find('button[data-test-subj="forLastExpression"]').text()).toEqual( + `for the last ${timeWindowSize} ${getTimeUnitLabel( + timeWindowUnit as TIME_UNITS, + timeWindowSize.toString() + )}` + ); + expect( + wrapper.find('EuiEmptyPrompt[data-test-subj="visualizationPlaceholder"]').text() + ).toEqual(`Complete the expression to generate a preview.`); + }); +}); diff --git a/x-pack/plugins/stack_alerts/public/alert_types/threshold/expression.tsx b/x-pack/plugins/stack_alerts/public/alert_types/threshold/expression.tsx index aed115a53fa26..380e2793043f8 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/threshold/expression.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/threshold/expression.tsx @@ -28,7 +28,7 @@ import { IndexThresholdAlertParams } from './types'; import './expression.scss'; import { IndexSelectPopover } from '../components/index_select_popover'; -const DEFAULT_VALUES = { +export const DEFAULT_VALUES = { AGGREGATION_TYPE: 'count', TERM_SIZE: 5, THRESHOLD_COMPARATOR: COMPARATORS.GREATER_THAN, @@ -100,7 +100,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent< alertParams[errorKey as keyof IndexThresholdAlertParams] !== undefined ); - const canShowVizualization = !!Object.keys(errors).find( + const cannotShowVisualization = !!Object.keys(errors).find( (errorKey) => expressionFieldsWithValidation.includes(errorKey) && errors[errorKey].length >= 1 ); @@ -158,6 +158,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent< setAlertParams('aggType', selectedAggType) @@ -196,6 +198,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent< {aggType && builtInAggregationTypes[aggType].fieldRequired ? ( @@ -258,9 +264,10 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent< />
- {canShowVizualization ? ( + {cannotShowVisualization ? ( @@ -275,6 +282,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent< ) : ( ({ + getThresholdAlertVisualizationData: jest.fn(() => + Promise.resolve({ + results: [ + { group: 'a', metrics: [['b', 2]] }, + { group: 'a', metrics: [['b', 10]] }, + ], + }) + ), +})); + +const { getThresholdAlertVisualizationData } = jest.requireMock('./index_threshold_api'); + +const dataMock = dataPluginMock.createStartContract(); +const chartsStartMock = chartPluginMock.createStartContract(); +dataMock.fieldFormats = ({ + getDefaultInstance: jest.fn(() => ({ + convert: jest.fn((s: unknown) => JSON.stringify(s)), + })), +} as unknown) as DataPublicPluginStart['fieldFormats']; + +describe('ThresholdVisualization', () => { + beforeAll(() => { + (useKibana as jest.Mock).mockReturnValue({ + services: { + uiSettings: uiSettingsServiceMock.createSetupContract(), + }, + }); + }); + + const alertParams = { + index: 'test-index', + aggType: 'count', + thresholdComparator: '>', + threshold: [0], + timeWindowSize: 15, + timeWindowUnit: 's', + }; + + async function setup() { + const wrapper = mountWithIntl( + + ); + + await act(async () => { + await nextTick(); + wrapper.update(); + }); + return wrapper; + } + + test('periodically requests visualization data', async () => { + const refreshRate = 10; + jest.useFakeTimers(); + + const wrapper = mountWithIntl( + + ); + + await act(async () => { + await nextTick(); + wrapper.update(); + }); + expect(getThresholdAlertVisualizationData).toHaveBeenCalledTimes(1); + + for (let i = 1; i <= 5; i++) { + await act(async () => { + jest.advanceTimersByTime(refreshRate); + await nextTick(); + wrapper.update(); + }); + expect(getThresholdAlertVisualizationData).toHaveBeenCalledTimes(i + 1); + } + }); + + test('renders loading message on initial load', async () => { + const wrapper = mountWithIntl( + + ); + expect(wrapper.find('[data-test-subj="firstLoad"]').exists()).toBeTruthy(); + + await act(async () => { + await nextTick(); + wrapper.update(); + }); + + expect(wrapper.find('[data-test-subj="firstLoad"]').exists()).toBeFalsy(); + expect(getThresholdAlertVisualizationData).toHaveBeenCalled(); + }); + + test('renders chart when visualization results are available', async () => { + const wrapper = await setup(); + + expect(wrapper.find('[data-test-subj="alertVisualizationChart"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="noDataCallout"]').exists()).toBeFalsy(); + expect(wrapper.find(Chart)).toHaveLength(1); + expect(wrapper.find(LineSeries)).toHaveLength(1); + expect(wrapper.find(LineAnnotation)).toHaveLength(1); + }); + + test('renders multiple line series chart when visualization results contain multiple groups', async () => { + getThresholdAlertVisualizationData.mockImplementation(() => + Promise.resolve({ + results: [ + { group: 'a', metrics: [['b', 2]] }, + { group: 'a', metrics: [['b', 10]] }, + { group: 'c', metrics: [['d', 1]] }, + ], + }) + ); + + const wrapper = await setup(); + + expect(wrapper.find('[data-test-subj="alertVisualizationChart"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="noDataCallout"]').exists()).toBeFalsy(); + expect(wrapper.find(Chart)).toHaveLength(1); + expect(wrapper.find(LineSeries)).toHaveLength(2); + expect(wrapper.find(LineAnnotation)).toHaveLength(1); + }); + + test('renders error message when getting visualization fails', async () => { + const errorMessage = 'oh no'; + getThresholdAlertVisualizationData.mockImplementation(() => Promise.reject(errorMessage)); + const wrapper = await setup(); + + expect(wrapper.find('[data-test-subj="errorCallout"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="errorCallout"]').first().text()).toBe( + `Cannot load alert visualization${errorMessage}` + ); + }); + + test('renders no data message when visualization results are empty', async () => { + getThresholdAlertVisualizationData.mockImplementation(() => Promise.resolve({ results: [] })); + const wrapper = await setup(); + + expect(wrapper.find('[data-test-subj="alertVisualizationChart"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="noDataCallout"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="noDataCallout"]').first().text()).toBe( + `No data matches this queryCheck that your time range and filters are correct.` + ); + }); +}); diff --git a/x-pack/plugins/stack_alerts/public/alert_types/threshold/visualization.tsx b/x-pack/plugins/stack_alerts/public/alert_types/threshold/visualization.tsx index 7401d0e26be68..40736f7350b1b 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/threshold/visualization.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/threshold/visualization.tsx @@ -202,6 +202,7 @@ export const ThresholdVisualization: React.FunctionComponent = ({ if (loadingState === LoadingStateType.FirstLoad) { return ( } body={ @@ -220,6 +221,7 @@ export const ThresholdVisualization: React.FunctionComponent = ({ = ({ ) : ( { index: ['[index]'], timeField: '[timeField]', esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n}`, + size: 100, timeWindowSize: 5, timeWindowUnit: 'm', thresholdComparator: '>', @@ -41,6 +42,7 @@ describe('ActionContext', () => { index: ['[index]'], timeField: '[timeField]', esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n}`, + size: 100, timeWindowSize: 5, timeWindowUnit: 'm', thresholdComparator: 'between', diff --git a/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type.test.ts b/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type.test.ts index 2049f9f1153dd..c38dad5134373 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type.test.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type.test.ts @@ -57,6 +57,10 @@ describe('alertType', () => { "description": "The string representation of the ES query.", "name": "esQuery", }, + Object { + "description": "The number of hits to retrieve for each query.", + "name": "size", + }, Object { "description": "An array of values to use as the threshold; 'between' and 'notBetween' require two values, the others require one.", "name": "threshold", @@ -75,6 +79,7 @@ describe('alertType', () => { index: ['index-name'], timeField: 'time-field', esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n}`, + size: 100, timeWindowSize: 5, timeWindowUnit: 'm', thresholdComparator: '<', @@ -92,6 +97,7 @@ describe('alertType', () => { index: ['index-name'], timeField: 'time-field', esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n}`, + size: 100, timeWindowSize: 5, timeWindowUnit: 'm', thresholdComparator: 'between', diff --git a/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type.ts b/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type.ts index 51c1fc4073d60..8fe988d95d72f 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type.ts @@ -23,8 +23,6 @@ import { ESSearchHit } from '../../../../../typings/elasticsearch'; export const ES_QUERY_ID = '.es-query'; -const DEFAULT_MAX_HITS_PER_EXECUTION = 1000; - const ActionGroupId = 'query matched'; const ConditionMetAlertInstanceId = 'query matched'; @@ -88,6 +86,13 @@ export function getAlertType( } ); + const actionVariableContextSizeLabel = i18n.translate( + 'xpack.stackAlerts.esQuery.actionVariableContextSizeLabel', + { + defaultMessage: 'The number of hits to retrieve for each query.', + } + ); + const actionVariableContextThresholdLabel = i18n.translate( 'xpack.stackAlerts.esQuery.actionVariableContextThresholdLabel', { @@ -130,6 +135,7 @@ export function getAlertType( params: [ { name: 'index', description: actionVariableContextIndexLabel }, { name: 'esQuery', description: actionVariableContextQueryLabel }, + { name: 'size', description: actionVariableContextSizeLabel }, { name: 'threshold', description: actionVariableContextThresholdLabel }, { name: 'thresholdComparator', description: actionVariableContextThresholdComparatorLabel }, ], @@ -160,7 +166,7 @@ export function getAlertType( } // During each alert execution, we run the configured query, get a hit count - // (hits.total) and retrieve up to DEFAULT_MAX_HITS_PER_EXECUTION hits. We + // (hits.total) and retrieve up to params.size hits. We // evaluate the threshold condition using the value of hits.total. If the threshold // condition is met, the hits are counted toward the query match and we update // the alert state with the timestamp of the latest hit. In the next execution @@ -200,7 +206,7 @@ export function getAlertType( from: dateStart, to: dateEnd, filter, - size: DEFAULT_MAX_HITS_PER_EXECUTION, + size: params.size, sortOrder: 'desc', searchAfterSortId: undefined, timeField: params.timeField, diff --git a/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type_params.test.ts b/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type_params.test.ts index a1a697446ff65..ab3ca6a2d4c31 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type_params.test.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type_params.test.ts @@ -7,12 +7,17 @@ import { TypeOf } from '@kbn/config-schema'; import type { Writable } from '@kbn/utility-types'; -import { EsQueryAlertParamsSchema, EsQueryAlertParams } from './alert_type_params'; +import { + EsQueryAlertParamsSchema, + EsQueryAlertParams, + ES_QUERY_MAX_HITS_PER_EXECUTION, +} from './alert_type_params'; const DefaultParams: Writable> = { index: ['index-name'], timeField: 'time-field', esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n}`, + size: 100, timeWindowSize: 5, timeWindowUnit: 'm', thresholdComparator: '>', @@ -99,6 +104,28 @@ describe('alertType Params validate()', () => { ); }); + it('fails for invalid size', async () => { + delete params.size; + expect(onValidate()).toThrowErrorMatchingInlineSnapshot( + `"[size]: expected value of type [number] but got [undefined]"` + ); + + params.size = 'foo'; + expect(onValidate()).toThrowErrorMatchingInlineSnapshot( + `"[size]: expected value of type [number] but got [string]"` + ); + + params.size = -1; + expect(onValidate()).toThrowErrorMatchingInlineSnapshot( + `"[size]: Value must be equal to or greater than [0]."` + ); + + params.size = ES_QUERY_MAX_HITS_PER_EXECUTION + 1; + expect(onValidate()).toThrowErrorMatchingInlineSnapshot( + `"[size]: Value must be equal to or lower than [10000]."` + ); + }); + it('fails for invalid timeWindowSize', async () => { delete params.timeWindowSize; expect(onValidate()).toThrowErrorMatchingInlineSnapshot( diff --git a/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type_params.ts b/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type_params.ts index 24fed92776b53..23f314b521511 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type_params.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type_params.ts @@ -11,6 +11,8 @@ import { ComparatorFnNames } from '../lib'; import { validateTimeWindowUnits } from '../../../../triggers_actions_ui/server'; import { AlertTypeState } from '../../../../alerts/server'; +export const ES_QUERY_MAX_HITS_PER_EXECUTION = 10000; + // alert type parameters export type EsQueryAlertParams = TypeOf; export interface EsQueryAlertState extends AlertTypeState { @@ -21,6 +23,7 @@ export const EsQueryAlertParamsSchemaProperties = { index: schema.arrayOf(schema.string({ minLength: 1 }), { minSize: 1 }), timeField: schema.string({ minLength: 1 }), esQuery: schema.string({ minLength: 1 }), + size: schema.number({ min: 0, max: ES_QUERY_MAX_HITS_PER_EXECUTION }), timeWindowSize: schema.number({ min: 1 }), timeWindowUnit: schema.string({ validate: validateTimeWindowUnits }), threshold: schema.arrayOf(schema.number(), { minSize: 1, maxSize: 2 }), diff --git a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json index 9e6a0c06808bc..d4b07203e8109 100644 --- a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json +++ b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json @@ -2219,13 +2219,6 @@ } } }, - "fileUploadTelemetry": { - "properties": { - "filesUploadedTotalCount": { - "type": "long" - } - } - }, "maps": { "properties": { "settings": { diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index b8a67d9c3388e..018d2d572eea0 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -9676,7 +9676,6 @@ "xpack.infra.alerting.alertFlyout.groupBy.placeholder": "なし(グループなし)", "xpack.infra.alerting.alertFlyout.groupByLabel": "グループ分けの条件", "xpack.infra.alerting.alertsButton": "アラート", - "xpack.infra.alerting.createAlertButton": "アラートの作成", "xpack.infra.alerting.logs.alertsButton": "アラート", "xpack.infra.alerting.logs.createAlertButton": "アラートの作成", "xpack.infra.alerting.logs.manageAlerts": "アラートを管理", @@ -9893,7 +9892,6 @@ "xpack.infra.logs.analysis.anomaliesExpandedRowActualRateTitle": "{actualCount, plural, other {件のメッセージ}}", "xpack.infra.logs.analysis.anomaliesExpandedRowTypicalRateDescription": "通常", "xpack.infra.logs.analysis.anomaliesExpandedRowTypicalRateTitle": "{typicalCount, plural, other {件のメッセージ}}", - "xpack.infra.logs.analysis.anomaliesSectionLineSeriesName": "15 分ごとのログエントリー (平均)", "xpack.infra.logs.analysis.anomaliesSectionLoadingAriaLabel": "異常を読み込み中", "xpack.infra.logs.analysis.anomaliesSectionTitle": "異常", "xpack.infra.logs.analysis.anomaliesTableAnomalyDatasetName": "データセット", @@ -9905,7 +9903,6 @@ "xpack.infra.logs.analysis.anomaliesTableMoreThanExpectedAnomalyMessage": "この{type, select, logRate {データセット} logCategory {カテゴリ}}のログメッセージ数が想定よりも多くなっています", "xpack.infra.logs.analysis.anomaliesTableNextPageLabel": "次のページ", "xpack.infra.logs.analysis.anomaliesTablePreviousPageLabel": "前のページ", - "xpack.infra.logs.analysis.anomalySectionLogRateChartNoData": "表示するログレートデータがありません。", "xpack.infra.logs.analysis.anomalySectionNoDataBody": "時間範囲を調整する必要があるかもしれません。", "xpack.infra.logs.analysis.anomalySectionNoDataTitle": "表示するデータがありません。", "xpack.infra.logs.analysis.createJobButtonLabel": "MLジョブを作成", @@ -9934,8 +9931,6 @@ "xpack.infra.logs.analysis.mlUnavailableTitle": "この機能には機械学習が必要です", "xpack.infra.logs.analysis.onboardingSuccessContent": "機械学習ロボットがデータの収集を開始するまでしばらくお待ちください。", "xpack.infra.logs.analysis.onboardingSuccessTitle": "成功!", - "xpack.infra.logs.analysis.overallAnomalyChartMaxScoresLabel": "最高異常スコア", - "xpack.infra.logs.analysis.partitionMaxAnomalyScoreAnnotationLabel": "最大異常スコア:{maxAnomalyScore}", "xpack.infra.logs.analysis.recreateJobButtonLabel": "ML ジョブを再作成", "xpack.infra.logs.analysis.setupFlyoutGotoListButtonLabel": "すべての機械学習ジョブ", "xpack.infra.logs.analysis.setupFlyoutTitle": "機械学習を使用した異常検知", @@ -9974,16 +9969,6 @@ "xpack.infra.logs.jumpToTailText": "最も新しいエントリーに移動", "xpack.infra.logs.lastUpdate": "前回の更新 {timestamp}", "xpack.infra.logs.loadingNewEntriesText": "新しいエントリーを読み込み中", - "xpack.infra.logs.logAnalysis.splash.learnMoreLink": "ドキュメンテーションを表示", - "xpack.infra.logs.logAnalysis.splash.learnMoreTitle": "詳細について", - "xpack.infra.logs.logAnalysis.splash.loadingMessage": "ライセンスを確認しています...", - "xpack.infra.logs.logAnalysis.splash.splashImageAlt": "プレースホルダー画像", - "xpack.infra.logs.logAnalysis.splash.startTrialCta": "トライアルを開始", - "xpack.infra.logs.logAnalysis.splash.startTrialDescription": "無料の試用版には、機械学習機能が含まれており、ログで異常を検出することができます。", - "xpack.infra.logs.logAnalysis.splash.startTrialTitle": "異常検知を利用するには、無料の試用版を開始してください", - "xpack.infra.logs.logAnalysis.splash.updateSubscriptionCta": "サブスクリプションのアップグレード", - "xpack.infra.logs.logAnalysis.splash.updateSubscriptionDescription": "機械学習機能を使用するには、プラチナサブスクリプションが必要です。", - "xpack.infra.logs.logAnalysis.splash.updateSubscriptionTitle": "異常検知を利用するには、プラチナサブスクリプションにアップグレードしてください", "xpack.infra.logs.logEntryActionsDetailsButton": "詳細を表示", "xpack.infra.logs.logEntryCategories.analyzeCategoryInMlButtonLabel": "ML で分析", "xpack.infra.logs.logEntryCategories.analyzeCategoryInMlTooltipDescription": "ML アプリでこのカテゴリーを分析します。", @@ -10179,10 +10164,6 @@ "xpack.infra.metrics.alertFlyout.alertPreviewError": "このアラート条件をプレビューするときにエラーが発生しました", "xpack.infra.metrics.alertFlyout.alertPreviewErrorDesc": "しばらくたってから再試行するか、詳細を確認してください。", "xpack.infra.metrics.alertFlyout.alertPreviewErrorResult": "一部のデータを評価するときにエラーが発生しました。", - "xpack.infra.metrics.alertFlyout.alertPreviewGroupsAcross": "すべてを対象にする", - "xpack.infra.metrics.alertFlyout.alertPreviewNoDataResult": "データなしの件数:{boldedResultsNumber}", - "xpack.infra.metrics.alertFlyout.alertPreviewNoDataResultNumber": "{noData, plural, other {件の結果がありました}}", - "xpack.infra.metrics.alertFlyout.alertPreviewResult": "{firedTimes} 回発生しました", "xpack.infra.metrics.alertFlyout.alertPreviewTotalNotifications": "結果として、このアラートは、「{alertThrottle}」に関して選択した[通知間隔]設定に基づいて{notifications}を送信しました。", "xpack.infra.metrics.alertFlyout.alertPreviewTotalNotificationsNumber": "{notifs, plural, other {#通知}}", "xpack.infra.metrics.alertFlyout.conditions": "条件", @@ -19247,7 +19228,6 @@ "xpack.securitySolution.open.timeline.exportSelectedButton": "選択した項目のエクスポート", "xpack.securitySolution.open.timeline.favoriteSelectedButton": "選択中のお気に入り", "xpack.securitySolution.open.timeline.favoritesTooltip": "お気に入り", - "xpack.securitySolution.open.timeline.filterByTimelineTypesTitle": "{timelineType}のみ", "xpack.securitySolution.open.timeline.lastModifiedTableHeader": "最終更新:", "xpack.securitySolution.open.timeline.missingSavedObjectIdTooltip": "savedObjectId がありません", "xpack.securitySolution.open.timeline.modifiedByTableHeader": "変更者:", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 229265fe62252..5a9695b8ddc3d 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -9702,7 +9702,6 @@ "xpack.infra.alerting.alertFlyout.groupBy.placeholder": "无内容(未分组)", "xpack.infra.alerting.alertFlyout.groupByLabel": "分组依据", "xpack.infra.alerting.alertsButton": "告警", - "xpack.infra.alerting.createAlertButton": "创建告警", "xpack.infra.alerting.logs.alertsButton": "告警", "xpack.infra.alerting.logs.createAlertButton": "创建告警", "xpack.infra.alerting.logs.manageAlerts": "管理告警", @@ -9919,7 +9918,6 @@ "xpack.infra.logs.analysis.anomaliesExpandedRowActualRateTitle": "{actualCount, plural, other {消息}}", "xpack.infra.logs.analysis.anomaliesExpandedRowTypicalRateDescription": "典型", "xpack.infra.logs.analysis.anomaliesExpandedRowTypicalRateTitle": "{typicalCount, plural, other {消息}}", - "xpack.infra.logs.analysis.anomaliesSectionLineSeriesName": "每 15 分钟日志条目数(平均值)", "xpack.infra.logs.analysis.anomaliesSectionLoadingAriaLabel": "正在加载异常", "xpack.infra.logs.analysis.anomaliesSectionTitle": "异常", "xpack.infra.logs.analysis.anomaliesTableAnomalyDatasetName": "数据集", @@ -9931,7 +9929,6 @@ "xpack.infra.logs.analysis.anomaliesTableMoreThanExpectedAnomalyMessage": "此{type, select, logRate {数据集} logCategory {类别}}中的日志消息多于预期", "xpack.infra.logs.analysis.anomaliesTableNextPageLabel": "下一页", "xpack.infra.logs.analysis.anomaliesTablePreviousPageLabel": "上一页", - "xpack.infra.logs.analysis.anomalySectionLogRateChartNoData": "没有要显示的日志速率数据。", "xpack.infra.logs.analysis.anomalySectionNoDataBody": "您可能想调整时间范围。", "xpack.infra.logs.analysis.anomalySectionNoDataTitle": "没有可显示的数据。", "xpack.infra.logs.analysis.createJobButtonLabel": "创建 ML 作业", @@ -9960,8 +9957,6 @@ "xpack.infra.logs.analysis.mlUnavailableTitle": "此功能需要 Machine Learning", "xpack.infra.logs.analysis.onboardingSuccessContent": "请注意,我们的 Machine Learning 机器人若干分钟后才会开始收集数据。", "xpack.infra.logs.analysis.onboardingSuccessTitle": "成功!", - "xpack.infra.logs.analysis.overallAnomalyChartMaxScoresLabel": "最大异常分数:", - "xpack.infra.logs.analysis.partitionMaxAnomalyScoreAnnotationLabel": "最大异常分数:{maxAnomalyScore}", "xpack.infra.logs.analysis.recreateJobButtonLabel": "重新创建 ML 作业", "xpack.infra.logs.analysis.setupFlyoutGotoListButtonLabel": "所有 Machine Learning 作业", "xpack.infra.logs.analysis.setupFlyoutTitle": "通过 Machine Learning 检测异常", @@ -10001,16 +9996,6 @@ "xpack.infra.logs.jumpToTailText": "跳到最近的条目", "xpack.infra.logs.lastUpdate": "上次更新时间 {timestamp}", "xpack.infra.logs.loadingNewEntriesText": "正在加载新条目", - "xpack.infra.logs.logAnalysis.splash.learnMoreLink": "阅读文档", - "xpack.infra.logs.logAnalysis.splash.learnMoreTitle": "希望了解详情?", - "xpack.infra.logs.logAnalysis.splash.loadingMessage": "正在检查许可证......", - "xpack.infra.logs.logAnalysis.splash.splashImageAlt": "占位符图像", - "xpack.infra.logs.logAnalysis.splash.startTrialCta": "开始试用", - "xpack.infra.logs.logAnalysis.splash.startTrialDescription": "我们的免费试用版包含 Machine Learning 功能,可用于检测日志中的异常。", - "xpack.infra.logs.logAnalysis.splash.startTrialTitle": "要访问异常检测,请启动免费试用版", - "xpack.infra.logs.logAnalysis.splash.updateSubscriptionCta": "升级订阅", - "xpack.infra.logs.logAnalysis.splash.updateSubscriptionDescription": "必须具有白金级订阅,才能使用 Machine Learning 功能。", - "xpack.infra.logs.logAnalysis.splash.updateSubscriptionTitle": "要访问异常检测,请升级到白金级订阅", "xpack.infra.logs.logEntryActionsDetailsButton": "查看详情", "xpack.infra.logs.logEntryCategories.analyzeCategoryInMlButtonLabel": "在 ML 中分析", "xpack.infra.logs.logEntryCategories.analyzeCategoryInMlTooltipDescription": "在 ML 应用中分析此类别。", @@ -10206,12 +10191,7 @@ "xpack.infra.metrics.alertFlyout.alertPreviewError": "尝试预览此告警条件时发生错误", "xpack.infra.metrics.alertFlyout.alertPreviewErrorDesc": "请稍后重试或查看详情了解更多信息。", "xpack.infra.metrics.alertFlyout.alertPreviewErrorResult": "尝试评估部分数据时发生错误。", - "xpack.infra.metrics.alertFlyout.alertPreviewGroups": "{numberOfGroups, plural,other {# 个 {groupName}}}", - "xpack.infra.metrics.alertFlyout.alertPreviewGroupsAcross": "在", - "xpack.infra.metrics.alertFlyout.alertPreviewNoDataResult": "存在 {boldedResultsNumber}无数据结果。", - "xpack.infra.metrics.alertFlyout.alertPreviewNoDataResultNumber": "{noData, plural, other {# 个结果}}", - "xpack.infra.metrics.alertFlyout.alertPreviewResult": "有 {firedTimes}", - "xpack.infra.metrics.alertFlyout.alertPreviewResultLookback": "在过去 {lookback} 满足此告警的条件。", + "xpack.infra.metrics.alertFlyout.alertPreviewGroups": "在 {numberOfGroups, plural,other {# 个 {groupName}}}", "xpack.infra.metrics.alertFlyout.alertPreviewTotalNotifications": "因此,此告警将根据“{alertThrottle}”的选定“通知频率”设置发送{notifications}。", "xpack.infra.metrics.alertFlyout.alertPreviewTotalNotificationsNumber": "{notifs, plural, other {# 个通知}}", "xpack.infra.metrics.alertFlyout.conditions": "条件", @@ -19294,7 +19274,6 @@ "xpack.securitySolution.open.timeline.exportSelectedButton": "导出所选", "xpack.securitySolution.open.timeline.favoriteSelectedButton": "收藏所选", "xpack.securitySolution.open.timeline.favoritesTooltip": "收藏夹", - "xpack.securitySolution.open.timeline.filterByTimelineTypesTitle": "仅 {timelineType}", "xpack.securitySolution.open.timeline.lastModifiedTableHeader": "最后修改时间", "xpack.securitySolution.open.timeline.missingSavedObjectIdTooltip": "缺失 savedObjectId", "xpack.securitySolution.open.timeline.modifiedByTableHeader": "修改者", diff --git a/x-pack/plugins/triggers_actions_ui/public/common/expression_items/for_the_last.tsx b/x-pack/plugins/triggers_actions_ui/public/common/expression_items/for_the_last.tsx index ccc8e6e2080a7..b0113cdd70451 100644 --- a/x-pack/plugins/triggers_actions_ui/public/common/expression_items/for_the_last.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/common/expression_items/for_the_last.tsx @@ -66,6 +66,7 @@ export const ForLastExpression = ({ defaultMessage: 'for the last', } )} + data-test-subj="forLastExpression" value={`${timeWindowSize} ${getTimeUnitLabel( timeWindowUnit as TIME_UNITS, (timeWindowSize ?? '').toString() diff --git a/x-pack/plugins/triggers_actions_ui/public/common/expression_items/group_by_over.tsx b/x-pack/plugins/triggers_actions_ui/public/common/expression_items/group_by_over.tsx index 5eb942b560b77..37894e6f5be98 100644 --- a/x-pack/plugins/triggers_actions_ui/public/common/expression_items/group_by_over.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/common/expression_items/group_by_over.tsx @@ -96,6 +96,7 @@ export const GroupByExpression = ({ } ) }`} + data-test-subj="groupByExpression" value={`${groupByTypes[groupBy].text} ${ groupByTypes[groupBy].sizeRequired ? `${termSize} ${termField ? `'${termField}'` : ''}` diff --git a/x-pack/plugins/triggers_actions_ui/public/common/expression_items/index.ts b/x-pack/plugins/triggers_actions_ui/public/common/expression_items/index.ts index bfcbba28b4bda..f975375adcb07 100644 --- a/x-pack/plugins/triggers_actions_ui/public/common/expression_items/index.ts +++ b/x-pack/plugins/triggers_actions_ui/public/common/expression_items/index.ts @@ -10,3 +10,4 @@ export { OfExpression } from './of'; export { GroupByExpression } from './group_by_over'; export { ThresholdExpression } from './threshold'; export { ForLastExpression } from './for_the_last'; +export { ValueExpression } from './value'; diff --git a/x-pack/plugins/triggers_actions_ui/public/common/expression_items/value.test.tsx b/x-pack/plugins/triggers_actions_ui/public/common/expression_items/value.test.tsx new file mode 100644 index 0000000000000..e9a3dce84e149 --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/common/expression_items/value.test.tsx @@ -0,0 +1,136 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as React from 'react'; +import { shallow } from 'enzyme'; +import { act } from 'react-dom/test-utils'; +import { ValueExpression } from './value'; +import { mountWithIntl, nextTick } from '@kbn/test/jest'; + +describe('value expression', () => { + it('renders description and value', () => { + const wrapper = shallow( + + ); + expect(wrapper.find('[data-test-subj="valueFieldTitle"]')).toMatchInlineSnapshot(` + + test + + `); + expect(wrapper.find('[data-test-subj="valueFieldNumberForm"]')).toMatchInlineSnapshot(` + + + + `); + }); + + it('renders errors', () => { + const wrapper = shallow( + + ); + expect(wrapper.find('[data-test-subj="valueFieldNumberForm"]')).toMatchInlineSnapshot(` + + + + `); + }); + + it('renders closed popover initially and opens on click', async () => { + const wrapper = mountWithIntl( + + ); + + expect(wrapper.find('[data-test-subj="valueExpression"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="valueFieldTitle"]').exists()).toBeFalsy(); + expect(wrapper.find('[data-test-subj="valueFieldNumber"]').exists()).toBeFalsy(); + + wrapper.find('[data-test-subj="valueExpression"]').first().simulate('click'); + await act(async () => { + await nextTick(); + wrapper.update(); + }); + + expect(wrapper.find('[data-test-subj="valueFieldTitle"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="valueFieldNumber"]').exists()).toBeTruthy(); + }); + + it('emits onChangeSelectedValue action when value is updated', async () => { + const onChangeSelectedValue = jest.fn(); + const wrapper = mountWithIntl( + + ); + + wrapper.find('[data-test-subj="valueExpression"]').first().simulate('click'); + await act(async () => { + await nextTick(); + wrapper.update(); + }); + wrapper + .find('input[data-test-subj="valueFieldNumber"]') + .simulate('change', { target: { value: 3000 } }); + expect(onChangeSelectedValue).toHaveBeenCalledWith(3000); + }); +}); diff --git a/x-pack/plugins/triggers_actions_ui/public/common/expression_items/value.tsx b/x-pack/plugins/triggers_actions_ui/public/common/expression_items/value.tsx new file mode 100644 index 0000000000000..cdf57136fe4b2 --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/common/expression_items/value.tsx @@ -0,0 +1,102 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useState } from 'react'; +import { + EuiExpression, + EuiPopover, + EuiFieldNumber, + EuiFlexGroup, + EuiFlexItem, + EuiFormRow, +} from '@elastic/eui'; +import { ClosablePopoverTitle } from './components'; +import { IErrorObject } from '../../types'; + +interface ValueExpressionProps { + description: string; + value: number; + onChangeSelectedValue: (updatedValue: number) => void; + popupPosition?: + | 'upCenter' + | 'upLeft' + | 'upRight' + | 'downCenter' + | 'downLeft' + | 'downRight' + | 'leftCenter' + | 'leftUp' + | 'leftDown' + | 'rightCenter' + | 'rightUp' + | 'rightDown'; + display?: 'fullWidth' | 'inline'; + errors: string | string[] | IErrorObject; +} + +export const ValueExpression = ({ + description, + value, + onChangeSelectedValue, + display = 'inline', + popupPosition, + errors, +}: ValueExpressionProps) => { + const [valuePopoverOpen, setValuePopoverOpen] = useState(false); + return ( + { + setValuePopoverOpen(true); + }} + /> + } + isOpen={valuePopoverOpen} + closePopover={() => { + setValuePopoverOpen(false); + }} + ownFocus + display={display === 'fullWidth' ? 'block' : 'inlineBlock'} + anchorPosition={popupPosition ?? 'downLeft'} + repositionOnScroll + > +
+ setValuePopoverOpen(false)} + > + <>{description} + + + + 0 && value !== undefined} + error={errors} + > + 0 && value !== undefined} + onChange={(e: any) => { + onChangeSelectedValue(e.target.value as number); + }} + /> + + + +
+
+ ); +}; diff --git a/x-pack/plugins/uptime/public/apps/plugin.ts b/x-pack/plugins/uptime/public/apps/plugin.ts index 8bbbecf8108fe..e7a22a080d79a 100644 --- a/x-pack/plugins/uptime/public/apps/plugin.ts +++ b/x-pack/plugins/uptime/public/apps/plugin.ts @@ -87,6 +87,28 @@ export class UptimePlugin order: 8400, title: PLUGIN.TITLE, category: DEFAULT_APP_CATEGORIES.observability, + meta: { + keywords: [ + 'Synthetics', + 'pings', + 'checks', + 'availability', + 'response duration', + 'response time', + 'outside in', + 'reachability', + 'reachable', + 'digital', + 'performance', + 'web performance', + 'web perf', + ], + searchDeepLinks: [ + { id: 'Down monitors', title: 'Down monitors', path: '/?statusFilter=down' }, + { id: 'Certificates', title: 'TLS Certificates', path: '/certificates' }, + { id: 'Settings', title: 'Settings', path: '/settings' }, + ], + }, mount: async (params: AppMountParameters) => { const [coreStart, corePlugins] = await core.getStartServices(); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/es_query/alert.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/es_query/alert.ts index 30fd3aea2b2dc..777caacd465d8 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/es_query/alert.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/es_query/alert.ts @@ -68,6 +68,7 @@ export default function alertTests({ getService }: FtrProviderContext) { await createAlert({ name: 'never fire', esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n}`, + size: 100, thresholdComparator: '<', threshold: [0], }); @@ -75,6 +76,7 @@ export default function alertTests({ getService }: FtrProviderContext) { await createAlert({ name: 'always fire', esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n}`, + size: 100, thresholdComparator: '>', threshold: [-1], }); @@ -123,6 +125,7 @@ export default function alertTests({ getService }: FtrProviderContext) { await createAlert({ name: 'never fire', esQuery: JSON.stringify(rangeQuery(ES_GROUPS_TO_WRITE * ALERT_INTERVALS_TO_WRITE + 1)), + size: 100, thresholdComparator: '>=', threshold: [0], }); @@ -132,6 +135,7 @@ export default function alertTests({ getService }: FtrProviderContext) { esQuery: JSON.stringify( rangeQuery(Math.floor((ES_GROUPS_TO_WRITE * ALERT_INTERVALS_TO_WRITE) / 2)) ), + size: 100, thresholdComparator: '>=', threshold: [0], }); @@ -173,6 +177,7 @@ export default function alertTests({ getService }: FtrProviderContext) { name: string; timeField?: string; esQuery: string; + size: number; thresholdComparator: string; threshold: number[]; timeWindowSize?: number; @@ -215,6 +220,7 @@ export default function alertTests({ getService }: FtrProviderContext) { index: [ES_TEST_INDEX_NAME], timeField: params.timeField || 'date', esQuery: params.esQuery, + size: params.size, timeWindowSize: params.timeWindowSize || ALERT_INTERVAL_SECONDS * 5, timeWindowUnit: 's', thresholdComparator: params.thresholdComparator, diff --git a/x-pack/test/api_integration/apis/metrics_ui/index.js b/x-pack/test/api_integration/apis/metrics_ui/index.js index 254360ce64922..34ad92e6b89a6 100644 --- a/x-pack/test/api_integration/apis/metrics_ui/index.js +++ b/x-pack/test/api_integration/apis/metrics_ui/index.js @@ -8,7 +8,6 @@ export default function ({ loadTestFile }) { describe('MetricsUI Endpoints', () => { loadTestFile(require.resolve('./metadata')); - loadTestFile(require.resolve('./log_analysis')); loadTestFile(require.resolve('./log_entries')); loadTestFile(require.resolve('./log_entry_highlights')); loadTestFile(require.resolve('./logs_without_millis')); diff --git a/x-pack/test/api_integration/apis/metrics_ui/log_analysis.ts b/x-pack/test/api_integration/apis/metrics_ui/log_analysis.ts deleted file mode 100644 index ecfa0cc6f2438..0000000000000 --- a/x-pack/test/api_integration/apis/metrics_ui/log_analysis.ts +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; - -import { pipe } from 'fp-ts/lib/pipeable'; -import { identity } from 'fp-ts/lib/function'; -import { fold } from 'fp-ts/lib/Either'; -import { - LOG_ANALYSIS_GET_LOG_ENTRY_RATE_PATH, - getLogEntryRateRequestPayloadRT, - getLogEntryRateSuccessReponsePayloadRT, -} from '../../../../plugins/infra/common/http_api/log_analysis'; -import { createPlainError, throwErrors } from '../../../../plugins/infra/common/runtime_types'; -import { FtrProviderContext } from '../../ftr_provider_context'; - -const TIME_BEFORE_START = 1569934800000; -const TIME_AFTER_END = 1570016700000; -const COMMON_HEADERS = { - 'kbn-xsrf': 'some-xsrf-token', -}; -const ML_JOB_ID = 'kibana-logs-ui-default-default-log-entry-rate'; - -export default ({ getService }: FtrProviderContext) => { - const esArchiver = getService('esArchiver'); - const supertest = getService('supertest'); - const retry = getService('retry'); - - async function createDummyJob(jobId: string) { - await supertest - .put(`/api/ml/anomaly_detectors/${jobId}`) - .set(COMMON_HEADERS) - .send({ - job_id: jobId, - groups: [], - analysis_config: { - bucket_span: '15m', - detectors: [{ function: 'count' }], - influencers: [], - }, - data_description: { time_field: '@timestamp' }, - analysis_limits: { model_memory_limit: '11MB' }, - model_plot_config: { enabled: false, annotations_enabled: false }, - }) - .expect(200); - } - - async function deleteDummyJob(jobId: string) { - await supertest.delete(`/api/ml/anomaly_detectors/${jobId}`).set(COMMON_HEADERS).expect(200); - - await retry.waitForWithTimeout(`'${jobId}' to not exist`, 5 * 1000, async () => { - if (await supertest.get(`/api/ml/anomaly_detectors/${jobId}`).expect(404)) { - return true; - } else { - throw new Error(`expected anomaly detection job '${jobId}' not to exist`); - } - }); - } - - describe('log analysis apis', () => { - before(async () => { - // a real ML job must exist when searching for the results - await createDummyJob(ML_JOB_ID); - await esArchiver.load('infra/8.0.0/ml_anomalies_partitioned_log_rate'); - }); - after(async () => { - await deleteDummyJob(ML_JOB_ID); - await esArchiver.unload('infra/8.0.0/ml_anomalies_partitioned_log_rate'); - }); - - describe('log rate results', () => { - describe('with the default source', () => { - it('should return buckets when there are matching ml result documents', async () => { - const { body } = await supertest - .post(LOG_ANALYSIS_GET_LOG_ENTRY_RATE_PATH) - .set(COMMON_HEADERS) - .send( - getLogEntryRateRequestPayloadRT.encode({ - data: { - sourceId: 'default', - timeRange: { - startTime: TIME_BEFORE_START, - endTime: TIME_AFTER_END, - }, - bucketDuration: 15 * 60 * 1000, - }, - }) - ) - .expect(200); - - const logEntryRateBuckets = pipe( - getLogEntryRateSuccessReponsePayloadRT.decode(body), - fold(throwErrors(createPlainError), identity) - ); - expect(logEntryRateBuckets.data.bucketDuration).to.be(15 * 60 * 1000); - expect(logEntryRateBuckets.data.histogramBuckets).to.not.be.empty(); - expect( - logEntryRateBuckets.data.histogramBuckets.some((bucket) => { - return bucket.partitions.some((partition) => partition.anomalies.length > 0); - }) - ).to.be(true); - }); - - it('should return no buckets when there are no matching ml result documents', async () => { - const { body } = await supertest - .post(LOG_ANALYSIS_GET_LOG_ENTRY_RATE_PATH) - .set(COMMON_HEADERS) - .send( - getLogEntryRateRequestPayloadRT.encode({ - data: { - sourceId: 'default', - timeRange: { - startTime: TIME_BEFORE_START - 10 * 15 * 60 * 1000, - endTime: TIME_BEFORE_START - 1, - }, - bucketDuration: 15 * 60 * 1000, - }, - }) - ) - .expect(200); - - const logEntryRateBuckets = pipe( - getLogEntryRateSuccessReponsePayloadRT.decode(body), - fold(throwErrors(createPlainError), identity) - ); - - expect(logEntryRateBuckets.data.bucketDuration).to.be(15 * 60 * 1000); - expect(logEntryRateBuckets.data.histogramBuckets).to.be.empty(); - }); - }); - }); - }); -}; diff --git a/x-pack/test/api_integration/apis/metrics_ui/sources.ts b/x-pack/test/api_integration/apis/metrics_ui/sources.ts index 7fb631477cb76..a5bab8de92f38 100644 --- a/x-pack/test/api_integration/apis/metrics_ui/sources.ts +++ b/x-pack/test/api_integration/apis/metrics_ui/sources.ts @@ -17,11 +17,12 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); const supertest = getService('supertest'); + const SOURCE_API_URL = '/api/metrics/source/default'; const patchRequest = async ( body: InfraSavedSourceConfiguration ): Promise => { const response = await supertest - .patch('/api/metrics/source/default') + .patch(SOURCE_API_URL) .set('kbn-xsrf', 'xxx') .send(body) .expect(200); @@ -73,6 +74,7 @@ export default function ({ getService }: FtrProviderContext) { expect(configuration?.fields.timestamp).to.be('@timestamp'); expect(configuration?.fields.container).to.be('container.id'); expect(configuration?.logColumns).to.have.length(3); + expect(configuration?.anomalyThreshold).to.be(50); expect(status?.logIndicesExist).to.be(true); expect(status?.metricIndicesExist).to.be(true); }); @@ -173,6 +175,31 @@ export default function ({ getService }: FtrProviderContext) { expect(fieldColumn).to.have.property('id', 'ADDED_COLUMN_ID'); expect(fieldColumn).to.have.property('field', 'ADDED_COLUMN_FIELD'); }); + it('validates anomalyThreshold is between range 1-100', async () => { + // create config with bad request + await supertest + .patch(SOURCE_API_URL) + .set('kbn-xsrf', 'xxx') + .send({ name: 'NAME', anomalyThreshold: -20 }) + .expect(400); + // create config with good request + await supertest + .patch(SOURCE_API_URL) + .set('kbn-xsrf', 'xxx') + .send({ name: 'NAME', anomalyThreshold: 20 }) + .expect(200); + + await supertest + .patch(SOURCE_API_URL) + .set('kbn-xsrf', 'xxx') + .send({ anomalyThreshold: -2 }) + .expect(400); + await supertest + .patch(SOURCE_API_URL) + .set('kbn-xsrf', 'xxx') + .send({ anomalyThreshold: 101 }) + .expect(400); + }); }); }); } 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 be1ac7fbb0965..8064d498774a3 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 @@ -772,6 +772,7 @@ export default ({ getService }: FtrProviderContext) => { const expectedRspDatafeeds = sortBy( testData.expected.jobs.map((job) => { return { + awaitingMlNodeAllocation: false, id: `datafeed-${job.jobId}`, success: true, started: testData.requestBody.startDatafeed, diff --git a/x-pack/test/api_integration/apis/security_solution/users.ts b/x-pack/test/api_integration/apis/security_solution/users.ts index 45e06ab72adbb..b888be2bf6276 100644 --- a/x-pack/test/api_integration/apis/security_solution/users.ts +++ b/x-pack/test/api_integration/apis/security_solution/users.ts @@ -23,6 +23,7 @@ export default function ({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); const supertest = getService('supertest'); // Failing: See https://github.com/elastic/kibana/issues/90135 + // Failing: See https://github.com/elastic/kibana/issues/90136 describe.skip('Users', () => { describe('With auditbeat', () => { before(() => esArchiver.load('auditbeat/default')); diff --git a/x-pack/test/api_integration/apis/telemetry/telemetry_local.js b/x-pack/test/api_integration/apis/telemetry/telemetry_local.js index 9a6602ef923d3..3be24b273ae4c 100644 --- a/x-pack/test/api_integration/apis/telemetry/telemetry_local.js +++ b/x-pack/test/api_integration/apis/telemetry/telemetry_local.js @@ -83,7 +83,7 @@ export default function ({ getService }) { expect(stats.stack_stats.kibana.plugins.reporting.enabled).to.be(true); expect(stats.stack_stats.kibana.plugins.rollups.index_patterns).to.be.an('object'); expect(stats.stack_stats.kibana.plugins.spaces.available).to.be(true); - expect(stats.stack_stats.kibana.plugins.fileUploadTelemetry.filesUploadedTotalCount).to.be.a( + expect(stats.stack_stats.kibana.plugins.fileUpload.file_upload.index_creation_count).to.be.a( 'number' ); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/roles_users_utils/index.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/roles_users_utils/index.ts index 1d3e5244a59ed..9e84ad0a547aa 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/roles_users_utils/index.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/roles_users_utils/index.ts @@ -6,6 +6,7 @@ */ import { assertUnreachable } from '../../../../plugins/security_solution/common/utility_types'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; import { t1AnalystUser, t2AnalystUser, @@ -26,10 +27,9 @@ import { } from '../../../../plugins/security_solution/server/lib/detection_engine/scripts/roles_users'; import { ROLES } from '../../../../plugins/security_solution/common/test'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; export const createUserAndRole = async ( - securityService: ReturnType, + getService: FtrProviderContext['getService'], role: ROLES ): Promise => { switch (role) { @@ -38,32 +38,47 @@ export const createUserAndRole = async ( ROLES.detections_admin, detectionsAdminRole, detectionsAdminUser, - securityService + getService ); case ROLES.t1_analyst: - return postRoleAndUser(ROLES.t1_analyst, t1AnalystRole, t1AnalystUser, securityService); + return postRoleAndUser(ROLES.t1_analyst, t1AnalystRole, t1AnalystUser, getService); case ROLES.t2_analyst: - return postRoleAndUser(ROLES.t2_analyst, t2AnalystRole, t2AnalystUser, securityService); + return postRoleAndUser(ROLES.t2_analyst, t2AnalystRole, t2AnalystUser, getService); case ROLES.hunter: - return postRoleAndUser(ROLES.hunter, hunterRole, hunterUser, securityService); + return postRoleAndUser(ROLES.hunter, hunterRole, hunterUser, getService); case ROLES.rule_author: - return postRoleAndUser(ROLES.rule_author, ruleAuthorRole, ruleAuthorUser, securityService); + return postRoleAndUser(ROLES.rule_author, ruleAuthorRole, ruleAuthorUser, getService); case ROLES.soc_manager: - return postRoleAndUser(ROLES.soc_manager, socManagerRole, socManagerUser, securityService); + return postRoleAndUser(ROLES.soc_manager, socManagerRole, socManagerUser, getService); case ROLES.platform_engineer: return postRoleAndUser( ROLES.platform_engineer, platformEngineerRole, platformEngineerUser, - securityService + getService ); case ROLES.reader: - return postRoleAndUser(ROLES.reader, readerRole, readerUser, securityService); + return postRoleAndUser(ROLES.reader, readerRole, readerUser, getService); default: return assertUnreachable(role); } }; +/** + * Given a roleName and security service this will delete the roleName + * and user + * @param roleName The user and role to delete with the same name + * @param securityService The security service + */ +export const deleteUserAndRole = async ( + getService: FtrProviderContext['getService'], + roleName: ROLES +): Promise => { + const securityService = getService('security'); + await securityService.user.delete(roleName); + await securityService.role.delete(roleName); +}; + interface UserInterface { password: string; roles: string[]; @@ -95,8 +110,9 @@ export const postRoleAndUser = async ( roleName: string, role: RoleInterface, user: UserInterface, - securityService: ReturnType -) => { + getService: FtrProviderContext['getService'] +): Promise => { + const securityService = getService('security'); await securityService.role.create(roleName, { kibana: role.kibana, elasticsearch: role.elasticsearch, diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_index.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_index.ts index c2822b8638d76..a319c30fa20de 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_index.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_index.ts @@ -14,16 +14,14 @@ import { import { FtrProviderContext } from '../../common/ftr_provider_context'; import { deleteSignalsIndex } from '../../utils'; import { ROLES } from '../../../../plugins/security_solution/common/test'; -import { createUserAndRole } from '../roles_users_utils'; +import { createUserAndRole, deleteUserAndRole } from '../roles_users_utils'; // eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); const supertestWithoutAuth = getService('supertestWithoutAuth'); - const security = getService('security'); - // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/90229 - describe.skip('create_index', () => { + describe('create_index', () => { afterEach(async () => { await deleteSignalsIndex(supertest); }); @@ -66,8 +64,13 @@ export default ({ getService }: FtrProviderContext) => { describe('t1_analyst', () => { const role = ROLES.t1_analyst; + beforeEach(async () => { - await createUserAndRole(security, role); + await createUserAndRole(getService, role); + }); + + afterEach(async () => { + await deleteUserAndRole(getService, role); }); it('should return a 404 when the signal index has never been created', async () => { @@ -88,7 +91,7 @@ export default ({ getService }: FtrProviderContext) => { .expect(403); expect(body).to.eql({ message: - 'security_exception: action [cluster:admin/ilm/get] is unauthorized for user [t1_analyst], this action is granted by the privileges [read_ilm,manage_ilm,manage,all]', + 'security_exception: action [cluster:admin/ilm/get] is unauthorized for user [t1_analyst], this action is granted by the cluster privileges [read_ilm,manage_ilm,manage,all]', status_code: 403, }); }); @@ -111,8 +114,13 @@ export default ({ getService }: FtrProviderContext) => { describe('t2_analyst', () => { const role = ROLES.t2_analyst; + beforeEach(async () => { - await createUserAndRole(security, role); + await createUserAndRole(getService, role); + }); + + afterEach(async () => { + await deleteUserAndRole(getService, role); }); it('should return a 404 when the signal index has never been created', async () => { @@ -133,7 +141,7 @@ export default ({ getService }: FtrProviderContext) => { .expect(403); expect(body).to.eql({ message: - 'security_exception: action [cluster:admin/ilm/get] is unauthorized for user [t2_analyst], this action is granted by the privileges [read_ilm,manage_ilm,manage,all]', + 'security_exception: action [cluster:admin/ilm/get] is unauthorized for user [t2_analyst], this action is granted by the cluster privileges [read_ilm,manage_ilm,manage,all]', status_code: 403, }); }); @@ -156,8 +164,13 @@ export default ({ getService }: FtrProviderContext) => { describe('detections_admin', () => { const role = ROLES.detections_admin; + beforeEach(async () => { - await createUserAndRole(security, role); + await createUserAndRole(getService, role); + }); + + afterEach(async () => { + await deleteUserAndRole(getService, role); }); it('should return a 404 when the signal index has never been created', async () => { @@ -201,8 +214,13 @@ export default ({ getService }: FtrProviderContext) => { describe('soc_manager', () => { const role = ROLES.soc_manager; + beforeEach(async () => { - await createUserAndRole(security, role); + await createUserAndRole(getService, role); + }); + + afterEach(async () => { + await deleteUserAndRole(getService, role); }); it('should return a 404 when the signal index has never been created', async () => { @@ -223,7 +241,7 @@ export default ({ getService }: FtrProviderContext) => { .expect(403); expect(body).to.eql({ message: - 'security_exception: action [cluster:admin/ilm/get] is unauthorized for user [soc_manager], this action is granted by the privileges [read_ilm,manage_ilm,manage,all]', + 'security_exception: action [cluster:admin/ilm/get] is unauthorized for user [soc_manager], this action is granted by the cluster privileges [read_ilm,manage_ilm,manage,all]', status_code: 403, }); }); @@ -246,8 +264,13 @@ export default ({ getService }: FtrProviderContext) => { describe('hunter', () => { const role = ROLES.hunter; + beforeEach(async () => { - await createUserAndRole(security, role); + await createUserAndRole(getService, role); + }); + + afterEach(async () => { + await deleteUserAndRole(getService, role); }); it('should return a 404 when the signal index has never been created', async () => { @@ -268,7 +291,7 @@ export default ({ getService }: FtrProviderContext) => { .expect(403); expect(body).to.eql({ message: - 'security_exception: action [cluster:admin/ilm/get] is unauthorized for user [hunter], this action is granted by the privileges [read_ilm,manage_ilm,manage,all]', + 'security_exception: action [cluster:admin/ilm/get] is unauthorized for user [hunter], this action is granted by the cluster privileges [read_ilm,manage_ilm,manage,all]', status_code: 403, }); }); @@ -291,8 +314,13 @@ export default ({ getService }: FtrProviderContext) => { describe('platform_engineer', () => { const role = ROLES.platform_engineer; + beforeEach(async () => { - await createUserAndRole(security, role); + await createUserAndRole(getService, role); + }); + + afterEach(async () => { + await deleteUserAndRole(getService, role); }); it('should return a 404 when the signal index has never been created', async () => { @@ -336,8 +364,13 @@ export default ({ getService }: FtrProviderContext) => { describe('reader', () => { const role = ROLES.reader; + beforeEach(async () => { - await createUserAndRole(security, role); + await createUserAndRole(getService, role); + }); + + afterEach(async () => { + await deleteUserAndRole(getService, role); }); it('should return a 404 when the signal index has never been created', async () => { @@ -358,7 +391,7 @@ export default ({ getService }: FtrProviderContext) => { .expect(403); expect(body).to.eql({ message: - 'security_exception: action [cluster:admin/ilm/get] is unauthorized for user [reader], this action is granted by the privileges [read_ilm,manage_ilm,manage,all]', + 'security_exception: action [cluster:admin/ilm/get] is unauthorized for user [reader], this action is granted by the cluster privileges [read_ilm,manage_ilm,manage,all]', status_code: 403, }); }); @@ -381,8 +414,13 @@ export default ({ getService }: FtrProviderContext) => { describe('rule_author', () => { const role = ROLES.rule_author; + beforeEach(async () => { - await createUserAndRole(security, role); + await createUserAndRole(getService, role); + }); + + afterEach(async () => { + await deleteUserAndRole(getService, role); }); it('should return a 404 when the signal index has never been created', async () => { @@ -403,7 +441,7 @@ export default ({ getService }: FtrProviderContext) => { .expect(403); expect(body).to.eql({ message: - 'security_exception: action [cluster:admin/ilm/get] is unauthorized for user [rule_author], this action is granted by the privileges [read_ilm,manage_ilm,manage,all]', + 'security_exception: action [cluster:admin/ilm/get] is unauthorized for user [rule_author], this action is granted by the cluster privileges [read_ilm,manage_ilm,manage,all]', status_code: 403, }); }); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_signals_migrations.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_signals_migrations.ts index fc77fba5fa339..dd0052b03382a 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_signals_migrations.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_signals_migrations.ts @@ -21,7 +21,7 @@ import { getIndexNameFromLoad, waitForIndexToPopulate, } from '../../utils'; -import { createUserAndRole } from '../roles_users_utils'; +import { createUserAndRole, deleteUserAndRole } from '../roles_users_utils'; interface CreateResponse { index: string; @@ -34,7 +34,6 @@ export default ({ getService }: FtrProviderContext): void => { const es = getService('es'); const esArchiver = getService('esArchiver'); const kbnClient = getService('kibanaServer'); - const security = getService('security'); const supertest = getService('supertest'); const supertestWithoutAuth = getService('supertestWithoutAuth'); @@ -173,7 +172,7 @@ export default ({ getService }: FtrProviderContext): void => { }); it('rejects the request if the user does not have sufficient privileges', async () => { - await createUserAndRole(security, ROLES.t1_analyst); + await createUserAndRole(getService, ROLES.t1_analyst); await supertestWithoutAuth .post(DETECTION_ENGINE_SIGNALS_MIGRATION_URL) @@ -181,6 +180,8 @@ export default ({ getService }: FtrProviderContext): void => { .auth(ROLES.t1_analyst, 'changeme') .send({ index: [legacySignalsIndexName] }) .expect(400); + + await deleteUserAndRole(getService, ROLES.t1_analyst); }); }); }; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/delete_signals_migrations.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/delete_signals_migrations.ts index 234370e4f104e..bba6ce1125c37 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/delete_signals_migrations.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/delete_signals_migrations.ts @@ -32,12 +32,10 @@ interface FinalizeResponse extends CreateResponse { export default ({ getService }: FtrProviderContext): void => { const es = getService('es'); const esArchiver = getService('esArchiver'); - const security = getService('security'); const supertest = getService('supertest'); const supertestWithoutAuth = getService('supertestWithoutAuth'); - // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/90229 - describe.skip('deleting signals migrations', () => { + describe('deleting signals migrations', () => { let outdatedSignalsIndexName: string; let createdMigration: CreateResponse; let finalizedMigration: FinalizeResponse; @@ -105,7 +103,7 @@ export default ({ getService }: FtrProviderContext): void => { }); it('rejects the request if the user does not have sufficient privileges', async () => { - await createUserAndRole(security, ROLES.t1_analyst); + await createUserAndRole(getService, ROLES.t1_analyst); const { body } = await supertestWithoutAuth .delete(DETECTION_ENGINE_SIGNALS_MIGRATION_URL) @@ -119,7 +117,7 @@ export default ({ getService }: FtrProviderContext): void => { expect(deletedMigration.id).to.eql(createdMigration.migration_id); expect(deletedMigration.error).to.eql({ message: - 'security_exception: action [indices:admin/settings/update] is unauthorized for user [t1_analyst] on indices [], this action is granted by the privileges [manage,all]', + 'security_exception: action [indices:admin/settings/update] is unauthorized for user [t1_analyst] on indices [], this action is granted by the index privileges [manage,all]', status_code: 403, }); }); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/finalize_signals_migrations.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/finalize_signals_migrations.ts index 64c0c6666469a..0fd05904d5e33 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/finalize_signals_migrations.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/finalize_signals_migrations.ts @@ -21,7 +21,7 @@ import { getIndexNameFromLoad, waitFor, } from '../../utils'; -import { createUserAndRole } from '../roles_users_utils'; +import { createUserAndRole, deleteUserAndRole } from '../roles_users_utils'; interface StatusResponse { index: string; @@ -44,12 +44,10 @@ interface FinalizeResponse { export default ({ getService }: FtrProviderContext): void => { const esArchiver = getService('esArchiver'); const kbnClient = getService('kibanaServer'); - const security = getService('security'); const supertest = getService('supertest'); const supertestWithoutAuth = getService('supertestWithoutAuth'); - // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/88302 - describe.skip('Finalizing signals migrations', () => { + describe('Finalizing signals migrations', () => { let legacySignalsIndexName: string; let outdatedSignalsIndexName: string; let createdMigrations: CreateResponse[]; @@ -234,7 +232,7 @@ export default ({ getService }: FtrProviderContext): void => { }); it('rejects the request if the user does not have sufficient privileges', async () => { - await createUserAndRole(security, ROLES.t1_analyst); + await createUserAndRole(getService, ROLES.t1_analyst); const { body } = await supertestWithoutAuth .post(DETECTION_ENGINE_SIGNALS_FINALIZE_MIGRATION_URL) @@ -249,9 +247,11 @@ export default ({ getService }: FtrProviderContext): void => { expect(finalizeResponse.completed).not.to.eql(true); expect(finalizeResponse.error).to.eql({ message: - 'security_exception: action [cluster:monitor/task/get] is unauthorized for user [t1_analyst]', + 'security_exception: action [cluster:monitor/task/get] is unauthorized for user [t1_analyst], this action is granted by the cluster privileges [monitor,manage,all]', status_code: 403, }); + + await deleteUserAndRole(getService, ROLES.t1_analyst); }); }); }; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/get_signals_migration_status.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/get_signals_migration_status.ts index 3b9ec8e0909dc..793dec9eaae4b 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/get_signals_migration_status.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/get_signals_migration_status.ts @@ -11,12 +11,11 @@ import { DETECTION_ENGINE_SIGNALS_MIGRATION_STATUS_URL } from '../../../../plugi import { ROLES } from '../../../../plugins/security_solution/common/test'; import { FtrProviderContext } from '../../common/ftr_provider_context'; import { createSignalsIndex, deleteSignalsIndex, getIndexNameFromLoad } from '../../utils'; -import { createUserAndRole } from '../roles_users_utils'; +import { createUserAndRole, deleteUserAndRole } from '../roles_users_utils'; // eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext): void => { const esArchiver = getService('esArchiver'); - const security = getService('security'); const supertest = getService('supertest'); const supertestWithoutAuth = getService('supertestWithoutAuth'); @@ -99,7 +98,7 @@ export default ({ getService }: FtrProviderContext): void => { }); it('rejects the request if the user does not have sufficient privileges', async () => { - await createUserAndRole(security, ROLES.t1_analyst); + await createUserAndRole(getService, ROLES.t1_analyst); await supertestWithoutAuth .get(DETECTION_ENGINE_SIGNALS_MIGRATION_STATUS_URL) @@ -107,6 +106,8 @@ export default ({ getService }: FtrProviderContext): void => { .auth(ROLES.t1_analyst, 'changeme') .query({ from: '2020-10-10' }) .expect(403); + + await deleteUserAndRole(getService, ROLES.t1_analyst); }); }); }; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/open_close_signals.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/open_close_signals.ts index 973b643a7a425..36a05f0ae8c0e 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/open_close_signals.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/open_close_signals.ts @@ -27,7 +27,7 @@ import { waitForRuleSuccessOrStatus, getRuleForSignalTesting, } from '../../utils'; -import { createUserAndRole } from '../roles_users_utils'; +import { createUserAndRole, deleteUserAndRole } from '../roles_users_utils'; import { ROLES } from '../../../../plugins/security_solution/common/test'; // eslint-disable-next-line import/no-default-export @@ -35,7 +35,6 @@ export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); const esArchiver = getService('esArchiver'); const supertestWithoutAuth = getService('supertestWithoutAuth'); - const securityService = getService('security'); describe('open_close_signals', () => { describe('validation checks', () => { @@ -172,7 +171,7 @@ export default ({ getService }: FtrProviderContext) => { const { id } = await createRule(supertest, rule); await waitForRuleSuccessOrStatus(supertest, id); await waitForSignalsToBePresent(supertest, 1, [id]); - await createUserAndRole(securityService, ROLES.t1_analyst); + await createUserAndRole(getService, ROLES.t1_analyst); const signalsOpen = await getSignalsByIds(supertest, [id]); const signalIds = signalsOpen.hits.hits.map((signal) => signal._id); @@ -203,6 +202,8 @@ export default ({ getService }: FtrProviderContext) => { }) => status === 'closed' ); expect(everySignalOpen).to.eql(true); + + await deleteUserAndRole(getService, ROLES.t1_analyst); }); it('should be able to close signals with soc_manager user', async () => { @@ -211,7 +212,7 @@ export default ({ getService }: FtrProviderContext) => { await waitForRuleSuccessOrStatus(supertest, id); await waitForSignalsToBePresent(supertest, 1, [id]); const userAndRole = ROLES.soc_manager; - await createUserAndRole(securityService, userAndRole); + await createUserAndRole(getService, userAndRole); const signalsOpen = await getSignalsByIds(supertest, [id]); const signalIds = signalsOpen.hits.hits.map((signal) => signal._id); @@ -240,6 +241,8 @@ export default ({ getService }: FtrProviderContext) => { }) => status === 'closed' ); expect(everySignalClosed).to.eql(true); + + await deleteUserAndRole(getService, userAndRole); }); }); }); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/read_privileges.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/read_privileges.ts index 614f08295b38f..f8949daea831e 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/read_privileges.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/read_privileges.ts @@ -10,14 +10,14 @@ import { DETECTION_ENGINE_PRIVILEGES_URL } from '../../../../plugins/security_so import { FtrProviderContext } from '../../common/ftr_provider_context'; import { ROLES } from '../../../../plugins/security_solution/common/test'; +import { createUserAndRole, deleteUserAndRole } from '../roles_users_utils'; // eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); const supertestWithoutAuth = getService('supertestWithoutAuth'); - // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/90229 - describe.skip('read_privileges', () => { + describe('read_privileges', () => { it('should return expected privileges for elastic admin', async () => { const { body } = await supertest.get(DETECTION_ENGINE_PRIVILEGES_URL).send().expect(200); expect(body).to.eql({ @@ -78,6 +78,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('should return expected privileges for a "reader" user', async () => { + await createUserAndRole(getService, ROLES.reader); const { body } = await supertestWithoutAuth .get(DETECTION_ENGINE_PRIVILEGES_URL) .auth(ROLES.reader, 'changeme') @@ -138,9 +139,11 @@ export default ({ getService }: FtrProviderContext) => { is_authenticated: true, has_encryption_key: true, }); + await deleteUserAndRole(getService, ROLES.reader); }); it('should return expected privileges for a "t1_analyst" user', async () => { + await createUserAndRole(getService, ROLES.t1_analyst); const { body } = await supertestWithoutAuth .get(DETECTION_ENGINE_PRIVILEGES_URL) .auth(ROLES.t1_analyst, 'changeme') @@ -201,9 +204,11 @@ export default ({ getService }: FtrProviderContext) => { is_authenticated: true, has_encryption_key: true, }); + await deleteUserAndRole(getService, ROLES.t1_analyst); }); it('should return expected privileges for a "t2_analyst" user', async () => { + await createUserAndRole(getService, ROLES.t2_analyst); const { body } = await supertestWithoutAuth .get(DETECTION_ENGINE_PRIVILEGES_URL) .auth(ROLES.t2_analyst, 'changeme') @@ -264,9 +269,11 @@ export default ({ getService }: FtrProviderContext) => { is_authenticated: true, has_encryption_key: true, }); + await deleteUserAndRole(getService, ROLES.t2_analyst); }); it('should return expected privileges for a "hunter" user', async () => { + await createUserAndRole(getService, ROLES.hunter); const { body } = await supertestWithoutAuth .get(DETECTION_ENGINE_PRIVILEGES_URL) .auth(ROLES.hunter, 'changeme') @@ -327,9 +334,11 @@ export default ({ getService }: FtrProviderContext) => { is_authenticated: true, has_encryption_key: true, }); + await deleteUserAndRole(getService, ROLES.hunter); }); it('should return expected privileges for a "rule_author" user', async () => { + await createUserAndRole(getService, ROLES.rule_author); const { body } = await supertestWithoutAuth .get(DETECTION_ENGINE_PRIVILEGES_URL) .auth(ROLES.rule_author, 'changeme') @@ -390,9 +399,11 @@ export default ({ getService }: FtrProviderContext) => { is_authenticated: true, has_encryption_key: true, }); + await deleteUserAndRole(getService, ROLES.rule_author); }); it('should return expected privileges for a "soc_manager" user', async () => { + await createUserAndRole(getService, ROLES.soc_manager); const { body } = await supertestWithoutAuth .get(DETECTION_ENGINE_PRIVILEGES_URL) .auth(ROLES.soc_manager, 'changeme') @@ -453,9 +464,11 @@ export default ({ getService }: FtrProviderContext) => { is_authenticated: true, has_encryption_key: true, }); + await deleteUserAndRole(getService, ROLES.soc_manager); }); it('should return expected privileges for a "platform_engineer" user', async () => { + await createUserAndRole(getService, ROLES.platform_engineer); const { body } = await supertestWithoutAuth .get(DETECTION_ENGINE_PRIVILEGES_URL) .auth(ROLES.platform_engineer, 'changeme') @@ -516,9 +529,11 @@ export default ({ getService }: FtrProviderContext) => { is_authenticated: true, has_encryption_key: true, }); + await deleteUserAndRole(getService, ROLES.platform_engineer); }); it('should return expected privileges for a "detections_admin" user', async () => { + await createUserAndRole(getService, ROLES.detections_admin); const { body } = await supertestWithoutAuth .get(DETECTION_ENGINE_PRIVILEGES_URL) .auth(ROLES.detections_admin, 'changeme') @@ -579,6 +594,7 @@ export default ({ getService }: FtrProviderContext) => { is_authenticated: true, has_encryption_key: true, }); + await deleteUserAndRole(getService, ROLES.detections_admin); }); }); }; diff --git a/x-pack/test/fleet_api_integration/apis/agents/enroll.ts b/x-pack/test/fleet_api_integration/apis/agents/enroll.ts index 96c472697801e..3358d045fe69b 100644 --- a/x-pack/test/fleet_api_integration/apis/agents/enroll.ts +++ b/x-pack/test/fleet_api_integration/apis/agents/enroll.ts @@ -18,8 +18,9 @@ export default function (providerContext: FtrProviderContext) { const esArchiver = getService('esArchiver'); const esClient = getService('es'); const kibanaServer = getService('kibanaServer'); - + const supertestWithAuth = getService('supertest'); const supertest = getSupertestWithoutAuth(providerContext); + let apiKey: { id: string; api_key: string }; let kibanaVersion: string; @@ -58,6 +59,51 @@ export default function (providerContext: FtrProviderContext) { await esArchiver.unload('fleet/agents'); }); + it('should not allow enrolling in a managed policy', async () => { + // update existing policy to managed + await supertestWithAuth + .put(`/api/fleet/agent_policies/policy1`) + .set('kbn-xsrf', 'xxxx') + .send({ + name: 'Test policy', + namespace: 'default', + is_managed: true, + }) + .expect(200); + + // try to enroll in managed policy + const { body } = await supertest + .post(`/api/fleet/agents/enroll`) + .set('kbn-xsrf', 'xxx') + .set( + 'Authorization', + `ApiKey ${Buffer.from(`${apiKey.id}:${apiKey.api_key}`).toString('base64')}` + ) + .send({ + type: 'PERMANENT', + metadata: { + local: { + elastic: { agent: { version: kibanaVersion } }, + }, + user_provided: {}, + }, + }) + .expect(400); + + expect(body.message).to.contain('Cannot enroll in managed policy'); + + // restore to original (unmanaged) + await supertestWithAuth + .put(`/api/fleet/agent_policies/policy1`) + .set('kbn-xsrf', 'xxxx') + .send({ + name: 'Test policy', + namespace: 'default', + is_managed: false, + }) + .expect(200); + }); + it('should not allow to enroll an agent with a invalid enrollment', async () => { await supertest .post(`/api/fleet/agents/enroll`) diff --git a/x-pack/test/functional/apps/index_management/home_page.ts b/x-pack/test/functional/apps/index_management/home_page.ts index 9fbe5373dd3d4..f8f852b9667fb 100644 --- a/x-pack/test/functional/apps/index_management/home_page.ts +++ b/x-pack/test/functional/apps/index_management/home_page.ts @@ -13,6 +13,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const pageObjects = getPageObjects(['common', 'indexManagement', 'header']); const log = getService('log'); const browser = getService('browser'); + const retry = getService('retry'); describe('Home page', function () { before(async () => { @@ -49,8 +50,9 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { expect(url).to.contain(`/data_streams`); // Verify content - const dataStreamList = await testSubjects.exists('dataStreamList'); - expect(dataStreamList).to.be(true); + await retry.waitFor('Wait until dataStream Table is visible.', async () => { + return await testSubjects.isDisplayed('dataStreamTable'); + }); }); }); diff --git a/x-pack/test/functional/apps/maps/import_geojson/file_indexing_panel.js b/x-pack/test/functional/apps/maps/import_geojson/file_indexing_panel.js index 4496b59393eec..0ce9b7022b38d 100644 --- a/x-pack/test/functional/apps/maps/import_geojson/file_indexing_panel.js +++ b/x-pack/test/functional/apps/maps/import_geojson/file_indexing_panel.js @@ -11,7 +11,6 @@ import uuid from 'uuid/v4'; export default function ({ getService, getPageObjects }) { const PageObjects = getPageObjects(['maps', 'common']); - const testSubjects = getService('testSubjects'); const log = getService('log'); const security = getService('security'); @@ -99,20 +98,6 @@ export default function ({ getService, getPageObjects }) { expect(newIndexedLayerExists).to.be(false); }); - it('should create a link to new index in management', async () => { - const indexName = await indexPoint(); - - const layerAddReady = await PageObjects.maps.importLayerReadyForAdd(); - expect(layerAddReady).to.be(true); - - const newIndexLinkExists = await testSubjects.exists('indexManagementNewIndexLink'); - expect(newIndexLinkExists).to.be(true); - - const indexLink = await testSubjects.getAttribute('indexManagementNewIndexLink', 'href'); - const linkDirectsToNewIndex = indexLink.endsWith(indexName); - expect(linkDirectsToNewIndex).to.be(true); - }); - const GEO_POINT = 'geo_point'; const pointGeojsonFiles = ['point.json', 'multi_point.json']; pointGeojsonFiles.forEach(async (pointFile) => { diff --git a/x-pack/test/functional/apps/ml/data_frame_analytics/cloning.ts b/x-pack/test/functional/apps/ml/data_frame_analytics/cloning.ts index 72e81dad44629..04712fc0c1426 100644 --- a/x-pack/test/functional/apps/ml/data_frame_analytics/cloning.ts +++ b/x-pack/test/functional/apps/ml/data_frame_analytics/cloning.ts @@ -15,8 +15,7 @@ export default function ({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); const ml = getService('ml'); - // Failing ES promotion, see https://github.com/elastic/kibana/issues/89980 - describe.skip('jobs cloning supported by UI form', function () { + describe('jobs cloning supported by UI form', function () { const testDataList: Array<{ suiteTitle: string; archive: string; diff --git a/x-pack/test/functional/apps/status_page/status_page.ts b/x-pack/test/functional/apps/status_page/status_page.ts index d2d6a24bdccd1..55a54245cf832 100644 --- a/x-pack/test/functional/apps/status_page/status_page.ts +++ b/x-pack/test/functional/apps/status_page/status_page.ts @@ -14,7 +14,8 @@ export default function statusPageFunctonalTests({ const esArchiver = getService('esArchiver'); const PageObjects = getPageObjects(['security', 'statusPage', 'home']); - describe('Status Page', function () { + // FLAKY: https://github.com/elastic/kibana/issues/50448 + describe.skip('Status Page', function () { this.tags(['skipCloud', 'includeFirefox']); before(async () => await esArchiver.load('empty_kibana')); after(async () => await esArchiver.unload('empty_kibana')); diff --git a/x-pack/test/functional/apps/transform/feature_controls/transform_security.ts b/x-pack/test/functional/apps/transform/feature_controls/transform_security.ts index 46e0c01afcc38..b8d6b88e4ed9a 100644 --- a/x-pack/test/functional/apps/transform/feature_controls/transform_security.ts +++ b/x-pack/test/functional/apps/transform/feature_controls/transform_security.ts @@ -15,7 +15,8 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const appsMenu = getService('appsMenu'); const managementMenu = getService('managementMenu'); - describe('security', () => { + // FLAKY: https://github.com/elastic/kibana/issues/90576 + describe.skip('security', () => { before(async () => { await esArchiver.load('empty_kibana'); await PageObjects.security.forceLogout(); diff --git a/x-pack/test/functional/apps/upgrade_assistant/upgrade_assistant.ts b/x-pack/test/functional/apps/upgrade_assistant/upgrade_assistant.ts index 711c9b7683678..93955fb741044 100644 --- a/x-pack/test/functional/apps/upgrade_assistant/upgrade_assistant.ts +++ b/x-pack/test/functional/apps/upgrade_assistant/upgrade_assistant.ts @@ -18,7 +18,8 @@ export default function upgradeAssistantFunctionalTests({ const log = getService('log'); const retry = getService('retry'); - describe('Upgrade Checkup', function () { + // Failing: See https://github.com/elastic/kibana/issues/86546 + describe.skip('Upgrade Checkup', function () { this.tags('includeFirefox'); before(async () => { diff --git a/x-pack/test/functional/apps/uptime/locations.ts b/x-pack/test/functional/apps/uptime/locations.ts index e3f1d04640754..15b4773373bf7 100644 --- a/x-pack/test/functional/apps/uptime/locations.ts +++ b/x-pack/test/functional/apps/uptime/locations.ts @@ -39,8 +39,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await makeChecksWithStatus(es, LessAvailMonitor, 5, 2, 10000, {}, 'down'); }; - // FLAKY: https://github.com/elastic/kibana/issues/85208 - describe.skip('Observer location', () => { + describe('Observer location', () => { const start = '~ 15 minutes ago'; const end = 'now'; diff --git a/x-pack/test/functional/apps/uptime/ping_redirects.ts b/x-pack/test/functional/apps/uptime/ping_redirects.ts index e0abee38f4195..9c39ed7017721 100644 --- a/x-pack/test/functional/apps/uptime/ping_redirects.ts +++ b/x-pack/test/functional/apps/uptime/ping_redirects.ts @@ -19,8 +19,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const monitor = () => uptime.monitor; - // FLAKY: https://github.com/elastic/kibana/issues/84992 - describe.skip('Ping redirects', () => { + describe('Ping redirects', () => { const start = '~ 15 minutes ago'; const end = 'now'; diff --git a/x-pack/test/functional_with_es_ssl/config.ts b/x-pack/test/functional_with_es_ssl/config.ts index 5be8eee3155b9..a7259f2410d6b 100644 --- a/x-pack/test/functional_with_es_ssl/config.ts +++ b/x-pack/test/functional_with_es_ssl/config.ts @@ -5,6 +5,7 @@ * 2.0. */ +import Fs from 'fs'; import { resolve, join } from 'path'; import { CA_CERT_PATH } from '@kbn/dev-utils'; import { FtrConfigProviderContext } from '@kbn/test/types/ftr'; @@ -33,6 +34,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { elasticsearch: { ...xpackFunctionalConfig.get('servers.elasticsearch'), protocol: 'https', + certificateAuthorities: [Fs.readFileSync(CA_CERT_PATH)], }, }; diff --git a/x-pack/test/tsconfig.json b/x-pack/test/tsconfig.json index 7ba5c00a71b37..4cbec2da21807 100644 --- a/x-pack/test/tsconfig.json +++ b/x-pack/test/tsconfig.json @@ -82,9 +82,10 @@ { "path": "../plugins/ui_actions_enhanced/tsconfig.json" }, { "path": "../plugins/upgrade_assistant/tsconfig.json" }, { "path": "../plugins/watcher/tsconfig.json" }, - { "path": "../plugins/runtime_fields/tsconfig.json" }, - { "path": "../plugins/index_management/tsconfig.json" }, - { "path": "../plugins/watcher/tsconfig.json" }, + { "path": "../plugins/rollup/tsconfig.json" }, + { "path": "../plugins/remote_clusters/tsconfig.json" }, + { "path": "../plugins/cross_cluster_replication/tsconfig.json" }, + { "path": "../plugins/index_lifecycle_management/tsconfig.json"}, { "path": "../plugins/uptime/tsconfig.json" } ] } diff --git a/x-pack/tsconfig.json b/x-pack/tsconfig.json index 3afbb027e7fde..00286ac47da6e 100644 --- a/x-pack/tsconfig.json +++ b/x-pack/tsconfig.json @@ -27,7 +27,6 @@ "plugins/licensing/**/*", "plugins/lens/**/*", "plugins/maps/**/*", - "plugins/maps_file_upload/**/*", "plugins/maps_legacy_licensing/**/*", "plugins/ml/**/*", "plugins/observability/**/*", @@ -57,6 +56,10 @@ "plugins/index_management/**/*", "plugins/grokdebugger/**/*", "plugins/upgrade_assistant/**/*", + "plugins/rollup/**/*", + "plugins/remote_clusters/**/*", + "plugins/cross_cluster_replication/**/*", + "plugins/index_lifecycle_management/**/*", "plugins/uptime/**/*", "test/**/*" ], @@ -126,7 +129,6 @@ { "path": "./plugins/lens/tsconfig.json" }, { "path": "./plugins/license_management/tsconfig.json" }, { "path": "./plugins/licensing/tsconfig.json" }, - { "path": "./plugins/maps_file_upload/tsconfig.json" }, { "path": "./plugins/maps_legacy_licensing/tsconfig.json" }, { "path": "./plugins/maps/tsconfig.json" }, { "path": "./plugins/ml/tsconfig.json" }, @@ -148,6 +150,10 @@ { "path": "./plugins/runtime_fields/tsconfig.json" }, { "path": "./plugins/index_management/tsconfig.json" }, { "path": "./plugins/watcher/tsconfig.json" }, + { "path": "./plugins/rollup/tsconfig.json" }, + { "path": "./plugins/remote_clusters/tsconfig.json" }, + { "path": "./plugins/cross_cluster_replication/tsconfig.json"}, + { "path": "./plugins/index_lifecycle_management/tsconfig.json"}, { "path": "./plugins/uptime/tsconfig.json" } ] } diff --git a/x-pack/tsconfig.refs.json b/x-pack/tsconfig.refs.json index 54cee9b124237..a36f4e205ab7d 100644 --- a/x-pack/tsconfig.refs.json +++ b/x-pack/tsconfig.refs.json @@ -29,7 +29,6 @@ { "path": "./plugins/lens/tsconfig.json" }, { "path": "./plugins/license_management/tsconfig.json" }, { "path": "./plugins/licensing/tsconfig.json" }, - { "path": "./plugins/maps_file_upload/tsconfig.json" }, { "path": "./plugins/maps_legacy_licensing/tsconfig.json" }, { "path": "./plugins/maps/tsconfig.json" }, { "path": "./plugins/ml/tsconfig.json" }, @@ -52,6 +51,10 @@ { "path": "./plugins/runtime_fields/tsconfig.json" }, { "path": "./plugins/index_management/tsconfig.json" }, { "path": "./plugins/watcher/tsconfig.json" }, + { "path": "./plugins/rollup/tsconfig.json"}, + { "path": "./plugins/remote_clusters/tsconfig.json"}, + { "path": "./plugins/cross_cluster_replication/tsconfig.json"}, + { "path": "./plugins/index_lifecycle_management/tsconfig.json"}, { "path": "./plugins/uptime/tsconfig.json" } ] } diff --git a/yarn.lock b/yarn.lock index ec6cf338a43da..c9f3186ffcba2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2187,10 +2187,10 @@ pump "^3.0.0" secure-json-parse "^2.1.0" -"@elastic/ems-client@7.11.0": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@elastic/ems-client/-/ems-client-7.11.0.tgz#d2142d0ef5bd1aff7ae67b37c1394b73cdd48d8b" - integrity sha512-7+gDEkBr8nRS7X9i/UPg1WkS7bEBuNbBBjXCchQeYwqPRmw6vOb4wjlNzVwmOFsp2OH4lVFfZ+XU4pxTt32EXA== +"@elastic/ems-client@7.12.0": + version "7.12.0" + resolved "https://registry.yarnpkg.com/@elastic/ems-client/-/ems-client-7.12.0.tgz#cf83f5ad76e26cedfa6f5b91277d2d919b9423d1" + integrity sha512-Svv3boWL1n14nIt6tL9gaA9Ym1B4AwWl6ISZT62+uKM2G+imZxWLkqpQc/HHcf7TfuAmleF2NFwnT5vw2vZTpA== dependencies: lodash "^4.17.15" semver "7.3.2"