diff --git a/src/components/common/action-panel.js b/src/components/common/action-panel.js index 25494ce293..48f07d7584 100644 --- a/src/components/common/action-panel.js +++ b/src/components/common/action-panel.js @@ -34,8 +34,9 @@ const StyledItem = styled.div` min-height: ${props => props.theme.actionPanelHeight}px; text-transform: capitalize; background-color: ${props => props.theme.dropdownListBgd}; - width: ${props => props.theme.actionPanelWidth}px; + max-width: 200px; position: relative; + ${props => (props.color ? `border-left: 3px solid rgb(${props.color});` : '')} :hover { cursor: pointer; color: ${props => props.theme.textColorHl}; @@ -46,6 +47,8 @@ const StyledItem = styled.div` .label { margin-left: 8px; + white-space: nowrap; + text-overflow: ellipsis; } .label-icon { @@ -53,13 +56,19 @@ const StyledItem = styled.div` } .nested-group { - width: 110px; + max-width: 200px; + overflow: hidden; display: none; color: ${props => props.theme.textColor}; position: absolute; - left: 110px; + left: 100%; top: 0px; padding-left: 4px; + + label { + white-space: nowrap; + text-overflow: ellipsis; + } } `; diff --git a/src/components/editor/editor.js b/src/components/editor/editor.js index 0cd5ec4ee3..0e34f93ce9 100644 --- a/src/components/editor/editor.js +++ b/src/components/editor/editor.js @@ -197,6 +197,7 @@ export default function EditorFactory(FeatureActionPanel) { /> {showActions && Boolean(selectedFeatureId) ? ( { + const [copied, setCopied] = useState(false); + const {layerId = []} = currentFilter || {}; + const intl = useIntl(); - static defaultProps = { - position: {} - }; + const copyGeometry = useCallback(() => { + if (selectedFeature?.geometry) copy(JSON.stringify(selectedFeature.geometry)); + setCopied(true); + }, [selectedFeature?.geometry]); - // Used by onClickOutside - handleClickOutside = e => { - e.preventDefault(); - e.stopPropagation(); - this.props.onClose(); - }; + return ( + + + + {layers.map((layer, index) => ( + onToggleLayer(layer)} + className="layer-panel-item" + /> + ))} + + - render() { - const { - className, - datasets, - position, - layers, - currentFilter, - onToggleLayer, - onDeleteFeature - } = this.props; - - const {layerId = []} = currentFilter || {}; - - return ( - - - - {layers.map((layer, index) => ( - onToggleLayer(layer)} - className="layer-panel-item" - /> - ))} - - - - - ); - } - } + + + + ); + }; FeatureActionPanel.displayName = 'FeatureActionPanel'; + FeatureActionPanel.propTypes = { + className: PropTypes.string, + datasets: PropTypes.object.isRequired, + position: PropTypes.object.isRequired, + layers: PropTypes.arrayOf(PropTypes.object).isRequired, + currentFilter: PropTypes.object, + onClose: PropTypes.func.isRequired, + onDeleteFeature: PropTypes.func.isRequired + }; + + FeatureActionPanel.defaultProps = { + position: {} + }; return FeatureActionPanel; } @@ -112,5 +122,22 @@ export function PureFeatureActionPanelFactory() { FeatureActionPanelFactory.deps = PureFeatureActionPanelFactory.deps; export default function FeatureActionPanelFactory() { - return onClickOutside(PureFeatureActionPanelFactory()); + const PureFeatureActionPanel = PureFeatureActionPanelFactory(); + + const ClickOutsideFeatureActionPanel = props => { + // @ts-ignore + ClickOutsideFeatureActionPanel.handleClickOutside = e => { + e.preventDefault(); + e.stopPropagation(); + props.onClose?.(); + }; + return ; + }; + + const clickOutsideConfig = { + // @ts-ignore + handleClickOutside: () => ClickOutsideFeatureActionPanel.handleClickOutside + }; + + return onClickOutside(ClickOutsideFeatureActionPanel, clickOutsideConfig); } diff --git a/src/localization/en.js b/src/localization/en.js index a3e83c10f4..ec47c566f1 100644 --- a/src/localization/en.js +++ b/src/localization/en.js @@ -221,13 +221,18 @@ export default { exportMap: 'Export Map', shareMapURL: 'Share Map URL', saveMap: 'Save Map', - select: 'select', - polygon: 'polygon', - rectangle: 'rectangle', - hide: 'hide', - show: 'show', + select: 'Select', + polygon: 'Polygon', + rectangle: 'Rectangle', + hide: 'Hide', + show: 'Show', ...LOCALES }, + editor: { + filterLayer: 'Filter Layers', + copyGeometry: 'Copy Geometry' + }, + modal: { title: { deleteDataset: 'Delete Dataset', diff --git a/test/browser/components/editor/feature-action-panel-test.js b/test/browser/components/editor/feature-action-panel-test.js index 8966c0e020..4c7e525cb1 100644 --- a/test/browser/components/editor/feature-action-panel-test.js +++ b/test/browser/components/editor/feature-action-panel-test.js @@ -20,9 +20,9 @@ import React from 'react'; import test from 'tape'; -import {shallow} from 'enzyme'; import sinon from 'sinon'; import {PureFeatureActionPanelFactory} from 'components/editor/feature-action-panel'; +import {IntlWrapper, mountWithTheme} from 'test/helpers/component-utils'; const FeatureActionPanel = PureFeatureActionPanelFactory(); @@ -51,17 +51,34 @@ test('FeatureActionPanel -> display layers', t => { const onToggleLayer = sinon.spy(); const onDeleteFeature = sinon.spy(); - const $ = shallow( - - ); + let wrapper; - t.equal($.find('.layer-panel-item').length, 2, 'We should display only 2 action panel items'); + t.doesNotThrow(() => { + wrapper = mountWithTheme( + + + + ); + }, 'FeatureActionPanel should not fail mount'); + + t.equal(wrapper.find('Checkbox').length, 2, 'We should display only 2 layer checkbox'); + for (let i = 0; i < wrapper.find('Checkbox').length; i++) { + t.equal( + wrapper + .find('Checkbox') + .at(i) + .find('label') + .text(), + `layer ${i + 1}`, + 'should render correct layer label' + ); + } t.end(); });