@grafana/scenes 4.32.0 → 5.0.1--canary.793.9495294297.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,34 +2,38 @@ import { locationService } from '@grafana/runtime';
2
2
  import { SceneObjectStateChangedEvent } from '../core/events.js';
3
3
  import { writeSceneLog } from '../utils/writeSceneLog.js';
4
4
  import { UniqueUrlKeyMapper } from './UniqueUrlKeyMapper.js';
5
- import { syncStateFromUrl, isUrlValueEqual, getUrlState } from './utils.js';
5
+ import { syncStateFromUrl, getUrlState, isUrlValueEqual } from './utils.js';
6
6
 
7
+ var __accessCheck = (obj, member, msg) => {
8
+ if (!member.has(obj))
9
+ throw TypeError("Cannot " + msg);
10
+ };
11
+ var __privateGet = (obj, member, getter) => {
12
+ __accessCheck(obj, member, "read from private field");
13
+ return getter ? getter.call(obj) : member.get(obj);
14
+ };
15
+ var __privateAdd = (obj, member, value) => {
16
+ if (member.has(obj))
17
+ throw TypeError("Cannot add the same private member more than once");
18
+ member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
19
+ };
20
+ var __privateSet = (obj, member, value, setter) => {
21
+ __accessCheck(obj, member, "write to private field");
22
+ setter ? setter.call(obj, value) : member.set(obj, value);
23
+ return value;
24
+ };
25
+ var _onStateChanged, _cache, _location;
7
26
  class UrlSyncManager {
8
27
  constructor() {
9
28
  this._urlKeyMapper = new UniqueUrlKeyMapper();
10
29
  this._stateSub = null;
11
- this._locationSub = null;
12
- this._ignoreNextLocationUpdate = false;
13
- this._onLocationUpdate = (location) => {
14
- if (this._ignoreNextLocationUpdate) {
15
- this._ignoreNextLocationUpdate = false;
16
- return;
17
- }
18
- if (this._lastPath !== location.pathname) {
19
- return;
20
- }
21
- const urlParams = new URLSearchParams(location.search);
22
- this._urlKeyMapper.rebuildIndex(this._sceneRoot);
23
- syncStateFromUrl(this._sceneRoot, urlParams, this._urlKeyMapper);
24
- this._lastPath = location.pathname;
25
- };
26
- this._onStateChanged = ({ payload }) => {
30
+ this._paramsCache = new UrlParamsCache();
31
+ __privateAdd(this, _onStateChanged, ({ payload }) => {
27
32
  const changedObject = payload.changedObject;
28
33
  if (changedObject.urlSync) {
29
34
  const newUrlState = changedObject.urlSync.getUrlState();
30
35
  const searchParams = locationService.getSearch();
31
36
  const mappedUpdated = {};
32
- this._urlKeyMapper.rebuildIndex(this._sceneRoot);
33
37
  for (const [key, newUrlValue] of Object.entries(newUrlState)) {
34
38
  const uniqueKey = this._urlKeyMapper.getUniqueKey(key, changedObject);
35
39
  const currentUrlValue = searchParams.getAll(uniqueKey);
@@ -38,36 +42,32 @@ class UrlSyncManager {
38
42
  }
39
43
  }
40
44
  if (Object.keys(mappedUpdated).length > 0) {
41
- this._ignoreNextLocationUpdate = true;
45
+ writeSceneLog("UrlSyncManager", "onStateChange updating URL");
42
46
  locationService.partial(mappedUpdated, true);
47
+ this._lastLocation = locationService.getLocation();
43
48
  }
44
49
  }
45
- };
50
+ });
46
51
  }
47
52
  initSync(root) {
48
- if (!this._locationSub) {
49
- writeSceneLog("UrlSyncManager", "New location listen");
50
- this._locationSub = locationService.getHistory().listen(this._onLocationUpdate);
51
- }
53
+ var _a;
52
54
  if (this._stateSub) {
53
- writeSceneLog("UrlSyncManager", "Unregister previous scene state subscription", this._sceneRoot.state.key);
55
+ writeSceneLog("UrlSyncManager", "Unregister previous scene state subscription", (_a = this._sceneRoot) == null ? void 0 : _a.state.key);
54
56
  this._stateSub.unsubscribe();
55
57
  }
58
+ writeSceneLog("UrlSyncManager", "init", root.state.key);
56
59
  this._sceneRoot = root;
57
- this._lastPath = locationService.getLocation().pathname;
58
- this._stateSub = root.subscribeToEvent(SceneObjectStateChangedEvent, this._onStateChanged);
59
- this.syncFrom(this._sceneRoot);
60
+ this._stateSub = root.subscribeToEvent(SceneObjectStateChangedEvent, __privateGet(this, _onStateChanged));
61
+ this._urlKeyMapper.clear();
62
+ this._lastLocation = locationService.getLocation();
63
+ console.log("initSync", this._lastLocation.search);
64
+ this.handleNewObject(this._sceneRoot);
60
65
  }
61
66
  cleanUp(root) {
62
67
  if (this._sceneRoot !== root) {
63
68
  return;
64
69
  }
65
70
  writeSceneLog("UrlSyncManager", "Clean up");
66
- if (this._locationSub) {
67
- this._locationSub();
68
- writeSceneLog("UrlSyncManager", "Unregister history listen");
69
- this._locationSub = null;
70
- }
71
71
  if (this._stateSub) {
72
72
  this._stateSub.unsubscribe();
73
73
  this._stateSub = null;
@@ -78,16 +78,46 @@ class UrlSyncManager {
78
78
  this._sceneRoot.state.key === root.state.key
79
79
  );
80
80
  }
81
+ this._sceneRoot = void 0;
82
+ this._lastLocation = void 0;
83
+ }
84
+ handleNewLocation(location) {
85
+ if (!this._sceneRoot || this._lastLocation === location) {
86
+ return;
87
+ }
88
+ writeSceneLog("UrlSyncManager", "handleNewLocation");
89
+ this._lastLocation = location;
90
+ syncStateFromUrl(this._sceneRoot, this._paramsCache.getParams(), this._urlKeyMapper);
81
91
  }
82
- syncFrom(sceneObj) {
83
- const urlParams = locationService.getSearch();
84
- this._urlKeyMapper.rebuildIndex(this._sceneRoot);
85
- syncStateFromUrl(sceneObj, urlParams, this._urlKeyMapper);
92
+ handleNewObject(sceneObj) {
93
+ if (!this._sceneRoot) {
94
+ return;
95
+ }
96
+ syncStateFromUrl(sceneObj, this._paramsCache.getParams(), this._urlKeyMapper);
86
97
  }
87
98
  getUrlState(root) {
88
99
  return getUrlState(root);
89
100
  }
90
101
  }
102
+ _onStateChanged = new WeakMap();
103
+ class UrlParamsCache {
104
+ constructor() {
105
+ __privateAdd(this, _cache, void 0);
106
+ __privateAdd(this, _location, void 0);
107
+ }
108
+ getParams() {
109
+ const location = locationService.getLocation();
110
+ if (__privateGet(this, _location) === location) {
111
+ return __privateGet(this, _cache);
112
+ }
113
+ __privateSet(this, _location, location);
114
+ __privateSet(this, _cache, new URLSearchParams(location.search));
115
+ console.log("UrlParamsCache.getParams", __privateGet(this, _cache).toString());
116
+ return __privateGet(this, _cache);
117
+ }
118
+ }
119
+ _cache = new WeakMap();
120
+ _location = new WeakMap();
91
121
  let urlSyncManager;
92
122
  function getUrlSyncManager() {
93
123
  if (!urlSyncManager) {
@@ -1 +1 @@
1
- {"version":3,"file":"UrlSyncManager.js","sources":["../../../src/services/UrlSyncManager.ts"],"sourcesContent":["import { Location, UnregisterCallback } from 'history';\n\nimport { locationService } from '@grafana/runtime';\n\nimport { SceneObjectStateChangedEvent } from '../core/events';\nimport { SceneObject, SceneObjectUrlValues } from '../core/types';\nimport { writeSceneLog } from '../utils/writeSceneLog';\nimport { Unsubscribable } from 'rxjs';\nimport { UniqueUrlKeyMapper } from './UniqueUrlKeyMapper';\nimport { getUrlState, isUrlValueEqual, syncStateFromUrl } from './utils';\n\nexport interface UrlSyncManagerLike {\n initSync(root: SceneObject): void;\n cleanUp(root: SceneObject): void;\n getUrlState(root: SceneObject): SceneObjectUrlValues;\n}\n\nexport class UrlSyncManager implements UrlSyncManagerLike {\n private _urlKeyMapper = new UniqueUrlKeyMapper();\n private _sceneRoot!: SceneObject;\n private _stateSub: Unsubscribable | null = null;\n private _locationSub?: UnregisterCallback | null = null;\n private _lastPath?: string;\n private _ignoreNextLocationUpdate = false;\n\n /**\n * Updates the current scene state to match URL state.\n */\n public initSync(root: SceneObject) {\n if (!this._locationSub) {\n writeSceneLog('UrlSyncManager', 'New location listen');\n this._locationSub = locationService.getHistory().listen(this._onLocationUpdate);\n }\n\n if (this._stateSub) {\n writeSceneLog('UrlSyncManager', 'Unregister previous scene state subscription', this._sceneRoot.state.key);\n this._stateSub.unsubscribe();\n }\n\n this._sceneRoot = root;\n this._lastPath = locationService.getLocation().pathname;\n this._stateSub = root.subscribeToEvent(SceneObjectStateChangedEvent, this._onStateChanged);\n\n this.syncFrom(this._sceneRoot);\n }\n\n public cleanUp(root: SceneObject) {\n // Ignore this if we have a new or different root\n if (this._sceneRoot !== root) {\n return;\n }\n\n writeSceneLog('UrlSyncManager', 'Clean up');\n\n if (this._locationSub) {\n this._locationSub();\n writeSceneLog('UrlSyncManager', 'Unregister history listen');\n this._locationSub = null;\n }\n\n if (this._stateSub) {\n this._stateSub.unsubscribe();\n this._stateSub = null;\n writeSceneLog(\n 'UrlSyncManager',\n 'Root deactived, unsub to state',\n 'same key',\n this._sceneRoot.state.key === root.state.key\n );\n }\n }\n\n public syncFrom(sceneObj: SceneObject) {\n const urlParams = locationService.getSearch();\n // The index is always from the root\n this._urlKeyMapper.rebuildIndex(this._sceneRoot);\n syncStateFromUrl(sceneObj, urlParams, this._urlKeyMapper);\n }\n\n private _onLocationUpdate = (location: Location) => {\n if (this._ignoreNextLocationUpdate) {\n this._ignoreNextLocationUpdate = false;\n return;\n }\n\n if (this._lastPath !== location.pathname) {\n return;\n }\n\n const urlParams = new URLSearchParams(location.search);\n // Rebuild key mapper index before starting sync\n this._urlKeyMapper.rebuildIndex(this._sceneRoot);\n // Sync scene state tree from url\n syncStateFromUrl(this._sceneRoot, urlParams, this._urlKeyMapper);\n this._lastPath = location.pathname;\n };\n\n private _onStateChanged = ({ payload }: SceneObjectStateChangedEvent) => {\n const changedObject = payload.changedObject;\n\n if (changedObject.urlSync) {\n const newUrlState = changedObject.urlSync.getUrlState();\n\n const searchParams = locationService.getSearch();\n const mappedUpdated: SceneObjectUrlValues = {};\n\n this._urlKeyMapper.rebuildIndex(this._sceneRoot);\n\n for (const [key, newUrlValue] of Object.entries(newUrlState)) {\n const uniqueKey = this._urlKeyMapper.getUniqueKey(key, changedObject);\n const currentUrlValue = searchParams.getAll(uniqueKey);\n\n if (!isUrlValueEqual(currentUrlValue, newUrlValue)) {\n mappedUpdated[uniqueKey] = newUrlValue;\n }\n }\n\n if (Object.keys(mappedUpdated).length > 0) {\n this._ignoreNextLocationUpdate = true;\n locationService.partial(mappedUpdated, true);\n }\n }\n };\n\n public getUrlState(root: SceneObject): SceneObjectUrlValues {\n return getUrlState(root);\n }\n}\n\nlet urlSyncManager: UrlSyncManagerLike | undefined;\n\nexport function getUrlSyncManager(): UrlSyncManagerLike {\n if (!urlSyncManager) {\n urlSyncManager = new UrlSyncManager();\n }\n\n return urlSyncManager;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"UrlSyncManager.js","sources":["../../../src/services/UrlSyncManager.ts"],"sourcesContent":["import { Location } from 'history';\n\nimport { locationService } from '@grafana/runtime';\n\nimport { SceneObjectStateChangedEvent } from '../core/events';\nimport { SceneObject, SceneObjectUrlValues } from '../core/types';\nimport { writeSceneLog } from '../utils/writeSceneLog';\nimport { Unsubscribable } from 'rxjs';\nimport { UniqueUrlKeyMapper } from './UniqueUrlKeyMapper';\nimport { getUrlState, isUrlValueEqual, syncStateFromUrl } from './utils';\n\nexport interface UrlSyncManagerLike {\n initSync(root: SceneObject): void;\n cleanUp(root: SceneObject): void;\n getUrlState(root: SceneObject): SceneObjectUrlValues;\n handleNewLocation(location: Location): void;\n handleNewObject(sceneObj: SceneObject): void;\n}\n\nexport class UrlSyncManager implements UrlSyncManagerLike {\n private _urlKeyMapper = new UniqueUrlKeyMapper();\n private _sceneRoot?: SceneObject;\n private _stateSub: Unsubscribable | null = null;\n private _lastLocation: Location | undefined;\n private _paramsCache = new UrlParamsCache();\n\n /**\n * Updates the current scene state to match URL state.\n */\n public initSync(root: SceneObject) {\n if (this._stateSub) {\n writeSceneLog('UrlSyncManager', 'Unregister previous scene state subscription', this._sceneRoot?.state.key);\n this._stateSub.unsubscribe();\n }\n\n writeSceneLog('UrlSyncManager', 'init', root.state.key);\n\n this._sceneRoot = root;\n this._stateSub = root.subscribeToEvent(SceneObjectStateChangedEvent, this.#onStateChanged);\n\n this._urlKeyMapper.clear();\n this._lastLocation = locationService.getLocation();\n console.log('initSync', this._lastLocation.search);\n\n this.handleNewObject(this._sceneRoot);\n }\n\n public cleanUp(root: SceneObject) {\n // Ignore this if we have a new or different root\n if (this._sceneRoot !== root) {\n return;\n }\n\n writeSceneLog('UrlSyncManager', 'Clean up');\n\n if (this._stateSub) {\n this._stateSub.unsubscribe();\n this._stateSub = null;\n writeSceneLog(\n 'UrlSyncManager',\n 'Root deactived, unsub to state',\n 'same key',\n this._sceneRoot.state.key === root.state.key\n );\n }\n\n this._sceneRoot = undefined;\n this._lastLocation = undefined;\n }\n\n public handleNewLocation(location: Location) {\n if (!this._sceneRoot || this._lastLocation === location) {\n return;\n }\n\n writeSceneLog('UrlSyncManager', 'handleNewLocation');\n\n this._lastLocation = location;\n\n // Sync scene state tree from url\n syncStateFromUrl(this._sceneRoot!, this._paramsCache.getParams(), this._urlKeyMapper);\n }\n\n public handleNewObject(sceneObj: SceneObject) {\n if (!this._sceneRoot) {\n return;\n }\n\n syncStateFromUrl(sceneObj, this._paramsCache.getParams(), this._urlKeyMapper);\n }\n\n #onStateChanged = ({ payload }: SceneObjectStateChangedEvent) => {\n const changedObject = payload.changedObject;\n\n if (changedObject.urlSync) {\n const newUrlState = changedObject.urlSync.getUrlState();\n\n const searchParams = locationService.getSearch();\n const mappedUpdated: SceneObjectUrlValues = {};\n\n for (const [key, newUrlValue] of Object.entries(newUrlState)) {\n const uniqueKey = this._urlKeyMapper.getUniqueKey(key, changedObject);\n const currentUrlValue = searchParams.getAll(uniqueKey);\n\n if (!isUrlValueEqual(currentUrlValue, newUrlValue)) {\n mappedUpdated[uniqueKey] = newUrlValue;\n }\n }\n\n if (Object.keys(mappedUpdated).length > 0) {\n writeSceneLog('UrlSyncManager', 'onStateChange updating URL');\n locationService.partial(mappedUpdated, true);\n\n /// Mark the location already handled\n this._lastLocation = locationService.getLocation();\n }\n }\n };\n\n public getUrlState(root: SceneObject): SceneObjectUrlValues {\n return getUrlState(root);\n }\n}\n\nclass UrlParamsCache {\n #cache: URLSearchParams | undefined;\n #location: Location | undefined;\n\n public getParams(): URLSearchParams {\n const location = locationService.getLocation();\n\n if (this.#location === location) {\n return this.#cache!;\n }\n\n this.#location = location;\n this.#cache = new URLSearchParams(location.search);\n\n console.log('UrlParamsCache.getParams', this.#cache.toString());\n return this.#cache;\n }\n}\n\nlet urlSyncManager: UrlSyncManagerLike | undefined;\n\nexport function getUrlSyncManager(): UrlSyncManagerLike {\n if (!urlSyncManager) {\n urlSyncManager = new UrlSyncManager();\n }\n\n return urlSyncManager;\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { useState, useEffect } from 'react';
2
+ import { useLocation } from 'react-router-dom';
3
+ import { getUrlSyncManager } from './UrlSyncManager.js';
4
+ import { locationService } from '@grafana/runtime';
5
+
6
+ function useUrlSync(sceneRoot) {
7
+ const urlSyncManager = getUrlSyncManager();
8
+ const location = useLocation();
9
+ const [isInitialized, setIsInitialized] = useState(false);
10
+ useEffect(() => {
11
+ urlSyncManager.initSync(sceneRoot);
12
+ setIsInitialized(true);
13
+ return () => urlSyncManager.cleanUp(sceneRoot);
14
+ }, [sceneRoot, urlSyncManager]);
15
+ useEffect(() => {
16
+ const latestLocation = locationService.getLocation();
17
+ const locationToHandle = latestLocation !== location ? latestLocation : location;
18
+ if (latestLocation !== location) {
19
+ console.log("latestLocation different from location");
20
+ }
21
+ urlSyncManager.handleNewLocation(locationToHandle);
22
+ }, [sceneRoot, urlSyncManager, location]);
23
+ return isInitialized;
24
+ }
25
+
26
+ export { useUrlSync };
27
+ //# sourceMappingURL=useUrlSync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useUrlSync.js","sources":["../../../src/services/useUrlSync.ts"],"sourcesContent":["import { SceneObject } from '../core/types';\nimport { useEffect, useState } from 'react';\nimport { useLocation } from 'react-router-dom';\nimport { getUrlSyncManager } from './UrlSyncManager';\nimport { locationService } from '@grafana/runtime';\n\nexport function useUrlSync(sceneRoot: SceneObject): boolean {\n const urlSyncManager = getUrlSyncManager();\n const location = useLocation();\n const [isInitialized, setIsInitialized] = useState(false);\n\n useEffect(() => {\n urlSyncManager.initSync(sceneRoot);\n setIsInitialized(true);\n return () => urlSyncManager.cleanUp(sceneRoot);\n }, [sceneRoot, urlSyncManager]);\n\n useEffect(() => {\n // Use latest location, as by the time this effect runs, the location might have changed again\n const latestLocation = locationService.getLocation();\n const locationToHandle = latestLocation !== location ? latestLocation : location;\n\n if (latestLocation !== location) {\n console.log('latestLocation different from location');\n }\n\n urlSyncManager.handleNewLocation(locationToHandle);\n }, [sceneRoot, urlSyncManager, location]);\n\n return isInitialized;\n}\n\nexport interface UrlSyncContextProviderProps {\n scene: SceneObject;\n children: React.ReactNode;\n}\n"],"names":[],"mappings":";;;;;AAMO,SAAS,WAAW,SAAiC,EAAA;AAC1D,EAAA,MAAM,iBAAiB,iBAAkB,EAAA,CAAA;AACzC,EAAA,MAAM,WAAW,WAAY,EAAA,CAAA;AAC7B,EAAA,MAAM,CAAC,aAAA,EAAe,gBAAgB,CAAA,GAAI,SAAS,KAAK,CAAA,CAAA;AAExD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,cAAA,CAAe,SAAS,SAAS,CAAA,CAAA;AACjC,IAAA,gBAAA,CAAiB,IAAI,CAAA,CAAA;AACrB,IAAO,OAAA,MAAM,cAAe,CAAA,OAAA,CAAQ,SAAS,CAAA,CAAA;AAAA,GAC5C,EAAA,CAAC,SAAW,EAAA,cAAc,CAAC,CAAA,CAAA;AAE9B,EAAA,SAAA,CAAU,MAAM;AAEd,IAAM,MAAA,cAAA,GAAiB,gBAAgB,WAAY,EAAA,CAAA;AACnD,IAAM,MAAA,gBAAA,GAAmB,cAAmB,KAAA,QAAA,GAAW,cAAiB,GAAA,QAAA,CAAA;AAExE,IAAA,IAAI,mBAAmB,QAAU,EAAA;AAC/B,MAAA,OAAA,CAAQ,IAAI,wCAAwC,CAAA,CAAA;AAAA,KACtD;AAEA,IAAA,cAAA,CAAe,kBAAkB,gBAAgB,CAAA,CAAA;AAAA,GAChD,EAAA,CAAC,SAAW,EAAA,cAAA,EAAgB,QAAQ,CAAC,CAAA,CAAA;AAExC,EAAO,OAAA,aAAA,CAAA;AACT;;;;"}
@@ -3,7 +3,6 @@ import { UniqueUrlKeyMapper } from './UniqueUrlKeyMapper.js';
3
3
 
4
4
  function getUrlState(root) {
5
5
  const urlKeyMapper = new UniqueUrlKeyMapper();
6
- urlKeyMapper.rebuildIndex(root);
7
6
  const result = {};
8
7
  const visitNode = (obj) => {
9
8
  if (obj.urlSync) {
@@ -22,10 +21,18 @@ function getUrlState(root) {
22
21
  }
23
22
  function syncStateFromSearchParams(root, urlParams) {
24
23
  const urlKeyMapper = new UniqueUrlKeyMapper();
25
- urlKeyMapper.rebuildIndex(root);
26
24
  syncStateFromUrl(root, urlParams, urlKeyMapper);
27
25
  }
28
- function syncStateFromUrl(sceneObject, urlParams, urlKeyMapper) {
26
+ function syncStateFromUrl(root, urlParams, urlKeyMapper) {
27
+ if (!root.parent) {
28
+ syncUrlStateToObject(root, urlParams, urlKeyMapper);
29
+ }
30
+ root.forEachChild((child) => {
31
+ syncUrlStateToObject(child, urlParams, urlKeyMapper);
32
+ });
33
+ root.forEachChild((child) => syncStateFromUrl(child, urlParams, urlKeyMapper));
34
+ }
35
+ function syncUrlStateToObject(sceneObject, urlParams, urlKeyMapper) {
29
36
  if (sceneObject.urlSync) {
30
37
  const urlState = {};
31
38
  const currentState = sceneObject.urlSync.getUrlState();
@@ -50,7 +57,6 @@ function syncStateFromUrl(sceneObject, urlParams, urlKeyMapper) {
50
57
  sceneObject.urlSync.updateFromUrl(urlState);
51
58
  }
52
59
  }
53
- sceneObject.forEachChild((child) => syncStateFromUrl(child, urlParams, urlKeyMapper));
54
60
  }
55
61
  function isUrlValueEqual(currentUrlValue, newUrlValue) {
56
62
  if (currentUrlValue.length === 0 && newUrlValue == null) {
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sources":["../../../src/services/utils.ts"],"sourcesContent":["import { isEqual } from 'lodash';\n\nimport { SceneObject, SceneObjectUrlValue, SceneObjectUrlValues } from '../core/types';\nimport { UniqueUrlKeyMapper } from './UniqueUrlKeyMapper';\n\n/**\n * @param root\n * @returns the full scene url state as a object with keys and values\n */\nexport function getUrlState(root: SceneObject): SceneObjectUrlValues {\n const urlKeyMapper = new UniqueUrlKeyMapper();\n urlKeyMapper.rebuildIndex(root);\n\n const result: SceneObjectUrlValues = {};\n\n const visitNode = (obj: SceneObject) => {\n if (obj.urlSync) {\n const newUrlState = obj.urlSync.getUrlState();\n\n for (const [key, value] of Object.entries(newUrlState)) {\n if (value != null) {\n const uniqueKey = urlKeyMapper.getUniqueKey(key, obj);\n result[uniqueKey] = value;\n }\n }\n }\n\n obj.forEachChild(visitNode);\n };\n\n visitNode(root);\n return result;\n}\n\n/**\n * Exported util function to sync state from an initial url state.\n * Useful for initializing an embedded scenes with a url state string.\n */\nexport function syncStateFromSearchParams(root: SceneObject, urlParams: URLSearchParams) {\n const urlKeyMapper = new UniqueUrlKeyMapper();\n urlKeyMapper.rebuildIndex(root);\n syncStateFromUrl(root, urlParams, urlKeyMapper);\n}\n\nexport function syncStateFromUrl(\n sceneObject: SceneObject,\n urlParams: URLSearchParams,\n urlKeyMapper: UniqueUrlKeyMapper\n) {\n if (sceneObject.urlSync) {\n const urlState: SceneObjectUrlValues = {};\n const currentState = sceneObject.urlSync.getUrlState();\n\n for (const key of sceneObject.urlSync.getKeys()) {\n const uniqueKey = urlKeyMapper.getUniqueKey(key, sceneObject);\n const newValue = urlParams.getAll(uniqueKey);\n const currentValue = currentState[key];\n\n if (isUrlValueEqual(newValue, currentValue)) {\n continue;\n }\n\n if (newValue.length > 0) {\n if (Array.isArray(currentValue)) {\n urlState[key] = newValue;\n } else {\n urlState[key] = newValue[0];\n }\n } else {\n // mark this key as having no url state\n urlState[key] = null;\n }\n }\n\n if (Object.keys(urlState).length > 0) {\n sceneObject.urlSync.updateFromUrl(urlState);\n }\n }\n\n sceneObject.forEachChild((child) => syncStateFromUrl(child, urlParams, urlKeyMapper));\n}\n\nexport function isUrlValueEqual(currentUrlValue: string[], newUrlValue: SceneObjectUrlValue): boolean {\n if (currentUrlValue.length === 0 && newUrlValue == null) {\n return true;\n }\n\n if (!Array.isArray(newUrlValue) && currentUrlValue?.length === 1) {\n return newUrlValue === currentUrlValue[0];\n }\n\n if (newUrlValue?.length === 0 && currentUrlValue === null) {\n return true;\n }\n\n // We have two arrays, lets compare them\n return isEqual(currentUrlValue, newUrlValue);\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"utils.js","sources":["../../../src/services/utils.ts"],"sourcesContent":["import { isEqual } from 'lodash';\n\nimport { SceneObject, SceneObjectUrlValue, SceneObjectUrlValues } from '../core/types';\nimport { UniqueUrlKeyMapper } from './UniqueUrlKeyMapper';\n\n/**\n * @param root\n * @returns the full scene url state as a object with keys and values\n */\nexport function getUrlState(root: SceneObject): SceneObjectUrlValues {\n const urlKeyMapper = new UniqueUrlKeyMapper();\n const result: SceneObjectUrlValues = {};\n\n const visitNode = (obj: SceneObject) => {\n if (obj.urlSync) {\n const newUrlState = obj.urlSync.getUrlState();\n\n for (const [key, value] of Object.entries(newUrlState)) {\n if (value != null) {\n const uniqueKey = urlKeyMapper.getUniqueKey(key, obj);\n result[uniqueKey] = value;\n }\n }\n }\n\n obj.forEachChild(visitNode);\n };\n\n visitNode(root);\n return result;\n}\n\n/**\n * Exported util function to sync state from an initial url state.\n * Useful for initializing an embedded scenes with a url state string.\n */\nexport function syncStateFromSearchParams(root: SceneObject, urlParams: URLSearchParams) {\n const urlKeyMapper = new UniqueUrlKeyMapper();\n syncStateFromUrl(root, urlParams, urlKeyMapper);\n}\n\nexport function syncStateFromUrl(root: SceneObject, urlParams: URLSearchParams, urlKeyMapper: UniqueUrlKeyMapper) {\n if (!root.parent) {\n // If top level object we need to sync here\n syncUrlStateToObject(root, urlParams, urlKeyMapper);\n }\n\n // These two forEachChild loops might look strange but it's to make sure we walk through the scene graph one level at a time as url key conflicts depend depth in the scene tree\n root.forEachChild((child) => {\n syncUrlStateToObject(child, urlParams, urlKeyMapper);\n });\n\n root.forEachChild((child) => syncStateFromUrl(child, urlParams, urlKeyMapper));\n}\n\nfunction syncUrlStateToObject(sceneObject: SceneObject, urlParams: URLSearchParams, urlKeyMapper: UniqueUrlKeyMapper) {\n if (sceneObject.urlSync) {\n const urlState: SceneObjectUrlValues = {};\n const currentState = sceneObject.urlSync.getUrlState();\n\n for (const key of sceneObject.urlSync.getKeys()) {\n const uniqueKey = urlKeyMapper.getUniqueKey(key, sceneObject);\n const newValue = urlParams.getAll(uniqueKey);\n const currentValue = currentState[key];\n\n if (isUrlValueEqual(newValue, currentValue)) {\n continue;\n }\n\n if (newValue.length > 0) {\n if (Array.isArray(currentValue)) {\n urlState[key] = newValue;\n } else {\n urlState[key] = newValue[0];\n }\n } else {\n // mark this key as having no url state\n urlState[key] = null;\n }\n }\n\n if (Object.keys(urlState).length > 0) {\n sceneObject.urlSync.updateFromUrl(urlState);\n }\n }\n}\n\nexport function isUrlValueEqual(currentUrlValue: string[], newUrlValue: SceneObjectUrlValue): boolean {\n if (currentUrlValue.length === 0 && newUrlValue == null) {\n return true;\n }\n\n if (!Array.isArray(newUrlValue) && currentUrlValue?.length === 1) {\n return newUrlValue === currentUrlValue[0];\n }\n\n if (newUrlValue?.length === 0 && currentUrlValue === null) {\n return true;\n }\n\n // We have two arrays, lets compare them\n return isEqual(currentUrlValue, newUrlValue);\n}\n"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -7,6 +7,7 @@ import { Observable, Unsubscribable, MonoTypeOperatorFunction, Subscription, Rep
7
7
  import * as _grafana_schema from '@grafana/schema';
8
8
  import { VariableType, VariableHide, TimeZone, DataTopic, DataQuery, DataSourceRef, VariableRefresh, LoadingState, DashboardCursorSync, MatcherConfig, TableFieldOptions } from '@grafana/schema';
9
9
  import { VariableInterpolation } from '@grafana/runtime';
10
+ import { Location } from 'history';
10
11
  import { PanelContext, IconName } from '@grafana/ui';
11
12
  import ReactGridLayout from 'react-grid-layout';
12
13
  import { RouteComponentProps } from 'react-router-dom';
@@ -1567,26 +1568,38 @@ interface UrlSyncManagerLike {
1567
1568
  initSync(root: SceneObject): void;
1568
1569
  cleanUp(root: SceneObject): void;
1569
1570
  getUrlState(root: SceneObject): SceneObjectUrlValues;
1571
+ handleNewLocation(location: Location): void;
1572
+ handleNewObject(sceneObj: SceneObject): void;
1570
1573
  }
1571
1574
  declare class UrlSyncManager implements UrlSyncManagerLike {
1575
+ #private;
1572
1576
  private _urlKeyMapper;
1573
- private _sceneRoot;
1577
+ private _sceneRoot?;
1574
1578
  private _stateSub;
1575
- private _locationSub?;
1576
- private _lastPath?;
1577
- private _ignoreNextLocationUpdate;
1579
+ private _lastLocation;
1580
+ private _paramsCache;
1578
1581
  /**
1579
1582
  * Updates the current scene state to match URL state.
1580
1583
  */
1581
1584
  initSync(root: SceneObject): void;
1582
1585
  cleanUp(root: SceneObject): void;
1583
- syncFrom(sceneObj: SceneObject): void;
1584
- private _onLocationUpdate;
1585
- private _onStateChanged;
1586
+ handleNewLocation(location: Location): void;
1587
+ handleNewObject(sceneObj: SceneObject): void;
1586
1588
  getUrlState(root: SceneObject): SceneObjectUrlValues;
1587
1589
  }
1588
1590
  declare function getUrlSyncManager(): UrlSyncManagerLike;
1589
1591
 
1592
+ declare function useUrlSync(sceneRoot: SceneObject): boolean;
1593
+
1594
+ interface UrlSyncContextProviderProps {
1595
+ scene: SceneObject;
1596
+ children: React.ReactNode;
1597
+ }
1598
+ /**
1599
+ * Right now this is actually not defining a context, but think it might in the future (with UrlSyncManager as the context value)
1600
+ */
1601
+ declare function UrlSyncContextProvider({ children, scene }: UrlSyncContextProviderProps): React$1.ReactNode;
1602
+
1590
1603
  interface EmbeddedSceneState extends SceneObjectState {
1591
1604
  /**
1592
1605
  * The main content of the scene (usually a SceneFlexLayout)
@@ -1600,13 +1613,6 @@ interface EmbeddedSceneState extends SceneObjectState {
1600
1613
  declare class EmbeddedScene extends SceneObjectBase<EmbeddedSceneState> {
1601
1614
  static Component: typeof EmbeddedSceneRenderer;
1602
1615
  constructor(state: EmbeddedSceneState);
1603
- /**
1604
- * initUrlSync should be called before the scene is rendered to ensure that objects are in sync
1605
- * before they get activated. This saves some unnecessary re-renders and makes sure variables
1606
- * queries are issued as needed. If your using SceneAppPage you will not need to call this as
1607
- * url sync is handled on the SceneAppPage level not this level.
1608
- */
1609
- initUrlSync(): void;
1610
1616
  }
1611
1617
  declare function EmbeddedSceneRenderer({ model }: SceneComponentProps<EmbeddedScene>): React__default.JSX.Element;
1612
1618
 
@@ -2643,4 +2649,4 @@ declare const sceneUtils: {
2643
2649
  isGroupByVariable: typeof isGroupByVariable;
2644
2650
  };
2645
2651
 
2646
- export { AdHocFiltersVariable, CancelActivationHandler, ConstantVariable, ControlsLayout, CustomFormatterVariable, CustomTransformOperator, CustomTransformerDefinition, CustomVariable, CustomVariableValue, DataLayerFilter, DataRequestEnricher, DataSourceVariable, DeepPartial, EmbeddedScene, EmbeddedSceneState, ExtraQueryDataProcessor, ExtraQueryDescriptor, ExtraQueryProvider, FieldConfigBuilder, FieldConfigBuilders, FieldConfigOverridesBuilder, FiltersRequestEnricher, FormatVariable, GroupByVariable, InterpolationFormatParameter, IntervalVariable, LocalValueVariable, MacroVariableConstructor, MultiValueVariable, MultiValueVariableState, NestedScene, PanelBuilders, PanelOptionsBuilders, QueryRunnerState, QueryVariable, RuntimeDataSource, SceneActivationHandler, SceneApp, SceneAppDrilldownView, SceneAppPage, SceneAppPageLike, SceneAppPageState, SceneAppRoute, SceneByFrameRepeater, SceneByVariableRepeater, SceneCSSGridItem, SceneCSSGridLayout, SceneCanvasText, SceneComponent, SceneComponentProps, SceneControlsSpacer, SceneDataLayerBase, SceneDataLayerControls, SceneDataLayerProvider, SceneDataLayerProviderState, SceneDataLayerSet, SceneDataLayerSetBase, SceneDataNode, SceneDataProvider, SceneDataProviderResult, SceneDataQuery, SceneDataState, SceneDataTransformer, SceneDeactivationHandler, SceneDebugger, SceneFlexItem, SceneFlexItemLike, SceneFlexItemState, SceneFlexLayout, SceneGridItem, SceneGridItemLike, SceneGridItemStateLike, SceneGridLayout, SceneGridRow, SceneLayout, SceneLayoutChildOptions, SceneLayoutState, SceneObject, SceneObjectBase, SceneObjectRef, SceneObjectState, SceneObjectStateChangedEvent, SceneObjectStateChangedPayload, SceneObjectUrlSyncConfig, SceneObjectUrlSyncHandler, SceneObjectUrlValue, SceneObjectUrlValues, SceneObjectWithUrlSync, SceneQueryControllerEntry, SceneQueryControllerEntryType, SceneQueryControllerLike, SceneQueryRunner, SceneReactObject, SceneRefreshPicker, SceneRefreshPickerState, SceneRouteMatch, SceneStateChangedHandler, SceneStatelessBehavior, SceneTimePicker, SceneTimeRange, SceneTimeRangeCompare, SceneTimeRangeLike, SceneTimeRangeState, SceneTimeRangeTransformerBase, SceneTimeZoneOverride, SceneToolbarButton, SceneToolbarInput, SceneVariable, SceneVariableDependencyConfigLike, SceneVariableSet, SceneVariableSetState, SceneVariableState, SceneVariableValueChangedEvent, SceneVariables, SplitLayout, TestVariable, TextBoxVariable, UrlSyncManager, UrlSyncManagerLike, UseStateHookOptions, UserActionEvent, ValidateAndUpdateResult, VariableCustomFormatterFn, VariableDependencyConfig, VariableGetOptionsArgs, VariableValue, VariableValueControl, VariableValueOption, VariableValueSelectWrapper, VariableValueSelectors, VariableValueSingle, VizConfig, VizConfigBuilder, VizConfigBuilders, VizPanel, VizPanelBuilder, VizPanelMenu, VizPanelState, index$1 as behaviors, index as dataLayers, formatRegistry, getUrlSyncManager, isCustomVariableValue, isDataLayer, isDataRequestEnricher, isFiltersRequestEnricher, isSceneObject, registerQueryWithController, registerRuntimeDataSource, renderSelectForVariable, sceneGraph, sceneUtils, useSceneApp, useSceneObjectState };
2652
+ export { AdHocFiltersVariable, CancelActivationHandler, ConstantVariable, ControlsLayout, CustomFormatterVariable, CustomTransformOperator, CustomTransformerDefinition, CustomVariable, CustomVariableValue, DataLayerFilter, DataRequestEnricher, DataSourceVariable, DeepPartial, EmbeddedScene, EmbeddedSceneState, ExtraQueryDataProcessor, ExtraQueryDescriptor, ExtraQueryProvider, FieldConfigBuilder, FieldConfigBuilders, FieldConfigOverridesBuilder, FiltersRequestEnricher, FormatVariable, GroupByVariable, InterpolationFormatParameter, IntervalVariable, LocalValueVariable, MacroVariableConstructor, MultiValueVariable, MultiValueVariableState, NestedScene, PanelBuilders, PanelOptionsBuilders, QueryRunnerState, QueryVariable, RuntimeDataSource, SceneActivationHandler, SceneApp, SceneAppDrilldownView, SceneAppPage, SceneAppPageLike, SceneAppPageState, SceneAppRoute, SceneByFrameRepeater, SceneByVariableRepeater, SceneCSSGridItem, SceneCSSGridLayout, SceneCanvasText, SceneComponent, SceneComponentProps, SceneControlsSpacer, SceneDataLayerBase, SceneDataLayerControls, SceneDataLayerProvider, SceneDataLayerProviderState, SceneDataLayerSet, SceneDataLayerSetBase, SceneDataNode, SceneDataProvider, SceneDataProviderResult, SceneDataQuery, SceneDataState, SceneDataTransformer, SceneDeactivationHandler, SceneDebugger, SceneFlexItem, SceneFlexItemLike, SceneFlexItemState, SceneFlexLayout, SceneGridItem, SceneGridItemLike, SceneGridItemStateLike, SceneGridLayout, SceneGridRow, SceneLayout, SceneLayoutChildOptions, SceneLayoutState, SceneObject, SceneObjectBase, SceneObjectRef, SceneObjectState, SceneObjectStateChangedEvent, SceneObjectStateChangedPayload, SceneObjectUrlSyncConfig, SceneObjectUrlSyncHandler, SceneObjectUrlValue, SceneObjectUrlValues, SceneObjectWithUrlSync, SceneQueryControllerEntry, SceneQueryControllerEntryType, SceneQueryControllerLike, SceneQueryRunner, SceneReactObject, SceneRefreshPicker, SceneRefreshPickerState, SceneRouteMatch, SceneStateChangedHandler, SceneStatelessBehavior, SceneTimePicker, SceneTimeRange, SceneTimeRangeCompare, SceneTimeRangeLike, SceneTimeRangeState, SceneTimeRangeTransformerBase, SceneTimeZoneOverride, SceneToolbarButton, SceneToolbarInput, SceneVariable, SceneVariableDependencyConfigLike, SceneVariableSet, SceneVariableSetState, SceneVariableState, SceneVariableValueChangedEvent, SceneVariables, SplitLayout, TestVariable, TextBoxVariable, UrlSyncContextProvider, UrlSyncManager, UrlSyncManagerLike, UseStateHookOptions, UserActionEvent, ValidateAndUpdateResult, VariableCustomFormatterFn, VariableDependencyConfig, VariableGetOptionsArgs, VariableValue, VariableValueControl, VariableValueOption, VariableValueSelectWrapper, VariableValueSelectors, VariableValueSingle, VizConfig, VizConfigBuilder, VizConfigBuilders, VizPanel, VizPanelBuilder, VizPanelMenu, VizPanelState, index$1 as behaviors, index as dataLayers, formatRegistry, getUrlSyncManager, isCustomVariableValue, isDataLayer, isDataRequestEnricher, isFiltersRequestEnricher, isSceneObject, registerQueryWithController, registerRuntimeDataSource, renderSelectForVariable, sceneGraph, sceneUtils, useSceneApp, useSceneObjectState, useUrlSync };