From 206dda7f5decebef7fd3cbfb30cd7e3554c58575 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Tue, 7 May 2019 13:40:36 -0600 Subject: [PATCH] [Maps] show dynamic style ranges in legend (#35417) * show grab and edit buttons when hovering over layer name * display layer details when layer name is clicked * add range to dynamic style property state * render dynamic ranges in TOC details * render symbol size and border width header in legend * simplify VectorStyle.getIcon * removed unused component * open TOC details on map load * save open TOC details state in embeddable config * show gradients for dynmaic fill color icon * round corners of dynamic icon if points only * add tooltip to legend label * add edit panel action to action panel * add functional test for details in legend * fix broken gis_page function doesLayerExist * add unit tests for VectorStyle.getDescriptorWithDynamicRanges * open actions menu on layer title click, add arrow up/down for togging layer details * Design cleanup of layers panel (#31) * fix functional test * update jest snapshots * refactor StylePropertyLegendRow to use same function to render lineWidth and iconSize legends * fix functional test * fix another functional test * make escapeLayerName function instead of instance method * move _isLayerDetailsOpen into prop from redux connector * remove index.js file * do not show legend details toggle when layer has not legend details * rename FillableVector to FillableRectangle * use mixin pattern instead of encapulated function call --- .../maps/public/angular/map_controller.js | 4 +- .../public/angular/services/saved_gis_map.js | 5 +- .../widget_overlay/_widget_overlay.scss | 7 +- .../layer_control/_layer_control.scss | 4 +- .../layer_toc/__snapshots__/view.test.js.snap | 19 +- .../toc_entry/__snapshots__/view.test.js.snap | 269 +++++++++++------- .../layer_toc/toc_entry/_toc_entry.scss | 113 +++++++- .../layer_toc/toc_entry/index.js | 20 +- .../layer_control/layer_toc/toc_entry/view.js | 207 +++++++++----- .../layer_toc/toc_entry/view.test.js | 25 +- .../layer_control/layer_toc/view.js | 33 ++- .../widget_overlay/widget_overlay.js | 2 +- .../maps/public/embeddable/map_embeddable.js | 20 +- .../layer_toc_actions.test.js.snap | 172 +++++++++-- .../shared/components/layer_toc_actions.js | 36 ++- .../components/layer_toc_actions.test.js | 3 +- .../shared/icons/additional_layer_icons.js | 2 +- .../public/shared/icons/color_gradient.js | 22 +- .../maps/public/shared/layers/layer.js | 6 +- .../components/static_dynamic_style_row.js | 2 +- .../vector/color/dynamic_color_selection.js | 6 +- .../vector/color/static_color_selection.js | 5 +- .../vector/color/vector_style_color_editor.js | 3 +- .../vector/get_vector_style_label.js | 30 ++ .../legend/style_property_legend_row.js | 134 +++++++++ .../components/vector/legend/vector_icon.js | 52 ++++ .../vector/legend/vector_style_legend.js | 36 +++ .../vector/size/dynamic_size_selection.js | 7 +- .../vector/size/static_size_selection.js | 5 +- .../vector/size/vector_style_size_editor.js | 3 +- .../components/vector/style_option_shapes.js | 39 +++ .../components/vector/vector_style_editor.js | 21 -- .../shared/layers/styles/vector_style.js | 65 ++--- .../maps/public/shared/layers/vector_layer.js | 8 +- .../maps/public/shared/utils/color_utils.js | 29 +- x-pack/plugins/maps/public/store/ui.js | 48 +++- x-pack/test/functional/apps/maps/joins.js | 12 +- .../es_archives/maps/kibana/data.json | 18 +- .../test/functional/page_objects/gis_page.js | 21 +- 39 files changed, 1118 insertions(+), 395 deletions(-) create mode 100644 x-pack/plugins/maps/public/shared/layers/styles/components/vector/get_vector_style_label.js create mode 100644 x-pack/plugins/maps/public/shared/layers/styles/components/vector/legend/style_property_legend_row.js create mode 100644 x-pack/plugins/maps/public/shared/layers/styles/components/vector/legend/vector_icon.js create mode 100644 x-pack/plugins/maps/public/shared/layers/styles/components/vector/legend/vector_style_legend.js create mode 100644 x-pack/plugins/maps/public/shared/layers/styles/components/vector/style_option_shapes.js diff --git a/x-pack/plugins/maps/public/angular/map_controller.js b/x-pack/plugins/maps/public/angular/map_controller.js index 13db2dc3a6e1d..31830a402eb23 100644 --- a/x-pack/plugins/maps/public/angular/map_controller.js +++ b/x-pack/plugins/maps/public/angular/map_controller.js @@ -33,7 +33,8 @@ import { updateFlyout, FLYOUT_STATE, setReadOnly, - setIsLayerTOCOpen + setIsLayerTOCOpen, + setOpenTOCDetails, } from '../store/ui'; import { getQueryableUniqueIndexPatternIds } from '../selectors/map_selectors'; import { getInspectorAdapters } from '../store/non_serializable_instances'; @@ -147,6 +148,7 @@ app.controller('GisMapController', ($scope, $route, config, kbnUrl, localStorage if (savedMap.uiStateJSON) { const uiState = JSON.parse(savedMap.uiStateJSON); store.dispatch(setIsLayerTOCOpen(_.get(uiState, 'isLayerTOCOpen', DEFAULT_IS_LAYER_TOC_OPEN))); + store.dispatch(setOpenTOCDetails(_.get(uiState, 'openTOCDetails', []))); } const layerList = getInitialLayers(savedMap.layerListJSON); diff --git a/x-pack/plugins/maps/public/angular/services/saved_gis_map.js b/x-pack/plugins/maps/public/angular/services/saved_gis_map.js index 9c2f4426961e9..a110c0d214d3a 100644 --- a/x-pack/plugins/maps/public/angular/services/saved_gis_map.js +++ b/x-pack/plugins/maps/public/angular/services/saved_gis_map.js @@ -17,7 +17,7 @@ import { getRefreshConfig, getQuery, } from '../../selectors/map_selectors'; -import { getIsLayerTOCOpen } from '../../store/ui'; +import { getIsLayerTOCOpen, getOpenTOCDetails } from '../../store/ui'; import { convertMapExtentToPolygon } from '../../elasticsearch_geo_utils'; import { copyPersistentState } from '../../store/util'; import { extractReferences, injectReferences } from '../../../common/migrations/references'; @@ -101,7 +101,8 @@ module.factory('SavedGisMap', function (Private) { }); this.uiStateJSON = JSON.stringify({ - isLayerTOCOpen: getIsLayerTOCOpen(state) + isLayerTOCOpen: getIsLayerTOCOpen(state), + openTOCDetails: getOpenTOCDetails(state), }); this.bounds = convertMapExtentToPolygon(getMapExtent(state)); diff --git a/x-pack/plugins/maps/public/components/widget_overlay/_widget_overlay.scss b/x-pack/plugins/maps/public/components/widget_overlay/_widget_overlay.scss index 433509a0060e0..c2ff67ac818d2 100644 --- a/x-pack/plugins/maps/public/components/widget_overlay/_widget_overlay.scss +++ b/x-pack/plugins/maps/public/components/widget_overlay/_widget_overlay.scss @@ -13,9 +13,12 @@ pointer-events: none; /* 1 */ } +.mapWidgetOverlay__rightSideWrapper { + overflow: hidden; // Fixes Chrome overflow +} + .mapWidgetOverlay__rightSide { - min-width: 19rem; - max-width: 24rem; + width: $euiSize * 20; } .mapWidgetOverlay__layerWrapper { diff --git a/x-pack/plugins/maps/public/components/widget_overlay/layer_control/_layer_control.scss b/x-pack/plugins/maps/public/components/widget_overlay/layer_control/_layer_control.scss index 381d4b24f8e45..c87342aaf31ff 100644 --- a/x-pack/plugins/maps/public/components/widget_overlay/layer_control/_layer_control.scss +++ b/x-pack/plugins/maps/public/components/widget_overlay/layer_control/_layer_control.scss @@ -2,6 +2,8 @@ @include euiScrollBar; overflow-y: auto; flex-basis: auto !important; // Fixes IE and ensures the layer items are visible + padding-bottom: $euiSizeS + 1px; + border-top: 1px solid $euiColorLightestShade; } .mapLayerControl__addLayerButton, @@ -18,5 +20,5 @@ .mapLayerControl__openLayerTOCButton, .mapLayerControl__closeLayerTOCButton { @include size($euiSizeXL); - background-color: $euiColorEmptyShade; + background-color: $euiColorEmptyShade !important; // During all states } diff --git a/x-pack/plugins/maps/public/components/widget_overlay/layer_control/layer_toc/__snapshots__/view.test.js.snap b/x-pack/plugins/maps/public/components/widget_overlay/layer_control/layer_toc/__snapshots__/view.test.js.snap index 554ff3834eff4..beacaaecbf7f8 100644 --- a/x-pack/plugins/maps/public/components/widget_overlay/layer_control/layer_toc/__snapshots__/view.test.js.snap +++ b/x-pack/plugins/maps/public/components/widget_overlay/layer_control/layer_toc/__snapshots__/view.test.js.snap @@ -11,24 +11,7 @@ exports[`LayerTOC is rendered 1`] = ` droppableId="mapLayerTOC" spacing="none" > - - - - - - + diff --git a/x-pack/plugins/maps/public/components/widget_overlay/layer_control/layer_toc/toc_entry/__snapshots__/view.test.js.snap b/x-pack/plugins/maps/public/components/widget_overlay/layer_control/layer_toc/toc_entry/__snapshots__/view.test.js.snap index 2f8256ff7806b..2c8531c5c8030 100644 --- a/x-pack/plugins/maps/public/components/widget_overlay/layer_control/layer_toc/toc_entry/__snapshots__/view.test.js.snap +++ b/x-pack/plugins/maps/public/components/widget_overlay/layer_control/layer_toc/toc_entry/__snapshots__/view.test.js.snap @@ -6,70 +6,68 @@ exports[`TOCEntry is rendered 1`] = ` data-layerid="1" id="1" > - - - - - - +
+ -
- layer 1 -
- - - - + - - - - - -
- TOC details mock + color="subdued" + iconSize="m" + iconType="grab" + title="Reorder layer" + type="button" + /> +
+ + + `; @@ -79,54 +77,125 @@ exports[`TOCEntry props isReadOnly 1`] = ` data-layerid="1" id="1" > - - + + + + + +`; + +exports[`TOCEntry props should display layer details when isLegendDetailsOpen is true 1`] = ` +
+
+ +
+ - - - -
- layer 1 -
-
-
- - -
- TOC details mock + +
+
+
+
+ TOC details mock +
+ + +
`; diff --git a/x-pack/plugins/maps/public/components/widget_overlay/layer_control/layer_toc/toc_entry/_toc_entry.scss b/x-pack/plugins/maps/public/components/widget_overlay/layer_control/layer_toc/toc_entry/_toc_entry.scss index b000ed47967c1..316ba65f2c2cf 100644 --- a/x-pack/plugins/maps/public/components/widget_overlay/layer_control/layer_toc/toc_entry/_toc_entry.scss +++ b/x-pack/plugins/maps/public/components/widget_overlay/layer_control/layer_toc/toc_entry/_toc_entry.scss @@ -1,22 +1,121 @@ +/** + * 1. Truncate the layer name + * 2. For showing the layer details toggle above the following entry + */ + .mapTocEntry { - padding: $euiSizeS $euiSize; position: relative; - background-color: $euiColorEmptyShade; + padding: $euiSizeS; + border-bottom: 1px solid $euiColorLightestShade; + + &:hover, + &:focus, + &:focus-within { + z-index: 2; /* 2 */ + + .mapTocEntry__layerIcons, + .mapTocEntry__detailsToggle { + display: block; + animation: mapTocEntryBecomeVisible $euiAnimSpeedFast $euiAnimSlightResistance; + } + } + + .mapTocEntry__layerIcons, + .mapTocEntry__detailsToggle { + &:hover, + &:focus { + display: block; + animation: mapTocEntryBecomeVisible $euiAnimSpeedFast $euiAnimSlightResistance; + } + } +} + +.mapTocEntry-isDragging { + @include euiBottomShadowMedium; } -.mapTocEntry-visible { - opacity: 1; +.mapTocEntry-isDraggingOver { + background-color: $euiColorEmptyShade; + // Don't allow interaction events while layer is being re-ordered + pointer-events: none !important; } +.mapTocEntry-visible, .mapTocEntry-notVisible { - opacity: 0.5; + display: flex; +} + +.mapLayTocActions { + overflow: hidden; /* 1 */ + flex-grow: 1; +} + +.mapLayTocActions__popoverAnchor { + max-width: 100%; } -.mapTocEntry__grab { - margin-left: $euiSizeXS; +.mapTocEntry-notVisible .mapTocEntry__layerName { + opacity: 0.5; } .mapTocEntry__grab:hover { cursor: grab; } +.mapTocEntry__layerName { + font-weight: $euiFontWeightMedium; +} + +.mapTocEntry__layerNameText { + display: flex; + align-items: center; +} + +.mapTocEntry__layerNameIcon { + flex-shrink: 0; + margin-right: $euiSizeS; + + > * { + vertical-align: sub; + } +} + +.mapTocEntry__layerIcons { + flex-shrink: 0; + display: none; +} + +.mapTocEntry__detailsToggle { + position: absolute; + display: none; + left: 50%; + top: $euiSizeXL; + transform: translateX(-50%); +} + +.mapTocEntry__detailsToggleButton { + background-color: $euiColorEmptyShade; + border: $euiBorderThin; + color: $euiTextColor; + border-radius: $euiBorderRadius / 2; + height: $euiSize; + width: $euiSizeXL; + line-height: $euiSize; + text-align: center; + + &:focus { + @include euiFocusRing; + } +} + +.mapTocEntry__layerDetails { + @include euiOverflowShadow(transparentize($euiShadowColor, .7)); + background-color: $euiPageBackgroundColor; + padding: $euiSize $euiSizeS $euiSizeS; + margin: $euiSizeS (-$euiSizeS) (-$euiSizeS); +} + +@keyframes mapTocEntryBecomeVisible { + 0% { opacity: 0; } + 100% { opacity: 1; } +} diff --git a/x-pack/plugins/maps/public/components/widget_overlay/layer_control/layer_toc/toc_entry/index.js b/x-pack/plugins/maps/public/components/widget_overlay/layer_control/layer_toc/toc_entry/index.js index 5d33cdb4e9ac6..102f61684c589 100644 --- a/x-pack/plugins/maps/public/components/widget_overlay/layer_control/layer_toc/toc_entry/index.js +++ b/x-pack/plugins/maps/public/components/widget_overlay/layer_control/layer_toc/toc_entry/index.js @@ -7,7 +7,14 @@ import _ from 'lodash'; import { connect } from 'react-redux'; import { TOCEntry } from './view'; -import { getIsReadOnly, updateFlyout, FLYOUT_STATE } from '../../../../../store/ui'; +import { + getIsReadOnly, + updateFlyout, + FLYOUT_STATE, + getOpenTOCDetails, + hideTOCDetails, + showTOCDetails, +} from '../../../../../store/ui'; import { fitToLayerExtent, setSelectedLayer, @@ -18,12 +25,13 @@ import { import { hasDirtyState, getSelectedLayer } from '../../../../../selectors/map_selectors'; -function mapStateToProps(state = {}) { +function mapStateToProps(state = {}, ownProps) { return { isReadOnly: getIsReadOnly(state), zoom: _.get(state, 'map.mapState.zoom', 0), selectedLayer: getSelectedLayer(state), hasDirtyStateSelector: hasDirtyState(state), + isLegendDetailsOpen: getOpenTOCDetails(state).includes(ownProps.layer.getId()), }; } @@ -42,7 +50,13 @@ function mapDispatchToProps(dispatch) { }, cloneLayer: layerId => { dispatch(cloneLayer(layerId)); - } + }, + hideTOCDetails: layerId => { + dispatch(hideTOCDetails(layerId)); + }, + showTOCDetails: layerId => { + dispatch(showTOCDetails(layerId)); + }, }); } diff --git a/x-pack/plugins/maps/public/components/widget_overlay/layer_control/layer_toc/toc_entry/view.js b/x-pack/plugins/maps/public/components/widget_overlay/layer_control/layer_toc/toc_entry/view.js index 031dca7cb2dfd..4c0417ca96613 100644 --- a/x-pack/plugins/maps/public/components/widget_overlay/layer_control/layer_toc/toc_entry/view.js +++ b/x-pack/plugins/maps/public/components/widget_overlay/layer_control/layer_toc/toc_entry/view.js @@ -4,22 +4,27 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { Fragment } from 'react'; +import React from 'react'; +import classNames from 'classnames'; + import { - EuiFlexGroup, - EuiFlexItem, EuiIcon, - EuiSpacer, EuiOverlayMask, EuiModal, EuiModalBody, EuiModalFooter, EuiButton, EuiButtonEmpty, - EuiLink, - EuiText, + EuiButtonIcon, } from '@elastic/eui'; import { LayerTocActions } from '../../../../../shared/components/layer_toc_actions'; +import { i18n } from '@kbn/i18n'; + +function escapeLayerName(name) { + return name + ? name.split(' ').join('_') + : ''; +} export class TOCEntry extends React.Component { @@ -37,6 +42,18 @@ export class TOCEntry extends React.Component { this._isMounted = false; } + componentDidUpdate() { + this._updateDisplayName(); + } + + _toggleLayerDetailsVisibility = () => { + if (this.props.isLegendDetailsOpen) { + this.props.hideTOCDetails(this.props.layer.getId()); + } else { + this.props.showTOCDetails(this.props.layer.getId()); + } + } + async _updateDisplayName() { const label = await this.props.layer.getDisplayName(); if (this._isMounted) { @@ -48,10 +65,6 @@ export class TOCEntry extends React.Component { } } - componentDidUpdate() { - this._updateDisplayName(); - } - _openLayerPanelWithCheck = () => { const { selectedLayer, hasDirtyStateSelector } = this.props; if (selectedLayer && selectedLayer.getId() === this.props.layer.getId()) { @@ -112,33 +125,73 @@ export class TOCEntry extends React.Component { ); } - _renderLayerName() { - const displayName = ( -
- {this.state.displayName} + _renderLayerIcons() { + if (this.props.isReadOnly) { + return null; + } + + return ( +
+ + + + +
); + } - if (this.props.isReadOnly) { - return ( - - {displayName} - - ); + _renderDetailsToggle() { + if (!this.props.layer.hasLegendDetails()) { + return null; } + const { isLegendDetailsOpen } = this.props; return ( - - {displayName} - + + + ); } @@ -152,78 +205,78 @@ export class TOCEntry extends React.Component { fitToBounds } = this.props; - let sortIcon; - if (!isReadOnly) { - sortIcon = ( - - - - - - ); - } - return ( - - - { - fitToBounds(layer.getId()); - }} - zoom={zoom} - toggleVisible={() => { - toggleVisible(layer.getId()); - }} - displayName={this.state.displayName} - cloneLayer={() => { - cloneLayer(layer.getId()); - }} - isReadOnly={this.props.isReadOnly} - /> - - - {this._renderLayerName()} - - {sortIcon} - + { + fitToBounds(layer.getId()); + }} + zoom={zoom} + toggleVisible={() => { + toggleVisible(layer.getId()); + }} + displayName={this.state.displayName} + escapedDisplayName={escapeLayerName(this.state.displayName)} + cloneLayer={() => { + cloneLayer(layer.getId()); + }} + editLayer={this._openLayerPanelWithCheck} + isReadOnly={isReadOnly} + /> + + {this._renderLayerIcons()} +
); } - _renderLayerDetails() { - const tocDetails = this.props.layer.getTOCDetails(); + _renderLegendDetails = () => { + if (!this.props.isLegendDetailsOpen || !this.props.layer.hasLegendDetails()) { + return null; + } + + const tocDetails = this.props.layer.getLegendDetails(); if (!tocDetails) { return null; } return ( - - +
{tocDetails} - +
); } render() { + const classes = classNames( + 'mapTocEntry', + { + 'mapTocEntry-isDragging': this.props.isDragging, + 'mapTocEntry-isDraggingOver': this.props.isDraggingOver, + }, + ); + return (
- {this._renderCancelModal()} - {this._renderLayerHeader()} - {this._renderLayerDetails()} + {this._renderLegendDetails()} + + {this._renderDetailsToggle()} + + {this._renderCancelModal()}
); } diff --git a/x-pack/plugins/maps/public/components/widget_overlay/layer_control/layer_toc/toc_entry/view.test.js b/x-pack/plugins/maps/public/components/widget_overlay/layer_control/layer_toc/toc_entry/view.test.js index 5622a17fd39b8..dc0f9950919e4 100644 --- a/x-pack/plugins/maps/public/components/widget_overlay/layer_control/layer_toc/toc_entry/view.test.js +++ b/x-pack/plugins/maps/public/components/widget_overlay/layer_control/layer_toc/toc_entry/view.test.js @@ -9,13 +9,16 @@ import { shallowWithIntl } from 'test_utils/enzyme_helpers'; import { TOCEntry } from './view'; +const LAYER_ID = '1'; + const mockLayer = { - getId: () => { return '1'; }, - getTOCDetails: () => { return (
TOC details mock
); }, + getId: () => { return LAYER_ID; }, + getLegendDetails: () => { return (
TOC details mock
); }, getDisplayName: () => { return 'layer 1'; }, isVisible: () => { return true; }, showAtZoomLevel: () => { return true; }, hasErrors: () => { return false; }, + hasLegendDetails: () => { return true; }, }; const defaultProps = { @@ -26,6 +29,7 @@ const defaultProps = { getSelectedLayerSelector: () => {}, hasDirtyStateSelector: () => {}, zoom: 0, + isLegendDetailsOpen: false, }; describe('TOCEntry', () => { @@ -62,5 +66,22 @@ describe('TOCEntry', () => { expect(component) .toMatchSnapshot(); }); + + test('should display layer details when isLegendDetailsOpen is true', async () => { + const component = shallowWithIntl( + + ); + + // Ensure all promises resolve + await new Promise(resolve => process.nextTick(resolve)); + // Ensure the state changes are reflected + component.update(); + + expect(component) + .toMatchSnapshot(); + }); }); }); diff --git a/x-pack/plugins/maps/public/components/widget_overlay/layer_control/layer_toc/view.js b/x-pack/plugins/maps/public/components/widget_overlay/layer_control/layer_toc/view.js index 4a308c54cf12d..02831d81075c9 100644 --- a/x-pack/plugins/maps/public/components/widget_overlay/layer_control/layer_toc/view.js +++ b/x-pack/plugins/maps/public/components/widget_overlay/layer_control/layer_toc/view.js @@ -65,21 +65,30 @@ export class LayerTOC extends React.Component { }); } - const draggableLayers = reverseLayerList.map((layer, idx) => ( - - {(provided) => ( - - )} - - )); - return ( - {draggableLayers} + {(provided, snapshot) => ( + reverseLayerList.map((layer, idx) => ( + + {(provided, state) => ( + + )} + + )) + )} ); diff --git a/x-pack/plugins/maps/public/components/widget_overlay/widget_overlay.js b/x-pack/plugins/maps/public/components/widget_overlay/widget_overlay.js index ea858ba8997d8..bd59361cc61b2 100644 --- a/x-pack/plugins/maps/public/components/widget_overlay/widget_overlay.js +++ b/x-pack/plugins/maps/public/components/widget_overlay/widget_overlay.js @@ -16,7 +16,7 @@ import { AttributionControl } from './attribution_control'; export function WidgetOverlay() { return ( - + -
- icon mock -
+ +
+ icon mock +
+
+ layer 1 } + className="mapLayTocActions" closePopover={[Function]} hasArrow={true} id="contextMenu" @@ -54,6 +62,15 @@ exports[`LayerTocActions is rendered 1`] = ` "name": "Hide layer", "onClick": [Function], }, + Object { + "data-test-subj": "editLayerButton", + "icon": , + "name": "Edit layer", + "onClick": [Function], + }, Object { "data-test-subj": "cloneLayerButton", "icon": -
- icon mock -
+ +
+ icon mock +
+
+ layer 1 } + className="mapLayTocActions" closePopover={[Function]} hasArrow={true} id="contextMenu" @@ -126,6 +151,15 @@ exports[`LayerTocActions should disable fit to data when supportsFitToBounds is "name": "Hide layer", "onClick": [Function], }, + Object { + "data-test-subj": "editLayerButton", + "icon": , + "name": "Edit layer", + "onClick": [Function], + }, Object { "data-test-subj": "cloneLayerButton", "icon": - + + + + layer 1 } + className="mapLayTocActions" closePopover={[Function]} hasArrow={true} id="contextMenu" @@ -198,6 +240,15 @@ exports[`LayerTocActions should display spinner when layer is loading 1`] = ` "name": "Hide layer", "onClick": [Function], }, + Object { + "data-test-subj": "editLayerButton", + "icon": , + "name": "Edit layer", + "onClick": [Function], + }, Object { "data-test-subj": "cloneLayerButton", "icon": -
- icon mock -
+ +
+ icon mock +
+
+ layer 1 } + className="mapLayTocActions" closePopover={[Function]} hasArrow={true} id="contextMenu" @@ -281,9 +340,11 @@ exports[`LayerTocActions should not show edit actions in read only mode 1`] = ` exports[`LayerTocActions should provide feedback when layer is not visible because of current zoom level 1`] = ` - -
- icon mock -
-
+ +
+ icon mock +
+
+ + layer 1 } + className="mapLayTocActions" closePopover={[Function]} hasArrow={true} id="contextMenu" @@ -340,6 +407,15 @@ exports[`LayerTocActions should provide feedback when layer is not visible becau "name": "Hide layer", "onClick": [Function], }, + Object { + "data-test-subj": "editLayerButton", + "icon": , + "name": "Edit layer", + "onClick": [Function], + }, Object { "data-test-subj": "cloneLayerButton", "icon": -
- icon mock -
+ +
+ icon mock +
+
+ layer 1 } + className="mapLayTocActions" closePopover={[Function]} hasArrow={true} id="contextMenu" @@ -412,6 +496,15 @@ exports[`LayerTocActions should show visible toggle when layer is not visible 1` "name": "Show layer", "onClick": [Function], }, + Object { + "data-test-subj": "editLayerButton", + "icon": , + "name": "Edit layer", + "onClick": [Function], + }, Object { "data-test-subj": "cloneLayerButton", "icon": - + + + + layer 1 } + className="mapLayTocActions" closePopover={[Function]} hasArrow={true} id="contextMenu" @@ -488,6 +589,15 @@ exports[`LayerTocActions should show warning when layer has errors 1`] = ` "name": "Hide layer", "onClick": [Function], }, + Object { + "data-test-subj": "editLayerButton", + "icon": , + "name": "Edit layer", + "onClick": [Function], + }, Object { "data-test-subj": "cloneLayerButton", "icon": - {icon} + {icon} + {this.props.displayName} ); } @@ -160,6 +156,22 @@ export class LayerTocActions extends Component { ]; if (!this.props.isReadOnly) { + actionItems.push({ + name: i18n.translate('xpack.maps.layerTocActions.editLayerTitle', { + defaultMessage: 'Edit layer', + }), + icon: ( + + ), + 'data-test-subj': 'editLayerButton', + onClick: () => { + this._closePopover(); + this.props.editLayer(); + } + }); actionItems.push({ name: i18n.translate('xpack.maps.layerTocActions.cloneLayerTitle', { defaultMessage: 'Clone layer', @@ -193,17 +205,19 @@ export class LayerTocActions extends Component { return ( ); } diff --git a/x-pack/plugins/maps/public/shared/components/layer_toc_actions.test.js b/x-pack/plugins/maps/public/shared/components/layer_toc_actions.test.js index 3787244e8cd20..a5f1b2464e083 100644 --- a/x-pack/plugins/maps/public/shared/components/layer_toc_actions.test.js +++ b/x-pack/plugins/maps/public/shared/components/layer_toc_actions.test.js @@ -26,7 +26,8 @@ const layerMock = { }; const defaultProps = { - displayName: 'layer1', + displayName: 'layer 1', + escapedDisplayName: 'layer1', zoom: 0, layer: layerMock, }; diff --git a/x-pack/plugins/maps/public/shared/icons/additional_layer_icons.js b/x-pack/plugins/maps/public/shared/icons/additional_layer_icons.js index bf23450a29cb5..54b7620b155f3 100644 --- a/x-pack/plugins/maps/public/shared/icons/additional_layer_icons.js +++ b/x-pack/plugins/maps/public/shared/icons/additional_layer_icons.js @@ -44,7 +44,7 @@ export const FillableCircle = ({ style }) => ( ); -export const FillableVector = ({ style }) => ( +export const FillableRectangle = ({ style }) => ( { +export const ColorGradient = ({ color, className }) => { if (!color || !COLOR_KEYS.includes(color)) { return null; - } else { - const rgbColorStrings = getLegendColors(vislibColorMaps[color].value, GRADIENT_INTERVALS); - const background = getLinearGradient(rgbColorStrings, GRADIENT_INTERVALS); - return ( -
- ); } + + const classes = classNames('mapColorGradient', className); + const rgbColorStrings = getLegendColors(vislibColorMaps[color].value, GRADIENT_INTERVALS); + const background = getLinearGradient(rgbColorStrings, GRADIENT_INTERVALS); + return ( +
+ ); }; function getLinearGradient(colorStrings, intervals) { diff --git a/x-pack/plugins/maps/public/shared/layers/layer.js b/x-pack/plugins/maps/public/shared/layers/layer.js index 03b56247ac15a..4b93d86717d13 100644 --- a/x-pack/plugins/maps/public/shared/layers/layer.js +++ b/x-pack/plugins/maps/public/shared/layers/layer.js @@ -105,7 +105,11 @@ export class AbstractLayer { console.warn('Icon not available for this layer type'); } - getTOCDetails() { + hasLegendDetails() { + return false; + } + + getLegendDetails() { return null; } diff --git a/x-pack/plugins/maps/public/shared/layers/styles/components/static_dynamic_style_row.js b/x-pack/plugins/maps/public/shared/layers/styles/components/static_dynamic_style_row.js index f4ef285e94b9c..0ae0924961f30 100644 --- a/x-pack/plugins/maps/public/shared/layers/styles/components/static_dynamic_style_row.js +++ b/x-pack/plugins/maps/public/shared/layers/styles/components/static_dynamic_style_row.js @@ -105,7 +105,7 @@ export class StaticDynamicStyleRow extends React.Component { return ( - + {this._renderStyleSelector()} diff --git a/x-pack/plugins/maps/public/shared/layers/styles/components/vector/color/dynamic_color_selection.js b/x-pack/plugins/maps/public/shared/layers/styles/components/vector/color/dynamic_color_selection.js index 045848f7433c6..59701b9088015 100644 --- a/x-pack/plugins/maps/public/shared/layers/styles/components/vector/color/dynamic_color_selection.js +++ b/x-pack/plugins/maps/public/shared/layers/styles/components/vector/color/dynamic_color_selection.js @@ -7,6 +7,7 @@ import _ from 'lodash'; import React, { Fragment } from 'react'; import PropTypes from 'prop-types'; +import { dynamicColorShape } from '../style_option_shapes'; import { FieldSelect, fieldShape } from '../field_select'; import { ColorRampSelect } from './color_ramp_select'; import { EuiSpacer } from '@elastic/eui'; @@ -38,9 +39,6 @@ export function DynamicColorSelection({ ordinalFields, onChange, styleOptions }) DynamicColorSelection.propTypes = { ordinalFields: PropTypes.arrayOf(fieldShape).isRequired, - styleOptions: PropTypes.shape({ - color: PropTypes.string.isRequired, - field: fieldShape, - }).isRequired, + styleOptions: dynamicColorShape.isRequired, onChange: PropTypes.func.isRequired }; diff --git a/x-pack/plugins/maps/public/shared/layers/styles/components/vector/color/static_color_selection.js b/x-pack/plugins/maps/public/shared/layers/styles/components/vector/color/static_color_selection.js index c6c547fdcf1f4..6e5fe90fda9e3 100644 --- a/x-pack/plugins/maps/public/shared/layers/styles/components/vector/color/static_color_selection.js +++ b/x-pack/plugins/maps/public/shared/layers/styles/components/vector/color/static_color_selection.js @@ -10,6 +10,7 @@ import { EuiColorPicker, EuiFormControlLayout } from '@elastic/eui'; +import { staticColorShape } from '../style_option_shapes'; export function StaticColorSelection({ onChange, styleOptions }) { const onColorChange = color => { @@ -28,8 +29,6 @@ export function StaticColorSelection({ onChange, styleOptions }) { } StaticColorSelection.propTypes = { - styleOptions: PropTypes.shape({ - color: PropTypes.string.isRequired, - }).isRequired, + styleOptions: staticColorShape.isRequired, onChange: PropTypes.func.isRequired }; diff --git a/x-pack/plugins/maps/public/shared/layers/styles/components/vector/color/vector_style_color_editor.js b/x-pack/plugins/maps/public/shared/layers/styles/components/vector/color/vector_style_color_editor.js index 522cbfcfc31b1..f5b2f7294975a 100644 --- a/x-pack/plugins/maps/public/shared/layers/styles/components/vector/color/vector_style_color_editor.js +++ b/x-pack/plugins/maps/public/shared/layers/styles/components/vector/color/vector_style_color_editor.js @@ -9,13 +9,14 @@ import React from 'react'; import { StaticDynamicStyleRow } from '../../static_dynamic_style_row'; import { DynamicColorSelection } from './dynamic_color_selection'; import { StaticColorSelection } from './static_color_selection'; +import { getVectorStyleLabel } from '../get_vector_style_label'; export function VectorStyleColorEditor(props) { return ( , + , + , + ]; +} + +function getSymbolSizeIcons() { + const defaultStyle = { + stroke: 'grey', + strokeWidth: 'none', + fill: 'grey', + }; + return [ + , + , + , + ]; +} + +function renderHeaderWithIcons(icons) { + return ( + + { + icons.map((icon, index) => { + const isLast = index === icons.length - 1; + let spacer; + if (!isLast) { + spacer = ( + + + + ); + } + return ( + + + {icon} + + {spacer} + + ); + }) + } + + ); +} + +export function StylePropertyLegendRow({ name, type, options, range }) { + if (type === VectorStyle.STYLE_TYPE.STATIC || + !options.field || !options.field.name) { + return null; + } + + let header; + if (options.color) { + header = ; + } else if (name === 'lineWidth') { + header = renderHeaderWithIcons(getLineWidthIcons()); + } else if (name === 'iconSize') { + header = renderHeaderWithIcons(getSymbolSizeIcons()); + } + + return ( +
+ + {header} + + + + {_.get(range, 'min', '')} + + + + + + {options.field.label} + + + + + + {_.get(range, 'max', '')} + + + +
+ ); +} + +StylePropertyLegendRow.propTypes = { + name: PropTypes.string.isRequired, + type: PropTypes.string.isRequired, + options: PropTypes.oneOfType(styleOptionShapes).isRequired, + range: rangeShape, +}; diff --git a/x-pack/plugins/maps/public/shared/layers/styles/components/vector/legend/vector_icon.js b/x-pack/plugins/maps/public/shared/layers/styles/components/vector/legend/vector_icon.js new file mode 100644 index 0000000000000..dcdff386873ff --- /dev/null +++ b/x-pack/plugins/maps/public/shared/layers/styles/components/vector/legend/vector_icon.js @@ -0,0 +1,52 @@ +/* + * 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 React from 'react'; +import PropTypes from 'prop-types'; + +import { dynamicColorShape, staticColorShape } from '../style_option_shapes'; +import { FillableCircle, FillableRectangle } from '../../../../../icons/additional_layer_icons'; +import { VectorStyle } from '../../../vector_style'; +import { getColorRampCenterColor } from '../../../../../utils/color_utils'; + +export function VectorIcon({ fillColor, lineColor, isPointsOnly }) { + const style = { + stroke: extractColorFromStyleProperty(lineColor, 'none'), + strokeWidth: '1px', + fill: extractColorFromStyleProperty(fillColor, 'grey'), + }; + + return isPointsOnly + ? + : ; +} + +function extractColorFromStyleProperty(colorStyleProperty, defaultColor) { + if (!colorStyleProperty) { + return defaultColor; + } + + if (colorStyleProperty.type === VectorStyle.STYLE_TYPE.STATIC) { + return colorStyleProperty.options.color; + } + + // return middle of gradient for dynamic style property + return getColorRampCenterColor(colorStyleProperty.options.color); +} + +const colorStylePropertyShape = PropTypes.shape({ + type: PropTypes.string.isRequired, + options: PropTypes.oneOfType([ + dynamicColorShape, + staticColorShape + ]).isRequired, +}); + +VectorIcon.propTypes = { + fillColor: colorStylePropertyShape, + lineColor: colorStylePropertyShape, + isPointsOnly: PropTypes.bool, +}; diff --git a/x-pack/plugins/maps/public/shared/layers/styles/components/vector/legend/vector_style_legend.js b/x-pack/plugins/maps/public/shared/layers/styles/components/vector/legend/vector_style_legend.js new file mode 100644 index 0000000000000..8d400e8db9b02 --- /dev/null +++ b/x-pack/plugins/maps/public/shared/layers/styles/components/vector/legend/vector_style_legend.js @@ -0,0 +1,36 @@ +/* + * 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 React from 'react'; +import PropTypes from 'prop-types'; + +import { styleOptionShapes, rangeShape } from '../style_option_shapes'; +import { StylePropertyLegendRow } from './style_property_legend_row'; + +export function VectorStyleLegend({ styleProperties }) { + return styleProperties.map(styleProperty => { + return ( + + ); + }); +} + +const stylePropertyShape = PropTypes.shape({ + name: PropTypes.string.isRequired, + type: PropTypes.string.isRequired, + options: PropTypes.oneOfType(styleOptionShapes).isRequired, + range: rangeShape, +}); + +VectorStyleLegend.propTypes = { + styleProperties: PropTypes.arrayOf(stylePropertyShape).isRequired +}; diff --git a/x-pack/plugins/maps/public/shared/layers/styles/components/vector/size/dynamic_size_selection.js b/x-pack/plugins/maps/public/shared/layers/styles/components/vector/size/dynamic_size_selection.js index f003cc0e10c85..bd0420cdc8631 100644 --- a/x-pack/plugins/maps/public/shared/layers/styles/components/vector/size/dynamic_size_selection.js +++ b/x-pack/plugins/maps/public/shared/layers/styles/components/vector/size/dynamic_size_selection.js @@ -7,6 +7,7 @@ import _ from 'lodash'; import React, { Fragment } from 'react'; import PropTypes from 'prop-types'; +import { dynamicSizeShape } from '../style_option_shapes'; import { FieldSelect, fieldShape } from '../field_select'; import { SizeRangeSelector } from './size_range_selector'; import { EuiSpacer } from '@elastic/eui'; @@ -39,10 +40,6 @@ export function DynamicSizeSelection({ ordinalFields, styleOptions, onChange }) DynamicSizeSelection.propTypes = { ordinalFields: PropTypes.arrayOf(fieldShape).isRequired, - styleOptions: PropTypes.shape({ - minSize: PropTypes.number.isRequired, - maxSize: PropTypes.number.isRequired, - field: fieldShape, - }).isRequired, + styleOptions: dynamicSizeShape.isRequired, onChange: PropTypes.func.isRequired }; diff --git a/x-pack/plugins/maps/public/shared/layers/styles/components/vector/size/static_size_selection.js b/x-pack/plugins/maps/public/shared/layers/styles/components/vector/size/static_size_selection.js index 0a0c29e28c289..a5ecfb5e3e3ce 100644 --- a/x-pack/plugins/maps/public/shared/layers/styles/components/vector/size/static_size_selection.js +++ b/x-pack/plugins/maps/public/shared/layers/styles/components/vector/size/static_size_selection.js @@ -6,6 +6,7 @@ import React from 'react'; import PropTypes from 'prop-types'; +import { staticSizeShape } from '../style_option_shapes'; import { ValidatedRange } from '../../../../../components/validated_range'; export function StaticSizeSelection({ onChange, styleOptions }) { @@ -27,8 +28,6 @@ export function StaticSizeSelection({ onChange, styleOptions }) { } StaticSizeSelection.propTypes = { - styleOptions: PropTypes.shape({ - size: PropTypes.number.isRequired, - }).isRequired, + styleOptions: staticSizeShape.isRequired, onChange: PropTypes.func.isRequired }; diff --git a/x-pack/plugins/maps/public/shared/layers/styles/components/vector/size/vector_style_size_editor.js b/x-pack/plugins/maps/public/shared/layers/styles/components/vector/size/vector_style_size_editor.js index e72f13279e9f5..a03835f7a9501 100644 --- a/x-pack/plugins/maps/public/shared/layers/styles/components/vector/size/vector_style_size_editor.js +++ b/x-pack/plugins/maps/public/shared/layers/styles/components/vector/size/vector_style_size_editor.js @@ -9,13 +9,14 @@ import React from 'react'; import { StaticDynamicStyleRow } from '../../static_dynamic_style_row'; import { DynamicSizeSelection } from './dynamic_size_selection'; import { StaticSizeSelection } from './static_size_selection'; +import { getVectorStyleLabel } from '../get_vector_style_label'; export function VectorStyleSizeEditor(props) { return ( { return { name: options.field.name, @@ -194,7 +194,7 @@ export class VectorStyle extends AbstractStyle { return this._descriptor.properties || {}; } - _getDynamicPropertiesArray() { + getDynamicPropertiesArray() { const styles = this.getProperties(); return Object.keys(styles) .map(styleName => { @@ -224,48 +224,29 @@ export class VectorStyle extends AbstractStyle { } getIcon = () => { - let style = { - stroke: 'grey', - strokeWidth: '1px', - fill: 'none' - }; - const isDynamic = this._isPropertyDynamic('fillColor'); - if (!isDynamic) { - const { fillColor, lineColor } = this._descriptor.properties; - const stroke = _.get(lineColor, 'options.color'); - const fill = _.get(fillColor, 'options.color'); - - style = { - ...style, - ...stroke && { stroke }, - ...fill && { fill }, - }; - } - + const styles = this.getProperties(); return ( - this._getIsPointsOnly() - ? - : + ); } - getColorRamp() { - const color = _.get(this._descriptor, 'properties.fillColor.options.color'); - return color && this._isPropertyDynamic('fillColor') - ? - : null; - } + getLegendDetails() { + const styles = this.getProperties(); + const styleProperties = Object.keys(styles).map(styleName => { + const { type, options } = styles[styleName]; + return { + name: styleName, + type, + options, + range: options && options.field && options.field.name ? this._getFieldRange(options.field.name) : null, + }; + }); - getTOCDetails() { - const isDynamic = this._isPropertyDynamic('fillColor'); - if (isDynamic) { - return ( - - {this.getColorRamp()} - - ); - } - return null; + return (); } addScaledPropertiesBasedOnStyle(featureCollection) { @@ -273,7 +254,7 @@ export class VectorStyle extends AbstractStyle { return false; } - const scaledFields = this._getDynamicPropertiesArray() + const scaledFields = this.getDynamicPropertiesArray() .map(({ options }) => { const name = options.field.name; return { diff --git a/x-pack/plugins/maps/public/shared/layers/vector_layer.js b/x-pack/plugins/maps/public/shared/layers/vector_layer.js index c3fa4f1ac5e5d..b3122b18ee89d 100644 --- a/x-pack/plugins/maps/public/shared/layers/vector_layer.js +++ b/x-pack/plugins/maps/public/shared/layers/vector_layer.js @@ -86,8 +86,12 @@ export class VectorLayer extends AbstractLayer { return 'vector'; } - getTOCDetails() { - return this._style.getTOCDetails(); + hasLegendDetails() { + return this._style.getDynamicPropertiesArray().length > 0; + } + + getLegendDetails() { + return this._style.getLegendDetails(); } _getBoundsBasedOnData() { diff --git a/x-pack/plugins/maps/public/shared/utils/color_utils.js b/x-pack/plugins/maps/public/shared/utils/color_utils.js index 187fcd7293e79..8f7ca601f8b9f 100644 --- a/x-pack/plugins/maps/public/shared/utils/color_utils.js +++ b/x-pack/plugins/maps/public/shared/utils/color_utils.js @@ -5,20 +5,29 @@ */ import { vislibColorMaps } from 'ui/vislib/components/color/colormaps'; -import { getLegendColors } from 'ui/vis/map/color_util'; +import { getLegendColors, getColor } from 'ui/vis/map/color_util'; import chroma from 'chroma-js'; -export function getRGBColorRangeStrings(colorName, numberColors) { - const colorKeys = Object.keys(vislibColorMaps); - if (!colorKeys.includes(colorName)) { - //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}`); +function getColorRamp(colorRampName) { + const colorRamp = vislibColorMaps[colorRampName]; + if (!colorRamp) { + throw new Error(`${colorRampName} not found. Expected one of following values: ${Object.keys(vislibColorMaps)}`); } - return getLegendColors(vislibColorMaps[colorName].value, numberColors); + return colorRamp; } -export function getHexColorRangeStrings(colorName, numberColors) { - return getRGBColorRangeStrings(colorName, numberColors) +export function getRGBColorRangeStrings(colorRampName, numberColors) { + const colorRamp = getColorRamp(colorRampName); + return getLegendColors(colorRamp.value, numberColors); +} + +export function getHexColorRangeStrings(colorRampName, numberColors) { + return getRGBColorRangeStrings(colorRampName, numberColors) .map(rgbColor => chroma(rgbColor).hex()); } + +export function getColorRampCenterColor(colorRampName) { + const colorRamp = getColorRamp(colorRampName); + const centerIndex = Math.floor(colorRamp.value.length / 2); + return getColor(colorRamp.value, centerIndex); +} diff --git a/x-pack/plugins/maps/public/store/ui.js b/x-pack/plugins/maps/public/store/ui.js index 408df7ed67388..6af80c5844b7f 100644 --- a/x-pack/plugins/maps/public/store/ui.js +++ b/x-pack/plugins/maps/public/store/ui.js @@ -10,6 +10,10 @@ export const SET_IS_LAYER_TOC_OPEN = 'SET_IS_LAYER_TOC_OPEN'; export const SET_FULL_SCREEN = 'SET_FULL_SCREEN'; export const SET_READ_ONLY = 'SET_READ_ONLY'; export const SET_FILTERABLE = 'IS_FILTERABLE'; +export const SET_OPEN_TOC_DETAILS = 'SET_OPEN_TOC_DETAILS'; +export const SHOW_TOC_DETAILS = 'SHOW_TOC_DETAILS'; +export const HIDE_TOC_DETAILS = 'HIDE_TOC_DETAILS'; + export const FLYOUT_STATE = { NONE: 'NONE', LAYER_PANEL: 'LAYER_PANEL', @@ -23,7 +27,10 @@ const INITIAL_STATE = { isFullScreen: false, isReadOnly: false, isLayerTOCOpen: DEFAULT_IS_LAYER_TOC_OPEN, - isFilterable: false + isFilterable: false, + // storing TOC detail visibility outside of map.layerList because its UI state and not map rendering state. + // This also makes for easy read/write access for embeddables. + openTOCDetails: [], }; // Reducer @@ -43,6 +50,23 @@ export function ui(state = INITIAL_STATE, action) { return { ...state, isReadOnly: action.isReadOnly }; case SET_FILTERABLE: return { ...state, isFilterable: action.isFilterable }; + case SET_OPEN_TOC_DETAILS: + return { ...state, openTOCDetails: action.layerIds }; + case SHOW_TOC_DETAILS: + return { + ...state, + openTOCDetails: [ + ...state.openTOCDetails, + action.layerId + ] + }; + case HIDE_TOC_DETAILS: + return { + ...state, + openTOCDetails: state.openTOCDetails.filter(layerId => { + return layerId !== action.layerId; + }) + }; default: return state; } @@ -97,11 +121,33 @@ export function setFilterable(isFilterable) { }; } +export function setOpenTOCDetails(layerIds) { + return { + type: SET_OPEN_TOC_DETAILS, + layerIds + }; +} + +export function showTOCDetails(layerId) { + return { + type: SHOW_TOC_DETAILS, + layerId + }; +} + +export function hideTOCDetails(layerId) { + return { + type: HIDE_TOC_DETAILS, + layerId + }; +} + // Selectors export const getFlyoutDisplay = ({ ui }) => ui && ui.flyoutDisplay || INITIAL_STATE.flyoutDisplay; export const getIsSetViewOpen = ({ ui }) => ui.isSetViewOpen; export const getIsLayerTOCOpen = ({ ui }) => ui.isLayerTOCOpen; +export const getOpenTOCDetails = ({ ui }) => ui.openTOCDetails; export const getIsFullScreen = ({ ui }) => ui.isFullScreen; export const getIsReadOnly = ({ ui }) => ui.isReadOnly; export const getIsFilterable = ({ ui }) => ui.isFilterable; diff --git a/x-pack/test/functional/apps/maps/joins.js b/x-pack/test/functional/apps/maps/joins.js index 0e750d5fa83a7..8c65bde460e0e 100644 --- a/x-pack/test/functional/apps/maps/joins.js +++ b/x-pack/test/functional/apps/maps/joins.js @@ -45,6 +45,17 @@ export default function ({ getPageObjects, getService }) { expect(beforeRefreshTimerTimestamp).not.to.equal(afterRefreshTimerTimestamp); }); + it('should show dynamic data range in legend', async () => { + const layerTOCDetails = await PageObjects.maps.getLayerTOCDetails('geo_shapes*'); + const split = layerTOCDetails.trim().split('\n'); + + const min = split[0]; + expect(min).to.equal('3'); + + const max = split[2]; + expect(max).to.equal('12'); + }); + it('should decorate feature properties with join property', async () => { const mapboxStyle = await PageObjects.maps.getMapboxStyle(); expect(mapboxStyle.sources[VECTOR_SOURCE_ID].data.features.length).to.equal(4); @@ -60,7 +71,6 @@ export default function ({ getPageObjects, getService }) { }); }); - it('should style fills, points and lines independently', async () => { const mapboxStyle = await PageObjects.maps.getMapboxStyle(); const layersForVectorSource = mapboxStyle.layers.filter(mbLayer => { diff --git a/x-pack/test/functional/es_archives/maps/kibana/data.json b/x-pack/test/functional/es_archives/maps/kibana/data.json index 4a46af3a38cb1..322c493531504 100644 --- a/x-pack/test/functional/es_archives/maps/kibana/data.json +++ b/x-pack/test/functional/es_archives/maps/kibana/data.json @@ -110,7 +110,7 @@ "type": "envelope" }, "description": "", - "layerListJSON": "[{\"id\":\"0hmz5\",\"sourceDescriptor\":{\"type\":\"EMS_TMS\",\"id\":\"road_map\"},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"TILE\",\"properties\":{\"alphaValue\":1}},\"type\":\"TILE\",\"minZoom\":0,\"maxZoom\":24},{\"id\":\"z52lq\",\"label\":\"logstash\",\"minZoom\":0,\"maxZoom\":24,\"sourceDescriptor\":{\"id\":\"e1a5e1a6-676c-4a89-8ea9-0d91d64b73c6\",\"type\":\"ES_SEARCH\",\"indexPatternId\":\"c698b940-e149-11e8-a35a-370a8516603a\",\"geoField\":\"geo.coordinates\",\"limit\":2048,\"filterByMapBounds\":true,\"showTooltip\":true,\"tooltipProperties\":[]},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#e6194b\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}},\"alphaValue\":1},\"previousStyle\":null},\"type\":\"VECTOR\"}]", + "layerListJSON": "[{\"id\":\"0hmz5\",\"sourceDescriptor\":{\"type\":\"EMS_TMS\",\"id\":\"road_map\"},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"TILE\",\"properties\":{}},\"type\":\"TILE\",\"minZoom\":0,\"maxZoom\":24},{\"id\":\"z52lq\",\"label\":\"logstash\",\"minZoom\":0,\"maxZoom\":24,\"sourceDescriptor\":{\"id\":\"e1a5e1a6-676c-4a89-8ea9-0d91d64b73c6\",\"type\":\"ES_SEARCH\",\"indexPatternId\":\"c698b940-e149-11e8-a35a-370a8516603a\",\"geoField\":\"geo.coordinates\",\"limit\":2048,\"filterByMapBounds\":true,\"showTooltip\":true,\"tooltipProperties\":[]},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#e6194b\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}}},\"previousStyle\":null},\"type\":\"VECTOR\"}]", "mapStateJSON": "{\"zoom\":4.1,\"center\":{\"lon\":-100.61091,\"lat\":33.23887},\"timeFilters\":{\"from\":\"2015-09-20T00:00:00.000Z\",\"to\":\"2015-09-20T01:00:00.000Z\"},\"refreshConfig\":{\"isPaused\":true,\"interval\":1000}}", "title": "document example", "uiStateJSON": "{\"isDarkMode\":false}" @@ -141,7 +141,7 @@ "type": "envelope" }, "description": "", - "layerListJSON": "[{\"id\":\"0hmz5\",\"sourceDescriptor\":{\"type\":\"EMS_TMS\",\"id\":\"road_map\"},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"TILE\",\"properties\":{\"alphaValue\":1}},\"type\":\"TILE\",\"minZoom\":0,\"maxZoom\":24},{\"id\":\"z52lq\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"sourceDescriptor\":{\"id\":\"e1a5e1a6-676c-4a89-8ea9-0d91d64b73c6\",\"type\":\"ES_SEARCH\",\"indexPatternId\":\"c698b940-e149-11e8-a35a-370a8516603a\",\"geoField\":\"geo.coordinates\",\"limit\":2048,\"filterByMapBounds\":true,\"showTooltip\":true,\"tooltipProperties\":[\"machine.os\"]},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#e6194b\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}},\"alphaValue\":1},\"previousStyle\":null},\"type\":\"VECTOR\"}]", + "layerListJSON": "[{\"id\":\"0hmz5\",\"sourceDescriptor\":{\"type\":\"EMS_TMS\",\"id\":\"road_map\"},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"TILE\",\"properties\":{}},\"type\":\"TILE\",\"minZoom\":0,\"maxZoom\":24},{\"id\":\"z52lq\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"sourceDescriptor\":{\"id\":\"e1a5e1a6-676c-4a89-8ea9-0d91d64b73c6\",\"type\":\"ES_SEARCH\",\"indexPatternId\":\"c698b940-e149-11e8-a35a-370a8516603a\",\"geoField\":\"geo.coordinates\",\"limit\":2048,\"filterByMapBounds\":true,\"showTooltip\":true,\"tooltipProperties\":[\"machine.os\"]},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#e6194b\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}}},\"previousStyle\":null},\"type\":\"VECTOR\"}]", "mapStateJSON": "{\"zoom\":4.1,\"center\":{\"lon\":-100.61091,\"lat\":33.23887},\"timeFilters\":{\"from\":\"2015-09-20T00:00:00.000Z\",\"to\":\"2015-09-20T01:00:00.000Z\"},\"refreshConfig\":{\"isPaused\":true,\"interval\":1000},\"query\":{\"query\":\"machine.os.raw : \\\"ios\\\"\",\"language\":\"kuery\"}}", "title": "document example with query", "uiStateJSON": "{\"isDarkMode\":false}" @@ -172,10 +172,10 @@ "type": "envelope" }, "description": "", - "layerListJSON": "[{\"id\":\"0hmz5\",\"label\":\"EMS base layer (road_map)\",\"sourceDescriptor\":{\"type\":\"EMS_TMS\",\"id\":\"road_map\"},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"TILE\",\"properties\":{\"alphaValue\":1}},\"type\":\"TILE\",\"minZoom\":0,\"maxZoom\":24},{\"id\":\"n1t6f\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"sourceDescriptor\":{\"id\":\"62eca1fc-fe42-11e8-8eb2-f2801f1b9fd1\",\"type\":\"ES_SEARCH\",\"geoField\":\"geometry\",\"limit\":2048,\"filterByMapBounds\":false,\"showTooltip\":true,\"tooltipProperties\":[],\"indexPatternRefName\":\"layer_1_source_index_pattern\"},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"DYNAMIC\",\"options\":{\"field\":{\"label\":\"max(prop1) group by meta_for_geo_shapes*.shape_name\",\"name\":\"__kbnjoin__max_of_prop1_groupby_meta_for_geo_shapes*.shape_name\",\"origin\":\"join\"},\"color\":\"Blues\"}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}},\"alphaValue\":1},\"temporary\":true,\"previousStyle\":null},\"type\":\"VECTOR\",\"joins\":[{\"leftField\":\"name\",\"right\":{\"id\":\"855ccb86-fe42-11e8-8eb2-f2801f1b9fd1\",\"indexPatternTitle\":\"meta_for_geo_shapes*\",\"term\":\"shape_name\",\"metrics\":[{\"type\":\"max\",\"field\":\"prop1\"}],\"indexPatternRefName\":\"layer_1_join_0_index_pattern\"}}]}]", + "layerListJSON": "[{\"id\":\"0hmz5\",\"label\":\"EMS base layer (road_map)\",\"sourceDescriptor\":{\"type\":\"EMS_TMS\",\"id\":\"road_map\"},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"TILE\",\"properties\":{}},\"type\":\"TILE\",\"minZoom\":0,\"maxZoom\":24},{\"id\":\"n1t6f\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"sourceDescriptor\":{\"id\":\"62eca1fc-fe42-11e8-8eb2-f2801f1b9fd1\",\"type\":\"ES_SEARCH\",\"geoField\":\"geometry\",\"limit\":2048,\"filterByMapBounds\":false,\"showTooltip\":true,\"tooltipProperties\":[],\"indexPatternRefName\":\"layer_1_source_index_pattern\"},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"DYNAMIC\",\"options\":{\"field\":{\"label\":\"max(prop1) group by meta_for_geo_shapes*.shape_name\",\"name\":\"__kbnjoin__max_of_prop1_groupby_meta_for_geo_shapes*.shape_name\",\"origin\":\"join\"},\"color\":\"Blues\"}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}}},\"temporary\":true,\"previousStyle\":null},\"type\":\"VECTOR\",\"joins\":[{\"leftField\":\"name\",\"right\":{\"id\":\"855ccb86-fe42-11e8-8eb2-f2801f1b9fd1\",\"indexPatternTitle\":\"meta_for_geo_shapes*\",\"term\":\"shape_name\",\"metrics\":[{\"type\":\"max\",\"field\":\"prop1\"}],\"indexPatternRefName\":\"layer_1_join_0_index_pattern\"}}]}]", "mapStateJSON": "{\"zoom\":3.02,\"center\":{\"lon\":77.33426,\"lat\":-0.04647},\"timeFilters\":{\"from\":\"now-17m\",\"to\":\"now\",\"mode\":\"quick\"},\"refreshConfig\":{\"isPaused\":true,\"interval\":1000}}", "title": "join example", - "uiStateJSON": "{\"isDarkMode\":false}" + "uiStateJSON": "{\"isLayerTOCOpen\":true,\"openTOCDetails\":[\"n1t6f\"]}" }, "type": "map", "references" : [ @@ -217,7 +217,7 @@ ], "type": "envelope" }, - "layerListJSON": "[{\"id\":\"0hmz5\",\"sourceDescriptor\":{\"type\":\"EMS_TMS\",\"id\":\"road_map\"},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"TILE\",\"properties\":{\"alphaValue\":1}},\"type\":\"TILE\",\"minZoom\":0,\"maxZoom\":24},{\"id\":\"3xlvm\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"sourceDescriptor\":{\"resolution\": \"COARSE\",\"type\":\"ES_GEO_GRID\",\"id\":\"427aa49d-a552-4e7d-a629-67c47db27128\",\"indexPatternId\":\"c698b940-e149-11e8-a35a-370a8516603a\",\"geoField\":\"geo.coordinates\",\"requestType\":\"heatmap\"},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"HEATMAP\",\"refinement\":\"coarse\",\"properties\":{\"alphaValue\":1},\"previousStyle\":null},\"type\":\"HEATMAP\"}]", + "layerListJSON": "[{\"id\":\"0hmz5\",\"sourceDescriptor\":{\"type\":\"EMS_TMS\",\"id\":\"road_map\"},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"TILE\",\"properties\":{}},\"type\":\"TILE\",\"minZoom\":0,\"maxZoom\":24},{\"id\":\"3xlvm\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"sourceDescriptor\":{\"resolution\": \"COARSE\",\"type\":\"ES_GEO_GRID\",\"id\":\"427aa49d-a552-4e7d-a629-67c47db27128\",\"indexPatternId\":\"c698b940-e149-11e8-a35a-370a8516603a\",\"geoField\":\"geo.coordinates\",\"requestType\":\"heatmap\"},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"HEATMAP\",\"refinement\":\"coarse\",\"properties\":{},\"previousStyle\":null},\"type\":\"HEATMAP\"}]", "mapStateJSON": "{\"zoom\":3.59,\"center\":{\"lon\":-98.05765,\"lat\":38.32288},\"timeFilters\":{\"from\":\"2015-09-20T00:00:00.000Z\",\"to\":\"2015-09-20T01:00:00.000Z\"},\"refreshConfig\":{\"isPaused\":true,\"interval\":1000}}", "title": "geo grid heatmap example", "uiStateJSON": "{\"isDarkMode\":false}" @@ -248,7 +248,7 @@ "type": "envelope" }, "description": "", - "layerListJSON": "[{\"id\":\"0hmz5\",\"sourceDescriptor\":{\"type\":\"EMS_TMS\",\"id\":\"road_map\"},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"TILE\",\"properties\":{\"alphaValue\":1}},\"type\":\"TILE\",\"minZoom\":0,\"maxZoom\":24},{\"id\":\"g1xkv\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"sourceDescriptor\":{\"resolution\": \"COARSE\",\"type\":\"ES_GEO_GRID\",\"id\":\"9305f6ea-4518-4c06-95b9-33321aa38d6a\",\"indexPatternId\":\"c698b940-e149-11e8-a35a-370a8516603a\",\"geoField\":\"geo.coordinates\",\"requestType\":\"grid\",\"metrics\":[{\"type\":\"count\"},{\"type\":\"max\",\"field\":\"bytes\"}]},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"DYNAMIC\",\"options\":{\"field\":{\"label\":\"max of bytes\",\"name\":\"max_of_bytes\",\"origin\":\"source\"},\"color\":\"Blues\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#cccccc\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"DYNAMIC\",\"options\":{\"field\":{\"label\":\"Count\",\"name\":\"doc_count\",\"origin\":\"source\"},\"minSize\":4,\"maxSize\":32}},\"alphaValue\":1},\"temporary\":true,\"previousStyle\":null},\"type\":\"VECTOR\"}]", + "layerListJSON": "[{\"id\":\"0hmz5\",\"sourceDescriptor\":{\"type\":\"EMS_TMS\",\"id\":\"road_map\"},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"TILE\",\"properties\":{}},\"type\":\"TILE\",\"minZoom\":0,\"maxZoom\":24},{\"id\":\"g1xkv\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"sourceDescriptor\":{\"resolution\": \"COARSE\",\"type\":\"ES_GEO_GRID\",\"id\":\"9305f6ea-4518-4c06-95b9-33321aa38d6a\",\"indexPatternId\":\"c698b940-e149-11e8-a35a-370a8516603a\",\"geoField\":\"geo.coordinates\",\"requestType\":\"grid\",\"metrics\":[{\"type\":\"count\"},{\"type\":\"max\",\"field\":\"bytes\"}]},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"DYNAMIC\",\"options\":{\"field\":{\"label\":\"max of bytes\",\"name\":\"max_of_bytes\",\"origin\":\"source\"},\"color\":\"Blues\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#cccccc\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"DYNAMIC\",\"options\":{\"field\":{\"label\":\"Count\",\"name\":\"doc_count\",\"origin\":\"source\"},\"minSize\":4,\"maxSize\":32}}},\"temporary\":true,\"previousStyle\":null},\"type\":\"VECTOR\"}]", "mapStateJSON": "{\"zoom\":3.59,\"center\":{\"lon\":-98.05765,\"lat\":38.32288},\"timeFilters\":{\"from\":\"2015-09-20T00:00:00.000Z\",\"to\":\"2015-09-20T01:00:00.000Z\"},\"refreshConfig\":{\"isPaused\":true,\"interval\":1000}}", "title": "geo grid vector grid example", "uiStateJSON": "{\"isDarkMode\":false}" @@ -293,7 +293,7 @@ "type": "polygon" }, "description": "", - "layerListJSON": "[{\"id\":\"0hmz5\",\"sourceDescriptor\":{\"type\":\"EMS_TMS\",\"id\":\"road_map\"},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"TILE\",\"properties\":{\"alphaValue\":1}},\"type\":\"TILE\",\"minZoom\":0,\"maxZoom\":24},{\"id\":\"frk92\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"sourceDescriptor\":{\"id\":\"7d807c75-088a-44b7-920a-e7e47f4fc038\",\"type\":\"ES_SEARCH\",\"indexPatternId\":\"1035e930-1811-11e9-b78a-23d706cd2507\",\"geoField\":\"location\",\"limit\":2048,\"filterByMapBounds\":true,\"tooltipProperties\":[]},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#e6194b\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}},\"alphaValue\":1},\"previousStyle\":null},\"type\":\"VECTOR\"}]", + "layerListJSON": "[{\"id\":\"0hmz5\",\"sourceDescriptor\":{\"type\":\"EMS_TMS\",\"id\":\"road_map\"},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"TILE\",\"properties\":{}},\"type\":\"TILE\",\"minZoom\":0,\"maxZoom\":24},{\"id\":\"frk92\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"sourceDescriptor\":{\"id\":\"7d807c75-088a-44b7-920a-e7e47f4fc038\",\"type\":\"ES_SEARCH\",\"indexPatternId\":\"1035e930-1811-11e9-b78a-23d706cd2507\",\"geoField\":\"location\",\"limit\":2048,\"filterByMapBounds\":true,\"tooltipProperties\":[]},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#e6194b\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}}},\"previousStyle\":null},\"type\":\"VECTOR\"}]", "mapStateJSON": "{\"zoom\":8.8,\"center\":{\"lon\":-179.98743,\"lat\":-0.09561},\"timeFilters\":{\"from\":\"now-15m\",\"to\":\"now\",\"mode\":\"quick\"},\"refreshConfig\":{\"isPaused\":true,\"interval\":0},\"query\":{\"query\":\"\",\"language\":\"kuery\"}}", "title": "antimeridian points example", "uiStateJSON": "{\"isDarkMode\":false}" @@ -338,7 +338,7 @@ "type": "polygon" }, "description": "", - "layerListJSON": "[{\"id\":\"0hmz5\",\"sourceDescriptor\":{\"type\":\"EMS_TMS\",\"id\":\"road_map\"},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"TILE\",\"properties\":{\"alphaValue\":1}},\"type\":\"TILE\",\"minZoom\":0,\"maxZoom\":24},{\"id\":\"ad9fj\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"sourceDescriptor\":{\"id\":\"4e4b5628-dbdc-40bb-93f0-8a7a48be1141\",\"type\":\"ES_SEARCH\",\"indexPatternId\":\"502886a0-18f8-11e9-97c8-5da5e037299c\",\"geoField\":\"location\",\"limit\":2048,\"filterByMapBounds\":true,\"tooltipProperties\":[]},\"visible\":true,\"temporary\":true,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#e6194b\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}},\"alphaValue\":1}},\"type\":\"VECTOR\"}]", + "layerListJSON": "[{\"id\":\"0hmz5\",\"sourceDescriptor\":{\"type\":\"EMS_TMS\",\"id\":\"road_map\"},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"TILE\",\"properties\":{}},\"type\":\"TILE\",\"minZoom\":0,\"maxZoom\":24},{\"id\":\"ad9fj\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"sourceDescriptor\":{\"id\":\"4e4b5628-dbdc-40bb-93f0-8a7a48be1141\",\"type\":\"ES_SEARCH\",\"indexPatternId\":\"502886a0-18f8-11e9-97c8-5da5e037299c\",\"geoField\":\"location\",\"limit\":2048,\"filterByMapBounds\":true,\"tooltipProperties\":[]},\"visible\":true,\"temporary\":true,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#e6194b\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}}}},\"type\":\"VECTOR\"}]", "mapStateJSON": "{\"zoom\":5.65,\"center\":{\"lon\":179.03193,\"lat\":0.09593},\"timeFilters\":{\"from\":\"now-15m\",\"to\":\"now\"},\"refreshConfig\":{\"isPaused\":true,\"interval\":0},\"query\":{\"language\":\"kuery\",\"query\":\"\"}}", "title": "antimeridian shapes example", "uiStateJSON": "{\"isDarkMode\":false}" @@ -383,7 +383,7 @@ "type": "polygon" }, "description": "", - "layerListJSON" : "[{\"sourceDescriptor\":{\"type\":\"KIBANA_TILEMAP\"},\"id\":\"ap0ys\",\"label\":\"Custom_TMS\",\"minZoom\":0,\"maxZoom\":24,\"alpha\":1,\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"TILE\",\"properties\":{},\"previousStyle\":null},\"type\":\"TILE\"},{\"sourceDescriptor\":{\"type\":\"REGIONMAP_FILE\",\"name\":\"nameThatDoesNotExitForKibanaRegionmapSource\"},\"temporary\":false,\"id\":\"0sabv\",\"label\":\"Custom_vector_shapes\",\"minZoom\":0,\"maxZoom\":24,\"alpha\":0.75,\"visible\":true,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#3cb44b\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}}},\"previousStyle\":null},\"type\":\"VECTOR\"},{\"sourceDescriptor\":{\"type\":\"EMS_TMS\",\"id\":\"idThatDoesNotExitForEMSTile\"},\"temporary\":false,\"id\":\"plw9l\",\"label\":\"EMS_tiles\",\"minZoom\":0,\"maxZoom\":24,\"alpha\":1,\"visible\":true,\"style\":{\"type\":\"TILE\",\"properties\":{},\"previousStyle\":null},\"type\":\"TILE\"},{\"sourceDescriptor\":{\"type\":\"EMS_FILE\",\"id\":\"idThatDoesNotExitForEMSFileSource\"},\"temporary\":false,\"id\":\"2gro0\",\"label\":\"EMS_vector_shapes\",\"minZoom\":0,\"maxZoom\":24,\"alpha\":0.75,\"visible\":true,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#e6194b\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}}},\"previousStyle\":null},\"type\":\"VECTOR\"},{\"sourceDescriptor\":{\"type\":\"ES_GEO_GRID\",\"id\":\"f67fe707-95dd-46d6-89b8-82617b251b61\",\"indexPatternId\":\"idThatDoesNotExitForESGeoGridSource\",\"geoField\":\"geo.coordinates\",\"requestType\":\"grid\",\"resolution\":\"COARSE\"},\"temporary\":false,\"id\":\"pl5qd\",\"label\":\"\",\"minZoom\":0,\"maxZoom\":24,\"alpha\":0.75,\"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\":\"#FFFFFF\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"DYNAMIC\",\"options\":{\"field\":{\"label\":\"Count\",\"name\":\"doc_count\",\"origin\":\"source\"},\"minSize\":4,\"maxSize\":32}}},\"previousStyle\":null},\"type\":\"VECTOR\"},{\"sourceDescriptor\":{\"id\":\"a07072bb-3a92-4320-bd37-250ef6d04db7\",\"type\":\"ES_SEARCH\",\"indexPatternId\":\"idThatDoesNotExitForESSearchSource\",\"geoField\":\"geo.coordinates\",\"limit\":2048,\"filterByMapBounds\":true,\"tooltipProperties\":[]},\"temporary\":false,\"id\":\"9bw8h\",\"label\":\"\",\"minZoom\":0,\"maxZoom\":24,\"alpha\":0.75,\"visible\":true,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#e6194b\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}}},\"previousStyle\":null},\"type\":\"VECTOR\"},{\"id\":\"n1t6f\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"sourceDescriptor\":{\"id\":\"62eca1fc-fe42-11e8-8eb2-f2801f1b9fd1\",\"type\":\"ES_SEARCH\",\"indexPatternId\":\"561253e0-f731-11e8-8487-11b9dd924f96\",\"geoField\":\"geometry\",\"limit\":2048,\"filterByMapBounds\":false,\"showTooltip\":true,\"tooltipProperties\":[]},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"DYNAMIC\",\"options\":{\"field\":{\"label\":\"max(prop1) group by meta_for_geo_shapes*.shape_name\",\"name\":\"__kbnjoin__max_of_prop1_groupby_meta_for_geo_shapes*.shape_name\",\"origin\":\"join\"},\"color\":\"Blues\"}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}},\"alphaValue\":1},\"temporary\":true,\"previousStyle\":null},\"type\":\"VECTOR\",\"joins\":[{\"leftField\":\"name\",\"right\":{\"id\":\"855ccb86-fe42-11e8-8eb2-f2801f1b9fd1\",\"indexPatternId\":\"idThatDoesNotExitForESJoinSource\",\"indexPatternTitle\":\"meta_for_geo_shapes*\",\"term\":\"shape_name\",\"metrics\":[{\"type\":\"max\",\"field\":\"prop1\"}]}}]}]", + "layerListJSON" : "[{\"sourceDescriptor\":{\"type\":\"KIBANA_TILEMAP\"},\"id\":\"ap0ys\",\"label\":\"Custom_TMS\",\"minZoom\":0,\"maxZoom\":24,\"alpha\":1,\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"TILE\",\"properties\":{},\"previousStyle\":null},\"type\":\"TILE\"},{\"sourceDescriptor\":{\"type\":\"REGIONMAP_FILE\",\"name\":\"nameThatDoesNotExitForKibanaRegionmapSource\"},\"temporary\":false,\"id\":\"0sabv\",\"label\":\"Custom_vector_shapes\",\"minZoom\":0,\"maxZoom\":24,\"alpha\":0.75,\"visible\":true,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#3cb44b\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}}},\"previousStyle\":null},\"type\":\"VECTOR\"},{\"sourceDescriptor\":{\"type\":\"EMS_TMS\",\"id\":\"idThatDoesNotExitForEMSTile\"},\"temporary\":false,\"id\":\"plw9l\",\"label\":\"EMS_tiles\",\"minZoom\":0,\"maxZoom\":24,\"alpha\":1,\"visible\":true,\"style\":{\"type\":\"TILE\",\"properties\":{},\"previousStyle\":null},\"type\":\"TILE\"},{\"sourceDescriptor\":{\"type\":\"EMS_FILE\",\"id\":\"idThatDoesNotExitForEMSFileSource\"},\"temporary\":false,\"id\":\"2gro0\",\"label\":\"EMS_vector_shapes\",\"minZoom\":0,\"maxZoom\":24,\"alpha\":0.75,\"visible\":true,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#e6194b\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}}},\"previousStyle\":null},\"type\":\"VECTOR\"},{\"sourceDescriptor\":{\"type\":\"ES_GEO_GRID\",\"id\":\"f67fe707-95dd-46d6-89b8-82617b251b61\",\"indexPatternId\":\"idThatDoesNotExitForESGeoGridSource\",\"geoField\":\"geo.coordinates\",\"requestType\":\"grid\",\"resolution\":\"COARSE\"},\"temporary\":false,\"id\":\"pl5qd\",\"label\":\"\",\"minZoom\":0,\"maxZoom\":24,\"alpha\":0.75,\"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\":\"#FFFFFF\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"DYNAMIC\",\"options\":{\"field\":{\"label\":\"Count\",\"name\":\"doc_count\",\"origin\":\"source\"},\"minSize\":4,\"maxSize\":32}}},\"previousStyle\":null},\"type\":\"VECTOR\"},{\"sourceDescriptor\":{\"id\":\"a07072bb-3a92-4320-bd37-250ef6d04db7\",\"type\":\"ES_SEARCH\",\"indexPatternId\":\"idThatDoesNotExitForESSearchSource\",\"geoField\":\"geo.coordinates\",\"limit\":2048,\"filterByMapBounds\":true,\"tooltipProperties\":[]},\"temporary\":false,\"id\":\"9bw8h\",\"label\":\"\",\"minZoom\":0,\"maxZoom\":24,\"alpha\":0.75,\"visible\":true,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#e6194b\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}}},\"previousStyle\":null},\"type\":\"VECTOR\"},{\"id\":\"n1t6f\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"sourceDescriptor\":{\"id\":\"62eca1fc-fe42-11e8-8eb2-f2801f1b9fd1\",\"type\":\"ES_SEARCH\",\"indexPatternId\":\"561253e0-f731-11e8-8487-11b9dd924f96\",\"geoField\":\"geometry\",\"limit\":2048,\"filterByMapBounds\":false,\"showTooltip\":true,\"tooltipProperties\":[]},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"DYNAMIC\",\"options\":{\"field\":{\"label\":\"max(prop1) group by meta_for_geo_shapes*.shape_name\",\"name\":\"__kbnjoin__max_of_prop1_groupby_meta_for_geo_shapes*.shape_name\",\"origin\":\"join\"},\"color\":\"Blues\"}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}}},\"temporary\":true,\"previousStyle\":null},\"type\":\"VECTOR\",\"joins\":[{\"leftField\":\"name\",\"right\":{\"id\":\"855ccb86-fe42-11e8-8eb2-f2801f1b9fd1\",\"indexPatternId\":\"idThatDoesNotExitForESJoinSource\",\"indexPatternTitle\":\"meta_for_geo_shapes*\",\"term\":\"shape_name\",\"metrics\":[{\"type\":\"max\",\"field\":\"prop1\"}]}}]}]", "mapStateJSON": "{\"zoom\":0.71,\"center\":{\"lon\":0.10268,\"lat\":0},\"timeFilters\":{\"from\":\"now-7d\",\"to\":\"now\"},\"refreshConfig\":{\"isPaused\":true,\"interval\":0},\"query\":{\"query\":\"\",\"language\":\"kuery\"}}", "title": "layer with errors", "uiStateJSON": "{}" diff --git a/x-pack/test/functional/page_objects/gis_page.js b/x-pack/test/functional/page_objects/gis_page.js index 6f2ecf4625cf6..f865d8b0060b5 100644 --- a/x-pack/test/functional/page_objects/gis_page.js +++ b/x-pack/test/functional/page_objects/gis_page.js @@ -17,6 +17,10 @@ export function GisPageProvider({ getService, getPageObjects }) { const queryBar = getService('queryBar'); const comboBox = getService('comboBox'); + function escapeLayerName(layerName) { + return layerName.split(' ').join('_'); + } + class GisPage { constructor() { @@ -247,16 +251,21 @@ export function GisPageProvider({ getService, getPageObjects }) { } async openLayerTocActionsPanel(layerName) { - const cleanLayerName = layerName.split(' ').join(''); - const isOpen = await testSubjects.exists(`layerTocActionsPanel${cleanLayerName}`); + const escapedDisplayName = escapeLayerName(layerName); + const isOpen = await testSubjects.exists(`layerTocActionsPanel${escapedDisplayName}`); if (!isOpen) { - await testSubjects.click(`layerTocActionsPanelToggleButton${cleanLayerName}`); + await testSubjects.click(`layerTocActionsPanelToggleButton${escapedDisplayName}`); } } async openLayerPanel(layerName) { log.debug(`Open layer panel, layer: ${layerName}`); - await testSubjects.click(`mapOpenLayerButton${layerName}`); + await this.openLayerTocActionsPanel(layerName); + await testSubjects.click('editLayerButton'); + } + + async getLayerTOCDetails(layerName) { + return await testSubjects.getVisibleText(`mapLayerTOCDetails${escapeLayerName(layerName)}`); } async disableApplyGlobalQuery() { @@ -276,9 +285,7 @@ export function GisPageProvider({ getService, getPageObjects }) { } async doesLayerExist(layerName) { - layerName = layerName.replace(' ', '_'); - log.debug(`Open layer panel, layer: ${layerName}`); - return await testSubjects.exists(`mapOpenLayerButton${layerName}`); + return await testSubjects.exists(`layerTocActionsPanelToggleButton${escapeLayerName(layerName)}`); } /*