Skip to content

Commit

Permalink
[Maps] remove indexing state from redux (#69765) (#70106)
Browse files Browse the repository at this point in the history
* [Maps] remove indexing state from redux

* add indexing step

* tslint

* tslint fixes

* tslint item

* clear preview when file changes

* review feedback

* use prevState instead of this.state in setState

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
  • Loading branch information
nreese and elasticmachine authored Jun 26, 2020
1 parent a6de9a7 commit 69bc772
Show file tree
Hide file tree
Showing 15 changed files with 356 additions and 368 deletions.
10 changes: 1 addition & 9 deletions x-pack/plugins/maps/public/actions/ui_actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import { Dispatch } from 'redux';
import { MapStoreState } from '../reducers/store';
import { getFlyoutDisplay } from '../selectors/ui_selectors';
import { FLYOUT_STATE, INDEXING_STAGE } from '../reducers/ui';
import { FLYOUT_STATE } from '../reducers/ui';
import { trackMapSettings } from './map_actions';
import { setSelectedLayer } from './layer_actions';

Expand All @@ -20,7 +20,6 @@ export const SET_READ_ONLY = 'SET_READ_ONLY';
export const SET_OPEN_TOC_DETAILS = 'SET_OPEN_TOC_DETAILS';
export const SHOW_TOC_DETAILS = 'SHOW_TOC_DETAILS';
export const HIDE_TOC_DETAILS = 'HIDE_TOC_DETAILS';
export const UPDATE_INDEXING_STAGE = 'UPDATE_INDEXING_STAGE';

export function exitFullScreen() {
return {
Expand Down Expand Up @@ -95,10 +94,3 @@ export function hideTOCDetails(layerId: string) {
layerId,
};
}

export function updateIndexingStage(stage: INDEXING_STAGE | null) {
return {
type: UPDATE_INDEXING_STAGE,
stage,
};
}
20 changes: 12 additions & 8 deletions x-pack/plugins/maps/public/classes/layers/layer_wizard_registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,26 @@ import { LayerDescriptor } from '../../../common/descriptor_types';
import { LAYER_WIZARD_CATEGORY } from '../../../common/constants';

export type RenderWizardArguments = {
previewLayers: (layerDescriptors: LayerDescriptor[], isIndexingSource?: boolean) => void;
previewLayers: (layerDescriptors: LayerDescriptor[]) => void;
mapColors: string[];
// upload arguments
isIndexingTriggered: boolean;
onRemove: () => void;
onIndexReady: (indexReady: boolean) => void;
importSuccessHandler: (indexResponses: unknown) => void;
importErrorHandler: (indexResponses: unknown) => void;
// multi-step arguments for wizards that supply 'prerequisiteSteps'
currentStepId: string | null;
enableNextBtn: () => void;
disableNextBtn: () => void;
startStepLoading: () => void;
stopStepLoading: () => void;
// Typically, next step will be triggered via user clicking next button.
// However, this method is made available to trigger next step manually
// for async task completion that triggers the next step.
advanceToNextStep: () => void;
};

export type LayerWizard = {
categories: LAYER_WIZARD_CATEGORY[];
checkVisibility?: () => Promise<boolean>;
description: string;
icon: string;
isIndexingSource?: boolean;
prerequisiteSteps?: Array<{ id: string; label: string }>;
renderWizard(renderWizardArguments: RenderWizardArguments): ReactElement<any>;
title: string;
};
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
/*
* 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 React, { Component } from 'react';
import { IFieldType } from 'src/plugins/data/public';
import {
ES_GEO_FIELD_TYPE,
DEFAULT_MAX_RESULT_WINDOW,
SCALING_TYPES,
} from '../../../../common/constants';
import { getFileUploadComponent } from '../../../kibana_services';
// @ts-ignore
import { GeojsonFileSource } from './geojson_file_source';
import { VectorLayer } from '../../layers/vector_layer/vector_layer';
// @ts-ignore
import { createDefaultLayerDescriptor } from '../es_search_source';
import { RenderWizardArguments } from '../../layers/layer_wizard_registry';

export const INDEX_SETUP_STEP_ID = 'INDEX_SETUP_STEP_ID';
export const INDEXING_STEP_ID = 'INDEXING_STEP_ID';

enum INDEXING_STAGE {
READY = 'READY',
TRIGGERED = 'TRIGGERED',
SUCCESS = 'SUCCESS',
ERROR = 'ERROR',
}

interface State {
indexingStage: INDEXING_STAGE | null;
}

export class ClientFileCreateSourceEditor extends Component<RenderWizardArguments, State> {
private _isMounted: boolean = false;

state = {
indexingStage: null,
};

componentDidMount() {
this._isMounted = true;
}

componentWillUnmount() {
this._isMounted = false;
}

componentDidUpdate() {
if (
this.props.currentStepId === INDEXING_STEP_ID &&
this.state.indexingStage === INDEXING_STAGE.READY
) {
this.setState({ indexingStage: INDEXING_STAGE.TRIGGERED });
this.props.startStepLoading();
}
}

_onFileUpload = (geojsonFile: unknown, name: string) => {
if (!this._isMounted) {
return;
}

if (!geojsonFile) {
this.props.previewLayers([]);
return;
}

const sourceDescriptor = GeojsonFileSource.createDescriptor(geojsonFile, name);
const layerDescriptor = VectorLayer.createDescriptor(
{ sourceDescriptor },
this.props.mapColors
);
this.props.previewLayers([layerDescriptor]);
};

_onIndexingComplete = (indexResponses: { indexDataResp: unknown; indexPatternResp: unknown }) => {
if (!this._isMounted) {
return;
}

this.props.advanceToNextStep();

const { indexDataResp, indexPatternResp } = indexResponses;

// @ts-ignore
const indexCreationFailed = !(indexDataResp && indexDataResp.success);
// @ts-ignore
const allDocsFailed = indexDataResp.failures.length === indexDataResp.docCount;
// @ts-ignore
const indexPatternCreationFailed = !(indexPatternResp && indexPatternResp.success);
if (indexCreationFailed || allDocsFailed || indexPatternCreationFailed) {
this.setState({ indexingStage: INDEXING_STAGE.ERROR });
return;
}

// @ts-ignore
const { fields, id: indexPatternId } = indexPatternResp;
const geoField = fields.find((field: IFieldType) =>
[ES_GEO_FIELD_TYPE.GEO_POINT as string, ES_GEO_FIELD_TYPE.GEO_SHAPE as string].includes(
field.type
)
);
if (!indexPatternId || !geoField) {
this.setState({ indexingStage: INDEXING_STAGE.ERROR });
this.props.previewLayers([]);
} else {
const esSearchSourceConfig = {
indexPatternId,
geoField: geoField.name,
// Only turn on bounds filter for large doc counts
// @ts-ignore
filterByMapBounds: indexDataResp.docCount > DEFAULT_MAX_RESULT_WINDOW,
scalingType:
geoField.type === ES_GEO_FIELD_TYPE.GEO_POINT
? SCALING_TYPES.CLUSTERS
: SCALING_TYPES.LIMIT,
};
this.setState({ indexingStage: INDEXING_STAGE.SUCCESS });
this.props.previewLayers([
createDefaultLayerDescriptor(esSearchSourceConfig, this.props.mapColors),
]);
}
};

// Called on file upload screen when UI state changes
_onIndexReady = (indexReady: boolean) => {
if (!this._isMounted) {
return;
}
this.setState({ indexingStage: indexReady ? INDEXING_STAGE.READY : null });
if (indexReady) {
this.props.enableNextBtn();
} else {
this.props.disableNextBtn();
}
};

// Called on file upload screen when upload file is changed or removed
_onFileRemove = () => {
this.props.previewLayers([]);
};

render() {
const FileUpload = getFileUploadComponent();
return (
<FileUpload
appName={'Maps'}
isIndexingTriggered={this.state.indexingStage === INDEXING_STAGE.TRIGGERED}
onFileUpload={this._onFileUpload}
onFileRemove={this._onFileRemove}
onIndexReady={this._onIndexReady}
transformDetails={'geo'}
onIndexingComplete={this._onIndexingComplete}
/>
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,102 +6,37 @@

import { i18n } from '@kbn/i18n';
import React from 'react';
import { IFieldType } from 'src/plugins/data/public';
import {
ES_GEO_FIELD_TYPE,
DEFAULT_MAX_RESULT_WINDOW,
SCALING_TYPES,
} from '../../../../common/constants';
// @ts-ignore
import { createDefaultLayerDescriptor } from '../es_search_source';
import { LayerWizard, RenderWizardArguments } from '../../layers/layer_wizard_registry';
// @ts-ignore
import { ClientFileCreateSourceEditor } from './create_client_file_source_editor';
// @ts-ignore
import { GeojsonFileSource } from './geojson_file_source';
import { VectorLayer } from '../../layers/vector_layer/vector_layer';
import {
ClientFileCreateSourceEditor,
INDEX_SETUP_STEP_ID,
INDEXING_STEP_ID,
} from './create_client_file_source_editor';

export const uploadLayerWizardConfig: LayerWizard = {
categories: [],
description: i18n.translate('xpack.maps.source.geojsonFileDescription', {
description: i18n.translate('xpack.maps.fileUploadWizard.description', {
defaultMessage: 'Index GeoJSON data in Elasticsearch',
}),
icon: 'importAction',
isIndexingSource: true,
renderWizard: ({
previewLayers,
mapColors,
isIndexingTriggered,
onRemove,
onIndexReady,
importSuccessHandler,
importErrorHandler,
}: RenderWizardArguments) => {
function previewGeojsonFile(geojsonFile: unknown, name: string) {
if (!geojsonFile) {
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
previewLayers([layerDescriptor], true);
}

function viewIndexedData(indexResponses: {
indexDataResp: unknown;
indexPatternResp: unknown;
}) {
const { indexDataResp, indexPatternResp } = indexResponses;

// @ts-ignore
const indexCreationFailed = !(indexDataResp && indexDataResp.success);
// @ts-ignore
const allDocsFailed = indexDataResp.failures.length === indexDataResp.docCount;
// @ts-ignore
const indexPatternCreationFailed = !(indexPatternResp && indexPatternResp.success);

if (indexCreationFailed || allDocsFailed || indexPatternCreationFailed) {
importErrorHandler(indexResponses);
return;
}
// @ts-ignore
const { fields, id: indexPatternId } = indexPatternResp;
const geoField = fields.find((field: IFieldType) =>
[ES_GEO_FIELD_TYPE.GEO_POINT as string, ES_GEO_FIELD_TYPE.GEO_SHAPE as string].includes(
field.type
)
);
if (!indexPatternId || !geoField) {
previewLayers([]);
} else {
const esSearchSourceConfig = {
indexPatternId,
geoField: geoField.name,
// Only turn on bounds filter for large doc counts
// @ts-ignore
filterByMapBounds: indexDataResp.docCount > DEFAULT_MAX_RESULT_WINDOW,
scalingType:
geoField.type === ES_GEO_FIELD_TYPE.GEO_POINT
? SCALING_TYPES.CLUSTERS
: SCALING_TYPES.LIMIT,
};
previewLayers([createDefaultLayerDescriptor(esSearchSourceConfig, mapColors)]);
importSuccessHandler(indexResponses);
}
}

return (
<ClientFileCreateSourceEditor
previewGeojsonFile={previewGeojsonFile}
isIndexingTriggered={isIndexingTriggered}
onIndexingComplete={viewIndexedData}
onRemove={onRemove}
onIndexReady={onIndexReady}
/>
);
prerequisiteSteps: [
{
id: INDEX_SETUP_STEP_ID,
label: i18n.translate('xpack.maps.fileUploadWizard.importFileSetupLabel', {
defaultMessage: 'Import file',
}),
},
{
id: INDEXING_STEP_ID,
label: i18n.translate('xpack.maps.fileUploadWizard.indexingLabel', {
defaultMessage: 'Importing file',
}),
},
],
renderWizard: (renderWizardArguments: RenderWizardArguments) => {
return <ClientFileCreateSourceEditor {...renderWizardArguments} />;
},
title: i18n.translate('xpack.maps.source.geojsonFileTitle', {
title: i18n.translate('xpack.maps.fileUploadWizard.title', {
defaultMessage: 'Upload GeoJSON',
}),
};
Loading

0 comments on commit 69bc772

Please sign in to comment.