@iotready/nextjs-components-library 1.0.0-preview23 → 1.0.0-preview25
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.js +9 -21
- package/components/groups/GroupUpdate.d.ts +3 -7
- package/components/groups/GroupUpdate.js +1 -31
- package/components/groups/GroupsDevices.d.ts +11 -9
- package/components/groups/GroupsDevices.js +24 -68
- package/components/groups/Map.d.ts +3 -8
- package/package.json +1 -1
- package/server-actions/groups.d.ts +4 -1
- package/server-actions/groups.js +17 -5
- package/server-actions/influx.js +2 -2
- package/server-actions/trackle.d.ts +3 -2
- package/server-actions/trackle.js +8 -4
- 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
|
@@ -21,6 +21,7 @@ import { ThemeProvider } from '@mui/material/styles';
|
|
|
21
21
|
import TimelineIcon from '@mui/icons-material/Timeline';
|
|
22
22
|
import MuiTooltip from '@mui/material/Tooltip';
|
|
23
23
|
import EditNoteIcon from '@mui/icons-material/EditNote';
|
|
24
|
+
// import AspectRatioIcon from '@mui/icons-material/AspectRatio';
|
|
24
25
|
import { FilterTagMode } from '../../server-actions/types';
|
|
25
26
|
const lineOptions = {
|
|
26
27
|
parsing: false,
|
|
@@ -126,15 +127,6 @@ const chartConfigByPeriod = {
|
|
|
126
127
|
scaleUnit: 'year',
|
|
127
128
|
}
|
|
128
129
|
};
|
|
129
|
-
// function getChartPoints(data: any): Point[] {
|
|
130
|
-
// const points: Point[] = data.results[0].series[0].values.map((row: any) => {
|
|
131
|
-
// return {
|
|
132
|
-
// x: moment.unix(row[0]),
|
|
133
|
-
// y: row[1]
|
|
134
|
-
// }
|
|
135
|
-
// });
|
|
136
|
-
// return points;
|
|
137
|
-
// }
|
|
138
130
|
function getPollTime(intervalInSeconds, pollTime) {
|
|
139
131
|
const CalculatedPollTime = Math.round(intervalInSeconds / 2880);
|
|
140
132
|
if (CalculatedPollTime <= pollTime) {
|
|
@@ -195,8 +187,8 @@ function getCsvData(data, measures) {
|
|
|
195
187
|
const TrendChart = ({ deviceId, measures1, annotationsDataFn, measures2, enableDatePicker, handleGetInfluxData, handleGetDwSlotsCB, handleExportDataCB, theme, initialTimeStart, initialTimeEnd }) => {
|
|
196
188
|
const [chartJsLoaded, setChartJsLoaded] = useState(false);
|
|
197
189
|
// Dichiarazione di annotationsData come funzione che ritorna una Promise<any>
|
|
198
|
-
const [annotationsData, setAnnotationsData] = useState(
|
|
199
|
-
const [
|
|
190
|
+
const [annotationsData, setAnnotationsData] = useState(null);
|
|
191
|
+
const [annotationsEnabled, setAnnotationsEnabled] = useState(true);
|
|
200
192
|
const [dataMeasures, setDataMeasures] = useState(null);
|
|
201
193
|
const [chartPeriod, setChartPeriod] = useState('1D');
|
|
202
194
|
const [chartPeriodConfig, setChartPeriodConfig] = useState(chartConfigByPeriod['1D']);
|
|
@@ -318,13 +310,13 @@ const TrendChart = ({ deviceId, measures1, annotationsDataFn, measures2, enableD
|
|
|
318
310
|
}
|
|
319
311
|
}, [csvData]);
|
|
320
312
|
useEffect(() => {
|
|
321
|
-
if (annotationsDataFn &&
|
|
313
|
+
if (annotationsDataFn && annotationsEnabled) {
|
|
322
314
|
(async () => {
|
|
323
315
|
const resp = await annotationsDataFn();
|
|
324
316
|
setAnnotationsData(resp);
|
|
325
317
|
})();
|
|
326
318
|
}
|
|
327
|
-
}, [annotationsDataFn,
|
|
319
|
+
}, [annotationsDataFn, annotationsEnabled]);
|
|
328
320
|
function getDwSlotsFromValues(dwValues) {
|
|
329
321
|
const slots = [];
|
|
330
322
|
let start = null;
|
|
@@ -368,11 +360,7 @@ const TrendChart = ({ deviceId, measures1, annotationsDataFn, measures2, enableD
|
|
|
368
360
|
dwPoints = rawDwPoints;
|
|
369
361
|
}
|
|
370
362
|
}
|
|
371
|
-
const
|
|
372
|
-
// Mappa sul formato Point
|
|
373
|
-
const stdPoints = stdRaw
|
|
374
|
-
.map((r) => ({ x: Number(r.x), y: r.y }))
|
|
375
|
-
.filter((p) => p.y !== null);
|
|
363
|
+
const stdPoints = await handleGetInfluxData(measure.name, timeStart, timeEnd, deviceId, polltime, !measure.polltime && rawQuery, !measure.polltime ? "none" : "null", 100, FilterTagMode.Exclude);
|
|
376
364
|
const filtered = dwSlots.length
|
|
377
365
|
? stdPoints.filter((p) => !dwSlots.some(slot => p.x >= slot.start && p.x <= slot.end))
|
|
378
366
|
: stdPoints;
|
|
@@ -443,7 +431,7 @@ const TrendChart = ({ deviceId, measures1, annotationsDataFn, measures2, enableD
|
|
|
443
431
|
const { paddedMin: paddedMin2, paddedMax: paddedMax2 } = getPaddedMinMax(min2, max2);
|
|
444
432
|
// Handle undefined/null annotationsData
|
|
445
433
|
let dynamicAnnotations = {};
|
|
446
|
-
if (Array.isArray(annotationsData) && annotationsData.length > 0 &&
|
|
434
|
+
if (annotationsData && Array.isArray(annotationsData) && annotationsData.length > 0 && annotationsEnabled) {
|
|
447
435
|
dynamicAnnotations = annotationsData.reduce((acc, [timestamp, label], index) => {
|
|
448
436
|
const yVal = paddedMin1 !== null && paddedMin1 !== undefined
|
|
449
437
|
? paddedMin1 + 0.01 * (paddedMax1 - paddedMin1)
|
|
@@ -579,7 +567,7 @@ const TrendChart = ({ deviceId, measures1, annotationsDataFn, measures2, enableD
|
|
|
579
567
|
loadDatasets(chartPeriod).then(() => {
|
|
580
568
|
setChartLoading(false);
|
|
581
569
|
});
|
|
582
|
-
}, [measures1, timeEnd, timeStart, measures2,
|
|
570
|
+
}, [measures1, timeEnd, timeStart, measures2, annotationsEnabled, annotationsData]);
|
|
583
571
|
useEffect(() => {
|
|
584
572
|
const loadZoomPlugin = async () => {
|
|
585
573
|
const zoomPlugin = (await import('chartjs-plugin-zoom')).default;
|
|
@@ -671,7 +659,7 @@ const TrendChart = ({ deviceId, measures1, annotationsDataFn, measures2, enableD
|
|
|
671
659
|
'& .MuiToggleButton-root': {
|
|
672
660
|
color: 'text.primary', fontSize: '0.95rem', fontWeight: 'normal', paddingTop: '6px', paddingBottom: '6px'
|
|
673
661
|
}
|
|
674
|
-
}, 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 !==
|
|
662
|
+
}, 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("span", { children: _jsx(ToggleButton, { value: "check", color: "primary", size: "small", selected: spanGapsOption, disabled: chartLoading, onChange: () => handleSpanGaps(!spanGapsOption), sx: { ml: 1 }, children: _jsx(TimelineIcon, {}) }) }) }), annotationsData !== null && (_jsx(MuiTooltip, { placement: "top", arrow: true, title: "Show annotations", 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' ?
|
|
675
663
|
_jsx(_Fragment, { children: dataMeasures && (dataMeasures.length > 1 || (dataMeasures.length === 1 && dataMeasures[0].data?.length)) ?
|
|
676
664
|
(_jsx(Line, { options: options, data: {
|
|
677
665
|
// datasets: dataMeasures || [{ data: [] }]
|
|
@@ -1,14 +1,10 @@
|
|
|
1
|
-
import { UserType } from '../../types';
|
|
2
|
-
declare const GroupUpdate: ({
|
|
1
|
+
import { AssetType, TrackleDeviceType, UserType } from '../../types';
|
|
2
|
+
declare const GroupUpdate: ({ groupInfo, usersGroup, usersList, devicesList, handleAddUserToGroup, handleRemoveUserFromGroup, handleUpdateGroup, handleDeleteGroup, container, containerProps, afterUpdateCallback, afterRemoveCallback, confirmMui }: {
|
|
3
3
|
userInfo: UserType;
|
|
4
4
|
groupInfo: any;
|
|
5
5
|
usersGroup: any[];
|
|
6
6
|
usersList: any[];
|
|
7
|
-
devicesList:
|
|
8
|
-
id: string;
|
|
9
|
-
state: any;
|
|
10
|
-
managers: any[];
|
|
11
|
-
}[];
|
|
7
|
+
devicesList: AssetType[] | TrackleDeviceType[];
|
|
12
8
|
handleAddUserToGroup: (groupID: string, userName: string, userID: string) => Promise<any>;
|
|
13
9
|
handleRemoveUserFromGroup: (groupID: string, userID: string) => Promise<any>;
|
|
14
10
|
handleUpdateDevice: (id: string, body: any, user: UserType) => Promise<any>;
|
|
@@ -8,15 +8,13 @@ import AddIcon from '@mui/icons-material/Add';
|
|
|
8
8
|
import CloseIcon from '@mui/icons-material/Close';
|
|
9
9
|
import DeleteIcon from '@mui/icons-material/Delete';
|
|
10
10
|
import { LoadingButton } from '@mui/lab';
|
|
11
|
-
const GroupUpdate = ({
|
|
11
|
+
const GroupUpdate = ({ groupInfo, usersGroup, usersList, devicesList, handleAddUserToGroup, handleRemoveUserFromGroup, handleUpdateGroup, handleDeleteGroup, container = 'Box', containerProps = {}, afterUpdateCallback, afterRemoveCallback, confirmMui }) => {
|
|
12
12
|
const [group, setGroup] = useState(groupInfo);
|
|
13
13
|
const [loadingUpdateButton, setLoadingUpdateButton] = useState(false);
|
|
14
14
|
const [loadingRemoveUserButton, setLoadingRemoveUserButton] = useState(false);
|
|
15
15
|
const [loadingAddUserButton, setLoadingAddUserButton] = useState(false);
|
|
16
16
|
const [loadingDeleteGroupButton, setLoadingDeleteGroupButton] = useState(false);
|
|
17
17
|
const [selectedUser, setSelectedUser] = useState(null);
|
|
18
|
-
const [error, setError] = useState(null);
|
|
19
|
-
const [success, setSuccess] = useState(null);
|
|
20
18
|
function handleChange(event) {
|
|
21
19
|
setGroup({ ...group, [event.target.name]: event.target.value });
|
|
22
20
|
}
|
|
@@ -25,23 +23,6 @@ const GroupUpdate = ({ userInfo, groupInfo, usersGroup, usersList, devicesList,
|
|
|
25
23
|
try {
|
|
26
24
|
const response = await handleRemoveUserFromGroup(group.id, userId);
|
|
27
25
|
if (response) {
|
|
28
|
-
if (devicesList.length > 0) {
|
|
29
|
-
// should check if device is present in other groups the user is member of
|
|
30
|
-
const groupsData = await handleGetGroups({ role: 'support', uid: userId });
|
|
31
|
-
const userGroupIds = groupsData.map((group) => group.id);
|
|
32
|
-
// for all devices in the group set the selectedUser as manager
|
|
33
|
-
for (const device of devicesList) {
|
|
34
|
-
// check device is in a group of user is member of
|
|
35
|
-
const found = device.state.groups.some((gID) => userGroupIds.includes(gID));
|
|
36
|
-
if (!found) {
|
|
37
|
-
// remove user from managers
|
|
38
|
-
const managers = device.managers && device.managers.filter(man => man !== userId) || [];
|
|
39
|
-
await handleUpdateDevice(device.id, {
|
|
40
|
-
managers
|
|
41
|
-
}, userInfo);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
26
|
if (afterUpdateCallback) {
|
|
46
27
|
await afterUpdateCallback(group);
|
|
47
28
|
}
|
|
@@ -60,17 +41,6 @@ const GroupUpdate = ({ userInfo, groupInfo, usersGroup, usersList, devicesList,
|
|
|
60
41
|
try {
|
|
61
42
|
const response = await handleAddUserToGroup(group.id, selectedUser.label, selectedUser.id);
|
|
62
43
|
if (response) {
|
|
63
|
-
if (devicesList.length > 0) {
|
|
64
|
-
for (const device of devicesList) {
|
|
65
|
-
// for all devices in the group set the selectedUser as manager
|
|
66
|
-
await handleUpdateDevice(device.id, {
|
|
67
|
-
managers: [
|
|
68
|
-
...(device?.managers || []),
|
|
69
|
-
selectedUser.id
|
|
70
|
-
]
|
|
71
|
-
}, userInfo);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
44
|
if (afterUpdateCallback) {
|
|
75
45
|
await afterUpdateCallback(group);
|
|
76
46
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { UserType } from '../../types/user';
|
|
2
|
-
import { Position } from "./Map";
|
|
3
1
|
import { Theme } from "@emotion/react";
|
|
4
|
-
|
|
2
|
+
import { UserType, AssetType, DevicePositionType, TrackleDeviceType } from "../../types";
|
|
3
|
+
declare const GroupsDevices: ({ userInfo, handleGetUsersList, handleAddUserToGroup, handleRemoveUserFromGroup, handleGetGroups, handleGetUsersGroup, handleGetDevices, handleUpdateDevice, handleGetPositions, handleAddDevicesToGroup, handleRemoveDevicesFromGroup, handleCreateGroup, handleDeleteGroup, handleUpdateGroup, group, columnsArray, containerDataGrid, props, propsDatagrid, loadingComponent, containerProps, enableMaps, mapsHeight, mapsClickCallback, theme, confirmMui, propsHeaderGroups, forceGetDevices, groupsLabelAll }: {
|
|
5
4
|
userInfo: UserType;
|
|
6
5
|
handleGetUsersList: ({ page, pageSize }: {
|
|
7
6
|
page: number;
|
|
@@ -14,24 +13,27 @@ declare const GroupsDevices: ({ userInfo, handleGetUsersList, handleAddUserToGro
|
|
|
14
13
|
handleGetGroups: (userInfo?: UserType) => Promise<any>;
|
|
15
14
|
handleGetUsersGroup: (groupID: string) => Promise<any>;
|
|
16
15
|
handleCreateGroup: (group: any) => Promise<any>;
|
|
17
|
-
handleGetDevices: (user: UserType,
|
|
18
|
-
handleGetPositions
|
|
19
|
-
handleAddDevicesToGroup: (user: UserType, group: string, devicesToPatch:
|
|
20
|
-
handleRemoveDevicesFromGroup: (user: UserType, group: string, devicesToPatch:
|
|
16
|
+
handleGetDevices: (user: UserType, group: string, selectedGroup: string) => Promise<AssetType[] | TrackleDeviceType[]>;
|
|
17
|
+
handleGetPositions?: (devices: any) => Promise<DevicePositionType[]>;
|
|
18
|
+
handleAddDevicesToGroup: (user: UserType, group: string, devicesToPatch: AssetType[] | TrackleDeviceType[]) => Promise<TrackleDeviceType[]>;
|
|
19
|
+
handleRemoveDevicesFromGroup: (user: UserType, group: string, devicesToPatch: AssetType[] | TrackleDeviceType[]) => Promise<TrackleDeviceType[]>;
|
|
21
20
|
handleDeleteGroup: (id: string) => Promise<void>;
|
|
22
21
|
handleUpdateGroup: (id: string, group: any) => Promise<void>;
|
|
23
|
-
handleUpdateDevice: (id: string, body: any, user: UserType) => Promise<
|
|
22
|
+
handleUpdateDevice: (id: string, body: any, user: UserType) => Promise<void>;
|
|
24
23
|
group: string;
|
|
25
24
|
columnsArray: any[];
|
|
26
25
|
containerDataGrid?: "Card" | "Box";
|
|
27
26
|
props?: any;
|
|
28
27
|
propsDatagrid?: any;
|
|
28
|
+
propsHeaderGroups?: any;
|
|
29
29
|
loadingComponent?: React.ReactNode;
|
|
30
30
|
containerProps?: any;
|
|
31
31
|
enableMaps?: boolean;
|
|
32
32
|
mapsHeight: string;
|
|
33
|
-
mapsClickCallback?: (position:
|
|
33
|
+
mapsClickCallback?: (position: DevicePositionType) => void;
|
|
34
34
|
theme: Theme;
|
|
35
35
|
confirmMui?: (options?: any) => Promise<void>;
|
|
36
|
+
forceGetDevices: number;
|
|
37
|
+
groupsLabelAll?: string;
|
|
36
38
|
}) => string | number | bigint | boolean | import("react/jsx-runtime").JSX.Element | Iterable<import("react").ReactNode> | Promise<import("react").AwaitedReactNode> | null;
|
|
37
39
|
export default GroupsDevices;
|
|
@@ -15,8 +15,8 @@ import GroupUpdate from "./GroupUpdate";
|
|
|
15
15
|
import BackIcon from '@mui/icons-material/ArrowBack';
|
|
16
16
|
import dynamic from "next/dynamic";
|
|
17
17
|
import { ThemeProvider } from '@mui/material/styles';
|
|
18
|
-
const GroupsDevices = ({ userInfo, handleGetUsersList, handleAddUserToGroup, handleRemoveUserFromGroup, handleGetGroups, handleGetUsersGroup, handleGetDevices, handleUpdateDevice, handleGetPositions, handleAddDevicesToGroup, handleRemoveDevicesFromGroup, handleCreateGroup, handleDeleteGroup, handleUpdateGroup, group = 'all', columnsArray = [], containerDataGrid = 'Card', props = {}, propsDatagrid = {}, loadingComponent = _jsx(CircularProgress, {}), containerProps = {}, enableMaps = true, mapsHeight = '400px', mapsClickCallback = () => { }, theme, confirmMui }) => {
|
|
19
|
-
const [devices, setDevices] = useState(
|
|
18
|
+
const GroupsDevices = ({ userInfo, handleGetUsersList, handleAddUserToGroup, handleRemoveUserFromGroup, handleGetGroups, handleGetUsersGroup, handleGetDevices, handleUpdateDevice, handleGetPositions, handleAddDevicesToGroup, handleRemoveDevicesFromGroup, handleCreateGroup, handleDeleteGroup, handleUpdateGroup, group = 'all', columnsArray = [], containerDataGrid = 'Card', props = {}, propsDatagrid = {}, loadingComponent = _jsx(CircularProgress, {}), containerProps = {}, enableMaps = true, mapsHeight = '400px', mapsClickCallback = () => { }, theme, confirmMui, propsHeaderGroups, forceGetDevices, groupsLabelAll }) => {
|
|
19
|
+
const [devices, setDevices] = useState([]);
|
|
20
20
|
const [positions, setPositions] = useState([]);
|
|
21
21
|
const [loadingDevices, setLoadingDevices] = useState(false);
|
|
22
22
|
const [loadingGroups, setLoadingGroups] = useState(false);
|
|
@@ -73,22 +73,9 @@ const GroupsDevices = ({ userInfo, handleGetUsersList, handleAddUserToGroup, han
|
|
|
73
73
|
const fetchDevices = async (group, selected) => {
|
|
74
74
|
try {
|
|
75
75
|
setLoadingDevices(true);
|
|
76
|
-
|
|
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);
|
|
76
|
+
const devices = await handleGetDevices(userInfo, group, selected);
|
|
90
77
|
setDevices(devices);
|
|
91
|
-
if (enableMaps) {
|
|
78
|
+
if (enableMaps && handleGetPositions) {
|
|
92
79
|
const positions = await handleGetPositions(devices);
|
|
93
80
|
setPositions(positions);
|
|
94
81
|
}
|
|
@@ -138,6 +125,11 @@ const GroupsDevices = ({ userInfo, handleGetUsersList, handleAddUserToGroup, han
|
|
|
138
125
|
fetchDevices(currentGroup, currentGroup);
|
|
139
126
|
}
|
|
140
127
|
}, [currentGroup]);
|
|
128
|
+
useEffect(() => {
|
|
129
|
+
if (forceGetDevices !== 0) {
|
|
130
|
+
fetchDevices(currentGroup, currentGroup);
|
|
131
|
+
}
|
|
132
|
+
}, [forceGetDevices]);
|
|
141
133
|
const handleSubmit = async (e) => {
|
|
142
134
|
e.preventDefault();
|
|
143
135
|
setLoadingAdd(true);
|
|
@@ -186,28 +178,12 @@ const GroupsDevices = ({ userInfo, handleGetUsersList, handleAddUserToGroup, han
|
|
|
186
178
|
const addToSelectedGroup = async () => {
|
|
187
179
|
setLoadingGroups(true);
|
|
188
180
|
try {
|
|
189
|
-
const
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
if (userIdsToAdd && userIdsToAdd.length > 0) {
|
|
196
|
-
for (const device of devicesToPatch) {
|
|
197
|
-
// add members to devices managers
|
|
198
|
-
await handleUpdateDevice(device.id, {
|
|
199
|
-
managers: [
|
|
200
|
-
...(device?.managers || []),
|
|
201
|
-
...userIdsToAdd
|
|
202
|
-
]
|
|
203
|
-
}, userInfo);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
setLoadingGroups(false);
|
|
207
|
-
setCurrentGroup(selectedGroup);
|
|
208
|
-
setDevicesToAdd([...[]]);
|
|
209
|
-
fetchDevices(selectedGroup, selectedGroup);
|
|
210
|
-
}
|
|
181
|
+
const devicesToPatch = devices.filter((row) => devicesToAdd.includes(row.id));
|
|
182
|
+
await handleAddDevicesToGroup(userInfo, selectedGroup, devicesToPatch);
|
|
183
|
+
setLoadingGroups(false);
|
|
184
|
+
setCurrentGroup(selectedGroup);
|
|
185
|
+
setDevicesToAdd([...[]]);
|
|
186
|
+
fetchDevices(selectedGroup, selectedGroup);
|
|
211
187
|
}
|
|
212
188
|
catch (err) {
|
|
213
189
|
console.error(err);
|
|
@@ -220,31 +196,10 @@ const GroupsDevices = ({ userInfo, handleGetUsersList, handleAddUserToGroup, han
|
|
|
220
196
|
setLoadingGroups(true);
|
|
221
197
|
try {
|
|
222
198
|
const devicesToRemove = devices.filter((row) => devicesToAdd.includes(row.id));
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
if (device.managers && device.managers.length > 0) {
|
|
228
|
-
let managersToKeep = device.managers;
|
|
229
|
-
for (const manager of device.managers) {
|
|
230
|
-
// should check if device is present in other groups the user is member of
|
|
231
|
-
const groupsData = await handleGetGroups({ role: 'support', uid: manager });
|
|
232
|
-
const userGroupIds = groupsData && groupsData.map((group) => group.id) || [];
|
|
233
|
-
const found = device.groups && device.groups.some((gID) => userGroupIds.includes(gID));
|
|
234
|
-
if (!found) {
|
|
235
|
-
// @ts-ignore
|
|
236
|
-
managersToKeep = managersToKeep.filter(man => man !== manager);
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
await handleUpdateDevice(device.id, {
|
|
240
|
-
managers: managersToKeep
|
|
241
|
-
}, userInfo);
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
setLoadingGroups(false);
|
|
245
|
-
setDevicesToAdd([]);
|
|
246
|
-
fetchDevices(currentGroup, selectedGroup);
|
|
247
|
-
}
|
|
199
|
+
await handleRemoveDevicesFromGroup(userInfo, selectedGroup, devicesToRemove);
|
|
200
|
+
setLoadingGroups(false);
|
|
201
|
+
setDevicesToAdd([]);
|
|
202
|
+
fetchDevices(currentGroup, selectedGroup);
|
|
248
203
|
}
|
|
249
204
|
catch (err) {
|
|
250
205
|
console.error(err);
|
|
@@ -279,6 +234,7 @@ const GroupsDevices = ({ userInfo, handleGetUsersList, handleAddUserToGroup, han
|
|
|
279
234
|
sorting: {
|
|
280
235
|
sortModel: [{ field: 'online', sort: 'desc' }],
|
|
281
236
|
},
|
|
237
|
+
pagination: { paginationModel: { pageSize: 100 } }
|
|
282
238
|
}, ...propsDatagrid }) }));
|
|
283
239
|
const renderTabContext = (_jsxs(TabContext, { value: valueTab, children: [_jsx(Box, { sx: { borderBottom: 1, borderColor: 'divider' }, children: _jsxs(TabList, { onChange: handleChangeTab, sx: { minHeight: 20 }, children: [_jsx(Tab, { label: "List", value: "1", sx: { minHeight: 20 } }), _jsx(Tab, { label: "Map", value: "2", sx: { minHeight: 20 } })] }) }), _jsx(TabPanel, { value: "1", sx: { p: 0 }, children: renderDataGrid }), _jsx(TabPanel, { value: "2", sx: { p: 0 }, children: renderMaps })] }));
|
|
284
240
|
const renderDatagridAndMaps = (enableMaps ?
|
|
@@ -287,10 +243,10 @@ const GroupsDevices = ({ userInfo, handleGetUsersList, handleAddUserToGroup, han
|
|
|
287
243
|
_jsx(Card, { ...containerProps, children: renderDataGrid }) : _jsx(Box, { ...containerProps, children: renderDataGrid }));
|
|
288
244
|
if (!userInfo || !groups || !devices)
|
|
289
245
|
return loadingComponent;
|
|
290
|
-
return (_jsx(ThemeProvider, { theme: theme, children: _jsxs(Box, { ...props, children: [_jsxs(Box, { component: "div", sx: { display: 'flex', alignItems: 'center',
|
|
291
|
-
_jsx(Autocomplete, { disablePortal: true, onChange: handleChangeGroupSelect, value: groupInfo?.name || 'All devices', disableClearable: currentGroup === 'all', isOptionEqualToValue: (o, v) => o.label === v, options: [{ label: 'All devices', id: 'all' }, ...groups.map((grp) => ({ label: grp.name, id: grp.id }))], sx: { width: { xs: 200, sm: 300 }, textAlign: 'left' }, size: 'small', renderInput: (params) => _jsx(TextField, { ...params, label: "Group" }) })
|
|
246
|
+
return (_jsx(ThemeProvider, { theme: theme, children: _jsxs(Box, { ...props, children: [_jsxs(Box, { component: "div", sx: { display: 'flex', alignItems: 'center', mb: 1, backgroundColor: editGroup ? 'secondary.light' : '', borderRadius: 3, px: editGroup ? 2 : 0, py: 1, height: 50, ...propsHeaderGroups }, children: [editGroup ? _jsxs(Typography, { variant: 'subtitle1', children: [_jsx(Box, { component: 'span', sx: { display: { xs: 'none' } }, children: "Edit group" }), " ", _jsx("b", { children: groupInfo?.name })] }) : '', groups && !checkboxSelection && !(editGroup && currentGroup === 'all') ?
|
|
247
|
+
_jsx(Autocomplete, { disablePortal: true, onChange: handleChangeGroupSelect, value: groupInfo?.name || groupsLabelAll || 'All devices', disableClearable: currentGroup === 'all', isOptionEqualToValue: (o, v) => o.label === v, options: [{ label: groupsLabelAll || 'All devices', id: 'all' }, ...groups.map((grp) => ({ label: grp.name, id: grp.id }))], sx: { width: { xs: 200, sm: 300 }, textAlign: 'left' }, size: 'small', renderInput: (params) => _jsx(TextField, { ...params, label: "Group" }) })
|
|
292
248
|
: '', userInfo.role === 'admin' &&
|
|
293
|
-
_jsxs(Box, { children: [checkboxSelection ?
|
|
249
|
+
_jsxs(Box, { sx: { ml: 2 }, children: [checkboxSelection ?
|
|
294
250
|
_jsx(Input, { value: selectedGroup, type: 'hidden', size: 'small' })
|
|
295
251
|
: '', selectedGroup === 'all' ? _jsxs(Button, { variant: "contained", color: "primary", onClick: () => { handleOpenAdd(); }, children: [_jsx(AddIcon, { sx: { mr: 1 } }), _jsx(Box, { component: 'span', sx: { display: { xs: 'none', sm: 'inline' } }, children: "Create\u00A0" }), " group"] }) : '', editGroup ?
|
|
296
252
|
currentGroup === 'all' ?
|
|
@@ -308,6 +264,6 @@ const GroupsDevices = ({ userInfo, handleGetUsersList, handleAddUserToGroup, han
|
|
|
308
264
|
transform: 'translate(-50%, -50%)',
|
|
309
265
|
width: 400,
|
|
310
266
|
borderRadius: 4
|
|
311
|
-
}, children: [_jsx(CardHeader, { title: "New Group", action: _jsx(IconButton, { onClick: handleCloseAdd, children: _jsx(CloseIcon, {}) }) }), _jsx(CardContent, { children: _jsxs("form", { onSubmit: handleSubmit, children: [_jsx(TextField, { fullWidth: true, label: "Group Name", value: groupName, onChange: (e) => setGroupName(e.target.value), required: true }), _jsx(TextField, { fullWidth: true, label: "Description", value: description, onChange: (e) => setDescription(e.target.value), margin: "normal", multiline: true, rows: 4 }), _jsxs(Box, { mt: 2, display: "flex", justifyContent: "space-between", children: [_jsx(Button, { variant: "contained", color: "info", onClick: handleCloseAdd, children: "Cancel" }), _jsx(LoadingButton, { loading: loadingAdd, variant: "contained", color: "primary", type: "submit", children: "Create" })] })] }) })] }) }), !groupUpdateVisible && renderDatagridAndMaps, groupInfo && editGroup && groupUpdateVisible && _jsx(GroupUpdate, { confirmMui: confirmMui, userInfo: userInfo, usersGroup: usersGroup, usersList: usersList, handleGetGroups: handleGetGroups, handleUpdateDevice: handleUpdateDevice, handleAddUserToGroup: handleAddUserToGroup, handleRemoveUserFromGroup: handleRemoveUserFromGroup, groupInfo: groupInfo, afterUpdateCallback: async (groupInfo) => { setGroupInfo(groupInfo); await getGroups(); await getUsersGroup(groupInfo.id); }, afterRemoveCallback: async () => { closeEditGroup(); await getGroups(); setCurrentGroup('all'); }, container: 'Card', handleDeleteGroup: handleDeleteGroup, handleUpdateGroup: handleUpdateGroup, devicesList: devices
|
|
267
|
+
}, children: [_jsx(CardHeader, { title: "New Group", action: _jsx(IconButton, { onClick: handleCloseAdd, children: _jsx(CloseIcon, {}) }) }), _jsx(CardContent, { children: _jsxs("form", { onSubmit: handleSubmit, children: [_jsx(TextField, { fullWidth: true, label: "Group Name", value: groupName, onChange: (e) => setGroupName(e.target.value), required: true }), _jsx(TextField, { fullWidth: true, label: "Description", value: description, onChange: (e) => setDescription(e.target.value), margin: "normal", multiline: true, rows: 4 }), _jsxs(Box, { mt: 2, display: "flex", justifyContent: "space-between", children: [_jsx(Button, { variant: "contained", color: "info", onClick: handleCloseAdd, children: "Cancel" }), _jsx(LoadingButton, { loading: loadingAdd, variant: "contained", color: "primary", type: "submit", children: "Create" })] })] }) })] }) }), !groupUpdateVisible && renderDatagridAndMaps, groupInfo && editGroup && groupUpdateVisible && _jsx(GroupUpdate, { confirmMui: confirmMui, userInfo: userInfo, usersGroup: usersGroup, usersList: usersList, handleGetGroups: handleGetGroups, handleUpdateDevice: handleUpdateDevice, handleAddUserToGroup: handleAddUserToGroup, handleRemoveUserFromGroup: handleRemoveUserFromGroup, groupInfo: groupInfo, afterUpdateCallback: async (groupInfo) => { setGroupInfo(groupInfo); await getGroups(); await getUsersGroup(groupInfo.id); }, afterRemoveCallback: async () => { closeEditGroup(); await getGroups(); setCurrentGroup('all'); }, container: 'Card', handleDeleteGroup: handleDeleteGroup, handleUpdateGroup: handleUpdateGroup, devicesList: devices })] }) }));
|
|
312
268
|
};
|
|
313
269
|
export default GroupsDevices;
|
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
import 'leaflet/dist/leaflet.css';
|
|
2
2
|
import "leaflet-defaulticon-compatibility";
|
|
3
3
|
import "leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.css";
|
|
4
|
-
|
|
5
|
-
deviceID: string;
|
|
6
|
-
name: string;
|
|
7
|
-
lat: number;
|
|
8
|
-
lng: number;
|
|
9
|
-
};
|
|
4
|
+
import { DevicePositionType } from "../../types/device";
|
|
10
5
|
export default function Map({ positions, height, mapsClickCallback }: {
|
|
11
|
-
positions:
|
|
6
|
+
positions: DevicePositionType[];
|
|
12
7
|
height: string;
|
|
13
|
-
mapsClickCallback: (position:
|
|
8
|
+
mapsClickCallback: (position: DevicePositionType) => void;
|
|
14
9
|
}): import("react/jsx-runtime").JSX.Element;
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Firestore } from "firebase-admin/firestore";
|
|
2
|
-
export declare const getGroups: (db: Firestore, productID: number, userID?: string) => Promise<{
|
|
2
|
+
export declare const getGroups: (db: Firestore, productID: number, userID?: string, assetID?: string) => Promise<{
|
|
3
3
|
id: string;
|
|
4
4
|
}[]>;
|
|
5
5
|
export declare const getGroupById: (db: Firestore, id: string) => Promise<{
|
|
@@ -11,5 +11,8 @@ export declare const deleteGroup: (db: Firestore, id: string) => Promise<void>;
|
|
|
11
11
|
export declare const getUsersGroup: (db: Firestore, groupID: string) => Promise<{
|
|
12
12
|
id: string;
|
|
13
13
|
}[]>;
|
|
14
|
+
export declare const getGroupsUser: (db: Firestore, userID: string) => Promise<{
|
|
15
|
+
id: string;
|
|
16
|
+
}[]>;
|
|
14
17
|
export declare const addUsersGroup: (db: Firestore, groupID: string, userName: string, userID: string) => Promise<string>;
|
|
15
18
|
export declare const removeUserGroup: (db: Firestore, groupID: string, userID: string) => Promise<string | undefined>;
|
package/server-actions/groups.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"use server";
|
|
2
2
|
// 1. GET GROUPS
|
|
3
|
-
export const getGroups = async (db, productID, userID) => {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
.where("
|
|
7
|
-
|
|
3
|
+
export const getGroups = async (db, productID, userID, assetID) => {
|
|
4
|
+
let groupsRef = db.collection("groups").where("productID", "==", productID);
|
|
5
|
+
if (assetID) {
|
|
6
|
+
groupsRef = groupsRef.where("assets", "array-contains", assetID);
|
|
7
|
+
}
|
|
8
|
+
groupsRef = groupsRef.orderBy("created", "desc");
|
|
8
9
|
let groupIds = null;
|
|
9
10
|
if (userID) {
|
|
10
11
|
const userGroupsSnapshot = await db
|
|
@@ -67,6 +68,17 @@ export const getUsersGroup = async (db, groupID) => {
|
|
|
67
68
|
...doc.data()
|
|
68
69
|
}));
|
|
69
70
|
};
|
|
71
|
+
// 6b. GET GROUPS USER
|
|
72
|
+
export const getGroupsUser = async (db, userID) => {
|
|
73
|
+
const snapshot = await db
|
|
74
|
+
.collection("userGroups")
|
|
75
|
+
.where("user.userId", "==", userID)
|
|
76
|
+
.get();
|
|
77
|
+
return snapshot.docs.map((doc) => ({
|
|
78
|
+
id: doc.id,
|
|
79
|
+
...doc.data()
|
|
80
|
+
}));
|
|
81
|
+
};
|
|
70
82
|
// 7. ADD USER TO GROUP
|
|
71
83
|
export const addUsersGroup = async (db, groupID, userName, userID) => {
|
|
72
84
|
const created = new Date().toISOString();
|
package/server-actions/influx.js
CHANGED
|
@@ -155,7 +155,7 @@ export async function getInfluxDataV1(influxConfig, field, timeStart, timeEnd, d
|
|
|
155
155
|
query += ` fill(null)`;
|
|
156
156
|
}
|
|
157
157
|
}
|
|
158
|
-
if (fill) {
|
|
158
|
+
if (fill !== "null") {
|
|
159
159
|
// Query to get the last data point before timeStart
|
|
160
160
|
const preStartQuery = `SELECT last("value") FROM "${influxConfig.measurement}" WHERE "deviceid" = '${deviceID}' AND "valueName" = '${field}'${filterTagCondition} AND time < '${moment
|
|
161
161
|
.unix(timeStart)
|
|
@@ -196,7 +196,7 @@ export async function getInfluxDataV1(influxConfig, field, timeStart, timeEnd, d
|
|
|
196
196
|
series.name = field; // Force the series name to be the field name
|
|
197
197
|
});
|
|
198
198
|
// 1000000 REMOVED AND ADDED TO MOVE THE POINT AWAY IN THE CHART
|
|
199
|
-
if (fill) {
|
|
199
|
+
if (fill !== "null") {
|
|
200
200
|
if (preStartValue !== null && preStartValue !== undefined) {
|
|
201
201
|
// Insert the pre-start value at the beginning of the dataset
|
|
202
202
|
data.results[0].series[0].values.unshift([
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { TrackleDeviceType } from "../types";
|
|
1
2
|
export type TrackleConfig = {
|
|
2
3
|
orgName: string;
|
|
3
4
|
apiUrl: string;
|
|
@@ -32,5 +33,5 @@ export declare function post(trackleConfig: TrackleConfig, id: string, endpoint:
|
|
|
32
33
|
export declare function put(trackleConfig: TrackleConfig, id: string, endpoint: string, value: any, productId?: number, uid?: string): Promise<{
|
|
33
34
|
return_value: number;
|
|
34
35
|
}>;
|
|
35
|
-
export declare function addDevicesToGroup(trackleConfig: TrackleConfig, productId: number, uid: string, group: string, devicesToPatch:
|
|
36
|
-
export declare function removeDevicesFromGroup(trackleConfig: TrackleConfig, productId: number, uid: string, group: string, devicesToPatch:
|
|
36
|
+
export declare function addDevicesToGroup(trackleConfig: TrackleConfig, productId: number, uid: string, group: string, devicesToPatch: TrackleDeviceType[]): Promise<TrackleDeviceType[]>;
|
|
37
|
+
export declare function removeDevicesFromGroup(trackleConfig: TrackleConfig, productId: number, uid: string, group: string, devicesToPatch: TrackleDeviceType[]): Promise<TrackleDeviceType[]>;
|
|
@@ -110,7 +110,9 @@ export async function put(trackleConfig, id, endpoint, value, productId, uid) {
|
|
|
110
110
|
export async function addDevicesToGroup(trackleConfig, productId, uid, group, devicesToPatch) {
|
|
111
111
|
const devicesPatched = [];
|
|
112
112
|
for (const device of devicesToPatch) {
|
|
113
|
-
const newGroups = device?.groups && device?.groups instanceof Array
|
|
113
|
+
const newGroups = device.state?.groups && device.state?.groups instanceof Array
|
|
114
|
+
? device.state?.groups
|
|
115
|
+
: [];
|
|
114
116
|
if (!newGroups.includes(group)) {
|
|
115
117
|
newGroups.push(group);
|
|
116
118
|
await wretchApi(trackleConfig, uid)
|
|
@@ -120,7 +122,7 @@ export async function addDevicesToGroup(trackleConfig, productId, uid, group, de
|
|
|
120
122
|
})
|
|
121
123
|
.setTimeout(trackleConfig.apiTimeout)
|
|
122
124
|
.res();
|
|
123
|
-
devicesPatched.push(device
|
|
125
|
+
devicesPatched.push(device);
|
|
124
126
|
}
|
|
125
127
|
}
|
|
126
128
|
return devicesPatched;
|
|
@@ -128,7 +130,9 @@ export async function addDevicesToGroup(trackleConfig, productId, uid, group, de
|
|
|
128
130
|
export async function removeDevicesFromGroup(trackleConfig, productId, uid, group, devicesToPatch) {
|
|
129
131
|
const devicesPatched = [];
|
|
130
132
|
for (const device of devicesToPatch) {
|
|
131
|
-
let newGroups = device?.groups && device?.groups instanceof Array
|
|
133
|
+
let newGroups = device.state?.groups && device.state?.groups instanceof Array
|
|
134
|
+
? device.state?.groups
|
|
135
|
+
: [];
|
|
132
136
|
if (newGroups.includes(group)) {
|
|
133
137
|
newGroups = newGroups.filter((newGroup) => newGroup !== group);
|
|
134
138
|
await wretchApi(trackleConfig, uid)
|
|
@@ -138,7 +142,7 @@ export async function removeDevicesFromGroup(trackleConfig, productId, uid, grou
|
|
|
138
142
|
})
|
|
139
143
|
.setTimeout(trackleConfig.apiTimeout)
|
|
140
144
|
.res();
|
|
141
|
-
devicesPatched.push(device
|
|
145
|
+
devicesPatched.push(device);
|
|
142
146
|
}
|
|
143
147
|
}
|
|
144
148
|
return devicesPatched;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export type AssetType = {
|
|
2
|
+
id: string;
|
|
3
|
+
device?: TrackleDeviceType;
|
|
4
|
+
[key: string]: any;
|
|
5
|
+
};
|
|
6
|
+
export type TrackleDeviceType = {
|
|
7
|
+
id: string;
|
|
8
|
+
state: {
|
|
9
|
+
groups: string[] | null;
|
|
10
|
+
};
|
|
11
|
+
managers: string[] | null;
|
|
12
|
+
[key: string]: any;
|
|
13
|
+
};
|
|
14
|
+
export type DevicePositionType = {
|
|
15
|
+
deviceID: string;
|
|
16
|
+
name: string;
|
|
17
|
+
lat: number;
|
|
18
|
+
lng: number;
|
|
19
|
+
};
|
package/types/device.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/types/index.d.ts
CHANGED
package/types/index.js
CHANGED