[7.x] Migrate legacy maps service to NP & update refs (#60942) (#63407)

* Get legacy maps into basic NP plugin form. Swap out legacy services for NP

* Pull service settings from injected vars. Return new instance of service settings from setup

* Use NP service settings in vega maps. Clean up legacy shim

* Use NP maps service in region maps. Clean up shim. Add exports to NP service

* Pull zoom precision out to separate module since it's dependent on config

* Update paths to point to NP resources

* More path updates, clean up, use IServiceSettings

* Remove dependency on legacy service settings. Add tile_map dependency ng-sanitize

* More path cleanup. Use zoomPrecision provided through plugin inteface

* Move getPrecision into contract-provided function since it depends on config

* Move tests to new service location, remove vis dir

* Update test paths. Move origin const declaration into public

* Clean up, fixes

* Fix type errors. General cleaning

* Inject toast service into map when needed

* Fix typo in regionmap config

* i18n fixes

* Update jest test path

* Fix karma tests

* i18n fixes

* Type updates. Add mapsLegacy to np karma mock

* Remove html sanitizer

* Fix vega test that depends on serviceSettings

* Revise xpack license handling to use NP serviceSettings. Remove angular bindings

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
Aaron Caldwell 2020-04-14 14:04:31 -06:00 committed by GitHub
parent 029bc380cb
commit 83b1c95bbd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
70 changed files with 733 additions and 493 deletions

View file

@ -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",

View file

@ -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';

View file

@ -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,

View file

@ -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 = {

View file

@ -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<RegionMapVisParams>;
function RegionMapOptions(props: RegionMapOptionsProps) {

View file

@ -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<RegionMapPluginSetupDependencies> = {
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);

View file

@ -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<ExpressionsPublicPlugin['setup']>;
visualizations: VisualizationsSetup;
__LEGACY: LegacyDependenciesPlugin;
mapsLegacy: MapsLegacyPluginSetup;
}
/** @internal */
@ -61,10 +66,13 @@ export class RegionMapPlugin implements Plugin<Promise<void>, void> {
public async setup(
core: CoreSetup,
{ expressions, visualizations, __LEGACY }: RegionMapPluginSetupDependencies
{ expressions, visualizations, mapsLegacy, __LEGACY }: RegionMapPluginSetupDependencies
) {
const visualizationDependencies: Readonly<RegionMapVisualizationDependencies> = {
uiSettings: core.uiSettings,
regionmapsConfig: core.injectedMetadata.getInjectedVar('regionmap') as RegionMapsConfig,
serviceSettings: mapsLegacy.serviceSettings,
notificationService: core.notifications.toasts,
...(await __LEGACY.setup()),
};

View file

@ -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 {

View file

@ -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<Promise<LegacyDependenciesPluginSetup>, 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;
}

View file

@ -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 {

View file

@ -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';

View file

@ -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));

View file

@ -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;

View file

@ -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

View file

@ -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';

View file

@ -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';

View file

@ -27,6 +27,7 @@ import { plugin } from '.';
const plugins: Readonly<TileMapPluginSetupDependencies> = {
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.

View file

@ -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 {

View file

@ -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<ExpressionsPublicPlugin['setup']>;
visualizations: VisualizationsSetup;
mapsLegacy: MapsLegacyPluginSetup;
__LEGACY: LegacyDependenciesPlugin;
}
@ -55,9 +61,14 @@ export class TileMapPlugin implements Plugin<Promise<void>, void> {
public async setup(
core: CoreSetup,
{ expressions, visualizations, __LEGACY }: TileMapPluginSetupDependencies
{ expressions, visualizations, mapsLegacy, __LEGACY }: TileMapPluginSetupDependencies
) {
const { getZoomPrecision, getPrecision, serviceSettings } = mapsLegacy;
const visualizationDependencies: Readonly<TileMapVisualizationDependencies> = {
serviceSettings,
getZoomPrecision,
getPrecision,
notificationService: core.notifications.toasts,
uiSettings: core.uiSettings,
...(await __LEGACY.setup()),
};

View file

@ -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;
}

View file

@ -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 = () => ({

View file

@ -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';

View file

@ -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);

View file

@ -22,8 +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',
@ -38,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());

View file

@ -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 {

View file

@ -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

View file

@ -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,
},

View file

@ -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<VegaPluginSetupDependencies> = {
...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<VegaPluginStartDependencies> = {

View file

@ -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<DataPublicPlugin['setup']>;
};
serviceSettings: IServiceSettings;
}
/** @internal */
@ -47,7 +48,7 @@ export interface VegaPluginSetupDependencies {
visualizations: VisualizationsSetup;
data: ReturnType<DataPublicPlugin['setup']>;
visTypeVega: VisTypeVegaSetup;
__LEGACY: LegacyDependenciesPlugin;
mapsLegacy: any;
}
/** @internal */
@ -65,7 +66,7 @@ export class VegaPlugin implements Plugin<Promise<void>, 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<Promise<void>, void> {
plugins: {
data,
},
...(await __LEGACY.setup()),
serviceSettings: mapsLegacy.serviceSettings,
};
expressions.registerFunction(() => createVegaFn(visualizationDependencies));

View file

@ -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<Promise<LegacyDependenciesPluginSetup>, 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
}
}

View file

@ -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) {

View file

@ -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({

View file

@ -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);
}

View file

@ -309,6 +309,12 @@ export const npSetup = {
registerAlias: sinon.fake(),
hideTypes: sinon.fake(),
},
mapsLegacy: {
serviceSettings: sinon.fake(),
getPrecision: sinon.fake(),
getZoomPrecision: sinon.fake(),
},
},
};

View file

@ -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;
}

View file

@ -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();
});

View file

@ -0,0 +1,6 @@
{
"id": "mapsLegacy",
"version": "8.0.0",
"kibanaVersion": "kibana",
"ui": true
}

View file

@ -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;

View file

@ -17,4 +17,7 @@
* under the License.
*/
export * from './legacy_dependencies_plugin';
export const ORIGIN = {
EMS: 'elastic_maps_service',
KIBANA_YML: 'self_hosted',
};

View file

@ -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<MapsLegacyPlugin['setup']>;
export type MapsLegacyPluginStart = ReturnType<MapsLegacyPlugin['start']>;

View file

@ -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;

View file

@ -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;

View file

@ -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) {

View file

@ -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() {
<div>
<p>
<FormattedMessage
id="common.ui.vis.kibanaMap.zoomWarning"
id="maps_legacy.kibanaMap.zoomWarning"
defaultMessage="You've reached the maximum number of zoom
levels. To zoom all the way in, upgrade to the
{defaultDistribution} of Elasticsearch and Kibana. You'll get
@ -105,12 +104,12 @@ export const createZoomWarningMsg = (function() {
'data-test-subj': 'maxZoomWarning',
};
return (getZoomLevel, getMaxZoomLevel) => {
return (toastService, getZoomLevel, getMaxZoomLevel) => {
return () => {
const zoomLevel = getZoomLevel();
const maxMapZoom = getMaxZoomLevel();
if (!disableZoomMsg && zoomLevel === maxMapZoom) {
toastNotifications.addDanger(zoomToast);
toastService.addDanger(zoomToast);
}
};
};

View file

@ -0,0 +1,74 @@
/*
* 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 { getUiSettings } from '../kibana_services';
import { geohashColumns } from './decode_geo_hash';
/**
* Get the number of geohash columns (world-wide) for a given precision
* @param precision the geohash precision
* @returns {number} the number of columns
*/
const DEFAULT_PRECISION = 2;
function getMaxPrecision() {
const config = getUiSettings();
return parseInt(config.get('visualization:tileMap:maxPrecision'), 10) || 12;
}
export function getZoomPrecision() {
/**
* 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.
*/
const zoomPrecision: any = {};
const minGeohashPixels = 16;
const maxPrecision = getMaxPrecision();
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;
}
}
}
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;
}

View file

@ -44,7 +44,7 @@ export interface VectorLayer extends FileLayer {
isEMS: boolean;
}
export interface ServiceSettings {
export interface IServiceSettings {
getEMSHotLink(layer: FileLayer): Promise<string>;
getTMSServices(): Promise<TmsLayer[]>;
getFileLayers(): Promise<FileLayer[]>;

View file

@ -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();
}
}

View file

@ -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<MapsLegacyPluginSetup, MapsLegacyPluginStart> {
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) {}
}

View file

@ -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();
});
}

View file

@ -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 としてコピーされました",

View file

@ -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",