import _ from 'lodash' ; import React , { Component } from 'react' ; import { Required } from '@osd/utility-types' ; import { EuiComboBox , EuiComboBoxProps } from '@elastic/eui' ; import { SavedObjectsClientContract , SimpleSavedObject } from 'src/core/public' ; import { getTitle } from '../../../common/index_patterns/lib' ; export type IndexPatternSelectProps = Required < Omit < EuiComboBoxProps < any > , 'isLoading' | 'onSearchChange' | 'options' | 'selectedOptions' > , 'onChange' | 'placeholder' > & { indexPatternId : string ; fieldTypes ? : string [ ] ; onNoIndexPatterns ? : ( ) => void ; savedObjectsClient : SavedObjectsClientContract ; } ; interface IndexPatternSelectState { isLoading : boolean ; options : [ ] ; selectedIndexPattern : { value : string ; label : string ; } | undefined ; searchValue : string | undefined ; } const getIndexPatterns = async ( client , search , fields ) => { const resp = await client . find ( { type : 'index-pattern' , fields , search : `${ search }*` , searchFields : [ 'title' ] , perPage : 100 , } ) ; return resp . savedObjects ; } ; export default class IndexPatternSelect extends Component < IndexPatternSelectProps > { private isMounted : boolean = false ; state : IndexPatternSelectState ; constructor ( props ) { super ( props ) ; this . state = { isLoading : false , options : [ ] , selectedIndexPattern : undefined , searchValue : undefined , } ; } componentWillUnmount ( ) { this . isMounted = false ; this . debouncedFetch . cancel ( ) ; } componentDidMount ( ) { this . isMounted = true ; this . fetchOptions ( ) ; this . fetchSelectedIndexPattern ( this . props . indexPatternId ) ; } UNSAFE_componentWillReceiveProps ( nextProps ) { if ( nextProps . indexPatternId !== this . props . indexPatternId ) { this . fetchSelectedIndexPattern ( nextProps . indexPatternId ) ; } } fetchSelectedIndexPattern = async ( indexPatternId ) => { if ( ! indexPatternId ) { this . setState ( { selectedIndexPattern : undefined , } ) ; return ; } let indexPatternTitle ; try { indexPatternTitle = await getTitle ( this . props . savedObjectsClient , indexPatternId ) ; } catch ( err ) { return ; } if ( ! this . isMounted ) { return ; } this . setState ( { selectedIndexPattern : { value : indexPatternId , label : indexPatternTitle , } , } ) ; } ; debouncedFetch = _ . debounce ( async ( searchValue ) => { const { fieldTypes , onNoIndexPatterns , savedObjectsClient } = this . props ; const savedObjectFields = [ 'title' ] ; if ( fieldTypes ) { savedObjectFields . push ( 'fields' ) ; } let savedObjects = await getIndexPatterns ( savedObjectsClient , searchValue , savedObjectFields ) ; if ( fieldTypes ) { savedObjects = savedObjects . filter ( ( savedObject ) => { try { const indexPatternFields = JSON . parse ( savedObject . attributes . fields as any ) ; return indexPatternFields . some ( ( field ) => { return fieldTypes ?. includes ( field . type ) ; } ) ; } catch ( err ) { return false ; } } ) ; } if ( ! this . isMounted ) { return ; } if ( searchValue === this . state . searchValue ) { const options = savedObjects . map ( ( indexPatternSavedObject ) => { return { label : indexPatternSavedObject . attributes . title , value : indexPatternSavedObject . id , } ; } ) ; this . setState ( { isLoading : false , options , } ) ; if ( onNoIndexPatterns && searchValue === '' && options . length === 0 ) { onNoIndexPatterns ( ) ; } } } , 300 ) ; fetchOptions = ( searchValue = '' ) => { this . setState ( { isLoading : true , searchValue , } , this . debouncedFetch . bind ( null , searchValue ) ) ; } ; onChange = ( selectedOptions ) => { this . props . onChange ( _ . get ( selectedOptions , '0.value' ) ) ; } ; render ( ) { const { fieldTypes , onChange , indexPatternId , placeholder , onNoIndexPatterns , savedObjectsClient , ... rest } = this . props ; return ( < EuiComboBox { ... rest } placeholder = { placeholder } singleSelection = { true } isLoading = { this . state . isLoading } onSearchChange = { this . fetchOptions } options = { this . state . options } selectedOptions = { this . state . selectedIndexPattern ? [ this . state . selectedIndexPattern ] : [ ] } onChange = { this . onChange } / > ) ; } }