import { i18n } from '@kbn/i18n' ; import React , { ReactNode } from 'react' ; import { EuiComboBox , EuiComboBoxProps , EuiComboBoxOptionOption , EuiFormRow , htmlIdGenerator , } from '@elastic/eui' ; import { getIndexPatternKey } from '../../../../common/index_patterns_utils' ; import type { SanitizedFieldType , IndexPatternValue } from '../../../../common/types' ; import type { TimeseriesUIRestrictions } from '../../../../common/ui_restrictions' ; import { isFieldEnabled } from '../../../../common/check_ui_restrictions' ; interface FieldSelectProps { label : string | ReactNode ; type : string ; fields : Record < string , SanitizedFieldType [ ] > ; indexPattern : IndexPatternValue ; value ? : string | null ; onChange : ( options : Array < EuiComboBoxOptionOption < string > > ) => void ; disabled ? : boolean ; restrict ? : string [ ] ; placeholder ? : string ; uiRestrictions ? : TimeseriesUIRestrictions ; 'data-test-subj' ? : string ; } const defaultPlaceholder = i18n . translate ( 'visTypeTimeseries.fieldSelect.selectFieldPlaceholder' , { defaultMessage : 'Select field...' , } ) ; const isFieldTypeEnabled = ( fieldRestrictions , fieldType ) => fieldRestrictions . length ? fieldRestrictions . includes ( fieldType ) : true ; const sortByLabel = ( a , b ) => { const getNormalizedString = ( option ) => ( option . label || '' ) . toLowerCase ( ) ; return getNormalizedString ( a ) . localeCompare ( getNormalizedString ( b ) ) ; } ; export function FieldSelect ( { label , type , fields , indexPattern = '' , value = '' , onChange , disabled = false , restrict = [ ] , placeholder = defaultPlaceholder , uiRestrictions , 'data-test-subj' : dataTestSubj = 'metricsIndexPatternFieldsSelect' , } ) { const htmlId = htmlIdGenerator ( ) ; let selectedOptions = [ ] ; let newPlaceholder = placeholder ; const fieldsSelector = getIndexPatternKey ( indexPattern ) ; const groupedOptions = Object . values ( ( fields [ fieldsSelector ] || [ ] ) . reduce < Record < string , EuiComboBoxOptionOption < string > > > ( ( acc , field ) => { if ( placeholder === field ?. name ) { newPlaceholder = field . label ?? field . name ; } if ( isFieldTypeEnabled ( restrict , field . type ) && isFieldEnabled ( field . name , type , uiRestrictions ) ) { const item = { value : field . name , label : field . label ?? field . name , } ; const fieldTypeOptions = acc [ field . type ] ?. options ; if ( fieldTypeOptions ) { fieldTypeOptions . push ( item ) ; } else { acc [ field . type ] = { options : [ item ] , label : field . type , } ; } if ( value === item . value ) { selectedOptions . push ( item ) ; } } return acc ; } , { } ) ) ; groupedOptions . sort ( sortByLabel ) ; groupedOptions . forEach ( ( group ) => { if ( Array . isArray ( group . options ) ) { group . options . sort ( sortByLabel ) ; } } ) ; const isInvalid = Boolean ( value && fields [ fieldsSelector ] && ! selectedOptions . length ) ; if ( value && ! selectedOptions . length ) { selectedOptions = [ { label : value , id : 'INVALID_FIELD' } ] ; } return ( < EuiFormRow id = { htmlId ( 'timeField' ) } label = { label } isInvalid = { isInvalid } error = { i18n . translate ( 'visTypeTimeseries.fieldSelect.fieldIsNotValid' , { defaultMessage : 'The "{fieldParameter}" field is not valid for use with the current index. Please select a new field.' , values : { fieldParameter : value , } , } ) } > < EuiComboBox data - test - subj = { dataTestSubj } placeholder = { newPlaceholder } isDisabled = { disabled } options = { groupedOptions } selectedOptions = { selectedOptions } onChange = { onChange } singleSelection = { { asPlainText : true } } isInvalid = { isInvalid } / > < /EuiFormRow>); }