import { kea , MakeLogicType } from 'kea' ; import { i18n } from '@kbn/i18n' ; import { DEFAULT_META } from '../../../shared/constants' ; import { flashAPIErrors , flashSuccessToast , setErrorMessage , clearFlashMessages , } from '../../../shared/flash_messages' ; import { HttpLogic } from '../../../shared/http' ; import { KibanaLogic } from '../../../shared/kibana' ; import { AppLogic } from '../../app_logic' ; import { PRIVATE_SOURCES_PATH , SOURCES_PATH , getSourcesPath } from '../../routes' ; import { ContentSourceFullData , Meta , DocumentSummaryItem , SourceContentItem } from '../../types' ; export interface SourceActions { setContentSource ( contentSource ) : ContentSourceFullData ; onUpdateSourceName ( name ) : string ; setSearchResults ( searchResultsResponse ) : SearchResultsResponse ; initializeFederatedSummary ( sourceId ) : { sourceId : string ; } ; initializeSourceSynchronization ( sourceId ) : { sourceId : string ; } ; onUpdateSummary ( summary ) : DocumentSummaryItem [ ] ; setContentFilterValue ( contentFilterValue ) : string ; setActivePage ( activePage ) : number ; searchContentSourceDocuments ( sourceId ) : { sourceId : string ; } ; updateContentSource ( sourceId , source ) : { sourceId : string ; source : ContentSourceFullData ; } ; updateContentSourceConfiguration ( sourceId , source ) : { sourceId : string ; source : ContentSourceFullData ; } ; resetSourceState ( ) : void ; removeContentSource ( sourceId ) : { sourceId : string ; } ; initializeSource ( sourceId ) : { sourceId : string ; } ; setButtonNotLoading ( ) : void ; setStagedPrivateKey ( stagedPrivateKey ) : string | null ; setConfigurationUpdateButtonNotLoading ( ) : void ; showDiagnosticDownloadButton ( ) : void ; } interface SourceValues { contentSource : ContentSourceFullData ; dataLoading : boolean ; sectionLoading : boolean ; buttonLoading : boolean ; diagnosticDownloadButtonVisible : boolean ; contentItems : SourceContentItem [ ] ; contentMeta : Meta ; contentFilterValue : string ; stagedPrivateKey : string | null ; isConfigurationUpdateButtonLoading : boolean ; } interface SearchResultsResponse { results : SourceContentItem [ ] ; meta : Meta ; } interface SourceUpdatePayload { name ? : string ; private_key ? : string | null ; indexing ? : { enabled ? : boolean ; features ? : { thumbnails ? : { enabled : boolean ; } ; content_extraction ? : { enabled : boolean ; } ; } ; } ; } export const SourceLogic = kea < MakeLogicType < SourceValues , SourceActions > > ( { path : [ 'enterprise_search' , 'workplace_search' , 'source_logic' ] , actions : { setContentSource : ( contentSource ) => contentSource , onUpdateSourceName : ( name ) => name , onUpdateSummary : ( summary ) => summary , setSearchResults : ( searchResultsResponse ) => searchResultsResponse , setContentFilterValue : ( contentFilterValue ) => contentFilterValue , setActivePage : ( activePage ) => activePage , initializeSource : ( sourceId ) => ( { sourceId } ) , initializeFederatedSummary : ( sourceId ) => ( { sourceId } ) , initializeSourceSynchronization : ( sourceId ) => ( { sourceId } ) , searchContentSourceDocuments : ( sourceId ) => ( { sourceId } ) , updateContentSource : ( sourceId , source ) => ( { sourceId , source } ) , updateContentSourceConfiguration : ( sourceId , source ) => ( { sourceId , source , } ) , removeContentSource : ( sourceId ) => ( { sourceId , } ) , resetSourceState : ( ) => true , setButtonNotLoading : ( ) => false , setStagedPrivateKey : ( stagedPrivateKey ) => stagedPrivateKey , setConfigurationUpdateButtonNotLoading : ( ) => false , showDiagnosticDownloadButton : true , } , reducers : { contentSource : [ { } as ContentSourceFullData , { setContentSource : ( _ , contentSource ) => contentSource , onUpdateSourceName : ( contentSource , name ) => ( { ... contentSource , name , } ) , onUpdateSummary : ( contentSource , summary ) => ( { ... contentSource , summary , } ) , resetSourceState : ( ) => ( { } as ContentSourceFullData ) , } , ] , dataLoading : [ true , { setContentSource : ( ) => false , resetSourceState : ( ) => true , removeContentSource : ( ) => true , } , ] , buttonLoading : [ false , { setButtonNotLoading : ( ) => false , resetSourceState : ( ) => false , } , ] , sectionLoading : [ true , { searchContentSourceDocuments : ( ) => true , setSearchResults : ( ) => false , } , ] , diagnosticDownloadButtonVisible : [ false , { showDiagnosticDownloadButton : ( ) => true , initializeSource : ( ) => false , } , ] , contentItems : [ [ ] , { setSearchResults : ( _ , { results } ) => results , } , ] , contentMeta : [ DEFAULT_META , { setActivePage : ( state , activePage ) => setPage ( state , activePage ) , setContentFilterValue : ( state ) => setPage ( state , DEFAULT_META . page . current ) , setSearchResults : ( _ , { meta } ) => meta , } , ] , contentFilterValue : [ '' , { setContentFilterValue : ( _ , contentFilterValue ) => contentFilterValue , resetSourceState : ( ) => '' , } , ] , stagedPrivateKey : [ null , { setStagedPrivateKey : ( _ , stagedPrivateKey ) => stagedPrivateKey , setContentSource : ( ) => null , } , ] , isConfigurationUpdateButtonLoading : [ false , { updateContentSourceConfiguration : ( ) => true , setConfigurationUpdateButtonNotLoading : ( ) => false , } , ] , } , listeners : ( { actions , values } ) => ( { initializeSource : async ( { sourceId } ) => { const { isOrganization } = AppLogic . values ; const route = isOrganization ? `/internal/workplace_search/org/sources/${ sourceId }` : `/internal/workplace_search/account/sources/${ sourceId }` ; try { const response = await HttpLogic . values . http . get < ContentSourceFullData & { errors ? : string ; } > ( route ) ; actions . setContentSource ( response ) ; if ( response . isFederatedSource ) { actions . initializeFederatedSummary ( sourceId ) ; } if ( response . errors ) { setErrorMessage ( response . errors ) ; if ( errorsHaveDiagnosticBundleString ( response . errors as unknown as string [ ] ) ) { actions . showDiagnosticDownloadButton ( ) ; } } else { clearFlashMessages ( ) ; } } catch ( e ) { if ( e ?. response ?. status === 404 ) { const redirect = isOrganization ? SOURCES_PATH : PRIVATE_SOURCES_PATH ; KibanaLogic . values . navigateToUrl ( redirect ) ; setErrorMessage ( i18n . translate ( 'xpack.enterpriseSearch.workplaceSearch.sources.notFoundErrorMessage' , { defaultMessage : 'Source not found.' , } ) ) ; } else { flashAPIErrors ( e ) ; } } } , initializeFederatedSummary : async ( { sourceId } ) => { const route = `/internal/workplace_search/account/sources/${ sourceId }/federated_summary` ; try { const response = await HttpLogic . values . http . get < { summary : DocumentSummaryItem [ ] ; } > ( route ) ; actions . onUpdateSummary ( response . summary ) ; } catch ( e ) { flashAPIErrors ( e ) ; } } , searchContentSourceDocuments : async ( { sourceId } , breakpoint ) => { await breakpoint ( 300 ) ; const { isOrganization } = AppLogic . values ; const route = isOrganization ? `/internal/workplace_search/org/sources/${ sourceId }/documents` : `/internal/workplace_search/account/sources/${ sourceId }/documents` ; const { contentFilterValue : query , contentMeta : { page } , } = values ; try { const response = await HttpLogic . values . http . post < SearchResultsResponse > ( route , { body : JSON . stringify ( { query , page } ) , } ) ; actions . setSearchResults ( response ) ; } catch ( e ) { flashAPIErrors ( e ) ; } } , updateContentSource : async ( { sourceId , source } ) => { const { isOrganization } = AppLogic . values ; const route = isOrganization ? `/internal/workplace_search/org/sources/${ sourceId }/settings` : `/internal/workplace_search/account/sources/${ sourceId }/settings` ; try { const response = await HttpLogic . values . http . patch < { name : string ; } > ( route , { body : JSON . stringify ( { content_source : source } ) , } ) ; if ( source . name ) { actions . onUpdateSourceName ( response . name ) ; } } catch ( e ) { flashAPIErrors ( e ) ; } } , updateContentSourceConfiguration : async ( { sourceId , source } ) => { const { isOrganization } = AppLogic . values ; const route = isOrganization ? `/internal/workplace_search/org/sources/${ sourceId }/settings` : `/internal/workplace_search/account/sources/${ sourceId }/settings` ; try { const response = await HttpLogic . values . http . patch < ContentSourceFullData > ( route , { body : JSON . stringify ( { content_source : source } ) , } ) ; actions . setContentSource ( response ) ; flashSuccessToast ( 'Content source configuration was updated.' ) ; } catch ( e ) { flashAPIErrors ( e ) ; } finally { actions . setConfigurationUpdateButtonNotLoading ( ) ; } } , removeContentSource : async ( { sourceId } ) => { clearFlashMessages ( ) ; const { isOrganization } = AppLogic . values ; const route = isOrganization ? `/internal/workplace_search/org/sources/${ sourceId }` : `/internal/workplace_search/account/sources/${ sourceId }` ; try { const response = await HttpLogic . values . http . delete < { name : string ; } > ( route ) ; KibanaLogic . values . navigateToUrl ( getSourcesPath ( SOURCES_PATH , isOrganization ) ) ; flashSuccessToast ( i18n . translate ( 'xpack.enterpriseSearch.workplaceSearch.sources.flashMessages.contentSourceRemoved' , { defaultMessage : 'Successfully deleted {sourceName}.' , values : { sourceName : response . name } , } ) ) ; } catch ( e ) { flashAPIErrors ( e ) ; } finally { actions . setButtonNotLoading ( ) ; } } , initializeSourceSynchronization : async ( { sourceId } ) => { const route = `/internal/workplace_search/org/sources/${ sourceId }/sync` ; try { await HttpLogic . values . http . post ( route ) ; actions . initializeSource ( sourceId ) ; } catch ( e ) { flashAPIErrors ( e ) ; } } , onUpdateSourceName : ( name ) => { flashSuccessToast ( i18n . translate ( 'xpack.enterpriseSearch.workplaceSearch.sources.flashMessages.contentSourceNameChanged' , { defaultMessage : 'Successfully changed name to {sourceName}.' , values : { sourceName : name } , } ) ) ; } , resetSourceState : ( ) => { clearFlashMessages ( ) ; } , } ) , } ) ; const setPage = ( state , page ) => ( { ... state , page : { ... state . page , current : page , } , } ) ; const errorsHaveDiagnosticBundleString = ( errors ) => { const ERROR_SUBSTRING = 'Check diagnostic bundle for details' ; return errors . find ( ( e ) => e . includes ( ERROR_SUBSTRING ) ) ; } ;