@perses-dev/timeseries-chart-plugin 0.12.0-beta.0 → 0.12.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/__mf/js/{TimeSeriesChart.a84df9d1.js → TimeSeriesChart.e51aefbf.js} +3 -3
- package/__mf/js/async/{675.450939c3.js → 390.ad50daba.js} +7 -7
- package/__mf/js/async/392.550376f0.js +2 -0
- package/__mf/js/async/{724.5594af97.js → 489.8bb61ec9.js} +1 -1
- package/__mf/js/async/{437.aa3568c0.js → 544.4dd63985.js} +2 -2
- package/__mf/js/async/648.128f31b8.js +22 -0
- package/__mf/js/async/78.362ece9d.js +1 -0
- package/__mf/js/async/867.12a42f78.js +38 -0
- package/__mf/js/async/97.3f27a901.js +7 -0
- package/__mf/js/async/__federation_expose_TimeSeriesChart.8cacec73.js +3 -0
- package/__mf/js/async/lib-router.9730f5e9.js +2 -0
- package/__mf/js/async/{lib-router.54d80a0a.js.LICENSE.txt → lib-router.9730f5e9.js.LICENSE.txt} +3 -3
- package/__mf/js/{main.7d4d10e5.js → main.90e8ca42.js} +3 -3
- package/lib/CSVExportUtils.js +1 -1
- package/lib/CSVExportUtils.js.map +1 -1
- package/lib/GeneralSettingsEditor.js +1 -1
- package/lib/GeneralSettingsEditor.js.map +1 -1
- package/lib/QuerySettingsEditor.d.ts.map +1 -1
- package/lib/QuerySettingsEditor.js +46 -8
- package/lib/QuerySettingsEditor.js.map +1 -1
- package/lib/TimeSeriesChart.js +1 -1
- package/lib/TimeSeriesChart.js.map +1 -1
- package/lib/TimeSeriesChartBase.d.ts +5 -1
- package/lib/TimeSeriesChartBase.d.ts.map +1 -1
- package/lib/TimeSeriesChartBase.js +5 -3
- package/lib/TimeSeriesChartBase.js.map +1 -1
- package/lib/TimeSeriesChartPanel.d.ts.map +1 -1
- package/lib/TimeSeriesChartPanel.js +100 -15
- package/lib/TimeSeriesChartPanel.js.map +1 -1
- package/lib/TimeSeriesExportAction.d.ts.map +1 -1
- package/lib/TimeSeriesExportAction.js +7 -6
- package/lib/TimeSeriesExportAction.js.map +1 -1
- package/lib/VisualOptionsEditor.js +1 -1
- package/lib/VisualOptionsEditor.js.map +1 -1
- package/lib/YAxisOptionsEditor.d.ts.map +1 -1
- package/lib/YAxisOptionsEditor.js +23 -3
- package/lib/YAxisOptionsEditor.js.map +1 -1
- package/lib/bootstrap.js +1 -1
- package/lib/bootstrap.js.map +1 -1
- package/lib/cjs/CSVExportUtils.js +1 -1
- package/lib/cjs/GeneralSettingsEditor.js +1 -1
- package/lib/cjs/QuerySettingsEditor.js +45 -7
- package/lib/cjs/TimeSeriesChart.js +1 -1
- package/lib/cjs/TimeSeriesChartBase.js +5 -3
- package/lib/cjs/TimeSeriesChartPanel.js +99 -14
- package/lib/cjs/TimeSeriesExportAction.js +5 -4
- package/lib/cjs/VisualOptionsEditor.js +1 -1
- package/lib/cjs/YAxisOptionsEditor.js +21 -1
- package/lib/cjs/bootstrap.js +1 -1
- package/lib/cjs/env.d.js +1 -1
- package/lib/cjs/getPluginModule.js +12 -0
- package/lib/cjs/index-federation.js +1 -1
- package/lib/cjs/index.js +1 -1
- package/lib/cjs/setup-tests.js +1 -1
- package/lib/cjs/test/mock-query-results.js +1 -1
- package/lib/cjs/time-series-chart-model.js +30 -2
- package/lib/cjs/utils/data-transform.js +32 -13
- package/lib/cjs/utils/palette-gen.js +1 -1
- package/lib/cjs/utils/palette.js +1 -1
- package/lib/env.d.js +1 -1
- package/lib/env.d.js.map +1 -1
- package/lib/getPluginModule.d.ts.map +1 -1
- package/lib/getPluginModule.js +12 -0
- package/lib/getPluginModule.js.map +1 -1
- package/lib/index-federation.js +1 -1
- package/lib/index-federation.js.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/setup-tests.js +1 -1
- package/lib/setup-tests.js.map +1 -1
- package/lib/test/mock-query-results.js +1 -1
- package/lib/test/mock-query-results.js.map +1 -1
- package/lib/time-series-chart-model.d.ts +15 -0
- package/lib/time-series-chart-model.d.ts.map +1 -1
- package/lib/time-series-chart-model.js +26 -2
- package/lib/time-series-chart-model.js.map +1 -1
- package/lib/utils/data-transform.d.ts +3 -2
- package/lib/utils/data-transform.d.ts.map +1 -1
- package/lib/utils/data-transform.js +34 -14
- package/lib/utils/data-transform.js.map +1 -1
- package/lib/utils/palette-gen.js +1 -1
- package/lib/utils/palette-gen.js.map +1 -1
- package/lib/utils/palette.js +1 -1
- package/lib/utils/palette.js.map +1 -1
- package/mf-manifest.json +18 -18
- package/mf-stats.json +18 -18
- package/package.json +4 -4
- package/__mf/js/async/197.e065f9da.js +0 -1
- package/__mf/js/async/252.eb86b477.js +0 -22
- package/__mf/js/async/392.fa5c2b2f.js +0 -2
- package/__mf/js/async/591.9d963c5f.js +0 -38
- package/__mf/js/async/743.d260286e.js +0 -7
- package/__mf/js/async/__federation_expose_TimeSeriesChart.b844f4c6.js +0 -3
- package/__mf/js/async/lib-router.54d80a0a.js +0 -2
- /package/__mf/js/async/{675.450939c3.js.LICENSE.txt → 390.ad50daba.js.LICENSE.txt} +0 -0
- /package/__mf/js/async/{392.fa5c2b2f.js.LICENSE.txt → 392.550376f0.js.LICENSE.txt} +0 -0
- /package/__mf/js/async/{437.aa3568c0.js.LICENSE.txt → 544.4dd63985.js.LICENSE.txt} +0 -0
- /package/__mf/js/async/{252.eb86b477.js.LICENSE.txt → 648.128f31b8.js.LICENSE.txt} +0 -0
- /package/__mf/js/async/{743.d260286e.js.LICENSE.txt → 97.3f27a901.js.LICENSE.txt} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright
|
|
1
|
+
// Copyright The Perses Authors
|
|
2
2
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
3
|
// you may not use this file except in compliance with the License.
|
|
4
4
|
// You may obtain a copy of the License at
|
|
@@ -212,6 +212,23 @@ function QuerySettingsEditor(props) {
|
|
|
212
212
|
qs.areaOpacity = undefined;
|
|
213
213
|
});
|
|
214
214
|
};
|
|
215
|
+
const addUnit = (i)=>{
|
|
216
|
+
updateQuerySettings(i, (qs)=>{
|
|
217
|
+
qs.format = {
|
|
218
|
+
unit: 'decimal'
|
|
219
|
+
};
|
|
220
|
+
});
|
|
221
|
+
};
|
|
222
|
+
const removeUnit = (i)=>{
|
|
223
|
+
updateQuerySettings(i, (qs)=>{
|
|
224
|
+
qs.format = undefined;
|
|
225
|
+
});
|
|
226
|
+
};
|
|
227
|
+
const handleUnitChange = (i, format)=>{
|
|
228
|
+
updateQuerySettings(i, (qs)=>{
|
|
229
|
+
qs.format = format;
|
|
230
|
+
});
|
|
231
|
+
};
|
|
215
232
|
const queryCount = (0, _pluginsystem.useQueryCountContext)();
|
|
216
233
|
// Compute the list of query indexes for which query settings are not already defined.
|
|
217
234
|
// This is to avoid already-booked indexes to still be selectable in the dropdown(s)
|
|
@@ -270,7 +287,10 @@ function QuerySettingsEditor(props) {
|
|
|
270
287
|
onAddLineStyle: ()=>addLineStyle(i),
|
|
271
288
|
onRemoveLineStyle: ()=>removeLineStyle(i),
|
|
272
289
|
onAddAreaOpacity: ()=>addAreaOpacity(i),
|
|
273
|
-
onRemoveAreaOpacity: ()=>removeAreaOpacity(i)
|
|
290
|
+
onRemoveAreaOpacity: ()=>removeAreaOpacity(i),
|
|
291
|
+
onAddUnit: ()=>addUnit(i),
|
|
292
|
+
onRemoveUnit: ()=>removeUnit(i),
|
|
293
|
+
onUnitChange: (format)=>handleUnitChange(i, format)
|
|
274
294
|
}, i)),
|
|
275
295
|
queryCount > 0 && firstAvailableQueryIndex !== NO_INDEX_AVAILABLE && /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Button, {
|
|
276
296
|
variant: "contained",
|
|
@@ -284,7 +304,7 @@ function QuerySettingsEditor(props) {
|
|
|
284
304
|
]
|
|
285
305
|
});
|
|
286
306
|
}
|
|
287
|
-
function QuerySettingsInput({ querySettings: { queryIndex, colorMode, colorValue, lineStyle, areaOpacity }, availableQueryIndexes, onQueryIndexChange, onColorModeChange, onColorValueChange, onLineStyleChange, onAreaOpacityChange, onDelete, inputRef, onAddColor: onAddColor, onRemoveColor: onRemoveColor, onAddLineStyle, onRemoveLineStyle, onAddAreaOpacity, onRemoveAreaOpacity }) {
|
|
307
|
+
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, onAddUnit, onRemoveUnit, onUnitChange }) {
|
|
288
308
|
// current query index should also be selectable
|
|
289
309
|
const selectableQueryIndexes = availableQueryIndexes.concat(queryIndex).sort((a, b)=>a - b);
|
|
290
310
|
// State for dropdown menu
|
|
@@ -307,14 +327,21 @@ function QuerySettingsInput({ querySettings: { queryIndex, colorMode, colorValue
|
|
|
307
327
|
label: 'Opacity',
|
|
308
328
|
action: onAddAreaOpacity
|
|
309
329
|
});
|
|
330
|
+
if (format === undefined) options.push({
|
|
331
|
+
key: 'unit',
|
|
332
|
+
label: 'Unit',
|
|
333
|
+
action: onAddUnit
|
|
334
|
+
});
|
|
310
335
|
return options;
|
|
311
336
|
}, [
|
|
312
337
|
colorMode,
|
|
313
338
|
lineStyle,
|
|
314
339
|
areaOpacity,
|
|
340
|
+
format,
|
|
315
341
|
onAddColor,
|
|
316
342
|
onAddLineStyle,
|
|
317
|
-
onAddAreaOpacity
|
|
343
|
+
onAddAreaOpacity,
|
|
344
|
+
onAddUnit
|
|
318
345
|
]);
|
|
319
346
|
const handleAddMenuClick = (event)=>{
|
|
320
347
|
if (availableOptions.length === 1 && availableOptions[0]) {
|
|
@@ -333,7 +360,6 @@ function QuerySettingsInput({ querySettings: { queryIndex, colorMode, colorValue
|
|
|
333
360
|
handleMenuClose();
|
|
334
361
|
};
|
|
335
362
|
return /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Stack, {
|
|
336
|
-
spacing: 2,
|
|
337
363
|
sx: {
|
|
338
364
|
borderBottom: '1px solid',
|
|
339
365
|
borderColor: 'divider',
|
|
@@ -343,10 +369,9 @@ function QuerySettingsInput({ querySettings: { queryIndex, colorMode, colorValue
|
|
|
343
369
|
children: /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Stack, {
|
|
344
370
|
direction: "row",
|
|
345
371
|
alignItems: "center",
|
|
346
|
-
spacing: 1,
|
|
347
372
|
sx: {
|
|
348
373
|
flexWrap: 'wrap',
|
|
349
|
-
gap:
|
|
374
|
+
gap: 2
|
|
350
375
|
},
|
|
351
376
|
children: [
|
|
352
377
|
/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.TextField, {
|
|
@@ -442,6 +467,19 @@ function QuerySettingsInput({ querySettings: { queryIndex, colorMode, colorValue
|
|
|
442
467
|
})
|
|
443
468
|
]
|
|
444
469
|
}),
|
|
470
|
+
format !== undefined && /*#__PURE__*/ (0, _jsxruntime.jsx)(SettingsSection, {
|
|
471
|
+
label: "Unit",
|
|
472
|
+
onRemove: onRemoveUnit,
|
|
473
|
+
children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Box, {
|
|
474
|
+
sx: {
|
|
475
|
+
minWidth: '180px'
|
|
476
|
+
},
|
|
477
|
+
children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.UnitSelector, {
|
|
478
|
+
value: format,
|
|
479
|
+
onChange: onUnitChange
|
|
480
|
+
})
|
|
481
|
+
})
|
|
482
|
+
}),
|
|
445
483
|
availableOptions.length > 0 && /*#__PURE__*/ (0, _jsxruntime.jsxs)(_jsxruntime.Fragment, {
|
|
446
484
|
children: [
|
|
447
485
|
/*#__PURE__*/ (0, _jsxruntime.jsx)(_material.IconButton, {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright
|
|
1
|
+
// Copyright The Perses Authors
|
|
2
2
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
3
|
// you may not use this file except in compliance with the License.
|
|
4
4
|
// You may obtain a copy of the License at
|
|
@@ -51,7 +51,7 @@ function _interop_require_default(obj) {
|
|
|
51
51
|
_components.TooltipComponent,
|
|
52
52
|
_renderers.CanvasRenderer
|
|
53
53
|
]);
|
|
54
|
-
const TimeSeriesChartBase = /*#__PURE__*/ (0, _react.forwardRef)(function TimeChart({ height, data, seriesMapping, timeScale: timeScaleProp, yAxis, format, 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, timeScale: timeScaleProp, yAxis, format, seriesFormatMap, grid, isStackedBar = false, tooltipConfig = _components1.DEFAULT_TOOLTIP_CONFIG, noDataVariant = 'message', syncGroup, onDataZoom, onDoubleClick, __experimentalEChartsOptionsOverride }, ref) {
|
|
55
55
|
const { chartsTheme, enablePinning, enableSyncGrouping, lastTooltipPinnedCoords, setLastTooltipPinnedCoords } = (0, _components1.useChartsContext)();
|
|
56
56
|
const isPinningEnabled = tooltipConfig.enablePinning && enablePinning;
|
|
57
57
|
const chartRef = (0, _react.useRef)();
|
|
@@ -181,7 +181,8 @@ const TimeSeriesChartBase = /*#__PURE__*/ (0, _react.forwardRef)(function TimeCh
|
|
|
181
181
|
snap: false
|
|
182
182
|
}
|
|
183
183
|
},
|
|
184
|
-
yAxis
|
|
184
|
+
// If yAxis is already an array (multiple Y axes), use it directly; otherwise use getFormattedAxis
|
|
185
|
+
yAxis: Array.isArray(yAxis) ? yAxis : (0, _components1.getFormattedAxis)(yAxis, format),
|
|
185
186
|
animation: false,
|
|
186
187
|
tooltip: {
|
|
187
188
|
show: true,
|
|
@@ -379,6 +380,7 @@ const TimeSeriesChartBase = /*#__PURE__*/ (0, _react.forwardRef)(function TimeCh
|
|
|
379
380
|
enablePinning: isPinningEnabled,
|
|
380
381
|
pinnedPos: tooltipPinnedCoords,
|
|
381
382
|
format: format,
|
|
383
|
+
seriesFormatMap: seriesFormatMap,
|
|
382
384
|
onUnpinClick: ()=>{
|
|
383
385
|
// Unpins tooltip when clicking Pin icon in TooltipHeader.
|
|
384
386
|
setTooltipPinnedCoords(null);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright
|
|
1
|
+
// Copyright The Perses Authors
|
|
2
2
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
3
|
// you may not use this file except in compliance with the License.
|
|
4
4
|
// You may obtain a copy of the License at
|
|
@@ -76,16 +76,47 @@ function TimeSeriesChartPanel(props) {
|
|
|
76
76
|
}, [
|
|
77
77
|
yAxis
|
|
78
78
|
]);
|
|
79
|
+
// Collect unique formats from query settings that differ from the base format
|
|
80
|
+
// These will create additional Y axes on the right side
|
|
81
|
+
const { additionalFormats, formatToYAxisIndex, seriesFormatMap } = (0, _react.useMemo)(()=>{
|
|
82
|
+
const baseUnit = format?.unit ?? 'decimal';
|
|
83
|
+
const additionalFormats = [];
|
|
84
|
+
const formatToYAxisIndex = new Map();
|
|
85
|
+
const seriesFormatMap = new Map();
|
|
86
|
+
// Index 0 is reserved for the base Y axis
|
|
87
|
+
formatToYAxisIndex.set(baseUnit, 0);
|
|
88
|
+
// Collect unique formats from query settings
|
|
89
|
+
for (const qs of querySettingsList ?? []){
|
|
90
|
+
if (qs.format?.unit && qs.format.unit !== baseUnit) {
|
|
91
|
+
const unitKey = qs.format.unit;
|
|
92
|
+
if (!formatToYAxisIndex.has(unitKey)) {
|
|
93
|
+
// Add new format - index is 1 + position in additionalFormats array
|
|
94
|
+
formatToYAxisIndex.set(unitKey, 1 + additionalFormats.length);
|
|
95
|
+
additionalFormats.push(qs.format);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
additionalFormats,
|
|
101
|
+
formatToYAxisIndex,
|
|
102
|
+
seriesFormatMap
|
|
103
|
+
};
|
|
104
|
+
}, [
|
|
105
|
+
format,
|
|
106
|
+
querySettingsList
|
|
107
|
+
]);
|
|
79
108
|
const [selectedLegendItems, setSelectedLegendItems] = (0, _react.useState)('ALL');
|
|
80
109
|
const [legendSorting, setLegendSorting] = (0, _react.useState)();
|
|
81
110
|
const { setTimeRange } = (0, _pluginsystem.useTimeRange)();
|
|
82
111
|
// Populate series data based on query results
|
|
83
|
-
const { timeScale, timeChartData, timeSeriesMapping, legendItems } = (0, _react.useMemo)(()=>{
|
|
112
|
+
const { timeScale, timeChartData, timeSeriesMapping, legendItems, seriesFormatMap: computedSeriesFormatMap, maxValuesByFormat } = (0, _react.useMemo)(()=>{
|
|
84
113
|
const timeScale = (0, _datatransform.getCommonTimeScaleForQueries)(queryResults);
|
|
85
114
|
if (timeScale === undefined) {
|
|
86
115
|
return {
|
|
87
116
|
timeChartData: [],
|
|
88
|
-
timeSeriesMapping: []
|
|
117
|
+
timeSeriesMapping: [],
|
|
118
|
+
seriesFormatMap: new Map(),
|
|
119
|
+
maxValuesByFormat: new Map()
|
|
89
120
|
};
|
|
90
121
|
}
|
|
91
122
|
const legendItems = [];
|
|
@@ -93,6 +124,8 @@ function TimeSeriesChartPanel(props) {
|
|
|
93
124
|
// https://apache.github.io/echarts-handbook/en/concepts/dataset/
|
|
94
125
|
const timeChartData = [];
|
|
95
126
|
const timeSeriesMapping = [];
|
|
127
|
+
// Track max values for each format unit (used for dynamic Y axis offset calculation)
|
|
128
|
+
const maxValuesByFormat = new Map();
|
|
96
129
|
// Index is counted across multiple queries which ensures the categorical color palette does not reset for every query
|
|
97
130
|
let seriesIndex = 0;
|
|
98
131
|
// Mapping of each set of query results to be ECharts option compatible
|
|
@@ -146,9 +179,25 @@ function TimeSeriesChartPanel(props) {
|
|
|
146
179
|
// which legend items are selected. This must happen before timeChartData.push to avoid an
|
|
147
180
|
// off-by-one error, seriesIndex cannot be used since it's needed to cycle through palette
|
|
148
181
|
const datasetIndex = timeChartData.length;
|
|
182
|
+
// Determine yAxisIndex based on the query's format setting
|
|
183
|
+
const queryFormat = querySettings?.format;
|
|
184
|
+
const yAxisIndex = queryFormat?.unit ? formatToYAxisIndex.get(queryFormat.unit) ?? 0 : 0;
|
|
149
185
|
// Each series is stored as a separate dataset source.
|
|
150
186
|
// https://apache.github.io/echarts-handbook/en/concepts/dataset/#how-to-reference-several-datasets
|
|
151
|
-
timeSeriesMapping.push((0, _datatransform.getTimeSeries)(seriesId, datasetIndex, formattedSeriesName, visual, timeScale, seriesColor, querySettings));
|
|
187
|
+
timeSeriesMapping.push((0, _datatransform.getTimeSeries)(seriesId, datasetIndex, formattedSeriesName, visual, timeScale, seriesColor, querySettings, yAxisIndex));
|
|
188
|
+
// Store the format for this series for tooltip formatting
|
|
189
|
+
if (queryFormat) {
|
|
190
|
+
seriesFormatMap.set(seriesId, queryFormat);
|
|
191
|
+
// Track max value for this format unit (used for dynamic Y axis offset calculation)
|
|
192
|
+
const unitKey = queryFormat.unit;
|
|
193
|
+
if (unitKey) {
|
|
194
|
+
const seriesMax = Math.max(...timeSeries.values.map((v)=>Math.abs(v[1] ?? 0)));
|
|
195
|
+
const currentMax = maxValuesByFormat.get(unitKey) ?? 0;
|
|
196
|
+
if (seriesMax > currentMax) {
|
|
197
|
+
maxValuesByFormat.set(unitKey, seriesMax);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
152
201
|
timeChartData.push({
|
|
153
202
|
name: formattedSeriesName,
|
|
154
203
|
values: (0, _core.getTimeSeriesValues)(timeSeries, timeScale)
|
|
@@ -205,7 +254,9 @@ function TimeSeriesChartPanel(props) {
|
|
|
205
254
|
timeScale,
|
|
206
255
|
timeChartData,
|
|
207
256
|
timeSeriesMapping,
|
|
208
|
-
legendItems
|
|
257
|
+
legendItems,
|
|
258
|
+
seriesFormatMap,
|
|
259
|
+
maxValuesByFormat
|
|
209
260
|
};
|
|
210
261
|
}, [
|
|
211
262
|
queryResults,
|
|
@@ -219,7 +270,27 @@ function TimeSeriesChartPanel(props) {
|
|
|
219
270
|
categoricalPalette,
|
|
220
271
|
chartId,
|
|
221
272
|
chartsTheme.thresholds,
|
|
222
|
-
muiTheme.palette.primary.main
|
|
273
|
+
muiTheme.palette.primary.main,
|
|
274
|
+
formatToYAxisIndex,
|
|
275
|
+
seriesFormatMap
|
|
276
|
+
]);
|
|
277
|
+
// Create multiple Y axes if there are additional formats
|
|
278
|
+
// Uses max values from data to compute dynamic offsets that adapt to label widths
|
|
279
|
+
const multipleYAxes = (0, _react.useMemo)(()=>{
|
|
280
|
+
if (additionalFormats.length === 0) {
|
|
281
|
+
return undefined; // Use single Y axis (default behavior)
|
|
282
|
+
}
|
|
283
|
+
// Build array of max values for each additional format (in order)
|
|
284
|
+
const maxValues = additionalFormats.map((fmt)=>{
|
|
285
|
+
const unitKey = fmt.unit;
|
|
286
|
+
return unitKey ? maxValuesByFormat?.get(unitKey) ?? 1000 : 1000;
|
|
287
|
+
});
|
|
288
|
+
return (0, _components.getFormattedMultipleYAxes)(echartsYAxis, format, additionalFormats, maxValues);
|
|
289
|
+
}, [
|
|
290
|
+
echartsYAxis,
|
|
291
|
+
format,
|
|
292
|
+
additionalFormats,
|
|
293
|
+
maxValuesByFormat
|
|
223
294
|
]);
|
|
224
295
|
// Translate the legend values into columns for the table legend.
|
|
225
296
|
const legendColumns = (0, _react.useMemo)(()=>{
|
|
@@ -254,16 +325,29 @@ function TimeSeriesChartPanel(props) {
|
|
|
254
325
|
legend?.values,
|
|
255
326
|
format
|
|
256
327
|
]);
|
|
328
|
+
const gridOverrides = (0, _react.useMemo)(()=>{
|
|
329
|
+
// When Y axes are hidden, disable containLabel to prevent auto-spacing, but add bottom padding for X axis
|
|
330
|
+
return echartsYAxis.show === false ? {
|
|
331
|
+
left: 0,
|
|
332
|
+
right: 0,
|
|
333
|
+
bottom: 30,
|
|
334
|
+
containLabel: false
|
|
335
|
+
} : {
|
|
336
|
+
left: yAxis && yAxis.label ? 30 : 20,
|
|
337
|
+
// With containLabel: true in theme, ECharts auto-reserves space for axis labels.
|
|
338
|
+
// For multiple right axes, add extra padding for the last axis labels that extend beyond the grid.
|
|
339
|
+
right: additionalFormats.length > 0 ? 10 : 20,
|
|
340
|
+
bottom: 0,
|
|
341
|
+
containLabel: true
|
|
342
|
+
};
|
|
343
|
+
}, [
|
|
344
|
+
echartsYAxis.show,
|
|
345
|
+
yAxis,
|
|
346
|
+
additionalFormats.length
|
|
347
|
+
]);
|
|
257
348
|
if (adjustedContentDimensions === undefined) {
|
|
258
349
|
return null;
|
|
259
350
|
}
|
|
260
|
-
// override default spacing, see: https://echarts.apache.org/en/option.html#grid
|
|
261
|
-
const gridLeft = yAxis && yAxis.label ? 30 : 20;
|
|
262
|
-
const gridOverrides = {
|
|
263
|
-
left: !echartsYAxis.show ? 0 : gridLeft,
|
|
264
|
-
right: 20,
|
|
265
|
-
bottom: 0
|
|
266
|
-
};
|
|
267
351
|
const handleDataZoom = (event)=>{
|
|
268
352
|
// TODO: add ECharts transition animation on zoom
|
|
269
353
|
setTimeRange({
|
|
@@ -331,8 +415,9 @@ function TimeSeriesChartPanel(props) {
|
|
|
331
415
|
data: timeChartData,
|
|
332
416
|
seriesMapping: timeSeriesMapping,
|
|
333
417
|
timeScale: timeScale,
|
|
334
|
-
yAxis: echartsYAxis,
|
|
418
|
+
yAxis: multipleYAxes ?? echartsYAxis,
|
|
335
419
|
format: format,
|
|
420
|
+
seriesFormatMap: computedSeriesFormatMap,
|
|
336
421
|
grid: gridOverrides,
|
|
337
422
|
isStackedBar: isStackedBar,
|
|
338
423
|
tooltipConfig: tooltipConfig,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright
|
|
1
|
+
// Copyright The Perses Authors
|
|
2
2
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
3
|
// you may not use this file except in compliance with the License.
|
|
4
4
|
// You may obtain a copy of the License at
|
|
@@ -21,9 +21,10 @@ Object.defineProperty(exports, "TimeSeriesExportAction", {
|
|
|
21
21
|
}
|
|
22
22
|
});
|
|
23
23
|
const _jsxruntime = require("react/jsx-runtime");
|
|
24
|
-
const _react = /*#__PURE__*/ _interop_require_wildcard(require("react"));
|
|
25
24
|
const _material = require("@mui/material");
|
|
25
|
+
const _components = require("@perses-dev/components");
|
|
26
26
|
const _Download = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/Download"));
|
|
27
|
+
const _react = /*#__PURE__*/ _interop_require_wildcard(require("react"));
|
|
27
28
|
const _CSVExportUtils = require("./CSVExportUtils");
|
|
28
29
|
function _interop_require_default(obj) {
|
|
29
30
|
return obj && obj.__esModule ? obj : {
|
|
@@ -109,8 +110,8 @@ const TimeSeriesExportAction = ({ queryResults, definition })=>{
|
|
|
109
110
|
if (!canExport) {
|
|
110
111
|
return null;
|
|
111
112
|
}
|
|
112
|
-
return /*#__PURE__*/ (0, _jsxruntime.jsx)(
|
|
113
|
-
|
|
113
|
+
return /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.InfoTooltip, {
|
|
114
|
+
description: "Export as CSV",
|
|
114
115
|
children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.IconButton, {
|
|
115
116
|
size: "small",
|
|
116
117
|
onClick: handleExport,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright
|
|
1
|
+
// Copyright The Perses Authors
|
|
2
2
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
3
|
// you may not use this file except in compliance with the License.
|
|
4
4
|
// You may obtain a copy of the License at
|
|
@@ -25,6 +25,7 @@ const _material = require("@mui/material");
|
|
|
25
25
|
const _components = require("@perses-dev/components");
|
|
26
26
|
const _timeserieschartmodel = require("./time-series-chart-model");
|
|
27
27
|
function YAxisOptionsEditor({ value, onChange }) {
|
|
28
|
+
const logBase = value.logBase ? _timeserieschartmodel.LOG_BASE_CONFIG[value.logBase] : undefined;
|
|
28
29
|
return /*#__PURE__*/ (0, _jsxruntime.jsxs)(_components.OptionsEditorGroup, {
|
|
29
30
|
title: "Y Axis",
|
|
30
31
|
children: [
|
|
@@ -47,6 +48,25 @@ function YAxisOptionsEditor({ value, onChange }) {
|
|
|
47
48
|
format: newFormat
|
|
48
49
|
})
|
|
49
50
|
}),
|
|
51
|
+
/*#__PURE__*/ (0, _jsxruntime.jsx)(_components.OptionsEditorControl, {
|
|
52
|
+
label: _timeserieschartmodel.Y_AXIS_CONFIG.logBase.label,
|
|
53
|
+
control: /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.SettingsAutocomplete, {
|
|
54
|
+
value: {
|
|
55
|
+
...logBase,
|
|
56
|
+
id: logBase?.label ?? 'None'
|
|
57
|
+
},
|
|
58
|
+
options: _timeserieschartmodel.LOG_BASE_OPTIONS,
|
|
59
|
+
onChange: (__, newValue)=>{
|
|
60
|
+
const updatedValue = {
|
|
61
|
+
...value,
|
|
62
|
+
logBase: newValue.log ?? undefined
|
|
63
|
+
};
|
|
64
|
+
onChange(updatedValue);
|
|
65
|
+
},
|
|
66
|
+
disabled: value === undefined,
|
|
67
|
+
disableClearable: true
|
|
68
|
+
})
|
|
69
|
+
}),
|
|
50
70
|
/*#__PURE__*/ (0, _jsxruntime.jsx)(_components.OptionsEditorControl, {
|
|
51
71
|
label: _timeserieschartmodel.Y_AXIS_CONFIG.label.label,
|
|
52
72
|
control: /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.TextField, {
|
package/lib/cjs/bootstrap.js
CHANGED
package/lib/cjs/env.d.js
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
// Copyright The Perses Authors
|
|
2
|
+
// Licensed under the Apache License, Version 2.0 (the \"License\");
|
|
3
|
+
// you may not use this file except in compliance with the License.
|
|
4
|
+
// You may obtain a copy of the License at
|
|
5
|
+
//
|
|
6
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
//
|
|
8
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
9
|
+
// distributed under the License is distributed on an \"AS IS\" BASIS,
|
|
10
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
|
+
// See the License for the specific language governing permissions and
|
|
12
|
+
// limitations under the License.
|
|
1
13
|
"use strict";
|
|
2
14
|
Object.defineProperty(exports, "__esModule", {
|
|
3
15
|
value: true
|
|
@@ -40,7 +40,7 @@ function _interop_require_wildcard(obj, nodeInterop) {
|
|
|
40
40
|
}
|
|
41
41
|
return newObj;
|
|
42
42
|
}
|
|
43
|
-
// Copyright
|
|
43
|
+
// Copyright The Perses Authors
|
|
44
44
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
45
45
|
// you may not use this file except in compliance with the License.
|
|
46
46
|
// You may obtain a copy of the License at
|
package/lib/cjs/index.js
CHANGED
package/lib/cjs/setup-tests.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright
|
|
1
|
+
// Copyright The Perses Authors
|
|
2
2
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
3
|
// you may not use this file except in compliance with the License.
|
|
4
4
|
// You may obtain a copy of the License at
|
|
@@ -51,6 +51,12 @@ _export(exports, {
|
|
|
51
51
|
get LINE_STYLE_CONFIG () {
|
|
52
52
|
return LINE_STYLE_CONFIG;
|
|
53
53
|
},
|
|
54
|
+
get LOG_BASE_CONFIG () {
|
|
55
|
+
return LOG_BASE_CONFIG;
|
|
56
|
+
},
|
|
57
|
+
get LOG_BASE_OPTIONS () {
|
|
58
|
+
return LOG_BASE_OPTIONS;
|
|
59
|
+
},
|
|
54
60
|
get NEGATIVE_MIN_VALUE_MULTIPLIER () {
|
|
55
61
|
return NEGATIVE_MIN_VALUE_MULTIPLIER;
|
|
56
62
|
},
|
|
@@ -91,7 +97,8 @@ const DEFAULT_Y_AXIS = {
|
|
|
91
97
|
label: '',
|
|
92
98
|
format: DEFAULT_FORMAT,
|
|
93
99
|
min: undefined,
|
|
94
|
-
max: undefined
|
|
100
|
+
max: undefined,
|
|
101
|
+
logBase: undefined
|
|
95
102
|
};
|
|
96
103
|
const Y_AXIS_CONFIG = {
|
|
97
104
|
show: {
|
|
@@ -108,6 +115,9 @@ const Y_AXIS_CONFIG = {
|
|
|
108
115
|
},
|
|
109
116
|
max: {
|
|
110
117
|
label: 'Max'
|
|
118
|
+
},
|
|
119
|
+
logBase: {
|
|
120
|
+
label: 'Log Base'
|
|
111
121
|
}
|
|
112
122
|
};
|
|
113
123
|
const DEFAULT_DISPLAY = 'line';
|
|
@@ -190,6 +200,24 @@ const OPACITY_CONFIG = {
|
|
|
190
200
|
max: 1,
|
|
191
201
|
step: 0.05
|
|
192
202
|
};
|
|
203
|
+
const LOG_BASE_CONFIG = {
|
|
204
|
+
none: {
|
|
205
|
+
label: 'None',
|
|
206
|
+
log: undefined
|
|
207
|
+
},
|
|
208
|
+
'2': {
|
|
209
|
+
label: '2',
|
|
210
|
+
log: 2
|
|
211
|
+
},
|
|
212
|
+
'10': {
|
|
213
|
+
label: '10',
|
|
214
|
+
log: 10
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
const LOG_BASE_OPTIONS = Object.entries(LOG_BASE_CONFIG).map(([id, config])=>({
|
|
218
|
+
id: id,
|
|
219
|
+
...config
|
|
220
|
+
}));
|
|
193
221
|
const POSITIVE_MIN_VALUE_MULTIPLIER = 0.8;
|
|
194
222
|
const NEGATIVE_MIN_VALUE_MULTIPLIER = 1.2;
|
|
195
223
|
function createInitialTimeSeriesChartOptions() {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright
|
|
1
|
+
// Copyright The Perses Authors
|
|
2
2
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
3
|
// you may not use this file except in compliance with the License.
|
|
4
4
|
// You may obtain a copy of the License at
|
|
@@ -63,7 +63,7 @@ function getCommonTimeScaleForQueries(queries) {
|
|
|
63
63
|
const seriesData = queries.map((query)=>query.data);
|
|
64
64
|
return (0, _core.getCommonTimeScale)(seriesData);
|
|
65
65
|
}
|
|
66
|
-
function getTimeSeries(id, datasetIndex, formattedName, visual, timeScale, paletteColor, querySettings) {
|
|
66
|
+
function getTimeSeries(id, datasetIndex, formattedName, visual, timeScale, paletteColor, querySettings, yAxisIndex) {
|
|
67
67
|
const lineWidth = visual.lineWidth ?? _timeserieschartmodel.DEFAULT_LINE_WIDTH;
|
|
68
68
|
const pointRadius = visual.pointRadius ?? _timeserieschartmodel.DEFAULT_POINT_RADIUS;
|
|
69
69
|
// Shows datapoint symbols when selected time range is roughly 15 minutes or less
|
|
@@ -81,6 +81,7 @@ function getTimeSeries(id, datasetIndex, formattedName, visual, timeScale, palet
|
|
|
81
81
|
name: formattedName,
|
|
82
82
|
color: paletteColor,
|
|
83
83
|
stack: visual.stack === 'all' ? visual.stack : undefined,
|
|
84
|
+
yAxisIndex: yAxisIndex,
|
|
84
85
|
label: {
|
|
85
86
|
show: false
|
|
86
87
|
}
|
|
@@ -95,6 +96,7 @@ function getTimeSeries(id, datasetIndex, formattedName, visual, timeScale, palet
|
|
|
95
96
|
connectNulls: visual.connectNulls ?? _timeserieschartmodel.DEFAULT_CONNECT_NULLS,
|
|
96
97
|
color: paletteColor,
|
|
97
98
|
stack: visual.stack === 'all' ? visual.stack : undefined,
|
|
99
|
+
yAxisIndex: yAxisIndex,
|
|
98
100
|
sampling: 'lttb',
|
|
99
101
|
progressiveThreshold: _components.OPTIMIZED_MODE_SERIES_LIMIT,
|
|
100
102
|
showSymbol: showPoints,
|
|
@@ -195,18 +197,21 @@ function findMax(data) {
|
|
|
195
197
|
return max;
|
|
196
198
|
}
|
|
197
199
|
function convertPanelYAxis(inputAxis = {}) {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
|
|
200
|
+
// Determine the appropriate min value based on scale type and user input
|
|
201
|
+
let minValue;
|
|
202
|
+
if (inputAxis.logBase !== undefined) {
|
|
203
|
+
// For logarithmic scales without explicit min:
|
|
204
|
+
// Let ECharts auto-calculate the range based on data to avoid issues with
|
|
205
|
+
// function-based calculations which can result in improper ranges (e.g., 1-10)
|
|
206
|
+
minValue = undefined;
|
|
207
|
+
} else if (inputAxis?.min !== undefined) {
|
|
208
|
+
// User explicitly set a min value - use it for both linear and log scales
|
|
209
|
+
minValue = inputAxis.min;
|
|
210
|
+
} else {
|
|
211
|
+
// For linear scales without explicit min:
|
|
212
|
+
// Use dynamic calculation with padding for better visualization
|
|
208
213
|
// https://echarts.apache.org/en/option.html#yAxis.min
|
|
209
|
-
|
|
214
|
+
minValue = (value)=>{
|
|
210
215
|
if (value.min >= 0 && value.min <= 1) {
|
|
211
216
|
// Helps with PercentDecimal units, or datasets that return 0 or 1 booleans
|
|
212
217
|
return 0;
|
|
@@ -220,6 +225,20 @@ function convertPanelYAxis(inputAxis = {}) {
|
|
|
220
225
|
}
|
|
221
226
|
};
|
|
222
227
|
}
|
|
228
|
+
// Build the yAxis configuration
|
|
229
|
+
const yAxis = {
|
|
230
|
+
show: inputAxis?.show ?? _timeserieschartmodel.DEFAULT_Y_AXIS.show,
|
|
231
|
+
min: minValue,
|
|
232
|
+
max: inputAxis?.max
|
|
233
|
+
};
|
|
234
|
+
// Apply logarithmic scale settings if requested
|
|
235
|
+
if (inputAxis.logBase !== undefined) {
|
|
236
|
+
return {
|
|
237
|
+
...yAxis,
|
|
238
|
+
type: 'log',
|
|
239
|
+
logBase: inputAxis.logBase
|
|
240
|
+
};
|
|
241
|
+
}
|
|
223
242
|
return yAxis;
|
|
224
243
|
}
|
|
225
244
|
function roundDown(num) {
|
package/lib/cjs/utils/palette.js
CHANGED
package/lib/env.d.js
CHANGED
package/lib/env.d.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/env.d.ts"],"sourcesContent":["// Copyright
|
|
1
|
+
{"version":3,"sources":["../../src/env.d.ts"],"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\n/// <reference types=\"@rsbuild/core/types\" />\n"],"names":[],"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,6CAA6C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getPluginModule.d.ts","sourceRoot":"","sources":["../../src/getPluginModule.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"getPluginModule.d.ts","sourceRoot":"","sources":["../../src/getPluginModule.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,oBAAoB,EAAoB,MAAM,2BAA2B,CAAC;AAGnF;;GAEG;AACH,wBAAgB,eAAe,IAAI,oBAAoB,CAUtD"}
|