@iotready/nextjs-components-library 1.0.0-preview2 → 1.0.0-preview21

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.
@@ -12,7 +12,7 @@ declare const GroupUpdate: ({ userInfo, groupInfo, usersGroup, usersList, device
12
12
  handleAddUserToGroup: (groupID: string, userName: string, userID: string) => Promise<any>;
13
13
  handleRemoveUserFromGroup: (groupID: string, userID: string) => Promise<any>;
14
14
  handleUpdateDevice: (id: string, body: any, user: UserType) => Promise<any>;
15
- handleGetGroups: (productID: number, userInfo?: UserType) => Promise<any>;
15
+ handleGetGroups: (userInfo?: UserType) => Promise<any>;
16
16
  handleUpdateGroup: (id: string, group: any) => Promise<void>;
17
17
  handleDeleteGroup: (id: string) => Promise<void>;
18
18
  container?: "Box" | "Card";
@@ -27,7 +27,7 @@ const GroupUpdate = ({ userInfo, groupInfo, usersGroup, usersList, devicesList,
27
27
  if (response) {
28
28
  if (devicesList.length > 0) {
29
29
  // should check if device is present in other groups the user is member of
30
- const groupsData = await handleGetGroups(1008, { role: 'support', uid: userId });
30
+ const groupsData = await handleGetGroups({ role: 'support', uid: userId });
31
31
  const userGroupIds = groupsData.map((group) => group.id);
32
32
  // for all devices in the group set the selectedUser as manager
33
33
  for (const device of devicesList) {
@@ -11,10 +11,10 @@ declare const GroupsDevices: ({ userInfo, handleGetUsersList, handleAddUserToGro
11
11
  }>;
12
12
  handleAddUserToGroup: (groupID: string, userName: string, userID: string) => Promise<any>;
13
13
  handleRemoveUserFromGroup: (groupID: string, userID: string) => Promise<any>;
14
- handleGetGroups: (productID: number, userInfo?: UserType) => Promise<any>;
14
+ handleGetGroups: (userInfo?: UserType) => Promise<any>;
15
15
  handleGetUsersGroup: (groupID: string) => Promise<any>;
16
16
  handleCreateGroup: (group: any) => Promise<any>;
17
- handleGetDevices: (user: UserType, group: string, selected: string) => Promise<any>;
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('');
@@ -60,7 +60,7 @@ const GroupsDevices = ({ userInfo, handleGetUsersList, handleAddUserToGroup, han
60
60
  moreData = usersList.users.length === pageSize;
61
61
  page++;
62
62
  }
63
- const userGroupsUserIds = usersGroup.map((ug) => ug.user.userId);
63
+ const userGroupsUserIds = usersGroup && usersGroup.map((ug) => ug.user.userId) || [];
64
64
  setUsersList(usersData.filter((user) => user.role === 'support' && !userGroupsUserIds.includes(user.uid)).map((user) => {
65
65
  const userName = user.name ? user.name.replace("/", " ") : "";
66
66
  return { label: `${userName} (${user.email})`, id: user.uid };
@@ -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
- const devices = await handleGetDevices(userInfo, group, selected);
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);
@@ -89,7 +102,7 @@ const GroupsDevices = ({ userInfo, handleGetUsersList, handleAddUserToGroup, han
89
102
  };
90
103
  const getGroups = async () => {
91
104
  try {
92
- const responseData = await handleGetGroups(1008, userInfo);
105
+ const responseData = await handleGetGroups(userInfo);
93
106
  setGroups(responseData);
94
107
  }
95
108
  catch (err) {
@@ -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
- getUsersGroup(currentGroup);
135
+ if (currentGroup !== 'all') {
136
+ getUsersGroup(currentGroup);
137
+ }
123
138
  fetchDevices(currentGroup, currentGroup);
124
139
  }
125
140
  }, [currentGroup]);
@@ -130,7 +145,6 @@ const GroupsDevices = ({ userInfo, handleGetUsersList, handleAddUserToGroup, han
130
145
  const newGroup = {
131
146
  name: groupName,
132
147
  description,
133
- productID: 1008, // Assuming this is the correct productID
134
148
  };
135
149
  const id = await handleCreateGroup(newGroup);
136
150
  await getGroups();
@@ -177,13 +191,13 @@ const GroupsDevices = ({ userInfo, handleGetUsersList, handleAddUserToGroup, han
177
191
  const devicesPatched = await handleAddDevicesToGroup(userInfo, selectedGroup, devicesToPatch);
178
192
  if (devicesPatched && devicesPatched.length > 0) {
179
193
  // get all members of the group
180
- const userIdsToAdd = usersGroup.map((ug) => ug.user.userId);
181
- if (userIdsToAdd.length > 0) {
194
+ const userIdsToAdd = usersGroup && usersGroup.map((ug) => ug.user.userId) || [];
195
+ if (userIdsToAdd && userIdsToAdd.length > 0) {
182
196
  for (const device of devicesToPatch) {
183
197
  // add members to devices managers
184
198
  await handleUpdateDevice(device.id, {
185
199
  managers: [
186
- ...device.managers,
200
+ ...(device?.managers || []),
187
201
  ...userIdsToAdd
188
202
  ]
189
203
  }, userInfo);
@@ -210,12 +224,12 @@ const GroupsDevices = ({ userInfo, handleGetUsersList, handleAddUserToGroup, han
210
224
  const devicesPatched = await handleRemoveDevicesFromGroup(userInfo, selectedGroup, devicesToPatch);
211
225
  if (devicesPatched && devicesPatched.length > 0) {
212
226
  for (const device of devicesToPatch) {
213
- if (device.managers.length > 0) {
214
- let managersToKeep = device.managers || [];
227
+ if (device.managers && device.managers.length > 0) {
228
+ let managersToKeep = device.managers;
215
229
  for (const manager of device.managers) {
216
230
  // should check if device is present in other groups the user is member of
217
- const groupsData = await handleGetGroups(1008, { role: 'support', uid: manager });
218
- const userGroupIds = groupsData.map((group) => group.id);
231
+ const groupsData = await handleGetGroups({ role: 'support', uid: manager });
232
+ const userGroupIds = groupsData && groupsData.map((group) => group.id) || [];
219
233
  const found = device.groups && device.groups.some((gID) => userGroupIds.includes(gID));
220
234
  if (!found) {
221
235
  // @ts-ignore
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iotready/nextjs-components-library",
3
- "version": "1.0.0-preview2",
3
+ "version": "1.0.0-preview21",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
6
  "build": "rm -rf dist && tsc --project tsconfig.build.json && cp package.json dist/",
@@ -19,6 +19,7 @@
19
19
  "chartjs-adapter-moment": "^1.0.1",
20
20
  "chartjs-plugin-annotation": "^3.1.0",
21
21
  "chartjs-plugin-zoom": "^2.0.1",
22
+ "csv-parse": "^5.6.0",
22
23
  "firebase": "^10.13.1",
23
24
  "leaflet": "^1.9.4",
24
25
  "leaflet-defaulticon-compatibility": "^0.1.2",
@@ -42,4 +43,4 @@
42
43
  "eslint-config-next": "14.2.9",
43
44
  "typescript": "^5"
44
45
  }
45
- }
46
+ }
@@ -0,0 +1,4 @@
1
+ import { FirebaseConfig } from "./types";
2
+ export declare const getAnnotations: (firebaseConfig: FirebaseConfig, deviceID: number) => Promise<{
3
+ id: string;
4
+ }[]>;
@@ -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
- export type FirebaseConfig = {
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
  }[]>;
@@ -2,3 +2,4 @@ export * from "./groups";
2
2
  export * from "./influx";
3
3
  export * from "./logto";
4
4
  export * from "./trackle";
5
+ export * from "./annotations";
@@ -3,3 +3,4 @@ export * from "./groups";
3
3
  export * from "./influx";
4
4
  export * from "./logto";
5
5
  export * from "./trackle";
6
+ export * from "./annotations";
@@ -1,13 +1,5 @@
1
- export type InfluxConfig = {
2
- url: string;
3
- accessToken: string;
4
- bucket: string;
5
- orgId: string;
6
- measurement: string;
7
- dbName: string;
8
- username: string;
9
- password: string;
10
- };
11
- export declare function getInfluxDataV1(influxConfig: InfluxConfig, field: string, timeStart: number, timeEnd: number, deviceID: string, timeGroup: string, raw: boolean): Promise<any>;
12
- export declare function getManyMeasuresV1(influxConfig: InfluxConfig, fields: string[], limit: number, offset: number, sort: any, deviceID: string, timeStart?: number, timeEnd?: number): Promise<any>;
13
- export declare function getFirstTimestamp(influxConfig: InfluxConfig, deviceID: string): Promise<any>;
1
+ import { FilterTagMode, 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 getDwSlots(influxConfig: InfluxConfig, timeStart: number, timeEnd: number, deviceID: string): Promise<any>;
4
+ export declare function getInfluxDataV1(influxConfig: InfluxConfig, field: string, timeStart: number, timeEnd: number, deviceID: string, timeGroup: string, raw: boolean, fill?: InfluxFillType, filterTag?: number, tagInclude?: FilterTagMode): Promise<any>;
5
+ export declare function exportDataV1(influxConfig: InfluxConfig, field: string, timeStart: number, timeEnd: number, deviceID: string): Promise<any>;
@@ -1,55 +1,175 @@
1
1
  "use server";
2
+ import { parse } from "csv-parse";
2
3
  import moment from "moment";
3
- /* export async function getInfluxDataV2(influxConfig: InfluxConfig, field: string, timeStart: string, timeEnd: string, deviceID: string, timeGroup: string, raw: boolean): Promise<Point[]> {
4
- const query = `
5
- from(bucket: "${influxConfig.bucket}")
6
- |> range(start: ${timeStart}, stop: ${timeEnd})
7
- |> filter(fn: (r) => r._measurement == "${influxConfig.measurement}")
8
- |> filter(fn: (r) => r["_field"] == "${field}")
9
- |> filter(fn: (r) => r["deviceid"] == "${deviceID}")
10
- |> aggregateWindow(every: ${timeGroup}m, fn: last, createEmpty: false)
11
- |> yield(name: "last")
4
+ import { FilterTagMode } from "./types";
5
+ export async function getInfluxAlerts(influxConfig, fields, limit, offset, sort, deviceID, timeStart, timeEnd) {
6
+ const conditions = fields
7
+ .map((field) => `r["valueName"] == "${field}"`)
8
+ .join(" or ");
9
+ let query = `
10
+ import "contrib/tomhollingworth/events"
11
+ from(bucket: "${influxConfig.bucket}")`;
12
+ if (timeStart && timeEnd) {
13
+ query += ` |> range(start: ${timeStart}, stop: ${timeEnd})`;
14
+ }
15
+ query += `
16
+ |> filter(fn: (r) => r["_measurement"] == "${influxConfig.measurement}" and r["deviceid"] == "${deviceID}" and (${conditions}))
17
+ `;
18
+ // Add filter for tag d === 3
19
+ query += `
20
+ |> filter(fn: (r) => r["d"] == "3" or r["d"] !~ /./) // Include only events with tag d == 3 or no tag d
21
+ `;
22
+ const queryCount = `${query} |> group() |> count()`;
23
+ query += `
24
+ |> sort(columns: ["_time"]) // Ordina gli eventi cronologicamente
25
+ |> group(columns: ["valueName"]) // Raggruppa per il tag
26
+ |> events.duration(unit: 1s, stop: 2020-01-02T00:00:00Z)
27
+ |> keep(columns: ["_time", "valueName", "_value", "duration"])
28
+ |> group() // Raggruppa tutti i dati in un unico gruppo
29
+ `;
30
+ if (sort && sort.field === "time" && sort.sort === "desc") {
31
+ query += ` |> sort(columns: ["_time"], desc: true)`;
32
+ }
33
+ else {
34
+ query += ` |> sort(columns: ["_time"])`;
35
+ }
36
+ query += ` |> limit(n:${limit}, offset:${offset})`;
37
+ const responses = await Promise.all([
38
+ fetch(encodeURI(`${influxConfig.url}/api/v2/query?org=${influxConfig.orgId}`), {
39
+ method: "POST",
40
+ headers: {
41
+ Authorization: `Token ${influxConfig.accessToken}`,
42
+ "Content-Type": "application/json"
43
+ },
44
+ body: JSON.stringify({
45
+ query: query,
46
+ type: "flux"
47
+ })
48
+ }),
49
+ fetch(encodeURI(`${influxConfig.url}/api/v2/query?org=${influxConfig.orgId}`), {
50
+ method: "POST",
51
+ headers: {
52
+ Authorization: `Token ${influxConfig.accessToken}`,
53
+ "Content-Type": "application/json"
54
+ },
55
+ body: JSON.stringify({
56
+ query: queryCount,
57
+ type: "flux"
58
+ })
59
+ })
60
+ ]);
61
+ if (!responses[0].ok) {
62
+ throw new Error(`Failed to fetch data from InfluxDB: ${responses[0].statusText}`);
63
+ }
64
+ const data = await responses[0].text();
65
+ const count = await responses[1].text();
66
+ const rows = [];
67
+ const parsedData = parse(data.trim(), { columns: true });
68
+ parsedData.forEach((row) => {
69
+ rows.push({
70
+ time: row["_time"],
71
+ duration: parseInt(row["duration"], 10),
72
+ value: parseInt(row["_value"], 10),
73
+ valueName: row["valueName"]
74
+ });
75
+ });
76
+ const parsedCount = count.split("\n")[1].split(",");
77
+ let countData = parsedCount[5];
78
+ return {
79
+ data: rows,
80
+ count: countData
81
+ };
82
+ }
83
+ export async function getDwSlots(influxConfig, timeStart, timeEnd, deviceID) {
84
+ const field = "dw";
85
+ const query = `
86
+ SELECT ("value") FROM "${influxConfig.measurement}"
87
+ WHERE "deviceid" = '${deviceID}'
88
+ AND "valueName" = '${field}'
89
+ AND time >= '${moment.unix(timeStart).toISOString()}'
90
+ AND time <= '${moment.unix(timeEnd).toISOString()}'
12
91
  `;
13
-
14
- const response = await fetch(`${influxConfig.url}/api/v2/query?org=${influxConfig.orgId}`, {
15
- method: 'POST',
16
- headers: {
17
- 'Content-Type': 'application/json',
18
- 'Authorization': `Token ${influxConfig.accessToken}`,
19
- 'Accept': 'application/csv'
20
- },
21
- body: JSON.stringify({
22
- query: query
23
- })
24
- });
25
- if (!response.ok) {
26
- throw new Error(`Failed to fetch data from InfluxDB: ${response.statusText}`);
27
- }
28
- const data = await response.text();
29
- return data.split('\n').map(line => {
30
- const row = line.split(',');
31
- const timestamp = row[5];
32
- const value = parseFloat(row[6]);
33
- console.log(timestamp, value);
34
- if (isNaN(value)) {
35
- return null;
36
- }
37
- return { x: new Date(timestamp).getTime(), y: value };
38
- }).filter(point => point !== null);
39
- }*/ // NOT WORKING, NEED TO FIX
40
- export async function getInfluxDataV1(influxConfig, field, timeStart, timeEnd, deviceID, timeGroup, raw) {
92
+ const response = await fetch(encodeURI(`${influxConfig.url}/query?db=${influxConfig.dbName}&epoch=s&q=${query}`), {
93
+ headers: {
94
+ Authorization: `Basic ${btoa(`${influxConfig.username}:${influxConfig.password}`)}`
95
+ }
96
+ });
97
+ if (!response.ok) {
98
+ throw new Error(`Failed to fetch DW data: ${response.statusText}`);
99
+ }
100
+ const data = await response.json();
101
+ const series = data?.results?.[0]?.series?.[0];
102
+ if (!series?.values || !Array.isArray(series.values)) {
103
+ return data; // niente da fare, ritorna i dati grezzi
104
+ }
105
+ const values = series.values;
106
+ // Modifiche ai valori
107
+ if (values.length > 0) {
108
+ // Aggiungi punto all'inizio se il primo valore è 0
109
+ if (values[0][1] === 0) {
110
+ values.unshift([moment.unix(timeStart).unix(), 1]);
111
+ }
112
+ // Aggiungi punto alla fine se l'ultimo valore è 1
113
+ if (values[values.length - 1][1] === 1) {
114
+ values.push([moment.unix(timeEnd).unix(), 0]);
115
+ }
116
+ }
117
+ return data; // stessa struttura di Influx, con values modificati
118
+ }
119
+ export async function getInfluxDataV1(influxConfig, field, timeStart, timeEnd, deviceID, timeGroup, raw, fill, filterTag, tagInclude = FilterTagMode.Include) {
41
120
  let query;
121
+ let preStartValue = null;
122
+ // Costruzione filtro tag
123
+ let filterTagCondition = "";
124
+ if (filterTag !== undefined && filterTag !== null) {
125
+ switch (tagInclude) {
126
+ case FilterTagMode.Include:
127
+ filterTagCondition = ` AND ("d" = '${filterTag}' OR "d" !~ /./)`;
128
+ break;
129
+ case FilterTagMode.Exclude:
130
+ filterTagCondition = ` AND ("d" != '${filterTag}' OR "d" !~ /./)`;
131
+ break;
132
+ case FilterTagMode.DW:
133
+ filterTagCondition = ` AND "d" = '${filterTag}'`;
134
+ break;
135
+ }
136
+ }
42
137
  if (raw) {
43
- query = `SELECT ("value") FROM "${influxConfig.measurement}" WHERE "deviceid" = '${deviceID}' AND "valueName" = '${field}' AND time >= '${moment
138
+ query = `SELECT ("value") FROM "${influxConfig.measurement}" WHERE "deviceid" = '${deviceID}' AND "valueName" = '${field}'${filterTagCondition} AND time >= '${moment
44
139
  .unix(timeStart)
45
140
  .toISOString()}' AND time <= '${moment.unix(timeEnd).toISOString()}'`;
46
141
  }
47
142
  else {
48
- query = `SELECT last("value") FROM "${influxConfig.measurement}" WHERE "deviceid" = '${deviceID}' AND "valueName" = '${field}' AND time >= '${moment
143
+ query = `SELECT last("value") FROM "${influxConfig.measurement}" WHERE "deviceid" = '${deviceID}' AND "valueName" = '${field}'${filterTagCondition} AND time >= '${moment
49
144
  .unix(timeStart)
50
145
  .toISOString()}' AND time <= '${moment
51
146
  .unix(timeEnd)
52
- .toISOString()}' GROUP BY time(${timeGroup}) fill(null)`;
147
+ .toISOString()}' GROUP BY time(${timeGroup})`;
148
+ if (fill === "none") {
149
+ query += ` fill(none)`;
150
+ }
151
+ else if (fill === "previous") {
152
+ query += ` fill(previous)`;
153
+ }
154
+ else {
155
+ query += ` fill(null)`;
156
+ }
157
+ }
158
+ if (fill) {
159
+ // Query to get the last data point before timeStart
160
+ const preStartQuery = `SELECT last("value") FROM "${influxConfig.measurement}" WHERE "deviceid" = '${deviceID}' AND "valueName" = '${field}'${filterTagCondition} AND time < '${moment
161
+ .unix(timeStart)
162
+ .toISOString()}'`;
163
+ const preStartResponse = await fetch(encodeURI(`${influxConfig.url}/query?db=${influxConfig.dbName}&epoch=s&q=${preStartQuery}`), {
164
+ headers: {
165
+ Authorization: `Basic ${btoa(`${influxConfig.username}:${influxConfig.password}`)}`
166
+ }
167
+ });
168
+ if (!preStartResponse.ok) {
169
+ throw new Error(`Failed to fetch pre-start data from InfluxDB: ${preStartResponse.statusText}`);
170
+ }
171
+ const preStartData = await preStartResponse.json();
172
+ preStartValue = preStartData.results[0].series?.[0]?.values?.[0]?.[1];
53
173
  }
54
174
  const response = await fetch(encodeURI(`${influxConfig.url}/query?db=${influxConfig.dbName}&epoch=s&q=${query}`), {
55
175
  headers: {
@@ -57,7 +177,6 @@ export async function getInfluxDataV1(influxConfig, field, timeStart, timeEnd, d
57
177
  }
58
178
  });
59
179
  if (!response.ok) {
60
- console.log(response);
61
180
  throw new Error(`Failed to fetch data from InfluxDB: ${response.statusText}`);
62
181
  }
63
182
  const data = await response.json();
@@ -72,61 +191,34 @@ export async function getInfluxDataV1(influxConfig, field, timeStart, timeEnd, d
72
191
  }
73
192
  ];
74
193
  }
75
- else {
76
- // Always override the name to be the field
77
- data.results[0].series.forEach((series) => {
78
- series.name = field; // Force the series name to be the field name
79
- });
80
- }
81
- return data;
82
- }
83
- export async function getManyMeasuresV1(influxConfig, fields, limit, offset, sort, deviceID, timeStart, timeEnd) {
84
- if (fields.length > 0) {
85
- const conditions = fields
86
- .map((field) => `"valueName" = '${field}'`)
87
- .join(" OR ");
88
- let queryCount = `SELECT count(*) FROM "${influxConfig.measurement}" WHERE "deviceid" = '${deviceID}' AND (${conditions})`;
89
- let queryPagination = `SELECT "valueName", "value" FROM "${influxConfig.measurement}" WHERE "deviceid" = '${deviceID}' AND (${conditions})`;
90
- if (timeStart) {
91
- queryCount += ` AND time >= '${moment.unix(timeStart).toISOString()}'`;
92
- queryPagination += ` AND time >= '${moment
93
- .unix(timeStart)
94
- .toISOString()}'`;
95
- }
96
- if (timeEnd) {
97
- queryCount += ` AND time <= '${moment.unix(timeEnd).toISOString()}'`;
98
- queryPagination += ` AND time <= '${moment.unix(timeEnd).toISOString()}'`;
99
- }
100
- if (sort && sort.field === "time") {
101
- queryPagination = `${queryPagination} ORDER BY "${sort.field}" ${sort.sort}`;
102
- }
103
- queryPagination = `${queryPagination} LIMIT ${limit} OFFSET ${offset}`;
104
- const responses = await Promise.all([
105
- fetch(encodeURI(`${influxConfig.url}/query?db=${influxConfig.dbName}&epoch=s&q=${queryPagination}`), {
106
- headers: {
107
- Authorization: `Basic ${btoa(`${influxConfig.username}:${influxConfig.password}`)}`
108
- }
109
- }),
110
- fetch(encodeURI(`${influxConfig.url}/query?db=${influxConfig.dbName}&epoch=s&q=${queryCount}`), {
111
- headers: {
112
- Authorization: `Basic ${btoa(`${influxConfig.username}:${influxConfig.password}`)}`
113
- }
114
- })
115
- ]);
116
- if (!responses[0].ok) {
117
- throw new Error(`Failed to fetch data from InfluxDB: ${responses[0].statusText}`);
194
+ // Always override the name to be the field
195
+ data.results[0].series.forEach((series) => {
196
+ series.name = field; // Force the series name to be the field name
197
+ });
198
+ // 1000000 REMOVED AND ADDED TO MOVE THE POINT AWAY IN THE CHART
199
+ if (fill) {
200
+ if (preStartValue !== null && preStartValue !== undefined) {
201
+ // Insert the pre-start value at the beginning of the dataset
202
+ data.results[0].series[0].values.unshift([
203
+ timeStart - 1000000,
204
+ preStartValue
205
+ ]);
118
206
  }
119
- const data = await responses[0].json();
120
- const count = await responses[1].json();
121
- return { data, count };
122
- }
123
- else {
124
- return null;
207
+ // Set the last point as the timeEnd and last value of the dataset
208
+ const lastSeries = data.results[0].series[0];
209
+ const lastValue = lastSeries?.values &&
210
+ lastSeries.values.length > 0 &&
211
+ lastSeries.values.slice(-1)[0].length > 1
212
+ ? lastSeries.values.slice(-1)[0][1]
213
+ : null;
214
+ data.results[0].series[0].values.push([timeEnd + 1000000, lastValue]);
125
215
  }
216
+ return data;
126
217
  }
127
- export async function getFirstTimestamp(influxConfig, deviceID) {
128
- // Query per ottenere il primo timestamp e il valore ordinato per "time" in modo crescente
129
- const query = `SELECT "time", "value" FROM "${influxConfig.measurement}" WHERE "deviceid" = '${deviceID}' ORDER BY time ASC LIMIT 1`;
218
+ export async function exportDataV1(influxConfig, field, timeStart, timeEnd, deviceID) {
219
+ const query = `SELECT ("value") FROM "${influxConfig.measurement}" WHERE "deviceid" = '${deviceID}' AND "valueName" = '${field}' AND time >= '${moment
220
+ .unix(timeStart)
221
+ .toISOString()}' AND time <= '${moment.unix(timeEnd).toISOString()}'`;
130
222
  const response = await fetch(encodeURI(`${influxConfig.url}/query?db=${influxConfig.dbName}&epoch=s&q=${query}`), {
131
223
  headers: {
132
224
  Authorization: `Basic ${btoa(`${influxConfig.username}:${influxConfig.password}`)}`
@@ -136,10 +228,22 @@ export async function getFirstTimestamp(influxConfig, deviceID) {
136
228
  throw new Error(`Failed to fetch data from InfluxDB: ${response.statusText}`);
137
229
  }
138
230
  const data = await response.json();
139
- // Verifica che ci siano risultati nella risposta
140
- if (data?.results[0]?.series && data?.results[0]?.series[0]?.values[0]?.[0]) {
141
- // Ritorna il primo timestamp
142
- return data.results[0].series[0].values[0][0];
231
+ // Ensure the name is manually set to the field
232
+ if (!data.results[0].series) {
233
+ // Set default value with null time and null value
234
+ data.results[0].series = [
235
+ {
236
+ name: field, // Manually set the series name as the field
237
+ columns: ["time", "value"],
238
+ values: [] // Set null point for time and value
239
+ }
240
+ ];
241
+ }
242
+ else {
243
+ // Always override the name to be the field
244
+ data.results[0].series.forEach((series) => {
245
+ series.name = field; // Force the series name to be the field name
246
+ });
143
247
  }
144
- return null; // Se non ci sono record, ritorna null
248
+ return data;
145
249
  }
@@ -1,19 +1,20 @@
1
1
  export type TrackleConfig = {
2
+ orgName: string;
2
3
  apiUrl: string;
3
- createCustomerUrl: string;
4
4
  clientId: string;
5
5
  clientSecret: string;
6
6
  tokenUrl: string;
7
7
  cookieName: string;
8
8
  cookieSecure: boolean;
9
9
  apiTimeout: number;
10
+ productID: number;
10
11
  };
11
12
  export declare function logOut(trackleConfig: TrackleConfig): Promise<void>;
12
13
  export declare function createCustomer(trackleConfig: TrackleConfig, uid: string): Promise<{
13
14
  organization: string;
14
15
  uid: string;
15
16
  }>;
16
- export declare function getDevices(trackleConfig: TrackleConfig, productId?: number, uid?: string, group?: string, selected?: string): Promise<{
17
+ export declare function getDevices(trackleConfig: TrackleConfig, productId?: number, uid?: string, query?: string): Promise<{
17
18
  devices: any[];
18
19
  }>;
19
20
  export declare function getDevice(trackleConfig: TrackleConfig, id: string, productId?: number, uid?: string): Promise<{
@@ -48,32 +48,19 @@ export async function logOut(trackleConfig) {
48
48
  cookies().delete(trackleConfig.cookieName);
49
49
  }
50
50
  export async function createCustomer(trackleConfig, uid) {
51
- return await wretch(trackleConfig.createCustomerUrl)
51
+ return await wretch(`${trackleConfig.apiUrl}/orgs/${trackleConfig.orgName}/customers`)
52
52
  .headers({
53
53
  Authorization: `Basic ${btoa(`${trackleConfig.clientId}:${trackleConfig.clientSecret}`)}`
54
54
  })
55
55
  .post({ uid })
56
56
  .json();
57
57
  }
58
- export async function getDevices(trackleConfig, productId, uid, group, selected) {
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?${queryParams}`
76
- : `/products/${productId}/devices?${queryParams}`)
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);