@perses-dev/timeseries-chart-plugin 0.13.0 → 0.14.0-beta.2

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 (172) hide show
  1. package/__mf/js/TimeSeriesChart.b9caac04.js +7 -0
  2. package/__mf/js/async/121.fde1320e.js +2 -0
  3. package/__mf/js/async/{527.f97d1b86.js → 182.9e1e293f.js} +9 -9
  4. package/__mf/js/async/192.66c6659d.js +1 -0
  5. package/__mf/js/async/2.166bda4f.js +1 -0
  6. package/__mf/js/async/235.76fd7af2.js +1 -0
  7. package/__mf/js/async/274.e4ed32f7.js +2 -0
  8. package/__mf/js/async/319.8e262f9c.js +1 -0
  9. package/__mf/js/async/356.52455d93.js +1 -0
  10. package/__mf/js/async/384.f40367cc.js +1 -0
  11. package/__mf/js/async/392.8cb3dcaa.js +2 -0
  12. package/__mf/js/async/463.f5dc7759.js +7 -0
  13. package/__mf/js/async/{694.0fb9ee5a.js.LICENSE.txt → 463.f5dc7759.js.LICENSE.txt} +41 -1
  14. package/__mf/js/async/465.add3260a.js +1 -0
  15. package/__mf/js/async/470.beedcbcc.js +2 -0
  16. package/__mf/js/async/522.806db24f.js +22 -0
  17. package/__mf/js/async/525.8b92c616.js +37 -0
  18. package/__mf/js/async/587.828c454a.js +1 -0
  19. package/__mf/js/async/597.0c5bd6dd.js +2 -0
  20. package/__mf/js/async/612.b2f31132.js +3 -0
  21. package/__mf/js/async/616.804d525d.js +1 -0
  22. package/__mf/js/async/663.892b9ad5.js +1 -0
  23. package/__mf/js/async/700.25c7e5dd.js +1 -0
  24. package/__mf/js/async/724.f74ffa12.js +1 -0
  25. package/__mf/js/async/730.058dea58.js +2 -0
  26. package/__mf/js/async/865.cb917066.js +2 -0
  27. package/__mf/js/async/941.3bb54150.js +2 -0
  28. package/__mf/js/async/955.52ca0671.js +1 -0
  29. package/__mf/js/async/968.2dd830b3.js +1 -0
  30. package/__mf/js/async/__federation_expose_TimeSeriesChart.4ddb01e0.js +1 -0
  31. package/__mf/js/async/lib-router.ecb51f08.js +2 -0
  32. package/__mf/js/main.f55169be.js +7 -0
  33. package/lib/GeneralSettingsEditor.d.ts +2 -2
  34. package/lib/GeneralSettingsEditor.d.ts.map +1 -1
  35. package/lib/GeneralSettingsEditor.js +7 -7
  36. package/lib/GeneralSettingsEditor.js.map +1 -1
  37. package/lib/QuerySettingsEditor.d.ts +2 -2
  38. package/lib/QuerySettingsEditor.d.ts.map +1 -1
  39. package/lib/QuerySettingsEditor.js +11 -11
  40. package/lib/QuerySettingsEditor.js.map +1 -1
  41. package/lib/TimeSeriesChart.d.ts +3 -3
  42. package/lib/TimeSeriesChart.d.ts.map +1 -1
  43. package/lib/TimeSeriesChart.js +6 -5
  44. package/lib/TimeSeriesChart.js.map +1 -1
  45. package/lib/TimeSeriesChartBase.d.ts +4 -4
  46. package/lib/TimeSeriesChartBase.d.ts.map +1 -1
  47. package/lib/TimeSeriesChartBase.js +12 -12
  48. package/lib/TimeSeriesChartBase.js.map +1 -1
  49. package/lib/TimeSeriesChartPanel.d.ts +4 -4
  50. package/lib/TimeSeriesChartPanel.d.ts.map +1 -1
  51. package/lib/TimeSeriesChartPanel.js +12 -12
  52. package/lib/TimeSeriesChartPanel.js.map +1 -1
  53. package/lib/TimeSeriesExportAction.d.ts +1 -1
  54. package/lib/TimeSeriesExportAction.d.ts.map +1 -1
  55. package/lib/TimeSeriesExportAction.js +5 -5
  56. package/lib/TimeSeriesExportAction.js.map +1 -1
  57. package/lib/VisualOptionsEditor.d.ts +2 -2
  58. package/lib/VisualOptionsEditor.d.ts.map +1 -1
  59. package/lib/VisualOptionsEditor.js +4 -4
  60. package/lib/VisualOptionsEditor.js.map +1 -1
  61. package/lib/YAxisOptionsEditor.d.ts +2 -2
  62. package/lib/YAxisOptionsEditor.d.ts.map +1 -1
  63. package/lib/YAxisOptionsEditor.js +3 -3
  64. package/lib/YAxisOptionsEditor.js.map +1 -1
  65. package/lib/annotations/AnnotationTooltip.d.ts +2 -2
  66. package/lib/annotations/AnnotationTooltip.d.ts.map +1 -1
  67. package/lib/annotations/AnnotationTooltip.js +6 -6
  68. package/lib/annotations/AnnotationTooltip.js.map +1 -1
  69. package/lib/bootstrap.js +2 -2
  70. package/lib/getPluginModule.d.ts +1 -1
  71. package/lib/getPluginModule.d.ts.map +1 -1
  72. package/lib/getPluginModule.js +3 -1
  73. package/lib/getPluginModule.js.map +1 -1
  74. package/lib/index-federation.js +1 -1
  75. package/lib/index.js +9 -9
  76. package/lib/index.js.map +1 -1
  77. package/lib/setup-tests.d.ts +1 -1
  78. package/lib/setup-tests.d.ts.map +1 -1
  79. package/lib/setup-tests.js +2 -2
  80. package/lib/setup-tests.js.map +1 -1
  81. package/lib/test/mock-query-results.d.ts +1 -1
  82. package/lib/test/mock-query-results.d.ts.map +1 -1
  83. package/lib/test/mock-query-results.js.map +1 -1
  84. package/lib/time-series-chart-model.d.ts +3 -3
  85. package/lib/time-series-chart-model.d.ts.map +1 -1
  86. package/lib/time-series-chart-model.js.map +1 -1
  87. package/lib/utils/annotation.d.ts +2 -2
  88. package/lib/utils/annotation.d.ts.map +1 -1
  89. package/lib/utils/annotation.js.map +1 -1
  90. package/lib/utils/data-transform.d.ts +5 -5
  91. package/lib/utils/data-transform.d.ts.map +1 -1
  92. package/lib/utils/data-transform.js +3 -3
  93. package/lib/utils/data-transform.js.map +1 -1
  94. package/lib/utils/palette-gen.d.ts +1 -1
  95. package/lib/utils/palette-gen.d.ts.map +1 -1
  96. package/lib/utils/palette-gen.js +1 -1
  97. package/lib/utils/palette-gen.js.map +1 -1
  98. package/lib/utils/palette.js +1 -1
  99. package/lib/utils/palette.js.map +1 -1
  100. package/lib/utils/timezone-formatter.js +1 -1
  101. package/mf-manifest.json +37 -81
  102. package/mf-stats.json +39 -91
  103. package/package.json +11 -11
  104. package/__mf/js/TimeSeriesChart.42841bce.js +0 -7
  105. package/__mf/js/async/121.c3c0e54f.js +0 -2
  106. package/__mf/js/async/177.2fef2962.js +0 -1
  107. package/__mf/js/async/187.f5e8932b.js +0 -1
  108. package/__mf/js/async/192.c3dd56d5.js +0 -1
  109. package/__mf/js/async/2.60fa4a40.js +0 -1
  110. package/__mf/js/async/208.b9f374ad.js +0 -7
  111. package/__mf/js/async/208.b9f374ad.js.LICENSE.txt +0 -39
  112. package/__mf/js/async/235.d23c8ef0.js +0 -1
  113. package/__mf/js/async/274.72dfa9c8.js +0 -2
  114. package/__mf/js/async/356.8170c96d.js +0 -1
  115. package/__mf/js/async/392.b9ba5bf2.js +0 -2
  116. package/__mf/js/async/470.e09f33b7.js +0 -2
  117. package/__mf/js/async/491.85194549.js +0 -1
  118. package/__mf/js/async/518.2ac1df43.js +0 -38
  119. package/__mf/js/async/52.0d78de2b.js +0 -1
  120. package/__mf/js/async/546.5fecffa4.js +0 -3
  121. package/__mf/js/async/568.45da2c30.js +0 -1
  122. package/__mf/js/async/587.c9460696.js +0 -1
  123. package/__mf/js/async/588.0a1aa144.js +0 -1
  124. package/__mf/js/async/603.3b771310.js +0 -2
  125. package/__mf/js/async/616.79484ac8.js +0 -1
  126. package/__mf/js/async/655.2f794f77.js +0 -1
  127. package/__mf/js/async/694.0fb9ee5a.js +0 -2
  128. package/__mf/js/async/702.785cd635.js +0 -2
  129. package/__mf/js/async/71.8c6cf914.js +0 -1
  130. package/__mf/js/async/724.c45dcf5b.js +0 -1
  131. package/__mf/js/async/873.04a201bf.js +0 -1
  132. package/__mf/js/async/941.b89f8595.js +0 -2
  133. package/__mf/js/async/955.176fe200.js +0 -1
  134. package/__mf/js/async/968.2a9fb1a0.js +0 -1
  135. package/__mf/js/async/978.a9865b23.js +0 -1
  136. package/__mf/js/async/984.83bd5c6d.js +0 -22
  137. package/__mf/js/async/__federation_expose_TimeSeriesChart.0ab11cd4.js +0 -1
  138. package/__mf/js/async/lib-router.319c02cd.js +0 -2
  139. package/__mf/js/main.691eecd6.js +0 -7
  140. package/lib/cjs/GeneralSettingsEditor.js +0 -103
  141. package/lib/cjs/QuerySettingsEditor.js +0 -666
  142. package/lib/cjs/TimeSeriesChart.js +0 -50
  143. package/lib/cjs/TimeSeriesChartBase.js +0 -488
  144. package/lib/cjs/TimeSeriesChartPanel.js +0 -456
  145. package/lib/cjs/TimeSeriesExportAction.js +0 -124
  146. package/lib/cjs/VisualOptionsEditor.js +0 -161
  147. package/lib/cjs/YAxisOptionsEditor.js +0 -118
  148. package/lib/cjs/annotations/AnnotationTooltip.js +0 -370
  149. package/lib/cjs/bootstrap.js +0 -26
  150. package/lib/cjs/env.d.js +0 -14
  151. package/lib/cjs/getPluginModule.js +0 -39
  152. package/lib/cjs/index-federation.js +0 -55
  153. package/lib/cjs/index.js +0 -44
  154. package/lib/cjs/setup-tests.js +0 -19
  155. package/lib/cjs/test/mock-query-results.js +0 -403
  156. package/lib/cjs/time-series-chart-model.js +0 -225
  157. package/lib/cjs/utils/annotation.js +0 -37
  158. package/lib/cjs/utils/data-transform.js +0 -243
  159. package/lib/cjs/utils/palette-gen.js +0 -75
  160. package/lib/cjs/utils/palette.js +0 -83
  161. package/lib/cjs/utils/timezone-formatter.js +0 -48
  162. /package/__mf/css/async/{208.85c2cbf6.css → 463.85c2cbf6.css} +0 -0
  163. /package/__mf/js/async/{121.c3c0e54f.js.LICENSE.txt → 121.fde1320e.js.LICENSE.txt} +0 -0
  164. /package/__mf/js/async/{527.f97d1b86.js.LICENSE.txt → 182.9e1e293f.js.LICENSE.txt} +0 -0
  165. /package/__mf/js/async/{274.72dfa9c8.js.LICENSE.txt → 274.e4ed32f7.js.LICENSE.txt} +0 -0
  166. /package/__mf/js/async/{392.b9ba5bf2.js.LICENSE.txt → 392.8cb3dcaa.js.LICENSE.txt} +0 -0
  167. /package/__mf/js/async/{470.e09f33b7.js.LICENSE.txt → 470.beedcbcc.js.LICENSE.txt} +0 -0
  168. /package/__mf/js/async/{984.83bd5c6d.js.LICENSE.txt → 522.806db24f.js.LICENSE.txt} +0 -0
  169. /package/__mf/js/async/{603.3b771310.js.LICENSE.txt → 597.0c5bd6dd.js.LICENSE.txt} +0 -0
  170. /package/__mf/js/async/{702.785cd635.js.LICENSE.txt → 865.cb917066.js.LICENSE.txt} +0 -0
  171. /package/__mf/js/async/{941.b89f8595.js.LICENSE.txt → 941.3bb54150.js.LICENSE.txt} +0 -0
  172. /package/__mf/js/async/{lib-router.319c02cd.js.LICENSE.txt → lib-router.ecb51f08.js.LICENSE.txt} +0 -0
@@ -1,456 +0,0 @@
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.
13
- "use strict";
14
- Object.defineProperty(exports, "__esModule", {
15
- value: true
16
- });
17
- Object.defineProperty(exports, "TimeSeriesChartPanel", {
18
- enumerable: true,
19
- get: function() {
20
- return TimeSeriesChartPanel;
21
- }
22
- });
23
- const _jsxruntime = require("react/jsx-runtime");
24
- const _react = require("react");
25
- const _material = require("@mui/material");
26
- const _merge = /*#__PURE__*/ _interop_require_default(require("lodash/merge"));
27
- const _pluginsystem = require("@perses-dev/plugin-system");
28
- const _components = require("@perses-dev/components");
29
- const _dashboards = require("@perses-dev/dashboards");
30
- const _timeserieschartmodel = require("./time-series-chart-model");
31
- const _datatransform = require("./utils/data-transform");
32
- const _palettegen = require("./utils/palette-gen");
33
- const _TimeSeriesChartBase = require("./TimeSeriesChartBase");
34
- const _annotation = require("./utils/annotation");
35
- function _interop_require_default(obj) {
36
- return obj && obj.__esModule ? obj : {
37
- default: obj
38
- };
39
- }
40
- function TimeSeriesChartPanel(props) {
41
- const { spec: { thresholds, yAxis, tooltip, querySettings: querySettingsList }, contentDimensions, queryResults } = props;
42
- const chartsTheme = (0, _components.useChartsTheme)();
43
- const muiTheme = (0, _material.useTheme)();
44
- const chartId = (0, _components.useId)('time-series-panel');
45
- const chartRef = (0, _react.useRef)(null);
46
- // ECharts theme comes from ChartsProvider, more info: https://echarts.apache.org/en/option.html#color
47
- // Colors are manually applied since our legend and tooltip are built custom with React.
48
- const categoricalPalette = chartsTheme.echartsTheme.color;
49
- // TODO: consider refactoring how the layout/spacing/alignment are calculated
50
- // the next time significant changes are made to the time series panel (e.g.
51
- // when making improvements to the legend to more closely match designs).
52
- // This may also want to include moving some of this logic down to the shared,
53
- // embeddable components.
54
- const contentPadding = chartsTheme.container.padding.default;
55
- const adjustedContentDimensions = contentDimensions ? {
56
- width: contentDimensions.width - contentPadding * 2,
57
- height: contentDimensions.height - contentPadding * 2
58
- } : undefined;
59
- // populate default 'position' and other future properties
60
- const legend = (0, _react.useMemo)(()=>{
61
- return props.spec.legend && (0, _pluginsystem.validateLegendSpec)(props.spec.legend) ? (0, _merge.default)({}, _components.DEFAULT_LEGEND, props.spec.legend) : undefined;
62
- }, [
63
- props.spec.legend
64
- ]);
65
- // TODO: add support for y_axis_alt.format
66
- const format = props.spec.yAxis?.format ?? _timeserieschartmodel.DEFAULT_FORMAT;
67
- // ensures there are fallbacks for unset properties since most
68
- // users should not need to customize visual display
69
- const visual = (0, _react.useMemo)(()=>{
70
- return (0, _merge.default)({}, _timeserieschartmodel.DEFAULT_VISUAL, props.spec.visual);
71
- }, [
72
- props.spec.visual
73
- ]);
74
- // convert Perses dashboard format to be ECharts compatible
75
- const echartsYAxis = (0, _react.useMemo)(()=>{
76
- return (0, _datatransform.convertPanelYAxis)(yAxis);
77
- }, [
78
- yAxis
79
- ]);
80
- // Collect unique formats from query settings that differ from the base format
81
- // These will create additional Y axes on the right side
82
- const { additionalFormats, formatToYAxisIndex, seriesFormatMap } = (0, _react.useMemo)(()=>{
83
- const baseUnit = format?.unit ?? 'decimal';
84
- const additionalFormats = [];
85
- const formatToYAxisIndex = new Map();
86
- const seriesFormatMap = new Map();
87
- // Index 0 is reserved for the base Y axis
88
- formatToYAxisIndex.set(baseUnit, 0);
89
- // Collect unique formats from query settings
90
- for (const qs of querySettingsList ?? []){
91
- if (qs.format?.unit && qs.format.unit !== baseUnit) {
92
- const unitKey = qs.format.unit;
93
- if (!formatToYAxisIndex.has(unitKey)) {
94
- // Add new format - index is 1 + position in additionalFormats array
95
- formatToYAxisIndex.set(unitKey, 1 + additionalFormats.length);
96
- additionalFormats.push(qs.format);
97
- }
98
- }
99
- }
100
- return {
101
- additionalFormats,
102
- formatToYAxisIndex,
103
- seriesFormatMap
104
- };
105
- }, [
106
- format,
107
- querySettingsList
108
- ]);
109
- const [selectedLegendItems, setSelectedLegendItems] = (0, _react.useState)('ALL');
110
- const [legendSorting, setLegendSorting] = (0, _react.useState)();
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
- ]);
116
- // Populate series data based on query results
117
- const { timeScale, timeChartData, timeSeriesMapping, legendItems, seriesFormatMap: computedSeriesFormatMap, maxValuesByFormat } = (0, _react.useMemo)(()=>{
118
- const timeScale = (0, _datatransform.getCommonTimeScaleForQueries)(queryResults);
119
- if (timeScale === undefined) {
120
- return {
121
- timeChartData: [],
122
- timeSeriesMapping: [],
123
- seriesFormatMap: new Map(),
124
- maxValuesByFormat: new Map()
125
- };
126
- }
127
- const legendItems = [];
128
- // Utilizes ECharts dataset so raw data is separate from series option style properties
129
- // https://apache.github.io/echarts-handbook/en/concepts/dataset/
130
- const timeChartData = [];
131
- const timeSeriesMapping = [];
132
- // Track max values for each format unit (used for dynamic Y axis offset calculation)
133
- const maxValuesByFormat = new Map();
134
- // Index is counted across multiple queries which ensures the categorical color palette does not reset for every query
135
- let seriesIndex = 0;
136
- // Mapping of each set of query results to be ECharts option compatible
137
- // TODO: Look into performance optimizations and moving parts of mapping to the lower level chart
138
- for(let queryIndex = 0; queryIndex < queryResults.length; queryIndex++){
139
- const result = queryResults[queryIndex];
140
- // Retrieve querySettings for this query, if exists.
141
- // queries & querySettings indices do not necessarily match, so we have to check the tail value of the $ref attribute
142
- let querySettings;
143
- for (const item of querySettingsList ?? []){
144
- if (item.queryIndex === queryIndex) {
145
- querySettings = item;
146
- // We don't break the loop here just in case there are multiple querySettings defined for the
147
- // same queryIndex, because in that case we want the last one to take precedence.
148
- }
149
- }
150
- if (result) {
151
- for(let i = 0; i < result.data.series.length; i++){
152
- const timeSeries = result.data.series[i];
153
- if (timeSeries === undefined) {
154
- return {
155
- timeChartData: [],
156
- timeSeriesMapping: [],
157
- legendItems: []
158
- };
159
- }
160
- // Format is determined by seriesNameFormat in query spec
161
- const formattedSeriesName = timeSeries.formattedName ?? timeSeries.name;
162
- // Color is used for line, tooltip, and legend
163
- const seriesColor = (0, _palettegen.getSeriesColor)({
164
- // ECharts type for color is not always an array but it is always an array in ChartsProvider
165
- categoricalPalette: categoricalPalette,
166
- visual,
167
- muiPrimaryColor: muiTheme.palette.primary.main,
168
- seriesName: formattedSeriesName,
169
- seriesIndex,
170
- querySettings: querySettings,
171
- queryHasMultipleResults: (queryResults[queryIndex]?.data?.series?.length ?? 0) > 1
172
- });
173
- // We add a unique id for the chart to disambiguate items across charts
174
- // when there are multiple on the page.
175
- const seriesId = chartId + timeSeries.name + seriesIndex;
176
- const legendCalculations = legend?.values ? (0, _pluginsystem.getCalculations)(timeSeries.values, legend.values) : undefined;
177
- // When we initially load the chart, we want to show all series, but
178
- // DO NOT want to visualy highlight all the items in the legend.
179
- const isSelectAll = selectedLegendItems === 'ALL';
180
- const isSelected = !isSelectAll && !!selectedLegendItems[seriesId];
181
- const showTimeSeries = isSelected || isSelectAll;
182
- if (showTimeSeries) {
183
- // Use timeChartData.length to ensure the data that is passed into the tooltip accounts for
184
- // which legend items are selected. This must happen before timeChartData.push to avoid an
185
- // off-by-one error, seriesIndex cannot be used since it's needed to cycle through palette
186
- const datasetIndex = timeChartData.length;
187
- // Determine yAxisIndex based on the query's format setting
188
- const queryFormat = querySettings?.format;
189
- const yAxisIndex = queryFormat?.unit ? formatToYAxisIndex.get(queryFormat.unit) ?? 0 : 0;
190
- // Each series is stored as a separate dataset source.
191
- // https://apache.github.io/echarts-handbook/en/concepts/dataset/#how-to-reference-several-datasets
192
- timeSeriesMapping.push((0, _datatransform.getTimeSeries)(seriesId, datasetIndex, formattedSeriesName, visual, timeScale, seriesColor, querySettings, yAxisIndex));
193
- // Store the format for this series for tooltip formatting
194
- if (queryFormat) {
195
- seriesFormatMap.set(seriesId, queryFormat);
196
- // Track max value for this format unit (used for dynamic Y axis offset calculation)
197
- const unitKey = queryFormat.unit;
198
- if (unitKey) {
199
- const seriesMax = Math.max(...timeSeries.values.map((v)=>Math.abs(v[1] ?? 0)));
200
- const currentMax = maxValuesByFormat.get(unitKey) ?? 0;
201
- if (seriesMax > currentMax) {
202
- maxValuesByFormat.set(unitKey, seriesMax);
203
- }
204
- }
205
- }
206
- // When negativeY is set on this query, negate the rendered values so the
207
- // series renders below the X axis. The original (positive) values are
208
- // preserved in `timeSeries.values` (used for legend calculations) and in
209
- // `queryResults` (used for CSV export).
210
- const baseValues = (0, _components.getTimeSeriesValues)(timeSeries, timeScale);
211
- const renderedValues = querySettings?.negativeY ? baseValues.map((tuple)=>{
212
- const [t, v] = tuple;
213
- return [
214
- t,
215
- v === null ? null : -v
216
- ];
217
- }) : baseValues;
218
- timeChartData.push({
219
- name: formattedSeriesName,
220
- values: renderedValues
221
- });
222
- }
223
- if (legend && legendItems) {
224
- legendItems.push({
225
- id: seriesId,
226
- label: formattedSeriesName,
227
- color: seriesColor,
228
- data: legendCalculations
229
- });
230
- }
231
- // Used for repeating colors in Categorical palette
232
- seriesIndex++;
233
- }
234
- }
235
- }
236
- // map thresholds only if there is at least one time series to avoid displaying thresholds without any data
237
- if (thresholds && thresholds.steps && timeChartData.length > 0) {
238
- // Convert how thresholds are defined in the panel spec to valid ECharts 'line' series.
239
- // These are styled with predefined colors and a dashed style to look different than series from query results.
240
- // Regular series are used instead of markLines since thresholds currently show in our React TimeSeriesTooltip.
241
- const thresholdsColors = chartsTheme.thresholds;
242
- const defaultThresholdColor = thresholds.defaultColor ?? thresholdsColors.defaultColor;
243
- thresholds.steps.forEach((step, index)=>{
244
- const stepPaletteColor = thresholdsColors.palette[index] ?? defaultThresholdColor;
245
- const thresholdLineColor = step.color ?? stepPaletteColor;
246
- const stepOption = {
247
- color: thresholdLineColor,
248
- value: // yAxis is passed here since it corresponds to dashboard JSON instead of the already converted ECharts yAxis
249
- thresholds.mode === 'percent' ? (0, _datatransform.convertPercentThreshold)(step.value, timeChartData, yAxis?.max, yAxis?.min) : step.value
250
- };
251
- const thresholdName = step.name ?? `Threshold ${index + 1}`;
252
- // Generates array of [time, step.value] where time ranges from timescale.startMs to timescale.endMs with an interval of 15s
253
- const thresholdTimeValueTuple = [];
254
- let currentTimestamp = timeScale.startMs;
255
- while(currentTimestamp <= timeScale.endMs){
256
- thresholdTimeValueTuple.push([
257
- currentTimestamp,
258
- stepOption.value
259
- ]);
260
- // Used to plot fake thresholds datapoints so correct nearby threshold series shows in tooltip without flicker
261
- currentTimestamp += 1000 * _timeserieschartmodel.THRESHOLD_PLOT_INTERVAL;
262
- }
263
- timeChartData.push({
264
- name: thresholdName,
265
- values: thresholdTimeValueTuple
266
- });
267
- timeSeriesMapping.push((0, _datatransform.getThresholdSeries)(thresholdName, stepOption, seriesIndex));
268
- seriesIndex++;
269
- });
270
- }
271
- return {
272
- timeScale,
273
- timeChartData,
274
- timeSeriesMapping,
275
- legendItems,
276
- seriesFormatMap,
277
- maxValuesByFormat
278
- };
279
- }, [
280
- queryResults,
281
- thresholds,
282
- selectedLegendItems,
283
- legend,
284
- visual,
285
- querySettingsList,
286
- yAxis?.max,
287
- yAxis?.min,
288
- categoricalPalette,
289
- chartId,
290
- chartsTheme.thresholds,
291
- muiTheme.palette.primary.main,
292
- formatToYAxisIndex,
293
- seriesFormatMap
294
- ]);
295
- // Create multiple Y axes if there are additional formats
296
- // Uses max values from data to compute dynamic offsets that adapt to label widths
297
- const multipleYAxes = (0, _react.useMemo)(()=>{
298
- if (additionalFormats.length === 0) {
299
- return undefined; // Use single Y axis (default behavior)
300
- }
301
- // Build array of max values for each additional format (in order)
302
- const maxValues = additionalFormats.map((fmt)=>{
303
- const unitKey = fmt.unit;
304
- return unitKey ? maxValuesByFormat?.get(unitKey) ?? 1000 : 1000;
305
- });
306
- return (0, _components.getFormattedMultipleYAxes)(echartsYAxis, format, additionalFormats, maxValues);
307
- }, [
308
- echartsYAxis,
309
- format,
310
- additionalFormats,
311
- maxValuesByFormat
312
- ]);
313
- // Translate the legend values into columns for the table legend.
314
- const legendColumns = (0, _react.useMemo)(()=>{
315
- if (!legend?.values) {
316
- return [];
317
- }
318
- // Iterating the predefined list of possible values to retain a specific
319
- // intended order of values.
320
- return _pluginsystem.legendValues.reduce((columns, legendValue)=>{
321
- const legendConfig = _pluginsystem.LEGEND_VALUE_CONFIG[legendValue];
322
- if (legendConfig && legend?.values?.includes(legendValue)) {
323
- columns.push({
324
- accessorKey: `data.${legendValue}`,
325
- header: legendConfig.label,
326
- headerDescription: legendConfig.description,
327
- // Intentionally hardcoding a column width to start based on discussions
328
- // with design around keeping this simple to start. This may need
329
- // revisiting in the future to handle edge cases with very large values.
330
- width: 72,
331
- align: 'right',
332
- cell: ({ getValue })=>{
333
- const cellValue = getValue();
334
- return typeof cellValue === 'number' && format ? (0, _components.formatValue)(cellValue, format) : cellValue;
335
- },
336
- cellDescription: true,
337
- enableSorting: true
338
- });
339
- }
340
- return columns;
341
- }, []);
342
- }, [
343
- legend?.values,
344
- format
345
- ]);
346
- const gridOverrides = (0, _react.useMemo)(()=>{
347
- // When Y axes are hidden, disable containLabel to prevent auto-spacing, but add bottom padding for X axis
348
- return echartsYAxis.show === false ? {
349
- left: 0,
350
- right: 0,
351
- bottom: 30,
352
- containLabel: false
353
- } : {
354
- left: yAxis && yAxis.label ? 30 : 20,
355
- // With containLabel: true in theme, ECharts auto-reserves space for axis labels.
356
- // For multiple right axes, add extra padding for the last axis labels that extend beyond the grid.
357
- right: additionalFormats.length > 0 ? 10 : 20,
358
- bottom: 0,
359
- containLabel: true
360
- };
361
- }, [
362
- echartsYAxis.show,
363
- yAxis,
364
- additionalFormats.length
365
- ]);
366
- if (adjustedContentDimensions === undefined) {
367
- return null;
368
- }
369
- const handleDataZoom = (event)=>{
370
- // TODO: add ECharts transition animation on zoom
371
- setTimeRange({
372
- start: new Date(event.start),
373
- end: new Date(event.end)
374
- });
375
- };
376
- // Used to opt in to ECharts trigger item which show subgroup data accurately.
377
- // Derived from the actual series mapping rather than `visual.stack` alone so that
378
- // bar charts stacked only via per-query overrides also use the right tooltip mode.
379
- const isStackedBar = visual.display === 'bar' && timeSeriesMapping.some((s)=>s?.type === 'bar' && s.stack === 'all');
380
- // Turn on tooltip pinning by default but opt out for stacked bar or if explicitly set in tooltip panel spec
381
- let enablePinning = true;
382
- if (isStackedBar) {
383
- enablePinning = false;
384
- } else if (tooltip?.enablePinning !== undefined) {
385
- enablePinning = tooltip.enablePinning;
386
- }
387
- const tooltipConfig = {
388
- ..._components.DEFAULT_TOOLTIP_CONFIG,
389
- enablePinning
390
- };
391
- return /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Box, {
392
- sx: {
393
- padding: `${contentPadding}px`
394
- },
395
- children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.ContentWithLegend, {
396
- width: adjustedContentDimensions.width,
397
- height: adjustedContentDimensions.height,
398
- // Making this small enough that the medium size doesn't get
399
- // responsive-handling-ed away when in the panel options editor.
400
- minChildrenHeight: 50,
401
- legendSize: legend?.size,
402
- legendProps: legend && {
403
- options: legend,
404
- data: legendItems || [],
405
- selectedItems: selectedLegendItems,
406
- onSelectedItemsChange: setSelectedLegendItems,
407
- tableProps: {
408
- columns: legendColumns,
409
- sorting: legendSorting,
410
- onSortingChange: setLegendSorting
411
- },
412
- onItemMouseOver: (e, { id })=>{
413
- chartRef.current?.highlightSeries({
414
- name: id
415
- });
416
- },
417
- onItemMouseOut: ()=>{
418
- chartRef.current?.clearHighlightedSeries();
419
- }
420
- },
421
- children: ({ height, width })=>{
422
- return /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Box, {
423
- style: {
424
- height,
425
- width
426
- },
427
- children: [
428
- yAxis && yAxis.show && yAxis.label && /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.YAxisLabel, {
429
- name: yAxis.label,
430
- height: height
431
- }),
432
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_TimeSeriesChartBase.TimeSeriesChartBase, {
433
- ref: chartRef,
434
- height: height,
435
- data: timeChartData,
436
- seriesMapping: timeSeriesMapping,
437
- annotations: annotations,
438
- timeScale: timeScale,
439
- yAxis: multipleYAxes ?? echartsYAxis,
440
- format: format,
441
- seriesFormatMap: computedSeriesFormatMap,
442
- grid: gridOverrides,
443
- isStackedBar: isStackedBar,
444
- tooltipConfig: tooltipConfig,
445
- syncGroup: "default-panel-group",
446
- onDataZoom: handleDataZoom,
447
- // Show an empty chart when there is no data because the user unselected all items in
448
- // the legend. Otherwise, show a "no data" message.
449
- noDataVariant: !timeChartData.length && legendItems && legendItems.length > 0 ? 'chart' : 'message'
450
- })
451
- ]
452
- });
453
- }
454
- })
455
- });
456
- }
@@ -1,124 +0,0 @@
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.
13
- "use strict";
14
- Object.defineProperty(exports, "__esModule", {
15
- value: true
16
- });
17
- Object.defineProperty(exports, "TimeSeriesExportAction", {
18
- enumerable: true,
19
- get: function() {
20
- return TimeSeriesExportAction;
21
- }
22
- });
23
- const _jsxruntime = require("react/jsx-runtime");
24
- const _material = require("@mui/material");
25
- const _components = require("@perses-dev/components");
26
- const _Download = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/Download"));
27
- const _react = /*#__PURE__*/ _interop_require_wildcard(require("react"));
28
- const _pluginsystem = require("@perses-dev/plugin-system");
29
- function _interop_require_default(obj) {
30
- return obj && obj.__esModule ? obj : {
31
- default: obj
32
- };
33
- }
34
- function _getRequireWildcardCache(nodeInterop) {
35
- if (typeof WeakMap !== "function") return null;
36
- var cacheBabelInterop = new WeakMap();
37
- var cacheNodeInterop = new WeakMap();
38
- return (_getRequireWildcardCache = function(nodeInterop) {
39
- return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
40
- })(nodeInterop);
41
- }
42
- function _interop_require_wildcard(obj, nodeInterop) {
43
- if (!nodeInterop && obj && obj.__esModule) {
44
- return obj;
45
- }
46
- if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
47
- return {
48
- default: obj
49
- };
50
- }
51
- var cache = _getRequireWildcardCache(nodeInterop);
52
- if (cache && cache.has(obj)) {
53
- return cache.get(obj);
54
- }
55
- var newObj = {
56
- __proto__: null
57
- };
58
- var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
59
- for(var key in obj){
60
- if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
61
- var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
62
- if (desc && (desc.get || desc.set)) {
63
- Object.defineProperty(newObj, key, desc);
64
- } else {
65
- newObj[key] = obj[key];
66
- }
67
- }
68
- }
69
- newObj.default = obj;
70
- if (cache) {
71
- cache.set(obj, newObj);
72
- }
73
- return newObj;
74
- }
75
- const TimeSeriesExportAction = ({ queryResults, definition })=>{
76
- const exportableData = (0, _react.useMemo)(()=>{
77
- return (0, _pluginsystem.extractExportableData)(queryResults);
78
- }, [
79
- queryResults
80
- ]);
81
- const canExport = (0, _react.useMemo)(()=>{
82
- return (0, _pluginsystem.isExportableData)(exportableData);
83
- }, [
84
- exportableData
85
- ]);
86
- const handleExport = (0, _react.useCallback)(()=>{
87
- if (!exportableData || !canExport) return;
88
- try {
89
- const title = definition?.spec?.display?.name || 'Time Series Data';
90
- const csvBlob = (0, _pluginsystem.exportDataAsCSV)({
91
- data: exportableData
92
- });
93
- const baseFilename = (0, _pluginsystem.sanitizeFilename)(title);
94
- const filename = `${baseFilename}_data.csv`;
95
- const link = document.createElement('a');
96
- link.href = URL.createObjectURL(csvBlob);
97
- link.download = filename;
98
- document.body.appendChild(link);
99
- link.click();
100
- document.body.removeChild(link);
101
- URL.revokeObjectURL(link.href);
102
- } catch (error) {
103
- console.error('Time series export failed:', error);
104
- }
105
- }, [
106
- exportableData,
107
- canExport,
108
- definition
109
- ]);
110
- if (!canExport) {
111
- return null;
112
- }
113
- return /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.InfoTooltip, {
114
- description: "Export as CSV",
115
- children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.IconButton, {
116
- size: "small",
117
- onClick: handleExport,
118
- "aria-label": "Export time series data as CSV",
119
- children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_Download.default, {
120
- fontSize: "inherit"
121
- })
122
- })
123
- });
124
- };