[Maps] Surface on prem EMS (#85729)

This commit is contained in:
Thomas Neirynck 2020-12-14 18:44:41 -05:00 committed by GitHub
parent 6017cb539d
commit 75ec9c1cab
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 213 additions and 88 deletions

View file

@ -31,34 +31,38 @@ export class EMSSettings {
this._getIsEnterprisePlus = getIsEnterPrisePlus;
}
_isEMSUrlSet() {
isEMSUrlSet() {
return !!this._config.emsUrl;
}
_getEMSRoot() {
getEMSRoot() {
return this._config.emsUrl!.replace(/\/$/, '');
}
isOnPrem(): boolean {
return this._isEMSUrlSet();
return this.isEMSUrlSet();
}
isIncludeElasticMapsService() {
return !!this._config.includeElasticMapsService;
}
hasOnPremLicense() {
return this._getIsEnterprisePlus();
}
isEMSEnabled(): boolean {
if (this._isEMSUrlSet()) {
if (this.isEMSUrlSet()) {
return this._getIsEnterprisePlus();
}
return this.isIncludeElasticMapsService();
}
getEMSFileApiUrl(): string {
if (this._config.emsFileApiUrl !== DEFAULT_EMS_FILE_API_URL || !this._isEMSUrlSet()) {
if (this._config.emsFileApiUrl !== DEFAULT_EMS_FILE_API_URL || !this.isEMSUrlSet()) {
return this._config.emsFileApiUrl!;
} else {
return `${this._getEMSRoot()}/file`;
return `${this.getEMSRoot()}/file`;
}
}
@ -67,25 +71,25 @@ export class EMSSettings {
}
getEMSTileApiUrl(): string {
if (this._config.emsTileApiUrl !== DEFAULT_EMS_TILE_API_URL || !this._isEMSUrlSet()) {
if (this._config.emsTileApiUrl !== DEFAULT_EMS_TILE_API_URL || !this.isEMSUrlSet()) {
return this._config.emsTileApiUrl!;
} else {
return `${this._getEMSRoot()}/tile`;
return `${this.getEMSRoot()}/tile`;
}
}
getEMSLandingPageUrl(): string {
if (this._config.emsLandingPageUrl !== DEFAULT_EMS_LANDING_PAGE_URL || !this._isEMSUrlSet()) {
if (this._config.emsLandingPageUrl !== DEFAULT_EMS_LANDING_PAGE_URL || !this.isEMSUrlSet()) {
return this._config.emsLandingPageUrl!;
} else {
return `${this._getEMSRoot()}/maps`;
return `${this.getEMSRoot()}/maps`;
}
}
getEMSFontLibraryUrl(): string {
if (this._config.emsFontLibraryUrl !== DEFAULT_EMS_FONT_LIBRARY_URL || !this._isEMSUrlSet()) {
if (this._config.emsFontLibraryUrl !== DEFAULT_EMS_FONT_LIBRARY_URL || !this.isEMSUrlSet()) {
return this._config.emsFontLibraryUrl!;
} else {
return `${this._getEMSRoot()}/tile/fonts/{fontstack}/{range}.pbf`;
return `${this.getEMSRoot()}/tile/fonts/{fontstack}/{range}.pbf`;
}
}
}

View file

@ -12,6 +12,13 @@ jest.mock('../../../kibana_services', () => {
getIndexPatternSelectComponent: () => {
return MockIndexPatternSelect;
},
getEMSSettings() {
return {
isEMSUrlSet() {
return false;
},
};
},
};
});

View file

@ -9,6 +9,13 @@ jest.mock('../../../../kibana_services', () => {
getIsDarkMode() {
return false;
},
getEMSSettings() {
return {
isEMSUrlSet() {
return false;
},
};
},
};
});

View file

@ -9,6 +9,13 @@ jest.mock('../../../../kibana_services', () => {
getIsDarkMode() {
return false;
},
getEMSSettings() {
return {
isEMSUrlSet() {
return false;
},
};
},
};
});

View file

@ -9,22 +9,38 @@ import { i18n } from '@kbn/i18n';
import { VectorLayer } from '../../layers/vector_layer/vector_layer';
import { LayerWizard, RenderWizardArguments } from '../../layers/layer_wizard_registry';
import { EMSFileCreateSourceEditor } from './create_source_editor';
import { EMSFileSource, sourceTitle } from './ems_file_source';
import { EMSFileSource, getSourceTitle } from './ems_file_source';
// @ts-ignore
import { getEMSSettings } from '../../../kibana_services';
import { EMSFileSourceDescriptor } from '../../../../common/descriptor_types';
import { LAYER_WIZARD_CATEGORY } from '../../../../common/constants';
import { EMSBoundariesLayerIcon } from '../../layers/icons/ems_boundaries_layer_icon';
function getDescription() {
const emsSettings = getEMSSettings();
return i18n.translate('xpack.maps.source.emsFileSourceDescription', {
defaultMessage: 'Administrative boundaries from {host}',
values: {
host: emsSettings.isEMSUrlSet() ? emsSettings.getEMSRoot() : 'Elastic Maps Service',
},
});
}
export const emsBoundariesLayerWizardConfig: LayerWizard = {
categories: [LAYER_WIZARD_CATEGORY.REFERENCE],
checkVisibility: async () => {
const emsSettings = getEMSSettings();
return emsSettings!.isEMSEnabled();
return emsSettings.isIncludeElasticMapsService();
},
description: i18n.translate('xpack.maps.source.emsFileDescription', {
defaultMessage: 'Administrative boundaries from Elastic Maps Service',
description: getDescription(),
disabledReason: i18n.translate('xpack.maps.source.emsFileDisabledReason', {
defaultMessage: 'Elastic Maps Server requires an Enterprise license',
}),
getIsDisabled: () => {
const emsSettings = getEMSSettings();
return emsSettings.isEMSUrlSet() && !emsSettings.hasOnPremLicense();
},
icon: EMSBoundariesLayerIcon,
renderWizard: ({ previewLayers, mapColors }: RenderWizardArguments) => {
const onSourceConfigChange = (sourceConfig: Partial<EMSFileSourceDescriptor>) => {
@ -34,5 +50,5 @@ export const emsBoundariesLayerWizardConfig: LayerWizard = {
};
return <EMSFileCreateSourceEditor onSourceConfigChange={onSourceConfigChange} />;
},
title: sourceTitle,
title: getSourceTitle(),
};

View file

@ -25,14 +25,35 @@ import { registerSource } from '../source_registry';
import { IField } from '../../fields/field';
import { EMSFileSourceDescriptor } from '../../../../common/descriptor_types';
import { ITooltipProperty } from '../../tooltips/tooltip_property';
import { getEMSSettings } from '../../../kibana_services';
import { getEmsUnavailableMessage } from '../../../components/ems_unavailable_message';
function getErrorInfo(fileId: string) {
return i18n.translate('xpack.maps.source.emsFile.unableToFindFileIdErrorMessage', {
defaultMessage: `Unable to find EMS vector shapes for id: {id}. {info}`,
values: {
id: fileId,
info: getEmsUnavailableMessage(),
},
});
}
export interface IEmsFileSource extends IVectorSource {
getEmsFieldLabel(emsFieldName: string): Promise<string>;
}
export const sourceTitle = i18n.translate('xpack.maps.source.emsFileTitle', {
defaultMessage: 'EMS Boundaries',
});
export function getSourceTitle() {
const emsSettings = getEMSSettings();
if (emsSettings.isEMSUrlSet()) {
return i18n.translate('xpack.maps.source.emsOnPremFileTitle', {
defaultMessage: 'Elastic Maps Server Boundaries',
});
} else {
return i18n.translate('xpack.maps.source.emsFileTitle', {
defaultMessage: 'EMS Boundaries',
});
}
}
export class EMSFileSource extends AbstractVectorSource implements IEmsFileSource {
static createDescriptor({ id, tooltipProperties = [] }: Partial<EMSFileSourceDescriptor>) {
@ -74,19 +95,19 @@ export class EMSFileSource extends AbstractVectorSource implements IEmsFileSourc
}
async getEMSFileLayer(): Promise<FileLayer> {
const emsFileLayers = await getEmsFileLayers();
const emsFileLayer = emsFileLayers.find((fileLayer) => fileLayer.hasId(this._descriptor.id));
if (!emsFileLayer) {
throw new Error(
i18n.translate('xpack.maps.source.emsFile.unableToFindIdErrorMessage', {
defaultMessage: `Unable to find EMS vector shapes for id: {id}`,
values: {
id: this._descriptor.id,
},
})
);
let emsFileLayers: FileLayer[];
try {
emsFileLayers = await getEmsFileLayers();
} catch (e) {
throw new Error(`${getErrorInfo(this._descriptor.id)} - ${e.message}`);
}
return emsFileLayer;
const emsFileLayer = emsFileLayers.find((fileLayer) => fileLayer.hasId(this._descriptor.id));
if (emsFileLayer) {
return emsFileLayer;
}
throw new Error(getErrorInfo(this._descriptor.id));
}
// Map EMS field name to language specific label
@ -129,10 +150,10 @@ export class EMSFileSource extends AbstractVectorSource implements IEmsFileSourc
// ignore error if EMS layer id could not be found
}
return [
const props = [
{
label: getDataSourceLabel(),
value: sourceTitle,
value: getSourceTitle(),
},
{
label: i18n.translate('xpack.maps.source.emsFile.layerLabel', {
@ -142,6 +163,17 @@ export class EMSFileSource extends AbstractVectorSource implements IEmsFileSourc
link: emsLink,
},
];
const emsSettings = getEMSSettings();
if (emsSettings.isEMSUrlSet()) {
props.push({
label: i18n.translate('xpack.maps.source.emsFile.emsOnPremLabel', {
defaultMessage: `Elastic Maps Server`,
}),
value: emsSettings.getEMSRoot(),
});
}
return props;
}
async getDisplayName(): Promise<string> {

View file

@ -8,7 +8,7 @@ import { i18n } from '@kbn/i18n';
import { EuiPanel } from '@elastic/eui';
import { LayerWizard, RenderWizardArguments } from '../../layers/layer_wizard_registry';
// @ts-ignore
import { EMSTMSSource, sourceTitle } from './ems_tms_source';
import { EMSTMSSource, getSourceTitle } from './ems_tms_source';
// @ts-ignore
import { VectorTileLayer } from '../../layers/vector_tile_layer/vector_tile_layer';
// @ts-ignore
@ -17,15 +17,30 @@ import { getEMSSettings } from '../../../kibana_services';
import { LAYER_WIZARD_CATEGORY } from '../../../../common/constants';
import { WorldMapLayerIcon } from '../../layers/icons/world_map_layer_icon';
function getDescription() {
const emsSettings = getEMSSettings();
return i18n.translate('xpack.maps.source.emsTileSourceDescription', {
defaultMessage: 'Basemap service from {host}',
values: {
host: emsSettings.isEMSUrlSet() ? emsSettings.getEMSRoot() : 'Elastic Maps Service',
},
});
}
export const emsBaseMapLayerWizardConfig: LayerWizard = {
categories: [LAYER_WIZARD_CATEGORY.REFERENCE],
checkVisibility: async () => {
const emsSettings = getEMSSettings();
return emsSettings!.isEMSEnabled();
return emsSettings.isIncludeElasticMapsService();
},
description: i18n.translate('xpack.maps.source.emsTileDescription', {
defaultMessage: 'Tile map service from Elastic Maps Service',
description: getDescription(),
disabledReason: i18n.translate('xpack.maps.source.emsTileDisabledReason', {
defaultMessage: 'Elastic Maps Server requires an Enterprise license',
}),
getIsDisabled: () => {
const emsSettings = getEMSSettings();
return emsSettings.isEMSUrlSet() && !emsSettings.hasOnPremLicense();
},
icon: WorldMapLayerIcon,
renderWizard: ({ previewLayers }: RenderWizardArguments) => {
const onSourceConfigChange = (sourceConfig: unknown) => {
@ -41,5 +56,5 @@ export const emsBaseMapLayerWizardConfig: LayerWizard = {
</EuiPanel>
);
},
title: sourceTitle,
title: getSourceTitle(),
};

View file

@ -11,12 +11,29 @@ import { UpdateSourceEditor } from './update_source_editor';
import { i18n } from '@kbn/i18n';
import { getDataSourceLabel } from '../../../../common/i18n_getters';
import { SOURCE_TYPES } from '../../../../common/constants';
import { getEmsTileLayerId, getIsDarkMode } from '../../../kibana_services';
import { getEmsTileLayerId, getIsDarkMode, getEMSSettings } from '../../../kibana_services';
import { registerSource } from '../source_registry';
import { getEmsUnavailableMessage } from '../../../components/ems_unavailable_message';
export const sourceTitle = i18n.translate('xpack.maps.source.emsTileTitle', {
defaultMessage: 'EMS Basemaps',
});
function getErrorInfo(emsTileLayerId) {
return i18n.translate('xpack.maps.source.emsTile.unableToFindTileIdErrorMessage', {
defaultMessage: `Unable to find EMS tile configuration for id: {id}. {info}`,
values: { id: emsTileLayerId, info: getEmsUnavailableMessage() },
});
}
export function getSourceTitle() {
const emsSettings = getEMSSettings();
if (emsSettings.isEMSUrlSet()) {
return i18n.translate('xpack.maps.source.emsOnPremTileTitle', {
defaultMessage: 'Elastic Maps Server Basemaps',
});
} else {
return i18n.translate('xpack.maps.source.emsTileTitle', {
defaultMessage: 'EMS Basemaps',
});
}
}
export class EMSTMSSource extends AbstractTMSSource {
static createDescriptor(descriptor) {
@ -43,10 +60,10 @@ export class EMSTMSSource extends AbstractTMSSource {
defaultMessage: 'autoselect based on Kibana theme',
});
return [
const props = [
{
label: getDataSourceLabel(),
value: sourceTitle,
value: getSourceTitle(),
},
{
label: i18n.translate('xpack.maps.source.emsTile.serviceId', {
@ -55,21 +72,34 @@ export class EMSTMSSource extends AbstractTMSSource {
value: this._descriptor.isAutoSelect ? `${displayName} - ${autoSelectMsg}` : displayName,
},
];
const emsSettings = getEMSSettings();
if (emsSettings.isEMSUrlSet()) {
props.push({
label: i18n.translate('xpack.maps.source.emsTile.emsOnPremLabel', {
defaultMessage: `Elastic Maps Server`,
}),
value: emsSettings.getEMSRoot(),
});
}
return props;
}
async _getEMSTMSService() {
const emsTMSServices = await getEmsTmsServices();
let emsTMSServices;
const emsTileLayerId = this.getTileLayerId();
const tmsService = emsTMSServices.find((tmsService) => tmsService.getId() === emsTileLayerId);
if (!tmsService) {
throw new Error(
i18n.translate('xpack.maps.source.emsTile.errorMessage', {
defaultMessage: `Unable to find EMS tile configuration for id: {id}`,
values: { id: emsTileLayerId },
})
);
try {
emsTMSServices = await getEmsTmsServices();
} catch (e) {
throw new Error(`${getErrorInfo(emsTileLayerId)} - ${e.message}`);
}
return tmsService;
const tmsService = emsTMSServices.find((tmsService) => tmsService.getId() === emsTileLayerId);
if (tmsService) {
return tmsService;
}
throw new Error(getErrorInfo());
}
async getDisplayName() {

View file

@ -60,10 +60,7 @@ export class TileServiceSelect extends React.Component {
};
render() {
const helpText =
this.state.hasLoaded && this.state.emsTmsOptions.length === 0
? getEmsUnavailableMessage()
: null;
const helpText = this.state.emsTmsOptions.length === 0 ? getEmsUnavailableMessage() : null;
let selectedId;
if (this.props.config) {

View file

@ -8,16 +8,34 @@ import { i18n } from '@kbn/i18n';
import { getEMSSettings } from '../kibana_services';
export function getEmsUnavailableMessage(): string {
const isEmsEnabled = getEMSSettings().isEMSEnabled();
if (isEmsEnabled) {
return i18n.translate('xpack.maps.source.ems.noAccessDescription', {
const emsSettings = getEMSSettings();
if (!emsSettings.isIncludeElasticMapsService()) {
return i18n.translate('xpack.maps.source.ems.disabledDescription', {
defaultMessage:
'Kibana is unable to access Elastic Maps Service. Contact your system administrator.',
'Access to Elastic Maps Service has been disabled. Ask your system administrator to set "map.includeElasticMapsService" in kibana.yml.',
});
}
return i18n.translate('xpack.maps.source.ems.disabledDescription', {
if (emsSettings.isEMSUrlSet()) {
if (!emsSettings.hasOnPremLicense()) {
return i18n.translate('xpack.maps.source.ems.noOnPremLicenseDescription', {
defaultMessage:
'An enterprise license is required to connect to local Elastic Maps Server installations.',
});
} else {
return i18n.translate('xpack.maps.source.ems.noOnPremConnectionDescription', {
defaultMessage: 'Cannot connect to {host}.',
values: {
host: emsSettings.getEMSRoot(),
},
});
}
}
// Not sure why.
return i18n.translate('xpack.maps.source.ems.noAccessDescription', {
defaultMessage:
'Access to Elastic Maps Service has been disabled. Ask your system administrator to set "map.includeElasticMapsService" in kibana.yml.',
'Kibana is unable to access Elastic Maps Service. Contact your system administrator.',
});
}

View file

@ -7,21 +7,25 @@
jest.mock('../../../meta', () => {
return {};
});
jest.mock('../../../kibana_services');
jest.mock('../../../kibana_services', () => {
return {
getEMSSettings() {
return {
isEMSEnabled: () => {
return true;
},
isEMSUrlSet() {
return false;
},
};
},
};
});
import { getInitialLayers } from './get_initial_layers';
const layerListNotProvided = undefined;
describe('Saved object has layer list', () => {
beforeEach(() => {
require('../../../kibana_services').getEMSSettings = () => {
return {
isEMSEnabled: () => true,
};
};
});
it('Should get initial layers from saved object', () => {
const layerListFromSavedObject = [
{
@ -69,11 +73,6 @@ describe('EMS is enabled', () => {
require('../../../meta').getKibanaTileMap = () => {
return null;
};
require('../../../kibana_services').getEMSSettings = () => {
return {
isEMSEnabled: () => true,
};
};
require('../../../kibana_services').getEmsTileLayerId = () => ({
bright: 'road_map',
desaturated: 'road_map_desaturated',
@ -112,6 +111,7 @@ describe('EMS is not enabled', () => {
require('../../../kibana_services').getEMSSettings = () => {
return {
isEMSEnabled: () => false,
isEMSUrlSet: () => false,
};
};
});

View file

@ -11262,17 +11262,13 @@
"xpack.maps.source.ems.disabledDescription": "Elastic Maps Service へのアクセスが無効になっています。システム管理者に問い合わせるか、kibana.yml で「map.includeElasticMapsService」を設定してください。",
"xpack.maps.source.ems.noAccessDescription": "Kibana が Elastic Maps Service にアクセスできません。システム管理者にお問い合わせください",
"xpack.maps.source.emsFile.layerLabel": "レイヤー",
"xpack.maps.source.emsFile.unableToFindIdErrorMessage": "ID {id} の EMS ベクターシェイプが見つかりません",
"xpack.maps.source.emsFileDescription": "Elastic Maps Service の行政区画のベクターシェイプ",
"xpack.maps.source.emsFileSelect.selectLabel": "レイヤー",
"xpack.maps.source.emsFileTitle": "ベクターシェイプ",
"xpack.maps.source.emsTile.autoLabel": "Kibana テーマに基づき自動選択",
"xpack.maps.source.emsTile.errorMessage": "ID {id} の EMS タイル構成が見つかりません",
"xpack.maps.source.emsTile.isAutoSelectLabel": "Kibana テーマに基づき自動選択",
"xpack.maps.source.emsTile.label": "タイルサービス",
"xpack.maps.source.emsTile.serviceId": "タイルサービス",
"xpack.maps.source.emsTile.settingsTitle": "ベースマップ",
"xpack.maps.source.emsTileDescription": "Elastic Maps Service のマップタイル",
"xpack.maps.source.emsTileTitle": "タイル",
"xpack.maps.source.esGeoGrid.geofieldLabel": "地理空間フィールド",
"xpack.maps.source.esGeoGrid.geofieldPlaceholder": "ジオフィールドを選択",

View file

@ -11275,17 +11275,13 @@
"xpack.maps.source.ems.disabledDescription": "已禁用对 Elastic 地图服务的访问。让您的系统管理员在 kibana.yml 中设置“map.includeElasticMapsService”。",
"xpack.maps.source.ems.noAccessDescription": "Kibana 无法访问 Elastic 地图服务。请联系您的系统管理员",
"xpack.maps.source.emsFile.layerLabel": "图层",
"xpack.maps.source.emsFile.unableToFindIdErrorMessage": "找不到 ID {id} 的 EMS 矢量形状",
"xpack.maps.source.emsFileDescription": "来自 Elastic 地图服务的管理边界的矢量形状",
"xpack.maps.source.emsFileSelect.selectLabel": "图层",
"xpack.maps.source.emsFileTitle": "矢量形状",
"xpack.maps.source.emsTile.autoLabel": "基于 Kibana 主题自动选择",
"xpack.maps.source.emsTile.errorMessage": "找不到 ID {id} 的 EMS 磁贴配置",
"xpack.maps.source.emsTile.isAutoSelectLabel": "基于 Kibana 主题自动选择",
"xpack.maps.source.emsTile.label": "Tile Service",
"xpack.maps.source.emsTile.serviceId": "Tile Service",
"xpack.maps.source.emsTile.settingsTitle": "Basemap",
"xpack.maps.source.emsTileDescription": "Elastic 地图服务的地图磁贴",
"xpack.maps.source.emsTileTitle": "磁贴",
"xpack.maps.source.esGeoGrid.geofieldLabel": "地理空间字段",
"xpack.maps.source.esGeoGrid.geofieldPlaceholder": "选择地理字段",