import React , { useState , useEffect , ReactNode } from 'react' ; import { EuiPopover , EuiSelectable , EuiBadge } from '@elastic/eui' ; import { i18n } from '@kbn/i18n' ; import classNames from 'classnames' ; import { FieldIcon } from '@kbn/react-field' ; import { WorkspaceField } from '../../types' ; export interface FieldPickerProps { fieldMap : Record < string , WorkspaceField > ; selectField : ( fieldName : string ) => void ; deselectField : ( fieldName : string ) => void ; open : boolean ; setOpen : ( open : boolean ) => void ; } export function FieldPicker ( { fieldMap , selectField , deselectField , open , setOpen , } ) { const allFields = Object . values ( fieldMap ) ; const hasFields = allFields . length > 0 ; const [ fieldOptions , setFieldOptions ] = useState ( toOptions ( allFields ) ) ; useEffect ( ( ) => { if ( ! open ) { setFieldOptions ( toOptions ( Object . values ( fieldMap ) ) ) ; } } , [ fieldMap , open ] ) ; const badgeDescription = i18n . translate ( 'xpack.graph.bar.pickFieldsLabel' , { defaultMessage : 'Add fields' , } ) ; return ( < EuiPopover id = "graphFieldPicker" anchorPosition = "downLeft" ownFocus panelPaddingSize = "none" button = { < EuiBadge data - test - subj = "graph-add-field-button" className = { classNames ( 'gphFieldPicker__button' , { 'gphFieldPicker__button--disabled' : ! hasFields , } ) } color = "hollow" iconType = "plusInCircleFilled" aria - disabled = { ! hasFields } onClick = { ( ) => { if ( hasFields ) { setOpen ( true ) ; } } } onClickAriaLabel = { badgeDescription } > { badgeDescription } < /EuiBadge>} isOpen={open} closePopover={() => setOpen(false)} panelClassName="gphFieldPicker__popoverPanel"> { open && ( < EuiSelectable searchProps = { { placeholder : i18n . translate ( 'xpack.graph.fieldManager.fieldSearchPlaceholder' , { defaultMessage : 'Filter by' , } ) , compressed : true , 'data-test-subj' : 'graph-field-search' , } } listProps = { { className : 'gphFieldPicker__selectableList' , } } searchable options = { fieldOptions } onChange = { ( newOptions ) => { newOptions . forEach ( ( option ) => { if ( option . checked === 'on' && ! fieldMap [ option . label ] . selected ) { selectField ( option . label ) ; } else if ( option . checked !== 'on' && fieldMap [ option . label ] . selected ) { deselectField ( option . label ) ; } } ) ; setFieldOptions ( newOptions ) ; } } > { ( list , search ) => ( < > { search } { list } < />)} < /EuiSelectable>)} < /EuiPopover>); } function toOptions ( fields ) { return ( fields . filter ( ( field ) => isExplorable ( field ) || field . selected ) . map ( ( field ) => ( { label : field . name , prepend : < FieldIcon className = "eui-alignMiddle" type = { field . type } fill = "none" / > , checked : field . selected ? 'on' : undefined , } ) ) ) ; } const explorableTypes = [ 'string' , 'number' , 'date' , 'ip' , 'boolean' ] ; function isExplorable ( field ) { if ( ! field . aggregatable ) { return false ; } return explorableTypes . includes ( field . type ) ; }