@grafana/scenes 6.19.0 → 6.20.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.
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sources":["../../../src/variables/utils.ts"],"sourcesContent":["import { isEqual } from 'lodash';\nimport { VariableValue } from './types';\nimport { AdHocVariableFilter, DataQueryError, GetTagResponse, MetricFindValue, SelectableValue } from '@grafana/data';\nimport { sceneGraph } from '../core/sceneGraph';\nimport { SceneDataQuery, SceneObject, SceneObjectState } from '../core/types';\nimport { SceneQueryRunner } from '../querying/SceneQueryRunner';\nimport { DataSourceRef } from '@grafana/schema';\n\nexport function isVariableValueEqual(a: VariableValue | null | undefined, b: VariableValue | null | undefined) {\n if (a === b) {\n return true;\n }\n\n return isEqual(a, b);\n}\n\nexport function safeStringifyValue(value: unknown) {\n // Avoid circular references ignoring those references\n const getCircularReplacer = () => {\n const seen = new WeakSet();\n return (_: string, value: object | null) => {\n if (typeof value === 'object' && value !== null) {\n if (seen.has(value)) {\n return;\n }\n seen.add(value);\n }\n return value;\n };\n };\n\n try {\n return JSON.stringify(value, getCircularReplacer());\n } catch (error) {\n console.error(error);\n }\n\n return '';\n}\n\nexport function renderPrometheusLabelFilters(filters: AdHocVariableFilter[]) {\n return filters.map((filter) => renderFilter(filter)).join(',');\n}\n\nfunction renderFilter(filter: AdHocVariableFilter) {\n let value = '';\n let operator = filter.operator;\n\n // map \"one of\" operator to regex\n if (operator === '=|') {\n operator = '=~';\n // TODO remove when we're on the latest version of @grafana/data\n // @ts-expect-error\n value = filter.values?.map(escapeLabelValueInRegexSelector).join('|');\n } else if (operator === '!=|') {\n operator = '!~';\n // TODO remove when we're on the latest version of @grafana/data\n // @ts-expect-error\n value = filter.values?.map(escapeLabelValueInRegexSelector).join('|');\n } else if (operator === '=~' || operator === '!~') {\n value = escapeLabelValueInRegexSelector(filter.value);\n } else {\n value = escapeLabelValueInExactSelector(filter.value);\n }\n\n return `${filter.key}${operator}\"${value}\"`;\n}\n\n// based on the openmetrics-documentation, the 3 symbols we have to handle are:\n// - \\n ... the newline character\n// - \\ ... the backslash character\n// - \" ... the double-quote character\nexport function escapeLabelValueInExactSelector(labelValue: string): string {\n return labelValue.replace(/\\\\/g, '\\\\\\\\').replace(/\\n/g, '\\\\n').replace(/\"/g, '\\\\\"');\n}\n\nexport function escapeLabelValueInRegexSelector(labelValue: string): string {\n return escapeLabelValueInExactSelector(escapeLokiRegexp(labelValue));\n}\n\nexport function isRegexSelector(selector?: string) {\n if (selector && (selector.includes('=~') || selector.includes('!~'))) {\n return true;\n }\n return false;\n}\n\n// Loki regular-expressions use the RE2 syntax (https://github.com/google/re2/wiki/Syntax),\n// so every character that matches something in that list has to be escaped.\n// the list of meta characters is: *+?()|\\.[]{}^$\n// we make a javascript regular expression that matches those characters:\nconst RE2_METACHARACTERS = /[*+?()|\\\\.\\[\\]{}^$]/g;\nfunction escapeLokiRegexp(value: string): string {\n return value.replace(RE2_METACHARACTERS, '\\\\$&');\n}\n\n/**\n * Get all queries in the scene that have the same datasource as provided source object\n */\nexport function getQueriesForVariables(\n sourceObject: SceneObject<SceneObjectState & { datasource: DataSourceRef | null }>\n) {\n const runners = sceneGraph.findAllObjects(\n sourceObject.getRoot(),\n (o) => o instanceof SceneQueryRunner\n ) as SceneQueryRunner[];\n\n const interpolatedDsUuid = sceneGraph.interpolate(sourceObject, sourceObject.state.datasource?.uid);\n\n const applicableRunners = filterOutInactiveRunnerDuplicates(runners).filter((r) => {\n const interpolatedQueryDsUuid = sceneGraph.interpolate(sourceObject, r.state.datasource?.uid);\n\n return interpolatedQueryDsUuid === interpolatedDsUuid;\n });\n\n if (applicableRunners.length === 0) {\n return [];\n }\n\n const result: SceneDataQuery[] = [];\n applicableRunners.forEach((r) => {\n result.push(\n ...r.state.queries.filter((q) => {\n if (!q.datasource || !q.datasource.uid) {\n return true;\n }\n\n const interpolatedQueryDsUuid = sceneGraph.interpolate(sourceObject, q.datasource.uid);\n return interpolatedQueryDsUuid === interpolatedDsUuid;\n })\n );\n });\n\n return result;\n}\n\n// Filters out inactive runner duplicates, keeping only the ones that are currently active.\n// This is needed for scnearios whan a query runner is cloned and the original is not removed but de-activated.\n// Can happen i.e. when editing a panel in Grafana Core dashboards.\nfunction filterOutInactiveRunnerDuplicates(runners: SceneQueryRunner[]) {\n // Group items by key\n const groupedItems: { [key: string]: SceneQueryRunner[] } = {};\n\n for (const item of runners) {\n if (item.state.key) {\n if (!(item.state.key in groupedItems)) {\n groupedItems[item.state.key] = [];\n }\n groupedItems[item.state.key].push(item);\n }\n }\n\n // Filter out inactive items and concatenate active items\n return Object.values(groupedItems).flatMap((group) => {\n const activeItems = group.filter((item) => item.isActive);\n // Keep inactive items if there's only one item with the key\n if (activeItems.length === 0 && group.length === 1) {\n return group;\n }\n return activeItems;\n });\n}\n\nexport function escapeUrlPipeDelimiters(value: string | undefined): string {\n if (value === null || value === undefined) {\n return '';\n }\n\n // Replace the pipe due to using it as a filter separator\n return (value = /\\|/g[Symbol.replace](value, '__gfp__'));\n}\n\nexport function escapeUrlCommaDelimiters(value: string | undefined): string {\n if (value === null || value === undefined) {\n return '';\n }\n\n // Replace the comma due to using it as a value/label separator\n return /,/g[Symbol.replace](value, '__gfc__');\n}\n\nexport function escapeUrlHashDelimiters(value: string | undefined): string {\n if (value === null || value === undefined) {\n return '';\n }\n\n // Replace the hash due to using it as a value/label separator\n return /#/g[Symbol.replace](value, '__gfh__');\n}\n\nexport function escapeInjectedFilterUrlDelimiters(value: string | undefined): string {\n return escapeUrlHashDelimiters(escapeUrlPipeDelimiters(value));\n}\n\nexport function escapeURLDelimiters(value: string | undefined): string {\n return escapeUrlCommaDelimiters(escapeUrlPipeDelimiters(value));\n}\n\nexport function unescapeUrlDelimiters(value: string | undefined): string {\n if (value === null || value === undefined) {\n return '';\n }\n\n value = /__gfp__/g[Symbol.replace](value, '|');\n value = /__gfc__/g[Symbol.replace](value, ',');\n value = /__gfh__/g[Symbol.replace](value, '#');\n\n return value;\n}\n\nexport function toUrlCommaDelimitedString(key: string, label?: string): string {\n // Omit for identical key/label or when label is not set at all\n if (!label || key === label) {\n return escapeUrlCommaDelimiters(key);\n }\n\n return [key, label].map(escapeUrlCommaDelimiters).join(',');\n}\n\nexport function dataFromResponse(response: GetTagResponse | MetricFindValue[]) {\n return Array.isArray(response) ? response : response.data;\n}\n\nexport function responseHasError(\n response: GetTagResponse | MetricFindValue[]\n): response is GetTagResponse & { error: DataQueryError } {\n return !Array.isArray(response) && Boolean(response.error);\n}\n\n// Collect a flat list of SelectableValues with a `group` property into a hierarchical list with groups\nexport function handleOptionGroups(values: SelectableValue[]): Array<SelectableValue<string>> {\n const result: Array<SelectableValue<string>> = [];\n const groupedResults = new Map<string, Array<SelectableValue<string>>>();\n\n for (const value of values) {\n const groupLabel = value.group;\n if (groupLabel) {\n let group = groupedResults.get(groupLabel);\n\n if (!group) {\n group = [];\n groupedResults.set(groupLabel, group);\n result.push({ label: groupLabel, options: group });\n }\n\n group.push(value);\n } else {\n result.push(value);\n }\n }\n\n return result;\n}\n"],"names":["value","_a"],"mappings":"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"}
1
+ {"version":3,"file":"utils.js","sources":["../../../src/variables/utils.ts"],"sourcesContent":["import { isEqual } from 'lodash';\nimport { VariableValue } from './types';\nimport { AdHocVariableFilter, DataQueryError, GetTagResponse, MetricFindValue, SelectableValue } from '@grafana/data';\nimport { sceneGraph } from '../core/sceneGraph';\nimport { SceneDataQuery, SceneObject, SceneObjectState } from '../core/types';\nimport { SceneQueryRunner } from '../querying/SceneQueryRunner';\nimport { DataSourceRef } from '@grafana/schema';\n\nexport function isVariableValueEqual(a: VariableValue | null | undefined, b: VariableValue | null | undefined) {\n if (a === b) {\n return true;\n }\n\n return isEqual(a, b);\n}\n\nexport function safeStringifyValue(value: unknown) {\n // Avoid circular references ignoring those references\n const getCircularReplacer = () => {\n const seen = new WeakSet();\n return (_: string, value: object | null) => {\n if (typeof value === 'object' && value !== null) {\n if (seen.has(value)) {\n return;\n }\n seen.add(value);\n }\n return value;\n };\n };\n\n try {\n return JSON.stringify(value, getCircularReplacer());\n } catch (error) {\n console.error(error);\n }\n\n return '';\n}\n\nexport function renderPrometheusLabelFilters(filters: AdHocVariableFilter[]) {\n return filters.map((filter) => renderFilter(filter)).join(',');\n}\n\nfunction renderFilter(filter: AdHocVariableFilter) {\n let value = '';\n let operator = filter.operator;\n\n // map \"one of\" operator to regex\n if (operator === '=|') {\n operator = '=~';\n // TODO remove when we're on the latest version of @grafana/data\n // @ts-expect-error\n value = filter.values?.map(escapeLabelValueInRegexSelector).join('|');\n } else if (operator === '!=|') {\n operator = '!~';\n // TODO remove when we're on the latest version of @grafana/data\n // @ts-expect-error\n value = filter.values?.map(escapeLabelValueInRegexSelector).join('|');\n } else if (operator === '=~' || operator === '!~') {\n value = escapeLabelValueInRegexSelector(filter.value);\n } else {\n value = escapeLabelValueInExactSelector(filter.value);\n }\n\n return `${filter.key}${operator}\"${value}\"`;\n}\n\n// based on the openmetrics-documentation, the 3 symbols we have to handle are:\n// - \\n ... the newline character\n// - \\ ... the backslash character\n// - \" ... the double-quote character\nexport function escapeLabelValueInExactSelector(labelValue: string): string {\n return labelValue.replace(/\\\\/g, '\\\\\\\\').replace(/\\n/g, '\\\\n').replace(/\"/g, '\\\\\"');\n}\n\nexport function escapeLabelValueInRegexSelector(labelValue: string): string {\n return escapeLabelValueInExactSelector(escapeLokiRegexp(labelValue));\n}\n\nexport function isRegexSelector(selector?: string) {\n if (selector && (selector.includes('=~') || selector.includes('!~'))) {\n return true;\n }\n return false;\n}\n\n// Loki regular-expressions use the RE2 syntax (https://github.com/google/re2/wiki/Syntax),\n// so every character that matches something in that list has to be escaped.\n// the list of meta characters is: *+?()|\\.[]{}^$\n// we make a javascript regular expression that matches those characters:\nconst RE2_METACHARACTERS = /[*+?()|\\\\.\\[\\]{}^$]/g;\nfunction escapeLokiRegexp(value: string): string {\n return value.replace(RE2_METACHARACTERS, '\\\\$&');\n}\n\n/**\n * Get all queries in the scene that have the same datasource as provided source object\n */\nexport function getQueriesForVariables(\n sourceObject: SceneObject<SceneObjectState & { datasource: DataSourceRef | null }>\n) {\n const runners = sceneGraph.findAllObjects(\n sourceObject.getRoot(),\n (o) => o instanceof SceneQueryRunner\n ) as SceneQueryRunner[];\n\n const interpolatedDsUuid = sceneGraph.interpolate(sourceObject, sourceObject.state.datasource?.uid);\n\n const applicableRunners = filterOutInactiveRunnerDuplicates(runners).filter((r) => {\n const interpolatedQueryDsUuid = sceneGraph.interpolate(sourceObject, r.state.datasource?.uid);\n\n return interpolatedQueryDsUuid === interpolatedDsUuid;\n });\n\n if (applicableRunners.length === 0) {\n return [];\n }\n\n const result: SceneDataQuery[] = [];\n applicableRunners.forEach((r) => {\n result.push(\n ...r.state.queries.filter((q) => {\n if (!q.datasource || !q.datasource.uid) {\n return true;\n }\n\n const interpolatedQueryDsUuid = sceneGraph.interpolate(sourceObject, q.datasource.uid);\n return interpolatedQueryDsUuid === interpolatedDsUuid;\n })\n );\n });\n\n return result;\n}\n\n// Filters out inactive runner duplicates, keeping only the ones that are currently active.\n// This is needed for scnearios whan a query runner is cloned and the original is not removed but de-activated.\n// Can happen i.e. when editing a panel in Grafana Core dashboards.\nfunction filterOutInactiveRunnerDuplicates(runners: SceneQueryRunner[]) {\n // Group items by key\n const groupedItems: { [key: string]: SceneQueryRunner[] } = {};\n\n for (const item of runners) {\n if (item.state.key) {\n if (!(item.state.key in groupedItems)) {\n groupedItems[item.state.key] = [];\n }\n groupedItems[item.state.key].push(item);\n }\n }\n\n // Filter out inactive items and concatenate active items\n return Object.values(groupedItems).flatMap((group) => {\n const activeItems = group.filter((item) => item.isActive);\n // Keep inactive items if there's only one item with the key\n if (activeItems.length === 0 && group.length === 1) {\n return group;\n }\n return activeItems;\n });\n}\n\nexport function escapeUrlPipeDelimiters(value: string | undefined): string {\n if (value === null || value === undefined) {\n return '';\n }\n\n // Replace the pipe due to using it as a filter separator\n return (value = /\\|/g[Symbol.replace](value, '__gfp__'));\n}\n\nexport function escapeUrlCommaDelimiters(value: string | undefined): string {\n if (value === null || value === undefined) {\n return '';\n }\n\n // Replace the comma due to using it as a value/label separator\n return /,/g[Symbol.replace](value, '__gfc__');\n}\n\nexport function escapeUrlHashDelimiters(value: string | undefined): string {\n if (value === null || value === undefined) {\n return '';\n }\n\n // Replace the hash due to using it as a value/label separator\n return /#/g[Symbol.replace](value, '__gfh__');\n}\n\nexport function escapeOriginFilterUrlDelimiters(value: string | undefined): string {\n return escapeUrlHashDelimiters(escapeUrlPipeDelimiters(value));\n}\n\nexport function escapeURLDelimiters(value: string | undefined): string {\n return escapeUrlCommaDelimiters(escapeUrlPipeDelimiters(value));\n}\n\nexport function unescapeUrlDelimiters(value: string | undefined): string {\n if (value === null || value === undefined) {\n return '';\n }\n\n value = /__gfp__/g[Symbol.replace](value, '|');\n value = /__gfc__/g[Symbol.replace](value, ',');\n value = /__gfh__/g[Symbol.replace](value, '#');\n\n return value;\n}\n\nexport function toUrlCommaDelimitedString(key: string, label?: string): string {\n // Omit for identical key/label or when label is not set at all\n if (!label || key === label) {\n return escapeUrlCommaDelimiters(key);\n }\n\n return [key, label].map(escapeUrlCommaDelimiters).join(',');\n}\n\nexport function dataFromResponse(response: GetTagResponse | MetricFindValue[]) {\n return Array.isArray(response) ? response : response.data;\n}\n\nexport function responseHasError(\n response: GetTagResponse | MetricFindValue[]\n): response is GetTagResponse & { error: DataQueryError } {\n return !Array.isArray(response) && Boolean(response.error);\n}\n\n// Collect a flat list of SelectableValues with a `group` property into a hierarchical list with groups\nexport function handleOptionGroups(values: SelectableValue[]): Array<SelectableValue<string>> {\n const result: Array<SelectableValue<string>> = [];\n const groupedResults = new Map<string, Array<SelectableValue<string>>>();\n\n for (const value of values) {\n const groupLabel = value.group;\n if (groupLabel) {\n let group = groupedResults.get(groupLabel);\n\n if (!group) {\n group = [];\n groupedResults.set(groupLabel, group);\n result.push({ label: groupLabel, options: group });\n }\n\n group.push(value);\n } else {\n result.push(value);\n }\n }\n\n return result;\n}\n"],"names":["value","_a"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -849,6 +849,8 @@ interface AdHocFiltersVariableState extends SceneVariableState {
849
849
  filters: AdHocFilterWithLabels[];
850
850
  /** Base filters to always apply when looking up keys*/
851
851
  baseFilters?: AdHocFilterWithLabels[];
852
+ /** Filters originated from a source */
853
+ originFilters?: AdHocFilterWithLabels[];
852
854
  /** Datasource to use for getTagKeys and getTagValues and also controls which scene queries the filters should apply to */
853
855
  datasource: DataSourceRef | null;
854
856
  /** Controls if the filters can be changed */
@@ -943,6 +945,7 @@ declare class AdHocFiltersVariable extends SceneObjectBase<AdHocFiltersVariableS
943
945
  private _scopedVars;
944
946
  private _dataSourceSrv;
945
947
  private _originalValues;
948
+ private _prevScopes;
946
949
  /** Needed for scopes dependency */
947
950
  protected _variableDependency: VariableDependencyConfig<AdHocFiltersVariableState>;
948
951
  protected _urlSync: AdHocFiltersVariableUrlSyncHandler;
package/dist/index.js CHANGED
@@ -3957,20 +3957,20 @@ class AdHocFiltersVariableUrlSyncHandler {
3957
3957
  }
3958
3958
  getUrlState() {
3959
3959
  const filters = this._variable.state.filters;
3960
- const baseFilters = this._variable.state.baseFilters;
3960
+ const originFilters = this._variable.state.originFilters;
3961
3961
  let value = [];
3962
- if (filters.length === 0 && (baseFilters == null ? void 0 : baseFilters.length) === 0) {
3962
+ if (filters.length === 0 && (originFilters == null ? void 0 : originFilters.length) === 0) {
3963
3963
  return { [this.getKey()]: [""] };
3964
3964
  }
3965
3965
  if (filters.length) {
3966
3966
  value.push(
3967
- ...filters.filter(isFilterComplete).filter((filter) => !filter.hidden).map((filter) => toArray(filter).map(escapeInjectedFilterUrlDelimiters).join("|"))
3967
+ ...filters.filter(isFilterComplete).filter((filter) => !filter.hidden).map((filter) => toArray(filter).map(escapeOriginFilterUrlDelimiters).join("|"))
3968
3968
  );
3969
3969
  }
3970
- if (baseFilters == null ? void 0 : baseFilters.length) {
3970
+ if (originFilters == null ? void 0 : originFilters.length) {
3971
3971
  value.push(
3972
- ...baseFilters == null ? void 0 : baseFilters.filter(isFilterComplete).filter((filter) => !filter.hidden && filter.origin && filter.restorable).map(
3973
- (filter) => toArray(filter).map(escapeInjectedFilterUrlDelimiters).join("|").concat(`#${filter.origin}#restorable`)
3972
+ ...originFilters == null ? void 0 : originFilters.filter(isFilterComplete).filter((filter) => !filter.hidden && filter.origin && filter.restorable).map(
3973
+ (filter) => toArray(filter).map(escapeOriginFilterUrlDelimiters).join("|").concat(`#${filter.origin}#restorable`)
3974
3974
  )
3975
3975
  );
3976
3976
  }
@@ -3984,31 +3984,35 @@ class AdHocFiltersVariableUrlSyncHandler {
3984
3984
  return;
3985
3985
  }
3986
3986
  const filters = deserializeUrlToFilters(urlValue);
3987
- const baseFilters = [...this._variable.state.baseFilters || []];
3988
- for (let i = 0; i < filters.length; i++) {
3989
- const foundBaseFilterIndex = baseFilters.findIndex((f) => f.key === filters[i].key);
3990
- if (foundBaseFilterIndex > -1) {
3991
- if (!filters[i].origin && baseFilters[foundBaseFilterIndex].origin === "dashboard") {
3992
- filters[i].origin = "dashboard";
3993
- filters[i].restorable = true;
3994
- }
3995
- if (isMatchAllFilter(filters[i])) {
3996
- filters[i].matchAllFilter = true;
3997
- }
3998
- baseFilters[foundBaseFilterIndex] = filters[i];
3999
- } else if (filters[i].origin === "dashboard") {
4000
- delete filters[i].origin;
4001
- delete filters[i].restorable;
4002
- } else if (foundBaseFilterIndex === -1 && filters[i].origin === "scope" && filters[i].restorable) {
4003
- baseFilters.push(filters[i]);
4004
- }
4005
- }
3987
+ const originFilters = updateOriginFilters([...this._variable.state.originFilters || []], filters);
4006
3988
  this._variable.setState({
4007
3989
  filters: filters.filter((f) => !f.origin),
4008
- baseFilters
3990
+ originFilters
4009
3991
  });
4010
3992
  }
4011
3993
  }
3994
+ function updateOriginFilters(prevOriginFilters, filters) {
3995
+ const updatedOriginFilters = [...prevOriginFilters];
3996
+ for (let i = 0; i < filters.length; i++) {
3997
+ const foundOriginFilterIndex = prevOriginFilters.findIndex((f) => f.key === filters[i].key);
3998
+ if (foundOriginFilterIndex > -1) {
3999
+ if (!filters[i].origin && prevOriginFilters[foundOriginFilterIndex].origin === "dashboard") {
4000
+ filters[i].origin = "dashboard";
4001
+ filters[i].restorable = true;
4002
+ }
4003
+ if (isMatchAllFilter(filters[i])) {
4004
+ filters[i].matchAllFilter = true;
4005
+ }
4006
+ updatedOriginFilters[foundOriginFilterIndex] = filters[i];
4007
+ } else if (filters[i].origin === "dashboard") {
4008
+ delete filters[i].origin;
4009
+ delete filters[i].restorable;
4010
+ } else if (foundOriginFilterIndex === -1 && filters[i].origin === "scope" && filters[i].restorable) {
4011
+ updatedOriginFilters.push(filters[i]);
4012
+ }
4013
+ }
4014
+ return updatedOriginFilters;
4015
+ }
4012
4016
  function deserializeUrlToFilters(value) {
4013
4017
  if (Array.isArray(value)) {
4014
4018
  const values = value;
@@ -5336,7 +5340,7 @@ const AdHocFiltersAlwaysWipCombobox = React.forwardRef(function AdHocFiltersAlwa
5336
5340
  });
5337
5341
 
5338
5342
  const AdHocFiltersComboboxRenderer = React.memo(function AdHocFiltersComboboxRenderer2({ model }) {
5339
- const { baseFilters, filters, readOnly } = model.useState();
5343
+ const { originFilters, filters, readOnly } = model.useState();
5340
5344
  const styles = ui.useStyles2(getStyles$a);
5341
5345
  const focusOnWipInputRef = React.useRef();
5342
5346
  return /* @__PURE__ */ React__default.default.createElement(
@@ -5349,7 +5353,7 @@ const AdHocFiltersComboboxRenderer = React.memo(function AdHocFiltersComboboxRen
5349
5353
  }
5350
5354
  },
5351
5355
  /* @__PURE__ */ React__default.default.createElement(ui.Icon, { name: "filter", className: styles.filterIcon, size: "lg" }),
5352
- baseFilters == null ? void 0 : baseFilters.map(
5356
+ originFilters == null ? void 0 : originFilters.map(
5353
5357
  (filter, index) => filter.origin ? /* @__PURE__ */ React__default.default.createElement(
5354
5358
  AdHocFilterPill,
5355
5359
  {
@@ -5513,17 +5517,14 @@ const OPERATORS = [
5513
5517
  ];
5514
5518
  class AdHocFiltersVariable extends SceneObjectBase {
5515
5519
  constructor(state) {
5516
- var _a, _b, _c, _d, _e, _f;
5520
+ var _a, _b, _c, _d, _e;
5517
5521
  super({
5518
5522
  type: "adhoc",
5519
5523
  name: (_a = state.name) != null ? _a : "Filters",
5520
5524
  filters: [],
5521
5525
  datasource: null,
5522
5526
  applyMode: "auto",
5523
- filterExpression: (_e = state.filterExpression) != null ? _e : renderExpression(state.expressionBuilder, [
5524
- ...(_c = (_b = state.baseFilters) == null ? void 0 : _b.filter((filter) => filter.origin)) != null ? _c : [],
5525
- ...(_d = state.filters) != null ? _d : []
5526
- ]),
5527
+ filterExpression: (_d = state.filterExpression) != null ? _d : renderExpression(state.expressionBuilder, [...(_b = state.originFilters) != null ? _b : [], ...(_c = state.filters) != null ? _c : []]),
5527
5528
  ...state
5528
5529
  });
5529
5530
  this._scopedVars = { __sceneObject: wrapInSafeSerializableSceneObject(this) };
@@ -5532,6 +5533,7 @@ class AdHocFiltersVariable extends SceneObjectBase {
5532
5533
  // are set on construct and used to restore a baseFilter with an origin
5533
5534
  // to its original value if edited at some point
5534
5535
  this._originalValues = /* @__PURE__ */ new Map();
5536
+ this._prevScopes = [];
5535
5537
  /** Needed for scopes dependency */
5536
5538
  this._variableDependency = new VariableDependencyConfig(this, {
5537
5539
  dependsOnScopes: true,
@@ -5539,44 +5541,33 @@ class AdHocFiltersVariable extends SceneObjectBase {
5539
5541
  });
5540
5542
  this._urlSync = new AdHocFiltersVariableUrlSyncHandler(this);
5541
5543
  this._activationHandler = () => {
5542
- this._updateScopesFilters();
5543
5544
  return () => {
5544
- var _a, _b;
5545
- if ((_a = this.state.baseFilters) == null ? void 0 : _a.length) {
5546
- this.setState({
5547
- baseFilters: [...this.state.baseFilters.filter((filter) => filter.origin !== "scope")]
5548
- });
5549
- (_b = this.state.baseFilters) == null ? void 0 : _b.forEach((filter) => {
5550
- if (filter.origin === "dashboard" && filter.restorable) {
5551
- this.restoreOriginalFilter(filter);
5552
- }
5553
- });
5554
- }
5545
+ var _a;
5546
+ (_a = this.state.originFilters) == null ? void 0 : _a.forEach((filter) => {
5547
+ if (filter.restorable) {
5548
+ this.restoreOriginalFilter(filter);
5549
+ }
5550
+ });
5555
5551
  };
5556
5552
  };
5557
5553
  if (this.state.applyMode === "auto") {
5558
5554
  patchGetAdhocFilters(this);
5559
5555
  }
5560
- (_f = this.state.baseFilters) == null ? void 0 : _f.forEach((baseFilter) => {
5556
+ (_e = this.state.originFilters) == null ? void 0 : _e.forEach((filter) => {
5561
5557
  var _a2;
5562
- if (baseFilter.origin === "dashboard") {
5563
- this._originalValues.set(baseFilter.key, {
5564
- operator: baseFilter.operator,
5565
- value: (_a2 = baseFilter.values) != null ? _a2 : [baseFilter.value]
5566
- });
5567
- }
5558
+ this._originalValues.set(filter.key, {
5559
+ operator: filter.operator,
5560
+ value: (_a2 = filter.values) != null ? _a2 : [filter.value]
5561
+ });
5568
5562
  });
5569
5563
  this.addActivationHandler(this._activationHandler);
5570
5564
  }
5571
5565
  _updateScopesFilters() {
5572
5566
  var _a, _b;
5573
5567
  const scopes = sceneGraph.getScopes(this);
5574
- if (!scopes) {
5575
- return;
5576
- }
5577
- if (!scopes.length) {
5568
+ if (!scopes || !scopes.length) {
5578
5569
  this.setState({
5579
- baseFilters: (_a = this.state.baseFilters) == null ? void 0 : _a.filter((filter) => filter.origin !== "scope")
5570
+ originFilters: (_a = this.state.originFilters) == null ? void 0 : _a.filter((filter) => filter.origin !== "scope")
5580
5571
  });
5581
5572
  return;
5582
5573
  }
@@ -5594,13 +5585,18 @@ class AdHocFiltersVariable extends SceneObjectBase {
5594
5585
  operator: scopeFilter.operator
5595
5586
  });
5596
5587
  });
5597
- (_b = this.state.baseFilters) == null ? void 0 : _b.forEach((filter) => {
5588
+ (_b = this.state.originFilters) == null ? void 0 : _b.forEach((filter) => {
5598
5589
  if (filter.origin === "scope") {
5599
5590
  scopeInjectedFilters.push(filter);
5600
5591
  } else {
5601
5592
  remainingFilters.push(filter);
5602
5593
  }
5603
5594
  });
5595
+ if (this._prevScopes.length) {
5596
+ this.setState({ originFilters: [...finalFilters, ...remainingFilters] });
5597
+ this._prevScopes = scopes;
5598
+ return;
5599
+ }
5604
5600
  const editedScopeFilters = scopeInjectedFilters.filter((filter) => filter.restorable);
5605
5601
  const editedScopeFilterKeys = editedScopeFilters.map((filter) => filter.key);
5606
5602
  const scopeFilterKeys = scopeFilters.map((filter) => filter.key);
@@ -5608,18 +5604,16 @@ class AdHocFiltersVariable extends SceneObjectBase {
5608
5604
  ...editedScopeFilters.filter((filter) => scopeFilterKeys.includes(filter.key)),
5609
5605
  ...scopeFilters.filter((filter) => !editedScopeFilterKeys.includes(filter.key))
5610
5606
  ];
5611
- this.setState({ baseFilters: [...finalFilters, ...remainingFilters] });
5607
+ this.setState({ originFilters: [...finalFilters, ...remainingFilters] });
5608
+ this._prevScopes = scopes;
5612
5609
  }
5613
5610
  setState(update) {
5614
- var _a, _b, _c;
5611
+ var _a, _b;
5615
5612
  let filterExpressionChanged = false;
5616
- if ((update.filters && update.filters !== this.state.filters || update.baseFilters && update.baseFilters !== this.state.baseFilters) && !update.filterExpression) {
5613
+ if ((update.filters && update.filters !== this.state.filters || update.originFilters && update.originFilters !== this.state.originFilters) && !update.filterExpression) {
5617
5614
  const filters = (_a = update.filters) != null ? _a : this.state.filters;
5618
- const baseFilters = (_b = update.baseFilters) != null ? _b : this.state.baseFilters;
5619
- update.filterExpression = renderExpression(this.state.expressionBuilder, [
5620
- ...(_c = baseFilters == null ? void 0 : baseFilters.filter((filter) => filter.origin)) != null ? _c : [],
5621
- ...filters != null ? filters : []
5622
- ]);
5615
+ const originFilters = (_b = update.originFilters) != null ? _b : this.state.originFilters;
5616
+ update.filterExpression = renderExpression(this.state.expressionBuilder, [...originFilters != null ? originFilters : [], ...filters]);
5623
5617
  filterExpressionChanged = update.filterExpression !== this.state.filterExpression;
5624
5618
  }
5625
5619
  super.setState(update);
@@ -5633,12 +5627,12 @@ class AdHocFiltersVariable extends SceneObjectBase {
5633
5627
  * allowing consumers to update the filters without triggering dependent data providers.
5634
5628
  */
5635
5629
  updateFilters(filters, options) {
5636
- var _a, _b;
5630
+ var _a;
5637
5631
  let filterExpressionChanged = false;
5638
5632
  let filterExpression = void 0;
5639
5633
  if (filters && filters !== this.state.filters) {
5640
5634
  filterExpression = renderExpression(this.state.expressionBuilder, [
5641
- ...(_b = (_a = this.state.baseFilters) == null ? void 0 : _a.filter((filter) => filter.origin)) != null ? _b : [],
5635
+ ...(_a = this.state.originFilters) != null ? _a : [],
5642
5636
  ...filters
5643
5637
  ]);
5644
5638
  filterExpressionChanged = filterExpression !== this.state.filterExpression;
@@ -5658,32 +5652,34 @@ class AdHocFiltersVariable extends SceneObjectBase {
5658
5652
  };
5659
5653
  if (filter.restorable) {
5660
5654
  const originalFilter = this._originalValues.get(filter.key);
5655
+ if (!originalFilter) {
5656
+ return;
5657
+ }
5661
5658
  original.value = originalFilter == null ? void 0 : originalFilter.value[0];
5662
5659
  original.values = originalFilter == null ? void 0 : originalFilter.value;
5663
5660
  original.valueLabels = originalFilter == null ? void 0 : originalFilter.value;
5664
5661
  original.operator = originalFilter == null ? void 0 : originalFilter.operator;
5662
+ this._updateFilter(filter, original);
5665
5663
  }
5666
- this._updateFilter(filter, original);
5667
5664
  }
5668
5665
  getValue() {
5669
5666
  return this.state.filterExpression;
5670
5667
  }
5671
5668
  _updateFilter(filter, update) {
5672
5669
  var _a;
5673
- const { baseFilters, filters, _wip } = this.state;
5670
+ const { originFilters, filters, _wip } = this.state;
5674
5671
  if (filter.origin) {
5675
5672
  const originalValues = this._originalValues.get(filter.key);
5676
5673
  const updateValues = update.values || (update.value ? [update.value] : void 0);
5677
- const isRestorableOverride = update.hasOwnProperty("restorable");
5678
- if (!isRestorableOverride && (updateValues && !lodash.isEqual(updateValues, originalValues == null ? void 0 : originalValues.value) || update.operator && update.operator !== (originalValues == null ? void 0 : originalValues.operator))) {
5674
+ if (updateValues && !lodash.isEqual(updateValues, originalValues == null ? void 0 : originalValues.value) || update.operator && update.operator !== (originalValues == null ? void 0 : originalValues.operator)) {
5679
5675
  update.restorable = true;
5680
5676
  } else if (updateValues && lodash.isEqual(updateValues, originalValues == null ? void 0 : originalValues.value)) {
5681
5677
  update.restorable = false;
5682
5678
  }
5683
- const updatedBaseFilters = (_a = baseFilters == null ? void 0 : baseFilters.map((f) => {
5679
+ const updatedFilters2 = (_a = originFilters == null ? void 0 : originFilters.map((f) => {
5684
5680
  return f === filter ? { ...f, ...update } : f;
5685
5681
  })) != null ? _a : [];
5686
- this.setState({ baseFilters: updatedBaseFilters });
5682
+ this.setState({ originFilters: updatedFilters2 });
5687
5683
  return;
5688
5684
  }
5689
5685
  if (filter === _wip) {
@@ -5746,13 +5742,13 @@ class AdHocFiltersVariable extends SceneObjectBase {
5746
5742
  return [...acc, f];
5747
5743
  }, [])
5748
5744
  });
5749
- } else if ((_a = this.state.baseFilters) == null ? void 0 : _a.length) {
5750
- let filterToForceIndex = this.state.baseFilters.length - 1;
5745
+ } else if ((_a = this.state.originFilters) == null ? void 0 : _a.length) {
5746
+ let filterToForceIndex = this.state.originFilters.length - 1;
5751
5747
  if (filter !== this.state._wip) {
5752
5748
  filterToForceIndex = -1;
5753
5749
  }
5754
5750
  this.setState({
5755
- baseFilters: this.state.baseFilters.reduce((acc, f, index) => {
5751
+ originFilters: this.state.originFilters.reduce((acc, f, index) => {
5756
5752
  if (index === filterToForceIndex && !f.readOnly) {
5757
5753
  return [
5758
5754
  ...acc,
@@ -5822,8 +5818,8 @@ class AdHocFiltersVariable extends SceneObjectBase {
5822
5818
  if (!ds || !ds.getTagValues) {
5823
5819
  return [];
5824
5820
  }
5825
- const filteredBaseFilters = (_d = (_c = this.state.baseFilters) == null ? void 0 : _c.filter((f) => f.origin && f.key !== filter.key)) != null ? _d : [];
5826
- const otherFilters = this.state.filters.filter((f) => f.key !== filter.key).concat(filteredBaseFilters);
5821
+ const originFilters = (_d = (_c = this.state.originFilters) == null ? void 0 : _c.filter((f) => f.key !== filter.key)) != null ? _d : [];
5822
+ const otherFilters = this.state.filters.filter((f) => f.key !== filter.key).concat(originFilters);
5827
5823
  const timeRange = sceneGraph.getTimeRange(this).state.value;
5828
5824
  const queries = this.state.useQueriesAsFilterForOptions ? getQueriesForVariables(this) : void 0;
5829
5825
  let scopes = sceneGraph.getScopes(this);
@@ -6307,12 +6303,10 @@ class SceneQueryRunner extends SceneObjectBase {
6307
6303
  ...getEnrichedDataRequest(this)
6308
6304
  };
6309
6305
  if (this._adhocFiltersVar) {
6310
- request.filters = [];
6311
- if ((_a = this._adhocFiltersVar.state.baseFilters) == null ? void 0 : _a.length) {
6312
- const injectedBaseFilters = this._adhocFiltersVar.state.baseFilters.filter((filter) => filter.origin);
6313
- request.filters = request.filters.concat(injectedBaseFilters);
6314
- }
6315
- request.filters = request.filters.concat(this._adhocFiltersVar.state.filters.filter(isFilterComplete));
6306
+ request.filters = [
6307
+ ...(_a = this._adhocFiltersVar.state.originFilters) != null ? _a : [],
6308
+ ...this._adhocFiltersVar.state.filters
6309
+ ].filter(isFilterComplete);
6316
6310
  }
6317
6311
  if (this._groupByVar) {
6318
6312
  request.groupByKeys = this._groupByVar.state.value;
@@ -6549,7 +6543,7 @@ function escapeUrlHashDelimiters(value) {
6549
6543
  }
6550
6544
  return /#/g[Symbol.replace](value, "__gfh__");
6551
6545
  }
6552
- function escapeInjectedFilterUrlDelimiters(value) {
6546
+ function escapeOriginFilterUrlDelimiters(value) {
6553
6547
  return escapeUrlHashDelimiters(escapeUrlPipeDelimiters(value));
6554
6548
  }
6555
6549
  function escapeURLDelimiters(value) {
@@ -6651,11 +6645,9 @@ class VariableDependencyConfig {
6651
6645
  * This is called whenever any set of variables have new values. It is up to this implementation to check if it's relevant given the current dependencies.
6652
6646
  */
6653
6647
  variableUpdateCompleted(variable, hasChanged) {
6648
+ var _a, _b, _c, _d;
6654
6649
  const deps = this.getNames();
6655
- let dependencyChanged = false;
6656
- if ((deps.has(variable.state.name) || deps.has(data.DataLinkBuiltInVars.includeVars)) && hasChanged) {
6657
- dependencyChanged = true;
6658
- }
6650
+ const dependencyChanged = (deps.has(variable.state.name) || deps.has(data.DataLinkBuiltInVars.includeVars)) && hasChanged;
6659
6651
  writeSceneLog(
6660
6652
  "VariableDependencyConfig",
6661
6653
  "variableUpdateCompleted",
@@ -6663,47 +6655,29 @@ class VariableDependencyConfig {
6663
6655
  dependencyChanged,
6664
6656
  this._isWaitingForVariables
6665
6657
  );
6666
- if (this._options.onAnyVariableChanged) {
6667
- this._options.onAnyVariableChanged(variable);
6668
- }
6658
+ (_b = (_a = this._options).onAnyVariableChanged) == null ? void 0 : _b.call(_a, variable);
6669
6659
  if (this._options.onVariableUpdateCompleted && (this._isWaitingForVariables || dependencyChanged)) {
6670
6660
  this._options.onVariableUpdateCompleted();
6671
6661
  }
6672
6662
  if (dependencyChanged) {
6673
- if (this._options.onReferencedVariableValueChanged) {
6674
- this._options.onReferencedVariableValueChanged(variable);
6675
- }
6663
+ (_d = (_c = this._options).onReferencedVariableValueChanged) == null ? void 0 : _d.call(_c, variable);
6676
6664
  if (!this._options.onReferencedVariableValueChanged && !this._options.onVariableUpdateCompleted) {
6677
6665
  this._sceneObject.forceRender();
6678
6666
  }
6679
6667
  }
6680
6668
  }
6681
6669
  hasDependencyInLoadingState() {
6682
- if (sceneGraph.hasVariableDependencyInLoadingState(this._sceneObject)) {
6683
- this._isWaitingForVariables = true;
6684
- return true;
6685
- }
6686
- this._isWaitingForVariables = false;
6687
- return false;
6670
+ this._isWaitingForVariables = sceneGraph.hasVariableDependencyInLoadingState(this._sceneObject);
6671
+ return this._isWaitingForVariables;
6688
6672
  }
6689
6673
  getNames() {
6690
6674
  const prevState = this._state;
6691
6675
  const newState = this._state = this._sceneObject.state;
6692
- if (!prevState) {
6693
- this.scanStateForDependencies(this._state);
6694
- return this._dependencies;
6695
- }
6696
- if (newState !== prevState) {
6697
- if (this._statePaths) {
6698
- for (const path of this._statePaths) {
6699
- if (path === "*" || newState[path] !== prevState[path]) {
6700
- this.scanStateForDependencies(newState);
6701
- break;
6702
- }
6703
- }
6704
- } else {
6705
- this.scanStateForDependencies(newState);
6706
- }
6676
+ const noPreviousState = !prevState;
6677
+ const stateDiffers = newState !== prevState;
6678
+ const shouldScanForDependencies = noPreviousState || stateDiffers && (!this._statePaths || this._statePaths.some((path) => path === "*" || newState[path] !== prevState[path]));
6679
+ if (shouldScanForDependencies) {
6680
+ this.scanStateForDependencies(newState);
6707
6681
  }
6708
6682
  return this._dependencies;
6709
6683
  }
@@ -6719,7 +6693,7 @@ class VariableDependencyConfig {
6719
6693
  }
6720
6694
  scanStateForDependencies(state) {
6721
6695
  this._dependencies.clear();
6722
- this.scanCount += 1;
6696
+ this.scanCount++;
6723
6697
  if (this._options.variableNames) {
6724
6698
  for (const name of this._options.variableNames) {
6725
6699
  this._dependencies.add(name);