mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[Maps] Localization (#30881)
Localize Maps-app UX with Kibana's i18n framework.
This commit is contained in:
parent
e365f0b646
commit
5e5a49a905
69 changed files with 1217 additions and 424 deletions
|
@ -31,6 +31,7 @@
|
|||
"xpack.infra": "x-pack/plugins/infra",
|
||||
"xpack.kueryAutocomplete": "x-pack/plugins/kuery_autocomplete",
|
||||
"xpack.licenseMgmt": "x-pack/plugins/license_management",
|
||||
"xpack.maps": "x-pack/plugins/maps",
|
||||
"xpack.ml": "x-pack/plugins/ml",
|
||||
"xpack.logstash": "x-pack/plugins/logstash",
|
||||
"xpack.main": "x-pack/plugins/xpack_main",
|
||||
|
|
|
@ -16,4 +16,8 @@ export const ZOOM_PRECISION = 2;
|
|||
|
||||
export const DEFAULT_EMS_TILE_LAYER = 'road_map';
|
||||
|
||||
export const APP_ID = 'maps';
|
||||
|
||||
export const APP_ICON = 'gisApp';
|
||||
|
||||
export const SOURCE_DATA_ID_ORIGIN = 'source';
|
||||
|
|
26
x-pack/plugins/maps/common/i18n_getters.js
Normal file
26
x-pack/plugins/maps/common/i18n_getters.js
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
export function getAppTitle() {
|
||||
return i18n.translate('xpack.maps.appTitle', {
|
||||
defaultMessage: 'Maps'
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export function getDataSourceLabel() {
|
||||
return i18n.translate('xpack.maps.source.dataSourceLabel', {
|
||||
defaultMessage: 'Data source'
|
||||
});
|
||||
}
|
||||
|
||||
export function getUrlLabel() {
|
||||
return i18n.translate('xpack.maps.source.urlLabel', {
|
||||
defaultMessage: 'Url'
|
||||
});
|
||||
}
|
|
@ -6,30 +6,35 @@
|
|||
|
||||
import { resolve } from 'path';
|
||||
import { initRoutes } from './server/routes';
|
||||
import ecommerceSavedObjects from './server/sample_data/ecommerce_saved_objects.json';
|
||||
import fligthsSavedObjects from './server/sample_data/flights_saved_objects.json';
|
||||
import webLogsSavedObjects from './server/sample_data/web_logs_saved_objects.json';
|
||||
import { getEcommerceSavedObjects } from './server/sample_data/ecommerce_saved_objects';
|
||||
import { getFlightsSavedObjects } from './server/sample_data/flights_saved_objects.js';
|
||||
import { getWebLogsSavedObjects } from './server/sample_data/web_logs_saved_objects.js';
|
||||
import mappings from './mappings.json';
|
||||
import { checkLicense } from './check_license';
|
||||
import { migrations } from './migrations';
|
||||
import { watchStatusAndLicenseToInitialize } from
|
||||
'../../server/lib/watch_status_and_license_to_initialize';
|
||||
import { initTelemetryCollection } from './server/maps_telemetry';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { APP_ID, APP_ICON } from './common/constants';
|
||||
import { getAppTitle } from './common/i18n_getters';
|
||||
|
||||
export function maps(kibana) {
|
||||
|
||||
return new kibana.Plugin({
|
||||
require: ['kibana', 'elasticsearch', 'xpack_main', 'tile_map', 'task_manager'],
|
||||
id: 'maps',
|
||||
id: APP_ID,
|
||||
configPrefix: 'xpack.maps',
|
||||
publicDir: resolve(__dirname, 'public'),
|
||||
uiExports: {
|
||||
app: {
|
||||
title: 'Maps',
|
||||
description: 'Map application',
|
||||
title: getAppTitle(),
|
||||
description: i18n.translate('xpack.maps.appDescription', {
|
||||
defaultMessage: 'Map application'
|
||||
}),
|
||||
main: 'plugins/maps/index',
|
||||
icon: 'plugins/maps/icon.svg',
|
||||
euiIconType: 'gisApp',
|
||||
euiIconType: APP_ICON,
|
||||
},
|
||||
injectDefaultVars(server) {
|
||||
const serverConfig = server.config();
|
||||
|
@ -86,9 +91,9 @@ export function maps(kibana) {
|
|||
.feature(this.id)
|
||||
.registerLicenseCheckResultsGenerator(checkLicense);
|
||||
|
||||
server.addSavedObjectsToSampleDataset('ecommerce', ecommerceSavedObjects);
|
||||
server.addSavedObjectsToSampleDataset('flights', fligthsSavedObjects);
|
||||
server.addSavedObjectsToSampleDataset('logs', webLogsSavedObjects);
|
||||
server.addSavedObjectsToSampleDataset('ecommerce', getEcommerceSavedObjects());
|
||||
server.addSavedObjectsToSampleDataset('flights', getFlightsSavedObjects());
|
||||
server.addSavedObjectsToSampleDataset('logs', getWebLogsSavedObjects());
|
||||
server.injectUiAppVars('maps', async () => {
|
||||
return await server.getInjectedUiAppVars('kibana');
|
||||
});
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
|
||||
import chrome from 'ui/chrome';
|
||||
import React from 'react';
|
||||
import { I18nContext } from 'ui/i18n';
|
||||
import { I18nProvider } from '@kbn/i18n/react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { render, unmountComponentAtNode } from 'react-dom';
|
||||
import { uiModules } from 'ui/modules';
|
||||
import { timefilter } from 'ui/timefilter';
|
||||
|
@ -143,9 +144,9 @@ app.controller('GisMapController', ($scope, $route, config, kbnUrl, localStorage
|
|||
const root = document.getElementById(REACT_ANCHOR_DOM_ELEMENT_ID);
|
||||
render(
|
||||
<Provider store={store}>
|
||||
<I18nContext>
|
||||
<I18nProvider>
|
||||
<GisMap/>
|
||||
</I18nContext>
|
||||
</I18nProvider>
|
||||
</Provider>,
|
||||
root
|
||||
);
|
||||
|
@ -201,7 +202,9 @@ app.controller('GisMapController', ($scope, $route, config, kbnUrl, localStorage
|
|||
|
||||
// TODO subscribe to store change and change when store updates title
|
||||
chrome.breadcrumbs.set([
|
||||
{ text: 'Maps', href: '#' },
|
||||
{ text: i18n.translate('xpack.maps.mapController.mapsBreadcrumbLabel', {
|
||||
defaultMessage: 'Maps'
|
||||
}), href: '#' },
|
||||
{ text: $scope.map.title }
|
||||
]);
|
||||
|
||||
|
@ -216,7 +219,10 @@ app.controller('GisMapController', ($scope, $route, config, kbnUrl, localStorage
|
|||
docTitle.change(savedMap.title);
|
||||
} catch(err) {
|
||||
toastNotifications.addDanger({
|
||||
title: `Error on saving '${savedMap.title}'`,
|
||||
title: i18n.translate('xpack.maps.mapController.saveErrorMessage', {
|
||||
defaultMessage: `Error on saving '{title}'`,
|
||||
values: { title: savedMap.title }
|
||||
}),
|
||||
text: err.message,
|
||||
'data-test-subj': 'saveMapError',
|
||||
});
|
||||
|
@ -225,7 +231,10 @@ app.controller('GisMapController', ($scope, $route, config, kbnUrl, localStorage
|
|||
|
||||
if (id) {
|
||||
toastNotifications.addSuccess({
|
||||
title: `Saved '${savedMap.title}'`,
|
||||
title: i18n.translate('xpack.maps.mapController.saveSuccessMessage', {
|
||||
defaultMessage: `Saved '{title}'`,
|
||||
values: { title: savedMap.title }
|
||||
}),
|
||||
'data-test-subj': 'saveMapSuccess',
|
||||
});
|
||||
|
||||
|
@ -243,23 +252,35 @@ app.controller('GisMapController', ($scope, $route, config, kbnUrl, localStorage
|
|||
timefilter.disableAutoRefreshSelector();
|
||||
$scope.showDatePicker = true; // used by query-bar directive to enable timepikcer in query bar
|
||||
$scope.topNavMenu = [{
|
||||
key: 'full screen',
|
||||
description: 'full screen',
|
||||
key: i18n.translate('xpack.maps.mapController.fullScreenButtonLabel', {
|
||||
defaultMessage: `full screen`
|
||||
}),
|
||||
description: i18n.translate('xpack.maps.mapController.fullScreenDescription', {
|
||||
defaultMessage: `full screen`
|
||||
}),
|
||||
testId: 'mapsFullScreenMode',
|
||||
run() {
|
||||
store.dispatch(enableFullScreen());
|
||||
}
|
||||
}, {
|
||||
key: 'inspect',
|
||||
description: 'Open Inspector',
|
||||
key: i18n.translate('xpack.maps.mapController.openInspectorButtonLabel', {
|
||||
defaultMessage: `inspect`
|
||||
}),
|
||||
description: i18n.translate('xpack.maps.mapController.openInspectorDescription', {
|
||||
defaultMessage: `Open Inspector`
|
||||
}),
|
||||
testId: 'openInspectorButton',
|
||||
run() {
|
||||
const inspectorAdapters = getInspectorAdapters(store.getState());
|
||||
Inspector.open(inspectorAdapters, {});
|
||||
}
|
||||
}, {
|
||||
key: 'save',
|
||||
description: 'Save map',
|
||||
key: i18n.translate('xpack.maps.mapController.saveMapButtonLabel', {
|
||||
defaultMessage: `save`
|
||||
}),
|
||||
description: i18n.translate('xpack.maps.mapController.saveMapDescription', {
|
||||
defaultMessage: `Save map`
|
||||
}),
|
||||
testId: 'mapSaveButton',
|
||||
run: async () => {
|
||||
const onSave = ({ newTitle, newCopyOnSave, isTitleDuplicateConfirmed, onTitleDuplicate }) => {
|
||||
|
|
|
@ -20,6 +20,7 @@ import {
|
|||
EuiFlyoutBody,
|
||||
EuiFlyoutFooter,
|
||||
} from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import _ from 'lodash';
|
||||
|
||||
export class AddLayerPanel extends Component {
|
||||
|
@ -71,7 +72,10 @@ export class AddLayerPanel extends Component {
|
|||
}}
|
||||
fill
|
||||
>
|
||||
Add layer
|
||||
<FormattedMessage
|
||||
id="xpack.maps.addLayerPanel.addLayerButtonLabel"
|
||||
defaultMessage="Add layer"
|
||||
/>
|
||||
</EuiButton>
|
||||
);
|
||||
}
|
||||
|
@ -102,7 +106,12 @@ export class AddLayerPanel extends Component {
|
|||
return (
|
||||
<Fragment>
|
||||
<EuiTitle size="xs">
|
||||
<h2>Choose data source</h2>
|
||||
<h2>
|
||||
<FormattedMessage
|
||||
id="xpack.maps.addLayerPanel.chooseDataSourceTitle"
|
||||
defaultMessage="Choose data source"
|
||||
/>
|
||||
</h2>
|
||||
</EuiTitle>
|
||||
{this._renderSourceCards()}
|
||||
</Fragment>
|
||||
|
@ -130,7 +139,10 @@ export class AddLayerPanel extends Component {
|
|||
onClick={this._clearSource}
|
||||
iconType="arrowLeft"
|
||||
>
|
||||
Change data source
|
||||
<FormattedMessage
|
||||
id="xpack.maps.addLayerPanel.changeDataSourceButtonLabel"
|
||||
defaultMessage="Change data source"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiPanel>
|
||||
|
@ -156,7 +168,12 @@ export class AddLayerPanel extends Component {
|
|||
>
|
||||
<EuiFlyoutHeader hasBorder className="mapLayerPanel__header">
|
||||
<EuiTitle size="s">
|
||||
<h2>Add layer</h2>
|
||||
<h2>
|
||||
<FormattedMessage
|
||||
id="xpack.maps.addLayerPanel.panelTitle"
|
||||
defaultMessage="Add layer"
|
||||
/>
|
||||
</h2>
|
||||
</EuiTitle>
|
||||
</EuiFlyoutHeader>
|
||||
|
||||
|
@ -175,7 +192,10 @@ export class AddLayerPanel extends Component {
|
|||
flush="left"
|
||||
data-test-subj="layerAddCancelButton"
|
||||
>
|
||||
Cancel
|
||||
<FormattedMessage
|
||||
id="xpack.maps.addLayerPanel.cancelButtonLabel"
|
||||
defaultMessage="Cancel"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
|
|
|
@ -35,7 +35,11 @@ exports[`LayerPanel is rendered 1`] = `
|
|||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
Fit
|
||||
<FormattedMessage
|
||||
defaultMessage="Fit"
|
||||
id="xpack.maps.layerPanel.fitToBoundsButtonLabel"
|
||||
values={Object {}}
|
||||
/>
|
||||
</EuiButtonIcon>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem
|
||||
|
|
|
@ -13,6 +13,8 @@ import {
|
|||
EuiSpacer,
|
||||
EuiButtonEmpty,
|
||||
} from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
export const FlyoutFooter = ({ cancelLayerPanel, saveLayerEdits, removeLayer,
|
||||
hasStateChanged }) => {
|
||||
const removeBtn = (
|
||||
|
@ -23,11 +25,24 @@ export const FlyoutFooter = ({ cancelLayerPanel, saveLayerEdits, removeLayer,
|
|||
flush="right"
|
||||
data-test-subj="mapRemoveLayerButton"
|
||||
>
|
||||
Remove layer
|
||||
<FormattedMessage
|
||||
id="xpack.maps.layerPanel.footer.removeLayerButtonLabel"
|
||||
defaultMessage="Remove layer"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
);
|
||||
|
||||
|
||||
const cancelButtonLabel = hasStateChanged ? (<FormattedMessage
|
||||
id="xpack.maps.layerPanel.footer.cancelButtonLabel"
|
||||
defaultMessage="Cancel"
|
||||
/>) : (<FormattedMessage
|
||||
id="xpack.maps.layerPanel.footer.closeButtonLabel"
|
||||
defaultMessage="Close"
|
||||
/>);
|
||||
|
||||
|
||||
return (
|
||||
<EuiFlexGroup responsive={false}>
|
||||
<EuiFlexItem grow={false}>
|
||||
|
@ -35,7 +50,7 @@ export const FlyoutFooter = ({ cancelLayerPanel, saveLayerEdits, removeLayer,
|
|||
onClick={cancelLayerPanel}
|
||||
flush="left"
|
||||
>
|
||||
{hasStateChanged ? 'Cancel' : 'Close'}
|
||||
{cancelButtonLabel}
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
|
@ -49,7 +64,10 @@ export const FlyoutFooter = ({ cancelLayerPanel, saveLayerEdits, removeLayer,
|
|||
onClick={saveLayerEdits}
|
||||
fill
|
||||
>
|
||||
Save & close
|
||||
<FormattedMessage
|
||||
id="xpack.maps.layerPanel.footer.saveAndCloseButtonLabel"
|
||||
defaultMessage="Save & close"
|
||||
/>
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
|
|
|
@ -6,13 +6,12 @@
|
|||
|
||||
import _ from 'lodash';
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import {
|
||||
EuiFlexItem,
|
||||
EuiFlexGroup,
|
||||
EuiButtonIcon,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { JoinExpression } from './join_expression';
|
||||
import { MetricsExpression } from './metrics_expression';
|
||||
|
||||
|
@ -74,7 +73,10 @@ export class Join extends Component {
|
|||
} catch (err) {
|
||||
if (this._isMounted) {
|
||||
this.setState({
|
||||
loadError: `Unable to find Index pattern ${indexPatternId}`
|
||||
loadError: i18n.translate('xpack.maps.layerPanel.join.noIndexPatternErrorMessage', {
|
||||
defaultMessage: `Unable to find Index pattern {indexPatternId}`,
|
||||
values: { indexPatternId }
|
||||
})
|
||||
});
|
||||
}
|
||||
return;
|
||||
|
@ -204,8 +206,12 @@ export class Join extends Component {
|
|||
className="mapJoinItem__delete"
|
||||
iconType="trash"
|
||||
color="danger"
|
||||
aria-label="Delete join"
|
||||
title="Delete join"
|
||||
aria-label={i18n.translate('xpack.maps.layerPanel.join.deleteJoinAriaLabel', {
|
||||
defaultMessage: 'Delete join'
|
||||
})}
|
||||
title={i18n.translate('xpack.maps.layerPanel.join.deleteJoinTitle', {
|
||||
defaultMessage: 'Delete join'
|
||||
})}
|
||||
onClick={onRemove}
|
||||
/>
|
||||
</EuiFlexGroup>
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
import _ from 'lodash';
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import {
|
||||
EuiPopover,
|
||||
EuiPopoverTitle,
|
||||
|
@ -15,9 +14,10 @@ import {
|
|||
EuiFormRow,
|
||||
EuiComboBox,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { IndexPatternSelect } from 'ui/index_patterns/components/index_pattern_select';
|
||||
import { SingleFieldSelect } from '../../../../shared/components/single_field_select';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
import {
|
||||
indexPatternService,
|
||||
|
@ -87,10 +87,14 @@ export class JoinExpression extends Component {
|
|||
|
||||
return (
|
||||
<EuiFormRow
|
||||
label="Left field"
|
||||
label={
|
||||
i18n.translate('xpack.maps.layerPanel.joinExpression.leftFieldLabel', {
|
||||
defaultMessage: 'Left field'
|
||||
})
|
||||
}
|
||||
>
|
||||
<EuiComboBox
|
||||
placeholder="Select field"
|
||||
placeholder={getSelectFieldPlaceholder()}
|
||||
singleSelection={true}
|
||||
isClearable={false}
|
||||
options={options}
|
||||
|
@ -108,10 +112,18 @@ export class JoinExpression extends Component {
|
|||
|
||||
return (
|
||||
<EuiFormRow
|
||||
label="Right source"
|
||||
label={
|
||||
i18n.translate('xpack.maps.layerPanel.joinExpression.rightSourceLabel', {
|
||||
defaultMessage: 'Right source'
|
||||
})
|
||||
}
|
||||
>
|
||||
<IndexPatternSelect
|
||||
placeholder="Select index pattern"
|
||||
placeholder={
|
||||
i18n.translate('xpack.maps.layerPanel.joinExpression.selectIndexPatternPlaceholder', {
|
||||
defaultMessage: 'Select index pattern'
|
||||
})
|
||||
}
|
||||
indexPatternId={this.props.rightSourceIndexPatternId}
|
||||
onChange={this._onRightSourceChange}
|
||||
isClearable={false}
|
||||
|
@ -131,10 +143,14 @@ export class JoinExpression extends Component {
|
|||
|
||||
return (
|
||||
<EuiFormRow
|
||||
label="Right field"
|
||||
label={
|
||||
i18n.translate('xpack.maps.layerPanel.joinExpression.rightFieldLabel', {
|
||||
defaultMessage: 'Right field'
|
||||
})
|
||||
}
|
||||
>
|
||||
<SingleFieldSelect
|
||||
placeholder="Select field"
|
||||
placeholder={getSelectFieldPlaceholder()}
|
||||
value={this.props.rightValue}
|
||||
onChange={this.props.onRightFieldChange}
|
||||
filterField={filterStringOrNumberFields}
|
||||
|
@ -156,7 +172,9 @@ export class JoinExpression extends Component {
|
|||
return `${leftSourceName}:${leftValue} with ${rightSourceName}:${rightValue}`;
|
||||
}
|
||||
|
||||
return '-- select --';
|
||||
return i18n.translate('xpack.maps.layerPanel.joinExpression.selectPlaceholder', {
|
||||
defaultMessage: '-- select --'
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -180,9 +198,18 @@ export class JoinExpression extends Component {
|
|||
}
|
||||
>
|
||||
<div style={{ width: 300 }}>
|
||||
<EuiPopoverTitle>Join</EuiPopoverTitle>
|
||||
<EuiPopoverTitle>
|
||||
<FormattedMessage
|
||||
id="xpack.maps.layerPanel.joinExpression.joinPopoverTitle"
|
||||
defaultMessage="Join"
|
||||
/>
|
||||
</EuiPopoverTitle>
|
||||
<EuiFormRow
|
||||
label="Left source"
|
||||
label={
|
||||
i18n.translate('xpack.maps.layerPanel.joinExpression.leftSourceLabel', {
|
||||
defaultMessage: 'Left source'
|
||||
})
|
||||
}
|
||||
>
|
||||
<EuiComboBox
|
||||
selectedOptions={[{ value: leftSourceName, label: leftSourceName }]}
|
||||
|
@ -222,3 +249,9 @@ JoinExpression.propTypes = {
|
|||
rightFields: PropTypes.object, // indexPattern.fields IndexedArray object
|
||||
onRightFieldChange: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
function getSelectFieldPlaceholder() {
|
||||
return i18n.translate('xpack.maps.layerPanel.joinExpression.selectFieldPlaceholder', {
|
||||
defaultMessage: 'Select field'
|
||||
});
|
||||
}
|
||||
|
|
|
@ -6,16 +6,15 @@
|
|||
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import {
|
||||
EuiPopover,
|
||||
EuiPopoverTitle,
|
||||
EuiExpression,
|
||||
EuiFormErrorText,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { MetricsEditor } from '../../../../shared/components/metrics_editor';
|
||||
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
export class MetricsExpression extends Component {
|
||||
|
||||
state = {
|
||||
|
@ -37,7 +36,12 @@ export class MetricsExpression extends Component {
|
|||
_renderMetricsEditor = () => {
|
||||
if (!this.props.rightFields) {
|
||||
return (
|
||||
<EuiFormErrorText>JOIN must be set</EuiFormErrorText>
|
||||
<EuiFormErrorText>
|
||||
<FormattedMessage
|
||||
id="xpack.maps.layerPanel.metricsExpression.joinMustBeSetErrorMessage"
|
||||
defaultMessage="JOIN must be set"
|
||||
/>
|
||||
</EuiFormErrorText>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -69,7 +73,12 @@ export class MetricsExpression extends Component {
|
|||
|
||||
return `${type} ${field}`;
|
||||
});
|
||||
|
||||
const useMetricDescription = i18n.translate('xpack.maps.layerPanel.metricsExpression.useMetricsDescription', {
|
||||
defaultMessage: '{metricsLength, plural, one {and use metric} other {and use metrics}}',
|
||||
values: {
|
||||
metricsLength: metricExpressions.length
|
||||
}
|
||||
});
|
||||
return (
|
||||
<EuiPopover
|
||||
id="metricsPopover"
|
||||
|
@ -82,14 +91,19 @@ export class MetricsExpression extends Component {
|
|||
button={
|
||||
<EuiExpression
|
||||
onClick={this._togglePopover}
|
||||
description={metricExpressions.length > 1 ? 'and use metrics' : 'and use metric'}
|
||||
description={useMetricDescription}
|
||||
uppercase={false}
|
||||
value={metricExpressions.length > 0 ? metricExpressions.join(', ') : 'count'}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<div style={{ width: 400 }}>
|
||||
<EuiPopoverTitle>Metrics</EuiPopoverTitle>
|
||||
<EuiPopoverTitle>
|
||||
<FormattedMessage
|
||||
id="xpack.maps.layerPanel.metricsExpression.metricsPopoverTitle"
|
||||
defaultMessage="Metrics"
|
||||
/>
|
||||
</EuiPopoverTitle>
|
||||
{this._renderMetricsEditor()}
|
||||
</div>
|
||||
</EuiPopover>
|
||||
|
|
|
@ -16,6 +16,8 @@ import {
|
|||
} from '@elastic/eui';
|
||||
|
||||
import { Join } from './resources/join';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
export function JoinEditor({ joins, layer, onChange }) {
|
||||
|
||||
|
@ -69,10 +71,30 @@ export function JoinEditor({ joins, layer, onChange }) {
|
|||
<div>
|
||||
<EuiFlexGroup responsive={false}>
|
||||
<EuiFlexItem>
|
||||
<EuiTitle size="xs"><h5>Term joins</h5></EuiTitle>
|
||||
<EuiTitle size="xs">
|
||||
<h5>
|
||||
<FormattedMessage
|
||||
id="xpack.maps.layerPanel.joinEditor.termJoinsTitle"
|
||||
defaultMessage="Term joins"
|
||||
/>
|
||||
</h5>
|
||||
</EuiTitle>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonIcon iconType="plusInCircle" onClick={addJoin} aria-label="Add join" title="Add join" />
|
||||
|
||||
<EuiButtonIcon
|
||||
iconType="plusInCircle"
|
||||
onClick={addJoin}
|
||||
aria-label={i18n.translate('xpack.maps.layerPanel.joinEditor.addJoinAriaLabel', {
|
||||
defaultMessage: 'Add join'
|
||||
})
|
||||
}
|
||||
title={
|
||||
i18n.translate('xpack.maps.layerPanel.joinEditor.addJoinButtonLabel', {
|
||||
defaultMessage: 'Add join'
|
||||
})
|
||||
}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
|
||||
|
|
|
@ -18,6 +18,8 @@ import {
|
|||
EuiCallOut,
|
||||
} from '@elastic/eui';
|
||||
import { ValidatedRange } from '../../../shared/components/validated_range';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
export function SettingsPanel(props) {
|
||||
|
||||
|
@ -53,7 +55,11 @@ export function SettingsPanel(props) {
|
|||
<Fragment>
|
||||
<EuiCallOut
|
||||
color="warning"
|
||||
title="Unable to load layer"
|
||||
title={
|
||||
i18n.translate('xpack.maps.layerPanel.settingsPanel.unableToLoadTitle', {
|
||||
defaultMessage: 'Unable to load layer'
|
||||
})
|
||||
}
|
||||
>
|
||||
<p data-test-subj="layerErrorMessage">
|
||||
{props.layer.getErrors()}
|
||||
|
@ -67,12 +73,18 @@ export function SettingsPanel(props) {
|
|||
const renderZoomSliders = () => {
|
||||
return (
|
||||
<EuiFormRow
|
||||
helpText="Display layer when map is in zoom range."
|
||||
helpText={
|
||||
i18n.translate('xpack.maps.layerPanel.settingsPanel.zoomFeedbackHelptext', {
|
||||
defaultMessage: 'Display layer when map is in zoom range.'
|
||||
})
|
||||
}
|
||||
>
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
<EuiFormRow
|
||||
label="Min zoom"
|
||||
label={i18n.translate('xpack.maps.layerPanel.settingsPanel.minZoomLabel', {
|
||||
defaultMessage: 'Min zoom'
|
||||
})}
|
||||
>
|
||||
<EuiRange
|
||||
min={0}
|
||||
|
@ -86,7 +98,9 @@ export function SettingsPanel(props) {
|
|||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiFormRow
|
||||
label="Max zoom"
|
||||
label={i18n.translate('xpack.maps.layerPanel.settingsPanel.maxZoomLabel', {
|
||||
defaultMessage: 'Max zoom'
|
||||
})}
|
||||
>
|
||||
<EuiRange
|
||||
min={0}
|
||||
|
@ -106,7 +120,11 @@ export function SettingsPanel(props) {
|
|||
const renderLabel = () => {
|
||||
return (
|
||||
<EuiFormRow
|
||||
label="Layer name"
|
||||
label={
|
||||
i18n.translate('xpack.maps.layerPanel.settingsPanel.layerNameLabel', {
|
||||
defaultMessage: 'Layer name'
|
||||
})
|
||||
}
|
||||
>
|
||||
<EuiFieldText
|
||||
value={props.label}
|
||||
|
@ -119,7 +137,11 @@ export function SettingsPanel(props) {
|
|||
const renderAlphaSlider = () => {
|
||||
return (
|
||||
<EuiFormRow
|
||||
label="Layer transparency"
|
||||
label={
|
||||
i18n.translate('xpack.maps.layerPanel.settingsPanel.layerTransparencyLabel', {
|
||||
defaultMessage: 'Layer transparency'
|
||||
})
|
||||
}
|
||||
>
|
||||
<div className="mapAlphaRange">
|
||||
<ValidatedRange
|
||||
|
@ -145,7 +167,14 @@ export function SettingsPanel(props) {
|
|||
<EuiPanel>
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
<EuiTitle size="xs"><h5>Settings</h5></EuiTitle>
|
||||
<EuiTitle size="xs">
|
||||
<h5>
|
||||
<FormattedMessage
|
||||
id="xpack.maps.layerPanel.settingsPanel.settingsTitle"
|
||||
defaultMessage="Settings"
|
||||
/>
|
||||
</h5>
|
||||
</EuiTitle>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ import { StyleTabs } from './style_tabs';
|
|||
import { JoinEditor } from './join_editor';
|
||||
import { FlyoutFooter } from './flyout_footer';
|
||||
import { SettingsPanel } from './settings_panel';
|
||||
|
||||
import {
|
||||
EuiButtonIcon,
|
||||
EuiFlexItem,
|
||||
|
@ -26,6 +25,9 @@ import {
|
|||
EuiLink,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
export class LayerPanel extends React.Component {
|
||||
|
||||
static getDerivedStateFromProps(nextProps, prevState) {
|
||||
|
@ -41,7 +43,7 @@ export class LayerPanel extends React.Component {
|
|||
return null;
|
||||
}
|
||||
|
||||
state = {}
|
||||
state = {};
|
||||
|
||||
componentDidMount() {
|
||||
this._isMounted = true;
|
||||
|
@ -133,11 +135,19 @@ export class LayerPanel extends React.Component {
|
|||
<EuiFlexGroup responsive={false} alignItems="center" gutterSize="s">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonIcon
|
||||
aria-label="Fit to bounds"
|
||||
aria-label={
|
||||
i18n.translate('xpack.maps.layerPanel.fitToBoundsAriaLabel', {
|
||||
defaultMessage: 'Fit to bounds'
|
||||
})
|
||||
}
|
||||
iconType={selectedLayer.getLayerTypeIconName()}
|
||||
onClick={this.props.fitToBounds}
|
||||
>
|
||||
Fit
|
||||
<FormattedMessage
|
||||
id="xpack.maps.layerPanel.fitToBoundsButtonLabel"
|
||||
defaultMessage="Fit"
|
||||
/>
|
||||
|
||||
</EuiButtonIcon>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
|
@ -150,7 +160,11 @@ export class LayerPanel extends React.Component {
|
|||
<div className="mapLayerPanel__sourceDetails">
|
||||
<EuiAccordion
|
||||
id="accordion1"
|
||||
buttonContent="Source details"
|
||||
buttonContent={
|
||||
i18n.translate('xpack.maps.layerPanel.sourceDetailsLabel', {
|
||||
defaultMessage: 'Source details'
|
||||
})
|
||||
}
|
||||
>
|
||||
<EuiText color="subdued" size="s">
|
||||
<EuiSpacer size="xs" />
|
||||
|
|
|
@ -29,7 +29,7 @@ jest.mock('./settings_panel', () => ({
|
|||
}));
|
||||
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
|
||||
|
||||
import { LayerPanel } from './view';
|
||||
|
||||
|
@ -53,7 +53,7 @@ const defaultProps = {
|
|||
|
||||
describe('LayerPanel', () => {
|
||||
test('is rendered', async () => {
|
||||
const component = shallow(
|
||||
const component = shallowWithIntl(
|
||||
<LayerPanel
|
||||
{...defaultProps}
|
||||
/>
|
||||
|
@ -69,7 +69,7 @@ describe('LayerPanel', () => {
|
|||
});
|
||||
|
||||
test('should render empty panel when selectedLayer is null', async () => {
|
||||
const component = shallow(
|
||||
const component = shallowWithIntl(
|
||||
<LayerPanel
|
||||
{...defaultProps}
|
||||
selectedLayer={undefined}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
|
||||
|
||||
import { AttributionControl } from './view';
|
||||
|
||||
|
@ -25,7 +25,7 @@ describe('AttributionControl', () => {
|
|||
];
|
||||
}
|
||||
};
|
||||
const component = shallow(
|
||||
const component = shallowWithIntl(
|
||||
<AttributionControl
|
||||
layerList={[mockLayer1, mockLayer2]}
|
||||
/>
|
||||
|
|
|
@ -30,7 +30,11 @@ exports[`LayerControl is rendered 1`] = `
|
|||
textTransform="none"
|
||||
>
|
||||
<h2>
|
||||
Layers
|
||||
<FormattedMessage
|
||||
defaultMessage="Layers"
|
||||
id="xpack.maps.layerControl.layersTitle"
|
||||
values={Object {}}
|
||||
/>
|
||||
</h2>
|
||||
</EuiTitle>
|
||||
</EuiFlexItem>
|
||||
|
@ -47,7 +51,11 @@ exports[`LayerControl is rendered 1`] = `
|
|||
size="xs"
|
||||
type="button"
|
||||
>
|
||||
Add layer
|
||||
<FormattedMessage
|
||||
defaultMessage="Add layer"
|
||||
id="xpack.maps.layerControl.addLayerButtonLabel"
|
||||
values={Object {}}
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
|
@ -92,7 +100,11 @@ exports[`LayerControl props isReadOnly 1`] = `
|
|||
textTransform="none"
|
||||
>
|
||||
<h2>
|
||||
Layers
|
||||
<FormattedMessage
|
||||
defaultMessage="Layers"
|
||||
id="xpack.maps.layerControl.layersTitle"
|
||||
values={Object {}}
|
||||
/>
|
||||
</h2>
|
||||
</EuiTitle>
|
||||
</EuiFlexItem>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
|
||||
|
||||
import { TOCEntry } from './view';
|
||||
|
||||
|
@ -30,7 +30,7 @@ const defaultProps = {
|
|||
|
||||
describe('TOCEntry', () => {
|
||||
test('is rendered', async () => {
|
||||
const component = shallow(
|
||||
const component = shallowWithIntl(
|
||||
<TOCEntry
|
||||
{...defaultProps}
|
||||
/>
|
||||
|
@ -47,7 +47,7 @@ describe('TOCEntry', () => {
|
|||
|
||||
describe('props', () => {
|
||||
test('isReadOnly', async () => {
|
||||
const component = shallow(
|
||||
const component = shallowWithIntl(
|
||||
<TOCEntry
|
||||
{...defaultProps}
|
||||
isReadOnly={true}
|
||||
|
|
|
@ -13,6 +13,7 @@ import {
|
|||
EuiTitle,
|
||||
} from '@elastic/eui';
|
||||
import { LayerTOC } from './layer_toc';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
export function LayerControl({ isReadOnly, showAddLayerWizard }) {
|
||||
let addLayer;
|
||||
|
@ -25,7 +26,10 @@ export function LayerControl({ isReadOnly, showAddLayerWizard }) {
|
|||
onClick={showAddLayerWizard}
|
||||
data-test-subj="addLayerButton"
|
||||
>
|
||||
Add layer
|
||||
<FormattedMessage
|
||||
id="xpack.maps.layerControl.addLayerButtonLabel"
|
||||
defaultMessage="Add layer"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
);
|
||||
|
@ -42,7 +46,12 @@ export function LayerControl({ isReadOnly, showAddLayerWizard }) {
|
|||
>
|
||||
<EuiFlexItem>
|
||||
<EuiTitle size="xs">
|
||||
<h2>Layers</h2>
|
||||
<h2>
|
||||
<FormattedMessage
|
||||
id="xpack.maps.layerControl.layersTitle"
|
||||
defaultMessage="Layers"
|
||||
/>
|
||||
</h2>
|
||||
</EuiTitle>
|
||||
</EuiFlexItem>
|
||||
{addLayer}
|
||||
|
|
|
@ -11,7 +11,7 @@ jest.mock('./layer_toc', () => ({
|
|||
}));
|
||||
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
|
||||
|
||||
import { LayerControl } from './view';
|
||||
|
||||
|
@ -21,7 +21,7 @@ const defaultProps = {
|
|||
|
||||
describe('LayerControl', () => {
|
||||
test('is rendered', () => {
|
||||
const component = shallow(
|
||||
const component = shallowWithIntl(
|
||||
<LayerControl
|
||||
{...defaultProps}
|
||||
/>
|
||||
|
@ -33,7 +33,7 @@ describe('LayerControl', () => {
|
|||
|
||||
describe('props', () => {
|
||||
test('isReadOnly', () => {
|
||||
const component = shallow(
|
||||
const component = shallowWithIntl(
|
||||
<LayerControl
|
||||
{...defaultProps}
|
||||
isReadOnly={true}
|
||||
|
|
|
@ -16,6 +16,7 @@ import {
|
|||
} from '@elastic/eui';
|
||||
import { SetView } from './set_view';
|
||||
import { DECIMAL_DEGREES_PRECISION } from '../../../../common/constants';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
export function ViewControl({ isSetViewOpen, closeSetView, openSetView, mouseCoordinates }) {
|
||||
const toggleSetViewVisibility = () => {
|
||||
|
@ -37,7 +38,10 @@ export function ViewControl({ isSetViewOpen, closeSetView, openSetView, mouseCoo
|
|||
onClick={toggleSetViewVisibility}
|
||||
data-test-subj="toggleSetViewVisibilityButton"
|
||||
>
|
||||
Go to
|
||||
<FormattedMessage
|
||||
id="xpack.maps.viewControl.goToButtonLabel"
|
||||
defaultMessage="Go to"
|
||||
/>
|
||||
</EuiButton>)}
|
||||
isOpen={isSetViewOpen}
|
||||
closePopover={closeSetView}
|
||||
|
@ -57,8 +61,18 @@ export function ViewControl({ isSetViewOpen, closeSetView, openSetView, mouseCoo
|
|||
<EuiPanel className="mapWidgetControl mapViewControl__coordinates" paddingSize="none">
|
||||
<EuiText size="xs">
|
||||
<p>
|
||||
<strong>lat:</strong> {lat},{' '}
|
||||
<strong>lon:</strong> {lon}
|
||||
<strong>
|
||||
<FormattedMessage
|
||||
id="xpack.maps.viewControl.latLabel"
|
||||
defaultMessage="lat:"
|
||||
/>
|
||||
</strong> {lat},{' '}
|
||||
<strong>
|
||||
<FormattedMessage
|
||||
id="xpack.maps.viewControl.lonLabel"
|
||||
defaultMessage="lon:"
|
||||
/>
|
||||
</strong> {lon}
|
||||
</p>
|
||||
</EuiText>
|
||||
</EuiPanel>
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
/**
|
||||
* Converts Elasticsearch search results into GeoJson FeatureCollection
|
||||
|
@ -27,7 +28,11 @@ export function hitsToGeoJson(hits, flattenHit, geoFieldName, geoFieldType) {
|
|||
} else if (geoFieldType === 'geo_shape') {
|
||||
geometries = geoShapeToGeometry(properties[geoFieldName]);
|
||||
} else {
|
||||
throw new Error(`Unsupported field type, expected: geo_shape or geo_point, you provided: ${geoFieldType}`);
|
||||
const errorMessage = i18n.translate('xpack.maps.elasticsearch_geo_utils.unsupportedFieldTypeErrorMessage', {
|
||||
defaultMessage: 'Unsupported field type, expected: geo_shape or geo_point, you provided: {geoFieldType}',
|
||||
values: { geoFieldType }
|
||||
});
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
// don't include geometry field value in properties
|
||||
|
@ -63,8 +68,11 @@ export function geoPointToGeometry(value) {
|
|||
if (typeof value === 'string') {
|
||||
const commaSplit = value.split(',');
|
||||
if (commaSplit.length === 1) {
|
||||
// Geo-point expressed as a geohash.
|
||||
throw new Error(`Unable to convert to geojson, geohash not supported`);
|
||||
const errorMessage = i18n.translate('xpack.maps.elasticsearch_geo_utils.geohashIsUnsupportedErrorMessage', {
|
||||
defaultMessage: `Unable to convert to geojson, geohash not supported`
|
||||
});
|
||||
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
// Geo-point expressed as a string with the format: "lat,lon".
|
||||
const lat = parseFloat(commaSplit[0]);
|
||||
|
@ -78,7 +86,13 @@ export function geoPointToGeometry(value) {
|
|||
}
|
||||
|
||||
if (!Array.isArray(value)) {
|
||||
throw new Error(`Unsupported geo_point value: ${value}`);
|
||||
const errorMessage = i18n.translate('xpack.maps.elasticsearch_geo_utils.unsupportedGeoPointValueErrorMessage', {
|
||||
defaultMessage: `Unsupported geo_point value: {geoPointValue}`,
|
||||
values: {
|
||||
geoPointValue: value
|
||||
}
|
||||
});
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
if (value.length === 2
|
||||
|
@ -116,7 +130,10 @@ export function geoShapeToGeometry(value) {
|
|||
|
||||
// TODO handle case where value is WKT and convert to geojson
|
||||
if (typeof value === 'string') {
|
||||
throw new Error(`Unable to convert WKT to geojson, not supported`);
|
||||
const errorMessage = i18n.translate('xpack.maps.elasticsearch_geo_utils.wktIsUnsupportedErrorMessage', {
|
||||
defaultMessage: `Unable to convert WKT to geojson, not supported`,
|
||||
});
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
const geoJson = _.cloneDeep(value);
|
||||
|
@ -180,7 +197,11 @@ export function createExtentFilter(mapExtent, geoFieldName, geoFieldType) {
|
|||
}
|
||||
};
|
||||
} else {
|
||||
throw new Error(`Unsupported field type, expected: geo_shape or geo_point, you provided: ${geoFieldType}`);
|
||||
const errorMessage = i18n.translate('xpack.maps.elasticsearch_geo_utils.unsupportedGeoFieldTypeErrorMessage', {
|
||||
defaultMessage: `Unsupported field type, expected: geo_shape or geo_point, you provided: {geoFieldType}`,
|
||||
values: { geoFieldType }
|
||||
});
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,9 @@ import {
|
|||
EuiTableRow,
|
||||
EuiTableRowCell,
|
||||
} from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
|
||||
const DETAILS_TAB_ID = 'details';
|
||||
const STYLE_TAB_ID = 'mapStyle';
|
||||
|
@ -23,11 +26,15 @@ class MapDetails extends Component {
|
|||
|
||||
tabs = [{
|
||||
id: DETAILS_TAB_ID,
|
||||
name: 'Map details',
|
||||
name: i18n.translate('xpack.maps.inspector.mapDetailsTitle', {
|
||||
defaultMessage: 'Map details'
|
||||
}),
|
||||
dataTestSubj: 'mapDetailsTab',
|
||||
}, {
|
||||
id: STYLE_TAB_ID,
|
||||
name: 'Mapbox style',
|
||||
name: i18n.translate('xpack.maps.inspector.mapboxStyleTitle', {
|
||||
defaultMessage: 'Mapbox style'
|
||||
}),
|
||||
dataTestSubj: 'mapboxStyleTab',
|
||||
}];
|
||||
|
||||
|
@ -60,21 +67,30 @@ class MapDetails extends Component {
|
|||
<EuiTableBody>
|
||||
<EuiTableRow>
|
||||
<EuiTableRowCell>
|
||||
Center lon
|
||||
<FormattedMessage
|
||||
id="xpack.maps.inspector.centerLonLabel"
|
||||
defaultMessage="Center lon"
|
||||
/>
|
||||
</EuiTableRowCell>
|
||||
<EuiTableRowCell data-test-subj="centerLon">{this.props.centerLon}</EuiTableRowCell>
|
||||
</EuiTableRow>
|
||||
|
||||
<EuiTableRow>
|
||||
<EuiTableRowCell>
|
||||
Center lat
|
||||
<FormattedMessage
|
||||
id="xpack.maps.inspector.centerLatLabel"
|
||||
defaultMessage="Center lat"
|
||||
/>
|
||||
</EuiTableRowCell>
|
||||
<EuiTableRowCell data-test-subj="centerLat">{this.props.centerLat}</EuiTableRowCell>
|
||||
</EuiTableRow>
|
||||
|
||||
<EuiTableRow>
|
||||
<EuiTableRowCell>
|
||||
Zoom
|
||||
<FormattedMessage
|
||||
id="xpack.maps.inspector.zoomLabel"
|
||||
defaultMessage="Zoom"
|
||||
/>
|
||||
</EuiTableRowCell>
|
||||
<EuiTableRowCell data-test-subj="zoom">{this.props.zoom}</EuiTableRowCell>
|
||||
</EuiTableRow>
|
||||
|
|
|
@ -9,6 +9,7 @@ import PropTypes from 'prop-types';
|
|||
|
||||
import { InspectorView } from 'ui/inspector';
|
||||
import { MapDetails } from './map_details';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
class MapViewComponent extends Component {
|
||||
|
||||
|
@ -54,9 +55,13 @@ MapViewComponent.propTypes = {
|
|||
};
|
||||
|
||||
const MapView = {
|
||||
title: 'Map details',
|
||||
title: i18n.translate('xpack.maps.inspector.mapDetailsViewTitle', {
|
||||
defaultMessage: 'Map details'
|
||||
}),
|
||||
order: 30,
|
||||
help: `View the map state`,
|
||||
help: i18n.translate('xpack.maps.inspector.mapDetailsViewHelpText', {
|
||||
defaultMessage: 'View the map state'
|
||||
}),
|
||||
shouldShow(adapters) {
|
||||
return Boolean(adapters.map);
|
||||
},
|
||||
|
|
|
@ -36,10 +36,10 @@ export async function getDataSources() {
|
|||
return loadingMetaPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should only call this after verifying `isMetadataLoaded` equals true
|
||||
*/
|
||||
export function getDataSourcesSync() {
|
||||
if (!isLoaded) {
|
||||
throw new Error('Metadata is not loaded yet. Use isMetadataLoaded first before calling this function.');
|
||||
}
|
||||
return meta;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,14 +8,18 @@ import {
|
|||
FeatureCatalogueRegistryProvider,
|
||||
FeatureCatalogueCategory
|
||||
} from 'ui/registry/feature_catalogue';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { APP_ID, APP_ICON } from '../common/constants';
|
||||
import { getAppTitle } from '../common/i18n_getters';
|
||||
|
||||
FeatureCatalogueRegistryProvider.register(() => {
|
||||
return {
|
||||
id: 'maps',
|
||||
title: 'Maps',
|
||||
description: 'Explore geospatial data from Elasticsearch and the Elastic Maps Service',
|
||||
icon: 'gisApp',
|
||||
id: APP_ID,
|
||||
title: getAppTitle(),
|
||||
description: i18n.translate('xpack.maps.feature.appDescription', {
|
||||
defaultMessage: 'Explore geospatial data from Elasticsearch and the Elastic Maps Service'
|
||||
}),
|
||||
icon: APP_ICON,
|
||||
path: '/app/maps',
|
||||
showOnHomePage: true,
|
||||
category: FeatureCatalogueCategory.DATA
|
||||
|
|
|
@ -15,6 +15,7 @@ import {
|
|||
EuiToolTip,
|
||||
EuiIconTip
|
||||
} from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
function flattenPanelTree(tree, array = []) {
|
||||
array.push(tree);
|
||||
|
@ -103,7 +104,7 @@ export class LayerTocActions extends Component {
|
|||
if (layer.hasErrors()) {
|
||||
smallLegendIcon = (
|
||||
<EuiIconTip
|
||||
aria-label="Load warning"
|
||||
aria-label={i18n.translate('xpack.maps.layerTocActions.loadWarningAriaLabel', { defaultMessage: 'Load warning' })}
|
||||
size="m"
|
||||
type="alert"
|
||||
color="warning"
|
||||
|
@ -118,8 +119,12 @@ export class LayerTocActions extends Component {
|
|||
smallLegendIcon = (
|
||||
<EuiToolTip
|
||||
position="top"
|
||||
content={`Map is at zoom level ${zoom}.
|
||||
This layer is only visible between zoom levels ${minZoom} to ${maxZoom}.`}
|
||||
content={
|
||||
i18n.translate('xpack.maps.layerTocActions.zoomFeedbackTooltip', {
|
||||
defaultMessage: `Map is at zoom level {zoom}.
|
||||
This layer is only visible between zoom levels {minZoom} to {maxZoom}.`,
|
||||
values: { minZoom, maxZoom, zoom }
|
||||
})}
|
||||
>
|
||||
{icon}
|
||||
</EuiToolTip>
|
||||
|
@ -135,10 +140,14 @@ export class LayerTocActions extends Component {
|
|||
const visibilityToggle = this._getVisbilityIcon();
|
||||
const panelTree = {
|
||||
id: 0,
|
||||
title: 'Layer actions',
|
||||
title: i18n.translate('xpack.maps.layerTocActions.layerActionsTitle', {
|
||||
defaultMessage: 'Layer actions',
|
||||
}),
|
||||
items: [
|
||||
{
|
||||
name: 'Fit to data',
|
||||
name: i18n.translate('xpack.maps.layerTocActions.fitToDataTitle', {
|
||||
defaultMessage: 'Fit to data',
|
||||
}),
|
||||
icon: (
|
||||
<EuiIcon
|
||||
type="search"
|
||||
|
@ -146,7 +155,9 @@ export class LayerTocActions extends Component {
|
|||
/>
|
||||
),
|
||||
'data-test-subj': 'fitToBoundsButton',
|
||||
toolTipContent: this.state.supportsFitToBounds ? null : 'Layer does not support fit to data',
|
||||
toolTipContent: this.state.supportsFitToBounds ? null : i18n.translate('xpack.maps.layerTocActions.noFitSupportTooltip', {
|
||||
defaultMessage: 'Layer does not support fit to data',
|
||||
}),
|
||||
disabled: !this.state.supportsFitToBounds,
|
||||
onClick: () => {
|
||||
this._closePopover();
|
||||
|
@ -154,7 +165,11 @@ export class LayerTocActions extends Component {
|
|||
},
|
||||
},
|
||||
{
|
||||
name: this.props.layer.isVisible() ? 'Hide layer' : 'Show layer',
|
||||
name: this.props.layer.isVisible() ? i18n.translate('xpack.maps.layerTocActions.hideLayerTitle', {
|
||||
defaultMessage: 'Hide layer',
|
||||
}) : i18n.translate('xpack.maps.layerTocActions.showLayerTitle', {
|
||||
defaultMessage: 'Show layer',
|
||||
}),
|
||||
icon: visibilityToggle,
|
||||
'data-test-subj': 'layerVisibilityToggleButton',
|
||||
onClick: () => {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
|
||||
|
||||
import { LayerTocActions } from './layer_toc_actions';
|
||||
|
||||
|
@ -41,7 +41,7 @@ describe('LayerTocActions', () => {
|
|||
});
|
||||
|
||||
test('is rendered', async () => {
|
||||
const component = shallow(
|
||||
const component = shallowWithIntl(
|
||||
<LayerTocActions
|
||||
{...defaultProps}
|
||||
/>
|
||||
|
@ -58,7 +58,7 @@ describe('LayerTocActions', () => {
|
|||
|
||||
test('should disable fit to data when supportsFitToBounds is false', async () => {
|
||||
supportsFitToBounds = false;
|
||||
const component = shallow(
|
||||
const component = shallowWithIntl(
|
||||
<LayerTocActions
|
||||
{...defaultProps}
|
||||
/>
|
||||
|
@ -75,7 +75,7 @@ describe('LayerTocActions', () => {
|
|||
|
||||
test('should display spinner when layer is loading', async () => {
|
||||
isLayerLoading = true;
|
||||
const component = shallow(
|
||||
const component = shallowWithIntl(
|
||||
<LayerTocActions
|
||||
{...defaultProps}
|
||||
/>
|
||||
|
@ -92,7 +92,7 @@ describe('LayerTocActions', () => {
|
|||
|
||||
test('should show warning when layer has errors', async () => {
|
||||
hasErrors = true;
|
||||
const component = shallow(
|
||||
const component = shallowWithIntl(
|
||||
<LayerTocActions
|
||||
{...defaultProps}
|
||||
/>
|
||||
|
@ -109,7 +109,7 @@ describe('LayerTocActions', () => {
|
|||
|
||||
test('should show visible toggle when layer is not visible', async () => {
|
||||
isVisible = false;
|
||||
const component = shallow(
|
||||
const component = shallowWithIntl(
|
||||
<LayerTocActions
|
||||
{...defaultProps}
|
||||
/>
|
||||
|
@ -126,7 +126,7 @@ describe('LayerTocActions', () => {
|
|||
|
||||
test('should provide feedback when layer is not visible because of current zoom level', async () => {
|
||||
showAtZoomLevel = false;
|
||||
const component = shallow(
|
||||
const component = shallowWithIntl(
|
||||
<LayerTocActions
|
||||
{...defaultProps}
|
||||
/>
|
||||
|
|
|
@ -25,6 +25,8 @@ import {
|
|||
EuiCallOut,
|
||||
EuiBetaBadge,
|
||||
} from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
export const EMPTY_FILTER = '';
|
||||
|
||||
|
@ -86,7 +88,9 @@ export class MapListing extends React.Component {
|
|||
await this.props.delete(this.state.selectedIds);
|
||||
} catch (error) {
|
||||
toastNotifications.addDanger({
|
||||
title: `Unable to delete map(s)`,
|
||||
title: i18n.translate('xpack.maps.mapListing.unableToDeleteToastTitle', {
|
||||
defaultMessage: `Unable to delete map(s)`
|
||||
}),
|
||||
text: `${error}`,
|
||||
});
|
||||
}
|
||||
|
@ -168,14 +172,25 @@ export class MapListing extends React.Component {
|
|||
return (
|
||||
<EuiOverlayMask>
|
||||
<EuiConfirmModal
|
||||
title="Delete selected items?"
|
||||
title={i18n.translate('xpack.maps.mapListing.deleteSelectedItemsTitle', {
|
||||
defaultMessage: 'Delete selected items?'
|
||||
})}
|
||||
onCancel={this.closeDeleteModal}
|
||||
onConfirm={this.deleteSelectedItems}
|
||||
cancelButtonText="Cancel"
|
||||
confirmButtonText="Delete"
|
||||
cancelButtonText={i18n.translate('xpack.maps.mapListing.cancelTitle', {
|
||||
defaultMessage: 'Cancel'
|
||||
})}
|
||||
confirmButtonText={i18n.translate('xpack.maps.mapListing.deleteTitle', {
|
||||
defaultMessage: 'Delete'
|
||||
})}
|
||||
defaultFocusedButton="cancel"
|
||||
>
|
||||
<p>{`You can't recover deleted items.`}</p>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.maps.mapListing.deleteWarning"
|
||||
defaultMessage="You can't recover deleted items."
|
||||
/>
|
||||
</p>
|
||||
</EuiConfirmModal>
|
||||
</EuiOverlayMask>
|
||||
);
|
||||
|
@ -186,14 +201,32 @@ export class MapListing extends React.Component {
|
|||
return (
|
||||
<React.Fragment>
|
||||
<EuiCallOut
|
||||
title="Listing limit exceeded"
|
||||
title={
|
||||
i18n.translate('xpack.maps.mapListing.limitExceededTitle', {
|
||||
defaultMessage: 'Listing limit exceeded'
|
||||
})
|
||||
}
|
||||
color="warning"
|
||||
iconType="help"
|
||||
>
|
||||
<p>
|
||||
You have {this.state.totalItems} items,
|
||||
but your <strong>listingLimit</strong> setting prevents the table below from displaying more than {this.props.listingLimit}.
|
||||
You can change this setting under <EuiLink href="#/management/kibana/settings">Advanced Settings</EuiLink>.
|
||||
|
||||
<FormattedMessage
|
||||
id="xpack.maps.mapListing.limitHelpDescription"
|
||||
defaultMessage="You have {totalItems} items,
|
||||
but your <strong>listingLimit</strong> setting prevents the table below from displaying more than {listingLimit}.
|
||||
You can change this setting under "
|
||||
values={{
|
||||
totalItems: this.state.totalItems,
|
||||
listingLimit: this.props.listingLimit
|
||||
}}
|
||||
/>
|
||||
<EuiLink href="#/management/kibana/settings">
|
||||
<FormattedMessage
|
||||
id="xpack.maps.mapListing.advancedSettingsLinkText"
|
||||
defaultMessage="Advanced Settings"
|
||||
/>
|
||||
</EuiLink>.
|
||||
</p>
|
||||
</EuiCallOut>
|
||||
<EuiSpacer size="m" />
|
||||
|
@ -208,10 +241,14 @@ export class MapListing extends React.Component {
|
|||
}
|
||||
|
||||
if (this.hasNoItems()) {
|
||||
return `Looks like you don't have any maps. Click the create button to create one.`;
|
||||
return i18n.translate('xpack.maps.mapListing.noItemsDescription', {
|
||||
defaultMessage: `Looks like you don't have any maps. Click the create button to create one.`
|
||||
});
|
||||
}
|
||||
|
||||
return 'No items matched your search.';
|
||||
return i18n.translate('xpack.maps.mapListing.noMatchDescription', {
|
||||
defaultMessage: 'No items matched your search.'
|
||||
});
|
||||
}
|
||||
|
||||
renderSearchBar() {
|
||||
|
@ -225,7 +262,10 @@ export class MapListing extends React.Component {
|
|||
data-test-subj="deleteSelectedItems"
|
||||
key="delete"
|
||||
>
|
||||
Delete selected
|
||||
<FormattedMessage
|
||||
id="xpack.maps.mapListing.deleteSelectedButtonLabel"
|
||||
defaultMessage="Delete selected"
|
||||
/>
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
);
|
||||
|
@ -236,8 +276,12 @@ export class MapListing extends React.Component {
|
|||
{deleteBtn}
|
||||
<EuiFlexItem grow={true}>
|
||||
<EuiFieldSearch
|
||||
aria-label="Filter items"
|
||||
placeholder="Search..."
|
||||
aria-label={i18n.translate('xpack.maps.mapListing.searchAriaLabel', {
|
||||
defaultMessage: 'Filter items'
|
||||
})}
|
||||
placeholder={i18n.translate('xpack.maps.mapListing.searchPlaceholder', {
|
||||
defaultMessage: 'Search...'
|
||||
})}
|
||||
fullWidth
|
||||
value={this.state.filter}
|
||||
onChange={(e) => {
|
||||
|
@ -256,7 +300,9 @@ export class MapListing extends React.Component {
|
|||
const tableColumns = [
|
||||
{
|
||||
field: 'title',
|
||||
name: 'Title',
|
||||
name: i18n.translate('xpack.maps.mapListing.titleFieldTitle', {
|
||||
defaultMessage: 'Title'
|
||||
}),
|
||||
sortable: true,
|
||||
render: (field, record) => (
|
||||
<EuiLink
|
||||
|
@ -269,7 +315,9 @@ export class MapListing extends React.Component {
|
|||
},
|
||||
{
|
||||
field: 'description',
|
||||
name: 'Description',
|
||||
name: i18n.translate('xpack.maps.mapListing.descriptionFieldTitle', {
|
||||
defaultMessage: 'Description'
|
||||
}),
|
||||
dataType: 'string',
|
||||
sortable: true,
|
||||
}
|
||||
|
@ -321,7 +369,10 @@ export class MapListing extends React.Component {
|
|||
data-test-subj="newMapLink"
|
||||
fill
|
||||
>
|
||||
Create map
|
||||
<FormattedMessage
|
||||
id="xpack.maps.mapListing.createMapButtonLabel"
|
||||
defaultMessage="Create map"
|
||||
/>
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
);
|
||||
|
@ -335,7 +386,10 @@ export class MapListing extends React.Component {
|
|||
<EuiFlexItem grow={false}>
|
||||
<EuiTitle size="l">
|
||||
<h1>
|
||||
Maps
|
||||
<FormattedMessage
|
||||
id="xpack.maps.mapListing.listingTableTitle"
|
||||
defaultMessage="Maps"
|
||||
/>
|
||||
</h1>
|
||||
</EuiTitle>
|
||||
</EuiFlexItem>
|
||||
|
@ -343,7 +397,11 @@ export class MapListing extends React.Component {
|
|||
<EuiFlexItem grow={false}>
|
||||
<EuiBetaBadge
|
||||
label="Beta"
|
||||
tooltipContent="Maps is still in beta. Please help us improve by reporting issues or bugs in the Kibana repo."
|
||||
tooltipContent={
|
||||
i18n.translate('xpack.maps.mapListing.betaMessageBadge', {
|
||||
defaultMessage: 'Maps is still in beta. Please help us improve by reporting issues or bugs in the Kibana repo.'
|
||||
})
|
||||
}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
|
|
|
@ -6,15 +6,30 @@
|
|||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { EuiComboBox } from '@elastic/eui';
|
||||
|
||||
const AGG_OPTIONS = [
|
||||
{ label: 'Average', value: 'avg' },
|
||||
{ label: 'Count', value: 'count' },
|
||||
{ label: 'Max', value: 'max' },
|
||||
{ label: 'Min', value: 'min' },
|
||||
{ label: 'Sum', value: 'sum' },
|
||||
{ label: i18n.translate('xpack.maps.metricSelect.averageDropDownOptionLabel', {
|
||||
defaultMessage: 'Average'
|
||||
}),
|
||||
value: 'avg' },
|
||||
{ label: i18n.translate('xpack.maps.metricSelect.countDropDownOptionLabel', {
|
||||
defaultMessage: 'Count'
|
||||
}),
|
||||
value: 'count' },
|
||||
{ label: i18n.translate('xpack.maps.metricSelect.maxDropDownOptionLabel', {
|
||||
defaultMessage: 'Max'
|
||||
}),
|
||||
value: 'max' },
|
||||
{ label: i18n.translate('xpack.maps.metricSelect.minDropDownOptionLabel', {
|
||||
defaultMessage: 'Min'
|
||||
}),
|
||||
value: 'min' },
|
||||
{ label: i18n.translate('xpack.maps.metricSelect.sumDropDownOptionLabel', {
|
||||
defaultMessage: 'Sum'
|
||||
}),
|
||||
value: 'sum' },
|
||||
];
|
||||
|
||||
export const METRIC_AGGREGATION_VALUES = AGG_OPTIONS.map(({ value }) => { return value; });
|
||||
|
@ -34,7 +49,11 @@ export function MetricSelect({ value, onChange, metricsFilter }) {
|
|||
|
||||
return (
|
||||
<EuiComboBox
|
||||
placeholder="Select aggregation"
|
||||
placeholder={
|
||||
i18n.translate('xpack.maps.metricSelect.selectAggregationPlaceholder', {
|
||||
defaultMessage: 'Select aggregation'
|
||||
})
|
||||
}
|
||||
singleSelection={true}
|
||||
isClearable={false}
|
||||
options={options}
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
import React, { Fragment } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
|
||||
import {
|
||||
EuiFlexGroup,
|
||||
|
@ -60,7 +62,9 @@ export function MetricsEditor({ fields, metrics, onChange, allowMultipleMetrics,
|
|||
fieldSelect = (
|
||||
<EuiFlexItem>
|
||||
<SingleFieldSelect
|
||||
placeholder="Select field"
|
||||
placeholder={i18n.translate('xpack.maps.metricsEditor.selectFieldPlaceholder', {
|
||||
defaultMessage: 'Select field'
|
||||
})}
|
||||
value={metric.field}
|
||||
onChange={onFieldChange}
|
||||
filterField={filterNumberFields}
|
||||
|
@ -77,8 +81,12 @@ export function MetricsEditor({ fields, metrics, onChange, allowMultipleMetrics,
|
|||
<EuiButtonIcon
|
||||
iconType="trash"
|
||||
color="danger"
|
||||
aria-label="Delete metric"
|
||||
title="Delete metric"
|
||||
aria-label={i18n.translate('xpack.maps.metricsEditor.deleteMetricAriaLabel', {
|
||||
defaultMessage: 'Delete metric'
|
||||
})}
|
||||
title={i18n.translate('xpack.maps.metricsEditor.deleteMetricButtonLabel', {
|
||||
defaultMessage: 'Delete metric'
|
||||
})}
|
||||
onClick={onRemove}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
|
@ -120,8 +128,12 @@ export function MetricsEditor({ fields, metrics, onChange, allowMultipleMetrics,
|
|||
return (<EuiButtonIcon
|
||||
iconType="plusInCircle"
|
||||
onClick={addMetric}
|
||||
aria-label="Add metric"
|
||||
title="Add metric"
|
||||
aria-label={i18n.translate('xpack.maps.metricsEditor.addMetricAriaLabel', {
|
||||
defaultMessage: 'Add metric'
|
||||
})}
|
||||
title={i18n.translate('xpack.maps.metricsEditor.addMetricButtonLabel', {
|
||||
defaultMessage: 'Add metric'
|
||||
})}
|
||||
/>);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,24 +8,45 @@ import chrome from 'ui/chrome';
|
|||
|
||||
import React from 'react';
|
||||
import { EuiCallOut, EuiLink } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
export function NoIndexPatternCallout() {
|
||||
return (
|
||||
<EuiCallOut
|
||||
title="Couldn't find any index patterns with geospatial fields"
|
||||
title={
|
||||
i18n.translate('xpack.maps.noIndexPattern.messageTitle', {
|
||||
defaultMessage: `Couldn't find any index patterns with geospatial fields`
|
||||
})
|
||||
}
|
||||
color="warning"
|
||||
>
|
||||
<p>
|
||||
You’ll need to{' '}
|
||||
<FormattedMessage
|
||||
id="xpack.maps.noIndexPattern.doThisPrefixDescription"
|
||||
defaultMessage="You'll need to "
|
||||
/>
|
||||
<EuiLink href={chrome.addBasePath('/app/kibana#/management/kibana/index_pattern')}>
|
||||
create an index pattern
|
||||
</EuiLink>{' '}
|
||||
with geospatial fields.
|
||||
<FormattedMessage
|
||||
id="xpack.maps.noIndexPattern.doThisLinkTextDescription"
|
||||
defaultMessage="create an index pattern"
|
||||
/>
|
||||
</EuiLink>
|
||||
<FormattedMessage
|
||||
id="xpack.maps.noIndexPattern.doThisSuffixDescription"
|
||||
defaultMessage=" with geospatial fields."
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
Don’t have any geospatial data sets?{' '}
|
||||
<FormattedMessage
|
||||
id="xpack.maps.noIndexPattern.hintDescription"
|
||||
defaultMessage="Don't have any geospatial data sets? "
|
||||
/>
|
||||
<EuiLink href={chrome.addBasePath('/app/kibana#/home/tutorial_directory/sampleData')}>
|
||||
Get started with some sample data sets.
|
||||
<FormattedMessage
|
||||
id="xpack.maps.noIndexPattern.getStartedLinkText"
|
||||
defaultMessage="Get started with some sample data sets."
|
||||
/>
|
||||
</EuiLink>
|
||||
</p>
|
||||
</EuiCallOut>
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
import React, { Fragment } from 'react';
|
||||
|
||||
import { EuiRange, EuiFormErrorText } from '@elastic/eui';
|
||||
import { FormattedText } from '@kbn/i18n/react';
|
||||
|
||||
function isWithinRange(min, max, value) {
|
||||
if (value >= min && value <= max) {
|
||||
|
@ -68,7 +69,11 @@ export class ValidatedRange extends React.Component {
|
|||
if (!this.state.isValid) {
|
||||
errorMessage = (
|
||||
<EuiFormErrorText>
|
||||
{`Must be between ${min} and ${max}`}
|
||||
<FormattedText
|
||||
id="xpack.maps.validatedRange.rangeErrorMessage"
|
||||
defaultMessage="Must be between {min} and {max}"
|
||||
values={{ min, max }}
|
||||
/>
|
||||
</EuiFormErrorText>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -20,15 +20,14 @@ export class HeatmapLayer extends AbstractLayer {
|
|||
static createDescriptor(options) {
|
||||
const heatmapLayerDescriptor = super.createDescriptor(options);
|
||||
heatmapLayerDescriptor.type = HeatmapLayer.type;
|
||||
const defaultStyle = HeatmapStyle.createDescriptor('coarse');
|
||||
heatmapLayerDescriptor.style = defaultStyle;
|
||||
heatmapLayerDescriptor.style = HeatmapStyle.createDescriptor();
|
||||
return heatmapLayerDescriptor;
|
||||
}
|
||||
|
||||
constructor({ layerDescriptor, source, style }) {
|
||||
super({ layerDescriptor, source, style });
|
||||
if (!style) {
|
||||
const defaultStyle = HeatmapStyle.createDescriptor('coarse');
|
||||
const defaultStyle = HeatmapStyle.createDescriptor();
|
||||
this._style = new HeatmapStyle(defaultStyle);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import {
|
|||
|
||||
import { getEmsVectorFilesMeta } from '../../../../meta';
|
||||
import { getEmsUnavailableMessage } from '../ems_unavailable_message';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
export class EMSFileCreateSourceEditor extends React.Component {
|
||||
|
||||
|
@ -63,11 +64,19 @@ export class EMSFileCreateSourceEditor extends React.Component {
|
|||
|
||||
return (
|
||||
<EuiFormRow
|
||||
label="Layer"
|
||||
label={
|
||||
i18n.translate('xpack.maps.source.emsFile.layerLabel', {
|
||||
defaultMessage: 'Layer'
|
||||
})
|
||||
}
|
||||
helpText={this.state.emsFileOptionsRaw.length === 0 ? getEmsUnavailableMessage() : null}
|
||||
>
|
||||
<EuiComboBox
|
||||
placeholder="Select EMS vector shapes"
|
||||
placeholder={
|
||||
i18n.translate('xpack.maps.source.emsFile.selectPlaceholder', {
|
||||
defaultMessage: 'Select EMS vector shapes'
|
||||
})
|
||||
}
|
||||
options={options}
|
||||
selectedOptions={this.state.selectedOption ? [this.state.selectedOption] : []}
|
||||
onChange={this._onChange}
|
||||
|
|
|
@ -10,12 +10,18 @@ import { GIS_API_PATH, EMS_FILE } from '../../../../../common/constants';
|
|||
import { emsServiceSettings } from '../../../../kibana_services';
|
||||
import { getEmsVectorFilesMeta } from '../../../../meta';
|
||||
import { EMSFileCreateSourceEditor } from './create_source_editor';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { getDataSourceLabel } from '../../../../../common/i18n_getters';
|
||||
|
||||
export class EMSFileSource extends AbstractVectorSource {
|
||||
|
||||
static type = EMS_FILE;
|
||||
static title = 'Vector shapes';
|
||||
static description = 'Vector shapes of administrative boundaries from Elastic Maps Service';
|
||||
static title = i18n.translate('xpack.maps.source.emsFileTitle', {
|
||||
defaultMessage: 'Vector shapes'
|
||||
});
|
||||
static description = i18n.translate('xpack.maps.source.emsFileDescription', {
|
||||
defaultMessage: 'Vector shapes of administrative boundaries from Elastic Maps Service'
|
||||
});
|
||||
static icon = 'emsApp';
|
||||
|
||||
static createDescriptor(id) {
|
||||
|
@ -38,7 +44,12 @@ export class EMSFileSource extends AbstractVectorSource {
|
|||
const emsFiles = await getEmsVectorFilesMeta();
|
||||
const meta = emsFiles.find((source => source.id === this._descriptor.id));
|
||||
if (!meta) {
|
||||
throw new Error(`Unable to find EMS vector shapes for id: ${this._descriptor.id}`);
|
||||
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
|
||||
}
|
||||
}));
|
||||
}
|
||||
return meta;
|
||||
}
|
||||
|
@ -59,8 +70,16 @@ export class EMSFileSource extends AbstractVectorSource {
|
|||
async getImmutableProperties() {
|
||||
const emsLink = await emsServiceSettings.getEMSHotLink({ id: this._descriptor.id });
|
||||
return [
|
||||
{ label: 'Data source', value: EMSFileSource.title },
|
||||
{ label: 'Layer', value: this._descriptor.id, link: emsLink }
|
||||
{
|
||||
label: getDataSourceLabel(),
|
||||
value: EMSFileSource.title
|
||||
},
|
||||
{
|
||||
label: i18n.translate('xpack.maps.source.emsFile.layerLabel', {
|
||||
defaultMessage: `Layer`,
|
||||
}),
|
||||
value: this._descriptor.id,
|
||||
link: emsLink }
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ import {
|
|||
|
||||
import { getEmsTMSServices } from '../../../../meta';
|
||||
import { getEmsUnavailableMessage } from '../ems_unavailable_message';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
export class EMSTMSCreateSourceEditor extends React.Component {
|
||||
|
||||
|
@ -53,7 +54,9 @@ export class EMSTMSCreateSourceEditor extends React.Component {
|
|||
|
||||
return (
|
||||
<EuiFormRow
|
||||
label="Tile service"
|
||||
label={i18n.translate('xpack.maps.source.emsTile.label', {
|
||||
defaultMessage: 'Tile service',
|
||||
})}
|
||||
helpText={this.state.emsTmsOptionsRaw.length === 0 ? getEmsUnavailableMessage() : null}
|
||||
>
|
||||
<EuiSelect
|
||||
|
|
|
@ -9,13 +9,19 @@ import { TileLayer } from '../../tile_layer';
|
|||
|
||||
import { getEmsTMSServices } from '../../../../meta';
|
||||
import { EMSTMSCreateSourceEditor } from './create_source_editor';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { getDataSourceLabel } from '../../../../../common/i18n_getters';
|
||||
|
||||
|
||||
export class EMSTMSSource extends AbstractTMSSource {
|
||||
|
||||
static type = 'EMS_TMS';
|
||||
static title = 'Tiles';
|
||||
static description = 'Map tiles from Elastic Maps Service';
|
||||
static title = i18n.translate('xpack.maps.source.emsTileTitle', {
|
||||
defaultMessage: 'Tiles'
|
||||
});
|
||||
static description = i18n.translate('xpack.maps.source.emsTileDescription', {
|
||||
defaultMessage: 'Map tiles from Elastic Maps Service'
|
||||
});
|
||||
static icon = 'emsApp';
|
||||
|
||||
static createDescriptor(serviceId) {
|
||||
|
@ -39,8 +45,16 @@ export class EMSTMSSource extends AbstractTMSSource {
|
|||
|
||||
async getImmutableProperties() {
|
||||
return [
|
||||
{ label: 'Data source', value: EMSTMSSource.title },
|
||||
{ label: 'Tile service', value: this._descriptor.id }
|
||||
{
|
||||
label: getDataSourceLabel(),
|
||||
value: EMSTMSSource.title
|
||||
},
|
||||
{
|
||||
label: i18n.translate('xpack.maps.source.emsTile.serviceId', {
|
||||
defaultMessage: `Tile service`,
|
||||
}),
|
||||
value: this._descriptor.id
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -50,7 +64,10 @@ export class EMSTMSSource extends AbstractTMSSource {
|
|||
return service.id === this._descriptor.id;
|
||||
});
|
||||
if (!meta) {
|
||||
throw new Error(`Unable to find EMS tile configuration for id: ${this._descriptor.id}`);
|
||||
throw new Error(i18n.translate('xpack.maps.source.emsTile.errorMessage', {
|
||||
defaultMessage: `Unable to find EMS tile configuration for id: {id}`,
|
||||
values: { id: this._descriptor.id }
|
||||
}));
|
||||
}
|
||||
return meta;
|
||||
}
|
||||
|
|
|
@ -5,19 +5,18 @@
|
|||
*/
|
||||
|
||||
import chrome from 'ui/chrome';
|
||||
|
||||
const NO_EMS_ACCESS_MSG =
|
||||
'Kibana is unable to access Elastic Maps Service. Contact your system administrator';
|
||||
|
||||
const EMS_ACCESS_DISABLED_MSG =
|
||||
'Access to Elastic Maps Service has been disabled.' +
|
||||
' Ask your system administrator to set "map.includeElasticMapsService" in kibana.yml.';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
export function getEmsUnavailableMessage() {
|
||||
const isEmsEnabled = chrome.getInjected('isEmsEnabled', true);
|
||||
if (isEmsEnabled) {
|
||||
return NO_EMS_ACCESS_MSG;
|
||||
return i18n.translate('xpack.maps.source.ems.noAccessDescription', {
|
||||
defaultMessage: 'Kibana is unable to access Elastic Maps Service. Contact your system administrator'
|
||||
});
|
||||
}
|
||||
|
||||
return EMS_ACCESS_DISABLED_MSG;
|
||||
return i18n.translate('xpack.maps.source.ems.disabledDescription', {
|
||||
// eslint-disable-next-line max-len
|
||||
defaultMessage: 'Access to Elastic Maps Service has been disabled. Ask your system administrator to set "map.includeElasticMapsService" in kibana.yml.'
|
||||
});
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import { SingleFieldSelect } from '../../../components/single_field_select';
|
|||
import { RENDER_AS } from './render_as';
|
||||
import { indexPatternService } from '../../../../kibana_services';
|
||||
import { NoIndexPatternCallout } from '../../../components/no_index_pattern_callout';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import {
|
||||
EuiFormRow,
|
||||
|
@ -26,15 +27,21 @@ function filterGeoField({ type }) {
|
|||
|
||||
const requestTypeOptions = [
|
||||
{
|
||||
label: 'points',
|
||||
label: i18n.translate('xpack.maps.source.esGeoGrid.pointsDropdownOption', {
|
||||
defaultMessage: 'points'
|
||||
}),
|
||||
value: RENDER_AS.POINT
|
||||
},
|
||||
{
|
||||
label: 'grid rectangles',
|
||||
label: i18n.translate('xpack.maps.source.esGeoGrid.gridRectangleDropdownOption', {
|
||||
defaultMessage: 'grid rectangles'
|
||||
}),
|
||||
value: RENDER_AS.GRID
|
||||
},
|
||||
{
|
||||
label: 'heat map',
|
||||
label: i18n.translate('xpack.maps.source.esGeoGrid.heatmapDropdownOption', {
|
||||
defaultMessage: 'heat map'
|
||||
}),
|
||||
value: RENDER_AS.HEATMAP
|
||||
}
|
||||
];
|
||||
|
@ -146,9 +153,14 @@ export class CreateSourceEditor extends Component {
|
|||
}
|
||||
|
||||
return (
|
||||
<EuiFormRow label="Geospatial field">
|
||||
<EuiFormRow label={i18n.translate('xpack.maps.source.esGeoGrid.geofieldLabel', {
|
||||
defaultMessage: 'Geospatial field'
|
||||
})}
|
||||
>
|
||||
<SingleFieldSelect
|
||||
placeholder="Select geo field"
|
||||
placeholder={i18n.translate('xpack.maps.source.esGeoGrid.geofieldPlaceholder', {
|
||||
defaultMessage: 'Select geo field'
|
||||
})}
|
||||
value={this.state.geoField}
|
||||
onChange={this._onGeoFieldSelect}
|
||||
filterField={filterGeoField}
|
||||
|
@ -164,9 +176,14 @@ export class CreateSourceEditor extends Component {
|
|||
}
|
||||
|
||||
return (
|
||||
<EuiFormRow label="Show as">
|
||||
<EuiFormRow label={i18n.translate('xpack.maps.source.esGeoGrid.showAsLabel', {
|
||||
defaultMessage: 'Show as'
|
||||
})}
|
||||
>
|
||||
<EuiComboBox
|
||||
placeholder="Select a single option"
|
||||
placeholder={i18n.translate('xpack.maps.source.esGeoGrid.showAsPlaceholder', {
|
||||
defaultMessage: 'Select a single option'
|
||||
})}
|
||||
singleSelection={{ asPlainText: true }}
|
||||
options={requestTypeOptions}
|
||||
selectedOptions={[this.state.requestType]}
|
||||
|
@ -178,12 +195,17 @@ export class CreateSourceEditor extends Component {
|
|||
|
||||
_renderIndexPatternSelect() {
|
||||
return (
|
||||
<EuiFormRow label="Index pattern">
|
||||
<EuiFormRow label={i18n.translate('xpack.maps.source.esGeoGrid.indexPatternLabel', {
|
||||
defaultMessage: 'Index pattern'
|
||||
})}
|
||||
>
|
||||
<IndexPatternSelect
|
||||
isDisabled={this.state.noGeoIndexPatternsExist}
|
||||
indexPatternId={this.state.indexPatternId}
|
||||
onChange={this.onIndexPatternSelect}
|
||||
placeholder="Select index pattern"
|
||||
placeholder={i18n.translate('xpack.maps.source.esGeoGrid.indexPatternPlaceholder', {
|
||||
defaultMessage: 'Select index pattern'
|
||||
})}
|
||||
fieldTypes={['geo_point']}
|
||||
onNoIndexPatterns={this._onNoIndexPatterns}
|
||||
/>
|
||||
|
|
|
@ -21,6 +21,8 @@ import { UpdateSourceEditor } from './update_source_editor';
|
|||
import { GRID_RESOLUTION } from '../../grid_resolution';
|
||||
import { SOURCE_DATA_ID_ORIGIN, ES_GEO_GRID } from '../../../../../common/constants';
|
||||
import { filterPropertiesForTooltip } from '../../util';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { getDataSourceLabel } from '../../../../../common/i18n_getters';
|
||||
|
||||
const COUNT_PROP_LABEL = 'count';
|
||||
const COUNT_PROP_NAME = 'doc_count';
|
||||
|
@ -51,8 +53,12 @@ const aggSchemas = new Schemas([
|
|||
export class ESGeoGridSource extends AbstractESSource {
|
||||
|
||||
static type = ES_GEO_GRID;
|
||||
static title = 'Grid aggregation';
|
||||
static description = 'Geospatial data grouped in grids with metrics for each gridded cell';
|
||||
static title = i18n.translate('xpack.maps.source.esGridTitle', {
|
||||
defaultMessage: 'Grid aggregation'
|
||||
});
|
||||
static description = i18n.translate('xpack.maps.source.esGridDescription', {
|
||||
defaultMessage: 'Geospatial data grouped in grids with metrics for each gridded cell'
|
||||
});
|
||||
|
||||
static createDescriptor({ indexPatternId, geoField, requestType, resolution }) {
|
||||
return {
|
||||
|
@ -102,10 +108,27 @@ export class ESGeoGridSource extends AbstractESSource {
|
|||
}
|
||||
|
||||
return [
|
||||
{ label: 'Data source', value: ESGeoGridSource.title },
|
||||
{ label: 'Index pattern', value: indexPatternTitle },
|
||||
{ label: 'Geospatial field', value: this._descriptor.geoField },
|
||||
{ label: 'Show as', value: this._descriptor.requestType },
|
||||
{
|
||||
label: getDataSourceLabel(),
|
||||
value: ESGeoGridSource.title
|
||||
},
|
||||
{
|
||||
label: i18n.translate('xpack.maps.source.esGrid.indexPatternLabel', {
|
||||
defaultMessage: 'Index pattern'
|
||||
}),
|
||||
value: indexPatternTitle },
|
||||
{
|
||||
label: i18n.translate('xpack.maps.source.esGrid.geospatialFieldLabel', {
|
||||
defaultMessage: 'Geospatial field'
|
||||
}),
|
||||
value: this._descriptor.geoField
|
||||
},
|
||||
{
|
||||
label: i18n.translate('xpack.maps.source.esGrid.showasFieldLabel', {
|
||||
defaultMessage: 'Show as'
|
||||
}),
|
||||
value: this._descriptor.requestType
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -145,7 +168,12 @@ export class ESGeoGridSource extends AbstractESSource {
|
|||
return 4;
|
||||
}
|
||||
|
||||
throw new Error(`Grid resolution param not recognized: ${this._descriptor.resolution}`);
|
||||
throw new Error(i18n.translate('xpack.maps.source.esGrid.resolutionParamErrorMessage', {
|
||||
defaultMessage: `Grid resolution param not recognized: {resolution}`,
|
||||
values: {
|
||||
resolution: this._descriptor.resolution
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
async getGeoJsonWithMeta(layerName, searchFilters) {
|
||||
|
@ -172,7 +200,9 @@ export class ESGeoGridSource extends AbstractESSource {
|
|||
const searchSource = await this._makeSearchSource(searchFilters, 0);
|
||||
const aggConfigs = new AggConfigs(indexPattern, this._makeAggConfigs(searchFilters.geogridPrecision), aggSchemas.all);
|
||||
searchSource.setField('aggs', aggConfigs.toDsl());
|
||||
const esResponse = await this._runEsQuery(layerName, searchSource, 'Elasticsearch geohash_grid aggregation request');
|
||||
const esResponse = await this._runEsQuery(layerName, searchSource, i18n.translate('xpack.maps.source.esGrid.inspectorDescription', {
|
||||
defaultMessage: 'Elasticsearch geo grid aggregation request'
|
||||
}));
|
||||
|
||||
const tabifiedResp = tabifyAggResponse(aggConfigs, esResponse);
|
||||
const { featureCollection } = convertToGeoJson({
|
||||
|
|
|
@ -12,12 +12,29 @@ import {
|
|||
EuiFlexItem,
|
||||
EuiFormLabel
|
||||
} from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
|
||||
const OPTIONS = [
|
||||
{ value: GRID_RESOLUTION.COARSE, inputDisplay: 'coarse' },
|
||||
{ value: GRID_RESOLUTION.FINE, inputDisplay: 'fine' },
|
||||
{ value: GRID_RESOLUTION.MOST_FINE, inputDisplay: 'finest' }
|
||||
{
|
||||
value: GRID_RESOLUTION.COARSE,
|
||||
inputDisplay: i18n.translate('xpack.maps.source.esGrid.coarseDropdownOption', {
|
||||
defaultMessage: 'coarse'
|
||||
})
|
||||
},
|
||||
{ value: GRID_RESOLUTION.FINE,
|
||||
inputDisplay: i18n.translate('xpack.maps.source.esGrid.fineDropdownOption', {
|
||||
defaultMessage: 'fine'
|
||||
})
|
||||
|
||||
},
|
||||
{
|
||||
value: GRID_RESOLUTION.MOST_FINE,
|
||||
inputDisplay: i18n.translate('xpack.maps.source.esGrid.finestDropdownOption', {
|
||||
defaultMessage: 'finest'
|
||||
})
|
||||
}
|
||||
];
|
||||
|
||||
export function ResolutionEditor({ resolution, onChange }) {
|
||||
|
@ -26,7 +43,10 @@ export function ResolutionEditor({ resolution, onChange }) {
|
|||
<EuiFlexGroup alignItems="center">
|
||||
<EuiFlexItem grow={true}>
|
||||
<EuiFormLabel style={{ marginBottom: 0 }}>
|
||||
Grid resolution
|
||||
<FormattedMessage
|
||||
id="xpack.maps.geoGrid.resolutionLabel"
|
||||
defaultMessage="Grid resolution"
|
||||
/>
|
||||
</EuiFormLabel>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
|
|
|
@ -10,6 +10,7 @@ import { RENDER_AS } from './render_as';
|
|||
import { MetricsEditor } from '../../../components/metrics_editor';
|
||||
import { indexPatternService } from '../../../../kibana_services';
|
||||
import { ResolutionEditor } from './resolution_editor';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
export class UpdateSourceEditor extends Component {
|
||||
|
||||
|
@ -33,7 +34,12 @@ export class UpdateSourceEditor extends Component {
|
|||
} catch (err) {
|
||||
if (this._isMounted) {
|
||||
this.setState({
|
||||
loadError: `Unable to find Index pattern ${this.props.indexPatternId}`
|
||||
loadError: i18n.translate('xpack.maps.source.esGrid.noIndexPatternErrorMessage', {
|
||||
defaultMessage: `Unable to find Index pattern {id}`,
|
||||
values: {
|
||||
id: this.props.indexPatternId
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
return;
|
||||
|
|
|
@ -14,6 +14,7 @@ import {
|
|||
} from '../../../kibana_services';
|
||||
import { AggConfigs } from 'ui/vis/agg_configs';
|
||||
import { timefilter } from 'ui/timefilter/timefilter';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
const TERMS_AGG_NAME = 'join';
|
||||
|
||||
|
@ -62,6 +63,7 @@ export class ESJoinSource extends AbstractESSource {
|
|||
|
||||
|
||||
static renderEditor({}) {
|
||||
//no need to localize. this editor is never rendered.
|
||||
return `<div>editor details</div>`;
|
||||
}
|
||||
|
||||
|
@ -123,7 +125,12 @@ export class ESJoinSource extends AbstractESSource {
|
|||
requestDesc: this.getJoinDescription(leftSourceName, leftFieldName),
|
||||
});
|
||||
} catch (error) {
|
||||
throw new Error(`Elasticsearch search request failed, error: ${error.message}`);
|
||||
throw new Error(i18n.translate('xpack.maps.source.esJoin.errorMessage', {
|
||||
defaultMessage: `Elasticsearch search request failed, error: {message}`,
|
||||
values: {
|
||||
message: error.message
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
const metricPropertyNames = configStates
|
||||
|
@ -154,10 +161,21 @@ export class ESJoinSource extends AbstractESSource {
|
|||
return metric.type !== 'count' ? `${metric.type} ${metric.field}` : 'count';
|
||||
});
|
||||
const joinStatement = [];
|
||||
joinStatement.push(`Join ${leftSourceName}:${leftFieldName} with`);
|
||||
joinStatement.push(i18n.translate('xpack.maps.source.esJoin.joinLeftDescription', {
|
||||
defaultMessage: `Join {leftSourceName}:{leftFieldName} with`,
|
||||
values: { leftSourceName, leftFieldName }
|
||||
}));
|
||||
joinStatement.push(`${this._descriptor.indexPatternTitle}:${this._descriptor.term}`);
|
||||
joinStatement.push(`for metrics ${metrics.join(',')}`);
|
||||
return `Elasticsearch terms aggregation request for ${joinStatement.join(' ')}`;
|
||||
joinStatement.push(i18n.translate('xpack.maps.source.esJoin.joinMetricsDescription', {
|
||||
defaultMessage: `for metrics {metrics}`,
|
||||
values: { metrics: metrics.join(',') }
|
||||
}));
|
||||
return i18n.translate('xpack.maps.source.esJoin.joinDescription', {
|
||||
defaultMessage: `Elasticsearch terms aggregation request for {description}`,
|
||||
values: {
|
||||
description: joinStatement.join(' ')
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_makeAggConfigs() {
|
||||
|
@ -191,6 +209,7 @@ export class ESJoinSource extends AbstractESSource {
|
|||
}
|
||||
|
||||
async getDisplayName() {
|
||||
//no need to localize. this is never rendered.
|
||||
return `es_table ${this._descriptor.indexPatternId}`;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import { IndexPatternSelect } from 'ui/index_patterns/components/index_pattern_s
|
|||
import { SingleFieldSelect } from '../../../components/single_field_select';
|
||||
import { indexPatternService } from '../../../../kibana_services';
|
||||
import { NoIndexPatternCallout } from '../../../components/no_index_pattern_callout';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
function filterGeoField(field) {
|
||||
return ['geo_point', 'geo_shape'].includes(field.type);
|
||||
|
@ -22,14 +23,14 @@ export class CreateSourceEditor extends Component {
|
|||
|
||||
static propTypes = {
|
||||
onSelect: PropTypes.func.isRequired,
|
||||
}
|
||||
};
|
||||
|
||||
state = {
|
||||
isLoadingIndexPattern: false,
|
||||
indexPatternId: '',
|
||||
geoField: '',
|
||||
noGeoIndexPatternsExist: false,
|
||||
}
|
||||
};
|
||||
|
||||
componentWillUnmount() {
|
||||
this._isMounted = false;
|
||||
|
@ -52,7 +53,7 @@ export class CreateSourceEditor extends Component {
|
|||
indexPattern: undefined,
|
||||
geoField: undefined,
|
||||
}, this.debouncedLoad.bind(null, indexPatternId));
|
||||
}
|
||||
};
|
||||
|
||||
debouncedLoad = _.debounce(async (indexPatternId) => {
|
||||
if (!indexPatternId || indexPatternId.length === 0) {
|
||||
|
@ -126,10 +127,14 @@ export class CreateSourceEditor extends Component {
|
|||
|
||||
return (
|
||||
<EuiFormRow
|
||||
label="Geospatial field"
|
||||
label={i18n.translate('xpack.maps.source.esSearch.geofieldLabel', {
|
||||
defaultMessage: 'Geospatial field'
|
||||
})}
|
||||
>
|
||||
<SingleFieldSelect
|
||||
placeholder="Select geo field"
|
||||
placeholder={i18n.translate('xpack.maps.source.esSearch.selectLabel', {
|
||||
defaultMessage: 'Select geo field'
|
||||
})}
|
||||
value={this.state.geoField}
|
||||
onChange={this.onGeoFieldSelect}
|
||||
filterField={filterGeoField}
|
||||
|
@ -159,13 +164,18 @@ export class CreateSourceEditor extends Component {
|
|||
{this._renderNoIndexPatternWarning()}
|
||||
|
||||
<EuiFormRow
|
||||
label="Index pattern"
|
||||
label={
|
||||
i18n.translate('xpack.maps.source.esSearch.indexPatternLabel', {
|
||||
defaultMessage: 'Index pattern'
|
||||
})}
|
||||
>
|
||||
<IndexPatternSelect
|
||||
isDisabled={this.state.noGeoIndexPatternsExist}
|
||||
indexPatternId={this.state.indexPatternId}
|
||||
onChange={this.onIndexPatternSelect}
|
||||
placeholder="Select index pattern"
|
||||
placeholder={i18n.translate('xpack.maps.source.esSearch.selectIndexPatternPlaceholder', {
|
||||
defaultMessage: 'Select index pattern'
|
||||
})}
|
||||
fieldTypes={['geo_point', 'geo_shape']}
|
||||
onNoIndexPatterns={this._onNoIndexPatterns}
|
||||
/>
|
||||
|
|
|
@ -13,14 +13,20 @@ import { hitsToGeoJson } from '../../../../elasticsearch_geo_utils';
|
|||
import { CreateSourceEditor } from './create_source_editor';
|
||||
import { UpdateSourceEditor } from './update_source_editor';
|
||||
import { ES_SEARCH } from '../../../../../common/constants';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { getDataSourceLabel } from '../../../../../common/i18n_getters';
|
||||
|
||||
const DEFAULT_LIMIT = 2048;
|
||||
|
||||
export class ESSearchSource extends AbstractESSource {
|
||||
|
||||
static type = ES_SEARCH;
|
||||
static title = 'Documents';
|
||||
static description = 'Geospatial data from a Kibana index pattern';
|
||||
static title = i18n.translate('xpack.maps.source.esSearchTitle', {
|
||||
defaultMessage: 'Documents'
|
||||
});
|
||||
static description = i18n.translate('xpack.maps.source.esSearchDescription', {
|
||||
defaultMessage: 'Geospatial data from a Kibana index pattern'
|
||||
});
|
||||
|
||||
static renderEditor({ onPreviewSource, inspectorAdapters }) {
|
||||
const onSelect = (sourceConfig) => {
|
||||
|
@ -96,10 +102,28 @@ export class ESSearchSource extends AbstractESSource {
|
|||
}
|
||||
|
||||
return [
|
||||
{ label: 'Data source', value: ESSearchSource.title },
|
||||
{ label: 'Index pattern', value: indexPatternTitle },
|
||||
{ label: 'Geospatial field', value: this._descriptor.geoField },
|
||||
{ label: 'Geospatial field type', value: geoFieldType },
|
||||
{
|
||||
label: getDataSourceLabel(),
|
||||
value: ESSearchSource.title
|
||||
},
|
||||
{
|
||||
label: i18n.translate('xpack.maps.source.esSearch.indexPatternLabel', {
|
||||
defaultMessage: `Index pattern`,
|
||||
}),
|
||||
value: indexPatternTitle
|
||||
},
|
||||
{
|
||||
label: i18n.translate('xpack.maps.source.esSearch.geoFieldLabel', {
|
||||
defaultMessage: 'Geospatial field',
|
||||
}),
|
||||
value: this._descriptor.geoField
|
||||
},
|
||||
{
|
||||
label: i18n.translate('xpack.maps.source.esSearch.geoFieldTypeLabel', {
|
||||
defaultMessage: 'Geospatial field type',
|
||||
}),
|
||||
value: geoFieldType
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ import {
|
|||
import { MultiFieldSelect } from '../../../components/multi_field_select';
|
||||
|
||||
import { indexPatternService } from '../../../../kibana_services';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
export class UpdateSourceEditor extends Component {
|
||||
|
||||
|
@ -43,7 +44,12 @@ export class UpdateSourceEditor extends Component {
|
|||
} catch (err) {
|
||||
if (this._isMounted) {
|
||||
this.setState({
|
||||
loadError: `Unable to find Index pattern ${this.props.indexPatternId}`
|
||||
loadError: i18n.translate('xpack.maps.source.esSearch.loadErrorMessage', {
|
||||
defaultMessage: `Unable to find Index pattern {id}`,
|
||||
values: {
|
||||
id: this.props.indexPatternId
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
return;
|
||||
|
@ -68,10 +74,17 @@ export class UpdateSourceEditor extends Component {
|
|||
return (
|
||||
<Fragment>
|
||||
<EuiFormRow
|
||||
label="Fields to display in tooltip"
|
||||
label={
|
||||
i18n.translate('xpack.maps.source.esSearch.fieldsLabel', {
|
||||
defaultMessage: `Fields to display in tooltip`
|
||||
})
|
||||
}
|
||||
>
|
||||
<MultiFieldSelect
|
||||
placeholder="Select fields"
|
||||
placeholder={i18n.translate('xpack.maps.source.esSearch.fieldsPlaceholder', {
|
||||
defaultMessage: `Select fields`
|
||||
})
|
||||
}
|
||||
value={this.props.tooltipProperties}
|
||||
onChange={this.onTooltipPropertiesSelect}
|
||||
fields={this.state.fields}
|
||||
|
@ -80,7 +93,12 @@ export class UpdateSourceEditor extends Component {
|
|||
|
||||
<EuiFormRow>
|
||||
<EuiSwitch
|
||||
label="Dynamically filter for data in the visible map area."
|
||||
label={
|
||||
i18n.translate('xpack.maps.source.esSearch.extentFilterLabel', {
|
||||
defaultMessage: `Dynamically filter for data in the visible map area.`
|
||||
})
|
||||
|
||||
}
|
||||
checked={this.props.filterByMapBounds}
|
||||
onChange={this.onFilterByMapBoundsChange}
|
||||
/>
|
||||
|
|
|
@ -14,6 +14,7 @@ import { createExtentFilter } from '../../../elasticsearch_geo_utils';
|
|||
import { timefilter } from 'ui/timefilter/timefilter';
|
||||
import _ from 'lodash';
|
||||
import { AggConfigs } from 'ui/vis/agg_configs';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
|
||||
export class AbstractESSource extends AbstractVectorSource {
|
||||
|
@ -87,7 +88,10 @@ export class AbstractESSource extends AbstractVectorSource {
|
|||
requestDesc: requestDescription
|
||||
});
|
||||
} catch(error) {
|
||||
throw new Error(`Elasticsearch search request failed, error: ${error.message}`);
|
||||
throw new Error('xpack.maps.source.esSource.requestFailedErrorMessage', {
|
||||
defaultMessage: `Elasticsearch search request failed, error: {message}`,
|
||||
values: { message: error.message }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -174,7 +178,10 @@ export class AbstractESSource extends AbstractVectorSource {
|
|||
this.indexPattern = await indexPatternService.get(this._descriptor.indexPatternId);
|
||||
return this.indexPattern;
|
||||
} catch (error) {
|
||||
throw new Error(`Unable to find Index pattern for id: ${this._descriptor.indexPatternId}`);
|
||||
throw new Error(i18n.translate('xpack.maps.source.esSource.noIndexPatternErrorMessage', {
|
||||
defaultMessage: `Unable to find Index pattern for id: {indexPatternId}`,
|
||||
values: { indexPatternId: this._descriptor.indexPatternId }
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -194,7 +201,10 @@ export class AbstractESSource extends AbstractVectorSource {
|
|||
const indexPattern = await this._getIndexPattern();
|
||||
const geoField = indexPattern.fields.byName[this._descriptor.geoField];
|
||||
if (!geoField) {
|
||||
throw new Error(`Index pattern ${indexPattern.title} no longer contains the geo field ${this._descriptor.geoField}`);
|
||||
throw new Error(i18n.translate('xpack.maps.source.esSource.noGeoFieldErrorMessage', {
|
||||
defaultMessage: `Index pattern {indexPatternTitle} no longer contains the geo field {geoField}`,
|
||||
values: { indexPatternTitle: indexPattern.title, geoField: this._descriptor.geoField }
|
||||
}));
|
||||
}
|
||||
return geoField;
|
||||
}
|
||||
|
|
|
@ -11,10 +11,7 @@ import {
|
|||
EuiFormRow,
|
||||
} from '@elastic/eui';
|
||||
import { getKibanaRegionList } from '../../../../meta';
|
||||
|
||||
const NO_REGIONMAP_LAYERS_MSG =
|
||||
'No vector layers are available.' +
|
||||
' Ask your system administrator to set "map.regionmap" in kibana.yml.';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
export class CreateSourceEditor extends React.Component {
|
||||
|
||||
|
@ -42,8 +39,6 @@ export class CreateSourceEditor extends React.Component {
|
|||
|
||||
render() {
|
||||
|
||||
|
||||
|
||||
const onChange = ({ target }) => {
|
||||
const selectedName = target.options[target.selectedIndex].text;
|
||||
this.props.onSelect({ name: selectedName });
|
||||
|
@ -58,8 +53,15 @@ export class CreateSourceEditor extends React.Component {
|
|||
|
||||
return (
|
||||
<EuiFormRow
|
||||
label="Vector layer"
|
||||
helpText={this.state.regionmapLayers.length === 0 ? NO_REGIONMAP_LAYERS_MSG : null}
|
||||
label={
|
||||
i18n.translate('xpack.maps.source.kbnRegionMap.vectorLayerLabel', {
|
||||
defaultMessage: 'Vector layer'
|
||||
})
|
||||
}
|
||||
helpText={this.state.regionmapLayers.length === 0 ? i18n.translate('xpack.maps.source.kbnRegionMap.noLayerAvailableHelptext', {
|
||||
defaultMessage: `No vector layers are available. Ask your system administrator to set "map.regionmap" in kibana.yml.`
|
||||
})
|
||||
: null}
|
||||
>
|
||||
<EuiSelect
|
||||
hasNoInitialSelection
|
||||
|
|
|
@ -7,14 +7,20 @@
|
|||
import { AbstractVectorSource } from '../vector_source';
|
||||
import React from 'react';
|
||||
import { CreateSourceEditor } from './create_source_editor';
|
||||
|
||||
import { getKibanaRegionList } from '../../../../meta';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { getDataSourceLabel } from '../../../../../common/i18n_getters';
|
||||
|
||||
export class KibanaRegionmapSource extends AbstractVectorSource {
|
||||
|
||||
static type = 'REGIONMAP_FILE';
|
||||
static title = 'Custom vector shapes';
|
||||
static description = 'Vector shapes from static files configured in kibana.yml';
|
||||
static title = i18n.translate('xpack.maps.source.kbnRegionMapTitle', {
|
||||
defaultMessage: 'Custom vector shapes'
|
||||
});
|
||||
static description = i18n.translate('xpack.maps.source.kbnRegionMapDescription', {
|
||||
defaultMessage: 'Vector shapes from static files configured in kibana.yml'
|
||||
})
|
||||
;
|
||||
static icon = 'logoKibana';
|
||||
|
||||
static createDescriptor(options) {
|
||||
|
@ -40,8 +46,15 @@ export class KibanaRegionmapSource extends AbstractVectorSource {
|
|||
|
||||
async getImmutableProperties() {
|
||||
return [
|
||||
{ label: 'Data source', value: KibanaRegionmapSource.title },
|
||||
{ label: 'Vector layer', value: this._descriptor.name },
|
||||
{
|
||||
label: getDataSourceLabel(),
|
||||
value: KibanaRegionmapSource.title },
|
||||
{
|
||||
label: i18n.translate('xpack.maps.source.kbnRegionMap.vectorLayerLabel', {
|
||||
defaultMessage: 'Vector layer'
|
||||
}),
|
||||
value: this._descriptor.name
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -49,7 +62,13 @@ export class KibanaRegionmapSource extends AbstractVectorSource {
|
|||
const regionList = await getKibanaRegionList();
|
||||
const meta = regionList.find(source => source.name === this._descriptor.name);
|
||||
if (!meta) {
|
||||
throw new Error(`Unable to find map.regionmap configuration for ${this._descriptor.name}`);
|
||||
throw new Error(i18n.translate('xpack.maps.source.kbnRegionMap.noConfigErrorMessage', {
|
||||
defaultMessage: `Unable to find map.regionmap configuration for {name}`,
|
||||
values: {
|
||||
name: this._descriptor.name
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
return meta;
|
||||
}
|
||||
|
|
|
@ -12,12 +12,7 @@ import {
|
|||
} from '@elastic/eui';
|
||||
|
||||
import { getKibanaTileMap } from '../../../../meta';
|
||||
|
||||
const NO_TILEMAP_LAYER_MSG =
|
||||
'No tilemap layer is available.' +
|
||||
' Ask your system administrator to set "map.tilemap.url" in kibana.yml.';
|
||||
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
export class CreateSourceEditor extends Component {
|
||||
|
||||
|
@ -56,8 +51,15 @@ export class CreateSourceEditor extends Component {
|
|||
|
||||
return (
|
||||
<EuiFormRow
|
||||
label="Tilemap url"
|
||||
helpText={this.state.url ? null : NO_TILEMAP_LAYER_MSG}
|
||||
label={
|
||||
i18n.translate('xpack.maps.source.kbnTMS.kbnTMS.urlLabel', {
|
||||
defaultMessage: 'Tilemap url'
|
||||
})
|
||||
}
|
||||
helpText={this.state.url ? null : i18n.translate('xpack.maps.source.kbnTMS.noLayerAvailableHelptext', {
|
||||
defaultMessage: 'No tilemap layer is available. Ask your system administrator to set "map.tilemap.url" in kibana.yml.'
|
||||
})
|
||||
}
|
||||
>
|
||||
<EuiFieldText
|
||||
readOnly
|
||||
|
|
|
@ -8,12 +8,19 @@ import { AbstractTMSSource } from '../tms_source';
|
|||
import { TileLayer } from '../../tile_layer';
|
||||
import { CreateSourceEditor } from './create_source_editor';
|
||||
import { getKibanaTileMap } from '../../../../meta';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { getDataSourceLabel } from '../../../../../common/i18n_getters';
|
||||
|
||||
export class KibanaTilemapSource extends AbstractTMSSource {
|
||||
|
||||
static type = 'KIBANA_TILEMAP';
|
||||
static title = 'Custom Tile Map Service';
|
||||
static description = 'Map tiles configured in kibana.yml';
|
||||
static title = i18n.translate('xpack.maps.source.kbnTMSTitle', {
|
||||
defaultMessage: 'Custom Tile Map Service'
|
||||
});
|
||||
static description = i18n.translate('xpack.maps.source.kbnTMSDescription', {
|
||||
defaultMessage: 'Map tiles configured in kibana.yml'
|
||||
});
|
||||
|
||||
static icon = 'logoKibana';
|
||||
|
||||
static createDescriptor() {
|
||||
|
@ -33,8 +40,16 @@ export class KibanaTilemapSource extends AbstractTMSSource {
|
|||
|
||||
async getImmutableProperties() {
|
||||
return [
|
||||
{ label: 'Data source', value: KibanaTilemapSource.title },
|
||||
{ label: 'Tilemap url', value: (await this.getUrlTemplate()) },
|
||||
{
|
||||
label: getDataSourceLabel(),
|
||||
value: KibanaTilemapSource.title
|
||||
},
|
||||
{
|
||||
label: i18n.translate('xpack.maps.source.kbnTMS.urlLabel', {
|
||||
defaultMessage: 'Tilemap url'
|
||||
}),
|
||||
value: (await this.getUrlTemplate())
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -55,7 +70,9 @@ export class KibanaTilemapSource extends AbstractTMSSource {
|
|||
async getUrlTemplate() {
|
||||
const tilemap = await getKibanaTileMap();
|
||||
if (!tilemap.url) {
|
||||
throw new Error(`Unable to find map.tilemap.url configuration in the kibana.yml`);
|
||||
throw new Error(i18n.translate('xpack.maps.source.kbnTMS.noConfigErrorMessage', {
|
||||
defaultMessage: `Unable to find map.tilemap.url configuration in the kibana.yml`
|
||||
}));
|
||||
}
|
||||
return tilemap.url;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import { VectorStyle } from '../styles/vector_style';
|
|||
import { AbstractSource } from './source';
|
||||
import * as topojson from 'topojson-client';
|
||||
import _ from 'lodash';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
export class AbstractVectorSource extends AbstractSource {
|
||||
|
||||
|
@ -24,7 +25,10 @@ export class AbstractVectorSource extends AbstractSource {
|
|||
}
|
||||
fetchedJson = await response.json();
|
||||
} catch (e) {
|
||||
throw new Error(`Unable to fetch vector shapes from url: ${fetchUrl}`);
|
||||
throw new Error(i18n.translate('xpack.maps.source.vetorSource.requestFailedErrorMessage', {
|
||||
defaultMessage: `Unable to fetch vector shapes from url: {fetchUrl}`,
|
||||
values: { fetchUrl }
|
||||
}));
|
||||
}
|
||||
|
||||
if (format === 'geojson') {
|
||||
|
@ -36,7 +40,10 @@ export class AbstractVectorSource extends AbstractSource {
|
|||
return topojson.feature(fetchedJson, features);
|
||||
}
|
||||
|
||||
throw new Error(`Unrecognized vector shape format: ${format}`);
|
||||
throw new Error(i18n.translate('xpack.maps.source.vetorSource.formatErrorMessage', {
|
||||
defaultMessage: `Unable to fetch vector shapes from url: {format}`,
|
||||
values: { format }
|
||||
}));
|
||||
}
|
||||
|
||||
_createDefaultLayerDescriptor(options, mapColors) {
|
||||
|
|
|
@ -13,12 +13,18 @@ import {
|
|||
|
||||
import { AbstractTMSSource } from './tms_source';
|
||||
import { TileLayer } from '../tile_layer';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { getDataSourceLabel, getUrlLabel } from '../../../../common/i18n_getters';
|
||||
|
||||
export class WMSSource extends AbstractTMSSource {
|
||||
|
||||
static type = 'WMS';
|
||||
static title = 'Web Map Service';
|
||||
static description = 'Maps from OGC Standard WMS';
|
||||
static title = i18n.translate('xpack.maps.source.wmsTitle', {
|
||||
defaultMessage: 'Web Map Service'
|
||||
});
|
||||
static description = i18n.translate('xpack.maps.source.wmsDescription', {
|
||||
defaultMessage: 'Maps from OGC Standard WMS'
|
||||
});
|
||||
static icon = 'grid';
|
||||
|
||||
static createDescriptor({ serviceUrl, layers, styles }) {
|
||||
|
@ -41,10 +47,14 @@ export class WMSSource extends AbstractTMSSource {
|
|||
|
||||
async getImmutableProperties() {
|
||||
return [
|
||||
{ label: 'Data source', value: WMSSource.title },
|
||||
{ label: 'Url', value: this._descriptor.serviceUrl },
|
||||
{ label: 'Layers', value: this._descriptor.layers },
|
||||
{ label: 'Styles', value: this._descriptor.styles },
|
||||
{ label: getDataSourceLabel(), value: WMSSource.title },
|
||||
{ label: getUrlLabel(), value: this._descriptor.serviceUrl },
|
||||
{ label: i18n.translate('xpack.maps.source.wms.layersLabel', {
|
||||
defaultMessage: 'Layers'
|
||||
}), value: this._descriptor.layers },
|
||||
{ label: i18n.translate('xpack.maps.source.wms.stylesLabel', {
|
||||
defaultMessage: 'Styles'
|
||||
}), value: this._descriptor.styles },
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -67,8 +77,7 @@ export class WMSSource extends AbstractTMSSource {
|
|||
}
|
||||
|
||||
getUrlTemplate() {
|
||||
console.warn('should compose url using url formatter, not string formatting');
|
||||
const styles = this._descriptor.styles ? this._descriptor.styles : '';
|
||||
const styles = this._descriptor.styles || '';
|
||||
// eslint-disable-next-line max-len
|
||||
return `${this._descriptor.serviceUrl}?bbox={bbox-epsg-3857}&format=image/png&service=WMS&version=1.1.1&request=GetMap&srs=EPSG:3857&transparent=true&width=256&height=256&layers=${this._descriptor.layers}&styles=${styles}`;
|
||||
}
|
||||
|
@ -125,12 +134,26 @@ class WMSEditor extends React.Component {
|
|||
onChange={(e) => this._handleServiceUrlChange(e)}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<EuiFormRow label="Layers" helpText={'use comma separated list of layer names'}>
|
||||
<EuiFormRow
|
||||
label={i18n.translate('xpack.maps.source.wms.layersLabel', {
|
||||
defaultMessage: 'Layers'
|
||||
})}
|
||||
helpText={i18n.translate('xpack.maps.source.wms.layersHelpText', {
|
||||
defaultMessage: 'use comma separated list of layer names'
|
||||
})}
|
||||
>
|
||||
<EuiFieldText
|
||||
onChange={(e) => this._handleLayersChange(e)}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<EuiFormRow label="Styles" helpText={'use comma separated list of style names'}>
|
||||
<EuiFormRow
|
||||
label={i18n.translate('xpack.maps.source.wms.stylesLabel', {
|
||||
defaultMessage: 'Styles'
|
||||
})}
|
||||
helpText={i18n.translate('xpack.maps.source.wms.stylesHelpText', {
|
||||
defaultMessage: 'use comma separated list of style names'
|
||||
})}
|
||||
>
|
||||
<EuiFieldText
|
||||
onChange={(e) => this._handleStylesChange(e)}
|
||||
/>
|
||||
|
|
|
@ -13,12 +13,18 @@ import {
|
|||
|
||||
import { AbstractTMSSource } from './tms_source';
|
||||
import { TileLayer } from '../tile_layer';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { getDataSourceLabel, getUrlLabel } from '../../../../common/i18n_getters';
|
||||
|
||||
export class XYZTMSSource extends AbstractTMSSource {
|
||||
|
||||
static type = 'EMS_XYZ';
|
||||
static title = 'Tile Map Service from URL';
|
||||
static description = 'Map tiles from a URL that includes the XYZ coordinates';
|
||||
static title = i18n.translate('xpack.maps.source.ems_xyzTitle', {
|
||||
defaultMessage: 'Tile Map Service from URL'
|
||||
});
|
||||
static description = i18n.translate('xpack.maps.source.ems_xyzDescription', {
|
||||
defaultMessage: 'Map tiles from a URL that includes the XYZ coordinates'
|
||||
});
|
||||
static icon = 'grid';
|
||||
|
||||
static createDescriptor(urlTemplate) {
|
||||
|
@ -39,8 +45,8 @@ export class XYZTMSSource extends AbstractTMSSource {
|
|||
|
||||
async getImmutableProperties() {
|
||||
return [
|
||||
{ label: 'Data source', value: XYZTMSSource.title },
|
||||
{ label: 'Url', value: this._descriptor.urlTemplate },
|
||||
{ label: getDataSourceLabel(), value: XYZTMSSource.title },
|
||||
{ label: getUrlLabel(), value: this._descriptor.urlTemplate },
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -92,7 +98,7 @@ class XYZTMSEditor extends React.Component {
|
|||
return (
|
||||
<EuiFormRow label="Url">
|
||||
<EuiFieldText
|
||||
placeholder="https://a.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
||||
placeholder={'https://a.tile.openstreetmap.org/{z}/{x}/{y}.png'}
|
||||
onChange={(e) => this._handleTMSInputChange(e)}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
import React from 'react';
|
||||
import { VectorStyle } from '../vector_style';
|
||||
import _ from 'lodash';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import {
|
||||
EuiFlexGroup,
|
||||
|
@ -93,7 +94,13 @@ export class StaticDynamicStyleRow extends React.Component {
|
|||
render() {
|
||||
const isDynamic = this._isDynamic();
|
||||
const dynamicTooltipContent =
|
||||
isDynamic ? 'Use static styling properties to symbolize features.' : 'Use property values to symbolize features.';
|
||||
isDynamic ?
|
||||
i18n.translate('xpack.maps.styles.staticDynamic.staticDescription', {
|
||||
defaultMessage: 'Use static styling properties to symbolize features.'
|
||||
}) :
|
||||
i18n.translate('xpack.maps.styles.staticDynamic.dynamicDescription', {
|
||||
defaultMessage: 'Use property values to symbolize features.'
|
||||
});
|
||||
|
||||
return (
|
||||
<EuiFlexGroup gutterSize="s">
|
||||
|
|
|
@ -9,6 +9,7 @@ import React from 'react';
|
|||
|
||||
import { EuiComboBox } from '@elastic/eui';
|
||||
import { SOURCE_DATA_ID_ORIGIN } from '../../../../../../common/constants';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
export function FieldSelect({ fields, selectedField, onChange }) {
|
||||
|
||||
|
@ -64,7 +65,11 @@ export function FieldSelect({ fields, selectedField, onChange }) {
|
|||
singleSelection={{ asPlainText: true }}
|
||||
isClearable={false}
|
||||
fullWidth
|
||||
placeholder="Select a field"
|
||||
placeholder={
|
||||
i18n.translate('xpack.maps.styles.vector.selectFieldPlaceholder', {
|
||||
defaultMessage: 'Select a field'
|
||||
})
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import {
|
|||
EuiFlexItem,
|
||||
} from '@elastic/eui';
|
||||
import { ValidatedRange } from '../../../../../components/validated_range';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { DEFAULT_MIN_SIZE, DEFAULT_MAX_SIZE } from '../../../vector_style_defaults';
|
||||
|
||||
export function SizeRangeSelector({ minSize, maxSize, onChange }) {
|
||||
|
@ -35,7 +36,11 @@ export function SizeRangeSelector({ minSize, maxSize, onChange }) {
|
|||
<EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
<EuiFormRow
|
||||
label="Min size"
|
||||
label={
|
||||
i18n.translate('xpack.maps.styles.vector.size.minLabel', {
|
||||
defaultMessage: 'Min size'
|
||||
})
|
||||
}
|
||||
compressed
|
||||
>
|
||||
<ValidatedRange
|
||||
|
@ -50,7 +55,11 @@ export function SizeRangeSelector({ minSize, maxSize, onChange }) {
|
|||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiFormRow
|
||||
label="Max size"
|
||||
label={
|
||||
i18n.translate('xpack.maps.styles.vector.size.maxLabel', {
|
||||
defaultMessage: 'Max size'
|
||||
})
|
||||
}
|
||||
compressed
|
||||
>
|
||||
<ValidatedRange
|
||||
|
|
|
@ -12,6 +12,7 @@ import { VectorStyleSizeEditor } from './size/vector_style_size_editor';
|
|||
import { getDefaultDynamicProperties, getDefaultStaticProperties } from '../../vector_style_defaults';
|
||||
|
||||
import { EuiSpacer } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
export class VectorStyleEditor extends Component {
|
||||
state = {
|
||||
|
@ -49,7 +50,11 @@ export class VectorStyleEditor extends Component {
|
|||
|
||||
<VectorStyleColorEditor
|
||||
styleProperty="fillColor"
|
||||
stylePropertyName="Fill color"
|
||||
stylePropertyName={
|
||||
i18n.translate('xpack.maps.styles.vector.fillColorLabel', {
|
||||
defaultMessage: 'Fill color'
|
||||
})
|
||||
}
|
||||
handlePropertyChange={this.props.handlePropertyChange}
|
||||
styleDescriptor={this.props.styleProperties.fillColor}
|
||||
ordinalFields={this.state.ordinalFields}
|
||||
|
@ -61,7 +66,11 @@ export class VectorStyleEditor extends Component {
|
|||
|
||||
<VectorStyleColorEditor
|
||||
styleProperty="lineColor"
|
||||
stylePropertyName="Border color"
|
||||
stylePropertyName={
|
||||
i18n.translate('xpack.maps.styles.vector.borderColorLabel', {
|
||||
defaultMessage: 'Border color'
|
||||
})
|
||||
}
|
||||
handlePropertyChange={this.props.handlePropertyChange}
|
||||
styleDescriptor={this.props.styleProperties.lineColor}
|
||||
ordinalFields={this.state.ordinalFields}
|
||||
|
@ -73,7 +82,11 @@ export class VectorStyleEditor extends Component {
|
|||
|
||||
<VectorStyleSizeEditor
|
||||
styleProperty="lineWidth"
|
||||
stylePropertyName="Border width"
|
||||
stylePropertyName={
|
||||
i18n.translate('xpack.maps.styles.vector.borderWidthLabel', {
|
||||
defaultMessage: 'Border width'
|
||||
})
|
||||
}
|
||||
handlePropertyChange={this.props.handlePropertyChange}
|
||||
styleDescriptor={this.props.styleProperties.lineWidth}
|
||||
ordinalFields={this.state.ordinalFields}
|
||||
|
@ -85,7 +98,11 @@ export class VectorStyleEditor extends Component {
|
|||
|
||||
<VectorStyleSizeEditor
|
||||
styleProperty="iconSize"
|
||||
stylePropertyName="Symbol size"
|
||||
stylePropertyName={
|
||||
i18n.translate('xpack.maps.styles.vector.symbolSizeLabel', {
|
||||
defaultMessage: 'Symbol size'
|
||||
})
|
||||
}
|
||||
handlePropertyChange={this.props.handlePropertyChange}
|
||||
styleDescriptor={this.props.styleProperties.iconSize}
|
||||
ordinalFields={this.state.ordinalFields}
|
||||
|
|
|
@ -6,35 +6,31 @@
|
|||
|
||||
import { GRID_RESOLUTION } from '../grid_resolution';
|
||||
import { AbstractStyle } from './abstract_style';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
export class HeatmapStyle extends AbstractStyle {
|
||||
|
||||
static type = 'HEATMAP';
|
||||
|
||||
constructor(styleDescriptor = {}) {
|
||||
constructor() {
|
||||
super();
|
||||
this._descriptor = HeatmapStyle.createDescriptor(
|
||||
styleDescriptor.refinement,
|
||||
styleDescriptor.properties
|
||||
);
|
||||
this._descriptor = HeatmapStyle.createDescriptor();
|
||||
}
|
||||
|
||||
static canEdit(styleInstance) {
|
||||
return styleInstance.constructor === HeatmapStyle;
|
||||
}
|
||||
|
||||
static createDescriptor(refinement, properties = {}) {
|
||||
static createDescriptor() {
|
||||
return {
|
||||
type: HeatmapStyle.type,
|
||||
refinement: refinement || 'coarse',
|
||||
properties: {
|
||||
...properties
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static getDisplayName() {
|
||||
return 'Heatmap style';
|
||||
return i18n.translate('xpack.maps.style.heatmap.displayNameLabel', {
|
||||
defaultMessage: 'Heatmap style'
|
||||
});
|
||||
}
|
||||
|
||||
static renderEditor() {
|
||||
|
@ -50,7 +46,11 @@ export class HeatmapStyle extends AbstractStyle {
|
|||
} else if (resolution === GRID_RESOLUTION.MOST_FINE) {
|
||||
radius = 32;
|
||||
} else {
|
||||
throw new Error(`Refinement param not recognized: ${this._descriptor.refinement}`);
|
||||
const errorMessage = i18n.translate('xpack.maps.style.heatmap.resolutionStyleErrorMessage', {
|
||||
defaultMessage: `Resolution param not recognized: {resolution}`,
|
||||
values: { resolution }
|
||||
});
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
mbMap.setPaintProperty(layerId, 'heatmap-radius', radius);
|
||||
mbMap.setPaintProperty(layerId, 'heatmap-weight', {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
import { AbstractStyle } from './abstract_style';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
export class TileStyle extends AbstractStyle {
|
||||
|
||||
|
@ -29,6 +30,8 @@ export class TileStyle extends AbstractStyle {
|
|||
}
|
||||
|
||||
static getDisplayName() {
|
||||
return 'Tile style';
|
||||
return i18n.translate('xpack.maps.style.tile.displayNameLabel', {
|
||||
defaultMessage: 'Tile style'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import _ from 'lodash';
|
||||
import React from 'react';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FillableCircle, FillableVector } from '../../icons/additional_layer_icons';
|
||||
import { ColorGradient } from '../../icons/color_gradient';
|
||||
import { getHexColorRangeStrings } from '../../utils/color_utils';
|
||||
|
@ -45,7 +45,9 @@ export class VectorStyle extends AbstractStyle {
|
|||
}
|
||||
|
||||
static getDisplayName() {
|
||||
return 'Vector style';
|
||||
return i18n.translate('xpack.maps.style.vector.displayNameLabel', {
|
||||
defaultMessage: 'Vector style'
|
||||
});
|
||||
}
|
||||
|
||||
static description = '';
|
||||
|
|
|
@ -11,8 +11,9 @@ import chroma from 'chroma-js';
|
|||
export function getRGBColorRangeStrings(colorName, numberColors) {
|
||||
const colorKeys = Object.keys(vislibColorMaps);
|
||||
if (!colorKeys.includes(colorName)) {
|
||||
throw `${colorName} not found. Expected one of following values: \
|
||||
${colorKeys}`;
|
||||
//This is an internal error and should never occur. If it does, then it is a bug.
|
||||
throw new Error(`${colorName} not found. Expected one of following values: \
|
||||
${colorKeys}`);
|
||||
}
|
||||
return getLegendColors(vislibColorMaps[colorName].value, numberColors);
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
/* eslint-disable max-len */
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
export const getFlightsSavedObjects = () => {
|
||||
return [
|
||||
{
|
||||
'id': '5dd88580-1906-11e9-919b-ffe5949a18d2',
|
||||
'type': 'map',
|
||||
'updated_at': '2019-01-15T20:44:54.767Z',
|
||||
'version': 2,
|
||||
'references': [
|
||||
{
|
||||
'name': 'layer_1_source_index_pattern',
|
||||
'type': 'index-pattern',
|
||||
'id': 'd3d7af60-4c81-11e8-b3d7-01146121b73d'
|
||||
},
|
||||
{
|
||||
'name': 'layer_2_source_index_pattern',
|
||||
'type': 'index-pattern',
|
||||
'id': 'd3d7af60-4c81-11e8-b3d7-01146121b73d'
|
||||
},
|
||||
{
|
||||
'name': 'layer_3_source_index_pattern',
|
||||
'type': 'index-pattern',
|
||||
'id': 'd3d7af60-4c81-11e8-b3d7-01146121b73d'
|
||||
}
|
||||
],
|
||||
'migrationVersion': {
|
||||
'map': '7.1.0'
|
||||
},
|
||||
'attributes': {
|
||||
'title': i18n.translate('xpack.maps.sampleData.flightaSpec.mapsTitle', {
|
||||
defaultMessage: '[Flights] Origin and Destination Flight Time'
|
||||
}),
|
||||
'description': '',
|
||||
'mapStateJSON': '{"zoom":3.14,"center":{"lon":-89.58746,"lat":38.38637},"timeFilters":{"from":"now-7d","to":"now"},"refreshConfig":{"isPaused":true,"interval":0},"query":{"query":"","language":"kuery"}}',
|
||||
'layerListJSON': '[{"id":"0hmz5","alpha":1,"sourceDescriptor":{"type":"EMS_TMS","id":"road_map"},"visible":true,"style":{"type":"TILE","properties":{}},"type":"TILE","minZoom":0,"maxZoom":24},{"id":"jzppx","label":"Flights","minZoom":9,"maxZoom":24,"alpha":1,"sourceDescriptor":{"id":"040e0f25-9687-4569-a1e0-76f1a108da56","type":"ES_SEARCH","geoField":"DestLocation","limit":2048,"filterByMapBounds":true,"tooltipProperties":["Carrier","DestCityName","DestCountry","OriginCityName","OriginCountry","FlightDelayMin","FlightTimeMin","DistanceMiles","AvgTicketPrice","FlightDelay"],"indexPatternRefName":"layer_1_source_index_pattern"},"visible":true,"style":{"type":"VECTOR","properties":{"fillColor":{"type":"DYNAMIC","options":{"field":{"label":"FlightTimeMin","name":"FlightTimeMin","origin":"source"},"color":"Greens"}},"lineColor":{"type":"STATIC","options":{"color":"#FFFFFF"}},"lineWidth":{"type":"STATIC","options":{"size":1}},"iconSize":{"type":"DYNAMIC","options":{"field":{"label":"DistanceMiles","name":"DistanceMiles","origin":"source"},"minSize":1,"maxSize":32}}}},"type":"VECTOR"},{"id":"y4jsz","label":"Flight Origin Location","minZoom":0,"maxZoom":9,"alpha":1,"sourceDescriptor":{"type":"ES_GEO_GRID","resolution":"COARSE","id":"fe893f84-388e-4865-8df4-650748533a77","geoField":"OriginLocation","requestType":"point","metrics":[{"type":"count"},{"type":"avg","field":"FlightTimeMin"}],"indexPatternRefName":"layer_2_source_index_pattern"},"visible":true,"style":{"type":"VECTOR","properties":{"fillColor":{"type":"DYNAMIC","options":{"field":{"label":"Count","name":"doc_count","origin":"source"},"color":"Blues"}},"lineColor":{"type":"STATIC","options":{"color":"#110081"}},"lineWidth":{"type":"STATIC","options":{"size":1}},"iconSize":{"type":"DYNAMIC","options":{"field":{"label":"avg of FlightTimeMin","name":"avg_of_FlightTimeMin","origin":"source"},"minSize":1,"maxSize":32}}}},"type":"VECTOR"},{"id":"x8xpo","label":"Flight Destination Location","minZoom":0,"maxZoom":9,"alpha":1,"sourceDescriptor":{"type":"ES_GEO_GRID","resolution":"COARSE","id":"60a7346a-8c5f-4c03-b7d1-e8b36e847551","geoField":"DestLocation","requestType":"point","metrics":[{"type":"count"},{"type":"avg","field":"FlightDelayMin"}],"indexPatternRefName":"layer_3_source_index_pattern"},"visible":true,"style":{"type":"VECTOR","properties":{"fillColor":{"type":"DYNAMIC","options":{"field":{"label":"Count","name":"doc_count","origin":"source"},"color":"Reds"}},"lineColor":{"type":"STATIC","options":{"color":"#af0303"}},"lineWidth":{"type":"STATIC","options":{"size":1}},"iconSize":{"type":"DYNAMIC","options":{"field":{"label":"avg of FlightDelayMin","name":"avg_of_FlightDelayMin","origin":"source"},"minSize":1,"maxSize":32}}}},"type":"VECTOR"}]',
|
||||
'uiStateJSON': '{"isDarkMode":false}',
|
||||
'bounds': {
|
||||
'type': 'envelope', 'coordinates': [[-139.83779, 56.64828], [-39.33713, 14.04811]] }
|
||||
}
|
||||
}
|
||||
];
|
||||
};
|
|
@ -1,36 +0,0 @@
|
|||
[
|
||||
{
|
||||
"id":"5dd88580-1906-11e9-919b-ffe5949a18d2",
|
||||
"type":"map",
|
||||
"updated_at":"2019-01-15T20:44:54.767Z",
|
||||
"version":2,
|
||||
"references" : [
|
||||
{
|
||||
"name" : "layer_1_source_index_pattern",
|
||||
"type" : "index-pattern",
|
||||
"id" : "d3d7af60-4c81-11e8-b3d7-01146121b73d"
|
||||
},
|
||||
{
|
||||
"name" : "layer_2_source_index_pattern",
|
||||
"type" : "index-pattern",
|
||||
"id" : "d3d7af60-4c81-11e8-b3d7-01146121b73d"
|
||||
},
|
||||
{
|
||||
"name" : "layer_3_source_index_pattern",
|
||||
"type" : "index-pattern",
|
||||
"id" : "d3d7af60-4c81-11e8-b3d7-01146121b73d"
|
||||
}
|
||||
],
|
||||
"migrationVersion" : {
|
||||
"map" : "7.1.0"
|
||||
},
|
||||
"attributes":{
|
||||
"title":"[Flights] Origin and Destination Flight Time",
|
||||
"description":"",
|
||||
"mapStateJSON":"{\"zoom\":3.14,\"center\":{\"lon\":-89.58746,\"lat\":38.38637},\"timeFilters\":{\"from\":\"now-7d\",\"to\":\"now\"},\"refreshConfig\":{\"isPaused\":true,\"interval\":0},\"query\":{\"query\":\"\",\"language\":\"kuery\"}}",
|
||||
"layerListJSON" : "[{\"id\":\"0hmz5\",\"alpha\":1,\"sourceDescriptor\":{\"type\":\"EMS_TMS\",\"id\":\"road_map\"},\"visible\":true,\"style\":{\"type\":\"TILE\",\"properties\":{}},\"type\":\"TILE\",\"minZoom\":0,\"maxZoom\":24},{\"id\":\"jzppx\",\"label\":\"Flights\",\"minZoom\":9,\"maxZoom\":24,\"alpha\":1,\"sourceDescriptor\":{\"id\":\"040e0f25-9687-4569-a1e0-76f1a108da56\",\"type\":\"ES_SEARCH\",\"geoField\":\"DestLocation\",\"limit\":2048,\"filterByMapBounds\":true,\"tooltipProperties\":[\"Carrier\",\"DestCityName\",\"DestCountry\",\"OriginCityName\",\"OriginCountry\",\"FlightDelayMin\",\"FlightTimeMin\",\"DistanceMiles\",\"AvgTicketPrice\",\"FlightDelay\"],\"indexPatternRefName\":\"layer_1_source_index_pattern\"},\"visible\":true,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"DYNAMIC\",\"options\":{\"field\":{\"label\":\"FlightTimeMin\",\"name\":\"FlightTimeMin\",\"origin\":\"source\"},\"color\":\"Greens\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"DYNAMIC\",\"options\":{\"field\":{\"label\":\"DistanceMiles\",\"name\":\"DistanceMiles\",\"origin\":\"source\"},\"minSize\":1,\"maxSize\":32}}}},\"type\":\"VECTOR\"},{\"id\":\"y4jsz\",\"label\":\"Flight Origin Location\",\"minZoom\":0,\"maxZoom\":9,\"alpha\":1,\"sourceDescriptor\":{\"type\":\"ES_GEO_GRID\",\"resolution\":\"COARSE\",\"id\":\"fe893f84-388e-4865-8df4-650748533a77\",\"geoField\":\"OriginLocation\",\"requestType\":\"point\",\"metrics\":[{\"type\":\"count\"},{\"type\":\"avg\",\"field\":\"FlightTimeMin\"}],\"indexPatternRefName\":\"layer_2_source_index_pattern\"},\"visible\":true,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"DYNAMIC\",\"options\":{\"field\":{\"label\":\"Count\",\"name\":\"doc_count\",\"origin\":\"source\"},\"color\":\"Blues\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#110081\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"DYNAMIC\",\"options\":{\"field\":{\"label\":\"avg of FlightTimeMin\",\"name\":\"avg_of_FlightTimeMin\",\"origin\":\"source\"},\"minSize\":1,\"maxSize\":32}}}},\"type\":\"VECTOR\"},{\"id\":\"x8xpo\",\"label\":\"Flight Destination Location\",\"minZoom\":0,\"maxZoom\":9,\"alpha\":1,\"sourceDescriptor\":{\"type\":\"ES_GEO_GRID\",\"resolution\":\"COARSE\",\"id\":\"60a7346a-8c5f-4c03-b7d1-e8b36e847551\",\"geoField\":\"DestLocation\",\"requestType\":\"point\",\"metrics\":[{\"type\":\"count\"},{\"type\":\"avg\",\"field\":\"FlightDelayMin\"}],\"indexPatternRefName\":\"layer_3_source_index_pattern\"},\"visible\":true,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"DYNAMIC\",\"options\":{\"field\":{\"label\":\"Count\",\"name\":\"doc_count\",\"origin\":\"source\"},\"color\":\"Reds\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#af0303\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"DYNAMIC\",\"options\":{\"field\":{\"label\":\"avg of FlightDelayMin\",\"name\":\"avg_of_FlightDelayMin\",\"origin\":\"source\"},\"minSize\":1,\"maxSize\":32}}}},\"type\":\"VECTOR\"}]",
|
||||
"uiStateJSON":"{\"isDarkMode\":false}",
|
||||
"bounds":{"type":"envelope","coordinates":[[-139.83779,56.64828],[-39.33713,14.04811]]}
|
||||
}
|
||||
}
|
||||
]
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
/* eslint-disable max-len */
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
export const getWebLogsSavedObjects = () => {
|
||||
return [
|
||||
{
|
||||
'id': 'de71f4f0-1902-11e9-919b-ffe5949a18d2',
|
||||
'type': 'map',
|
||||
'updated_at': '2019-01-15T20:30:25.436Z',
|
||||
'version': 5,
|
||||
'references': [
|
||||
{
|
||||
'name': 'layer_1_join_0_index_pattern',
|
||||
'type': 'index-pattern',
|
||||
'id': '90943e30-9a47-11e8-b64d-95841ca0b247'
|
||||
},
|
||||
{
|
||||
'name': 'layer_2_source_index_pattern',
|
||||
'type': 'index-pattern',
|
||||
'id': '90943e30-9a47-11e8-b64d-95841ca0b247'
|
||||
},
|
||||
{
|
||||
'name': 'layer_3_source_index_pattern',
|
||||
'type': 'index-pattern',
|
||||
'id': '90943e30-9a47-11e8-b64d-95841ca0b247'
|
||||
}
|
||||
],
|
||||
'migrationVersion': {
|
||||
'map': '7.1.0'
|
||||
},
|
||||
'attributes': {
|
||||
'title': i18n.translate('xpack.maps.sampleData.flightaSpec.logsTitle', {
|
||||
defaultMessage: '[Logs] Total Requests and Bytes'
|
||||
}),
|
||||
'description': '',
|
||||
'mapStateJSON': '{"zoom":3.64,"center":{"lon":-88.92107,"lat":42.16337},"timeFilters":{"from":"now-7d","to":"now"},"refreshConfig":{"isPaused":true,"interval":0},"query":{"language":"kuery","query":""}}',
|
||||
'layerListJSON': '[{"id":"0hmz5","alpha":1,"sourceDescriptor":{"type":"EMS_TMS","id":"road_map"},"visible":true,"style":{"type":"TILE","properties":{}},"type":"TILE","minZoom":0,"maxZoom":24},{"id":"edh66","label":"Total Requests by Country","minZoom":0,"maxZoom":24,"alpha":0.5,"sourceDescriptor":{"type":"EMS_FILE","id":"world_countries"},"visible":true,"style":{"type":"VECTOR","properties":{"fillColor":{"type":"DYNAMIC","options":{"field":{"label":"count of kibana_sample_data_logs:geo.src","name":"__kbnjoin__count_groupby_kibana_sample_data_logs.geo.src","origin":"join"},"color":"Greys"}},"lineColor":{"type":"STATIC","options":{"color":"#FFFFFF"}},"lineWidth":{"type":"STATIC","options":{"size":1}},"iconSize":{"type":"STATIC","options":{"size":10}}}},"type":"VECTOR","joins":[{"leftField":"iso2","right":{"id":"673ff994-fc75-4c67-909b-69fcb0e1060e","indexPatternTitle":"kibana_sample_data_logs","term":"geo.src","indexPatternRefName":"layer_1_join_0_index_pattern"}}]},{"id":"gaxya","label":"Actual Requests","minZoom":9,"maxZoom":24,"alpha":1,"sourceDescriptor":{"id":"b7486535-171b-4d3b-bb2e-33c1a0a2854c","type":"ES_SEARCH","geoField":"geo.coordinates","limit":2048,"filterByMapBounds":true,"tooltipProperties":["clientip","timestamp","host","request","response","machine.os","agent","bytes"],"indexPatternRefName":"layer_2_source_index_pattern"},"visible":true,"style":{"type":"VECTOR","properties":{"fillColor":{"type":"STATIC","options":{"color":"#2200ff"}},"lineColor":{"type":"STATIC","options":{"color":"#FFFFFF"}},"lineWidth":{"type":"STATIC","options":{"size":2}},"iconSize":{"type":"DYNAMIC","options":{"field":{"label":"bytes","name":"bytes","origin":"source"},"minSize":1,"maxSize":23}}}},"type":"VECTOR"},{"id":"tfi3f","label":"Total Requests and Bytes","minZoom":0,"maxZoom":9,"alpha":1,"sourceDescriptor":{"type":"ES_GEO_GRID","resolution":"COARSE","id":"8aaa65b5-a4e9-448b-9560-c98cb1c5ac5b","geoField":"geo.coordinates","requestType":"point","metrics":[{"type":"count"},{"type":"sum","field":"bytes"}],"indexPatternRefName":"layer_3_source_index_pattern"},"visible":true,"style":{"type":"VECTOR","properties":{"fillColor":{"type":"DYNAMIC","options":{"field":{"label":"Count","name":"doc_count","origin":"source"},"color":"Blues"}},"lineColor":{"type":"STATIC","options":{"color":"#cccccc"}},"lineWidth":{"type":"STATIC","options":{"size":1}},"iconSize":{"type":"DYNAMIC","options":{"field":{"label":"sum of bytes","name":"sum_of_bytes","origin":"source"},"minSize":1,"maxSize":25}}}},"type":"VECTOR"}]',
|
||||
'uiStateJSON': '{"isDarkMode":false}',
|
||||
'bounds': { 'type': 'envelope', 'coordinates': [[-124.45342, 54.91445], [-53.38872, 26.21461]] }
|
||||
}
|
||||
}
|
||||
];
|
||||
};
|
|
@ -1,36 +0,0 @@
|
|||
[
|
||||
{
|
||||
"id":"de71f4f0-1902-11e9-919b-ffe5949a18d2",
|
||||
"type":"map",
|
||||
"updated_at":"2019-01-15T20:30:25.436Z",
|
||||
"version":5,
|
||||
"references" : [
|
||||
{
|
||||
"name" : "layer_1_join_0_index_pattern",
|
||||
"type" : "index-pattern",
|
||||
"id" : "90943e30-9a47-11e8-b64d-95841ca0b247"
|
||||
},
|
||||
{
|
||||
"name" : "layer_2_source_index_pattern",
|
||||
"type" : "index-pattern",
|
||||
"id" : "90943e30-9a47-11e8-b64d-95841ca0b247"
|
||||
},
|
||||
{
|
||||
"name" : "layer_3_source_index_pattern",
|
||||
"type" : "index-pattern",
|
||||
"id" : "90943e30-9a47-11e8-b64d-95841ca0b247"
|
||||
}
|
||||
],
|
||||
"migrationVersion" : {
|
||||
"map" : "7.1.0"
|
||||
},
|
||||
"attributes":{
|
||||
"title":"[Logs] Total Requests and Bytes",
|
||||
"description":"",
|
||||
"mapStateJSON":"{\"zoom\":3.64,\"center\":{\"lon\":-88.92107,\"lat\":42.16337},\"timeFilters\":{\"from\":\"now-7d\",\"to\":\"now\"},\"refreshConfig\":{\"isPaused\":true,\"interval\":0},\"query\":{\"language\":\"kuery\",\"query\":\"\"}}",
|
||||
"layerListJSON" : "[{\"id\":\"0hmz5\",\"alpha\":1,\"sourceDescriptor\":{\"type\":\"EMS_TMS\",\"id\":\"road_map\"},\"visible\":true,\"style\":{\"type\":\"TILE\",\"properties\":{}},\"type\":\"TILE\",\"minZoom\":0,\"maxZoom\":24},{\"id\":\"edh66\",\"label\":\"Total Requests by Country\",\"minZoom\":0,\"maxZoom\":24,\"alpha\":0.5,\"sourceDescriptor\":{\"type\":\"EMS_FILE\",\"id\":\"world_countries\"},\"visible\":true,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"DYNAMIC\",\"options\":{\"field\":{\"label\":\"count of kibana_sample_data_logs:geo.src\",\"name\":\"__kbnjoin__count_groupby_kibana_sample_data_logs.geo.src\",\"origin\":\"join\"},\"color\":\"Greys\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}}}},\"type\":\"VECTOR\",\"joins\":[{\"leftField\":\"iso2\",\"right\":{\"id\":\"673ff994-fc75-4c67-909b-69fcb0e1060e\",\"indexPatternTitle\":\"kibana_sample_data_logs\",\"term\":\"geo.src\",\"indexPatternRefName\":\"layer_1_join_0_index_pattern\"}}]},{\"id\":\"gaxya\",\"label\":\"Actual Requests\",\"minZoom\":9,\"maxZoom\":24,\"alpha\":1,\"sourceDescriptor\":{\"id\":\"b7486535-171b-4d3b-bb2e-33c1a0a2854c\",\"type\":\"ES_SEARCH\",\"geoField\":\"geo.coordinates\",\"limit\":2048,\"filterByMapBounds\":true,\"tooltipProperties\":[\"clientip\",\"timestamp\",\"host\",\"request\",\"response\",\"machine.os\",\"agent\",\"bytes\"],\"indexPatternRefName\":\"layer_2_source_index_pattern\"},\"visible\":true,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#2200ff\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":2}},\"iconSize\":{\"type\":\"DYNAMIC\",\"options\":{\"field\":{\"label\":\"bytes\",\"name\":\"bytes\",\"origin\":\"source\"},\"minSize\":1,\"maxSize\":23}}}},\"type\":\"VECTOR\"},{\"id\":\"tfi3f\",\"label\":\"Total Requests and Bytes\",\"minZoom\":0,\"maxZoom\":9,\"alpha\":1,\"sourceDescriptor\":{\"type\":\"ES_GEO_GRID\",\"resolution\":\"COARSE\",\"id\":\"8aaa65b5-a4e9-448b-9560-c98cb1c5ac5b\",\"geoField\":\"geo.coordinates\",\"requestType\":\"point\",\"metrics\":[{\"type\":\"count\"},{\"type\":\"sum\",\"field\":\"bytes\"}],\"indexPatternRefName\":\"layer_3_source_index_pattern\"},\"visible\":true,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"DYNAMIC\",\"options\":{\"field\":{\"label\":\"Count\",\"name\":\"doc_count\",\"origin\":\"source\"},\"color\":\"Blues\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#cccccc\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"DYNAMIC\",\"options\":{\"field\":{\"label\":\"sum of bytes\",\"name\":\"sum_of_bytes\",\"origin\":\"source\"},\"minSize\":1,\"maxSize\":25}}}},\"type\":\"VECTOR\"}]",
|
||||
"uiStateJSON":"{\"isDarkMode\":false}",
|
||||
"bounds":{"type":"envelope","coordinates":[[-124.45342,54.91445],[-53.38872,26.21461]]}
|
||||
}
|
||||
}
|
||||
]
|
Loading…
Add table
Add a link
Reference in a new issue