[Maps] convert ToolbarOverlay to TS (#95368)
* [Maps] convert ToolbarOverlay to TS * remove getDerivedStateFromProps * remove unused function Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
73109fb3ab
commit
5f487292fb
|
@ -14,8 +14,6 @@ import { trackMapSettings } from './map_actions';
|
|||
import { setSelectedLayer } from './layer_actions';
|
||||
|
||||
export const UPDATE_FLYOUT = 'UPDATE_FLYOUT';
|
||||
export const CLOSE_SET_VIEW = 'CLOSE_SET_VIEW';
|
||||
export const OPEN_SET_VIEW = 'OPEN_SET_VIEW';
|
||||
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';
|
||||
|
@ -50,16 +48,6 @@ export function openMapSettings() {
|
|||
dispatch(updateFlyout(FLYOUT_STATE.MAP_SETTINGS_PANEL));
|
||||
};
|
||||
}
|
||||
export function closeSetView() {
|
||||
return {
|
||||
type: CLOSE_SET_VIEW,
|
||||
};
|
||||
}
|
||||
export function openSetView() {
|
||||
return {
|
||||
type: OPEN_SET_VIEW,
|
||||
};
|
||||
}
|
||||
export function setIsLayerTOCOpen(isLayerTOCOpen: boolean) {
|
||||
return {
|
||||
type: SET_IS_LAYER_TOC_OPEN,
|
||||
|
|
|
@ -25,9 +25,9 @@ export class DataMappingPopover extends Component<Props, State> {
|
|||
};
|
||||
|
||||
_togglePopover = () => {
|
||||
this.setState({
|
||||
isPopoverOpen: !this.state.isPopoverOpen,
|
||||
});
|
||||
this.setState((prevState) => ({
|
||||
isPopoverOpen: !prevState.isPopoverOpen,
|
||||
}));
|
||||
};
|
||||
|
||||
_closePopover = () => {
|
||||
|
|
|
@ -98,9 +98,9 @@ export class AddTooltipFieldPopover extends Component<Props, State> {
|
|||
}
|
||||
|
||||
_togglePopover = () => {
|
||||
this.setState({
|
||||
isPopoverOpen: !this.state.isPopoverOpen,
|
||||
});
|
||||
this.setState((prevState) => ({
|
||||
isPopoverOpen: !prevState.isPopoverOpen,
|
||||
}));
|
||||
};
|
||||
|
||||
_closePopover = () => {
|
||||
|
|
|
@ -16,7 +16,6 @@ import { ActionExecutionContext, Action } from 'src/plugins/ui_actions/public';
|
|||
import { MBMap } from '../mb_map';
|
||||
// @ts-expect-error
|
||||
import { WidgetOverlay } from '../widget_overlay';
|
||||
// @ts-expect-error
|
||||
import { ToolbarOverlay } from '../toolbar_overlay';
|
||||
// @ts-expect-error
|
||||
import { LayerPanel } from '../layer_panel';
|
||||
|
|
|
@ -35,7 +35,12 @@ exports[`Must zoom tools and draw filter tools 1`] = `
|
|||
<Connect(ToolsControl)
|
||||
geoFields={
|
||||
Array [
|
||||
"coordinates",
|
||||
Object {
|
||||
"geoFieldName": "myGeoFieldName",
|
||||
"geoFieldType": "geo_point",
|
||||
"indexPatternId": "1",
|
||||
"indexPatternTitle": "myIndex",
|
||||
},
|
||||
]
|
||||
}
|
||||
/>
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
import { ToolbarOverlay } from './toolbar_overlay';
|
||||
|
||||
function mapStateToProps() {
|
||||
return {};
|
||||
}
|
||||
|
||||
const connectedToolbarOverlay = connect(mapStateToProps, null)(ToolbarOverlay);
|
||||
export { connectedToolbarOverlay as ToolbarOverlay };
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
export { ToolbarOverlay } from './toolbar_overlay';
|
|
@ -5,33 +5,27 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { AnyAction } from 'redux';
|
||||
import { ThunkDispatch } from 'redux-thunk';
|
||||
import { connect } from 'react-redux';
|
||||
import { SetViewControl } from './set_view_control';
|
||||
import { setGotoWithCenter, closeSetView, openSetView } from '../../../actions';
|
||||
import { setGotoWithCenter } from '../../../actions';
|
||||
import { getMapZoom, getMapCenter, getMapSettings } from '../../../selectors/map_selectors';
|
||||
import { getIsSetViewOpen } from '../../../selectors/ui_selectors';
|
||||
import { MapStoreState } from '../../../reducers/store';
|
||||
|
||||
function mapStateToProps(state = {}) {
|
||||
function mapStateToProps(state: MapStoreState) {
|
||||
return {
|
||||
settings: getMapSettings(state),
|
||||
isSetViewOpen: getIsSetViewOpen(state),
|
||||
zoom: getMapZoom(state),
|
||||
center: getMapCenter(state),
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
function mapDispatchToProps(dispatch: ThunkDispatch<MapStoreState, void, AnyAction>) {
|
||||
return {
|
||||
onSubmit: ({ lat, lon, zoom }) => {
|
||||
dispatch(closeSetView());
|
||||
onSubmit: ({ lat, lon, zoom }: { lat: number; lon: number; zoom: number }) => {
|
||||
dispatch(setGotoWithCenter({ lat, lon, zoom }));
|
||||
},
|
||||
closeSetView: () => {
|
||||
dispatch(closeSetView());
|
||||
},
|
||||
openSetView: () => {
|
||||
dispatch(openSetView());
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
@ -5,8 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { ChangeEvent, Component } from 'react';
|
||||
import {
|
||||
EuiForm,
|
||||
EuiFormRow,
|
||||
|
@ -19,57 +18,86 @@ import {
|
|||
} from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { MapCenter } from '../../../../common/descriptor_types';
|
||||
import { MapSettings } from '../../../reducers/map';
|
||||
|
||||
function getViewString(lat, lon, zoom) {
|
||||
return `${lat},${lon},${zoom}`;
|
||||
export interface Props {
|
||||
settings: MapSettings;
|
||||
zoom: number;
|
||||
center: MapCenter;
|
||||
onSubmit: ({ lat, lon, zoom }: { lat: number; lon: number; zoom: number }) => void;
|
||||
}
|
||||
|
||||
export class SetViewControl extends Component {
|
||||
state = {};
|
||||
interface State {
|
||||
isPopoverOpen: boolean;
|
||||
lat: number | string;
|
||||
lon: number | string;
|
||||
zoom: number | string;
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps(nextProps, prevState) {
|
||||
const nextView = getViewString(nextProps.center.lat, nextProps.center.lon, nextProps.zoom);
|
||||
if (nextView !== prevState.prevView) {
|
||||
return {
|
||||
lat: nextProps.center.lat,
|
||||
lon: nextProps.center.lon,
|
||||
zoom: nextProps.zoom,
|
||||
prevView: nextView,
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
export class SetViewControl extends Component<Props, State> {
|
||||
state: State = {
|
||||
isPopoverOpen: false,
|
||||
lat: 0,
|
||||
lon: 0,
|
||||
zoom: 0,
|
||||
};
|
||||
|
||||
_togglePopover = () => {
|
||||
if (this.props.isSetViewOpen) {
|
||||
this.props.closeSetView();
|
||||
if (this.state.isPopoverOpen) {
|
||||
this._closePopover();
|
||||
return;
|
||||
}
|
||||
|
||||
this.props.openSetView();
|
||||
this.setState({
|
||||
lat: this.props.center.lat,
|
||||
lon: this.props.center.lon,
|
||||
zoom: this.props.zoom,
|
||||
isPopoverOpen: true,
|
||||
});
|
||||
};
|
||||
|
||||
_onLatChange = (evt) => {
|
||||
_closePopover = () => {
|
||||
this.setState({
|
||||
isPopoverOpen: false,
|
||||
});
|
||||
};
|
||||
|
||||
_onLatChange = (evt: ChangeEvent<HTMLInputElement>) => {
|
||||
this._onChange('lat', evt);
|
||||
};
|
||||
|
||||
_onLonChange = (evt) => {
|
||||
_onLonChange = (evt: ChangeEvent<HTMLInputElement>) => {
|
||||
this._onChange('lon', evt);
|
||||
};
|
||||
|
||||
_onZoomChange = (evt) => {
|
||||
_onZoomChange = (evt: ChangeEvent<HTMLInputElement>) => {
|
||||
this._onChange('zoom', evt);
|
||||
};
|
||||
|
||||
_onChange = (name, evt) => {
|
||||
_onChange = (name: 'lat' | 'lon' | 'zoom', evt: ChangeEvent<HTMLInputElement>) => {
|
||||
const sanitizedValue = parseFloat(evt.target.value);
|
||||
// @ts-expect-error
|
||||
this.setState({
|
||||
[name]: isNaN(sanitizedValue) ? '' : sanitizedValue,
|
||||
});
|
||||
};
|
||||
|
||||
_renderNumberFormRow = ({ value, min, max, onChange, label, dataTestSubj }) => {
|
||||
_renderNumberFormRow = ({
|
||||
value,
|
||||
min,
|
||||
max,
|
||||
onChange,
|
||||
label,
|
||||
dataTestSubj,
|
||||
}: {
|
||||
value: string | number;
|
||||
min: number;
|
||||
max: number;
|
||||
onChange: (evt: ChangeEvent<HTMLInputElement>) => void;
|
||||
label: string;
|
||||
dataTestSubj: string;
|
||||
}) => {
|
||||
const isInvalid = value === '' || value > max || value < min;
|
||||
const error = isInvalid ? `Must be between ${min} and ${max}` : null;
|
||||
return {
|
||||
|
@ -90,7 +118,8 @@ export class SetViewControl extends Component {
|
|||
|
||||
_onSubmit = () => {
|
||||
const { lat, lon, zoom } = this.state;
|
||||
this.props.onSubmit({ lat, lon, zoom });
|
||||
this._closePopover();
|
||||
this.props.onSubmit({ lat: lat as number, lon: lon as number, zoom: zoom as number });
|
||||
};
|
||||
|
||||
_renderSetViewForm() {
|
||||
|
@ -175,23 +204,11 @@ export class SetViewControl extends Component {
|
|||
})}
|
||||
/>
|
||||
}
|
||||
isOpen={this.props.isSetViewOpen}
|
||||
closePopover={this.props.closeSetView}
|
||||
isOpen={this.state.isPopoverOpen}
|
||||
closePopover={this._closePopover}
|
||||
>
|
||||
{this._renderSetViewForm()}
|
||||
</EuiPopover>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SetViewControl.propTypes = {
|
||||
isSetViewOpen: PropTypes.bool.isRequired,
|
||||
zoom: PropTypes.number.isRequired,
|
||||
center: PropTypes.shape({
|
||||
lat: PropTypes.number.isRequired,
|
||||
lon: PropTypes.number.isRequired,
|
||||
}),
|
||||
onSubmit: PropTypes.func.isRequired,
|
||||
closeSetView: PropTypes.func.isRequired,
|
||||
openSetView: PropTypes.func.isRequired,
|
||||
};
|
|
@ -1,53 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
|
||||
import { SetViewControl } from './set_view_control';
|
||||
import { ToolsControl } from './tools_control';
|
||||
import { FitToData } from './fit_to_data';
|
||||
|
||||
export class ToolbarOverlay extends React.Component {
|
||||
_renderToolsControl() {
|
||||
const { addFilters, geoFields, getFilterActions, getActionContext } = this.props;
|
||||
if (!addFilters || !geoFields.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<EuiFlexItem>
|
||||
<ToolsControl
|
||||
geoFields={geoFields}
|
||||
getFilterActions={getFilterActions}
|
||||
getActionContext={getActionContext}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<EuiFlexGroup
|
||||
className="mapToolbarOverlay"
|
||||
responsive={false}
|
||||
direction="column"
|
||||
alignItems="flexStart"
|
||||
gutterSize="s"
|
||||
>
|
||||
<EuiFlexItem>
|
||||
<SetViewControl />
|
||||
</EuiFlexItem>
|
||||
|
||||
<EuiFlexItem>
|
||||
<FitToData />
|
||||
</EuiFlexItem>
|
||||
|
||||
{this._renderToolsControl()}
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { Filter } from 'src/plugins/data/public';
|
||||
|
||||
jest.mock('../../kibana_services', () => {
|
||||
return {
|
||||
|
@ -16,15 +17,25 @@ jest.mock('../../kibana_services', () => {
|
|||
};
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
import { ToolbarOverlay } from './toolbar_overlay';
|
||||
|
||||
test('Must render zoom tools', async () => {
|
||||
const component = shallow(<ToolbarOverlay />);
|
||||
const component = shallow(<ToolbarOverlay geoFields={[]} />);
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('Must zoom tools and draw filter tools', async () => {
|
||||
const component = shallow(<ToolbarOverlay addFilters={() => {}} geoFields={['coordinates']} />);
|
||||
const geoFieldWithIndex = {
|
||||
geoFieldName: 'myGeoFieldName',
|
||||
geoFieldType: 'geo_point',
|
||||
indexPatternTitle: 'myIndex',
|
||||
indexPatternId: '1',
|
||||
};
|
||||
const component = shallow(
|
||||
<ToolbarOverlay
|
||||
addFilters={async (filters: Filter[], actionId: string) => {}}
|
||||
geoFields={[geoFieldWithIndex]}
|
||||
/>
|
||||
);
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
|
||||
import { Filter } from 'src/plugins/data/public';
|
||||
import { ActionExecutionContext, Action } from 'src/plugins/ui_actions/public';
|
||||
import { SetViewControl } from './set_view_control';
|
||||
import { ToolsControl } from './tools_control';
|
||||
import { FitToData } from './fit_to_data';
|
||||
import { GeoFieldWithIndex } from '../../components/geo_field_with_index';
|
||||
|
||||
export interface Props {
|
||||
addFilters?: ((filters: Filter[], actionId: string) => Promise<void>) | null;
|
||||
geoFields: GeoFieldWithIndex[];
|
||||
getFilterActions?: () => Promise<Action[]>;
|
||||
getActionContext?: () => ActionExecutionContext;
|
||||
}
|
||||
|
||||
export function ToolbarOverlay(props: Props) {
|
||||
function renderToolsControl() {
|
||||
const { addFilters, geoFields, getFilterActions, getActionContext } = props;
|
||||
if (!addFilters || !geoFields.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<EuiFlexItem>
|
||||
<ToolsControl
|
||||
geoFields={geoFields}
|
||||
getFilterActions={getFilterActions}
|
||||
getActionContext={getActionContext}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<EuiFlexGroup
|
||||
className="mapToolbarOverlay"
|
||||
responsive={false}
|
||||
direction="column"
|
||||
alignItems="flexStart"
|
||||
gutterSize="s"
|
||||
>
|
||||
<EuiFlexItem>
|
||||
<SetViewControl />
|
||||
</EuiFlexItem>
|
||||
|
||||
<EuiFlexItem>
|
||||
<FitToData />
|
||||
</EuiFlexItem>
|
||||
|
||||
{renderToolsControl()}
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
}
|
|
@ -11,8 +11,6 @@ import { getMapsCapabilities } from '../kibana_services';
|
|||
|
||||
import {
|
||||
UPDATE_FLYOUT,
|
||||
CLOSE_SET_VIEW,
|
||||
OPEN_SET_VIEW,
|
||||
SET_IS_LAYER_TOC_OPEN,
|
||||
SET_FULL_SCREEN,
|
||||
SET_READ_ONLY,
|
||||
|
@ -33,7 +31,6 @@ export type MapUiState = {
|
|||
isFullScreen: boolean;
|
||||
isReadOnly: boolean;
|
||||
isLayerTOCOpen: boolean;
|
||||
isSetViewOpen: boolean;
|
||||
openTOCDetails: string[];
|
||||
};
|
||||
|
||||
|
@ -44,7 +41,6 @@ export const DEFAULT_MAP_UI_STATE = {
|
|||
isFullScreen: false,
|
||||
isReadOnly: !getMapsCapabilities().save,
|
||||
isLayerTOCOpen: DEFAULT_IS_LAYER_TOC_OPEN,
|
||||
isSetViewOpen: 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: [],
|
||||
|
@ -55,10 +51,6 @@ export function ui(state: MapUiState = DEFAULT_MAP_UI_STATE, action: any) {
|
|||
switch (action.type) {
|
||||
case UPDATE_FLYOUT:
|
||||
return { ...state, flyoutDisplay: action.display };
|
||||
case CLOSE_SET_VIEW:
|
||||
return { ...state, isSetViewOpen: false };
|
||||
case OPEN_SET_VIEW:
|
||||
return { ...state, isSetViewOpen: true };
|
||||
case SET_IS_LAYER_TOC_OPEN:
|
||||
return { ...state, isLayerTOCOpen: action.isLayerTOCOpen };
|
||||
case SET_FULL_SCREEN:
|
||||
|
|
|
@ -10,7 +10,6 @@ import { MapStoreState } from '../reducers/store';
|
|||
import { FLYOUT_STATE } from '../reducers/ui';
|
||||
|
||||
export const getFlyoutDisplay = ({ ui }: MapStoreState): FLYOUT_STATE => ui.flyoutDisplay;
|
||||
export const getIsSetViewOpen = ({ ui }: MapStoreState): boolean => ui.isSetViewOpen;
|
||||
export const getIsLayerTOCOpen = ({ ui }: MapStoreState): boolean => ui.isLayerTOCOpen;
|
||||
export const getOpenTOCDetails = ({ ui }: MapStoreState): string[] => ui.openTOCDetails;
|
||||
export const getIsFullScreen = ({ ui }: MapStoreState): boolean => ui.isFullScreen;
|
||||
|
|
Loading…
Reference in a new issue