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 shape drawing wizard- creates index only #96913

Closed
wants to merge 70 commits into from
Closed
Show file tree
Hide file tree
Changes from 44 commits
Commits
Show all changes
70 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
miukimiu Apr 14, 2021
d3c064d
Merge branch 'shape-drawing-wizard' of https://github.com/aaronjcaldw…
miukimiu 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
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
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
7 changes: 7 additions & 0 deletions x-pack/plugins/maps/public/actions/layer_actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
UPDATE_LAYER_PROP,
UPDATE_LAYER_STYLE,
UPDATE_SOURCE_PROP,
CLEAR_DRAWING_DATA,
} from './map_action_constants';
import { clearDataRequests, syncDataForLayerId, updateStyleMeta } from './data_request_actions';
import { cleanTooltipStateForLayer } from './tooltip_actions';
Expand Down Expand Up @@ -548,3 +549,9 @@ export function setAreTilesLoaded(layerId: string, areTilesLoaded: boolean) {
newValue: areTilesLoaded,
};
}

export function clearDrawingData() {
kindsun marked this conversation as resolved.
Show resolved Hide resolved
return {
type: CLEAR_DRAWING_DATA,
};
}
3 changes: 3 additions & 0 deletions x-pack/plugins/maps/public/actions/map_action_constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,13 @@ export const ROLLBACK_TO_TRACKED_LAYER_STATE = 'ROLLBACK_TO_TRACKED_LAYER_STATE'
export const REMOVE_TRACKED_LAYER_STATE = 'REMOVE_TRACKED_LAYER_STATE';
export const SET_OPEN_TOOLTIPS = 'SET_OPEN_TOOLTIPS';
export const UPDATE_DRAW_STATE = 'UPDATE_DRAW_STATE';
export const UPDATE_EDIT_MODE = 'UPDATE_EDIT_MODE';
export const SET_SCROLL_ZOOM = 'SET_SCROLL_ZOOM';
export const SET_MAP_INIT_ERROR = 'SET_MAP_INIT_ERROR';
export const SET_WAITING_FOR_READY_HIDDEN_LAYERS = 'SET_WAITING_FOR_READY_HIDDEN_LAYERS';
export const SET_MAP_SETTINGS = 'SET_MAP_SETTINGS';
export const ROLLBACK_MAP_SETTINGS = 'ROLLBACK_MAP_SETTINGS';
export const TRACK_MAP_SETTINGS = 'TRACK_MAP_SETTINGS';
export const UPDATE_MAP_SETTING = 'UPDATE_MAP_SETTING';
export const SET_VECTOR_LAYER_INDEX_NAME = 'SET_VECTOR_LAYER_INDEX_NAME';
kindsun marked this conversation as resolved.
Show resolved Hide resolved
export const CLEAR_DRAWING_DATA = 'CLEAR_DRAWING_DATA';
17 changes: 16 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 Expand Up @@ -43,7 +42,9 @@ import {
TRACK_MAP_SETTINGS,
TRIGGER_REFRESH_TIMER,
UPDATE_DRAW_STATE,
UPDATE_EDIT_MODE,
UPDATE_MAP_SETTING,
SET_VECTOR_LAYER_INDEX_NAME,
} from './map_action_constants';
import { autoFitToBounds, syncDataForAllLayers } from './data_request_actions';
import { addLayer, addLayerWithoutDataSync } from './layer_actions';
Expand Down Expand Up @@ -323,3 +324,17 @@ export function updateDrawState(drawState: DrawState | null) {
});
};
}

export function updateEditMode(isActive: boolean) {
return {
type: UPDATE_EDIT_MODE,
isActive,
};
}

export function setVectorLayerIndexName(indexName: string) {
return {
type: SET_VECTOR_LAYER_INDEX_NAME,
indexName,
};
}
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/config';
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,53 @@
/*
* 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 './index';
import { DrawLayerIcon } from '../../layers/icons/draw_layer_icon';
import { CREATE_DRAWN_FEATURES_INDEX_STEP_ID, ADD_DRAWN_FEATURES_TO_INDEX_STEP_ID } from './wizard';
import { getFileUpload } from '../../../kibana_services';

export const newVectorLayerWizardConfig: LayerWizard = {
categories: [],
kindsun marked this conversation as resolved.
Show resolved Hide resolved
description: i18n.translate('xpack.maps.newVectorLayerWizard.description', {
defaultMessage: 'Draw points & shapes and save in Elasticsearch',
kindsun marked this conversation as resolved.
Show resolved Hide resolved
}),
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: CREATE_DRAWN_FEATURES_INDEX_STEP_ID,
label: i18n.translate('xpack.maps.newVectorLayerWizard.indexFeatures', {
defaultMessage: 'Index features',
kindsun marked this conversation as resolved.
Show resolved Hide resolved
}),
},
{
kindsun marked this conversation as resolved.
Show resolved Hide resolved
id: ADD_DRAWN_FEATURES_TO_INDEX_STEP_ID,
label: i18n.translate('xpack.maps.newVectorLayerWizard.indexingFeatures', {
defaultMessage: 'Indexing features',
}),
},
],
renderWizard: (renderWizardArguments: RenderWizardArguments) => {
return <NewVectorLayerEditor {...renderWizardArguments} />;
},
title: i18n.translate('xpack.maps.newVectorLayerWizard.title', {
defaultMessage: 'Draw new vector layer',
kindsun marked this conversation as resolved.
Show resolved Hide resolved
}),
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* 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 { ThunkDispatch } from 'redux-thunk';
import { AnyAction } from 'redux';
import { connect } from 'react-redux';
import { MapStoreState } from '../../../reducers/store';
import { NewVectorLayerEditor } from './wizard';
import {
addLayer,
clearDrawingData,
setSelectedLayer,
setVectorLayerIndexName,
updateEditMode,
updateFlyout,
} from '../../../actions';
import { FLYOUT_STATE } from '../../../reducers/ui';
import { LayerDescriptor } from '../../../../common/descriptor_types';
import { getVectorLayerIndexName } from '../../../selectors/map_selectors';

function mapStateToProps(state: MapStoreState) {
kindsun marked this conversation as resolved.
Show resolved Hide resolved
return {
indexName: getVectorLayerIndexName(state),
};
}

function mapDispatchToProps(dispatch: ThunkDispatch<MapStoreState, void, AnyAction>) {
return {
setEditModeActive: () => dispatch(updateEditMode(true)),
setEditModeInActive: () => {
dispatch(updateEditMode(false));
dispatch(clearDrawingData());
kindsun marked this conversation as resolved.
Show resolved Hide resolved
},
setIndexName: (indexName: string) => dispatch(setVectorLayerIndexName(indexName)),
clearDrawingData: () => {
dispatch(clearDrawingData());
},
addNewLayer: async (layerDescriptor: LayerDescriptor) => {
await dispatch(addLayer(layerDescriptor));
await dispatch(setSelectedLayer(layerDescriptor.id));
dispatch(updateFlyout(FLYOUT_STATE.LAYER_PANEL));
},
};
}

const connected = connect(mapStateToProps, mapDispatchToProps)(NewVectorLayerEditor);
export { connected as NewVectorLayerEditor };
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
kindsun marked this conversation as resolved.
Show resolved Hide resolved
* 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 { getHttp } from '../../../../kibana_services';

export async function http(options) {
if (!(options && options.url)) {
throw i18n.translate('xpack.maps.layers.newVectorLayerWizard.httpService.noUrl', {
defaultMessage: 'No URL provided',
});
}
const url = options.url || '';
const headers = {
'Content-Type': 'application/json',
...options.headers,
};

const allHeaders = options.headers === undefined ? headers : { ...options.headers, ...headers };
const body = options.data === undefined ? null : JSON.stringify(options.data);

const payload = {
method: options.method || 'GET',
headers: allHeaders,
credentials: 'same-origin',
query: options.query,
};

if (body !== null) {
payload.body = body;
}
return await doFetch(url, payload);
}

async function doFetch(url, payload) {
try {
return await getHttp().fetch(url, payload);
} catch (err) {
return {
failures: [
i18n.translate('xpack.maps.layers.newVectorLayerWizard.httpService.fetchError', {
defaultMessage: 'Error performing fetch: {error}',
values: { error: err.message },
}),
],
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
kindsun marked this conversation as resolved.
Show resolved Hide resolved
* 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 { http as httpService } from './http_service';
import { getSavedObjectsClient } from '../../../../kibana_services';

export const getExistingIndexNames = async () => {
const indexes = await httpService({
url: `/api/index_management/indices`,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see other. for an example, see use of

export const GIS_API_PATH = `api/${APP_ID}`;
constant in other modules

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/api/index_management/indices is the only I didn't change over since it's a one-off reference to the index management api. All others referring to maps api endpoints have been changed over to use the correct constants

method: 'GET',
});
return indexes ? indexes.map(({ name }) => name) : [];
};

export const createNewIndexAndPattern = async (indexName) => {
return await httpService({
url: `/api/maps/docSource`,
method: 'POST',
data: {
index: indexName,
// Initially set to static mappings
mappings: {
properties: {
coordinates: {
type: 'geo_shape',
},
},
},
},
});
};

export const addFeatureToIndex = async (indexName, geometry) => {
return await httpService({
url: `/api/maps/feature`,
kindsun marked this conversation as resolved.
Show resolved Hide resolved
method: 'POST',
data: {
index: indexName,
data: {
coordinates: geometry,
},
},
});
};

export const getExistingIndexPatternNames = async () => {
const indexPatterns = await getSavedObjectsClient()
.find({
type: 'index-pattern',
fields: ['id', 'title', 'type', 'fields'],
perPage: 10000,
})
.then(({ savedObjects }) => savedObjects.map((savedObject) => savedObject.get('title')));
return indexPatterns ? indexPatterns.map(({ name }) => name) : [];
};

export function checkIndexPatternValid(name) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is mostly a copy-paste from file_upload plugin. I'd expose it from there on the file_upload-setup interface? file_upload is already a dependency of the maps-plugin.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed that there's plenty of overlap with File Upload here. We do need to think more about what's worth exposing from File Upload in the long run, but I didn't tackle that in this PR since we're still behind an experimental flag and mostly just leveraging small pieces and utility functions.

const byteLength = encodeURI(name).split(/%(?:u[0-9A-F]{2})?[0-9A-F]{2}|./).length - 1;
const reg = new RegExp('[\\\\/*?"<>|\\s,#]+');
const indexPatternInvalid =
byteLength > 255 || // name can't be greater than 255 bytes
name !== name.toLowerCase() || // name should be lowercase
name === '.' ||
name === '..' || // name can't be . or ..
name.match(/^[-_+]/) !== null || // name can't start with these chars
name.match(reg) !== null; // name can't contain these chars
return !indexPatternInvalid;
}
Loading