diff --git a/x-pack/plugins/maps/public/actions/map_actions.d.ts b/x-pack/plugins/maps/public/actions/map_actions.d.ts index c8db284a5c4f1a..38c56405787eb2 100644 --- a/x-pack/plugins/maps/public/actions/map_actions.d.ts +++ b/x-pack/plugins/maps/public/actions/map_actions.d.ts @@ -74,3 +74,11 @@ export function updateMapSetting( settingKey: string, settingValue: string | boolean | number ): AnyAction; + +export function cloneLayer(layerId: string): AnyAction; + +export function fitToLayerExtent(layerId: string): AnyAction; + +export function removeLayer(layerId: string): AnyAction; + +export function toggleLayerVisible(layerId: string): AnyAction; diff --git a/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/__snapshots__/view.test.js.snap b/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/__snapshots__/view.test.js.snap index 27ea52bfed0440..f1cb1a88647539 100644 --- a/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/__snapshots__/view.test.js.snap +++ b/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/__snapshots__/view.test.js.snap @@ -9,12 +9,10 @@ exports[`TOCEntry is rendered 1`] = `
-
-
-
-
-
{ - dispatch(toggleLayerVisible(layerId)); - }, - fitToBounds: layerId => { - dispatch(fitToLayerExtent(layerId)); - }, - cloneLayer: layerId => { - dispatch(cloneLayer(layerId)); - }, - removeLayer: layerId => { - dispatch(removeLayer(layerId)); - }, hideTOCDetails: layerId => { dispatch(hideTOCDetails(layerId)); }, diff --git a/x-pack/plugins/maps/public/components/__snapshots__/layer_toc_actions.test.js.snap b/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/toc_entry_actions_popover/__snapshots__/toc_entry_actions_popover.test.tsx.snap similarity index 92% rename from x-pack/plugins/maps/public/components/__snapshots__/layer_toc_actions.test.js.snap rename to x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/toc_entry_actions_popover/__snapshots__/toc_entry_actions_popover.test.tsx.snap index af836ceffa4b7e..b8c652909408ac 100644 --- a/x-pack/plugins/maps/public/components/__snapshots__/layer_toc_actions.test.js.snap +++ b/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/toc_entry_actions_popover/__snapshots__/toc_entry_actions_popover.test.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`LayerTocActions is rendered 1`] = ` +exports[`TOCEntryActionsPopover is rendered 1`] = ` , "name": "Hide layer", "onClick": [Function], + "toolTipContent": null, }, Object { "data-test-subj": "editLayerButton", + "disabled": false, "icon": , "name": "Edit layer", "onClick": [Function], + "toolTipContent": null, }, Object { "data-test-subj": "cloneLayerButton", @@ -104,6 +107,7 @@ exports[`LayerTocActions is rendered 1`] = ` />, "name": "Clone layer", "onClick": [Function], + "toolTipContent": null, }, Object { "data-test-subj": "removeLayerButton", @@ -113,6 +117,7 @@ exports[`LayerTocActions is rendered 1`] = ` />, "name": "Remove layer", "onClick": [Function], + "toolTipContent": null, }, ], "title": "Layer actions", @@ -123,7 +128,7 @@ exports[`LayerTocActions is rendered 1`] = ` `; -exports[`LayerTocActions should disable fit to data when supportsFitToBounds is false 1`] = ` +exports[`TOCEntryActionsPopover should disable fit to data when supportsFitToBounds is false 1`] = ` , "name": "Hide layer", "onClick": [Function], + "toolTipContent": null, }, Object { "data-test-subj": "editLayerButton", + "disabled": false, "icon": , "name": "Edit layer", "onClick": [Function], + "toolTipContent": null, }, Object { "data-test-subj": "cloneLayerButton", @@ -227,6 +235,7 @@ exports[`LayerTocActions should disable fit to data when supportsFitToBounds is />, "name": "Clone layer", "onClick": [Function], + "toolTipContent": null, }, Object { "data-test-subj": "removeLayerButton", @@ -236,6 +245,7 @@ exports[`LayerTocActions should disable fit to data when supportsFitToBounds is />, "name": "Remove layer", "onClick": [Function], + "toolTipContent": null, }, ], "title": "Layer actions", @@ -246,7 +256,7 @@ exports[`LayerTocActions should disable fit to data when supportsFitToBounds is `; -exports[`LayerTocActions should not show edit actions in read only mode 1`] = ` +exports[`TOCEntryActionsPopover should not show edit actions in read only mode 1`] = ` , "name": "Hide layer", "onClick": [Function], + "toolTipContent": null, }, ], "title": "Layer actions", diff --git a/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/toc_entry_actions_popover/index.ts b/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/toc_entry_actions_popover/index.ts new file mode 100644 index 00000000000000..1437370557efc4 --- /dev/null +++ b/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/toc_entry_actions_popover/index.ts @@ -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. + */ + +import { AnyAction, Dispatch } from 'redux'; +import { connect } from 'react-redux'; +import { MapStoreState } from '../../../../../../reducers/store'; +import { + fitToLayerExtent, + toggleLayerVisible, + cloneLayer, + removeLayer, +} from '../../../../../../actions/map_actions'; +import { getMapZoom, isUsingSearch } from '../../../../../../selectors/map_selectors'; +import { getIsReadOnly } from '../../../../../../selectors/ui_selectors'; +import { TOCEntryActionsPopover } from './toc_entry_actions_popover'; + +function mapStateToProps(state: MapStoreState) { + return { + isReadOnly: getIsReadOnly(state), + isUsingSearch: isUsingSearch(state), + zoom: getMapZoom(state), + }; +} + +function mapDispatchToProps(dispatch: Dispatch) { + return { + cloneLayer: (layerId: string) => { + dispatch(cloneLayer(layerId)); + }, + fitToBounds: (layerId: string) => { + dispatch(fitToLayerExtent(layerId)); + }, + removeLayer: (layerId: string) => { + dispatch(removeLayer(layerId)); + }, + toggleVisible: (layerId: string) => { + dispatch(toggleLayerVisible(layerId)); + }, + }; +} + +const connectedTOCEntryActionsPopover = connect( + mapStateToProps, + mapDispatchToProps +)(TOCEntryActionsPopover); +export { connectedTOCEntryActionsPopover as TOCEntryActionsPopover }; diff --git a/x-pack/plugins/maps/public/components/layer_toc_actions.test.js b/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/toc_entry_actions_popover/toc_entry_actions_popover.test.tsx similarity index 52% rename from x-pack/plugins/maps/public/components/layer_toc_actions.test.js rename to x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/toc_entry_actions_popover/toc_entry_actions_popover.test.tsx index c3a8f59c4c736a..b873119fd7d139 100644 --- a/x-pack/plugins/maps/public/components/layer_toc_actions.test.js +++ b/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/toc_entry_actions_popover/toc_entry_actions_popover.test.tsx @@ -3,21 +3,45 @@ * 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-classes-per-file */ import React from 'react'; import { shallowWithIntl } from 'test_utils/enzyme_helpers'; +import { AbstractLayer, ILayer } from '../../../../../../layers/layer'; +import { AbstractSource, ISource } from '../../../../../../layers/sources/source'; +import { AbstractStyle, IStyle } from '../../../../../../layers/styles/style'; -import { LayerTocActions } from './layer_toc_actions'; +import { TOCEntryActionsPopover } from './toc_entry_actions_popover'; -let supportsFitToBounds; -const layerMock = { - supportsFitToBounds: () => { +let supportsFitToBounds: boolean; + +class MockSource extends AbstractSource implements ISource {} + +class MockStyle extends AbstractStyle implements IStyle {} + +class LayerMock extends AbstractLayer implements ILayer { + constructor() { + const sourceDescriptor = { + type: 'mySourceType', + }; + const source = new MockSource(sourceDescriptor); + const style = new MockStyle({ type: 'myStyleType' }); + const layerDescriptor = { + id: 'testLayer', + sourceDescriptor, + }; + super({ layerDescriptor, source, style }); + } + + async supportsFitToBounds(): Promise { return supportsFitToBounds; - }, - isVisible: () => { + } + + isVisible() { return true; - }, - getIconAndTooltipContent: (zoom, isUsingSearch) => { + } + + getIconAndTooltipContent(zoom: number, isUsingSearch: boolean) { return { icon: mockIcon, tooltipContent: `simulated tooltip content at zoom: ${zoom}`, @@ -28,24 +52,31 @@ const layerMock = { }, ], }; - }, -}; + } +} const defaultProps = { + cloneLayer: () => {}, displayName: 'layer 1', + editLayer: () => {}, escapedDisplayName: 'layer1', - zoom: 0, - layer: layerMock, + fitToBounds: () => {}, + isEditButtonDisabled: false, + isReadOnly: false, isUsingSearch: true, + layer: new LayerMock(), + removeLayer: () => {}, + toggleVisible: () => {}, + zoom: 0, }; -describe('LayerTocActions', () => { +describe('TOCEntryActionsPopover', () => { beforeEach(() => { supportsFitToBounds = true; }); test('is rendered', async () => { - const component = shallowWithIntl(); + const component = shallowWithIntl(); // Ensure all promises resolve await new Promise(resolve => process.nextTick(resolve)); @@ -56,7 +87,9 @@ describe('LayerTocActions', () => { }); test('should not show edit actions in read only mode', async () => { - const component = shallowWithIntl(); + const component = shallowWithIntl( + + ); // Ensure all promises resolve await new Promise(resolve => process.nextTick(resolve)); @@ -68,7 +101,7 @@ describe('LayerTocActions', () => { test('should disable fit to data when supportsFitToBounds is false', async () => { supportsFitToBounds = false; - const component = shallowWithIntl(); + const component = shallowWithIntl(); // Ensure all promises resolve await new Promise(resolve => process.nextTick(resolve)); diff --git a/x-pack/plugins/maps/public/components/layer_toc_actions.js b/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/toc_entry_actions_popover/toc_entry_actions_popover.tsx similarity index 81% rename from x-pack/plugins/maps/public/components/layer_toc_actions.js rename to x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/toc_entry_actions_popover/toc_entry_actions_popover.tsx index d79eda16037cb7..d628cca61de113 100644 --- a/x-pack/plugins/maps/public/components/layer_toc_actions.js +++ b/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/toc_entry_actions_popover/toc_entry_actions_popover.tsx @@ -8,8 +8,31 @@ import React, { Component, Fragment } from 'react'; import { EuiButtonEmpty, EuiPopover, EuiContextMenu, EuiIcon, EuiToolTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { ILayer } from '../../../../../../layers/layer'; + +interface Props { + cloneLayer: (layerId: string) => void; + displayName: string; + editLayer: () => void; + escapedDisplayName: string; + fitToBounds: (layerId: string) => void; + isEditButtonDisabled: boolean; + isReadOnly: boolean; + isUsingSearch: boolean; + layer: ILayer; + removeLayer: (layerId: string) => void; + toggleVisible: (layerId: string) => void; + zoom: number; +} + +interface State { + isPopoverOpen: boolean; + supportsFitToBounds: boolean; +} + +export class TOCEntryActionsPopover extends Component { + private _isMounted: boolean = false; -export class LayerTocActions extends Component { state = { isPopoverOpen: false, supportsFitToBounds: false, @@ -43,6 +66,22 @@ export class LayerTocActions extends Component { })); }; + _cloneLayer() { + this.props.cloneLayer(this.props.layer.getId()); + } + + _fitToBounds() { + this.props.fitToBounds(this.props.layer.getId()); + } + + _removeLayer() { + this.props.fitToBounds(this.props.layer.getId()); + } + + _toggleVisible() { + this.props.toggleVisible(this.props.layer.getId()); + } + _renderPopoverToggleButton() { const { icon, tooltipContent, footnotes } = this.props.layer.getIconAndTooltipContent( this.props.zoom, @@ -108,7 +147,7 @@ export class LayerTocActions extends Component { disabled: !this.state.supportsFitToBounds, onClick: () => { this._closePopover(); - this.props.fitToBounds(); + this._fitToBounds(); }, }, { @@ -121,20 +160,23 @@ export class LayerTocActions extends Component { }), icon: , 'data-test-subj': 'layerVisibilityToggleButton', + toolTipContent: null, onClick: () => { this._closePopover(); - this.props.toggleVisible(); + this._toggleVisible(); }, }, ]; if (!this.props.isReadOnly) { actionItems.push({ + disabled: this.props.isEditButtonDisabled, name: i18n.translate('xpack.maps.layerTocActions.editLayerTitle', { defaultMessage: 'Edit layer', }), icon: , 'data-test-subj': 'editLayerButton', + toolTipContent: null, onClick: () => { this._closePopover(); this.props.editLayer(); @@ -145,10 +187,11 @@ export class LayerTocActions extends Component { defaultMessage: 'Clone layer', }), icon: , + toolTipContent: null, 'data-test-subj': 'cloneLayerButton', onClick: () => { this._closePopover(); - this.props.cloneLayer(); + this._cloneLayer(); }, }); actionItems.push({ @@ -156,10 +199,11 @@ export class LayerTocActions extends Component { defaultMessage: 'Remove layer', }), icon: , + toolTipContent: null, 'data-test-subj': 'removeLayerButton', onClick: () => { this._closePopover(); - this.props.removeLayer(); + this._removeLayer(); }, }); } diff --git a/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/view.js b/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/view.js index fe56523fb25807..c0ce24fef9cd86 100644 --- a/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/view.js +++ b/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/view.js @@ -8,7 +8,7 @@ import React from 'react'; import classNames from 'classnames'; import { EuiIcon, EuiOverlayMask, EuiButtonIcon, EuiConfirmModal } from '@elastic/eui'; -import { LayerTocActions } from '../../../../../components/layer_toc_actions'; +import { TOCEntryActionsPopover } from './toc_entry_actions_popover'; import { i18n } from '@kbn/i18n'; function escapeLayerName(name) { @@ -124,6 +124,7 @@ export class TOCEntry extends React.Component { return (
- { - 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} - removeLayer={() => { - removeLayer(layer.getId()); - }} + isEditButtonDisabled={this.props.isEditButtonDisabled} /> {this._renderLayerIcons()} diff --git a/x-pack/plugins/maps/public/layers/layer.tsx b/x-pack/plugins/maps/public/layers/layer.tsx index 13fe447cec3dad..dccf413b489f1b 100644 --- a/x-pack/plugins/maps/public/layers/layer.tsx +++ b/x-pack/plugins/maps/public/layers/layer.tsx @@ -45,7 +45,7 @@ export interface ILayer { supportsFitToBounds(): Promise; getAttributions(): Promise; getLabel(): string; - getCustomIconAndTooltipContent(): IconAndTooltipContent; + getCustomIconAndTooltipContent(): CustomIconAndTooltipContent; getIconAndTooltipContent(zoomLevel: number, isUsingSearch: boolean): IconAndTooltipContent; renderLegendDetails(): ReactElement | null; showAtZoomLevel(zoom: number): boolean; @@ -87,7 +87,11 @@ export type Footnote = { export type IconAndTooltipContent = { icon?: ReactElement | null; tooltipContent?: string | null; - footnotes?: Footnote[] | null; + footnotes: Footnote[]; +}; +export type CustomIconAndTooltipContent = { + icon: ReactElement | null; + tooltipContent?: string | null; areResultsTrimmed?: boolean; }; @@ -212,7 +216,7 @@ export class AbstractLayer implements ILayer { return this._descriptor.label ? this._descriptor.label : ''; } - getCustomIconAndTooltipContent(): IconAndTooltipContent { + getCustomIconAndTooltipContent(): CustomIconAndTooltipContent { return { icon: , }; diff --git a/x-pack/plugins/maps/public/selectors/map_selectors.d.ts b/x-pack/plugins/maps/public/selectors/map_selectors.d.ts index 4d0f652af982a2..bc881d06f62ced 100644 --- a/x-pack/plugins/maps/public/selectors/map_selectors.d.ts +++ b/x-pack/plugins/maps/public/selectors/map_selectors.d.ts @@ -22,4 +22,6 @@ export function getMapSettings(state: MapStoreState): MapSettings; export function hasMapSettingsChanges(state: MapStoreState): boolean; +export function isUsingSearch(state: MapStoreState): boolean; + export function getSpatialFiltersLayer(state: MapStoreState): IVectorLayer;