import { useRef , useCallback , useState , useEffect } from 'react' ; import { ReindexStatusResponse , ReindexStatus , ReindexStep , ReindexWarning , } from '../../../../../../common/types' ; import { CancelLoadingState , LoadingState } from '../../../types' ; import { ApiService } from '../../../../lib/api' ; const POLL_INTERVAL = 1000 ; export interface ReindexState { loadingState : LoadingState ; cancelLoadingState ? : CancelLoadingState ; lastCompletedStep ? : ReindexStep ; status ? : ReindexStatus ; reindexTaskPercComplete : number | null ; errorMessage : string | null ; reindexWarnings ? : ReindexWarning [ ] ; hasRequiredPrivileges ? : boolean ; meta : { indexName : string ; reindexName : string ; aliases : string [ ] ; } ; } const getReindexState = ( reindexState , { reindexOp , warnings , hasRequiredPrivileges , meta : updatedMeta } ) => { const meta = { ... ( updatedMeta ?? reindexState . meta ) } ; const aliases = reindexState . meta . aliases . length > 0 ? reindexState . meta . aliases : updatedMeta . aliases ; const newReindexState = { ... reindexState , meta : { ... meta , aliases } , loadingState : LoadingState . Success , } ; if ( warnings ) { newReindexState . reindexWarnings = warnings ; } if ( hasRequiredPrivileges !== undefined ) { newReindexState . hasRequiredPrivileges = hasRequiredPrivileges ; } if ( reindexOp ) { let updateLastCompletedStep = true ; if ( reindexOp . lastCompletedStep === ReindexStep . aliasCreated && reindexOp . status !== ReindexStatus . completed ) { updateLastCompletedStep = false ; } if ( updateLastCompletedStep ) { newReindexState . lastCompletedStep = reindexOp . lastCompletedStep ; } newReindexState . status = reindexOp . status ; newReindexState . reindexTaskPercComplete = reindexOp . reindexTaskPercComplete ; newReindexState . errorMessage = reindexOp . errorMessage ; if ( ( reindexState . cancelLoadingState === CancelLoadingState . Requested || reindexState . cancelLoadingState === CancelLoadingState . Loading ) && reindexOp . status === ReindexStatus . cancelled ) { newReindexState . cancelLoadingState = CancelLoadingState . Success ; } else if ( reindexState . cancelLoadingState === CancelLoadingState . Requested && reindexOp . status === ReindexStatus . inProgress ) { newReindexState . cancelLoadingState = CancelLoadingState . Loading ; } else if ( newReindexState . status === ReindexStatus . completed ) { newReindexState . status = ReindexStatus . inProgress ; } } return newReindexState ; } ; export const useReindexStatus = ( { indexName , api } ) => { const [ reindexState , setReindexState ] = useState < ReindexState > ( { loadingState : LoadingState . Loading , errorMessage : null , reindexTaskPercComplete : null , meta : { indexName , reindexName : '' , aliases : [ ] , } , } ) ; const pollIntervalIdRef = useRef < ReturnType < typeof setTimeout > | null > ( null ) ; const isMounted = useRef ( false ) ; const clearPollInterval = useCallback ( ( ) => { if ( pollIntervalIdRef . current ) { clearTimeout ( pollIntervalIdRef . current ) ; pollIntervalIdRef . current = null ; } } , [ ] ) ; /**
     * When the server says that reindexing is complete we will fake
     * one (or two in case there are existing aliases to update) extra steps in the UI
     */ const simulateExtraSteps = useCallback ( ( ) => { const delay = 1000 ; const hasExistingAliases = reindexState . meta . aliases . length > 0 ; const completeUpdateExistingAliasesStep = ( ) => { if ( ! isMounted . current ) { return ; } setReindexState ( ( prevValue ) => { return { ... prevValue , status : ReindexStatus . completed , lastCompletedStep : ReindexStep . existingAliasesUpdated , } ; } ) ; } ; const completeDeleteOriginalIndexStep = ( ) => { if ( ! isMounted . current ) { return ; } setReindexState ( ( prevValue ) => { return { ... prevValue , status : hasExistingAliases ? ReindexStatus . inProgress : ReindexStatus . completed , lastCompletedStep : ReindexStep . originalIndexDeleted , } ; } ) ; if ( hasExistingAliases ) { setTimeout ( completeUpdateExistingAliasesStep , delay ) ; } } ; setTimeout ( completeDeleteOriginalIndexStep , delay ) ; } , [ reindexState . meta . aliases . length ] ) ; const updateStatus = useCallback ( async ( ) => { clearPollInterval ( ) ; const { data , error } = await api . getReindexStatus ( indexName ) ; if ( error ) { setReindexState ( ( prevValue ) => { return { ... prevValue , loadingState : LoadingState . Error , errorMessage : error . message . toString ( ) , status : ReindexStatus . fetchFailed , } ; } ) ; return ; } if ( data === null ) { return ; } setReindexState ( ( prevValue ) => { return getReindexState ( prevValue , data ) ; } ) ; if ( data . reindexOp && data . reindexOp . status === ReindexStatus . inProgress ) { pollIntervalIdRef . current = setTimeout ( updateStatus , POLL_INTERVAL ) ; } else if ( data . reindexOp && data . reindexOp . status === ReindexStatus . completed ) { simulateExtraSteps ( ) ; } } , [ clearPollInterval , api , indexName , simulateExtraSteps ] ) ; const startReindex = useCallback ( async ( ) => { setReindexState ( ( prevValue ) => { return { ... prevValue , lastCompletedStep : prevValue . status === ReindexStatus . paused ? prevValue . lastCompletedStep : undefined , status : ReindexStatus . inProgress , reindexTaskPercComplete : null , errorMessage : null , cancelLoadingState : undefined , } ; } ) ; const { data : reindexOp , error } = await api . startReindexTask ( indexName ) ; if ( error ) { setReindexState ( ( prevValue ) => { return { ... prevValue , loadingState : LoadingState . Error , errorMessage : error . message . toString ( ) , status : ReindexStatus . failed , } ; } ) ; return ; } setReindexState ( ( prevValue ) => { return getReindexState ( prevValue , { reindexOp , meta : prevValue . meta } ) ; } ) ; updateStatus ( ) ; } , [ api , indexName , updateStatus ] ) ; const cancelReindex = useCallback ( async ( ) => { setReindexState ( ( prevValue ) => { return { ... prevValue , cancelLoadingState : CancelLoadingState . Requested , } ; } ) ; const { error } = await api . cancelReindexTask ( indexName ) ; if ( error ) { setReindexState ( ( prevValue ) => { return { ... prevValue , cancelLoadingState : CancelLoadingState . Error , } ; } ) ; return ; } } , [ api , indexName ] ) ; useEffect ( ( ) => { updateStatus ( ) ; } , [ updateStatus ] ) ; useEffect ( ( ) => { isMounted . current = true ; return ( ) => { isMounted . current = false ; clearPollInterval ( ) ; } ; } , [ clearPollInterval ] ) ; return { reindexState , startReindex , cancelReindex , updateStatus , } ; } ;