import { createHashHistory , History , UnregisterCallback } from 'history' ; import { BehaviorSubject , Observable , Subscription } from 'rxjs' ; import { AppUpdater , ToastsSetup } from 'opensearch-dashboards/public' ; import { setStateToOsdUrl } from './osd_url_storage' ; import { unhashUrl } from './hash_unhash_url' ; export interface OsdUrlTracker { /**
     * Callback to invoke when the app is mounted
     */ appMounted : ( ) => void ; /**
     * Callback to invoke when the app is unmounted
     */ appUnMounted : ( ) => void ; /**
     * Unregistering the url tracker. This won't reset the current state of the nav link
     */ stop : ( ) => void ; setActiveUrl : ( newUrl : string ) => void ; getActiveUrl : ( ) => string ; /**
     * Resets internal state to the last active url, discarding the most recent change
     */ restorePreviousUrl : ( ) => void ; } /**
 * Listens to history changes and optionally to global state changes and updates the nav link url of
 * a given app to point to the last visited page within the app.
 *
 * This includes the following parts:
 * * When the app is currently active, the nav link points to the configurable default url of the app.
 * * When the app is not active the last visited url is set to the nav link.
 * * When a provided observable emits a new value, the state parameter in the url of the nav link is updated
 * as long as the app is not active.
 */ export function createOsdUrlTracker ( { baseUrl , defaultSubUrl , storageKey , stateParams , navLinkUpdater$ , toastNotifications , history , getHistory , storage , shouldTrackUrlUpdate = ( ) => { return true ; } , } ) { const storageInstance = storage || sessionStorage ; let previousActiveUrl = '' ; let activeUrl = '' ; let unsubscribeURLHistory ; let unsubscribeGlobalState ; function setNavLink ( hash ) { navLinkUpdater$ . next ( ( ) => ( { defaultPath : hash } ) ) ; } function getActiveSubUrl ( url ) { return url . substr ( baseUrl . length ) ; } function unsubscribe ( ) { if ( unsubscribeURLHistory ) { unsubscribeURLHistory ( ) ; unsubscribeURLHistory = undefined ; } if ( unsubscribeGlobalState ) { unsubscribeGlobalState . forEach ( ( sub ) => sub . unsubscribe ( ) ) ; unsubscribeGlobalState = undefined ; } } function setActiveUrl ( newUrl ) { const urlWithHashes = baseUrl + '#' + newUrl ; let urlWithStates = '' ; try { urlWithStates = unhashUrl ( urlWithHashes ) ; } catch ( e ) { toastNotifications . addDanger ( e . message ) ; } previousActiveUrl = activeUrl ; activeUrl = getActiveSubUrl ( urlWithStates || urlWithHashes ) ; storageInstance . setItem ( storageKey , activeUrl ) ; } function onMountApp ( ) { unsubscribe ( ) ; const historyInstance = history || ( getHistory && getHistory ( ) ) || createHashHistory ( ) ; unsubscribeURLHistory = historyInstance . listen ( ( location ) => { if ( shouldTrackUrlUpdate ( location . hash ) ) { setActiveUrl ( location . hash . substr ( 1 ) ) ; } } ) ; } function onUnmountApp ( ) { unsubscribe ( ) ; unsubscribeGlobalState = stateParams . map ( ( { stateUpdate$ , osdUrlKey } ) => stateUpdate$ . subscribe ( ( state ) => { const updatedUrl = setStateToOsdUrl ( osdUrlKey , state , { useHash : false } , baseUrl + ( activeUrl || defaultSubUrl ) ) ; previousActiveUrl = activeUrl ; activeUrl = getActiveSubUrl ( updatedUrl ) ; storageInstance . setItem ( storageKey , activeUrl ) ; setNavLink ( activeUrl ) ; } ) ) ; } onUnmountApp ( ) ; const storedUrl = storageInstance . getItem ( storageKey ) ; if ( storedUrl ) { activeUrl = storedUrl ; previousActiveUrl = storedUrl ; setNavLink ( storedUrl ) ; } return { appMounted ( ) { onMountApp ( ) ; setNavLink ( defaultSubUrl ) ; } , appUnMounted ( ) { onUnmountApp ( ) ; setNavLink ( activeUrl ) ; } , stop ( ) { unsubscribe ( ) ; } , setActiveUrl , getActiveUrl ( ) { return activeUrl ; } , restorePreviousUrl ( ) { activeUrl = previousActiveUrl ; } , } ; }