@iotready/nextjs-components-library 1.0.0-preview31 → 1.0.0-preview33
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/groups/GroupUpdate.d.ts +2 -1
- package/components/groups/GroupUpdate.js +2 -2
- package/components/groups/GroupsDevices.d.ts +5 -1
- package/components/groups/GroupsDevices.js +31 -19
- package/components/users/UsersDataGrid.d.ts +1 -1
- package/components/users/UsersDataGrid.js +3 -3
- package/package.json +1 -1
- package/server-actions/groups.d.ts +4 -1
- package/server-actions/groups.js +62 -1
- package/server-actions/trackle.d.ts +2 -2
- package/server-actions/trackle.js +13 -13
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AssetType, TrackleDeviceType, UserType } from '../../types';
|
|
2
|
-
declare const GroupUpdate: ({ groupInfo, usersGroup, usersList, devicesList, handleAddUserToGroup, handleRemoveUserFromGroup, handleUpdateGroup, handleDeleteGroup, container, containerProps, afterUpdateCallback, afterRemoveCallback, confirmMui }: {
|
|
2
|
+
declare const GroupUpdate: ({ labelEntity, 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[];
|
|
@@ -16,5 +16,6 @@ declare const GroupUpdate: ({ groupInfo, usersGroup, usersList, devicesList, han
|
|
|
16
16
|
afterUpdateCallback?: (groupInfo: any) => Promise<void>;
|
|
17
17
|
afterRemoveCallback?: () => Promise<void>;
|
|
18
18
|
confirmMui?: (options?: any) => Promise<void>;
|
|
19
|
+
labelEntity: string;
|
|
19
20
|
}) => import("react/jsx-runtime").JSX.Element;
|
|
20
21
|
export default GroupUpdate;
|
|
@@ -8,7 +8,7 @@ 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 = ({ groupInfo, usersGroup, usersList, devicesList, handleAddUserToGroup, handleRemoveUserFromGroup, handleUpdateGroup, handleDeleteGroup, container = 'Box', containerProps = {}, afterUpdateCallback, afterRemoveCallback, confirmMui }) => {
|
|
11
|
+
const GroupUpdate = ({ labelEntity, 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);
|
|
@@ -97,7 +97,7 @@ const GroupUpdate = ({ groupInfo, usersGroup, usersList, devicesList, handleAddU
|
|
|
97
97
|
_jsx(Table, { size: "small", children: _jsx(TableBody, { children: usersGroup.map((ug) => (_jsxs(TableRow, { children: [_jsx(TableCell, { children: _jsx(Typography, { variant: "body1", children: ug.user.fullName }) }), _jsx(TableCell, { align: 'right', children: _jsx(LoadingButton, { size: "small", color: "error", loading: loadingRemoveUserButton, onClick: () => removeUserFromCurrentGroup(ug.user.userId), children: _jsx(CloseIcon, { sx: { m: 0, p: 0 }, fontSize: "small" }) }) })] }, ug.id))) }) })
|
|
98
98
|
: _jsx(Box, { component: 'div', sx: { mt: 2 }, children: "No members found" }) }), _jsxs(Box, { component: "div", sx: { mt: 4, display: 'flex', alignItems: 'center' }, children: [_jsx(Autocomplete, { fullWidth: true, disablePortal: true, options: usersList || [], value: selectedUser, size: 'small', onChange: (event, newValue) => {
|
|
99
99
|
setSelectedUser(newValue);
|
|
100
|
-
}, renderInput: (params) => _jsx(TextField, { ...params, label: "Select user" }) }), _jsxs(LoadingButton, { variant: "contained", color: "success", loading: loadingAddUserButton, sx: { ml: 2 }, disabled: !selectedUser, onClick: () => addUserToCurrentGroup(), children: [_jsx(AddIcon, { sx: { mr: 1 } }), " Add"] })] }), _jsxs(Box, { component: "div", sx: { mt: 4 }, children: [
|
|
100
|
+
}, renderInput: (params) => _jsx(TextField, { ...params, label: "Select user" }) }), _jsxs(LoadingButton, { variant: "contained", color: "success", loading: loadingAddUserButton, sx: { ml: 2 }, disabled: !selectedUser, onClick: () => addUserToCurrentGroup(), children: [_jsx(AddIcon, { sx: { mr: 1 } }), " Add"] })] }), _jsxs(Box, { component: "div", sx: { mt: 4 }, children: [_jsxs(Typography, { variant: 'body1', sx: { fontWeight: 'bold' }, children: ["Delete ", labelEntity.toLocaleLowerCase()] }), _jsx(Alert, { severity: "error", sx: { mt: 2 }, action: _jsxs(LoadingButton, { variant: "contained", disabled: devicesList.length > 0, color: "error", loading: loadingDeleteGroupButton, onClick: () => deleteGroup(), size: 'small', children: [_jsx(DeleteIcon, { fontSize: "small", sx: { mr: 1 } }), " Delete"] }), children: devicesList.length === 0 ? `This action cannot be undone` : `You must manually remove devices from ${labelEntity.toLocaleLowerCase()} before deletion` })] })] }) })] }));
|
|
101
101
|
};
|
|
102
102
|
return (container === "Card" ? (_jsx(Card, { ...containerProps, children: _jsx(CardContent, { children: renderGroupUpdate() }) })) : (_jsx(Box, { ...containerProps, children: renderGroupUpdate() })));
|
|
103
103
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Theme } from "@emotion/react";
|
|
2
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, customToolbar, groupsLabelAll, addDevicesLabel, groupUpdateRoles }: {
|
|
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, customToolbar, groupsLabelAll, addDevicesLabel, noDevicesLabel, groupUpdateRoles, isOrg, currentOrg, userGroupsRole }: {
|
|
4
4
|
userInfo: UserType;
|
|
5
5
|
handleGetUsersList: ({ page, pageSize }: {
|
|
6
6
|
page: number;
|
|
@@ -22,6 +22,7 @@ declare const GroupsDevices: ({ userInfo, handleGetUsersList, handleAddUserToGro
|
|
|
22
22
|
handleUpdateDevice: (id: string, body: any, user: UserType) => Promise<void>;
|
|
23
23
|
group: string;
|
|
24
24
|
columnsArray: any[];
|
|
25
|
+
userGroupsRole?: string[];
|
|
25
26
|
containerDataGrid?: "Card" | "Box";
|
|
26
27
|
props?: any;
|
|
27
28
|
propsDatagrid?: any;
|
|
@@ -37,6 +38,9 @@ declare const GroupsDevices: ({ userInfo, handleGetUsersList, handleAddUserToGro
|
|
|
37
38
|
customToolbar?: string[];
|
|
38
39
|
groupsLabelAll?: string;
|
|
39
40
|
addDevicesLabel?: string;
|
|
41
|
+
noDevicesLabel?: string;
|
|
40
42
|
groupUpdateRoles?: string[];
|
|
43
|
+
isOrg?: boolean;
|
|
44
|
+
currentOrg?: string;
|
|
41
45
|
}) => string | number | bigint | boolean | import("react/jsx-runtime").JSX.Element | Iterable<import("react").ReactNode> | Promise<import("react").AwaitedReactNode> | null;
|
|
42
46
|
export default GroupsDevices;
|
|
@@ -15,13 +15,13 @@ 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, propsHeaderGroups, forceGetDevices, customToolbar, groupsLabelAll, addDevicesLabel, groupUpdateRoles }) => {
|
|
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 = 0, customToolbar, groupsLabelAll, addDevicesLabel, noDevicesLabel, groupUpdateRoles, isOrg = false, currentOrg, userGroupsRole = ['support'] }) => {
|
|
19
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);
|
|
23
23
|
const [loadingAdd, setLoadingAdd] = useState(false);
|
|
24
|
-
const [editGroup, setEditGroup] = useState(false);
|
|
24
|
+
const [editGroup, setEditGroup] = useState(isOrg ? true : false);
|
|
25
25
|
const [checkboxSelection, setCheckboxSelection] = useState(false);
|
|
26
26
|
const [devicesToAdd, setDevicesToAdd] = useState([]);
|
|
27
27
|
const [deviceSelectedObjs, setDeviceSelectedObjs] = useState([]);
|
|
@@ -37,6 +37,7 @@ const GroupsDevices = ({ userInfo, handleGetUsersList, handleAddUserToGroup, han
|
|
|
37
37
|
const [groupUpdateVisible, setGroupUpdateVisible] = useState(false);
|
|
38
38
|
const [valueTab, setValueTab] = useState('1');
|
|
39
39
|
const clickedIdRef = useRef(null);
|
|
40
|
+
const labelEntity = isOrg ? "Organization" : "Group";
|
|
40
41
|
const handleChangeTab = (event, newValue) => {
|
|
41
42
|
setValueTab(newValue);
|
|
42
43
|
};
|
|
@@ -63,7 +64,10 @@ const GroupsDevices = ({ userInfo, handleGetUsersList, handleAddUserToGroup, han
|
|
|
63
64
|
page++;
|
|
64
65
|
}
|
|
65
66
|
const userGroupsUserIds = usersGroup && usersGroup.map((ug) => ug.user.userId) || [];
|
|
66
|
-
setUsersList(usersData
|
|
67
|
+
setUsersList(usersData
|
|
68
|
+
.filter((user) => userGroupsRole.includes(user.role) &&
|
|
69
|
+
!userGroupsUserIds.includes(user.uid))
|
|
70
|
+
.map((user) => {
|
|
67
71
|
const userName = user.name ? user.name.replace("/", " ") : "";
|
|
68
72
|
return { label: `${userName} (${user.email})`, id: user.uid };
|
|
69
73
|
}));
|
|
@@ -73,9 +77,16 @@ const GroupsDevices = ({ userInfo, handleGetUsersList, handleAddUserToGroup, han
|
|
|
73
77
|
}
|
|
74
78
|
};
|
|
75
79
|
const fetchDevices = async (group, selected) => {
|
|
80
|
+
let groupToUse = group;
|
|
81
|
+
if (currentOrg === 'all' && group === 'all' && selected !== 'all') {
|
|
82
|
+
groupToUse = groupInfo.parent_id;
|
|
83
|
+
}
|
|
84
|
+
else if (currentOrg != undefined && group === 'all') {
|
|
85
|
+
groupToUse = currentOrg;
|
|
86
|
+
}
|
|
76
87
|
try {
|
|
77
88
|
setLoadingDevices(true);
|
|
78
|
-
const devices = await handleGetDevices(userInfo,
|
|
89
|
+
const devices = await handleGetDevices(userInfo, groupToUse, selected);
|
|
79
90
|
setDevices(devices);
|
|
80
91
|
if (enableMaps && handleGetPositions) {
|
|
81
92
|
const positions = await handleGetPositions(devices);
|
|
@@ -116,7 +127,7 @@ const GroupsDevices = ({ userInfo, handleGetUsersList, handleAddUserToGroup, han
|
|
|
116
127
|
getUsersList();
|
|
117
128
|
}, [usersGroup]);
|
|
118
129
|
useEffect(() => {
|
|
119
|
-
if (currentGroup && !checkboxSelection) {
|
|
130
|
+
if (currentGroup && !checkboxSelection && groups !== null) {
|
|
120
131
|
setSelectedGroup(currentGroup);
|
|
121
132
|
setGroupInfo(groups && groups.find((g) => g.id === currentGroup));
|
|
122
133
|
if (currentGroup !== 'all') {
|
|
@@ -124,7 +135,7 @@ const GroupsDevices = ({ userInfo, handleGetUsersList, handleAddUserToGroup, han
|
|
|
124
135
|
}
|
|
125
136
|
fetchDevices(currentGroup, currentGroup);
|
|
126
137
|
}
|
|
127
|
-
}, [currentGroup]);
|
|
138
|
+
}, [currentGroup, groups]);
|
|
128
139
|
useEffect(() => {
|
|
129
140
|
if (forceGetDevices !== 0) {
|
|
130
141
|
fetchDevices(currentGroup, currentGroup);
|
|
@@ -143,6 +154,7 @@ const GroupsDevices = ({ userInfo, handleGetUsersList, handleAddUserToGroup, han
|
|
|
143
154
|
setCurrentGroup(id);
|
|
144
155
|
setGroupInfo({ ...newGroup, id });
|
|
145
156
|
setSelectedGroup(id);
|
|
157
|
+
getUsersGroup(id);
|
|
146
158
|
setDevicesToAdd([]), setEditGroup(!editGroup);
|
|
147
159
|
setCheckboxSelection(!checkboxSelection);
|
|
148
160
|
fetchDevices(id, id);
|
|
@@ -266,8 +278,8 @@ const GroupsDevices = ({ userInfo, handleGetUsersList, handleAddUserToGroup, han
|
|
|
266
278
|
? columnsArray.filter(col => col.field !== 'id')
|
|
267
279
|
: columnsArray, slots: {
|
|
268
280
|
noRowsOverlay: () => (_jsx(Stack, { height: "100%", alignItems: "center", justifyContent: "center", children: currentGroup !== 'all'
|
|
269
|
-
? (_jsxs(_Fragment, { children: [
|
|
270
|
-
:
|
|
281
|
+
? (_jsxs(_Fragment, { children: [_jsxs(Box, { children: [noDevicesLabel || 'No devices', " in ", labelEntity.toLocaleLowerCase()] }), editGroup && (_jsxs(Button, { onClick: addDevicesToCurrentGroup, variant: "outlined", color: "primary", size: "small", sx: { mt: 2 }, children: [_jsx(PlaylistAddIcon, { fontSize: "small", sx: { mr: 1 } }), addDevicesLabel || 'Add devices'] }))] }))
|
|
282
|
+
: noDevicesLabel || 'No devices' })),
|
|
271
283
|
noResultsOverlay: () => (_jsx(Stack, { height: "100%", alignItems: "center", justifyContent: "center", children: "Filter returns no result" })),
|
|
272
284
|
toolbar: customToolbar && customToolbar.length ? CustomToolbar : GridToolbar,
|
|
273
285
|
}, slotProps: {
|
|
@@ -286,27 +298,27 @@ const GroupsDevices = ({ userInfo, handleGetUsersList, handleAddUserToGroup, han
|
|
|
286
298
|
_jsx(Card, { ...containerProps, children: renderDataGrid }) : _jsx(Box, { ...containerProps, children: renderDataGrid }));
|
|
287
299
|
if (!userInfo || !groups || !devices)
|
|
288
300
|
return loadingComponent;
|
|
289
|
-
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: [
|
|
290
|
-
_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:
|
|
291
|
-
: '', userInfo.role === 'admin' || (groupUpdateRoles && groupUpdateRoles.includes(userInfo.role)) &&
|
|
301
|
+
return (_jsx(ThemeProvider, { theme: theme, children: _jsxs(Box, { ...props, children: [_jsxs(Box, { component: "div", sx: { display: 'flex', alignItems: 'center', mb: 1, backgroundColor: editGroup && !isOrg ? 'secondary.light' : '', borderRadius: 3, px: editGroup ? 2 : 0, py: 1, height: 50, ...propsHeaderGroups }, children: [editGroup ? _jsxs(Typography, { variant: 'subtitle1', children: [_jsxs(Box, { component: 'span', sx: { display: { xs: 'none' } }, children: ["Edit ", labelEntity.toLocaleLowerCase()] }), " ", _jsx("b", { children: groupInfo?.name })] }) : '', groups && !checkboxSelection && !isOrg && !(editGroup && currentGroup === 'all') ?
|
|
302
|
+
_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: labelEntity }) })
|
|
303
|
+
: '', (userInfo.role === 'admin' || (groupUpdateRoles && groupUpdateRoles.includes(userInfo.role))) &&
|
|
292
304
|
_jsxs(Box, { sx: { ml: 2 }, children: [checkboxSelection ?
|
|
293
305
|
_jsx(Input, { value: selectedGroup, type: 'hidden', size: 'small' })
|
|
294
|
-
: '', 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" }), "
|
|
306
|
+
: '', selectedGroup === 'all' && (currentOrg !== '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" }), " ", labelEntity.toLocaleLowerCase()] }) : '', editGroup ?
|
|
295
307
|
currentGroup === 'all' ?
|
|
296
|
-
checkboxSelection ? _jsxs(_Fragment, { children: [_jsxs(Button, { onClick: () => { setGroupUpdateVisible(false); setDevicesToAdd([]); setCurrentGroup(selectedGroup); setCheckboxSelection(true); fetchDevices(selectedGroup, selectedGroup); }, variant: "text", color: "inherit", size: "small", children: [_jsx(BackIcon, { fontSize: "small" }),
|
|
297
|
-
: devicesToAdd.length === 0 ? groupUpdateVisible ? _jsxs(Button, { onClick: () => setGroupUpdateVisible(false), sx: { ml: 2 }, variant: "text", color: "inherit", size: "small", children: [_jsx(BackIcon, { fontSize: "small" }),
|
|
298
|
-
_jsxs(_Fragment, { children: [_jsxs(Button, { onClick: () => addDevicesToCurrentGroup(), sx: { ml: 2 }, variant: "outlined", color: "primary", size: "small", children: [_jsx(PlaylistAddIcon, { fontSize: "small", sx: { mr: 1 } }), " ", addDevicesLabel || 'Add devices'] }), _jsxs(Button, { onClick: () => setGroupUpdateVisible(true), sx: { ml: 2 }, variant: "outlined", color: "success", size: "small", children: [_jsx(SettingsIcon, { fontSize: "small" }),
|
|
299
|
-
: _jsxs(LoadingButton, { loading: loadingGroups, onClick: async () => { setLoadingGroups(true); await removeFromCurrentGroup(); }, variant: "contained", color: "error", size: "small", disabled: loadingGroups, sx: { ml: 2 }, children: [_jsx(PlaylistRemoveIcon, { fontSize: "small", sx: { mr: 1 } }), " Remove from
|
|
300
|
-
: '', selectedGroup !== 'all' ?
|
|
308
|
+
checkboxSelection ? _jsxs(_Fragment, { children: [_jsxs(Button, { onClick: () => { setGroupUpdateVisible(false); setDevicesToAdd([]); setCurrentGroup(selectedGroup); setCheckboxSelection(true); fetchDevices(selectedGroup, selectedGroup); }, variant: "text", color: "inherit", size: "small", children: [_jsx(BackIcon, { fontSize: "small" }), _jsxs(Box, { component: 'span', sx: { display: { xs: 'none', sm: 'inline' } }, children: ["\u00A0Back to ", labelEntity.toLocaleLowerCase()] })] }), _jsxs(LoadingButton, { loading: loadingGroups, onClick: () => addToSelectedGroup(), variant: 'contained', size: "small", disabled: devicesToAdd.length === 0 || selectedGroup === 'all' || loadingGroups, sx: { ml: 2 }, children: [_jsx(ReadMoreIcon, { sx: { mr: 1 } }), " Add to group"] })] }) : ''
|
|
309
|
+
: devicesToAdd.length === 0 ? groupUpdateVisible ? _jsxs(Button, { onClick: () => setGroupUpdateVisible(false), sx: { ml: 2 }, variant: "text", color: "inherit", size: "small", children: [_jsx(BackIcon, { fontSize: "small" }), _jsxs(Box, { component: 'span', sx: { display: { xs: 'none', sm: 'inline' } }, children: ["\u00A0Back to ", labelEntity.toLocaleLowerCase()] })] }) :
|
|
310
|
+
_jsxs(_Fragment, { children: [_jsxs(Button, { onClick: () => addDevicesToCurrentGroup(), sx: { ml: 2 }, variant: "outlined", color: "primary", size: "small", children: [_jsx(PlaylistAddIcon, { fontSize: "small", sx: { mr: 1 } }), " ", addDevicesLabel || 'Add devices'] }), _jsxs(Button, { onClick: () => setGroupUpdateVisible(true), sx: { ml: 2 }, variant: "outlined", color: "success", size: "small", children: [_jsx(SettingsIcon, { fontSize: "small" }), _jsxs(Box, { component: 'span', sx: { display: { xs: 'none', sm: 'inline' } }, children: ["\u00A0Manage ", labelEntity.toLocaleLowerCase()] })] })] })
|
|
311
|
+
: _jsxs(LoadingButton, { loading: loadingGroups, onClick: async () => { setLoadingGroups(true); await removeFromCurrentGroup(); }, variant: "contained", color: "error", size: "small", disabled: loadingGroups, sx: { ml: 2 }, children: [_jsx(PlaylistRemoveIcon, { fontSize: "small", sx: { mr: 1 } }), " Remove from ", labelEntity.toLocaleLowerCase()] })
|
|
312
|
+
: '', selectedGroup !== 'all' && !isOrg ?
|
|
301
313
|
_jsx(_Fragment, { children: editGroup ?
|
|
302
314
|
_jsxs(Button, { variant: "text", color: "inherit", onClick: () => closeEditGroup(), sx: { ml: 2 }, children: [_jsx(CloseIcon, { fontSize: "small" }), _jsx(Box, { component: 'span', sx: { display: { xs: 'none', sm: 'inline' } }, children: "\u00A0Close edit" })] })
|
|
303
|
-
: _jsxs(Button, { variant: "contained", color: "secondary", onClick: () => { setDevicesToAdd([]); setEditGroup(!editGroup); setCheckboxSelection(!checkboxSelection); }, children: [_jsx(EditIcon, { sx: { mr: 1 } }), _jsx(Box, { component: 'span', sx: { display: { xs: 'none', sm: 'inline' } }, children: "Edit\u00A0" }), "
|
|
315
|
+
: _jsxs(Button, { variant: "contained", color: "secondary", onClick: () => { setDevicesToAdd([]); setEditGroup(!editGroup); setCheckboxSelection(!checkboxSelection); }, children: [_jsx(EditIcon, { sx: { mr: 1 } }), _jsx(Box, { component: 'span', sx: { display: { xs: 'none', sm: 'inline' } }, children: "Edit\u00A0" }), " ", labelEntity.toLocaleLowerCase()] }) }) : ''] })] }), _jsx(Modal, { open: openAdd, onClose: handleCloseAdd, children: _jsxs(Card, { sx: {
|
|
304
316
|
position: 'absolute',
|
|
305
317
|
top: '50%',
|
|
306
318
|
left: '50%',
|
|
307
319
|
transform: 'translate(-50%, -50%)',
|
|
308
320
|
width: 400,
|
|
309
321
|
borderRadius: 4
|
|
310
|
-
}, children: [_jsx(CardHeader, { title: "
|
|
322
|
+
}, children: [_jsx(CardHeader, { title: "new" + labelEntity, action: _jsx(IconButton, { onClick: handleCloseAdd, children: _jsx(CloseIcon, {}) }) }), _jsx(CardContent, { children: _jsxs("form", { onSubmit: handleSubmit, children: [_jsx(TextField, { fullWidth: true, label: labelEntity + " 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, labelEntity: labelEntity })] }) }));
|
|
311
323
|
};
|
|
312
324
|
export default GroupsDevices;
|
|
@@ -17,7 +17,7 @@ declare const UsersDataGrid: ({ handleGetUsersList, pageSize, container, contain
|
|
|
17
17
|
}>;
|
|
18
18
|
pageSize: number;
|
|
19
19
|
container?: "Card" | "Box";
|
|
20
|
-
containerProps?:
|
|
20
|
+
containerProps?: any;
|
|
21
21
|
props?: object | undefined;
|
|
22
22
|
loadingComponent?: React.ReactNode;
|
|
23
23
|
theme: Theme;
|
|
@@ -8,7 +8,7 @@ const UsersDataGrid = ({ handleGetUsersList, pageSize, container = 'Box', contai
|
|
|
8
8
|
const [usersList, setUsersList] = useState(undefined);
|
|
9
9
|
const [userCount, setUserCount] = useState(undefined);
|
|
10
10
|
const filterType = {
|
|
11
|
-
email: 'Email',
|
|
11
|
+
email: 'Email Address',
|
|
12
12
|
name: 'Full name',
|
|
13
13
|
role: 'Role'
|
|
14
14
|
};
|
|
@@ -85,9 +85,9 @@ const UsersDataGrid = ({ handleGetUsersList, pageSize, container = 'Box', contai
|
|
|
85
85
|
showQuickFilter: false,
|
|
86
86
|
},
|
|
87
87
|
}, rowCount: userCount, loading: isLoading, pageSizeOptions: [], paginationModel: paginationModel, paginationMode: "server", onPaginationModelChange: setPaginationModel, ...props }) }));
|
|
88
|
-
const renderFilter = () => (_jsxs(Box, { sx: {
|
|
88
|
+
const renderFilter = () => (_jsxs(Box, { sx: { position: "absolute", top: 10, right: 10, zIndex: 1 }, children: [_jsxs(FormControl, { children: [_jsx(InputLabel, { shrink: true, id: "filter-by-select-label", children: "Filter by" }), _jsx(Select, { value: selectedFilterType || '', onChange: (e) => setSelectedFilterType(e.target.value), labelId: "filter-by-select-label", label: "Filter by", size: "small", sx: { mr: 2 }, children: Object.entries(filterType).map(([key, label]) => (_jsx(MenuItem, { value: key, children: label }, key))) })] }), _jsx(TextField, { value: selectedFilterValue || "", onChange: (e) => handleFilterModelChange(e.target.value), placeholder: "Search...", size: "small", InputProps: {
|
|
89
89
|
endAdornment: selectedFilterValue ? (_jsx(IconButton, { size: "small", onClick: () => handleFilterModelChange(""), children: _jsx(ClearIcon, { fontSize: "small" }) })) : null,
|
|
90
90
|
} })] }));
|
|
91
|
-
return _jsx(ThemeProvider, { theme: theme, children: container === "Card" ? (
|
|
91
|
+
return _jsx(ThemeProvider, { theme: theme, children: container === "Card" ? (_jsx(_Fragment, { children: _jsxs(Card, { ...containerProps, sx: { position: 'relative', ...(containerProps?.sx) }, children: [renderFilter(), renderUsersList()] }) })) : (_jsxs(_Fragment, { children: [renderFilter(), _jsxs(Box, { ...containerProps, sx: { position: 'relative', ...(containerProps?.sx) }, children: [renderFilter(), renderUsersList()] })] })) });
|
|
92
92
|
};
|
|
93
93
|
export default UsersDataGrid;
|
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, assetID?: string) => Promise<{
|
|
2
|
+
export declare const getGroups: (db: Firestore, productID: number, userID?: string, parentID?: string, assetID?: string) => Promise<{
|
|
3
3
|
id: string;
|
|
4
4
|
}[]>;
|
|
5
5
|
export declare const getGroupById: (db: Firestore, id: string) => Promise<{
|
|
@@ -16,3 +16,6 @@ export declare const getGroupsUser: (db: Firestore, userID: string) => Promise<{
|
|
|
16
16
|
}[]>;
|
|
17
17
|
export declare const addUsersGroup: (db: Firestore, groupID: string, userName: string, userID: string) => Promise<string>;
|
|
18
18
|
export declare const removeUserGroup: (db: Firestore, groupID: string, userID: string) => Promise<string | undefined>;
|
|
19
|
+
export declare const getUserOrganizations: (db: Firestore, productID: number, userID?: string, assetID?: string) => Promise<{
|
|
20
|
+
id: string;
|
|
21
|
+
}[]>;
|
package/server-actions/groups.js
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
"use server";
|
|
2
2
|
// 1. GET GROUPS
|
|
3
|
-
export const getGroups = async (db, productID, userID, assetID) => {
|
|
3
|
+
export const getGroups = async (db, productID, userID, parentID, assetID) => {
|
|
4
4
|
let groupsRef = db.collection("groups").where("productID", "==", productID);
|
|
5
|
+
if (parentID) {
|
|
6
|
+
if (parentID === "all") {
|
|
7
|
+
groupsRef = groupsRef.where("parent_id", "!=", null);
|
|
8
|
+
}
|
|
9
|
+
else {
|
|
10
|
+
groupsRef = groupsRef.where("parent_id", "==", parentID);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
5
13
|
if (assetID) {
|
|
6
14
|
groupsRef = groupsRef.where("assets", "array-contains", assetID);
|
|
7
15
|
}
|
|
@@ -106,3 +114,56 @@ export const removeUserGroup = async (db, groupID, userID) => {
|
|
|
106
114
|
return doc.id;
|
|
107
115
|
}
|
|
108
116
|
};
|
|
117
|
+
// 9. GET ORGANIZATIONS
|
|
118
|
+
export const getUserOrganizations = async (db, productID, userID, assetID) => {
|
|
119
|
+
let groupsRef = db
|
|
120
|
+
.collection("groups")
|
|
121
|
+
.where("productID", "==", productID);
|
|
122
|
+
if (assetID) {
|
|
123
|
+
groupsRef = groupsRef.where("assets", "array-contains", assetID);
|
|
124
|
+
}
|
|
125
|
+
groupsRef = groupsRef.orderBy("created", "desc");
|
|
126
|
+
let groupIds = null;
|
|
127
|
+
if (userID) {
|
|
128
|
+
const userGroupsSnapshot = await db
|
|
129
|
+
.collection("userGroups")
|
|
130
|
+
.where("user.userId", "==", userID)
|
|
131
|
+
.get();
|
|
132
|
+
const userGroupIds = userGroupsSnapshot.docs.map((doc) => doc.data().groupId);
|
|
133
|
+
let parentIds = [];
|
|
134
|
+
if (userGroupIds.length > 0) {
|
|
135
|
+
const chunks = [];
|
|
136
|
+
for (let i = 0; i < userGroupIds.length; i += 10) {
|
|
137
|
+
chunks.push(userGroupIds.slice(i, i + 10));
|
|
138
|
+
}
|
|
139
|
+
for (const chunk of chunks) {
|
|
140
|
+
const groupsSnapshot = await db
|
|
141
|
+
.collection("groups")
|
|
142
|
+
.where("__name__", "in", chunk)
|
|
143
|
+
.get();
|
|
144
|
+
const ids = groupsSnapshot.docs
|
|
145
|
+
.map((doc) => doc.data().parent_id)
|
|
146
|
+
.filter((id) => id !== null && id !== undefined);
|
|
147
|
+
parentIds.push(...ids);
|
|
148
|
+
}
|
|
149
|
+
// Rimuove duplicati
|
|
150
|
+
groupIds = Array.from(new Set(parentIds));
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
groupIds = [];
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
const groupsSnapshot = await groupsRef.get();
|
|
157
|
+
const organizations = groupsSnapshot.docs
|
|
158
|
+
.filter((doc) => {
|
|
159
|
+
const data = doc.data();
|
|
160
|
+
const parentId = data.parent_id;
|
|
161
|
+
return (parentId === null || parentId === undefined) &&
|
|
162
|
+
(!groupIds || groupIds.includes(doc.id));
|
|
163
|
+
})
|
|
164
|
+
.map((doc) => ({
|
|
165
|
+
id: doc.id,
|
|
166
|
+
...doc.data()
|
|
167
|
+
}));
|
|
168
|
+
return organizations;
|
|
169
|
+
};
|
|
@@ -37,5 +37,5 @@ export declare function post(trackleConfig: TrackleConfig, id: string, endpoint:
|
|
|
37
37
|
export declare function put(trackleConfig: TrackleConfig, id: string, endpoint: string, value: any, productId?: number, uid?: string): Promise<{
|
|
38
38
|
return_value: number;
|
|
39
39
|
}>;
|
|
40
|
-
export declare function addDevicesToGroup(trackleConfig: TrackleConfig, productId: number,
|
|
41
|
-
export declare function removeDevicesFromGroup(trackleConfig: TrackleConfig, productId: number,
|
|
40
|
+
export declare function addDevicesToGroup(trackleConfig: TrackleConfig, productId: number, group: string, devicesToPatch: TrackleDeviceType[], uid?: string): Promise<TrackleDeviceType[]>;
|
|
41
|
+
export declare function removeDevicesFromGroup(trackleConfig: TrackleConfig, productId: number, group: string, devicesToPatch: TrackleDeviceType[], uid?: string): Promise<TrackleDeviceType[]>;
|
|
@@ -121,7 +121,7 @@ export async function put(trackleConfig, id, endpoint, value, productId, uid) {
|
|
|
121
121
|
.setTimeout(trackleConfig.apiTimeout)
|
|
122
122
|
.json();
|
|
123
123
|
}
|
|
124
|
-
export async function addDevicesToGroup(trackleConfig, productId,
|
|
124
|
+
export async function addDevicesToGroup(trackleConfig, productId, group, devicesToPatch, uid) {
|
|
125
125
|
const devicesPatched = [];
|
|
126
126
|
for (const device of devicesToPatch) {
|
|
127
127
|
const newGroups = device.state?.groups && device.state?.groups instanceof Array
|
|
@@ -129,19 +129,19 @@ export async function addDevicesToGroup(trackleConfig, productId, uid, group, de
|
|
|
129
129
|
: [];
|
|
130
130
|
if (!newGroups.includes(group)) {
|
|
131
131
|
newGroups.push(group);
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
.put({
|
|
135
|
-
|
|
136
|
-
|
|
132
|
+
const api = uid ? wretchApi(trackleConfig, uid) : wretchApi(trackleConfig);
|
|
133
|
+
await api
|
|
134
|
+
.put({ value: newGroups }, uid
|
|
135
|
+
? `/devices/${device.id}/groups`
|
|
136
|
+
: `/products/${productId}/devices/${device.id}/groups`)
|
|
137
137
|
.setTimeout(trackleConfig.apiTimeout)
|
|
138
|
-
.
|
|
138
|
+
.json();
|
|
139
139
|
devicesPatched.push(device);
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
142
|
return devicesPatched;
|
|
143
143
|
}
|
|
144
|
-
export async function removeDevicesFromGroup(trackleConfig, productId,
|
|
144
|
+
export async function removeDevicesFromGroup(trackleConfig, productId, group, devicesToPatch, uid) {
|
|
145
145
|
const devicesPatched = [];
|
|
146
146
|
for (const device of devicesToPatch) {
|
|
147
147
|
let newGroups = device.state?.groups && device.state?.groups instanceof Array
|
|
@@ -149,11 +149,11 @@ export async function removeDevicesFromGroup(trackleConfig, productId, uid, grou
|
|
|
149
149
|
: [];
|
|
150
150
|
if (newGroups.includes(group)) {
|
|
151
151
|
newGroups = newGroups.filter((newGroup) => newGroup !== group);
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
.put({
|
|
155
|
-
|
|
156
|
-
|
|
152
|
+
const api = uid ? wretchApi(trackleConfig, uid) : wretchApi(trackleConfig);
|
|
153
|
+
await api
|
|
154
|
+
.put({ value: newGroups }, uid
|
|
155
|
+
? `/devices/${device.id}/groups`
|
|
156
|
+
: `/products/${productId}/devices/${device.id}/groups`)
|
|
157
157
|
.setTimeout(trackleConfig.apiTimeout)
|
|
158
158
|
.res();
|
|
159
159
|
devicesPatched.push(device);
|