@grafana/scenes 6.33.1--canary.1235.17408464975.0 → 6.34.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.
- package/CHANGELOG.md +17 -0
- package/dist/esm/behaviors/SceneRenderProfiler.js +19 -103
- package/dist/esm/behaviors/SceneRenderProfiler.js.map +1 -1
- package/dist/esm/components/SceneTimeRangeCompare.js +1 -17
- package/dist/esm/components/SceneTimeRangeCompare.js.map +1 -1
- package/dist/esm/utils/writeSceneLog.js +1 -10
- package/dist/esm/utils/writeSceneLog.js.map +1 -1
- package/dist/index.d.ts +0 -29
- package/dist/index.js +43 -331
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/dist/esm/behaviors/LongFrameDetector.js +0 -185
- package/dist/esm/behaviors/LongFrameDetector.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
# v6.34.0 (Wed Sep 03 2025)
|
|
2
|
+
|
|
3
|
+
#### 🚀 Enhancement
|
|
4
|
+
|
|
5
|
+
- SceneTimeRangeCompare: Export time shift as util [#1221](https://github.com/grafana/scenes/pull/1221) ([@drew08t](https://github.com/drew08t))
|
|
6
|
+
|
|
7
|
+
#### 🐛 Bug Fix
|
|
8
|
+
|
|
9
|
+
- Add SceneRenderProfiler integration tests [#1234](https://github.com/grafana/scenes/pull/1234) ([@dprokop](https://github.com/dprokop))
|
|
10
|
+
|
|
11
|
+
#### Authors: 2
|
|
12
|
+
|
|
13
|
+
- Dominik Prokop ([@dprokop](https://github.com/dprokop))
|
|
14
|
+
- Drew Slobodnjak ([@drew08t](https://github.com/drew08t))
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
1
18
|
# v6.33.0 (Tue Sep 02 2025)
|
|
2
19
|
|
|
3
20
|
#### 🚀 Enhancement
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { writeSceneLog
|
|
2
|
-
import { LongFrameDetector } from './LongFrameDetector.js';
|
|
1
|
+
import { writeSceneLog } from '../utils/writeSceneLog.js';
|
|
3
2
|
|
|
4
3
|
var __typeError = (msg) => {
|
|
5
4
|
throw TypeError(msg);
|
|
@@ -8,17 +7,9 @@ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot
|
|
|
8
7
|
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
|
|
9
8
|
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
10
9
|
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), member.set(obj, value), value);
|
|
11
|
-
var
|
|
12
|
-
set _(value) {
|
|
13
|
-
__privateSet(obj, member, value);
|
|
14
|
-
},
|
|
15
|
-
get _() {
|
|
16
|
-
return __privateGet(obj, member, getter);
|
|
17
|
-
}
|
|
18
|
-
});
|
|
19
|
-
var _profileInProgress, _profileStartTs, _trailAnimationFrameId, _recordedTrailingSpans, _longFrameDetector, _longFramesCount, _longFramesTotalTime, _visibilityChangeHandler;
|
|
10
|
+
var _profileInProgress, _profileStartTs, _trailAnimationFrameId, _recordedTrailingSpans, _visibilityChangeHandler;
|
|
20
11
|
const POST_STORM_WINDOW = 2e3;
|
|
21
|
-
const
|
|
12
|
+
const SPAN_THRESHOLD = 30;
|
|
22
13
|
const TAB_INACTIVE_THRESHOLD = 1e3;
|
|
23
14
|
class SceneRenderProfiler {
|
|
24
15
|
constructor(queryController) {
|
|
@@ -28,13 +19,9 @@ class SceneRenderProfiler {
|
|
|
28
19
|
__privateAdd(this, _trailAnimationFrameId, null);
|
|
29
20
|
// Will keep measured lengths trailing frames
|
|
30
21
|
__privateAdd(this, _recordedTrailingSpans, []);
|
|
31
|
-
// Long frame tracking
|
|
32
|
-
__privateAdd(this, _longFrameDetector);
|
|
33
|
-
__privateAdd(this, _longFramesCount, 0);
|
|
34
|
-
__privateAdd(this, _longFramesTotalTime, 0);
|
|
35
22
|
__privateAdd(this, _visibilityChangeHandler, null);
|
|
36
23
|
this.measureTrailingFrames = (measurementStartTs, lastFrameTime, profileStartTs) => {
|
|
37
|
-
var _a
|
|
24
|
+
var _a;
|
|
38
25
|
const currentFrameTime = performance.now();
|
|
39
26
|
const frameLength = currentFrameTime - lastFrameTime;
|
|
40
27
|
if (frameLength > TAB_INACTIVE_THRESHOLD) {
|
|
@@ -53,60 +40,18 @@ class SceneRenderProfiler {
|
|
|
53
40
|
const slowFrames = processRecordedSpans(__privateGet(this, _recordedTrailingSpans));
|
|
54
41
|
const slowFramesTime = slowFrames.reduce((acc, val) => acc + val, 0);
|
|
55
42
|
writeSceneLog(
|
|
56
|
-
|
|
57
|
-
|
|
43
|
+
this.constructor.name,
|
|
44
|
+
"Profile tail recorded, slow frames duration:",
|
|
45
|
+
slowFramesTime,
|
|
46
|
+
slowFrames,
|
|
47
|
+
__privateGet(this, _profileInProgress)
|
|
58
48
|
);
|
|
59
|
-
writeSceneLog("", ` \u251C\u2500 Origin: ${((_a = __privateGet(this, _profileInProgress)) == null ? void 0 : _a.origin) || "unknown"}`);
|
|
60
|
-
writeSceneLog("", ` \u2514\u2500 Crumbs:`, ((_b = __privateGet(this, _profileInProgress)) == null ? void 0 : _b.crumbs) || []);
|
|
61
49
|
__privateSet(this, _recordedTrailingSpans, []);
|
|
62
50
|
const profileDuration = measurementStartTs - profileStartTs;
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const startMarkName = `Dashboard Profile Start: ${profileName}`;
|
|
68
|
-
try {
|
|
69
|
-
performance.measure(
|
|
70
|
-
`Dashboard Profile: ${profileName} (${totalTime.toFixed(1)}ms)`,
|
|
71
|
-
startMarkName,
|
|
72
|
-
`Dashboard Profile End: ${profileName}`
|
|
73
|
-
);
|
|
74
|
-
} catch (e) {
|
|
75
|
-
performance.mark(`Dashboard Profile Complete: ${profileName} (${totalTime.toFixed(1)}ms)`);
|
|
76
|
-
}
|
|
77
|
-
if (slowFrames.length > 0) {
|
|
78
|
-
const slowFramesMarkName = `Slow Frames Summary: ${slowFrames.length} frames (${slowFramesTime.toFixed(
|
|
79
|
-
1
|
|
80
|
-
)}ms)`;
|
|
81
|
-
performance.mark(slowFramesMarkName);
|
|
82
|
-
slowFrames.forEach((frameTime, index) => {
|
|
83
|
-
if (frameTime > 16) {
|
|
84
|
-
try {
|
|
85
|
-
const frameStartTime = __privateGet(this, _profileStartTs) + profileDuration + (index > 0 ? slowFrames.slice(0, index).reduce((sum, t) => sum + t, 0) : 0);
|
|
86
|
-
const frameId = `slow-frame-${index}`;
|
|
87
|
-
const frameStartMark = `${frameId}-start`;
|
|
88
|
-
const frameEndMark = `${frameId}-end`;
|
|
89
|
-
performance.mark(frameStartMark, { startTime: frameStartTime });
|
|
90
|
-
performance.mark(frameEndMark, { startTime: frameStartTime + frameTime });
|
|
91
|
-
performance.measure(`Slow Frame ${index + 1}: ${frameTime.toFixed(1)}ms`, frameStartMark, frameEndMark);
|
|
92
|
-
} catch (e) {
|
|
93
|
-
performance.mark(`Slow Frame ${index + 1}: ${frameTime.toFixed(1)}ms`);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
const completionTimestamp = performance.now();
|
|
100
|
-
writeSceneLog("SceneRenderProfiler", "Profile completed");
|
|
101
|
-
writeSceneLog("", ` \u251C\u2500 Timestamp: ${completionTimestamp.toFixed(1)}ms`);
|
|
102
|
-
writeSceneLog("", ` \u251C\u2500 Total time: ${(profileDuration + slowFramesTime).toFixed(1)}ms`);
|
|
103
|
-
writeSceneLog("", ` \u251C\u2500 Slow frames: ${slowFramesTime}ms (${slowFrames.length} frames)`);
|
|
104
|
-
writeSceneLog("", ` \u2514\u2500 Long frames: ${__privateGet(this, _longFramesTotalTime)}ms (${__privateGet(this, _longFramesCount)} frames)`);
|
|
105
|
-
__privateGet(this, _longFrameDetector).stop();
|
|
106
|
-
writeSceneLogStyled(
|
|
107
|
-
"SceneRenderProfiler",
|
|
108
|
-
`Stopped long frame detection - profile complete at ${completionTimestamp.toFixed(1)}ms`,
|
|
109
|
-
"color: #00CC00; font-weight: bold;"
|
|
51
|
+
writeSceneLog(
|
|
52
|
+
this.constructor.name,
|
|
53
|
+
"Stoped recording, total measured time (network included):",
|
|
54
|
+
profileDuration + slowFramesTime
|
|
110
55
|
);
|
|
111
56
|
__privateSet(this, _trailAnimationFrameId, null);
|
|
112
57
|
const profileEndTs = profileStartTs + profileDuration + slowFramesTime;
|
|
@@ -118,7 +63,7 @@ class SceneRenderProfiler {
|
|
|
118
63
|
end: profileEndTs
|
|
119
64
|
});
|
|
120
65
|
const networkDuration = captureNetwork(profileStartTs, profileEndTs);
|
|
121
|
-
if (((
|
|
66
|
+
if (((_a = this.queryController) == null ? void 0 : _a.state.onProfileComplete) && __privateGet(this, _profileInProgress)) {
|
|
122
67
|
this.queryController.state.onProfileComplete({
|
|
123
68
|
origin: __privateGet(this, _profileInProgress).origin,
|
|
124
69
|
crumbs: __privateGet(this, _profileInProgress).crumbs,
|
|
@@ -126,8 +71,6 @@ class SceneRenderProfiler {
|
|
|
126
71
|
networkDuration,
|
|
127
72
|
startTs: profileStartTs,
|
|
128
73
|
endTs: profileEndTs,
|
|
129
|
-
longFramesCount: __privateGet(this, _longFramesCount),
|
|
130
|
-
longFramesTotalTime: __privateGet(this, _longFramesTotalTime),
|
|
131
74
|
// @ts-ignore
|
|
132
75
|
jsHeapSizeLimit: performance.memory ? performance.memory.jsHeapSizeLimit : 0,
|
|
133
76
|
// @ts-ignore
|
|
@@ -147,7 +90,6 @@ class SceneRenderProfiler {
|
|
|
147
90
|
}
|
|
148
91
|
}
|
|
149
92
|
};
|
|
150
|
-
__privateSet(this, _longFrameDetector, new LongFrameDetector());
|
|
151
93
|
this.setupVisibilityChangeHandler();
|
|
152
94
|
}
|
|
153
95
|
setQueryController(queryController) {
|
|
@@ -172,7 +114,6 @@ class SceneRenderProfiler {
|
|
|
172
114
|
document.removeEventListener("visibilitychange", __privateGet(this, _visibilityChangeHandler));
|
|
173
115
|
__privateSet(this, _visibilityChangeHandler, null);
|
|
174
116
|
}
|
|
175
|
-
__privateGet(this, _longFrameDetector).stop();
|
|
176
117
|
this.cancelProfile();
|
|
177
118
|
}
|
|
178
119
|
startProfile(name) {
|
|
@@ -202,32 +143,14 @@ class SceneRenderProfiler {
|
|
|
202
143
|
* - "clean": Started when no profile is currently active
|
|
203
144
|
*/
|
|
204
145
|
_startNewProfile(name, force = false) {
|
|
205
|
-
var _a;
|
|
206
146
|
__privateSet(this, _profileInProgress, { origin: name, crumbs: [] });
|
|
207
147
|
__privateSet(this, _profileStartTs, performance.now());
|
|
208
|
-
|
|
209
|
-
__privateSet(this, _longFramesTotalTime, 0);
|
|
210
|
-
if (typeof performance !== "undefined" && performance.mark) {
|
|
211
|
-
const markName = `Dashboard Profile Start: ${name}`;
|
|
212
|
-
performance.mark(markName);
|
|
213
|
-
}
|
|
214
|
-
writeSceneLogStyled(
|
|
148
|
+
writeSceneLog(
|
|
215
149
|
"SceneRenderProfiler",
|
|
216
150
|
`Profile started[${force ? "forced" : "clean"}]`,
|
|
217
|
-
|
|
151
|
+
__privateGet(this, _profileInProgress),
|
|
152
|
+
__privateGet(this, _profileStartTs)
|
|
218
153
|
);
|
|
219
|
-
writeSceneLog("", ` \u251C\u2500 Origin: ${((_a = __privateGet(this, _profileInProgress)) == null ? void 0 : _a.origin) || "unknown"}`);
|
|
220
|
-
writeSceneLog("", ` \u2514\u2500 Timestamp: ${__privateGet(this, _profileStartTs).toFixed(1)}ms`);
|
|
221
|
-
__privateGet(this, _longFrameDetector).start((event) => {
|
|
222
|
-
if (!__privateGet(this, _profileInProgress) || !__privateGet(this, _profileStartTs)) {
|
|
223
|
-
return;
|
|
224
|
-
}
|
|
225
|
-
if (event.timestamp < __privateGet(this, _profileStartTs)) {
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
__privateWrapper(this, _longFramesCount)._++;
|
|
229
|
-
__privateSet(this, _longFramesTotalTime, __privateGet(this, _longFramesTotalTime) + event.duration);
|
|
230
|
-
});
|
|
231
154
|
}
|
|
232
155
|
recordProfileTail(measurementStartTime, profileStartTs) {
|
|
233
156
|
__privateSet(this, _trailAnimationFrameId, requestAnimationFrame(
|
|
@@ -238,7 +161,7 @@ class SceneRenderProfiler {
|
|
|
238
161
|
var _a;
|
|
239
162
|
writeSceneLog("SceneRenderProfiler", "Trying to complete profile", __privateGet(this, _profileInProgress));
|
|
240
163
|
if (((_a = this.queryController) == null ? void 0 : _a.runningQueriesCount()) === 0 && __privateGet(this, _profileInProgress)) {
|
|
241
|
-
writeSceneLog("SceneRenderProfiler", "All queries completed,
|
|
164
|
+
writeSceneLog("SceneRenderProfiler", "All queries completed, stopping profile");
|
|
242
165
|
this.recordProfileTail(performance.now(), __privateGet(this, _profileStartTs));
|
|
243
166
|
}
|
|
244
167
|
}
|
|
@@ -261,11 +184,7 @@ class SceneRenderProfiler {
|
|
|
261
184
|
cancelAnimationFrame(__privateGet(this, _trailAnimationFrameId));
|
|
262
185
|
__privateSet(this, _trailAnimationFrameId, null);
|
|
263
186
|
}
|
|
264
|
-
__privateGet(this, _longFrameDetector).stop();
|
|
265
|
-
writeSceneLog("SceneRenderProfiler", "Stopped long frame detection - profile cancelled");
|
|
266
187
|
__privateSet(this, _recordedTrailingSpans, []);
|
|
267
|
-
__privateSet(this, _longFramesCount, 0);
|
|
268
|
-
__privateSet(this, _longFramesTotalTime, 0);
|
|
269
188
|
}
|
|
270
189
|
}
|
|
271
190
|
addCrumb(crumb) {
|
|
@@ -279,13 +198,10 @@ _profileInProgress = new WeakMap();
|
|
|
279
198
|
_profileStartTs = new WeakMap();
|
|
280
199
|
_trailAnimationFrameId = new WeakMap();
|
|
281
200
|
_recordedTrailingSpans = new WeakMap();
|
|
282
|
-
_longFrameDetector = new WeakMap();
|
|
283
|
-
_longFramesCount = new WeakMap();
|
|
284
|
-
_longFramesTotalTime = new WeakMap();
|
|
285
201
|
_visibilityChangeHandler = new WeakMap();
|
|
286
202
|
function processRecordedSpans(spans) {
|
|
287
203
|
for (let i = spans.length - 1; i >= 0; i--) {
|
|
288
|
-
if (spans[i] >
|
|
204
|
+
if (spans[i] > SPAN_THRESHOLD) {
|
|
289
205
|
return spans.slice(0, i + 1);
|
|
290
206
|
}
|
|
291
207
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SceneRenderProfiler.js","sources":["../../../src/behaviors/SceneRenderProfiler.ts"],"sourcesContent":["import { writeSceneLog, writeSceneLogStyled } from '../utils/writeSceneLog';\nimport { SceneQueryControllerLike, LongFrameEvent } from './types';\nimport { LongFrameDetector } from './LongFrameDetector';\n\nconst POST_STORM_WINDOW = 2000; // Time after last query to observe slow frames\nconst DEFAULT_LONG_FRAME_THRESHOLD = 30; // Threshold for tail recording slow frames\nconst TAB_INACTIVE_THRESHOLD = 1000; // Tab inactive threshold in ms\n\n/**\n * SceneRenderProfiler tracks dashboard interaction performance including:\n * - Total interaction duration\n * - Network time\n * - Long frame detection (50ms threshold) during interaction using LoAF API (default) or manual tracking (fallback)\n * - Slow frame detection (30ms threshold) for tail recording after interaction\n *\n * Long frame detection during interaction:\n * - 50ms threshold aligned with LoAF API default\n * - LoAF API preferred (Chrome 123+) with manual fallback\n * - Provides script attribution when using LoAF API\n *\n * Slow frame detection for tail recording:\n * - 30ms threshold for post-interaction monitoring\n * - Manual frame timing measurement\n * - Captures rendering delays after user interaction completes\n */\n\nexport class SceneRenderProfiler {\n #profileInProgress: {\n // Profile origin, i.e. scene refresh picker\n origin: string;\n crumbs: string[];\n } | null = null;\n\n #profileStartTs: number | null = null;\n #trailAnimationFrameId: number | null = null;\n\n // Will keep measured lengths trailing frames\n #recordedTrailingSpans: number[] = [];\n\n // Long frame tracking\n #longFrameDetector: LongFrameDetector;\n #longFramesCount = 0;\n #longFramesTotalTime = 0;\n\n #visibilityChangeHandler: (() => void) | null = null;\n\n public constructor(private queryController?: SceneQueryControllerLike) {\n this.#longFrameDetector = new LongFrameDetector();\n this.setupVisibilityChangeHandler();\n }\n\n public setQueryController(queryController: SceneQueryControllerLike) {\n this.queryController = queryController;\n }\n\n private setupVisibilityChangeHandler() {\n // Ensure event listener is only added once\n if (this.#visibilityChangeHandler) {\n return;\n }\n\n // Handle tab switching with Page Visibility API\n this.#visibilityChangeHandler = () => {\n if (document.hidden && this.#profileInProgress) {\n writeSceneLog('SceneRenderProfiler', 'Tab became inactive, cancelling profile');\n this.cancelProfile();\n }\n };\n\n if (typeof document !== 'undefined') {\n document.addEventListener('visibilitychange', this.#visibilityChangeHandler);\n }\n }\n\n public cleanup() {\n // Remove event listener to prevent memory leaks\n if (this.#visibilityChangeHandler && typeof document !== 'undefined') {\n document.removeEventListener('visibilitychange', this.#visibilityChangeHandler);\n this.#visibilityChangeHandler = null;\n }\n\n // Cleanup long frame tracking\n this.#longFrameDetector.stop();\n\n // Cancel any ongoing profiling\n this.cancelProfile();\n }\n\n public startProfile(name: string) {\n // Only start profile if tab is active. This makes sure we don't start a profile when i.e. someone opens a dashboard in a new tab\n // and doesn't interact with it.\n if (document.hidden) {\n writeSceneLog('SceneRenderProfiler', 'Tab is inactive, skipping profile', name);\n return;\n }\n\n if (this.#profileInProgress) {\n if (this.#trailAnimationFrameId) {\n this.cancelProfile();\n this._startNewProfile(name, true);\n } else {\n this.addCrumb(name);\n }\n } else {\n this._startNewProfile(name);\n }\n }\n\n /**\n * Starts a new profile for performance measurement.\n *\n * @param name - The origin/trigger of the profile (e.g., 'time_range_change', 'variable_value_changed')\n * @param force - Whether this is a \"forced\" profile (true) or \"clean\" profile (false)\n * - \"forced\": Started by canceling an existing profile that was recording trailing frames\n * This happens when a new user interaction occurs before the previous one\n * finished measuring its performance impact\n * - \"clean\": Started when no profile is currently active\n */\n private _startNewProfile(name: string, force = false) {\n this.#profileInProgress = { origin: name, crumbs: [] };\n this.#profileStartTs = performance.now();\n this.#longFramesCount = 0;\n this.#longFramesTotalTime = 0;\n\n // Add performance mark for debugging in dev tools\n if (typeof performance !== 'undefined' && performance.mark) {\n const markName = `Dashboard Profile Start: ${name}`;\n performance.mark(markName);\n }\n\n // Log profile start in structured format\n writeSceneLogStyled(\n 'SceneRenderProfiler',\n `Profile started[${force ? 'forced' : 'clean'}]`,\n 'color: #FFCC00; font-weight: bold;'\n );\n writeSceneLog('', ` ├─ Origin: ${this.#profileInProgress?.origin || 'unknown'}`);\n writeSceneLog('', ` └─ Timestamp: ${this.#profileStartTs.toFixed(1)}ms`);\n\n // Start long frame detection with callback\n this.#longFrameDetector.start((event: LongFrameEvent) => {\n // Only record long frames during active profiling\n if (!this.#profileInProgress || !this.#profileStartTs) {\n return;\n }\n\n // Only record frames that occur after profile started\n if (event.timestamp < this.#profileStartTs) {\n return;\n }\n\n this.#longFramesCount++;\n this.#longFramesTotalTime += event.duration;\n });\n }\n\n private recordProfileTail(measurementStartTime: number, profileStartTs: number) {\n this.#trailAnimationFrameId = requestAnimationFrame(() =>\n this.measureTrailingFrames(measurementStartTime, measurementStartTime, profileStartTs)\n );\n }\n\n private measureTrailingFrames = (measurementStartTs: number, lastFrameTime: number, profileStartTs: number) => {\n const currentFrameTime = performance.now();\n const frameLength = currentFrameTime - lastFrameTime;\n\n // Fallback: Detect if tab was inactive (frame longer than reasonable threshold)\n // This serves as backup to Page Visibility API in case the event wasn't triggered\n if (frameLength > TAB_INACTIVE_THRESHOLD) {\n writeSceneLog('SceneRenderProfiler', 'Tab was inactive, cancelling profile measurement');\n this.cancelProfile();\n return;\n }\n\n this.#recordedTrailingSpans.push(frameLength);\n\n if (currentFrameTime - measurementStartTs! < POST_STORM_WINDOW) {\n if (this.#profileInProgress) {\n this.#trailAnimationFrameId = requestAnimationFrame(() =>\n this.measureTrailingFrames(measurementStartTs, currentFrameTime, profileStartTs)\n );\n }\n } else {\n const slowFrames = processRecordedSpans(this.#recordedTrailingSpans);\n const slowFramesTime = slowFrames.reduce((acc, val) => acc + val, 0);\n\n // Log tail recording in structured format\n writeSceneLog(\n 'SceneRenderProfiler',\n `Profile tail recorded - Slow frames: ${slowFramesTime.toFixed(1)}ms (${slowFrames.length} frames)`\n );\n writeSceneLog('', ` ├─ Origin: ${this.#profileInProgress?.origin || 'unknown'}`);\n writeSceneLog('', ` └─ Crumbs:`, this.#profileInProgress?.crumbs || []);\n\n this.#recordedTrailingSpans = [];\n\n const profileDuration = measurementStartTs - profileStartTs;\n\n // Add performance marks for debugging in dev tools\n if (typeof performance !== 'undefined' && performance.mark) {\n const profileName = this.#profileInProgress?.origin || 'unknown';\n const totalTime = profileDuration + slowFramesTime;\n\n // Mark profile completion\n performance.mark(`Dashboard Profile End: ${profileName}`);\n\n // Add measure from start to end if possible\n const startMarkName = `Dashboard Profile Start: ${profileName}`;\n try {\n performance.measure(\n `Dashboard Profile: ${profileName} (${totalTime.toFixed(1)}ms)`,\n startMarkName,\n `Dashboard Profile End: ${profileName}`\n );\n } catch {\n // Start mark might not exist, create a simple end mark\n performance.mark(`Dashboard Profile Complete: ${profileName} (${totalTime.toFixed(1)}ms)`);\n }\n\n // Add measurements for slow frame details if significant\n if (slowFrames.length > 0) {\n const slowFramesMarkName = `Slow Frames Summary: ${slowFrames.length} frames (${slowFramesTime.toFixed(\n 1\n )}ms)`;\n performance.mark(slowFramesMarkName);\n\n // Create individual measurements for each slow frame during tail\n slowFrames.forEach((frameTime, index) => {\n if (frameTime > 16) {\n // Only measure frames slower than 16ms (60fps)\n try {\n const frameStartTime =\n this.#profileStartTs! +\n profileDuration +\n (index > 0 ? slowFrames.slice(0, index).reduce((sum, t) => sum + t, 0) : 0);\n const frameId = `slow-frame-${index}`;\n const frameStartMark = `${frameId}-start`;\n const frameEndMark = `${frameId}-end`;\n\n performance.mark(frameStartMark, { startTime: frameStartTime });\n performance.mark(frameEndMark, { startTime: frameStartTime + frameTime });\n performance.measure(`Slow Frame ${index + 1}: ${frameTime.toFixed(1)}ms`, frameStartMark, frameEndMark);\n } catch {\n // Fallback if startTime not supported\n performance.mark(`Slow Frame ${index + 1}: ${frameTime.toFixed(1)}ms`);\n }\n }\n });\n }\n }\n\n // Log performance summary in a structured format\n const completionTimestamp = performance.now();\n writeSceneLog('SceneRenderProfiler', 'Profile completed');\n writeSceneLog('', ` ├─ Timestamp: ${completionTimestamp.toFixed(1)}ms`);\n writeSceneLog('', ` ├─ Total time: ${(profileDuration + slowFramesTime).toFixed(1)}ms`);\n writeSceneLog('', ` ├─ Slow frames: ${slowFramesTime}ms (${slowFrames.length} frames)`);\n writeSceneLog('', ` └─ Long frames: ${this.#longFramesTotalTime}ms (${this.#longFramesCount} frames)`);\n\n // Stop long frame detection now that the profile is complete\n this.#longFrameDetector.stop();\n writeSceneLogStyled(\n 'SceneRenderProfiler',\n `Stopped long frame detection - profile complete at ${completionTimestamp.toFixed(1)}ms`,\n 'color: #00CC00; font-weight: bold;'\n );\n\n this.#trailAnimationFrameId = null;\n\n const profileEndTs = profileStartTs + profileDuration + slowFramesTime;\n\n // Guard against race condition where profile might be cancelled during execution\n if (!this.#profileInProgress) {\n return;\n }\n\n performance.measure(`DashboardInteraction ${this.#profileInProgress.origin}`, {\n start: profileStartTs,\n end: profileEndTs,\n });\n\n const networkDuration = captureNetwork(profileStartTs, profileEndTs);\n\n if (this.queryController?.state.onProfileComplete && this.#profileInProgress) {\n this.queryController.state.onProfileComplete({\n origin: this.#profileInProgress.origin,\n crumbs: this.#profileInProgress.crumbs,\n duration: profileDuration + slowFramesTime,\n networkDuration,\n startTs: profileStartTs,\n endTs: profileEndTs,\n longFramesCount: this.#longFramesCount,\n longFramesTotalTime: this.#longFramesTotalTime,\n // @ts-ignore\n jsHeapSizeLimit: performance.memory ? performance.memory.jsHeapSizeLimit : 0,\n // @ts-ignore\n usedJSHeapSize: performance.memory ? performance.memory.usedJSHeapSize : 0,\n // @ts-ignore\n totalJSHeapSize: performance.memory ? performance.memory.totalJSHeapSize : 0,\n });\n\n this.#profileInProgress = null;\n this.#trailAnimationFrameId = null;\n }\n // @ts-ignore\n if (window.__runs) {\n // @ts-ignore\n window.__runs += `${Date.now()}, ${profileDuration + slowFramesTime}\\n`;\n } else {\n // @ts-ignore\n window.__runs = `${Date.now()}, ${profileDuration + slowFramesTime}\\n`;\n }\n }\n };\n\n public tryCompletingProfile() {\n writeSceneLog('SceneRenderProfiler', 'Trying to complete profile', this.#profileInProgress);\n if (this.queryController?.runningQueriesCount() === 0 && this.#profileInProgress) {\n writeSceneLog('SceneRenderProfiler', 'All queries completed, starting tail measurement');\n // Note: Long frame detector continues running during tail measurement\n // It will be stopped when the profile completely finishes\n this.recordProfileTail(performance.now(), this.#profileStartTs!);\n }\n }\n\n public isTailRecording() {\n return Boolean(this.#trailAnimationFrameId);\n }\n\n public cancelTailRecording() {\n if (this.#trailAnimationFrameId) {\n cancelAnimationFrame(this.#trailAnimationFrameId);\n this.#trailAnimationFrameId = null;\n writeSceneLog('SceneRenderProfiler', 'Cancelled recording frames, new profile started');\n }\n }\n\n // cancel profile\n public cancelProfile() {\n if (this.#profileInProgress) {\n writeSceneLog('SceneRenderProfiler', 'Cancelling profile', this.#profileInProgress);\n this.#profileInProgress = null;\n // Cancel any pending animation frame to prevent accessing null profileInProgress\n if (this.#trailAnimationFrameId) {\n cancelAnimationFrame(this.#trailAnimationFrameId);\n this.#trailAnimationFrameId = null;\n }\n // Stop long frame tracking\n this.#longFrameDetector.stop();\n writeSceneLog('SceneRenderProfiler', 'Stopped long frame detection - profile cancelled');\n // Reset recorded spans to ensure complete cleanup\n this.#recordedTrailingSpans = [];\n this.#longFramesCount = 0;\n this.#longFramesTotalTime = 0;\n }\n }\n\n public addCrumb(crumb: string) {\n if (this.#profileInProgress) {\n writeSceneLog('SceneRenderProfiler', 'Adding crumb:', crumb);\n this.#profileInProgress.crumbs.push(crumb);\n }\n }\n}\n\nexport function processRecordedSpans(spans: number[]) {\n // identify last span in spans that's bigger than default threshold\n for (let i = spans.length - 1; i >= 0; i--) {\n if (spans[i] > DEFAULT_LONG_FRAME_THRESHOLD) {\n return spans.slice(0, i + 1);\n }\n }\n return [spans[0]];\n}\n\nexport function captureNetwork(startTs: number, endTs: number) {\n const entries = performance.getEntriesByType('resource') as PerformanceResourceTiming[];\n performance.clearResourceTimings();\n // Only include network entries that both started AND ended within the time window\n const networkEntries = entries.filter(\n (entry) =>\n entry.startTime >= startTs &&\n entry.startTime <= endTs &&\n entry.responseEnd >= startTs &&\n entry.responseEnd <= endTs\n );\n for (const entry of networkEntries) {\n performance.measure('Network entry ' + entry.name, {\n start: entry.startTime,\n end: entry.responseEnd,\n });\n }\n\n return calculateNetworkTime(networkEntries);\n}\n\n// Will calculate total time spent on Network\nexport function calculateNetworkTime(requests: PerformanceResourceTiming[]): number {\n if (requests.length === 0) {\n return 0;\n }\n\n // Step 1: Sort the requests by startTs\n requests.sort((a, b) => a.startTime - b.startTime);\n\n // Step 2: Initialize variables\n let totalNetworkTime = 0;\n let currentStart = requests[0].startTime;\n let currentEnd = requests[0].responseEnd;\n\n // Step 3: Iterate through the sorted list and merge overlapping intervals\n for (let i = 1; i < requests.length; i++) {\n if (requests[i].startTime <= currentEnd) {\n // Overlapping intervals, merge them\n currentEnd = Math.max(currentEnd, requests[i].responseEnd);\n } else {\n // Non-overlapping interval, add the duration to total time\n totalNetworkTime += currentEnd - currentStart;\n\n // Update current interval\n currentStart = requests[i].startTime;\n currentEnd = requests[i].responseEnd;\n }\n }\n\n // Step 4: Add the last interval\n totalNetworkTime += currentEnd - currentStart;\n\n return totalNetworkTime;\n}\n\nexport const REFRESH_INTERACTION = 'refresh';\nexport const TIME_RANGE_CHANGE_INTERACTION = 'time_range_change';\nexport const FILTER_ADDED_INTERACTION = 'filter_added';\nexport const FILTER_REMOVED_INTERACTION = 'filter_removed';\nexport const FILTER_CHANGED_INTERACTION = 'filter_changed';\nexport const FILTER_RESTORED_INTERACTION = 'filter_restored';\nexport const VARIABLE_VALUE_CHANGED_INTERACTION = 'variable_value_changed';\nexport const SCOPES_CHANGED_INTERACTION = 'scopes_changed';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SceneRenderProfiler.js","sources":["../../../src/behaviors/SceneRenderProfiler.ts"],"sourcesContent":["import { writeSceneLog } from '../utils/writeSceneLog';\nimport { SceneQueryControllerLike } from './types';\n\nconst POST_STORM_WINDOW = 2000; // Time after last query to observe slow frames\nconst SPAN_THRESHOLD = 30; // Frames longer than this will be considered slow\nconst TAB_INACTIVE_THRESHOLD = 1000; // Tab inactive threshold in ms\n\nexport class SceneRenderProfiler {\n #profileInProgress: {\n // Profile origin, i.e. scene refresh picker\n origin: string;\n crumbs: string[];\n } | null = null;\n\n #profileStartTs: number | null = null;\n #trailAnimationFrameId: number | null = null;\n\n // Will keep measured lengths trailing frames\n #recordedTrailingSpans: number[] = [];\n\n #visibilityChangeHandler: (() => void) | null = null;\n\n public constructor(private queryController?: SceneQueryControllerLike) {\n this.setupVisibilityChangeHandler();\n }\n\n public setQueryController(queryController: SceneQueryControllerLike) {\n this.queryController = queryController;\n }\n\n private setupVisibilityChangeHandler() {\n // Ensure event listener is only added once\n if (this.#visibilityChangeHandler) {\n return;\n }\n\n // Handle tab switching with Page Visibility API\n this.#visibilityChangeHandler = () => {\n if (document.hidden && this.#profileInProgress) {\n writeSceneLog('SceneRenderProfiler', 'Tab became inactive, cancelling profile');\n this.cancelProfile();\n }\n };\n\n if (typeof document !== 'undefined') {\n document.addEventListener('visibilitychange', this.#visibilityChangeHandler);\n }\n }\n\n public cleanup() {\n // Remove event listener to prevent memory leaks\n if (this.#visibilityChangeHandler && typeof document !== 'undefined') {\n document.removeEventListener('visibilitychange', this.#visibilityChangeHandler);\n this.#visibilityChangeHandler = null;\n }\n\n // Cancel any ongoing profiling\n this.cancelProfile();\n }\n\n public startProfile(name: string) {\n // Only start profile if tab is active. This makes sure we don't start a profile when i.e. someone opens a dashboard in a new tab\n // and doesn't interact with it.\n if (document.hidden) {\n writeSceneLog('SceneRenderProfiler', 'Tab is inactive, skipping profile', name);\n return;\n }\n\n if (this.#profileInProgress) {\n if (this.#trailAnimationFrameId) {\n this.cancelProfile();\n this._startNewProfile(name, true);\n } else {\n this.addCrumb(name);\n }\n } else {\n this._startNewProfile(name);\n }\n }\n\n /**\n * Starts a new profile for performance measurement.\n *\n * @param name - The origin/trigger of the profile (e.g., 'time_range_change', 'variable_value_changed')\n * @param force - Whether this is a \"forced\" profile (true) or \"clean\" profile (false)\n * - \"forced\": Started by canceling an existing profile that was recording trailing frames\n * This happens when a new user interaction occurs before the previous one\n * finished measuring its performance impact\n * - \"clean\": Started when no profile is currently active\n */\n private _startNewProfile(name: string, force = false) {\n this.#profileInProgress = { origin: name, crumbs: [] };\n this.#profileStartTs = performance.now();\n writeSceneLog(\n 'SceneRenderProfiler',\n `Profile started[${force ? 'forced' : 'clean'}]`,\n this.#profileInProgress,\n this.#profileStartTs\n );\n }\n\n private recordProfileTail(measurementStartTime: number, profileStartTs: number) {\n this.#trailAnimationFrameId = requestAnimationFrame(() =>\n this.measureTrailingFrames(measurementStartTime, measurementStartTime, profileStartTs)\n );\n }\n\n private measureTrailingFrames = (measurementStartTs: number, lastFrameTime: number, profileStartTs: number) => {\n const currentFrameTime = performance.now();\n const frameLength = currentFrameTime - lastFrameTime;\n\n // Fallback: Detect if tab was inactive (frame longer than reasonable threshold)\n // This serves as backup to Page Visibility API in case the event wasn't triggered\n if (frameLength > TAB_INACTIVE_THRESHOLD) {\n writeSceneLog('SceneRenderProfiler', 'Tab was inactive, cancelling profile measurement');\n this.cancelProfile();\n return;\n }\n\n this.#recordedTrailingSpans.push(frameLength);\n\n if (currentFrameTime - measurementStartTs! < POST_STORM_WINDOW) {\n if (this.#profileInProgress) {\n this.#trailAnimationFrameId = requestAnimationFrame(() =>\n this.measureTrailingFrames(measurementStartTs, currentFrameTime, profileStartTs)\n );\n }\n } else {\n const slowFrames = processRecordedSpans(this.#recordedTrailingSpans);\n const slowFramesTime = slowFrames.reduce((acc, val) => acc + val, 0);\n\n writeSceneLog(\n this.constructor.name,\n 'Profile tail recorded, slow frames duration:',\n slowFramesTime,\n slowFrames,\n this.#profileInProgress\n );\n\n this.#recordedTrailingSpans = [];\n\n const profileDuration = measurementStartTs - profileStartTs;\n\n writeSceneLog(\n this.constructor.name,\n 'Stoped recording, total measured time (network included):',\n profileDuration + slowFramesTime\n );\n this.#trailAnimationFrameId = null;\n\n const profileEndTs = profileStartTs + profileDuration + slowFramesTime;\n\n // Guard against race condition where profile might be cancelled during execution\n if (!this.#profileInProgress) {\n return;\n }\n\n performance.measure(`DashboardInteraction ${this.#profileInProgress.origin}`, {\n start: profileStartTs,\n end: profileEndTs,\n });\n\n const networkDuration = captureNetwork(profileStartTs, profileEndTs);\n\n if (this.queryController?.state.onProfileComplete && this.#profileInProgress) {\n this.queryController.state.onProfileComplete({\n origin: this.#profileInProgress.origin,\n crumbs: this.#profileInProgress.crumbs,\n duration: profileDuration + slowFramesTime,\n networkDuration,\n startTs: profileStartTs,\n endTs: profileEndTs,\n // @ts-ignore\n jsHeapSizeLimit: performance.memory ? performance.memory.jsHeapSizeLimit : 0,\n // @ts-ignore\n usedJSHeapSize: performance.memory ? performance.memory.usedJSHeapSize : 0,\n // @ts-ignore\n totalJSHeapSize: performance.memory ? performance.memory.totalJSHeapSize : 0,\n });\n\n this.#profileInProgress = null;\n this.#trailAnimationFrameId = null;\n }\n // @ts-ignore\n if (window.__runs) {\n // @ts-ignore\n window.__runs += `${Date.now()}, ${profileDuration + slowFramesTime}\\n`;\n } else {\n // @ts-ignore\n window.__runs = `${Date.now()}, ${profileDuration + slowFramesTime}\\n`;\n }\n }\n };\n\n public tryCompletingProfile() {\n writeSceneLog('SceneRenderProfiler', 'Trying to complete profile', this.#profileInProgress);\n if (this.queryController?.runningQueriesCount() === 0 && this.#profileInProgress) {\n writeSceneLog('SceneRenderProfiler', 'All queries completed, stopping profile');\n this.recordProfileTail(performance.now(), this.#profileStartTs!);\n }\n }\n\n public isTailRecording() {\n return Boolean(this.#trailAnimationFrameId);\n }\n\n public cancelTailRecording() {\n if (this.#trailAnimationFrameId) {\n cancelAnimationFrame(this.#trailAnimationFrameId);\n this.#trailAnimationFrameId = null;\n writeSceneLog('SceneRenderProfiler', 'Cancelled recording frames, new profile started');\n }\n }\n\n // cancel profile\n public cancelProfile() {\n if (this.#profileInProgress) {\n writeSceneLog('SceneRenderProfiler', 'Cancelling profile', this.#profileInProgress);\n this.#profileInProgress = null;\n // Cancel any pending animation frame to prevent accessing null profileInProgress\n if (this.#trailAnimationFrameId) {\n cancelAnimationFrame(this.#trailAnimationFrameId);\n this.#trailAnimationFrameId = null;\n }\n // Reset recorded spans to ensure complete cleanup\n this.#recordedTrailingSpans = [];\n }\n }\n\n public addCrumb(crumb: string) {\n if (this.#profileInProgress) {\n writeSceneLog('SceneRenderProfiler', 'Adding crumb:', crumb);\n this.#profileInProgress.crumbs.push(crumb);\n }\n }\n}\n\nexport function processRecordedSpans(spans: number[]) {\n // identify last span in spans that's bigger than SPAN_THRESHOLD\n for (let i = spans.length - 1; i >= 0; i--) {\n if (spans[i] > SPAN_THRESHOLD) {\n return spans.slice(0, i + 1);\n }\n }\n return [spans[0]];\n}\n\nexport function captureNetwork(startTs: number, endTs: number) {\n const entries = performance.getEntriesByType('resource') as PerformanceResourceTiming[];\n performance.clearResourceTimings();\n // Only include network entries that both started AND ended within the time window\n const networkEntries = entries.filter(\n (entry) =>\n entry.startTime >= startTs &&\n entry.startTime <= endTs &&\n entry.responseEnd >= startTs &&\n entry.responseEnd <= endTs\n );\n for (const entry of networkEntries) {\n performance.measure('Network entry ' + entry.name, {\n start: entry.startTime,\n end: entry.responseEnd,\n });\n }\n\n return calculateNetworkTime(networkEntries);\n}\n\n// Will calculate total time spent on Network\nexport function calculateNetworkTime(requests: PerformanceResourceTiming[]): number {\n if (requests.length === 0) {\n return 0;\n }\n\n // Step 1: Sort the requests by startTs\n requests.sort((a, b) => a.startTime - b.startTime);\n\n // Step 2: Initialize variables\n let totalNetworkTime = 0;\n let currentStart = requests[0].startTime;\n let currentEnd = requests[0].responseEnd;\n\n // Step 3: Iterate through the sorted list and merge overlapping intervals\n for (let i = 1; i < requests.length; i++) {\n if (requests[i].startTime <= currentEnd) {\n // Overlapping intervals, merge them\n currentEnd = Math.max(currentEnd, requests[i].responseEnd);\n } else {\n // Non-overlapping interval, add the duration to total time\n totalNetworkTime += currentEnd - currentStart;\n\n // Update current interval\n currentStart = requests[i].startTime;\n currentEnd = requests[i].responseEnd;\n }\n }\n\n // Step 4: Add the last interval\n totalNetworkTime += currentEnd - currentStart;\n\n return totalNetworkTime;\n}\n\nexport const REFRESH_INTERACTION = 'refresh';\nexport const TIME_RANGE_CHANGE_INTERACTION = 'time_range_change';\nexport const FILTER_ADDED_INTERACTION = 'filter_added';\nexport const FILTER_REMOVED_INTERACTION = 'filter_removed';\nexport const FILTER_CHANGED_INTERACTION = 'filter_changed';\nexport const FILTER_RESTORED_INTERACTION = 'filter_restored';\nexport const VARIABLE_VALUE_CHANGED_INTERACTION = 'variable_value_changed';\nexport const SCOPES_CHANGED_INTERACTION = 'scopes_changed';\n"],"names":[],"mappings":";;;;;;;;;AAAA,IAAA,kBAAA,EAAA,eAAA,EAAA,sBAAA,EAAA,sBAAA,EAAA,wBAAA;AAGA,MAAM,iBAAoB,GAAA,GAAA;AAC1B,MAAM,cAAiB,GAAA,EAAA;AACvB,MAAM,sBAAyB,GAAA,GAAA;AAExB,MAAM,mBAAoB,CAAA;AAAA,EAexB,YAAoB,eAA4C,EAAA;AAA5C,IAAA,IAAA,CAAA,eAAA,GAAA,eAAA;AAd3B,IAIW,YAAA,CAAA,IAAA,EAAA,kBAAA,EAAA,IAAA,CAAA;AAEX,IAAiC,YAAA,CAAA,IAAA,EAAA,eAAA,EAAA,IAAA,CAAA;AACjC,IAAwC,YAAA,CAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,CAAA;AAGxC;AAAA,IAAA,YAAA,CAAA,IAAA,EAAA,sBAAA,EAAmC,EAAC,CAAA;AAEpC,IAAgD,YAAA,CAAA,IAAA,EAAA,wBAAA,EAAA,IAAA,CAAA;AAuFhD,IAAA,IAAA,CAAQ,qBAAwB,GAAA,CAAC,kBAA4B,EAAA,aAAA,EAAuB,cAA2B,KAAA;AA3GjH,MAAA,IAAA,EAAA;AA4GI,MAAM,MAAA,gBAAA,GAAmB,YAAY,GAAI,EAAA;AACzC,MAAA,MAAM,cAAc,gBAAmB,GAAA,aAAA;AAIvC,MAAA,IAAI,cAAc,sBAAwB,EAAA;AACxC,QAAA,aAAA,CAAc,uBAAuB,kDAAkD,CAAA;AACvF,QAAA,IAAA,CAAK,aAAc,EAAA;AACnB,QAAA;AAAA;AAGF,MAAK,YAAA,CAAA,IAAA,EAAA,sBAAA,CAAA,CAAuB,KAAK,WAAW,CAAA;AAE5C,MAAI,IAAA,gBAAA,GAAmB,qBAAsB,iBAAmB,EAAA;AAC9D,QAAA,IAAI,mBAAK,kBAAoB,CAAA,EAAA;AAC3B,UAAA,YAAA,CAAA,IAAA,EAAK,sBAAyB,EAAA,qBAAA;AAAA,YAAsB,MAClD,IAAA,CAAK,qBAAsB,CAAA,kBAAA,EAAoB,kBAAkB,cAAc;AAAA,WACjF,CAAA;AAAA;AACF,OACK,MAAA;AACL,QAAM,MAAA,UAAA,GAAa,oBAAqB,CAAA,YAAA,CAAA,IAAA,EAAK,sBAAsB,CAAA,CAAA;AACnE,QAAM,MAAA,cAAA,GAAiB,WAAW,MAAO,CAAA,CAAC,KAAK,GAAQ,KAAA,GAAA,GAAM,KAAK,CAAC,CAAA;AAEnE,QAAA,aAAA;AAAA,UACE,KAAK,WAAY,CAAA,IAAA;AAAA,UACjB,8CAAA;AAAA,UACA,cAAA;AAAA,UACA,UAAA;AAAA,UACA,YAAK,CAAA,IAAA,EAAA,kBAAA;AAAA,SACP;AAEA,QAAA,YAAA,CAAA,IAAA,EAAK,wBAAyB,EAAC,CAAA;AAE/B,QAAA,MAAM,kBAAkB,kBAAqB,GAAA,cAAA;AAE7C,QAAA,aAAA;AAAA,UACE,KAAK,WAAY,CAAA,IAAA;AAAA,UACjB,2DAAA;AAAA,UACA,eAAkB,GAAA;AAAA,SACpB;AACA,QAAA,YAAA,CAAA,IAAA,EAAK,sBAAyB,EAAA,IAAA,CAAA;AAE9B,QAAM,MAAA,YAAA,GAAe,iBAAiB,eAAkB,GAAA,cAAA;AAGxD,QAAI,IAAA,CAAC,mBAAK,kBAAoB,CAAA,EAAA;AAC5B,UAAA;AAAA;AAGF,QAAA,WAAA,CAAY,OAAQ,CAAA,CAAA,qBAAA,EAAwB,YAAK,CAAA,IAAA,EAAA,kBAAA,CAAA,CAAmB,MAAM,CAAI,CAAA,EAAA;AAAA,UAC5E,KAAO,EAAA,cAAA;AAAA,UACP,GAAK,EAAA;AAAA,SACN,CAAA;AAED,QAAM,MAAA,eAAA,GAAkB,cAAe,CAAA,cAAA,EAAgB,YAAY,CAAA;AAEnE,QAAA,IAAA,CAAA,CAAI,UAAK,eAAL,KAAA,IAAA,GAAA,MAAA,GAAA,EAAA,CAAsB,KAAM,CAAA,iBAAA,KAAqB,mBAAK,kBAAoB,CAAA,EAAA;AAC5E,UAAK,IAAA,CAAA,eAAA,CAAgB,MAAM,iBAAkB,CAAA;AAAA,YAC3C,MAAA,EAAQ,mBAAK,kBAAmB,CAAA,CAAA,MAAA;AAAA,YAChC,MAAA,EAAQ,mBAAK,kBAAmB,CAAA,CAAA,MAAA;AAAA,YAChC,UAAU,eAAkB,GAAA,cAAA;AAAA,YAC5B,eAAA;AAAA,YACA,OAAS,EAAA,cAAA;AAAA,YACT,KAAO,EAAA,YAAA;AAAA;AAAA,YAEP,eAAiB,EAAA,WAAA,CAAY,MAAS,GAAA,WAAA,CAAY,OAAO,eAAkB,GAAA,CAAA;AAAA;AAAA,YAE3E,cAAgB,EAAA,WAAA,CAAY,MAAS,GAAA,WAAA,CAAY,OAAO,cAAiB,GAAA,CAAA;AAAA;AAAA,YAEzE,eAAiB,EAAA,WAAA,CAAY,MAAS,GAAA,WAAA,CAAY,OAAO,eAAkB,GAAA;AAAA,WAC5E,CAAA;AAED,UAAA,YAAA,CAAA,IAAA,EAAK,kBAAqB,EAAA,IAAA,CAAA;AAC1B,UAAA,YAAA,CAAA,IAAA,EAAK,sBAAyB,EAAA,IAAA,CAAA;AAAA;AAGhC,QAAA,IAAI,OAAO,MAAQ,EAAA;AAEjB,UAAA,MAAA,CAAO,UAAU,CAAG,EAAA,IAAA,CAAK,KAAK,CAAA,EAAA,EAAK,kBAAkB,cAAc;AAAA,CAAA;AAAA,SAC9D,MAAA;AAEL,UAAA,MAAA,CAAO,SAAS,CAAG,EAAA,IAAA,CAAK,KAAK,CAAA,EAAA,EAAK,kBAAkB,cAAc;AAAA,CAAA;AAAA;AACpE;AACF,KACF;AAzKE,IAAA,IAAA,CAAK,4BAA6B,EAAA;AAAA;AACpC,EAEO,mBAAmB,eAA2C,EAAA;AACnE,IAAA,IAAA,CAAK,eAAkB,GAAA,eAAA;AAAA;AACzB,EAEQ,4BAA+B,GAAA;AAErC,IAAA,IAAI,mBAAK,wBAA0B,CAAA,EAAA;AACjC,MAAA;AAAA;AAIF,IAAA,YAAA,CAAA,IAAA,EAAK,0BAA2B,MAAM;AACpC,MAAI,IAAA,QAAA,CAAS,MAAU,IAAA,YAAA,CAAA,IAAA,EAAK,kBAAoB,CAAA,EAAA;AAC9C,QAAA,aAAA,CAAc,uBAAuB,yCAAyC,CAAA;AAC9E,QAAA,IAAA,CAAK,aAAc,EAAA;AAAA;AACrB,KACF,CAAA;AAEA,IAAI,IAAA,OAAO,aAAa,WAAa,EAAA;AACnC,MAAS,QAAA,CAAA,gBAAA,CAAiB,kBAAoB,EAAA,YAAA,CAAA,IAAA,EAAK,wBAAwB,CAAA,CAAA;AAAA;AAC7E;AACF,EAEO,OAAU,GAAA;AAEf,IAAA,IAAI,YAAK,CAAA,IAAA,EAAA,wBAAA,CAAA,IAA4B,OAAO,QAAA,KAAa,WAAa,EAAA;AACpE,MAAS,QAAA,CAAA,mBAAA,CAAoB,kBAAoB,EAAA,YAAA,CAAA,IAAA,EAAK,wBAAwB,CAAA,CAAA;AAC9E,MAAA,YAAA,CAAA,IAAA,EAAK,wBAA2B,EAAA,IAAA,CAAA;AAAA;AAIlC,IAAA,IAAA,CAAK,aAAc,EAAA;AAAA;AACrB,EAEO,aAAa,IAAc,EAAA;AAGhC,IAAA,IAAI,SAAS,MAAQ,EAAA;AACnB,MAAc,aAAA,CAAA,qBAAA,EAAuB,qCAAqC,IAAI,CAAA;AAC9E,MAAA;AAAA;AAGF,IAAA,IAAI,mBAAK,kBAAoB,CAAA,EAAA;AAC3B,MAAA,IAAI,mBAAK,sBAAwB,CAAA,EAAA;AAC/B,QAAA,IAAA,CAAK,aAAc,EAAA;AACnB,QAAK,IAAA,CAAA,gBAAA,CAAiB,MAAM,IAAI,CAAA;AAAA,OAC3B,MAAA;AACL,QAAA,IAAA,CAAK,SAAS,IAAI,CAAA;AAAA;AACpB,KACK,MAAA;AACL,MAAA,IAAA,CAAK,iBAAiB,IAAI,CAAA;AAAA;AAC5B;AACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYQ,gBAAA,CAAiB,IAAc,EAAA,KAAA,GAAQ,KAAO,EAAA;AACpD,IAAA,YAAA,CAAA,IAAA,EAAK,oBAAqB,EAAE,MAAA,EAAQ,IAAM,EAAA,MAAA,EAAQ,EAAG,EAAA,CAAA;AACrD,IAAK,YAAA,CAAA,IAAA,EAAA,eAAA,EAAkB,YAAY,GAAI,EAAA,CAAA;AACvC,IAAA,aAAA;AAAA,MACE,qBAAA;AAAA,MACA,CAAA,gBAAA,EAAmB,KAAQ,GAAA,QAAA,GAAW,OAAO,CAAA,CAAA,CAAA;AAAA,MAC7C,YAAK,CAAA,IAAA,EAAA,kBAAA,CAAA;AAAA,MACL,YAAK,CAAA,IAAA,EAAA,eAAA;AAAA,KACP;AAAA;AACF,EAEQ,iBAAA,CAAkB,sBAA8B,cAAwB,EAAA;AAC9E,IAAA,YAAA,CAAA,IAAA,EAAK,sBAAyB,EAAA,qBAAA;AAAA,MAAsB,MAClD,IAAA,CAAK,qBAAsB,CAAA,oBAAA,EAAsB,sBAAsB,cAAc;AAAA,KACvF,CAAA;AAAA;AACF,EAyFO,oBAAuB,GAAA;AAlMhC,IAAA,IAAA,EAAA;AAmMI,IAAc,aAAA,CAAA,qBAAA,EAAuB,4BAA8B,EAAA,YAAA,CAAA,IAAA,EAAK,kBAAkB,CAAA,CAAA;AAC1F,IAAA,IAAA,CAAA,CAAI,UAAK,eAAL,KAAA,IAAA,GAAA,MAAA,GAAA,EAAA,CAAsB,mBAA0B,EAAA,MAAA,CAAA,IAAK,mBAAK,kBAAoB,CAAA,EAAA;AAChF,MAAA,aAAA,CAAc,uBAAuB,yCAAyC,CAAA;AAC9E,MAAA,IAAA,CAAK,iBAAkB,CAAA,WAAA,CAAY,GAAI,EAAA,EAAG,mBAAK,eAAgB,CAAA,CAAA;AAAA;AACjE;AACF,EAEO,eAAkB,GAAA;AACvB,IAAO,OAAA,OAAA,CAAQ,mBAAK,sBAAsB,CAAA,CAAA;AAAA;AAC5C,EAEO,mBAAsB,GAAA;AAC3B,IAAA,IAAI,mBAAK,sBAAwB,CAAA,EAAA;AAC/B,MAAA,oBAAA,CAAqB,mBAAK,sBAAsB,CAAA,CAAA;AAChD,MAAA,YAAA,CAAA,IAAA,EAAK,sBAAyB,EAAA,IAAA,CAAA;AAC9B,MAAA,aAAA,CAAc,uBAAuB,iDAAiD,CAAA;AAAA;AACxF;AACF;AAAA,EAGO,aAAgB,GAAA;AACrB,IAAA,IAAI,mBAAK,kBAAoB,CAAA,EAAA;AAC3B,MAAc,aAAA,CAAA,qBAAA,EAAuB,oBAAsB,EAAA,YAAA,CAAA,IAAA,EAAK,kBAAkB,CAAA,CAAA;AAClF,MAAA,YAAA,CAAA,IAAA,EAAK,kBAAqB,EAAA,IAAA,CAAA;AAE1B,MAAA,IAAI,mBAAK,sBAAwB,CAAA,EAAA;AAC/B,QAAA,oBAAA,CAAqB,mBAAK,sBAAsB,CAAA,CAAA;AAChD,QAAA,YAAA,CAAA,IAAA,EAAK,sBAAyB,EAAA,IAAA,CAAA;AAAA;AAGhC,MAAA,YAAA,CAAA,IAAA,EAAK,wBAAyB,EAAC,CAAA;AAAA;AACjC;AACF,EAEO,SAAS,KAAe,EAAA;AAC7B,IAAA,IAAI,mBAAK,kBAAoB,CAAA,EAAA;AAC3B,MAAc,aAAA,CAAA,qBAAA,EAAuB,iBAAiB,KAAK,CAAA;AAC3D,MAAK,YAAA,CAAA,IAAA,EAAA,kBAAA,CAAA,CAAmB,MAAO,CAAA,IAAA,CAAK,KAAK,CAAA;AAAA;AAC3C;AAEJ;AAnOE,kBAAA,GAAA,IAAA,OAAA,EAAA;AAMA,eAAA,GAAA,IAAA,OAAA,EAAA;AACA,sBAAA,GAAA,IAAA,OAAA,EAAA;AAGA,sBAAA,GAAA,IAAA,OAAA,EAAA;AAEA,wBAAA,GAAA,IAAA,OAAA,EAAA;AAyNK,SAAS,qBAAqB,KAAiB,EAAA;AAEpD,EAAA,KAAA,IAAS,IAAI,KAAM,CAAA,MAAA,GAAS,CAAG,EAAA,CAAA,IAAK,GAAG,CAAK,EAAA,EAAA;AAC1C,IAAI,IAAA,KAAA,CAAM,CAAC,CAAA,GAAI,cAAgB,EAAA;AAC7B,MAAA,OAAO,KAAM,CAAA,KAAA,CAAM,CAAG,EAAA,CAAA,GAAI,CAAC,CAAA;AAAA;AAC7B;AAEF,EAAO,OAAA,CAAC,KAAM,CAAA,CAAC,CAAC,CAAA;AAClB;AAEgB,SAAA,cAAA,CAAe,SAAiB,KAAe,EAAA;AAC7D,EAAM,MAAA,OAAA,GAAU,WAAY,CAAA,gBAAA,CAAiB,UAAU,CAAA;AACvD,EAAA,WAAA,CAAY,oBAAqB,EAAA;AAEjC,EAAA,MAAM,iBAAiB,OAAQ,CAAA,MAAA;AAAA,IAC7B,CAAC,KAAA,KACC,KAAM,CAAA,SAAA,IAAa,OACnB,IAAA,KAAA,CAAM,SAAa,IAAA,KAAA,IACnB,KAAM,CAAA,WAAA,IAAe,OACrB,IAAA,KAAA,CAAM,WAAe,IAAA;AAAA,GACzB;AACA,EAAA,KAAA,MAAW,SAAS,cAAgB,EAAA;AAClC,IAAY,WAAA,CAAA,OAAA,CAAQ,gBAAmB,GAAA,KAAA,CAAM,IAAM,EAAA;AAAA,MACjD,OAAO,KAAM,CAAA,SAAA;AAAA,MACb,KAAK,KAAM,CAAA;AAAA,KACZ,CAAA;AAAA;AAGH,EAAA,OAAO,qBAAqB,cAAc,CAAA;AAC5C;AAGO,SAAS,qBAAqB,QAA+C,EAAA;AAClF,EAAI,IAAA,QAAA,CAAS,WAAW,CAAG,EAAA;AACzB,IAAO,OAAA,CAAA;AAAA;AAIT,EAAA,QAAA,CAAS,KAAK,CAAC,CAAA,EAAG,MAAM,CAAE,CAAA,SAAA,GAAY,EAAE,SAAS,CAAA;AAGjD,EAAA,IAAI,gBAAmB,GAAA,CAAA;AACvB,EAAI,IAAA,YAAA,GAAe,QAAS,CAAA,CAAC,CAAE,CAAA,SAAA;AAC/B,EAAI,IAAA,UAAA,GAAa,QAAS,CAAA,CAAC,CAAE,CAAA,WAAA;AAG7B,EAAA,KAAA,IAAS,CAAI,GAAA,CAAA,EAAG,CAAI,GAAA,QAAA,CAAS,QAAQ,CAAK,EAAA,EAAA;AACxC,IAAA,IAAI,QAAS,CAAA,CAAC,CAAE,CAAA,SAAA,IAAa,UAAY,EAAA;AAEvC,MAAA,UAAA,GAAa,KAAK,GAAI,CAAA,UAAA,EAAY,QAAS,CAAA,CAAC,EAAE,WAAW,CAAA;AAAA,KACpD,MAAA;AAEL,MAAA,gBAAA,IAAoB,UAAa,GAAA,YAAA;AAGjC,MAAe,YAAA,GAAA,QAAA,CAAS,CAAC,CAAE,CAAA,SAAA;AAC3B,MAAa,UAAA,GAAA,QAAA,CAAS,CAAC,CAAE,CAAA,WAAA;AAAA;AAC3B;AAIF,EAAA,gBAAA,IAAoB,UAAa,GAAA,YAAA;AAEjC,EAAO,OAAA,gBAAA;AACT;AAEO,MAAM,mBAAsB,GAAA;AAC5B,MAAM,6BAAgC,GAAA;AAEtC,MAAM,0BAA6B,GAAA;AACnC,MAAM,0BAA6B,GAAA;AACnC,MAAM,2BAA8B,GAAA;AACpC,MAAM,kCAAqC,GAAA;AAC3C,MAAM,0BAA6B,GAAA;;;;"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { t, Trans } from '@grafana/i18n';
|
|
2
|
-
import { rangeUtil, dateTime
|
|
3
|
-
import { config } from '@grafana/runtime';
|
|
2
|
+
import { rangeUtil, dateTime } from '@grafana/data';
|
|
4
3
|
import { useStyles2, ButtonGroup, ToolbarButton, Checkbox, ButtonSelect } from '@grafana/ui';
|
|
5
4
|
import React from 'react';
|
|
6
5
|
import { sceneGraph } from '../core/sceneGraph/index.js';
|
|
@@ -152,21 +151,6 @@ const timeShiftAlignmentProcessor = (primary, secondary) => {
|
|
|
152
151
|
isTimeShiftQuery: true
|
|
153
152
|
}
|
|
154
153
|
};
|
|
155
|
-
series.fields.forEach((field) => {
|
|
156
|
-
if (field.type === FieldType.time) {
|
|
157
|
-
field.values = field.values.map((v) => {
|
|
158
|
-
return diff < 0 ? v - diff : v + diff;
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
field.config = {
|
|
162
|
-
...field.config,
|
|
163
|
-
color: {
|
|
164
|
-
mode: "fixed",
|
|
165
|
-
fixedColor: config.theme.palette.gray60
|
|
166
|
-
}
|
|
167
|
-
};
|
|
168
|
-
return field;
|
|
169
|
-
});
|
|
170
154
|
});
|
|
171
155
|
return of(secondary);
|
|
172
156
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SceneTimeRangeCompare.js","sources":["../../../src/components/SceneTimeRangeCompare.tsx"],"sourcesContent":["import { t, Trans } from '@grafana/i18n';\nimport { DataQueryRequest, DateTime, dateTime, FieldType, GrafanaTheme2, rangeUtil, TimeRange } from '@grafana/data';\nimport { config } from '@grafana/runtime';\nimport { ButtonGroup, ButtonSelect, Checkbox, ToolbarButton, useStyles2 } from '@grafana/ui';\nimport React from 'react';\nimport { sceneGraph } from '../core/sceneGraph';\nimport { SceneObjectBase } from '../core/SceneObjectBase';\nimport { SceneComponentProps, SceneDataQuery, SceneObjectState, SceneObjectUrlValues } from '../core/types';\nimport { DataQueryExtended } from '../querying/SceneQueryRunner';\nimport { ExtraQueryDescriptor, ExtraQueryDataProcessor, ExtraQueryProvider } from '../querying/ExtraQueryProvider';\nimport { SceneObjectUrlSyncConfig } from '../services/SceneObjectUrlSyncConfig';\nimport { getCompareSeriesRefId } from '../utils/getCompareSeriesRefId';\nimport { parseUrlParam } from '../utils/parseUrlParam';\nimport { css } from '@emotion/css';\nimport { of } from 'rxjs';\n\ninterface SceneTimeRangeCompareState extends SceneObjectState {\n compareWith?: string;\n compareOptions: Array<{ label: string; value: string }>;\n hideCheckbox?: boolean;\n}\n\nconst PREVIOUS_PERIOD_VALUE = '__previousPeriod';\nconst NO_PERIOD_VALUE = '__noPeriod';\n\nexport const PREVIOUS_PERIOD_COMPARE_OPTION = {\n label: 'Previous period',\n value: PREVIOUS_PERIOD_VALUE,\n};\n\nexport const NO_COMPARE_OPTION = {\n label: 'None',\n value: NO_PERIOD_VALUE,\n};\n\nexport const DEFAULT_COMPARE_OPTIONS = [\n { label: 'Day before', value: '24h' },\n { label: 'Week before', value: '1w' },\n { label: 'Month before', value: '1M' },\n];\n\nexport class SceneTimeRangeCompare\n extends SceneObjectBase<SceneTimeRangeCompareState>\n implements ExtraQueryProvider<SceneTimeRangeCompareState>\n{\n static Component = SceneTimeRangeCompareRenderer;\n protected _urlSync = new SceneObjectUrlSyncConfig(this, { keys: ['compareWith'] });\n\n public constructor(state: Partial<SceneTimeRangeCompareState>) {\n super({ compareOptions: DEFAULT_COMPARE_OPTIONS, ...state });\n this.addActivationHandler(this._onActivate);\n }\n\n private _onActivate = () => {\n const sceneTimeRange = sceneGraph.getTimeRange(this);\n this.setState({ compareOptions: this.getCompareOptions(sceneTimeRange.state.value) });\n\n this._subs.add(\n sceneTimeRange.subscribeToState((timeRange) => {\n const compareOptions = this.getCompareOptions(timeRange.value);\n const stateUpdate: Partial<SceneTimeRangeCompareState> = { compareOptions };\n\n // if current compareWith is not applicable to the new time range, set it to previous period comparison\n if (Boolean(this.state.compareWith) && !compareOptions.find(({ value }) => value === this.state.compareWith)) {\n stateUpdate.compareWith = PREVIOUS_PERIOD_VALUE;\n }\n\n this.setState(stateUpdate);\n })\n );\n };\n\n public getCompareOptions = (timeRange: TimeRange) => {\n const diffDays = Math.ceil(timeRange.to.diff(timeRange.from));\n\n const matchIndex = DEFAULT_COMPARE_OPTIONS.findIndex(({ value }) => {\n const intervalInMs = rangeUtil.intervalToMs(value);\n return intervalInMs >= diffDays;\n });\n\n return [\n NO_COMPARE_OPTION,\n PREVIOUS_PERIOD_COMPARE_OPTION,\n ...DEFAULT_COMPARE_OPTIONS.slice(matchIndex).map(({ label, value }) => ({ label, value })),\n ];\n };\n\n public onCompareWithChanged = (compareWith: string) => {\n if (compareWith === NO_PERIOD_VALUE) {\n this.onClearCompare();\n } else {\n this.setState({ compareWith });\n }\n };\n\n public onClearCompare = () => {\n this.setState({ compareWith: undefined });\n };\n\n // Get a time shifted request to compare with the primary request.\n public getExtraQueries(request: DataQueryRequest): ExtraQueryDescriptor[] {\n const extraQueries: ExtraQueryDescriptor[] = [];\n const compareRange = this.getCompareTimeRange(request.range);\n if (!compareRange) {\n return extraQueries;\n }\n\n const targets = request.targets.filter((query: DataQueryExtended) => query.timeRangeCompare !== false);\n if (targets.length) {\n extraQueries.push({\n req: {\n ...request,\n targets,\n range: compareRange,\n },\n processor: timeShiftAlignmentProcessor,\n });\n }\n return extraQueries;\n }\n\n // The query runner should rerun the comparison query if the compareWith value has changed and there are queries that haven't opted out of TWC\n public shouldRerun(\n prev: SceneTimeRangeCompareState,\n next: SceneTimeRangeCompareState,\n queries: SceneDataQuery[]\n ): boolean {\n return (\n prev.compareWith !== next.compareWith && queries.find((query) => query.timeRangeCompare !== false) !== undefined\n );\n }\n\n public getCompareTimeRange(timeRange: TimeRange): TimeRange | undefined {\n let compareFrom: DateTime;\n let compareTo: DateTime;\n\n if (this.state.compareWith) {\n if (this.state.compareWith === PREVIOUS_PERIOD_VALUE) {\n const diffMs = timeRange.to.diff(timeRange.from);\n compareFrom = dateTime(timeRange.from!).subtract(diffMs);\n compareTo = dateTime(timeRange.to!).subtract(diffMs);\n } else {\n compareFrom = dateTime(timeRange.from!).subtract(rangeUtil.intervalToMs(this.state.compareWith));\n compareTo = dateTime(timeRange.to!).subtract(rangeUtil.intervalToMs(this.state.compareWith));\n }\n return {\n from: compareFrom,\n to: compareTo,\n raw: {\n from: compareFrom,\n to: compareTo,\n },\n };\n }\n\n return undefined;\n }\n\n public getUrlState(): SceneObjectUrlValues {\n return {\n compareWith: this.state.compareWith,\n };\n }\n\n public updateFromUrl(values: SceneObjectUrlValues) {\n if (!values.compareWith) {\n return;\n }\n\n const compareWith = parseUrlParam(values.compareWith);\n\n if (compareWith) {\n const compareOptions = this.getCompareOptions(sceneGraph.getTimeRange(this).state.value);\n\n if (compareOptions.find(({ value }) => value === compareWith)) {\n this.setState({\n compareWith,\n });\n } else {\n this.setState({\n compareWith: '__previousPeriod',\n });\n }\n }\n }\n}\n\n// Processor function for use with time shifted comparison series.\n// This aligns the secondary series with the primary and adds custom\n// metadata and config to the secondary series' fields so that it is\n// rendered appropriately.\nconst timeShiftAlignmentProcessor: ExtraQueryDataProcessor = (primary, secondary) => {\n const diff = secondary.timeRange.from.diff(primary.timeRange.from);\n secondary.series.forEach((series) => {\n series.refId = getCompareSeriesRefId(series.refId || '');\n series.meta = {\n ...series.meta,\n // @ts-ignore Remove when https://github.com/grafana/grafana/pull/71129 is released\n timeCompare: {\n diffMs: diff,\n isTimeShiftQuery: true,\n },\n };\n series.fields.forEach((field) => {\n // Align compare series time stamps with reference series\n if (field.type === FieldType.time) {\n field.values = field.values.map((v) => {\n return diff < 0 ? v - diff : v + diff;\n });\n }\n\n field.config = {\n ...field.config,\n color: {\n mode: 'fixed',\n fixedColor: config.theme.palette.gray60,\n },\n };\n return field;\n });\n });\n return of(secondary);\n};\n\nfunction SceneTimeRangeCompareRenderer({ model }: SceneComponentProps<SceneTimeRangeCompare>) {\n const styles = useStyles2(getStyles);\n const { compareWith, compareOptions, hideCheckbox } = model.useState();\n\n const [previousCompare, setPreviousCompare] = React.useState(compareWith);\n const previousValue = compareOptions.find(({ value }) => value === previousCompare) ?? PREVIOUS_PERIOD_COMPARE_OPTION;\n\n const value = compareOptions.find(({ value }) => value === compareWith);\n const enabled = Boolean(value);\n\n const onClick = () => {\n if (enabled) {\n setPreviousCompare(compareWith);\n model.onClearCompare();\n } else if (!enabled) {\n model.onCompareWithChanged(previousValue.value);\n }\n };\n\n // When hideCheckbox is true, always show select and use NO_COMPARE_OPTION when no comparison is active\n const selectValue = hideCheckbox && !compareWith ? NO_COMPARE_OPTION : value;\n const showSelect = hideCheckbox || enabled;\n\n // Create display value with \"Comparison\" prefix when hideCheckbox is true\n const displayValue =\n hideCheckbox && selectValue\n ? {\n ...selectValue,\n label: `Comparison: ${selectValue.label}`,\n }\n : selectValue;\n\n return (\n <ButtonGroup>\n {!hideCheckbox && (\n <ToolbarButton\n variant=\"canvas\"\n tooltip={t(\n 'grafana-scenes.components.scene-time-range-compare-renderer.button-tooltip',\n 'Enable time frame comparison'\n )}\n onClick={(e) => {\n e.stopPropagation();\n e.preventDefault();\n onClick();\n }}\n >\n <Checkbox label=\" \" value={enabled} onClick={onClick} />\n <Trans i18nKey=\"grafana-scenes.components.scene-time-range-compare-renderer.button-label\">Comparison</Trans>\n </ToolbarButton>\n )}\n\n {showSelect ? (\n <ButtonSelect\n variant=\"canvas\"\n value={displayValue}\n options={compareOptions}\n onChange={(v) => {\n model.onCompareWithChanged(v.value!);\n }}\n />\n ) : (\n <ToolbarButton className={styles.previewButton} disabled variant=\"canvas\" isOpen={false}>\n {previousValue.label}\n </ToolbarButton>\n )}\n </ButtonGroup>\n );\n}\n\nfunction getStyles(theme: GrafanaTheme2) {\n return {\n previewButton: css({\n '&:disabled': {\n border: `1px solid ${theme.colors.secondary.border}`,\n color: theme.colors.text.disabled,\n opacity: 1,\n },\n }),\n };\n}\n"],"names":["value"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SceneTimeRangeCompare.js","sources":["../../../src/components/SceneTimeRangeCompare.tsx"],"sourcesContent":["import { t, Trans } from '@grafana/i18n';\nimport { DataQueryRequest, DateTime, dateTime, GrafanaTheme2, rangeUtil, TimeRange } from '@grafana/data';\nimport { ButtonGroup, ButtonSelect, Checkbox, ToolbarButton, useStyles2 } from '@grafana/ui';\nimport React from 'react';\nimport { sceneGraph } from '../core/sceneGraph';\nimport { SceneObjectBase } from '../core/SceneObjectBase';\nimport { SceneComponentProps, SceneDataQuery, SceneObjectState, SceneObjectUrlValues } from '../core/types';\nimport { DataQueryExtended } from '../querying/SceneQueryRunner';\nimport { ExtraQueryDescriptor, ExtraQueryDataProcessor, ExtraQueryProvider } from '../querying/ExtraQueryProvider';\nimport { SceneObjectUrlSyncConfig } from '../services/SceneObjectUrlSyncConfig';\nimport { getCompareSeriesRefId } from '../utils/getCompareSeriesRefId';\nimport { parseUrlParam } from '../utils/parseUrlParam';\nimport { css } from '@emotion/css';\nimport { of } from 'rxjs';\n\ninterface SceneTimeRangeCompareState extends SceneObjectState {\n compareWith?: string;\n compareOptions: Array<{ label: string; value: string }>;\n hideCheckbox?: boolean;\n}\n\nconst PREVIOUS_PERIOD_VALUE = '__previousPeriod';\nconst NO_PERIOD_VALUE = '__noPeriod';\n\nexport const PREVIOUS_PERIOD_COMPARE_OPTION = {\n label: 'Previous period',\n value: PREVIOUS_PERIOD_VALUE,\n};\n\nexport const NO_COMPARE_OPTION = {\n label: 'None',\n value: NO_PERIOD_VALUE,\n};\n\nexport const DEFAULT_COMPARE_OPTIONS = [\n { label: 'Day before', value: '24h' },\n { label: 'Week before', value: '1w' },\n { label: 'Month before', value: '1M' },\n];\n\nexport class SceneTimeRangeCompare\n extends SceneObjectBase<SceneTimeRangeCompareState>\n implements ExtraQueryProvider<SceneTimeRangeCompareState>\n{\n static Component = SceneTimeRangeCompareRenderer;\n protected _urlSync = new SceneObjectUrlSyncConfig(this, { keys: ['compareWith'] });\n\n public constructor(state: Partial<SceneTimeRangeCompareState>) {\n super({ compareOptions: DEFAULT_COMPARE_OPTIONS, ...state });\n this.addActivationHandler(this._onActivate);\n }\n\n private _onActivate = () => {\n const sceneTimeRange = sceneGraph.getTimeRange(this);\n this.setState({ compareOptions: this.getCompareOptions(sceneTimeRange.state.value) });\n\n this._subs.add(\n sceneTimeRange.subscribeToState((timeRange) => {\n const compareOptions = this.getCompareOptions(timeRange.value);\n const stateUpdate: Partial<SceneTimeRangeCompareState> = { compareOptions };\n\n // if current compareWith is not applicable to the new time range, set it to previous period comparison\n if (Boolean(this.state.compareWith) && !compareOptions.find(({ value }) => value === this.state.compareWith)) {\n stateUpdate.compareWith = PREVIOUS_PERIOD_VALUE;\n }\n\n this.setState(stateUpdate);\n })\n );\n };\n\n public getCompareOptions = (timeRange: TimeRange) => {\n const diffDays = Math.ceil(timeRange.to.diff(timeRange.from));\n\n const matchIndex = DEFAULT_COMPARE_OPTIONS.findIndex(({ value }) => {\n const intervalInMs = rangeUtil.intervalToMs(value);\n return intervalInMs >= diffDays;\n });\n\n return [\n NO_COMPARE_OPTION,\n PREVIOUS_PERIOD_COMPARE_OPTION,\n ...DEFAULT_COMPARE_OPTIONS.slice(matchIndex).map(({ label, value }) => ({ label, value })),\n ];\n };\n\n public onCompareWithChanged = (compareWith: string) => {\n if (compareWith === NO_PERIOD_VALUE) {\n this.onClearCompare();\n } else {\n this.setState({ compareWith });\n }\n };\n\n public onClearCompare = () => {\n this.setState({ compareWith: undefined });\n };\n\n // Get a time shifted request to compare with the primary request.\n public getExtraQueries(request: DataQueryRequest): ExtraQueryDescriptor[] {\n const extraQueries: ExtraQueryDescriptor[] = [];\n const compareRange = this.getCompareTimeRange(request.range);\n if (!compareRange) {\n return extraQueries;\n }\n\n const targets = request.targets.filter((query: DataQueryExtended) => query.timeRangeCompare !== false);\n if (targets.length) {\n extraQueries.push({\n req: {\n ...request,\n targets,\n range: compareRange,\n },\n processor: timeShiftAlignmentProcessor,\n });\n }\n return extraQueries;\n }\n\n // The query runner should rerun the comparison query if the compareWith value has changed and there are queries that haven't opted out of TWC\n public shouldRerun(\n prev: SceneTimeRangeCompareState,\n next: SceneTimeRangeCompareState,\n queries: SceneDataQuery[]\n ): boolean {\n return (\n prev.compareWith !== next.compareWith && queries.find((query) => query.timeRangeCompare !== false) !== undefined\n );\n }\n\n public getCompareTimeRange(timeRange: TimeRange): TimeRange | undefined {\n let compareFrom: DateTime;\n let compareTo: DateTime;\n\n if (this.state.compareWith) {\n if (this.state.compareWith === PREVIOUS_PERIOD_VALUE) {\n const diffMs = timeRange.to.diff(timeRange.from);\n compareFrom = dateTime(timeRange.from!).subtract(diffMs);\n compareTo = dateTime(timeRange.to!).subtract(diffMs);\n } else {\n compareFrom = dateTime(timeRange.from!).subtract(rangeUtil.intervalToMs(this.state.compareWith));\n compareTo = dateTime(timeRange.to!).subtract(rangeUtil.intervalToMs(this.state.compareWith));\n }\n return {\n from: compareFrom,\n to: compareTo,\n raw: {\n from: compareFrom,\n to: compareTo,\n },\n };\n }\n\n return undefined;\n }\n\n public getUrlState(): SceneObjectUrlValues {\n return {\n compareWith: this.state.compareWith,\n };\n }\n\n public updateFromUrl(values: SceneObjectUrlValues) {\n if (!values.compareWith) {\n return;\n }\n\n const compareWith = parseUrlParam(values.compareWith);\n\n if (compareWith) {\n const compareOptions = this.getCompareOptions(sceneGraph.getTimeRange(this).state.value);\n\n if (compareOptions.find(({ value }) => value === compareWith)) {\n this.setState({\n compareWith,\n });\n } else {\n this.setState({\n compareWith: '__previousPeriod',\n });\n }\n }\n }\n}\n\n// Processor function for use with time shifted comparison series.\n// This aligns the secondary series with the primary and adds custom\n// metadata and config to the secondary series' fields so that it is\n// rendered appropriately.\nconst timeShiftAlignmentProcessor: ExtraQueryDataProcessor = (primary, secondary) => {\n const diff = secondary.timeRange.from.diff(primary.timeRange.from);\n secondary.series.forEach((series) => {\n series.refId = getCompareSeriesRefId(series.refId || '');\n series.meta = {\n ...series.meta,\n // @ts-ignore Remove when https://github.com/grafana/grafana/pull/71129 is released\n timeCompare: {\n diffMs: diff,\n isTimeShiftQuery: true,\n },\n };\n });\n return of(secondary);\n};\n\nfunction SceneTimeRangeCompareRenderer({ model }: SceneComponentProps<SceneTimeRangeCompare>) {\n const styles = useStyles2(getStyles);\n const { compareWith, compareOptions, hideCheckbox } = model.useState();\n\n const [previousCompare, setPreviousCompare] = React.useState(compareWith);\n const previousValue = compareOptions.find(({ value }) => value === previousCompare) ?? PREVIOUS_PERIOD_COMPARE_OPTION;\n\n const value = compareOptions.find(({ value }) => value === compareWith);\n const enabled = Boolean(value);\n\n const onClick = () => {\n if (enabled) {\n setPreviousCompare(compareWith);\n model.onClearCompare();\n } else if (!enabled) {\n model.onCompareWithChanged(previousValue.value);\n }\n };\n\n // When hideCheckbox is true, always show select and use NO_COMPARE_OPTION when no comparison is active\n const selectValue = hideCheckbox && !compareWith ? NO_COMPARE_OPTION : value;\n const showSelect = hideCheckbox || enabled;\n\n // Create display value with \"Comparison\" prefix when hideCheckbox is true\n const displayValue =\n hideCheckbox && selectValue\n ? {\n ...selectValue,\n label: `Comparison: ${selectValue.label}`,\n }\n : selectValue;\n\n return (\n <ButtonGroup>\n {!hideCheckbox && (\n <ToolbarButton\n variant=\"canvas\"\n tooltip={t(\n 'grafana-scenes.components.scene-time-range-compare-renderer.button-tooltip',\n 'Enable time frame comparison'\n )}\n onClick={(e) => {\n e.stopPropagation();\n e.preventDefault();\n onClick();\n }}\n >\n <Checkbox label=\" \" value={enabled} onClick={onClick} />\n <Trans i18nKey=\"grafana-scenes.components.scene-time-range-compare-renderer.button-label\">Comparison</Trans>\n </ToolbarButton>\n )}\n\n {showSelect ? (\n <ButtonSelect\n variant=\"canvas\"\n value={displayValue}\n options={compareOptions}\n onChange={(v) => {\n model.onCompareWithChanged(v.value!);\n }}\n />\n ) : (\n <ToolbarButton className={styles.previewButton} disabled variant=\"canvas\" isOpen={false}>\n {previousValue.label}\n </ToolbarButton>\n )}\n </ButtonGroup>\n );\n}\n\nfunction getStyles(theme: GrafanaTheme2) {\n return {\n previewButton: css({\n '&:disabled': {\n border: `1px solid ${theme.colors.secondary.border}`,\n color: theme.colors.text.disabled,\n opacity: 1,\n },\n }),\n };\n}\n"],"names":["value"],"mappings":"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"}
|
|
@@ -7,15 +7,6 @@ function writeSceneLog(logger, message, ...rest) {
|
|
|
7
7
|
console.log(`${logger}: `, message, ...rest);
|
|
8
8
|
}
|
|
9
9
|
}
|
|
10
|
-
function writeSceneLogStyled(logger, message, style, ...rest) {
|
|
11
|
-
let loggingEnabled = false;
|
|
12
|
-
if (typeof window !== "undefined") {
|
|
13
|
-
loggingEnabled = localStorage.getItem("grafana.debug.scenes") === "true";
|
|
14
|
-
}
|
|
15
|
-
if (loggingEnabled) {
|
|
16
|
-
console.log(`%c${logger}: ${message}`, style, ...rest);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
10
|
|
|
20
|
-
export { writeSceneLog
|
|
11
|
+
export { writeSceneLog };
|
|
21
12
|
//# sourceMappingURL=writeSceneLog.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"writeSceneLog.js","sources":["../../../src/utils/writeSceneLog.ts"],"sourcesContent":["export function writeSceneLog(logger: string, message: string, ...rest: unknown[]) {\n let loggingEnabled = false;\n\n if (typeof window !== 'undefined') {\n loggingEnabled = localStorage.getItem('grafana.debug.scenes') === 'true';\n }\n\n if (loggingEnabled) {\n console.log(`${logger}: `, message, ...rest);\n }\n}\n
|
|
1
|
+
{"version":3,"file":"writeSceneLog.js","sources":["../../../src/utils/writeSceneLog.ts"],"sourcesContent":["export function writeSceneLog(logger: string, message: string, ...rest: unknown[]) {\n let loggingEnabled = false;\n\n if (typeof window !== 'undefined') {\n loggingEnabled = localStorage.getItem('grafana.debug.scenes') === 'true';\n }\n\n if (loggingEnabled) {\n console.log(`${logger}: `, message, ...rest);\n }\n}\n"],"names":[],"mappings":"AAAgB,SAAA,aAAA,CAAc,MAAgB,EAAA,OAAA,EAAA,GAAoB,IAAiB,EAAA;AACjF,EAAA,IAAI,cAAiB,GAAA,KAAA;AAErB,EAAI,IAAA,OAAO,WAAW,WAAa,EAAA;AACjC,IAAiB,cAAA,GAAA,YAAA,CAAa,OAAQ,CAAA,sBAAsB,CAAM,KAAA,MAAA;AAAA;AAGpE,EAAA,IAAI,cAAgB,EAAA;AAClB,IAAA,OAAA,CAAQ,IAAI,CAAG,EAAA,MAAM,CAAM,EAAA,CAAA,EAAA,OAAA,EAAS,GAAG,IAAI,CAAA;AAAA;AAE/C;;;;"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1308,13 +1308,6 @@ declare class UserActionEvent extends BusEventWithPayload<UserActionEventPayload
|
|
|
1308
1308
|
*/
|
|
1309
1309
|
declare function lookupVariable(name: string, sceneObject: SceneObject): SceneVariable | null;
|
|
1310
1310
|
|
|
1311
|
-
interface LongFrameEvent {
|
|
1312
|
-
duration: number;
|
|
1313
|
-
timestamp: number;
|
|
1314
|
-
method: 'manual' | 'loaf';
|
|
1315
|
-
}
|
|
1316
|
-
type LongFrameCallback = (event: LongFrameEvent) => void;
|
|
1317
|
-
|
|
1318
1311
|
interface QueryResultWithState {
|
|
1319
1312
|
state: LoadingState;
|
|
1320
1313
|
}
|
|
@@ -1325,9 +1318,6 @@ interface SceneQueryControllerEntry {
|
|
|
1325
1318
|
cancel?: () => void;
|
|
1326
1319
|
}
|
|
1327
1320
|
type SceneQueryControllerEntryType = 'data' | 'annotations' | 'variable' | 'alerts' | 'plugin' | string;
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
1321
|
interface SceneInteractionProfileEvent {
|
|
1332
1322
|
origin: string;
|
|
1333
1323
|
duration: number;
|
|
@@ -1338,8 +1328,6 @@ interface SceneInteractionProfileEvent {
|
|
|
1338
1328
|
crumbs: string[];
|
|
1339
1329
|
startTs: number;
|
|
1340
1330
|
endTs: number;
|
|
1341
|
-
longFramesCount: number;
|
|
1342
|
-
longFramesTotalTime: number;
|
|
1343
1331
|
}
|
|
1344
1332
|
interface SceneQueryStateControllerState extends SceneObjectState {
|
|
1345
1333
|
isRunning: boolean;
|
|
@@ -1535,23 +1523,6 @@ declare class PanelContextEventBus implements EventBus {
|
|
|
1535
1523
|
newScopedBus(key: string, filter: EventFilterOptions): EventBus;
|
|
1536
1524
|
}
|
|
1537
1525
|
|
|
1538
|
-
/**
|
|
1539
|
-
* SceneRenderProfiler tracks dashboard interaction performance including:
|
|
1540
|
-
* - Total interaction duration
|
|
1541
|
-
* - Network time
|
|
1542
|
-
* - Long frame detection (50ms threshold) during interaction using LoAF API (default) or manual tracking (fallback)
|
|
1543
|
-
* - Slow frame detection (30ms threshold) for tail recording after interaction
|
|
1544
|
-
*
|
|
1545
|
-
* Long frame detection during interaction:
|
|
1546
|
-
* - 50ms threshold aligned with LoAF API default
|
|
1547
|
-
* - LoAF API preferred (Chrome 123+) with manual fallback
|
|
1548
|
-
* - Provides script attribution when using LoAF API
|
|
1549
|
-
*
|
|
1550
|
-
* Slow frame detection for tail recording:
|
|
1551
|
-
* - 30ms threshold for post-interaction monitoring
|
|
1552
|
-
* - Manual frame timing measurement
|
|
1553
|
-
* - Captures rendering delays after user interaction completes
|
|
1554
|
-
*/
|
|
1555
1526
|
declare class SceneRenderProfiler {
|
|
1556
1527
|
#private;
|
|
1557
1528
|
private queryController?;
|