diff --git a/.i18nrc.json b/.i18nrc.json index 19d361aed9344..e18f529b92ac3 100644 --- a/.i18nrc.json +++ b/.i18nrc.json @@ -24,6 +24,7 @@ "src/legacy/core_plugins/management", "src/plugins/management" ], + "maps_legacy": "src/plugins/maps_legacy", "indexPatternManagement": "src/plugins/index_pattern_management", "advancedSettings": "src/plugins/advanced_settings", "kibana_legacy": "src/plugins/kibana_legacy", diff --git a/docs/images/tutorial-ilm-custom-policy.png b/docs/images/tutorial-ilm-custom-policy.png new file mode 100644 index 0000000000000..03b67829f605c Binary files /dev/null and b/docs/images/tutorial-ilm-custom-policy.png differ diff --git a/docs/images/tutorial-ilm-delete-phase-creation.png b/docs/images/tutorial-ilm-delete-phase-creation.png new file mode 100644 index 0000000000000..91a55733c284e Binary files /dev/null and b/docs/images/tutorial-ilm-delete-phase-creation.png differ diff --git a/docs/images/tutorial-ilm-delete-rollover.png b/docs/images/tutorial-ilm-delete-rollover.png new file mode 100644 index 0000000000000..ba021ecc2ac5c Binary files /dev/null and b/docs/images/tutorial-ilm-delete-rollover.png differ diff --git a/docs/images/tutorial-ilm-hotphaserollover-default.png b/docs/images/tutorial-ilm-hotphaserollover-default.png new file mode 100644 index 0000000000000..a9088c63d885d Binary files /dev/null and b/docs/images/tutorial-ilm-hotphaserollover-default.png differ diff --git a/docs/images/tutorial-ilm-modify-default-warm-phase-rollover.png b/docs/images/tutorial-ilm-modify-default-warm-phase-rollover.png new file mode 100644 index 0000000000000..c6f1e9b40e977 Binary files /dev/null and b/docs/images/tutorial-ilm-modify-default-warm-phase-rollover.png differ diff --git a/docs/management/index-lifecycle-policies/example-index-lifecycle-policy.asciidoc b/docs/management/index-lifecycle-policies/example-index-lifecycle-policy.asciidoc index f68708f1b6394..e6d94e9ca61a3 100644 --- a/docs/management/index-lifecycle-policies/example-index-lifecycle-policy.asciidoc +++ b/docs/management/index-lifecycle-policies/example-index-lifecycle-policy.asciidoc @@ -1,23 +1,179 @@ [role="xpack"] + [[example-using-index-lifecycle-policy]] -=== Example of using an index lifecycle policy +=== Tutorial: Use {ilm-init} to manage {filebeat} time-based indices + +With {ilm} ({ilm-init}), you can create policies that perform actions automatically +on indices as they age and grow. {ilm-init} policies help you to manage +performance, resilience, and retention of your data during its lifecycle. This tutorial shows +you how to use {kib}’s *Index Lifecycle Policies* to modify and create {ilm-init} +policies. You can learn more about all of the actions, benefits, and lifecycle +phases in the {ref}/overview-index-lifecycle-management.html[{ilm-init} overview]. + + +[discrete] +[[example-using-index-lifecycle-policy-scenario]] +==== Scenario + +You’re tasked with sending syslog files to an {es} cluster. This +log data has the following data retention guidelines: + +* Keep logs on hot data nodes for 30 days +* Roll over to a new index if the size reaches 50GB +* After 30 days: +** Move the logs to warm data nodes +** Set {ref}/glossary.html#glossary-replica-shard[replica shards] to 1 +** {ref}/indices-forcemerge.html[Force merge] multiple index segments to free up the space used by deleted documents +* Delete logs after 90 days + + +[discrete] +[[example-using-index-lifecycle-policy-prerequisites]] +==== Prerequisites + +To complete this tutorial, you'll need: + +* An {es} cluster with hot and warm nodes configured for shard allocation +awareness. If you’re using {cloud}/ec-getting-started-templates-hot-warm.html[{ess}], +choose the hot-warm architecture deployment template. + ++ +For a self-managed cluster, add node attributes as described for {ref}/shard-allocation-filtering.html[shard allocation filtering] +to label data nodes as hot or warm. This step is required to migrate shards between +nodes configured with specific hardware for the hot or warm phases. ++ +For example, you can set this in your `elasticsearch.yml` for each data node: ++ +[source,yaml] +-------------------------------------------------------------------------------- +node.attr.data: "warm" +-------------------------------------------------------------------------------- + +* A server with {filebeat} installed and configured to send logs to the `elasticsearch` +output as described in {filebeat-ref}/filebeat-getting-started.html[Getting Started with {filebeat}]. + +[discrete] +[[example-using-index-lifecycle-policy-view-fb-ilm-policy]] +==== View the {filebeat} {ilm-init} policy + +{filebeat} includes a default {ilm-init} policy that enables rollover. {ilm-init} +is enabled automatically if you’re using the default `filebeat.yml` and index template. + +To view the default policy in {kib}, go to *Management > Index Lifecycle Policies*, +search for _filebeat_, and choose the _filebeat-version_ policy. + +This policy initiates the rollover action when the index size reaches 50GB or +becomes 30 days old. + +[role="screenshot"] +image::images/tutorial-ilm-hotphaserollover-default.png["Default policy"] + + +[float] +==== Modify the policy + +The default policy is enough to prevent the creation of many tiny daily indices. +You can modify the policy to meet more complex requirements. + +. Activate the warm phase. + ++ +. Set either of the following options to control when the index moves to the warm phase: + +** Provide a value for *Timing for warm phase*. Setting this to *15* keeps the +indices on hot nodes for a range of 15-45 days, depending on when the initial +rollover occurred. + +** Enable *Move to warm phase on rollover*. The index might move to the warm phase +more quickly than intended if it reaches the *Maximum index size* before the +the *Maximum age*. + +. In the *Select a node attribute to control shard allocation* dropdown, select +*data:warm(2)* to migrate shards to warm data nodes. + +. Change *Number of replicas* to *1*. + +. Enable *Force merge data* and set *Number of segments* to *1*. ++ +NOTE: When rollover is enabled in the hot phase, action timing in the other phases +is based on the rollover date. + ++ +[role="screenshot"] +image::images/tutorial-ilm-modify-default-warm-phase-rollover.png["Modify to add warm phase"] + +. Activate the delete phase and set *Timing for delete phase* to *90* days. ++ +[role="screenshot"] +image::images/tutorial-ilm-delete-rollover.png["Add a delete phase"] + +[float] +==== Create a custom policy + +If meeting a specific retention time period is most important, you can create a +custom policy. For this option, you will use {filebeat} daily indices without +rollover. + +. Create a custom policy in {kib}, go to *Management > Index Lifecycle Policies > +Create Policy*. + +. Activate the warm phase and configure it as follows: ++ +|=== +|*Setting* |*Value* + +|Timing for warm phase +|30 days from index creation + +|Node attribute +|`data:warm` + +|Number of replicas +|1 + +|Force merge data +|enable + +|Number of segments +|1 +|=== + ++ +[role="screenshot"] +image::images/tutorial-ilm-custom-policy.png["Modify the custom policy to add a warm phase"] + -A common use case for managing index lifecycle policies is when you’re using -{beats-ref}/beats-reference.html[Beats] to continually send time-series data, -such as metrics and log data, to {es}. When you create the Beats packages, an -index template is installed. The template includes a default policy to apply -when new indices are created. ++ +. Activate the delete phase and set the timing. ++ +|=== +|*Setting* |*Value* +|Timing for delete phase +|90 +|=== -You can edit the policy in {kib}'s *Index Lifecycle Policies*. For example, you might: ++ +[role="screenshot"] +image::images/tutorial-ilm-delete-phase-creation.png["Delete phase"] -* Rollover the index when it reaches 50 GB in size or is 30 days old. These -settings are the default for the Beats lifecycle policy. This avoids -having 1000s of tiny indices. When a rollover occurs, a new “hot” index is -created and added to the index alias. +. Configure the index to use the new policy in *{kib} > Management > Index Lifecycle +Policies* -* Move the index into the warm phase, shrink the index down to a single shard, -and force merge to a single segment. +.. Find your {ilm-init} policy. +.. Click the *Actions* link next to your policy name. +.. Choose *Add policy to index template*. +.. Select your {filebeat} index template name from the *Index template* list. For example, `filebeat-7.5.x`. +.. Click *Add Policy* to save the changes. -* After 60 days, move the index into the cold phase and onto less expensive hardware. ++ +NOTE: If you initially used the default {filebeat} {ilm-init} policy, you will +see a notice that the template already has a policy associated with it. Confirm +that you want to overwrite that configuration. -* Delete the index after 90 days. ++ ++ +TIP: When you change the policy associated with the index template, the active +index will continue to use the policy it was associated with at index creation +unless you manually update it. The next new index will use the updated policy. +For more reasons that your {ilm-init} policy changes might be delayed, see +{ref}/update-lifecycle-policy.html#update-lifecycle-policy[Update Lifecycle Policy]. diff --git a/src/core/MIGRATION.md b/src/core/MIGRATION.md index 5d7b467052029..368d1f47e9c3f 100644 --- a/src/core/MIGRATION.md +++ b/src/core/MIGRATION.md @@ -24,6 +24,7 @@ - [7. Switch to new platform services](#7-switch-to-new-platform-services) - [8. Migrate to the new plugin system](#8-migrate-to-the-new-plugin-system) - [Bonus: Tips for complex migration scenarios](#bonus-tips-for-complex-migration-scenarios) + - [Keep Kibana fast](#keep-kibana-fast) - [Frequently asked questions](#frequently-asked-questions) - [Is migrating a plugin an all-or-nothing thing?](#is-migrating-a-plugin-an-all-or-nothing-thing) - [Do plugins need to be converted to TypeScript?](#do-plugins-need-to-be-converted-to-typescript) @@ -933,6 +934,66 @@ For a few plugins, some of these steps (such as angular removal) could be a mont One convention that is useful for this is creating a dedicated `public/np_ready` directory to house the code that is ready to migrate, and gradually move more and more code into it until the rest of your plugin is essentially empty. At that point, you'll be able to copy your `index.ts`, `plugin.ts`, and the contents of `./np_ready` over into your plugin in the new platform, leaving your legacy shim behind. This carries the added benefit of providing a way for us to introduce helpful tooling in the future, such as [custom eslint rules](https://github.com/elastic/kibana/pull/40537), which could be run against that specific directory to ensure your code is ready to migrate. +## Keep Kibana fast +**tl;dr**: Load as much code lazily as possible. +Everyone loves snappy applications with responsive UI and hates spinners. Users deserve the best user experiences regardless of whether they run Kibana locally or in the cloud, regardless of their hardware & environment. +There are 2 main aspects of the perceived speed of an application: loading time and responsiveness to user actions. +New platform loads and bootstraps **all** the plugins whenever a user lands on any page. It means that adding every new application affects overall **loading performance** in the new platform, as plugin code is loaded **eagerly** to initialize the plugin and provide plugin API to dependent plugins. +However, it's usually not necessary that the whole plugin code should be loaded and initialized at once. The plugin could keep on loading code covering API functionality on Kibana bootstrap but load UI related code lazily on-demand, when an application page or management section is mounted. +Always prefer to require UI root components lazily when possible (such as in mount handlers). Even if their size may seem negligible, they are likely using some heavy-weight libraries that will also be removed from the initial plugin bundle, therefore, reducing its size by a significant amount. + +```typescript +import { Plugin, CoreSetup, AppMountParameters } from 'src/core/public'; +export class MyPlugin implements Plugin { + setup(core: CoreSetup, plugins: SetupDeps){ + core.application.register({ + id: 'app', + title: 'My app', + async mount(params: AppMountParameters) { + const { mountApp } = await import('./app/mount_app'); + return mountApp(await core.getStartServices(), params); + }, + }); + plugins.management.sections.getSection('another').registerApp({ + id: 'app', + title: 'My app', + order: 1, + async mount(params) { + const { mountManagementSection } = await import('./app/mount_management_section'); + return mountManagementSection(coreSetup, params); + }, + }) + return { + doSomething(){} + } + } +} +``` + +#### How to understand how big the bundle size of my plugin is? +New platform plugins are distributed as a pre-built with `@kbn/optimizer` package artifacts. It allows us to get rid of the shipping of `optimizer` in the distributable version of Kibana. +Every NP plugin artifact contains all plugin dependencies required to run the plugin, except some stateful dependencies shared across plugin bundles via `@kbn/ui-shared-deps`. +It means that NP plugin artifacts tend to have a bigger size than the legacy platform version. +To understand the current size of your plugin artifact, run `@kbn/optimizer` as +```bash +node scripts/build_kibana_platform_plugins.js --dist --no-examples +``` +and check the output in the `target` sub-folder of your plugin folder +```bash +ls -lh plugins/my_plugin/target/public/ +# output +# an async chunk loaded on demand +... 262K 0.plugin.js +# eagerly loaded chunk +... 50K my_plugin.plugin.js +``` +you might see at least one js bundle - `my_plugin.plugin.js`. This is the only artifact loaded by the platform during bootstrap in the browser. The rule of thumb is to keep its size as small as possible. +Other lazily loaded parts of your plugin present in the same folder as separate chunks under `{number}.plugin.js` names. +If you want to investigate what your plugin bundle consists of you need to run `@kbn/optimizer` with `--profile` flag to get generated [webpack stats file](https://webpack.js.org/api/stats/). +Many OSS tools are allowing you to analyze generated stats file +- [an official tool](http://webpack.github.io/analyse/#modules) from webpack authors +- [webpack-visualizer](https://chrisbateman.github.io/webpack-visualizer/) + ## Frequently asked questions ### Is migrating a plugin an all-or-nothing thing? diff --git a/src/legacy/core_plugins/kibana/public/index.scss b/src/legacy/core_plugins/kibana/public/index.scss index 9b7d0afcd7e39..fbfb0a06fabcf 100644 --- a/src/legacy/core_plugins/kibana/public/index.scss +++ b/src/legacy/core_plugins/kibana/public/index.scss @@ -17,7 +17,7 @@ @import './visualize/index'; // Has to come after visualize because of some // bad cascading in the Editor layout -@import 'src/legacy/ui/public/vis/index'; +@import '../../../../plugins/maps_legacy/public/index'; // Home styles @import '../../../../plugins/home/public/application/index'; diff --git a/src/legacy/core_plugins/region_map/public/__tests__/region_map_visualization.js b/src/legacy/core_plugins/region_map/public/__tests__/region_map_visualization.js index 3880f42d52561..6e1b0b7160941 100644 --- a/src/legacy/core_plugins/region_map/public/__tests__/region_map_visualization.js +++ b/src/legacy/core_plugins/region_map/public/__tests__/region_map_visualization.js @@ -23,12 +23,18 @@ import _ from 'lodash'; import ChoroplethLayer from '../choropleth_layer'; import { ImageComparator } from 'test_utils/image_comparator'; import worldJson from './world.json'; -import EMS_CATALOGUE from '../../../../ui/public/vis/__tests__/map/ems_mocks/sample_manifest.json'; -import EMS_FILES from '../../../../ui/public/vis/__tests__/map/ems_mocks/sample_files.json'; -import EMS_TILES from '../../../../ui/public/vis/__tests__/map/ems_mocks/sample_tiles.json'; -import EMS_STYLE_ROAD_MAP_BRIGHT from '../../../../ui/public/vis/__tests__/map/ems_mocks/sample_style_bright'; -import EMS_STYLE_ROAD_MAP_DESATURATED from '../../../../ui/public/vis/__tests__/map/ems_mocks/sample_style_desaturated'; -import EMS_STYLE_DARK_MAP from '../../../../ui/public/vis/__tests__/map/ems_mocks/sample_style_dark'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import EMS_CATALOGUE from '../../../../../plugins/maps_legacy/public/__tests__/map/ems_mocks/sample_manifest.json'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import EMS_FILES from '../../../../../plugins/maps_legacy/public/__tests__/map/ems_mocks/sample_files.json'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import EMS_TILES from '../../../../../plugins/maps_legacy/public/__tests__/map/ems_mocks/sample_tiles.json'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import EMS_STYLE_ROAD_MAP_BRIGHT from '../../../../../plugins/maps_legacy/public/__tests__/map/ems_mocks/sample_style_bright'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import EMS_STYLE_ROAD_MAP_DESATURATED from '../../../../../plugins/maps_legacy/public/__tests__/map/ems_mocks/sample_style_desaturated'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import EMS_STYLE_DARK_MAP from '../../../../../plugins/maps_legacy/public/__tests__/map/ems_mocks/sample_style_dark'; import initialPng from './initial.png'; import toiso3Png from './toiso3.png'; @@ -44,6 +50,10 @@ import { createRegionMapTypeDefinition } from '../region_map_type'; import { ExprVis } from '../../../../../plugins/visualizations/public/expressions/vis'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { BaseVisType } from '../../../../../plugins/visualizations/public/vis_types/base_vis_type'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { setInjectedVarFunc } from '../../../../../plugins/maps_legacy/public/kibana_services'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { ServiceSettings } from '../../../../../plugins/maps_legacy/public/map/service_settings'; const THRESHOLD = 0.45; const PIXEL_DIFF = 96; @@ -92,7 +102,31 @@ describe('RegionMapsVisualizationTests', function() { let getManifestStub; beforeEach( ngMock.inject((Private, $injector) => { - const serviceSettings = $injector.get('serviceSettings'); + setInjectedVarFunc(injectedVar => { + switch (injectedVar) { + case 'mapConfig': + return { + emsFileApiUrl: '', + emsTileApiUrl: '', + emsLandingPageUrl: '', + }; + case 'tilemapsConfig': + return { + deprecated: { + config: { + options: { + attribution: '123', + }, + }, + }, + }; + case 'version': + return '123'; + default: + return 'not found'; + } + }); + const serviceSettings = new ServiceSettings(); const uiSettings = $injector.get('config'); const regionmapsConfig = { includeElasticMapsService: true, diff --git a/src/legacy/core_plugins/region_map/public/choropleth_layer.js b/src/legacy/core_plugins/region_map/public/choropleth_layer.js index e637a217bfbc3..4ea9cc1f7bfbf 100644 --- a/src/legacy/core_plugins/region_map/public/choropleth_layer.js +++ b/src/legacy/core_plugins/region_map/public/choropleth_layer.js @@ -22,11 +22,9 @@ import L from 'leaflet'; import _ from 'lodash'; import d3 from 'd3'; import { i18n } from '@kbn/i18n'; -import { KibanaMapLayer } from 'ui/vis/map/kibana_map_layer'; import * as topojson from 'topojson-client'; import { toastNotifications } from 'ui/notify'; -import * as colorUtil from 'ui/vis/map/color_util'; - +import { colorUtil, KibanaMapLayer } from '../../../../plugins/maps_legacy/public'; import { truncatedColorMaps } from '../../../../plugins/charts/public'; const EMPTY_STYLE = { diff --git a/src/legacy/core_plugins/region_map/public/components/region_map_options.tsx b/src/legacy/core_plugins/region_map/public/components/region_map_options.tsx index 187b27953830d..31a27c4da7fcf 100644 --- a/src/legacy/core_plugins/region_map/public/components/region_map_options.tsx +++ b/src/legacy/core_plugins/region_map/public/components/region_map_options.tsx @@ -21,9 +21,12 @@ import React, { useCallback, useMemo } from 'react'; import { EuiIcon, EuiLink, EuiPanel, EuiSpacer, EuiText, EuiTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; - -import { FileLayerField, VectorLayer, ServiceSettings } from 'ui/vis/map/service_settings'; import { VisOptionsProps } from 'src/plugins/vis_default_editor/public'; +import { + FileLayerField, + VectorLayer, + IServiceSettings, +} from '../../../../../plugins/maps_legacy/public'; import { NumberInputOption, SelectOption, @@ -43,7 +46,7 @@ const mapFieldForOption = ({ description, name }: FileLayerField) => ({ }); export type RegionMapOptionsProps = { - serviceSettings: ServiceSettings; + serviceSettings: IServiceSettings; } & VisOptionsProps; function RegionMapOptions(props: RegionMapOptionsProps) { diff --git a/src/legacy/core_plugins/region_map/public/legacy.ts b/src/legacy/core_plugins/region_map/public/legacy.ts index 08615946affa2..b0cc767a044e8 100644 --- a/src/legacy/core_plugins/region_map/public/legacy.ts +++ b/src/legacy/core_plugins/region_map/public/legacy.ts @@ -20,21 +20,18 @@ import { PluginInitializerContext } from 'kibana/public'; import { npSetup, npStart } from 'ui/new_platform'; -import { RegionMapPluginSetupDependencies, RegionMapsConfig } from './plugin'; +import { RegionMapPluginSetupDependencies } from './plugin'; import { LegacyDependenciesPlugin } from './shim'; import { plugin } from '.'; -const regionmapsConfig = npSetup.core.injectedMetadata.getInjectedVar( - 'regionmap' -) as RegionMapsConfig; - const plugins: Readonly = { expressions: npSetup.plugins.expressions, visualizations: npSetup.plugins.visualizations, + mapsLegacy: npSetup.plugins.mapsLegacy, // Temporary solution // It will be removed when all dependent services are migrated to the new platform. - __LEGACY: new LegacyDependenciesPlugin(regionmapsConfig), + __LEGACY: new LegacyDependenciesPlugin(), }; const pluginInstance = plugin({} as PluginInitializerContext); diff --git a/src/legacy/core_plugins/region_map/public/plugin.ts b/src/legacy/core_plugins/region_map/public/plugin.ts index cae569f8fd26d..1453c2155e2d6 100644 --- a/src/legacy/core_plugins/region_map/public/plugin.ts +++ b/src/legacy/core_plugins/region_map/public/plugin.ts @@ -32,10 +32,14 @@ import { LegacyDependenciesPlugin, LegacyDependenciesPluginSetup } from './shim' import { createRegionMapFn } from './region_map_fn'; // @ts-ignore import { createRegionMapTypeDefinition } from './region_map_type'; +import { IServiceSettings, MapsLegacyPluginSetup } from '../../../../plugins/maps_legacy/public'; /** @private */ interface RegionMapVisualizationDependencies extends LegacyDependenciesPluginSetup { uiSettings: IUiSettingsClient; + regionmapsConfig: RegionMapsConfig; + serviceSettings: IServiceSettings; + notificationService: any; } /** @internal */ @@ -43,6 +47,7 @@ export interface RegionMapPluginSetupDependencies { expressions: ReturnType; visualizations: VisualizationsSetup; __LEGACY: LegacyDependenciesPlugin; + mapsLegacy: MapsLegacyPluginSetup; } /** @internal */ @@ -61,10 +66,13 @@ export class RegionMapPlugin implements Plugin, void> { public async setup( core: CoreSetup, - { expressions, visualizations, __LEGACY }: RegionMapPluginSetupDependencies + { expressions, visualizations, mapsLegacy, __LEGACY }: RegionMapPluginSetupDependencies ) { const visualizationDependencies: Readonly = { uiSettings: core.uiSettings, + regionmapsConfig: core.injectedMetadata.getInjectedVar('regionmap') as RegionMapsConfig, + serviceSettings: mapsLegacy.serviceSettings, + notificationService: core.notifications.toasts, ...(await __LEGACY.setup()), }; diff --git a/src/legacy/core_plugins/region_map/public/region_map_visualization.js b/src/legacy/core_plugins/region_map/public/region_map_visualization.js index 72f9d66e7d2bf..f08d53ee35c8d 100644 --- a/src/legacy/core_plugins/region_map/public/region_map_visualization.js +++ b/src/legacy/core_plugins/region_map/public/region_map_visualization.js @@ -28,8 +28,16 @@ import { truncatedColorMaps } from '../../../../plugins/charts/public'; // TODO: reference to TILE_MAP plugin should be removed import { BaseMapsVisualizationProvider } from '../../tile_map/public/base_maps_visualization'; -export function createRegionMapVisualization({ serviceSettings, $injector, uiSettings }) { - const BaseMapsVisualization = new BaseMapsVisualizationProvider(serviceSettings); +export function createRegionMapVisualization({ + serviceSettings, + $injector, + uiSettings, + notificationService, +}) { + const BaseMapsVisualization = new BaseMapsVisualizationProvider( + serviceSettings, + notificationService + ); const tooltipFormatter = new TileMapTooltipFormatter($injector); return class RegionMapsVisualization extends BaseMapsVisualization { diff --git a/src/legacy/core_plugins/region_map/public/shim/legacy_dependencies_plugin.ts b/src/legacy/core_plugins/region_map/public/shim/legacy_dependencies_plugin.ts index c47fc40fbacd7..3a7615e83f281 100644 --- a/src/legacy/core_plugins/region_map/public/shim/legacy_dependencies_plugin.ts +++ b/src/legacy/core_plugins/region_map/public/shim/legacy_dependencies_plugin.ts @@ -19,31 +19,20 @@ import chrome from 'ui/chrome'; import { CoreStart, Plugin } from 'kibana/public'; -import 'ui/vis/map/service_settings'; -import { RegionMapsConfig } from '../plugin'; /** @internal */ export interface LegacyDependenciesPluginSetup { $injector: any; serviceSettings: any; - regionmapsConfig: RegionMapsConfig; } export class LegacyDependenciesPlugin implements Plugin, void> { - constructor(private readonly regionmapsConfig: RegionMapsConfig) {} - public async setup() { const $injector = await chrome.dangerouslyGetActiveInjector(); return { $injector, - regionmapsConfig: this.regionmapsConfig, - // Settings for EMSClient. - // EMSClient, which currently lives in the tile_map vis, - // will probably end up being exposed from the future vis_type_maps plugin, - // which would register both the tile_map and the region_map vis plugins. - serviceSettings: $injector.get('serviceSettings'), } as LegacyDependenciesPluginSetup; } diff --git a/src/legacy/core_plugins/region_map/public/types.ts b/src/legacy/core_plugins/region_map/public/types.ts index 2097aebd27ce0..8585bf720e0cf 100644 --- a/src/legacy/core_plugins/region_map/public/types.ts +++ b/src/legacy/core_plugins/region_map/public/types.ts @@ -17,7 +17,7 @@ * under the License. */ -import { VectorLayer, FileLayerField } from 'ui/vis/map/service_settings'; +import { VectorLayer, FileLayerField } from '../../../../plugins/maps_legacy/public'; import { WMSOptions } from '../../tile_map/public/types'; export interface RegionMapVisParams { diff --git a/src/legacy/core_plugins/region_map/public/util.ts b/src/legacy/core_plugins/region_map/public/util.ts index 69a7a1815bc8e..24c721da1f31a 100644 --- a/src/legacy/core_plugins/region_map/public/util.ts +++ b/src/legacy/core_plugins/region_map/public/util.ts @@ -17,7 +17,7 @@ * under the License. */ -import { FileLayer, VectorLayer } from 'ui/vis/map/service_settings'; +import { FileLayer, VectorLayer } from '../../../../plugins/maps_legacy/public'; // TODO: reference to TILE_MAP plugin should be removed import { ORIGIN } from '../../../../legacy/core_plugins/tile_map/common/origin'; diff --git a/src/legacy/core_plugins/tile_map/public/__tests__/coordinate_maps_visualization.js b/src/legacy/core_plugins/tile_map/public/__tests__/coordinate_maps_visualization.js index 2c142b19d9096..3904c43707906 100644 --- a/src/legacy/core_plugins/tile_map/public/__tests__/coordinate_maps_visualization.js +++ b/src/legacy/core_plugins/tile_map/public/__tests__/coordinate_maps_visualization.js @@ -25,12 +25,18 @@ import initial from './initial.png'; import blues from './blues.png'; import shadedGeohashGrid from './shadedGeohashGrid.png'; import heatmapRaw from './heatmap_raw.png'; -import EMS_CATALOGUE from '../../../../ui/public/vis/__tests__/map/ems_mocks/sample_manifest.json'; -import EMS_FILES from '../../../../ui/public/vis/__tests__/map/ems_mocks/sample_files.json'; -import EMS_TILES from '../../../../ui/public/vis/__tests__/map/ems_mocks/sample_tiles.json'; -import EMS_STYLE_ROAD_MAP_BRIGHT from '../../../../ui/public/vis/__tests__/map/ems_mocks/sample_style_bright'; -import EMS_STYLE_ROAD_MAP_DESATURATED from '../../../../ui/public/vis/__tests__/map/ems_mocks/sample_style_desaturated'; -import EMS_STYLE_DARK_MAP from '../../../../ui/public/vis/__tests__/map/ems_mocks/sample_style_dark'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import EMS_CATALOGUE from '../../../../../plugins/maps_legacy/public/__tests__/map/ems_mocks/sample_manifest.json'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import EMS_FILES from '../../../../../plugins/maps_legacy/public/__tests__/map/ems_mocks/sample_files.json'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import EMS_TILES from '../../../../../plugins/maps_legacy/public/__tests__/map/ems_mocks/sample_tiles.json'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import EMS_STYLE_ROAD_MAP_BRIGHT from '../../../../../plugins/maps_legacy/public/__tests__/map/ems_mocks/sample_style_bright'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import EMS_STYLE_ROAD_MAP_DESATURATED from '../../../../../plugins/maps_legacy/public/__tests__/map/ems_mocks/sample_style_desaturated'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import EMS_STYLE_DARK_MAP from '../../../../../plugins/maps_legacy/public/__tests__/map/ems_mocks/sample_style_dark'; import { createTileMapVisualization } from '../tile_map_visualization'; import { createTileMapTypeDefinition } from '../tile_map_type'; @@ -38,6 +44,15 @@ import { createTileMapTypeDefinition } from '../tile_map_type'; import { ExprVis } from '../../../../../plugins/visualizations/public/expressions/vis'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { BaseVisType } from '../../../../../plugins/visualizations/public/vis_types/base_vis_type'; +import { + getPrecision, + getZoomPrecision, + // eslint-disable-next-line @kbn/eslint/no-restricted-paths +} from '../../../../../plugins/maps_legacy/public/map/precision'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { ServiceSettings } from '../../../../../plugins/maps_legacy/public/map/service_settings'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { setInjectedVarFunc } from '../../../../../plugins/maps_legacy/public/kibana_services'; function mockRawData() { const stack = [dummyESResponse]; @@ -75,13 +90,39 @@ describe('CoordinateMapsVisualizationTest', function() { beforeEach(ngMock.module('kibana')); beforeEach( ngMock.inject((Private, $injector) => { - const serviceSettings = $injector.get('serviceSettings'); + setInjectedVarFunc(injectedVar => { + switch (injectedVar) { + case 'mapConfig': + return { + emsFileApiUrl: '', + emsTileApiUrl: '', + emsLandingPageUrl: '', + }; + case 'tilemapsConfig': + return { + deprecated: { + config: { + options: { + attribution: '123', + }, + }, + }, + }; + case 'version': + return '123'; + default: + return 'not found'; + } + }); + const serviceSettings = new ServiceSettings(); const uiSettings = $injector.get('config'); dependencies = { serviceSettings, uiSettings, $injector, + getPrecision, + getZoomPrecision, }; visType = new BaseVisType(createTileMapTypeDefinition(dependencies)); diff --git a/src/legacy/core_plugins/tile_map/public/__tests__/geohash_layer.js b/src/legacy/core_plugins/tile_map/public/__tests__/geohash_layer.js index 857432079e376..fc029d6bccb6e 100644 --- a/src/legacy/core_plugins/tile_map/public/__tests__/geohash_layer.js +++ b/src/legacy/core_plugins/tile_map/public/__tests__/geohash_layer.js @@ -18,13 +18,13 @@ */ import expect from '@kbn/expect'; -import { KibanaMap } from 'ui/vis/map/kibana_map'; import { GeohashLayer } from '../geohash_layer'; // import heatmapPng from './heatmap.png'; import scaledCircleMarkersPng from './scaledCircleMarkers.png'; // import shadedCircleMarkersPng from './shadedCircleMarkers.png'; import { ImageComparator } from 'test_utils/image_comparator'; import GeoHashSampleData from './dummy_es_response.json'; +import { KibanaMap } from '../../../../../plugins/maps_legacy/public'; describe('geohash_layer', function() { let domNode; diff --git a/src/legacy/core_plugins/tile_map/public/base_maps_visualization.js b/src/legacy/core_plugins/tile_map/public/base_maps_visualization.js index d38159c91ef9f..1dac4607280cc 100644 --- a/src/legacy/core_plugins/tile_map/public/base_maps_visualization.js +++ b/src/legacy/core_plugins/tile_map/public/base_maps_visualization.js @@ -19,22 +19,25 @@ import _ from 'lodash'; import { i18n } from '@kbn/i18n'; -import { KibanaMap } from 'ui/vis/map/kibana_map'; +import { KibanaMap } from '../../../../plugins/maps_legacy/public'; import * as Rx from 'rxjs'; import { filter, first } from 'rxjs/operators'; -import 'ui/vis/map/service_settings'; import { toastNotifications } from 'ui/notify'; import chrome from 'ui/chrome'; const WMS_MINZOOM = 0; const WMS_MAXZOOM = 22; //increase this to 22. Better for WMS -export function BaseMapsVisualizationProvider(serviceSettings) { +export function BaseMapsVisualizationProvider(mapServiceSettings, notificationService) { /** * Abstract base class for a visualization consisting of a map with a single baselayer. * @class BaseMapsVisualization * @constructor */ + + const serviceSettings = mapServiceSettings; + const toastService = notificationService; + return class BaseMapsVisualization { constructor(element, vis) { this.vis = vis; @@ -94,8 +97,9 @@ export function BaseMapsVisualizationProvider(serviceSettings) { const centerFromUIState = uiState.get('mapCenter'); options.zoom = !isNaN(zoomFromUiState) ? zoomFromUiState : this.vis.params.mapZoom; options.center = centerFromUIState ? centerFromUIState : this.vis.params.mapCenter; + const services = { toastService }; - this._kibanaMap = new KibanaMap(this._container, options); + this._kibanaMap = new KibanaMap(this._container, options, services); this._kibanaMap.setMinZoom(WMS_MINZOOM); //use a default this._kibanaMap.setMaxZoom(WMS_MAXZOOM); //use a default diff --git a/src/legacy/core_plugins/tile_map/public/components/wms_options.tsx b/src/legacy/core_plugins/tile_map/public/components/wms_options.tsx index b8535e72e8818..e74c260d3b8e5 100644 --- a/src/legacy/core_plugins/tile_map/public/components/wms_options.tsx +++ b/src/legacy/core_plugins/tile_map/public/components/wms_options.tsx @@ -21,8 +21,7 @@ import React, { useMemo } from 'react'; import { EuiPanel, EuiSpacer, EuiTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; - -import { TmsLayer } from 'ui/vis/map/service_settings'; +import { TmsLayer } from '../../../../../plugins/maps_legacy/public'; import { Vis } from '../../../../../plugins/visualizations/public'; import { RegionMapVisParams } from '../../../region_map/public/types'; import { SelectOption, SwitchOption } from '../../../../../plugins/charts/public'; diff --git a/src/legacy/core_plugins/tile_map/public/geohash_layer.js b/src/legacy/core_plugins/tile_map/public/geohash_layer.js index a604e02be7c8c..b9acf1a15208f 100644 --- a/src/legacy/core_plugins/tile_map/public/geohash_layer.js +++ b/src/legacy/core_plugins/tile_map/public/geohash_layer.js @@ -20,8 +20,7 @@ import L from 'leaflet'; import { min, isEqual } from 'lodash'; import { i18n } from '@kbn/i18n'; - -import { KibanaMapLayer } from 'ui/vis/map/kibana_map_layer'; +import { KibanaMapLayer } from '../../../../plugins/maps_legacy/public'; import { HeatmapMarkers } from './markers/heatmap'; import { ScaledCirclesMarkers } from './markers/scaled_circles'; import { ShadedCirclesMarkers } from './markers/shaded_circles'; diff --git a/src/legacy/core_plugins/tile_map/public/legacy.ts b/src/legacy/core_plugins/tile_map/public/legacy.ts index 7b1f916076f61..741e118750f32 100644 --- a/src/legacy/core_plugins/tile_map/public/legacy.ts +++ b/src/legacy/core_plugins/tile_map/public/legacy.ts @@ -27,6 +27,7 @@ import { plugin } from '.'; const plugins: Readonly = { expressions: npSetup.plugins.expressions, visualizations: npSetup.plugins.visualizations, + mapsLegacy: npSetup.plugins.mapsLegacy, // Temporary solution // It will be removed when all dependent services are migrated to the new platform. diff --git a/src/legacy/core_plugins/tile_map/public/markers/scaled_circles.js b/src/legacy/core_plugins/tile_map/public/markers/scaled_circles.js index 88d6db82946c7..f39de6ca7d179 100644 --- a/src/legacy/core_plugins/tile_map/public/markers/scaled_circles.js +++ b/src/legacy/core_plugins/tile_map/public/markers/scaled_circles.js @@ -22,8 +22,7 @@ import _ from 'lodash'; import d3 from 'd3'; import $ from 'jquery'; import { EventEmitter } from 'events'; -import * as colorUtil from 'ui/vis/map/color_util'; - +import { colorUtil } from '../../../../../plugins/maps_legacy/public'; import { truncatedColorMaps } from '../../../../../plugins/charts/public'; export class ScaledCirclesMarkers extends EventEmitter { diff --git a/src/legacy/core_plugins/tile_map/public/plugin.ts b/src/legacy/core_plugins/tile_map/public/plugin.ts index f2addbe3ab872..2b97407b17b38 100644 --- a/src/legacy/core_plugins/tile_map/public/plugin.ts +++ b/src/legacy/core_plugins/tile_map/public/plugin.ts @@ -32,16 +32,22 @@ import { LegacyDependenciesPlugin, LegacyDependenciesPluginSetup } from './shim' import { createTileMapFn } from './tile_map_fn'; // @ts-ignore import { createTileMapTypeDefinition } from './tile_map_type'; +import { IServiceSettings, MapsLegacyPluginSetup } from '../../../../plugins/maps_legacy/public'; /** @private */ interface TileMapVisualizationDependencies extends LegacyDependenciesPluginSetup { + serviceSettings: IServiceSettings; uiSettings: IUiSettingsClient; + getZoomPrecision: any; + getPrecision: any; + notificationService: any; } /** @internal */ export interface TileMapPluginSetupDependencies { expressions: ReturnType; visualizations: VisualizationsSetup; + mapsLegacy: MapsLegacyPluginSetup; __LEGACY: LegacyDependenciesPlugin; } @@ -55,9 +61,14 @@ export class TileMapPlugin implements Plugin, void> { public async setup( core: CoreSetup, - { expressions, visualizations, __LEGACY }: TileMapPluginSetupDependencies + { expressions, visualizations, mapsLegacy, __LEGACY }: TileMapPluginSetupDependencies ) { + const { getZoomPrecision, getPrecision, serviceSettings } = mapsLegacy; const visualizationDependencies: Readonly = { + serviceSettings, + getZoomPrecision, + getPrecision, + notificationService: core.notifications.toasts, uiSettings: core.uiSettings, ...(await __LEGACY.setup()), }; diff --git a/src/legacy/core_plugins/tile_map/public/shim/legacy_dependencies_plugin.ts b/src/legacy/core_plugins/tile_map/public/shim/legacy_dependencies_plugin.ts index 063b12bf0a2db..5296e98b09efe 100644 --- a/src/legacy/core_plugins/tile_map/public/shim/legacy_dependencies_plugin.ts +++ b/src/legacy/core_plugins/tile_map/public/shim/legacy_dependencies_plugin.ts @@ -18,12 +18,12 @@ */ import chrome from 'ui/chrome'; -import 'ui/vis/map/service_settings'; import { CoreStart, Plugin } from 'kibana/public'; +// TODO: Determine why visualizations don't populate without this +import 'angular-sanitize'; /** @internal */ export interface LegacyDependenciesPluginSetup { - serviceSettings: any; $injector: any; } @@ -34,11 +34,6 @@ export class LegacyDependenciesPlugin return { $injector, - // Settings for EMSClient. - // EMSClient, which currently lives in the tile_map vis, - // will probably end up being exposed from the future vis_type_maps plugin, - // which would register both the tile_map and the region_map vis plugins. - serviceSettings: $injector.get('serviceSettings'), } as LegacyDependenciesPluginSetup; } diff --git a/src/legacy/core_plugins/tile_map/public/tile_map_fn.js b/src/legacy/core_plugins/tile_map/public/tile_map_fn.js index 2f54d23590c33..5ad4a2c33db25 100644 --- a/src/legacy/core_plugins/tile_map/public/tile_map_fn.js +++ b/src/legacy/core_plugins/tile_map/public/tile_map_fn.js @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import { convertToGeoJson } from 'ui/vis/map/convert_to_geojson'; +import { convertToGeoJson } from '../../../../plugins/maps_legacy/public'; import { i18n } from '@kbn/i18n'; export const createTileMapFn = () => ({ diff --git a/src/legacy/core_plugins/tile_map/public/tile_map_type.js b/src/legacy/core_plugins/tile_map/public/tile_map_type.js index fe82ad5c7352b..ae3a839b600e9 100644 --- a/src/legacy/core_plugins/tile_map/public/tile_map_type.js +++ b/src/legacy/core_plugins/tile_map/public/tile_map_type.js @@ -19,9 +19,7 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; - -import { convertToGeoJson } from 'ui/vis/map/convert_to_geojson'; - +import { convertToGeoJson } from '../../../../plugins/maps_legacy/public'; import { Schemas } from '../../../../plugins/vis_default_editor/public'; import { createTileMapVisualization } from './tile_map_visualization'; import { TileMapOptions } from './components/tile_map_options'; diff --git a/src/legacy/core_plugins/tile_map/public/tile_map_visualization.js b/src/legacy/core_plugins/tile_map/public/tile_map_visualization.js index 910def8a0c78e..fdce8bc51fe86 100644 --- a/src/legacy/core_plugins/tile_map/public/tile_map_visualization.js +++ b/src/legacy/core_plugins/tile_map/public/tile_map_visualization.js @@ -23,15 +23,19 @@ import { BaseMapsVisualizationProvider } from './base_maps_visualization'; import { TileMapTooltipFormatterProvider } from './editors/_tooltip_formatter'; import { npStart } from 'ui/new_platform'; import { getFormat } from '../../../ui/public/visualize/loader/pipeline_helpers/utilities'; -import { - scaleBounds, - zoomPrecision, - getPrecision, - geoContains, -} from '../../../ui/public/vis/map/decode_geo_hash'; +import { scaleBounds, geoContains } from '../../../../plugins/maps_legacy/public'; -export const createTileMapVisualization = ({ serviceSettings, $injector }) => { - const BaseMapsVisualization = new BaseMapsVisualizationProvider(serviceSettings); +export const createTileMapVisualization = ({ + serviceSettings, + $injector, + getZoomPrecision, + getPrecision, + notificationService, +}) => { + const BaseMapsVisualization = new BaseMapsVisualizationProvider( + serviceSettings, + notificationService + ); const tooltipFormatter = new TileMapTooltipFormatterProvider($injector); return class CoordinateMapsVisualization extends BaseMapsVisualization { @@ -59,6 +63,7 @@ export const createTileMapVisualization = ({ serviceSettings, $injector }) => { updateVarsObject.data.boundingBox = geohashAgg.aggConfigParams.boundingBox; } // todo: autoPrecision should be vis parameter, not aggConfig one + const zoomPrecision = getZoomPrecision(); updateVarsObject.data.precision = geohashAgg.aggConfigParams.autoPrecision ? zoomPrecision[this.vis.getUiState().get('mapZoom')] : getPrecision(geohashAgg.aggConfigParams.precision); diff --git a/src/legacy/core_plugins/tile_map/public/tilemap_fn.test.js b/src/legacy/core_plugins/tile_map/public/tilemap_fn.test.js index 0913d6fc92e8a..6da37f4c5ef86 100644 --- a/src/legacy/core_plugins/tile_map/public/tilemap_fn.test.js +++ b/src/legacy/core_plugins/tile_map/public/tilemap_fn.test.js @@ -22,7 +22,7 @@ import { functionWrapper } from '../../../../plugins/expressions/common/expressi import { createTileMapFn } from './tile_map_fn'; jest.mock('ui/new_platform'); -jest.mock('ui/vis/map/convert_to_geojson', () => ({ +jest.mock('../../../../plugins/maps_legacy/public', () => ({ convertToGeoJson: jest.fn().mockReturnValue({ featureCollection: { type: 'FeatureCollection', @@ -37,7 +37,7 @@ jest.mock('ui/vis/map/convert_to_geojson', () => ({ }), })); -import { convertToGeoJson } from 'ui/vis/map/convert_to_geojson'; +import { convertToGeoJson } from '../../../../plugins/maps_legacy/public'; describe('interpreter/functions#tilemap', () => { const fn = functionWrapper(createTileMapFn()); diff --git a/src/legacy/core_plugins/tile_map/public/types.ts b/src/legacy/core_plugins/tile_map/public/types.ts index 5f1c3f9b03c9e..e1b4c27319123 100644 --- a/src/legacy/core_plugins/tile_map/public/types.ts +++ b/src/legacy/core_plugins/tile_map/public/types.ts @@ -17,7 +17,7 @@ * under the License. */ -import { TmsLayer } from 'ui/vis/map/service_settings'; +import { TmsLayer } from '../../../../plugins/maps_legacy/public'; import { MapTypes } from './map_types'; export interface WMSOptions { diff --git a/src/legacy/core_plugins/timelion/public/shim/timelion_legacy_module.ts b/src/legacy/core_plugins/timelion/public/shim/timelion_legacy_module.ts index 9de8477e3978c..8fadf223e1807 100644 --- a/src/legacy/core_plugins/timelion/public/shim/timelion_legacy_module.ts +++ b/src/legacy/core_plugins/timelion/public/shim/timelion_legacy_module.ts @@ -21,7 +21,6 @@ import 'ngreact'; import 'brace/mode/hjson'; import 'brace/ext/searchbox'; import 'ui/accessibility/kbn_ui_ace_keyboard_mode'; -import 'ui/vis/map/service_settings'; import { once } from 'lodash'; // @ts-ignore diff --git a/src/legacy/core_plugins/vis_type_vega/public/__tests__/vega_visualization.js b/src/legacy/core_plugins/vis_type_vega/public/__tests__/vega_visualization.js index c7fbc0815b07c..6412d8a569b2a 100644 --- a/src/legacy/core_plugins/vis_type_vega/public/__tests__/vega_visualization.js +++ b/src/legacy/core_plugins/vis_type_vega/public/__tests__/vega_visualization.js @@ -49,6 +49,10 @@ import { BaseVisType } from '../../../../../plugins/visualizations/public/vis_ty // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { ExprVis } from '../../../../../plugins/visualizations/public/expressions/vis'; import { setInjectedVars } from '../services'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { setInjectedVarFunc } from '../../../../../plugins/maps_legacy/public/kibana_services'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { ServiceSettings } from '../../../../../plugins/maps_legacy/public/map/service_settings'; const THRESHOLD = 0.1; const PIXEL_DIFF = 30; @@ -69,9 +73,34 @@ describe('VegaVisualizations', () => { beforeEach(ngMock.module('kibana')); beforeEach( - ngMock.inject($injector => { + ngMock.inject(() => { + setInjectedVarFunc(injectedVar => { + switch (injectedVar) { + case 'mapConfig': + return { + emsFileApiUrl: '', + emsTileApiUrl: '', + emsLandingPageUrl: '', + }; + case 'tilemapsConfig': + return { + deprecated: { + config: { + options: { + attribution: '123', + }, + }, + }, + }; + case 'version': + return '123'; + default: + return 'not found'; + } + }); + const serviceSettings = new ServiceSettings(); vegaVisualizationDependencies = { - serviceSettings: $injector.get('serviceSettings'), + serviceSettings, core: { uiSettings: npStart.core.uiSettings, }, diff --git a/src/legacy/core_plugins/vis_type_vega/public/legacy.ts b/src/legacy/core_plugins/vis_type_vega/public/legacy.ts index b2c73894d978d..450af4a6f253e 100644 --- a/src/legacy/core_plugins/vis_type_vega/public/legacy.ts +++ b/src/legacy/core_plugins/vis_type_vega/public/legacy.ts @@ -20,16 +20,12 @@ import { PluginInitializerContext } from 'kibana/public'; import { npSetup, npStart } from 'ui/new_platform'; import { VegaPluginSetupDependencies, VegaPluginStartDependencies } from './plugin'; -import { LegacyDependenciesPlugin } from './shim'; import { plugin } from '.'; const setupPlugins: Readonly = { ...npSetup.plugins, visualizations: npSetup.plugins.visualizations, - - // Temporary solution - // It will be removed when all dependent services are migrated to the new platform. - __LEGACY: new LegacyDependenciesPlugin(), + mapsLegacy: npSetup.plugins.mapsLegacy, }; const startPlugins: Readonly = { diff --git a/src/legacy/core_plugins/vis_type_vega/public/plugin.ts b/src/legacy/core_plugins/vis_type_vega/public/plugin.ts index 38b92a40cd99a..9fa77d28fbbfa 100644 --- a/src/legacy/core_plugins/vis_type_vega/public/plugin.ts +++ b/src/legacy/core_plugins/vis_type_vega/public/plugin.ts @@ -17,7 +17,6 @@ * under the License. */ import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from '../../../../core/public'; -import { LegacyDependenciesPlugin, LegacyDependenciesPluginSetup } from './shim'; import { Plugin as ExpressionsPublicPlugin } from '../../../../plugins/expressions/public'; import { Plugin as DataPublicPlugin } from '../../../../plugins/data/public'; import { VisualizationsSetup } from '../../../../plugins/visualizations/public'; @@ -32,13 +31,15 @@ import { import { createVegaFn } from './vega_fn'; import { createVegaTypeDefinition } from './vega_type'; import { VisTypeVegaSetup } from '../../../../plugins/vis_type_vega/public'; +import { IServiceSettings } from '../../../../plugins/maps_legacy/public'; /** @internal */ -export interface VegaVisualizationDependencies extends LegacyDependenciesPluginSetup { +export interface VegaVisualizationDependencies { core: CoreSetup; plugins: { data: ReturnType; }; + serviceSettings: IServiceSettings; } /** @internal */ @@ -47,7 +48,7 @@ export interface VegaPluginSetupDependencies { visualizations: VisualizationsSetup; data: ReturnType; visTypeVega: VisTypeVegaSetup; - __LEGACY: LegacyDependenciesPlugin; + mapsLegacy: any; } /** @internal */ @@ -65,7 +66,7 @@ export class VegaPlugin implements Plugin, void> { public async setup( core: CoreSetup, - { data, expressions, visualizations, visTypeVega, __LEGACY }: VegaPluginSetupDependencies + { data, expressions, visualizations, visTypeVega, mapsLegacy }: VegaPluginSetupDependencies ) { setInjectedVars({ enableExternalUrls: visTypeVega.config.enableExternalUrls, @@ -79,7 +80,7 @@ export class VegaPlugin implements Plugin, void> { plugins: { data, }, - ...(await __LEGACY.setup()), + serviceSettings: mapsLegacy.serviceSettings, }; expressions.registerFunction(() => createVegaFn(visualizationDependencies)); diff --git a/src/legacy/core_plugins/vis_type_vega/public/shim/legacy_dependencies_plugin.ts b/src/legacy/core_plugins/vis_type_vega/public/shim/legacy_dependencies_plugin.ts deleted file mode 100644 index 8925f76cffa43..0000000000000 --- a/src/legacy/core_plugins/vis_type_vega/public/shim/legacy_dependencies_plugin.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -// TODO remove this file as soon as serviceSettings is exposed in the new platform -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import chrome from 'ui/chrome'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import 'ui/vis/map/service_settings'; -import { CoreStart, Plugin } from 'kibana/public'; - -/** @internal */ -export interface LegacyDependenciesPluginSetup { - serviceSettings: any; -} - -export class LegacyDependenciesPlugin - implements Plugin, void> { - public async setup() { - const $injector = await chrome.dangerouslyGetActiveInjector(); - - return { - // Settings for EMSClient. - // EMSClient, which currently lives in the tile_map vis, - // will probably end up being exposed from the future vis_type_maps plugin, - // which would register both the tile_map and the region_map vis plugins. - serviceSettings: $injector.get('serviceSettings'), - } as LegacyDependenciesPluginSetup; - } - - public start(core: CoreStart) { - // nothing to do here yet - } -} diff --git a/src/legacy/core_plugins/vis_type_vega/public/vega_view/vega_map_layer.js b/src/legacy/core_plugins/vis_type_vega/public/vega_view/vega_map_layer.js index 38540e9f218fb..d43eb9c3351ea 100644 --- a/src/legacy/core_plugins/vis_type_vega/public/vega_view/vega_map_layer.js +++ b/src/legacy/core_plugins/vis_type_vega/public/vega_view/vega_map_layer.js @@ -19,7 +19,7 @@ import L from 'leaflet'; import 'leaflet-vega'; -import { KibanaMapLayer } from '../legacy_imports'; +import { KibanaMapLayer } from '../../../../../plugins/maps_legacy/public'; export class VegaMapLayer extends KibanaMapLayer { constructor(spec, options) { diff --git a/src/legacy/core_plugins/vis_type_vega/public/vega_view/vega_map_view.js b/src/legacy/core_plugins/vis_type_vega/public/vega_view/vega_map_view.js index 487c90d01ada3..03aef29dc5739 100644 --- a/src/legacy/core_plugins/vis_type_vega/public/vega_view/vega_map_view.js +++ b/src/legacy/core_plugins/vis_type_vega/public/vega_view/vega_map_view.js @@ -21,10 +21,15 @@ import * as vega from 'vega-lib'; import { i18n } from '@kbn/i18n'; import { VegaBaseView } from './vega_base_view'; import { VegaMapLayer } from './vega_map_layer'; -import { KibanaMap } from '../legacy_imports'; +import { KibanaMap } from '../../../../../plugins/maps_legacy/public'; import { getEmsTileLayerId, getUISettings } from '../services'; export class VegaMapView extends VegaBaseView { + constructor(opts, services) { + super(opts); + this.services = services; + } + async _initViewCustomizations() { const mapConfig = this._parser.mapConfig; let baseMapOpts; @@ -102,14 +107,18 @@ export class VegaMapView extends VegaBaseView { // maxBounds = L.latLngBounds(L.latLng(b[1], b[0]), L.latLng(b[3], b[2])); // } - this._kibanaMap = new KibanaMap(this._$container.get(0), { - zoom, - minZoom, - maxZoom, - center: [mapConfig.latitude, mapConfig.longitude], - zoomControl: mapConfig.zoomControl, - scrollWheelZoom: mapConfig.scrollWheelZoom, - }); + this._kibanaMap = new KibanaMap( + this._$container.get(0), + { + zoom, + minZoom, + maxZoom, + center: [mapConfig.latitude, mapConfig.longitude], + zoomControl: mapConfig.zoomControl, + scrollWheelZoom: mapConfig.scrollWheelZoom, + }, + this.services + ); if (baseMapOpts) { this._kibanaMap.setBaseLayer({ diff --git a/src/legacy/core_plugins/vis_type_vega/public/vega_visualization.js b/src/legacy/core_plugins/vis_type_vega/public/vega_visualization.js index 96835ef3b10bc..a6e911de7f0cb 100644 --- a/src/legacy/core_plugins/vis_type_vega/public/vega_visualization.js +++ b/src/legacy/core_plugins/vis_type_vega/public/vega_visualization.js @@ -116,7 +116,8 @@ export const createVegaVisualization = ({ serviceSettings }) => }; if (vegaParser.useMap) { - this._vegaView = new VegaMapView(vegaViewParams); + const services = { toastService: getNotifications().toasts }; + this._vegaView = new VegaMapView(vegaViewParams, services); } else { this._vegaView = new VegaView(vegaViewParams); } diff --git a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js index 0779d6472671c..33a7fdad065b4 100644 --- a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js +++ b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js @@ -309,6 +309,12 @@ export const npSetup = { registerAlias: sinon.fake(), hideTypes: sinon.fake(), }, + + mapsLegacy: { + serviceSettings: sinon.fake(), + getPrecision: sinon.fake(), + getZoomPrecision: sinon.fake(), + }, }, }; diff --git a/src/legacy/ui/public/new_platform/new_platform.ts b/src/legacy/ui/public/new_platform/new_platform.ts index cdd7e1a994912..21b80e827e4c2 100644 --- a/src/legacy/ui/public/new_platform/new_platform.ts +++ b/src/legacy/ui/public/new_platform/new_platform.ts @@ -68,6 +68,7 @@ import { VisualizationsSetup, VisualizationsStart, } from '../../../../plugins/visualizations/public'; +import { MapsLegacyPluginSetup } from '../../../../plugins/maps_legacy/public'; export interface PluginsSetup { bfetch: BfetchPublicSetup; @@ -90,6 +91,7 @@ export interface PluginsSetup { visualizations: VisualizationsSetup; telemetry?: TelemetryPluginSetup; savedObjectsManagement: SavedObjectsManagementPluginSetup; + mapsLegacy: MapsLegacyPluginSetup; indexPatternManagement: IndexPatternManagementSetup; } diff --git a/src/legacy/ui/public/vis/map/service_settings.js b/src/legacy/ui/public/vis/map/service_settings.js deleted file mode 100644 index a014aeb182c67..0000000000000 --- a/src/legacy/ui/public/vis/map/service_settings.js +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { uiModules } from '../../modules'; -import _ from 'lodash'; -import MarkdownIt from 'markdown-it'; -import { ORIGIN } from '../../../../core_plugins/tile_map/common/origin'; -import { EMSClient } from '@elastic/ems-client'; -import { i18n } from '@kbn/i18n'; -import 'angular-sanitize'; - -const markdownIt = new MarkdownIt({ - html: false, - linkify: true, -}); - -const TMS_IN_YML_ID = 'TMS in config/kibana.yml'; - -uiModules - .get('kibana', ['ngSanitize']) - .service('serviceSettings', function($sanitize, mapConfig, tilemapsConfig, kbnVersion) { - const attributionFromConfig = $sanitize( - markdownIt.render(tilemapsConfig.deprecated.config.options.attribution || '') - ); - const tmsOptionsFromConfig = _.assign({}, tilemapsConfig.deprecated.config.options, { - attribution: attributionFromConfig, - }); - - class ServiceSettings { - constructor() { - this._showZoomMessage = true; - this._emsClient = new EMSClient({ - language: i18n.getLocale(), - appVersion: kbnVersion, - appName: 'kibana', - fileApiUrl: mapConfig.emsFileApiUrl, - tileApiUrl: mapConfig.emsTileApiUrl, - htmlSanitizer: $sanitize, - landingPageUrl: mapConfig.emsLandingPageUrl, - // Wrap to avoid errors passing window fetch - fetchFunction: function(...args) { - return fetch(...args); - }, - }); - } - - shouldShowZoomMessage({ origin }) { - return origin === ORIGIN.EMS && this._showZoomMessage; - } - - disableZoomMessage() { - this._showZoomMessage = false; - } - - __debugStubManifestCalls(manifestRetrieval) { - const oldGetManifest = this._emsClient.getManifest; - this._emsClient.getManifest = manifestRetrieval; - return { - removeStub: () => { - delete this._emsClient.getManifest; - //not strictly necessary since this is prototype method - if (this._emsClient.getManifest !== oldGetManifest) { - this._emsClient.getManifest = oldGetManifest; - } - }, - }; - } - - async getFileLayers() { - if (!mapConfig.includeElasticMapsService) { - return []; - } - - const fileLayers = await this._emsClient.getFileLayers(); - return fileLayers.map(fileLayer => { - //backfill to older settings - const format = fileLayer.getDefaultFormatType(); - const meta = fileLayer.getDefaultFormatMeta(); - - return { - name: fileLayer.getDisplayName(), - origin: fileLayer.getOrigin(), - id: fileLayer.getId(), - created_at: fileLayer.getCreatedAt(), - attribution: fileLayer.getHTMLAttribution(), - fields: fileLayer.getFieldsInLanguage(), - format: format, //legacy: format and meta are split up - meta: meta, //legacy, format and meta are split up - }; - }); - } - - /** - * Returns all the services published by EMS (if configures) - * It also includes the service configured in tilemap (override) - */ - async getTMSServices() { - let allServices = []; - if (tilemapsConfig.deprecated.isOverridden) { - //use tilemap.* settings from yml - const tmsService = _.cloneDeep(tmsOptionsFromConfig); - tmsService.id = TMS_IN_YML_ID; - tmsService.origin = ORIGIN.KIBANA_YML; - allServices.push(tmsService); - } - - if (mapConfig.includeElasticMapsService) { - const servicesFromManifest = await this._emsClient.getTMSServices(); - const strippedServiceFromManifest = await Promise.all( - servicesFromManifest - .filter(tmsService => tmsService.getId() === mapConfig.emsTileLayerId.bright) - .map(async tmsService => { - //shim for compatibility - const shim = { - origin: tmsService.getOrigin(), - id: tmsService.getId(), - minZoom: await tmsService.getMinZoom(), - maxZoom: await tmsService.getMaxZoom(), - attribution: tmsService.getHTMLAttribution(), - }; - return shim; - }) - ); - allServices = allServices.concat(strippedServiceFromManifest); - } - - return allServices; - } - - /** - * Add optional query-parameters to all requests - * - * @param additionalQueryParams - */ - addQueryParams(additionalQueryParams) { - this._emsClient.addQueryParams(additionalQueryParams); - } - - async getEMSHotLink(fileLayerConfig) { - const fileLayers = await this._emsClient.getFileLayers(); - const layer = fileLayers.find(fileLayer => { - const hasIdByName = fileLayer.hasId(fileLayerConfig.name); //legacy - const hasIdById = fileLayer.hasId(fileLayerConfig.id); - return hasIdByName || hasIdById; - }); - return layer ? layer.getEMSHotLink() : null; - } - - async _getAttributesForEMSTMSLayer(isDesaturated, isDarkMode) { - const tmsServices = await this._emsClient.getTMSServices(); - const emsTileLayerId = mapConfig.emsTileLayerId; - let serviceId; - if (isDarkMode) { - serviceId = emsTileLayerId.dark; - } else { - if (isDesaturated) { - serviceId = emsTileLayerId.desaturated; - } else { - serviceId = emsTileLayerId.bright; - } - } - const tmsService = tmsServices.find(service => { - return service.getId() === serviceId; - }); - return { - url: await tmsService.getUrlTemplate(), - minZoom: await tmsService.getMinZoom(), - maxZoom: await tmsService.getMaxZoom(), - attribution: await tmsService.getHTMLAttribution(), - origin: ORIGIN.EMS, - }; - } - - async getAttributesForTMSLayer(tmsServiceConfig, isDesaturated, isDarkMode) { - if (tmsServiceConfig.origin === ORIGIN.EMS) { - return this._getAttributesForEMSTMSLayer(isDesaturated, isDarkMode); - } else if (tmsServiceConfig.origin === ORIGIN.KIBANA_YML) { - const config = tilemapsConfig.deprecated.config; - const attrs = _.pick(config, ['url', 'minzoom', 'maxzoom', 'attribution']); - return { ...attrs, ...{ origin: ORIGIN.KIBANA_YML } }; - } else { - //this is an older config. need to resolve this dynamically. - if (tmsServiceConfig.id === TMS_IN_YML_ID) { - const config = tilemapsConfig.deprecated.config; - const attrs = _.pick(config, ['url', 'minzoom', 'maxzoom', 'attribution']); - return { ...attrs, ...{ origin: ORIGIN.KIBANA_YML } }; - } else { - //assume ems - return this._getAttributesForEMSTMSLayer(isDesaturated, isDarkMode); - } - } - } - - async _getFileUrlFromEMS(fileLayerConfig) { - const fileLayers = await this._emsClient.getFileLayers(); - const layer = fileLayers.find(fileLayer => { - const hasIdByName = fileLayer.hasId(fileLayerConfig.name); //legacy - const hasIdById = fileLayer.hasId(fileLayerConfig.id); - return hasIdByName || hasIdById; - }); - - if (layer) { - return layer.getDefaultFormatUrl(); - } else { - throw new Error(`File ${fileLayerConfig.name} not recognized`); - } - } - - async getUrlForRegionLayer(fileLayerConfig) { - let url; - if (fileLayerConfig.origin === ORIGIN.EMS) { - url = this._getFileUrlFromEMS(fileLayerConfig); - } else if ( - fileLayerConfig.layerId && - fileLayerConfig.layerId.startsWith(`${ORIGIN.EMS}.`) - ) { - //fallback for older saved objects - url = this._getFileUrlFromEMS(fileLayerConfig); - } else if ( - fileLayerConfig.layerId && - fileLayerConfig.layerId.startsWith(`${ORIGIN.KIBANA_YML}.`) - ) { - //fallback for older saved objects - url = fileLayerConfig.url; - } else { - //generic fallback - url = fileLayerConfig.url; - } - return url; - } - - async getJsonForRegionLayer(fileLayerConfig) { - const url = await this.getUrlForRegionLayer(fileLayerConfig); - const response = await fetch(url); - return await response.json(); - } - } - - return new ServiceSettings(); - }); diff --git a/src/plugins/console/public/application/models/sense_editor/__tests__/editor_input1.txt b/src/plugins/console/public/application/models/sense_editor/__tests__/editor_input1.txt index f9a4bcb85034d..398a0fdeab61f 100644 --- a/src/plugins/console/public/application/models/sense_editor/__tests__/editor_input1.txt +++ b/src/plugins/console/public/application/models/sense_editor/__tests__/editor_input1.txt @@ -25,3 +25,9 @@ GET index_1/type1/1/_source?_source_include=f DELETE index_2 + +POST /_sql?format=txt +{ + "query": "SELECT prenom FROM claude_index WHERE prenom = 'claude' ", + "fetch_size": 1 +} diff --git a/src/plugins/console/public/application/models/sense_editor/__tests__/sense_editor.test.js b/src/plugins/console/public/application/models/sense_editor/__tests__/sense_editor.test.js index 6afc03df13b4c..34b4cad7fbb6b 100644 --- a/src/plugins/console/public/application/models/sense_editor/__tests__/sense_editor.test.js +++ b/src/plugins/console/public/application/models/sense_editor/__tests__/sense_editor.test.js @@ -470,6 +470,18 @@ curl -XGET "http://localhost:9200/_stats?level=shards" curl -XPUT "http://localhost:9200/index_1/type1/1" -H 'Content-Type: application/json' -d' { "f": 1 +}'`.trim() + ); + + multiReqCopyAsCurlTest( + 'with single quotes', + editorInput1, + { start: { lineNumber: 29 }, end: { lineNumber: 33 } }, + ` +curl -XPOST "http://localhost:9200/_sql?format=txt" -H 'Content-Type: application/json' -d' +{ + "query": "SELECT prenom FROM claude_index WHERE prenom = '\\''claude'\\'' ", + "fetch_size": 1 }'`.trim() ); }); diff --git a/src/plugins/console/public/application/models/sense_editor/sense_editor.ts b/src/plugins/console/public/application/models/sense_editor/sense_editor.ts index 9bcd3a6872196..d326543bbe00b 100644 --- a/src/plugins/console/public/application/models/sense_editor/sense_editor.ts +++ b/src/plugins/console/public/application/models/sense_editor/sense_editor.ts @@ -484,8 +484,9 @@ export class SenseEditor { if (esData && esData.length) { ret += " -H 'Content-Type: application/json' -d'\n"; const dataAsString = collapseLiteralStrings(esData.join('\n')); - // since Sense doesn't allow single quote json string any single qoute is within a string. - ret += dataAsString.replace(/'/g, '\\"'); + + // We escape single quoted strings that that are wrapped in single quoted strings + ret += dataAsString.replace(/'/g, "'\\''"); if (esData.length > 1) { ret += '\n'; } // end with a new line diff --git a/src/plugins/maps_legacy/kibana.json b/src/plugins/maps_legacy/kibana.json new file mode 100644 index 0000000000000..d66be2b156bb9 --- /dev/null +++ b/src/plugins/maps_legacy/kibana.json @@ -0,0 +1,6 @@ +{ + "id": "mapsLegacy", + "version": "8.0.0", + "kibanaVersion": "kibana", + "ui": true +} diff --git a/src/legacy/ui/public/vis/__tests__/map/ems_mocks/sample_files.json b/src/plugins/maps_legacy/public/__tests__/map/ems_mocks/sample_files.json similarity index 100% rename from src/legacy/ui/public/vis/__tests__/map/ems_mocks/sample_files.json rename to src/plugins/maps_legacy/public/__tests__/map/ems_mocks/sample_files.json diff --git a/src/legacy/ui/public/vis/__tests__/map/ems_mocks/sample_manifest.json b/src/plugins/maps_legacy/public/__tests__/map/ems_mocks/sample_manifest.json similarity index 100% rename from src/legacy/ui/public/vis/__tests__/map/ems_mocks/sample_manifest.json rename to src/plugins/maps_legacy/public/__tests__/map/ems_mocks/sample_manifest.json diff --git a/src/legacy/ui/public/vis/__tests__/map/ems_mocks/sample_style_bright.json b/src/plugins/maps_legacy/public/__tests__/map/ems_mocks/sample_style_bright.json similarity index 100% rename from src/legacy/ui/public/vis/__tests__/map/ems_mocks/sample_style_bright.json rename to src/plugins/maps_legacy/public/__tests__/map/ems_mocks/sample_style_bright.json diff --git a/src/legacy/ui/public/vis/__tests__/map/ems_mocks/sample_style_bright_vector.json b/src/plugins/maps_legacy/public/__tests__/map/ems_mocks/sample_style_bright_vector.json similarity index 100% rename from src/legacy/ui/public/vis/__tests__/map/ems_mocks/sample_style_bright_vector.json rename to src/plugins/maps_legacy/public/__tests__/map/ems_mocks/sample_style_bright_vector.json diff --git a/src/legacy/ui/public/vis/__tests__/map/ems_mocks/sample_style_bright_vector_source.json b/src/plugins/maps_legacy/public/__tests__/map/ems_mocks/sample_style_bright_vector_source.json similarity index 100% rename from src/legacy/ui/public/vis/__tests__/map/ems_mocks/sample_style_bright_vector_source.json rename to src/plugins/maps_legacy/public/__tests__/map/ems_mocks/sample_style_bright_vector_source.json diff --git a/src/legacy/ui/public/vis/__tests__/map/ems_mocks/sample_style_dark.json b/src/plugins/maps_legacy/public/__tests__/map/ems_mocks/sample_style_dark.json similarity index 100% rename from src/legacy/ui/public/vis/__tests__/map/ems_mocks/sample_style_dark.json rename to src/plugins/maps_legacy/public/__tests__/map/ems_mocks/sample_style_dark.json diff --git a/src/legacy/ui/public/vis/__tests__/map/ems_mocks/sample_style_desaturated.json b/src/plugins/maps_legacy/public/__tests__/map/ems_mocks/sample_style_desaturated.json similarity index 100% rename from src/legacy/ui/public/vis/__tests__/map/ems_mocks/sample_style_desaturated.json rename to src/plugins/maps_legacy/public/__tests__/map/ems_mocks/sample_style_desaturated.json diff --git a/src/legacy/ui/public/vis/__tests__/map/ems_mocks/sample_tiles.json b/src/plugins/maps_legacy/public/__tests__/map/ems_mocks/sample_tiles.json similarity index 100% rename from src/legacy/ui/public/vis/__tests__/map/ems_mocks/sample_tiles.json rename to src/plugins/maps_legacy/public/__tests__/map/ems_mocks/sample_tiles.json diff --git a/src/legacy/ui/public/vis/__tests__/map/kibana_map.js b/src/plugins/maps_legacy/public/__tests__/map/kibana_map.js similarity index 100% rename from src/legacy/ui/public/vis/__tests__/map/kibana_map.js rename to src/plugins/maps_legacy/public/__tests__/map/kibana_map.js diff --git a/src/legacy/ui/public/vis/__tests__/map/service_settings.js b/src/plugins/maps_legacy/public/__tests__/map/service_settings.js similarity index 99% rename from src/legacy/ui/public/vis/__tests__/map/service_settings.js rename to src/plugins/maps_legacy/public/__tests__/map/service_settings.js index 61925760457c6..a9272ea396639 100644 --- a/src/legacy/ui/public/vis/__tests__/map/service_settings.js +++ b/src/plugins/maps_legacy/public/__tests__/map/service_settings.js @@ -26,7 +26,7 @@ import EMS_TILES from './ems_mocks/sample_tiles.json'; import EMS_STYLE_ROAD_MAP_BRIGHT from './ems_mocks/sample_style_bright'; import EMS_STYLE_ROAD_MAP_DESATURATED from './ems_mocks/sample_style_desaturated'; import EMS_STYLE_DARK_MAP from './ems_mocks/sample_style_dark'; -import { ORIGIN } from '../../../../../core_plugins/tile_map/common/origin'; +import { ORIGIN } from '../../common/origin'; describe('service_settings (FKA tilemaptest)', function() { let serviceSettings; diff --git a/src/legacy/ui/public/vis/_index.scss b/src/plugins/maps_legacy/public/_index.scss similarity index 100% rename from src/legacy/ui/public/vis/_index.scss rename to src/plugins/maps_legacy/public/_index.scss diff --git a/src/legacy/core_plugins/vis_type_vega/public/shim/index.ts b/src/plugins/maps_legacy/public/common/origin.ts similarity index 90% rename from src/legacy/core_plugins/vis_type_vega/public/shim/index.ts rename to src/plugins/maps_legacy/public/common/origin.ts index cfc7b62ff4f86..fdf74cae4ba68 100644 --- a/src/legacy/core_plugins/vis_type_vega/public/shim/index.ts +++ b/src/plugins/maps_legacy/public/common/origin.ts @@ -17,4 +17,7 @@ * under the License. */ -export * from './legacy_dependencies_plugin'; +export const ORIGIN = { + EMS: 'elastic_maps_service', + KIBANA_YML: 'self_hosted', +}; diff --git a/src/plugins/maps_legacy/public/index.ts b/src/plugins/maps_legacy/public/index.ts new file mode 100644 index 0000000000000..861f67006ad83 --- /dev/null +++ b/src/plugins/maps_legacy/public/index.ts @@ -0,0 +1,61 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { MapsLegacyPlugin } from './plugin'; +// @ts-ignore +import * as colorUtil from './map/color_util'; +// @ts-ignore +import { KibanaMap } from './map/kibana_map'; +// @ts-ignore +import { KibanaMapLayer } from './map/kibana_map_layer'; +// @ts-ignore +import { convertToGeoJson } from './map/convert_to_geojson'; +// @ts-ignore +import { scaleBounds, getPrecision, geoContains } from './map/decode_geo_hash'; +// @ts-ignore +import { + VectorLayer, + FileLayerField, + FileLayer, + TmsLayer, + IServiceSettings, +} from './map/service_settings'; + +export function plugin() { + return new MapsLegacyPlugin(); +} + +/** @public */ +export { + scaleBounds, + getPrecision, + geoContains, + colorUtil, + convertToGeoJson, + IServiceSettings, + KibanaMap, + KibanaMapLayer, + VectorLayer, + FileLayerField, + FileLayer, + TmsLayer, +}; + +export type MapsLegacyPluginSetup = ReturnType; +export type MapsLegacyPluginStart = ReturnType; diff --git a/src/legacy/core_plugins/vis_type_vega/public/legacy_imports.ts b/src/plugins/maps_legacy/public/kibana_services.js similarity index 64% rename from src/legacy/core_plugins/vis_type_vega/public/legacy_imports.ts rename to src/plugins/maps_legacy/public/kibana_services.js index b868321d6310f..815c6f9e5651f 100644 --- a/src/legacy/core_plugins/vis_type_vega/public/legacy_imports.ts +++ b/src/plugins/maps_legacy/public/kibana_services.js @@ -17,7 +17,14 @@ * under the License. */ -// @ts-ignore -export { KibanaMapLayer } from 'ui/vis/map/kibana_map_layer'; -// @ts-ignore -export { KibanaMap } from 'ui/vis/map/kibana_map'; +let toast; +export const setToasts = notificationToast => (toast = notificationToast); +export const getToasts = () => toast; + +let uiSettings; +export const setUiSettings = coreUiSettings => (uiSettings = coreUiSettings); +export const getUiSettings = () => uiSettings; + +let getInjectedVar; +export const setInjectedVarFunc = getInjectedVarFunc => (getInjectedVar = getInjectedVarFunc); +export const getInjectedVarFunc = () => getInjectedVar; diff --git a/src/legacy/ui/public/vis/map/_index.scss b/src/plugins/maps_legacy/public/map/_index.scss similarity index 100% rename from src/legacy/ui/public/vis/map/_index.scss rename to src/plugins/maps_legacy/public/map/_index.scss diff --git a/src/legacy/ui/public/vis/map/_leaflet_overrides.scss b/src/plugins/maps_legacy/public/map/_leaflet_overrides.scss similarity index 100% rename from src/legacy/ui/public/vis/map/_leaflet_overrides.scss rename to src/plugins/maps_legacy/public/map/_leaflet_overrides.scss diff --git a/src/legacy/ui/public/vis/map/_legend.scss b/src/plugins/maps_legacy/public/map/_legend.scss similarity index 100% rename from src/legacy/ui/public/vis/map/_legend.scss rename to src/plugins/maps_legacy/public/map/_legend.scss diff --git a/src/legacy/ui/public/vis/map/color_util.js b/src/plugins/maps_legacy/public/map/color_util.js similarity index 100% rename from src/legacy/ui/public/vis/map/color_util.js rename to src/plugins/maps_legacy/public/map/color_util.js diff --git a/src/legacy/ui/public/vis/map/convert_to_geojson.js b/src/plugins/maps_legacy/public/map/convert_to_geojson.js similarity index 100% rename from src/legacy/ui/public/vis/map/convert_to_geojson.js rename to src/plugins/maps_legacy/public/map/convert_to_geojson.js diff --git a/src/legacy/ui/public/vis/map/decode_geo_hash.test.ts b/src/plugins/maps_legacy/public/map/decode_geo_hash.test.ts similarity index 100% rename from src/legacy/ui/public/vis/map/decode_geo_hash.test.ts rename to src/plugins/maps_legacy/public/map/decode_geo_hash.test.ts diff --git a/src/legacy/ui/public/vis/map/decode_geo_hash.ts b/src/plugins/maps_legacy/public/map/decode_geo_hash.ts similarity index 79% rename from src/legacy/ui/public/vis/map/decode_geo_hash.ts rename to src/plugins/maps_legacy/public/map/decode_geo_hash.ts index 3f8430b8628d7..8c39ada03a46b 100644 --- a/src/legacy/ui/public/vis/map/decode_geo_hash.ts +++ b/src/plugins/maps_legacy/public/map/decode_geo_hash.ts @@ -17,11 +17,8 @@ * under the License. */ -import chrome from 'ui/chrome'; import _ from 'lodash'; -const config = chrome.getUiSettingsClient(); - interface DecodedGeoHash { latitude: number[]; longitude: number[]; @@ -74,6 +71,10 @@ function refineInterval(interval: number[], cd: number, mask: number) { } } +export function geohashColumns(precision: number): number { + return geohashCells(precision, 0); +} + /** * Get the number of geohash cells for a given precision * @@ -90,51 +91,6 @@ function geohashCells(precision: number, axis: number) { return cells; } -/** - * Get the number of geohash columns (world-wide) for a given precision - * @param precision the geohash precision - * @returns {number} the number of columns - */ -export function geohashColumns(precision: number): number { - return geohashCells(precision, 0); -} - -const defaultPrecision = 2; -const maxPrecision = parseInt(config.get('visualization:tileMap:maxPrecision'), 10) || 12; -/** - * Map Leaflet zoom levels to geohash precision levels. - * The size of a geohash column-width on the map should be at least `minGeohashPixels` pixels wide. - */ -export const zoomPrecision: any = {}; -const minGeohashPixels = 16; - -for (let zoom = 0; zoom <= 21; zoom += 1) { - const worldPixels = 256 * Math.pow(2, zoom); - zoomPrecision[zoom] = 1; - for (let precision = 2; precision <= maxPrecision; precision += 1) { - const columns = geohashColumns(precision); - if (worldPixels / columns >= minGeohashPixels) { - zoomPrecision[zoom] = precision; - } else { - break; - } - } -} - -export function getPrecision(val: string) { - let precision = parseInt(val, 10); - - if (Number.isNaN(precision)) { - precision = defaultPrecision; - } - - if (precision > maxPrecision) { - return maxPrecision; - } - - return precision; -} - interface GeoBoundingBoxCoordinate { lat: number; lon: number; diff --git a/src/legacy/ui/public/vis/map/grid_dimensions.js b/src/plugins/maps_legacy/public/map/grid_dimensions.js similarity index 100% rename from src/legacy/ui/public/vis/map/grid_dimensions.js rename to src/plugins/maps_legacy/public/map/grid_dimensions.js diff --git a/src/legacy/ui/public/vis/map/kibana_map.js b/src/plugins/maps_legacy/public/map/kibana_map.js similarity index 96% rename from src/legacy/ui/public/vis/map/kibana_map.js rename to src/plugins/maps_legacy/public/map/kibana_map.js index bc581b1a8fbaf..1c4d0882cb7da 100644 --- a/src/legacy/ui/public/vis/map/kibana_map.js +++ b/src/plugins/maps_legacy/public/map/kibana_map.js @@ -24,7 +24,7 @@ import $ from 'jquery'; import _ from 'lodash'; import { zoomToPrecision } from './zoom_to_precision'; import { i18n } from '@kbn/i18n'; -import { ORIGIN } from '../../../../core_plugins/tile_map/common/origin'; +import { ORIGIN } from '../common/origin'; function makeFitControl(fitContainer, kibanaMap) { const FitControl = L.Control.extend({ @@ -39,7 +39,7 @@ function makeFitControl(fitContainer, kibanaMap) { onAdd: function(leafletMap) { this._leafletMap = leafletMap; const fitDatBoundsLabel = i18n.translate( - 'common.ui.vis.kibanaMap.leaflet.fitDataBoundsAriaLabel', + 'maps_legacy.kibanaMap.leaflet.fitDataBoundsAriaLabel', { defaultMessage: 'Fit Data Bounds' } ); $(this._fitContainer) @@ -101,7 +101,7 @@ function makeLegendControl(container, kibanaMap, position) { * Serves as simple abstraction for leaflet as well. */ export class KibanaMap extends EventEmitter { - constructor(containerNode, options) { + constructor(containerNode, options, services) { super(); this._containerNode = containerNode; this._leafletBaseLayer = null; @@ -116,6 +116,7 @@ export class KibanaMap extends EventEmitter { this._layers = []; this._listeners = []; this._showTooltip = false; + this.toastService = services ? services.toastService : null; const leafletOptions = { minZoom: options.minZoom, @@ -482,15 +483,21 @@ export class KibanaMap extends EventEmitter { } _addMaxZoomMessage = layer => { - const zoomWarningMsg = createZoomWarningMsg(this.getZoomLevel, this.getMaxZoomLevel); + if (this.toastService) { + const zoomWarningMsg = createZoomWarningMsg( + this.toastService, + this.getZoomLevel, + this.getMaxZoomLevel + ); - this._leafletMap.on('zoomend', zoomWarningMsg); - this._containerNode.setAttribute('data-test-subj', 'zoomWarningEnabled'); + this._leafletMap.on('zoomend', zoomWarningMsg); + this._containerNode.setAttribute('data-test-subj', 'zoomWarningEnabled'); - layer.on('remove', () => { - this._leafletMap.off('zoomend', zoomWarningMsg); - this._containerNode.removeAttribute('data-test-subj'); - }); + layer.on('remove', () => { + this._leafletMap.off('zoomend', zoomWarningMsg); + this._containerNode.removeAttribute('data-test-subj'); + }); + } }; setLegendPosition(position) { diff --git a/src/legacy/ui/public/vis/map/kibana_map_layer.js b/src/plugins/maps_legacy/public/map/kibana_map_layer.js similarity index 100% rename from src/legacy/ui/public/vis/map/kibana_map_layer.js rename to src/plugins/maps_legacy/public/map/kibana_map_layer.js diff --git a/src/legacy/ui/public/vis/map/map_messages.js b/src/plugins/maps_legacy/public/map/map_messages.js similarity index 93% rename from src/legacy/ui/public/vis/map/map_messages.js rename to src/plugins/maps_legacy/public/map/map_messages.js index 211796d734958..7422fa71280fb 100644 --- a/src/legacy/ui/public/vis/map/map_messages.js +++ b/src/plugins/maps_legacy/public/map/map_messages.js @@ -17,11 +17,10 @@ * under the License. */ -import { toastNotifications } from 'ui/notify'; import React from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiSpacer, EuiButtonEmpty } from '@elastic/eui'; -import { toMountPoint } from '../../../../../plugins/kibana_react/public'; +import { toMountPoint } from '../../../kibana_react/public'; export const createZoomWarningMsg = (function() { let disableZoomMsg = false; @@ -40,7 +39,7 @@ export const createZoomWarningMsg = (function() {

= minGeohashPixels) { + zoomPrecision[zoom] = precision; + } else { + break; + } + } + } + return zoomPrecision; +} + +export function getPrecision(val: string) { + let precision = parseInt(val, 10); + const maxPrecision = getMaxPrecision(); + + if (Number.isNaN(precision)) { + precision = DEFAULT_PRECISION; + } + + if (precision > maxPrecision) { + return maxPrecision; + } + + return precision; +} diff --git a/src/legacy/ui/public/vis/map/service_settings.d.ts b/src/plugins/maps_legacy/public/map/service_settings.d.ts similarity index 97% rename from src/legacy/ui/public/vis/map/service_settings.d.ts rename to src/plugins/maps_legacy/public/map/service_settings.d.ts index 6766000861e47..e265accaeb8fd 100644 --- a/src/legacy/ui/public/vis/map/service_settings.d.ts +++ b/src/plugins/maps_legacy/public/map/service_settings.d.ts @@ -44,7 +44,7 @@ export interface VectorLayer extends FileLayer { isEMS: boolean; } -export interface ServiceSettings { +export interface IServiceSettings { getEMSHotLink(layer: FileLayer): Promise; getTMSServices(): Promise; getFileLayers(): Promise; diff --git a/src/plugins/maps_legacy/public/map/service_settings.js b/src/plugins/maps_legacy/public/map/service_settings.js new file mode 100644 index 0000000000000..11c853d39e107 --- /dev/null +++ b/src/plugins/maps_legacy/public/map/service_settings.js @@ -0,0 +1,254 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import _ from 'lodash'; +import MarkdownIt from 'markdown-it'; +import { EMSClient } from '@elastic/ems-client'; +import { i18n } from '@kbn/i18n'; +import { getInjectedVarFunc } from '../kibana_services'; +import { ORIGIN } from '../common/origin'; + +const TMS_IN_YML_ID = 'TMS in config/kibana.yml'; + +export class ServiceSettings { + constructor() { + const getInjectedVar = getInjectedVarFunc(); + this.mapConfig = getInjectedVar('mapConfig'); + this.tilemapsConfig = getInjectedVar('tilemapsConfig'); + const kbnVersion = getInjectedVar('version'); + + this._showZoomMessage = true; + this._emsClient = new EMSClient({ + language: i18n.getLocale(), + appVersion: kbnVersion, + appName: 'kibana', + fileApiUrl: this.mapConfig.emsFileApiUrl, + tileApiUrl: this.mapConfig.emsTileApiUrl, + landingPageUrl: this.mapConfig.emsLandingPageUrl, + // Wrap to avoid errors passing window fetch + fetchFunction: function(...args) { + return fetch(...args); + }, + }); + this.getTMSOptions(); + } + + getTMSOptions() { + const markdownIt = new MarkdownIt({ + html: false, + linkify: true, + }); + + // TMS attribution + const attributionFromConfig = _.escape( + markdownIt.render(this.tilemapsConfig.deprecated.config.options.attribution || '') + ); + // TMS Options + this.tmsOptionsFromConfig = _.assign({}, this.tilemapsConfig.deprecated.config.options, { + attribution: attributionFromConfig, + }); + } + + shouldShowZoomMessage({ origin }) { + return origin === ORIGIN.EMS && this._showZoomMessage; + } + + disableZoomMessage() { + this._showZoomMessage = false; + } + + __debugStubManifestCalls(manifestRetrieval) { + const oldGetManifest = this._emsClient.getManifest; + this._emsClient.getManifest = manifestRetrieval; + return { + removeStub: () => { + delete this._emsClient.getManifest; + //not strictly necessary since this is prototype method + if (this._emsClient.getManifest !== oldGetManifest) { + this._emsClient.getManifest = oldGetManifest; + } + }, + }; + } + + async getFileLayers() { + if (!this.mapConfig.includeElasticMapsService) { + return []; + } + + const fileLayers = await this._emsClient.getFileLayers(); + return fileLayers.map(fileLayer => { + //backfill to older settings + const format = fileLayer.getDefaultFormatType(); + const meta = fileLayer.getDefaultFormatMeta(); + + return { + name: fileLayer.getDisplayName(), + origin: fileLayer.getOrigin(), + id: fileLayer.getId(), + created_at: fileLayer.getCreatedAt(), + attribution: fileLayer.getHTMLAttribution(), + fields: fileLayer.getFieldsInLanguage(), + format: format, //legacy: format and meta are split up + meta: meta, //legacy, format and meta are split up + }; + }); + } + + /** + * Returns all the services published by EMS (if configures) + * It also includes the service configured in tilemap (override) + */ + async getTMSServices() { + let allServices = []; + if (this.tilemapsConfig.deprecated.isOverridden) { + //use tilemap.* settings from yml + const tmsService = _.cloneDeep(this.tmsOptionsFromConfig); + tmsService.id = TMS_IN_YML_ID; + tmsService.origin = ORIGIN.KIBANA_YML; + allServices.push(tmsService); + } + + if (this.mapConfig.includeElasticMapsService) { + const servicesFromManifest = await this._emsClient.getTMSServices(); + const strippedServiceFromManifest = await Promise.all( + servicesFromManifest + .filter(tmsService => tmsService.getId() === this.mapConfig.emsTileLayerId.bright) + .map(async tmsService => { + //shim for compatibility + return { + origin: tmsService.getOrigin(), + id: tmsService.getId(), + minZoom: await tmsService.getMinZoom(), + maxZoom: await tmsService.getMaxZoom(), + attribution: tmsService.getHTMLAttribution(), + }; + }) + ); + allServices = allServices.concat(strippedServiceFromManifest); + } + + return allServices; + } + + /** + * Add optional query-parameters to all requests + * + * @param additionalQueryParams + */ + addQueryParams(additionalQueryParams) { + this._emsClient.addQueryParams(additionalQueryParams); + } + + async getEMSHotLink(fileLayerConfig) { + const fileLayers = await this._emsClient.getFileLayers(); + const layer = fileLayers.find(fileLayer => { + const hasIdByName = fileLayer.hasId(fileLayerConfig.name); //legacy + const hasIdById = fileLayer.hasId(fileLayerConfig.id); + return hasIdByName || hasIdById; + }); + return layer ? layer.getEMSHotLink() : null; + } + + async _getAttributesForEMSTMSLayer(isDesaturated, isDarkMode) { + const tmsServices = await this._emsClient.getTMSServices(); + const emsTileLayerId = this.mapConfig.emsTileLayerId; + let serviceId; + if (isDarkMode) { + serviceId = emsTileLayerId.dark; + } else { + if (isDesaturated) { + serviceId = emsTileLayerId.desaturated; + } else { + serviceId = emsTileLayerId.bright; + } + } + const tmsService = tmsServices.find(service => { + return service.getId() === serviceId; + }); + return { + url: await tmsService.getUrlTemplate(), + minZoom: await tmsService.getMinZoom(), + maxZoom: await tmsService.getMaxZoom(), + attribution: await tmsService.getHTMLAttribution(), + origin: ORIGIN.EMS, + }; + } + + async getAttributesForTMSLayer(tmsServiceConfig, isDesaturated, isDarkMode) { + if (tmsServiceConfig.origin === ORIGIN.EMS) { + return this._getAttributesForEMSTMSLayer(isDesaturated, isDarkMode); + } else if (tmsServiceConfig.origin === ORIGIN.KIBANA_YML) { + const config = this.tilemapsConfig.deprecated.config; + const attrs = _.pick(config, ['url', 'minzoom', 'maxzoom', 'attribution']); + return { ...attrs, ...{ origin: ORIGIN.KIBANA_YML } }; + } else { + //this is an older config. need to resolve this dynamically. + if (tmsServiceConfig.id === TMS_IN_YML_ID) { + const config = this.tilemapsConfig.deprecated.config; + const attrs = _.pick(config, ['url', 'minzoom', 'maxzoom', 'attribution']); + return { ...attrs, ...{ origin: ORIGIN.KIBANA_YML } }; + } else { + //assume ems + return this._getAttributesForEMSTMSLayer(isDesaturated, isDarkMode); + } + } + } + + async _getFileUrlFromEMS(fileLayerConfig) { + const fileLayers = await this._emsClient.getFileLayers(); + const layer = fileLayers.find(fileLayer => { + const hasIdByName = fileLayer.hasId(fileLayerConfig.name); //legacy + const hasIdById = fileLayer.hasId(fileLayerConfig.id); + return hasIdByName || hasIdById; + }); + + if (layer) { + return layer.getDefaultFormatUrl(); + } else { + throw new Error(`File ${fileLayerConfig.name} not recognized`); + } + } + + async getUrlForRegionLayer(fileLayerConfig) { + let url; + if (fileLayerConfig.origin === ORIGIN.EMS) { + url = this._getFileUrlFromEMS(fileLayerConfig); + } else if (fileLayerConfig.layerId && fileLayerConfig.layerId.startsWith(`${ORIGIN.EMS}.`)) { + //fallback for older saved objects + url = this._getFileUrlFromEMS(fileLayerConfig); + } else if ( + fileLayerConfig.layerId && + fileLayerConfig.layerId.startsWith(`${ORIGIN.KIBANA_YML}.`) + ) { + //fallback for older saved objects + url = fileLayerConfig.url; + } else { + //generic fallback + url = fileLayerConfig.url; + } + return url; + } + + async getJsonForRegionLayer(fileLayerConfig) { + const url = await this.getUrlForRegionLayer(fileLayerConfig); + const response = await fetch(url); + return await response.json(); + } +} diff --git a/src/legacy/ui/public/vis/map/zoom_to_precision.ts b/src/plugins/maps_legacy/public/map/zoom_to_precision.ts similarity index 100% rename from src/legacy/ui/public/vis/map/zoom_to_precision.ts rename to src/plugins/maps_legacy/public/map/zoom_to_precision.ts diff --git a/src/plugins/maps_legacy/public/plugin.ts b/src/plugins/maps_legacy/public/plugin.ts new file mode 100644 index 0000000000000..751be65e1dbf6 --- /dev/null +++ b/src/plugins/maps_legacy/public/plugin.ts @@ -0,0 +1,57 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// @ts-ignore +import { CoreSetup, CoreStart, Plugin } from 'kibana/public'; +// @ts-ignore +import { setToasts, setUiSettings, setInjectedVarFunc } from './kibana_services'; +// @ts-ignore +import { ServiceSettings } from './map/service_settings'; +// @ts-ignore +import { getPrecision, getZoomPrecision } from './map/precision'; +import { MapsLegacyPluginSetup, MapsLegacyPluginStart } from './index'; + +/** + * These are the interfaces with your public contracts. You should export these + * for other plugins to use in _their_ `SetupDeps`/`StartDeps` interfaces. + * @public + */ + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface MapsLegacySetupDependencies {} +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface MapsLegacyStartDependencies {} + +export class MapsLegacyPlugin implements Plugin { + constructor() {} + + public setup(core: CoreSetup, plugins: MapsLegacySetupDependencies) { + setToasts(core.notifications.toasts); + setUiSettings(core.uiSettings); + setInjectedVarFunc(core.injectedMetadata.getInjectedVar); + + return { + serviceSettings: new ServiceSettings(), + getZoomPrecision, + getPrecision, + }; + } + + public start(core: CoreStart, plugins: MapsLegacyStartDependencies) {} +} diff --git a/test/common/config.js b/test/common/config.js index faf8cef027170..ca80dfb01012f 100644 --- a/test/common/config.js +++ b/test/common/config.js @@ -56,6 +56,10 @@ export default function() { `--elasticsearch.password=${kibanaServerTestUser.password}`, `--home.disableWelcomeScreen=true`, '--telemetry.banner=false', + '--telemetry.optIn=false', + // These are *very* important to have them pointing to staging + '--telemetry.url=https://telemetry-staging.elastic.co/xpack/v2/send', + '--telemetry.optInStatusUrl=https://telemetry-staging.elastic.co/opt_in_status/v2/send', `--server.maxPayloadBytes=1679958`, // newsfeed mock service `--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'newsfeed')}`, diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/plugin.ts b/x-pack/legacy/plugins/canvas/canvas_plugin_src/plugin.ts index 7cd1efe9e27c8..a654c6b28b350 100644 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/plugin.ts +++ b/x-pack/legacy/plugins/canvas/canvas_plugin_src/plugin.ts @@ -6,11 +6,14 @@ import { CoreSetup, CoreStart, Plugin } from 'src/core/public'; import { CanvasSetup } from '../public'; +import { EmbeddableStart } from '../../../../../src/plugins/embeddable/public'; +import { UiActionsStart } from '../../../../../src/plugins/ui_actions/public'; +import { Start as InspectorStart } from '../../../../../src/plugins/inspector/public'; import { functions } from './functions/browser'; import { typeFunctions } from './expression_types'; // @ts-ignore: untyped local -import { renderFunctions } from './renderers'; +import { renderFunctions, renderFunctionFactories } from './renderers'; import { elementSpecs } from './elements'; // @ts-ignore Untyped Local @@ -30,13 +33,26 @@ interface SetupDeps { canvas: CanvasSetup; } +export interface StartDeps { + embeddable: EmbeddableStart; + uiActions: UiActionsStart; + inspector: InspectorStart; +} + /** @internal */ -export class CanvasSrcPlugin implements Plugin<{}, {}, SetupDeps, {}> { - public setup(core: CoreSetup, plugins: SetupDeps) { +export class CanvasSrcPlugin implements Plugin { + public setup(core: CoreSetup, plugins: SetupDeps) { plugins.canvas.addFunctions(functions); plugins.canvas.addTypes(typeFunctions); + plugins.canvas.addRenderers(renderFunctions); + core.getStartServices().then(([coreStart, depsStart]) => { + plugins.canvas.addRenderers( + renderFunctionFactories.map((factory: any) => factory(coreStart, depsStart)) + ); + }); + plugins.canvas.addElements(elementSpecs); plugins.canvas.addDatasourceUIs(datasourceSpecs); plugins.canvas.addModelUIs(modelSpecs); @@ -45,11 +61,7 @@ export class CanvasSrcPlugin implements Plugin<{}, {}, SetupDeps, {}> { plugins.canvas.addTagUIs(tagSpecs); plugins.canvas.addTemplates(templateSpecs); plugins.canvas.addTransformUIs(transformSpecs); - - return {}; } - public start(core: CoreStart, plugins: {}) { - return {}; - } + public start(core: CoreStart, plugins: StartDeps) {} } diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx index 817be6e144fc8..a1096d50c1653 100644 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx +++ b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx @@ -7,7 +7,8 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { I18nContext } from 'ui/i18n'; -import { npStart } from 'ui/new_platform'; +import { CoreStart } from '../../../../../../../src/core/public'; +import { StartDeps } from '../../plugin'; import { IEmbeddable, EmbeddableFactory, @@ -28,86 +29,88 @@ const embeddablesRegistry: { [key: string]: IEmbeddable; } = {}; -const renderEmbeddable = (embeddableObject: IEmbeddable, domNode: HTMLElement) => { - return ( -

- - - -
- ); +const renderEmbeddableFactory = (core: CoreStart, plugins: StartDeps) => { + return (embeddableObject: IEmbeddable, domNode: HTMLElement) => { + return ( +
+ + + +
+ ); + }; }; -const embeddable = () => ({ - name: 'embeddable', - displayName: strings.getDisplayName(), - help: strings.getHelpDescription(), - reuseDomNode: true, - render: async ( - domNode: HTMLElement, - { input, embeddableType }: EmbeddableExpression, - handlers: RendererHandlers - ) => { - const uniqueId = handlers.getElementId(); - - if (!embeddablesRegistry[uniqueId]) { - const factory = Array.from(npStart.plugins.embeddable.getEmbeddableFactories()).find( - embeddableFactory => embeddableFactory.type === embeddableType - ) as EmbeddableFactory; - - if (!factory) { - handlers.done(); - throw new EmbeddableFactoryNotFoundError(embeddableType); - } - - const embeddableObject = await factory.createFromSavedObject(input.id, input); +export const embeddableRendererFactory = (core: CoreStart, plugins: StartDeps) => { + const renderEmbeddable = renderEmbeddableFactory(core, plugins); + return () => ({ + name: 'embeddable', + displayName: strings.getDisplayName(), + help: strings.getHelpDescription(), + reuseDomNode: true, + render: async ( + domNode: HTMLElement, + { input, embeddableType }: EmbeddableExpression, + handlers: RendererHandlers + ) => { + const uniqueId = handlers.getElementId(); + + if (!embeddablesRegistry[uniqueId]) { + const factory = Array.from(plugins.embeddable.getEmbeddableFactories()).find( + embeddableFactory => embeddableFactory.type === embeddableType + ) as EmbeddableFactory; + + if (!factory) { + handlers.done(); + throw new EmbeddableFactoryNotFoundError(embeddableType); + } - embeddablesRegistry[uniqueId] = embeddableObject; - ReactDOM.unmountComponentAtNode(domNode); + const embeddableObject = await factory.createFromSavedObject(input.id, input); - const subscription = embeddableObject.getInput$().subscribe(function(updatedInput) { - const updatedExpression = embeddableInputToExpression(updatedInput, embeddableType); + embeddablesRegistry[uniqueId] = embeddableObject; + ReactDOM.unmountComponentAtNode(domNode); - if (updatedExpression) { - handlers.onEmbeddableInputChange(updatedExpression); - } - }); + const subscription = embeddableObject.getInput$().subscribe(function(updatedInput) { + const updatedExpression = embeddableInputToExpression(updatedInput, embeddableType); - ReactDOM.render(renderEmbeddable(embeddableObject, domNode), domNode, () => handlers.done()); + if (updatedExpression) { + handlers.onEmbeddableInputChange(updatedExpression); + } + }); - handlers.onResize(() => { ReactDOM.render(renderEmbeddable(embeddableObject, domNode), domNode, () => handlers.done() ); - }); - handlers.onDestroy(() => { - subscription.unsubscribe(); - handlers.onEmbeddableDestroyed(); + handlers.onResize(() => { + ReactDOM.render(renderEmbeddable(embeddableObject, domNode), domNode, () => + handlers.done() + ); + }); - delete embeddablesRegistry[uniqueId]; + handlers.onDestroy(() => { + subscription.unsubscribe(); + handlers.onEmbeddableDestroyed(); - return ReactDOM.unmountComponentAtNode(domNode); - }); - } else { - embeddablesRegistry[uniqueId].updateInput(input); - } - }, -}); + delete embeddablesRegistry[uniqueId]; -export { embeddable }; + return ReactDOM.unmountComponentAtNode(domNode); + }); + } else { + embeddablesRegistry[uniqueId].updateInput(input); + } + }, + }); +}; diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/index.js b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/index.js index 48364be06e539..84f92f5149893 100644 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/index.js +++ b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/index.js @@ -7,7 +7,7 @@ import { advancedFilter } from './advanced_filter'; import { debug } from './debug'; import { dropdownFilter } from './dropdown_filter'; -import { embeddable } from './embeddable/embeddable'; +import { embeddableRendererFactory } from './embeddable/embeddable'; import { error } from './error'; import { image } from './image'; import { markdown } from './markdown'; @@ -26,7 +26,6 @@ export const renderFunctions = [ advancedFilter, debug, dropdownFilter, - embeddable, error, image, markdown, @@ -41,3 +40,5 @@ export const renderFunctions = [ text, timeFilter, ]; + +export const renderFunctionFactories = [embeddableRendererFactory]; diff --git a/x-pack/legacy/plugins/canvas/index.js b/x-pack/legacy/plugins/canvas/index.js index 489b9600f200e..a1d4b35826b00 100644 --- a/x-pack/legacy/plugins/canvas/index.js +++ b/x-pack/legacy/plugins/canvas/index.js @@ -7,9 +7,7 @@ import { resolve } from 'path'; import { DEFAULT_APP_CATEGORIES } from '../../../../src/core/utils'; import { init } from './init'; -import { mappings } from './server/mappings'; import { CANVAS_APP, CANVAS_TYPE, CUSTOM_ELEMENT_TYPE } from './common/lib'; -import { migrations } from './migrations'; export function canvas(kibana) { return new kibana.Plugin({ @@ -33,8 +31,6 @@ export function canvas(kibana) { 'plugins/canvas/lib/window_error_handler.js', ], home: ['plugins/canvas/legacy_register_feature'], - mappings, - migrations, savedObjectsManagement: { [CANVAS_TYPE]: { icon: 'canvasApp', diff --git a/x-pack/legacy/plugins/canvas/migrations.test.js b/x-pack/legacy/plugins/canvas/migrations.test.js deleted file mode 100644 index 182ef3b18cce7..0000000000000 --- a/x-pack/legacy/plugins/canvas/migrations.test.js +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { migrations } from './migrations'; -import { CANVAS_TYPE } from './common/lib'; - -describe(`${CANVAS_TYPE}`, () => { - describe('7.0.0', () => { - const migrate = doc => migrations[CANVAS_TYPE]['7.0.0'](doc); - - it('does not throw error on empty object', () => { - const migratedDoc = migrate({}); - expect(migratedDoc).toMatchInlineSnapshot(`Object {}`); - }); - - it('removes id from "attributes"', () => { - const migratedDoc = migrate({ - foo: true, - attributes: { - id: '123', - bar: true, - }, - }); - expect(migratedDoc).toMatchInlineSnapshot(` -Object { - "attributes": Object { - "bar": true, - }, - "foo": true, -} -`); - }); - }); -}); diff --git a/x-pack/legacy/plugins/canvas/public/components/embeddable_flyout/flyout.tsx b/x-pack/legacy/plugins/canvas/public/components/embeddable_flyout/flyout.tsx index 08cd3084c35cf..4916a27fcbe60 100644 --- a/x-pack/legacy/plugins/canvas/public/components/embeddable_flyout/flyout.tsx +++ b/x-pack/legacy/plugins/canvas/public/components/embeddable_flyout/flyout.tsx @@ -5,7 +5,6 @@ */ import React from 'react'; -import { npStart } from 'ui/new_platform'; import { EuiFlyout, EuiFlyoutHeader, EuiFlyoutBody, EuiTitle } from '@elastic/eui'; import { SavedObjectFinderUi, @@ -13,6 +12,7 @@ import { } from '../../../../../../../src/plugins/saved_objects/public/'; import { ComponentStrings } from '../../../i18n'; import { CoreStart } from '../../../../../../../src/core/public'; +import { CanvasStartDeps } from '../../plugin'; const { AddEmbeddableFlyout: strings } = ComponentStrings; @@ -22,11 +22,12 @@ export interface Props { availableEmbeddables: string[]; savedObjects: CoreStart['savedObjects']; uiSettings: CoreStart['uiSettings']; + getEmbeddableFactories: CanvasStartDeps['embeddable']['getEmbeddableFactories']; } export class AddEmbeddableFlyout extends React.Component { onAddPanel = (id: string, savedObjectType: string, name: string) => { - const embeddableFactories = npStart.plugins.embeddable.getEmbeddableFactories(); + const embeddableFactories = this.props.getEmbeddableFactories(); // Find the embeddable type from the saved object type const found = Array.from(embeddableFactories).find(embeddableFactory => { @@ -42,7 +43,7 @@ export class AddEmbeddableFlyout extends React.Component { }; render() { - const embeddableFactories = npStart.plugins.embeddable.getEmbeddableFactories(); + const embeddableFactories = this.props.getEmbeddableFactories(); const availableSavedObjects = Array.from(embeddableFactories) .filter(factory => { diff --git a/x-pack/legacy/plugins/canvas/public/components/embeddable_flyout/index.tsx b/x-pack/legacy/plugins/canvas/public/components/embeddable_flyout/index.tsx index a86784d374f49..c13cbfd042237 100644 --- a/x-pack/legacy/plugins/canvas/public/components/embeddable_flyout/index.tsx +++ b/x-pack/legacy/plugins/canvas/public/components/embeddable_flyout/index.tsx @@ -105,6 +105,7 @@ export class EmbeddableFlyoutPortal extends React.Component, this.el ); diff --git a/x-pack/legacy/plugins/canvas/public/legacy.ts b/x-pack/legacy/plugins/canvas/public/legacy.ts index a6caa1985325e..4af7c9b2bd057 100644 --- a/x-pack/legacy/plugins/canvas/public/legacy.ts +++ b/x-pack/legacy/plugins/canvas/public/legacy.ts @@ -26,7 +26,9 @@ const shimSetupPlugins: CanvasSetupDeps = { }; const shimStartPlugins: CanvasStartDeps = { ...npStart.plugins, + embeddable: npStart.plugins.embeddable, expressions: npStart.plugins.expressions, + inspector: npStart.plugins.inspector, uiActions: npStart.plugins.uiActions, __LEGACY: { // ToDo: Copy directly into canvas diff --git a/x-pack/legacy/plugins/canvas/public/plugin.tsx b/x-pack/legacy/plugins/canvas/public/plugin.tsx index d9e5e6b4b084b..3ea3ce625ca71 100644 --- a/x-pack/legacy/plugins/canvas/public/plugin.tsx +++ b/x-pack/legacy/plugins/canvas/public/plugin.tsx @@ -11,6 +11,8 @@ import { initLoadingIndicator } from './lib/loading_indicator'; import { featureCatalogueEntry } from './feature_catalogue_entry'; import { ExpressionsSetup, ExpressionsStart } from '../../../../../src/plugins/expressions/public'; import { UiActionsStart } from '../../../../../src/plugins/ui_actions/public'; +import { EmbeddableStart } from '../../../../../src/plugins/embeddable/public'; +import { Start as InspectorStart } from '../../../../../src/plugins/inspector/public'; // @ts-ignore untyped local import { argTypeSpecs } from './expression_types/arg_types'; import { transitions } from './transitions'; @@ -31,7 +33,9 @@ export interface CanvasSetupDeps { } export interface CanvasStartDeps { + embeddable: EmbeddableStart; expressions: ExpressionsStart; + inspector: InspectorStart; uiActions: UiActionsStart; __LEGACY: { absoluteToParsedUrl: (url: string, basePath: string) => any; @@ -48,14 +52,19 @@ export interface CanvasStartDeps { // These interfaces are empty for now but will be populate as we need to export // things for other plugins to use at startup or runtime export type CanvasSetup = CanvasApi; -export interface CanvasStart {} // eslint-disable-line @typescript-eslint/no-empty-interface +export type CanvasStart = void; /** @internal */ export class CanvasPlugin implements Plugin { + // TODO: Do we want to completely move canvas_plugin_src into it's own plugin? + private srcPlugin = new CanvasSrcPlugin(); + public setup(core: CoreSetup, plugins: CanvasSetupDeps) { const { api: canvasApi, registries } = getPluginApi(plugins.expressions); + this.srcPlugin.setup(core, { canvas: canvasApi }); + core.application.register({ id: 'canvas', title: 'Canvas App', @@ -84,10 +93,6 @@ export class CanvasPlugin canvasApi.addElements(legacyRegistries.elements.getOriginalFns()); canvasApi.addTypes(legacyRegistries.types.getOriginalFns()); - // TODO: Do we want to completely move canvas_plugin_src into it's own plugin? - const srcPlugin = new CanvasSrcPlugin(); - srcPlugin.setup(core, { canvas: canvasApi }); - // Register core canvas stuff canvasApi.addFunctions(initFunctions({ typesRegistry: plugins.expressions.__LEGACY.types })); canvasApi.addArgumentUIs(argTypeSpecs); @@ -99,8 +104,7 @@ export class CanvasPlugin } public start(core: CoreStart, plugins: CanvasStartDeps) { + this.srcPlugin.start(core, plugins); initLoadingIndicator(core.http.addLoadingCountSource); - - return {}; } } diff --git a/x-pack/legacy/plugins/maps/common/migrations/ems_raster_tile_to_ems_vector_tile.js b/x-pack/legacy/plugins/maps/common/migrations/ems_raster_tile_to_ems_vector_tile.js index 94f4018bbdbb7..091cfd8605cb6 100644 --- a/x-pack/legacy/plugins/maps/common/migrations/ems_raster_tile_to_ems_vector_tile.js +++ b/x-pack/legacy/plugins/maps/common/migrations/ems_raster_tile_to_ems_vector_tile.js @@ -5,11 +5,11 @@ */ import _ from 'lodash'; -import { EMS_TMS, LAYER_TYPE } from '../constants'; +import { SOURCE_TYPES, LAYER_TYPE } from '../constants'; function isEmsTileSource(layerDescriptor) { const sourceType = _.get(layerDescriptor, 'sourceDescriptor.type'); - return sourceType === EMS_TMS; + return sourceType === SOURCE_TYPES.EMS_TMS; } function isTileLayer(layerDescriptor) { diff --git a/x-pack/legacy/plugins/maps/common/migrations/move_apply_global_query.js b/x-pack/legacy/plugins/maps/common/migrations/move_apply_global_query.js index 490e760d8c003..0d6b0052d2b0d 100644 --- a/x-pack/legacy/plugins/maps/common/migrations/move_apply_global_query.js +++ b/x-pack/legacy/plugins/maps/common/migrations/move_apply_global_query.js @@ -5,11 +5,13 @@ */ import _ from 'lodash'; -import { ES_GEO_GRID, ES_PEW_PEW, ES_SEARCH } from '../constants'; +import { SOURCE_TYPES } from '../constants'; function isEsSource(layerDescriptor) { const sourceType = _.get(layerDescriptor, 'sourceDescriptor.type'); - return [ES_GEO_GRID, ES_PEW_PEW, ES_SEARCH].includes(sourceType); + return [SOURCE_TYPES.ES_GEO_GRID, SOURCE_TYPES.ES_PEW_PEW, SOURCE_TYPES.ES_SEARCH].includes( + sourceType + ); } // Migration to move applyGlobalQuery from layer to sources. diff --git a/x-pack/legacy/plugins/maps/common/migrations/references.js b/x-pack/legacy/plugins/maps/common/migrations/references.js index a96af700da37c..3980705fd7cfa 100644 --- a/x-pack/legacy/plugins/maps/common/migrations/references.js +++ b/x-pack/legacy/plugins/maps/common/migrations/references.js @@ -7,11 +7,15 @@ // Can not use public Layer classes to extract references since this logic must run in both client and server. import _ from 'lodash'; -import { ES_GEO_GRID, ES_SEARCH, ES_PEW_PEW } from '../constants'; +import { SOURCE_TYPES } from '../constants'; function doesSourceUseIndexPattern(layerDescriptor) { const sourceType = _.get(layerDescriptor, 'sourceDescriptor.type'); - return sourceType === ES_GEO_GRID || sourceType === ES_SEARCH || sourceType === ES_PEW_PEW; + return ( + sourceType === SOURCE_TYPES.ES_GEO_GRID || + sourceType === SOURCE_TYPES.ES_SEARCH || + sourceType === SOURCE_TYPES.ES_PEW_PEW + ); } export function extractReferences({ attributes, references = [] }) { diff --git a/x-pack/legacy/plugins/maps/common/migrations/references.test.js b/x-pack/legacy/plugins/maps/common/migrations/references.test.js index 40f6fd72a48d7..50a45c81339dc 100644 --- a/x-pack/legacy/plugins/maps/common/migrations/references.test.js +++ b/x-pack/legacy/plugins/maps/common/migrations/references.test.js @@ -5,16 +5,16 @@ */ import { extractReferences, injectReferences } from './references'; -import { ES_GEO_GRID, ES_SEARCH, ES_PEW_PEW } from '../constants'; +import { SOURCE_TYPES } from '../constants'; const layerListJSON = { esSearchSource: { - withIndexPatternId: `[{\"sourceDescriptor\":{\"type\":\"${ES_SEARCH}\",\"indexPatternId\":\"c698b940-e149-11e8-a35a-370a8516603a\"}}]`, - withIndexPatternRef: `[{\"sourceDescriptor\":{\"type\":\"${ES_SEARCH}\",\"indexPatternRefName\":\"layer_0_source_index_pattern\"}}]`, + withIndexPatternId: `[{\"sourceDescriptor\":{\"type\":\"${SOURCE_TYPES.ES_SEARCH}\",\"indexPatternId\":\"c698b940-e149-11e8-a35a-370a8516603a\"}}]`, + withIndexPatternRef: `[{\"sourceDescriptor\":{\"type\":\"${SOURCE_TYPES.ES_SEARCH}\",\"indexPatternRefName\":\"layer_0_source_index_pattern\"}}]`, }, esGeoGridSource: { - withIndexPatternId: `[{\"sourceDescriptor\":{\"type\":\"${ES_GEO_GRID}\",\"indexPatternId\":\"c698b940-e149-11e8-a35a-370a8516603a\"}}]`, - withIndexPatternRef: `[{\"sourceDescriptor\":{\"type\":\"${ES_GEO_GRID}\",\"indexPatternRefName\":\"layer_0_source_index_pattern\"}}]`, + withIndexPatternId: `[{\"sourceDescriptor\":{\"type\":\"${SOURCE_TYPES.ES_GEO_GRID}\",\"indexPatternId\":\"c698b940-e149-11e8-a35a-370a8516603a\"}}]`, + withIndexPatternRef: `[{\"sourceDescriptor\":{\"type\":\"${SOURCE_TYPES.ES_GEO_GRID}\",\"indexPatternRefName\":\"layer_0_source_index_pattern\"}}]`, }, join: { withIndexPatternId: @@ -23,8 +23,8 @@ const layerListJSON = { '[{"joins":[{"right":{"indexPatternRefName":"layer_0_join_0_index_pattern"}}]}]', }, pewPewSource: { - withIndexPatternId: `[{\"sourceDescriptor\":{\"type\":\"${ES_PEW_PEW}\",\"indexPatternId\":\"c698b940-e149-11e8-a35a-370a8516603a\"}}]`, - withIndexPatternRef: `[{\"sourceDescriptor\":{\"type\":\"${ES_PEW_PEW}\",\"indexPatternRefName\":\"layer_0_source_index_pattern\"}}]`, + withIndexPatternId: `[{\"sourceDescriptor\":{\"type\":\"${SOURCE_TYPES.ES_PEW_PEW}\",\"indexPatternId\":\"c698b940-e149-11e8-a35a-370a8516603a\"}}]`, + withIndexPatternRef: `[{\"sourceDescriptor\":{\"type\":\"${SOURCE_TYPES.ES_PEW_PEW}\",\"indexPatternRefName\":\"layer_0_source_index_pattern\"}}]`, }, }; diff --git a/x-pack/legacy/plugins/maps/common/migrations/scaling_type.ts b/x-pack/legacy/plugins/maps/common/migrations/scaling_type.ts index 5823ddd6b42e3..551975fbacea5 100644 --- a/x-pack/legacy/plugins/maps/common/migrations/scaling_type.ts +++ b/x-pack/legacy/plugins/maps/common/migrations/scaling_type.ts @@ -5,13 +5,13 @@ */ import _ from 'lodash'; -import { ES_SEARCH, SCALING_TYPES } from '../constants'; +import { SOURCE_TYPES, SCALING_TYPES } from '../constants'; import { LayerDescriptor, ESSearchSourceDescriptor } from '../descriptor_types'; import { MapSavedObjectAttributes } from '../../../../../plugins/maps/common/map_saved_object_type'; function isEsDocumentSource(layerDescriptor: LayerDescriptor) { const sourceType = _.get(layerDescriptor, 'sourceDescriptor.type'); - return sourceType === ES_SEARCH; + return sourceType === SOURCE_TYPES.ES_SEARCH; } export function migrateUseTopHitsToScalingType({ diff --git a/x-pack/legacy/plugins/maps/common/migrations/top_hits_time_to_sort.js b/x-pack/legacy/plugins/maps/common/migrations/top_hits_time_to_sort.js index 7392dfa71bf3a..055c867486f6c 100644 --- a/x-pack/legacy/plugins/maps/common/migrations/top_hits_time_to_sort.js +++ b/x-pack/legacy/plugins/maps/common/migrations/top_hits_time_to_sort.js @@ -5,11 +5,11 @@ */ import _ from 'lodash'; -import { ES_SEARCH, SORT_ORDER } from '../constants'; +import { SOURCE_TYPES, SORT_ORDER } from '../constants'; function isEsDocumentSource(layerDescriptor) { const sourceType = _.get(layerDescriptor, 'sourceDescriptor.type'); - return sourceType === ES_SEARCH; + return sourceType === SOURCE_TYPES.ES_SEARCH; } export function topHitsTimeToSort({ attributes }) { diff --git a/x-pack/legacy/plugins/maps/public/actions/map_actions.js b/x-pack/legacy/plugins/maps/public/actions/map_actions.js index aa55cf0808ef2..7bfbf5761c5b8 100644 --- a/x-pack/legacy/plugins/maps/public/actions/map_actions.js +++ b/x-pack/legacy/plugins/maps/public/actions/map_actions.js @@ -125,9 +125,21 @@ async function syncDataForAllLayers(dispatch, getState, dataFilters) { export function cancelAllInFlightRequests() { return (dispatch, getState) => { getLayerList(getState()).forEach(layer => { - layer.getInFlightRequestTokens().forEach(requestToken => { - dispatch(cancelRequest(requestToken)); - }); + dispatch(clearDataRequests(layer)); + }); + }; +} + +function clearDataRequests(layer) { + return dispatch => { + layer.getInFlightRequestTokens().forEach(requestToken => { + dispatch(cancelRequest(requestToken)); + }); + dispatch({ + type: UPDATE_LAYER_PROP, + id: layer.getId(), + propName: '__dataRequests', + newValue: [], }); }; } @@ -663,13 +675,31 @@ export function updateSourceProp(layerId, propName, value, newLayerType) { layerId, propName, value, - newLayerType, }); + if (newLayerType) { + dispatch(updateLayerType(layerId, newLayerType)); + } await dispatch(clearMissingStyleProperties(layerId)); dispatch(syncDataForLayer(layerId)); }; } +function updateLayerType(layerId, newLayerType) { + return (dispatch, getState) => { + const layer = getLayerById(layerId, getState()); + if (!layer || layer.getType() === newLayerType) { + return; + } + dispatch(clearDataRequests(layer)); + dispatch({ + type: UPDATE_LAYER_PROP, + id: layerId, + propName: 'type', + newValue: newLayerType, + }); + }; +} + export function syncDataForLayer(layerId) { return async (dispatch, getState) => { const targetLayer = getLayerById(layerId, getState()); diff --git a/x-pack/legacy/plugins/maps/public/connected_components/map/mb/draw_control/draw_control.js b/x-pack/legacy/plugins/maps/public/connected_components/map/mb/draw_control/draw_control.js index df2988d399c5b..cc0e665525036 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/map/mb/draw_control/draw_control.js +++ b/x-pack/legacy/plugins/maps/public/connected_components/map/mb/draw_control/draw_control.js @@ -12,7 +12,6 @@ import DrawRectangle from 'mapbox-gl-draw-rectangle-mode'; import { DrawCircle } from './draw_circle'; import { createDistanceFilterWithMeta, - createSpatialFilterWithBoundingBox, createSpatialFilterWithGeometry, getBoundingBoxGeometry, roundCoordinates, @@ -84,23 +83,17 @@ export class DrawControl extends React.Component { roundCoordinates(geometry.coordinates); try { - const options = { + const filter = createSpatialFilterWithGeometry({ + geometry: + this.props.drawState.drawType === DRAW_TYPE.BOUNDS + ? getBoundingBoxGeometry(geometry) + : geometry, indexPatternId: this.props.drawState.indexPatternId, geoFieldName: this.props.drawState.geoFieldName, geoFieldType: this.props.drawState.geoFieldType, geometryLabel: this.props.drawState.geometryLabel, relation: this.props.drawState.relation, - }; - const filter = - this.props.drawState.drawType === DRAW_TYPE.BOUNDS - ? createSpatialFilterWithBoundingBox({ - ...options, - geometry: getBoundingBoxGeometry(geometry), - }) - : createSpatialFilterWithGeometry({ - ...options, - geometry, - }); + }); this.props.addFilters([filter]); } catch (error) { // TODO notify user why filter was not created diff --git a/x-pack/legacy/plugins/maps/server/maps_telemetry/maps_telemetry.ts b/x-pack/legacy/plugins/maps/server/maps_telemetry/maps_telemetry.ts index 0300f22eeeb82..27c0211446e85 100644 --- a/x-pack/legacy/plugins/maps/server/maps_telemetry/maps_telemetry.ts +++ b/x-pack/legacy/plugins/maps/server/maps_telemetry/maps_telemetry.ts @@ -12,7 +12,7 @@ import { } from 'src/core/server'; import { IFieldType, IIndexPattern } from 'src/plugins/data/public'; import { - EMS_FILE, + SOURCE_TYPES, ES_GEO_FIELD_TYPE, MAP_SAVED_OBJECT_TYPE, TELEMETRY_TYPE, @@ -100,7 +100,7 @@ export function buildMapsTelemetry({ const emsLayersCount = layerLists.map(lList => _(lList) .countBy((layer: LayerDescriptor) => { - const isEmsFile = _.get(layer, 'sourceDescriptor.type') === EMS_FILE; + const isEmsFile = _.get(layer, 'sourceDescriptor.type') === SOURCE_TYPES.EMS_FILE; return isEmsFile && _.get(layer, 'sourceDescriptor.id'); }) .pick((val, key) => key !== 'false') diff --git a/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/flyout/__snapshots__/flyout.test.js.snap b/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/flyout/__snapshots__/flyout.test.js.snap index eb1c65c6a696d..4a7537166bd8a 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/flyout/__snapshots__/flyout.test.js.snap +++ b/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/flyout/__snapshots__/flyout.test.js.snap @@ -161,7 +161,7 @@ exports[`Flyout apm part two should show instructions to migrate to metricbeat 1 "children":

{ return [ { - sourceDescriptor: { type: 'EMS_TMS', isAutoSelect: true }, + sourceDescriptor: { type: SOURCE_TYPES.EMS_TMS, isAutoSelect: true }, id: uuid.v4(), label: null, minZoom: 0, @@ -260,7 +261,7 @@ export const getLineLayer = ( layerDetails: LayerMapping ) => ({ sourceDescriptor: { - type: 'ES_PEW_PEW', + type: SOURCE_TYPES.ES_PEW_PEW, applyGlobalQuery: true, id: uuid.v4(), indexPatternId, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_anomalous_network_activity.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_anomalous_network_activity.json index fe248a6c1e23e..41f38173dba33 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_anomalous_network_activity.json +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_anomalous_network_activity.json @@ -20,5 +20,6 @@ "ML" ], "type": "machine_learning", + "note": "### Investigating Unusual Network Activity ###\nSignals from this rule indicate the presence of network activity from a Linux process for which network activity is rare and unusual. Here are some possible avenues of investigation:\n- Consider the IP addresses and ports. Are these used by normal but infrequent network workflows? Are they expected or unexpected? \n- If the destination IP address is remote or external, does it associate with an expected domain, organization or geography? Note: avoid interacting directly with suspected malicious IP addresses.\n- Consider the user as identified by the username field. Is this network activity part of an expected workflow for the user who ran the program?\n- Examine the history of execution. If this process manifested only very recently, it might be part of a new software package. If it has a consistent cadence - for example if it runs monthly or quarterly - it might be part of a monthly or quarterly business or maintenance process.\n- Examine the process arguments, title and working directory. These may provide indications as to the source of the program or the nature of the tasks it is performing.", "version": 1 -} \ No newline at end of file +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_anomalous_process_all_hosts.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_anomalous_process_all_hosts.json index d15c4fc794378..103171bcdfe50 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_anomalous_process_all_hosts.json +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_anomalous_process_all_hosts.json @@ -20,5 +20,6 @@ "ML" ], "type": "machine_learning", + "note": "### Investigating an Unusual Linux Process ###\nSignals from this rule indicate the presence of a Linux process that is rare and unusual for all of the monitored Linux hosts for which Auditbeat data is available. Here are some possible avenues of investigation:\n- Consider the user as identified by the username field. Is this program part of an expected workflow for the user who ran this program on this host?\n- Examine the history of execution. If this process manifested only very recently, it might be part of a new software package. If it has a consistent cadence - for example if it runs monthly or quarterly - it might be part of a monthly or quarterly business process.\n- Examine the process arguments, title and working directory. These may provide indications as to the source of the program or the nature of the tasks it is performing.", "version": 1 -} \ No newline at end of file +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_anomalous_user_name.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_anomalous_user_name.json index 2f33948b0a93e..6642bb5d73fbd 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_anomalous_user_name.json +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/linux_anomalous_user_name.json @@ -20,5 +20,6 @@ "ML" ], "type": "machine_learning", + "note": "### Investigating an Unusual Linux User ###\nSignals from this rule indicate activity for a Linux user name that is rare and unusual. Here are some possible avenues of investigation:\n- Consider the user as identified by the username field. Is this program part of an expected workflow for the user who ran this program on this host? Could this be related to troubleshooting or debugging activity by a developer or site reliability engineer?\n- Examine the history of user activity. If this user manifested only very recently, it might be a service account for a new software package. If it has a consistent cadence - for example if it runs monthly or quarterly - it might be part of a monthly or quarterly business process.\n- Examine the process arguments, title and working directory. These may provide indications as to the source of the program or the nature of the tasks that the user is performing.", "version": 1 -} \ No newline at end of file +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/rare_process_by_host_linux.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/rare_process_by_host_linux.json index f071677ae8d33..8ae1b84aaf199 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/rare_process_by_host_linux.json +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/rare_process_by_host_linux.json @@ -20,5 +20,6 @@ "ML" ], "type": "machine_learning", + "note": "### Investigating an Unusual Linux Process ###\nSignals from this rule indicate the presence of a Linux process that is rare and unusual for the host it ran on. Here are some possible avenues of investigation:\n- Consider the user as identified by the username field. Is this program part of an expected workflow for the user who ran this program on this host?\n- Examine the history of execution. If this process manifested only very recently, it might be part of a new software package. If it has a consistent cadence - for example if it runs monthly or quarterly - it might be part of a monthly or quarterly business process.\n- Examine the process arguments, title and working directory. These may provide indications as to the source of the program or the nature of the tasks it is performing.", "version": 1 -} \ No newline at end of file +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/rare_process_by_host_windows.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/rare_process_by_host_windows.json index 5e0050c6c25ec..879cee388f5dd 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/rare_process_by_host_windows.json +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/rare_process_by_host_windows.json @@ -20,5 +20,6 @@ "Windows" ], "type": "machine_learning", + "note": "### Investigating an Unusual Windows Process ###\nSignals from this rule indicate the presence of a Windows process that is rare and unusual for the host it ran on. Here are some possible avenues of investigation:\n- Consider the user as identified by the username field. Is this program part of an expected workflow for the user who ran this program on this host?\n- Examine the history of execution. If this process manifested only very recently, it might be part of a new software package. If it has a consistent cadence - for example if it runs monthly or quarterly - it might be part of a monthly or quarterly business process.\n- Examine the process metadata like the values of the Company, Description and Product fields which may indicate whether the program is associated with an expected software vendor or package. \n- Examine arguments and working directory. These may provide indications as to the source of the program or the nature of the tasks it is performing.\n- Consider the same for the parent process. If the parent process is a legitimate system utility or service, this could be related to software updates or system management. If the parent process is something user-facing like an Office application, this process could be more suspicious.\n- If you have file hash values in the event data, and you suspect malware, you can optionally run a search for the file hash to see if the file is identified as malware by anti-malware tools. ", "version": 1 -} \ No newline at end of file +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_network_activity.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_network_activity.json index ca18fe95b1fc1..1092bcb20bcc3 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_network_activity.json +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_network_activity.json @@ -20,5 +20,6 @@ "Windows" ], "type": "machine_learning", + "note": "### Investigating Unusual Network Activity ###\nSignals from this rule indicate the presence of network activity from a Windows process for which network activity is very unusual. Here are some possible avenues of investigation:\n- Consider the IP addresses, protocol and ports. Are these used by normal but infrequent network workflows? Are they expected or unexpected? \n- If the destination IP address is remote or external, does it associate with an expected domain, organization or geography? Note: avoid interacting directly with suspected malicious IP addresses.\n- Consider the user as identified by the username field. Is this network activity part of an expected workflow for the user who ran the program?\n- Examine the history of execution. If this process manifested only very recently, it might be part of a new software package. If it has a consistent cadence - for example if it runs monthly or quarterly - it might be part of a monthly or quarterly business process.\n- Examine the process arguments, title and working directory. These may provide indications as to the source of the program or the nature of the tasks it is performing.\n- Consider the same for the parent process. If the parent process is a legitimate system utility or service, this could be related to software updates or system management. If the parent process is something user-facing like an Office application, this process could be more suspicious.\n- If you have file hash values in the event data, and you suspect malware, you can optionally run a search for the file hash to see if the file is identified as malware by anti-malware tools. ", "version": 1 -} \ No newline at end of file +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_process_all_hosts.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_process_all_hosts.json index 1229c4a52b97d..f9adfeb830618 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_process_all_hosts.json +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_process_all_hosts.json @@ -20,5 +20,6 @@ "Windows" ], "type": "machine_learning", + "note": "### Investigating an Unusual Windows Process ###\nSignals from this rule indicate the presence of a Windows process that is rare and unusual for all of the Windows hosts for which Winlogbeat data is available. Here are some possible avenues of investigation:\n- Consider the user as identified by the username field. Is this program part of an expected workflow for the user who ran this program on this host?\n- Examine the history of execution. If this process manifested only very recently, it might be part of a new software package. If it has a consistent cadence - for example if it runs monthly or quarterly - it might be part of a monthly or quarterly business process.\n- Examine the process metadata like the values of the Company, Description and Product fields which may indicate whether the program is associated with an expected software vendor or package. \n- Examine arguments and working directory. These may provide indications as to the source of the program or the nature of the tasks it is performing.\n- Consider the same for the parent process. If the parent process is a legitimate system utility or service, this could be related to software updates or system management. If the parent process is something user-facing like an Office application, this process could be more suspicious.\n- If you have file hash values in the event data, and you suspect malware, you can optionally run a search for the file hash to see if the file is identified as malware by anti-malware tools. ", "version": 1 -} \ No newline at end of file +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_user_name.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_user_name.json index 703dc1a1dc633..a0c6ff5c938f1 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_user_name.json +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_anomalous_user_name.json @@ -20,5 +20,6 @@ "Windows" ], "type": "machine_learning", + "note": "### Investigating an Unusual Windows User ###\nSignals from this rule indicate activity for a Windows user name that is rare and unusual. Here are some possible avenues of investigation:\n- Consider the user as identified by the username field. Is this program part of an expected workflow for the user who ran this program on this host? Could this be related to occasional troubleshooting or support activity?\n- Examine the history of user activity. If this user manifested only very recently, it might be a service account for a new software package. If it has a consistent cadence - for example if it runs monthly or quarterly - it might be part of a monthly or quarterly business process.\n- Examine the process arguments, title and working directory. These may provide indications as to the source of the program or the nature of the tasks that the user is performing.\n- Consider the same for the parent process. If the parent process is a legitimate system utility or service, this could be related to software updates or system management. If the parent process is something user-facing like an Office application, this process could be more suspicious.", "version": 1 -} \ No newline at end of file +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_rare_user_type10_remote_login.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_rare_user_type10_remote_login.json index 946cdb95b8e70..7318364c3aac2 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_rare_user_type10_remote_login.json +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/prepackaged_rules/windows_rare_user_type10_remote_login.json @@ -20,5 +20,6 @@ "Windows" ], "type": "machine_learning", + "note": "### Investigating an Unusual Windows User ###\nSignals from this rule indicate activity for a rare and unusual Windows RDP (remote desktop) user. Here are some possible avenues of investigation:\n- Consider the user as identified by the username field. Is the user part of a group who normally logs into Windows hosts using RDP (remote desktop protocol)? Is this logon activity part of an expected workflow for the user? \n- Consider the source of the login. If the source is remote, could this be related to occasional troubleshooting or support activity by a vendor or an employee working remotely?", "version": 1 -} \ No newline at end of file +} diff --git a/x-pack/legacy/plugins/tilemap/public/vis_type_enhancers/update_tilemap_settings.js b/x-pack/legacy/plugins/tilemap/public/vis_type_enhancers/update_tilemap_settings.js index 45764016f0311..294bc31e3893e 100644 --- a/x-pack/legacy/plugins/tilemap/public/vis_type_enhancers/update_tilemap_settings.js +++ b/x-pack/legacy/plugins/tilemap/public/vis_type_enhancers/update_tilemap_settings.js @@ -4,20 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ -import uiRoutes from 'ui/routes'; import { xpackInfo } from 'plugins/xpack_main/services/xpack_info'; -import 'ui/vis/map/service_settings'; +import { npSetup } from 'ui/new_platform'; -uiRoutes.addSetupWork(function($injector, serviceSettings) { - const tileMapPluginInfo = xpackInfo.get('features.tilemap'); +const tileMapPluginInfo = xpackInfo.get('features.tilemap'); - if (!tileMapPluginInfo) { - return; - } - - if (!tileMapPluginInfo.license.active || !tileMapPluginInfo.license.valid) { - return; - } +if (tileMapPluginInfo && (tileMapPluginInfo.license.active || tileMapPluginInfo.license.valid)) { + const { serviceSettings } = npSetup.plugins.mapsLegacy; serviceSettings.addQueryParams({ license: tileMapPluginInfo.license.uid }); serviceSettings.disableZoomMessage(); -}); +} diff --git a/x-pack/plugins/actions/server/builtin_action_types/email.test.ts b/x-pack/plugins/actions/server/builtin_action_types/email.test.ts index 469df4fd86e2c..658f8f3fd8cf9 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/email.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/email.test.ts @@ -255,7 +255,14 @@ describe('execute()', () => { services, }; sendEmailMock.mockReset(); - await actionType.executor(executorOptions); + const result = await actionType.executor(executorOptions); + expect(result).toMatchInlineSnapshot(` + Object { + "actionId": "some-id", + "data": undefined, + "status": "ok", + } + `); expect(sendEmailMock.mock.calls[0][1]).toMatchInlineSnapshot(` Object { "content": Object { @@ -282,4 +289,102 @@ describe('execute()', () => { } `); }); + + test('parameters are as expected with no auth', async () => { + const config: ActionTypeConfigType = { + service: null, + host: 'a host', + port: 42, + secure: true, + from: 'bob@example.com', + }; + const secrets: ActionTypeSecretsType = { + user: null, + password: null, + }; + const params: ActionParamsType = { + to: ['jim@example.com'], + cc: ['james@example.com'], + bcc: ['jimmy@example.com'], + subject: 'the subject', + message: 'a message to you', + }; + + const actionId = 'some-id'; + const executorOptions: ActionTypeExecutorOptions = { + actionId, + config, + params, + secrets, + services, + }; + sendEmailMock.mockReset(); + await actionType.executor(executorOptions); + expect(sendEmailMock.mock.calls[0][1]).toMatchInlineSnapshot(` + Object { + "content": Object { + "message": "a message to you", + "subject": "the subject", + }, + "routing": Object { + "bcc": Array [ + "jimmy@example.com", + ], + "cc": Array [ + "james@example.com", + ], + "from": "bob@example.com", + "to": Array [ + "jim@example.com", + ], + }, + "transport": Object { + "host": "a host", + "port": 42, + "secure": true, + }, + } + `); + }); + + test('returns expected result when an error is thrown', async () => { + const config: ActionTypeConfigType = { + service: null, + host: 'a host', + port: 42, + secure: true, + from: 'bob@example.com', + }; + const secrets: ActionTypeSecretsType = { + user: null, + password: null, + }; + const params: ActionParamsType = { + to: ['jim@example.com'], + cc: ['james@example.com'], + bcc: ['jimmy@example.com'], + subject: 'the subject', + message: 'a message to you', + }; + + const actionId = 'some-id'; + const executorOptions: ActionTypeExecutorOptions = { + actionId, + config, + params, + secrets, + services, + }; + sendEmailMock.mockReset(); + sendEmailMock.mockRejectedValue(new Error('wops')); + const result = await actionType.executor(executorOptions); + expect(result).toMatchInlineSnapshot(` + Object { + "actionId": "some-id", + "message": "error sending email", + "serviceMessage": "wops", + "status": "error", + } + `); + }); }); diff --git a/x-pack/plugins/actions/server/builtin_action_types/email.ts b/x-pack/plugins/actions/server/builtin_action_types/email.ts index 7992920fdfcb4..ca8d089ad2946 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/email.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/email.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import { schema, TypeOf } from '@kbn/config-schema'; import nodemailerGetService from 'nodemailer/lib/well-known'; -import { sendEmail, JSON_TRANSPORT_SERVICE } from './lib/send_email'; +import { sendEmail, JSON_TRANSPORT_SERVICE, SendEmailOptions, Transport } from './lib/send_email'; import { portSchema } from './lib/schemas'; import { Logger } from '../../../../../src/core/server'; import { ActionType, ActionTypeExecutorOptions, ActionTypeExecutorResult } from '../types'; @@ -143,7 +143,7 @@ async function executor( const secrets = execOptions.secrets as ActionTypeSecretsType; const params = execOptions.params as ActionParamsType; - const transport: any = {}; + const transport: Transport = {}; if (secrets.user != null) { transport.user = secrets.user; @@ -155,12 +155,13 @@ async function executor( if (config.service !== null) { transport.service = config.service; } else { - transport.host = config.host; - transport.port = config.port; + // already validated service or host/port is not null ... + transport.host = config.host!; + transport.port = config.port!; transport.secure = getSecureValue(config.secure, config.port); } - const sendEmailOptions = { + const sendEmailOptions: SendEmailOptions = { transport, routing: { from: config.from, diff --git a/x-pack/plugins/actions/server/builtin_action_types/lib/send_email.test.ts b/x-pack/plugins/actions/server/builtin_action_types/lib/send_email.test.ts new file mode 100644 index 0000000000000..42160dc2fc22b --- /dev/null +++ b/x-pack/plugins/actions/server/builtin_action_types/lib/send_email.test.ts @@ -0,0 +1,175 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +jest.mock('nodemailer', () => ({ + createTransport: jest.fn(), +})); + +import { Logger } from '../../../../../../src/core/server'; +import { sendEmail } from './send_email'; +import { loggingServiceMock } from '../../../../../../src/core/server/mocks'; +import nodemailer from 'nodemailer'; + +const createTransportMock = nodemailer.createTransport as jest.Mock; +const sendMailMockResult = { result: 'does not matter' }; +const sendMailMock = jest.fn(); + +const mockLogger = loggingServiceMock.create().get() as jest.Mocked; + +describe('send_email module', () => { + beforeEach(() => { + jest.resetAllMocks(); + createTransportMock.mockReturnValue({ sendMail: sendMailMock }); + sendMailMock.mockResolvedValue(sendMailMockResult); + }); + + test('handles authenticated email using service', async () => { + const sendEmailOptions = getSendEmailOptions(); + const result = await sendEmail(mockLogger, sendEmailOptions); + expect(result).toBe(sendMailMockResult); + expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "auth": Object { + "pass": "changeme", + "user": "elastic", + }, + "service": "whatever", + }, + ] + `); + expect(sendMailMock.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "bcc": Array [], + "cc": Array [ + "bob@example.com", + "robert@example.com", + ], + "from": "fred@example.com", + "html": "

a message

+ ", + "subject": "a subject", + "text": "a message", + "to": Array [ + "jim@example.com", + ], + }, + ] + `); + }); + + test('handles unauthenticated email using not secure host/port', async () => { + const sendEmailOptions = getSendEmailOptions(); + delete sendEmailOptions.transport.service; + delete sendEmailOptions.transport.user; + delete sendEmailOptions.transport.password; + sendEmailOptions.transport.host = 'example.com'; + sendEmailOptions.transport.port = 1025; + const result = await sendEmail(mockLogger, sendEmailOptions); + expect(result).toBe(sendMailMockResult); + expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "host": "example.com", + "port": 1025, + "secure": false, + "tls": Object { + "rejectUnauthorized": false, + }, + }, + ] + `); + expect(sendMailMock.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "bcc": Array [], + "cc": Array [ + "bob@example.com", + "robert@example.com", + ], + "from": "fred@example.com", + "html": "

a message

+ ", + "subject": "a subject", + "text": "a message", + "to": Array [ + "jim@example.com", + ], + }, + ] + `); + }); + + test('handles unauthenticated email using secure host/port', async () => { + const sendEmailOptions = getSendEmailOptions(); + delete sendEmailOptions.transport.service; + delete sendEmailOptions.transport.user; + delete sendEmailOptions.transport.password; + sendEmailOptions.transport.host = 'example.com'; + sendEmailOptions.transport.port = 1025; + sendEmailOptions.transport.secure = true; + const result = await sendEmail(mockLogger, sendEmailOptions); + expect(result).toBe(sendMailMockResult); + expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "host": "example.com", + "port": 1025, + "secure": true, + }, + ] + `); + expect(sendMailMock.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "bcc": Array [], + "cc": Array [ + "bob@example.com", + "robert@example.com", + ], + "from": "fred@example.com", + "html": "

a message

+ ", + "subject": "a subject", + "text": "a message", + "to": Array [ + "jim@example.com", + ], + }, + ] + `); + }); + + test('passes nodemailer exceptions to caller', async () => { + const sendEmailOptions = getSendEmailOptions(); + + sendMailMock.mockReset(); + sendMailMock.mockRejectedValue(new Error('wops')); + + await expect(sendEmail(mockLogger, sendEmailOptions)).rejects.toThrow('wops'); + }); +}); + +function getSendEmailOptions(): any { + return { + content: { + message: 'a message', + subject: 'a subject', + }, + routing: { + from: 'fred@example.com', + to: ['jim@example.com'], + cc: ['bob@example.com', 'robert@example.com'], + bcc: [], + }, + transport: { + service: 'whatever', + user: 'elastic', + password: 'changeme', + }, + }; +} diff --git a/x-pack/plugins/actions/server/builtin_action_types/lib/send_email.ts b/x-pack/plugins/actions/server/builtin_action_types/lib/send_email.ts index 47d7aff8022ce..ffbf7485a8b0b 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/lib/send_email.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/lib/send_email.ts @@ -14,30 +14,30 @@ import { Logger } from '../../../../../../src/core/server'; // an email "service" which doesn't actually send, just returns what it would send export const JSON_TRANSPORT_SERVICE = '__json'; -interface SendEmailOptions { +export interface SendEmailOptions { transport: Transport; routing: Routing; content: Content; } // config validation ensures either service is set or host/port are set -interface Transport { - user: string; - password: string; +export interface Transport { + user?: string; + password?: string; service?: string; // see: https://nodemailer.com/smtp/well-known/ host?: string; port?: number; secure?: boolean; // see: https://nodemailer.com/smtp/#tls-options } -interface Routing { +export interface Routing { from: string; to: string[]; cc: string[]; bcc: string[]; } -interface Content { +export interface Content { subject: string; message: string; } @@ -49,12 +49,14 @@ export async function sendEmail(logger: Logger, options: SendEmailOptions): Prom const { from, to, cc, bcc } = routing; const { subject, message } = content; - const transportConfig: Record = { - auth: { + const transportConfig: Record = {}; + + if (user != null && password != null) { + transportConfig.auth = { user, pass: password, - }, - }; + }; + } if (service === JSON_TRANSPORT_SERVICE) { transportConfig.jsonTransport = true; diff --git a/x-pack/plugins/canvas/server/plugin.ts b/x-pack/plugins/canvas/server/plugin.ts index 0325de9cf29e2..91a5634734559 100644 --- a/x-pack/plugins/canvas/server/plugin.ts +++ b/x-pack/plugins/canvas/server/plugin.ts @@ -14,6 +14,7 @@ import { initRoutes } from './routes'; import { registerCanvasUsageCollector } from './collectors'; import { loadSampleData } from './sample_data'; import { setupInterpreter } from './setup_interpreter'; +import { customElementType, workpadType } from './saved_objects'; interface PluginsSetup { expressions: ExpressionsServerSetup; @@ -29,6 +30,9 @@ export class CanvasPlugin implements Plugin { } public async setup(coreSetup: CoreSetup, plugins: PluginsSetup) { + coreSetup.savedObjects.registerType(customElementType); + coreSetup.savedObjects.registerType(workpadType); + plugins.features.registerFeature({ id: 'canvas', name: 'Canvas', diff --git a/x-pack/legacy/plugins/canvas/server/mappings.ts b/x-pack/plugins/canvas/server/saved_objects/custom_element.ts similarity index 56% rename from x-pack/legacy/plugins/canvas/server/mappings.ts rename to x-pack/plugins/canvas/server/saved_objects/custom_element.ts index bf2be51882b1a..dadead0263be1 100644 --- a/x-pack/legacy/plugins/canvas/server/mappings.ts +++ b/x-pack/plugins/canvas/server/saved_objects/custom_element.ts @@ -4,26 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ -// @ts-ignore converting /libs/constants to TS breaks CI -import { CANVAS_TYPE, CUSTOM_ELEMENT_TYPE } from '../common/lib/constants'; +import { SavedObjectsType } from 'src/core/server'; +import { CUSTOM_ELEMENT_TYPE } from '../../../../legacy/plugins/canvas/common/lib/constants'; -export const mappings = { - [CANVAS_TYPE]: { - dynamic: false, - properties: { - name: { - type: 'text', - fields: { - keyword: { - type: 'keyword', - }, - }, - }, - '@timestamp': { type: 'date' }, - '@created': { type: 'date' }, - }, - }, - [CUSTOM_ELEMENT_TYPE]: { +export const customElementType: SavedObjectsType = { + name: CUSTOM_ELEMENT_TYPE, + hidden: false, + namespaceAgnostic: false, + mappings: { dynamic: false, properties: { name: { @@ -41,4 +29,5 @@ export const mappings = { '@created': { type: 'date' }, }, }, + migrations: {}, }; diff --git a/x-pack/legacy/plugins/canvas/migrations.js b/x-pack/plugins/canvas/server/saved_objects/index.ts similarity index 53% rename from x-pack/legacy/plugins/canvas/migrations.js rename to x-pack/plugins/canvas/server/saved_objects/index.ts index d5b3d3fb1ce2a..dd7e74b87e2f4 100644 --- a/x-pack/legacy/plugins/canvas/migrations.js +++ b/x-pack/plugins/canvas/server/saved_objects/index.ts @@ -4,15 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { CANVAS_TYPE } from './common/lib'; +import { workpadType } from './workpad'; +import { customElementType } from './custom_element'; -export const migrations = { - [CANVAS_TYPE]: { - '7.0.0': doc => { - if (doc.attributes) { - delete doc.attributes.id; - } - return doc; - }, - }, -}; +export { customElementType, workpadType }; diff --git a/x-pack/plugins/canvas/server/saved_objects/migrations/remove_attributes_id.test.ts b/x-pack/plugins/canvas/server/saved_objects/migrations/remove_attributes_id.test.ts new file mode 100644 index 0000000000000..a7112504e9980 --- /dev/null +++ b/x-pack/plugins/canvas/server/saved_objects/migrations/remove_attributes_id.test.ts @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { removeAttributesId } from './remove_attributes_id'; + +const context: any = { + log: jest.fn(), +}; + +describe(`removeAttributesId`, () => { + it('does not throw error on empty object', () => { + const migratedDoc = removeAttributesId({} as any, context); + expect(migratedDoc).toMatchInlineSnapshot(`Object {}`); + }); + + it('removes id from "attributes"', () => { + const migratedDoc = removeAttributesId( + { + foo: true, + attributes: { + id: '123', + bar: true, + }, + } as any, + context + ); + expect(migratedDoc).toMatchInlineSnapshot(` +Object { + "attributes": Object { + "bar": true, + }, + "foo": true, +} +`); + }); +}); diff --git a/x-pack/plugins/canvas/server/saved_objects/migrations/remove_attributes_id.ts b/x-pack/plugins/canvas/server/saved_objects/migrations/remove_attributes_id.ts new file mode 100644 index 0000000000000..893a73d7b5913 --- /dev/null +++ b/x-pack/plugins/canvas/server/saved_objects/migrations/remove_attributes_id.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { SavedObjectMigrationFn } from 'src/core/server'; + +export const removeAttributesId: SavedObjectMigrationFn = doc => { + if (typeof doc.attributes === 'object' && doc.attributes !== null) { + delete (doc.attributes as any).id; + } + return doc; +}; diff --git a/x-pack/plugins/canvas/server/saved_objects/workpad.ts b/x-pack/plugins/canvas/server/saved_objects/workpad.ts new file mode 100644 index 0000000000000..e83ba9720b43a --- /dev/null +++ b/x-pack/plugins/canvas/server/saved_objects/workpad.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { SavedObjectsType } from 'src/core/server'; +import { CANVAS_TYPE } from '../../../../legacy/plugins/canvas/common/lib/constants'; +import { removeAttributesId } from './migrations/remove_attributes_id'; + +export const workpadType: SavedObjectsType = { + name: CANVAS_TYPE, + hidden: false, + namespaceAgnostic: false, + mappings: { + dynamic: false, + properties: { + name: { + type: 'text', + fields: { + keyword: { + type: 'keyword', + }, + }, + }, + '@timestamp': { type: 'date' }, + '@created': { type: 'date' }, + }, + }, + migrations: { + '7.0.0': removeAttributesId, + }, +}; diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/action.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/action.ts index 3f4f3f39e9be0..3db224f049c05 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/action.ts +++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/action.ts @@ -21,15 +21,4 @@ interface ServerFailedToReturnPolicyListData { payload: ServerApiError; } -interface UserPaginatedPolicyListTable { - type: 'userPaginatedPolicyListTable'; - payload: { - pageSize: number; - pageIndex: number; - }; -} - -export type PolicyListAction = - | ServerReturnedPolicyListData - | UserPaginatedPolicyListTable - | ServerFailedToReturnPolicyListData; +export type PolicyListAction = ServerReturnedPolicyListData | ServerFailedToReturnPolicyListData; diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/index.test.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/index.test.ts index 0cf0eb8bfa3cd..4d153b5e03cd2 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/index.test.ts +++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/index.test.ts @@ -4,71 +4,106 @@ * you may not use this file except in compliance with the Elastic License. */ -import { PolicyListState } from '../../types'; +import { EndpointAppLocation, PolicyListState } from '../../types'; import { applyMiddleware, createStore, Dispatch, Store } from 'redux'; import { AppAction } from '../action'; import { policyListReducer } from './reducer'; import { policyListMiddlewareFactory } from './middleware'; import { coreMock } from '../../../../../../../../src/core/public/mocks'; -import { CoreStart } from 'kibana/public'; -import { selectIsLoading } from './selectors'; +import { isOnPolicyListPage, selectIsLoading, urlSearchParams } from './selectors'; import { DepsStartMock, depsStartMock } from '../../mocks'; +import { + createSpyMiddleware, + MiddlewareActionSpyHelper, + setPolicyListApiMockImplementation, +} from './test_mock_utils'; +import { INGEST_API_DATASOURCES } from './services/ingest'; describe('policy list store concerns', () => { - const sleep = () => new Promise(resolve => setTimeout(resolve, 1000)); - let fakeCoreStart: jest.Mocked; + let fakeCoreStart: ReturnType; let depsStart: DepsStartMock; let store: Store; let getState: typeof store['getState']; let dispatch: Dispatch; + let waitForAction: MiddlewareActionSpyHelper['waitForAction']; beforeEach(() => { fakeCoreStart = coreMock.createStart({ basePath: '/mock' }); depsStart = depsStartMock(); + setPolicyListApiMockImplementation(fakeCoreStart.http); + let actionSpyMiddleware; + ({ actionSpyMiddleware, waitForAction } = createSpyMiddleware()); + store = createStore( policyListReducer, - applyMiddleware(policyListMiddlewareFactory(fakeCoreStart, depsStart)) + applyMiddleware(policyListMiddlewareFactory(fakeCoreStart, depsStart), actionSpyMiddleware) ); getState = store.getState; dispatch = store.dispatch; }); - // https://github.com/elastic/kibana/issues/58972 - test.skip('it sets `isLoading` when `userNavigatedToPage`', async () => { - expect(selectIsLoading(getState())).toBe(false); - dispatch({ type: 'userNavigatedToPage', payload: 'policyListPage' }); - expect(selectIsLoading(getState())).toBe(true); - await sleep(); - expect(selectIsLoading(getState())).toBe(false); + it('it does nothing on `userChangedUrl` if pathname is NOT `/policy`', async () => { + const state = getState(); + expect(isOnPolicyListPage(state)).toBe(false); + dispatch({ + type: 'userChangedUrl', + payload: { + pathname: '/foo', + search: '', + hash: '', + } as EndpointAppLocation, + }); + expect(getState()).toEqual(state); }); - // https://github.com/elastic/kibana/issues/58896 - test.skip('it sets `isLoading` when `userPaginatedPolicyListTable`', async () => { + it('it reports `isOnPolicyListPage` correctly when router pathname is `/policy`', async () => { + dispatch({ + type: 'userChangedUrl', + payload: { + pathname: '/policy', + search: '', + hash: '', + }, + }); + expect(isOnPolicyListPage(getState())).toBe(true); + }); + + it('it sets `isLoading` when `userChangedUrl`', async () => { expect(selectIsLoading(getState())).toBe(false); dispatch({ - type: 'userPaginatedPolicyListTable', + type: 'userChangedUrl', payload: { - pageSize: 10, - pageIndex: 1, + pathname: '/policy', + search: '', + hash: '', }, }); expect(selectIsLoading(getState())).toBe(true); - await sleep(); + await waitForAction('serverReturnedPolicyListData'); expect(selectIsLoading(getState())).toBe(false); }); - test('it resets state on `userNavigatedFromPage` action', async () => { + it('it resets state on `userChangedUrl` and pathname is NOT `/policy`', async () => { + dispatch({ + type: 'userChangedUrl', + payload: { + pathname: '/policy', + search: '', + hash: '', + }, + }); + await waitForAction('serverReturnedPolicyListData'); dispatch({ - type: 'serverReturnedPolicyListData', + type: 'userChangedUrl', payload: { - policyItems: [], - pageIndex: 20, - pageSize: 50, - total: 200, + pathname: '/foo', + search: '', + hash: '', }, }); - dispatch({ type: 'userNavigatedFromPage', payload: 'policyListPage' }); expect(getState()).toEqual({ + apiError: undefined, + location: undefined, policyItems: [], isLoading: false, pageIndex: 0, @@ -76,4 +111,85 @@ describe('policy list store concerns', () => { total: 0, }); }); + it('uses default pagination params when not included in url', async () => { + dispatch({ + type: 'userChangedUrl', + payload: { + pathname: '/policy', + search: '', + hash: '', + }, + }); + await waitForAction('serverReturnedPolicyListData'); + expect(fakeCoreStart.http.get).toHaveBeenCalledWith(INGEST_API_DATASOURCES, { + query: { kuery: 'datasources.package.name: endpoint', page: 1, perPage: 10 }, + }); + }); + + describe('when url contains search params', () => { + const dispatchUserChangedUrl = (searchParams: string = '') => + dispatch({ + type: 'userChangedUrl', + payload: { + pathname: '/policy', + search: searchParams, + hash: '', + }, + }); + + it('uses pagination params from url', async () => { + dispatchUserChangedUrl('?page_size=50&page_index=0'); + await waitForAction('serverReturnedPolicyListData'); + expect(fakeCoreStart.http.get).toHaveBeenCalledWith(INGEST_API_DATASOURCES, { + query: { kuery: 'datasources.package.name: endpoint', page: 1, perPage: 50 }, + }); + }); + it('uses defaults for params not in url', async () => { + dispatchUserChangedUrl('?page_index=99'); + expect(urlSearchParams(getState())).toEqual({ + page_index: 99, + page_size: 10, + }); + dispatchUserChangedUrl('?page_size=50'); + expect(urlSearchParams(getState())).toEqual({ + page_index: 0, + page_size: 50, + }); + }); + it('accepts only positive numbers for page_index and page_size', async () => { + dispatchUserChangedUrl('?page_size=-50&page_index=-99'); + await waitForAction('serverReturnedPolicyListData'); + expect(fakeCoreStart.http.get).toHaveBeenCalledWith(INGEST_API_DATASOURCES, { + query: { kuery: 'datasources.package.name: endpoint', page: 1, perPage: 10 }, + }); + }); + it('it ignores non-numeric values for page_index and page_size', async () => { + dispatchUserChangedUrl('?page_size=fifty&page_index=ten'); + await waitForAction('serverReturnedPolicyListData'); + expect(fakeCoreStart.http.get).toHaveBeenCalledWith(INGEST_API_DATASOURCES, { + query: { kuery: 'datasources.package.name: endpoint', page: 1, perPage: 10 }, + }); + }); + it('accepts only known values for `page_size`', async () => { + dispatchUserChangedUrl('?page_size=300&page_index=10'); + await waitForAction('serverReturnedPolicyListData'); + expect(fakeCoreStart.http.get).toHaveBeenCalledWith(INGEST_API_DATASOURCES, { + query: { kuery: 'datasources.package.name: endpoint', page: 11, perPage: 10 }, + }); + }); + it(`ignores unknown url search params`, async () => { + dispatchUserChangedUrl('?page_size=20&page_index=10&foo=bar'); + expect(urlSearchParams(getState())).toEqual({ + page_index: 10, + page_size: 20, + }); + }); + it(`uses last param value if param is defined multiple times`, async () => { + dispatchUserChangedUrl('?page_size=20&page_size=50&page_index=20&page_index=40'); + expect(urlSearchParams(getState())).toEqual({ + page_index: 20, + page_size: 20, + }); + }); + }); }); diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/middleware.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/middleware.ts index adc176740fb4b..c073d26a676f0 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/middleware.ts +++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/middleware.ts @@ -6,6 +6,7 @@ import { MiddlewareFactory, PolicyListState, GetDatasourcesResponse } from '../../types'; import { sendGetEndpointSpecificDatasources } from './services/ingest'; +import { isOnPolicyListPage, urlSearchParams } from './selectors'; export const policyListMiddlewareFactory: MiddlewareFactory = coreStart => { const http = coreStart.http; @@ -13,22 +14,10 @@ export const policyListMiddlewareFactory: MiddlewareFactory = c return ({ getState, dispatch }) => next => async action => { next(action); - if ( - (action.type === 'userNavigatedToPage' && action.payload === 'policyListPage') || - action.type === 'userPaginatedPolicyListTable' - ) { - const state = getState(); - let pageSize: number; - let pageIndex: number; - - if (action.type === 'userPaginatedPolicyListTable') { - pageSize = action.payload.pageSize; - pageIndex = action.payload.pageIndex; - } else { - pageSize = state.pageSize; - pageIndex = state.pageIndex; - } + const state = getState(); + if (action.type === 'userChangedUrl' && isOnPolicyListPage(state)) { + const { page_index: pageIndex, page_size: pageSize } = urlSearchParams(state); let response: GetDatasourcesResponse; try { diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/reducer.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/reducer.ts index b964f4f023866..30c1deac7f5e1 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/reducer.ts +++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/reducer.ts @@ -7,6 +7,7 @@ import { Reducer } from 'redux'; import { PolicyListState } from '../../types'; import { AppAction } from '../action'; +import { isOnPolicyListPage } from './selectors'; const initialPolicyListState = (): PolicyListState => { return { @@ -16,6 +17,7 @@ const initialPolicyListState = (): PolicyListState => { pageIndex: 0, pageSize: 10, total: 0, + location: undefined, }; }; @@ -39,19 +41,26 @@ export const policyListReducer: Reducer = ( }; } - if ( - action.type === 'userPaginatedPolicyListTable' || - (action.type === 'userNavigatedToPage' && action.payload === 'policyListPage') - ) { - return { + if (action.type === 'userChangedUrl') { + const newState = { ...state, - apiError: undefined, - isLoading: true, + location: action.payload, }; - } + const isCurrentlyOnListPage = isOnPolicyListPage(newState); + const wasPreviouslyOnListPage = isOnPolicyListPage(state); - if (action.type === 'userNavigatedFromPage' && action.payload === 'policyListPage') { - return initialPolicyListState(); + // If on the current page, then return new state with location information + // Also adjust some state if user is just entering the policy list view + if (isCurrentlyOnListPage) { + if (!wasPreviouslyOnListPage) { + newState.apiError = undefined; + newState.isLoading = true; + } + return newState; + } + return { + ...initialPolicyListState(), + }; } return state; diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/selectors.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/selectors.ts index 7ca25e81ce75a..ce13d89b2b8c2 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/selectors.ts +++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/selectors.ts @@ -4,7 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import { PolicyListState } from '../../types'; +import { createSelector } from 'reselect'; +import { parse } from 'query-string'; +import { PolicyListState, PolicyListUrlSearchParams } from '../../types'; + +const PAGE_SIZES = Object.freeze([10, 20, 50]); export const selectPolicyItems = (state: PolicyListState) => state.policyItems; @@ -17,3 +21,47 @@ export const selectTotal = (state: PolicyListState) => state.total; export const selectIsLoading = (state: PolicyListState) => state.isLoading; export const selectApiError = (state: PolicyListState) => state.apiError; + +export const isOnPolicyListPage = (state: PolicyListState) => { + return state.location?.pathname === '/policy'; +}; + +const routeLocation = (state: PolicyListState) => state.location; + +/** + * Returns the supported URL search params, populated with defaults if none where present in the URL + */ +export const urlSearchParams: ( + state: PolicyListState +) => PolicyListUrlSearchParams = createSelector(routeLocation, location => { + const searchParams = { + page_index: 0, + page_size: 10, + }; + if (!location) { + return searchParams; + } + + const query = parse(location.search); + + // Search params can appear multiple times in the URL, in which case the value for them, + // once parsed, would be an array. In these case, we take the first value defined + searchParams.page_index = Number( + (Array.isArray(query.page_index) ? query.page_index[0] : query.page_index) ?? 0 + ); + searchParams.page_size = Number( + (Array.isArray(query.page_size) ? query.page_size[0] : query.page_size) ?? 10 + ); + + // If pageIndex is not a valid positive integer, set it to 0 + if (!Number.isFinite(searchParams.page_index) || searchParams.page_index < 0) { + searchParams.page_index = 0; + } + + // if pageSize is not one of the expected page sizes, reset it to 10 + if (!PAGE_SIZES.includes(searchParams.page_size)) { + searchParams.page_size = 10; + } + + return searchParams; +}); diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/services/ingest.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/services/ingest.ts index 16c885f26f0a4..bfbb5f94e8950 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/services/ingest.ts +++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/services/ingest.ts @@ -17,7 +17,7 @@ import { } from '../../../types'; const INGEST_API_ROOT = `/api/ingest_manager`; -const INGEST_API_DATASOURCES = `${INGEST_API_ROOT}/datasources`; +export const INGEST_API_DATASOURCES = `${INGEST_API_ROOT}/datasources`; const INGEST_API_FLEET = `${INGEST_API_ROOT}/fleet`; const INGEST_API_FLEET_AGENT_STATUS = `${INGEST_API_FLEET}/agent-status`; diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/test_mock_utils.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/test_mock_utils.ts new file mode 100644 index 0000000000000..0d41ae0d76da4 --- /dev/null +++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/test_mock_utils.ts @@ -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; + * you may not use this file except in compliance with the Elastic License. + */ + +import { HttpStart } from 'kibana/public'; +import { Dispatch } from 'redux'; +import { INGEST_API_DATASOURCES } from './services/ingest'; +import { EndpointDocGenerator } from '../../../../../common/generate_data'; +import { AppAction, GetDatasourcesResponse, GlobalState, MiddlewareFactory } from '../../types'; + +const generator = new EndpointDocGenerator('policy-list'); + +/** + * It sets the mock implementation on the necessary http methods to support the policy list view + * @param mockedHttpService + * @param responseItems + */ +export const setPolicyListApiMockImplementation = ( + mockedHttpService: jest.Mocked, + responseItems: GetDatasourcesResponse['items'] = [generator.generatePolicyDatasource()] +): void => { + mockedHttpService.get.mockImplementation((...args) => { + const [path] = args; + if (typeof path === 'string') { + if (path === INGEST_API_DATASOURCES) { + return Promise.resolve({ + items: responseItems, + total: 10, + page: 1, + perPage: 10, + success: true, + }); + } + } + return Promise.reject(new Error(`MOCK: unknown policy list api: ${path}`)); + }); +}; + +/** + * Utilities for testing Redux middleware + */ +export interface MiddlewareActionSpyHelper { + /** + * Returns a promise that is fulfilled when the given action is dispatched or a timeout occurs. + * The use of this method instead of a `sleep()` type of delay should avoid test case instability + * especially when run in a CI environment. + * + * @param actionType + */ + waitForAction: (actionType: AppAction['type']) => Promise; + /** + * A property holding the information around the calls that were processed by the internal + * `actionSpyMiddlware`. This property holds the information typically found in Jets's mocked + * function `mock` property - [see here for more information](https://jestjs.io/docs/en/mock-functions#mock-property) + * + * **Note**: this property will only be set **after* the `actionSpyMiddlware` has been + * initialized (ex. via `createStore()`. Attempting to reference this property before that time + * will throw an error. + * Also - do not hold on to references to this property value if `jest.clearAllMocks()` or + * `jest.resetAllMocks()` is called between usages of the value. + */ + dispatchSpy: jest.Mock>['mock']; + /** + * Redux middleware that enables spying on the action that are dispatched through the store + */ + actionSpyMiddleware: ReturnType>; +} + +/** + * Creates a new instance of middleware action helpers + * Note: in most cases (testing concern specific middleware) this function should be given + * the state type definition, else, the global state will be used. + * + * @example + * // Use in Policy List middleware testing + * const middlewareSpyUtils = createSpyMiddleware(); + * store = createStore( + * policyListReducer, + * applyMiddleware( + * policyListMiddlewareFactory(fakeCoreStart, depsStart), + * middlewareSpyUtils.actionSpyMiddleware + * ) + * ); + * // Reference `dispatchSpy` ONLY after creating the store that includes `actionSpyMiddleware` + * const { waitForAction, dispatchSpy } = middlewareSpyUtils; + * // + * // later in test + * // + * it('...', async () => { + * //... + * await waitForAction('serverReturnedPolicyListData'); + * // do assertions + * // or check how action was called + * expect(dispatchSpy.calls.length).toBe(2) + * }); + */ +export const createSpyMiddleware = (): MiddlewareActionSpyHelper => { + type ActionWatcher = (action: AppAction) => void; + + const watchers = new Set(); + let spyDispatch: jest.Mock>; + + return { + waitForAction: async (actionType: string) => { + // Error is defined here so that we get a better stack trace that points to the test from where it was used + const err = new Error(`action '${actionType}' was not dispatched within the allocated time`); + + await new Promise((resolve, reject) => { + const watch: ActionWatcher = action => { + if (action.type === actionType) { + watchers.delete(watch); + clearTimeout(timeout); + resolve(); + } + }; + + // We timeout before jest's default 5s, so that a better error stack is returned + const timeout = setTimeout(() => { + watchers.delete(watch); + reject(err); + }, 4500); + watchers.add(watch); + }); + }, + + get dispatchSpy() { + if (!spyDispatch) { + throw new Error( + 'Spy Middleware has not been initialized. Access this property only after using `actionSpyMiddleware` in a redux store' + ); + } + return spyDispatch.mock; + }, + + actionSpyMiddleware: api => { + return next => { + spyDispatch = jest.fn(action => { + next(action); + // loop through the list of watcher (if any) and call them with this action + for (const watch of watchers) { + watch(action); + } + return action; + }); + return spyDispatch; + }; + }, + }; +}; diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/routing/action.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/routing/action.ts index f22272bc68233..fd72a02b33588 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/store/routing/action.ts +++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/routing/action.ts @@ -5,21 +5,11 @@ */ import { Immutable } from '../../../../../common/types'; -import { EndpointAppLocation, PageId } from '../../types'; - -interface UserNavigatedToPage { - readonly type: 'userNavigatedToPage'; - readonly payload: PageId; -} - -interface UserNavigatedFromPage { - readonly type: 'userNavigatedFromPage'; - readonly payload: PageId; -} +import { EndpointAppLocation } from '../../types'; interface UserChangedUrl { readonly type: 'userChangedUrl'; readonly payload: Immutable; } -export type RoutingAction = UserNavigatedToPage | UserNavigatedFromPage | UserChangedUrl; +export type RoutingAction = UserChangedUrl; diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/types.ts b/x-pack/plugins/endpoint/public/applications/endpoint/types.ts index f9ad8f6708f6b..a625c49bf7d5a 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/types.ts +++ b/x-pack/plugins/endpoint/public/applications/endpoint/types.ts @@ -95,6 +95,8 @@ export interface PolicyListState { pageIndex: number; /** data is being retrieved from server */ isLoading: boolean; + /** current location information */ + location?: Immutable; } /** @@ -117,6 +119,14 @@ export interface PolicyDetailsState { }; } +/** + * The URL search params that are supported by the Policy List page view + */ +export interface PolicyListUrlSearchParams { + page_index: number; + page_size: number; +} + /** * Endpoint Policy configuration */ diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_list.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_list.tsx index 06ba74aa46732..295312fff01dd 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_list.tsx +++ b/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_list.tsx @@ -9,8 +9,7 @@ import { EuiBasicTable, EuiText, EuiTableFieldDataColumnType, EuiLink } from '@e import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { useDispatch } from 'react-redux'; -import { useHistory } from 'react-router-dom'; -import { usePageId } from '../use_page_id'; +import { useHistory, useLocation } from 'react-router-dom'; import { selectApiError, selectIsLoading, @@ -50,9 +49,9 @@ const renderPolicyNameLink = (value: string, _item: PolicyData) => { }; export const PolicyList = React.memo(() => { - usePageId('policyListPage'); - const { services, notifications } = useKibana(); + const history = useHistory(); + const location = useLocation(); const dispatch = useDispatch<(action: PolicyListAction) => void>(); const policyItems = usePolicyListSelector(selectPolicyItems); @@ -84,15 +83,9 @@ export const PolicyList = React.memo(() => { const handleTableChange = useCallback( ({ page: { index, size } }: TableChangeCallbackArguments) => { - dispatch({ - type: 'userPaginatedPolicyListTable', - payload: { - pageIndex: index, - pageSize: size, - }, - }); + history.push(`${location.pathname}?page_index=${index}&page_size=${size}`); }, - [dispatch] + [history, location.pathname] ); const columns: Array> = useMemo( diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/view/use_page_id.ts b/x-pack/plugins/endpoint/public/applications/endpoint/view/use_page_id.ts deleted file mode 100644 index 85ed8a39fb386..0000000000000 --- a/x-pack/plugins/endpoint/public/applications/endpoint/view/use_page_id.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { useEffect } from 'react'; -import { useDispatch } from 'react-redux'; -import { RoutingAction } from '../store/routing'; -import { PageId } from '../types'; - -/** - * Dispatches a 'userNavigatedToPage' action with the given 'pageId' as the action payload. - * When the component is un-mounted, a `userNavigatedFromPage` action will be dispatched - * with the given `pageId`. - * - * @param pageId A page id - */ -export function usePageId(pageId: PageId) { - const dispatch: (action: RoutingAction) => unknown = useDispatch(); - useEffect(() => { - dispatch({ type: 'userNavigatedToPage', payload: pageId }); - - return () => { - dispatch({ type: 'userNavigatedFromPage', payload: pageId }); - }; - }, [dispatch, pageId]); -} diff --git a/x-pack/plugins/endpoint/scripts/alert_mapping.json b/x-pack/plugins/endpoint/scripts/alert_mapping.json index a21e48b4bc95f..2e0041d0af986 100644 --- a/x-pack/plugins/endpoint/scripts/alert_mapping.json +++ b/x-pack/plugins/endpoint/scripts/alert_mapping.json @@ -394,7 +394,8 @@ "type": "nested" }, "file_extension": { - "type": "long" + "ignore_above": 1024, + "type": "keyword" }, "project_file": { "properties": { diff --git a/x-pack/plugins/endpoint/scripts/event_mapping.json b/x-pack/plugins/endpoint/scripts/event_mapping.json index 59d1ed17852b1..f410edc7abe5e 100644 --- a/x-pack/plugins/endpoint/scripts/event_mapping.json +++ b/x-pack/plugins/endpoint/scripts/event_mapping.json @@ -386,7 +386,8 @@ "type": "nested" }, "file_extension": { - "type": "long" + "ignore_above": 1024, + "type": "keyword" }, "project_file": { "properties": { diff --git a/x-pack/plugins/maps/common/constants.ts b/x-pack/plugins/maps/common/constants.ts index f3997f741a1bf..1468bf7fdc1f2 100644 --- a/x-pack/plugins/maps/common/constants.ts +++ b/x-pack/plugins/maps/common/constants.ts @@ -56,15 +56,18 @@ export enum SORT_ORDER { DESC = 'desc', } -export const EMS_TMS = 'EMS_TMS'; -export const EMS_FILE = 'EMS_FILE'; -export const ES_GEO_GRID = 'ES_GEO_GRID'; -export const ES_SEARCH = 'ES_SEARCH'; -export const ES_PEW_PEW = 'ES_PEW_PEW'; -export const EMS_XYZ = 'EMS_XYZ'; // identifies a custom TMS source. Name is a little unfortunate. -export const WMS = 'WMS'; -export const KIBANA_TILEMAP = 'KIBANA_TILEMAP'; -export const REGIONMAP_FILE = 'REGIONMAP_FILE'; +export enum SOURCE_TYPES { + EMS_TMS = 'EMS_TMS', + EMS_FILE = 'EMS_FILE', + ES_GEO_GRID = 'ES_GEO_GRID', + ES_SEARCH = 'ES_SEARCH', + ES_PEW_PEW = 'ES_PEW_PEW', + EMS_XYZ = 'EMS_XYZ', // identifies a custom TMS source. Name is a little unfortunate. + WMS = 'WMS', + KIBANA_TILEMAP = 'KIBANA_TILEMAP', + REGIONMAP_FILE = 'REGIONMAP_FILE', + GEOJSON_FILE = 'GEOJSON_FILE', +} export enum FIELD_ORIGIN { SOURCE = 'source', @@ -77,8 +80,6 @@ export const SOURCE_META_ID_ORIGIN = `${SOURCE_DATA_ID_ORIGIN}_${META_ID_ORIGIN_ export const FORMATTERS_ID_ORIGIN_SUFFIX = 'formatters'; export const SOURCE_FORMATTERS_ID_ORIGIN = `${SOURCE_DATA_ID_ORIGIN}_${FORMATTERS_ID_ORIGIN_SUFFIX}`; -export const GEOJSON_FILE = 'GEOJSON_FILE'; - export const MIN_ZOOM = 0; export const MAX_ZOOM = 24; diff --git a/x-pack/plugins/maps/public/elasticsearch_geo_utils.js b/x-pack/plugins/maps/public/elasticsearch_geo_utils.js index 79467e26ec3fa..617cf537fd5c3 100644 --- a/x-pack/plugins/maps/public/elasticsearch_geo_utils.js +++ b/x-pack/plugins/maps/public/elasticsearch_geo_utils.js @@ -231,28 +231,16 @@ function createGeoBoundBoxFilter(geometry, geoFieldName, filterProps = {}) { }; } -function createGeoPolygonFilter(polygonCoordinates, geoFieldName, filterProps = {}) { - return { - geo_polygon: { - ignore_unmapped: true, - [geoFieldName]: { - points: polygonCoordinates[POLYGON_COORDINATES_EXTERIOR_INDEX].map(coordinatePair => { - return { - lon: coordinatePair[LON_INDEX], - lat: coordinatePair[LAT_INDEX], - }; - }), - }, - }, - ...filterProps, - }; -} - export function createExtentFilter(mapExtent, geoFieldName, geoFieldType) { ensureGeoField(geoFieldType); const safePolygon = convertMapExtentToPolygon(mapExtent); + // Extent filters are used to dynamically filter data for the current map view port. + // Continue to use geo_bounding_box queries for extent filters + // 1) geo_bounding_box queries are faster than polygon queries + // 2) geo_shape benefits of pre-indexed shapes and + // compatability across multi-indices with geo_point and geo_shape do not apply to this use case. if (geoFieldType === ES_GEO_FIELD_TYPE.GEO_POINT) { return createGeoBoundBoxFilter(safePolygon, geoFieldName); } @@ -267,15 +255,7 @@ export function createExtentFilter(mapExtent, geoFieldName, geoFieldType) { }; } -export function createSpatialFilterWithBoundingBox(options) { - return createGeometryFilterWithMeta({ ...options, isBoundingBox: true }); -} - -export function createSpatialFilterWithGeometry(options) { - return createGeometryFilterWithMeta(options); -} - -function createGeometryFilterWithMeta({ +export function createSpatialFilterWithGeometry({ preIndexedShape, geometry, geometryLabel, @@ -283,16 +263,16 @@ function createGeometryFilterWithMeta({ geoFieldName, geoFieldType, relation = ES_SPATIAL_RELATIONS.INTERSECTS, - isBoundingBox = false, }) { ensureGeoField(geoFieldType); - const relationLabel = - geoFieldType === ES_GEO_FIELD_TYPE.GEO_POINT - ? i18n.translate('xpack.maps.es_geo_utils.shapeFilter.geoPointRelationLabel', { - defaultMessage: 'in', - }) - : getEsSpatialRelationLabel(relation); + const isGeoPoint = geoFieldType === ES_GEO_FIELD_TYPE.GEO_POINT; + + const relationLabel = isGeoPoint + ? i18n.translate('xpack.maps.es_geo_utils.shapeFilter.geoPointRelationLabel', { + defaultMessage: 'in', + }) + : getEsSpatialRelationLabel(relation); const meta = { type: SPATIAL_FILTER_TYPE, negate: false, @@ -301,47 +281,24 @@ function createGeometryFilterWithMeta({ alias: `${geoFieldName} ${relationLabel} ${geometryLabel}`, }; - if (geoFieldType === ES_GEO_FIELD_TYPE.GEO_SHAPE) { - const shapeQuery = { - relation, - }; - - if (preIndexedShape) { - shapeQuery.indexed_shape = preIndexedShape; - } else { - shapeQuery.shape = geometry; - } - - return { - meta, - geo_shape: { - ignore_unmapped: true, - [geoFieldName]: shapeQuery, - }, - }; - } - - // geo_points supports limited geometry types - ensureGeometryType(geometry.type, [GEO_JSON_TYPE.POLYGON, GEO_JSON_TYPE.MULTI_POLYGON]); - - if (geometry.type === GEO_JSON_TYPE.MULTI_POLYGON) { - return { - meta, - query: { - bool: { - should: geometry.coordinates.map(polygonCoordinates => { - return createGeoPolygonFilter(polygonCoordinates, geoFieldName); - }), - }, - }, - }; - } + const shapeQuery = { + // geo_shape query with geo_point field only supports intersects relation + relation: isGeoPoint ? ES_SPATIAL_RELATIONS.INTERSECTS : relation, + }; - if (isBoundingBox) { - return createGeoBoundBoxFilter(geometry, geoFieldName, { meta }); + if (preIndexedShape) { + shapeQuery.indexed_shape = preIndexedShape; + } else { + shapeQuery.shape = geometry; } - return createGeoPolygonFilter(geometry.coordinates, geoFieldName, { meta }); + return { + meta, + geo_shape: { + ignore_unmapped: true, + [geoFieldName]: shapeQuery, + }, + }; } export function createDistanceFilterWithMeta({ diff --git a/x-pack/plugins/maps/public/layers/blended_vector_layer.ts b/x-pack/plugins/maps/public/layers/blended_vector_layer.ts index 80bf0299380d9..9a9ea2968ceeb 100644 --- a/x-pack/plugins/maps/public/layers/blended_vector_layer.ts +++ b/x-pack/plugins/maps/public/layers/blended_vector_layer.ts @@ -11,9 +11,9 @@ import { getDefaultDynamicProperties } from './styles/vector/vector_style_defaul import { IDynamicStyleProperty } from './styles/vector/properties/dynamic_style_property'; import { IStyleProperty } from './styles/vector/properties/style_property'; import { + SOURCE_TYPES, COUNT_PROP_LABEL, COUNT_PROP_NAME, - ES_GEO_GRID, LAYER_TYPE, AGG_TYPE, RENDER_AS, @@ -180,7 +180,11 @@ export class BlendedVectorLayer extends VectorLayer implements IVectorLayer { const sourceDataRequest = this.getSourceDataRequest(); if (sourceDataRequest) { const requestMeta = sourceDataRequest.getMeta(); - if (requestMeta && requestMeta.sourceType && requestMeta.sourceType === ES_GEO_GRID) { + if ( + requestMeta && + requestMeta.sourceType && + requestMeta.sourceType === SOURCE_TYPES.ES_GEO_GRID + ) { isClustered = true; } } diff --git a/x-pack/plugins/maps/public/layers/sources/client_file_source/geojson_file_source.js b/x-pack/plugins/maps/public/layers/sources/client_file_source/geojson_file_source.js index df11fe9f32770..137513ad7c612 100644 --- a/x-pack/plugins/maps/public/layers/sources/client_file_source/geojson_file_source.js +++ b/x-pack/plugins/maps/public/layers/sources/client_file_source/geojson_file_source.js @@ -8,7 +8,7 @@ import { AbstractVectorSource } from '../vector_source'; import React from 'react'; import { ES_GEO_FIELD_TYPE, - GEOJSON_FILE, + SOURCE_TYPES, DEFAULT_MAX_RESULT_WINDOW, SCALING_TYPES, } from '../../../../common/constants'; @@ -19,7 +19,7 @@ import { i18n } from '@kbn/i18n'; import { registerSource } from '../source_registry'; export class GeojsonFileSource extends AbstractVectorSource { - static type = GEOJSON_FILE; + static type = SOURCE_TYPES.GEOJSON_FILE; static isIndexingSource = true; @@ -130,7 +130,7 @@ const previewGeojsonFile = (onPreviewSource, inspectorAdapters) => { registerSource({ ConstructorFunction: GeojsonFileSource, - type: GEOJSON_FILE, + type: SOURCE_TYPES.GEOJSON_FILE, }); export const uploadLayerWizardConfig = { diff --git a/x-pack/plugins/maps/public/layers/sources/ems_file_source/ems_file_source.js b/x-pack/plugins/maps/public/layers/sources/ems_file_source/ems_file_source.js index d3ccc0cb55821..e8af17b911939 100644 --- a/x-pack/plugins/maps/public/layers/sources/ems_file_source/ems_file_source.js +++ b/x-pack/plugins/maps/public/layers/sources/ems_file_source/ems_file_source.js @@ -7,7 +7,7 @@ import { AbstractVectorSource } from '../vector_source'; import { VECTOR_SHAPE_TYPES } from '../vector_feature_types'; import React from 'react'; -import { EMS_FILE, FIELD_ORIGIN } from '../../../../common/constants'; +import { SOURCE_TYPES, FIELD_ORIGIN } from '../../../../common/constants'; import { getEMSClient } from '../../../meta'; import { EMSFileCreateSourceEditor } from './create_source_editor'; import { i18n } from '@kbn/i18n'; @@ -21,7 +21,7 @@ const sourceTitle = i18n.translate('xpack.maps.source.emsFileTitle', { }); export class EMSFileSource extends AbstractVectorSource { - static type = EMS_FILE; + static type = SOURCE_TYPES.EMS_FILE; static createDescriptor({ id, tooltipProperties = [] }) { return { @@ -159,7 +159,7 @@ export class EMSFileSource extends AbstractVectorSource { registerSource({ ConstructorFunction: EMSFileSource, - type: EMS_FILE, + type: SOURCE_TYPES.EMS_FILE, }); export const emsBoundariesLayerWizardConfig = { diff --git a/x-pack/plugins/maps/public/layers/sources/ems_tms_source/ems_tms_source.js b/x-pack/plugins/maps/public/layers/sources/ems_tms_source/ems_tms_source.js index 1da3680dfdc86..79121c4cdb31f 100644 --- a/x-pack/plugins/maps/public/layers/sources/ems_tms_source/ems_tms_source.js +++ b/x-pack/plugins/maps/public/layers/sources/ems_tms_source/ems_tms_source.js @@ -14,7 +14,7 @@ import { TileServiceSelect } from './tile_service_select'; import { UpdateSourceEditor } from './update_source_editor'; import { i18n } from '@kbn/i18n'; import { getDataSourceLabel } from '../../../../common/i18n_getters'; -import { EMS_TMS } from '../../../../common/constants'; +import { SOURCE_TYPES } from '../../../../common/constants'; import { getInjectedVarFunc, getUiSettings } from '../../../kibana_services'; import { registerSource } from '../source_registry'; @@ -23,7 +23,7 @@ const sourceTitle = i18n.translate('xpack.maps.source.emsTileTitle', { }); export class EMSTMSSource extends AbstractTMSSource { - static type = EMS_TMS; + static type = SOURCE_TYPES.EMS_TMS; static createDescriptor(sourceConfig) { return { @@ -148,7 +148,7 @@ export class EMSTMSSource extends AbstractTMSSource { registerSource({ ConstructorFunction: EMSTMSSource, - type: EMS_TMS, + type: SOURCE_TYPES.EMS_TMS, }); export const emsBaseMapLayerWizardConfig = { diff --git a/x-pack/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.js b/x-pack/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.js index 04f944396ab35..b9ef13e520bf8 100644 --- a/x-pack/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.js +++ b/x-pack/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.js @@ -17,8 +17,8 @@ import { COLOR_GRADIENTS } from '../../styles/color_utils'; import { CreateSourceEditor } from './create_source_editor'; import { UpdateSourceEditor } from './update_source_editor'; import { + SOURCE_TYPES, DEFAULT_MAX_BUCKETS_LIMIT, - ES_GEO_GRID, COUNT_PROP_NAME, COLOR_MAP_TYPE, RENDER_AS, @@ -45,7 +45,7 @@ const heatmapTitle = i18n.translate('xpack.maps.source.esGridHeatmapTitle', { }); export class ESGeoGridSource extends AbstractESAggSource { - static type = ES_GEO_GRID; + static type = SOURCE_TYPES.ES_GEO_GRID; static createDescriptor({ indexPatternId, geoField, requestType, resolution }) { return { @@ -311,7 +311,7 @@ export class ESGeoGridSource extends AbstractESAggSource { }, meta: { areResultsTrimmed: false, - sourceType: ES_GEO_GRID, + sourceType: SOURCE_TYPES.ES_GEO_GRID, }, }; } @@ -420,7 +420,7 @@ export class ESGeoGridSource extends AbstractESAggSource { registerSource({ ConstructorFunction: ESGeoGridSource, - type: ES_GEO_GRID, + type: SOURCE_TYPES.ES_GEO_GRID, }); export const clustersLayerWizardConfig = { diff --git a/x-pack/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.test.ts b/x-pack/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.test.ts index 727435c3cbfef..e35bb998ce7db 100644 --- a/x-pack/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.test.ts +++ b/x-pack/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.test.ts @@ -7,7 +7,7 @@ jest.mock('../../../kibana_services', () => {}); jest.mock('ui/new_platform'); import { ESGeoGridSource } from './es_geo_grid_source'; -import { ES_GEO_GRID, GRID_RESOLUTION, RENDER_AS } from '../../../../common/constants'; +import { GRID_RESOLUTION, RENDER_AS, SOURCE_TYPES } from '../../../../common/constants'; describe('ESGeoGridSource', () => { const geogridSource = new ESGeoGridSource( @@ -17,7 +17,7 @@ describe('ESGeoGridSource', () => { geoField: 'bar', metrics: [], resolution: GRID_RESOLUTION.COARSE, - type: ES_GEO_GRID, + type: SOURCE_TYPES.ES_GEO_GRID, requestType: RENDER_AS.HEATMAP, }, {} diff --git a/x-pack/plugins/maps/public/layers/sources/es_pew_pew_source/es_pew_pew_source.js b/x-pack/plugins/maps/public/layers/sources/es_pew_pew_source/es_pew_pew_source.js index ea3a2d2fe634d..57e5afb99404b 100644 --- a/x-pack/plugins/maps/public/layers/sources/es_pew_pew_source/es_pew_pew_source.js +++ b/x-pack/plugins/maps/public/layers/sources/es_pew_pew_source/es_pew_pew_source.js @@ -16,7 +16,7 @@ import { getDefaultDynamicProperties } from '../../styles/vector/vector_style_de import { i18n } from '@kbn/i18n'; import { FIELD_ORIGIN, - ES_PEW_PEW, + SOURCE_TYPES, COUNT_PROP_NAME, VECTOR_STYLES, } from '../../../../common/constants'; @@ -35,7 +35,7 @@ const sourceTitle = i18n.translate('xpack.maps.source.pewPewTitle', { }); export class ESPewPewSource extends AbstractESAggSource { - static type = ES_PEW_PEW; + static type = SOURCE_TYPES.ES_PEW_PEW; static createDescriptor({ indexPatternId, sourceGeoField, destGeoField }) { return { @@ -232,7 +232,7 @@ export class ESPewPewSource extends AbstractESAggSource { registerSource({ ConstructorFunction: ESPewPewSource, - type: ES_PEW_PEW, + type: SOURCE_TYPES.ES_PEW_PEW, }); export const point2PointLayerWizardConfig = { diff --git a/x-pack/plugins/maps/public/layers/sources/es_search_source/es_search_source.js b/x-pack/plugins/maps/public/layers/sources/es_search_source/es_search_source.js index ce9932bd15cea..96679f0e85941 100644 --- a/x-pack/plugins/maps/public/layers/sources/es_search_source/es_search_source.js +++ b/x-pack/plugins/maps/public/layers/sources/es_search_source/es_search_source.js @@ -17,7 +17,7 @@ import { hitsToGeoJson } from '../../../elasticsearch_geo_utils'; import { CreateSourceEditor } from './create_source_editor'; import { UpdateSourceEditor } from './update_source_editor'; import { - ES_SEARCH, + SOURCE_TYPES, ES_GEO_FIELD_TYPE, DEFAULT_MAX_BUCKETS_LIMIT, SORT_ORDER, @@ -69,7 +69,7 @@ function getDocValueAndSourceFields(indexPattern, fieldNames) { } export class ESSearchSource extends AbstractESSource { - static type = ES_SEARCH; + static type = SOURCE_TYPES.ES_SEARCH; constructor(descriptor, inspectorAdapters) { super( @@ -404,7 +404,7 @@ export class ESSearchSource extends AbstractESSource { return { data: featureCollection, - meta: { ...meta, sourceType: ES_SEARCH }, + meta: { ...meta, sourceType: SOURCE_TYPES.ES_SEARCH }, }; } @@ -570,7 +570,7 @@ export class ESSearchSource extends AbstractESSource { registerSource({ ConstructorFunction: ESSearchSource, - type: ES_SEARCH, + type: SOURCE_TYPES.ES_SEARCH, }); export const esDocumentsLayerWizardConfig = { diff --git a/x-pack/plugins/maps/public/layers/sources/es_search_source/es_search_source.test.ts b/x-pack/plugins/maps/public/layers/sources/es_search_source/es_search_source.test.ts index 2197e24aedb59..66cc2ddd85404 100644 --- a/x-pack/plugins/maps/public/layers/sources/es_search_source/es_search_source.test.ts +++ b/x-pack/plugins/maps/public/layers/sources/es_search_source/es_search_source.test.ts @@ -8,11 +8,11 @@ jest.mock('../../../kibana_services'); import { ESSearchSource } from './es_search_source'; import { VectorLayer } from '../../vector_layer'; -import { ES_SEARCH, SCALING_TYPES } from '../../../../common/constants'; +import { SCALING_TYPES, SOURCE_TYPES } from '../../../../common/constants'; import { ESSearchSourceDescriptor } from '../../../../common/descriptor_types'; const descriptor: ESSearchSourceDescriptor = { - type: ES_SEARCH, + type: SOURCE_TYPES.ES_SEARCH, id: '1234', indexPatternId: 'myIndexPattern', geoField: 'myLocation', diff --git a/x-pack/plugins/maps/public/layers/sources/kibana_regionmap_source/kibana_regionmap_source.js b/x-pack/plugins/maps/public/layers/sources/kibana_regionmap_source/kibana_regionmap_source.js index 7f4bcfa41f7c4..be333f8ee85a4 100644 --- a/x-pack/plugins/maps/public/layers/sources/kibana_regionmap_source/kibana_regionmap_source.js +++ b/x-pack/plugins/maps/public/layers/sources/kibana_regionmap_source/kibana_regionmap_source.js @@ -10,7 +10,7 @@ import { CreateSourceEditor } from './create_source_editor'; import { getKibanaRegionList } from '../../../meta'; import { i18n } from '@kbn/i18n'; import { getDataSourceLabel } from '../../../../common/i18n_getters'; -import { FIELD_ORIGIN, REGIONMAP_FILE } from '../../../../common/constants'; +import { FIELD_ORIGIN, SOURCE_TYPES } from '../../../../common/constants'; import { KibanaRegionField } from '../../fields/kibana_region_field'; import { registerSource } from '../source_registry'; @@ -19,7 +19,7 @@ const sourceTitle = i18n.translate('xpack.maps.source.kbnRegionMapTitle', { }); export class KibanaRegionmapSource extends AbstractVectorSource { - static type = REGIONMAP_FILE; + static type = SOURCE_TYPES.REGIONMAP_FILE; static createDescriptor({ name }) { return { @@ -99,7 +99,7 @@ export class KibanaRegionmapSource extends AbstractVectorSource { registerSource({ ConstructorFunction: KibanaRegionmapSource, - type: REGIONMAP_FILE, + type: SOURCE_TYPES.REGIONMAP_FILE, }); export const kibanaRegionMapLayerWizardConfig = { diff --git a/x-pack/plugins/maps/public/layers/sources/kibana_tilemap_source/kibana_tilemap_source.js b/x-pack/plugins/maps/public/layers/sources/kibana_tilemap_source/kibana_tilemap_source.js index b21bb6bdbbad4..bbb653eff32e2 100644 --- a/x-pack/plugins/maps/public/layers/sources/kibana_tilemap_source/kibana_tilemap_source.js +++ b/x-pack/plugins/maps/public/layers/sources/kibana_tilemap_source/kibana_tilemap_source.js @@ -11,7 +11,7 @@ import { getKibanaTileMap } from '../../../meta'; import { i18n } from '@kbn/i18n'; import { getDataSourceLabel } from '../../../../common/i18n_getters'; import _ from 'lodash'; -import { KIBANA_TILEMAP } from '../../../../common/constants'; +import { SOURCE_TYPES } from '../../../../common/constants'; import { registerSource } from '../source_registry'; const sourceTitle = i18n.translate('xpack.maps.source.kbnTMSTitle', { @@ -19,7 +19,7 @@ const sourceTitle = i18n.translate('xpack.maps.source.kbnTMSTitle', { }); export class KibanaTilemapSource extends AbstractTMSSource { - static type = KIBANA_TILEMAP; + static type = SOURCE_TYPES.KIBANA_TILEMAP; static createDescriptor() { return { @@ -86,7 +86,7 @@ export class KibanaTilemapSource extends AbstractTMSSource { registerSource({ ConstructorFunction: KibanaTilemapSource, - type: KIBANA_TILEMAP, + type: SOURCE_TYPES.KIBANA_TILEMAP, }); export const kibanaBasemapLayerWizardConfig = { diff --git a/x-pack/plugins/maps/public/layers/sources/wms_source/wms_source.js b/x-pack/plugins/maps/public/layers/sources/wms_source/wms_source.js index 749560a2bb4b1..33f764784124e 100644 --- a/x-pack/plugins/maps/public/layers/sources/wms_source/wms_source.js +++ b/x-pack/plugins/maps/public/layers/sources/wms_source/wms_source.js @@ -12,7 +12,7 @@ import { WMSCreateSourceEditor } from './wms_create_source_editor'; import { i18n } from '@kbn/i18n'; import { getDataSourceLabel, getUrlLabel } from '../../../../common/i18n_getters'; import { WmsClient } from './wms_client'; -import { WMS } from '../../../../common/constants'; +import { SOURCE_TYPES } from '../../../../common/constants'; import { registerSource } from '../source_registry'; const sourceTitle = i18n.translate('xpack.maps.source.wmsTitle', { @@ -20,7 +20,7 @@ const sourceTitle = i18n.translate('xpack.maps.source.wmsTitle', { }); export class WMSSource extends AbstractTMSSource { - static type = WMS; + static type = SOURCE_TYPES.WMS; static createDescriptor({ serviceUrl, layers, styles, attributionText, attributionUrl }) { return { @@ -92,7 +92,7 @@ export class WMSSource extends AbstractTMSSource { registerSource({ ConstructorFunction: WMSSource, - type: WMS, + type: SOURCE_TYPES.WMS, }); export const wmsLayerWizardConfig = { diff --git a/x-pack/plugins/maps/public/layers/sources/xyz_tms_source/xyz_tms_source.test.ts b/x-pack/plugins/maps/public/layers/sources/xyz_tms_source/xyz_tms_source.test.ts index 8a5cfb01e5821..4031a18bff7cb 100644 --- a/x-pack/plugins/maps/public/layers/sources/xyz_tms_source/xyz_tms_source.test.ts +++ b/x-pack/plugins/maps/public/layers/sources/xyz_tms_source/xyz_tms_source.test.ts @@ -7,11 +7,11 @@ import { XYZTMSSource } from './xyz_tms_source'; import { ILayer } from '../../layer'; import { TileLayer } from '../../tile_layer'; -import { EMS_XYZ } from '../../../../common/constants'; +import { SOURCE_TYPES } from '../../../../common/constants'; import { XYZTMSSourceDescriptor } from '../../../../common/descriptor_types'; const descriptor: XYZTMSSourceDescriptor = { - type: EMS_XYZ, + type: SOURCE_TYPES.EMS_XYZ, urlTemplate: 'https://example.com/{x}/{y}/{z}.png', id: 'foobar', }; diff --git a/x-pack/plugins/maps/public/layers/sources/xyz_tms_source/xyz_tms_source.ts b/x-pack/plugins/maps/public/layers/sources/xyz_tms_source/xyz_tms_source.ts index dd96c31573316..8b64480f92961 100644 --- a/x-pack/plugins/maps/public/layers/sources/xyz_tms_source/xyz_tms_source.ts +++ b/x-pack/plugins/maps/public/layers/sources/xyz_tms_source/xyz_tms_source.ts @@ -7,7 +7,7 @@ import { i18n } from '@kbn/i18n'; import { TileLayer } from '../../tile_layer'; import { getDataSourceLabel, getUrlLabel } from '../../../../common/i18n_getters'; -import { EMS_XYZ } from '../../../../common/constants'; +import { SOURCE_TYPES } from '../../../../common/constants'; import { registerSource } from '../source_registry'; import { AbstractTMSSource } from '../tms_source'; import { LayerDescriptor, XYZTMSSourceDescriptor } from '../../../../common/descriptor_types'; @@ -19,7 +19,7 @@ export const sourceTitle = i18n.translate('xpack.maps.source.ems_xyzTitle', { }); export class XYZTMSSource extends AbstractTMSSource { - static type = EMS_XYZ; + static type = SOURCE_TYPES.EMS_XYZ; readonly _descriptor: XYZTMSSourceDescriptor; @@ -83,5 +83,5 @@ export class XYZTMSSource extends AbstractTMSSource { registerSource({ ConstructorFunction: XYZTMSSource, - type: EMS_XYZ, + type: SOURCE_TYPES.EMS_XYZ, }); diff --git a/x-pack/plugins/maps/public/layers/tile_layer.test.ts b/x-pack/plugins/maps/public/layers/tile_layer.test.ts index 43465eac7f3ce..f8c2fd9db60fa 100644 --- a/x-pack/plugins/maps/public/layers/tile_layer.test.ts +++ b/x-pack/plugins/maps/public/layers/tile_layer.test.ts @@ -5,13 +5,13 @@ */ import { TileLayer } from './tile_layer'; -import { EMS_XYZ } from '../../common/constants'; +import { SOURCE_TYPES } from '../../common/constants'; import { XYZTMSSourceDescriptor } from '../../common/descriptor_types'; import { ITMSSource, AbstractTMSSource } from './sources/tms_source'; import { ILayer } from './layer'; const sourceDescriptor: XYZTMSSourceDescriptor = { - type: EMS_XYZ, + type: SOURCE_TYPES.EMS_XYZ, urlTemplate: 'https://example.com/{x}/{y}/{z}.png', id: 'foobar', }; diff --git a/x-pack/plugins/maps/public/reducers/map.js b/x-pack/plugins/maps/public/reducers/map.js index 1e20df89c8fad..7e07569b44b83 100644 --- a/x-pack/plugins/maps/public/reducers/map.js +++ b/x-pack/plugins/maps/public/reducers/map.js @@ -74,7 +74,7 @@ const updateLayerInList = (state, layerId, attribute, newValue) => { return { ...state, layerList: updatedList }; }; -const updateLayerSourceDescriptorProp = (state, layerId, propName, value, newLayerType) => { +const updateLayerSourceDescriptorProp = (state, layerId, propName, value) => { const { layerList } = state; const layerIdx = getLayerIndex(layerList, layerId); const updatedLayer = { @@ -84,9 +84,6 @@ const updateLayerSourceDescriptorProp = (state, layerId, propName, value, newLay [propName]: value, }, }; - if (newLayerType) { - updatedLayer.type = newLayerType; - } const updatedList = [ ...layerList.slice(0, layerIdx), updatedLayer, @@ -261,13 +258,7 @@ export function map(state = INITIAL_STATE, action) { case UPDATE_LAYER_PROP: return updateLayerInList(state, action.id, action.propName, action.newValue); case UPDATE_SOURCE_PROP: - return updateLayerSourceDescriptorProp( - state, - action.layerId, - action.propName, - action.value, - action.newLayerType - ); + return updateLayerSourceDescriptorProp(state, action.layerId, action.propName, action.value); case SET_JOINS: const layerDescriptor = state.layerList.find( descriptor => descriptor.id === action.layer.getId() diff --git a/x-pack/plugins/task_manager/server/queries/mark_available_tasks_as_claimed.ts b/x-pack/plugins/task_manager/server/queries/mark_available_tasks_as_claimed.ts index b0d9dc61c9667..8f7cc47f936b2 100644 --- a/x-pack/plugins/task_manager/server/queries/mark_available_tasks_as_claimed.ts +++ b/x-pack/plugins/task_manager/server/queries/mark_available_tasks_as_claimed.ts @@ -11,7 +11,7 @@ import { RangeFilter, mustBeAllOf, MustCondition, - MustNotCondition, + BoolClauseWithAnyCondition, } from './query_clauses'; export const TaskWithSchedule: ExistsFilter = { @@ -54,15 +54,16 @@ export const IdleTaskWithExpiredRunAt: MustCondition = }, }; -export const InactiveTasks: MustNotCondition = { +// TODO: Fix query clauses to support this +export const InactiveTasks: BoolClauseWithAnyCondition = { bool: { must_not: [ { bool: { should: [{ term: { 'task.status': 'running' } }, { term: { 'task.status': 'claiming' } }], + must: { range: { 'task.retryAt': { gt: 'now' } } }, }, }, - { range: { 'task.retryAt': { gt: 'now' } } }, ], }, }; diff --git a/x-pack/plugins/task_manager/server/task_store.test.ts b/x-pack/plugins/task_manager/server/task_store.test.ts index 97794311fb3d2..4ecefcb7984eb 100644 --- a/x-pack/plugins/task_manager/server/task_store.test.ts +++ b/x-pack/plugins/task_manager/server/task_store.test.ts @@ -407,9 +407,9 @@ describe('TaskStore', () => { { term: { 'task.status': 'running' } }, { term: { 'task.status': 'claiming' } }, ], + must: { range: { 'task.retryAt': { gt: 'now' } } }, }, }, - { range: { 'task.retryAt': { gt: 'now' } } }, ], }, }, @@ -553,9 +553,9 @@ describe('TaskStore', () => { { term: { 'task.status': 'running' } }, { term: { 'task.status': 'claiming' } }, ], + must: { range: { 'task.retryAt': { gt: 'now' } } }, }, }, - { range: { 'task.retryAt': { gt: 'now' } } }, ], }, }, diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 3cebde793a085..a8574971426f5 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -319,8 +319,6 @@ "common.ui.stateManagement.unableToStoreHistoryInSessionErrorMessage": "セッションがいっぱいで安全に削除できるアイテムが見つからないため、Kibana は履歴アイテムを保存できません。\n\nこれは大抵新規タブに移動することで解決されますが、より大きな問題が原因である可能性もあります。このメッセージが定期的に表示される場合は、{gitHubIssuesUrl} で問題を報告してください。", "common.ui.url.replacementFailedErrorMessage": "置換に失敗、未解決の表現式: {expr}", "common.ui.url.savedObjectIsMissingNotificationMessage": "保存されたオブジェクトがありません", - "common.ui.vis.kibanaMap.leaflet.fitDataBoundsAriaLabel": "データバウンドを合わせる", - "common.ui.vis.kibanaMap.zoomWarning": "ズームレベルが最大に達しました。完全にズームインするには、Elasticsearch と Kibana の {defaultDistribution} にアップグレードしてください。{ems} でより多くのズームレベルが利用できます。または、独自のマップサーバーを構成できます。詳細は { wms } または { configSettings} をご覧ください。", "console.autocomplete.addMethodMetaText": "メソド", "console.consoleDisplayName": "コンソール", "console.consoleMenu.copyAsCurlMessage": "リクエストが URL としてコピーされました", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 1daf66117e948..df5cccf1a9b97 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -319,8 +319,6 @@ "common.ui.stateManagement.unableToStoreHistoryInSessionErrorMessage": "Kibana 无法将历史记录项存储在您的会话中,因为其已满,并且似乎没有任何可安全删除的项。\n\n通常可通过移至新的标签页来解决此问题,但这会导致更大的问题。如果您有规律地看到此消息,请在 {gitHubIssuesUrl} 提交问题。", "common.ui.url.replacementFailedErrorMessage": "替换失败,未解析的表达式:{expr}", "common.ui.url.savedObjectIsMissingNotificationMessage": "已保存对象缺失", - "common.ui.vis.kibanaMap.leaflet.fitDataBoundsAriaLabel": "适应数据边界", - "common.ui.vis.kibanaMap.zoomWarning": "已达到缩放级别最大数目。要一直放大,请升级到 Elasticsearch 和 Kibana 的 {defaultDistribution}。您可以通过 {ems} 免费使用其他缩放级别。或者,您可以配置自己的地图服务器。请前往 { wms } 或 { configSettings} 以获取详细信息。", "console.autocomplete.addMethodMetaText": "方法", "console.consoleDisplayName": "控制台", "console.consoleMenu.copyAsCurlMessage": "请求已复制为 cURL", diff --git a/x-pack/test/api_integration/config.js b/x-pack/test/api_integration/config.js index b62368bf2d608..0eac7c58044e6 100644 --- a/x-pack/test/api_integration/config.js +++ b/x-pack/test/api_integration/config.js @@ -27,6 +27,8 @@ export async function getApiIntegrationConfig({ readConfigFile }) { '--xpack.security.session.idleTimeout=3600000', // 1 hour '--optimize.enabled=false', '--xpack.endpoint.enabled=true', + '--telemetry.optIn=true', + '--xpack.endpoint.enabled=true', '--xpack.ingestManager.enabled=true', '--xpack.ingestManager.fleet.enabled=true', '--xpack.endpoint.alertResultListDefaultDateRange.from=2018-01-10T00:00:00.000Z', diff --git a/x-pack/test/functional/config.js b/x-pack/test/functional/config.js index bc9a67da731cc..f26110513a9b3 100644 --- a/x-pack/test/functional/config.js +++ b/x-pack/test/functional/config.js @@ -85,7 +85,6 @@ export default async function({ readConfigFile }) { '--stats.maximumWaitTimeForAllCollectorsInS=1', '--xpack.security.encryptionKey="wuGNaIhoMpk5sO4UBxgr3NyW1sFcLgIf"', // server restarts should not invalidate active sessions '--xpack.encryptedSavedObjects.encryptionKey="DkdXazszSCYexXqz4YktBGHCRkV6hyNK"', - '--telemetry.banner=false', '--timelion.ui.enabled=true', ], }, diff --git a/x-pack/test/functional/config_security_basic.js b/x-pack/test/functional/config_security_basic.js index 12d94e922a97c..2bb59796b5517 100644 --- a/x-pack/test/functional/config_security_basic.js +++ b/x-pack/test/functional/config_security_basic.js @@ -42,7 +42,6 @@ export default async function({ readConfigFile }) { ...kibanaCommonConfig.get('kbnTestServer.serverArgs'), '--server.uuid=5b2de169-2785-441b-ae8c-186a1936b17d', '--xpack.security.encryptionKey="wuGNaIhoMpk5sO4UBxgr3NyW1sFcLgIf"', // server restarts should not invalidate active sessions - '--telemetry.banner=false', ], }, uiSettings: {