[Maps] allow adding multiple layers (#67544)

* [Maps] allow adding multiple layers

* update RenderWizardArguments arguments

* fix toc_entry jest test

* fix tslint error

* cleanup

* remove __transientLayerId from store signature

* rename setSelectedLayerToFirstPreviewLayer

* revert changes to es_search_source/create_source_editor.js
This commit is contained in:
Nathan Reese 2020-05-28 15:14:39 -06:00 committed by GitHub
parent 067a810a4a
commit 7118e750a0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 161 additions and 150 deletions

View file

@ -38,7 +38,6 @@ import {
setGotoWithCenter,
replaceLayerList,
setQuery,
clearTransientLayerStateAndCloseFlyout,
setMapSettings,
enableFullScreen,
updateFlyout,
@ -535,7 +534,6 @@ app.controller(
addHelpMenuToAppChrome();
async function doSave(saveOptions) {
await store.dispatch(clearTransientLayerStateAndCloseFlyout());
savedMap.syncWithStore(store.getState());
let id;

View file

@ -132,6 +132,7 @@ export type SourceDescriptor =
export type LayerDescriptor = {
__dataRequests?: DataRequestDescriptor[];
__isInErrorState?: boolean;
__isPreviewLayer?: boolean;
__errorMessage?: string;
__trackedLayerDescriptor?: LayerDescriptor;
alpha?: number;

View file

@ -9,10 +9,10 @@ import { Query } from 'src/plugins/data/public';
import { MapStoreState } from '../reducers/store';
import {
getLayerById,
getLayerList,
getLayerListRaw,
getSelectedLayerId,
getMapReady,
getTransientLayerId,
} from '../selectors/map_selectors';
import { FLYOUT_STATE } from '../reducers/ui';
import { cancelRequest } from '../reducers/non_serializable_instances';
@ -27,7 +27,6 @@ import {
SET_JOINS,
SET_LAYER_VISIBILITY,
SET_SELECTED_LAYER,
SET_TRANSIENT_LAYER,
SET_WAITING_FOR_READY_HIDDEN_LAYERS,
TRACK_CURRENT_LAYER_STATE,
UPDATE_LAYER_ORDER,
@ -139,6 +138,41 @@ export function addLayerWithoutDataSync(layerDescriptor: LayerDescriptor) {
};
}
export function addPreviewLayers(layerDescriptors: LayerDescriptor[]) {
return (dispatch: Dispatch) => {
dispatch<any>(removePreviewLayers());
layerDescriptors.forEach((layerDescriptor) => {
dispatch<any>(addLayer({ ...layerDescriptor, __isPreviewLayer: true }));
});
};
}
export function removePreviewLayers() {
return (dispatch: Dispatch, getState: () => MapStoreState) => {
getLayerList(getState()).forEach((layer) => {
if (layer.isPreviewLayer()) {
dispatch<any>(removeLayer(layer.getId()));
}
});
};
}
export function promotePreviewLayers() {
return (dispatch: Dispatch, getState: () => MapStoreState) => {
getLayerList(getState()).forEach((layer) => {
if (layer.isPreviewLayer()) {
dispatch({
type: UPDATE_LAYER_PROP,
id: layer.getId(),
propName: '__isPreviewLayer',
newValue: false,
});
}
});
};
}
export function setLayerVisibility(layerId: string, makeVisible: boolean) {
return async (dispatch: Dispatch, getState: () => MapStoreState) => {
// if the current-state is invisible, we also want to sync data
@ -193,31 +227,17 @@ export function setSelectedLayer(layerId: string | null) {
};
}
export function removeTransientLayer() {
export function setFirstPreviewLayerToSelectedLayer() {
return async (dispatch: Dispatch, getState: () => MapStoreState) => {
const transientLayerId = getTransientLayerId(getState());
if (transientLayerId) {
await dispatch<any>(removeLayerFromLayerList(transientLayerId));
await dispatch<any>(setTransientLayer(null));
const firstPreviewLayer = getLayerList(getState()).find((layer) => {
return layer.isPreviewLayer();
});
if (firstPreviewLayer) {
dispatch<any>(setSelectedLayer(firstPreviewLayer.getId()));
}
};
}
export function setTransientLayer(layerId: string | null) {
return {
type: SET_TRANSIENT_LAYER,
transientLayerId: layerId,
};
}
export function clearTransientLayerStateAndCloseFlyout() {
return async (dispatch: Dispatch) => {
await dispatch(updateFlyout(FLYOUT_STATE.NONE));
await dispatch<any>(setSelectedLayer(null));
await dispatch<any>(removeTransientLayer());
};
}
export function updateLayerOrder(newLayerOrder: number[]) {
return {
type: UPDATE_LAYER_ORDER,

View file

@ -5,7 +5,6 @@
*/
export const SET_SELECTED_LAYER = 'SET_SELECTED_LAYER';
export const SET_TRANSIENT_LAYER = 'SET_TRANSIENT_LAYER';
export const UPDATE_LAYER_ORDER = 'UPDATE_LAYER_ORDER';
export const ADD_LAYER = 'ADD_LAYER';
export const SET_LAYER_ERROR_STATUS = 'SET_LAYER_ERROR_STATUS';

View file

@ -80,6 +80,7 @@ export interface ILayer {
getInFlightRequestTokens(): symbol[];
getPrevRequestToken(dataId: string): symbol | undefined;
destroy: () => void;
isPreviewLayer: () => boolean;
}
export type Footnote = {
icon: ReactElement<any>;
@ -179,6 +180,10 @@ export class AbstractLayer implements ILayer {
return this.getSource().isJoinable();
}
isPreviewLayer(): boolean {
return !!this._descriptor.__isPreviewLayer;
}
supportsElasticsearchFilters(): boolean {
return this.getSource().isESSource();
}

View file

@ -9,7 +9,7 @@ import { ReactElement } from 'react';
import { LayerDescriptor } from '../../../common/descriptor_types';
export type RenderWizardArguments = {
previewLayer: (layerDescriptor: LayerDescriptor | null, isIndexingSource?: boolean) => void;
previewLayers: (layerDescriptors: LayerDescriptor[], isIndexingSource?: boolean) => void;
mapColors: string[];
// upload arguments
isIndexingTriggered: boolean;

View file

@ -53,13 +53,12 @@ export class ObservabilityLayerTemplate extends Component<RenderWizardArguments,
};
_previewLayer() {
this.props.previewLayer(
createLayerDescriptor({
layer: this.state.layer,
metric: this.state.metric,
display: this.state.display,
})
);
const layerDescriptor = createLayerDescriptor({
layer: this.state.layer,
metric: this.state.metric,
display: this.state.display,
});
this.props.previewLayers(layerDescriptor ? [layerDescriptor] : []);
}
render() {

View file

@ -28,7 +28,7 @@ export const uploadLayerWizardConfig: LayerWizard = {
icon: 'importAction',
isIndexingSource: true,
renderWizard: ({
previewLayer,
previewLayers,
mapColors,
isIndexingTriggered,
onRemove,
@ -38,13 +38,13 @@ export const uploadLayerWizardConfig: LayerWizard = {
}: RenderWizardArguments) => {
function previewGeojsonFile(geojsonFile: unknown, name: string) {
if (!geojsonFile) {
previewLayer(null);
previewLayers([]);
return;
}
const sourceDescriptor = GeojsonFileSource.createDescriptor(geojsonFile, name);
const layerDescriptor = VectorLayer.createDescriptor({ sourceDescriptor }, mapColors);
// TODO figure out a better way to handle passing this information back to layer_addpanel
previewLayer(layerDescriptor, true);
previewLayers([layerDescriptor], true);
}
function viewIndexedData(indexResponses: {
@ -72,7 +72,7 @@ export const uploadLayerWizardConfig: LayerWizard = {
)
);
if (!indexPatternId || !geoField) {
previewLayer(null);
previewLayers([]);
} else {
const esSearchSourceConfig = {
indexPatternId,
@ -85,7 +85,7 @@ export const uploadLayerWizardConfig: LayerWizard = {
? SCALING_TYPES.CLUSTERS
: SCALING_TYPES.LIMIT,
};
previewLayer(createDefaultLayerDescriptor(esSearchSourceConfig, mapColors));
previewLayers([createDefaultLayerDescriptor(esSearchSourceConfig, mapColors)]);
importSuccessHandler(indexResponses);
}
}

View file

@ -22,11 +22,11 @@ export const emsBoundariesLayerWizardConfig: LayerWizard = {
defaultMessage: 'Administrative boundaries from Elastic Maps Service',
}),
icon: 'emsApp',
renderWizard: ({ previewLayer, mapColors }: RenderWizardArguments) => {
renderWizard: ({ previewLayers, mapColors }: RenderWizardArguments) => {
const onSourceConfigChange = (sourceConfig: Partial<EMSFileSourceDescriptor>) => {
const sourceDescriptor = EMSFileSource.createDescriptor(sourceConfig);
const layerDescriptor = VectorLayer.createDescriptor({ sourceDescriptor }, mapColors);
previewLayer(layerDescriptor);
previewLayers([layerDescriptor]);
};
return <EMSFileCreateSourceEditor onSourceConfigChange={onSourceConfigChange} />;
},

View file

@ -22,12 +22,12 @@ export const emsBaseMapLayerWizardConfig: LayerWizard = {
defaultMessage: 'Tile map service from Elastic Maps Service',
}),
icon: 'emsApp',
renderWizard: ({ previewLayer }: RenderWizardArguments) => {
renderWizard: ({ previewLayers }: RenderWizardArguments) => {
const onSourceConfigChange = (sourceConfig: unknown) => {
const layerDescriptor = VectorTileLayer.createDescriptor({
sourceDescriptor: EMSTMSSource.createDescriptor(sourceConfig),
});
previewLayer(layerDescriptor);
previewLayers([layerDescriptor]);
};
return <TileServiceSelect onTileSelect={onSourceConfigChange} />;

View file

@ -34,10 +34,10 @@ export const clustersLayerWizardConfig: LayerWizard = {
defaultMessage: 'Geospatial data grouped in grids with metrics for each gridded cell',
}),
icon: 'logoElasticsearch',
renderWizard: ({ previewLayer }: RenderWizardArguments) => {
renderWizard: ({ previewLayers }: RenderWizardArguments) => {
const onSourceConfigChange = (sourceConfig: Partial<ESGeoGridSourceDescriptor>) => {
if (!sourceConfig) {
previewLayer(null);
previewLayers([]);
return;
}
@ -93,7 +93,7 @@ export const clustersLayerWizardConfig: LayerWizard = {
},
}),
});
previewLayer(layerDescriptor);
previewLayers([layerDescriptor]);
};
return (

View file

@ -21,17 +21,17 @@ export const heatmapLayerWizardConfig: LayerWizard = {
defaultMessage: 'Geospatial data grouped in grids to show density',
}),
icon: 'logoElasticsearch',
renderWizard: ({ previewLayer }: RenderWizardArguments) => {
renderWizard: ({ previewLayers }: RenderWizardArguments) => {
const onSourceConfigChange = (sourceConfig: Partial<ESGeoGridSourceDescriptor>) => {
if (!sourceConfig) {
previewLayer(null);
previewLayers([]);
return;
}
const layerDescriptor = HeatmapLayer.createDescriptor({
sourceDescriptor: ESGeoGridSource.createDescriptor(sourceConfig),
});
previewLayer(layerDescriptor);
previewLayers([layerDescriptor]);
};
return (

View file

@ -28,10 +28,10 @@ export const point2PointLayerWizardConfig: LayerWizard = {
defaultMessage: 'Aggregated data paths between the source and destination',
}),
icon: 'logoElasticsearch',
renderWizard: ({ previewLayer }: RenderWizardArguments) => {
renderWizard: ({ previewLayers }: RenderWizardArguments) => {
const onSourceConfigChange = (sourceConfig: unknown) => {
if (!sourceConfig) {
previewLayer(null);
previewLayers([]);
return;
}
@ -64,7 +64,7 @@ export const point2PointLayerWizardConfig: LayerWizard = {
},
}),
});
previewLayer(layerDescriptor);
previewLayers([layerDescriptor]);
};
return <CreateSourceEditor onSourceConfigChange={onSourceConfigChange} />;

View file

@ -28,14 +28,14 @@ export const esDocumentsLayerWizardConfig: LayerWizard = {
defaultMessage: 'Vector data from a Kibana index pattern',
}),
icon: 'logoElasticsearch',
renderWizard: ({ previewLayer, mapColors }: RenderWizardArguments) => {
renderWizard: ({ previewLayers, mapColors }: RenderWizardArguments) => {
const onSourceConfigChange = (sourceConfig: unknown) => {
if (!sourceConfig) {
previewLayer(null);
previewLayers([]);
return;
}
previewLayer(createDefaultLayerDescriptor(sourceConfig, mapColors));
previewLayers([createDefaultLayerDescriptor(sourceConfig, mapColors)]);
};
return <CreateSourceEditor onSourceConfigChange={onSourceConfigChange} />;
},

View file

@ -24,11 +24,11 @@ export const kibanaRegionMapLayerWizardConfig: LayerWizard = {
defaultMessage: 'Vector data from hosted GeoJSON configured in kibana.yml',
}),
icon: 'logoKibana',
renderWizard: ({ previewLayer, mapColors }: RenderWizardArguments) => {
renderWizard: ({ previewLayers, mapColors }: RenderWizardArguments) => {
const onSourceConfigChange = (sourceConfig: unknown) => {
const sourceDescriptor = KibanaRegionmapSource.createDescriptor(sourceConfig);
const layerDescriptor = VectorLayer.createDescriptor({ sourceDescriptor }, mapColors);
previewLayer(layerDescriptor);
previewLayers([layerDescriptor]);
};
return <CreateSourceEditor onSourceConfigChange={onSourceConfigChange} />;

View file

@ -24,12 +24,12 @@ export const kibanaBasemapLayerWizardConfig: LayerWizard = {
defaultMessage: 'Tile map service configured in kibana.yml',
}),
icon: 'logoKibana',
renderWizard: ({ previewLayer }: RenderWizardArguments) => {
renderWizard: ({ previewLayers }: RenderWizardArguments) => {
const onSourceConfigChange = () => {
const layerDescriptor = TileLayer.createDescriptor({
sourceDescriptor: KibanaTilemapSource.createDescriptor(),
});
previewLayer(layerDescriptor);
previewLayers([layerDescriptor]);
};
return <CreateSourceEditor onSourceConfigChange={onSourceConfigChange} />;
},

View file

@ -19,11 +19,11 @@ export const mvtVectorSourceWizardConfig: LayerWizard = {
defaultMessage: 'Vector source wizard',
}),
icon: 'grid',
renderWizard: ({ previewLayer, mapColors }: RenderWizardArguments) => {
renderWizard: ({ previewLayers, mapColors }: RenderWizardArguments) => {
const onSourceConfigChange = (sourceConfig: MVTSingleLayerVectorSourceConfig) => {
const sourceDescriptor = MVTSingleLayerVectorSource.createDescriptor(sourceConfig);
const layerDescriptor = TiledVectorLayer.createDescriptor({ sourceDescriptor }, mapColors);
previewLayer(layerDescriptor);
previewLayers([layerDescriptor]);
};
return <MVTSingleLayerVectorSourceEditor onSourceConfigChange={onSourceConfigChange} />;

View file

@ -18,17 +18,17 @@ export const wmsLayerWizardConfig: LayerWizard = {
defaultMessage: 'Maps from OGC Standard WMS',
}),
icon: 'grid',
renderWizard: ({ previewLayer }: RenderWizardArguments) => {
renderWizard: ({ previewLayers }: RenderWizardArguments) => {
const onSourceConfigChange = (sourceConfig: unknown) => {
if (!sourceConfig) {
previewLayer(null);
previewLayers([]);
return;
}
const layerDescriptor = TileLayer.createDescriptor({
sourceDescriptor: WMSSource.createDescriptor(sourceConfig),
});
previewLayer(layerDescriptor);
previewLayers([layerDescriptor]);
};
return <WMSCreateSourceEditor onSourceConfigChange={onSourceConfigChange} />;
},

View file

@ -16,12 +16,12 @@ export const tmsLayerWizardConfig: LayerWizard = {
defaultMessage: 'Tile map service configured in interface',
}),
icon: 'grid',
renderWizard: ({ previewLayer }: RenderWizardArguments) => {
renderWizard: ({ previewLayers }: RenderWizardArguments) => {
const onSourceConfigChange = (sourceConfig: XYZTMSSourceConfig) => {
const layerDescriptor = TileLayer.createDescriptor({
sourceDescriptor: XYZTMSSource.createDescriptor(sourceConfig),
});
previewLayer(layerDescriptor);
previewLayers([layerDescriptor]);
};
return <XYZTMSEditor onSourceConfigChange={onSourceConfigChange} />;
},

View file

@ -24,7 +24,7 @@ export const FlyoutBody = (props: Props) => {
}
const renderWizardArgs = {
previewLayer: props.previewLayer,
previewLayers: props.previewLayers,
mapColors: props.mapColors,
isIndexingTriggered: props.isIndexingTriggered,
onRemove: props.onRemove,

View file

@ -7,22 +7,24 @@
import { AnyAction, Dispatch } from 'redux';
import { connect } from 'react-redux';
import { FlyoutFooter } from './view';
import { getSelectedLayer } from '../../../selectors/map_selectors';
import { clearTransientLayerStateAndCloseFlyout } from '../../../actions';
import { hasPreviewLayers, isLoadingPreviewLayers } from '../../../selectors/map_selectors';
import { removePreviewLayers, updateFlyout } from '../../../actions';
import { MapStoreState } from '../../../reducers/store';
import { FLYOUT_STATE } from '../../../reducers/ui';
function mapStateToProps(state: MapStoreState) {
const selectedLayer = getSelectedLayer(state);
const hasLayerSelected = !!selectedLayer;
return {
hasLayerSelected,
isLoading: hasLayerSelected && selectedLayer!.isLayerLoading(),
hasPreviewLayers: hasPreviewLayers(state),
isLoading: isLoadingPreviewLayers(state),
};
}
function mapDispatchToProps(dispatch: Dispatch<AnyAction>) {
return {
closeFlyout: () => dispatch<any>(clearTransientLayerStateAndCloseFlyout()),
closeFlyout: () => {
dispatch(updateFlyout(FLYOUT_STATE.NONE));
dispatch<any>(removePreviewLayers());
},
};
}

View file

@ -20,7 +20,7 @@ interface Props {
disableNextButton: boolean;
nextButtonText: string;
closeFlyout: () => void;
hasLayerSelected: boolean;
hasPreviewLayers: boolean;
isLoading: boolean;
}
@ -30,14 +30,14 @@ export const FlyoutFooter = ({
disableNextButton,
nextButtonText,
closeFlyout,
hasLayerSelected,
hasPreviewLayers,
isLoading,
}: Props) => {
const nextButton = showNextButton ? (
<EuiButton
data-test-subj="importFileButton"
disabled={!hasLayerSelected || disableNextButton || isLoading}
isLoading={hasLayerSelected && isLoading}
disabled={disableNextButton || !hasPreviewLayers || isLoading}
isLoading={isLoading}
iconSide="right"
iconType={'sortRight'}
onClick={onClick}

View file

@ -10,10 +10,9 @@ import { AddLayerPanel } from './view';
import { FLYOUT_STATE, INDEXING_STAGE } from '../../reducers/ui';
import { getFlyoutDisplay, getIndexingStage } from '../../selectors/ui_selectors';
import {
setTransientLayer,
addLayer,
setSelectedLayer,
removeTransientLayer,
addPreviewLayers,
promotePreviewLayers,
setFirstPreviewLayerToSelectedLayer,
updateFlyout,
updateIndexingStage,
} from '../../actions';
@ -32,20 +31,13 @@ function mapStateToProps(state: MapStoreState) {
function mapDispatchToProps(dispatch: Dispatch<AnyAction>) {
return {
previewLayer: async (layerDescriptor: LayerDescriptor) => {
await dispatch<any>(setSelectedLayer(null));
await dispatch<any>(removeTransientLayer());
dispatch<any>(addLayer(layerDescriptor));
dispatch<any>(setSelectedLayer(layerDescriptor.id));
dispatch(setTransientLayer(layerDescriptor.id));
addPreviewLayers: (layerDescriptors: LayerDescriptor[]) => {
dispatch<any>(addPreviewLayers(layerDescriptors));
},
removeTransientLayer: () => {
dispatch<any>(setSelectedLayer(null));
dispatch<any>(removeTransientLayer());
},
selectLayerAndAdd: () => {
dispatch(setTransientLayer(null));
promotePreviewLayers: () => {
dispatch<any>(setFirstPreviewLayerToSelectedLayer());
dispatch(updateFlyout(FLYOUT_STATE.LAYER_PANEL));
dispatch<any>(promotePreviewLayers());
},
setIndexingTriggered: () => dispatch(updateIndexingStage(INDEXING_STAGE.TRIGGERED)),
resetIndexing: () => dispatch(updateIndexingStage(null)),

View file

@ -17,17 +17,15 @@ interface Props {
isIndexingReady: boolean;
isIndexingSuccess: boolean;
isIndexingTriggered: boolean;
previewLayer: (layerDescriptor: LayerDescriptor) => void;
removeTransientLayer: () => void;
addPreviewLayers: (layerDescriptors: LayerDescriptor[]) => void;
promotePreviewLayers: () => void;
resetIndexing: () => void;
selectLayerAndAdd: () => void;
setIndexingTriggered: () => void;
}
interface State {
importView: boolean;
isIndexingSource: boolean;
layerDescriptor: LayerDescriptor | null;
layerImportAddReady: boolean;
layerWizard: LayerWizard | null;
}
@ -37,7 +35,6 @@ export class AddLayerPanel extends Component<Props, State> {
state = {
layerWizard: null,
layerDescriptor: null, // TODO get this from redux store instead of storing locally
isIndexingSource: false,
importView: false,
layerImportAddReady: false,
@ -57,21 +54,13 @@ export class AddLayerPanel extends Component<Props, State> {
}
}
_previewLayer = (layerDescriptor: LayerDescriptor | null, isIndexingSource?: boolean) => {
_previewLayers = (layerDescriptors: LayerDescriptor[], isIndexingSource?: boolean) => {
if (!this._isMounted) {
return;
}
if (!layerDescriptor) {
this.setState({
layerDescriptor: null,
isIndexingSource: false,
});
this.props.removeTransientLayer();
return;
}
this.setState({ layerDescriptor, isIndexingSource: !!isIndexingSource });
this.props.previewLayer(layerDescriptor);
this.setState({ isIndexingSource: layerDescriptors.length ? !!isIndexingSource : false });
this.props.addPreviewLayers(layerDescriptors);
};
_clearLayerData = ({ keepSourceType = false }: { keepSourceType: boolean }) => {
@ -80,7 +69,6 @@ export class AddLayerPanel extends Component<Props, State> {
}
const newState: Partial<State> = {
layerDescriptor: null,
isIndexingSource: false,
};
if (!keepSourceType) {
@ -90,7 +78,7 @@ export class AddLayerPanel extends Component<Props, State> {
// @ts-ignore
this.setState(newState);
this.props.removeTransientLayer();
this.props.addPreviewLayers([]);
};
_onWizardSelect = (layerWizard: LayerWizard) => {
@ -101,7 +89,7 @@ export class AddLayerPanel extends Component<Props, State> {
if (this.state.isIndexingSource && !this.props.isIndexingTriggered) {
this.props.setIndexingTriggered();
} else {
this.props.selectLayerAndAdd();
this.props.promotePreviewLayers();
if (this.state.importView) {
this.setState({
layerImportAddReady: false,
@ -126,7 +114,7 @@ export class AddLayerPanel extends Component<Props, State> {
});
const isNextBtnEnabled = this.state.importView
? this.props.isIndexingReady || this.props.isIndexingSuccess
: !!this.state.layerDescriptor;
: true;
return (
<Fragment>
@ -141,7 +129,7 @@ export class AddLayerPanel extends Component<Props, State> {
onClear={() => this._clearLayerData({ keepSourceType: false })}
onRemove={() => this._clearLayerData({ keepSourceType: true })}
onWizardSelect={this._onWizardSelect}
previewLayer={this._previewLayer}
previewLayers={this._previewLayers}
/>
<FlyoutFooter

View file

@ -19,6 +19,7 @@ exports[`TOCEntry is rendered 1`] = `
"getId": [Function],
"hasErrors": [Function],
"hasLegendDetails": [Function],
"isPreviewLayer": [Function],
"isVisible": [Function],
"renderLegendDetails": [Function],
"showAtZoomLevel": [Function],
@ -81,6 +82,7 @@ exports[`TOCEntry props Should shade background when not selected layer 1`] = `
"getId": [Function],
"hasErrors": [Function],
"hasLegendDetails": [Function],
"isPreviewLayer": [Function],
"isVisible": [Function],
"renderLegendDetails": [Function],
"showAtZoomLevel": [Function],
@ -143,6 +145,7 @@ exports[`TOCEntry props Should shade background when selected layer 1`] = `
"getId": [Function],
"hasErrors": [Function],
"hasLegendDetails": [Function],
"isPreviewLayer": [Function],
"isVisible": [Function],
"renderLegendDetails": [Function],
"showAtZoomLevel": [Function],
@ -205,6 +208,7 @@ exports[`TOCEntry props isReadOnly 1`] = `
"getId": [Function],
"hasErrors": [Function],
"hasLegendDetails": [Function],
"isPreviewLayer": [Function],
"isVisible": [Function],
"renderLegendDetails": [Function],
"showAtZoomLevel": [Function],
@ -250,6 +254,7 @@ exports[`TOCEntry props should display layer details when isLegendDetailsOpen is
"getId": [Function],
"hasErrors": [Function],
"hasLegendDetails": [Function],
"isPreviewLayer": [Function],
"isVisible": [Function],
"renderLegendDetails": [Function],
"showAtZoomLevel": [Function],

View file

@ -19,7 +19,6 @@ import {
} from '../../../../../selectors/ui_selectors';
import {
setSelectedLayer,
removeTransientLayer,
updateFlyout,
hideTOCDetails,
showTOCDetails,
@ -41,7 +40,6 @@ function mapStateToProps(state = {}, ownProps) {
function mapDispatchToProps(dispatch) {
return {
openLayerPanel: async (layerId) => {
await dispatch(removeTransientLayer());
await dispatch(setSelectedLayer(layerId));
dispatch(updateFlyout(FLYOUT_STATE.LAYER_PANEL));
},

View file

@ -239,7 +239,8 @@ export class TOCEntry extends React.Component {
'mapTocEntry-isDragging': this.props.isDragging,
'mapTocEntry-isDraggingOver': this.props.isDraggingOver,
'mapTocEntry-isSelected':
this.props.selectedLayer && this.props.selectedLayer.getId() === this.props.layer.getId(),
this.props.layer.isPreviewLayer() ||
(this.props.selectedLayer && this.props.selectedLayer.getId() === this.props.layer.getId()),
});
return (

View file

@ -21,6 +21,9 @@ const mockLayer = {
getDisplayName: () => {
return 'layer 1';
},
isPreviewLayer: () => {
return false;
},
isVisible: () => {
return true;
},

View file

@ -66,7 +66,6 @@ export type MapState = {
openTooltips: TooltipState[];
mapState: MapContext;
selectedLayerId: string | null;
__transientLayerId: string | null;
layerList: LayerDescriptor[];
waitingForMapReadyLayerList: LayerDescriptor[];
settings: MapSettings;

View file

@ -6,7 +6,6 @@
import {
SET_SELECTED_LAYER,
SET_TRANSIENT_LAYER,
UPDATE_LAYER_ORDER,
LAYER_DATA_LOAD_STARTED,
LAYER_DATA_LOAD_ENDED,
@ -126,7 +125,6 @@ export const DEFAULT_MAP_STATE = {
hideViewControl: false,
},
selectedLayerId: null,
__transientLayerId: null,
layerList: [],
waitingForMapReadyLayerList: [],
settings: getDefaultMapSettings(),
@ -285,9 +283,6 @@ export function map(state = DEFAULT_MAP_STATE, action) {
case SET_SELECTED_LAYER:
const selectedMatch = state.layerList.find((layer) => layer.id === action.selectedLayerId);
return { ...state, selectedLayerId: selectedMatch ? action.selectedLayerId : null };
case SET_TRANSIENT_LAYER:
const transientMatch = state.layerList.find((layer) => layer.id === action.transientLayerId);
return { ...state, __transientLayerId: transientMatch ? action.transientLayerId : null };
case UPDATE_LAYER_ORDER:
return {
...state,

View file

@ -137,9 +137,6 @@ export const getSelectedLayerId = ({ map }: MapStoreState): string | null => {
return !map.selectedLayerId || !map.layerList ? null : map.selectedLayerId;
};
export const getTransientLayerId = ({ map }: MapStoreState): string | null =>
map.__transientLayerId;
export const getLayerListRaw = ({ map }: MapStoreState): LayerDescriptor[] =>
map.layerList ? map.layerList : [];
@ -331,15 +328,28 @@ export const getSelectedLayer = createSelector(
}
);
export const getMapColors = createSelector(
getTransientLayerId,
getLayerListRaw,
(transientLayerId, layerList) =>
layerList.reduce((accu: string[], layer: LayerDescriptor) => {
if (layer.id === transientLayerId) {
return accu;
}
const color: string | undefined = _.get(layer, 'style.properties.fillColor.options.color');
export const hasPreviewLayers = createSelector(getLayerList, (layerList) => {
return layerList.some((layer) => {
return layer.isPreviewLayer();
});
});
export const isLoadingPreviewLayers = createSelector(getLayerList, (layerList) => {
return layerList.some((layer) => {
return layer.isPreviewLayer() && layer.isLayerLoading();
});
});
export const getMapColors = createSelector(getLayerListRaw, (layerList) =>
layerList
.filter((layerDescriptor) => {
return !layerDescriptor.__isPreviewLayer;
})
.reduce((accu: string[], layerDescriptor: LayerDescriptor) => {
const color: string | undefined = _.get(
layerDescriptor,
'style.properties.fillColor.options.color'
);
if (color) accu.push(color);
return accu;
}, [])
@ -373,24 +383,20 @@ export const getQueryableUniqueIndexPatternIds = createSelector(getLayerList, (l
return _.uniq(indexPatternIds);
});
export const hasDirtyState = createSelector(
getLayerListRaw,
getTransientLayerId,
(layerListRaw, transientLayerId) => {
if (transientLayerId) {
export const hasDirtyState = createSelector(getLayerListRaw, (layerListRaw) => {
return layerListRaw.some((layerDescriptor) => {
if (layerDescriptor.__isPreviewLayer) {
return true;
}
return layerListRaw.some((layerDescriptor) => {
const trackedState = layerDescriptor[TRACKED_LAYER_DESCRIPTOR];
if (!trackedState) {
return false;
}
const currentState = copyPersistentState(layerDescriptor);
return !_.isEqual(currentState, trackedState);
});
}
);
const trackedState = layerDescriptor[TRACKED_LAYER_DESCRIPTOR];
if (!trackedState) {
return false;
}
const currentState = copyPersistentState(layerDescriptor);
return !_.isEqual(currentState, trackedState);
});
});
export const areLayersLoaded = createSelector(
getLayerList,