@perses-dev/timeseries-chart-plugin 0.13.0-beta.1 → 0.13.0-beta.3

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 (105) hide show
  1. package/__mf/js/TimeSeriesChart.693fccf6.js +7 -0
  2. package/__mf/js/async/121.c3c0e54f.js +2 -0
  3. package/__mf/js/async/137.59c998ab.js +38 -0
  4. package/__mf/js/async/177.2fef2962.js +1 -0
  5. package/__mf/js/async/187.f5e8932b.js +1 -0
  6. package/__mf/js/async/192.c3dd56d5.js +1 -0
  7. package/__mf/js/async/2.60fa4a40.js +1 -0
  8. package/__mf/js/async/235.d23c8ef0.js +1 -0
  9. package/__mf/js/async/247.b8cba23e.js +7 -0
  10. package/__mf/js/async/274.72dfa9c8.js +2 -0
  11. package/__mf/js/async/356.8170c96d.js +1 -0
  12. package/__mf/js/async/392.b9ba5bf2.js +2 -0
  13. package/__mf/js/async/470.e09f33b7.js +2 -0
  14. package/__mf/js/async/491.85194549.js +1 -0
  15. package/__mf/js/async/52.0850e52c.js +1 -0
  16. package/__mf/js/async/527.f97d1b86.js +110 -0
  17. package/__mf/js/async/555.a66f6ab5.js +2 -0
  18. package/__mf/js/async/568.45da2c30.js +1 -0
  19. package/__mf/js/async/570.bafa9150.js +3 -0
  20. package/__mf/js/async/587.c9460696.js +1 -0
  21. package/__mf/js/async/588.0a1aa144.js +1 -0
  22. package/__mf/js/async/603.3b771310.js +2 -0
  23. package/__mf/js/async/603.3b771310.js.LICENSE.txt +9 -0
  24. package/__mf/js/async/616.79484ac8.js +1 -0
  25. package/__mf/js/async/655.dbf8c618.js +1 -0
  26. package/__mf/js/async/702.785cd635.js +2 -0
  27. package/__mf/js/async/71.8c6cf914.js +1 -0
  28. package/__mf/js/async/724.c45dcf5b.js +1 -0
  29. package/__mf/js/async/873.04a201bf.js +1 -0
  30. package/__mf/js/async/941.b89f8595.js +2 -0
  31. package/__mf/js/async/955.176fe200.js +1 -0
  32. package/__mf/js/async/968.2a9fb1a0.js +1 -0
  33. package/__mf/js/async/978.a9865b23.js +1 -0
  34. package/__mf/js/async/984.5778f693.js +22 -0
  35. package/__mf/js/async/{187.2cc43fac.js.LICENSE.txt → 984.5778f693.js.LICENSE.txt} +0 -10
  36. package/__mf/js/async/__federation_expose_TimeSeriesChart.5f574fcb.js +1 -0
  37. package/__mf/js/async/lib-router.319c02cd.js +2 -0
  38. package/__mf/js/async/{lib-router.1934857d.js.LICENSE.txt → lib-router.319c02cd.js.LICENSE.txt} +3 -3
  39. package/__mf/js/main.046b2715.js +7 -0
  40. package/lib/QuerySettingsEditor.d.ts.map +1 -1
  41. package/lib/QuerySettingsEditor.js +13 -11
  42. package/lib/QuerySettingsEditor.js.map +1 -1
  43. package/lib/TimeSeriesChartBase.d.ts +2 -0
  44. package/lib/TimeSeriesChartBase.d.ts.map +1 -1
  45. package/lib/TimeSeriesChartBase.js +90 -7
  46. package/lib/TimeSeriesChartBase.js.map +1 -1
  47. package/lib/TimeSeriesChartPanel.d.ts.map +1 -1
  48. package/lib/TimeSeriesChartPanel.js +7 -0
  49. package/lib/TimeSeriesChartPanel.js.map +1 -1
  50. package/lib/annotations/AnnotationTooltip.d.ts +18 -0
  51. package/lib/annotations/AnnotationTooltip.d.ts.map +1 -0
  52. package/lib/annotations/AnnotationTooltip.js +352 -0
  53. package/lib/annotations/AnnotationTooltip.js.map +1 -0
  54. package/lib/cjs/QuerySettingsEditor.js +12 -10
  55. package/lib/cjs/TimeSeriesChartBase.js +90 -7
  56. package/lib/cjs/TimeSeriesChartPanel.js +7 -0
  57. package/lib/cjs/annotations/AnnotationTooltip.js +370 -0
  58. package/lib/cjs/utils/annotation.js +37 -0
  59. package/lib/utils/annotation.d.ts +5 -0
  60. package/lib/utils/annotation.d.ts.map +1 -0
  61. package/lib/utils/annotation.js +29 -0
  62. package/lib/utils/annotation.js.map +1 -0
  63. package/mf-manifest.json +61 -36
  64. package/mf-stats.json +68 -36
  65. package/package.json +6 -4
  66. package/__mf/js/TimeSeriesChart.f9dd142d.js +0 -7
  67. package/__mf/js/async/121.df4898d6.js +0 -2
  68. package/__mf/js/async/177.56f1be10.js +0 -1
  69. package/__mf/js/async/187.2cc43fac.js +0 -24
  70. package/__mf/js/async/192.beef3a1a.js +0 -1
  71. package/__mf/js/async/2.c3740bb9.js +0 -1
  72. package/__mf/js/async/235.c24f24f7.js +0 -1
  73. package/__mf/js/async/274.d112354f.js +0 -2
  74. package/__mf/js/async/356.9f551c8a.js +0 -1
  75. package/__mf/js/async/392.2350fb02.js +0 -2
  76. package/__mf/js/async/470.a4fd777e.js +0 -2
  77. package/__mf/js/async/491.6f81cf51.js +0 -1
  78. package/__mf/js/async/568.cdcaf97d.js +0 -1
  79. package/__mf/js/async/587.c12780da.js +0 -1
  80. package/__mf/js/async/588.6662e16a.js +0 -1
  81. package/__mf/js/async/616.52acb1b4.js +0 -1
  82. package/__mf/js/async/681.8d61b348.js +0 -110
  83. package/__mf/js/async/702.de247ad8.js +0 -2
  84. package/__mf/js/async/71.84e486c9.js +0 -1
  85. package/__mf/js/async/724.3439df06.js +0 -1
  86. package/__mf/js/async/78.91de282a.js +0 -1
  87. package/__mf/js/async/780.12a33d06.js +0 -39
  88. package/__mf/js/async/873.9aad328a.js +0 -1
  89. package/__mf/js/async/907.5ce8f69d.js +0 -7
  90. package/__mf/js/async/941.c0e2d25e.js +0 -2
  91. package/__mf/js/async/968.6de5fa7c.js +0 -1
  92. package/__mf/js/async/978.5c14e175.js +0 -1
  93. package/__mf/js/async/__federation_expose_TimeSeriesChart.d1167045.js +0 -1
  94. package/__mf/js/async/lib-router.1934857d.js +0 -2
  95. package/__mf/js/main.2bb9f3e3.js +0 -7
  96. /package/__mf/css/async/{907.85c2cbf6.css → 247.85c2cbf6.css} +0 -0
  97. /package/__mf/js/async/{121.df4898d6.js.LICENSE.txt → 121.c3c0e54f.js.LICENSE.txt} +0 -0
  98. /package/__mf/js/async/{907.5ce8f69d.js.LICENSE.txt → 247.b8cba23e.js.LICENSE.txt} +0 -0
  99. /package/__mf/js/async/{274.d112354f.js.LICENSE.txt → 274.72dfa9c8.js.LICENSE.txt} +0 -0
  100. /package/__mf/js/async/{392.2350fb02.js.LICENSE.txt → 392.b9ba5bf2.js.LICENSE.txt} +0 -0
  101. /package/__mf/js/async/{470.a4fd777e.js.LICENSE.txt → 470.e09f33b7.js.LICENSE.txt} +0 -0
  102. /package/__mf/js/async/{681.8d61b348.js.LICENSE.txt → 527.f97d1b86.js.LICENSE.txt} +0 -0
  103. /package/__mf/js/async/{780.12a33d06.js.LICENSE.txt → 555.a66f6ab5.js.LICENSE.txt} +0 -0
  104. /package/__mf/js/async/{702.de247ad8.js.LICENSE.txt → 702.785cd635.js.LICENSE.txt} +0 -0
  105. /package/__mf/js/async/{941.c0e2d25e.js.LICENSE.txt → 941.b89f8595.js.LICENSE.txt} +0 -0
@@ -0,0 +1,352 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ // Copyright The Perses Authors
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ import { Box, Divider, Portal, Stack, Typography } from '@mui/material';
15
+ import Pin from 'mdi-material-ui/Pin';
16
+ import PinOutline from 'mdi-material-ui/PinOutline';
17
+ import useResizeObserver from 'use-resize-observer';
18
+ import { assembleTransform, getDateAndTime, getTooltipStyles, PIN_TOOLTIP_HELP_TEXT, TOOLTIP_BG_COLOR_FALLBACK, TOOLTIP_MAX_WIDTH, UNPIN_TOOLTIP_HELP_TEXT, useMousePosition } from '@perses-dev/components';
19
+ import { DEFAULT_ANNOTATION_COLOR } from '@perses-dev/plugin-system';
20
+ export function AnnotationTooltip({ annotation, containerId, formatWithUserTimeZone, pinnedPos, enablePinning = true, onUnpinClick }) {
21
+ const mousePos = useMousePosition();
22
+ const { height, width, ref: tooltipRef } = useResizeObserver();
23
+ const isPinned = pinnedPos !== null;
24
+ if (!isPinned && mousePos === null) return null;
25
+ const containerElement = containerId ? document.querySelector(containerId) : undefined;
26
+ const maxHeight = containerElement ? containerElement.getBoundingClientRect().height : undefined;
27
+ const transform = assembleTransform(mousePos, pinnedPos, height ?? 0, width ?? 0, containerElement);
28
+ const start = getDateAndTime(annotation.start, formatWithUserTimeZone);
29
+ const end = annotation.end !== undefined ? getDateAndTime(annotation.end, formatWithUserTimeZone) : null;
30
+ return /*#__PURE__*/ _jsx(Portal, {
31
+ container: containerElement,
32
+ children: /*#__PURE__*/ _jsx(Box, {
33
+ ref: tooltipRef,
34
+ sx: (theme)=>getTooltipStyles(theme, pinnedPos, maxHeight),
35
+ style: {
36
+ transform
37
+ },
38
+ children: /*#__PURE__*/ _jsxs(Stack, {
39
+ spacing: 0.5,
40
+ children: [
41
+ /*#__PURE__*/ _jsxs(Box, {
42
+ sx: (theme)=>({
43
+ width: '100%',
44
+ maxWidth: TOOLTIP_MAX_WIDTH,
45
+ padding: theme.spacing(1.5, 2, 0.5, 2),
46
+ backgroundColor: theme.palette.designSystem?.grey[800] ?? TOOLTIP_BG_COLOR_FALLBACK,
47
+ position: 'sticky',
48
+ top: 0,
49
+ left: 0
50
+ }),
51
+ children: [
52
+ /*#__PURE__*/ _jsxs(Box, {
53
+ sx: {
54
+ display: 'flex',
55
+ alignItems: 'center',
56
+ paddingBottom: 0.5,
57
+ width: '100%'
58
+ },
59
+ children: [
60
+ /*#__PURE__*/ _jsx(Box, {
61
+ sx: {
62
+ width: 8,
63
+ height: 8,
64
+ borderRadius: '50%',
65
+ backgroundColor: annotation.color ?? DEFAULT_ANNOTATION_COLOR,
66
+ marginRight: 1,
67
+ flexShrink: 0
68
+ }
69
+ }),
70
+ /*#__PURE__*/ _jsxs(Box, {
71
+ sx: {
72
+ flexGrow: 1,
73
+ minWidth: 0
74
+ },
75
+ children: [
76
+ /*#__PURE__*/ _jsxs(Typography, {
77
+ variant: "caption",
78
+ children: [
79
+ start.formattedDate,
80
+ " - ",
81
+ /*#__PURE__*/ _jsx("strong", {
82
+ children: start.formattedTime
83
+ })
84
+ ]
85
+ }),
86
+ end && /*#__PURE__*/ _jsxs(_Fragment, {
87
+ children: [
88
+ /*#__PURE__*/ _jsx(Typography, {
89
+ variant: "caption",
90
+ children: ' → '
91
+ }),
92
+ /*#__PURE__*/ _jsxs(Typography, {
93
+ variant: "caption",
94
+ children: [
95
+ end.formattedDate,
96
+ " - ",
97
+ /*#__PURE__*/ _jsx("strong", {
98
+ children: end.formattedTime
99
+ })
100
+ ]
101
+ })
102
+ ]
103
+ })
104
+ ]
105
+ }),
106
+ enablePinning && /*#__PURE__*/ _jsxs(Stack, {
107
+ direction: "row",
108
+ alignItems: "center",
109
+ sx: {
110
+ marginLeft: 1,
111
+ flexShrink: 0
112
+ },
113
+ children: [
114
+ /*#__PURE__*/ _jsx(Typography, {
115
+ sx: {
116
+ marginRight: 0.5,
117
+ fontSize: 11,
118
+ verticalAlign: 'middle'
119
+ },
120
+ children: isPinned ? UNPIN_TOOLTIP_HELP_TEXT : PIN_TOOLTIP_HELP_TEXT
121
+ }),
122
+ isPinned ? /*#__PURE__*/ _jsx(Pin, {
123
+ onClick: ()=>{
124
+ if (onUnpinClick !== undefined) onUnpinClick();
125
+ },
126
+ sx: {
127
+ fontSize: 16,
128
+ cursor: 'pointer'
129
+ }
130
+ }) : /*#__PURE__*/ _jsx(PinOutline, {
131
+ sx: {
132
+ fontSize: 16
133
+ }
134
+ })
135
+ ]
136
+ })
137
+ ]
138
+ }),
139
+ /*#__PURE__*/ _jsx(Divider, {
140
+ sx: (theme)=>({
141
+ width: '100%',
142
+ borderColor: theme.palette.grey['500']
143
+ })
144
+ })
145
+ ]
146
+ }),
147
+ /*#__PURE__*/ _jsxs(Box, {
148
+ sx: (theme)=>({
149
+ padding: theme.spacing(0.5, 2, 1.5, 2)
150
+ }),
151
+ children: [
152
+ annotation.title && /*#__PURE__*/ _jsx(Typography, {
153
+ variant: "caption",
154
+ sx: {
155
+ display: 'block',
156
+ fontWeight: 'bold',
157
+ marginBottom: 0.5
158
+ },
159
+ children: annotation.title
160
+ }),
161
+ annotation.legend && /*#__PURE__*/ _jsx(Typography, {
162
+ variant: "caption",
163
+ sx: {
164
+ display: 'block',
165
+ marginBottom: 0.5
166
+ },
167
+ children: annotation.legend
168
+ }),
169
+ annotation.tags && Object.keys(annotation.tags).length > 0 && /*#__PURE__*/ _jsx(Box, {
170
+ sx: {
171
+ display: 'flex',
172
+ flexWrap: 'wrap',
173
+ gap: 0.5,
174
+ marginTop: 0.5
175
+ },
176
+ children: Object.entries(annotation.tags).map(([key, value])=>/*#__PURE__*/ _jsxs(Box, {
177
+ sx: (theme)=>({
178
+ backgroundColor: theme.palette.grey['700'],
179
+ borderRadius: '4px',
180
+ padding: '2px 6px',
181
+ fontSize: '0.7rem',
182
+ fontFamily: 'monospace'
183
+ }),
184
+ children: [
185
+ key,
186
+ ": ",
187
+ value
188
+ ]
189
+ }, key))
190
+ })
191
+ ]
192
+ })
193
+ ]
194
+ })
195
+ })
196
+ });
197
+ }
198
+ /**
199
+ * Build ECharts series options for rendering annotations as markArea (range),
200
+ * markLine (vertical dashed lines) and markPoint (triangle markers under the X-axis).
201
+ */ export function buildAnnotationSeries(annotations) {
202
+ if (!annotations?.length) return [];
203
+ const markAreaData = [];
204
+ const markLineData = [];
205
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
206
+ const markPointData = [];
207
+ annotations.forEach((annotation, index)=>{
208
+ const color = annotation.color ?? DEFAULT_ANNOTATION_COLOR;
209
+ const opacity = 0.3;
210
+ if (annotation.end !== undefined) {
211
+ // Range annotation - use markArea and markLine (silent) + markers at start/end
212
+ markLineData.push({
213
+ xAxis: annotation.start,
214
+ lineStyle: {
215
+ color,
216
+ width: 2,
217
+ type: 'dashed'
218
+ },
219
+ label: {
220
+ show: false
221
+ },
222
+ annotationIndex: index
223
+ });
224
+ markLineData.push({
225
+ xAxis: annotation.end,
226
+ lineStyle: {
227
+ color,
228
+ width: 2,
229
+ type: 'dashed'
230
+ },
231
+ label: {
232
+ show: false
233
+ },
234
+ annotationIndex: index
235
+ });
236
+ markAreaData.push([
237
+ {
238
+ xAxis: annotation.start,
239
+ itemStyle: {
240
+ color,
241
+ opacity
242
+ }
243
+ },
244
+ {
245
+ xAxis: annotation.end
246
+ }
247
+ ]);
248
+ // Add start and end markers
249
+ for (const isStart of [
250
+ true,
251
+ false
252
+ ]){
253
+ markPointData.push({
254
+ coord: [
255
+ isStart ? annotation.start : annotation.end,
256
+ 0
257
+ ],
258
+ symbol: 'triangle',
259
+ symbolSize: [
260
+ 12,
261
+ 12
262
+ ],
263
+ symbolRotate: 0,
264
+ symbolOffset: [
265
+ 0,
266
+ 4
267
+ ],
268
+ itemStyle: {
269
+ color
270
+ },
271
+ annotationIndex: index,
272
+ emphasis: {
273
+ disabled: true
274
+ },
275
+ isStart: isStart,
276
+ isEnd: !isStart
277
+ });
278
+ }
279
+ } else {
280
+ // Point annotation - use markLine (silent) + single marker
281
+ markLineData.push({
282
+ xAxis: annotation.start,
283
+ lineStyle: {
284
+ color,
285
+ width: 2,
286
+ type: 'dashed'
287
+ },
288
+ label: {
289
+ show: false
290
+ },
291
+ annotationIndex: index
292
+ });
293
+ // Add point marker
294
+ markPointData.push({
295
+ coord: [
296
+ annotation.start,
297
+ 0
298
+ ],
299
+ symbol: 'triangle',
300
+ symbolSize: [
301
+ 12,
302
+ 10
303
+ ],
304
+ symbolRotate: 0,
305
+ symbolOffset: [
306
+ 0,
307
+ '120%'
308
+ ],
309
+ itemStyle: {
310
+ color
311
+ },
312
+ annotationIndex: index,
313
+ isPoint: true
314
+ });
315
+ }
316
+ });
317
+ const series = {
318
+ type: 'line',
319
+ data: [],
320
+ silent: false,
321
+ markArea: markAreaData.length > 0 ? {
322
+ silent: true,
323
+ data: markAreaData,
324
+ label: {
325
+ show: false
326
+ }
327
+ } : undefined,
328
+ markLine: markLineData.length > 0 ? {
329
+ silent: true,
330
+ symbol: [
331
+ 'none',
332
+ 'none'
333
+ ],
334
+ data: markLineData,
335
+ lineStyle: {
336
+ type: 'dashed'
337
+ }
338
+ } : undefined,
339
+ markPoint: markPointData.length > 0 ? {
340
+ silent: false,
341
+ data: markPointData,
342
+ label: {
343
+ show: false
344
+ }
345
+ } : undefined
346
+ };
347
+ return [
348
+ series
349
+ ];
350
+ }
351
+
352
+ //# sourceMappingURL=AnnotationTooltip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/annotations/AnnotationTooltip.tsx"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { Box, Divider, Portal, Stack, Typography } from '@mui/material';\nimport Pin from 'mdi-material-ui/Pin';\nimport PinOutline from 'mdi-material-ui/PinOutline';\nimport useResizeObserver from 'use-resize-observer';\nimport type { LineSeriesOption } from 'echarts';\nimport {\n assembleTransform,\n CursorCoordinates,\n getDateAndTime,\n getTooltipStyles,\n PIN_TOOLTIP_HELP_TEXT,\n TOOLTIP_BG_COLOR_FALLBACK,\n TOOLTIP_MAX_WIDTH,\n UNPIN_TOOLTIP_HELP_TEXT,\n useMousePosition,\n} from '@perses-dev/components';\nimport { DEFAULT_ANNOTATION_COLOR } from '@perses-dev/plugin-system';\nimport { TimeSeriesAnnotation } from '../utils/annotation';\n\nexport interface AnnotationTooltipProps {\n annotation: TimeSeriesAnnotation;\n containerId?: string;\n formatWithUserTimeZone: (date: Date, formatString: string) => string;\n pinnedPos: CursorCoordinates | null;\n enablePinning?: boolean;\n onUnpinClick?: () => void;\n}\n\nexport function AnnotationTooltip({\n annotation,\n containerId,\n formatWithUserTimeZone,\n pinnedPos,\n enablePinning = true,\n onUnpinClick,\n}: AnnotationTooltipProps): JSX.Element | null {\n const mousePos = useMousePosition();\n const { height, width, ref: tooltipRef } = useResizeObserver<HTMLDivElement>();\n\n const isPinned = pinnedPos !== null;\n if (!isPinned && mousePos === null) return null;\n\n const containerElement = containerId ? document.querySelector(containerId) : undefined;\n const maxHeight = containerElement ? containerElement.getBoundingClientRect().height : undefined;\n const transform = assembleTransform(mousePos, pinnedPos, height ?? 0, width ?? 0, containerElement);\n\n const start = getDateAndTime(annotation.start, formatWithUserTimeZone);\n const end = annotation.end !== undefined ? getDateAndTime(annotation.end, formatWithUserTimeZone) : null;\n\n return (\n <Portal container={containerElement}>\n <Box ref={tooltipRef} sx={(theme) => getTooltipStyles(theme, pinnedPos, maxHeight)} style={{ transform }}>\n <Stack spacing={0.5}>\n <Box\n sx={(theme) => ({\n width: '100%',\n maxWidth: TOOLTIP_MAX_WIDTH,\n padding: theme.spacing(1.5, 2, 0.5, 2),\n backgroundColor: theme.palette.designSystem?.grey[800] ?? TOOLTIP_BG_COLOR_FALLBACK,\n position: 'sticky',\n top: 0,\n left: 0,\n })}\n >\n <Box sx={{ display: 'flex', alignItems: 'center', paddingBottom: 0.5, width: '100%' }}>\n <Box\n sx={{\n width: 8,\n height: 8,\n borderRadius: '50%',\n backgroundColor: annotation.color ?? DEFAULT_ANNOTATION_COLOR,\n marginRight: 1,\n flexShrink: 0,\n }}\n />\n <Box sx={{ flexGrow: 1, minWidth: 0 }}>\n <Typography variant=\"caption\">\n {start.formattedDate} - <strong>{start.formattedTime}</strong>\n </Typography>\n {end && (\n <>\n <Typography variant=\"caption\">{' → '}</Typography>\n <Typography variant=\"caption\">\n {end.formattedDate} - <strong>{end.formattedTime}</strong>\n </Typography>\n </>\n )}\n </Box>\n {enablePinning && (\n <Stack direction=\"row\" alignItems=\"center\" sx={{ marginLeft: 1, flexShrink: 0 }}>\n <Typography sx={{ marginRight: 0.5, fontSize: 11, verticalAlign: 'middle' }}>\n {isPinned ? UNPIN_TOOLTIP_HELP_TEXT : PIN_TOOLTIP_HELP_TEXT}\n </Typography>\n {isPinned ? (\n <Pin\n onClick={() => {\n if (onUnpinClick !== undefined) onUnpinClick();\n }}\n sx={{ fontSize: 16, cursor: 'pointer' }}\n />\n ) : (\n <PinOutline sx={{ fontSize: 16 }} />\n )}\n </Stack>\n )}\n </Box>\n <Divider sx={(theme) => ({ width: '100%', borderColor: theme.palette.grey['500'] })} />\n </Box>\n <Box sx={(theme) => ({ padding: theme.spacing(0.5, 2, 1.5, 2) })}>\n {annotation.title && (\n <Typography variant=\"caption\" sx={{ display: 'block', fontWeight: 'bold', marginBottom: 0.5 }}>\n {annotation.title}\n </Typography>\n )}\n {annotation.legend && (\n <Typography variant=\"caption\" sx={{ display: 'block', marginBottom: 0.5 }}>\n {annotation.legend}\n </Typography>\n )}\n {annotation.tags && Object.keys(annotation.tags).length > 0 && (\n <Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 0.5, marginTop: 0.5 }}>\n {Object.entries(annotation.tags).map(([key, value]) => (\n <Box\n key={key}\n sx={(theme) => ({\n backgroundColor: theme.palette.grey['700'],\n borderRadius: '4px',\n padding: '2px 6px',\n fontSize: '0.7rem',\n fontFamily: 'monospace',\n })}\n >\n {key}: {value}\n </Box>\n ))}\n </Box>\n )}\n </Box>\n </Stack>\n </Box>\n </Portal>\n );\n}\n\n/**\n * Build ECharts series options for rendering annotations as markArea (range),\n * markLine (vertical dashed lines) and markPoint (triangle markers under the X-axis).\n */\nexport function buildAnnotationSeries(annotations: TimeSeriesAnnotation[] | undefined): LineSeriesOption[] {\n if (!annotations?.length) return [];\n\n const markAreaData: Array<[{ xAxis: number; itemStyle?: { color: string; opacity: number } }, { xAxis: number }]> =\n [];\n const markLineData: Array<{\n xAxis: number;\n lineStyle?: { color: string; width: number; type: 'dashed' | 'solid' | 'dotted' };\n label?: { show: boolean };\n annotationIndex?: number;\n }> = [];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const markPointData: any[] = [];\n\n annotations.forEach((annotation, index) => {\n const color = annotation.color ?? DEFAULT_ANNOTATION_COLOR;\n const opacity = 0.3;\n\n if (annotation.end !== undefined) {\n // Range annotation - use markArea and markLine (silent) + markers at start/end\n markLineData.push({\n xAxis: annotation.start,\n lineStyle: { color, width: 2, type: 'dashed' as const },\n label: { show: false },\n annotationIndex: index,\n });\n\n markLineData.push({\n xAxis: annotation.end,\n lineStyle: { color, width: 2, type: 'dashed' as const },\n label: { show: false },\n annotationIndex: index,\n });\n\n markAreaData.push([\n {\n xAxis: annotation.start,\n itemStyle: { color, opacity },\n },\n { xAxis: annotation.end },\n ]);\n\n // Add start and end markers\n for (const isStart of [true, false]) {\n markPointData.push({\n coord: [isStart ? annotation.start : annotation.end, 0],\n symbol: 'triangle',\n symbolSize: [12, 12],\n symbolRotate: 0,\n symbolOffset: [0, 4], // Position below X-axis\n itemStyle: { color },\n annotationIndex: index,\n emphasis: {\n disabled: true,\n },\n isStart: isStart,\n isEnd: !isStart,\n });\n }\n } else {\n // Point annotation - use markLine (silent) + single marker\n markLineData.push({\n xAxis: annotation.start,\n lineStyle: { color, width: 2, type: 'dashed' as const },\n label: { show: false },\n annotationIndex: index,\n });\n\n // Add point marker\n markPointData.push({\n coord: [annotation.start, 0],\n symbol: 'triangle',\n symbolSize: [12, 10],\n symbolRotate: 0,\n symbolOffset: [0, '120%'], // Position below X-axis\n itemStyle: { color },\n annotationIndex: index,\n isPoint: true,\n });\n }\n });\n\n const series: LineSeriesOption = {\n type: 'line',\n data: [],\n silent: false,\n markArea:\n markAreaData.length > 0\n ? {\n silent: true, // Make area silent, only markers are interactive\n data: markAreaData,\n label: {\n show: false,\n },\n }\n : undefined,\n markLine:\n markLineData.length > 0\n ? {\n silent: true, // Non-interactive: hovering the dashed line keeps the TimeSeries tooltip\n symbol: ['none', 'none'],\n data: markLineData,\n lineStyle: {\n type: 'dashed',\n },\n }\n : undefined,\n markPoint:\n markPointData.length > 0\n ? {\n silent: false, // Markers are interactive\n data: markPointData,\n label: {\n show: false,\n },\n }\n : undefined,\n };\n\n return [series];\n}\n"],"names":["Box","Divider","Portal","Stack","Typography","Pin","PinOutline","useResizeObserver","assembleTransform","getDateAndTime","getTooltipStyles","PIN_TOOLTIP_HELP_TEXT","TOOLTIP_BG_COLOR_FALLBACK","TOOLTIP_MAX_WIDTH","UNPIN_TOOLTIP_HELP_TEXT","useMousePosition","DEFAULT_ANNOTATION_COLOR","AnnotationTooltip","annotation","containerId","formatWithUserTimeZone","pinnedPos","enablePinning","onUnpinClick","mousePos","height","width","ref","tooltipRef","isPinned","containerElement","document","querySelector","undefined","maxHeight","getBoundingClientRect","transform","start","end","container","sx","theme","style","spacing","maxWidth","padding","backgroundColor","palette","designSystem","grey","position","top","left","display","alignItems","paddingBottom","borderRadius","color","marginRight","flexShrink","flexGrow","minWidth","variant","formattedDate","strong","formattedTime","direction","marginLeft","fontSize","verticalAlign","onClick","cursor","borderColor","title","fontWeight","marginBottom","legend","tags","Object","keys","length","flexWrap","gap","marginTop","entries","map","key","value","fontFamily","buildAnnotationSeries","annotations","markAreaData","markLineData","markPointData","forEach","index","opacity","push","xAxis","lineStyle","type","label","show","annotationIndex","itemStyle","isStart","coord","symbol","symbolSize","symbolRotate","symbolOffset","emphasis","disabled","isEnd","isPoint","series","data","silent","markArea","markLine","markPoint"],"mappings":"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"}
@@ -230,7 +230,11 @@ function QuerySettingsEditor(props) {
230
230
  qs.format = format;
231
231
  });
232
232
  };
233
- const queryCount = (0, _pluginsystem.useQueryCountContext)();
233
+ const { queryDefinitions } = (0, _pluginsystem.useDataQueriesContext)();
234
+ const queryCount = queryDefinitions.length;
235
+ const queryNames = (0, _react.useMemo)(()=>(0, _pluginsystem.generateQueryNames)(queryDefinitions), [
236
+ queryDefinitions
237
+ ]);
234
238
  // Compute the list of query indexes for which query settings are not already defined.
235
239
  // This is to avoid already-booked indexes to still be selectable in the dropdown(s)
236
240
  const availableQueryIndexes = (0, _react.useMemo)(()=>{
@@ -269,10 +273,11 @@ function QuerySettingsEditor(props) {
269
273
  mb: 2,
270
274
  fontStyle: "italic",
271
275
  children: "No query defined"
272
- }) : querySettingsList?.length && querySettingsList.map((querySettings, i)=>/*#__PURE__*/ (0, _jsxruntime.jsx)(QuerySettingsInput, {
276
+ }) : querySettingsList?.map((querySettings, i)=>/*#__PURE__*/ (0, _jsxruntime.jsx)(QuerySettingsInput, {
273
277
  inputRef: i === querySettingsList.length - 1 ? recentlyAddedInputRef : undefined,
274
278
  querySettings: querySettings,
275
279
  availableQueryIndexes: availableQueryIndexes,
280
+ queryNames: queryNames,
276
281
  onQueryIndexChange: (e)=>{
277
282
  handleQueryIndexChange(e, i);
278
283
  },
@@ -305,7 +310,7 @@ function QuerySettingsEditor(props) {
305
310
  ]
306
311
  });
307
312
  }
308
- function QuerySettingsInput({ querySettings: { queryIndex, colorMode, colorValue, lineStyle, areaOpacity, format }, availableQueryIndexes, onQueryIndexChange, onColorModeChange, onColorValueChange, onLineStyleChange, onAreaOpacityChange, onDelete, inputRef, onAddColor: onAddColor, onRemoveColor: onRemoveColor, onAddLineStyle, onRemoveLineStyle, onAddAreaOpacity, onRemoveAreaOpacity, onAddFormat, onRemoveFormat, onFormatChange }) {
313
+ function QuerySettingsInput({ querySettings: { queryIndex, colorMode, colorValue, lineStyle, areaOpacity, format }, availableQueryIndexes, queryNames, onQueryIndexChange, onColorModeChange, onColorValueChange, onLineStyleChange, onAreaOpacityChange, onDelete, inputRef, onAddColor: onAddColor, onRemoveColor: onRemoveColor, onAddLineStyle, onRemoveLineStyle, onAddAreaOpacity, onRemoveAreaOpacity, onAddFormat, onRemoveFormat, onFormatChange }) {
309
314
  // current query index should also be selectable
310
315
  const selectableQueryIndexes = availableQueryIndexes.concat(queryIndex).sort((a, b)=>a - b);
311
316
  // State for dropdown menu
@@ -389,12 +394,9 @@ function QuerySettingsInput({ querySettings: { queryIndex, colorMode, colorValue
389
394
  sx: {
390
395
  minWidth: '75px'
391
396
  },
392
- children: selectableQueryIndexes.map((qi)=>/*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.MenuItem, {
397
+ children: selectableQueryIndexes.map((qi)=>/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.MenuItem, {
393
398
  value: qi,
394
- children: [
395
- "#",
396
- qi + 1
397
- ]
399
+ children: queryNames[qi] ?? `#${qi + 1}`
398
400
  }, `query-${qi}`))
399
401
  }),
400
402
  colorMode && /*#__PURE__*/ (0, _jsxruntime.jsxs)(SettingsSection, {
@@ -421,7 +423,7 @@ function QuerySettingsInput({ querySettings: { queryIndex, colorMode, colorValue
421
423
  ]
422
424
  }),
423
425
  /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.OptionsColorPicker, {
424
- label: `Query n°${queryIndex + 1}`,
426
+ label: queryNames[queryIndex] ?? `Query n°${queryIndex + 1}`,
425
427
  color: colorValue || DEFAULT_COLOR_VALUE,
426
428
  onColorChange: onColorValueChange
427
429
  })
@@ -531,7 +533,7 @@ function QuerySettingsInput({ querySettings: { queryIndex, colorMode, colorValue
531
533
  justifyContent: 'center'
532
534
  },
533
535
  children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.IconButton, {
534
- "aria-label": `delete settings for query n°${queryIndex + 1}`,
536
+ "aria-label": `delete settings for ${queryNames[queryIndex] ?? `query n°${queryIndex + 1}`}`,
535
537
  onClick: onDelete,
536
538
  children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_DeleteOutline.default, {})
537
539
  })
@@ -31,6 +31,7 @@ const _components = require("echarts/components");
31
31
  const _renderers = require("echarts/renderers");
32
32
  const _components1 = require("@perses-dev/components");
33
33
  const _timezoneformatter = require("./utils/timezone-formatter");
34
+ const _AnnotationTooltip = require("./annotations/AnnotationTooltip");
34
35
  function _interop_require_default(obj) {
35
36
  return obj && obj.__esModule ? obj : {
36
37
  default: obj
@@ -50,7 +51,7 @@ function _interop_require_default(obj) {
50
51
  _components.TooltipComponent,
51
52
  _renderers.CanvasRenderer
52
53
  ]);
53
- const TimeSeriesChartBase = /*#__PURE__*/ (0, _react.forwardRef)(function TimeChart({ height, data, seriesMapping, timeScale: timeScaleProp, yAxis, format, seriesFormatMap, grid, isStackedBar = false, tooltipConfig = _components1.DEFAULT_TOOLTIP_CONFIG, noDataVariant = 'message', syncGroup, onDataZoom, onDoubleClick, __experimentalEChartsOptionsOverride }, ref) {
54
+ const TimeSeriesChartBase = /*#__PURE__*/ (0, _react.forwardRef)(function TimeChart({ height, data, seriesMapping, annotations, timeScale: timeScaleProp, yAxis, format, seriesFormatMap, grid, isStackedBar = false, tooltipConfig = _components1.DEFAULT_TOOLTIP_CONFIG, noDataVariant = 'message', syncGroup, onDataZoom, onDoubleClick, __experimentalEChartsOptionsOverride }, ref) {
54
55
  const { chartsTheme, enablePinning, enableSyncGrouping, lastTooltipPinnedCoords, setLastTooltipPinnedCoords } = (0, _components1.useChartsContext)();
55
56
  const isPinningEnabled = tooltipConfig.enablePinning && enablePinning;
56
57
  const chartRef = (0, _react.useRef)();
@@ -59,7 +60,10 @@ const TimeSeriesChartBase = /*#__PURE__*/ (0, _react.forwardRef)(function TimeCh
59
60
  const [pinnedCrosshair, setPinnedCrosshair] = (0, _react.useState)(null);
60
61
  const [isDragging, setIsDragging] = (0, _react.useState)(false);
61
62
  const [startX, setStartX] = (0, _react.useState)(0);
62
- const { timeZone } = (0, _components1.useTimeZone)();
63
+ const [hoveredAnnotation, setHoveredAnnotation] = (0, _react.useState)(null);
64
+ const [pinnedAnnotation, setPinnedAnnotation] = (0, _react.useState)(null);
65
+ const [pinnedAnnotationPos, setPinnedAnnotationPos] = (0, _react.useState)(null);
66
+ const { timeZone, formatWithUserTimeZone } = (0, _components1.useTimeZone)();
63
67
  const getTimezoneAwareAxisFormatter = (0, _react.useCallback)((rangeMs)=>(0, _timezoneformatter.createTimezoneAwareAxisFormatter)(rangeMs, timeZone), [
64
68
  timeZone
65
69
  ]);
@@ -130,11 +134,44 @@ const TimeSeriesChartBase = /*#__PURE__*/ (0, _react.forwardRef)(function TimeCh
130
134
  if (chartRef.current !== undefined) {
131
135
  (0, _components1.enableDataZoom)(chartRef.current);
132
136
  }
137
+ },
138
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
139
+ mouseover: (params)=>{
140
+ // Only markPoint (triangles under the X-axis) opens the annotation tooltip.
141
+ // Hovering markLine or anything else keeps the regular TimeSeries tooltip visible
142
+ // and clears any stale hovered annotation (mouseout is sometimes missed by ECharts).
143
+ if (annotations && params.componentType === 'markPoint' && params.data?.annotationIndex !== undefined) {
144
+ const matchedAnnotation = annotations[params.data.annotationIndex] || null;
145
+ if (matchedAnnotation) {
146
+ setHoveredAnnotation(matchedAnnotation);
147
+ return;
148
+ }
149
+ }
150
+ setHoveredAnnotation(null);
151
+ },
152
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
153
+ mouseout: (params)=>{
154
+ if (annotations && params.componentType === 'markPoint' && params.data?.annotationIndex !== undefined && annotations) {
155
+ // Only clear if the mouseout corresponds to the currently hovered annotation, so that
156
+ // a quick move from one markPoint to another isn't cancelled by a late mouseout event.
157
+ const leaving = annotations[params.data.annotationIndex] || null;
158
+ setHoveredAnnotation((current)=>current === leaving ? null : current);
159
+ }
160
+ },
161
+ globalout: ()=>{
162
+ if (annotations) {
163
+ // Cursor left the chart canvas — guarantee the annotation tooltip is dismissed.
164
+ setHoveredAnnotation(null);
165
+ }
133
166
  }
134
167
  };
135
168
  }, [
136
- onDataZoom,
137
- setTooltipPinnedCoords
169
+ annotations,
170
+ onDataZoom
171
+ ]);
172
+ // Generate annotation series for ECharts markArea (range), markLine (point), and markPoint (markers under X-axis)
173
+ const annotationSeries = (0, _react.useMemo)(()=>(0, _AnnotationTooltip.buildAnnotationSeries)(annotations), [
174
+ annotations
138
175
  ]);
139
176
  const { noDataOption } = chartsTheme;
140
177
  const option = (0, _react.useMemo)(()=>{
@@ -165,8 +202,12 @@ const TimeSeriesChartBase = /*#__PURE__*/ (0, _react.forwardRef)(function TimeCh
165
202
  });
166
203
  const updatedSeriesMapping = enablePinning && pinnedCrosshair !== null ? [
167
204
  ...seriesMapping,
168
- pinnedCrosshair
169
- ] : seriesMapping;
205
+ pinnedCrosshair,
206
+ ...annotationSeries
207
+ ] : [
208
+ ...seriesMapping,
209
+ ...annotationSeries
210
+ ];
170
211
  const option = {
171
212
  dataset: dataset,
172
213
  series: updatedSeriesMapping,
@@ -218,6 +259,7 @@ const TimeSeriesChartBase = /*#__PURE__*/ (0, _react.forwardRef)(function TimeCh
218
259
  }, [
219
260
  data,
220
261
  seriesMapping,
262
+ annotationSeries,
221
263
  timeScale,
222
264
  yAxis,
223
265
  format,
@@ -258,6 +300,34 @@ const TimeSeriesChartBase = /*#__PURE__*/ (0, _react.forwardRef)(function TimeCh
258
300
  // e.preventDefault(); // Prevent the default behaviour when right clicked
259
301
  // }}
260
302
  onClick: (e)=>{
303
+ // If clicking while hovering an annotation, toggle the annotation tooltip pin
304
+ // instead of pinning the TimeChartTooltip, so pinned TimeChartTooltip is preserved.
305
+ if (hoveredAnnotation !== null && e.target instanceof HTMLCanvasElement) {
306
+ const pinnedPos = {
307
+ page: {
308
+ x: e.pageX,
309
+ y: e.pageY
310
+ },
311
+ client: {
312
+ x: e.clientX,
313
+ y: e.clientY
314
+ },
315
+ plotCanvas: {
316
+ x: e.nativeEvent.offsetX,
317
+ y: e.nativeEvent.offsetY
318
+ },
319
+ target: e.target
320
+ };
321
+ setPinnedAnnotation((current)=>{
322
+ if (current === hoveredAnnotation) {
323
+ setPinnedAnnotationPos(null);
324
+ return null;
325
+ }
326
+ setPinnedAnnotationPos(pinnedPos);
327
+ return hoveredAnnotation;
328
+ });
329
+ return;
330
+ }
261
331
  // Allows user to opt-in to multi tooltip pinning when Ctrl or Cmd key held down
262
332
  const isControlKeyPressed = e.ctrlKey || e.metaKey;
263
333
  if (isControlKeyPressed) {
@@ -350,6 +420,8 @@ const TimeSeriesChartBase = /*#__PURE__*/ (0, _react.forwardRef)(function TimeCh
350
420
  if (tooltipPinnedCoords === null) {
351
421
  setShowTooltip(false);
352
422
  }
423
+ // Defensive: clear hovered annotation in case ECharts missed a mouseout event.
424
+ setHoveredAnnotation(null);
353
425
  if (chartRef.current !== undefined) {
354
426
  (0, _components1.clearHighlightedSeries)(chartRef.current);
355
427
  }
@@ -372,7 +444,7 @@ const TimeSeriesChartBase = /*#__PURE__*/ (0, _react.forwardRef)(function TimeCh
372
444
  }
373
445
  },
374
446
  children: [
375
- showTooltip === true && option.tooltip?.showContent === false && tooltipConfig.hidden !== true && /*#__PURE__*/ (0, _jsxruntime.jsx)(_components1.TimeChartTooltip, {
447
+ showTooltip === true && (tooltipPinnedCoords !== null || hoveredAnnotation === null) && option.tooltip?.showContent === false && tooltipConfig.hidden !== true && /*#__PURE__*/ (0, _jsxruntime.jsx)(_components1.TimeChartTooltip, {
376
448
  containerId: chartsTheme.tooltipPortalContainerId,
377
449
  chartRef: chartRef,
378
450
  data: data,
@@ -389,6 +461,17 @@ const TimeSeriesChartBase = /*#__PURE__*/ (0, _react.forwardRef)(function TimeCh
389
461
  setPinnedCrosshair(null);
390
462
  }
391
463
  }),
464
+ (pinnedAnnotation ?? hoveredAnnotation) && /*#__PURE__*/ (0, _jsxruntime.jsx)(_AnnotationTooltip.AnnotationTooltip, {
465
+ annotation: pinnedAnnotation ?? hoveredAnnotation,
466
+ containerId: chartsTheme.tooltipPortalContainerId,
467
+ formatWithUserTimeZone: formatWithUserTimeZone,
468
+ pinnedPos: pinnedAnnotation !== null ? pinnedAnnotationPos : null,
469
+ enablePinning: isPinningEnabled,
470
+ onUnpinClick: ()=>{
471
+ setPinnedAnnotation(null);
472
+ setPinnedAnnotationPos(null);
473
+ }
474
+ }),
392
475
  /*#__PURE__*/ (0, _jsxruntime.jsx)(_components1.EChart, {
393
476
  sx: {
394
477
  width: '100%',
@@ -26,10 +26,12 @@ const _material = require("@mui/material");
26
26
  const _merge = /*#__PURE__*/ _interop_require_default(require("lodash/merge"));
27
27
  const _pluginsystem = require("@perses-dev/plugin-system");
28
28
  const _components = require("@perses-dev/components");
29
+ const _dashboards = require("@perses-dev/dashboards");
29
30
  const _timeserieschartmodel = require("./time-series-chart-model");
30
31
  const _datatransform = require("./utils/data-transform");
31
32
  const _palettegen = require("./utils/palette-gen");
32
33
  const _TimeSeriesChartBase = require("./TimeSeriesChartBase");
34
+ const _annotation = require("./utils/annotation");
33
35
  function _interop_require_default(obj) {
34
36
  return obj && obj.__esModule ? obj : {
35
37
  default: obj
@@ -107,6 +109,10 @@ function TimeSeriesChartPanel(props) {
107
109
  const [selectedLegendItems, setSelectedLegendItems] = (0, _react.useState)('ALL');
108
110
  const [legendSorting, setLegendSorting] = (0, _react.useState)();
109
111
  const { setTimeRange } = (0, _pluginsystem.useTimeRange)();
112
+ const annotationsWithData = (0, _dashboards.useAnnotationsWithData)();
113
+ const annotations = (0, _react.useMemo)(()=>(0, _annotation.convertAnnotationToTimeSeriesAnnotation)(annotationsWithData), [
114
+ annotationsWithData
115
+ ]);
110
116
  // Populate series data based on query results
111
117
  const { timeScale, timeChartData, timeSeriesMapping, legendItems, seriesFormatMap: computedSeriesFormatMap, maxValuesByFormat } = (0, _react.useMemo)(()=>{
112
118
  const timeScale = (0, _datatransform.getCommonTimeScaleForQueries)(queryResults);
@@ -414,6 +420,7 @@ function TimeSeriesChartPanel(props) {
414
420
  height: height,
415
421
  data: timeChartData,
416
422
  seriesMapping: timeSeriesMapping,
423
+ annotations: annotations,
417
424
  timeScale: timeScale,
418
425
  yAxis: multipleYAxes ?? echartsYAxis,
419
426
  format: format,