@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.
- package/__mf/js/TimeSeriesChart.693fccf6.js +7 -0
- package/__mf/js/async/121.c3c0e54f.js +2 -0
- package/__mf/js/async/137.59c998ab.js +38 -0
- package/__mf/js/async/177.2fef2962.js +1 -0
- package/__mf/js/async/187.f5e8932b.js +1 -0
- package/__mf/js/async/192.c3dd56d5.js +1 -0
- package/__mf/js/async/2.60fa4a40.js +1 -0
- package/__mf/js/async/235.d23c8ef0.js +1 -0
- package/__mf/js/async/247.b8cba23e.js +7 -0
- package/__mf/js/async/274.72dfa9c8.js +2 -0
- package/__mf/js/async/356.8170c96d.js +1 -0
- package/__mf/js/async/392.b9ba5bf2.js +2 -0
- package/__mf/js/async/470.e09f33b7.js +2 -0
- package/__mf/js/async/491.85194549.js +1 -0
- package/__mf/js/async/52.0850e52c.js +1 -0
- package/__mf/js/async/527.f97d1b86.js +110 -0
- package/__mf/js/async/555.a66f6ab5.js +2 -0
- package/__mf/js/async/568.45da2c30.js +1 -0
- package/__mf/js/async/570.bafa9150.js +3 -0
- package/__mf/js/async/587.c9460696.js +1 -0
- package/__mf/js/async/588.0a1aa144.js +1 -0
- package/__mf/js/async/603.3b771310.js +2 -0
- package/__mf/js/async/603.3b771310.js.LICENSE.txt +9 -0
- package/__mf/js/async/616.79484ac8.js +1 -0
- package/__mf/js/async/655.dbf8c618.js +1 -0
- package/__mf/js/async/702.785cd635.js +2 -0
- package/__mf/js/async/71.8c6cf914.js +1 -0
- package/__mf/js/async/724.c45dcf5b.js +1 -0
- package/__mf/js/async/873.04a201bf.js +1 -0
- package/__mf/js/async/941.b89f8595.js +2 -0
- package/__mf/js/async/955.176fe200.js +1 -0
- package/__mf/js/async/968.2a9fb1a0.js +1 -0
- package/__mf/js/async/978.a9865b23.js +1 -0
- package/__mf/js/async/984.5778f693.js +22 -0
- package/__mf/js/async/{187.2cc43fac.js.LICENSE.txt → 984.5778f693.js.LICENSE.txt} +0 -10
- package/__mf/js/async/__federation_expose_TimeSeriesChart.5f574fcb.js +1 -0
- package/__mf/js/async/lib-router.319c02cd.js +2 -0
- package/__mf/js/async/{lib-router.1934857d.js.LICENSE.txt → lib-router.319c02cd.js.LICENSE.txt} +3 -3
- package/__mf/js/main.046b2715.js +7 -0
- package/lib/QuerySettingsEditor.d.ts.map +1 -1
- package/lib/QuerySettingsEditor.js +13 -11
- package/lib/QuerySettingsEditor.js.map +1 -1
- package/lib/TimeSeriesChartBase.d.ts +2 -0
- package/lib/TimeSeriesChartBase.d.ts.map +1 -1
- package/lib/TimeSeriesChartBase.js +90 -7
- package/lib/TimeSeriesChartBase.js.map +1 -1
- package/lib/TimeSeriesChartPanel.d.ts.map +1 -1
- package/lib/TimeSeriesChartPanel.js +7 -0
- package/lib/TimeSeriesChartPanel.js.map +1 -1
- package/lib/annotations/AnnotationTooltip.d.ts +18 -0
- package/lib/annotations/AnnotationTooltip.d.ts.map +1 -0
- package/lib/annotations/AnnotationTooltip.js +352 -0
- package/lib/annotations/AnnotationTooltip.js.map +1 -0
- package/lib/cjs/QuerySettingsEditor.js +12 -10
- package/lib/cjs/TimeSeriesChartBase.js +90 -7
- package/lib/cjs/TimeSeriesChartPanel.js +7 -0
- package/lib/cjs/annotations/AnnotationTooltip.js +370 -0
- package/lib/cjs/utils/annotation.js +37 -0
- package/lib/utils/annotation.d.ts +5 -0
- package/lib/utils/annotation.d.ts.map +1 -0
- package/lib/utils/annotation.js +29 -0
- package/lib/utils/annotation.js.map +1 -0
- package/mf-manifest.json +61 -36
- package/mf-stats.json +68 -36
- package/package.json +6 -4
- package/__mf/js/TimeSeriesChart.f9dd142d.js +0 -7
- package/__mf/js/async/121.df4898d6.js +0 -2
- package/__mf/js/async/177.56f1be10.js +0 -1
- package/__mf/js/async/187.2cc43fac.js +0 -24
- package/__mf/js/async/192.beef3a1a.js +0 -1
- package/__mf/js/async/2.c3740bb9.js +0 -1
- package/__mf/js/async/235.c24f24f7.js +0 -1
- package/__mf/js/async/274.d112354f.js +0 -2
- package/__mf/js/async/356.9f551c8a.js +0 -1
- package/__mf/js/async/392.2350fb02.js +0 -2
- package/__mf/js/async/470.a4fd777e.js +0 -2
- package/__mf/js/async/491.6f81cf51.js +0 -1
- package/__mf/js/async/568.cdcaf97d.js +0 -1
- package/__mf/js/async/587.c12780da.js +0 -1
- package/__mf/js/async/588.6662e16a.js +0 -1
- package/__mf/js/async/616.52acb1b4.js +0 -1
- package/__mf/js/async/681.8d61b348.js +0 -110
- package/__mf/js/async/702.de247ad8.js +0 -2
- package/__mf/js/async/71.84e486c9.js +0 -1
- package/__mf/js/async/724.3439df06.js +0 -1
- package/__mf/js/async/78.91de282a.js +0 -1
- package/__mf/js/async/780.12a33d06.js +0 -39
- package/__mf/js/async/873.9aad328a.js +0 -1
- package/__mf/js/async/907.5ce8f69d.js +0 -7
- package/__mf/js/async/941.c0e2d25e.js +0 -2
- package/__mf/js/async/968.6de5fa7c.js +0 -1
- package/__mf/js/async/978.5c14e175.js +0 -1
- package/__mf/js/async/__federation_expose_TimeSeriesChart.d1167045.js +0 -1
- package/__mf/js/async/lib-router.1934857d.js +0 -2
- package/__mf/js/main.2bb9f3e3.js +0 -7
- /package/__mf/css/async/{907.85c2cbf6.css → 247.85c2cbf6.css} +0 -0
- /package/__mf/js/async/{121.df4898d6.js.LICENSE.txt → 121.c3c0e54f.js.LICENSE.txt} +0 -0
- /package/__mf/js/async/{907.5ce8f69d.js.LICENSE.txt → 247.b8cba23e.js.LICENSE.txt} +0 -0
- /package/__mf/js/async/{274.d112354f.js.LICENSE.txt → 274.72dfa9c8.js.LICENSE.txt} +0 -0
- /package/__mf/js/async/{392.2350fb02.js.LICENSE.txt → 392.b9ba5bf2.js.LICENSE.txt} +0 -0
- /package/__mf/js/async/{470.a4fd777e.js.LICENSE.txt → 470.e09f33b7.js.LICENSE.txt} +0 -0
- /package/__mf/js/async/{681.8d61b348.js.LICENSE.txt → 527.f97d1b86.js.LICENSE.txt} +0 -0
- /package/__mf/js/async/{780.12a33d06.js.LICENSE.txt → 555.a66f6ab5.js.LICENSE.txt} +0 -0
- /package/__mf/js/async/{702.de247ad8.js.LICENSE.txt → 702.785cd635.js.LICENSE.txt} +0 -0
- /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":";AAAA,+BAA+B;AAC/B,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAEjC,SAASA,GAAG,EAAEC,OAAO,EAAEC,MAAM,EAAEC,KAAK,EAAEC,UAAU,QAAQ,gBAAgB;AACxE,OAAOC,SAAS,sBAAsB;AACtC,OAAOC,gBAAgB,6BAA6B;AACpD,OAAOC,uBAAuB,sBAAsB;AAEpD,SACEC,iBAAiB,EAEjBC,cAAc,EACdC,gBAAgB,EAChBC,qBAAqB,EACrBC,yBAAyB,EACzBC,iBAAiB,EACjBC,uBAAuB,EACvBC,gBAAgB,QACX,yBAAyB;AAChC,SAASC,wBAAwB,QAAQ,4BAA4B;AAYrE,OAAO,SAASC,kBAAkB,EAChCC,UAAU,EACVC,WAAW,EACXC,sBAAsB,EACtBC,SAAS,EACTC,gBAAgB,IAAI,EACpBC,YAAY,EACW;IACvB,MAAMC,WAAWT;IACjB,MAAM,EAAEU,MAAM,EAAEC,KAAK,EAAEC,KAAKC,UAAU,EAAE,GAAGrB;IAE3C,MAAMsB,WAAWR,cAAc;IAC/B,IAAI,CAACQ,YAAYL,aAAa,MAAM,OAAO;IAE3C,MAAMM,mBAAmBX,cAAcY,SAASC,aAAa,CAACb,eAAec;IAC7E,MAAMC,YAAYJ,mBAAmBA,iBAAiBK,qBAAqB,GAAGV,MAAM,GAAGQ;IACvF,MAAMG,YAAY5B,kBAAkBgB,UAAUH,WAAWI,UAAU,GAAGC,SAAS,GAAGI;IAElF,MAAMO,QAAQ5B,eAAeS,WAAWmB,KAAK,EAAEjB;IAC/C,MAAMkB,MAAMpB,WAAWoB,GAAG,KAAKL,YAAYxB,eAAeS,WAAWoB,GAAG,EAAElB,0BAA0B;IAEpG,qBACE,KAAClB;QAAOqC,WAAWT;kBACjB,cAAA,KAAC9B;YAAI2B,KAAKC;YAAYY,IAAI,CAACC,QAAU/B,iBAAiB+B,OAAOpB,WAAWa;YAAYQ,OAAO;gBAAEN;YAAU;sBACrG,cAAA,MAACjC;gBAAMwC,SAAS;;kCACd,MAAC3C;wBACCwC,IAAI,CAACC,QAAW,CAAA;gCACdf,OAAO;gCACPkB,UAAU/B;gCACVgC,SAASJ,MAAME,OAAO,CAAC,KAAK,GAAG,KAAK;gCACpCG,iBAAiBL,MAAMM,OAAO,CAACC,YAAY,EAAEC,IAAI,CAAC,IAAI,IAAIrC;gCAC1DsC,UAAU;gCACVC,KAAK;gCACLC,MAAM;4BACR,CAAA;;0CAEA,MAACpD;gCAAIwC,IAAI;oCAAEa,SAAS;oCAAQC,YAAY;oCAAUC,eAAe;oCAAK7B,OAAO;gCAAO;;kDAClF,KAAC1B;wCACCwC,IAAI;4CACFd,OAAO;4CACPD,QAAQ;4CACR+B,cAAc;4CACdV,iBAAiB5B,WAAWuC,KAAK,IAAIzC;4CACrC0C,aAAa;4CACbC,YAAY;wCACd;;kDAEF,MAAC3D;wCAAIwC,IAAI;4CAAEoB,UAAU;4CAAGC,UAAU;wCAAE;;0DAClC,MAACzD;gDAAW0D,SAAQ;;oDACjBzB,MAAM0B,aAAa;oDAAC;kEAAG,KAACC;kEAAQ3B,MAAM4B,aAAa;;;;4CAErD3B,qBACC;;kEACE,KAAClC;wDAAW0D,SAAQ;kEAAW;;kEAC/B,MAAC1D;wDAAW0D,SAAQ;;4DACjBxB,IAAIyB,aAAa;4DAAC;0EAAG,KAACC;0EAAQ1B,IAAI2B,aAAa;;;;;;;;oCAKvD3C,+BACC,MAACnB;wCAAM+D,WAAU;wCAAMZ,YAAW;wCAASd,IAAI;4CAAE2B,YAAY;4CAAGR,YAAY;wCAAE;;0DAC5E,KAACvD;gDAAWoC,IAAI;oDAAEkB,aAAa;oDAAKU,UAAU;oDAAIC,eAAe;gDAAS;0DACvExC,WAAWf,0BAA0BH;;4CAEvCkB,yBACC,KAACxB;gDACCiE,SAAS;oDACP,IAAI/C,iBAAiBU,WAAWV;gDAClC;gDACAiB,IAAI;oDAAE4B,UAAU;oDAAIG,QAAQ;gDAAU;+DAGxC,KAACjE;gDAAWkC,IAAI;oDAAE4B,UAAU;gDAAG;;;;;;0CAKvC,KAACnE;gCAAQuC,IAAI,CAACC,QAAW,CAAA;wCAAEf,OAAO;wCAAQ8C,aAAa/B,MAAMM,OAAO,CAACE,IAAI,CAAC,MAAM;oCAAC,CAAA;;;;kCAEnF,MAACjD;wBAAIwC,IAAI,CAACC,QAAW,CAAA;gCAAEI,SAASJ,MAAME,OAAO,CAAC,KAAK,GAAG,KAAK;4BAAG,CAAA;;4BAC3DzB,WAAWuD,KAAK,kBACf,KAACrE;gCAAW0D,SAAQ;gCAAUtB,IAAI;oCAAEa,SAAS;oCAASqB,YAAY;oCAAQC,cAAc;gCAAI;0CACzFzD,WAAWuD,KAAK;;4BAGpBvD,WAAW0D,MAAM,kBAChB,KAACxE;gCAAW0D,SAAQ;gCAAUtB,IAAI;oCAAEa,SAAS;oCAASsB,cAAc;gCAAI;0CACrEzD,WAAW0D,MAAM;;4BAGrB1D,WAAW2D,IAAI,IAAIC,OAAOC,IAAI,CAAC7D,WAAW2D,IAAI,EAAEG,MAAM,GAAG,mBACxD,KAAChF;gCAAIwC,IAAI;oCAAEa,SAAS;oCAAQ4B,UAAU;oCAAQC,KAAK;oCAAKC,WAAW;gCAAI;0CACpEL,OAAOM,OAAO,CAAClE,WAAW2D,IAAI,EAAEQ,GAAG,CAAC,CAAC,CAACC,KAAKC,MAAM,iBAChD,MAACvF;wCAECwC,IAAI,CAACC,QAAW,CAAA;gDACdK,iBAAiBL,MAAMM,OAAO,CAACE,IAAI,CAAC,MAAM;gDAC1CO,cAAc;gDACdX,SAAS;gDACTuB,UAAU;gDACVoB,YAAY;4CACd,CAAA;;4CAECF;4CAAI;4CAAGC;;uCATHD;;;;;;;;AAmBzB;AAEA;;;CAGC,GACD,OAAO,SAASG,sBAAsBC,WAA+C;IACnF,IAAI,CAACA,aAAaV,QAAQ,OAAO,EAAE;IAEnC,MAAMW,eACJ,EAAE;IACJ,MAAMC,eAKD,EAAE;IACP,8DAA8D;IAC9D,MAAMC,gBAAuB,EAAE;IAE/BH,YAAYI,OAAO,CAAC,CAAC5E,YAAY6E;QAC/B,MAAMtC,QAAQvC,WAAWuC,KAAK,IAAIzC;QAClC,MAAMgF,UAAU;QAEhB,IAAI9E,WAAWoB,GAAG,KAAKL,WAAW;YAChC,+EAA+E;YAC/E2D,aAAaK,IAAI,CAAC;gBAChBC,OAAOhF,WAAWmB,KAAK;gBACvB8D,WAAW;oBAAE1C;oBAAO/B,OAAO;oBAAG0E,MAAM;gBAAkB;gBACtDC,OAAO;oBAAEC,MAAM;gBAAM;gBACrBC,iBAAiBR;YACnB;YAEAH,aAAaK,IAAI,CAAC;gBAChBC,OAAOhF,WAAWoB,GAAG;gBACrB6D,WAAW;oBAAE1C;oBAAO/B,OAAO;oBAAG0E,MAAM;gBAAkB;gBACtDC,OAAO;oBAAEC,MAAM;gBAAM;gBACrBC,iBAAiBR;YACnB;YAEAJ,aAAaM,IAAI,CAAC;gBAChB;oBACEC,OAAOhF,WAAWmB,KAAK;oBACvBmE,WAAW;wBAAE/C;wBAAOuC;oBAAQ;gBAC9B;gBACA;oBAAEE,OAAOhF,WAAWoB,GAAG;gBAAC;aACzB;YAED,4BAA4B;YAC5B,KAAK,MAAMmE,WAAW;gBAAC;gBAAM;aAAM,CAAE;gBACnCZ,cAAcI,IAAI,CAAC;oBACjBS,OAAO;wBAACD,UAAUvF,WAAWmB,KAAK,GAAGnB,WAAWoB,GAAG;wBAAE;qBAAE;oBACvDqE,QAAQ;oBACRC,YAAY;wBAAC;wBAAI;qBAAG;oBACpBC,cAAc;oBACdC,cAAc;wBAAC;wBAAG;qBAAE;oBACpBN,WAAW;wBAAE/C;oBAAM;oBACnB8C,iBAAiBR;oBACjBgB,UAAU;wBACRC,UAAU;oBACZ;oBACAP,SAASA;oBACTQ,OAAO,CAACR;gBACV;YACF;QACF,OAAO;YACL,2DAA2D;YAC3Db,aAAaK,IAAI,CAAC;gBAChBC,OAAOhF,WAAWmB,KAAK;gBACvB8D,WAAW;oBAAE1C;oBAAO/B,OAAO;oBAAG0E,MAAM;gBAAkB;gBACtDC,OAAO;oBAAEC,MAAM;gBAAM;gBACrBC,iBAAiBR;YACnB;YAEA,mBAAmB;YACnBF,cAAcI,IAAI,CAAC;gBACjBS,OAAO;oBAACxF,WAAWmB,KAAK;oBAAE;iBAAE;gBAC5BsE,QAAQ;gBACRC,YAAY;oBAAC;oBAAI;iBAAG;gBACpBC,cAAc;gBACdC,cAAc;oBAAC;oBAAG;iBAAO;gBACzBN,WAAW;oBAAE/C;gBAAM;gBACnB8C,iBAAiBR;gBACjBmB,SAAS;YACX;QACF;IACF;IAEA,MAAMC,SAA2B;QAC/Bf,MAAM;QACNgB,MAAM,EAAE;QACRC,QAAQ;QACRC,UACE3B,aAAaX,MAAM,GAAG,IAClB;YACEqC,QAAQ;YACRD,MAAMzB;YACNU,OAAO;gBACLC,MAAM;YACR;QACF,IACArE;QACNsF,UACE3B,aAAaZ,MAAM,GAAG,IAClB;YACEqC,QAAQ;YACRV,QAAQ;gBAAC;gBAAQ;aAAO;YACxBS,MAAMxB;YACNO,WAAW;gBACTC,MAAM;YACR;QACF,IACAnE;QACNuF,WACE3B,cAAcb,MAAM,GAAG,IACnB;YACEqC,QAAQ;YACRD,MAAMvB;YACNQ,OAAO;gBACLC,MAAM;YACR;QACF,IACArE;IACR;IAEA,OAAO;QAACkF;KAAO;AACjB"}
|
|
@@ -230,7 +230,11 @@ function QuerySettingsEditor(props) {
|
|
|
230
230
|
qs.format = format;
|
|
231
231
|
});
|
|
232
232
|
};
|
|
233
|
-
const
|
|
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?.
|
|
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.
|
|
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
|
|
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
|
-
|
|
137
|
-
|
|
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
|
-
|
|
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,
|