@iotready/nextjs-components-library 1.0.0-preview19 → 1.0.0-preview20
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/charts/TrendChart.d.ts +7 -2
- package/components/charts/TrendChart.js +121 -43
- package/package.json +2 -2
- package/server-actions/annotations.d.ts +4 -0
- package/server-actions/annotations.js +15 -0
- package/server-actions/groups.d.ts +1 -8
- package/server-actions/index.d.ts +1 -0
- package/server-actions/index.js +1 -0
- package/server-actions/influx.d.ts +3 -12
- package/server-actions/influx.js +19 -6
- package/server-actions/types.d.ts +19 -0
- package/server-actions/types.js +1 -0
- package/types/user.d.ts +1 -0
@@ -1,6 +1,7 @@
|
|
1
1
|
import 'chartjs-adapter-moment';
|
2
2
|
import 'moment/locale/it';
|
3
3
|
import { Theme } from "@emotion/react";
|
4
|
+
import { InfluxFillType } from '../../server-actions/types';
|
4
5
|
type Measure = {
|
5
6
|
name: string;
|
6
7
|
description: string;
|
@@ -8,15 +9,19 @@ type Measure = {
|
|
8
9
|
unit: string;
|
9
10
|
stepped: boolean;
|
10
11
|
};
|
11
|
-
declare const TrendChart: ({ deviceId, measures1, measures2, enableDatePicker, handleGetInfluxData, handleExportDataCB, theme, initialTimeStart, initialTimeEnd }: {
|
12
|
+
declare const TrendChart: ({ deviceId, measures1, annotationsData, measures2, enableDatePicker, handleGetInfluxData, handleExportDataCB, theme, initialTimeStart, initialTimeEnd, dwEnabled, dwCallback, dwHandled }: {
|
12
13
|
deviceId: string;
|
14
|
+
annotationsData?: Array<[any, any]>;
|
13
15
|
measures1?: Array<Measure>;
|
14
16
|
measures2?: Array<Measure>;
|
15
17
|
enableDatePicker: boolean;
|
16
|
-
handleGetInfluxData: (measure: string, timeStart: number, timeEnd: number, deviceId: string, timeGroup: string, raw: boolean, fill?:
|
18
|
+
handleGetInfluxData: (measure: string, timeStart: number, timeEnd: number, deviceId: string, timeGroup: string, raw: boolean, fill?: InfluxFillType) => Promise<any>;
|
17
19
|
handleExportDataCB?: (measure: string, timeStart: number, timeEnd: number, deviceId: string) => Promise<any>;
|
18
20
|
theme: Theme;
|
19
21
|
initialTimeStart?: number;
|
20
22
|
initialTimeEnd?: number;
|
23
|
+
dwEnabled?: boolean;
|
24
|
+
dwCallback?: (val: boolean) => void;
|
25
|
+
dwHandled?: boolean;
|
21
26
|
}) => import("react/jsx-runtime").JSX.Element;
|
22
27
|
export default TrendChart;
|
@@ -20,6 +20,8 @@ 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';
|
23
25
|
const lineOptions = {
|
24
26
|
parsing: false,
|
25
27
|
normalized: true,
|
@@ -186,8 +188,9 @@ function getCsvData(data, measures) {
|
|
186
188
|
return csvData.map(row => row.join(',')).join('\n');
|
187
189
|
}
|
188
190
|
// eslint-disable-next-line no-unused-vars
|
189
|
-
const TrendChart = ({ deviceId, measures1, measures2, enableDatePicker, handleGetInfluxData, handleExportDataCB, theme, initialTimeStart, initialTimeEnd }) => {
|
191
|
+
const TrendChart = ({ deviceId, measures1, annotationsData, measures2, enableDatePicker, handleGetInfluxData, handleExportDataCB, theme, initialTimeStart, initialTimeEnd, dwEnabled, dwCallback, dwHandled }) => {
|
190
192
|
const [chartJsLoaded, setChartJsLoaded] = useState(false);
|
193
|
+
const [annotentionsEnabled, setAnnotationsEnabled] = useState(true);
|
191
194
|
const [dataMeasures, setDataMeasures] = useState(null);
|
192
195
|
const [chartPeriod, setChartPeriod] = useState('1D');
|
193
196
|
const [chartPeriodConfig, setChartPeriodConfig] = useState(chartConfigByPeriod['1D']);
|
@@ -258,22 +261,24 @@ const TrendChart = ({ deviceId, measures1, measures2, enableDatePicker, handleGe
|
|
258
261
|
setSpanGapsOption(spanG);
|
259
262
|
};
|
260
263
|
const handleChange = (event, newPeriod) => {
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
264
|
+
if (newPeriod && newPeriod !== chartPeriod) {
|
265
|
+
setChartLoading(true);
|
266
|
+
setZoomed(false);
|
267
|
+
setDatePickerUsed(false);
|
268
|
+
setCsvData('');
|
269
|
+
if (newPeriod === "ALL") {
|
270
|
+
setTimeStart(1577854800);
|
271
|
+
setTimeEnd(moment().unix());
|
272
|
+
setChartPeriod(newPeriod);
|
273
|
+
return;
|
274
|
+
}
|
275
|
+
const periodConfig = chartConfigByPeriod[newPeriod];
|
276
|
+
if (periodConfig) {
|
277
|
+
setTimeStart(Math.round(moment().subtract(periodConfig.from).valueOf() / 1000));
|
278
|
+
setTimeEnd(Math.round(moment().valueOf() / 1000));
|
279
|
+
setChartPeriod(newPeriod);
|
280
|
+
setChartPeriodConfig(periodConfig);
|
281
|
+
}
|
277
282
|
}
|
278
283
|
};
|
279
284
|
const handleExportData = async () => {
|
@@ -302,7 +307,7 @@ const TrendChart = ({ deviceId, measures1, measures2, enableDatePicker, handleGe
|
|
302
307
|
];
|
303
308
|
const datasetsPromises = allMeasures.map(async (measure) => {
|
304
309
|
const polltime = getPollTime(intervalInSeconds, measure.polltime || 30);
|
305
|
-
const influxData = await handleGetInfluxData(measure.name, timeStart, timeEnd, deviceId, polltime, !measure.polltime && rawQuery, !measure.polltime);
|
310
|
+
const influxData = await handleGetInfluxData(measure.name, timeStart, timeEnd, deviceId, polltime, !measure.polltime && rawQuery, dwEnabled ? "previous" : !measure.polltime ? "none" : "null");
|
306
311
|
const points = getChartPoints(influxData);
|
307
312
|
return {
|
308
313
|
label: measure.description || measure.name,
|
@@ -357,33 +362,106 @@ const TrendChart = ({ deviceId, measures1, measures2, enableDatePicker, handleGe
|
|
357
362
|
};
|
358
363
|
const { paddedMin: paddedMin1, paddedMax: paddedMax1 } = getPaddedMinMax(min1, max1);
|
359
364
|
const { paddedMin: paddedMin2, paddedMax: paddedMax2 } = getPaddedMinMax(min2, max2);
|
365
|
+
// Handle undefined/null annotationsData
|
366
|
+
let dynamicAnnotations = {};
|
367
|
+
if (Array.isArray(annotationsData) && annotationsData.length > 0 && annotentionsEnabled) {
|
368
|
+
dynamicAnnotations = annotationsData.reduce((acc, [timestamp, label], index) => {
|
369
|
+
const yVal = paddedMin1 !== null && paddedMin1 !== undefined
|
370
|
+
? paddedMin1 + 0.01 * (paddedMax1 - paddedMin1)
|
371
|
+
: paddedMin2 !== null && paddedMin2 !== undefined
|
372
|
+
? paddedMin2 + 0.01 * (paddedMax2 - paddedMin2)
|
373
|
+
: 0;
|
374
|
+
acc[`line${index}`] = {
|
375
|
+
type: 'line',
|
376
|
+
xMin: timestamp,
|
377
|
+
xMax: timestamp,
|
378
|
+
borderColor: 'rgba(255, 225, 0, 0.8)',
|
379
|
+
borderWidth: 2,
|
380
|
+
drawTime: 'afterDatasetsDraw',
|
381
|
+
label: {
|
382
|
+
content: label,
|
383
|
+
enabled: false
|
384
|
+
}
|
385
|
+
};
|
386
|
+
acc[`triangle${index}`] = {
|
387
|
+
type: 'point',
|
388
|
+
xValue: timestamp,
|
389
|
+
yValue: yVal,
|
390
|
+
backgroundColor: 'rgba(255, 225, 0, 0.8)',
|
391
|
+
pointStyle: 'triangle',
|
392
|
+
radius: 6,
|
393
|
+
rotation: 0,
|
394
|
+
tooltip: {
|
395
|
+
enabled: true,
|
396
|
+
callbacks: {
|
397
|
+
label: () => label
|
398
|
+
}
|
399
|
+
}
|
400
|
+
};
|
401
|
+
acc[`label${index}`] = {
|
402
|
+
type: 'label',
|
403
|
+
xValue: timestamp,
|
404
|
+
yValue: yVal + 0.1 * (((paddedMax1 ?? paddedMax2 ?? 0) - (paddedMax1 ?? paddedMax2 ?? 0))),
|
405
|
+
xAdjust: 0,
|
406
|
+
yAdjust: -20,
|
407
|
+
backgroundColor: 'rgba(245,245,245)',
|
408
|
+
borderColor: 'rgba(255, 225, 0, 0.8)',
|
409
|
+
borderWidth: 1,
|
410
|
+
content: [label],
|
411
|
+
textAlign: 'start',
|
412
|
+
font: {
|
413
|
+
size: 10,
|
414
|
+
weight: 'bold'
|
415
|
+
},
|
416
|
+
callout: {
|
417
|
+
display: false,
|
418
|
+
}
|
419
|
+
};
|
420
|
+
return acc;
|
421
|
+
}, {});
|
422
|
+
}
|
423
|
+
// 👇 Combina statiche + dinamiche
|
424
|
+
const annotations = {
|
425
|
+
// ...staticAnnotations,
|
426
|
+
...dynamicAnnotations
|
427
|
+
};
|
428
|
+
// 👇 Configurazione completa
|
360
429
|
setDataMeasures(datasets);
|
361
430
|
setTimeStartPicker(minTime || timeStart);
|
362
|
-
const scalesOptions = {
|
363
|
-
...options.scales,
|
364
|
-
y1: {
|
365
|
-
...options.scales.y1,
|
366
|
-
min: paddedMin1,
|
367
|
-
max: paddedMax1,
|
368
|
-
position: "left",
|
369
|
-
display: "auto"
|
370
|
-
},
|
371
|
-
y2: {
|
372
|
-
...options.scales.y2,
|
373
|
-
min: paddedMin2,
|
374
|
-
max: paddedMax2,
|
375
|
-
position: "right",
|
376
|
-
display: "auto"
|
377
|
-
},
|
378
|
-
x: {
|
379
|
-
...options.scales.x,
|
380
|
-
min: moment.unix(minTime || timeStart).toString(),
|
381
|
-
max: moment.unix(timeEnd).toString()
|
382
|
-
}
|
383
|
-
};
|
384
431
|
setOptions({
|
385
432
|
...options,
|
386
|
-
scales:
|
433
|
+
scales: {
|
434
|
+
...options.scales,
|
435
|
+
y1: {
|
436
|
+
...options.scales.y1,
|
437
|
+
min: paddedMin1,
|
438
|
+
max: paddedMax1,
|
439
|
+
position: "left",
|
440
|
+
display: "auto"
|
441
|
+
},
|
442
|
+
y2: {
|
443
|
+
...options.scales.y2,
|
444
|
+
min: paddedMin2,
|
445
|
+
max: paddedMax2,
|
446
|
+
position: "right",
|
447
|
+
display: "auto"
|
448
|
+
},
|
449
|
+
x: {
|
450
|
+
...options.scales.x,
|
451
|
+
min: moment.unix(minTime || timeStart).toString(),
|
452
|
+
max: moment.unix(timeEnd).toString()
|
453
|
+
}
|
454
|
+
},
|
455
|
+
plugins: {
|
456
|
+
...options.plugins,
|
457
|
+
annotation: {
|
458
|
+
interaction: {
|
459
|
+
mode: 'nearest',
|
460
|
+
intersect: true
|
461
|
+
},
|
462
|
+
annotations
|
463
|
+
}
|
464
|
+
}
|
387
465
|
});
|
388
466
|
};
|
389
467
|
useEffect(() => {
|
@@ -422,7 +500,7 @@ const TrendChart = ({ deviceId, measures1, measures2, enableDatePicker, handleGe
|
|
422
500
|
loadDatasets(chartPeriod).then(() => {
|
423
501
|
setChartLoading(false);
|
424
502
|
});
|
425
|
-
}, [measures1, timeEnd, timeStart, measures2]);
|
503
|
+
}, [measures1, timeEnd, timeStart, measures2, annotentionsEnabled, annotationsData, dwEnabled]);
|
426
504
|
useEffect(() => {
|
427
505
|
const loadZoomPlugin = async () => {
|
428
506
|
const zoomPlugin = (await import('chartjs-plugin-zoom')).default;
|
@@ -514,7 +592,7 @@ const TrendChart = ({ deviceId, measures1, measures2, enableDatePicker, handleGe
|
|
514
592
|
'& .MuiToggleButton-root': {
|
515
593
|
color: 'text.primary', fontSize: '0.95rem', fontWeight: 'normal', paddingTop: '6px', paddingBottom: '6px'
|
516
594
|
}
|
517
|
-
}, 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:
|
595
|
+
}, 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: 1 }, children: _jsx(TimelineIcon, {}) }) }), annotationsData !== undefined && (_jsx(MuiTooltip, { placement: "top", arrow: true, title: "Show annotations", children: _jsx(ToggleButton, { value: "check", color: "primary", size: "small", selected: annotentionsEnabled, disabled: chartLoading, onChange: () => setAnnotationsEnabled(!annotentionsEnabled), sx: { ml: 1 }, children: _jsx(EditNoteIcon, {}) }) })), dwCallback !== undefined && dwEnabled != undefined && (_jsx(MuiTooltip, { placement: "top", arrow: true, title: "Show data window data", children: _jsx(ToggleButton, { value: "check", color: "primary", size: "small", selected: dwEnabled, disabled: chartLoading || !dwHandled, onChange: () => dwCallback(!dwEnabled), sx: { ml: 1 }, children: _jsx(AspectRatioIcon, {}) }) }))] })] }), _jsx(Box, { component: 'div', className: "chart-container", sx: { mt: 2, height: '100%' }, children: chartJsLoaded && !chartLoading && typeof window !== 'undefined' ?
|
518
596
|
_jsx(_Fragment, { children: dataMeasures && (dataMeasures.length > 1 || (dataMeasures.length === 1 && dataMeasures[0].data?.length)) ?
|
519
597
|
(_jsx(Line, { options: options, data: {
|
520
598
|
// datasets: dataMeasures || [{ data: [] }]
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@iotready/nextjs-components-library",
|
3
|
-
"version": "1.0.0-
|
3
|
+
"version": "1.0.0-preview20",
|
4
4
|
"main": "index.js",
|
5
5
|
"scripts": {
|
6
6
|
"build": "rm -rf dist && tsc --project tsconfig.build.json && cp package.json dist/",
|
@@ -43,4 +43,4 @@
|
|
43
43
|
"eslint-config-next": "14.2.9",
|
44
44
|
"typescript": "^5"
|
45
45
|
}
|
46
|
-
}
|
46
|
+
}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
"use server";
|
2
|
+
import { initializeApp } from "firebase/app";
|
3
|
+
import { collection, query, orderBy, getDocs, where } from "@firebase/firestore";
|
4
|
+
import { getFirestore } from "@firebase/firestore";
|
5
|
+
export const getAnnotations = async (firebaseConfig, deviceID) => {
|
6
|
+
// Initialize Firebase
|
7
|
+
const app = initializeApp(firebaseConfig);
|
8
|
+
const db = getFirestore(app);
|
9
|
+
const annotationsQuery = query(collection(db, "annotations"), where("target", "==", deviceID), orderBy("createdAt", "desc"));
|
10
|
+
const groupsSnapshot = await getDocs(annotationsQuery);
|
11
|
+
return groupsSnapshot.docs.map((doc) => ({
|
12
|
+
id: doc.id,
|
13
|
+
...doc.data()
|
14
|
+
}));
|
15
|
+
};
|
@@ -1,11 +1,4 @@
|
|
1
|
-
|
2
|
-
apiKey: string;
|
3
|
-
authDomain: string;
|
4
|
-
projectId: string;
|
5
|
-
storageBucket: string;
|
6
|
-
messagingSenderId: string;
|
7
|
-
appId: string;
|
8
|
-
};
|
1
|
+
import { FirebaseConfig } from "./types";
|
9
2
|
export declare const getGroups: (firebaseConfig: FirebaseConfig, productID: number, userID?: string) => Promise<{
|
10
3
|
id: string;
|
11
4
|
}[]>;
|
package/server-actions/index.js
CHANGED
@@ -1,13 +1,4 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
bucket: string;
|
5
|
-
orgId: string;
|
6
|
-
measurement: string;
|
7
|
-
dbName: string;
|
8
|
-
username: string;
|
9
|
-
password: string;
|
10
|
-
};
|
11
|
-
export declare function getInfluxAlarms(influxConfig: InfluxConfig, fields: string[], limit: number, offset: number, sort: any, deviceID: string, timeStart: number, timeEnd: number): Promise<any>;
|
12
|
-
export declare function getInfluxDataV1(influxConfig: InfluxConfig, field: string, timeStart: number, timeEnd: number, deviceID: string, timeGroup: string, raw: boolean, fill?: boolean): Promise<any>;
|
1
|
+
import { InfluxConfig, InfluxFillType } from "./types";
|
2
|
+
export declare function getInfluxAlerts(influxConfig: InfluxConfig, fields: string[], limit: number, offset: number, sort: any, deviceID: string, timeStart: number, timeEnd: number): Promise<any>;
|
3
|
+
export declare function getInfluxDataV1(influxConfig: InfluxConfig, field: string, timeStart: number, timeEnd: number, deviceID: string, timeGroup: string, raw: boolean, fill?: InfluxFillType, filterTag?: number): Promise<any>;
|
13
4
|
export declare function exportDataV1(influxConfig: InfluxConfig, field: string, timeStart: number, timeEnd: number, deviceID: string): Promise<any>;
|
package/server-actions/influx.js
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
"use server";
|
2
2
|
import { parse } from "csv-parse";
|
3
3
|
import moment from "moment";
|
4
|
-
export async function
|
4
|
+
export async function getInfluxAlerts(influxConfig, fields, limit, offset, sort, deviceID, timeStart, timeEnd) {
|
5
5
|
const conditions = fields
|
6
6
|
.map((field) => `r["valueName"] == "${field}"`)
|
7
7
|
.join(" or ");
|
@@ -13,6 +13,10 @@ export async function getInfluxAlarms(influxConfig, fields, limit, offset, sort,
|
|
13
13
|
}
|
14
14
|
query += `
|
15
15
|
|> filter(fn: (r) => r["_measurement"] == "${influxConfig.measurement}" and r["deviceid"] == "${deviceID}" and (${conditions}))
|
16
|
+
`;
|
17
|
+
// Add filter for tag d === 3
|
18
|
+
query += `
|
19
|
+
|> filter(fn: (r) => r["d"] == "3" or r["d"] !~ /./) // Include only events with tag d == 3 or no tag d
|
16
20
|
`;
|
17
21
|
const queryCount = `${query} |> group() |> count()`;
|
18
22
|
query += `
|
@@ -70,35 +74,44 @@ export async function getInfluxAlarms(influxConfig, fields, limit, offset, sort,
|
|
70
74
|
});
|
71
75
|
const parsedCount = count.split("\n")[1].split(",");
|
72
76
|
let countData = parsedCount[5];
|
77
|
+
console.log("Count Data:", countData);
|
78
|
+
console.log("Rows:", rows);
|
73
79
|
return {
|
74
80
|
data: rows,
|
75
81
|
count: countData
|
76
82
|
};
|
77
83
|
}
|
78
|
-
export async function getInfluxDataV1(influxConfig, field, timeStart, timeEnd, deviceID, timeGroup, raw, fill) {
|
84
|
+
export async function getInfluxDataV1(influxConfig, field, timeStart, timeEnd, deviceID, timeGroup, raw, fill, filterTag) {
|
79
85
|
let query;
|
80
86
|
let preStartValue = null;
|
87
|
+
// Build filter for filterTag if provided
|
88
|
+
const filterTagCondition = filterTag !== undefined && filterTag !== null
|
89
|
+
? ` AND ("d" = '${filterTag}' OR "d" !~ /./)`
|
90
|
+
: "";
|
81
91
|
if (raw) {
|
82
|
-
query = `SELECT ("value") FROM "${influxConfig.measurement}" WHERE "deviceid" = '${deviceID}' AND "valueName" = '${field}' AND time >= '${moment
|
92
|
+
query = `SELECT ("value") FROM "${influxConfig.measurement}" WHERE "deviceid" = '${deviceID}' AND "valueName" = '${field}'${filterTagCondition} AND time >= '${moment
|
83
93
|
.unix(timeStart)
|
84
94
|
.toISOString()}' AND time <= '${moment.unix(timeEnd).toISOString()}'`;
|
85
95
|
}
|
86
96
|
else {
|
87
|
-
query = `SELECT last("value") FROM "${influxConfig.measurement}" WHERE "deviceid" = '${deviceID}' AND "valueName" = '${field}' AND time >= '${moment
|
97
|
+
query = `SELECT last("value") FROM "${influxConfig.measurement}" WHERE "deviceid" = '${deviceID}' AND "valueName" = '${field}'${filterTagCondition} AND time >= '${moment
|
88
98
|
.unix(timeStart)
|
89
99
|
.toISOString()}' AND time <= '${moment
|
90
100
|
.unix(timeEnd)
|
91
101
|
.toISOString()}' GROUP BY time(${timeGroup})`;
|
92
|
-
if (fill) {
|
102
|
+
if (fill === "none") {
|
93
103
|
query += ` fill(none)`;
|
94
104
|
}
|
105
|
+
else if (fill === "previous") {
|
106
|
+
query += ` fill(previous)`;
|
107
|
+
}
|
95
108
|
else {
|
96
109
|
query += ` fill(null)`;
|
97
110
|
}
|
98
111
|
}
|
99
112
|
if (fill) {
|
100
113
|
// Query to get the last data point before timeStart
|
101
|
-
const preStartQuery = `SELECT last("value") FROM "${influxConfig.measurement}" WHERE "deviceid" = '${deviceID}' AND "valueName" = '${field}' AND time < '${moment
|
114
|
+
const preStartQuery = `SELECT last("value") FROM "${influxConfig.measurement}" WHERE "deviceid" = '${deviceID}' AND "valueName" = '${field}'${filterTagCondition} AND time < '${moment
|
102
115
|
.unix(timeStart)
|
103
116
|
.toISOString()}'`;
|
104
117
|
const preStartResponse = await fetch(encodeURI(`${influxConfig.url}/query?db=${influxConfig.dbName}&epoch=s&q=${preStartQuery}`), {
|
@@ -0,0 +1,19 @@
|
|
1
|
+
export type FirebaseConfig = {
|
2
|
+
apiKey: string;
|
3
|
+
authDomain: string;
|
4
|
+
projectId: string;
|
5
|
+
storageBucket: string;
|
6
|
+
messagingSenderId: string;
|
7
|
+
appId: string;
|
8
|
+
};
|
9
|
+
export type InfluxConfig = {
|
10
|
+
url: string;
|
11
|
+
accessToken: string;
|
12
|
+
bucket: string;
|
13
|
+
orgId: string;
|
14
|
+
measurement: string;
|
15
|
+
dbName: string;
|
16
|
+
username: string;
|
17
|
+
password: string;
|
18
|
+
};
|
19
|
+
export type InfluxFillType = "null" | "none" | "previous";
|
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|