mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[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:
parent
067a810a4a
commit
7118e750a0
31 changed files with 161 additions and 150 deletions
|
@ -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;
|
||||
|
||||
|
|
|
@ -132,6 +132,7 @@ export type SourceDescriptor =
|
|||
export type LayerDescriptor = {
|
||||
__dataRequests?: DataRequestDescriptor[];
|
||||
__isInErrorState?: boolean;
|
||||
__isPreviewLayer?: boolean;
|
||||
__errorMessage?: string;
|
||||
__trackedLayerDescriptor?: LayerDescriptor;
|
||||
alpha?: number;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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} />;
|
||||
},
|
||||
|
|
|
@ -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} />;
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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} />;
|
||||
|
|
|
@ -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} />;
|
||||
},
|
||||
|
|
|
@ -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} />;
|
||||
|
|
|
@ -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} />;
|
||||
},
|
||||
|
|
|
@ -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} />;
|
||||
|
|
|
@ -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} />;
|
||||
},
|
||||
|
|
|
@ -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} />;
|
||||
},
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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());
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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)),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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));
|
||||
},
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -21,6 +21,9 @@ const mockLayer = {
|
|||
getDisplayName: () => {
|
||||
return 'layer 1';
|
||||
},
|
||||
isPreviewLayer: () => {
|
||||
return false;
|
||||
},
|
||||
isVisible: () => {
|
||||
return true;
|
||||
},
|
||||
|
|
1
x-pack/plugins/maps/public/reducers/map.d.ts
vendored
1
x-pack/plugins/maps/public/reducers/map.d.ts
vendored
|
@ -66,7 +66,6 @@ export type MapState = {
|
|||
openTooltips: TooltipState[];
|
||||
mapState: MapContext;
|
||||
selectedLayerId: string | null;
|
||||
__transientLayerId: string | null;
|
||||
layerList: LayerDescriptor[];
|
||||
waitingForMapReadyLayerList: LayerDescriptor[];
|
||||
settings: MapSettings;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue