@grafana/scenes 6.12.0--canary.1121.15045230319.0 → 6.12.0--canary.1122.15063334499.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +10 -0
  3. package/dist/esm/components/SceneApp/SceneApp.js +2 -2
  4. package/dist/esm/components/SceneApp/SceneApp.js.map +1 -1
  5. package/dist/esm/components/SceneApp/SceneAppPage.js +18 -2
  6. package/dist/esm/components/SceneApp/SceneAppPage.js.map +1 -1
  7. package/dist/esm/components/VizPanel/VizPanel.js +2 -2
  8. package/dist/esm/components/VizPanel/VizPanel.js.map +1 -1
  9. package/dist/esm/core/SceneScopesBridge.js +93 -0
  10. package/dist/esm/core/SceneScopesBridge.js.map +1 -0
  11. package/dist/esm/core/sceneGraph/index.js +2 -2
  12. package/dist/esm/core/sceneGraph/index.js.map +1 -1
  13. package/dist/esm/core/sceneGraph/sceneGraph.js +5 -9
  14. package/dist/esm/core/sceneGraph/sceneGraph.js.map +1 -1
  15. package/dist/esm/index.js +1 -1
  16. package/dist/esm/index.js.map +1 -1
  17. package/dist/esm/querying/SceneQueryRunner.js +33 -10
  18. package/dist/esm/querying/SceneQueryRunner.js.map +1 -1
  19. package/dist/esm/variables/VariableDependencyConfig.js +1 -4
  20. package/dist/esm/variables/VariableDependencyConfig.js.map +1 -1
  21. package/dist/esm/variables/adhoc/AdHocFiltersVariable.js +18 -19
  22. package/dist/esm/variables/adhoc/AdHocFiltersVariable.js.map +1 -1
  23. package/dist/esm/variables/components/VariableValueSelectors.js +0 -3
  24. package/dist/esm/variables/components/VariableValueSelectors.js.map +1 -1
  25. package/dist/esm/variables/constants.js +1 -2
  26. package/dist/esm/variables/constants.js.map +1 -1
  27. package/dist/esm/variables/groupby/DefaultGroupByCustomIndicatorContainer.js +102 -0
  28. package/dist/esm/variables/groupby/DefaultGroupByCustomIndicatorContainer.js.map +1 -0
  29. package/dist/esm/variables/groupby/GroupByVariable.js +40 -7
  30. package/dist/esm/variables/groupby/GroupByVariable.js.map +1 -1
  31. package/dist/esm/variables/groupby/GroupByVariableUrlSyncHandler.js +31 -7
  32. package/dist/esm/variables/groupby/GroupByVariableUrlSyncHandler.js.map +1 -1
  33. package/dist/esm/variables/sets/SceneVariableSet.js +7 -10
  34. package/dist/esm/variables/sets/SceneVariableSet.js.map +1 -1
  35. package/dist/esm/variables/types.js.map +1 -1
  36. package/dist/index.d.ts +60 -56
  37. package/dist/index.js +311 -122
  38. package/dist/index.js.map +1 -1
  39. package/package.json +2 -2
  40. package/dist/esm/variables/variants/ScopesVariable.js +0 -80
  41. package/dist/esm/variables/variants/ScopesVariable.js.map +0 -1
package/dist/index.js CHANGED
@@ -1283,7 +1283,6 @@ const AUTO_VARIABLE_TEXT = "Auto";
1283
1283
  const AUTO_VARIABLE_VALUE = "$__auto";
1284
1284
  const VARIABLE_REGEX = /\$(\w+)|\[\[(\w+?)(?::(\w+))?\]\]|\${(\w+)(?:\.([^:^\}]+))?(?::([^\}]+))?}/g;
1285
1285
  const SEARCH_FILTER_VARIABLE = "__searchFilter";
1286
- const SCOPES_VARIABLE_NAME = "__scopes";
1287
1286
 
1288
1287
  const formatRegistry = new data.Registry(() => {
1289
1288
  const formats = [
@@ -2965,18 +2964,34 @@ class GroupByVariableUrlSyncHandler {
2965
2964
  return [this.getKey()];
2966
2965
  }
2967
2966
  getUrlState() {
2967
+ var _a;
2968
2968
  if (this._sceneObject.state.skipUrlSync) {
2969
2969
  return {};
2970
2970
  }
2971
- return { [this.getKey()]: toUrlValues(this._sceneObject.state.value, this._sceneObject.state.text) };
2971
+ return {
2972
+ [this.getKey()]: toUrlValues(
2973
+ this._sceneObject.state.value,
2974
+ this._sceneObject.state.text,
2975
+ (_a = this._sceneObject.state.defaultValues) == null ? void 0 : _a.value
2976
+ )
2977
+ };
2972
2978
  }
2973
2979
  updateFromUrl(values) {
2980
+ var _a, _b;
2974
2981
  let urlValue = values[this.getKey()];
2975
2982
  if (urlValue != null) {
2976
2983
  if (!this._sceneObject.isActive) {
2977
2984
  this._sceneObject.skipNextValidation = true;
2978
2985
  }
2979
- const { values: values2, texts } = fromUrlValues(urlValue);
2986
+ const { values: values2, texts, defaults } = fromUrlValues(urlValue);
2987
+ if (lodash.isEqual(values2, defaults) && this._sceneObject.state.defaultValues) {
2988
+ this._sceneObject.changeValueTo(
2989
+ (_a = this._sceneObject.state.defaultValues) == null ? void 0 : _a.value,
2990
+ (_b = this._sceneObject.state.defaultValues) == null ? void 0 : _b.text,
2991
+ false
2992
+ );
2993
+ return;
2994
+ }
2980
2995
  this._sceneObject.changeValueTo(values2, texts);
2981
2996
  }
2982
2997
  }
@@ -2989,9 +3004,10 @@ class GroupByVariableUrlSyncHandler {
2989
3004
  return this._nextChangeShouldAddHistoryStep;
2990
3005
  }
2991
3006
  }
2992
- function toUrlValues(values, texts) {
3007
+ function toUrlValues(values, texts, defaultValues) {
2993
3008
  values = Array.isArray(values) ? values : [values];
2994
3009
  texts = Array.isArray(texts) ? texts : [texts];
3010
+ const defaults = defaultValues ? Array.isArray(defaultValues) ? defaultValues : [defaultValues] : [];
2995
3011
  return values.map((value, idx) => {
2996
3012
  if (value === void 0 || value === null) {
2997
3013
  return "";
@@ -2999,21 +3015,27 @@ function toUrlValues(values, texts) {
2999
3015
  value = String(value);
3000
3016
  let text = texts[idx];
3001
3017
  text = text === void 0 || text === null ? value : String(text);
3002
- return toUrlCommaDelimitedString(value, text);
3018
+ return toUrlCommaDelimitedString(value, text) + (defaults.includes(value) ? escapeUrlPipeDelimiters("|default") : "");
3003
3019
  });
3004
3020
  }
3005
3021
  function fromUrlValues(urlValues) {
3006
3022
  urlValues = Array.isArray(urlValues) ? urlValues : [urlValues];
3007
3023
  return urlValues.reduce(
3008
3024
  (acc, urlValue) => {
3009
- const [value, label] = (urlValue != null ? urlValue : "").split(",");
3025
+ const pipeEscapedVal = /__gfp__/g[Symbol.replace](urlValue, "|");
3026
+ const [commaValues, isDefault] = (pipeEscapedVal != null ? pipeEscapedVal : "").split("|");
3027
+ const [value, label] = (commaValues != null ? commaValues : "").split(",");
3010
3028
  acc.values.push(unescapeUrlDelimiters(value));
3011
3029
  acc.texts.push(unescapeUrlDelimiters(label != null ? label : value));
3030
+ if (isDefault) {
3031
+ acc.defaults.push(value);
3032
+ }
3012
3033
  return acc;
3013
3034
  },
3014
3035
  {
3015
3036
  values: [],
3016
- texts: []
3037
+ texts: [],
3038
+ defaults: []
3017
3039
  }
3018
3040
  );
3019
3041
  }
@@ -3077,6 +3099,101 @@ function wrapInSafeSerializableSceneObject(sceneObject) {
3077
3099
  return { value: sceneObject, text: "__sceneObject" };
3078
3100
  }
3079
3101
 
3102
+ function DefaultGroupByCustomIndicatorContainer(props) {
3103
+ const { model } = props;
3104
+ const theme = ui.useTheme2();
3105
+ const styles = getStyles$h(theme);
3106
+ const inputStyles = ui.getInputStyles({ theme, invalid: false });
3107
+ const value = React.useMemo(
3108
+ () => lodash.isArray(model.state.value) ? model.state.value : model.state.value ? [model.state.value] : [],
3109
+ [model.state.value]
3110
+ );
3111
+ const isRestorable = React.useMemo(() => {
3112
+ return model.checkIfRestorable(value);
3113
+ }, [value, model]);
3114
+ let buttons = [];
3115
+ if (value && value.length) {
3116
+ buttons.push(
3117
+ /* @__PURE__ */ React__default.default.createElement(
3118
+ ui.IconButton,
3119
+ {
3120
+ "aria-label": "clear",
3121
+ key: "clear",
3122
+ name: "times",
3123
+ size: "md",
3124
+ className: styles.clearIcon,
3125
+ onClick: (e) => {
3126
+ model.changeValueTo([], void 0, true);
3127
+ }
3128
+ }
3129
+ )
3130
+ );
3131
+ }
3132
+ if (isRestorable) {
3133
+ buttons.push(
3134
+ /* @__PURE__ */ React__default.default.createElement(
3135
+ ui.IconButton,
3136
+ {
3137
+ onClick: (e) => {
3138
+ props.model.restoreDefaultValues();
3139
+ },
3140
+ onKeyDownCapture: (e) => {
3141
+ if (e.key === "Enter") {
3142
+ props.model.restoreDefaultValues();
3143
+ }
3144
+ },
3145
+ key: "restore",
3146
+ name: "history",
3147
+ size: "md",
3148
+ className: styles.clearIcon,
3149
+ tooltip: "Restore groupby set by this dashboard."
3150
+ }
3151
+ )
3152
+ );
3153
+ }
3154
+ if (!isRestorable) {
3155
+ buttons.push(
3156
+ /* @__PURE__ */ React__default.default.createElement(
3157
+ ui.Tooltip,
3158
+ {
3159
+ key: "tooltip",
3160
+ content: "Applied by default in this dashboard. If edited, it carries over to other dashboards.",
3161
+ placement: "bottom"
3162
+ },
3163
+ /* @__PURE__ */ React__default.default.createElement(ui.Icon, { name: "info-circle", size: "md" })
3164
+ )
3165
+ );
3166
+ }
3167
+ return /* @__PURE__ */ React__default.default.createElement(
3168
+ "div",
3169
+ {
3170
+ onMouseDown: (e) => {
3171
+ e.preventDefault();
3172
+ e.stopPropagation();
3173
+ },
3174
+ className: css.cx(
3175
+ inputStyles.suffix,
3176
+ css.css({
3177
+ position: "relative"
3178
+ })
3179
+ )
3180
+ },
3181
+ buttons
3182
+ );
3183
+ }
3184
+ const getStyles$h = (theme) => ({
3185
+ clearIcon: css.css({
3186
+ color: theme.colors.action.disabledText,
3187
+ cursor: "pointer",
3188
+ "&:hover:before": {
3189
+ backgroundColor: "transparent"
3190
+ },
3191
+ "&:hover": {
3192
+ color: theme.colors.text.primary
3193
+ }
3194
+ })
3195
+ });
3196
+
3080
3197
  class GroupByVariable extends MultiValueVariable {
3081
3198
  constructor(initialState) {
3082
3199
  super({
@@ -3095,11 +3212,20 @@ class GroupByVariable extends MultiValueVariable {
3095
3212
  });
3096
3213
  this.isLazy = true;
3097
3214
  this._urlSync = new GroupByVariableUrlSyncHandler(this);
3215
+ this._activationHandler = () => {
3216
+ if (this.state.defaultValues && (lodash.isArray(this.state.value) && !this.state.value.length || !this.state.value)) {
3217
+ this.setState({
3218
+ value: this.state.defaultValues.value,
3219
+ text: this.state.defaultValues.text
3220
+ });
3221
+ return;
3222
+ }
3223
+ };
3098
3224
  /**
3099
3225
  * Get possible keys given current filters. Do not call from plugins directly
3100
3226
  */
3101
3227
  this._getKeys = async (ds) => {
3102
- var _a, _b, _c;
3228
+ var _a, _b, _c, _d;
3103
3229
  const override = await ((_b = (_a = this.state).getTagKeysProvider) == null ? void 0 : _b.call(_a, this, null));
3104
3230
  if (override && override.replace) {
3105
3231
  return override.values;
@@ -3117,7 +3243,7 @@ class GroupByVariable extends MultiValueVariable {
3117
3243
  filters: otherFilters,
3118
3244
  queries,
3119
3245
  timeRange,
3120
- scopes: sceneGraph.getScopes(this),
3246
+ scopes: (_d = this._scopesBridge) == null ? void 0 : _d.getValue(),
3121
3247
  ...getEnrichedFiltersRequest(this)
3122
3248
  });
3123
3249
  if (responseHasError(response)) {
@@ -3139,6 +3265,7 @@ class GroupByVariable extends MultiValueVariable {
3139
3265
  return () => allActiveGroupByVariables.delete(this);
3140
3266
  });
3141
3267
  }
3268
+ this.addActivationHandler(this._activationHandler);
3142
3269
  }
3143
3270
  validateAndUpdate() {
3144
3271
  return this.getValueOptions({}).pipe(
@@ -3197,6 +3324,21 @@ class GroupByVariable extends MultiValueVariable {
3197
3324
  })
3198
3325
  );
3199
3326
  }
3327
+ checkIfRestorable(values) {
3328
+ var _a, _b, _c, _d;
3329
+ const originalValues = lodash.isArray((_a = this.state.defaultValues) == null ? void 0 : _a.value) ? (_b = this.state.defaultValues) == null ? void 0 : _b.value : ((_c = this.state.defaultValues) == null ? void 0 : _c.value) ? [(_d = this.state.defaultValues) == null ? void 0 : _d.value] : [];
3330
+ const vals = lodash.isArray(values) ? values : [values];
3331
+ if (vals.length !== originalValues.length) {
3332
+ return true;
3333
+ }
3334
+ return !lodash.isEqual(vals, originalValues);
3335
+ }
3336
+ restoreDefaultValues() {
3337
+ if (!this.state.defaultValues) {
3338
+ return;
3339
+ }
3340
+ this.changeValueTo(this.state.defaultValues.value, this.state.defaultValues.text, true);
3341
+ }
3200
3342
  /**
3201
3343
  * Allows clearing the value of the variable to an empty value. Overrides default behavior of a MultiValueVariable
3202
3344
  */
@@ -3215,7 +3357,8 @@ function GroupByVariableRenderer({ model }) {
3215
3357
  noValueOnClear,
3216
3358
  options,
3217
3359
  includeAll,
3218
- allowCustomValue = true
3360
+ allowCustomValue = true,
3361
+ defaultValues
3219
3362
  } = model.useState();
3220
3363
  const values = React.useMemo(() => {
3221
3364
  const arrayValue = lodash.isArray(value) ? value : [value];
@@ -3233,6 +3376,7 @@ function GroupByVariableRenderer({ model }) {
3233
3376
  const [inputValue, setInputValue] = React.useState("");
3234
3377
  const [uncommittedValue, setUncommittedValue] = React.useState(values);
3235
3378
  const optionSearcher = React.useMemo(() => getOptionSearcher(options, includeAll), [options, includeAll]);
3379
+ const hasDefaultValues = defaultValues !== void 0;
3236
3380
  React.useEffect(() => {
3237
3381
  setUncommittedValue(values);
3238
3382
  }, [values]);
@@ -3260,7 +3404,7 @@ function GroupByVariableRenderer({ model }) {
3260
3404
  "aria-label": "Group by selector",
3261
3405
  "data-testid": `GroupBySelect-${key}`,
3262
3406
  id: key,
3263
- placeholder: "Select value",
3407
+ placeholder: "Group by label",
3264
3408
  width: "auto",
3265
3409
  allowCustomValue,
3266
3410
  inputValue,
@@ -3276,7 +3420,12 @@ function GroupByVariableRenderer({ model }) {
3276
3420
  isClearable: true,
3277
3421
  hideSelectedOptions: false,
3278
3422
  isLoading: isFetchingOptions,
3279
- components: { Option: OptionWithCheckbox },
3423
+ components: {
3424
+ Option: OptionWithCheckbox,
3425
+ ...hasDefaultValues ? {
3426
+ IndicatorsContainer: () => /* @__PURE__ */ React__default.default.createElement(DefaultGroupByCustomIndicatorContainer, { model })
3427
+ } : {}
3428
+ },
3280
3429
  onInputChange,
3281
3430
  onBlur: () => {
3282
3431
  model.changeValueTo(
@@ -3307,7 +3456,7 @@ function GroupByVariableRenderer({ model }) {
3307
3456
  "aria-label": "Group by selector",
3308
3457
  "data-testid": `GroupBySelect-${key}`,
3309
3458
  id: key,
3310
- placeholder: "Select value",
3459
+ placeholder: "Group by label",
3311
3460
  width: "auto",
3312
3461
  inputValue,
3313
3462
  value: uncommittedValue && uncommittedValue.length > 0 ? uncommittedValue : null,
@@ -5351,21 +5500,25 @@ class AdHocFiltersVariable extends SceneObjectBase {
5351
5500
  // are set on construct and used to restore a baseFilter with an origin
5352
5501
  // to its original value if edited at some point
5353
5502
  this._originalValues = /* @__PURE__ */ new Map();
5354
- /** Needed for scopes dependency */
5355
- this._variableDependency = new VariableDependencyConfig(this, {
5356
- dependsOnScopes: true,
5357
- onReferencedVariableValueChanged: () => this._updateScopesFilters()
5358
- });
5359
5503
  this._urlSync = new AdHocFiltersVariableUrlSyncHandler(this);
5360
5504
  this._activationHandler = () => {
5361
- this._updateScopesFilters();
5505
+ var _a, _b;
5506
+ this._scopesBridge = sceneGraph.getScopesBridge(this);
5507
+ const scopes = (_a = this._scopesBridge) == null ? void 0 : _a.getValue();
5508
+ if (scopes) {
5509
+ this._updateScopesFilters(scopes);
5510
+ }
5511
+ const sub = (_b = this._scopesBridge) == null ? void 0 : _b.subscribeToValue((n, _) => {
5512
+ this._updateScopesFilters(n);
5513
+ });
5362
5514
  return () => {
5363
- var _a, _b;
5364
- if ((_a = this.state.baseFilters) == null ? void 0 : _a.length) {
5515
+ var _a2, _b2;
5516
+ sub == null ? void 0 : sub.unsubscribe();
5517
+ if ((_a2 = this.state.baseFilters) == null ? void 0 : _a2.length) {
5365
5518
  this.setState({
5366
5519
  baseFilters: [...this.state.baseFilters.filter((filter) => filter.origin !== "scope")]
5367
5520
  });
5368
- (_b = this.state.baseFilters) == null ? void 0 : _b.forEach((filter) => {
5521
+ (_b2 = this.state.baseFilters) == null ? void 0 : _b2.forEach((filter) => {
5369
5522
  if (filter.origin === "dashboard" && filter.restorable) {
5370
5523
  this.restoreOriginalFilter(filter);
5371
5524
  }
@@ -5387,12 +5540,8 @@ class AdHocFiltersVariable extends SceneObjectBase {
5387
5540
  });
5388
5541
  this.addActivationHandler(this._activationHandler);
5389
5542
  }
5390
- _updateScopesFilters() {
5543
+ _updateScopesFilters(scopes) {
5391
5544
  var _a, _b;
5392
- const scopes = sceneGraph.getScopes(this);
5393
- if (!scopes) {
5394
- return;
5395
- }
5396
5545
  if (!scopes.length) {
5397
5546
  this.setState({
5398
5547
  baseFilters: (_a = this.state.baseFilters) == null ? void 0 : _a.filter((filter) => filter.origin !== "scope")
@@ -5593,7 +5742,7 @@ class AdHocFiltersVariable extends SceneObjectBase {
5593
5742
  * Get possible keys given current filters. Do not call from plugins directly
5594
5743
  */
5595
5744
  async _getKeys(currentKey) {
5596
- var _a, _b, _c;
5745
+ var _a, _b, _c, _d;
5597
5746
  const override = await ((_b = (_a = this.state).getTagKeysProvider) == null ? void 0 : _b.call(_a, this, currentKey));
5598
5747
  if (override && override.replace) {
5599
5748
  return dataFromResponse(override.values).map(toSelectableValue);
@@ -5612,7 +5761,7 @@ class AdHocFiltersVariable extends SceneObjectBase {
5612
5761
  filters: otherFilters,
5613
5762
  queries,
5614
5763
  timeRange,
5615
- scopes: sceneGraph.getScopes(this),
5764
+ scopes: (_d = this._scopesBridge) == null ? void 0 : _d.getValue(),
5616
5765
  ...getEnrichedFiltersRequest(this)
5617
5766
  });
5618
5767
  if (responseHasError(response)) {
@@ -5632,7 +5781,7 @@ class AdHocFiltersVariable extends SceneObjectBase {
5632
5781
  * Get possible key values for a specific key given current filters. Do not call from plugins directly
5633
5782
  */
5634
5783
  async _getValuesFor(filter) {
5635
- var _a, _b, _c, _d;
5784
+ var _a, _b, _c, _d, _e;
5636
5785
  const override = await ((_b = (_a = this.state).getTagValuesProvider) == null ? void 0 : _b.call(_a, this, filter));
5637
5786
  if (override && override.replace) {
5638
5787
  return dataFromResponse(override.values).map(toSelectableValue);
@@ -5645,7 +5794,7 @@ class AdHocFiltersVariable extends SceneObjectBase {
5645
5794
  const otherFilters = this.state.filters.filter((f) => f.key !== filter.key).concat(filteredBaseFilters);
5646
5795
  const timeRange = sceneGraph.getTimeRange(this).state.value;
5647
5796
  const queries = this.state.useQueriesAsFilterForOptions ? getQueriesForVariables(this) : void 0;
5648
- let scopes = sceneGraph.getScopes(this);
5797
+ let scopes = (_e = this._scopesBridge) == null ? void 0 : _e.getValue();
5649
5798
  if (filter.origin === "scope") {
5650
5799
  scopes = scopes == null ? void 0 : scopes.map((scope) => {
5651
5800
  return {
@@ -5803,8 +5952,7 @@ class SceneQueryRunner extends SceneObjectBase {
5803
5952
  this._variableDependency = new VariableDependencyConfig(this, {
5804
5953
  statePaths: ["queries", "datasource", "minInterval"],
5805
5954
  onVariableUpdateCompleted: this.onVariableUpdatesCompleted.bind(this),
5806
- onAnyVariableChanged: this.onAnyVariableChanged.bind(this),
5807
- dependsOnScopes: true
5955
+ onAnyVariableChanged: this.onAnyVariableChanged.bind(this)
5808
5956
  });
5809
5957
  this.onDataReceived = (data$1) => {
5810
5958
  const preProcessedData = data.preProcessPanelData(data$1, this.state.data);
@@ -5825,6 +5973,7 @@ class SceneQueryRunner extends SceneObjectBase {
5825
5973
  _onActivate() {
5826
5974
  if (this.isQueryModeAuto()) {
5827
5975
  const timeRange = sceneGraph.getTimeRange(this);
5976
+ const scopesBridge = sceneGraph.getScopesBridge(this);
5828
5977
  const providers = this.getClosestExtraQueryProviders();
5829
5978
  for (const provider of providers) {
5830
5979
  this._subs.add(
@@ -5835,6 +5984,7 @@ class SceneQueryRunner extends SceneObjectBase {
5835
5984
  })
5836
5985
  );
5837
5986
  }
5987
+ this.subscribeToScopesChanges(scopesBridge);
5838
5988
  this.subscribeToTimeRangeChanges(timeRange);
5839
5989
  if (this.shouldRunQueriesOnActivate()) {
5840
5990
  this.runQueries();
@@ -5998,6 +6148,21 @@ class SceneQueryRunner extends SceneObjectBase {
5998
6148
  isDataReadyToDisplay() {
5999
6149
  return Boolean(this.state._hasFetchedData);
6000
6150
  }
6151
+ subscribeToScopesChanges(scopesBridge) {
6152
+ if (!scopesBridge) {
6153
+ return;
6154
+ }
6155
+ if (this._scopesSubBridge === scopesBridge) {
6156
+ return;
6157
+ }
6158
+ if (this._scopesSub) {
6159
+ this._scopesSub.unsubscribe();
6160
+ }
6161
+ this._scopesSubBridge = scopesBridge;
6162
+ this._scopesSub = scopesBridge.subscribeToValue(() => {
6163
+ this.runWithTimeRangeAndScopes(sceneGraph.getTimeRange(this), scopesBridge);
6164
+ });
6165
+ }
6001
6166
  subscribeToTimeRangeChanges(timeRange) {
6002
6167
  if (this._timeSubRange === timeRange) {
6003
6168
  return;
@@ -6007,15 +6172,17 @@ class SceneQueryRunner extends SceneObjectBase {
6007
6172
  }
6008
6173
  this._timeSubRange = timeRange;
6009
6174
  this._timeSub = timeRange.subscribeToState(() => {
6010
- this.runWithTimeRange(timeRange);
6175
+ this.runWithTimeRangeAndScopes(timeRange, sceneGraph.getScopesBridge(this));
6011
6176
  });
6012
6177
  }
6013
6178
  runQueries() {
6014
6179
  const timeRange = sceneGraph.getTimeRange(this);
6180
+ const scopesBridge = sceneGraph.getScopesBridge(this);
6015
6181
  if (this.isQueryModeAuto()) {
6016
6182
  this.subscribeToTimeRangeChanges(timeRange);
6183
+ this.subscribeToScopesChanges(scopesBridge);
6017
6184
  }
6018
- this.runWithTimeRange(timeRange);
6185
+ this.runWithTimeRangeAndScopes(timeRange, scopesBridge);
6019
6186
  }
6020
6187
  getMaxDataPoints() {
6021
6188
  var _a;
@@ -6035,8 +6202,8 @@ class SceneQueryRunner extends SceneObjectBase {
6035
6202
  data: { ...this.state.data, state: schema.LoadingState.Done }
6036
6203
  });
6037
6204
  }
6038
- async runWithTimeRange(timeRange) {
6039
- var _a, _b, _c;
6205
+ async runWithTimeRangeAndScopes(timeRange, scopesBridge) {
6206
+ var _a, _b, _c, _d;
6040
6207
  if (!this.state.maxDataPoints && this.state.maxDataPointsFromWidth && !this._containerWidth) {
6041
6208
  return;
6042
6209
  }
@@ -6049,17 +6216,22 @@ class SceneQueryRunner extends SceneObjectBase {
6049
6216
  this.setState({ data: { ...(_b = this.state.data) != null ? _b : emptyPanelData, state: schema.LoadingState.Loading } });
6050
6217
  return;
6051
6218
  }
6219
+ if ((scopesBridge == null ? void 0 : scopesBridge.isLoading()) && (scopesBridge == null ? void 0 : scopesBridge.getValue().length)) {
6220
+ writeSceneLog("SceneQueryRunner", "Scopes are in loading state, skipping query execution");
6221
+ this.setState({ data: { ...(_c = this.state.data) != null ? _c : emptyPanelData, state: schema.LoadingState.Loading } });
6222
+ return;
6223
+ }
6052
6224
  const { queries } = this.state;
6053
6225
  if (!(queries == null ? void 0 : queries.length)) {
6054
6226
  this._setNoDataState();
6055
6227
  return;
6056
6228
  }
6057
6229
  try {
6058
- const datasource = (_c = this.state.datasource) != null ? _c : findFirstDatasource(queries);
6230
+ const datasource = (_d = this.state.datasource) != null ? _d : findFirstDatasource(queries);
6059
6231
  const ds = await getDataSource(datasource, this._scopedVars);
6060
6232
  this.findAndSubscribeToAdHocFilters(ds.uid);
6061
6233
  const runRequest = runtime.getRunRequest();
6062
- const { primary, secondaries, processors } = this.prepareRequests(timeRange, ds);
6234
+ const { primary, secondaries, processors } = this.prepareRequests(timeRange, ds, scopesBridge);
6063
6235
  writeSceneLog("SceneQueryRunner", "Starting runRequest", this.state.key);
6064
6236
  let stream = runRequest(ds, primary);
6065
6237
  if (secondaries.length > 0) {
@@ -6100,7 +6272,7 @@ class SceneQueryRunner extends SceneObjectBase {
6100
6272
  clone["_results"].next({ origin: this, data: (_a = this.state.data) != null ? _a : emptyPanelData });
6101
6273
  return clone;
6102
6274
  }
6103
- prepareRequests(timeRange, ds) {
6275
+ prepareRequests(timeRange, ds, scopesBridge) {
6104
6276
  var _a, _b;
6105
6277
  const { minInterval, queries } = this.state;
6106
6278
  let request = {
@@ -6121,7 +6293,7 @@ class SceneQueryRunner extends SceneObjectBase {
6121
6293
  },
6122
6294
  cacheTimeout: this.state.cacheTimeout,
6123
6295
  queryCachingTTL: this.state.queryCachingTTL,
6124
- scopes: sceneGraph.getScopes(this),
6296
+ scopes: scopesBridge == null ? void 0 : scopesBridge.getValue(),
6125
6297
  // This asks the scene root to provide context properties like app, panel and dashboardUID
6126
6298
  ...getEnrichedDataRequest(this)
6127
6299
  };
@@ -6544,9 +6716,6 @@ class VariableDependencyConfig {
6544
6716
  this._dependencies.add(name);
6545
6717
  }
6546
6718
  }
6547
- if (this._options.dependsOnScopes) {
6548
- this._dependencies.add(SCOPES_VARIABLE_NAME);
6549
- }
6550
6719
  if (this._statePaths) {
6551
6720
  for (const path of this._statePaths) {
6552
6721
  if (path === "*") {
@@ -7075,73 +7244,87 @@ function containsSearchFilter(query) {
7075
7244
  return str.indexOf(SEARCH_FILTER_VARIABLE) > -1;
7076
7245
  }
7077
7246
 
7078
- class ScopesVariable extends SceneObjectBase {
7079
- constructor(state) {
7080
- super({
7081
- skipUrlSync: true,
7082
- loading: true,
7083
- scopes: [],
7084
- ...state,
7085
- type: "system",
7086
- name: SCOPES_VARIABLE_NAME,
7087
- hide: schema.VariableHide.hideVariable
7088
- });
7247
+ class SceneScopesBridge extends SceneObjectBase {
7248
+ constructor() {
7249
+ super(...arguments);
7089
7250
  this._renderBeforeActivation = true;
7251
+ this._contextSubject = new rxjs.BehaviorSubject(void 0);
7252
+ }
7253
+ getValue() {
7254
+ var _a, _b;
7255
+ return (_b = (_a = this.context) == null ? void 0 : _a.state.value) != null ? _b : [];
7090
7256
  }
7091
7257
  /**
7092
- * Temporary simple implementation to stringify the scopes.
7258
+ * Emits values of the selected scopes array. It emits the current value and the previous value if there is a change.
7259
+ * @param cb
7093
7260
  */
7094
- getValue(fieldPath) {
7261
+ subscribeToValue(cb) {
7262
+ return this.contextObservable.pipe(
7263
+ rxjs.map((context) => {
7264
+ var _a;
7265
+ return (_a = context == null ? void 0 : context.state.value) != null ? _a : [];
7266
+ }),
7267
+ rxjs.pairwise(),
7268
+ rxjs.filter(([prevScopes, newScopes]) => !lodash.isEqual(prevScopes, newScopes))
7269
+ ).subscribe(([prevScopes, newScopes]) => {
7270
+ cb(newScopes, prevScopes);
7271
+ });
7272
+ }
7273
+ isLoading() {
7274
+ var _a, _b;
7275
+ return (_b = (_a = this.context) == null ? void 0 : _a.state.loading) != null ? _b : false;
7276
+ }
7277
+ subscribeToLoading(cb) {
7278
+ return this.contextObservable.pipe(
7279
+ rxjs.filter((context) => !!context),
7280
+ rxjs.pairwise(),
7281
+ rxjs.map(
7282
+ ([prevContext, newContext]) => {
7283
+ var _a, _b;
7284
+ return [(_a = prevContext == null ? void 0 : prevContext.state.loading) != null ? _a : false, (_b = newContext == null ? void 0 : newContext.state.loading) != null ? _b : false];
7285
+ }
7286
+ ),
7287
+ rxjs.filter(([prevLoading, newLoading]) => prevLoading !== newLoading)
7288
+ ).subscribe(([_prevLoading, newLoading]) => {
7289
+ cb(newLoading);
7290
+ });
7291
+ }
7292
+ setEnabled(enabled) {
7095
7293
  var _a;
7096
- const scopes = (_a = this.state.scopes) != null ? _a : [];
7097
- const scopeNames = scopes.map((scope) => scope.metadata.name);
7098
- return scopeNames.join(", ");
7294
+ (_a = this.context) == null ? void 0 : _a.setEnabled(enabled);
7099
7295
  }
7100
- getScopes() {
7101
- return this.state.scopes;
7296
+ setReadOnly(readOnly) {
7297
+ var _a;
7298
+ (_a = this.context) == null ? void 0 : _a.setReadOnly(readOnly);
7102
7299
  }
7103
7300
  /**
7104
7301
  * This method is used to keep the context up to date with the scopes context received from React
7105
- * 1) Subscribes to ScopesContext state changes and synchronizes it with the variable state
7106
- * 2) Handles enable / disabling of scopes based on variable enable option.
7302
+ *
7303
+ * Its rationale is:
7304
+ * - When a new context is available, check if we have pending scopes passed from the URL
7305
+ * - If we have pending scopes, ask the new context to load them
7306
+ * - The loading should happen in a setTimeout to allow the existing context to pass its values to the URL sync handler
7307
+ * - If a new context is received, propagate it as a new value in the behavior subject
7308
+ * - If a new value is received, force a re-render to trigger the URL sync handler
7107
7309
  */
7108
- setContext(context) {
7109
- if (!context) {
7110
- return;
7111
- }
7112
- this._context = context;
7113
- const oldState = context.state;
7114
- if (this.state.enable != null) {
7115
- context.setEnabled(this.state.enable);
7310
+ updateContext(newContext) {
7311
+ var _a;
7312
+ if (this.context !== newContext || ((_a = this.context) == null ? void 0 : _a.state) !== (newContext == null ? void 0 : newContext.state)) {
7313
+ this._contextSubject.next(newContext);
7116
7314
  }
7117
- const sub = context.stateObservable.subscribe((state) => {
7118
- this.updateStateFromContext(state);
7119
- });
7120
- return () => {
7121
- sub.unsubscribe();
7122
- if (this.state.enable != null) {
7123
- context.setEnabled(oldState.enabled);
7124
- }
7125
- };
7126
7315
  }
7127
- updateStateFromContext(state) {
7128
- const loading = state.value.length === 0 ? false : state.loading;
7129
- this.setState({ scopes: state.value, loading });
7130
- if (!loading) {
7131
- this.publishEvent(new SceneVariableValueChangedEvent(this), true);
7132
- }
7316
+ get context() {
7317
+ return this._contextSubject.getValue();
7133
7318
  }
7134
- /**
7135
- * Special function that enables variables to be hidden but still render to access react contexts
7136
- */
7137
- hiddenRender() {
7138
- return /* @__PURE__ */ React__default.default.createElement(ScopesVariableRenderer, { model: this });
7319
+ get contextObservable() {
7320
+ return this._contextSubject.asObservable();
7139
7321
  }
7140
7322
  }
7141
- function ScopesVariableRenderer({ model }) {
7142
- const context = React.useContext(runtime.ScopesContext);
7323
+ SceneScopesBridge.Component = SceneScopesBridgeRenderer;
7324
+ function SceneScopesBridgeRenderer({ model }) {
7325
+ const context = runtime.useScopes();
7143
7326
  React.useEffect(() => {
7144
- return model.setContext(context);
7327
+ model.updateContext(context);
7145
7328
  }, [context, model]);
7146
7329
  return null;
7147
7330
  }
@@ -7289,12 +7472,9 @@ function findDescendents(scene, descendentType) {
7289
7472
  const targetScenes = findAllObjects(scene, isDescendentType);
7290
7473
  return targetScenes.filter(isDescendentType);
7291
7474
  }
7292
- function getScopes(sceneObject) {
7293
- const scopesVariable = lookupVariable(SCOPES_VARIABLE_NAME, sceneObject);
7294
- if (scopesVariable instanceof ScopesVariable) {
7295
- return scopesVariable.state.scopes;
7296
- }
7297
- return void 0;
7475
+ function getScopesBridge(sceneObject) {
7476
+ var _a;
7477
+ return (_a = findObject(sceneObject, (s) => s instanceof SceneScopesBridge)) != null ? _a : void 0;
7298
7478
  }
7299
7479
 
7300
7480
  const sceneGraph = {
@@ -7313,7 +7493,7 @@ const sceneGraph = {
7313
7493
  getAncestor,
7314
7494
  getQueryController,
7315
7495
  findDescendents,
7316
- getScopes
7496
+ getScopesBridge
7317
7497
  };
7318
7498
 
7319
7499
  class UniqueUrlKeyMapper {
@@ -8351,8 +8531,8 @@ class VizPanel extends SceneObjectBase {
8351
8531
  this._prevData = rawData;
8352
8532
  return this._dataWithFieldConfig;
8353
8533
  }
8354
- clone() {
8355
- return super.clone({ _pluginInstanceState: void 0, _pluginLoadError: void 0 });
8534
+ clone(withState) {
8535
+ return super.clone({ _pluginInstanceState: void 0, _pluginLoadError: void 0, ...withState });
8356
8536
  }
8357
8537
  buildPanelContext() {
8358
8538
  const sync = getCursorSyncScope(this);
@@ -9407,9 +9587,6 @@ function VariableValueSelectorsRenderer({ model }) {
9407
9587
  function VariableValueSelectWrapper({ variable, layout, showAlways, hideLabel }) {
9408
9588
  const state = useSceneObjectState(variable, { shouldActivateOrKeepAlive: true });
9409
9589
  if (state.hide === data.VariableHide.hideVariable && !showAlways) {
9410
- if (variable.hiddenRender) {
9411
- return variable.hiddenRender();
9412
- }
9413
9590
  return null;
9414
9591
  }
9415
9592
  if (layout === "vertical") {
@@ -9473,6 +9650,8 @@ function VariableValueControlRenderer({ model }) {
9473
9650
  class SceneVariableSet extends SceneObjectBase {
9474
9651
  constructor(state) {
9475
9652
  super(state);
9653
+ /** Variables that have changed in since the activation or since the first manual value change */
9654
+ this._variablesThatHaveChanged = /* @__PURE__ */ new Set();
9476
9655
  /** Variables that are scheduled to be validated and updated */
9477
9656
  this._variablesToUpdate = /* @__PURE__ */ new Set();
9478
9657
  /** Variables currently updating */
@@ -9599,8 +9778,7 @@ class SceneVariableSet extends SceneObjectBase {
9599
9778
  _updateNextBatch() {
9600
9779
  for (const variable of this._variablesToUpdate) {
9601
9780
  if (!variable.validateAndUpdate) {
9602
- console.error("Variable added to variablesToUpdate but does not have validateAndUpdate");
9603
- continue;
9781
+ throw new Error("Variable added to variablesToUpdate but does not have validateAndUpdate");
9604
9782
  }
9605
9783
  if (this._updating.has(variable)) {
9606
9784
  continue;
@@ -9656,6 +9834,7 @@ class SceneVariableSet extends SceneObjectBase {
9656
9834
  this._updateNextBatch();
9657
9835
  }
9658
9836
  _handleVariableValueChanged(variableThatChanged) {
9837
+ this._variablesThatHaveChanged.add(variableThatChanged);
9659
9838
  this._addDependentVariablesToUpdateQueue(variableThatChanged);
9660
9839
  if (!this._updating.has(variableThatChanged)) {
9661
9840
  this._updateNextBatch();
@@ -9682,10 +9861,7 @@ class SceneVariableSet extends SceneObjectBase {
9682
9861
  if (this._updating.has(otherVariable) && otherVariable.onCancel) {
9683
9862
  otherVariable.onCancel();
9684
9863
  }
9685
- if (otherVariable.validateAndUpdate) {
9686
- this._variablesToUpdate.add(otherVariable);
9687
- }
9688
- otherVariable.variableDependency.variableUpdateCompleted(variableThatChanged, true);
9864
+ this._variablesToUpdate.add(otherVariable);
9689
9865
  }
9690
9866
  }
9691
9867
  }
@@ -9697,7 +9873,8 @@ class SceneVariableSet extends SceneObjectBase {
9697
9873
  if (!this.parent) {
9698
9874
  return;
9699
9875
  }
9700
- this._traverseSceneAndNotify(this.parent, variable, true);
9876
+ this._traverseSceneAndNotify(this.parent, variable, this._variablesThatHaveChanged.has(variable));
9877
+ this._variablesThatHaveChanged.delete(variable);
9701
9878
  }
9702
9879
  /**
9703
9880
  * Recursivly walk the full scene object graph and notify all objects with dependencies that include any of changed variables
@@ -9729,9 +9906,6 @@ class SceneVariableSet extends SceneObjectBase {
9729
9906
  * For example if C depends on variable B which depends on variable A and A is loading this returns true for variable C and B.
9730
9907
  */
9731
9908
  isVariableLoadingOrWaitingToUpdate(variable) {
9732
- if (variable.state.loading) {
9733
- return true;
9734
- }
9735
9909
  if (variable.isAncestorLoading && variable.isAncestorLoading()) {
9736
9910
  return true;
9737
9911
  }
@@ -12620,8 +12794,8 @@ class SceneApp extends SceneObjectBase {
12620
12794
  }
12621
12795
  }
12622
12796
  SceneApp.Component = ({ model }) => {
12623
- const { pages } = model.useState();
12624
- return /* @__PURE__ */ React__default.default.createElement(React__default.default.Fragment, null, /* @__PURE__ */ React__default.default.createElement(SceneAppContext.Provider, { value: model }, /* @__PURE__ */ React__default.default.createElement(reactRouterDom.Routes, null, pages.map((page) => /* @__PURE__ */ React__default.default.createElement(reactRouterDom.Route, { key: page.state.url, path: page.state.routePath, element: /* @__PURE__ */ React__default.default.createElement(page.Component, { model: page }) })))));
12797
+ const { pages, scopesBridge } = model.useState();
12798
+ return /* @__PURE__ */ React__default.default.createElement(React__default.default.Fragment, null, scopesBridge && /* @__PURE__ */ React__default.default.createElement(scopesBridge.Component, { model: scopesBridge }), /* @__PURE__ */ React__default.default.createElement(SceneAppContext.Provider, { value: model }, /* @__PURE__ */ React__default.default.createElement(reactRouterDom.Routes, null, pages.map((page) => /* @__PURE__ */ React__default.default.createElement(reactRouterDom.Route, { key: page.state.url, path: page.state.routePath, element: /* @__PURE__ */ React__default.default.createElement(page.Component, { model: page }) })))));
12625
12799
  };
12626
12800
  const SceneAppContext = React.createContext(null);
12627
12801
  const sceneAppCache = /* @__PURE__ */ new Map();
@@ -12897,10 +13071,25 @@ function SceneAppDrilldownViewRender({ drilldown, parent }) {
12897
13071
  }
12898
13072
 
12899
13073
  class SceneAppPage extends SceneObjectBase {
12900
- constructor() {
12901
- super(...arguments);
13074
+ constructor(state) {
13075
+ super(state);
12902
13076
  this._sceneCache = /* @__PURE__ */ new Map();
12903
13077
  this._drilldownCache = /* @__PURE__ */ new Map();
13078
+ this._activationHandler = () => {
13079
+ if (!this.state.useScopes) {
13080
+ return;
13081
+ }
13082
+ this._scopesBridge = sceneGraph.getScopesBridge(this);
13083
+ if (!this._scopesBridge) {
13084
+ throw new Error("Use of scopes is enabled but no scopes bridge found");
13085
+ }
13086
+ this._scopesBridge.setEnabled(true);
13087
+ return () => {
13088
+ var _a;
13089
+ (_a = this._scopesBridge) == null ? void 0 : _a.setEnabled(false);
13090
+ };
13091
+ };
13092
+ this.addActivationHandler(this._activationHandler);
12904
13093
  }
12905
13094
  initializeScene(scene) {
12906
13095
  this.setState({ initializedScene: scene });
@@ -14008,6 +14197,7 @@ exports.SceneObjectUrlSyncConfig = SceneObjectUrlSyncConfig;
14008
14197
  exports.SceneQueryRunner = SceneQueryRunner;
14009
14198
  exports.SceneReactObject = SceneReactObject;
14010
14199
  exports.SceneRefreshPicker = SceneRefreshPicker;
14200
+ exports.SceneScopesBridge = SceneScopesBridge;
14011
14201
  exports.SceneTimePicker = SceneTimePicker;
14012
14202
  exports.SceneTimeRange = SceneTimeRange;
14013
14203
  exports.SceneTimeRangeCompare = SceneTimeRangeCompare;
@@ -14017,7 +14207,6 @@ exports.SceneToolbarButton = SceneToolbarButton;
14017
14207
  exports.SceneToolbarInput = SceneToolbarInput;
14018
14208
  exports.SceneVariableSet = SceneVariableSet;
14019
14209
  exports.SceneVariableValueChangedEvent = SceneVariableValueChangedEvent;
14020
- exports.ScopesVariable = ScopesVariable;
14021
14210
  exports.SplitLayout = SplitLayout;
14022
14211
  exports.TestVariable = TestVariable;
14023
14212
  exports.TextBoxVariable = TextBoxVariable;