{"version":3,"file":"LocationService.mjs","sources":["../../../src/services/LocationService.tsx"],"sourcesContent":["import * as H from 'history';\nimport React, { useContext } from 'react';\nimport { BehaviorSubject, Observable } from 'rxjs';\n\nimport { deprecationWarning, UrlQueryMap, urlUtil } from '@grafana/data';\nimport { attachDebugger, createLogger } from '@grafana/ui';\n\nimport { config } from '../config';\n\nimport { LocationUpdate } from './LocationSrv';\n\n/**\n * @public\n * A wrapper to help work with browser location and history\n */\nexport interface LocationService {\n  partial: (query: Record<string, any>, replace?: boolean) => void;\n  push: (location: H.Path | H.LocationDescriptor<any>) => void;\n  replace: (location: H.Path | H.LocationDescriptor<any>) => void;\n  reload: () => void;\n  getLocation: () => H.Location;\n  getHistory: () => H.History;\n  getSearch: () => URLSearchParams;\n  getSearchObject: () => UrlQueryMap;\n  getLocationObservable: () => Observable<H.Location>;\n\n  /**\n   * This is from the old LocationSrv interface\n   * @deprecated use partial, push or replace instead */\n  update: (update: LocationUpdate) => void;\n}\n\n/** @internal */\nexport class HistoryWrapper implements LocationService {\n  private readonly history: H.History;\n  private locationObservable: BehaviorSubject<H.Location>;\n\n  constructor(history?: H.History) {\n    // If no history passed create an in memory one if being called from test\n    this.history =\n      history ||\n      (process.env.NODE_ENV === 'test'\n        ? H.createMemoryHistory({ initialEntries: ['/'] })\n        : H.createBrowserHistory({ basename: config.appSubUrl ?? '/' }));\n\n    this.locationObservable = new BehaviorSubject(this.history.location);\n\n    this.history.listen((location) => {\n      this.locationObservable.next(location);\n    });\n\n    this.partial = this.partial.bind(this);\n    this.push = this.push.bind(this);\n    this.replace = this.replace.bind(this);\n    this.getSearch = this.getSearch.bind(this);\n    this.getHistory = this.getHistory.bind(this);\n    this.getLocation = this.getLocation.bind(this);\n  }\n\n  getLocationObservable() {\n    return this.locationObservable.asObservable();\n  }\n\n  getHistory() {\n    return this.history;\n  }\n\n  getSearch() {\n    return new URLSearchParams(this.history.location.search);\n  }\n\n  partial(query: Record<string, any>, replace?: boolean) {\n    const currentLocation = this.history.location;\n    const newQuery = this.getSearchObject();\n\n    for (const key in query) {\n      // removing params with null | undefined\n      if (query[key] === null || query[key] === undefined) {\n        delete newQuery[key];\n      } else {\n        newQuery[key] = query[key];\n      }\n    }\n\n    const updatedUrl = urlUtil.renderUrl(currentLocation.pathname, newQuery);\n\n    if (replace) {\n      this.history.replace(updatedUrl, this.history.location.state);\n    } else {\n      this.history.push(updatedUrl, this.history.location.state);\n    }\n  }\n\n  push(location: H.Path | H.LocationDescriptor) {\n    this.history.push(location);\n  }\n\n  replace(location: H.Path | H.LocationDescriptor) {\n    this.history.replace(location);\n  }\n\n  reload() {\n    const prevState = (this.history.location.state as any)?.routeReloadCounter;\n    this.history.replace({\n      ...this.history.location,\n      state: { routeReloadCounter: prevState ? prevState + 1 : 1 },\n    });\n  }\n\n  getLocation() {\n    return this.history.location;\n  }\n\n  getSearchObject() {\n    return locationSearchToObject(this.history.location.search);\n  }\n\n  /** @deprecated use partial, push or replace instead */\n  update(options: LocationUpdate) {\n    deprecationWarning('LocationSrv', 'update', 'partial, push or replace');\n    if (options.partial && options.query) {\n      this.partial(options.query, options.partial);\n    } else {\n      const newLocation: H.LocationDescriptor = {\n        pathname: options.path,\n      };\n      if (options.query) {\n        newLocation.search = urlUtil.toUrlParams(options.query);\n      }\n      if (options.replace) {\n        this.replace(newLocation);\n      } else {\n        this.push(newLocation);\n      }\n    }\n  }\n}\n\n/**\n * @public\n * Parses a location search string to an object\n * */\nexport function locationSearchToObject(search: string | number): UrlQueryMap {\n  let queryString = typeof search === 'number' ? String(search) : search;\n\n  if (queryString.length > 0) {\n    if (queryString.startsWith('?')) {\n      return urlUtil.parseKeyValue(queryString.substring(1));\n    }\n    return urlUtil.parseKeyValue(queryString);\n  }\n\n  return {};\n}\n\n/**\n * @public\n */\nexport let locationService: LocationService = new HistoryWrapper();\n\n/**\n * Used for tests only\n * @internal\n */\nexport const setLocationService = (location: LocationService) => {\n  if (process.env.NODE_ENV !== 'test') {\n    throw new Error('locationService can be only overriden in test environment');\n  }\n  locationService = location;\n};\n\nconst navigationLog = createLogger('Router');\n\n/** @internal */\nexport const navigationLogger = navigationLog.logger;\n\n// For debugging purposes the location service is attached to global _debug variable\nattachDebugger('location', locationService, navigationLog);\n\n// Simple context so the location service can be used without being a singleton\nconst LocationServiceContext = React.createContext<LocationService | undefined>(undefined);\n\nexport function useLocationService(): LocationService {\n  const service = useContext(LocationServiceContext);\n  if (!service) {\n    throw new Error('useLocationService must be used within a LocationServiceProvider');\n  }\n  return service;\n}\n\nexport const LocationServiceProvider: React.FC<{ service: LocationService; children: React.ReactNode }> = ({\n  service,\n  children,\n}) => {\n  return <LocationServiceContext.Provider value={service}>{children}</LocationServiceContext.Provider>;\n};\n"],"names":[],"mappings":"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"}