[Maps] replace singleton inspectorAdapters with per map inspector adapter instance (#31009)

* [Maps] replace singleton inspectorAdapters with per map inspector adapter instance

* pass inspectorAdapters to all source constructors in renderEditor

* rename non_serializable_kibana_instances to non_serializable_instances, fix test jest test broken by import
This commit is contained in:
Nathan Reese 2019-02-15 09:41:12 -07:00 committed by GitHub
parent 3727b5355a
commit 98fdd1a6f2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 120 additions and 118 deletions

View file

@ -27,9 +27,10 @@ import {
FLYOUT_STATE
} from '../store/ui';
import { getUniqueIndexPatternIds } from '../selectors/map_selectors';
import { getInspectorAdapters } from '../store/non_serializable_instances';
import { Inspector } from 'ui/inspector';
import { DocTitleProvider } from 'ui/doc_title';
import { inspectorAdapters, indexPatternService } from '../kibana_services';
import { indexPatternService } from '../kibana_services';
import { SavedObjectSaveModal } from 'ui/saved_objects/components/saved_object_save_modal';
import { showSaveModal } from 'ui/saved_objects/show_saved_object_save_modal';
import { toastNotifications } from 'ui/notify';
@ -49,7 +50,6 @@ app.controller('GisMapController', ($scope, $route, config, kbnUrl, localStorage
let unsubscribe;
const store = createMapStore();
inspectorAdapters.requests.reset();
$scope.$listen(globalState, 'fetch_with_changes', (diff) => {
if (diff.includes('time')) {
@ -252,6 +252,7 @@ app.controller('GisMapController', ($scope, $route, config, kbnUrl, localStorage
description: 'Open Inspector',
testId: 'openInspectorButton',
run() {
const inspectorAdapters = getInspectorAdapters(store.getState());
Inspector.open(inspectorAdapters, {});
}
}, {

View file

@ -8,6 +8,7 @@ import { connect } from 'react-redux';
import { AddLayerPanel } from './view';
import { getFlyoutDisplay, updateFlyout, FLYOUT_STATE } from '../../store/ui';
import { getTemporaryLayers, getMapColors } from '../../selectors/map_selectors';
import { getInspectorAdapters } from '../../store/non_serializable_instances';
import {
addLayer,
removeLayer,
@ -23,6 +24,7 @@ function mapStateToProps(state = {}) {
return tmp.some((layer) => layer.isLayerLoading());
}
return {
inspectorAdapters: getInspectorAdapters(state),
flyoutVisible: getFlyoutDisplay(state) !== FLYOUT_STATE.NONE,
layerLoading: isLoading(),
temporaryLayers: !_.isEmpty(getTemporaryLayers(state)),

View file

@ -23,12 +23,8 @@ import {
export class AddLayerPanel extends Component {
constructor() {
super();
this.state = {
sourceType: null,
};
state = {
sourceType: null,
}
_previewLayer = (source) => {
@ -107,7 +103,8 @@ export class AddLayerPanel extends Component {
_renderSourceEditor() {
const editorProperties = {
onPreviewSource: this._previewLayer
onPreviewSource: this._previewLayer,
inspectorAdapters: this.props.inspectorAdapters,
};
const Source = ALL_SOURCES.find((Source) => {

View file

@ -16,12 +16,14 @@ import {
setLayerErrorStatus,
} from '../../../actions/store_actions';
import { getLayerList, getMapReady, getGoto } from '../../../selectors/map_selectors';
import { getInspectorAdapters } from '../../../store/non_serializable_instances';
function mapStateToProps(state = {}) {
return {
isMapReady: getMapReady(state),
layerList: getLayerList(state),
goto: getGoto(state)
goto: getGoto(state),
inspectorAdapters: getInspectorAdapters(state),
};
}

View file

@ -8,7 +8,6 @@ import _ from 'lodash';
import React from 'react';
import { ResizeChecker } from 'ui/resize_checker';
import { syncLayerOrder, removeOrphanedSourcesAndLayers, createMbMapInstance } from './utils';
import { inspectorAdapters } from '../../../kibana_services';
import { DECIMAL_DEGREES_PRECISION, ZOOM_PRECISION } from '../../../../common/constants';
import mapboxgl from 'mapbox-gl';
@ -217,7 +216,7 @@ export class MBMapContainer extends React.Component {
};
_syncMbMapWithInspector = () => {
if (!this.props.isMapReady || !inspectorAdapters.map) {
if (!this.props.isMapReady || !this.props.inspectorAdapters.map) {
return;
}
@ -226,7 +225,7 @@ export class MBMapContainer extends React.Component {
zoom: this._mbMap.getZoom(),
};
inspectorAdapters.map.setMapState({
this.props.inspectorAdapters.map.setMapState({
stats,
style: this._mbMap.getStyle(),
});

View file

@ -15,11 +15,8 @@ import {
export class AttributionControl extends React.Component {
constructor() {
super();
this.state = {
uniqueAttributions: []
};
state = {
uniqueAttributions: []
}
componentDidMount() {

View file

@ -4,11 +4,8 @@
* you may not use this file except in compliance with the Elastic License.
*/
import chrome from 'ui/chrome';
import { uiModules } from 'ui/modules';
import { SearchSourceProvider } from 'ui/courier';
import { RequestAdapter } from 'ui/inspector/adapters';
import { MapAdapter } from './inspector/adapters/map_adapter';
import { timefilter } from 'ui/timefilter/timefilter';
import { getRequestInspectorStats, getResponseInspectorStats } from 'ui/courier/utils/courier_inspector_utils';
@ -17,14 +14,7 @@ export let indexPatternService;
export let SearchSource;
export let emsServiceSettings;
export const inspectorAdapters = {
requests: new RequestAdapter(),
};
if (chrome.getInjected('showMapsInspectorAdapter', false)) {
inspectorAdapters.map = new MapAdapter();
}
export async function fetchSearchSourceAndRecordWithInspector({ searchSource, requestId, requestName, requestDesc }) {
export async function fetchSearchSourceAndRecordWithInspector({ searchSource, requestId, requestName, requestDesc, inspectorAdapters }) {
const inspectorRequest = inspectorAdapters.requests.start(
requestName,
{ id: requestId, description: requestDesc });

View file

@ -14,11 +14,11 @@ import { VectorStyle } from '../shared/layers/styles/vector_style';
import { HeatmapStyle } from '../shared/layers/styles/heatmap_style';
import { TileStyle } from '../shared/layers/styles/tile_style';
import { timefilter } from 'ui/timefilter';
import { getInspectorAdapters } from '../store/non_serializable_instances';
import { copyPersistentState, TRACKED_LAYER_DESCRIPTOR } from '../store/util';
function createLayerInstance(layerDescriptor) {
const source = createSourceInstance(layerDescriptor.sourceDescriptor);
function createLayerInstance(layerDescriptor, inspectorAdapters) {
const source = createSourceInstance(layerDescriptor.sourceDescriptor, inspectorAdapters);
const style = createStyleInstance(layerDescriptor.style);
switch (layerDescriptor.type) {
case TileLayer.type:
@ -32,14 +32,14 @@ function createLayerInstance(layerDescriptor) {
}
}
function createSourceInstance(sourceDescriptor) {
function createSourceInstance(sourceDescriptor, inspectorAdapters) {
const Source = ALL_SOURCES.find(Source => {
return Source.type === sourceDescriptor.type;
});
if (!Source) {
throw new Error(`Unrecognized sourceType ${sourceDescriptor.type}`);
}
return new Source(sourceDescriptor);
return new Source(sourceDescriptor, inspectorAdapters);
}
@ -131,9 +131,10 @@ export const getDataFilters = createSelector(
export const getLayerList = createSelector(
getLayerListRaw,
(layerDescriptorList) => {
getInspectorAdapters,
(layerDescriptorList, inspectorAdapters) => {
return layerDescriptorList.map(layerDescriptor =>
createLayerInstance(layerDescriptor));
createLayerInstance(layerDescriptor, inspectorAdapters));
});
export const getSelectedLayer = createSelector(

View file

@ -6,6 +6,11 @@
jest.mock('../shared/layers/vector_layer', () => {});
jest.mock('../shared/layers/sources/all_sources', () => {});
jest.mock('../store/non_serializable_instances', () => ({
getInspectorAdapters: () => {
return {};
}
}));
jest.mock('ui/timefilter', () => ({
timefilter: {
getTime: () => {

View file

@ -29,20 +29,16 @@ export const EMPTY_FILTER = '';
export class MapListing extends React.Component {
constructor(props) {
super(props);
this.state = {
hasInitialFetchReturned: false,
isFetchingItems: false,
showDeleteModal: false,
showLimitError: false,
filter: EMPTY_FILTER,
items: [],
selectedIds: [],
page: 0,
perPage: 20,
};
state = {
hasInitialFetchReturned: false,
isFetchingItems: false,
showDeleteModal: false,
showLimitError: false,
filter: EMPTY_FILTER,
items: [],
selectedIds: [],
page: 0,
perPage: 20,
}
componentWillMount() {

View file

@ -14,9 +14,9 @@ export class LeftInnerJoin {
return JSON.stringify(descriptor);
}
constructor(joinDescriptor) {
constructor(joinDescriptor, inspectorAdapters) {
this._descriptor = joinDescriptor;
this._rightSource = new ESJoinSource(joinDescriptor.right);
this._rightSource = new ESJoinSource(joinDescriptor.right, inspectorAdapters);
}
destroy() {

View file

@ -25,19 +25,15 @@ export class EMSFileSource extends AbstractVectorSource {
};
}
static renderEditor({ onPreviewSource }) {
static renderEditor({ onPreviewSource, inspectorAdapters }) {
const onChange = (selectedId) => {
const emsFileSourceDescriptor = EMSFileSource.createDescriptor(selectedId);
const emsFileSource = new EMSFileSource(emsFileSourceDescriptor);
const emsFileSource = new EMSFileSource(emsFileSourceDescriptor, inspectorAdapters);
onPreviewSource(emsFileSource);
};
return <EMSFileCreateSourceEditor onChange={onChange}/>;
}
constructor(descriptor) {
super(descriptor);
}
async _getEmsVectorFileMeta() {
const emsFiles = await getEmsVectorFilesMeta();
const meta = emsFiles.find((source => source.id === this._descriptor.id));

View file

@ -25,22 +25,18 @@ export class EMSTMSSource extends AbstractTMSSource {
};
}
static renderEditor({ onPreviewSource }) {
static renderEditor({ onPreviewSource, inspectorAdapters }) {
const onChange = ({ target }) => {
const selectedId = target.options[target.selectedIndex].value;
const emsTMSSourceDescriptor = EMSTMSSource.createDescriptor(selectedId);
const emsTMSSource = new EMSTMSSource(emsTMSSourceDescriptor);
const emsTMSSource = new EMSTMSSource(emsTMSSourceDescriptor, inspectorAdapters);
onPreviewSource(emsTMSSource);
};
return <EMSTMSCreateSourceEditor onChange={onChange}/>;
}
constructor(descriptor) {
super(descriptor);
}
async getImmutableProperties() {
return [
{ label: 'Data source', value: EMSTMSSource.title },

View file

@ -64,10 +64,10 @@ export class ESGeoGridSource extends AbstractESSource {
};
}
static renderEditor({ onPreviewSource }) {
static renderEditor({ onPreviewSource, inspectorAdapters }) {
const onSelect = (sourceConfig) => {
const sourceDescriptor = ESGeoGridSource.createDescriptor(sourceConfig);
const source = new ESGeoGridSource(sourceDescriptor);
const source = new ESGeoGridSource(sourceDescriptor, inspectorAdapters);
onPreviewSource(source);
};

View file

@ -10,7 +10,6 @@ import { AbstractESSource } from './es_source';
import { Schemas } from 'ui/vis/editors/default/schemas';
import {
fetchSearchSourceAndRecordWithInspector,
inspectorAdapters,
SearchSource,
} from '../../../kibana_services';
import { AggConfigs } from 'ui/vis/agg_configs';
@ -74,10 +73,6 @@ export class ESJoinSource extends AbstractESSource {
return false;
}
destroy() {
inspectorAdapters.requests.resetRequest(this._descriptor.id);
}
getIndexPatternIds() {
return [this._descriptor.indexPatternId];
}
@ -111,6 +106,7 @@ export class ESJoinSource extends AbstractESSource {
const dsl = aggConfigs.toDsl();
searchSource.setField('aggs', dsl);
resp = await fetchSearchSourceAndRecordWithInspector({
inspectorAdapters: this._inspectorAdapters,
searchSource,
requestName: `${this._descriptor.indexPatternTitle}.${this._descriptor.term}`,
requestId: this._descriptor.id,

View file

@ -21,18 +21,18 @@ export class ESSearchSource extends AbstractESSource {
static title = 'Documents';
static description = 'Geospatial data from a Kibana index pattern';
static renderEditor({ onPreviewSource }) {
static renderEditor({ onPreviewSource, inspectorAdapters }) {
const onSelect = (layerConfig) => {
const layerSource = new ESSearchSource({
id: uuid(),
...layerConfig
});
}, inspectorAdapters);
onPreviewSource(layerSource);
};
return (<CreateSourceEditor onSelect={onSelect}/>);
}
constructor(descriptor) {
constructor(descriptor, inspectorAdapters) {
super({
id: descriptor.id,
type: ESSearchSource.type,
@ -41,7 +41,7 @@ export class ESSearchSource extends AbstractESSource {
limit: _.get(descriptor, 'limit', DEFAULT_LIMIT),
filterByMapBounds: _.get(descriptor, 'filterByMapBounds', true),
tooltipProperties: _.get(descriptor, 'tooltipProperties', []),
});
}, inspectorAdapters);
}
renderSourceSettingsEditor({ onChange }) {

View file

@ -8,7 +8,7 @@ import { AbstractVectorSource } from './vector_source';
import {
fetchSearchSourceAndRecordWithInspector,
indexPatternService,
inspectorAdapters, SearchSource
SearchSource
} from '../../../kibana_services';
import { createExtentFilter } from '../../../elasticsearch_geo_utils';
import { timefilter } from 'ui/timefilter/timefilter';
@ -20,10 +20,6 @@ export class AbstractESSource extends AbstractVectorSource {
static icon = 'logoElasticsearch';
constructor(descriptor) {
super(descriptor);
}
isFieldAware() {
return true;
}
@ -41,12 +37,13 @@ export class AbstractESSource extends AbstractVectorSource {
}
destroy() {
inspectorAdapters.requests.resetRequest(this._descriptor.id);
this._inspectorAdapters.requests.resetRequest(this._descriptor.id);
}
async _runEsQuery(layerName, searchSource, requestDescription) {
try {
return await fetchSearchSourceAndRecordWithInspector({
inspectorAdapters: this._inspectorAdapters,
searchSource,
requestName: layerName,
requestId: this._descriptor.id,

View file

@ -17,10 +17,6 @@ export class KibanaRegionmapSource extends AbstractVectorSource {
static description = 'Vector shapes from static files configured in kibana.yml';
static icon = 'logoKibana';
constructor(descriptor) {
super(descriptor);
}
static createDescriptor(options) {
return {
type: KibanaRegionmapSource.type,
@ -28,10 +24,10 @@ export class KibanaRegionmapSource extends AbstractVectorSource {
};
}
static renderEditor = ({ onPreviewSource }) => {
static renderEditor = ({ onPreviewSource, inspectorAdapters }) => {
const onSelect = (layerConfig) => {
const sourceDescriptor = KibanaRegionmapSource.createDescriptor(layerConfig);
const source = new KibanaRegionmapSource(sourceDescriptor);
const source = new KibanaRegionmapSource(sourceDescriptor, inspectorAdapters);
onPreviewSource(source);
};

View file

@ -22,10 +22,10 @@ export class KibanaTilemapSource extends AbstractTMSSource {
};
}
static renderEditor = ({ onPreviewSource }) => {
static renderEditor = ({ onPreviewSource, inspectorAdapters }) => {
const previewTilemap = () => {
const sourceDescriptor = KibanaTilemapSource.createDescriptor();
const source = new KibanaTilemapSource(sourceDescriptor);
const source = new KibanaTilemapSource(sourceDescriptor, inspectorAdapters);
onPreviewSource(source);
};
return (<CreateSourceEditor previewTilemap={previewTilemap}/>);

View file

@ -18,8 +18,9 @@ export class AbstractSource {
throw new Error('Must implement Source.renderDropdownDisplayOption');
}
constructor(descriptor) {
constructor(descriptor, inspectorAdapters) {
this._descriptor = descriptor;
this._inspectorAdapters = inspectorAdapters;
}
destroy() {}
@ -32,6 +33,10 @@ export class AbstractSource {
return [];
}
getInspectorAdapters() {
return this._inspectorAdapters;
}
_createDefaultLayerDescriptor() {
throw new Error(`Source#createDefaultLayerDescriptor not implemented`);
}

View file

@ -30,10 +30,10 @@ export class WMSSource extends AbstractTMSSource {
};
}
static renderEditor({ onPreviewSource }) {
static renderEditor({ onPreviewSource, inspectorAdapters }) {
const previewWMS = (options) => {
const sourceDescriptor = WMSSource.createDescriptor(options);
const source = new WMSSource(sourceDescriptor);
const source = new WMSSource(sourceDescriptor, inspectorAdapters);
onPreviewSource(source);
};
return (<WMSEditor previewWMS={previewWMS} />);
@ -77,16 +77,12 @@ export class WMSSource extends AbstractTMSSource {
class WMSEditor extends React.Component {
constructor() {
super();
this.state = {
serviceUrl: '',
layers: '',
styles: ''
};
state = {
serviceUrl: '',
layers: '',
styles: ''
}
_previewIfPossible() {
if (this.state.serviceUrl && this.state.layers) {
//todo: should really debounce this so we don't get a ton of changes during typing

View file

@ -28,10 +28,10 @@ export class XYZTMSSource extends AbstractTMSSource {
};
}
static renderEditor({ onPreviewSource }) {
static renderEditor({ onPreviewSource, inspectorAdapters }) {
const previewTMS = (urlTemplate) => {
const sourceDescriptor = XYZTMSSource.createDescriptor(urlTemplate);
const source = new XYZTMSSource(sourceDescriptor);
const source = new XYZTMSSource(sourceDescriptor, inspectorAdapters);
onPreviewSource(source);
};
return (<XYZTMSEditor previewTMS={previewTMS} />);
@ -70,12 +70,9 @@ export class XYZTMSSource extends AbstractTMSSource {
class XYZTMSEditor extends React.Component {
constructor() {
super();
this.state = {
tmsInput: '',
tmsCanPreview: false
};
state = {
tmsInput: '',
tmsCanPreview: false
}
_handleTMSInputChange(e) {

View file

@ -14,14 +14,10 @@ import { getDefaultDynamicProperties, getDefaultStaticProperties } from '../../v
import { EuiSpacer } from '@elastic/eui';
export class VectorStyleEditor extends Component {
constructor(props) {
super(props);
this.state = {
ordinalFields: [],
defaultDynamicProperties: getDefaultDynamicProperties(),
defaultStaticProperties: getDefaultStaticProperties()
};
state = {
ordinalFields: [],
defaultDynamicProperties: getDefaultDynamicProperties(),
defaultStaticProperties: getDefaultStaticProperties()
}
componentWillUnmount() {

View file

@ -49,7 +49,7 @@ export class VectorLayer extends AbstractLayer {
this._joins = [];
if (options.layerDescriptor.joins) {
options.layerDescriptor.joins.forEach((joinDescriptor) => {
this._joins.push(new LeftInnerJoin(joinDescriptor));
this._joins.push(new LeftInnerJoin(joinDescriptor, this._source.getInspectorAdapters()));
});
}
}

View file

@ -0,0 +1,35 @@
/*
* 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 _ from 'lodash';
import chrome from 'ui/chrome';
import { RequestAdapter } from 'ui/inspector/adapters';
import { MapAdapter } from '../inspector/adapters/map_adapter';
function createInspectorAdapters() {
const inspectorAdapters = {
requests: new RequestAdapter(),
};
if (chrome.getInjected('showMapsInspectorAdapter', false)) {
inspectorAdapters.map = new MapAdapter();
}
return inspectorAdapters;
}
const INITIAL_STATE = {
inspectorAdapters: createInspectorAdapters(),
};
// Reducer
export function nonSerializableInstances(state = INITIAL_STATE) {
// state is read only and provides access to non-serializeable object instances
return state;
}
// Selectors
export const getInspectorAdapters = ({ nonSerializableInstances }) => {
return _.get(nonSerializableInstances, 'inspectorAdapters', {});
};

View file

@ -8,10 +8,12 @@ import { combineReducers, applyMiddleware, createStore, compose } from 'redux';
import thunk from 'redux-thunk';
import { ui } from './ui';
import { map } from './map';
import { nonSerializableInstances } from './non_serializable_instances';
const rootReducer = combineReducers({
map,
ui
ui,
nonSerializableInstances
});
const enhancers = [ applyMiddleware(thunk) ];