@grafana/scenes 4.26.2--canary.770.9388861265.0 → 4.26.3--canary.765.9397990341.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/esm/components/EmbeddedScene.js +0 -5
  3. package/dist/esm/components/EmbeddedScene.js.map +1 -1
  4. package/dist/esm/components/SceneApp/SceneAppPage.js +0 -5
  5. package/dist/esm/components/SceneApp/SceneAppPage.js.map +1 -1
  6. package/dist/esm/components/SceneApp/SceneAppPageView.js +3 -1
  7. package/dist/esm/components/SceneApp/SceneAppPageView.js.map +1 -1
  8. package/dist/esm/index.js +2 -0
  9. package/dist/esm/index.js.map +1 -1
  10. package/dist/esm/querying/SceneQueryRunner.js +1 -0
  11. package/dist/esm/querying/SceneQueryRunner.js.map +1 -1
  12. package/dist/esm/services/UniqueUrlKeyMapper.js +20 -16
  13. package/dist/esm/services/UniqueUrlKeyMapper.js.map +1 -1
  14. package/dist/esm/services/UrlSyncContextProvider.js +12 -0
  15. package/dist/esm/services/UrlSyncContextProvider.js.map +1 -0
  16. package/dist/esm/services/UrlSyncManager.js +27 -30
  17. package/dist/esm/services/UrlSyncManager.js.map +1 -1
  18. package/dist/esm/services/useUrlSync.js +21 -0
  19. package/dist/esm/services/useUrlSync.js.map +1 -0
  20. package/dist/esm/services/utils.js +10 -4
  21. package/dist/esm/services/utils.js.map +1 -1
  22. package/dist/esm/variables/components/VariableValueSelect.js +5 -6
  23. package/dist/esm/variables/components/VariableValueSelect.js.map +1 -1
  24. package/dist/esm/variables/interpolation/sceneInterpolator.js +3 -3
  25. package/dist/esm/variables/interpolation/sceneInterpolator.js.map +1 -1
  26. package/dist/index.d.ts +20 -13
  27. package/dist/index.js +93 -68
  28. package/dist/index.js.map +1 -1
  29. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -591,39 +591,42 @@ class UniqueUrlKeyMapper {
591
591
  this.index = /* @__PURE__ */ new Map();
592
592
  }
593
593
  getUniqueKey(key, obj) {
594
- const objectsWithKey = this.index.get(key);
594
+ let objectsWithKey = this.index.get(key);
595
595
  if (!objectsWithKey) {
596
- throw new Error("Cannot find any scene object that uses the key '" + key + "'");
596
+ this.index.set(key, [obj]);
597
+ return key;
598
+ }
599
+ let address = objectsWithKey.findIndex((o) => o === obj);
600
+ if (address === -1) {
601
+ objectsWithKey = filterOutDeadObjects(objectsWithKey);
602
+ objectsWithKey.push(obj);
603
+ address = objectsWithKey.length - 1;
597
604
  }
598
- const address = objectsWithKey.findIndex((o) => o.sceneObject === obj);
599
605
  if (address > 0) {
600
606
  return `${key}-${address + 1}`;
601
607
  }
602
608
  return key;
603
609
  }
604
- rebuildIndex(root) {
610
+ clear() {
605
611
  this.index.clear();
606
- this.buildIndex(root, 0);
607
- }
608
- buildIndex(sceneObject, depth) {
609
- if (sceneObject.urlSync) {
610
- for (const key of sceneObject.urlSync.getKeys()) {
611
- const hit = this.index.get(key);
612
- if (hit) {
613
- hit.push({ sceneObject, depth });
614
- hit.sort((a, b) => a.depth - b.depth);
615
- } else {
616
- this.index.set(key, [{ sceneObject, depth }]);
612
+ }
613
+ }
614
+ function filterOutDeadObjects(sceneObjects) {
615
+ const filtered = [];
616
+ for (const obj of sceneObjects) {
617
+ if (obj.parent) {
618
+ obj.parent.forEachChild((child) => {
619
+ if (child === obj) {
620
+ filtered.push(child);
617
621
  }
618
- }
622
+ });
619
623
  }
620
- sceneObject.forEachChild((child) => this.buildIndex(child, depth + 1));
621
624
  }
625
+ return filtered;
622
626
  }
623
627
 
624
628
  function getUrlState(root) {
625
629
  const urlKeyMapper = new UniqueUrlKeyMapper();
626
- urlKeyMapper.rebuildIndex(root);
627
630
  const result = {};
628
631
  const visitNode = (obj) => {
629
632
  if (obj.urlSync) {
@@ -642,10 +645,18 @@ function getUrlState(root) {
642
645
  }
643
646
  function syncStateFromSearchParams(root, urlParams) {
644
647
  const urlKeyMapper = new UniqueUrlKeyMapper();
645
- urlKeyMapper.rebuildIndex(root);
646
648
  syncStateFromUrl(root, urlParams, urlKeyMapper);
647
649
  }
648
- function syncStateFromUrl(sceneObject, urlParams, urlKeyMapper) {
650
+ function syncStateFromUrl(root, urlParams, urlKeyMapper) {
651
+ if (!root.parent) {
652
+ syncUrlStateToObject(root, urlParams, urlKeyMapper);
653
+ }
654
+ root.forEachChild((child) => {
655
+ syncUrlStateToObject(child, urlParams, urlKeyMapper);
656
+ });
657
+ root.forEachChild((child) => syncStateFromUrl(child, urlParams, urlKeyMapper));
658
+ }
659
+ function syncUrlStateToObject(sceneObject, urlParams, urlKeyMapper) {
649
660
  if (sceneObject.urlSync) {
650
661
  const urlState = {};
651
662
  const currentState = sceneObject.urlSync.getUrlState();
@@ -670,7 +681,6 @@ function syncStateFromUrl(sceneObject, urlParams, urlKeyMapper) {
670
681
  sceneObject.urlSync.updateFromUrl(urlState);
671
682
  }
672
683
  }
673
- sceneObject.forEachChild((child) => syncStateFromUrl(child, urlParams, urlKeyMapper));
674
684
  }
675
685
  function isUrlValueEqual(currentUrlValue, newUrlValue) {
676
686
  if (currentUrlValue.length === 0 && newUrlValue == null) {
@@ -1347,7 +1357,7 @@ function sceneInterpolator(sceneObject, target, scopedVars, format, interpolatio
1347
1357
  }
1348
1358
  return match;
1349
1359
  }
1350
- const value = formatValue(variable, variable.getValue(fieldPath), fmt);
1360
+ const value = formatValue(sceneObject, variable, variable.getValue(fieldPath), fmt);
1351
1361
  if (interpolations) {
1352
1362
  interpolations.push({ match, variableName, fieldPath, format: fmt, value, found: value !== match });
1353
1363
  }
@@ -1368,12 +1378,12 @@ function lookupFormatVariable(name, match, scopedVars, sceneObject) {
1368
1378
  }
1369
1379
  return null;
1370
1380
  }
1371
- function formatValue(variable, value, formatNameOrFn) {
1381
+ function formatValue(context, variable, value, formatNameOrFn) {
1372
1382
  if (value === null || value === void 0) {
1373
1383
  return "";
1374
1384
  }
1375
1385
  if (isCustomVariableValue(value)) {
1376
- return value.formatter(formatNameOrFn);
1386
+ return sceneInterpolator(context, value.formatter(formatNameOrFn));
1377
1387
  }
1378
1388
  if (!Array.isArray(value) && typeof value === "object") {
1379
1389
  value = `${value}`;
@@ -2959,7 +2969,6 @@ const OptionWithCheckbox = ({
2959
2969
  isSelected,
2960
2970
  renderOptionLabel
2961
2971
  }) => {
2962
- var _b;
2963
2972
  const _a = innerProps, rest = __objRest$3(_a, ["onMouseMove", "onMouseOver"]);
2964
2973
  const theme = ui.useTheme2();
2965
2974
  const selectStyles = ui.getSelectStyles(theme);
@@ -2968,17 +2977,17 @@ const OptionWithCheckbox = ({
2968
2977
  ref: innerRef,
2969
2978
  className: css.cx(selectStyles.option, isFocused && selectStyles.optionFocused)
2970
2979
  }, rest), {
2971
- "data-testid": e2eSelectors.selectors.components.Select.option,
2980
+ "aria-label": "Select option",
2981
+ "data-testid": e2eSelectors.selectors.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts(
2982
+ data.label || String(data.value)
2983
+ ),
2972
2984
  title: data.title
2973
2985
  }), /* @__PURE__ */ React__default["default"].createElement("div", {
2974
2986
  className: optionStyles.checkbox
2975
2987
  }, /* @__PURE__ */ React__default["default"].createElement(ui.Checkbox, {
2976
2988
  value: isSelected
2977
2989
  })), /* @__PURE__ */ React__default["default"].createElement("div", {
2978
- className: selectStyles.optionBody,
2979
- "data-testid": e2eSelectors.selectors.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts(
2980
- (_b = data.label) != null ? _b : String(data.value)
2981
- )
2990
+ className: selectStyles.optionBody
2982
2991
  }, /* @__PURE__ */ React__default["default"].createElement("span", null, children)));
2983
2992
  };
2984
2993
  OptionWithCheckbox.displayName = "SelectMenuOptions";
@@ -4124,6 +4133,7 @@ class SceneQueryRunner extends SceneObjectBase {
4124
4133
  (_a = this._querySub) == null ? void 0 : _a.unsubscribe();
4125
4134
  if (this._variableDependency.hasDependencyInLoadingState()) {
4126
4135
  writeSceneLog("SceneQueryRunner", "Variable dependency is in loading state, skipping query execution");
4136
+ this.setState({ data: __spreadProps$l(__spreadValues$x({}, this.state.data), { state: schema.LoadingState.Loading }) });
4127
4137
  return;
4128
4138
  }
4129
4139
  const { queries } = this.state;
@@ -7720,28 +7730,12 @@ class UrlSyncManager {
7720
7730
  constructor() {
7721
7731
  this._urlKeyMapper = new UniqueUrlKeyMapper();
7722
7732
  this._stateSub = null;
7723
- this._locationSub = null;
7724
- this._ignoreNextLocationUpdate = false;
7725
- this._onLocationUpdate = (location) => {
7726
- if (this._ignoreNextLocationUpdate) {
7727
- this._ignoreNextLocationUpdate = false;
7728
- return;
7729
- }
7730
- if (this._lastPath !== location.pathname) {
7731
- return;
7732
- }
7733
- const urlParams = new URLSearchParams(location.search);
7734
- this._urlKeyMapper.rebuildIndex(this._sceneRoot);
7735
- syncStateFromUrl(this._sceneRoot, urlParams, this._urlKeyMapper);
7736
- this._lastPath = location.pathname;
7737
- };
7738
7733
  this._onStateChanged = ({ payload }) => {
7739
7734
  const changedObject = payload.changedObject;
7740
7735
  if (changedObject.urlSync) {
7741
7736
  const newUrlState = changedObject.urlSync.getUrlState();
7742
7737
  const searchParams = runtime.locationService.getSearch();
7743
7738
  const mappedUpdated = {};
7744
- this._urlKeyMapper.rebuildIndex(this._sceneRoot);
7745
7739
  for (const [key, newUrlValue] of Object.entries(newUrlState)) {
7746
7740
  const uniqueKey = this._urlKeyMapper.getUniqueKey(key, changedObject);
7747
7741
  const currentUrlValue = searchParams.getAll(uniqueKey);
@@ -7750,24 +7744,26 @@ class UrlSyncManager {
7750
7744
  }
7751
7745
  }
7752
7746
  if (Object.keys(mappedUpdated).length > 0) {
7753
- this._ignoreNextLocationUpdate = true;
7747
+ writeSceneLog("UrlSyncManager", "onStateChange updating URL");
7754
7748
  runtime.locationService.partial(mappedUpdated, true);
7749
+ this._lastLocation = runtime.locationService.getLocation();
7755
7750
  }
7756
7751
  }
7757
7752
  };
7758
7753
  }
7759
7754
  initSync(root) {
7760
- if (!this._locationSub) {
7761
- writeSceneLog("UrlSyncManager", "New location listen");
7762
- this._locationSub = runtime.locationService.getHistory().listen(this._onLocationUpdate);
7763
- }
7755
+ var _a;
7764
7756
  if (this._stateSub) {
7765
- writeSceneLog("UrlSyncManager", "Unregister previous scene state subscription", this._sceneRoot.state.key);
7757
+ writeSceneLog("UrlSyncManager", "Unregister previous scene state subscription", (_a = this._sceneRoot) == null ? void 0 : _a.state.key);
7766
7758
  this._stateSub.unsubscribe();
7767
7759
  }
7760
+ writeSceneLog("UrlSyncManager", "init", root.state.key);
7761
+ const location = runtime.locationService.getLocation();
7768
7762
  this._sceneRoot = root;
7769
- this._lastPath = runtime.locationService.getLocation().pathname;
7763
+ this._lastLocation = location;
7764
+ this._urlParams = new URLSearchParams(location.search);
7770
7765
  this._stateSub = root.subscribeToEvent(SceneObjectStateChangedEvent, this._onStateChanged);
7766
+ this._urlKeyMapper.clear();
7771
7767
  this.syncFrom(this._sceneRoot);
7772
7768
  }
7773
7769
  cleanUp(root) {
@@ -7775,11 +7771,6 @@ class UrlSyncManager {
7775
7771
  return;
7776
7772
  }
7777
7773
  writeSceneLog("UrlSyncManager", "Clean up");
7778
- if (this._locationSub) {
7779
- this._locationSub();
7780
- writeSceneLog("UrlSyncManager", "Unregister history listen");
7781
- this._locationSub = null;
7782
- }
7783
7774
  if (this._stateSub) {
7784
7775
  this._stateSub.unsubscribe();
7785
7776
  this._stateSub = null;
@@ -7790,12 +7781,28 @@ class UrlSyncManager {
7790
7781
  this._sceneRoot.state.key === root.state.key
7791
7782
  );
7792
7783
  }
7784
+ this._sceneRoot = void 0;
7785
+ this._urlParams = void 0;
7793
7786
  }
7794
7787
  syncFrom(sceneObj) {
7795
7788
  const urlParams = runtime.locationService.getSearch();
7796
- this._urlKeyMapper.rebuildIndex(this._sceneRoot);
7797
7789
  syncStateFromUrl(sceneObj, urlParams, this._urlKeyMapper);
7798
7790
  }
7791
+ handleNewLocation(location) {
7792
+ if (!this._sceneRoot || this._lastLocation === location) {
7793
+ return;
7794
+ }
7795
+ writeSceneLog("UrlSyncManager", "handleNewLocation");
7796
+ this._urlParams = new URLSearchParams(location.search);
7797
+ this._lastLocation = location;
7798
+ syncStateFromUrl(this._sceneRoot, this._urlParams, this._urlKeyMapper);
7799
+ }
7800
+ handleNewObject(sceneObj) {
7801
+ if (!this._sceneRoot || !this._urlParams) {
7802
+ return;
7803
+ }
7804
+ syncStateFromUrl(sceneObj, this._urlParams, this._urlKeyMapper);
7805
+ }
7799
7806
  getUrlState(root) {
7800
7807
  return getUrlState(root);
7801
7808
  }
@@ -7808,6 +7815,29 @@ function getUrlSyncManager() {
7808
7815
  return urlSyncManager;
7809
7816
  }
7810
7817
 
7818
+ function useUrlSync(sceneRoot) {
7819
+ const urlSyncManager = getUrlSyncManager();
7820
+ const location = reactRouterDom.useLocation();
7821
+ const [isInitialized, setIsInitialized] = React.useState(false);
7822
+ React.useEffect(() => {
7823
+ urlSyncManager.initSync(sceneRoot);
7824
+ setIsInitialized(true);
7825
+ return () => urlSyncManager.cleanUp(sceneRoot);
7826
+ }, [sceneRoot, urlSyncManager]);
7827
+ React.useEffect(() => {
7828
+ urlSyncManager.handleNewLocation(location);
7829
+ }, [sceneRoot, urlSyncManager, location]);
7830
+ return isInitialized;
7831
+ }
7832
+
7833
+ function UrlSyncContextProvider({ children, scene }) {
7834
+ const isInitialized = useUrlSync(scene);
7835
+ if (!isInitialized) {
7836
+ return null;
7837
+ }
7838
+ return children;
7839
+ }
7840
+
7811
7841
  function setWindowGrafanaSceneContext(activeScene) {
7812
7842
  const prevScene = window.__grafanaSceneContext;
7813
7843
  writeSceneLog("setWindowGrafanaScene", "set window.__grafanaSceneContext", activeScene);
@@ -7827,13 +7857,9 @@ class EmbeddedScene extends SceneObjectBase {
7827
7857
  const unsetGlobalScene = setWindowGrafanaSceneContext(this);
7828
7858
  return () => {
7829
7859
  unsetGlobalScene();
7830
- getUrlSyncManager().cleanUp(this);
7831
7860
  };
7832
7861
  });
7833
7862
  }
7834
- initUrlSync() {
7835
- getUrlSyncManager().initSync(this);
7836
- }
7837
7863
  }
7838
7864
  EmbeddedScene.Component = EmbeddedSceneRenderer;
7839
7865
  function EmbeddedSceneRenderer({ model }) {
@@ -10306,7 +10332,8 @@ function SceneAppPageView({ page, routeProps }) {
10306
10332
  React.useEffect(() => {
10307
10333
  return () => containerPage.setState({ initializedScene: void 0 });
10308
10334
  }, [containerPage]);
10309
- if (!isInitialized) {
10335
+ const urlSyncInitialized = useUrlSync(containerPage);
10336
+ if (!isInitialized && !urlSyncInitialized) {
10310
10337
  return null;
10311
10338
  }
10312
10339
  const pageNav = {
@@ -10379,13 +10406,9 @@ class SceneAppPage extends SceneObjectBase {
10379
10406
  super(state);
10380
10407
  this._sceneCache = /* @__PURE__ */ new Map();
10381
10408
  this._drilldownCache = /* @__PURE__ */ new Map();
10382
- this.addActivationHandler(() => {
10383
- return () => getUrlSyncManager().cleanUp(this);
10384
- });
10385
10409
  }
10386
10410
  initializeScene(scene) {
10387
10411
  this.setState({ initializedScene: scene });
10388
- getUrlSyncManager().initSync(this);
10389
10412
  }
10390
10413
  getScene(routeMatch) {
10391
10414
  let scene = this._sceneCache.get(routeMatch.url);
@@ -11380,6 +11403,7 @@ exports.SceneVariableValueChangedEvent = SceneVariableValueChangedEvent;
11380
11403
  exports.SplitLayout = SplitLayout;
11381
11404
  exports.TestVariable = TestVariable;
11382
11405
  exports.TextBoxVariable = TextBoxVariable;
11406
+ exports.UrlSyncContextProvider = UrlSyncContextProvider;
11383
11407
  exports.UrlSyncManager = UrlSyncManager;
11384
11408
  exports.UserActionEvent = UserActionEvent;
11385
11409
  exports.VariableDependencyConfig = VariableDependencyConfig;
@@ -11405,4 +11429,5 @@ exports.sceneGraph = sceneGraph;
11405
11429
  exports.sceneUtils = sceneUtils;
11406
11430
  exports.useSceneApp = useSceneApp;
11407
11431
  exports.useSceneObjectState = useSceneObjectState;
11432
+ exports.useUrlSync = useUrlSync;
11408
11433
  //# sourceMappingURL=index.js.map