@iotready/nextjs-components-library 1.0.0-preview4 → 1.0.0-preview41
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/assets/translations/en.json +92 -0
- package/assets/translations/index.d.ts +95 -0
- package/assets/translations/index.js +4 -0
- package/assets/translations/it.json +92 -0
- package/assets/translations/scripts/export.js +74 -0
- package/assets/translations/scripts/import.js +66 -0
- package/components/accounts/AccountMenu.d.ts +2 -1
- package/components/accounts/AccountMenu.js +2 -2
- package/components/accounts/AccountProfile.d.ts +2 -1
- package/components/accounts/AccountProfile.js +15 -15
- package/components/charts/TrendChart.d.ts +28 -6
- package/components/charts/TrendChart.js +555 -149
- package/components/groups/GroupUpdate.d.ts +9 -10
- package/components/groups/GroupUpdate.js +21 -38
- package/components/groups/GroupsDevices.d.ts +22 -17
- package/components/groups/GroupsDevices.js +165 -110
- package/components/groups/Map.d.ts +5 -9
- package/components/groups/Map.js +2 -2
- package/components/settings/DynamicMenu.d.ts +1 -0
- package/components/settings/DynamicMenu.js +2 -1
- package/components/users/UserUpdate.d.ts +2 -1
- package/components/users/UserUpdate.js +2 -2
- package/components/users/UsersDataGrid.d.ts +11 -3
- package/components/users/UsersDataGrid.js +49 -32
- package/package.json +8 -4
- package/server-actions/annotations.d.ts +4 -0
- package/server-actions/annotations.js +12 -0
- package/server-actions/groups.d.ts +16 -16
- package/server-actions/groups.js +157 -72
- package/server-actions/index.d.ts +1 -0
- package/server-actions/index.js +1 -0
- package/server-actions/influx.d.ts +17 -13
- package/server-actions/influx.js +207 -98
- package/server-actions/trackle.d.ts +10 -4
- package/server-actions/trackle.js +59 -38
- package/server-actions/types.d.ts +16 -0
- package/server-actions/types.js +6 -0
- package/types/device.d.ts +19 -0
- package/types/device.js +1 -0
- package/types/index.d.ts +1 -0
- package/types/index.js +1 -0
- package/types/user.d.ts +2 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import { useState, useEffect, useRef } from 'react';
|
|
4
4
|
import { Line } from 'react-chartjs-2';
|
|
5
|
-
import { Chart as ChartJS, Colors, Title, LinearScale, Legend, Tooltip, TimeScale, PointElement, LineElement } from 'chart.js';
|
|
5
|
+
import { Chart as ChartJS, Colors, Title, LinearScale, Legend, Tooltip, TimeScale, PointElement, LineElement, Interaction } from 'chart.js';
|
|
6
6
|
import annotationPlugin from 'chartjs-plugin-annotation';
|
|
7
7
|
import 'chartjs-adapter-moment';
|
|
8
8
|
import { ToggleButtonGroup, ToggleButton, Box, Button, Typography } from "@mui/material";
|
|
@@ -20,24 +20,173 @@ import { AdapterMoment } from '@mui/x-date-pickers/AdapterMoment';
|
|
|
20
20
|
import { ThemeProvider } from '@mui/material/styles';
|
|
21
21
|
import TimelineIcon from '@mui/icons-material/Timeline';
|
|
22
22
|
import MuiTooltip from '@mui/material/Tooltip';
|
|
23
|
+
import EditNoteIcon from '@mui/icons-material/EditNote';
|
|
24
|
+
// import AspectRatioIcon from '@mui/icons-material/AspectRatio';
|
|
25
|
+
import { FilterTagMode } from '../../server-actions/types';
|
|
26
|
+
import { getRelativePosition } from 'chart.js/helpers';
|
|
27
|
+
import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight';
|
|
28
|
+
import KeyboardArrowLeftIcon from '@mui/icons-material/KeyboardArrowLeft';
|
|
29
|
+
function findIndexForX(arr, t) {
|
|
30
|
+
if (!arr || arr.length === 0)
|
|
31
|
+
return -1;
|
|
32
|
+
if (t <= arr[0].x)
|
|
33
|
+
return 0;
|
|
34
|
+
let lo = 0;
|
|
35
|
+
let hi = arr.length - 1;
|
|
36
|
+
let res = -1;
|
|
37
|
+
while (lo <= hi) {
|
|
38
|
+
const mid = Math.floor((lo + hi) / 2);
|
|
39
|
+
const midX = arr[mid]?.x;
|
|
40
|
+
if (midX === undefined)
|
|
41
|
+
return -1;
|
|
42
|
+
if (midX === t)
|
|
43
|
+
return mid;
|
|
44
|
+
if (midX < t) {
|
|
45
|
+
res = mid;
|
|
46
|
+
lo = mid + 1;
|
|
47
|
+
}
|
|
48
|
+
else
|
|
49
|
+
hi = mid - 1;
|
|
50
|
+
}
|
|
51
|
+
return res;
|
|
52
|
+
}
|
|
53
|
+
// @ts-ignore
|
|
54
|
+
Tooltip.positioners.myCustomPositioner = function (elements, eventPosition) {
|
|
55
|
+
const chart = this.chart;
|
|
56
|
+
const activePos = chart.__activePos;
|
|
57
|
+
if (!activePos || !activePos.closestPoint) {
|
|
58
|
+
return { x: eventPosition.x, y: eventPosition.y };
|
|
59
|
+
}
|
|
60
|
+
const closest = activePos.closestPoint.element;
|
|
61
|
+
const pixelX = activePos.closestPoint.pixelX;
|
|
62
|
+
const pixelY = closest?.y ?? eventPosition.y;
|
|
63
|
+
return { x: pixelX, y: pixelY };
|
|
64
|
+
};
|
|
65
|
+
// Definisci la modalità solo se Interaction è disponibile
|
|
66
|
+
if (Interaction && Interaction.modes) {
|
|
67
|
+
// @ts-ignore
|
|
68
|
+
Interaction.modes.myCustomMode = function (chart, e, options, useFinalPosition) {
|
|
69
|
+
const pos = getRelativePosition(e, chart);
|
|
70
|
+
const xScale = chart.scales?.x;
|
|
71
|
+
const hoveredX = xScale && typeof xScale.getValueForPixel === "function"
|
|
72
|
+
? xScale.getValueForPixel(pos.x)
|
|
73
|
+
: null;
|
|
74
|
+
const items = [];
|
|
75
|
+
let closestPoint = null;
|
|
76
|
+
let closestDistance = Infinity;
|
|
77
|
+
for (let datasetIndex = 0; datasetIndex < chart.data.datasets.length; datasetIndex++) {
|
|
78
|
+
const meta = chart.getDatasetMeta(datasetIndex);
|
|
79
|
+
if (!meta || !meta.data || meta.data.length === 0)
|
|
80
|
+
continue;
|
|
81
|
+
let found = null;
|
|
82
|
+
let pointPixelX = null;
|
|
83
|
+
for (let i = 0; i < meta.data.length; i++) {
|
|
84
|
+
const el = meta.data[i];
|
|
85
|
+
if (el && typeof el.inXRange === "function" && el.inXRange(pos.x, useFinalPosition)) {
|
|
86
|
+
found = { element: el, datasetIndex, index: i };
|
|
87
|
+
pointPixelX = el.x;
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (!found && hoveredX != null) {
|
|
92
|
+
const dataArr = chart.data.datasets[datasetIndex]?.data || [];
|
|
93
|
+
const idx = findIndexForX(dataArr, hoveredX);
|
|
94
|
+
if (idx >= 0 && meta.data[idx]) {
|
|
95
|
+
found = { element: meta.data[idx], datasetIndex, index: idx };
|
|
96
|
+
const valX = dataArr[idx].x;
|
|
97
|
+
pointPixelX = xScale.getPixelForValue(valX);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (found && pointPixelX != null) {
|
|
101
|
+
items.push(found);
|
|
102
|
+
const xMin = xScale?.left ?? 0;
|
|
103
|
+
const xMax = xScale?.right ?? chart.width;
|
|
104
|
+
console.log({ pointPixelX, xMin, xMax });
|
|
105
|
+
if (pointPixelX < xMin || pointPixelX > xMax) {
|
|
106
|
+
continue; // ignora questo punto
|
|
107
|
+
}
|
|
108
|
+
// Aggiorna il closestPoint globale per la barra verticale
|
|
109
|
+
const distance = Math.abs(pointPixelX - pos.x);
|
|
110
|
+
if (distance < closestDistance) {
|
|
111
|
+
closestDistance = distance;
|
|
112
|
+
closestPoint = { ...found, pixelX: pointPixelX };
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
chart.__activePos = hoveredX != null
|
|
117
|
+
? {
|
|
118
|
+
value: hoveredX,
|
|
119
|
+
px: closestPoint ? closestPoint.pixelX : pos.x,
|
|
120
|
+
hasPoint: !!closestPoint
|
|
121
|
+
}
|
|
122
|
+
: null;
|
|
123
|
+
return items;
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function getValueAtX(datasetData, t) {
|
|
127
|
+
if (!datasetData || datasetData.length === 0)
|
|
128
|
+
return null;
|
|
129
|
+
// se t è prima del primo punto -> primo valore
|
|
130
|
+
if (t <= datasetData[0].x)
|
|
131
|
+
return datasetData[0].y;
|
|
132
|
+
// binary search per ultimo index con x <= t
|
|
133
|
+
let lo = 0;
|
|
134
|
+
let hi = datasetData.length - 1;
|
|
135
|
+
let res = -1;
|
|
136
|
+
while (lo <= hi) {
|
|
137
|
+
const mid = (lo + hi) >> 1;
|
|
138
|
+
const midX = datasetData[mid].x;
|
|
139
|
+
if (midX <= t) {
|
|
140
|
+
res = mid;
|
|
141
|
+
lo = mid + 1;
|
|
142
|
+
}
|
|
143
|
+
else
|
|
144
|
+
hi = mid - 1;
|
|
145
|
+
}
|
|
146
|
+
return res >= 0 ? datasetData[res].y : null;
|
|
147
|
+
}
|
|
23
148
|
const lineOptions = {
|
|
24
149
|
parsing: false,
|
|
25
150
|
normalized: true,
|
|
26
|
-
spanGaps:
|
|
151
|
+
spanGaps: true, // enable for all datasets
|
|
27
152
|
// showLine: false, // disable for all datasets
|
|
28
153
|
animation: false,
|
|
29
154
|
responsive: true,
|
|
30
155
|
maintainAspectRatio: false,
|
|
31
156
|
interaction: {
|
|
32
157
|
intersect: false,
|
|
33
|
-
mode: '
|
|
158
|
+
mode: 'myCustomMode',
|
|
34
159
|
axis: 'x'
|
|
35
160
|
},
|
|
36
161
|
plugins: {
|
|
37
162
|
tooltip: {
|
|
163
|
+
position: 'myCustomPositioner',
|
|
38
164
|
callbacks: {
|
|
39
165
|
label: (context) => {
|
|
40
|
-
|
|
166
|
+
const ds = context.dataset || {};
|
|
167
|
+
const parsed = context.parsed || {};
|
|
168
|
+
const unit = ds.unit ?? '';
|
|
169
|
+
const chart = context.chart;
|
|
170
|
+
// 1) se parsed.y è disponibile usalo (gestisci stepped senza toFixed)
|
|
171
|
+
if (parsed.y !== null && parsed.y !== undefined) {
|
|
172
|
+
// se la serie è stepped vogliamo mostrare il valore grezzo (es. 1/0)
|
|
173
|
+
if (ds.stepped)
|
|
174
|
+
return `${ds.label}: ${parsed.y} ${unit}`;
|
|
175
|
+
// numero normale -> 3 decimali
|
|
176
|
+
return `${ds.label}: ${Number(parsed.y).toFixed(3)} ${unit}`;
|
|
177
|
+
}
|
|
178
|
+
// 2) fallback: usa parsed.x o context.parsed.x per calcolare il valore via getValueAtX
|
|
179
|
+
const xVal = parsed.x ?? (context.parsed && context.parsed.x) ?? null;
|
|
180
|
+
if (xVal != null && Array.isArray(ds.data)) {
|
|
181
|
+
const val = getValueAtX(ds.data, xVal);
|
|
182
|
+
if (val !== null && val !== undefined) {
|
|
183
|
+
if (ds.stepped)
|
|
184
|
+
return `${ds.label}: ${val} ${unit}`;
|
|
185
|
+
return `${ds.label}: ${Number(val).toFixed(3)} ${unit}`;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
// 3) fallback finale
|
|
189
|
+
return `${ds.label}: - ${unit}`;
|
|
41
190
|
}
|
|
42
191
|
},
|
|
43
192
|
},
|
|
@@ -64,7 +213,19 @@ const lineOptions = {
|
|
|
64
213
|
day: 'DD MMM YY',
|
|
65
214
|
hour: 'DD MMM HH:mm',
|
|
66
215
|
minute: 'HH:mm'
|
|
67
|
-
}
|
|
216
|
+
},
|
|
217
|
+
y1: {
|
|
218
|
+
type: 'linear',
|
|
219
|
+
position: 'left',
|
|
220
|
+
title: { display: false, text: 'Primary Axis' },
|
|
221
|
+
display: false
|
|
222
|
+
},
|
|
223
|
+
y2: {
|
|
224
|
+
type: 'linear',
|
|
225
|
+
position: 'right',
|
|
226
|
+
title: { display: false, text: 'Secondary Axis' },
|
|
227
|
+
display: false
|
|
228
|
+
},
|
|
68
229
|
},
|
|
69
230
|
title: {
|
|
70
231
|
display: false,
|
|
@@ -76,15 +237,6 @@ const lineOptions = {
|
|
|
76
237
|
drawOnChartArea: false,
|
|
77
238
|
}
|
|
78
239
|
},
|
|
79
|
-
y: {
|
|
80
|
-
ticks: {
|
|
81
|
-
callback: function (value) {
|
|
82
|
-
if (Math.floor(value) === value) {
|
|
83
|
-
return value;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
},
|
|
88
240
|
},
|
|
89
241
|
};
|
|
90
242
|
const chartConfigByPeriod = {
|
|
@@ -121,15 +273,6 @@ const chartConfigByPeriod = {
|
|
|
121
273
|
scaleUnit: 'year',
|
|
122
274
|
}
|
|
123
275
|
};
|
|
124
|
-
function GetPoints(data) {
|
|
125
|
-
const points = data.results[0].series[0].values.map((row) => {
|
|
126
|
-
return {
|
|
127
|
-
x: moment.unix(row[0]),
|
|
128
|
-
y: row[1]
|
|
129
|
-
};
|
|
130
|
-
});
|
|
131
|
-
return points;
|
|
132
|
-
}
|
|
133
276
|
function getPollTime(intervalInSeconds, pollTime) {
|
|
134
277
|
const CalculatedPollTime = Math.round(intervalInSeconds / 2880);
|
|
135
278
|
if (CalculatedPollTime <= pollTime) {
|
|
@@ -140,65 +283,76 @@ function getPollTime(intervalInSeconds, pollTime) {
|
|
|
140
283
|
}
|
|
141
284
|
}
|
|
142
285
|
function getCsvData(data, measures) {
|
|
143
|
-
//
|
|
144
|
-
const headers = [
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
286
|
+
// Intestazioni CSV
|
|
287
|
+
const headers = [
|
|
288
|
+
'timestamp',
|
|
289
|
+
...measures.map(m => m.description || m.name)
|
|
290
|
+
];
|
|
291
|
+
const csvRows = [headers];
|
|
292
|
+
// Mappa temporale: ISO string → { timestamp, [measureName]: value, … }
|
|
149
293
|
const timestampMap = {};
|
|
150
|
-
//
|
|
151
|
-
data.forEach((
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
});
|
|
294
|
+
// Ogni serie corrisponde a measures[index]
|
|
295
|
+
data.forEach((series, index) => {
|
|
296
|
+
const measure = measures[index];
|
|
297
|
+
if (!measure)
|
|
298
|
+
return; // difesa su mismatch lunghezze
|
|
299
|
+
series.forEach(point => {
|
|
300
|
+
// usa moment per coerenza con prima versione
|
|
301
|
+
const ts = moment(point.x).toISOString();
|
|
302
|
+
if (!timestampMap[ts]) {
|
|
303
|
+
timestampMap[ts] = { timestamp: ts };
|
|
304
|
+
}
|
|
305
|
+
timestampMap[ts][measure.name] = point.y;
|
|
163
306
|
});
|
|
164
307
|
});
|
|
165
|
-
//
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
308
|
+
// Ordina i timestamp
|
|
309
|
+
const sortedTs = Object.keys(timestampMap)
|
|
310
|
+
.sort((a, b) => new Date(a).getTime() - new Date(b).getTime());
|
|
311
|
+
// Costruisci le righe CSV
|
|
312
|
+
sortedTs.forEach(ts => {
|
|
313
|
+
const entry = timestampMap[ts];
|
|
314
|
+
// prima colonna timestamp, poi i valori nelle colonne in ordine measures[]
|
|
170
315
|
const row = [entry.timestamp];
|
|
171
|
-
measures.forEach(
|
|
172
|
-
|
|
173
|
-
|
|
316
|
+
measures.forEach(m => {
|
|
317
|
+
row.push(entry[m.name] !== undefined
|
|
318
|
+
? entry[m.name]
|
|
319
|
+
: '');
|
|
174
320
|
});
|
|
175
|
-
//
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
csvData.push(row);
|
|
321
|
+
// optional: filtra le righe che non hanno alcun valore utile
|
|
322
|
+
const hasValue = row.slice(1).some(v => v !== '' && v !== null);
|
|
323
|
+
if (hasValue) {
|
|
324
|
+
csvRows.push(row);
|
|
180
325
|
}
|
|
181
326
|
});
|
|
182
|
-
//
|
|
183
|
-
return
|
|
327
|
+
// Unisci in stringa
|
|
328
|
+
return csvRows
|
|
329
|
+
.map(r => r.join(','))
|
|
330
|
+
.join('\n');
|
|
184
331
|
}
|
|
185
332
|
// eslint-disable-next-line no-unused-vars
|
|
186
|
-
const TrendChart = ({
|
|
333
|
+
const TrendChart = ({ filter, measures1, annotationsDataFn, measures2, enableDatePicker, handleGetInfluxData, handleGetDwSlotsCB, handleExportDataCB, theme, initialTimeStart, initialTimeEnd, t }) => {
|
|
187
334
|
const [chartJsLoaded, setChartJsLoaded] = useState(false);
|
|
335
|
+
// Dichiarazione di annotationsData come funzione che ritorna una Promise<any>
|
|
336
|
+
const [annotationsData, setAnnotationsData] = useState(null);
|
|
337
|
+
const [annotationsEnabled, setAnnotationsEnabled] = useState(true);
|
|
188
338
|
const [dataMeasures, setDataMeasures] = useState(null);
|
|
189
339
|
const [chartPeriod, setChartPeriod] = useState('1D');
|
|
190
340
|
const [chartPeriodConfig, setChartPeriodConfig] = useState(chartConfigByPeriod['1D']);
|
|
191
341
|
const [chartLoading, setChartLoading] = useState(false);
|
|
192
|
-
const [timeStartPicker, setTimeStartPicker] = useState(moment().subtract(1, 'day').unix());
|
|
193
|
-
const [timeStart, setTimeStart] = useState(moment().subtract(1, 'day').unix());
|
|
194
|
-
const [timeEnd, setTimeEnd] = useState(moment().unix());
|
|
195
|
-
const [datePickerUsed, setDatePickerUsed] = useState(false);
|
|
196
|
-
const [pickerTimeStart, setPickerTimeStart] = useState(moment().subtract(1, 'day').unix());
|
|
197
|
-
const [pickerTimeEnd, setPickerTimeEnd] = useState(moment().unix());
|
|
342
|
+
const [timeStartPicker, setTimeStartPicker] = useState(initialTimeStart || moment().subtract(1, 'day').unix());
|
|
343
|
+
const [timeStart, setTimeStart] = useState(initialTimeStart || moment().subtract(1, 'day').unix());
|
|
344
|
+
const [timeEnd, setTimeEnd] = useState(initialTimeEnd || moment().unix());
|
|
345
|
+
const [datePickerUsed, setDatePickerUsed] = useState(initialTimeStart || initialTimeEnd ? true : false);
|
|
346
|
+
const [pickerTimeStart, setPickerTimeStart] = useState(initialTimeStart || moment().subtract(1, 'day').unix());
|
|
347
|
+
const [pickerTimeEnd, setPickerTimeEnd] = useState(initialTimeEnd || moment().unix());
|
|
198
348
|
const [loadingButton, setLoadingButton] = useState(false);
|
|
199
349
|
const csvLinkRef = useRef(null);
|
|
200
350
|
const [csvData, setCsvData] = useState('');
|
|
201
|
-
const [spanGapsOption, setSpanGapsOption] = useState(
|
|
351
|
+
const [spanGapsOption, setSpanGapsOption] = useState(true);
|
|
352
|
+
const enableExportData = handleExportDataCB ? true : false;
|
|
353
|
+
const measures = measures1 && measures2 ? [...measures1, ...measures2] :
|
|
354
|
+
measures1 ? [...measures1] :
|
|
355
|
+
measures2 ? [...measures2] : [];
|
|
202
356
|
const [options, setOptions] = useState({
|
|
203
357
|
...lineOptions,
|
|
204
358
|
plugins: {
|
|
@@ -222,13 +376,19 @@ const TrendChart = ({ deviceId, measures, enableExportData, enableDatePicker, ha
|
|
|
222
376
|
}
|
|
223
377
|
});
|
|
224
378
|
const [zoomed, setZoomed] = useState(false);
|
|
379
|
+
const prevMeasures = useRef();
|
|
225
380
|
const resetChart = () => {
|
|
226
381
|
setOptions({
|
|
227
382
|
...options,
|
|
228
383
|
scales: {
|
|
229
384
|
...options.scales,
|
|
230
|
-
|
|
231
|
-
...options.scales.
|
|
385
|
+
y1: {
|
|
386
|
+
...options.scales.y1,
|
|
387
|
+
min: 0,
|
|
388
|
+
max: 1
|
|
389
|
+
},
|
|
390
|
+
y2: {
|
|
391
|
+
...options.scales.y2,
|
|
232
392
|
min: 0,
|
|
233
393
|
max: 1
|
|
234
394
|
}
|
|
@@ -245,61 +405,141 @@ const TrendChart = ({ deviceId, measures, enableExportData, enableDatePicker, ha
|
|
|
245
405
|
setSpanGapsOption(spanG);
|
|
246
406
|
};
|
|
247
407
|
const handleChange = (event, newPeriod) => {
|
|
248
|
-
|
|
249
|
-
setDatePickerUsed(false);
|
|
250
|
-
setCsvData('');
|
|
251
|
-
if (newPeriod === "ALL") {
|
|
252
|
-
setTimeStart(1577854800);
|
|
253
|
-
setTimeEnd(moment().unix());
|
|
254
|
-
setChartPeriod(newPeriod);
|
|
408
|
+
if (newPeriod == null) {
|
|
255
409
|
return;
|
|
256
410
|
}
|
|
257
|
-
|
|
258
|
-
|
|
411
|
+
if (chartPeriod === newPeriod) {
|
|
412
|
+
setChartLoading(true);
|
|
413
|
+
setZoomed(false);
|
|
414
|
+
setDatePickerUsed(false);
|
|
415
|
+
setCsvData('');
|
|
416
|
+
const periodConfig = chartConfigByPeriod[chartPeriod];
|
|
259
417
|
setTimeStart(Math.round(moment().subtract(periodConfig.from).valueOf() / 1000));
|
|
260
418
|
setTimeEnd(Math.round(moment().valueOf() / 1000));
|
|
261
|
-
setChartPeriod(
|
|
419
|
+
setChartPeriod(chartPeriod);
|
|
262
420
|
setChartPeriodConfig(periodConfig);
|
|
263
421
|
}
|
|
422
|
+
if (newPeriod && newPeriod !== chartPeriod) {
|
|
423
|
+
setChartLoading(true);
|
|
424
|
+
setZoomed(false);
|
|
425
|
+
setDatePickerUsed(false);
|
|
426
|
+
setCsvData('');
|
|
427
|
+
if (newPeriod === "ALL") {
|
|
428
|
+
setTimeStart(1577854800);
|
|
429
|
+
setTimeEnd(moment().unix());
|
|
430
|
+
setChartPeriod(newPeriod);
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
const periodConfig = chartConfigByPeriod[newPeriod];
|
|
434
|
+
if (periodConfig) {
|
|
435
|
+
setTimeStart(Math.round(moment().subtract(periodConfig.from).valueOf() / 1000));
|
|
436
|
+
setTimeEnd(Math.round(moment().valueOf() / 1000));
|
|
437
|
+
setChartPeriod(newPeriod);
|
|
438
|
+
setChartPeriodConfig(periodConfig);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
264
441
|
};
|
|
265
442
|
const handleExportData = async () => {
|
|
266
443
|
setLoadingButton(true);
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
444
|
+
if (handleExportDataCB) {
|
|
445
|
+
const data = await Promise.all(measures.map(async (measure) => {
|
|
446
|
+
return await handleExportDataCB(measure.name, timeStart, timeEnd, filter);
|
|
447
|
+
}));
|
|
448
|
+
const csvData = getCsvData(data, measures);
|
|
449
|
+
setCsvData(csvData);
|
|
450
|
+
setLoadingButton(false);
|
|
451
|
+
}
|
|
273
452
|
};
|
|
274
453
|
useEffect(() => {
|
|
275
454
|
if (csvData.length > 0) {
|
|
276
455
|
csvLinkRef.current?.link.click();
|
|
277
456
|
}
|
|
278
457
|
}, [csvData]);
|
|
458
|
+
useEffect(() => {
|
|
459
|
+
if (annotationsDataFn && annotationsEnabled) {
|
|
460
|
+
(async () => {
|
|
461
|
+
const resp = await annotationsDataFn();
|
|
462
|
+
setAnnotationsData(resp);
|
|
463
|
+
})();
|
|
464
|
+
}
|
|
465
|
+
}, [annotationsDataFn, annotationsEnabled]);
|
|
466
|
+
function getDwSlotsFromValues(dwValues) {
|
|
467
|
+
const slots = [];
|
|
468
|
+
let start = null;
|
|
469
|
+
for (const point of dwValues) {
|
|
470
|
+
if (point.y === 1 && start === null) {
|
|
471
|
+
start = point.x;
|
|
472
|
+
}
|
|
473
|
+
if (point.y === 0 && start !== null) {
|
|
474
|
+
slots.push({ start, end: point.x });
|
|
475
|
+
start = null;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
return slots;
|
|
479
|
+
}
|
|
279
480
|
const loadDatasets = async (chartPeriod) => {
|
|
280
|
-
|
|
281
|
-
const
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
const
|
|
285
|
-
|
|
286
|
-
|
|
481
|
+
let intervalInSeconds = chartPeriod === "ALL" && !datePickerUsed && !zoomed ? 31536000 : timeEnd - timeStart;
|
|
482
|
+
const rawQuery = intervalInSeconds < 86400;
|
|
483
|
+
let tempSlots = [];
|
|
484
|
+
if (handleGetDwSlotsCB) {
|
|
485
|
+
const dwValues = await handleGetDwSlotsCB(timeStart, timeEnd, filter);
|
|
486
|
+
tempSlots = getDwSlotsFromValues(dwValues);
|
|
487
|
+
}
|
|
488
|
+
// Combine measures and track their source
|
|
489
|
+
const allMeasures = [
|
|
490
|
+
...(measures1?.map(m => ({ ...m, source: 'measures1' })) || []),
|
|
491
|
+
...(measures2?.map(m => ({ ...m, source: 'measures2' })) || [])
|
|
492
|
+
];
|
|
493
|
+
const datasetsPromises = allMeasures.map(async (measure) => {
|
|
494
|
+
const polltime = getPollTime(intervalInSeconds, measure.polltime || 30);
|
|
495
|
+
let dwPoints = [];
|
|
496
|
+
let dwSlots = [];
|
|
497
|
+
if (measure.dwPolltime) {
|
|
498
|
+
const dwPolltime = getPollTime(intervalInSeconds, measure.dwPolltime);
|
|
499
|
+
// Query DW solo tag=100
|
|
500
|
+
const rawDwPoints = await handleGetInfluxData(measure.name, timeStart, timeEnd, filter, dwPolltime, false, "previous", 100, FilterTagMode.DW);
|
|
501
|
+
dwSlots = tempSlots;
|
|
502
|
+
if (dwSlots.length > 0) {
|
|
503
|
+
dwPoints = rawDwPoints.filter((p) => dwSlots.some(slot => p.x >= slot.start && p.x <= slot.end));
|
|
504
|
+
}
|
|
505
|
+
else {
|
|
506
|
+
dwPoints = rawDwPoints;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
const stdPoints = await handleGetInfluxData(measure.name, timeStart, timeEnd, filter, polltime, !measure.polltime && rawQuery, !measure.polltime ? "none" : "null", 100, FilterTagMode.Exclude);
|
|
510
|
+
const filtered = dwSlots.length
|
|
511
|
+
? stdPoints.filter((p) => !dwSlots.some(slot => p.x >= slot.start && p.x <= slot.end))
|
|
512
|
+
: stdPoints;
|
|
513
|
+
let combined;
|
|
514
|
+
// 6) Unisco e ordino
|
|
515
|
+
if (dwPoints.length > 2 && dwSlots.length > 0) {
|
|
516
|
+
combined = [...dwPoints, ...filtered]
|
|
517
|
+
.sort((a, b) => a.x - b.x);
|
|
518
|
+
}
|
|
519
|
+
else if (dwPoints.length > 2 && dwSlots.length <= 0) {
|
|
520
|
+
combined = [...dwPoints];
|
|
521
|
+
}
|
|
522
|
+
else {
|
|
523
|
+
combined = [...filtered];
|
|
524
|
+
}
|
|
287
525
|
return {
|
|
288
|
-
label: measure.name,
|
|
289
|
-
data:
|
|
526
|
+
label: measure.description || measure.name,
|
|
527
|
+
data: combined,
|
|
290
528
|
unit: measure.unit,
|
|
291
529
|
borderWidth: 2,
|
|
292
530
|
pointRadius: 1,
|
|
293
531
|
pointHoverRadius: 5,
|
|
294
532
|
pointHoverBackgroundColor: 'rgba(52, 125, 236, 0.5)',
|
|
295
|
-
|
|
296
|
-
|
|
533
|
+
change: !measure.polltime,
|
|
534
|
+
stepped: measure.stepped,
|
|
535
|
+
yAxisID: measure.source === 'measures1' ? 'y1' : 'y2'
|
|
297
536
|
};
|
|
298
537
|
});
|
|
299
|
-
// Risolvi tutte le promesse per popolare i dataset
|
|
300
538
|
const datasets = await Promise.all(datasetsPromises);
|
|
301
|
-
let
|
|
302
|
-
let
|
|
539
|
+
let min1 = null;
|
|
540
|
+
let max1 = null;
|
|
541
|
+
let min2 = null;
|
|
542
|
+
let max2 = null;
|
|
303
543
|
let time;
|
|
304
544
|
let minTime = null;
|
|
305
545
|
datasets.forEach(dataset => {
|
|
@@ -309,45 +549,150 @@ const TrendChart = ({ deviceId, measures, enableExportData, enableDatePicker, ha
|
|
|
309
549
|
}
|
|
310
550
|
const datasetMin = Math.min(...values);
|
|
311
551
|
const datasetMax = Math.max(...values);
|
|
312
|
-
if (
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
552
|
+
if (dataset.yAxisID === 'y1') {
|
|
553
|
+
if (min1 === null || datasetMin < min1)
|
|
554
|
+
min1 = datasetMin;
|
|
555
|
+
if (max1 === null || datasetMax > max1)
|
|
556
|
+
max1 = datasetMax;
|
|
557
|
+
}
|
|
558
|
+
else {
|
|
559
|
+
if (min2 === null || datasetMin < min2)
|
|
560
|
+
min2 = datasetMin;
|
|
561
|
+
if (max2 === null || datasetMax > max2)
|
|
562
|
+
max2 = datasetMax;
|
|
563
|
+
}
|
|
564
|
+
if (time && (minTime === null || time < minTime))
|
|
565
|
+
minTime = Math.floor(time / 1000) - 86400;
|
|
318
566
|
});
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
const diff =
|
|
323
|
-
|
|
324
|
-
|
|
567
|
+
const getPaddedMinMax = (min, max) => {
|
|
568
|
+
if (min === null || max === null)
|
|
569
|
+
return { paddedMin: null, paddedMax: null };
|
|
570
|
+
const diff = ((max - min) * 0.2) < 0.1 ? 0.1 : (max - min) * 0.2;
|
|
571
|
+
return {
|
|
572
|
+
paddedMin: Math.floor((min - diff) * 10) / 10,
|
|
573
|
+
paddedMax: Math.ceil((max + diff) * 10) / 10
|
|
574
|
+
};
|
|
575
|
+
};
|
|
576
|
+
const { paddedMin: paddedMin1, paddedMax: paddedMax1 } = getPaddedMinMax(min1, max1);
|
|
577
|
+
const { paddedMin: paddedMin2, paddedMax: paddedMax2 } = getPaddedMinMax(min2, max2);
|
|
578
|
+
// Handle undefined/null annotationsData
|
|
579
|
+
let dynamicAnnotations = {};
|
|
580
|
+
if (annotationsData && Array.isArray(annotationsData) && annotationsData.length > 0 && annotationsEnabled) {
|
|
581
|
+
dynamicAnnotations = annotationsData.reduce((acc, [timestamp, label], index) => {
|
|
582
|
+
const yVal = paddedMin1 !== null && paddedMin1 !== undefined
|
|
583
|
+
? paddedMin1 + 0.01 * (paddedMax1 - paddedMin1)
|
|
584
|
+
: paddedMin2 !== null && paddedMin2 !== undefined
|
|
585
|
+
? paddedMin2 + 0.01 * (paddedMax2 - paddedMin2)
|
|
586
|
+
: 0;
|
|
587
|
+
acc[`line${index}`] = {
|
|
588
|
+
type: 'line',
|
|
589
|
+
xMin: timestamp,
|
|
590
|
+
xMax: timestamp,
|
|
591
|
+
borderColor: 'rgba(255, 225, 0, 0.8)',
|
|
592
|
+
borderWidth: 2,
|
|
593
|
+
drawTime: 'afterDatasetsDraw',
|
|
594
|
+
label: {
|
|
595
|
+
content: label,
|
|
596
|
+
enabled: false
|
|
597
|
+
}
|
|
598
|
+
};
|
|
599
|
+
acc[`triangle${index}`] = {
|
|
600
|
+
type: 'point',
|
|
601
|
+
xValue: timestamp,
|
|
602
|
+
yValue: yVal,
|
|
603
|
+
backgroundColor: 'rgba(255, 225, 0, 0.8)',
|
|
604
|
+
pointStyle: 'triangle',
|
|
605
|
+
radius: 6,
|
|
606
|
+
rotation: 0,
|
|
607
|
+
tooltip: {
|
|
608
|
+
enabled: true,
|
|
609
|
+
callbacks: {
|
|
610
|
+
label: () => label
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
};
|
|
614
|
+
acc[`label${index}`] = {
|
|
615
|
+
type: 'label',
|
|
616
|
+
xValue: timestamp,
|
|
617
|
+
yValue: yVal + 0.1 * (((paddedMax1 ?? paddedMax2 ?? 0) - (paddedMax1 ?? paddedMax2 ?? 0))),
|
|
618
|
+
xAdjust: 0,
|
|
619
|
+
yAdjust: -20,
|
|
620
|
+
backgroundColor: 'rgba(245,245,245)',
|
|
621
|
+
borderColor: 'rgba(255, 225, 0, 0.8)',
|
|
622
|
+
borderWidth: 1,
|
|
623
|
+
content: [label],
|
|
624
|
+
textAlign: 'start',
|
|
625
|
+
font: {
|
|
626
|
+
size: 10,
|
|
627
|
+
weight: 'bold'
|
|
628
|
+
},
|
|
629
|
+
callout: {
|
|
630
|
+
display: false,
|
|
631
|
+
}
|
|
632
|
+
};
|
|
633
|
+
return acc;
|
|
634
|
+
}, {});
|
|
325
635
|
}
|
|
326
|
-
|
|
636
|
+
// Combina statiche + dinamiche
|
|
637
|
+
const annotations = {
|
|
638
|
+
// ...staticAnnotations,
|
|
639
|
+
...dynamicAnnotations
|
|
640
|
+
};
|
|
641
|
+
// 👇 Configurazione completa
|
|
642
|
+
setDataMeasures(datasets);
|
|
327
643
|
setTimeStartPicker(minTime || timeStart);
|
|
328
644
|
setOptions({
|
|
329
645
|
...options,
|
|
330
646
|
scales: {
|
|
331
647
|
...options.scales,
|
|
332
|
-
|
|
333
|
-
...options.scales.
|
|
334
|
-
min:
|
|
335
|
-
max:
|
|
648
|
+
y1: {
|
|
649
|
+
...options.scales.y1,
|
|
650
|
+
min: paddedMin1,
|
|
651
|
+
max: paddedMax1,
|
|
652
|
+
position: "left",
|
|
653
|
+
display: "auto"
|
|
654
|
+
},
|
|
655
|
+
y2: {
|
|
656
|
+
...options.scales.y2,
|
|
657
|
+
min: paddedMin2,
|
|
658
|
+
max: paddedMax2,
|
|
659
|
+
position: "right",
|
|
660
|
+
display: "auto"
|
|
336
661
|
},
|
|
337
662
|
x: {
|
|
338
663
|
...options.scales.x,
|
|
339
664
|
min: moment.unix(minTime || timeStart).toString(),
|
|
340
|
-
max: moment.unix(timeEnd).toString()
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
665
|
+
max: moment.unix(timeEnd).toString()
|
|
666
|
+
}
|
|
667
|
+
},
|
|
668
|
+
plugins: {
|
|
669
|
+
...options.plugins,
|
|
670
|
+
annotation: {
|
|
671
|
+
interaction: {
|
|
672
|
+
mode: 'nearest',
|
|
673
|
+
intersect: true
|
|
674
|
+
},
|
|
675
|
+
annotations
|
|
345
676
|
}
|
|
346
677
|
}
|
|
347
678
|
});
|
|
348
679
|
};
|
|
680
|
+
const shiftChart = ((timeToShift) => {
|
|
681
|
+
setChartLoading(true);
|
|
682
|
+
const timeInRange = timeEnd - timeStart;
|
|
683
|
+
const percentageToShift = 0.1; // 10%
|
|
684
|
+
const shiftAmount = Math.floor(timeInRange * percentageToShift);
|
|
685
|
+
if (timeToShift === 'timeStart') {
|
|
686
|
+
setTimeStart(prev => prev - shiftAmount);
|
|
687
|
+
setTimeEnd(prev => prev - shiftAmount);
|
|
688
|
+
}
|
|
689
|
+
else {
|
|
690
|
+
setTimeEnd(prev => prev + shiftAmount);
|
|
691
|
+
setTimeStart(prev => prev + shiftAmount);
|
|
692
|
+
}
|
|
693
|
+
});
|
|
349
694
|
useEffect(() => {
|
|
350
|
-
const timeDifference = Math.abs(moment(
|
|
695
|
+
const timeDifference = Math.abs(moment(timeEnd).valueOf() - moment(timeStart).valueOf()); // Convert milliseconds to seconds
|
|
351
696
|
let newChartPeriod = '1D'; // Default to 1 day
|
|
352
697
|
if (timeDifference < 86400) { // Less than 1 day
|
|
353
698
|
newChartPeriod = '1H'; // Set to 1 day
|
|
@@ -355,47 +700,70 @@ const TrendChart = ({ deviceId, measures, enableExportData, enableDatePicker, ha
|
|
|
355
700
|
else if (timeDifference < 604800) { // Less than 1 week
|
|
356
701
|
newChartPeriod = '1D'; // Set to 1 day
|
|
357
702
|
}
|
|
358
|
-
else if (timeDifference <
|
|
703
|
+
else if (timeDifference < 2678400) { // Less than 1 month
|
|
359
704
|
newChartPeriod = '1W'; // Set to 1 week
|
|
360
705
|
}
|
|
361
|
-
else if (timeDifference <
|
|
706
|
+
else if (timeDifference < 8035200) { // Less than 3 months
|
|
362
707
|
newChartPeriod = '1M'; // Set to 1 month
|
|
363
708
|
}
|
|
364
|
-
else if (timeDifference <
|
|
709
|
+
else if (timeDifference < 16070400) { // Less than 6 months
|
|
365
710
|
newChartPeriod = '3M'; // Set to 3 months
|
|
366
711
|
}
|
|
367
|
-
else if (timeDifference <
|
|
712
|
+
else if (timeDifference < 31536000) { // Less than 1 year
|
|
368
713
|
newChartPeriod = '6M'; // Set to 6 months
|
|
369
714
|
}
|
|
370
715
|
else {
|
|
371
716
|
newChartPeriod = '1Y'; // Set to 1 year
|
|
372
717
|
}
|
|
373
718
|
setChartPeriodConfig(chartConfigByPeriod[newChartPeriod]);
|
|
719
|
+
// check prev measures value in order to show the loader
|
|
720
|
+
// hide the loader if measure is the same (for interval get measure value)
|
|
721
|
+
const prevMeasuresValue = prevMeasures.current || [];
|
|
722
|
+
//@ts-ignore
|
|
723
|
+
prevMeasures.current = measures;
|
|
724
|
+
if (!prevMeasuresValue || prevMeasuresValue.length !== measures?.length || (prevMeasuresValue[0] && prevMeasuresValue[0].name !== measures[0].name)) {
|
|
725
|
+
setChartLoading(true);
|
|
726
|
+
}
|
|
374
727
|
loadDatasets(chartPeriod).then(() => {
|
|
375
728
|
setChartLoading(false);
|
|
376
729
|
});
|
|
377
|
-
}, [timeEnd, timeStart]);
|
|
730
|
+
}, [measures1, timeEnd, timeStart, measures2, annotationsEnabled, annotationsData]);
|
|
378
731
|
useEffect(() => {
|
|
379
732
|
const loadZoomPlugin = async () => {
|
|
380
733
|
const zoomPlugin = (await import('chartjs-plugin-zoom')).default;
|
|
381
734
|
ChartJS.register(Colors, Legend, Title, Tooltip, PointElement, LineElement, LinearScale, TimeScale, annotationPlugin, zoomPlugin, {
|
|
382
735
|
id: 'uniqueid5',
|
|
383
736
|
afterDraw: function (chart) {
|
|
384
|
-
if (chart.
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
ctx.restore();
|
|
737
|
+
if (!chart.__activePos?.hasPoint)
|
|
738
|
+
return; // disegna solo sui punti
|
|
739
|
+
const ctx = chart.ctx;
|
|
740
|
+
const x = chart.__activePos.px; // pixel esatto del punto attivo
|
|
741
|
+
let topY1 = 0;
|
|
742
|
+
let topY2 = 0;
|
|
743
|
+
let bottomY1 = 0;
|
|
744
|
+
let bottomY2 = 0;
|
|
745
|
+
if (chart.scales.y1?.top) {
|
|
746
|
+
topY1 = chart.scales.y1.top;
|
|
747
|
+
}
|
|
748
|
+
if (chart.scales.y2?.top) {
|
|
749
|
+
topY2 = chart.scales.y2.top;
|
|
398
750
|
}
|
|
751
|
+
if (chart.scales.y1?.bottom) {
|
|
752
|
+
bottomY1 = chart.scales.y1.bottom;
|
|
753
|
+
}
|
|
754
|
+
if (chart.scales.y2?.bottom) {
|
|
755
|
+
bottomY2 = chart.scales.y2.bottom;
|
|
756
|
+
}
|
|
757
|
+
const topY = Math.max(topY1, topY2);
|
|
758
|
+
const bottomY = Math.min(bottomY1, bottomY2);
|
|
759
|
+
ctx.save();
|
|
760
|
+
ctx.beginPath();
|
|
761
|
+
ctx.moveTo(x, topY);
|
|
762
|
+
ctx.lineTo(x, bottomY);
|
|
763
|
+
ctx.lineWidth = 1;
|
|
764
|
+
ctx.strokeStyle = '#722257';
|
|
765
|
+
ctx.stroke();
|
|
766
|
+
ctx.restore();
|
|
399
767
|
}
|
|
400
768
|
});
|
|
401
769
|
setChartJsLoaded(true);
|
|
@@ -403,7 +771,8 @@ const TrendChart = ({ deviceId, measures, enableExportData, enableDatePicker, ha
|
|
|
403
771
|
loadZoomPlugin();
|
|
404
772
|
resetChart();
|
|
405
773
|
}, []);
|
|
406
|
-
const datePicker = _jsx(Box, { sx: { display: 'flex', alignItems: 'center'
|
|
774
|
+
const datePicker = _jsx(Box, { sx: { display: 'flex', alignItems: 'center' }, children: _jsxs(LocalizationProvider, { dateAdapter: AdapterMoment, adapterLocale: "it", children: [_jsx(DateTimePicker, { value: moment(timeStartPicker * 1000), onChange: (newValue) => {
|
|
775
|
+
setChartLoading(true);
|
|
407
776
|
setDatePickerUsed(true);
|
|
408
777
|
setZoomed(false);
|
|
409
778
|
setPickerTimeStart(moment(newValue).unix());
|
|
@@ -411,6 +780,7 @@ const TrendChart = ({ deviceId, measures, enableExportData, enableDatePicker, ha
|
|
|
411
780
|
}, maxDateTime: moment(timeEnd * 1000), slotProps: {
|
|
412
781
|
textField: { size: 'small', sx: { width: { sm: 210 } } }
|
|
413
782
|
} }), " \u00A0\u00A0 ", _jsx(Box, { children: "\u2013" }), " \u00A0\u00A0", _jsx(DateTimePicker, { value: moment(timeEnd * 1000), onChange: (newValue) => {
|
|
783
|
+
setChartLoading(true);
|
|
414
784
|
setDatePickerUsed(true);
|
|
415
785
|
setZoomed(false);
|
|
416
786
|
setPickerTimeEnd(moment(newValue).unix());
|
|
@@ -418,11 +788,28 @@ const TrendChart = ({ deviceId, measures, enableExportData, enableDatePicker, ha
|
|
|
418
788
|
}, minDateTime: moment(timeStart * 1000), slotProps: {
|
|
419
789
|
textField: { size: 'small', sx: { width: { sm: 210 } } }
|
|
420
790
|
} })] }) });
|
|
421
|
-
return (_jsxs(ThemeProvider, { theme: theme, children: [
|
|
791
|
+
return (_jsxs(ThemeProvider, { theme: theme, children: [_jsxs(Box, { sx: { display: { xs: 'flex', lg: 'none', justifyContent: 'center' }, alignItems: 'center', mb: 3, mt: 1 }, children: [_jsx(Button, { sx: {
|
|
792
|
+
borderWidth: 1,
|
|
793
|
+
borderStyle: 'solid',
|
|
794
|
+
borderColor: '#c4c4c4',
|
|
795
|
+
color: 'text.primary',
|
|
796
|
+
":hover": { backgroundColor: 'action.hover' },
|
|
797
|
+
mr: enableDatePicker ? 1 : 0,
|
|
798
|
+
p: 0.85
|
|
799
|
+
}, onClick: () => shiftChart('timeStart'), children: _jsx(KeyboardArrowLeftIcon, {}) }), enableDatePicker && _jsx(Box, { sx: { display: { xs: 'flex', lg: 'none', justifyContent: 'flex-end' } }, children: datePicker }), _jsx(Button, { sx: {
|
|
800
|
+
borderWidth: 1,
|
|
801
|
+
borderStyle: 'solid',
|
|
802
|
+
borderColor: '#c4c4c4',
|
|
803
|
+
color: 'text.primary',
|
|
804
|
+
":hover": { backgroundColor: 'action.hover' },
|
|
805
|
+
ml: enableDatePicker ? 1 : 0,
|
|
806
|
+
p: 0.85
|
|
807
|
+
}, onClick: () => shiftChart('timeEnd'), children: _jsx(KeyboardArrowRightIcon, {}) })] }), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', justifyContent: 'space-between' }, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center' }, children: [!enableExportData && measures && measures.length === 1 ? _jsx(Typography, { variant: 'body1', sx: { mr: 2 }, children: measures[0].description || measures[0].name }) : '', enableExportData && (_jsxs(_Fragment, { children: [_jsxs(LoadingButton, { sx: { minWidth: '40px !important', mr: 1, px: 1 }, loading: loadingButton, type: "submit", variant: "text", color: "primary", onClick: handleExportData, disabled: !dataMeasures || !dataMeasures.length, size: 'small', children: [_jsx(LoginIcon, { fontSize: 'small', style: { transform: "rotate(90deg)" } }), _jsx(Box, { sx: { display: { xs: 'none', xl: 'block' }, ml: { md: 1 } }, children: t('library.trendChart.export') })] }), _jsx(CSVLink
|
|
422
808
|
//@ts-ignore
|
|
423
809
|
, {
|
|
424
810
|
//@ts-ignore
|
|
425
|
-
ref: csvLinkRef, data: csvData, filename: `export_${moment().toISOString()}.csv`, separator: ';' })] })), zoomed && (
|
|
811
|
+
ref: csvLinkRef, data: csvData, filename: `export_${moment().toISOString()}.csv`, separator: ';' })] })), zoomed && measures.length > 0 && (_jsx(Button, { sx: { minWidth: '40px !important', boxShadow: 1, p: 1, mr: 1 }, variant: "contained", color: "primary", size: 'small', onClick: () => {
|
|
812
|
+
setChartLoading(true);
|
|
426
813
|
setZoomed(false);
|
|
427
814
|
if (chartPeriod === "ALL") {
|
|
428
815
|
setDatePickerUsed(false);
|
|
@@ -443,12 +830,31 @@ const TrendChart = ({ deviceId, measures, enableExportData, enableDatePicker, ha
|
|
|
443
830
|
: moment().subtract(1, 'day').unix());
|
|
444
831
|
setTimeEnd(moment().unix());
|
|
445
832
|
}
|
|
446
|
-
}, children:
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
833
|
+
}, children: _jsx(ZoomOut, { fontSize: 'small' }) }))] }), _jsxs(Box, { sx: { display: 'flex', justifyContent: 'flex-end' }, children: [_jsxs(Box, { sx: { display: { xs: 'none', lg: 'flex' }, alignItems: 'center', mr: 1 }, children: [_jsx(Button, { sx: {
|
|
834
|
+
borderWidth: 1,
|
|
835
|
+
borderStyle: 'solid',
|
|
836
|
+
borderColor: '#c4c4c4',
|
|
837
|
+
color: 'text.primary',
|
|
838
|
+
":hover": { backgroundColor: 'action.hover' },
|
|
839
|
+
mr: enableDatePicker ? 1 : 0,
|
|
840
|
+
p: 0.85
|
|
841
|
+
}, onClick: () => shiftChart('timeStart'), children: _jsx(KeyboardArrowLeftIcon, {}) }), enableDatePicker && _jsx(Box, { sx: { display: { xs: 'none', lg: 'flex' } }, children: datePicker }), _jsx(Button, { sx: {
|
|
842
|
+
borderWidth: 1,
|
|
843
|
+
borderStyle: 'solid',
|
|
844
|
+
borderColor: '#c4c4c4',
|
|
845
|
+
color: 'text.primary',
|
|
846
|
+
":hover": { backgroundColor: 'action.hover' },
|
|
847
|
+
ml: 1,
|
|
848
|
+
p: 0.85
|
|
849
|
+
}, onClick: () => shiftChart('timeEnd'), children: _jsx(KeyboardArrowRightIcon, {}) })] }), _jsxs(ToggleButtonGroup, { color: "primary", value: !datePickerUsed && !zoomed ? chartPeriod : null, exclusive: true, onChange: handleChange, size: "small", sx: {
|
|
850
|
+
'& .MuiToggleButton-root': {
|
|
851
|
+
color: 'text.primary', fontSize: '0.95rem', fontWeight: 'normal', paddingTop: '6px', paddingBottom: '6px'
|
|
852
|
+
}
|
|
853
|
+
}, disabled: chartLoading, children: [_jsx(ToggleButton, { value: "1D", sx: { px: 1 }, children: "1d" }), _jsx(ToggleButton, { value: "1W", sx: { px: 1 }, children: "1w" }), _jsx(ToggleButton, { value: "1M", sx: { px: 1 }, children: "1M" }), _jsx(ToggleButton, { value: "3M", sx: { px: 1 }, children: "3M" }), _jsx(ToggleButton, { value: "6M", sx: { px: 1 }, children: "6M" }), _jsx(ToggleButton, { value: "1Y", sx: { px: 1 }, children: "1Y" }), _jsx(ToggleButton, { value: "ALL", sx: { px: 1 }, children: "ALL" })] }), _jsx(MuiTooltip, { placement: "top", arrow: true, title: t('library.trendChart.connectPointValues'), children: _jsx("span", { children: _jsx(ToggleButton, { value: "check", color: "primary", size: "small", selected: spanGapsOption, disabled: chartLoading, onChange: () => handleSpanGaps(!spanGapsOption), sx: { ml: 1 }, children: _jsx(TimelineIcon, {}) }) }) }), annotationsDataFn && annotationsData !== null && (_jsx(MuiTooltip, { placement: "top", arrow: true, title: t('library.trendChart.showAnnotations'), children: _jsx("span", { children: _jsx(ToggleButton, { value: "check", color: "primary", size: "small", selected: annotationsEnabled, disabled: chartLoading, onChange: () => setAnnotationsEnabled(!annotationsEnabled), sx: { ml: 1 }, children: _jsx(EditNoteIcon, {}) }) }) }))] })] }), _jsx(Box, { component: 'div', className: "chart-container", sx: { mt: 2, height: '100%' }, children: chartJsLoaded && !chartLoading && typeof window !== 'undefined' ?
|
|
854
|
+
_jsx(_Fragment, { children: dataMeasures && (dataMeasures.length > 1 || (dataMeasures.length === 1 && dataMeasures[0].data?.length)) ?
|
|
450
855
|
(_jsx(Line, { options: options, data: {
|
|
451
|
-
datasets: dataMeasures || [{ data: [] }]
|
|
856
|
+
// datasets: dataMeasures || [{ data: [] }]
|
|
857
|
+
datasets: dataMeasures.map(d => ({ ...d, showLine: spanGapsOption || !d.change })) || [{ data: [] }]
|
|
452
858
|
} })) : _jsxs(Box, { sx: {
|
|
453
859
|
display: 'flex',
|
|
454
860
|
flexDirection: 'column',
|
|
@@ -456,13 +862,13 @@ const TrendChart = ({ deviceId, measures, enableExportData, enableDatePicker, ha
|
|
|
456
862
|
justifyContent: 'center',
|
|
457
863
|
textAlign: 'center',
|
|
458
864
|
height: '100%',
|
|
459
|
-
}, children: [_jsx(SearchOffOutlinedIcon, { sx: { fontSize: 50, color: 'grey.500', mb: 2 } }), _jsx(Typography, { variant: "body1", color: "textSecondary", align: "center", children:
|
|
865
|
+
}, children: [_jsx(SearchOffOutlinedIcon, { sx: { fontSize: 50, color: 'grey.500', mb: 2 } }), _jsx(Typography, { variant: "body1", color: "textSecondary", align: "center", children: t('library.trendChart.noDataMeasure') })] }) }) : (_jsx(Box, { sx: {
|
|
460
866
|
display: 'flex',
|
|
461
867
|
flexDirection: 'column',
|
|
462
868
|
alignItems: 'center',
|
|
463
869
|
justifyContent: 'center',
|
|
464
870
|
textAlign: 'center',
|
|
465
|
-
height: '100%'
|
|
871
|
+
height: 'calc(100% - 50px)'
|
|
466
872
|
}, children: _jsx(CircularProgress, {}) })) })] }));
|
|
467
873
|
};
|
|
468
874
|
export default TrendChart;
|