@iotready/nextjs-components-library 1.0.0-preview1 → 1.0.0-preview10
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/components/accounts/AccountMenu.d.ts +1 -1
- package/components/charts/TrendChart.d.ts +1 -1
- package/components/charts/TrendChart.js +91 -76
- package/components/groups/GroupsDevices.d.ts +1 -1
- package/components/groups/GroupsDevices.js +18 -3
- package/package.json +1 -1
- package/server-actions/trackle.d.ts +1 -1
- package/server-actions/trackle.js +3 -16
@@ -2,7 +2,7 @@ import { UserType } from '../../types/user';
|
|
2
2
|
import { Theme } from "@emotion/react";
|
3
3
|
export default function UserMenuAccount({ userInfo, handleClick, handleSignOut, accountRoute, theme }: {
|
4
4
|
userInfo: UserType;
|
5
|
-
handleClick: () =>
|
5
|
+
handleClick: () => void;
|
6
6
|
handleSignOut: () => Promise<void>;
|
7
7
|
accountRoute?: string;
|
8
8
|
theme: Theme;
|
@@ -6,7 +6,7 @@ type Measure = {
|
|
6
6
|
polltime: number;
|
7
7
|
unit: string;
|
8
8
|
};
|
9
|
-
declare const TrendChart: ({ deviceId, measures, enableExportData, enableDatePicker, handleGetInfluxData,
|
9
|
+
declare const TrendChart: ({ deviceId, measures, enableExportData, enableDatePicker, handleGetInfluxData, theme, ...props }: {
|
10
10
|
deviceId: string;
|
11
11
|
measures: Array<Measure>;
|
12
12
|
enableenableExportData: boolean;
|
@@ -18,6 +18,8 @@ import 'moment/locale/it';
|
|
18
18
|
// import 'moment/locale/en-gb'; // TODO set locale based on browser
|
19
19
|
import { AdapterMoment } from '@mui/x-date-pickers/AdapterMoment';
|
20
20
|
import { ThemeProvider } from '@mui/material/styles';
|
21
|
+
import TimelineIcon from '@mui/icons-material/Timeline';
|
22
|
+
import MuiTooltip from '@mui/material/Tooltip';
|
21
23
|
const lineOptions = {
|
22
24
|
parsing: false,
|
23
25
|
normalized: true,
|
@@ -35,7 +37,7 @@ const lineOptions = {
|
|
35
37
|
tooltip: {
|
36
38
|
callbacks: {
|
37
39
|
label: (context) => {
|
38
|
-
return `${context.dataset.label}: ${context.parsed.y.toFixed(
|
40
|
+
return `${context.dataset.label}: ${context.parsed.y.toFixed(3)} ${context.dataset.unit}`;
|
39
41
|
}
|
40
42
|
},
|
41
43
|
},
|
@@ -74,15 +76,7 @@ const lineOptions = {
|
|
74
76
|
drawOnChartArea: false,
|
75
77
|
}
|
76
78
|
},
|
77
|
-
y: {
|
78
|
-
ticks: {
|
79
|
-
callback: function (value) {
|
80
|
-
if (Math.floor(value) === value) {
|
81
|
-
return value;
|
82
|
-
}
|
83
|
-
}
|
84
|
-
}
|
85
|
-
},
|
79
|
+
y: {},
|
86
80
|
},
|
87
81
|
};
|
88
82
|
const chartConfigByPeriod = {
|
@@ -119,7 +113,7 @@ const chartConfigByPeriod = {
|
|
119
113
|
scaleUnit: 'year',
|
120
114
|
}
|
121
115
|
};
|
122
|
-
function
|
116
|
+
function getChartPoints(data) {
|
123
117
|
const points = data.results[0].series[0].values.map((row) => {
|
124
118
|
return {
|
125
119
|
x: moment.unix(row[0]),
|
@@ -160,8 +154,11 @@ function getCsvData(data, measures) {
|
|
160
154
|
});
|
161
155
|
});
|
162
156
|
});
|
163
|
-
//
|
164
|
-
Object.
|
157
|
+
// Sort timestamps in ascending order
|
158
|
+
const sortedTimestamps = Object.keys(timestampMap).sort((a, b) => new Date(a).getTime() - new Date(b).getTime());
|
159
|
+
// Create rows from sorted timestampMap
|
160
|
+
sortedTimestamps.forEach(timestamp => {
|
161
|
+
const entry = timestampMap[timestamp];
|
165
162
|
const row = [entry.timestamp];
|
166
163
|
measures.forEach(measure => {
|
167
164
|
// Push the corresponding value or an empty string if undefined
|
@@ -169,7 +166,7 @@ function getCsvData(data, measures) {
|
|
169
166
|
});
|
170
167
|
// Check if the row contains only empty values (besides the timestamp)
|
171
168
|
const hasNonEmptyValues = row.slice(1).some(value => value !== null && value !== '' && value !== undefined);
|
172
|
-
// If the row has at least one non-empty value
|
169
|
+
// If the row has at least one non-empty value, add it to csvData
|
173
170
|
if (hasNonEmptyValues || row.length === 1) {
|
174
171
|
csvData.push(row);
|
175
172
|
}
|
@@ -178,19 +175,22 @@ function getCsvData(data, measures) {
|
|
178
175
|
return csvData.map(row => row.join(',')).join('\n');
|
179
176
|
}
|
180
177
|
// eslint-disable-next-line no-unused-vars
|
181
|
-
const TrendChart = ({ deviceId, measures, enableExportData, enableDatePicker, handleGetInfluxData,
|
178
|
+
const TrendChart = ({ deviceId, measures, enableExportData, enableDatePicker, handleGetInfluxData, theme, ...props }) => {
|
182
179
|
const [chartJsLoaded, setChartJsLoaded] = useState(false);
|
183
180
|
const [dataMeasures, setDataMeasures] = useState(null);
|
184
181
|
const [chartPeriod, setChartPeriod] = useState('1D');
|
185
182
|
const [chartPeriodConfig, setChartPeriodConfig] = useState(chartConfigByPeriod['1D']);
|
186
183
|
const [chartLoading, setChartLoading] = useState(false);
|
184
|
+
const [timeStartPicker, setTimeStartPicker] = useState(moment().subtract(1, 'day').unix());
|
187
185
|
const [timeStart, setTimeStart] = useState(moment().subtract(1, 'day').unix());
|
188
186
|
const [timeEnd, setTimeEnd] = useState(moment().unix());
|
189
|
-
const [firstTimestamp, setFirstTimestamp] = useState();
|
190
187
|
const [datePickerUsed, setDatePickerUsed] = useState(false);
|
188
|
+
const [pickerTimeStart, setPickerTimeStart] = useState(moment().subtract(1, 'day').unix());
|
189
|
+
const [pickerTimeEnd, setPickerTimeEnd] = useState(moment().unix());
|
191
190
|
const [loadingButton, setLoadingButton] = useState(false);
|
192
191
|
const csvLinkRef = useRef(null);
|
193
192
|
const [csvData, setCsvData] = useState('');
|
193
|
+
const [spanGapsOption, setSpanGapsOption] = useState(true);
|
194
194
|
const [options, setOptions] = useState({
|
195
195
|
...lineOptions,
|
196
196
|
plugins: {
|
@@ -214,6 +214,7 @@ const TrendChart = ({ deviceId, measures, enableExportData, enableDatePicker, ha
|
|
214
214
|
}
|
215
215
|
});
|
216
216
|
const [zoomed, setZoomed] = useState(false);
|
217
|
+
const prevMeasures = useRef();
|
217
218
|
const resetChart = () => {
|
218
219
|
setOptions({
|
219
220
|
...options,
|
@@ -229,12 +230,20 @@ const TrendChart = ({ deviceId, measures, enableExportData, enableDatePicker, ha
|
|
229
230
|
setDataMeasures([...[]]);
|
230
231
|
setCsvData("");
|
231
232
|
};
|
233
|
+
const handleSpanGaps = (spanG) => {
|
234
|
+
setOptions({
|
235
|
+
...options,
|
236
|
+
spanGaps: spanG,
|
237
|
+
});
|
238
|
+
setSpanGapsOption(spanG);
|
239
|
+
};
|
232
240
|
const handleChange = (event, newPeriod) => {
|
241
|
+
setChartLoading(true);
|
233
242
|
setZoomed(false);
|
234
243
|
setDatePickerUsed(false);
|
235
244
|
setCsvData('');
|
236
245
|
if (newPeriod === "ALL") {
|
237
|
-
setTimeStart(
|
246
|
+
setTimeStart(1577854800);
|
238
247
|
setTimeEnd(moment().unix());
|
239
248
|
setChartPeriod(newPeriod);
|
240
249
|
return;
|
@@ -249,10 +258,8 @@ const TrendChart = ({ deviceId, measures, enableExportData, enableDatePicker, ha
|
|
249
258
|
};
|
250
259
|
const handleExportData = async () => {
|
251
260
|
setLoadingButton(true);
|
252
|
-
const intervalInSeconds = timeEnd - timeStart;
|
253
261
|
const data = await Promise.all(measures.map(async (measure) => {
|
254
|
-
|
255
|
-
return await handleGetInfluxData(measure.name, timeStart, timeEnd, deviceId, polltime, true);
|
262
|
+
return await handleGetInfluxData(measure.name, timeStart, timeEnd, deviceId, "0s", true);
|
256
263
|
}));
|
257
264
|
const csvData = getCsvData(data, measures);
|
258
265
|
setCsvData(csvData);
|
@@ -264,23 +271,22 @@ const TrendChart = ({ deviceId, measures, enableExportData, enableDatePicker, ha
|
|
264
271
|
}
|
265
272
|
}, [csvData]);
|
266
273
|
const loadDatasets = async (chartPeriod) => {
|
267
|
-
|
268
|
-
const
|
274
|
+
let intervalInSeconds = chartPeriod === "ALL" && !datePickerUsed && !zoomed ? 31536000 : timeEnd - timeStart;
|
275
|
+
const rawQuery = intervalInSeconds < 86400; //
|
269
276
|
// Inizializza un array di promesse per ottenere i dati per ciascuna misura
|
270
277
|
const datasetsPromises = measures.map(async (measure) => {
|
271
|
-
const polltime = getPollTime(intervalInSeconds, measure.polltime);
|
272
|
-
const influxData = await handleGetInfluxData(measure.name, timeStart, timeEnd, deviceId, polltime,
|
273
|
-
const points =
|
278
|
+
const polltime = getPollTime(intervalInSeconds, measure.polltime || 30);
|
279
|
+
const influxData = await handleGetInfluxData(measure.name, timeStart, timeEnd, deviceId, polltime, !measure.polltime && rawQuery);
|
280
|
+
const points = getChartPoints(influxData);
|
274
281
|
return {
|
275
282
|
label: measure.name,
|
276
283
|
data: points,
|
277
284
|
unit: measure.unit,
|
278
|
-
// borderColor: `hsl(${index * 50}, 70%, 50%)`, // Colore unico per ogni dataset
|
279
285
|
borderWidth: 2,
|
280
286
|
pointRadius: 1,
|
281
287
|
pointHoverRadius: 5,
|
282
288
|
pointHoverBackgroundColor: 'rgba(52, 125, 236, 0.5)',
|
283
|
-
|
289
|
+
change: !measure.polltime,
|
284
290
|
fill: false
|
285
291
|
};
|
286
292
|
});
|
@@ -288,24 +294,31 @@ const TrendChart = ({ deviceId, measures, enableExportData, enableDatePicker, ha
|
|
288
294
|
const datasets = await Promise.all(datasetsPromises);
|
289
295
|
let min = null;
|
290
296
|
let max = null;
|
291
|
-
let
|
297
|
+
let time;
|
298
|
+
let minTime = null;
|
292
299
|
datasets.forEach(dataset => {
|
293
|
-
values =
|
300
|
+
const values = dataset.data.map((point) => point.y).filter((data) => data !== null);
|
301
|
+
if (chartPeriod === "ALL" && !datePickerUsed && !zoomed && values.length) {
|
302
|
+
time = dataset.data.filter((data) => data.y !== null).map((data) => data.x)[0];
|
303
|
+
}
|
294
304
|
const datasetMin = Math.min(...values);
|
295
305
|
const datasetMax = Math.max(...values);
|
296
306
|
if (min === null || datasetMin < min)
|
297
307
|
min = datasetMin;
|
298
308
|
if (max === null || datasetMax > max)
|
299
309
|
max = datasetMax;
|
310
|
+
if (time && (minTime === null || time.unix() < minTime))
|
311
|
+
minTime = time.unix() - 86400;
|
300
312
|
});
|
301
313
|
let paddedMin = null;
|
302
314
|
let paddedMax = null;
|
303
315
|
if (min !== null && max !== null) {
|
304
|
-
const diff =
|
305
|
-
paddedMin = min - diff;
|
306
|
-
paddedMax = max + diff;
|
316
|
+
const diff = ((max - min) * 0.2) < 0.1 ? 0.1 : (max - min) * 0.2;
|
317
|
+
paddedMin = Math.floor((min - diff) * 10) / 10;
|
318
|
+
paddedMax = Math.ceil((max + diff) * 10) / 10;
|
307
319
|
}
|
308
320
|
setDataMeasures([...datasets]);
|
321
|
+
setTimeStartPicker(minTime || timeStart);
|
309
322
|
setOptions({
|
310
323
|
...options,
|
311
324
|
scales: {
|
@@ -317,27 +330,14 @@ const TrendChart = ({ deviceId, measures, enableExportData, enableDatePicker, ha
|
|
317
330
|
},
|
318
331
|
x: {
|
319
332
|
...options.scales.x,
|
320
|
-
min: moment.unix(timeStart).toString(),
|
321
|
-
max: moment.unix(timeEnd).toString()
|
322
|
-
time: {
|
323
|
-
...options.scales.x.time,
|
324
|
-
unit: chartPeriod.scaleUnit
|
325
|
-
}
|
333
|
+
min: moment.unix(minTime || timeStart).toString(),
|
334
|
+
max: moment.unix(timeEnd).toString()
|
326
335
|
}
|
327
336
|
}
|
328
337
|
});
|
329
338
|
};
|
330
339
|
useEffect(() => {
|
331
|
-
const
|
332
|
-
const response = await handleGetFirstTimestamp(deviceId);
|
333
|
-
if (response) {
|
334
|
-
setFirstTimestamp(response);
|
335
|
-
}
|
336
|
-
};
|
337
|
-
fetchFirstTimestamp();
|
338
|
-
}, []);
|
339
|
-
useEffect(() => {
|
340
|
-
const timeDifference = Math.abs(moment(timeStart).valueOf() - moment(timeEnd).valueOf()); // Convert milliseconds to seconds
|
340
|
+
const timeDifference = Math.abs(moment(timeEnd).valueOf() - moment(timeStart).valueOf()); // Convert milliseconds to seconds
|
341
341
|
let newChartPeriod = '1D'; // Default to 1 day
|
342
342
|
if (timeDifference < 86400) { // Less than 1 day
|
343
343
|
newChartPeriod = '1H'; // Set to 1 day
|
@@ -345,26 +345,33 @@ const TrendChart = ({ deviceId, measures, enableExportData, enableDatePicker, ha
|
|
345
345
|
else if (timeDifference < 604800) { // Less than 1 week
|
346
346
|
newChartPeriod = '1D'; // Set to 1 day
|
347
347
|
}
|
348
|
-
else if (timeDifference <
|
348
|
+
else if (timeDifference < 2678400) { // Less than 1 month
|
349
349
|
newChartPeriod = '1W'; // Set to 1 week
|
350
350
|
}
|
351
|
-
else if (timeDifference <
|
351
|
+
else if (timeDifference < 8035200) { // Less than 3 months
|
352
352
|
newChartPeriod = '1M'; // Set to 1 month
|
353
353
|
}
|
354
|
-
else if (timeDifference <
|
354
|
+
else if (timeDifference < 16070400) { // Less than 6 months
|
355
355
|
newChartPeriod = '3M'; // Set to 3 months
|
356
356
|
}
|
357
|
-
else if (timeDifference <
|
357
|
+
else if (timeDifference < 31536000) { // Less than 1 year
|
358
358
|
newChartPeriod = '6M'; // Set to 6 months
|
359
359
|
}
|
360
360
|
else {
|
361
361
|
newChartPeriod = '1Y'; // Set to 1 year
|
362
362
|
}
|
363
363
|
setChartPeriodConfig(chartConfigByPeriod[newChartPeriod]);
|
364
|
+
// check prev measures value in order to show the loader
|
365
|
+
// hide the loader if measure is the same (for interval get measure value)
|
366
|
+
const prevMeasuresValue = prevMeasures.current;
|
367
|
+
prevMeasures.current = measures;
|
368
|
+
if (!prevMeasuresValue || prevMeasuresValue.length !== measures.length || (prevMeasuresValue[0] && prevMeasuresValue[0].name !== measures[0].name)) {
|
369
|
+
setChartLoading(true);
|
370
|
+
}
|
364
371
|
loadDatasets(chartPeriod).then(() => {
|
365
372
|
setChartLoading(false);
|
366
373
|
});
|
367
|
-
}, [timeEnd, timeStart]);
|
374
|
+
}, [measures, timeEnd, timeStart]);
|
368
375
|
useEffect(() => {
|
369
376
|
const loadZoomPlugin = async () => {
|
370
377
|
const zoomPlugin = (await import('chartjs-plugin-zoom')).default;
|
@@ -393,34 +400,41 @@ const TrendChart = ({ deviceId, measures, enableExportData, enableDatePicker, ha
|
|
393
400
|
loadZoomPlugin();
|
394
401
|
resetChart();
|
395
402
|
}, []);
|
396
|
-
const datePicker = _jsx(Box, { sx: { display: 'flex', alignItems: 'center', mr: { xs: 0, lg: 2 } }, children: _jsxs(LocalizationProvider, { dateAdapter: AdapterMoment, adapterLocale: "it", children: [_jsx(DateTimePicker, { value: moment(
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
403
|
+
const datePicker = _jsx(Box, { sx: { display: 'flex', alignItems: 'center', mr: { xs: 0, lg: 2 } }, children: _jsxs(LocalizationProvider, { dateAdapter: AdapterMoment, adapterLocale: "it", children: [_jsx(DateTimePicker, { value: moment(timeStartPicker * 1000), onChange: (newValue) => {
|
404
|
+
setChartLoading(true);
|
405
|
+
setDatePickerUsed(true);
|
406
|
+
setZoomed(false);
|
407
|
+
setPickerTimeStart(moment(newValue).unix());
|
408
|
+
setTimeStart(moment(newValue).unix());
|
409
|
+
}, maxDateTime: moment(timeEnd * 1000), slotProps: {
|
401
410
|
textField: { size: 'small', sx: { width: { sm: 210 } } }
|
402
|
-
} }), " \u00A0\u00A0 ", _jsx(Box, { children: "\u2013" }), " \u00A0\u00A0", _jsx(DateTimePicker, { value: moment(timeEnd * 1000),
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
411
|
+
} }), " \u00A0\u00A0 ", _jsx(Box, { children: "\u2013" }), " \u00A0\u00A0", _jsx(DateTimePicker, { value: moment(timeEnd * 1000), onChange: (newValue) => {
|
412
|
+
setChartLoading(true);
|
413
|
+
setDatePickerUsed(true);
|
414
|
+
setZoomed(false);
|
415
|
+
setPickerTimeEnd(moment(newValue).unix());
|
416
|
+
setTimeEnd(moment(newValue).unix());
|
417
|
+
}, minDateTime: moment(timeStart * 1000), slotProps: {
|
407
418
|
textField: { size: 'small', sx: { width: { sm: 210 } } }
|
408
419
|
} })] }) });
|
409
|
-
return (_jsxs(ThemeProvider, { theme: theme, children: [enableDatePicker && _jsx(Box, { sx: { display: { xs: 'flex', lg: 'none', justifyContent: 'flex-end' }, mb: 2 }, children: datePicker }), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', justifyContent: 'space-between' }, children: [_jsxs(Box, { children: [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: "Export" })] }), _jsx(CSVLink
|
420
|
+
return (_jsxs(ThemeProvider, { theme: theme, children: [enableDatePicker && _jsx(Box, { sx: { display: { xs: 'flex', lg: 'none', justifyContent: 'flex-end' }, mb: 2 }, children: datePicker }), _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].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: "Export" })] }), _jsx(CSVLink
|
410
421
|
//@ts-ignore
|
411
422
|
, {
|
412
423
|
//@ts-ignore
|
413
424
|
ref: csvLinkRef, data: csvData, filename: `export_${moment().toISOString()}.csv`, separator: ';' })] })), zoomed && (_jsxs(Button, { sx: { minWidth: '40px !important', boxShadow: 1, px: 1 }, variant: "contained", color: "secondary", size: 'small', onClick: () => {
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
425
|
+
setChartLoading(true);
|
426
|
+
setZoomed(false);
|
427
|
+
if (chartPeriod === "ALL") {
|
428
|
+
setDatePickerUsed(false);
|
429
|
+
setTimeStart(1577854800);
|
419
430
|
setTimeEnd(moment().unix());
|
420
|
-
|
431
|
+
}
|
432
|
+
else if (datePickerUsed) {
|
433
|
+
setTimeStart(pickerTimeStart);
|
434
|
+
setTimeEnd(pickerTimeEnd);
|
421
435
|
}
|
422
436
|
else {
|
423
|
-
|
437
|
+
setDatePickerUsed(false);
|
424
438
|
setChartPeriodConfig(chartConfigByPeriod[chartPeriod]);
|
425
439
|
setTimeStart(chartPeriodConfig.from?.days
|
426
440
|
? moment()
|
@@ -429,12 +443,13 @@ const TrendChart = ({ deviceId, measures, enableExportData, enableDatePicker, ha
|
|
429
443
|
: moment().subtract(1, 'day').unix());
|
430
444
|
setTimeEnd(moment().unix());
|
431
445
|
}
|
432
|
-
}, children: [_jsx(ZoomOut, { fontSize: 'small' }), _jsx(Box, { sx: { display: { xs: 'none',
|
446
|
+
}, children: [_jsx(ZoomOut, { fontSize: 'small' }), _jsx(Box, { sx: { display: { xs: 'none', lg: 'block' }, ml: { md: 1 } }, children: "Reset" })] }))] }), _jsxs(Box, { sx: { display: 'flex', justifyContent: 'flex-end' }, children: [enableDatePicker && _jsx(Box, { sx: { display: { xs: 'none', lg: 'flex' } }, children: datePicker }), _jsxs(ToggleButtonGroup, { color: "primary", value: !datePickerUsed && !zoomed ? chartPeriod : null, exclusive: true, onChange: handleChange, size: "small",
|
433
447
|
// sx={{ boxShadow: 1 }}
|
434
|
-
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" })] })
|
435
|
-
_jsx(_Fragment, { children: dataMeasures && dataMeasures[0]
|
448
|
+
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: "Connect point values", children: _jsx(ToggleButton, { value: "check", color: "primary", size: "small", selected: spanGapsOption, disabled: chartLoading, onChange: () => handleSpanGaps(!spanGapsOption), sx: { ml: 2 }, children: _jsx(TimelineIcon, {}) }) })] })] }), _jsx(Box, { component: 'div', className: "chart-container", sx: { mt: 2, height: '100%' }, children: chartJsLoaded && !chartLoading && typeof window !== 'undefined' ?
|
449
|
+
_jsx(_Fragment, { children: dataMeasures && (dataMeasures.length > 1 || (dataMeasures.length === 1 && dataMeasures[0].data?.length)) ?
|
436
450
|
(_jsx(Line, { options: options, data: {
|
437
|
-
datasets: dataMeasures || [{ data: [] }]
|
451
|
+
// datasets: dataMeasures || [{ data: [] }]
|
452
|
+
datasets: dataMeasures.map(d => ({ ...d, showLine: spanGapsOption || !d.change })) || [{ data: [] }]
|
438
453
|
} })) : _jsxs(Box, { sx: {
|
439
454
|
display: 'flex',
|
440
455
|
flexDirection: 'column',
|
@@ -448,7 +463,7 @@ const TrendChart = ({ deviceId, measures, enableExportData, enableDatePicker, ha
|
|
448
463
|
alignItems: 'center',
|
449
464
|
justifyContent: 'center',
|
450
465
|
textAlign: 'center',
|
451
|
-
height: '100%'
|
466
|
+
height: 'calc(100% - 50px)'
|
452
467
|
}, children: _jsx(CircularProgress, {}) })) })] }));
|
453
468
|
};
|
454
469
|
export default TrendChart;
|
@@ -14,7 +14,7 @@ declare const GroupsDevices: ({ userInfo, handleGetUsersList, handleAddUserToGro
|
|
14
14
|
handleGetGroups: (productID: number, userInfo?: UserType) => Promise<any>;
|
15
15
|
handleGetUsersGroup: (groupID: string) => Promise<any>;
|
16
16
|
handleCreateGroup: (group: any) => Promise<any>;
|
17
|
-
handleGetDevices: (user: UserType,
|
17
|
+
handleGetDevices: (user: UserType, query: string) => Promise<any>;
|
18
18
|
handleGetPositions: (devices: any) => Promise<any>;
|
19
19
|
handleAddDevicesToGroup: (user: UserType, group: string, devicesToPatch: any[]) => Promise<any>;
|
20
20
|
handleRemoveDevicesFromGroup: (user: UserType, group: string, devicesToPatch: any[]) => Promise<any>;
|
@@ -28,7 +28,7 @@ const GroupsDevices = ({ userInfo, handleGetUsersList, handleAddUserToGroup, han
|
|
28
28
|
const [selectedGroup, setSelectedGroup] = useState(group);
|
29
29
|
const [groups, setGroups] = useState(null);
|
30
30
|
const [usersList, setUsersList] = useState([]);
|
31
|
-
const [usersGroup, setUsersGroup] = useState(
|
31
|
+
const [usersGroup, setUsersGroup] = useState(null);
|
32
32
|
const [groupInfo, setGroupInfo] = useState(null);
|
33
33
|
const [openAdd, setOpenAdd] = useState(false);
|
34
34
|
const [groupName, setGroupName] = useState('');
|
@@ -73,7 +73,20 @@ const GroupsDevices = ({ userInfo, handleGetUsersList, handleAddUserToGroup, han
|
|
73
73
|
const fetchDevices = async (group, selected) => {
|
74
74
|
try {
|
75
75
|
setLoadingDevices(true);
|
76
|
-
|
76
|
+
let queryParams = "last_handshake_at!=null";
|
77
|
+
if (group !== "all") {
|
78
|
+
queryParams = `last_handshake_at!=null&state.groups=/${group}/`;
|
79
|
+
if (userInfo.role === "admin") {
|
80
|
+
queryParams += "&quarantined=false";
|
81
|
+
}
|
82
|
+
}
|
83
|
+
else if (selected !== "all") {
|
84
|
+
queryParams = `last_handshake_at!=null&state.groups!=/${selected}/`;
|
85
|
+
if (userInfo.role === "admin") {
|
86
|
+
queryParams += "&quarantined=false";
|
87
|
+
}
|
88
|
+
}
|
89
|
+
const devices = await handleGetDevices(userInfo, queryParams);
|
77
90
|
setDevices(devices);
|
78
91
|
if (enableMaps) {
|
79
92
|
const positions = await handleGetPositions(devices);
|
@@ -119,7 +132,9 @@ const GroupsDevices = ({ userInfo, handleGetUsersList, handleAddUserToGroup, han
|
|
119
132
|
if (currentGroup && !checkboxSelection) {
|
120
133
|
setSelectedGroup(currentGroup);
|
121
134
|
setGroupInfo(groups && groups.find((g) => g.id === currentGroup));
|
122
|
-
|
135
|
+
if (currentGroup !== 'all') {
|
136
|
+
getUsersGroup(currentGroup);
|
137
|
+
}
|
123
138
|
fetchDevices(currentGroup, currentGroup);
|
124
139
|
}
|
125
140
|
}, [currentGroup]);
|
package/package.json
CHANGED
@@ -13,7 +13,7 @@ export declare function createCustomer(trackleConfig: TrackleConfig, uid: string
|
|
13
13
|
organization: string;
|
14
14
|
uid: string;
|
15
15
|
}>;
|
16
|
-
export declare function getDevices(trackleConfig: TrackleConfig, productId?: number, uid?: string,
|
16
|
+
export declare function getDevices(trackleConfig: TrackleConfig, productId?: number, uid?: string, query?: string): Promise<{
|
17
17
|
devices: any[];
|
18
18
|
}>;
|
19
19
|
export declare function getDevice(trackleConfig: TrackleConfig, id: string, productId?: number, uid?: string): Promise<{
|
@@ -55,25 +55,12 @@ export async function createCustomer(trackleConfig, uid) {
|
|
55
55
|
.post({ uid })
|
56
56
|
.json();
|
57
57
|
}
|
58
|
-
export async function getDevices(trackleConfig, productId, uid,
|
59
|
-
let queryParams = "last_handshake_at!=null";
|
60
|
-
if (group !== "all") {
|
61
|
-
queryParams = `last_handshake_at!=null&state.groups=/${group}/`;
|
62
|
-
if (!uid) {
|
63
|
-
queryParams += "&quarantined=false";
|
64
|
-
}
|
65
|
-
}
|
66
|
-
else if (selected !== "all") {
|
67
|
-
queryParams = `last_handshake_at!=null&state.groups!=/${selected}/`;
|
68
|
-
if (!uid) {
|
69
|
-
queryParams += "&quarantined=false";
|
70
|
-
}
|
71
|
-
}
|
58
|
+
export async function getDevices(trackleConfig, productId, uid, query) {
|
72
59
|
const api = uid ? wretchApi(trackleConfig, uid) : wretchApi(trackleConfig);
|
73
60
|
const response = await api
|
74
61
|
.get(uid
|
75
|
-
? `/devices
|
76
|
-
: `/products/${productId}/devices
|
62
|
+
? `/devices${query ? "?" + query : ""}`
|
63
|
+
: `/products/${productId}/devices${query ? "?" + query : ""}`)
|
77
64
|
.setTimeout(trackleConfig.apiTimeout)
|
78
65
|
.json();
|
79
66
|
return (uid ? { devices: response } : response);
|