Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Maps] Add draw wizard #100278

Merged
merged 85 commits into from
May 26, 2021
Merged
Show file tree
Hide file tree
Changes from 84 commits
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
5f8aa18
Placeholder feature edit control in place
Mar 26, 2021
2cbd6b0
Merge remote-tracking branch 'upstream/master' into shape-drawing-ui
Mar 31, 2021
a80038a
Placeholder menu added
Mar 31, 2021
26ec7bf
Redux integrated
Apr 1, 2021
8ca809a
Single shape drawing
Apr 1, 2021
f9eeb95
Merge remote-tracking branch 'upstream/master' into shape-drawing-ui
Apr 1, 2021
b8eea96
Keep draw mode active
Apr 2, 2021
b4f3af0
Trigger editing through add layer wizard
Apr 5, 2021
001c87f
Add index checking utils
Apr 5, 2021
95f8f14
Connect error checking
Apr 5, 2021
2de30ec
Conditionally show edit toolbar
Apr 5, 2021
92e17aa
Connect missing shapes. Some clean up
Apr 5, 2021
143b24a
Track features and index name in store
Apr 5, 2021
e129539
Connect add layer button enablement
Apr 6, 2021
9c5ca16
Connect persistence utils
Apr 6, 2021
423e3aa
Dispatch clearing action
Apr 6, 2021
f238ccb
Full roundtrip w/ settings showing. Moved async calls to component
Apr 6, 2021
d450fd1
Adjust addLayer call for async
Apr 7, 2021
3d7ad76
Merge remote-tracking branch 'upstream/master' into shape-drawing-ui
Apr 7, 2021
b12ad85
Add edit controls
Apr 7, 2021
576b3d3
Fix deleting functionality to update store
Apr 7, 2021
cd211f9
Add toggle color to buttons. Fall back to edit between drawings
Apr 8, 2021
4f79738
Deselect features still selected when entering trash mode
Apr 8, 2021
ceae6d2
Add geometry check to filter out invalid geometries
Apr 8, 2021
bee0fd5
Clear out old drawing data on cancel. Update action names
Apr 8, 2021
3725859
Add circle drawing button
Apr 8, 2021
5200165
Add tools show on map with cancel. Not completely connected to add la…
Apr 12, 2021
2cb1832
Merge remote-tracking branch 'upstream/master' into shape-drawing-wizard
Apr 12, 2021
4ab4c54
Controls and feature handling almost entirely removed. Index creation…
Apr 12, 2021
32e4dcf
Remove more unused files related to draw toolbar
Apr 12, 2021
9579d44
Fix step handling
Apr 12, 2021
da58916
Remove toolbar logic
Apr 12, 2021
28ffc5f
Add same disabling logic used by file upload
Apr 12, 2021
2217bc1
Put wizard behind feature flag
Apr 13, 2021
fa6fd2e
More clean up
Apr 13, 2021
7d2d5a4
Merge remote-tracking branch 'upstream/master' into shape-drawing-wizard
Apr 13, 2021
634ede6
Remove unused source
Apr 13, 2021
a549a1e
Clean up, type fixes
Apr 13, 2021
5bcd3a9
Remove unused constant
Apr 13, 2021
5035bc5
Clean up unused feature actions. Misc. clean up
Apr 13, 2021
5e39efb
Fix i18n
Apr 14, 2021
7cd1482
eslint fix
Apr 14, 2021
958cc6a
Adding toolbar icons and draw layer icon
elizabetdev Apr 14, 2021
d3c064d
Merge branch 'shape-drawing-wizard' of https://github.com/aaronjcaldw…
elizabetdev Apr 14, 2021
9529b94
Merge remote-tracking branch 'upstream/master' into shape-drawing-wizard
Apr 14, 2021
177d5d2
TS conversions
Apr 15, 2021
65257a0
Review feedback. Lots of clean up
Apr 15, 2021
69e9393
Update card description
Apr 15, 2021
78c3721
Merge branch 'shape-drawing-wizard' of github.com:aaronjcaldwell/kiba…
Apr 15, 2021
9c817f7
Linting errors
Apr 15, 2021
431890a
Merge remote-tracking branch 'upstream/master' into shape-drawing-wizard
Apr 20, 2021
a5b1b1d
Review feedback. Update layer card title and description
Apr 20, 2021
087861a
Review feedback. Update wording on index name entry page
Apr 20, 2021
e2b19c2
Update x-pack/plugins/maps/public/classes/layers/new_vector_layer_wiz…
kindsun Apr 20, 2021
09017eb
Merge remote-tracking branch 'upstream/master' into shape-drawing-wizard
Apr 26, 2021
2dd166d
Integrate file upload index name component
Apr 27, 2021
bc75830
Revise index calls to use kibana https fetch. Remove http service
Apr 27, 2021
4162876
Merge remote-tracking branch 'upstream/master' into shape-drawing-wizard
Apr 28, 2021
b25bcae
Review feedback. Mostly clean up
Apr 29, 2021
73f2536
Merge remote-tracking branch 'upstream/master' into shape-drawing-wizard
Apr 30, 2021
58c84e8
Make index name validation callback props optional
May 3, 2021
bd783ad
Review feedback. Async checks, revised async component init, clean up
May 3, 2021
8799716
Merge remote-tracking branch 'upstream/master' into shape-drawing-wizard
May 3, 2021
7706cca
More clean up around async component init handling
May 3, 2021
f02a8d4
Review feedback. Handle async component load on file upload side
May 5, 2021
6107902
Update maps side to not use async in component load
May 5, 2021
4f09cd8
Merge remote-tracking branch 'upstream/master' into shape-drawing-wizard
May 5, 2021
065f745
Review feedback. Move button enable/disable out of callback
May 5, 2021
e4c1c92
Review feedback. Move wrapper components to api dir
May 5, 2021
0d8c253
Add semi-colon
May 5, 2021
6cb65ee
Merge branch 'shape-drawing-wizard' of https://github.com/aaronjcaldw…
thomasneirynck May 17, 2021
cf4ca63
Merge branch 'master' of github.com:elastic/kibana into maps/drawing_…
thomasneirynck May 17, 2021
ce73372
remove indirection
thomasneirynck May 18, 2021
ceefa04
use contentloading
thomasneirynck May 18, 2021
cc488a6
feedback
thomasneirynck May 18, 2021
5ab8b71
reduce indirection
thomasneirynck May 18, 2021
8c9e91f
feedback
thomasneirynck May 18, 2021
3a63176
simplify
thomasneirynck May 18, 2021
79953ec
language
thomasneirynck May 18, 2021
d561532
tighten ux
thomasneirynck May 18, 2021
004fb15
Merge branch 'master' of github.com:elastic/kibana into maps/drawing_…
thomasneirynck May 24, 2021
6f06429
init feedback
thomasneirynck May 24, 2021
9e18b51
use callout
thomasneirynck May 24, 2021
722e406
avoid loop
thomasneirynck May 24, 2021
9b75b47
simplify
thomasneirynck May 25, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 7 additions & 18 deletions x-pack/plugins/file_upload/public/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@
* 2.0.
*/

import React from 'react';
import { FileUploadComponentProps, lazyLoadModules } from '../lazy_load_bundle';
import { lazyLoadModules } from '../lazy_load_bundle';
import type { IImporter, ImportFactoryOptions } from '../importer';
import { IndexNameFormProps } from '../';
import type { HasImportPermission, FindFileStructureResponse } from '../../common';
import type { getMaxBytes, getMaxBytesFormatted } from '../importer/get_max_bytes';
import { JsonUploadAndParseAsyncWrapper } from './json_upload_and_parse_async_wrapper';
import { IndexNameFormAsyncWrapper } from './index_name_form_async_wrapper';

export interface FileUploadStartApi {
getFileUploadComponent(): ReturnType<typeof getFileUploadComponent>;
getIndexNameFormComponent(): Promise<React.ComponentType<IndexNameFormProps>>;
FileUploadComponent: typeof JsonUploadAndParseAsyncWrapper;
IndexNameFormComponent: typeof IndexNameFormAsyncWrapper;
importerFactory: typeof importerFactory;
getMaxBytes: typeof getMaxBytes;
getMaxBytesFormatted: typeof getMaxBytesFormatted;
Expand All @@ -30,19 +30,8 @@ export interface GetTimeFieldRangeResponse {
end: { epoch: number; string: string };
}

export async function getFileUploadComponent(): Promise<
React.ComponentType<FileUploadComponentProps>
> {
const fileUploadModules = await lazyLoadModules();
return fileUploadModules.JsonUploadAndParse;
}

export async function getIndexNameFormComponent(): Promise<
React.ComponentType<IndexNameFormProps>
> {
const fileUploadModules = await lazyLoadModules();
return fileUploadModules.IndexNameForm;
}
export const FileUploadComponent = JsonUploadAndParseAsyncWrapper;
export const IndexNameFormComponent = IndexNameFormAsyncWrapper;

export async function importerFactory(
format: string,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* 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 { EuiLoadingContent } from '@elastic/eui';
import { lazyLoadModules } from '../lazy_load_bundle';
import { IndexNameFormProps } from '../index';

interface State {
IndexNameForm: React.ComponentType<IndexNameFormProps> | null;
}

export class IndexNameFormAsyncWrapper extends React.Component<IndexNameFormProps, State> {
state: State = {
IndexNameForm: null,
};

private _isMounted = false;

componentWillUnmount(): void {
this._isMounted = false;
}

componentDidMount() {
this._isMounted = true;
lazyLoadModules().then((modules) => {
if (this._isMounted) {
this.setState({
IndexNameForm: modules.IndexNameForm,
});
}
});
}

render() {
const { IndexNameForm } = this.state;
return IndexNameForm ? <IndexNameForm {...this.props} /> : <EuiLoadingContent lines={3} />;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* 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 { EuiLoadingContent } from '@elastic/eui';
import { FileUploadComponentProps, lazyLoadModules } from '../lazy_load_bundle';

interface State {
JsonUploadAndParse: React.ComponentType<FileUploadComponentProps> | null;
}

export class JsonUploadAndParseAsyncWrapper extends React.Component<
FileUploadComponentProps,
State
> {
state: State = {
JsonUploadAndParse: null,
};
private _isMounted = false;

componentDidMount() {
this._isMounted = true;
lazyLoadModules().then((modules) => {
if (this._isMounted) {
this.setState({
JsonUploadAndParse: modules.JsonUploadAndParse,
});
}
});
}

thomasneirynck marked this conversation as resolved.
Show resolved Hide resolved
componentWillUnmount(): void {
this._isMounted = false;
}

render() {
const { JsonUploadAndParse } = this.state;
return JsonUploadAndParse ? (
<JsonUploadAndParse {...this.props} />
) : (
<EuiLoadingContent lines={3} />
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export interface FileUploadComponentProps {

let loadModulesPromise: Promise<LazyLoadedFileUploadModules>;

interface LazyLoadedFileUploadModules {
export interface LazyLoadedFileUploadModules {
JsonUploadAndParse: React.ComponentType<FileUploadComponentProps>;
IndexNameForm: React.ComponentType<IndexNameFormProps>;
importerFactory: (format: string, options: ImportFactoryOptions) => IImporter | undefined;
Expand Down
8 changes: 4 additions & 4 deletions x-pack/plugins/file_upload/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
import { CoreStart, Plugin } from '../../../../src/core/public';
import {
FileUploadStartApi,
getFileUploadComponent,
FileUploadComponent,
importerFactory,
hasImportPermission,
getIndexNameFormComponent,
IndexNameFormComponent,
checkIndexExists,
getTimeFieldRange,
analyzeFile,
Expand Down Expand Up @@ -42,8 +42,8 @@ export class FileUploadPlugin
public start(core: CoreStart, plugins: FileUploadStartDependencies): FileUploadStartApi {
setStartServices(core, plugins);
return {
getFileUploadComponent,
getIndexNameFormComponent,
FileUploadComponent,
IndexNameFormComponent,
importerFactory,
getMaxBytes,
getMaxBytesFormatted,
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/maps/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export const GIS_API_PATH = `api/${APP_ID}`;
export const INDEX_SETTINGS_API_PATH = `${GIS_API_PATH}/indexSettings`;
export const FONTS_API_PATH = `${GIS_API_PATH}/fonts`;
export const INDEX_SOURCE_API_PATH = `${GIS_API_PATH}/docSource`;
export const INDEX_FEATURE_PATH = `/${GIS_API_PATH}/feature`;
export const API_ROOT_PATH = `/${GIS_API_PATH}`;

export const MVT_GETTILE_API_PATH = 'mvt/getTile';
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/maps/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

export interface CreateDocSourceResp {
indexPatternId?: string;
success: boolean;
error?: Error;
}
Expand Down
1 change: 0 additions & 1 deletion x-pack/plugins/maps/public/actions/map_actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { AnyAction, Dispatch } from 'redux';
import { ThunkDispatch } from 'redux-thunk';
import turfBboxPolygon from '@turf/bbox-polygon';
import turfBooleanContains from '@turf/boolean-contains';

import { Filter, Query, TimeRange } from 'src/plugins/data/public';
import { MapStoreState } from '../reducers/store';
import {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ import React, { Component } from 'react';
import { FeatureCollection } from 'geojson';
import { EuiPanel } from '@elastic/eui';
import { DEFAULT_MAX_RESULT_WINDOW, SCALING_TYPES } from '../../../../common/constants';
import { getFileUpload } from '../../../kibana_services';
import { GeoJsonFileSource } from '../../sources/geojson_file_source';
import { VectorLayer } from '../../layers/vector_layer';
import { createDefaultLayerDescriptor } from '../../sources/es_search_source';
import { RenderWizardArguments } from '../../layers/layer_wizard_registry';
import { FileUploadComponentProps, FileUploadGeoResults } from '../../../../../file_upload/public';
import { FileUploadGeoResults } from '../../../../../file_upload/public';
import { ES_FIELD_TYPES } from '../../../../../../../src/plugins/data/public';
import { getFileUploadComponent } from '../../../kibana_services';

export enum UPLOAD_STEPS {
CONFIGURE_UPLOAD = 'CONFIGURE_UPLOAD',
Expand All @@ -34,7 +34,6 @@ enum INDEXING_STAGE {

interface State {
indexingStage: INDEXING_STAGE;
fileUploadComponent: React.ComponentType<FileUploadComponentProps> | null;
results?: FileUploadGeoResults;
}

Expand All @@ -43,12 +42,10 @@ export class ClientFileCreateSourceEditor extends Component<RenderWizardArgument

state: State = {
indexingStage: INDEXING_STAGE.CONFIGURE,
fileUploadComponent: null,
};

componentDidMount() {
this._isMounted = true;
this._loadFileUploadComponent();
}

componentWillUnmount() {
Expand Down Expand Up @@ -91,13 +88,6 @@ export class ClientFileCreateSourceEditor extends Component<RenderWizardArgument
this.props.advanceToNextStep();
});

async _loadFileUploadComponent() {
const fileUploadComponent = await getFileUpload().getFileUploadComponent();
if (this._isMounted) {
this.setState({ fileUploadComponent });
}
}

_onFileSelect = (geojsonFile: FeatureCollection, name: string, previewCoverage: number) => {
if (!this._isMounted) {
return;
Expand Down Expand Up @@ -157,11 +147,8 @@ export class ClientFileCreateSourceEditor extends Component<RenderWizardArgument
};

render() {
if (!this.state.fileUploadComponent) {
return null;
}
const FileUpload = getFileUploadComponent();

const FileUpload = this.state.fileUploadComponent;
return (
<EuiPanel>
<FileUpload
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* 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, { FunctionComponent } from 'react';

export const DrawLayerIcon: FunctionComponent = () => (
<svg
xmlns="http://www.w3.org/2000/svg"
width="49"
height="25"
fill="none"
viewBox="0 0 49 25"
className="mapLayersWizardIcon"
>
<path
className="mapLayersWizardIcon__background"
d="M12.281 3l-6.625 7.625 1.657 8.938 35.218-.813v-13l-10.625-3.5-9.781 9.5L12.281 3z"
/>
<path
className="mapLayersWizardIcon__highlight"
fillRule="evenodd"
d="M31.775 1.68l11.256 3.708v13.85l-36.133.834-1.777-9.593 7.114-8.189 9.875 8.778 9.665-9.388zm.262 1.14l-9.897 9.612-9.813-8.722-6.135 7.06 1.535 8.283 34.304-.792V6.111L32.037 2.82z"
clipRule="evenodd"
/>
<circle cx="7.281" cy="19.5" r="2.5" className="mapLayersWizardIcon__highlight" />
<circle cx="5.656" cy="10.25" r="2.5" className="mapLayersWizardIcon__highlight" />
<circle cx="12.156" cy="3.625" r="2.5" className="mapLayersWizardIcon__highlight" />
<circle cx="22" cy="11.6" r="2.5" className="mapLayersWizardIcon__highlight" />
<circle cx="31.969" cy="2.5" r="2.5" className="mapLayersWizardIcon__highlight" />
<circle cx="42.344" cy="6.125" r="2.5" className="mapLayersWizardIcon__highlight" />
<circle cx="42.344" cy="19" r="2.5" className="mapLayersWizardIcon__highlight" />
</svg>
);
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ import { mvtVectorSourceWizardConfig } from '../sources/mvt_single_layer_vector_
import { ObservabilityLayerWizardConfig } from './solution_layers/observability';
import { SecurityLayerWizardConfig } from './solution_layers/security';
import { choroplethLayerWizardConfig } from './choropleth_layer_wizard';
import { newVectorLayerWizardConfig } from './new_vector_layer_wizard';
import { getMapAppConfig } from '../../kibana_services';

let registered = false;
export function registerLayerWizards() {
Expand All @@ -39,6 +41,9 @@ export function registerLayerWizards() {

// Registration order determines display order
registerLayerWizard(uploadLayerWizardConfig);
if (getMapAppConfig().enableDrawingFeature) {
registerLayerWizard(newVectorLayerWizardConfig);
}
registerLayerWizard(esDocumentsLayerWizardConfig);
// @ts-ignore
registerLayerWizard(choroplethLayerWizardConfig);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* 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 { i18n } from '@kbn/i18n';
import React from 'react';
import { LayerWizard, RenderWizardArguments } from '../../layers/layer_wizard_registry';
import { NewVectorLayerEditor } from './wizard';
import { DrawLayerIcon } from '../../layers/icons/draw_layer_icon';
import { getFileUpload } from '../../../kibana_services';
import { LAYER_WIZARD_CATEGORY } from '../../../../common';

const ADD_VECTOR_DRAWING_LAYER = 'ADD_VECTOR_DRAWING_LAYER';

export const newVectorLayerWizardConfig: LayerWizard = {
categories: [LAYER_WIZARD_CATEGORY.ELASTICSEARCH],
description: i18n.translate('xpack.maps.newVectorLayerWizard.description', {
defaultMessage: 'Creates a new empty layer. Use this to add shapes to the map',
}),
disabledReason: i18n.translate('xpack.maps.newVectorLayerWizard.disabledDesc', {
defaultMessage:
'Unable to draw vector shapes, you are missing the Kibana privilege "Index Pattern Management".',
}),
getIsDisabled: async () => {
const hasImportPermission = await getFileUpload().hasImportPermission({
checkCreateIndexPattern: true,
checkHasManagePipeline: false,
});
return !hasImportPermission;
},
icon: DrawLayerIcon,
prerequisiteSteps: [
{
id: ADD_VECTOR_DRAWING_LAYER,
label: i18n.translate('xpack.maps.newVectorLayerWizard.indexNewLayer', {
defaultMessage: 'Index new layer',
}),
},
],
renderWizard: (renderWizardArguments: RenderWizardArguments) => {
return <NewVectorLayerEditor {...renderWizardArguments} />;
},
title: i18n.translate('xpack.maps.newVectorLayerWizard.title', {
defaultMessage: 'Create new layer',
}),
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* 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 { getHttp } from '../../../kibana_services';
import { CreateDocSourceResp, INDEX_SOURCE_API_PATH } from '../../../../common';

export const createNewIndexAndPattern = async (indexName: string) => {
return await getHttp().fetch<CreateDocSourceResp>({
path: `/${INDEX_SOURCE_API_PATH}`,
method: 'POST',
body: convertObjectToBlob({
thomasneirynck marked this conversation as resolved.
Show resolved Hide resolved
index: indexName,
// Initially set to static mappings
mappings: {
properties: {
coordinates: {
type: 'geo_shape',
},
},
},
}),
});
};

const convertObjectToBlob = (obj: unknown) => {
return new Blob([JSON.stringify(obj)], { type: 'application/json' });
};
Loading