@grafana/scenes 0.0.1

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 (102) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +26 -0
  3. package/dist/esm/components/NestedScene.js +119 -0
  4. package/dist/esm/components/NestedScene.js.map +1 -0
  5. package/dist/esm/components/Scene.js +39 -0
  6. package/dist/esm/components/Scene.js.map +1 -0
  7. package/dist/esm/components/SceneCanvasText.js +41 -0
  8. package/dist/esm/components/SceneCanvasText.js.map +1 -0
  9. package/dist/esm/components/SceneDragHandle.js +18 -0
  10. package/dist/esm/components/SceneDragHandle.js.map +1 -0
  11. package/dist/esm/components/ScenePanelRepeater.js +66 -0
  12. package/dist/esm/components/ScenePanelRepeater.js.map +1 -0
  13. package/dist/esm/components/SceneSubMenu.js +18 -0
  14. package/dist/esm/components/SceneSubMenu.js.map +1 -0
  15. package/dist/esm/components/SceneTimePicker.js +40 -0
  16. package/dist/esm/components/SceneTimePicker.js.map +1 -0
  17. package/dist/esm/components/SceneToolbarButton.js +28 -0
  18. package/dist/esm/components/SceneToolbarButton.js.map +1 -0
  19. package/dist/esm/components/VizPanel/VizPanel.js +105 -0
  20. package/dist/esm/components/VizPanel/VizPanel.js.map +1 -0
  21. package/dist/esm/components/VizPanel/VizPanelRenderer.js +76 -0
  22. package/dist/esm/components/VizPanel/VizPanelRenderer.js.map +1 -0
  23. package/dist/esm/components/layout/SceneFlexLayout.js +88 -0
  24. package/dist/esm/components/layout/SceneFlexLayout.js.map +1 -0
  25. package/dist/esm/components/layout/SceneGridLayout.js +288 -0
  26. package/dist/esm/components/layout/SceneGridLayout.js.map +1 -0
  27. package/dist/esm/components/layout/SceneGridRow.js +124 -0
  28. package/dist/esm/components/layout/SceneGridRow.js.map +1 -0
  29. package/dist/esm/components/layout/constants.js +7 -0
  30. package/dist/esm/components/layout/constants.js.map +1 -0
  31. package/dist/esm/core/SceneComponentWrapper.js +84 -0
  32. package/dist/esm/core/SceneComponentWrapper.js.map +1 -0
  33. package/dist/esm/core/SceneDataNode.js +7 -0
  34. package/dist/esm/core/SceneDataNode.js.map +1 -0
  35. package/dist/esm/core/SceneDataTransformer.js +51 -0
  36. package/dist/esm/core/SceneDataTransformer.js.map +1 -0
  37. package/dist/esm/core/SceneObjectBase.js +141 -0
  38. package/dist/esm/core/SceneObjectBase.js.map +1 -0
  39. package/dist/esm/core/SceneTimeRange.js +108 -0
  40. package/dist/esm/core/SceneTimeRange.js.map +1 -0
  41. package/dist/esm/core/events.js +8 -0
  42. package/dist/esm/core/events.js.map +1 -0
  43. package/dist/esm/core/sceneGraph.js +68 -0
  44. package/dist/esm/core/sceneGraph.js.map +1 -0
  45. package/dist/esm/core/types.js +6 -0
  46. package/dist/esm/core/types.js.map +1 -0
  47. package/dist/esm/core/utils.js +57 -0
  48. package/dist/esm/core/utils.js.map +1 -0
  49. package/dist/esm/index.js +33 -0
  50. package/dist/esm/index.js.map +1 -0
  51. package/dist/esm/querying/SceneQueryRunner.js +161 -0
  52. package/dist/esm/querying/SceneQueryRunner.js.map +1 -0
  53. package/dist/esm/services/SceneObjectUrlSyncConfig.js +18 -0
  54. package/dist/esm/services/SceneObjectUrlSyncConfig.js.map +1 -0
  55. package/dist/esm/services/UrlSyncManager.js +133 -0
  56. package/dist/esm/services/UrlSyncManager.js.map +1 -0
  57. package/dist/esm/utils/metricTree.js +53 -0
  58. package/dist/esm/utils/metricTree.js.map +1 -0
  59. package/dist/esm/variables/VariableDependencyConfig.js +86 -0
  60. package/dist/esm/variables/VariableDependencyConfig.js.map +1 -0
  61. package/dist/esm/variables/components/VariableValueSelect.js +58 -0
  62. package/dist/esm/variables/components/VariableValueSelect.js.map +1 -0
  63. package/dist/esm/variables/components/VariableValueSelectors.js +56 -0
  64. package/dist/esm/variables/components/VariableValueSelectors.js.map +1 -0
  65. package/dist/esm/variables/constants.js +6 -0
  66. package/dist/esm/variables/constants.js.map +1 -0
  67. package/dist/esm/variables/interpolation/ScopedVarsVariable.js +49 -0
  68. package/dist/esm/variables/interpolation/ScopedVarsVariable.js.map +1 -0
  69. package/dist/esm/variables/interpolation/defaults.js +17 -0
  70. package/dist/esm/variables/interpolation/defaults.js.map +1 -0
  71. package/dist/esm/variables/interpolation/formatRegistry.js +280 -0
  72. package/dist/esm/variables/interpolation/formatRegistry.js.map +1 -0
  73. package/dist/esm/variables/interpolation/sceneInterpolator.js +83 -0
  74. package/dist/esm/variables/interpolation/sceneInterpolator.js.map +1 -0
  75. package/dist/esm/variables/sets/SceneVariableSet.js +123 -0
  76. package/dist/esm/variables/sets/SceneVariableSet.js.map +1 -0
  77. package/dist/esm/variables/types.js +8 -0
  78. package/dist/esm/variables/types.js.map +1 -0
  79. package/dist/esm/variables/variants/ConstantVariable.js +33 -0
  80. package/dist/esm/variables/variants/ConstantVariable.js.map +1 -0
  81. package/dist/esm/variables/variants/CustomVariable.js +58 -0
  82. package/dist/esm/variables/variants/CustomVariable.js.map +1 -0
  83. package/dist/esm/variables/variants/DataSourceVariable.js +92 -0
  84. package/dist/esm/variables/variants/DataSourceVariable.js.map +1 -0
  85. package/dist/esm/variables/variants/MultiValueVariable.js +183 -0
  86. package/dist/esm/variables/variants/MultiValueVariable.js.map +1 -0
  87. package/dist/esm/variables/variants/TestVariable.js +81 -0
  88. package/dist/esm/variables/variants/TestVariable.js.map +1 -0
  89. package/dist/esm/variables/variants/query/QueryVariable.js +137 -0
  90. package/dist/esm/variables/variants/query/QueryVariable.js.map +1 -0
  91. package/dist/esm/variables/variants/query/createQueryVariableRunner.js +93 -0
  92. package/dist/esm/variables/variants/query/createQueryVariableRunner.js.map +1 -0
  93. package/dist/esm/variables/variants/query/guards.js +18 -0
  94. package/dist/esm/variables/variants/query/guards.js.map +1 -0
  95. package/dist/esm/variables/variants/query/toMetricFindValues.js +93 -0
  96. package/dist/esm/variables/variants/query/toMetricFindValues.js.map +1 -0
  97. package/dist/esm/variables/variants/query/utils.js +93 -0
  98. package/dist/esm/variables/variants/query/utils.js.map +1 -0
  99. package/dist/index.d.ts +796 -0
  100. package/dist/index.js +3356 -0
  101. package/dist/index.js.map +1 -0
  102. package/package.json +103 -0
@@ -0,0 +1,57 @@
1
+ import { SceneObjectBase } from './SceneObjectBase.js';
2
+
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
+ var __spreadValues = (a, b) => {
9
+ for (var prop in b || (b = {}))
10
+ if (__hasOwnProp.call(b, prop))
11
+ __defNormalProp(a, prop, b[prop]);
12
+ if (__getOwnPropSymbols)
13
+ for (var prop of __getOwnPropSymbols(b)) {
14
+ if (__propIsEnum.call(b, prop))
15
+ __defNormalProp(a, prop, b[prop]);
16
+ }
17
+ return a;
18
+ };
19
+ function forEachSceneObjectInState(state, callback) {
20
+ for (const propValue of Object.values(state)) {
21
+ if (propValue instanceof SceneObjectBase) {
22
+ callback(propValue);
23
+ }
24
+ if (Array.isArray(propValue)) {
25
+ for (const child of propValue) {
26
+ if (child instanceof SceneObjectBase) {
27
+ callback(child);
28
+ }
29
+ }
30
+ }
31
+ }
32
+ }
33
+ function cloneSceneObject(sceneObject, withState) {
34
+ const clonedState = __spreadValues({}, sceneObject.state);
35
+ for (const key in clonedState) {
36
+ const propValue = clonedState[key];
37
+ if (propValue instanceof SceneObjectBase) {
38
+ clonedState[key] = propValue.clone();
39
+ }
40
+ if (Array.isArray(propValue)) {
41
+ const newArray = [];
42
+ for (const child of propValue) {
43
+ if (child instanceof SceneObjectBase) {
44
+ newArray.push(child.clone());
45
+ } else {
46
+ newArray.push(child);
47
+ }
48
+ }
49
+ clonedState[key] = newArray;
50
+ }
51
+ }
52
+ Object.assign(clonedState, withState);
53
+ return new sceneObject.constructor(clonedState);
54
+ }
55
+
56
+ export { cloneSceneObject, forEachSceneObjectInState };
57
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sources":["../../../src/core/utils.ts"],"sourcesContent":["import { SceneObjectState, SceneObjectStatePlain } from './types';\n\nimport { SceneObjectBase } from './SceneObjectBase';\n\n/**\n * Will call callback for all first level child scene objects and scene objects inside arrays\n */\nexport function forEachSceneObjectInState(state: SceneObjectStatePlain, callback: (scene: SceneObjectBase) => void) {\n for (const propValue of Object.values(state)) {\n if (propValue instanceof SceneObjectBase) {\n callback(propValue);\n }\n\n if (Array.isArray(propValue)) {\n for (const child of propValue) {\n if (child instanceof SceneObjectBase) {\n callback(child);\n }\n }\n }\n }\n}\n\n/**\n * Will create new SceneItem with shalled cloned state, but all states items of type SceneObject are deep cloned\n */\nexport function cloneSceneObject<T extends SceneObjectBase<TState>, TState extends SceneObjectState>(\n sceneObject: SceneObjectBase<TState>,\n withState?: Partial<TState>\n): T {\n const clonedState = { ...sceneObject.state };\n\n // Clone any SceneItems in state\n for (const key in clonedState) {\n const propValue = clonedState[key];\n if (propValue instanceof SceneObjectBase) {\n clonedState[key] = propValue.clone();\n }\n\n // Clone scene objects in arrays\n if (Array.isArray(propValue)) {\n const newArray: any = [];\n for (const child of propValue) {\n if (child instanceof SceneObjectBase) {\n newArray.push(child.clone());\n } else {\n newArray.push(child);\n }\n }\n clonedState[key] = newArray;\n }\n }\n\n Object.assign(clonedState, withState);\n\n return new (sceneObject.constructor as any)(clonedState);\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAOgB,SAAA,yBAAA,CAA0B,OAA8B,QAA4C,EAAA;AAClH,EAAA,KAAA,MAAW,SAAa,IAAA,MAAA,CAAO,MAAO,CAAA,KAAK,CAAG,EAAA;AAC5C,IAAA,IAAI,qBAAqB,eAAiB,EAAA;AACxC,MAAA,QAAA,CAAS,SAAS,CAAA,CAAA;AAAA,KACpB;AAEA,IAAI,IAAA,KAAA,CAAM,OAAQ,CAAA,SAAS,CAAG,EAAA;AAC5B,MAAA,KAAA,MAAW,SAAS,SAAW,EAAA;AAC7B,QAAA,IAAI,iBAAiB,eAAiB,EAAA;AACpC,UAAA,QAAA,CAAS,KAAK,CAAA,CAAA;AAAA,SAChB;AAAA,OACF;AAAA,KACF;AAAA,GACF;AACF,CAAA;AAKgB,SAAA,gBAAA,CACd,aACA,SACG,EAAA;AACH,EAAM,MAAA,WAAA,GAAc,mBAAK,WAAY,CAAA,KAAA,CAAA,CAAA;AAGrC,EAAA,KAAA,MAAW,OAAO,WAAa,EAAA;AAC7B,IAAA,MAAM,YAAY,WAAY,CAAA,GAAA,CAAA,CAAA;AAC9B,IAAA,IAAI,qBAAqB,eAAiB,EAAA;AACxC,MAAY,WAAA,CAAA,GAAA,CAAA,GAAO,UAAU,KAAM,EAAA,CAAA;AAAA,KACrC;AAGA,IAAI,IAAA,KAAA,CAAM,OAAQ,CAAA,SAAS,CAAG,EAAA;AAC5B,MAAA,MAAM,WAAgB,EAAC,CAAA;AACvB,MAAA,KAAA,MAAW,SAAS,SAAW,EAAA;AAC7B,QAAA,IAAI,iBAAiB,eAAiB,EAAA;AACpC,UAAS,QAAA,CAAA,IAAA,CAAK,KAAM,CAAA,KAAA,EAAO,CAAA,CAAA;AAAA,SACtB,MAAA;AACL,UAAA,QAAA,CAAS,KAAK,KAAK,CAAA,CAAA;AAAA,SACrB;AAAA,OACF;AACA,MAAA,WAAA,CAAY,GAAO,CAAA,GAAA,QAAA,CAAA;AAAA,KACrB;AAAA,GACF;AAEA,EAAO,MAAA,CAAA,MAAA,CAAO,aAAa,SAAS,CAAA,CAAA;AAEpC,EAAO,OAAA,IAAK,WAAY,CAAA,WAAA,CAAoB,WAAW,CAAA,CAAA;AACzD;;;;"}
@@ -0,0 +1,33 @@
1
+ export { isSceneObject } from './core/types.js';
2
+ export { SceneObjectStateChangedEvent } from './core/events.js';
3
+ export { sceneGraph } from './core/sceneGraph.js';
4
+ export { SceneObjectBase } from './core/SceneObjectBase.js';
5
+ export { SceneDataNode } from './core/SceneDataNode.js';
6
+ export { SceneDataTransformer } from './core/SceneDataTransformer.js';
7
+ export { SceneTimeRange } from './core/SceneTimeRange.js';
8
+ export { SceneQueryRunner } from './querying/SceneQueryRunner.js';
9
+ export { SceneVariableValueChangedEvent } from './variables/types.js';
10
+ export { FormatRegistryID, formatRegistry } from './variables/interpolation/formatRegistry.js';
11
+ import './variables/interpolation/ScopedVarsVariable.js';
12
+ import './variables/interpolation/defaults.js';
13
+ export { VariableValueSelectors } from './variables/components/VariableValueSelectors.js';
14
+ export { SceneVariableSet } from './variables/sets/SceneVariableSet.js';
15
+ export { ConstantVariable } from './variables/variants/ConstantVariable.js';
16
+ export { CustomVariable } from './variables/variants/CustomVariable.js';
17
+ export { DataSourceVariable } from './variables/variants/DataSourceVariable.js';
18
+ export { QueryVariable } from './variables/variants/query/QueryVariable.js';
19
+ export { TestVariable } from './variables/variants/TestVariable.js';
20
+ export { UrlSyncManager } from './services/UrlSyncManager.js';
21
+ export { SceneObjectUrlSyncConfig } from './services/SceneObjectUrlSyncConfig.js';
22
+ export { EmbeddedScene } from './components/Scene.js';
23
+ export { VizPanel } from './components/VizPanel/VizPanel.js';
24
+ export { NestedScene } from './components/NestedScene.js';
25
+ export { SceneCanvasText } from './components/SceneCanvasText.js';
26
+ export { SceneToolbarButton, SceneToolbarInput } from './components/SceneToolbarButton.js';
27
+ export { SceneTimePicker } from './components/SceneTimePicker.js';
28
+ export { ScenePanelRepeater } from './components/ScenePanelRepeater.js';
29
+ export { SceneSubMenu } from './components/SceneSubMenu.js';
30
+ export { SceneFlexLayout } from './components/layout/SceneFlexLayout.js';
31
+ export { SceneGridLayout } from './components/layout/SceneGridLayout.js';
32
+ export { SceneGridRow } from './components/layout/SceneGridRow.js';
33
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -0,0 +1,161 @@
1
+ import { cloneDeep } from 'lodash';
2
+ import { mergeMap, of, map } from 'rxjs';
3
+ import { CoreApp, rangeUtil, transformDataFrame } from '@grafana/data';
4
+ import { getRunRequest, getDataSourceSrv } from '@grafana/runtime';
5
+ import { SceneObjectBase } from '../core/SceneObjectBase.js';
6
+ import { sceneGraph } from '../core/sceneGraph.js';
7
+ import { VariableDependencyConfig } from '../variables/VariableDependencyConfig.js';
8
+
9
+ var __defProp = Object.defineProperty;
10
+ var __defProps = Object.defineProperties;
11
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
12
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
13
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
14
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
15
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
16
+ var __spreadValues = (a, b) => {
17
+ for (var prop in b || (b = {}))
18
+ if (__hasOwnProp.call(b, prop))
19
+ __defNormalProp(a, prop, b[prop]);
20
+ if (__getOwnPropSymbols)
21
+ for (var prop of __getOwnPropSymbols(b)) {
22
+ if (__propIsEnum.call(b, prop))
23
+ __defNormalProp(a, prop, b[prop]);
24
+ }
25
+ return a;
26
+ };
27
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
28
+ let counter = 100;
29
+ function getNextRequestId() {
30
+ return "QS" + counter++;
31
+ }
32
+ class SceneQueryRunner extends SceneObjectBase {
33
+ constructor() {
34
+ super(...arguments);
35
+ this._variableDependency = new VariableDependencyConfig(this, {
36
+ statePaths: ["queries"],
37
+ onReferencedVariableValueChanged: () => this.runQueries()
38
+ });
39
+ this.onDataReceived = (data) => {
40
+ this.setState({ data });
41
+ };
42
+ }
43
+ activate() {
44
+ super.activate();
45
+ const timeRange = sceneGraph.getTimeRange(this);
46
+ this._subs.add(
47
+ timeRange.subscribeToState({
48
+ next: (timeRange2) => {
49
+ this.runWithTimeRange(timeRange2.value);
50
+ }
51
+ })
52
+ );
53
+ if (this.shouldRunQueriesOnActivate()) {
54
+ this.runQueries();
55
+ }
56
+ }
57
+ shouldRunQueriesOnActivate() {
58
+ if (this.state.data) {
59
+ return false;
60
+ }
61
+ if (!this.state.maxDataPoints && this.state.maxDataPointsFromWidth && !this._containerWidth) {
62
+ return false;
63
+ }
64
+ return true;
65
+ }
66
+ deactivate() {
67
+ super.deactivate();
68
+ if (this._querySub) {
69
+ this._querySub.unsubscribe();
70
+ this._querySub = void 0;
71
+ }
72
+ }
73
+ setContainerWidth(width) {
74
+ if (!this._containerWidth && width > 0) {
75
+ this._containerWidth = width;
76
+ if (this.state.maxDataPointsFromWidth && !this.state.maxDataPoints) {
77
+ setTimeout(() => {
78
+ if (this.isActive && !this._querySub) {
79
+ this.runQueries();
80
+ }
81
+ }, 0);
82
+ }
83
+ } else {
84
+ this._containerWidth = width;
85
+ }
86
+ }
87
+ runQueries() {
88
+ const timeRange = sceneGraph.getTimeRange(this);
89
+ this.runWithTimeRange(timeRange.state.value);
90
+ }
91
+ getMaxDataPoints() {
92
+ var _a, _b;
93
+ return (_b = (_a = this.state.maxDataPoints) != null ? _a : this._containerWidth) != null ? _b : 500;
94
+ }
95
+ async runWithTimeRange(timeRange) {
96
+ const { datasource, minInterval, queries } = this.state;
97
+ const request = {
98
+ app: CoreApp.Dashboard,
99
+ requestId: getNextRequestId(),
100
+ timezone: "browser",
101
+ panelId: 1,
102
+ dashboardId: 1,
103
+ range: timeRange,
104
+ interval: "1s",
105
+ intervalMs: 1e3,
106
+ targets: cloneDeep(queries),
107
+ maxDataPoints: this.getMaxDataPoints(),
108
+ scopedVars: {},
109
+ startTime: Date.now()
110
+ };
111
+ try {
112
+ const ds = await getDataSource(datasource, request.scopedVars);
113
+ request.targets = request.targets.map((query) => {
114
+ if (!query.datasource) {
115
+ query.datasource = ds.getRef();
116
+ }
117
+ return query;
118
+ });
119
+ const lowerIntervalLimit = minInterval ? minInterval : ds.interval;
120
+ const norm = rangeUtil.calculateInterval(timeRange, request.maxDataPoints, lowerIntervalLimit);
121
+ request.scopedVars = Object.assign({}, request.scopedVars, {
122
+ __interval: { text: norm.interval, value: norm.interval },
123
+ __interval_ms: { text: norm.intervalMs.toString(), value: norm.intervalMs }
124
+ });
125
+ request.interval = norm.interval;
126
+ request.intervalMs = norm.intervalMs;
127
+ const runRequest = getRunRequest();
128
+ this._querySub = runRequest(ds, request).pipe(getTransformationsStream(this, this.state.transformations)).subscribe({
129
+ next: this.onDataReceived
130
+ });
131
+ } catch (err) {
132
+ console.error("PanelQueryRunner Error", err);
133
+ }
134
+ }
135
+ }
136
+ async function getDataSource(datasource, scopedVars) {
137
+ if (datasource && datasource.query) {
138
+ return datasource;
139
+ }
140
+ return await getDataSourceSrv().get(datasource, scopedVars);
141
+ }
142
+ const getTransformationsStream = (sceneObject, transformations) => (inputStream) => {
143
+ return inputStream.pipe(
144
+ mergeMap((data) => {
145
+ if (!transformations || transformations.length === 0) {
146
+ return of(data);
147
+ }
148
+ const replace = (option) => {
149
+ var _a;
150
+ return sceneGraph.interpolate(sceneObject, option, (_a = data == null ? void 0 : data.request) == null ? void 0 : _a.scopedVars);
151
+ };
152
+ transformations.forEach((transform) => {
153
+ transform.replace = replace;
154
+ });
155
+ return transformDataFrame(transformations, data.series).pipe(map((series) => __spreadProps(__spreadValues({}, data), { series })));
156
+ })
157
+ );
158
+ };
159
+
160
+ export { SceneQueryRunner, getNextRequestId, getTransformationsStream };
161
+ //# sourceMappingURL=SceneQueryRunner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SceneQueryRunner.js","sources":["../../../src/querying/SceneQueryRunner.ts"],"sourcesContent":["import { cloneDeep } from 'lodash';\nimport { mergeMap, MonoTypeOperatorFunction, Unsubscribable, map, of } from 'rxjs';\n\nimport {\n CoreApp,\n DataQuery,\n DataQueryRequest,\n DataSourceApi,\n DataSourceRef,\n DataTransformerConfig,\n PanelData,\n rangeUtil,\n ScopedVars,\n TimeRange,\n transformDataFrame,\n} from '@grafana/data';\nimport { getDataSourceSrv, getRunRequest } from '@grafana/runtime';\n\nimport { SceneObjectBase } from '../core/SceneObjectBase';\nimport { sceneGraph } from '../core/sceneGraph';\nimport { SceneObject, SceneObjectStatePlain } from '../core/types';\nimport { VariableDependencyConfig } from '../variables/VariableDependencyConfig';\n\nlet counter = 100;\n\nexport function getNextRequestId() {\n return 'QS' + counter++;\n}\n\nexport interface QueryRunnerState extends SceneObjectStatePlain {\n data?: PanelData;\n queries: DataQueryExtended[];\n transformations?: DataTransformerConfig[];\n datasource?: DataSourceRef;\n minInterval?: string;\n maxDataPoints?: number;\n // Non persisted state\n maxDataPointsFromWidth?: boolean;\n}\n\nexport interface DataQueryExtended extends DataQuery {\n [key: string]: any;\n}\n\nexport class SceneQueryRunner extends SceneObjectBase<QueryRunnerState> {\n private _querySub?: Unsubscribable;\n private _containerWidth?: number;\n\n protected _variableDependency = new VariableDependencyConfig(this, {\n statePaths: ['queries'],\n onReferencedVariableValueChanged: () => this.runQueries(),\n });\n\n public activate() {\n super.activate();\n\n const timeRange = sceneGraph.getTimeRange(this);\n\n this._subs.add(\n timeRange.subscribeToState({\n next: (timeRange) => {\n this.runWithTimeRange(timeRange.value);\n },\n })\n );\n\n if (this.shouldRunQueriesOnActivate()) {\n this.runQueries();\n }\n }\n\n private shouldRunQueriesOnActivate() {\n // If we already have data, no need\n // TODO validate that time range is similar and if not we should run queries again\n if (this.state.data) {\n return false;\n }\n\n // If no maxDataPoints specified we need might to wait for container width to be set from the outside\n if (!this.state.maxDataPoints && this.state.maxDataPointsFromWidth && !this._containerWidth) {\n return false;\n }\n\n return true;\n }\n\n public deactivate(): void {\n super.deactivate();\n\n if (this._querySub) {\n this._querySub.unsubscribe();\n this._querySub = undefined;\n }\n }\n\n public setContainerWidth(width: number) {\n // If we don't have a width we should run queries\n if (!this._containerWidth && width > 0) {\n this._containerWidth = width;\n\n // If we don't have maxDataPoints specifically set and maxDataPointsFromWidth is true\n if (this.state.maxDataPointsFromWidth && !this.state.maxDataPoints) {\n // As this is called from render path we need to wait for next tick before running queries\n setTimeout(() => {\n if (this.isActive && !this._querySub) {\n this.runQueries();\n }\n }, 0);\n }\n } else {\n // let's just remember the width until next query issue\n this._containerWidth = width;\n }\n }\n\n public runQueries() {\n const timeRange = sceneGraph.getTimeRange(this);\n this.runWithTimeRange(timeRange.state.value);\n }\n\n private getMaxDataPoints() {\n return this.state.maxDataPoints ?? this._containerWidth ?? 500;\n }\n\n private async runWithTimeRange(timeRange: TimeRange) {\n const { datasource, minInterval, queries } = this.state;\n\n const request: DataQueryRequest = {\n app: CoreApp.Dashboard,\n requestId: getNextRequestId(),\n timezone: 'browser',\n panelId: 1,\n dashboardId: 1,\n range: timeRange,\n interval: '1s',\n intervalMs: 1000,\n targets: cloneDeep(queries),\n maxDataPoints: this.getMaxDataPoints(),\n scopedVars: {},\n startTime: Date.now(),\n };\n\n try {\n const ds = await getDataSource(datasource, request.scopedVars);\n\n // Attach the data source name to each query\n request.targets = request.targets.map((query) => {\n if (!query.datasource) {\n query.datasource = ds.getRef();\n }\n return query;\n });\n\n // TODO interpolate minInterval\n const lowerIntervalLimit = minInterval ? minInterval : ds.interval;\n const norm = rangeUtil.calculateInterval(timeRange, request.maxDataPoints!, lowerIntervalLimit);\n\n // make shallow copy of scoped vars,\n // and add built in variables interval and interval_ms\n request.scopedVars = Object.assign({}, request.scopedVars, {\n __interval: { text: norm.interval, value: norm.interval },\n __interval_ms: { text: norm.intervalMs.toString(), value: norm.intervalMs },\n });\n\n request.interval = norm.interval;\n request.intervalMs = norm.intervalMs;\n\n const runRequest = getRunRequest();\n this._querySub = runRequest(ds, request)\n .pipe(getTransformationsStream(this, this.state.transformations))\n .subscribe({\n next: this.onDataReceived,\n });\n } catch (err) {\n console.error('PanelQueryRunner Error', err);\n }\n }\n\n private onDataReceived = (data: PanelData) => {\n this.setState({ data });\n };\n}\n\nasync function getDataSource(datasource: DataSourceRef | undefined, scopedVars: ScopedVars): Promise<DataSourceApi> {\n if (datasource && (datasource as any).query) {\n return datasource as DataSourceApi;\n }\n return await getDataSourceSrv().get(datasource as string, scopedVars);\n}\n\nexport const getTransformationsStream: (\n sceneObject: SceneObject,\n transformations?: DataTransformerConfig[]\n) => MonoTypeOperatorFunction<PanelData> = (sceneObject, transformations) => (inputStream) => {\n return inputStream.pipe(\n mergeMap((data) => {\n if (!transformations || transformations.length === 0) {\n return of(data);\n }\n\n const replace: (option?: string) => string = (option) => {\n return sceneGraph.interpolate(sceneObject, option, data?.request?.scopedVars);\n };\n\n transformations.forEach((transform: DataTransformerConfig) => {\n transform.replace = replace;\n });\n\n return transformDataFrame(transformations, data.series).pipe(map((series) => ({ ...data, series })));\n })\n );\n};\n"],"names":["timeRange"],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ class SceneObjectUrlSyncConfig {
2
+ constructor(_sceneObject, _options) {
3
+ this._sceneObject = _sceneObject;
4
+ this._keys = _options.keys;
5
+ }
6
+ getKeys() {
7
+ return this._keys;
8
+ }
9
+ getUrlState(state) {
10
+ return this._sceneObject.getUrlState(state);
11
+ }
12
+ updateFromUrl(values) {
13
+ this._sceneObject.updateFromUrl(values);
14
+ }
15
+ }
16
+
17
+ export { SceneObjectUrlSyncConfig };
18
+ //# sourceMappingURL=SceneObjectUrlSyncConfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SceneObjectUrlSyncConfig.js","sources":["../../../src/services/SceneObjectUrlSyncConfig.ts"],"sourcesContent":["import {\n SceneObjectState,\n SceneObjectUrlSyncHandler,\n SceneObjectWithUrlSync,\n SceneObjectUrlValues,\n} from '../core/types';\n\ninterface SceneObjectUrlSyncConfigOptions {\n keys: string[];\n}\n\nexport class SceneObjectUrlSyncConfig<TState extends SceneObjectState> implements SceneObjectUrlSyncHandler<TState> {\n private _keys: string[];\n\n public constructor(private _sceneObject: SceneObjectWithUrlSync<TState>, _options: SceneObjectUrlSyncConfigOptions) {\n this._keys = _options.keys;\n }\n\n public getKeys(): string[] {\n return this._keys;\n }\n\n public getUrlState(state: TState): SceneObjectUrlValues {\n return this._sceneObject.getUrlState(state);\n }\n\n public updateFromUrl(values: SceneObjectUrlValues): void {\n this._sceneObject.updateFromUrl(values);\n }\n}\n"],"names":[],"mappings":"AAWO,MAAM,wBAAuG,CAAA;AAAA,EAG3G,WAAA,CAAoB,cAA8C,QAA2C,EAAA;AAAzF,IAAA,IAAA,CAAA,YAAA,GAAA,YAAA,CAAA;AACzB,IAAA,IAAA,CAAK,QAAQ,QAAS,CAAA,IAAA,CAAA;AAAA,GACxB;AAAA,EAEO,OAAoB,GAAA;AACzB,IAAA,OAAO,IAAK,CAAA,KAAA,CAAA;AAAA,GACd;AAAA,EAEO,YAAY,KAAqC,EAAA;AACtD,IAAO,OAAA,IAAA,CAAK,YAAa,CAAA,WAAA,CAAY,KAAK,CAAA,CAAA;AAAA,GAC5C;AAAA,EAEO,cAAc,MAAoC,EAAA;AACvD,IAAK,IAAA,CAAA,YAAA,CAAa,cAAc,MAAM,CAAA,CAAA;AAAA,GACxC;AACF;;;;"}
@@ -0,0 +1,133 @@
1
+ import { isEqual } from 'lodash';
2
+ import { locationService } from '@grafana/runtime';
3
+ import { SceneObjectStateChangedEvent } from '../core/events.js';
4
+ import { forEachSceneObjectInState } from '../core/utils.js';
5
+
6
+ class UrlSyncManager {
7
+ constructor(sceneRoot) {
8
+ this.sceneRoot = sceneRoot;
9
+ this.initialStates = /* @__PURE__ */ new Map();
10
+ this.urlKeyMapper = new UniqueUrlKeyMapper();
11
+ this.onLocationUpdate = (location) => {
12
+ const urlParams = new URLSearchParams(location.search);
13
+ this.urlKeyMapper.rebuldIndex(this.sceneRoot);
14
+ this.syncSceneStateFromUrl(this.sceneRoot, urlParams);
15
+ };
16
+ this.onStateChanged = ({ payload }) => {
17
+ const changedObject = payload.changedObject;
18
+ if (changedObject.urlSync) {
19
+ const newUrlState = changedObject.urlSync.getUrlState(payload.newState);
20
+ const prevUrlState = changedObject.urlSync.getUrlState(payload.prevState);
21
+ const searchParams = locationService.getSearch();
22
+ const mappedUpdated = {};
23
+ this.urlKeyMapper.rebuldIndex(this.sceneRoot);
24
+ for (const [key, newUrlValue] of Object.entries(newUrlState)) {
25
+ const uniqueKey = this.urlKeyMapper.getUniqueKey(key, changedObject);
26
+ const currentUrlValue = searchParams.getAll(uniqueKey);
27
+ if (!isUrlValueEqual(currentUrlValue, newUrlValue)) {
28
+ mappedUpdated[uniqueKey] = newUrlValue;
29
+ if (!this.initialStates.has(uniqueKey) && prevUrlState[key] !== void 0) {
30
+ this.initialStates.set(uniqueKey, prevUrlState[key]);
31
+ }
32
+ }
33
+ }
34
+ if (Object.keys(mappedUpdated).length > 0) {
35
+ locationService.partial(mappedUpdated, true);
36
+ }
37
+ }
38
+ };
39
+ this.stateChangeSub = sceneRoot.subscribeToEvent(SceneObjectStateChangedEvent, this.onStateChanged);
40
+ this.locationListenerUnsub = locationService.getHistory().listen(this.onLocationUpdate);
41
+ }
42
+ initSync() {
43
+ const urlParams = locationService.getSearch();
44
+ this.urlKeyMapper.rebuldIndex(this.sceneRoot);
45
+ this.syncSceneStateFromUrl(this.sceneRoot, urlParams);
46
+ }
47
+ cleanUp() {
48
+ this.stateChangeSub.unsubscribe();
49
+ this.locationListenerUnsub();
50
+ }
51
+ syncSceneStateFromUrl(sceneObject, urlParams) {
52
+ if (sceneObject.urlSync) {
53
+ const urlState = {};
54
+ const currentState = sceneObject.urlSync.getUrlState(sceneObject.state);
55
+ for (const key of sceneObject.urlSync.getKeys()) {
56
+ const uniqueKey = this.urlKeyMapper.getUniqueKey(key, sceneObject);
57
+ const newValue = urlParams.getAll(uniqueKey);
58
+ const currentValue = currentState[key];
59
+ if (isUrlValueEqual(newValue, currentValue)) {
60
+ continue;
61
+ }
62
+ if (newValue.length > 0) {
63
+ if (Array.isArray(currentValue)) {
64
+ urlState[key] = newValue;
65
+ } else {
66
+ urlState[key] = newValue[0];
67
+ }
68
+ if (!this.initialStates.has(uniqueKey) && currentValue !== void 0) {
69
+ this.initialStates.set(uniqueKey, currentValue);
70
+ }
71
+ } else {
72
+ const initialValue = this.initialStates.get(uniqueKey);
73
+ if (initialValue !== void 0) {
74
+ urlState[key] = initialValue;
75
+ }
76
+ }
77
+ }
78
+ if (Object.keys(urlState).length > 0) {
79
+ sceneObject.urlSync.updateFromUrl(urlState);
80
+ }
81
+ }
82
+ forEachSceneObjectInState(sceneObject.state, (obj) => this.syncSceneStateFromUrl(obj, urlParams));
83
+ }
84
+ }
85
+ class UniqueUrlKeyMapper {
86
+ constructor() {
87
+ this.index = /* @__PURE__ */ new Map();
88
+ }
89
+ getUniqueKey(key, obj) {
90
+ const objectsWithKey = this.index.get(key);
91
+ if (!objectsWithKey) {
92
+ throw new Error("Cannot find any scene object that uses the key '" + key + "'");
93
+ }
94
+ const address = objectsWithKey.findIndex((o) => o.sceneObject === obj);
95
+ if (address > 0) {
96
+ return `${key}-${address + 1}`;
97
+ }
98
+ return key;
99
+ }
100
+ rebuldIndex(root) {
101
+ this.index.clear();
102
+ this.buildIndex(root, 0);
103
+ }
104
+ buildIndex(sceneObject, depth) {
105
+ if (sceneObject.urlSync) {
106
+ for (const key of sceneObject.urlSync.getKeys()) {
107
+ const hit = this.index.get(key);
108
+ if (hit) {
109
+ hit.push({ sceneObject, depth });
110
+ hit.sort((a, b) => a.depth - b.depth);
111
+ } else {
112
+ this.index.set(key, [{ sceneObject, depth }]);
113
+ }
114
+ }
115
+ }
116
+ forEachSceneObjectInState(sceneObject.state, (obj) => this.buildIndex(obj, depth + 1));
117
+ }
118
+ }
119
+ function isUrlValueEqual(currentUrlValue, newUrlValue) {
120
+ if (currentUrlValue.length === 0 && newUrlValue == null) {
121
+ return true;
122
+ }
123
+ if (!Array.isArray(newUrlValue) && (currentUrlValue == null ? void 0 : currentUrlValue.length) === 1) {
124
+ return newUrlValue === currentUrlValue[0];
125
+ }
126
+ if ((newUrlValue == null ? void 0 : newUrlValue.length) === 0 && currentUrlValue === null) {
127
+ return true;
128
+ }
129
+ return isEqual(currentUrlValue, newUrlValue);
130
+ }
131
+
132
+ export { UrlSyncManager, isUrlValueEqual };
133
+ //# sourceMappingURL=UrlSyncManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UrlSyncManager.js","sources":["../../../src/services/UrlSyncManager.ts"],"sourcesContent":["import { Location } from 'history';\nimport { isEqual } from 'lodash';\nimport { Unsubscribable } from 'rxjs';\n\nimport { locationService } from '@grafana/runtime';\n\nimport { SceneObjectStateChangedEvent } from '../core/events';\nimport { SceneObject, SceneObjectUrlValue, SceneObjectUrlValues } from '../core/types';\nimport { forEachSceneObjectInState } from '../core/utils';\n\nexport class UrlSyncManager {\n private locationListenerUnsub: () => void;\n private stateChangeSub: Unsubscribable;\n private initialStates: Map<string, SceneObjectUrlValue> = new Map();\n private urlKeyMapper = new UniqueUrlKeyMapper();\n\n public constructor(private sceneRoot: SceneObject) {\n this.stateChangeSub = sceneRoot.subscribeToEvent(SceneObjectStateChangedEvent, this.onStateChanged);\n this.locationListenerUnsub = locationService.getHistory().listen(this.onLocationUpdate);\n }\n\n /**\n * Updates the current scene state to match URL state.\n */\n public initSync() {\n const urlParams = locationService.getSearch();\n this.urlKeyMapper.rebuldIndex(this.sceneRoot);\n this.syncSceneStateFromUrl(this.sceneRoot, urlParams);\n }\n\n private onLocationUpdate = (location: Location) => {\n const urlParams = new URLSearchParams(location.search);\n // Rebuild key mapper index before starting sync\n this.urlKeyMapper.rebuldIndex(this.sceneRoot);\n // Sync scene state tree from url\n this.syncSceneStateFromUrl(this.sceneRoot, urlParams);\n };\n\n private onStateChanged = ({ payload }: SceneObjectStateChangedEvent) => {\n const changedObject = payload.changedObject;\n\n if (changedObject.urlSync) {\n const newUrlState = changedObject.urlSync.getUrlState(payload.newState);\n const prevUrlState = changedObject.urlSync.getUrlState(payload.prevState);\n\n const searchParams = locationService.getSearch();\n const mappedUpdated: SceneObjectUrlValues = {};\n\n this.urlKeyMapper.rebuldIndex(this.sceneRoot);\n\n for (const [key, newUrlValue] of Object.entries(newUrlState)) {\n const uniqueKey = this.urlKeyMapper.getUniqueKey(key, changedObject);\n const currentUrlValue = searchParams.getAll(uniqueKey);\n\n if (!isUrlValueEqual(currentUrlValue, newUrlValue)) {\n mappedUpdated[uniqueKey] = newUrlValue;\n\n // Remember the initial state so we can go back to it\n if (!this.initialStates.has(uniqueKey) && prevUrlState[key] !== undefined) {\n this.initialStates.set(uniqueKey, prevUrlState[key]);\n }\n }\n }\n\n if (Object.keys(mappedUpdated).length > 0) {\n locationService.partial(mappedUpdated, true);\n }\n }\n };\n\n public cleanUp() {\n this.stateChangeSub.unsubscribe();\n this.locationListenerUnsub();\n }\n\n private syncSceneStateFromUrl(sceneObject: SceneObject, urlParams: URLSearchParams) {\n if (sceneObject.urlSync) {\n const urlState: SceneObjectUrlValues = {};\n const currentState = sceneObject.urlSync.getUrlState(sceneObject.state);\n\n for (const key of sceneObject.urlSync.getKeys()) {\n const uniqueKey = this.urlKeyMapper.getUniqueKey(key, sceneObject);\n const newValue = urlParams.getAll(uniqueKey);\n const currentValue = currentState[key];\n\n if (isUrlValueEqual(newValue, currentValue)) {\n continue;\n }\n\n if (newValue.length > 0) {\n if (Array.isArray(currentValue)) {\n urlState[key] = newValue;\n } else {\n urlState[key] = newValue[0];\n }\n\n // Remember the initial state so we can go back to it\n if (!this.initialStates.has(uniqueKey) && currentValue !== undefined) {\n this.initialStates.set(uniqueKey, currentValue);\n }\n } else {\n const initialValue = this.initialStates.get(uniqueKey);\n if (initialValue !== undefined) {\n urlState[key] = initialValue;\n }\n }\n }\n\n if (Object.keys(urlState).length > 0) {\n sceneObject.urlSync.updateFromUrl(urlState);\n }\n }\n\n forEachSceneObjectInState(sceneObject.state, (obj) => this.syncSceneStateFromUrl(obj, urlParams));\n }\n}\n\ninterface SceneObjectWithDepth {\n sceneObject: SceneObject;\n depth: number;\n}\nclass UniqueUrlKeyMapper {\n private index = new Map<string, SceneObjectWithDepth[]>();\n\n public getUniqueKey(key: string, obj: SceneObject) {\n const objectsWithKey = this.index.get(key);\n if (!objectsWithKey) {\n throw new Error(\"Cannot find any scene object that uses the key '\" + key + \"'\");\n }\n\n const address = objectsWithKey.findIndex((o) => o.sceneObject === obj);\n if (address > 0) {\n return `${key}-${address + 1}`;\n }\n\n return key;\n }\n\n public rebuldIndex(root: SceneObject) {\n this.index.clear();\n this.buildIndex(root, 0);\n }\n\n private buildIndex(sceneObject: SceneObject, depth: number) {\n if (sceneObject.urlSync) {\n for (const key of sceneObject.urlSync.getKeys()) {\n const hit = this.index.get(key);\n if (hit) {\n hit.push({ sceneObject, depth });\n hit.sort((a, b) => a.depth - b.depth);\n } else {\n this.index.set(key, [{ sceneObject, depth }]);\n }\n }\n }\n\n forEachSceneObjectInState(sceneObject.state, (obj) => this.buildIndex(obj, depth + 1));\n }\n}\n\nexport function isUrlValueEqual(currentUrlValue: string[], newUrlValue: SceneObjectUrlValue): boolean {\n if (currentUrlValue.length === 0 && newUrlValue == null) {\n return true;\n }\n\n if (!Array.isArray(newUrlValue) && currentUrlValue?.length === 1) {\n return newUrlValue === currentUrlValue[0];\n }\n\n if (newUrlValue?.length === 0 && currentUrlValue === null) {\n return true;\n }\n\n // We have two arrays, lets compare them\n return isEqual(currentUrlValue, newUrlValue);\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ function buildMetricTree(parent, depth) {
2
+ const chars = ["A", "B", "C", "D", "E", "F", "G", "H"];
3
+ const children = [];
4
+ if (depth > 5) {
5
+ return [];
6
+ }
7
+ for (const letter of chars) {
8
+ const nodeName = `${parent}${letter}`;
9
+ children.push({
10
+ name: nodeName,
11
+ children: buildMetricTree(nodeName, depth + 1)
12
+ });
13
+ }
14
+ return children;
15
+ }
16
+ function queryTree(children, query, queryIndex) {
17
+ if (queryIndex >= query.length) {
18
+ return children;
19
+ }
20
+ if (query[queryIndex] === "*") {
21
+ return children;
22
+ }
23
+ const nodeQuery = query[queryIndex];
24
+ let result = [];
25
+ let namesToMatch = [nodeQuery];
26
+ if (nodeQuery.startsWith("{")) {
27
+ namesToMatch = nodeQuery.replace(/\{|\}/g, "").split(",");
28
+ }
29
+ for (const node of children) {
30
+ for (const nameToMatch of namesToMatch) {
31
+ if (nameToMatch.indexOf("*") !== -1) {
32
+ const pattern = nameToMatch.replace("*", "");
33
+ const regex = new RegExp(`^${pattern}.*`, "gi");
34
+ if (regex.test(node.name)) {
35
+ result = result.concat(queryTree([node], query, queryIndex + 1));
36
+ }
37
+ } else if (node.name === nameToMatch) {
38
+ result = result.concat(queryTree(node.children, query, queryIndex + 1));
39
+ }
40
+ }
41
+ }
42
+ return result;
43
+ }
44
+ function queryMetricTree(query) {
45
+ if (query.indexOf("value") === 0) {
46
+ return [{ name: query, children: [] }];
47
+ }
48
+ const children = buildMetricTree("", 0);
49
+ return queryTree(children, query.split("."), 0);
50
+ }
51
+
52
+ export { queryMetricTree };
53
+ //# sourceMappingURL=metricTree.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metricTree.js","sources":["../../../src/utils/metricTree.ts"],"sourcesContent":["export interface TreeNode {\n name: string;\n children: TreeNode[];\n}\n\n/*\n * Builds a nested tree like\n * [\n * {\n * name: 'A',\n * children: [\n * { name: 'AA', children: [] },\n * { name: 'AB', children: [] },\n * ]\n * }\n * ]\n */\nfunction buildMetricTree(parent: string, depth: number): TreeNode[] {\n const chars = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'];\n const children: TreeNode[] = [];\n\n if (depth > 5) {\n return [];\n }\n\n for (const letter of chars) {\n const nodeName = `${parent}${letter}`;\n children.push({\n name: nodeName,\n children: buildMetricTree(nodeName, depth + 1),\n });\n }\n\n return children;\n}\n\nfunction queryTree(children: TreeNode[], query: string[], queryIndex: number): TreeNode[] {\n if (queryIndex >= query.length) {\n return children;\n }\n\n if (query[queryIndex] === '*') {\n return children;\n }\n\n const nodeQuery = query[queryIndex];\n let result: TreeNode[] = [];\n let namesToMatch = [nodeQuery];\n\n // handle glob queries\n if (nodeQuery.startsWith('{')) {\n namesToMatch = nodeQuery.replace(/\\{|\\}/g, '').split(',');\n }\n\n for (const node of children) {\n for (const nameToMatch of namesToMatch) {\n if (nameToMatch.indexOf('*') !== -1) {\n const pattern = nameToMatch.replace('*', '');\n const regex = new RegExp(`^${pattern}.*`, 'gi');\n if (regex.test(node.name)) {\n result = result.concat(queryTree([node], query, queryIndex + 1));\n }\n } else if (node.name === nameToMatch) {\n result = result.concat(queryTree(node.children, query, queryIndex + 1));\n }\n }\n }\n\n return result;\n}\n\nexport function queryMetricTree(query: string): TreeNode[] {\n if (query.indexOf('value') === 0) {\n return [{ name: query, children: [] }];\n }\n\n const children = buildMetricTree('', 0);\n return queryTree(children, query.split('.'), 0);\n}\n"],"names":[],"mappings":"AAiBA,SAAS,eAAA,CAAgB,QAAgB,KAA2B,EAAA;AAClE,EAAM,MAAA,KAAA,GAAQ,CAAC,GAAK,EAAA,GAAA,EAAK,KAAK,GAAK,EAAA,GAAA,EAAK,GAAK,EAAA,GAAA,EAAK,GAAG,CAAA,CAAA;AACrD,EAAA,MAAM,WAAuB,EAAC,CAAA;AAE9B,EAAA,IAAI,QAAQ,CAAG,EAAA;AACb,IAAA,OAAO,EAAC,CAAA;AAAA,GACV;AAEA,EAAA,KAAA,MAAW,UAAU,KAAO,EAAA;AAC1B,IAAM,MAAA,QAAA,GAAW,GAAG,MAAS,CAAA,EAAA,MAAA,CAAA,CAAA,CAAA;AAC7B,IAAA,QAAA,CAAS,IAAK,CAAA;AAAA,MACZ,IAAM,EAAA,QAAA;AAAA,MACN,QAAU,EAAA,eAAA,CAAgB,QAAU,EAAA,KAAA,GAAQ,CAAC,CAAA;AAAA,KAC9C,CAAA,CAAA;AAAA,GACH;AAEA,EAAO,OAAA,QAAA,CAAA;AACT,CAAA;AAEA,SAAS,SAAA,CAAU,QAAsB,EAAA,KAAA,EAAiB,UAAgC,EAAA;AACxF,EAAI,IAAA,UAAA,IAAc,MAAM,MAAQ,EAAA;AAC9B,IAAO,OAAA,QAAA,CAAA;AAAA,GACT;AAEA,EAAI,IAAA,KAAA,CAAM,gBAAgB,GAAK,EAAA;AAC7B,IAAO,OAAA,QAAA,CAAA;AAAA,GACT;AAEA,EAAA,MAAM,YAAY,KAAM,CAAA,UAAA,CAAA,CAAA;AACxB,EAAA,IAAI,SAAqB,EAAC,CAAA;AAC1B,EAAI,IAAA,YAAA,GAAe,CAAC,SAAS,CAAA,CAAA;AAG7B,EAAI,IAAA,SAAA,CAAU,UAAW,CAAA,GAAG,CAAG,EAAA;AAC7B,IAAA,YAAA,GAAe,UAAU,OAAQ,CAAA,QAAA,EAAU,EAAE,CAAA,CAAE,MAAM,GAAG,CAAA,CAAA;AAAA,GAC1D;AAEA,EAAA,KAAA,MAAW,QAAQ,QAAU,EAAA;AAC3B,IAAA,KAAA,MAAW,eAAe,YAAc,EAAA;AACtC,MAAA,IAAI,WAAY,CAAA,OAAA,CAAQ,GAAG,CAAA,KAAM,CAAI,CAAA,EAAA;AACnC,QAAA,MAAM,OAAU,GAAA,WAAA,CAAY,OAAQ,CAAA,GAAA,EAAK,EAAE,CAAA,CAAA;AAC3C,QAAA,MAAM,KAAQ,GAAA,IAAI,MAAO,CAAA,CAAA,CAAA,EAAI,aAAa,IAAI,CAAA,CAAA;AAC9C,QAAA,IAAI,KAAM,CAAA,IAAA,CAAK,IAAK,CAAA,IAAI,CAAG,EAAA;AACzB,UAAS,MAAA,GAAA,MAAA,CAAO,OAAO,SAAU,CAAA,CAAC,IAAI,CAAG,EAAA,KAAA,EAAO,UAAa,GAAA,CAAC,CAAC,CAAA,CAAA;AAAA,SACjE;AAAA,OACF,MAAA,IAAW,IAAK,CAAA,IAAA,KAAS,WAAa,EAAA;AACpC,QAAS,MAAA,GAAA,MAAA,CAAO,OAAO,SAAU,CAAA,IAAA,CAAK,UAAU,KAAO,EAAA,UAAA,GAAa,CAAC,CAAC,CAAA,CAAA;AAAA,OACxE;AAAA,KACF;AAAA,GACF;AAEA,EAAO,OAAA,MAAA,CAAA;AACT,CAAA;AAEO,SAAS,gBAAgB,KAA2B,EAAA;AACzD,EAAA,IAAI,KAAM,CAAA,OAAA,CAAQ,OAAO,CAAA,KAAM,CAAG,EAAA;AAChC,IAAA,OAAO,CAAC,EAAE,IAAA,EAAM,OAAO,QAAU,EAAA,IAAI,CAAA,CAAA;AAAA,GACvC;AAEA,EAAM,MAAA,QAAA,GAAW,eAAgB,CAAA,EAAA,EAAI,CAAC,CAAA,CAAA;AACtC,EAAA,OAAO,UAAU,QAAU,EAAA,KAAA,CAAM,KAAM,CAAA,GAAG,GAAG,CAAC,CAAA,CAAA;AAChD;;;;"}
@@ -0,0 +1,86 @@
1
+ import { VARIABLE_REGEX } from './constants.js';
2
+
3
+ class VariableDependencyConfig {
4
+ constructor(_sceneObject, options) {
5
+ this._sceneObject = _sceneObject;
6
+ this._dependencies = /* @__PURE__ */ new Set();
7
+ this.scanCount = 0;
8
+ this.defaultHandlerReferencedVariableValueChanged = () => {
9
+ this._sceneObject.forceRender();
10
+ };
11
+ var _a;
12
+ this._statePaths = options.statePaths;
13
+ this._onReferencedVariableValueChanged = (_a = options.onReferencedVariableValueChanged) != null ? _a : this.defaultHandlerReferencedVariableValueChanged;
14
+ }
15
+ hasDependencyOn(name) {
16
+ return this.getNames().has(name);
17
+ }
18
+ variableValuesChanged(variables) {
19
+ const deps = this.getNames();
20
+ for (const variable of variables) {
21
+ if (deps.has(variable.state.name)) {
22
+ this._onReferencedVariableValueChanged();
23
+ return;
24
+ }
25
+ }
26
+ }
27
+ getNames() {
28
+ const prevState = this._state;
29
+ const newState = this._state = this._sceneObject.state;
30
+ if (!prevState) {
31
+ this.scanStateForDependencies(this._state);
32
+ return this._dependencies;
33
+ }
34
+ if (newState !== prevState) {
35
+ if (this._statePaths) {
36
+ for (const path of this._statePaths) {
37
+ if (newState[path] !== prevState[path]) {
38
+ this.scanStateForDependencies(newState);
39
+ break;
40
+ }
41
+ }
42
+ } else {
43
+ this.scanStateForDependencies(newState);
44
+ }
45
+ }
46
+ return this._dependencies;
47
+ }
48
+ scanStateForDependencies(state) {
49
+ this._dependencies.clear();
50
+ this.scanCount += 1;
51
+ if (this._statePaths) {
52
+ for (const path of this._statePaths) {
53
+ const value = state[path];
54
+ if (value) {
55
+ this.extractVariablesFrom(value);
56
+ }
57
+ }
58
+ } else {
59
+ this.extractVariablesFrom(state);
60
+ }
61
+ }
62
+ extractVariablesFrom(value) {
63
+ VARIABLE_REGEX.lastIndex = 0;
64
+ const stringToCheck = typeof value !== "string" ? safeStringifyValue(value) : value;
65
+ const matches = stringToCheck.matchAll(VARIABLE_REGEX);
66
+ if (!matches) {
67
+ return;
68
+ }
69
+ for (const match of matches) {
70
+ const [, var1, var2, , var3] = match;
71
+ const variableName = var1 || var2 || var3;
72
+ this._dependencies.add(variableName);
73
+ }
74
+ }
75
+ }
76
+ const safeStringifyValue = (value) => {
77
+ try {
78
+ return JSON.stringify(value, null);
79
+ } catch (error) {
80
+ console.error(error);
81
+ }
82
+ return "";
83
+ };
84
+
85
+ export { VariableDependencyConfig };
86
+ //# sourceMappingURL=VariableDependencyConfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VariableDependencyConfig.js","sources":["../../../src/variables/VariableDependencyConfig.ts"],"sourcesContent":["import { SceneObject, SceneObjectState } from '../core/types';\nimport { VARIABLE_REGEX } from './constants';\n\nimport { SceneVariable, SceneVariableDependencyConfigLike } from './types';\n\ninterface VariableDependencyConfigOptions<TState extends SceneObjectState> {\n /**\n * State paths to scan / extract variable dependencies from. Leave empty to scan all paths.\n */\n statePaths?: Array<keyof TState>;\n /**\n * Optional way to customize how to handle when a dependent variable changes\n * If not specified the default behavior is to trigger a re-render\n */\n onReferencedVariableValueChanged?: () => void;\n}\n\nexport class VariableDependencyConfig<TState extends SceneObjectState> implements SceneVariableDependencyConfigLike {\n private _state: TState | undefined;\n private _dependencies = new Set<string>();\n private _statePaths?: Array<keyof TState>;\n private _onReferencedVariableValueChanged: () => void;\n\n public scanCount = 0;\n\n public constructor(private _sceneObject: SceneObject<TState>, options: VariableDependencyConfigOptions<TState>) {\n this._statePaths = options.statePaths;\n this._onReferencedVariableValueChanged =\n options.onReferencedVariableValueChanged ?? this.defaultHandlerReferencedVariableValueChanged;\n }\n\n /**\n * Used to check for dependency on a specific variable\n */\n public hasDependencyOn(name: string): boolean {\n return this.getNames().has(name);\n }\n\n /**\n * This is called whenever any set of variables have new values. It up to this implementation to check if it's relevant given the current dependencies.\n */\n public variableValuesChanged(variables: Set<SceneVariable>) {\n const deps = this.getNames();\n\n for (const variable of variables) {\n if (deps.has(variable.state.name)) {\n this._onReferencedVariableValueChanged();\n return;\n }\n }\n }\n\n /**\n * Only way to force a re-render is to update state right now\n */\n private defaultHandlerReferencedVariableValueChanged = () => {\n this._sceneObject.forceRender();\n };\n\n public getNames(): Set<string> {\n const prevState = this._state;\n const newState = (this._state = this._sceneObject.state);\n\n if (!prevState) {\n // First time we always scan for dependencies\n this.scanStateForDependencies(this._state);\n return this._dependencies;\n }\n\n // Second time we only scan if state is a different and if any specific state path has changed\n if (newState !== prevState) {\n if (this._statePaths) {\n for (const path of this._statePaths) {\n if (newState[path] !== prevState[path]) {\n this.scanStateForDependencies(newState);\n break;\n }\n }\n } else {\n this.scanStateForDependencies(newState);\n }\n }\n\n return this._dependencies;\n }\n\n private scanStateForDependencies(state: TState) {\n this._dependencies.clear();\n this.scanCount += 1;\n\n if (this._statePaths) {\n for (const path of this._statePaths) {\n const value = state[path];\n if (value) {\n this.extractVariablesFrom(value);\n }\n }\n } else {\n this.extractVariablesFrom(state);\n }\n }\n\n private extractVariablesFrom(value: unknown) {\n VARIABLE_REGEX.lastIndex = 0;\n\n const stringToCheck = typeof value !== 'string' ? safeStringifyValue(value) : value;\n\n const matches = stringToCheck.matchAll(VARIABLE_REGEX);\n if (!matches) {\n return;\n }\n\n for (const match of matches) {\n const [, var1, var2, , var3] = match;\n const variableName = var1 || var2 || var3;\n this._dependencies.add(variableName);\n }\n }\n}\n\nconst safeStringifyValue = (value: unknown) => {\n try {\n return JSON.stringify(value, null);\n } catch (error) {\n console.error(error);\n }\n\n return '';\n};\n"],"names":[],"mappings":"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"}