import { useState , useEffect } from 'react' ; import { useService } from '@cloudbeaver/core-di' ; import { NotificationService } from '@cloudbeaver/core-events' ; import { ErrorBoundary } from './ErrorBoundary' ; interface IComplexLoaderData < T > { promise : Promise < T > | undefined ; data : T | undefined ; error : Error | undefined ; loader : ( ) => Promise < T > ; } export interface ComplexLoaderProps < T > { loader : IComplexLoaderData < T > ; placeholder : React . ReactElement ; keepLoading ? : boolean ; children : ( content : T ) => JSX . Element ; } export const ComplexLoader = function ComplexLoader ( props ) { const [ content , setContent ] = useState < unknown | null > ( props . loader . data ) ; const notificationService = useService ( NotificationService ) ; useEffect ( ( ) => { let unmounted = false ; if ( ! content ) { props . loader . loader ( ) . then ( value => ! unmounted && setContent ( value ) ) . catch ( exception => ! unmounted && notificationService . logException ( exception , 'Can\'t load resource' ) ) ; } return ( ) => { unmounted = true ; } ; } , [ content ] ) ; if ( ! content || props . keepLoading ) { return props . placeholder ; } function refresh ( ) { setContent ( null ) ; } return ( < ErrorBoundary onRefresh = { refresh } > { props . children ( content ) } < /ErrorBoundary>); } ; export function createComplexLoader < T > ( loader ) { return { promise : undefined , data : undefined , error : undefined , async loader ( ) { if ( this . data !== undefined ) { return this . data ; } if ( this . error ) { throw this . error ; } if ( this . promise ) { return await this . promise ; } this . promise = loader ( ) ; try { this . data = await this . promise ; return this . data ; } catch ( exception ) { this . error = exception ; throw exception ; } } , } ; }