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] Autocomplete for custom color palettes and custom icon palettes #56446

Merged
merged 17 commits into from
Feb 12, 2020
Merged
Changes from 1 commit
Commits
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
Next Next commit
[Maps] type ahead for stop values for custom color maps and custom ic…
…on maps
  • Loading branch information
nreese committed Jan 29, 2020
commit 212b9b7b5a3f085424fc8b9863efcd722a840dac
2 changes: 2 additions & 0 deletions x-pack/legacy/plugins/maps/public/kibana_services.js
Original file line number Diff line number Diff line change
@@ -14,6 +14,8 @@ import { npStart } from 'ui/new_platform';
export const SPATIAL_FILTER_TYPE = esFilters.FILTERS.SPATIAL_FILTER;
export { SearchSource } from '../../../../../src/plugins/data/public';
export const indexPatternService = npStart.plugins.data.indexPatterns;
console.log(npStart.plugins.data);
export const autocompleteService = npStart.plugins.data.autocomplete;

let licenseId;
export const setLicenseId = latestLicenseId => (licenseId = latestLicenseId);
22 changes: 22 additions & 0 deletions x-pack/legacy/plugins/maps/public/layers/sources/es_source.js
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@

import { AbstractVectorSource } from './vector_source';
import {
autocompleteService,
fetchSearchSourceAndRecordWithInspector,
indexPatternService,
SearchSource,
@@ -344,4 +345,25 @@ export class AbstractESSource extends AbstractVectorSource {

return resp.aggregations;
}

getValueSuggestions = async (fieldName, query) => {
thomasneirynck marked this conversation as resolved.
Show resolved Hide resolved
if (!fieldName) {
return [];
}

try {
const indexPattern = await this.getIndexPattern();
const field = indexPattern.fields.getByName(fieldName);
return await autocompleteService.getValueSuggestions({
indexPattern,
field,
query,
});
} catch (error) {
console.warn(
`Unable to fetch suggestions for field: ${fieldName}, query: ${query}, error: ${error.message}`
);
return [];
}
};
}
4 changes: 4 additions & 0 deletions x-pack/legacy/plugins/maps/public/layers/sources/source.js
Original file line number Diff line number Diff line change
@@ -139,4 +139,8 @@ export class AbstractSource {
async loadStylePropsMeta() {
throw new Error(`Source#loadStylePropsMeta not implemented`);
}

async getValueSuggestions(/* fieldName, query */) {
return [];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* 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 React, { Component } from 'react';

import { EuiFieldText } from '@elastic/eui';

export class StopInput extends Component {
state = {
localValue: '',
suggestions: [],
isLoadingSuggestions: false,
};

static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.value === prevState.prevValue) {
return null;
}

return {
prevValue: nextProps.value,
localValue: nextProps.value,
suggestions: [],
isLoadingSuggestions: false,
};
}

componentDidMount() {
this._isMounted = true;
}

componentWillUnmount() {
this._isMounted = false;
}

_onChange = e => {
this.setState({ localValue: e.target.value }, this._debouncedOnChange);
};

_debouncedOnChange = _.debounce(() => {
this._loadSuggestions();
this.props.onChange(this.state.localValue);
}, 300);

async _loadSuggestions() {
this.setState({ isLoadingSuggestions: true });

let suggestions = [];
try {
suggestions = await this.props.getValueSuggestions(this.state.localValue);
} catch (error) {
// ignore suggestions error
}

if (this._isMounted) {
console.log(suggestions);
this.setState({ isLoadingSuggestions: false, suggestions });
}
}

render() {
const {
onChange, // eslint-disable-line no-unused-vars
getValueSuggestions, // eslint-disable-line no-unused-vars
value, // eslint-disable-line no-unused-vars
...rest
} = this.props;

thomasneirynck marked this conversation as resolved.
Show resolved Hide resolved
return <EuiFieldText {...rest} onChange={this._onChange} value={this.state.localValue} />;
}
}
Original file line number Diff line number Diff line change
@@ -43,6 +43,7 @@ export function DynamicIconForm({
return (
<IconMapSelect
{...styleOptions}
getValueSuggestions={styleProperty.getValueSuggestions}
onChange={onIconMapChange}
isDarkMode={isDarkMode}
symbolOptions={symbolOptions}
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@ import { IconStops } from './icon_stops';

export function IconMapSelect({
customIconStops,
getValueSuggestions,
iconPaletteId,
isDarkMode,
onChange,
@@ -30,6 +31,7 @@ export function IconMapSelect({
function renderCustomIconStopsInput(onCustomMapChange) {
return (
<IconStops
getValueSuggestions={getValueSuggestions}
iconStops={customIconStops}
isDarkMode={isDarkMode}
onChange={onCustomMapChange}
Original file line number Diff line number Diff line change
@@ -8,8 +8,9 @@ import React from 'react';
import { DEFAULT_ICON } from '../../../../../../common/constants';
import { i18n } from '@kbn/i18n';
import { getOtherCategoryLabel } from '../../style_util';
import { EuiButtonIcon, EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiFieldText } from '@elastic/eui';
import { EuiButtonIcon, EuiFlexGroup, EuiFlexItem, EuiFormRow } from '@elastic/eui';
import { IconSelect } from './icon_select';
import { StopInput } from '../stop_input';

function isDuplicateStop(targetStop, iconStops) {
const stops = iconStops.filter(({ stop }) => {
@@ -23,7 +24,13 @@ const DEFAULT_ICON_STOPS = [
{ stop: '', icon: DEFAULT_ICON },
];

export function IconStops({ iconStops = DEFAULT_ICON_STOPS, isDarkMode, onChange, symbolOptions }) {
export function IconStops({
getValueSuggestions,
iconStops = DEFAULT_ICON_STOPS,
isDarkMode,
onChange,
symbolOptions,
}) {
return iconStops.map(({ stop, icon }, index) => {
const onIconSelect = selectedIconId => {
const newIconStops = [...iconStops];
@@ -33,8 +40,7 @@ export function IconStops({ iconStops = DEFAULT_ICON_STOPS, isDarkMode, onChange
};
onChange({ customMapStops: newIconStops });
};
const onStopChange = e => {
const newStopValue = e.target.value;
const onStopChange = newStopValue => {
const newIconStops = [...iconStops];
newIconStops[index] = {
...iconStops[index],
@@ -95,7 +101,8 @@ export function IconStops({ iconStops = DEFAULT_ICON_STOPS, isDarkMode, onChange
<div>
<EuiFlexGroup responsive={false} alignItems="center" gutterSize="xs">
<EuiFlexItem>
<EuiFieldText
<StopInput
getValueSuggestions={getValueSuggestions}
aria-label={i18n.translate('xpack.maps.styles.iconStops.stopInputAriaLabel', {
defaultMessage: 'Icon stop',
})}
Original file line number Diff line number Diff line change
@@ -43,8 +43,16 @@ function getSymbolSizeIcons() {
}

export class DynamicSizeProperty extends DynamicStyleProperty {
constructor(options, styleName, field, getFieldMeta, getFieldFormatter, isSymbolizedAsIcon) {
super(options, styleName, field, getFieldMeta, getFieldFormatter);
constructor(
options,
styleName,
field,
getFieldMeta,
getFieldFormatter,
getValueSuggestions,
isSymbolizedAsIcon
) {
super(options, styleName, field, getFieldMeta, getFieldFormatter, getValueSuggestions);
this._isSymbolizedAsIcon = isSymbolizedAsIcon;
}

Original file line number Diff line number Diff line change
@@ -17,13 +17,21 @@ import { OrdinalFieldMetaOptionsPopover } from '../components/ordinal_field_meta
export class DynamicStyleProperty extends AbstractStyleProperty {
static type = STYLE_TYPE.DYNAMIC;

constructor(options, styleName, field, getFieldMeta, getFieldFormatter) {
constructor(options, styleName, field, getFieldMeta, getFieldFormatter, getValueSuggestions) {
super(options, styleName);
this._field = field;
this._getFieldMeta = getFieldMeta;
this._getFieldFormatter = getFieldFormatter;
this._getValueSuggestions = getValueSuggestions;
nreese marked this conversation as resolved.
Show resolved Hide resolved
}

getValueSuggestions = query => {
const fieldName = this.getFieldName();
return this._getValueSuggestions && fieldName
? this._getValueSuggestions(fieldName, query)
: [];
};

getFieldMeta() {
return this._getFieldMeta && this._field ? this._getFieldMeta(this._field.getName()) : null;
}
Original file line number Diff line number Diff line change
@@ -160,6 +160,8 @@ export class VectorStyle extends AbstractStyle {
styleProperties[styleProperty.getStyleName()] = styleProperty;
});

this._source.getValueSuggestions('machine.os.keyword', '');

return (
<VectorStyleEditor
handlePropertyChange={handlePropertyChange}
@@ -612,6 +614,7 @@ export class VectorStyle extends AbstractStyle {
field,
this._getFieldMeta,
this._getFieldFormatter,
this._source.getValueSuggestions,
isSymbolizedAsIcon
);
} else {
@@ -631,7 +634,8 @@ export class VectorStyle extends AbstractStyle {
styleName,
field,
this._getFieldMeta,
this._getFieldFormatter
this._getFieldFormatter,
this._source.getValueSuggestions
);
} else {
throw new Error(`${descriptor} not implemented`);
@@ -663,7 +667,8 @@ export class VectorStyle extends AbstractStyle {
VECTOR_STYLES.LABEL_TEXT,
field,
this._getFieldMeta,
this._getFieldFormatter
this._getFieldFormatter,
this._source.getValueSuggestions
);
} else {
throw new Error(`${descriptor} not implemented`);
@@ -682,7 +687,8 @@ export class VectorStyle extends AbstractStyle {
VECTOR_STYLES.ICON,
field,
this._getFieldMeta,
this._getFieldFormatter
this._getFieldFormatter,
this._source.getValueSuggestions
);
} else {
throw new Error(`${descriptor} not implemented`);