diff --git a/x-pack/plugins/maps/public/classes/styles/vector/components/color/vector_style_color_editor.js b/x-pack/plugins/maps/public/classes/styles/vector/components/color/vector_style_color_editor.tsx similarity index 69% rename from x-pack/plugins/maps/public/classes/styles/vector/components/color/vector_style_color_editor.js rename to x-pack/plugins/maps/public/classes/styles/vector/components/color/vector_style_color_editor.tsx index 43e7050b3d1d2..4527f56c04d2e 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/components/color/vector_style_color_editor.js +++ b/x-pack/plugins/maps/public/classes/styles/vector/components/color/vector_style_color_editor.tsx @@ -6,12 +6,15 @@ import React from 'react'; -import { StylePropEditor } from '../style_prop_editor'; +import { i18n } from '@kbn/i18n'; +import { Props, StylePropEditor } from '../style_prop_editor'; +// @ts-expect-error import { DynamicColorForm } from './dynamic_color_form'; +// @ts-expect-error import { StaticColorForm } from './static_color_form'; -import { i18n } from '@kbn/i18n'; +import { ColorDynamicOptions, ColorStaticOptions } from '../../../../../../common/descriptor_types'; -export function VectorStyleColorEditor(props) { +export function VectorStyleColorEditor(props: Props) { const colorForm = props.styleProperty.isDynamic() ? ( ) : ( @@ -19,7 +22,7 @@ export function VectorStyleColorEditor(props) { ); return ( - {...props} customStaticOptionLabel={i18n.translate( 'xpack.maps.styles.color.staticDynamicSelect.staticLabel', diff --git a/x-pack/plugins/maps/public/classes/styles/vector/components/field_select.js b/x-pack/plugins/maps/public/classes/styles/vector/components/field_select.tsx similarity index 56% rename from x-pack/plugins/maps/public/classes/styles/vector/components/field_select.js rename to x-pack/plugins/maps/public/classes/styles/vector/components/field_select.tsx index dcc1f1eadbd54..57c63413aecda 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/components/field_select.js +++ b/x-pack/plugins/maps/public/classes/styles/vector/components/field_select.tsx @@ -4,20 +4,30 @@ * you may not use this file except in compliance with the Elastic License. */ -import PropTypes from 'prop-types'; import React from 'react'; -import { EuiComboBox, EuiHighlight, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import { FIELD_ORIGIN } from '../../../../../common/constants'; +import { + EuiComboBox, + EuiComboBoxProps, + EuiComboBoxOptionOption, + EuiHighlight, + EuiFlexGroup, + EuiFlexItem, +} from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { FIELD_ORIGIN, VECTOR_STYLES } from '../../../../../common/constants'; import { FieldIcon } from '../../../../../../../../src/plugins/kibana_react/public'; +import { StyleField } from '../style_fields_helper'; -function renderOption(option, searchValue, contentClassName) { +function renderOption( + option: EuiComboBoxOptionOption, + searchValue: string, + contentClassName: string +) { + const fieldIcon = option.value ? : null; return ( - - - + {fieldIcon} {option.label} @@ -25,11 +35,11 @@ function renderOption(option, searchValue, contentClassName) { ); } -function groupFieldsByOrigin(fields) { - const fieldsByOriginMap = new Map(); +function groupFieldsByOrigin(fields: StyleField[]) { + const fieldsByOriginMap = new Map(); fields.forEach((field) => { if (fieldsByOriginMap.has(field.origin)) { - const fieldsList = fieldsByOriginMap.get(field.origin); + const fieldsList = fieldsByOriginMap.get(field.origin)!; fieldsList.push(field); fieldsByOriginMap.set(field.origin, fieldsList); } else { @@ -37,7 +47,7 @@ function groupFieldsByOrigin(fields) { } }); - function fieldsListToOptions(fieldsList) { + function fieldsListToOptions(fieldsList: StyleField[]) { return fieldsList .map((field) => { return { value: field, label: field.label }; @@ -50,11 +60,14 @@ function groupFieldsByOrigin(fields) { if (fieldsByOriginMap.size === 1) { // do not show origin group if all fields are from same origin const onlyOriginKey = fieldsByOriginMap.keys().next().value; - const fieldsList = fieldsByOriginMap.get(onlyOriginKey); + const fieldsList = fieldsByOriginMap.get(onlyOriginKey)!; return fieldsListToOptions(fieldsList); } - const optionGroups = []; + const optionGroups: Array<{ + label: string; + options: Array>; + }> = []; fieldsByOriginMap.forEach((fieldsList, fieldOrigin) => { optionGroups.push({ label: i18n.translate('xpack.maps.style.fieldSelect.OriginLabel', { @@ -65,29 +78,46 @@ function groupFieldsByOrigin(fields) { }); }); - optionGroups.sort((a, b) => { - return a.label.toLowerCase().localeCompare(b.label.toLowerCase()); - }); + optionGroups.sort( + (a: EuiComboBoxOptionOption, b: EuiComboBoxOptionOption) => { + return a.label.toLowerCase().localeCompare(b.label.toLowerCase()); + } + ); return optionGroups; } -export function FieldSelect({ fields, selectedFieldName, onChange, styleName, ...rest }) { - const onFieldChange = (selectedFields) => { +type Props = { + fields: StyleField[]; + selectedFieldName: string; + onChange: ({ field }: { field: StyleField | null }) => void; + styleName: VECTOR_STYLES; +} & Omit< + EuiComboBoxProps, + | 'selectedOptions' + | 'options' + | 'onChange' + | 'singleSelection' + | 'isClearable' + | 'fullWidth' + | 'renderOption' +>; + +export function FieldSelect({ fields, selectedFieldName, onChange, styleName, ...rest }: Props) { + const onFieldChange = (selectedFields: Array>) => { onChange({ - field: selectedFields.length > 0 ? selectedFields[0].value : null, + field: selectedFields.length > 0 && selectedFields[0].value ? selectedFields[0].value : null, }); }; let selectedOption; if (selectedFieldName) { - const field = fields.find((field) => { - return field.name === selectedFieldName; + const field = fields.find((f) => { + return f.name === selectedFieldName; }); - //Do not spread in all the other unused values (e.g. type, supportsAutoDomain etc...) if (field) { selectedOption = { - value: field.value, + value: field, label: field.label, }; } @@ -110,15 +140,3 @@ export function FieldSelect({ fields, selectedFieldName, onChange, styleName, .. /> ); } - -export const fieldShape = PropTypes.shape({ - name: PropTypes.string.isRequired, - origin: PropTypes.oneOf(Object.values(FIELD_ORIGIN)).isRequired, - type: PropTypes.string.isRequired, -}); - -FieldSelect.propTypes = { - selectedFieldName: PropTypes.string, - fields: PropTypes.arrayOf(fieldShape).isRequired, - onChange: PropTypes.func.isRequired, -}; diff --git a/x-pack/plugins/maps/public/classes/styles/vector/components/get_vector_style_label.js b/x-pack/plugins/maps/public/classes/styles/vector/components/get_vector_style_label.ts similarity index 94% rename from x-pack/plugins/maps/public/classes/styles/vector/components/get_vector_style_label.js rename to x-pack/plugins/maps/public/classes/styles/vector/components/get_vector_style_label.ts index 5d39b423e56e6..1b5f3f47d2204 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/components/get_vector_style_label.js +++ b/x-pack/plugins/maps/public/classes/styles/vector/components/get_vector_style_label.ts @@ -8,14 +8,14 @@ import { i18n } from '@kbn/i18n'; import { VECTOR_STYLES } from '../../../../../common/constants'; -export function getDisabledByMessage(styleName) { +export function getDisabledByMessage(styleName: VECTOR_STYLES) { return i18n.translate('xpack.maps.styles.vector.disabledByMessage', { defaultMessage: `Set '{styleLabel}' to enable`, values: { styleLabel: getVectorStyleLabel(styleName) }, }); } -export function getVectorStyleLabel(styleName) { +export function getVectorStyleLabel(styleName: VECTOR_STYLES) { switch (styleName) { case VECTOR_STYLES.FILL_COLOR: return i18n.translate('xpack.maps.styles.vector.fillColorLabel', { diff --git a/x-pack/plugins/maps/public/classes/styles/vector/components/stop_input.js b/x-pack/plugins/maps/public/classes/styles/vector/components/stop_input.tsx similarity index 76% rename from x-pack/plugins/maps/public/classes/styles/vector/components/stop_input.js rename to x-pack/plugins/maps/public/classes/styles/vector/components/stop_input.tsx index 64a5f806e34c4..765626329a7c5 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/components/stop_input.js +++ b/x-pack/plugins/maps/public/classes/styles/vector/components/stop_input.tsx @@ -5,18 +5,37 @@ */ import _ from 'lodash'; -import React, { Component } from 'react'; +import React, { ChangeEvent, Component } from 'react'; +import { EuiComboBox, EuiComboBoxOptionOption, EuiFieldText } from '@elastic/eui'; +import { IField } from '../../../fields/field'; + +interface Props { + dataTestSubj: string; + field: IField; + getValueSuggestions: (query: string) => Promise; + onChange: (value: string) => void; + value: string; +} + +interface State { + suggestions: string[]; + isLoadingSuggestions: boolean; + hasPrevFocus: boolean; + fieldDataType: string | null; + localFieldTextValue: string; + searchValue?: string; +} -import { EuiComboBox, EuiFieldText } from '@elastic/eui'; +export class StopInput extends Component { + private _isMounted: boolean = false; -export class StopInput extends Component { - constructor(props) { + constructor(props: Props) { super(props); this.state = { suggestions: [], isLoadingSuggestions: false, hasPrevFocus: false, - fieldDataType: undefined, + fieldDataType: null, localFieldTextValue: props.value, }; } @@ -45,15 +64,15 @@ export class StopInput extends Component { } }; - _onChange = (selectedOptions) => { + _onChange = (selectedOptions: Array>) => { this.props.onChange(_.get(selectedOptions, '[0].label', '')); }; - _onCreateOption = (newValue) => { + _onCreateOption = (newValue: string) => { this.props.onChange(newValue); }; - _onSearchChange = async (searchValue) => { + _onSearchChange = async (searchValue: string) => { this.setState( { isLoadingSuggestions: true, @@ -65,8 +84,8 @@ export class StopInput extends Component { ); }; - _loadSuggestions = _.debounce(async (searchValue) => { - let suggestions = []; + _loadSuggestions = _.debounce(async (searchValue: string) => { + let suggestions: string[] = []; try { suggestions = await this.props.getValueSuggestions(searchValue); } catch (error) { @@ -81,7 +100,7 @@ export class StopInput extends Component { } }, 300); - _onFieldTextChange = (event) => { + _onFieldTextChange = (event: ChangeEvent) => { this.setState({ localFieldTextValue: event.target.value }); // onChange can cause UI lag, ensure smooth input typing by debouncing onChange this._debouncedOnFieldTextChange(); diff --git a/x-pack/plugins/maps/public/classes/styles/vector/components/style_prop_editor.js b/x-pack/plugins/maps/public/classes/styles/vector/components/style_prop_editor.tsx similarity index 59% rename from x-pack/plugins/maps/public/classes/styles/vector/components/style_prop_editor.js rename to x-pack/plugins/maps/public/classes/styles/vector/components/style_prop_editor.tsx index e7df47bc6d4cb..43b088074a30e 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/components/style_prop_editor.js +++ b/x-pack/plugins/maps/public/classes/styles/vector/components/style_prop_editor.tsx @@ -4,8 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { Component, Fragment } from 'react'; -import { getVectorStyleLabel, getDisabledByMessage } from './get_vector_style_label'; +import React, { Component, Fragment, ReactElement } from 'react'; import { EuiFormRow, EuiSelect, @@ -14,12 +13,31 @@ import { EuiFieldText, EuiToolTip, } from '@elastic/eui'; -import { STYLE_TYPE } from '../../../../../common/constants'; import { i18n } from '@kbn/i18n'; +import { getVectorStyleLabel, getDisabledByMessage } from './get_vector_style_label'; +import { STYLE_TYPE, VECTOR_STYLES } from '../../../../../common/constants'; +import { FieldMetaOptions } from '../../../../../common/descriptor_types'; +import { IStyleProperty } from '../properties/style_property'; +import { StyleField } from '../style_fields_helper'; + +export interface Props { + children: ReactElement; + customStaticOptionLabel?: string; + defaultStaticStyleOptions: StaticOptions; + defaultDynamicStyleOptions: DynamicOptions; + disabled: boolean; + disabledBy?: VECTOR_STYLES; + fields: StyleField[]; + onDynamicStyleChange: (propertyName: VECTOR_STYLES, options: DynamicOptions) => void; + onStaticStyleChange: (propertyName: VECTOR_STYLES, options: StaticOptions) => void; + styleProperty: IStyleProperty; +} -export class StylePropEditor extends Component { - _prevStaticStyleOptions = this.props.defaultStaticStyleOptions; - _prevDynamicStyleOptions = this.props.defaultDynamicStyleOptions; +export class StylePropEditor extends Component< + Props +> { + private _prevStaticStyleOptions = this.props.defaultStaticStyleOptions; + private _prevDynamicStyleOptions = this.props.defaultDynamicStyleOptions; _onTypeToggle = () => { if (this.props.styleProperty.isDynamic()) { @@ -41,7 +59,7 @@ export class StylePropEditor extends Component { } }; - _onFieldMetaOptionsChange = (fieldMetaOptions) => { + _onFieldMetaOptionsChange = (fieldMetaOptions: FieldMetaOptions) => { const options = { ...this.props.styleProperty.getOptions(), fieldMetaOptions, @@ -89,28 +107,29 @@ export class StylePropEditor extends Component { const staticDynamicSelect = this.renderStaticDynamicSelect(); - const stylePropertyForm = this.props.disabled ? ( - - - - {staticDynamicSelect} - - - - - - - ) : ( - - {React.cloneElement(this.props.children, { - staticDynamicSelect, - })} - {fieldMetaOptionsPopover} - - ); + const stylePropertyForm = + this.props.disabled && this.props.disabledBy ? ( + + + + {staticDynamicSelect} + + + + + + + ) : ( + + {React.cloneElement(this.props.children, { + staticDynamicSelect, + })} + {fieldMetaOptionsPopover} + + ); return (